import { describe, it } from "node:test"; import assert from "node:assert"; import { reportError, reportCliError, handleSyncRun, handleAsyncRun, } from "../src/cli-helpers.js"; import type { ExecResult, Job } from "../src/types.js"; function captureConsole() { const logs: string[] = []; const errors: string[] = []; const origLog = console.log; const origError = console.error; console.log = (...args: unknown[]) => logs.push(args.map(String).join(" ")); console.error = (...args: unknown[]) => errors.push(args.map(String).join(" ")); return { logs, errors, restore() { console.log = origLog; console.error = origError; }, }; } describe("reportError", () => { it("prints JSON error for Error instance when jsonMode=true", () => { const out = captureConsole(); try { const code = reportError(new Error("boom"), true); assert.strictEqual(code, 1); assert.strictEqual(out.errors.length, 1); const parsed = JSON.parse(out.errors[0]); assert.strictEqual(parsed.error, "boom"); } finally { out.restore(); } }); it("prints plain text error for Error instance when jsonMode=false", () => { const out = captureConsole(); try { const code = reportError(new Error("boom"), false); assert.strictEqual(code, 1); assert.strictEqual(out.errors.length, 1); assert.strictEqual(out.errors[0], "boom"); } finally { out.restore(); } }); it("prints JSON error for non-Error value when jsonMode=true", () => { const out = captureConsole(); try { const code = reportError("plain string", true); assert.strictEqual(code, 1); const parsed = JSON.parse(out.errors[0]); assert.strictEqual(parsed.error, "plain string"); } finally { out.restore(); } }); }); describe("reportCliError", () => { it("prints JSON error with jsonMode=true", () => { const out = captureConsole(); try { const code = reportCliError("missing arg", true); assert.strictEqual(code, 1); const parsed = JSON.parse(out.errors[0]); assert.strictEqual(parsed.error, "missing arg"); } finally { out.restore(); } }); it("prints prefixed text error with jsonMode=false", () => { const out = captureConsole(); try { const code = reportCliError("missing arg", false); assert.strictEqual(code, 1); assert.strictEqual(out.errors[0], "Error: missing arg"); } finally { out.restore(); } }); }); describe("handleSyncRun", () => { it("returns 0 and prints JSON result in jsonMode", async () => { const out = captureConsole(); try { const result: ExecResult = { stdout: "out", stderr: "err", exitCode: 0, client: "codex", durationMs: 10, }; const code = await handleSyncRun( async () => result, "codex", "hello", 5000, false, { jsonMode: true, stdoutWrite: () => {}, stderrWrite: () => {} } ); assert.strictEqual(code, 0); assert.strictEqual(out.logs.length, 1); const parsed = JSON.parse(out.logs[0]); assert.strictEqual(parsed.stdout, "out"); } finally { out.restore(); } }); it("returns 0 and writes stdout/stderr in text mode", async () => { const out = captureConsole(); const stdout: string[] = []; const stderr: string[] = []; try { const result: ExecResult = { stdout: "out", stderr: "err", exitCode: 0, client: "codex", durationMs: 10, }; const code = await handleSyncRun( async () => result, "codex", "hello", 5000, false, { jsonMode: false, stdoutWrite: (c) => stdout.push(c), stderrWrite: (c) => stderr.push(c), } ); assert.strictEqual(code, 0); assert.strictEqual(stdout.join(""), "out"); assert.strictEqual(stderr.join(""), "err"); assert.strictEqual(out.logs.length, 0); } finally { out.restore(); } }); it("passes timeoutMs and debug to executePrompt", async () => { const out = captureConsole(); try { let received: any; const code = await handleSyncRun( async (_c, _p, opts) => { received = opts; return { stdout: "", stderr: "", exitCode: 0, client: "codex", durationMs: 1, }; }, "codex", "hello", 12345, true, { jsonMode: true, stdoutWrite: () => {}, stderrWrite: () => {} } ); assert.strictEqual(code, 0); assert.strictEqual(received?.timeoutMs, 12345); assert.strictEqual(received?.debug, true); } finally { out.restore(); } }); it("returns 1 and prints error JSON when executePrompt throws", async () => { const out = captureConsole(); try { const code = await handleSyncRun( async () => { throw new Error("fail"); }, "codex", "hello", undefined, false, { jsonMode: true, stdoutWrite: () => {}, stderrWrite: () => {} } ); assert.strictEqual(code, 1); const parsed = JSON.parse(out.errors[0]); assert.strictEqual(parsed.error, "fail"); } finally { out.restore(); } }); }); describe("handleAsyncRun", () => { it("returns 0 and prints JSON job in jsonMode", async () => { const out = captureConsole(); try { const job: Job = { id: "j1", client: "codex", prompt: "hi", status: "running", startedAt: "2024-01-01T00:00:00Z", }; const code = await handleAsyncRun( async () => job, "codex", "hi", undefined, false, { jsonMode: true, stdoutWrite: () => {}, stderrWrite: () => {} } ); assert.strictEqual(code, 0); const parsed = JSON.parse(out.logs[0]); assert.strictEqual(parsed.jobId, "j1"); assert.strictEqual(parsed.status, "running"); } finally { out.restore(); } }); it("returns 0 and prints text job info", async () => { const out = captureConsole(); try { const job: Job = { id: "j1", client: "codex", prompt: "hi", status: "running", startedAt: "2024-01-01T00:00:00Z", }; const code = await handleAsyncRun( async () => job, "codex", "hi", undefined, false, { jsonMode: false, stdoutWrite: () => {}, stderrWrite: () => {} } ); assert.strictEqual(code, 0); assert.ok(out.logs[0].includes("j1")); assert.ok(out.logs[0].includes("running")); } finally { out.restore(); } }); it("returns 1 and prints error JSON when startJob throws", async () => { const out = captureConsole(); try { const code = await handleAsyncRun( async () => { throw new Error("fail"); }, "codex", "hi", undefined, false, { jsonMode: true, stdoutWrite: () => {}, stderrWrite: () => {} } ); assert.strictEqual(code, 1); const parsed = JSON.parse(out.errors[0]); assert.strictEqual(parsed.error, "fail"); } finally { out.restore(); } }); });