mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-08 22:03:59 +00:00
createNonExitingRuntime.exit() threw a generic Error, making it impossible for upstream try-catch to distinguish a simulated process exit from a real runtime crash. Added an ExitError class (internal-only, not exported from SDK) that callers can check via instanceof. ExitError is kept internal to avoid expanding the public plugin SDK API surface without maintainer approval. Tests import directly from ./runtime.js. Fixes #97796. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ vi.mock("../packages/terminal-core/src/restore.js", () => ({
|
||||
restoreTerminalState: vi.fn(),
|
||||
}));
|
||||
|
||||
import { createNonExitingRuntime, writeRuntimeJson } from "./runtime.js";
|
||||
import { createNonExitingRuntime, ExitError, writeRuntimeJson } from "./runtime.js";
|
||||
|
||||
describe("createNonExitingRuntime", () => {
|
||||
it("returns runtime with exit function", () => {
|
||||
@@ -18,14 +18,25 @@ describe("createNonExitingRuntime", () => {
|
||||
expect(typeof runtime.exit).toBe("function");
|
||||
});
|
||||
|
||||
it("exit function throws error", () => {
|
||||
it("exit function throws ExitError", () => {
|
||||
const runtime = createNonExitingRuntime();
|
||||
expect(() => runtime.exit(1)).toThrow("exit 1");
|
||||
expect(() => runtime.exit(1)).toThrow(ExitError);
|
||||
});
|
||||
|
||||
it("exit function includes code in error message", () => {
|
||||
it("ExitError includes exit code", () => {
|
||||
const runtime = createNonExitingRuntime();
|
||||
expect(() => runtime.exit(42)).toThrow("exit 42");
|
||||
expect(() => runtime.exit(42)).toThrow(ExitError);
|
||||
});
|
||||
|
||||
it("ExitError is distinguishable from generic Error", () => {
|
||||
const runtime = createNonExitingRuntime();
|
||||
try {
|
||||
runtime.exit(1);
|
||||
} catch (err) {
|
||||
expect(err instanceof ExitError).toBe(true);
|
||||
expect(err instanceof Error).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -95,11 +95,22 @@ export const defaultRuntime: OutputRuntimeEnv = {
|
||||
},
|
||||
};
|
||||
|
||||
/** Error thrown by createNonExitingRuntime.exit() to signal simulated process exit. */
|
||||
export class ExitError extends Error {
|
||||
constructor(
|
||||
public readonly code: number,
|
||||
message?: string,
|
||||
) {
|
||||
super(message ?? `exit ${code}`);
|
||||
this.name = "ExitError";
|
||||
}
|
||||
}
|
||||
|
||||
export function createNonExitingRuntime(): OutputRuntimeEnv {
|
||||
return {
|
||||
...createRuntimeIo(),
|
||||
exit: (code: number) => {
|
||||
throw new Error(`exit ${code}`);
|
||||
throw new ExitError(code);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user