diff --git a/tools/ai-cli-dispatch/src/cli.ts b/tools/ai-cli-dispatch/src/cli.ts index 080692e..b04dae2 100644 --- a/tools/ai-cli-dispatch/src/cli.ts +++ b/tools/ai-cli-dispatch/src/cli.ts @@ -71,10 +71,25 @@ function printHelp(): void { Usage: ai-cli-dispatch list [--json|--text] - ai-cli-dispatch run --client --prompt [--json|--text] - ai-cli-dispatch dispatch [--client ] [--json|--text] + ai-cli-dispatch run --client --prompt [--sync] [--timeout ] [--debug] [--json|--text] + ai-cli-dispatch dispatch [--client ] [--sync] [--timeout ] [--debug] [--json|--text] + ai-cli-dispatch start --client --prompt [--timeout ] [--debug] [--json|--text] + ai-cli-dispatch status [--json|--text] + ai-cli-dispatch results [--json|--text] + ai-cli-dispatch cancel [--json|--text] + ai-cli-dispatch list-jobs [--status running|completed|failed] [--json|--text] + ai-cli-dispatch cleanup-jobs [--max-age [h|m|s|d]] [--json|--text] ai-cli-dispatch --help +Flags: + --sync Run synchronously and block until the client returns (default is async) + --timeout Timeout in milliseconds (or override via config) + --debug Emit diagnostic JSON to stderr + --max-age Maximum age for cleanup (default unit: hours) + --status Filter jobs by status (running, completed, failed) + --json Output JSON (default) + --text Output plain text + Clients: codex, claude, opencode`); } diff --git a/tools/ai-cli-dispatch/tests/cli.test.ts b/tools/ai-cli-dispatch/tests/cli.test.ts index 69e2286..107613c 100644 --- a/tools/ai-cli-dispatch/tests/cli.test.ts +++ b/tools/ai-cli-dispatch/tests/cli.test.ts @@ -1428,4 +1428,180 @@ describe("main", () => { out.restore(); } }); + + // S-303: help output and CLI integration smoke tests + + it("--help output documents start subcommand", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("start"), "help should mention start"); + } finally { + out.restore(); + } + }); + + it("--help output documents status subcommand", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("status"), "help should mention status"); + } finally { + out.restore(); + } + }); + + it("--help output documents results subcommand", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("results"), "help should mention results"); + } finally { + out.restore(); + } + }); + + it("--help output documents cancel subcommand", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("cancel"), "help should mention cancel"); + } finally { + out.restore(); + } + }); + + it("--help output documents list-jobs subcommand", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("list-jobs"), "help should mention list-jobs"); + } finally { + out.restore(); + } + }); + + it("--help output documents cleanup-jobs subcommand", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("cleanup-jobs"), "help should mention cleanup-jobs"); + } finally { + out.restore(); + } + }); + + it("--help output documents --sync flag", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("--sync"), "help should mention --sync"); + } finally { + out.restore(); + } + }); + + it("--help output documents --timeout flag", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("--timeout"), "help should mention --timeout"); + } finally { + out.restore(); + } + }); + + it("--help output documents --debug flag", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("--debug"), "help should mention --debug"); + } finally { + out.restore(); + } + }); + + it("--help output documents --max-age flag", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("--max-age"), "help should mention --max-age"); + } finally { + out.restore(); + } + }); + + it("--help output documents --status flag for list-jobs", async () => { + const out = captureOutput(); + try { + const code = await main(["node", "cli.ts", "--help"]); + assert.strictEqual(code, 0); + const help = out.logs.join("\n"); + assert.ok(help.includes("--status"), "help should mention --status"); + } finally { + out.restore(); + } + }); + + it("start returns 1 for unknown client", async () => { + const out = captureOutput(); + try { + const code = await main( + ["node", "cli.ts", "start", "--client", "bogus", "--prompt", "hello"], + { + detectClients: () => mockClients, + } + ); + assert.strictEqual(code, 1); + const parsed = JSON.parse(out.errors[0]); + assert.ok(parsed.error.includes("client")); + } finally { + out.restore(); + } + }); + + it("start prints text output with --text", async () => { + const out = captureOutput(); + try { + const code = await main( + ["node", "cli.ts", "start", "--client", "codex", "--prompt", "hello", "--text"], + { + detectClients: () => mockClients, + startJob: async (client, prompt) => ({ + id: "job-start-txt", + client, + prompt, + status: "running", + startedAt: new Date().toISOString(), + }), + } + ); + assert.strictEqual(code, 0); + assert.ok(out.logs[0].includes("job-start-txt")); + assert.ok(out.logs[0].includes("codex")); + assert.ok(out.logs[0].includes("running")); + } finally { + out.restore(); + } + }); });