From 110ef579e7adf7761abf17d37fbb343c450687e2 Mon Sep 17 00:00:00 2001 From: bitkyc08-arch Date: Tue, 18 Aug 2026 15:42:04 +0900 Subject: [PATCH 1/2] release: v2.25.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f4e8bbd5c9..178d6a9c7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitkyc08/opencodex", - "version": "2.24.2", + "version": "2.25.0", "description": "Universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code", "type": "module", "main": "./bin/package-main.mjs", From 154b5359652d1879d06e24388ec89c5db87f52b4 Mon Sep 17 00:00:00 2001 From: yzxcj797 Date: Tue, 18 Aug 2026 20:28:52 +0800 Subject: [PATCH 2/2] fix(providers): gate OpenCode Go quota on the canonical base URL The quota probe required the provider to be literally named opencode-go, so multi-account setups pointing sibling providers at the canonical https://opencode.ai/zen/go/v1 base URL showed no rate-limit panel and produced no report rows (#1924). The Kimmi/A6api/CommandCode branches already gate on their canonical base URLs, and fetchOpenCodeGoQuota re-validates the canonical URL before sending the bearer key, so the name check was both too narrow and redundant. Gate on isCanonicalOpenCodeGoBaseUrl(provider.baseUrl) instead. Regression tests cover the sibling-provider repro and that a non-canonical base URL never probes opencode.ai. --- src/providers/quota.ts | 2 +- tests/opencode-go-quota.test.ts | 60 +++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/providers/quota.ts b/src/providers/quota.ts index bb3bab2837..7ee2bb0e1c 100644 --- a/src/providers/quota.ts +++ b/src/providers/quota.ts @@ -2084,7 +2084,7 @@ async function maybeFetchProviderQuota( && isCanonicalCommandCodeBaseUrl(provider.baseUrl)) { return fetchCommandCodeQuota(name, provider); } - if ((provider.authMode ?? "key") === "key" && name === "opencode-go") { + if ((provider.authMode ?? "key") === "key" && isCanonicalOpenCodeGoBaseUrl(provider.baseUrl)) { return fetchOpenCodeGoQuota(name, provider); } if ((provider.authMode ?? "key") === "key" && isCanonicalA6apiBaseUrl(provider.baseUrl)) { diff --git a/tests/opencode-go-quota.test.ts b/tests/opencode-go-quota.test.ts index ece8d22b53..8a34056ff2 100644 --- a/tests/opencode-go-quota.test.ts +++ b/tests/opencode-go-quota.test.ts @@ -88,3 +88,63 @@ describe("OpenCode Go provider quota", () => { expect(result.reports).toEqual([]); }); }); + +describe("OpenCode Go provider quota (canonical base URL gating, #1924)", () => { + test("reports quota for every key-auth provider on the canonical Go base URL, not just the literal name", async () => { + const seen: Array<{ url: string; authorization?: string }> = []; + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + const headers = init?.headers as Record | undefined; + seen.push({ url: String(input), authorization: headers?.Authorization }); + return new Response( + JSON.stringify({ + usage: { + rolling: { status: "ok", percent: 10, resetsAt: "2026-08-12T20:00:00.000Z" }, + weekly: { status: "ok", percent: 20, resetsAt: "2026-08-17T00:00:00.000Z" }, + monthly: { status: "ok", percent: 30, resetsAt: "2026-09-01T00:00:00.000Z" }, + }, + }), + { status: 200, headers: { "content-type": "application/json" } }, + ); + }) as typeof fetch; + + const config = openCodeGoConfig(); + config.providers = { + ...config.providers, + "opencode-go-2": { + adapter: "openai-chat", + authMode: "key", + baseUrl: "https://opencode.ai/zen/go/v1", + apiKey: "opencode-go-secret-2", + }, + }; + + const result = await fetchProviderQuotaReports(config, true); + + // Before #1924's fix only the provider literally named "opencode-go" + // produced a report; the sibling on the same canonical base URL was silent. + expect(result.reports.map((r: { provider: string }) => r.provider).sort()).toEqual([ + "opencode-go", + "opencode-go-2", + ]); + expect(seen).toHaveLength(2); + }); + + test("does not probe the Go usage endpoint for providers on other base URLs", async () => { + const seen: Array = []; + globalThis.fetch = (async (input: RequestInfo | URL) => { + seen.push(String(input)); + return new Response(JSON.stringify({ usage: {} }), { + status: 200, + headers: { "content-type": "application/json" }, + }); + }) as typeof fetch; + + const config = openCodeGoConfig("https://api.example.com/v1"); + const result = await fetchProviderQuotaReports(config, true); + + // The bearer key must never leave for a non-canonical host just because + // the provider is named opencode-go. + expect(result.reports).toHaveLength(0); + expect(seen.filter((u) => u.includes("opencode.ai"))).toHaveLength(0); + }); +});