Files
openclaw/src/entry.version-fast-path.ts
maweibin 84cd3aa7f5 fix(cli): call process.exit(1) in root help and version fast path error handlers (#97793) (#97807)
The error handler in tryHandleRootHelpFastPath only set process.exitCode=1
without calling process.exit(). When dangling async handles exist (timers,
connections, promises), the Node event loop stays open and the CLI hangs
indefinitely instead of returning to the terminal.

In tryHandleRootVersionFastPath, the default onError handler called
process.exit(1) directly, bypassing the injected exit seam that the
success path already uses. Changed to exit(1) (deps.exit ?? process.exit)
so tests and embedded callers can observe and control exit on failure.

Added rejection-path tests for version fast path: injected exit called
on resolveVersion rejection, and caller-supplied onError honored.

Fixes #97793.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 10:47:55 -07:00

55 lines
1.7 KiB
TypeScript

// Handles fast version output before the full CLI graph loads.
import { isRootVersionInvocation } from "./cli/argv.js";
import { resolveCliContainerTarget } from "./cli/container-target.js";
export function tryHandleRootVersionFastPath(
argv: string[],
deps: {
env?: NodeJS.ProcessEnv;
moduleUrl?: string;
output?: (message: string) => void;
exit?: (code?: number) => void;
onError?: (error: unknown) => void;
resolveVersion?: () => Promise<{
VERSION: string;
resolveCommitHash: (params: { moduleUrl: string }) => string | null;
}>;
} = {},
): boolean {
if (resolveCliContainerTarget(argv, deps.env)) {
return false;
}
if (!isRootVersionInvocation(argv)) {
return false;
}
const output = deps.output ?? ((message: string) => console.log(message));
const exit = deps.exit ?? ((code?: number) => process.exit(code));
const onError =
deps.onError ??
((error: unknown) => {
console.error(
"[openclaw] Failed to resolve version:",
error instanceof Error ? (error.stack ?? error.message) : error,
);
exit(1);
});
const resolveVersion =
deps.resolveVersion ??
(async () => {
const [{ VERSION }, { resolveCommitHash }] = await Promise.all([
import("./version.js"),
import("./infra/git-commit.js"),
]);
return { VERSION, resolveCommitHash };
});
resolveVersion()
.then(({ VERSION, resolveCommitHash }) => {
const commit = resolveCommitHash({ moduleUrl: deps.moduleUrl ?? import.meta.url });
output(commit ? `OpenClaw ${VERSION} (${commit})` : `OpenClaw ${VERSION}`);
exit(0);
})
.catch(onError);
return true;
}