refactor(shared): consolidate core leaf lazy loaders (#99278)

This commit is contained in:
Dallin Romney
2026-07-02 18:06:00 -07:00
committed by GitHub
parent 9238d9aeae
commit 5fa2082655
42 changed files with 307 additions and 576 deletions
@@ -24,23 +24,19 @@ import {
POSIX_SHELL_WRAPPERS,
resolveShellWrapperTransportArgv,
} from "../infra/shell-wrapper-resolution.js";
import { createLazyPromise } from "../shared/lazy-runtime.js";
import {
DEFAULT_APPROVAL_REQUEST_TIMEOUT_MS,
DEFAULT_APPROVAL_TIMEOUT_MS,
} from "./bash-tools.exec-runtime.js";
import { callGatewayTool } from "./tools/gateway.js";
type ExecApprovalCommandSpansRuntime =
typeof import("./bash-tools.exec-approval-request.runtime.js");
let execApprovalCommandSpansRuntimePromise: Promise<ExecApprovalCommandSpansRuntime> | null = null;
const POSIX_COMMAND_HIGHLIGHT_SHELLS: ReadonlySet<string> = POSIX_SHELL_WRAPPERS;
function loadExecApprovalCommandSpansRuntime(): Promise<ExecApprovalCommandSpansRuntime> {
execApprovalCommandSpansRuntimePromise ??=
import("./bash-tools.exec-approval-request.runtime.js");
return execApprovalCommandSpansRuntimePromise;
}
const loadExecApprovalCommandSpansRuntime = createLazyPromise(
() => import("./bash-tools.exec-approval-request.runtime.js"),
{ cacheRejections: true },
);
/** Gateway payload fields used to register or wait for an exec approval decision. */
type RequestExecApprovalDecisionParams = {
+7 -4
View File
@@ -14,6 +14,7 @@ import { isRecord } from "@openclaw/normalization-core/record-coerce";
import { uniqueValues } from "@openclaw/normalization-core/string-normalization";
import { Type } from "typebox";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createLazyPromiseLoader } from "../shared/lazy-runtime.js";
import { resolveAgentConfig } from "./agent-scope-config.js";
import type { HookContext } from "./agent-tools.before-tool-call.js";
import {
@@ -151,7 +152,9 @@ type CodeModeWorkerResult =
const activeRuns = new Map<string, CodeModeRunState>();
const resumingRunIds = new Set<string>();
let activeRunReservations = 0;
let typescriptRuntimePromise: Promise<typeof import("typescript")> | null = null;
const typescriptRuntimeLoader = createLazyPromiseLoader(() => import("typescript"), {
cacheRejections: true,
});
let typescriptRuntimeForTest: typeof import("typescript") | null = null;
function normalizeCodeModeRawConfig(value: unknown): Record<string, unknown> | undefined {
@@ -438,8 +441,7 @@ async function loadTypeScriptRuntime(): Promise<typeof import("typescript")> {
if (typescriptRuntimeForTest) {
return typescriptRuntimeForTest;
}
typescriptRuntimePromise ??= import("typescript");
return await typescriptRuntimePromise;
return await typescriptRuntimeLoader.load();
}
async function prepareSource(input: {
@@ -1274,7 +1276,8 @@ export const testing = {
runCodeModeWorker,
resolveCodeModeWorkerUrl,
resolveCodeModeConfig,
getTypescriptRuntimePromise: () => typescriptRuntimePromise,
getTypescriptRuntimePromise: (): Promise<typeof import("typescript")> | null =>
typescriptRuntimeLoader.peek() ?? null,
setTypescriptRuntimeForTest: (runtime: typeof import("typescript") | null) => {
typescriptRuntimeForTest = runtime;
},
@@ -19,6 +19,7 @@ import type {
import { formatErrorMessage } from "../../../infra/errors.js";
import type { Model } from "../../../llm/types.js";
import type { PluginMetadataSnapshot } from "../../../plugins/plugin-metadata-snapshot.js";
import { createLazyPromise } from "../../../shared/lazy-runtime.js";
import type { EmbeddedContextFile } from "../../embedded-agent-helpers.js";
import type {
MessagingToolSend,
@@ -924,18 +925,15 @@ function createCompletedAssistantStream(): TestAgentStream {
},
};
}
let runEmbeddedAttemptPromise:
| Promise<typeof import("./attempt.js").runEmbeddedAttempt>
| undefined;
const ATTEMPT_SPAWN_WORKSPACE_TEST_SPECIFIER = "./attempt.ts?spawn-workspace-test";
async function loadRunEmbeddedAttempt() {
runEmbeddedAttemptPromise ??= (
import(ATTEMPT_SPAWN_WORKSPACE_TEST_SPECIFIER) as Promise<typeof import("./attempt.js")>
).then((mod) => mod.runEmbeddedAttempt);
return await runEmbeddedAttemptPromise;
}
const loadRunEmbeddedAttempt = createLazyPromise(
() =>
(import(ATTEMPT_SPAWN_WORKSPACE_TEST_SPECIFIER) as Promise<typeof import("./attempt.js")>).then(
(mod) => mod.runEmbeddedAttempt,
),
{ cacheRejections: true },
);
export async function preloadRunEmbeddedAttemptForTests(): Promise<void> {
await loadRunEmbeddedAttempt();
+3 -8
View File
@@ -1,5 +1,6 @@
// Commander registration for device pairing and auth-token commands.
import type { Command } from "commander";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { applyParentDefaultHelpAction } from "./program/parent-default-help.js";
type DevicesRpcOpts = {
@@ -18,14 +19,8 @@ type DevicesRpcOpts = {
const DEFAULT_DEVICES_TIMEOUT_MS = 10_000;
type DevicesRuntimeModule = typeof import("./devices-cli.runtime.js");
let devicesRuntimePromise: Promise<DevicesRuntimeModule> | undefined;
function loadDevicesRuntime(): Promise<DevicesRuntimeModule> {
// Keep device-pairing crypto/table dependencies out of root help startup.
return (devicesRuntimePromise ??= import("./devices-cli.runtime.js"));
}
// Keep device-pairing crypto/table dependencies out of root help startup.
const loadDevicesRuntime = createLazyRuntimeModule(() => import("./devices-cli.runtime.js"));
const devicesCallOpts = (cmd: Command, defaults?: { timeoutMs?: number }) =>
cmd
+4 -5
View File
@@ -2,6 +2,7 @@
import type { Command } from "commander";
import { formatDocsLink } from "../../../packages/terminal-core/src/links.js";
import { theme } from "../../../packages/terminal-core/src/theme.js";
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
import { hasExplicitOptions } from "../command-options.js";
import { formatHelpExamples } from "../help-format.js";
import { collectOption } from "./helpers.js";
@@ -14,11 +15,9 @@ type AgentsListModule = typeof import("../../commands/agents.commands.list.js");
type CliUtilsModule = typeof import("../cli-utils.js");
type RuntimeModule = typeof import("../../runtime.js");
let agentsBindModulePromise: Promise<AgentsBindModule> | undefined;
function loadAgentsBindModule(): Promise<AgentsBindModule> {
return (agentsBindModulePromise ??= import("../../commands/agents.commands.bind.js"));
}
const loadAgentsBindModule = createLazyRuntimeModule(
() => import("../../commands/agents.commands.bind.js"),
);
async function loadAgentsAddCommand(): Promise<AgentsAddModule["agentsAddCommand"]> {
return (await import("../../commands/agents.commands.add.js")).agentsAddCommand;
+24 -28
View File
@@ -37,6 +37,7 @@ import {
scopeLegacySessionKeyToAgent,
} from "../routing/session-key.js";
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";
import { createLazyPromiseLoader } from "../shared/lazy-runtime.js";
import { normalizeMessageChannel } from "../utils/message-channel-normalize.js";
type AgentGatewayResult = {
@@ -104,9 +105,7 @@ type AgentGatewayCallIdentity = Pick<
Parameters<typeof callGateway>[0],
"clientName" | "mode" | "scopes"
>;
type EmbeddedAgentCommandModule = typeof import("./agent.js");
type AgentSessionModule = typeof import("./agent/session.js");
type RuntimeConfigModule = typeof import("../config/io.js");
type AgentSessionModuleLoader = () => Promise<AgentSessionModule>;
const AGENT_CLI_SIGNALS: readonly AgentCliSignal[] = ["SIGINT", "SIGTERM"];
@@ -118,53 +117,50 @@ const AGENT_CLI_SIGNAL_EXIT_CODES: Record<AgentCliSignal, number> = {
};
const MESSAGE_FILE_DECODER = new TextDecoder("utf-8", { fatal: true });
let embeddedAgentCommandPromise: Promise<EmbeddedAgentCommandModule["agentCommand"]> | undefined;
let agentSessionModulePromise: Promise<AgentSessionModule> | undefined;
let runtimeConfigModulePromise: Promise<RuntimeConfigModule> | undefined;
let replyPayloadModulePromise:
| Promise<typeof import("openclaw/plugin-sdk/reply-payload")>
| undefined;
const defaultAgentSessionModuleLoader: AgentSessionModuleLoader = () =>
import("./agent/session.js");
let agentSessionModuleLoader: AgentSessionModuleLoader = defaultAgentSessionModuleLoader;
const embeddedAgentCommandLoader = createLazyPromiseLoader(
() => import("./agent.js").then((module) => module.agentCommand),
{ cacheRejections: true },
);
const agentSessionModuleCache = createLazyPromiseLoader(() => agentSessionModuleLoader(), {
cacheRejections: true,
});
const runtimeConfigModuleLoader = createLazyPromiseLoader(() => import("../config/io.js"), {
cacheRejections: true,
});
const replyPayloadModuleLoader = createLazyPromiseLoader(
() => import("openclaw/plugin-sdk/reply-payload"),
{ cacheRejections: true },
);
let gatewayAbortRetryDelaysMsForTests: readonly number[] | undefined;
function resolveGatewayAbortRetryDelaysMs(): readonly number[] {
return gatewayAbortRetryDelaysMsForTests ?? GATEWAY_ABORT_RETRY_DELAYS_MS;
}
function loadEmbeddedAgentCommand(): Promise<EmbeddedAgentCommandModule["agentCommand"]> {
embeddedAgentCommandPromise ??= import("./agent.js").then((module) => module.agentCommand);
return embeddedAgentCommandPromise;
}
function loadAgentSessionModule(): Promise<AgentSessionModule> {
agentSessionModulePromise ??= agentSessionModuleLoader();
return agentSessionModulePromise;
}
const loadEmbeddedAgentCommand = embeddedAgentCommandLoader.load;
const loadAgentSessionModule = agentSessionModuleCache.load;
async function loadRuntimeConfig(): Promise<OpenClawConfig> {
runtimeConfigModulePromise ??= import("../config/io.js");
const { getRuntimeConfig } = await runtimeConfigModulePromise;
const { getRuntimeConfig } = await runtimeConfigModuleLoader.load();
return getRuntimeConfig();
}
function loadReplyPayloadModule() {
replyPayloadModulePromise ??= import("openclaw/plugin-sdk/reply-payload");
return replyPayloadModulePromise;
}
const loadReplyPayloadModule = replyPayloadModuleLoader.load;
/** Test-only hooks for resetting lazy imports and shortening retry timing. */
export const agentViaGatewayTesting = {
resetLazyImportsForTests(): void {
embeddedAgentCommandPromise = undefined;
agentSessionModulePromise = undefined;
runtimeConfigModulePromise = undefined;
replyPayloadModulePromise = undefined;
embeddedAgentCommandLoader.clear();
agentSessionModuleCache.clear();
runtimeConfigModuleLoader.clear();
replyPayloadModuleLoader.clear();
agentSessionModuleLoader = defaultAgentSessionModuleLoader;
},
setAgentSessionModuleLoaderForTests(loader: AgentSessionModuleLoader): void {
agentSessionModulePromise = undefined;
agentSessionModuleCache.clear();
agentSessionModuleLoader = loader;
},
resolveGatewayAgentTimeoutMs,
+9 -17
View File
@@ -43,6 +43,7 @@ import {
import { collectPluginConfigAssignments } from "../secrets/runtime-config-collectors-plugins.js";
import { createResolverContext } from "../secrets/runtime-shared.js";
import { discoverConfigSecretTargets } from "../secrets/target-registry.js";
import { createLazyPromise } from "../shared/lazy-runtime.js";
import {
emitDaemonInstallRuntimeWarning,
resolveDaemonInstallRuntimeInputs,
@@ -60,13 +61,6 @@ type GatewayInstallPlan = {
environmentValueSources?: Record<string, GatewayServiceEnvironmentValueSource | undefined>;
};
let daemonInstallAuthProfileSourceRuntimePromise:
| Promise<typeof import("./daemon-install-auth-profiles-source.runtime.js")>
| undefined;
let daemonInstallAuthProfileStoreRuntimePromise:
| Promise<typeof import("./daemon-install-auth-profiles-store.runtime.js")>
| undefined;
const NON_PERSISTED_CONFIG_SECRET_ENV_TARGET_IDS = new Set([
"gateway.auth.password",
"gateway.auth.token",
@@ -83,17 +77,15 @@ function isBlockedExecSecretRefPassEnvKey(key: string): boolean {
return !EXEC_SECRET_REF_PASS_ENV_ALLOWED_OVERRIDE_ONLY_KEYS.has(key.toUpperCase());
}
function loadDaemonInstallAuthProfileSourceRuntime() {
daemonInstallAuthProfileSourceRuntimePromise ??=
import("./daemon-install-auth-profiles-source.runtime.js");
return daemonInstallAuthProfileSourceRuntimePromise;
}
const loadDaemonInstallAuthProfileSourceRuntime = createLazyPromise(
() => import("./daemon-install-auth-profiles-source.runtime.js"),
{ cacheRejections: true },
);
function loadDaemonInstallAuthProfileStoreRuntime() {
daemonInstallAuthProfileStoreRuntimePromise ??=
import("./daemon-install-auth-profiles-store.runtime.js");
return daemonInstallAuthProfileStoreRuntimePromise;
}
const loadDaemonInstallAuthProfileStoreRuntime = createLazyPromise(
() => import("./daemon-install-auth-profiles-store.runtime.js"),
{ cacheRejections: true },
);
async function resolveAuthProfileStoreForServiceEnv(
authStore: AuthProfileStore | undefined,
+5 -14
View File
@@ -11,26 +11,17 @@ import { formatConfigIssueLines } from "../config/issue-format.js";
import type { ConfigFileSnapshot, LegacyConfigIssue } from "../config/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { isTruthyEnvValue } from "../infra/env.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { resolveHomeDir } from "../utils.js";
import { noteIncludeConfinementWarning } from "./doctor-config-analysis.js";
import { findDoctorLegacyConfigIssues } from "./doctor/shared/legacy-config-issues.js";
import { resolveStateMigrationConfigInput } from "./doctor/shared/legacy-config-state-migration-input.js";
type DoctorStateMigrationsModule = typeof import("./doctor-state-migrations.js");
type DoctorCronModule = typeof import("./doctor/cron/index.js");
const loadDoctorStateMigrations = createLazyRuntimeModule(
() => import("./doctor-state-migrations.js"),
);
let doctorStateMigrationsPromise: Promise<DoctorStateMigrationsModule> | null = null;
let doctorCronPromise: Promise<DoctorCronModule> | null = null;
function loadDoctorStateMigrations(): Promise<DoctorStateMigrationsModule> {
doctorStateMigrationsPromise ??= import("./doctor-state-migrations.js");
return doctorStateMigrationsPromise;
}
function loadDoctorCron(): Promise<DoctorCronModule> {
doctorCronPromise ??= import("./doctor/cron/index.js");
return doctorCronPromise;
}
const loadDoctorCron = createLazyRuntimeModule(() => import("./doctor/cron/index.js"));
async function maybeMigrateLegacyConfig(): Promise<string[]> {
const changes: string[] = [];
+2 -6
View File
@@ -7,6 +7,7 @@ import { fileURLToPath } from "node:url";
import { sortUniqueStrings } from "@openclaw/normalization-core/string-normalization";
import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js";
import { replaceFileAtomicSync } from "../infra/replace-file.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import type { ConfigSchemaResponse } from "./schema.js";
import { schemaHasChildren } from "./schema.shared.js";
@@ -91,8 +92,6 @@ const DEFAULT_CHANNEL_OUTPUT = "docs/.generated/config-baseline.channel.json";
const DEFAULT_PLUGIN_OUTPUT = "docs/.generated/config-baseline.plugin.json";
const DEFAULT_HASH_OUTPUT = "docs/.generated/config-baseline.sha256";
let cachedConfigDocBaselinePromise: Promise<ConfigDocBaseline> | null = null;
let cachedDocBaselineRuntimePromise: Promise<typeof import("./doc-baseline.runtime.js")> | null =
null;
const uiHintIndexCache = new WeakMap<
ConfigSchemaResponse["uiHints"],
Map<
@@ -123,10 +122,7 @@ function resolveRepoRoot(): string {
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
}
async function loadDocBaselineRuntime() {
cachedDocBaselineRuntimePromise ??= import("./doc-baseline.runtime.js");
return await cachedDocBaselineRuntimePromise;
}
const loadDocBaselineRuntime = createLazyRuntimeModule(() => import("./doc-baseline.runtime.js"));
function normalizeBaselinePath(rawPath: string): string {
return rawPath
+4 -8
View File
@@ -20,6 +20,7 @@ import type {
SessionTranscriptUpdate,
SessionTranscriptUpdateTarget,
} from "../../sessions/transcript-events.js";
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
import type { OpenClawConfig } from "../types.openclaw.js";
import { formatSessionArchiveTimestamp } from "./artifacts.js";
import { extractGeneratedTranscriptSessionId } from "./generated-transcript-session-id.js";
@@ -441,14 +442,9 @@ type SessionEntryRetirement = {
key: string;
};
let sessionArchiveRuntimePromise: Promise<
typeof import("../../gateway/session-archive.runtime.js")
> | null = null;
function loadSessionArchiveRuntime() {
sessionArchiveRuntimePromise ??= import("../../gateway/session-archive.runtime.js");
return sessionArchiveRuntimePromise;
}
const loadSessionArchiveRuntime = createLazyRuntimeModule(
() => import("../../gateway/session-archive.runtime.js"),
);
export type SessionEntryPatchOptions = {
/** Entry to synthesize when a patch operation is allowed to create. */
+7 -14
View File
@@ -7,6 +7,7 @@ import { resolveStoredSessionOwnerAgentId } from "../../gateway/session-store-ke
import { writeTextAtomic } from "../../infra/json-files.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js";
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
import {
deliveryContextFromChannelRoute,
deliveryContextFromSession,
@@ -115,26 +116,18 @@ export type SessionEntryPatchProjectionResult<TFailure extends SessionEntryPatch
{ ok: true; entry: SessionEntry } | TFailure;
const log = createSubsystemLogger("sessions/store");
let sessionArchiveRuntimePromise: Promise<
typeof import("../../gateway/session-archive.runtime.js")
> | null = null;
let trajectoryCleanupRuntimePromise: Promise<typeof import("../../trajectory/cleanup.js")> | null =
null;
const writerStoreFileStats = new WeakMap<
Record<string, SessionEntry>,
ReturnType<typeof getFileStatSnapshot> | null
>();
function loadSessionArchiveRuntime() {
// Archive cleanup is a cold maintenance path, so keep it lazy to avoid gateway import cycles.
sessionArchiveRuntimePromise ??= import("../../gateway/session-archive.runtime.js");
return sessionArchiveRuntimePromise;
}
const loadSessionArchiveRuntime = createLazyRuntimeModule(
() => import("../../gateway/session-archive.runtime.js"),
);
function loadTrajectoryCleanupRuntime() {
trajectoryCleanupRuntimePromise ??= import("../../trajectory/cleanup.js");
return trajectoryCleanupRuntimePromise;
}
const loadTrajectoryCleanupRuntime = createLazyRuntimeModule(
() => import("../../trajectory/cleanup.js"),
);
function removeThreadFromDeliveryContext(context?: DeliveryContext): DeliveryContext | undefined {
if (!context || context.threadId == null) {
+2 -7
View File
@@ -3,19 +3,14 @@ import { intro as clackIntro, outro as clackOutro } from "@clack/prompts";
import { stylePromptTitle } from "../../packages/terminal-core/src/prompt-style.js";
import type { DoctorOptions } from "../commands/doctor-prompter.js";
import type { RuntimeEnv } from "../runtime.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import type { DoctorHealthFlowContext } from "./doctor-health-contributions.js";
// Interactive doctor entrypoint; lazy imports keep normal CLI startup light.
const intro = (message: string) => clackIntro(stylePromptTitle(message) ?? message);
const outro = (message: string) => clackOutro(stylePromptTitle(message) ?? message);
type ConfigModule = typeof import("../config/config.js");
let configModulePromise: Promise<ConfigModule> | undefined;
function loadConfigModule(): Promise<ConfigModule> {
return (configModulePromise ??= import("../config/config.js"));
}
const loadConfigModule = createLazyRuntimeModule(() => import("../config/config.js"));
/** Runs the full interactive doctor flow against the provided or default runtime. */
export async function doctorCommand(runtime?: RuntimeEnv, options: DoctorOptions = {}) {
+2 -6
View File
@@ -13,15 +13,11 @@ import {
} from "../plugins/install-security-scan.js";
import { PLUGIN_MANIFEST_FILENAME } from "../plugins/manifest.js";
import type { InstallPolicySource } from "../security/install-policy.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { CONFIG_DIR, resolveUserPath } from "../utils.js";
import { parseFrontmatter } from "./frontmatter.js";
let hookInstallRuntimePromise: Promise<typeof import("./install.runtime.js")> | undefined;
async function loadHookInstallRuntime() {
hookInstallRuntimePromise ??= import("./install.runtime.js");
return hookInstallRuntimePromise;
}
const loadHookInstallRuntime = createLazyRuntimeModule(() => import("./install.runtime.js"));
/** Logger contract used by hook install and update operations. */
export type HookInstallLogger = {
+2 -8
View File
@@ -15,6 +15,7 @@ import {
resolveBackupPlanFromDisk,
} from "../commands/backup-shared.js";
import { isPathWithin } from "../commands/cleanup-utils.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { resolveOpenClawStateSqlitePath } from "../state/openclaw-state-db.paths.js";
import { resolveHomeDir, resolveUserPath } from "../utils.js";
import { resolveRuntimeServiceVersion } from "../version.js";
@@ -22,14 +23,7 @@ import { isVolatileBackupPath } from "./backup-volatile-filter.js";
import { writeJson } from "./json-files.js";
import { requireNodeSqlite } from "./node-sqlite.js";
type TarRuntime = typeof import("tar");
let tarRuntimePromise: Promise<TarRuntime> | undefined;
function loadTarRuntime(): Promise<TarRuntime> {
tarRuntimePromise ??= import("tar");
return tarRuntimePromise;
}
const loadTarRuntime = createLazyRuntimeModule(() => import("tar"));
type BackupLinkCacheKey = `${number}:${number}`;
+9 -5
View File
@@ -1,18 +1,22 @@
// Normalizes env flag values and logs env warnings lazily.
import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
import type { SubsystemLogger } from "../logging/subsystem.js";
import { createLazyPromise } from "../shared/lazy-runtime.js";
let log: SubsystemLogger | null = null;
let logPromise: Promise<SubsystemLogger> | null = null;
const loadLog = createLazyPromise(
() =>
import("../logging/subsystem.js").then(({ createSubsystemLogger }) =>
createSubsystemLogger("env"),
),
{ cacheRejections: true },
);
const loggedEnv = new Set<string>();
const ENV_NORMALIZATION_KEY_GROUPS = [["ZAI_API_KEY", "Z_AI_API_KEY"]] as const;
async function getLog(): Promise<SubsystemLogger> {
if (!log) {
logPromise ??= import("../logging/subsystem.js").then(({ createSubsystemLogger }) =>
createSubsystemLogger("env"),
);
log = await logPromise;
log = await loadLog();
}
return log;
}
+4 -7
View File
@@ -20,6 +20,7 @@ import {
buildPluginApprovalResolvedReplyPayload,
} from "../plugin-sdk/approval-renderers.js";
import { channelRouteDedupeKey } from "../plugin-sdk/channel-route.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import {
isDeliverableMessageChannel,
normalizeMessageChannel,
@@ -142,14 +143,10 @@ type ExecApprovalForwarderDeps = {
const DEFAULT_MODE = "session" as const;
const SYNTHETIC_APPROVAL_REQUEST_ID = "__approval-routing__";
let execApprovalForwarderRuntimePromise: Promise<
typeof import("./exec-approval-forwarder.runtime.js")
> | null = null;
function loadExecApprovalForwarderRuntime() {
execApprovalForwarderRuntimePromise ??= import("./exec-approval-forwarder.runtime.js");
return execApprovalForwarderRuntimePromise;
}
const loadExecApprovalForwarderRuntime = createLazyRuntimeModule(
() => import("./exec-approval-forwarder.runtime.js"),
);
function normalizeMode(mode?: ExecApprovalForwardingConfig["mode"]) {
return mode ?? DEFAULT_MODE;
+4 -6
View File
@@ -106,6 +106,7 @@ import {
toAgentStoreSessionKey,
} from "../routing/session-key.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { escapeRegExp } from "../utils.js";
import { MAX_SAFE_TIMEOUT_DELAY_MS, resolveSafeTimeoutDelayMs } from "../utils/timer-delay.js";
import { loadOrCreateDeviceIdentity } from "./device-identity.js";
@@ -172,13 +173,10 @@ export type HeartbeatDeps = OutboundSendDeps &
};
const log = createSubsystemLogger("gateway/heartbeat");
let heartbeatRunnerRuntimePromise: Promise<typeof import("./heartbeat-runner.runtime.js")> | null =
null;
function loadHeartbeatRunnerRuntime() {
heartbeatRunnerRuntimePromise ??= import("./heartbeat-runner.runtime.js");
return heartbeatRunnerRuntimePromise;
}
const loadHeartbeatRunnerRuntime = createLazyRuntimeModule(
() => import("./heartbeat-runner.runtime.js"),
);
const HEARTBEAT_ALWAYS_BUSY_LANES = [CommandLane.Cron, CommandLane.CronNested] as const;
const DEFAULT_HEARTBEAT_TIMEOUT_SECONDS = 10 * 60;
+9 -17
View File
@@ -41,6 +41,7 @@ import { createSubsystemLogger } from "../../logging/subsystem.js";
import type { OutboundMediaAccess } from "../../media/load-options.js";
import { resolveAgentScopedOutboundMediaAccess } from "../../media/read-capability.js";
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
import { diagnosticErrorCategory } from "../diagnostic-error-metadata.js";
import {
emitInternalDiagnosticEvent as emitDiagnosticEvent,
@@ -123,25 +124,16 @@ export type OutboundDurableDeliverySupport =
};
const log = createSubsystemLogger("outbound/deliver");
let transcriptRuntimePromise:
| Promise<typeof import("../../config/sessions/transcript.runtime.js")>
| undefined;
async function loadTranscriptRuntime() {
// Transcript writes are optional side effects; keep this lazy for import-only
// delivery policy checks and tests.
transcriptRuntimePromise ??= import("../../config/sessions/transcript.runtime.js");
return await transcriptRuntimePromise;
}
// Transcript writes are optional side effects; keep this lazy for import-only
// delivery policy checks and tests.
const loadTranscriptRuntime = createLazyRuntimeModule(
() => import("../../config/sessions/transcript.runtime.js"),
);
let channelBootstrapRuntimePromise:
| Promise<typeof import("./channel-bootstrap.runtime.js")>
| undefined;
async function loadChannelBootstrapRuntime() {
channelBootstrapRuntimePromise ??= import("./channel-bootstrap.runtime.js");
return await channelBootstrapRuntimePromise;
}
const loadChannelBootstrapRuntime = createLazyRuntimeModule(
() => import("./channel-bootstrap.runtime.js"),
);
type ChannelHandler = {
chunker: ChannelOutboundAdapter["chunker"] | null;
+6 -10
View File
@@ -42,6 +42,7 @@ import { extractToolPayload } from "../../plugin-sdk/tool-payload.js";
import { hasPollCreationParams } from "../../poll-params.js";
import { resolvePollMaxSelections } from "../../polls.js";
import { resolveFirstBoundAccountId } from "../../routing/bound-account-read.js";
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
import { stripUnsupportedCitationControlMarkers } from "../../shared/text/citation-control-markers.js";
import { stripFormattedReasoningMessage } from "../../shared/text/formatted-reasoning-message.js";
import { parseInlineDirectives } from "../../utils/directive-tags.js";
@@ -104,16 +105,11 @@ export type MessageActionRunnerGateway = {
mode: GatewayClientMode;
};
let messageActionGatewayRuntimePromise: Promise<
typeof import("./message.gateway.runtime.js")
> | null = null;
function loadMessageActionGatewayRuntime() {
// Gateway runtime is only needed for remote message action dispatch or
// idempotency keys; keep normal in-process actions import-light.
messageActionGatewayRuntimePromise ??= import("./message.gateway.runtime.js");
return messageActionGatewayRuntimePromise;
}
// Gateway runtime is only needed for remote message action dispatch or
// idempotency keys; keep normal in-process actions import-light.
const loadMessageActionGatewayRuntime = createLazyRuntimeModule(
() => import("./message.gateway.runtime.js"),
);
export type RunMessageActionParams = {
cfg: OpenClawConfig;
+5 -7
View File
@@ -5,15 +5,13 @@ import { resolveStorePath } from "../../config/sessions.js";
import { loadSessionEntry } from "../../config/sessions/session-accessor.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { TtsAutoMode } from "../../config/types.tts.js";
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
import { shouldAttemptTtsPayload } from "../../tts/tts-config.js";
let ttsRuntimePromise: Promise<typeof import("../../tts/tts.runtime.js")> | null = null;
function loadMessageActionTtsRuntime() {
// Keep the TTS runtime lazy so ordinary message sends do not pay the provider import cost.
ttsRuntimePromise ??= import("../../tts/tts.runtime.js");
return ttsRuntimePromise;
}
// Keep the TTS runtime lazy so ordinary message sends do not pay the provider import cost.
const loadMessageActionTtsRuntime = createLazyRuntimeModule(
() => import("../../tts/tts.runtime.js"),
);
/** Reads the session-level TTS auto mode for a message-action send. */
export function resolveMessageActionSessionTtsAuto(params: {
+9 -14
View File
@@ -7,6 +7,7 @@ import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { OutboundMediaAccess } from "../../media/load-options.js";
import type { PollInput } from "../../polls.js";
import { normalizePollInput } from "../../polls.js";
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
import { resolveOutboundChannelPlugin } from "./channel-resolution.js";
import { resolveMessageChannelSelection } from "./channel-selection.js";
import {
@@ -29,23 +30,17 @@ import {
import { buildOutboundSessionContext } from "./session-context.js";
import { resolveOutboundTarget } from "./targets.js";
let messageConfigRuntimePromise: Promise<typeof import("./message.config.runtime.js")> | null =
null;
let messageGatewayRuntimePromise: Promise<typeof import("./message.gateway.runtime.js")> | null =
null;
const SEND_BUFFER_MEDIA_URL = "buffer://message-send/attachment";
function loadMessageConfigRuntime() {
// Keep config/runtime loading lazy so importing message helpers does not
// bootstrap plugin registries or gateway clients.
messageConfigRuntimePromise ??= import("./message.config.runtime.js");
return messageConfigRuntimePromise;
}
const loadMessageConfigRuntime = createLazyRuntimeModule(
() => import("./message.config.runtime.js"),
);
function loadMessageGatewayRuntime() {
messageGatewayRuntimePromise ??= import("./message.gateway.runtime.js");
return messageGatewayRuntimePromise;
}
// Keep config/runtime loading lazy so importing message helpers does not
// bootstrap plugin registries or gateway clients.
const loadMessageGatewayRuntime = createLazyRuntimeModule(
() => import("./message.gateway.runtime.js"),
);
export type MessageGatewayOptions = OutboundMessageGatewayOptionsInput;
+4 -8
View File
@@ -2,6 +2,7 @@
import { createHash, randomUUID } from "node:crypto";
import path from "node:path";
import { resolveStateDir } from "../config/paths.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { createAsyncLock, tryReadJson, writeJson } from "./json-files.js";
// --- Types ---
@@ -44,14 +45,9 @@ const withLock = createAsyncLock();
type WebPushRuntime = typeof import("web-push");
type WebPushRuntimeModule = WebPushRuntime & { default?: WebPushRuntime };
let webPushRuntimePromise: Promise<WebPushRuntime> | undefined;
async function loadWebPushRuntime(): Promise<WebPushRuntime> {
webPushRuntimePromise ??= import("web-push").then(
(mod: WebPushRuntimeModule) => mod.default ?? mod,
);
return await webPushRuntimePromise;
}
const loadWebPushRuntime = createLazyRuntimeModule(() =>
import("web-push").then((mod: WebPushRuntimeModule) => mod.default ?? mod),
);
// --- Helpers ---
+7 -6
View File
@@ -3,6 +3,7 @@ import type { SessionMaintenanceWarning } from "../config/sessions/store-mainten
import type { SessionEntry } from "../config/sessions/types.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { createLazyPromiseLoader } from "../shared/lazy-runtime.js";
import { deliveryContextFromSession } from "../utils/delivery-context.shared.js";
import { isDeliverableMessageChannel, normalizeMessageChannel } from "../utils/message-channel.js";
import { buildOutboundSessionContext } from "./outbound/session-context.js";
@@ -19,21 +20,21 @@ type WarningParams = {
const warnedContexts = new Map<string, string>();
const log = createSubsystemLogger("session-maintenance-warning");
let messageRuntimePromise: Promise<typeof import("../channels/message/runtime.js")> | null = null;
const messageRuntimeLoader = createLazyPromiseLoader(
() => import("../channels/message/runtime.js"),
{ cacheRejections: true },
);
function resetSessionMaintenanceWarningForTests() {
warnedContexts.clear();
messageRuntimePromise = null;
messageRuntimeLoader.clear();
}
export const testing = {
resetSessionMaintenanceWarningForTests,
} as const;
function loadDeliverRuntime() {
messageRuntimePromise ??= import("../channels/message/runtime.js");
return messageRuntimePromise;
}
const loadDeliverRuntime = messageRuntimeLoader.load;
function shouldSendWarning(): boolean {
return process.env.NODE_ENV !== "test";
+9 -12
View File
@@ -10,6 +10,7 @@ import {
type DiagnosticPhaseSnapshot,
type DiagnosticLivenessWarningReason,
} from "../infra/diagnostic-events.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { emitDiagnosticMemorySample, resetDiagnosticMemoryForTest } from "./diagnostic-memory.js";
import {
getCurrentDiagnosticPhase,
@@ -65,6 +66,7 @@ import {
startDiagnosticStabilityRecorder,
stopDiagnosticStabilityRecorder,
} from "./diagnostic-stability.js";
export { diagnosticLogger, logLaneDequeue, logLaneEnqueue } from "./diagnostic-runtime.js";
const webhookStats = {
@@ -84,12 +86,9 @@ const DEFAULT_LIVENESS_EVENT_LOOP_DELAY_WARN_MS = 1_000;
const DEFAULT_LIVENESS_EVENT_LOOP_UTILIZATION_WARN = 0.95;
const DEFAULT_LIVENESS_CPU_CORE_RATIO_WARN = 0.9;
const DEFAULT_LIVENESS_WARN_COOLDOWN_MS = 120_000;
let commandPollBackoffRuntimePromise: Promise<
typeof import("../agents/command-poll-backoff.runtime.js")
> | null = null;
let stuckSessionRecoveryRuntimePromise: Promise<
typeof import("./diagnostic-stuck-session-recovery.runtime.js")
> | null = null;
const loadStuckSessionRecoveryRuntime = createLazyRuntimeModule(
() => import("./diagnostic-stuck-session-recovery.runtime.js"),
);
type EmitDiagnosticMemorySample = typeof emitDiagnosticMemorySample;
type EventLoopDelayMonitor = ReturnType<typeof monitorEventLoopDelay>;
@@ -153,16 +152,14 @@ let lastDiagnosticLivenessEventLoopUtilization: EventLoopUtilization | null = nu
let lastDiagnosticLivenessEventAt = 0;
let lastDiagnosticLivenessWarnAt = 0;
function loadCommandPollBackoffRuntime() {
commandPollBackoffRuntimePromise ??= import("../agents/command-poll-backoff.runtime.js");
return commandPollBackoffRuntimePromise;
}
const loadCommandPollBackoffRuntime = createLazyRuntimeModule(
() => import("../agents/command-poll-backoff.runtime.js"),
);
async function recoverStuckSession(
params: StuckSessionRecoveryRequest,
): Promise<StuckSessionRecoveryOutcome> {
stuckSessionRecoveryRuntimePromise ??= import("./diagnostic-stuck-session-recovery.runtime.js");
return stuckSessionRecoveryRuntimePromise
return loadStuckSessionRecoveryRuntime()
.then(({ recoverStuckDiagnosticSession }) => recoverStuckDiagnosticSession(params))
.catch((err: unknown) => {
diag.warn(`stuck session recovery unavailable: ${String(err)}`);
+4 -8
View File
@@ -4,16 +4,12 @@ import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/st
import type { MsgContext } from "../auto-reply/templating.js";
import type { OpenClawConfig } from "../config/types.js";
import { logVerbose, shouldLogVerbose } from "../globals.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { isDeliverableMessageChannel } from "../utils/message-channel.js";
let messageRuntimePromise: Promise<typeof import("../channels/message/runtime.js")> | null = null;
function loadMessageRuntime() {
// The message runtime is heavy and only needed when echo delivery actually
// proceeds to a deliverable channel.
messageRuntimePromise ??= import("../channels/message/runtime.js");
return messageRuntimePromise;
}
// The message runtime is heavy and only needed when echo delivery actually
// proceeds to a deliverable channel.
const loadMessageRuntime = createLazyRuntimeModule(() => import("../channels/message/runtime.js"));
/** Default operator-visible transcript echo format for preflight audio transcription. */
export const DEFAULT_ECHO_TRANSCRIPT_FORMAT = '📝 "{transcript}"';
+2 -14
View File
@@ -43,6 +43,7 @@ import {
import { resolveOfficialExternalPluginRepairHint } from "../plugins/official-external-plugin-repair-hints.js";
import { runExec } from "../process/exec.js";
import { providerOperationRetryConfig } from "../provider-runtime/operation-retry.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { MediaAttachmentCache } from "./attachments.js";
import {
CLI_OUTPUT_MAX_BUFFER,
@@ -65,20 +66,7 @@ import type {
} from "./types.js";
type ProviderRegistry = Map<string, MediaUnderstandingProvider>;
type ResolveApiKeyForProvider = typeof import("../agents/model-auth.js").resolveApiKeyForProvider;
type RequireApiKey = typeof import("../agents/model-auth.js").requireApiKey;
type IsProviderAuthError = typeof import("../agents/model-auth.js").isProviderAuthError;
let cachedModelAuth: {
resolveApiKeyForProvider: ResolveApiKeyForProvider;
requireApiKey: RequireApiKey;
isProviderAuthError: IsProviderAuthError;
} | null = null;
async function loadModelAuth() {
cachedModelAuth ??= await import("../agents/model-auth.js");
return cachedModelAuth;
}
const loadModelAuth = createLazyRuntimeModule(async () => await import("../agents/model-auth.js"));
function resolveLiteralProviderApiKey(params: {
cfg: OpenClawConfig;
+14 -14
View File
@@ -15,6 +15,9 @@ import {
normalizeStringEntries,
uniqueStrings,
} from "@openclaw/normalization-core/string-normalization";
import type { ActiveMediaModel } from "../../packages/media-understanding-common/src/active-model.js";
import { isMediaUnderstandingSkipError } from "../../packages/media-understanding-common/src/errors.js";
import { providerSupportsCapability } from "../../packages/media-understanding-common/src/provider-supports.js";
import { isMinimaxVlmModel, isMinimaxVlmProvider } from "../agents/minimax-vlm.js";
import {
buildModelAliasIndex,
@@ -38,9 +41,7 @@ import { logWarn } from "../logger.js";
import { resolveChannelInboundAttachmentRoots } from "../media/channel-inbound-roots.js";
import { getDefaultMediaLocalRoots } from "../media/local-roots.js";
import { runExec } from "../process/exec.js";
import type { ActiveMediaModel } from "../../packages/media-understanding-common/src/active-model.js";
import { isMediaUnderstandingSkipError } from "../../packages/media-understanding-common/src/errors.js";
import { providerSupportsCapability } from "../../packages/media-understanding-common/src/provider-supports.js";
import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "../shared/lazy-runtime.js";
import { MediaAttachmentCache, selectAttachments } from "./attachments.js";
import { fileExists } from "./fs.js";
import { resolveOpenAiAudioAuthModelApi } from "./openai-audio-api.js";
@@ -64,12 +65,11 @@ import type {
MediaUnderstandingOutput,
MediaUnderstandingProvider,
} from "./types.js";
export { createMediaAttachmentCache, normalizeMediaAttachments } from "./runner.attachments.js";
export type { ActiveMediaModel } from "../../packages/media-understanding-common/src/active-model.js";
type ProviderRegistry = Map<string, MediaUnderstandingProvider>;
type HasAvailableAuthForProvider =
typeof import("../agents/model-auth.js").hasAvailableAuthForProvider;
type ModelCatalogApi = typeof import("../agents/model-catalog.js");
type ModelCatalog = Awaited<ReturnType<ModelCatalogApi["loadModelCatalog"]>>;
@@ -78,13 +78,14 @@ export type RunCapabilityResult = {
decision: MediaUnderstandingDecision;
};
let cachedHasAvailableAuthForProvider: HasAvailableAuthForProvider | null = null;
let cachedModelCatalogApi: ModelCatalogApi | null = null;
const loadHasAvailableAuthForProvider = createLazyRuntimeNamedExport(
() => import("../agents/model-auth.js"),
"hasAvailableAuthForProvider",
);
async function loadModelCatalogApi(): Promise<ModelCatalogApi> {
cachedModelCatalogApi ??= await import("../agents/model-catalog.js");
return cachedModelCatalogApi;
}
const loadModelCatalogApi = createLazyRuntimeModule(
async () => await import("../agents/model-catalog.js"),
);
function resolveLiteralProviderApiKey(
cfg: OpenClawConfig | undefined,
@@ -107,9 +108,8 @@ async function hasProviderAuthAvailable(params: {
if (resolveLiteralProviderApiKey(params.cfg, params.provider)) {
return true;
}
cachedHasAvailableAuthForProvider ??= (await import("../agents/model-auth.js"))
.hasAvailableAuthForProvider;
return await cachedHasAvailableAuthForProvider({
const hasAvailableAuthForProvider = await loadHasAvailableAuthForProvider();
return await hasAvailableAuthForProvider({
...params,
modelApi: resolveOpenAiAudioAuthModelApi({
capability: params.capability,
+5 -10
View File
@@ -10,6 +10,7 @@ import { withEnv, withEnvAsync } from "openclaw/plugin-sdk/test-env";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { AssistantMessage, Model } from "../../llm/types.js";
import { resolveWorkspacePackagePublicModuleUrl } from "../../plugin-sdk/test-helpers/public-surface-loader.js";
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
type TtsRuntimeModule = typeof import("openclaw/plugin-sdk/tts-runtime");
type TtsCoreModule = typeof import("openclaw/plugin-sdk/speech-core");
@@ -21,9 +22,7 @@ const speechCoreRuntimeApiModuleId = resolveWorkspacePackagePublicModuleUrl({
});
let ttsRuntime: TtsRuntimeModule;
let ttsRuntimePromise: Promise<TtsRuntimeModule> | null = null;
let ttsRuntimeInitialized = false;
let ttsCorePromise: Promise<TtsCoreModule> | null = null;
let completeSimple: typeof import("openclaw/plugin-sdk/llm").completeSimple;
let prepareSimpleCompletionModelMock: SummarizeTextDeps["prepareSimpleCompletionModel"];
let requireApiKeyMock: SummarizeTextDeps["requireApiKey"];
@@ -413,15 +412,11 @@ function buildTestGoogleSpeechProvider(): SpeechProviderPlugin {
};
}
async function loadTtsRuntime(): Promise<TtsRuntimeModule> {
ttsRuntimePromise ??= import(speechCoreRuntimeApiModuleId) as Promise<TtsRuntimeModule>;
return await ttsRuntimePromise;
}
const loadTtsRuntime = createLazyRuntimeModule(
() => import(speechCoreRuntimeApiModuleId) as Promise<TtsRuntimeModule>,
);
async function loadTtsCore(): Promise<TtsCoreModule> {
ttsCorePromise ??= import("openclaw/plugin-sdk/speech-core");
return await ttsCorePromise;
}
const loadTtsCore = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/speech-core"));
function createPrepareSimpleCompletionModelMock(): SummarizeTextDeps["prepareSimpleCompletionModel"] {
return vi.fn(async ({ provider, modelId }) => ({
+7 -16
View File
@@ -14,6 +14,7 @@ import { extractDeliveryInfo } from "../config/sessions/delivery-info.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { formatErrorMessage } from "../infra/errors.js";
import { resolveAgentIdFromSessionKey } from "../routing/session-key.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { isDeliverableMessageChannel, normalizeMessageChannel } from "../utils/message-channel.js";
import type {
PluginAttachmentChannelHints,
@@ -31,17 +32,10 @@ export const attachmentProbeFs = {
const MAX_ATTACHMENT_FILES = 10;
type SendMessage = typeof import("../infra/outbound/message.js").sendMessage;
let sendMessagePromise: Promise<SendMessage> | undefined;
async function loadSendMessage(): Promise<SendMessage> {
sendMessagePromise ??= import("../infra/outbound/message.js").then(
(module) => module.sendMessage,
);
return sendMessagePromise;
}
type GetChannelPlugin = typeof import("../channels/plugins/index.js").getChannelPlugin;
let getChannelPluginPromise: Promise<GetChannelPlugin> | undefined;
const loadSendMessage = createLazyRuntimeModule(() =>
import("../infra/outbound/message.js").then((module) => module.sendMessage),
);
type AttachmentDeliveryChannelPlugin = {
outbound?: {
@@ -49,12 +43,9 @@ type AttachmentDeliveryChannelPlugin = {
};
};
async function loadGetChannelPlugin(): Promise<GetChannelPlugin> {
getChannelPluginPromise ??= import("../channels/plugins/index.js").then(
(module) => module.getChannelPlugin,
);
return getChannelPluginPromise;
}
const loadGetChannelPlugin = createLazyRuntimeModule(() =>
import("../channels/plugins/index.js").then((module) => module.getChannelPlugin),
);
type ResolvedAttachmentDelivery = {
parseMode?: "HTML";
+4 -6
View File
@@ -1,3 +1,4 @@
import { createLazyRuntimeModule } from "../../../shared/lazy-runtime.js";
// PTY adapter wraps pseudo-terminal processes for the process supervisor.
import { signalProcessTree } from "../../kill-tree.js";
import { prepareOomScoreAdjustedSpawn } from "../../linux-oom-score.js";
@@ -36,12 +37,9 @@ type PtyModule = {
export type PtyAdapter = SpawnProcessAdapter;
let ptyModulePromise: Promise<PtyModule> | null = null;
async function loadPtyModule(): Promise<PtyModule> {
ptyModulePromise ??= import("@lydell/node-pty") as Promise<unknown> as Promise<PtyModule>;
return ptyModulePromise;
}
const loadPtyModule = createLazyRuntimeModule(
() => import("@lydell/node-pty") as Promise<unknown> as Promise<PtyModule>,
);
export async function createPtyAdapter(params: {
shell: string;
+4 -8
View File
@@ -3,6 +3,7 @@ import crypto from "node:crypto";
import { performance } from "node:perf_hooks";
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
import { getShellConfig } from "../../agents/shell-utils.js";
import { createLazyRuntimeModule } from "../../shared/lazy-runtime.js";
import { createChildAdapter } from "./adapters/child.js";
import { createPtyAdapter } from "./adapters/pty.js";
import { createRunRegistry } from "./registry.js";
@@ -15,8 +16,6 @@ import type {
TerminationReason,
} from "./types.js";
type SupervisorLogRuntime = typeof import("./supervisor-log.runtime.js");
type ActiveRun = {
run: ManagedRun;
scopeKey?: string;
@@ -25,12 +24,9 @@ type ActiveRun = {
const GRACEFUL_CANCEL_TIMEOUT_MS = 5000;
const DEFAULT_MAX_CAPTURED_OUTPUT_CHARS = 1024 * 1024;
let supervisorLogRuntimePromise: Promise<SupervisorLogRuntime> | undefined;
function loadSupervisorLogRuntime(): Promise<SupervisorLogRuntime> {
supervisorLogRuntimePromise ??= import("./supervisor-log.runtime.js");
return supervisorLogRuntimePromise;
}
const loadSupervisorLogRuntime = createLazyRuntimeModule(
() => import("./supervisor-log.runtime.js"),
);
function clampTimeout(value?: number): number | undefined {
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
+7 -11
View File
@@ -12,6 +12,7 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { PluginManifestRegistry } from "../plugins/manifest-registry.js";
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
import type { PluginOrigin } from "../plugins/plugin-origin.types.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { resolveUserPath } from "../utils.js";
import {
canUseSecretsRuntimeFastPath,
@@ -41,18 +42,13 @@ export type { PreparedSecretsRuntimeSnapshot } from "./runtime-state.js";
registerSecretsRuntimeStateClearHook(clearRuntimeAuthProfileStoreSnapshots);
let runtimeManifestPromise: Promise<typeof import("./runtime-manifest.runtime.js")> | null = null;
let runtimePreparePromise: Promise<typeof import("./runtime-prepare.runtime.js")> | null = null;
const loadRuntimeManifestHelpers = createLazyRuntimeModule(
() => import("./runtime-manifest.runtime.js"),
);
function loadRuntimeManifestHelpers() {
runtimeManifestPromise ??= import("./runtime-manifest.runtime.js");
return runtimeManifestPromise;
}
function loadRuntimePrepareHelpers() {
runtimePreparePromise ??= import("./runtime-prepare.runtime.js");
return runtimePreparePromise;
}
const loadRuntimePrepareHelpers = createLazyRuntimeModule(
() => import("./runtime-prepare.runtime.js"),
);
async function resolveLoadablePluginOrigins(params: {
config: OpenClawConfig;
+2 -6
View File
@@ -1,14 +1,10 @@
// Audits code paths for deep safety risks that require manual review.
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import type { SecurityAuditFinding } from "./audit.types.js";
let auditDeepModulePromise: Promise<typeof import("./audit.deep.runtime.js")> | undefined;
/** Lazily load deep audit code paths so normal audits avoid plugin/skill scans. */
async function loadAuditDeepModule() {
auditDeepModulePromise ??= import("./audit.deep.runtime.js");
return await auditDeepModulePromise;
}
const loadAuditDeepModule = createLazyRuntimeModule(() => import("./audit.deep.runtime.js"));
/** Collect plugin and installed-skill code safety findings when deep audit is enabled. */
export async function collectDeepCodeSafetyFindings(params: {
+24 -54
View File
@@ -22,6 +22,7 @@ import type { OpenClawConfig, ConfigFileSnapshot } from "../config/config.js";
import { collectIncludePathsRecursive } from "../config/includes-scan.js";
import { resolveOAuthDir } from "../config/paths.js";
import { normalizeAgentId } from "../routing/session-key.js";
import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "../shared/lazy-runtime.js";
import type { SkillScanFinding } from "../skills/security/scanner.js";
import { shouldIgnoreInstalledPluginDirName } from "./installed-plugin-dirs.js";
import { extensionUsesSkippedScannerPath, isPathInside } from "./scan-paths.js";
@@ -49,73 +50,42 @@ type ExecDockerRawFn = (
const DEFAULT_SANDBOX_BROWSER_DOCKER_PROBE_TIMEOUT_MS = 5000;
type CodeSafetySummaryCache = Map<string, Promise<unknown>>;
let skillsModulePromise: Promise<typeof import("../skills/loading/workspace.js")> | undefined;
let configModulePromise: Promise<typeof import("../config/config.js")> | undefined;
let agentScopeModulePromise: Promise<typeof import("../agents/agent-scope.js")> | undefined;
let agentWorkspaceDirsModulePromise:
| Promise<typeof import("../agents/workspace-dirs.js")>
| undefined;
let skillSourceModulePromise: Promise<typeof import("../skills/loading/source.js")> | undefined;
let sandboxDockerModulePromise: Promise<typeof import("../agents/sandbox/docker.js")> | undefined;
let sandboxConstantsModulePromise:
| Promise<typeof import("../agents/sandbox/constants.js")>
| undefined;
let auditPluginsTrustModulePromise: Promise<typeof import("./audit-plugins-trust.js")> | undefined;
let auditFsModulePromise: Promise<typeof import("./audit-fs.js")> | undefined;
let skillScannerModulePromise: Promise<typeof import("../skills/security/scanner.js")> | undefined;
const loadSkillsModule = createLazyRuntimeModule(() => import("../skills/loading/workspace.js"));
function loadSkillsModule() {
skillsModulePromise ??= import("../skills/loading/workspace.js");
return skillsModulePromise;
}
const loadConfigModule = createLazyRuntimeModule(() => import("../config/config.js"));
function loadConfigModule() {
configModulePromise ??= import("../config/config.js");
return configModulePromise;
}
const loadAuditFsModule = createLazyRuntimeModule(() => import("./audit-fs.js"));
function loadAuditFsModule() {
auditFsModulePromise ??= import("./audit-fs.js");
return auditFsModulePromise;
}
const loadAgentScopeModule = createLazyRuntimeModule(() => import("../agents/agent-scope.js"));
function loadAgentScopeModule() {
agentScopeModulePromise ??= import("../agents/agent-scope.js");
return agentScopeModulePromise;
}
const loadAgentWorkspaceDirsModule = createLazyRuntimeModule(
() => import("../agents/workspace-dirs.js"),
);
function loadAgentWorkspaceDirsModule() {
agentWorkspaceDirsModulePromise ??= import("../agents/workspace-dirs.js");
return agentWorkspaceDirsModulePromise;
}
const loadSkillSourceModule = createLazyRuntimeModule(() => import("../skills/loading/source.js"));
function loadSkillSourceModule() {
skillSourceModulePromise ??= import("../skills/loading/source.js");
return skillSourceModulePromise;
}
const loadSkillScannerModule = createLazyRuntimeModule(
() => import("../skills/security/scanner.js"),
);
function loadSkillScannerModule() {
skillScannerModulePromise ??= import("../skills/security/scanner.js");
return skillScannerModulePromise;
}
const loadExecDockerRaw = createLazyRuntimeNamedExport(
() => import("../agents/sandbox/docker.js"),
"execDockerRaw",
) satisfies () => Promise<ExecDockerRawFn>;
async function loadExecDockerRaw(): Promise<ExecDockerRawFn> {
sandboxDockerModulePromise ??= import("../agents/sandbox/docker.js");
const { execDockerRaw } = await sandboxDockerModulePromise;
return execDockerRaw;
}
const loadSandboxBrowserSecurityHashEpoch = createLazyRuntimeNamedExport(
() => import("../agents/sandbox/constants.js"),
"SANDBOX_BROWSER_SECURITY_HASH_EPOCH",
);
async function loadSandboxBrowserSecurityHashEpoch(): Promise<string> {
sandboxConstantsModulePromise ??= import("../agents/sandbox/constants.js");
const { SANDBOX_BROWSER_SECURITY_HASH_EPOCH } = await sandboxConstantsModulePromise;
return SANDBOX_BROWSER_SECURITY_HASH_EPOCH;
}
const loadAuditPluginsTrustModule = createLazyRuntimeModule(
() => import("./audit-plugins-trust.js"),
);
export async function collectPluginsTrustFindings(
params: CollectPluginsTrustFindingsParams,
): Promise<SecurityAuditFinding[]> {
auditPluginsTrustModulePromise ??= import("./audit-plugins-trust.js");
const { collectPluginsTrustFindings: collect } = await auditPluginsTrustModulePromise;
const { collectPluginsTrustFindings: collect } = await loadAuditPluginsTrustModule();
return await collect(params);
}
+18 -18
View File
@@ -15,6 +15,7 @@ import {
createPluginRegistryIdNormalizer,
loadPluginRegistrySnapshot,
} from "../plugins/plugin-registry.js";
import { createLazyPromise } from "../shared/lazy-runtime.js";
import type { SecurityAuditFinding } from "./audit.types.js";
import { shouldIgnoreInstalledPluginDirName } from "./installed-plugin-dirs.js";
@@ -28,25 +29,24 @@ type PluginTrustPolicyDeps = {
resolveToolProfilePolicy: typeof import("../agents/tool-policy.js").resolveToolProfilePolicy;
};
let pluginTrustPolicyDepsPromise: Promise<PluginTrustPolicyDeps> | undefined;
/** Lazily load tool-policy helpers so basic security imports avoid agent policy modules. */
async function loadPluginTrustPolicyDeps(): Promise<PluginTrustPolicyDeps> {
pluginTrustPolicyDepsPromise ??= Promise.all([
import("../agents/sandbox/config.js"),
import("../agents/sandbox/tool-policy.js"),
import("../agents/tool-policy-match.js"),
import("../agents/tool-policy.js"),
import("../agents/sandbox-tool-policy.js"),
]).then(([sandboxConfig, sandboxToolPolicy, toolPolicyMatch, toolPolicy, auditToolPolicy]) => ({
isToolAllowedByPolicies: toolPolicyMatch.isToolAllowedByPolicies,
pickSandboxToolPolicy: auditToolPolicy.pickSandboxToolPolicy,
resolveSandboxConfigForAgent: sandboxConfig.resolveSandboxConfigForAgent,
resolveSandboxToolPolicyForAgent: sandboxToolPolicy.resolveSandboxToolPolicyForAgent,
resolveToolProfilePolicy: toolPolicy.resolveToolProfilePolicy,
}));
return await pluginTrustPolicyDepsPromise;
}
const loadPluginTrustPolicyDeps = createLazyPromise(
() =>
Promise.all([
import("../agents/sandbox/config.js"),
import("../agents/sandbox/tool-policy.js"),
import("../agents/tool-policy-match.js"),
import("../agents/tool-policy.js"),
import("../agents/sandbox-tool-policy.js"),
]).then(([sandboxConfig, sandboxToolPolicy, toolPolicyMatch, toolPolicy, auditToolPolicy]) => ({
isToolAllowedByPolicies: toolPolicyMatch.isToolAllowedByPolicies,
pickSandboxToolPolicy: auditToolPolicy.pickSandboxToolPolicy,
resolveSandboxConfigForAgent: sandboxConfig.resolveSandboxConfigForAgent,
resolveSandboxToolPolicyForAgent: sandboxToolPolicy.resolveSandboxToolPolicyForAgent,
resolveToolProfilePolicy: toolPolicy.resolveToolProfilePolicy,
})),
{ cacheRejections: true },
);
function readChannelCommandSetting(
cfg: OpenClawConfig,
+22 -60
View File
@@ -40,6 +40,7 @@ import {
} from "../infra/exec-safe-bin-runtime-policy.js";
import { listRiskyConfiguredSafeBins } from "../infra/exec-safe-bin-semantics.js";
import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { collectDeepCodeSafetyFindings } from "./audit-deep-code-safety.js";
import { collectDeepProbeFindings } from "./audit-deep-probe-findings.js";
import {
@@ -147,70 +148,32 @@ export type AuditExecutionContext = {
workspaceDir?: string;
};
let readOnlyChannelPluginsModulePromise:
| Promise<typeof import("../channels/plugins/read-only.js")>
| undefined;
let auditNonDeepModulePromise: Promise<typeof import("./audit.nondeep.runtime.js")> | undefined;
let auditChannelModulePromise:
| Promise<typeof import("./audit-channel.collect.runtime.js")>
| undefined;
let pluginMetadataRegistryLoaderModulePromise:
| Promise<typeof import("../plugins/runtime/metadata-registry-loader.js")>
| undefined;
let pluginAutoEnableModulePromise:
| Promise<typeof import("../config/plugin-auto-enable.js")>
| undefined;
let channelPluginIdsModulePromise:
| Promise<typeof import("../plugins/channel-plugin-ids.js")>
| undefined;
let pluginRuntimeModulePromise: Promise<typeof import("../plugins/runtime.js")> | undefined;
let gatewayProbeDepsPromise:
| Promise<{
buildGatewayConnectionDetails: typeof import("../gateway/call.js").buildGatewayConnectionDetails;
resolveGatewayProbeAuthSafe: typeof import("../gateway/probe-auth.js").resolveGatewayProbeAuthSafe;
resolveGatewayProbeTarget: typeof import("../gateway/probe-auth.js").resolveGatewayProbeTarget;
probeGateway: typeof import("../gateway/probe.js").probeGateway;
}>
| undefined;
const loadReadOnlyChannelPlugins = createLazyRuntimeModule(
() => import("../channels/plugins/read-only.js"),
);
async function loadReadOnlyChannelPlugins() {
readOnlyChannelPluginsModulePromise ??= import("../channels/plugins/read-only.js");
return await readOnlyChannelPluginsModulePromise;
}
const loadAuditNonDeepModule = createLazyRuntimeModule(() => import("./audit.nondeep.runtime.js"));
async function loadAuditNonDeepModule() {
auditNonDeepModulePromise ??= import("./audit.nondeep.runtime.js");
return await auditNonDeepModulePromise;
}
const loadAuditChannelModule = createLazyRuntimeModule(
() => import("./audit-channel.collect.runtime.js"),
);
async function loadAuditChannelModule() {
auditChannelModulePromise ??= import("./audit-channel.collect.runtime.js");
return await auditChannelModulePromise;
}
const loadPluginMetadataRegistryLoaderModule = createLazyRuntimeModule(
() => import("../plugins/runtime/metadata-registry-loader.js"),
);
async function loadPluginMetadataRegistryLoaderModule() {
pluginMetadataRegistryLoaderModulePromise ??=
import("../plugins/runtime/metadata-registry-loader.js");
return await pluginMetadataRegistryLoaderModulePromise;
}
const loadPluginAutoEnableModule = createLazyRuntimeModule(
() => import("../config/plugin-auto-enable.js"),
);
async function loadPluginAutoEnableModule() {
pluginAutoEnableModulePromise ??= import("../config/plugin-auto-enable.js");
return await pluginAutoEnableModulePromise;
}
const loadChannelPluginIdsModule = createLazyRuntimeModule(
() => import("../plugins/channel-plugin-ids.js"),
);
async function loadChannelPluginIdsModule() {
channelPluginIdsModulePromise ??= import("../plugins/channel-plugin-ids.js");
return await channelPluginIdsModulePromise;
}
const loadPluginRuntimeModule = createLazyRuntimeModule(() => import("../plugins/runtime.js"));
async function loadPluginRuntimeModule() {
pluginRuntimeModulePromise ??= import("../plugins/runtime.js");
return await pluginRuntimeModulePromise;
}
async function loadGatewayProbeDeps() {
gatewayProbeDepsPromise ??= Promise.all([
const loadGatewayProbeDeps = createLazyRuntimeModule(() =>
Promise.all([
import("../gateway/call.js"),
import("../gateway/probe-auth.js"),
import("../gateway/probe.js"),
@@ -219,9 +182,8 @@ async function loadGatewayProbeDeps() {
resolveGatewayProbeAuthSafe: probeAuthModule.resolveGatewayProbeAuthSafe,
resolveGatewayProbeTarget: probeAuthModule.resolveGatewayProbeTarget,
probeGateway: probeModule.probeGateway,
}));
return await gatewayProbeDepsPromise;
}
})),
);
function countBySeverity(findings: SecurityAuditFinding[]): SecurityAuditSummary {
let critical = 0;
+16 -44
View File
@@ -40,6 +40,7 @@ import {
} from "../infra/provider-usage.js";
import { normalizeAccountId } from "../routing/account-id.js";
import { resolveNormalizedAccountEntry } from "../routing/account-lookup.js";
import { createLazyPromise, createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import {
listTasksForAgentIdForStatus,
listTasksForSessionKeyForStatus,
@@ -98,52 +99,23 @@ function resolveStatusChannelFeatureLine(params: {
: "Telegram rich messages: off · set channels.telegram.richMessages=true for tables/details/rich media";
}
let statusMessageRuntimePromise: Promise<typeof import("../auto-reply/status.runtime.js")> | null =
null;
let agentHarnessSelectionRuntimePromise: Promise<
typeof import("../agents/harness/selection.js")
> | null = null;
let statusQueueRuntimePromise: Promise<typeof import("./status-queue.runtime.js")> | null = null;
let statusSubagentsRuntimePromise: Promise<typeof import("./status-subagents.runtime.js")> | null =
null;
let statusPluginHealthRuntimePromise: Promise<
typeof import("./status-plugin-health.runtime.js")
> | null = null;
const loadStatusMessageRuntime = createLazyPromise(
() =>
import("./status-message.runtime.js").then((module) => module.loadStatusMessageRuntimeModule()),
{ cacheRejections: true },
);
const loadAgentHarnessSelectionRuntime = createLazyRuntimeModule(
() => import("../agents/harness/selection.js"),
);
const loadStatusSubagentsRuntime = createLazyRuntimeModule(
() => import("./status-subagents.runtime.js"),
);
function loadStatusMessageRuntime(): Promise<typeof import("../auto-reply/status.runtime.js")> {
const runtimePromise = (statusMessageRuntimePromise ??=
import("./status-message.runtime.js").then((module) =>
module.loadStatusMessageRuntimeModule(),
));
return runtimePromise;
}
const loadStatusQueueRuntime = createLazyRuntimeModule(() => import("./status-queue.runtime.js"));
function loadAgentHarnessSelectionRuntime(): Promise<
typeof import("../agents/harness/selection.js")
> {
const runtimePromise = (agentHarnessSelectionRuntimePromise ??=
import("../agents/harness/selection.js"));
return runtimePromise;
}
function loadStatusSubagentsRuntime(): Promise<typeof import("./status-subagents.runtime.js")> {
const runtimePromise = (statusSubagentsRuntimePromise ??=
import("./status-subagents.runtime.js"));
return runtimePromise;
}
function loadStatusQueueRuntime(): Promise<typeof import("./status-queue.runtime.js")> {
const runtimePromise = (statusQueueRuntimePromise ??= import("./status-queue.runtime.js"));
return runtimePromise;
}
function loadStatusPluginHealthRuntime(): Promise<
typeof import("./status-plugin-health.runtime.js")
> {
const runtimePromise = (statusPluginHealthRuntimePromise ??=
import("./status-plugin-health.runtime.js"));
return runtimePromise;
}
const loadStatusPluginHealthRuntime = createLazyRuntimeModule(
() => import("./status-plugin-health.runtime.js"),
);
// Context lookup stays synchronous/non-refreshing so status output does not
// trigger provider/catalog IO while rendering a command response.
+4 -7
View File
@@ -37,6 +37,7 @@ import { ensureControlUiAssetsBuilt } from "../infra/control-ui-assets.js";
import { formatErrorMessage } from "../infra/errors.js";
import { formatWindowsGatewayFirewallGuidance } from "../infra/windows-gateway-firewall-diagnostics.js";
import type { RuntimeEnv } from "../runtime.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { launchTuiCli } from "../tui/tui-launch.js";
import { resolveUserPath } from "../utils.js";
import { listConfiguredWebSearchProviders } from "../web-search/runtime.js";
@@ -58,9 +59,6 @@ type FinalizeOnboardingOptions = {
runtime: RuntimeEnv;
};
type OnboardSearchModule = typeof import("../commands/onboard-search.js");
let onboardSearchModulePromise: Promise<OnboardSearchModule> | undefined;
const HATCH_TUI_TIMEOUT_MS = 5 * 60 * 1000;
function buildSessionGatewayAuthOverride(params: {
@@ -186,10 +184,9 @@ function getLocalizedGatewayDaemonRuntimeOptions() {
}));
}
function loadOnboardSearchModule(): Promise<OnboardSearchModule> {
onboardSearchModulePromise ??= import("../commands/onboard-search.js");
return onboardSearchModulePromise;
}
const loadOnboardSearchModule = createLazyRuntimeModule(
() => import("../commands/onboard-search.js"),
);
export async function finalizeSetupWizard(
options: FinalizeOnboardingOptions,
+8 -19
View File
@@ -25,6 +25,7 @@ import type {
MigrationProviderPlugin,
} from "../plugins/types.js";
import type { RuntimeEnv } from "../runtime.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { resolveUserPath } from "../utils.js";
import { t } from "./i18n/index.js";
import { WizardCancelledError, type WizardPrompter } from "./prompts.js";
@@ -68,27 +69,15 @@ const MEANINGFUL_WORKSPACE_ENTRIES = [
] as const;
const MEANINGFUL_STATE_ENTRIES = ["credentials", "sessions", "agents"] as const;
let migrationProviderRuntimeModulePromise: Promise<
typeof import("../plugins/migration-provider-runtime.js")
> | null = null;
let migrationContextModulePromise: Promise<typeof import("../commands/migrate/context.js")> | null =
null;
let configPathsModulePromise: Promise<typeof import("../config/paths.js")> | null = null;
const loadMigrationProviderRuntimeModule = createLazyRuntimeModule(
() => import("../plugins/migration-provider-runtime.js"),
);
const loadMigrationProviderRuntimeModule = async () => {
migrationProviderRuntimeModulePromise ??= import("../plugins/migration-provider-runtime.js");
return await migrationProviderRuntimeModulePromise;
};
const loadMigrationContextModule = createLazyRuntimeModule(
() => import("../commands/migrate/context.js"),
);
const loadMigrationContextModule = async () => {
migrationContextModulePromise ??= import("../commands/migrate/context.js");
return await migrationContextModulePromise;
};
const loadConfigPathsModule = async () => {
configPathsModulePromise ??= import("../config/paths.js");
return await configPathsModulePromise;
};
const loadConfigPathsModule = createLazyRuntimeModule(() => import("../config/paths.js"));
async function exists(candidate: string): Promise<boolean> {
try {
+4 -8
View File
@@ -5,6 +5,7 @@ import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
import type { PluginConfigUiHint } from "../plugins/types.js";
import { getPath, setPathCreateStrict } from "../secrets/path-utils.js";
import type { JsonSchemaObject } from "../shared/json-schema.types.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { t } from "./i18n/index.js";
import type { WizardPrompter } from "./prompts.js";
@@ -20,14 +21,9 @@ export type ConfigurablePlugin = {
jsonSchema?: JsonSchemaObject;
};
type PluginMetadataSnapshotModule = typeof import("../plugins/plugin-metadata-snapshot.js");
let pluginMetadataSnapshotModulePromise: Promise<PluginMetadataSnapshotModule> | undefined;
function loadPluginMetadataSnapshotModule(): Promise<PluginMetadataSnapshotModule> {
pluginMetadataSnapshotModulePromise ??= import("../plugins/plugin-metadata-snapshot.js");
return pluginMetadataSnapshotModulePromise;
}
const loadPluginMetadataSnapshotModule = createLazyRuntimeModule(
() => import("../plugins/plugin-metadata-snapshot.js"),
);
type JsonSchemaProperty = {
type?: string;
+5 -12
View File
@@ -8,6 +8,7 @@ import {
} from "../plugin-sdk/migration.js";
import type { MigrationProviderPlugin } from "../plugins/types.js";
import type { RuntimeEnv } from "../runtime.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import type { WizardPrompter } from "./prompts.js";
export type PostInstallMigrationOptions = {
@@ -34,19 +35,11 @@ type ResolvedProviderCandidate = {
source?: string;
};
let migrationContextModulePromise: Promise<typeof import("../commands/migrate/context.js")> | null =
null;
let configPathsModulePromise: Promise<typeof import("../config/paths.js")> | null = null;
const loadMigrationContextModule = createLazyRuntimeModule(
() => import("../commands/migrate/context.js"),
);
const loadMigrationContextModule = async () => {
migrationContextModulePromise ??= import("../commands/migrate/context.js");
return await migrationContextModulePromise;
};
const loadConfigPathsModule = async () => {
configPathsModulePromise ??= import("../config/paths.js");
return await configPathsModulePromise;
};
const loadConfigPathsModule = createLazyRuntimeModule(() => import("../config/paths.js"));
async function resolveCandidates(params: {
config: OpenClawConfig;
+7 -25
View File
@@ -24,6 +24,7 @@ import {
} from "../plugins/status.js";
import type { RuntimeEnv } from "../runtime.js";
import { defaultRuntime } from "../runtime.js";
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
import { resolveUserPath } from "../utils.js";
import { t } from "./i18n/index.js";
import { runWizardWithPromptNavigation } from "./navigation-prompter.js";
@@ -43,37 +44,18 @@ import type { QuickstartGatewayDefaults, WizardFlow } from "./setup.types.js";
type SetupFlowChoice = WizardFlow | "import" | "keep-model" | `import:${string}`;
type AuthChoiceModule = typeof import("../commands/auth-choice.js");
type ConfigLoggingModule = typeof import("../config/logging.js");
type ModelPickerModule = typeof import("../commands/model-picker.js");
type OnboardConfigModule = typeof import("../commands/onboard-config.js");
type KeepCurrentAuthChoice =
typeof import("../commands/auth-choice-prompt.js").KEEP_CURRENT_AUTH_CHOICE;
let authChoiceModulePromise: Promise<AuthChoiceModule> | undefined;
let configLoggingModulePromise: Promise<ConfigLoggingModule> | undefined;
let modelPickerModulePromise: Promise<ModelPickerModule> | undefined;
let onboardConfigModulePromise: Promise<OnboardConfigModule> | undefined;
const loadAuthChoiceModule = createLazyRuntimeModule(() => import("../commands/auth-choice.js"));
function loadAuthChoiceModule(): Promise<AuthChoiceModule> {
authChoiceModulePromise ??= import("../commands/auth-choice.js");
return authChoiceModulePromise;
}
const loadConfigLoggingModule = createLazyRuntimeModule(() => import("../config/logging.js"));
function loadConfigLoggingModule(): Promise<ConfigLoggingModule> {
configLoggingModulePromise ??= import("../config/logging.js");
return configLoggingModulePromise;
}
const loadModelPickerModule = createLazyRuntimeModule(() => import("../commands/model-picker.js"));
function loadModelPickerModule(): Promise<ModelPickerModule> {
modelPickerModulePromise ??= import("../commands/model-picker.js");
return modelPickerModulePromise;
}
function loadOnboardConfigModule(): Promise<OnboardConfigModule> {
onboardConfigModulePromise ??= import("../commands/onboard-config.js");
return onboardConfigModulePromise;
}
const loadOnboardConfigModule = createLazyRuntimeModule(
() => import("../commands/onboard-config.js"),
);
async function writeWizardConfigFile(
configInput: OpenClawConfig,