import assert from "node:assert/strict"; import { mkdtemp, realpath, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import test from "node:test"; import { runClawCommandForTesting } from "../src/lib/execution/backends/claw-runner.ts"; async function createTempScript(source: string) { const dir = await mkdtemp(join(tmpdir(), "claw-runner-")); const scriptPath = join(dir, "claw-script.mjs"); await writeFile(scriptPath, source, "utf8"); return { dir, scriptPath }; } test("Claw runner 把 completed JSON 响应映射成 completed,并把 payload 写入 stdin", async () => { const workspace = await mkdtemp(join(tmpdir(), "claw-runner-cwd-")); const expectedWorkspace = await realpath(workspace); const { scriptPath } = await createTempScript(` import { readFile } from "node:fs/promises"; let stdin = ""; process.stdin.setEncoding("utf8"); for await (const chunk of process.stdin) { stdin += chunk; } const payload = JSON.parse(stdin); process.stdout.write(JSON.stringify({ status: "completed", output: JSON.stringify({ body: payload.body, cwd: process.cwd(), command: payload.command, }), })); `); const result = await runClawCommandForTesting({ config: { enabled: true, command: process.execPath, args: [scriptPath], cwd: workspace, timeoutMs: 1000, }, payload: { body: "继续执行", command: "claw", }, }); assert.equal(result.status, "completed"); if (result.status !== "completed") { assert.fail("expected completed"); } const output = JSON.parse(result.output) as { body: string; cwd: string; command: string; }; assert.equal(output.body, "继续执行"); assert.equal(output.cwd, expectedWorkspace); assert.equal(output.command, "claw"); }); test("Claw runner 把 failed JSON 响应映射成 failed", async () => { const { scriptPath } = await createTempScript(` let stdin = ""; process.stdin.setEncoding("utf8"); for await (const chunk of process.stdin) { stdin += chunk; } const payload = JSON.parse(stdin); process.stdout.write(JSON.stringify({ status: "failed", error: "bad-request:" + payload.body, })); `); const result = await runClawCommandForTesting({ config: { enabled: true, command: process.execPath, args: [scriptPath], timeoutMs: 1000, }, payload: { body: "格式不对", }, }); assert.equal(result.status, "failed"); if (result.status !== "failed") { assert.fail("expected failed"); } assert.equal(result.error, "bad-request:格式不对"); }); test("Claw runner 把无效 JSON 响应映射成 INVALID_CLAW_RESPONSE", async () => { const { scriptPath } = await createTempScript(` process.stdout.write("not-json"); `); const result = await runClawCommandForTesting({ config: { enabled: true, command: process.execPath, args: [scriptPath], timeoutMs: 1000, }, payload: { body: "anything", }, }); assert.equal(result.status, "failed"); if (result.status !== "failed") { assert.fail("expected failed"); } assert.match(result.error, /INVALID_CLAW_RESPONSE/); }); test("Claw runner 把非零退出码映射成 stderr 或退出码错误", async () => { const { scriptPath } = await createTempScript(` process.stderr.write("claw crashed"); process.exit(2); `); const result = await runClawCommandForTesting({ config: { enabled: true, command: process.execPath, args: [scriptPath], timeoutMs: 1000, }, payload: { body: "anything", }, }); assert.equal(result.status, "failed"); if (result.status !== "failed") { assert.fail("expected failed"); } assert.match(result.error, /claw crashed/); }); test("Claw runner 超时后返回 CLAW_TIMEOUT", async () => { const { scriptPath } = await createTempScript(` setTimeout(() => { process.stdout.write(JSON.stringify({ status: "completed", output: "late" })); }, 500); `); const result = await runClawCommandForTesting({ config: { enabled: true, command: process.execPath, args: [scriptPath], timeoutMs: 50, }, payload: { body: "slow", }, }); assert.equal(result.status, "failed"); if (result.status !== "failed") { assert.fail("expected failed"); } assert.match(result.error, /CLAW_TIMEOUT/); });