ea20f6d629
Uses Codex first, then Claude, then OpenCode through OpenRouter when quota is exhausted. Every generated comment and review now identifies the selected profile and model in a final quote. The dependent action interface remains one master key. Verified formatting, lint, type checks, encrypted profile decryption, current OpenCode CLI flags, and 45 tests. Reviewed-on: #18 Reviewed-by: bot <noreply@capsulizers.com> Co-authored-by: Danny Kim <temeddix@gmail.com> Co-committed-by: Danny Kim <temeddix@gmail.com>
77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
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<Uint8Array>({
|
|
start(controller) {
|
|
controller.enqueue(encode("first\n"));
|
|
controller.enqueue(encode("second\n"));
|
|
controller.close();
|
|
},
|
|
});
|
|
const stderr = new ReadableStream<Uint8Array>({
|
|
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"]);
|
|
});
|