/** *EX_CONFIG(78)fromsysexits.h—usedforconfigurationerrorssosystemd *(viaRestartPreventExitStatus=78)stopsrestartinginsteadofenteringa *restartstormthatcanrenderlow-resourcehostsunresponsive.
*/ const EXIT_CONFIG_ERROR = 78; const CONFIG_AUTO_RECOVERY_MESSAGE = "Gateway recovered automatically after a failed config change and restored the last known good configuration.";
function createGatewayCliStartupTrace() { const enabled = isTruthyEnvValue(process.env.OPENCLAW_GATEWAY_STARTUP_TRACE); const started = performance.now();
let last = started; const emit = (name: string, durationMs: number, totalMs: number) => { if (enabled) {
gatewayLog.info(
`startup trace: ${name} ${durationMs.toFixed(1)}ms total=${totalMs.toFixed(1)}ms`,
);
}
}; return {
mark(name: string) { const now = performance.now();
emit(name, now - last, now - started);
last = now;
},
async measure<T>(name: string, run: () => Awaitable<T>): Promise<T> { const before = performance.now(); try { return await run();
} finally { const now = performance.now();
emit(name, now - before, now - started);
last = now;
}
},
};
}
function warnInlinePasswordFlag() {
defaultRuntime.error( "Warning: --password can be exposed via process listings. Prefer --password-file or OPENCLAW_GATEWAY_PASSWORD.",
);
}
function resolveGatewayPasswordOption(opts: GatewayRunOpts): string | undefined { const direct = toOptionString(opts.password); const file = toOptionString(opts.passwordFile); if (direct && file) { thrownew Error("Use either --password or --password-file.");
} if (file) { return readSecretFromFile(file, "Gateway password");
} return direct;
}
function parseEnumOption<T extends string>(
raw: string | undefined,
allowed: readonly T[],
): T | null { if (!raw) { returnnull;
} return (allowed as readonly string[]).includes(raw) ? (raw as T) : null;
}
function formatModeErrorList(modes: readonly string[]): string { const quoted = modes.map((mode) => `"${mode}"`); if (quoted.length === 0) { return"";
} if (quoted.length === 1) { return quoted[0];
} if (quoted.length === 2) { return `${quoted[0]} or ${quoted[1]}`;
} return `${quoted.slice(0, -1).join(", ")}, or ${quoted[quoted.length - 1]}`;
}
function maybeLogPendingControlUiBuild(cfg: OpenClawConfig): void { if (cfg.gateway?.controlUi?.enabled === false) { return;
} if (toOptionString(cfg.gateway?.controlUi?.root)) { return;
} if (
resolveControlUiRootSync({
moduleUrl: import.meta.url,
argv1: process.argv[1],
cwd: process.cwd(),
})
) { return;
}
gatewayLog.info( "Control UI assets are missing; first startup may spend a few seconds building them before the gateway binds. `pnpm gateway:watch` does not rebuild Control UI assets, so rerun `pnpm ui:build` after UI changes or use `pnpm ui:dev` while developing the Control UI. For a full local dist, run `pnpm build && pnpm ui:build`.",
);
}
function getGatewayStartGuardErrors(params: {
allowUnconfigured?: boolean;
configExists: boolean;
configAuditPath: string;
mode: string | undefined;
}): string[] { if (params.allowUnconfigured || params.mode === "local") { return [];
} if (!params.configExists) { return [
`Missing config. Run \`${formatCliCommand("openclaw setup")}\` or set gateway.mode=local (or pass --allow-unconfigured).`,
];
} if (params.mode === undefined) { return [
[ "Gateway start blocked: existing config is missing gateway.mode.", "Treat this as suspicious or clobbered config.",
`Re-run \`${formatCliCommand("openclaw onboard --mode local")}\` or \`${formatCliCommand("openclaw setup")}\`, set gateway.mode=local manually, or pass --allow-unconfigured.`,
].join(" "),
`Config write audit: ${params.configAuditPath}`,
];
} return [
`Gateway start blocked: set gateway.mode=local (current: ${params.mode}) or pass --allow-unconfigured.`,
`Config write audit: ${params.configAuditPath}`,
];
}
for (const key of GATEWAY_RUN_VALUE_KEYS) { const inherited = inheritOptionFromParent(command, key); if (key === "wsLog") { // wsLog has a child default ("auto"), so prefer inherited parent CLI value when present.
resolved[key] = inherited ?? resolved[key]; continue;
}
resolved[key] = resolved[key] ?? inherited;
}
for (const key of GATEWAY_RUN_BOOLEAN_KEYS) { const inherited = inheritOptionFromParent<boolean>(command, key);
resolved[key] = Boolean(resolved[key] || inherited);
}
return resolved;
}
function isGatewayLockError(err: unknown): err is GatewayLockError { return (
err instanceof GatewayLockError ||
(!!err && typeof err === "object" && (err as { name?: string }).name === "GatewayLockError")
);
}
function isHealthyGatewayLockError(err: unknown): boolean { if (!isGatewayLockError(err) || typeof err.message !== "string") { returnfalse;
} return (
err.message.includes("gateway already running") ||
err.message.includes("another gateway instance is already listening")
);
}
function maybeWriteGatewayStartupFailureBundle(err: unknown): void { const result = writeDiagnosticStabilityBundleForFailureSync("gateway.startup_failed", err); if ("message" in result) {
gatewayLog.warn(result.message);
}
}
async function runGatewayCommand(opts: GatewayRunOpts) { const isDevProfile = normalizeOptionalLowercaseString(process.env.OPENCLAW_PROFILE) === "dev"; const devMode = Boolean(opts.dev) || isDevProfile; if (opts.reset && !devMode) {
defaultRuntime.error("Use --reset with --dev.");
defaultRuntime.exit(1); return;
}
// The heaviest part of gateway startup is loading the server module tree // (channels, plugins, HTTP stack, etc.). Show a spinner so the user sees // progress instead of a silent 15-20 s pause (especially on Windows/NTFS). const { startGatewayServer } = await startupTrace.measure("cli.server-import", () =>
withProgress(
{ label: "Loading gateway modules…", indeterminate: true },
async () => import("../../gateway/server.js"),
),
);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.