feat(quota): add Command Code usage tracking

This commit is contained in:
Bohdan Triapitsyn
2026-08-18 16:24:02 +03:00
parent a01b7eec78
commit 17d08c0395
21 changed files with 345 additions and 0 deletions
+3
View File
@@ -2845,6 +2845,9 @@ export const dict = {
'quota.window.monthly': 'Monatliches Limit',
'quota.window.credits': 'Credits',
'quota.window.creditsBalance': 'Kreditguthaben',
'quota.window.monthlyCredits': 'Monatliche Credits',
'quota.window.purchasedCredits': 'Gekaufte Credits',
'quota.window.freeCredits': 'Kostenlose Credits',
'quota.window.billingCycle': 'Abrechnungszyklus',
'quota.window.auto': 'Automatisch',
'quota.window.api': 'API',
+3
View File
@@ -3023,6 +3023,9 @@ export const dict = {
'quota.window.monthly': 'Monthly Limit',
'quota.window.credits': 'Credits',
'quota.window.creditsBalance': 'Credits Balance',
'quota.window.monthlyCredits': 'Monthly Credits',
'quota.window.purchasedCredits': 'Purchased Credits',
'quota.window.freeCredits': 'Free Credits',
'quota.window.billingCycle': 'Billing Cycle',
'quota.window.auto': 'Auto',
'quota.window.api': 'API',
+3
View File
@@ -3024,6 +3024,9 @@ export const dict: Record<I18nKey, string> = {
"quota.window.monthly": "Monthly Limit",
"quota.window.credits": "Credits",
"quota.window.creditsBalance": "Credits Balance",
"quota.window.monthlyCredits": "Créditos mensuales",
"quota.window.purchasedCredits": "Créditos comprados",
"quota.window.freeCredits": "Créditos gratuitos",
"quota.window.billingCycle": "Billing Cycle",
"quota.window.auto": "Auto",
"quota.window.api": "API",
+3
View File
@@ -2716,6 +2716,9 @@ export const dict = {
'quota.window.monthly': 'Limite mensuelle',
'quota.window.credits': 'Crédits',
'quota.window.creditsBalance': 'Solde de crédits',
'quota.window.monthlyCredits': 'Crédits mensuels',
'quota.window.purchasedCredits': 'Crédits achetés',
'quota.window.freeCredits': 'Crédits gratuits',
'quota.window.billingCycle': 'Cycle de facturation',
'quota.window.auto': 'Auto',
'quota.window.api': 'API',
+3
View File
@@ -3019,6 +3019,9 @@ export const dict: Record<I18nKey, string> = {
'quota.window.monthly': '月間制限',
'quota.window.credits': 'クレジット',
'quota.window.creditsBalance': 'クレジット残高',
'quota.window.monthlyCredits': '月間クレジット',
'quota.window.purchasedCredits': '購入済みクレジット',
'quota.window.freeCredits': '無料クレジット',
'quota.window.billingCycle': '請求サイクル',
'quota.window.auto': '自動',
'quota.window.api': 'API',
+3
View File
@@ -3023,6 +3023,9 @@ export const dict: Record<I18nKey, string> = {
'quota.window.monthly': 'Monthly Limit',
'quota.window.credits': 'Credits',
'quota.window.creditsBalance': 'Credits Balance',
'quota.window.monthlyCredits': '월간 크레딧',
'quota.window.purchasedCredits': '구매한 크레딧',
'quota.window.freeCredits': '무료 크레딧',
'quota.window.billingCycle': 'Billing Cycle',
'quota.window.auto': 'Auto',
'quota.window.api': 'API',
+3
View File
@@ -3040,6 +3040,9 @@ export const dict: Record<I18nKey, string> = {
'quota.window.monthly': 'Monthly Limit',
'quota.window.credits': 'Credits',
'quota.window.creditsBalance': 'Credits Balance',
'quota.window.monthlyCredits': 'Kredyty miesięczne',
'quota.window.purchasedCredits': 'Kupione kredyty',
'quota.window.freeCredits': 'Darmowe kredyty',
'quota.window.billingCycle': 'Billing Cycle',
'quota.window.auto': 'Auto',
'quota.window.api': 'API',
@@ -3024,6 +3024,9 @@ export const dict: Record<I18nKey, string> = {
"quota.window.monthly": "Monthly Limit",
"quota.window.credits": "Credits",
"quota.window.creditsBalance": "Credits Balance",
"quota.window.monthlyCredits": "Créditos mensais",
"quota.window.purchasedCredits": "Créditos comprados",
"quota.window.freeCredits": "Créditos gratuitos",
"quota.window.billingCycle": "Billing Cycle",
"quota.window.auto": "Auto",
"quota.window.api": "API",
+3
View File
@@ -3024,6 +3024,9 @@ export const dict: Record<I18nKey, string> = {
"quota.window.monthly": "Monthly Limit",
"quota.window.credits": "Credits",
"quota.window.creditsBalance": "Credits Balance",
"quota.window.monthlyCredits": "Місячні кредити",
"quota.window.purchasedCredits": "Придбані кредити",
"quota.window.freeCredits": "Безкоштовні кредити",
"quota.window.billingCycle": "Billing Cycle",
"quota.window.auto": "Auto",
"quota.window.api": "API",
@@ -3024,6 +3024,9 @@ export const dict: Record<I18nKey, string> = {
'quota.window.monthly': 'Monthly Limit',
'quota.window.credits': 'Credits',
'quota.window.creditsBalance': 'Credits Balance',
'quota.window.monthlyCredits': '每月积分',
'quota.window.purchasedCredits': '已购买积分',
'quota.window.freeCredits': '免费积分',
'quota.window.billingCycle': 'Billing Cycle',
'quota.window.auto': 'Auto',
'quota.window.api': 'API',
@@ -3023,6 +3023,9 @@ export const dict: Record<I18nKey, string> = {
'quota.window.monthly': 'Monthly Limit',
'quota.window.credits': 'Credits',
'quota.window.creditsBalance': 'Credits Balance',
'quota.window.monthlyCredits': '每月點數',
'quota.window.purchasedCredits': '已購買點數',
'quota.window.freeCredits': '免費點數',
'quota.window.billingCycle': 'Billing Cycle',
'quota.window.auto': 'Auto',
'quota.window.api': 'API',
@@ -8,6 +8,7 @@ export interface QuotaProviderMeta {
export const QUOTA_PROVIDERS: QuotaProviderMeta[] = [
{ id: 'claude', name: 'Claude' },
{ id: 'codex', name: 'Codex' },
{ id: 'command-code', name: 'Command Code' },
{ id: 'cursor', name: 'Cursor' },
{ id: 'github-copilot', name: 'GitHub Copilot' },
{ id: 'google', name: 'Google' },
+3
View File
@@ -81,6 +81,9 @@ export const formatWindowLabel = (label: string): string => {
if (label === 'monthly') return t('quota.window.monthly');
if (label === 'credits') return t('quota.window.credits');
if (label === 'credits_balance') return t('quota.window.creditsBalance');
if (label === 'monthly_credits') return t('quota.window.monthlyCredits');
if (label === 'purchased_credits') return t('quota.window.purchasedCredits');
if (label === 'free_credits') return t('quota.window.freeCredits');
if (label === 'billing_cycle') return t('quota.window.billingCycle');
if (label === 'plan_limit') return t('quota.window.planLimit');
if (label === 'auto') return t('quota.window.auto');
+1
View File
@@ -1,6 +1,7 @@
export type QuotaProviderId =
| 'openai'
| 'codex'
| 'command-code'
| 'cursor'
| 'claude'
| 'github-copilot'
+66
View File
@@ -0,0 +1,66 @@
type CommandCodeCredits = {
credits?: { monthlyCredits?: number; purchasedCredits?: number; freeCredits?: number };
windowLimits?: {
fiveHour?: { used?: number; cap?: number; resetAt?: number };
weekly?: { used?: number; cap?: number; resetAt?: number };
};
};
type WindowData = { usedPercent: number | null; resetAt: number | null; windowSeconds: number | null; valueLabel: string };
const toWindow = (data: WindowData) => ({
usedPercent: data.usedPercent,
remainingPercent: data.usedPercent === null ? null : Math.max(0, 100 - data.usedPercent),
windowSeconds: data.windowSeconds,
resetAfterSeconds: data.resetAt === null ? null : Math.max(0, Math.floor((data.resetAt - Date.now()) / 1000)),
resetAt: data.resetAt,
resetAtFormatted: null,
resetAfterFormatted: null,
valueLabel: data.valueLabel,
});
const isFiniteNumber = (value: unknown): value is number => typeof value === 'number' && Number.isFinite(value);
const formatCredits = (value: number): string => String(Math.round((value + Number.EPSILON) * 100) / 100);
const parseCredits = (value: unknown): CommandCodeCredits | null => {
if (!value || typeof value !== 'object') return null;
const payload = value as CommandCodeCredits;
return payload;
};
const parseOrgId = (value: unknown): string | null | undefined => {
if (!value || typeof value !== 'object') return undefined;
const org = (value as { org?: { id?: unknown } }).org;
return typeof org?.id === 'string' && org.id.trim() ? org.id.trim() : null;
};
const parseCommandCodeCredits = (payload: CommandCodeCredits) => {
const windows: Record<string, ReturnType<typeof toWindow>> = {};
for (const [label, value] of [['monthly_credits', payload.credits?.monthlyCredits], ['purchased_credits', payload.credits?.purchasedCredits], ['free_credits', payload.credits?.freeCredits]] as const) {
if (isFiniteNumber(value)) windows[label] = toWindow({ usedPercent: null, resetAt: null, windowSeconds: null, valueLabel: formatCredits(value) });
}
for (const [label, limit, seconds] of [['5h', payload.windowLimits?.fiveHour, 5 * 60 * 60], ['weekly', payload.windowLimits?.weekly, 7 * 24 * 60 * 60]] as const) {
if (!isFiniteNumber(limit?.used) || !isFiniteNumber(limit.cap) || limit.cap <= 0) continue;
const resetAt = isFiniteNumber(limit.resetAt) ? (limit.resetAt < 1_000_000_000_000 ? limit.resetAt * 1000 : limit.resetAt) : null;
windows[label] = toWindow({ usedPercent: Math.min(100, Math.max(0, limit.used / limit.cap * 100)), resetAt, windowSeconds: seconds, valueLabel: `${formatCredits(limit.used)} / ${formatCredits(limit.cap)}` });
}
return windows;
};
const requestJson = async (path: string, apiKey: string): Promise<unknown> => {
const response = await fetch(`https://api.commandcode.ai${path}`, { headers: { Accept: 'application/json', Authorization: `Bearer ${apiKey}` }, signal: AbortSignal.timeout(15_000) });
if (response.status === 401 || response.status === 403) throw new Error('Command Code authentication failed');
if (!response.ok) throw new Error(`Command Code usage API returned HTTP ${response.status}`);
return response.json().catch(() => null);
};
export const fetchCommandCodeUsage = async (apiKey: string) => {
const orgId = parseOrgId(await requestJson('/alpha/whoami', apiKey));
if (orgId === undefined) throw new Error('Command Code account could not be determined');
const creditsPath = orgId ? `/alpha/billing/credits?orgId=${encodeURIComponent(orgId)}` : '/alpha/billing/credits';
const payload = parseCredits(await requestJson(creditsPath, apiKey));
if (!payload) throw new Error('Command Code usage data could not be parsed');
const windows = parseCommandCodeCredits(payload);
if (!Object.keys(windows).length) throw new Error('Command Code usage data could not be parsed');
return windows;
};
@@ -17,6 +17,7 @@ const AUTH = JSON.stringify({
crof: { key: 'test-token' },
neuralwatt: { key: 'test-token' },
'opencode-go': { key: 'test-token' },
'command-code': { type: 'oauth', access: 'test-token' },
'zai-coding-plan': { key: 'test-token' },
deepseek: { key: 'test-token' },
});
@@ -102,6 +103,58 @@ describe('OpenCode Go quota provider (VS Code parity)', () => {
});
});
describe('Command Code quota provider (VS Code parity)', () => {
test('uses the OAuth access token and resolves server-backed limits', async () => {
const requests: Array<{ url: string; init?: RequestInit }> = [];
globalThis.fetch = (async (url: string, init?: RequestInit) => {
requests.push({ url, init });
return mockResponse(url.endsWith('/alpha/whoami')
? { org: { id: 'org/a' } }
: { credits: { monthlyCredits: 120 }, windowLimits: { fiveHour: { used: 25, cap: 100, resetAt: 1_776_000_000 } } });
}) as typeof fetch;
const result = await fetchQuotaForProvider('command-code');
assert.equal(result.ok, true);
assert.deepEqual(requests.map(({ url }) => url), [
'https://api.commandcode.ai/alpha/whoami',
'https://api.commandcode.ai/alpha/billing/credits?orgId=org%2Fa',
]);
assert.equal((requests[0].init?.headers as Record<string, string>).Authorization, 'Bearer test-token');
assert.equal(result.usage!.windows['5h']!.usedPercent, 25);
assert.equal(result.usage!.windows.monthly_credits!.valueLabel, '120');
});
test('omits orgId for personal accounts', async () => {
const urls: string[] = [];
globalThis.fetch = (async (url: string) => {
urls.push(url);
return mockResponse(url.endsWith('/alpha/whoami')
? { user: { id: 'user-1' }, org: null }
: { credits: { monthlyCredits: 120 } });
}) as typeof fetch;
const result = await fetchQuotaForProvider('command-code');
assert.equal(result.ok, true);
assert.deepEqual(urls, [
'https://api.commandcode.ai/alpha/whoami',
'https://api.commandcode.ai/alpha/billing/credits',
]);
});
test('formats fractional credit values for display', async () => {
globalThis.fetch = (async (url: string) => mockResponse(url.endsWith('/alpha/whoami')
? { org: null }
: { credits: { monthlyCredits: 69.7947070034 }, windowLimits: { fiveHour: { used: 0.2052929966, cap: 14 } } })) as typeof fetch;
const result = await fetchQuotaForProvider('command-code');
assert.equal(result.usage!.windows.monthly_credits!.valueLabel, '69.79');
assert.equal(result.usage!.windows['5h']!.valueLabel, '0.21 / 14');
});
});
describe('Crof quota provider (VS Code parity)', () => {
test('reports credits balance as valueLabel with null percent', async () => {
stubFetchReturning(() => Promise.resolve(mockResponse({ usable_requests: 450, credits: 12.3456 })));
+16
View File
@@ -2,6 +2,7 @@ import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { fetchOpenCodeGoUsage } from './opencodeGoQuota';
import { fetchCommandCodeUsage } from './commandCodeQuota';
import { deleteLegacyOpenCodeGoCredential, readCredential } from './quotaCredentials';
import { getProviderAuth, updateProviderAuth } from './opencodeAuth';
@@ -748,6 +749,9 @@ export const listConfiguredQuotaProviders = () => {
const configured = new Set<string>();
const openCodeGoAuth = normalizeAuthEntry(getAuthEntry(auth, ['opencode-go']));
if (openCodeGoAuth && (typeof openCodeGoAuth.key === 'string' || typeof openCodeGoAuth.token === 'string')) configured.add('opencode-go');
const commandCodeAuth = normalizeAuthEntry(getAuthEntry(auth, ['command-code']));
if (commandCodeAuth && (typeof commandCodeAuth.key === 'string' || typeof commandCodeAuth.access === 'string' || typeof commandCodeAuth.token === 'string')) configured.add('command-code');
if (process.env.COMMAND_CODE_API_KEY?.trim()) configured.add('command-code');
if (readCredential('ollama-cloud')) configured.add('ollama-cloud');
if (readCredential('cursor')) configured.add('cursor');
@@ -2746,6 +2750,18 @@ export const fetchQuotaForProvider = async (providerId: string): Promise<Provide
return buildResult({ providerId, providerName: 'OpenCode Go', ok: false, configured: true, error: error instanceof Error ? error.message : 'Request failed' });
}
}
case 'command-code': {
try {
const entry = normalizeAuthEntry(getAuthEntry(readAuthFile(), ['command-code']));
const stored = typeof entry?.key === 'string' ? entry.key : typeof entry?.access === 'string' ? entry.access : typeof entry?.token === 'string' ? entry.token : null;
const environment = process.env.COMMAND_CODE_API_KEY?.trim() || null;
const apiKey = stored?.trim() || environment;
if (!apiKey) return buildResult({ providerId, providerName: 'Command Code', ok: false, configured: false, error: 'Not configured' });
return buildResult({ providerId, providerName: 'Command Code', ok: true, configured: true, usage: { windows: await fetchCommandCodeUsage(apiKey) } });
} catch (error) {
return buildResult({ providerId, providerName: 'Command Code', ok: false, configured: true, error: error instanceof Error ? error.message : 'Request failed' });
}
}
case 'cursor':
return fetchCursorQuota();
case 'crof':
@@ -19,6 +19,7 @@ These provider IDs are currently dispatchable via `fetchQuotaForProvider(provide
| --- | --- | --- | --- |
| `claude` | Claude | `providers/claude/` | Claude Code Keychain entry, Claude Code credentials file, OpenCode `auth.json` (`anthropic`, `claude`), `CLAUDE_CODE_OAUTH_TOKEN` |
| `codex` | Codex | `providers/codex.js` | `openai`, `codex`, `chatgpt` |
| `command-code` | Command Code | `providers/command-code.js` | `command-code` OAuth/API credential in OpenCode `auth.json`, or `COMMAND_CODE_API_KEY` |
| `cursor` | Cursor | `providers/cursor.js` | Environment/token files, OpenChamber-managed credentials, or explicit one-time Cursor import |
| `crof` | CrofAI | `providers/crof.js` | `crof` (API key under `key` or `token`) |
| `deepseek` | DeepSeek | `providers/deepseek.js` | `deepseek` (API key under `key` or `token`) |
@@ -52,6 +53,8 @@ Provider modules must export `providerId`, `providerName`, `aliases`, `isConfigu
Ollama Cloud and Cursor credentials are explicitly managed through Settings. OpenCode Go usage uses `GET https://opencode.ai/zen/go/v1/usage` with the `opencode-go` API key from OpenCode `auth.json` as a bearer token. The server validates managed credentials before atomic `0600` writes and never returns secrets through its API. OpenChamber never scans browser cookie stores or automatically reads Cursor storage; Cursor import is an explicit one-time user action and never modifies Cursor's database.
Command Code usage resolves account scope through `GET /alpha/whoami`, then reads server-backed credit balances and five-hour/weekly limits from `GET /alpha/billing/credits?orgId=...`. Personal accounts return `org: null` and use `/alpha/billing/credits` without an `orgId`; organization accounts include their organization id. Web/Electron and VS Code read the standard `command-code` OpenCode auth entry (including OAuth `access`) or `COMMAND_CODE_API_KEY`; credentials remain in the owning runtime and are never returned to shared UI.
On the first OpenCode Go usage refresh after upgrading, OpenChamber deletes the obsolete `quota/opencode-go.json` credential file without reading its cookie value.
## Claude credential and limit semantics
@@ -0,0 +1,90 @@
import { readAuthFile } from '../../opencode/auth.js';
import { asObject, buildResult, getAuthEntry, normalizeAuthEntry, toNumber, toUsageWindow } from '../utils/index.js';
export const providerId = 'command-code';
export const providerName = 'Command Code';
export const aliases = ['command-code'];
const API_BASE_URL = 'https://api.commandcode.ai';
const getApiKey = (auth = readAuthFile()) => {
const entry = normalizeAuthEntry(getAuthEntry(auth, aliases));
const stored = entry?.key ?? entry?.access ?? entry?.token;
return (typeof stored === 'string' ? stored.trim() : '') || process.env.COMMAND_CODE_API_KEY?.trim() || null;
};
const requestJson = async (path, apiKey, fetchImpl) => {
const response = await fetchImpl(`${API_BASE_URL}${path}`, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${apiKey}`,
'User-Agent': 'OpenChamber quota provider',
},
signal: AbortSignal.timeout(15_000),
});
if (response.status === 401 || response.status === 403) throw new Error('Command Code authentication failed');
if (!response.ok) throw new Error(`Command Code usage API returned HTTP ${response.status}`);
return response.json().catch(() => null);
};
const formatCredits = (value) => String(Math.round((value + Number.EPSILON) * 100) / 100);
const toBalanceWindow = (value) => toUsageWindow({
usedPercent: null,
windowSeconds: null,
resetAt: null,
valueLabel: formatCredits(value),
});
export const parseCommandCodeCredits = (payload) => {
const root = asObject(payload);
const credits = asObject(root?.credits);
const limits = asObject(root?.windowLimits);
const windows = {};
for (const [label, field] of [['monthly_credits', 'monthlyCredits'], ['purchased_credits', 'purchasedCredits'], ['free_credits', 'freeCredits']]) {
const value = toNumber(credits?.[field]);
if (value !== null) windows[label] = toBalanceWindow(value);
}
for (const [label, field, windowSeconds] of [['5h', 'fiveHour', 5 * 60 * 60], ['weekly', 'weekly', 7 * 24 * 60 * 60]]) {
const limit = asObject(limits?.[field]);
const used = toNumber(limit?.used);
const cap = toNumber(limit?.cap);
if (used === null || cap === null || cap <= 0) continue;
const resetAt = toNumber(limit?.resetAt);
windows[label] = toUsageWindow({
usedPercent: Math.min(100, Math.max(0, used / cap * 100)),
windowSeconds,
resetAt: resetAt === null ? null : resetAt < 1_000_000_000_000 ? resetAt * 1000 : resetAt,
valueLabel: `${formatCredits(used)} / ${formatCredits(cap)}`,
});
}
return windows;
};
export const fetchCommandCodeUsage = async (apiKey, fetchImpl = fetch) => {
const identity = asObject(await requestJson('/alpha/whoami', apiKey, fetchImpl));
const org = asObject(identity?.org);
const orgId = typeof org?.id === 'string' ? org.id.trim() : '';
const creditsPath = orgId
? `/alpha/billing/credits?orgId=${encodeURIComponent(orgId)}`
: '/alpha/billing/credits';
const credits = await requestJson(creditsPath, apiKey, fetchImpl);
const windows = parseCommandCodeCredits(credits);
if (Object.keys(windows).length === 0) throw new Error('Command Code usage data could not be parsed');
return windows;
};
export const isConfigured = () => Boolean(getApiKey());
export const fetchQuota = async (auth = readAuthFile()) => {
const apiKey = getApiKey(auth);
if (!apiKey) return buildResult({ providerId, providerName, ok: false, configured: false, error: 'Not configured' });
try {
return buildResult({ providerId, providerName, ok: true, configured: true, usage: { windows: await fetchCommandCodeUsage(apiKey) } });
} catch (error) {
return buildResult({ providerId, providerName, ok: false, configured: true, error: error instanceof Error ? error.message : 'Request failed' });
}
};
@@ -0,0 +1,72 @@
import { describe, expect, it, vi } from 'vitest';
import { fetchCommandCodeUsage, fetchQuota, parseCommandCodeCredits } from './command-code.js';
const creditsPayload = {
credits: { monthlyCredits: 120, purchasedCredits: 30, freeCredits: 5 },
windowLimits: {
fiveHour: { used: 25, cap: 100, resetAt: 1_776_000_000 },
weekly: { used: 70, cap: 200, resetAt: 1_776_604_800 },
},
};
describe('Command Code quota provider', () => {
it('parses balances and rate-limit windows', () => {
const windows = parseCommandCodeCredits(creditsPayload);
expect(windows.monthly_credits).toMatchObject({ usedPercent: null, valueLabel: '120' });
expect(windows.purchased_credits).toMatchObject({ usedPercent: null, valueLabel: '30' });
expect(windows.free_credits).toMatchObject({ usedPercent: null, valueLabel: '5' });
expect(windows['5h']).toMatchObject({ usedPercent: 25, valueLabel: '25 / 100', resetAt: 1_776_000_000_000 });
expect(windows.weekly.usedPercent).toBe(35);
});
it('formats fractional credit values for display', () => {
const windows = parseCommandCodeCredits({
credits: { monthlyCredits: 69.7947070034 },
windowLimits: { fiveHour: { used: 0.2052929966, cap: 14 } },
});
expect(windows.monthly_credits.valueLabel).toBe('69.79');
expect(windows['5h'].valueLabel).toBe('0.21 / 14');
});
it('resolves the organization before fetching credits', async () => {
const requests = [];
const windows = await fetchCommandCodeUsage('secret', async (url, options) => {
requests.push({ url, options });
return new Response(JSON.stringify(url.endsWith('/alpha/whoami') ? { org: { id: 'org/a' } } : creditsPayload));
});
expect(requests.map(({ url }) => url)).toEqual([
'https://api.commandcode.ai/alpha/whoami',
'https://api.commandcode.ai/alpha/billing/credits?orgId=org%2Fa',
]);
expect(requests[0].options.headers.Authorization).toBe('Bearer secret');
expect(windows['5h'].usedPercent).toBe(25);
});
it('fetches account-scoped credits without orgId for personal accounts', async () => {
const urls = [];
await fetchCommandCodeUsage('secret', async (url) => {
urls.push(url);
return new Response(JSON.stringify(url.endsWith('/alpha/whoami') ? { user: { id: 'user-1' }, org: null } : creditsPayload));
});
expect(urls).toEqual([
'https://api.commandcode.ai/alpha/whoami',
'https://api.commandcode.ai/alpha/billing/credits',
]);
});
it('does not expose credentials in authentication errors', async () => {
await expect(fetchCommandCodeUsage('secret', async () => new Response('', { status: 401 }))).rejects.toThrow('authentication failed');
});
it('reads OAuth access credentials from the OpenCode auth file', async () => {
const fetchMock = vi.fn()
.mockResolvedValueOnce(new Response(JSON.stringify({ org: { id: 'org-1' } })))
.mockResolvedValueOnce(new Response(JSON.stringify(creditsPayload)));
vi.stubGlobal('fetch', fetchMock);
const result = await fetchQuota({ 'command-code': { type: 'oauth', access: 'test-token' } });
expect(result).toMatchObject({ providerId: 'command-code', ok: true, configured: true });
expect(fetchMock.mock.calls[0][1].headers.Authorization).toBe('Bearer test-token');
vi.unstubAllGlobals();
});
});
@@ -9,6 +9,7 @@ import { buildResult } from '../utils/index.js';
import * as claude from './claude/index.js';
import * as codex from './codex.js';
import * as commandCode from './command-code.js';
import * as copilot from './copilot.js';
import * as crof from './crof.js';
import * as cursor from './cursor.js';
@@ -29,6 +30,12 @@ import * as opencodeGo from './opencode-go.js';
import * as xai from './xai.js';
const registry = {
'command-code': {
providerId: commandCode.providerId,
providerName: commandCode.providerName,
isConfigured: commandCode.isConfigured,
fetchQuota: commandCode.fetchQuota
},
claude: {
providerId: claude.providerId,
providerName: claude.providerName,