Show the selected bot profile and add OpenRouter fallback (#18)
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>
This commit was merged in pull request #18.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
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"]);
|
||||
});
|
||||
Reference in New Issue
Block a user