import { assertEquals, assertRejects } from "jsr:@std/assert@1"; import { collectOpenCodeOutput, openCodeArgs, parseOpenCodeEvents, } from "./opencode.ts"; Deno.test("builds a non-interactive auto-approved OpenCode command", () => { assertEquals( openCodeArgs("openrouter/qwen/qwen3.8-27b", "Review this"), [ "run", "--format", "json", "--auto", "--model", "openrouter/qwen/qwen3.8-27b", "Review this", ], ); }); Deno.test("returns the final visible OpenCode text event", () => { assertEquals( parseOpenCodeEvents([ JSON.stringify({ type: "step_start", part: { type: "step-start" } }), JSON.stringify({ type: "text", part: { type: "text", text: "draft" } }), JSON.stringify({ type: "text", part: { type: "text", text: "done" } }), JSON.stringify({ type: "step_finish", part: { type: "step-finish" } }), ].join("\n")), "done", ); }); Deno.test("rejects a successful OpenCode run without visible text", async () => { await assertRejects( async () => { parseOpenCodeEvents('{"type":"step_start"}'); await Promise.resolve(); }, Error, "no text output", ); }); Deno.test("streams OpenCode output while collecting it", async () => { const encode = (value: string) => new TextEncoder().encode(value); const stdout = new ReadableStream({ start(controller) { controller.enqueue(encode("first\n")); controller.enqueue(encode("second\n")); controller.close(); }, }); const stderr = new ReadableStream({ start(controller) { controller.enqueue(encode("warning\n")); controller.close(); }, }); const shown: string[] = []; const result = await collectOpenCodeOutput( stdout, stderr, (chunk: Uint8Array) => { shown.push(`out:${new TextDecoder().decode(chunk)}`); }, (chunk: Uint8Array) => { shown.push(`err:${new TextDecoder().decode(chunk)}`); }, ); assertEquals(result, { stdout: "first\nsecond\n", stderr: "warning\n" }); assertEquals(shown, ["out:first\n", "err:warning\n", "out:second\n"]); });