import { describe, expect, test } from "vitest"; import { CommandModelError, canonicalPrompt } from "../../src/prose/index.js"; describe("command model", () => { const supportedCases: Array<[Parameters, string]> = [ [["compile", []], "prose compile"], [["compile", ["."]], "prose compile ."], [["compile", ["./responsibilities", "--out", "dist"]], "prose compile ./responsibilities --out dist"], [["compile", ["--out=build/prose"]], "prose compile --out=build/prose"], [["run", ["system.prose.md"]], "prose run system.prose.md"], [["run", ["std/evals/inspector"]], "prose run std/evals/inspector"], [["run", ["co/systems/company-repo-checker"]], "prose run co/systems/company-repo-checker"], [["run", ["system.prose.md", "--topic", "two words"]], "prose run system.prose.md --topic 'two words'"], [ ["run", ["system.prose.md", "--activation-context", "{\"kind\":\"openprose.activation\"}"]], "prose run system.prose.md --activation-context '{\"kind\":\"openprose.activation\"}'", ], [["write", ["draft a release readiness responsibility"]], "prose write output_mode: source-package-only apply: false run_state: in-context terminal_summary: required interactive: false request: 'draft a release readiness responsibility'"], [["write", ["--", "--no-interactive is literal request text"]], "prose write output_mode: source-package-only apply: false run_state: in-context terminal_summary: required interactive: false request: '--no-interactive is literal request text'"], [["lint", ["system.prose.md"]], "prose lint system.prose.md"], [["preflight", ["system.prose.md"]], "prose preflight system.prose.md"], [["test", ["tests/systems"]], "prose test tests/systems"], [["inspect", ["run-123"]], "prose inspect run-123"], [["status", []], "prose status"], [["install", []], "prose install"], [["install", ["--update"]], "prose install --update"], [["help", []], "prose help"], [["examples", []], "prose examples"], [["examples", ["stargazer-outreach"]], "prose examples stargazer-outreach"], [["upgrade", []], "prose upgrade"], [["upgrade", ["--dry-run"]], "prose upgrade --dry-run"], ]; for (const [[command, args], prompt] of supportedCases) { test(`translates ${command} ${args.join(" ")} to ${prompt}`, () => { expect(canonicalPrompt(command, args)).toBe(prompt); }); } test("preserves user path text and extension", () => { expect(canonicalPrompt("run", ["./systems/needs review.prose.md"])).toBe( "prose run './systems/needs review.prose.md'", ); }); const validationCases: Array<[Parameters, string, string]> = [ [["compile", ["one", "two"]], "Unexpected argument 'two'", "prose compile [path] [--out ]"], [["compile", ["--out"]], "Missing value for --out", "prose compile [path] [--out ]"], [["compile", ["--out="]], "Missing value for --out", "prose compile [path] [--out ]"], [["compile", ["--json"]], "Unexpected option '--json'", "prose compile [path] [--out ]"], [["compile", ["--out", "dist", "--out", "other"]], "Duplicate option", "prose compile [path] [--out ]"], [["run", []], "Missing required argument ", "prose run [inputs...]"], [["run", ["system.md"]], "Expected ", "prose run [inputs...]"], [["run", ["script.prose"]], "Expected ", "prose run [inputs...]"], [["write", []], "Pass text arguments or pipe stdin", "prose write [request...]"], [["write", [" "]], "Pass text arguments or pipe stdin", "prose write [request...]"], [["write", ["--interactive", "draft"]], "does not support interactive flags", "prose write [request...]"], [["write", ["--no-interactive", "draft"]], "does not support interactive flags", "prose write [request...]"], [["inspect", []], "Missing required argument ", "prose inspect "], [["lint", ["system.md"]], "Expected ", "prose lint "], [["preflight", ["system.md"]], "Expected ", "prose preflight "], [["upgrade", ["script.prose"]], "Unexpected argument 'script.prose'", "prose upgrade [--dry-run]"], [["upgrade", ["--force"]], "Unexpected option '--force'", "prose upgrade [--dry-run]"], [["upgrade", ["--dry-run", "--dry-run"]], "Duplicate option", "prose upgrade [--dry-run]"], [["status", ["--json"]], "Unexpected option '--json'", "prose status"], [["status", ["--graph"]], "Unexpected option '--graph'", "prose status"], [["install", ["--graph"]], "Unexpected option '--graph'", "prose install [--update]"], [["install", ["--update", "--update"]], "Duplicate option", "prose install [--update]"], [["help", ["run"]], "Unexpected argument 'run'", "prose help"], [["examples", ["one", "two"]], "Unexpected argument 'two'", "prose examples [name]"], ]; for (const [[command, args], messagePart, usage] of validationCases) { test(`raises validation details for ${command} ${args.join(" ")}`, () => { try { canonicalPrompt(command, args); throw new Error("expected canonicalPrompt to fail"); } catch (error) { expect(error).toBeInstanceOf(CommandModelError); if (error instanceof CommandModelError) { expect(error.message).toContain(messagePart); expect(error.usage).toBe(usage); } } }); } });