diff --git a/src/cliproxy/quota-fetcher.ts b/src/cliproxy/quota-fetcher.ts index 0291d9b9..d2daa236 100644 --- a/src/cliproxy/quota-fetcher.ts +++ b/src/cliproxy/quota-fetcher.ts @@ -625,6 +625,10 @@ export async function findAvailableAccount( ): Promise<{ account: AccountInfo; quota: QuotaResult } | null> { const allQuotas = await fetchAllProviderQuotas(provider); + // Get excluded account's project ID to avoid switching to same-project accounts + const excludedProjectId = allQuotas.accounts.find((a) => a.account.id === excludeAccountId)?.quota + .projectId; + for (const { account, quota } of allQuotas.accounts) { // Skip excluded account if (excludeAccountId && account.id === excludeAccountId) { @@ -636,6 +640,11 @@ export async function findAvailableAccount( continue; } + // Skip accounts sharing same GCP project (quota is pooled) + if (excludedProjectId && quota.projectId === excludedProjectId) { + continue; + } + // Check if any model has remaining quota (> 5% to avoid edge cases) const hasQuota = quota.models.some((m) => m.percentage > 5); if (hasQuota) { diff --git a/src/commands/cliproxy-command.ts b/src/commands/cliproxy-command.ts index c8af0f25..080d271b 100644 --- a/src/commands/cliproxy-command.ts +++ b/src/commands/cliproxy-command.ts @@ -609,7 +609,7 @@ async function handleDoctor(): Promise { // Display per-account quota status for (const { account, quota } of quotaResult.accounts) { - const accountLabel = account.email || account.id; + const accountLabel = account.email || account.id || 'Unknown Account'; const defaultBadge = account.isDefault ? color(' (default)', 'info') : ''; if (!quota.success) { @@ -624,8 +624,11 @@ async function handleDoctor(): Promise { continue; } - // Calculate overall quota health - const avgQuota = quota.models.reduce((sum, m) => sum + m.percentage, 0) / quota.models.length; + // Calculate overall quota health (guard against empty models array) + const avgQuota = + quota.models.length > 0 + ? quota.models.reduce((sum, m) => sum + m.percentage, 0) / quota.models.length + : 0; const statusIcon = avgQuota > 50 ? ok('') : avgQuota > 10 ? warn('') : fail(''); console.log(` ${statusIcon}${accountLabel}${defaultBadge}`); @@ -681,9 +684,10 @@ async function handleDoctor(): Promise { function formatQuotaBar(percentage: number): string { const width = 20; - const filled = Math.round((percentage / 100) * width); + const clampedPct = Math.max(0, Math.min(100, percentage)); + const filled = Math.round((clampedPct / 100) * width); const empty = width - filled; - const filledChar = percentage > 50 ? '█' : percentage > 10 ? '▓' : '░'; + const filledChar = clampedPct > 50 ? '█' : clampedPct > 10 ? '▓' : '░'; return `[${filledChar.repeat(filled)}${' '.repeat(empty)}]`; }