



























@@ -4,7 +4,7 @@ import process from "node:process";
44import { fileURLToPath } from "node:url";
55import { resolveStateDir } from "../config/paths.js";
66import type { OpenClawConfig } from "../config/types.openclaw.js";
7-import { normalizeEnv } from "../infra/env.js";
7+import { isTruthyEnvValue, normalizeEnv } from "../infra/env.js";
88import { isMainModule } from "../infra/is-main.js";
99import { ensureOpenClawCliOnPath } from "../infra/path-env.js";
1010import { assertSupportedRuntime } from "../infra/runtime-guard.js";
@@ -37,6 +37,41 @@ export {
3737shouldUseRootHelpFastPath,
3838} from "./run-main-policy.js";
393940+type Awaitable<T> = T | Promise<T>;
41+42+function createGatewayCliMainStartupTrace(argv: string[]) {
43+const enabled =
44+isTruthyEnvValue(process.env.OPENCLAW_GATEWAY_STARTUP_TRACE) &&
45+argv.slice(2).includes("gateway");
46+const started = performance.now();
47+let last = started;
48+const emit = (name: string, durationMs: number, totalMs: number) => {
49+if (!enabled) {
50+return;
51+}
52+process.stderr.write(
53+`[gateway] startup trace: cli.main.${name} ${durationMs.toFixed(1)}ms total=${totalMs.toFixed(1)}ms\n`,
54+);
55+};
56+return {
57+mark(name: string) {
58+const now = performance.now();
59+emit(name, now - last, now - started);
60+last = now;
61+},
62+async measure<T>(name: string, run: () => Awaitable<T>): Promise<T> {
63+const before = performance.now();
64+try {
65+return await run();
66+} finally {
67+const now = performance.now();
68+emit(name, now - before, now - started);
69+last = now;
70+}
71+},
72+};
73+}
74+4075async function closeCliMemoryManagers(): Promise<void> {
4176const { hasMemoryRuntime } = await import("../plugins/memory-state.js");
4277if (!hasMemoryRuntime()) {
@@ -98,6 +133,7 @@ async function ensureCliEnvProxyDispatcher(): Promise<void> {
9813399134export async function runCli(argv: string[] = process.argv) {
100135const originalArgv = normalizeWindowsArgv(argv);
136+const startupTrace = createGatewayCliMainStartupTrace(originalArgv);
101137const parsedContainer = parseCliContainerArgs(originalArgv);
102138if (!parsedContainer.ok) {
103139throw new Error(parsedContainer.error);
@@ -123,10 +159,13 @@ export async function runCli(argv: string[] = process.argv) {
123159return;
124160}
125161let normalizedArgv = parsedProfile.argv;
162+startupTrace.mark("argv");
126163127164if (shouldLoadCliDotEnv()) {
128-const { loadCliDotEnv } = await import("./dotenv.js");
129-loadCliDotEnv({ quiet: true });
165+await startupTrace.measure("dotenv", async () => {
166+const { loadCliDotEnv } = await import("./dotenv.js");
167+loadCliDotEnv({ quiet: true });
168+});
130169}
131170normalizeEnv();
132171if (shouldEnsureCliPath(normalizedArgv)) {
@@ -206,19 +245,18 @@ export async function runCli(argv: string[] = process.argv) {
206245const [
207246{ initializeDebugProxyCapture, finalizeDebugProxyCapture },
208247{ maybeWarnAboutDebugProxyCoverage },
209-] = await Promise.all([
210-import("../proxy-capture/runtime.js"),
211-import("../proxy-capture/coverage.js"),
212-]);
248+] = await startupTrace.measure("proxy-imports", () =>
249+Promise.all([import("../proxy-capture/runtime.js"), import("../proxy-capture/coverage.js")]),
250+);
213251initializeDebugProxyCapture("cli");
214252process.once("exit", () => {
215253finalizeDebugProxyCapture();
216254});
217-await ensureCliEnvProxyDispatcher();
255+await startupTrace.measure("proxy-dispatcher", () => ensureCliEnvProxyDispatcher());
218256maybeWarnAboutDebugProxyCoverage();
219257220-const { tryRouteCli } = await import("./route.js");
221-if (await tryRouteCli(normalizedArgv)) {
258+const { tryRouteCli } = await startupTrace.measure("route-import", () => import("./route.js"));
259+if (await startupTrace.measure("route", () => tryRouteCli(normalizedArgv))) {
222260return;
223261}
224262@@ -253,14 +291,16 @@ export async function runCli(argv: string[] = process.argv) {
253291 isUncaughtExceptionHandled,
254292},
255293{ restoreTerminalState },
256-] = await Promise.all([
257-import("./program.js"),
258-import("../infra/errors.js"),
259-import("../infra/fatal-error-hooks.js"),
260-import("../infra/unhandled-rejections.js"),
261-import("../terminal/restore.js"),
262-]);
263-const program = buildProgram();
294+] = await startupTrace.measure("core-imports", () =>
295+Promise.all([
296+import("./program.js"),
297+import("../infra/errors.js"),
298+import("../infra/fatal-error-hooks.js"),
299+import("../infra/unhandled-rejections.js"),
300+import("../terminal/restore.js"),
301+]),
302+);
303+const program = await startupTrace.measure("build-program", () => buildProgram());
264304265305// Global error handlers to prevent silent crashes from unhandled rejections/exceptions.
266306// These log the error and exit gracefully instead of crashing without trace.
@@ -291,14 +331,16 @@ export async function runCli(argv: string[] = process.argv) {
291331// are correct even with lazy command registration.
292332const { primary } = invocation;
293333if (primary && shouldRegisterPrimaryCommandOnly(parseArgv)) {
294-const { getProgramContext } = await import("./program/program-context.js");
295-const ctx = getProgramContext(program);
296-if (ctx) {
297-const { registerCoreCliByName } = await import("./program/command-registry.js");
298-await registerCoreCliByName(program, ctx, primary, parseArgv);
299-}
300-const { registerSubCliByName } = await import("./program/register.subclis.js");
301-await registerSubCliByName(program, primary);
334+await startupTrace.measure("register-primary", async () => {
335+const { getProgramContext } = await import("./program/program-context.js");
336+const ctx = getProgramContext(program);
337+if (ctx) {
338+const { registerCoreCliByName } = await import("./program/command-registry.js");
339+await registerCoreCliByName(program, ctx, primary, parseArgv);
340+}
341+const { registerSubCliByName } = await import("./program/register.subclis.js");
342+await registerSubCliByName(program, primary);
343+});
302344}
303345304346const hasBuiltinPrimary =
@@ -312,17 +354,14 @@ export async function runCli(argv: string[] = process.argv) {
312354 hasBuiltinPrimary,
313355});
314356if (!shouldSkipPluginRegistration) {
315-// Register plugin CLI commands before parsing
316-const { registerPluginCliCommandsFromValidatedConfig } = await import("../plugins/cli.js");
317-const config = await registerPluginCliCommandsFromValidatedConfig(
318-program,
319-undefined,
320-undefined,
321-{
357+const config = await startupTrace.measure("register-plugin-commands", async () => {
358+const { registerPluginCliCommandsFromValidatedConfig } =
359+await import("../plugins/cli.js");
360+return await registerPluginCliCommandsFromValidatedConfig(program, undefined, undefined, {
322361mode: "lazy",
323362 primary,
324-},
325-);
363+});
364+});
326365if (config) {
327366if (
328367primary &&
@@ -349,7 +388,7 @@ export async function runCli(argv: string[] = process.argv) {
349388stopStartupProgress();
350389351390try {
352-await program.parseAsync(parseArgv);
391+await startupTrace.measure("parse", () => program.parseAsync(parseArgv));
353392} catch (error) {
354393if (!isCommanderParseExit(error)) {
355394throw error;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。