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:
Danny Kim
2026-09-24 01:39:49 +00:00
committed by temeddix
parent 4ecdf5adc0
commit ea20f6d629
13 changed files with 429 additions and 78 deletions
+9 -3
View File
@@ -4,6 +4,7 @@ import type { BotProfile } from "./profiles.ts";
const DEFAULT_MODELS: Record<BotProfile["type"], string> = {
claude: "claude-sonnet-5",
codex: "gpt-5.6-terra",
opencode: "openrouter/qwen/qwen3.8-27b",
};
export type BotCredentials = {
@@ -110,13 +111,18 @@ export async function parseCredentials(
}
}
const { type, model, token } = profile;
if (type !== "claude" && type !== "codex") {
throw new Error(`${at}.type: expected \"claude\" or \"codex\"`);
if (type !== "claude" && type !== "codex" && type !== "opencode") {
throw new Error(
`${at}.type: expected \"claude\", \"codex\", or \"opencode\"`,
);
}
if (model !== undefined && (typeof model !== "string" || model === "")) {
throw new Error(`${at}.model: expected a model name`);
}
if (type === "claude" && typeof token !== "string") {
if (
(type === "claude" || type === "opencode") &&
typeof token !== "string"
) {
throw new Error(`${at}.token: expected an encrypted credential`);
}
if (token !== undefined && typeof token !== "string") {