import process from "node:process"; import { beforeEach, describe, expect, it, vi } from "vitest"; const tryRouteCliMock = vi.hoisted(() => vi.fn()); const loadDotEnvMock = vi.hoisted(() => vi.fn()); const normalizeEnvMock = vi.hoisted(() => vi.fn()); const ensurePathMock = vi.hoisted(() => vi.fn()); const assertRuntimeMock = vi.hoisted(() => vi.fn()); vi.mock("./route.js", () => ({ tryRouteCli: tryRouteCliMock, })); vi.mock("../infra/dotenv.js", () => ({ loadDotEnv: loadDotEnvMock, })); vi.mock("../infra/env.js", () => ({ normalizeEnv: normalizeEnvMock, })); vi.mock("../infra/path-env.js", () => ({ ensureOpenClawCliOnPath: ensurePathMock, })); vi.mock("../infra/runtime-guard.js", () => ({ assertSupportedRuntime: assertRuntimeMock, })); const { runCli } = await import("./run-main.js"); describe("runCli exit behavior", () => { beforeEach(() => { vi.clearAllMocks(); }); it("does not force process.exit after successful routed command", async () => { tryRouteCliMock.mockResolvedValueOnce(true); const exitSpy = vi.spyOn(process, "exit").mockImplementation(((code?: number) => { throw new Error(`unexpected process.exit(${String(code)})`); }) as typeof process.exit); await runCli(["node", "openclaw", "status"]); expect(tryRouteCliMock).toHaveBeenCalledWith(["node", "openclaw", "status"]); expect(exitSpy).not.toHaveBeenCalled(); exitSpy.mockRestore(); }); });