mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-12 14:14:47 +00:00
feat(cliproxy): clarify quota percentages are remaining in CLI output
Closes #1714
This commit is contained in:
1 parent
65dc902299
commit
eca266ad30
5 files changed
+107
-4
No files matched your search
@@ -138,7 +138,7 @@ export async function handleDoctor(verbose = false): Promise<void> {
|
|||||||
|
|
||||||
for (const model of quota.models) {
|
for (const model of quota.models) {
|
||||||
const bar = formatQuotaBar(model.percentage);
|
const bar = formatQuotaBar(model.percentage);
|
||||||
console.log(` ${model.name.padEnd(20)} ${bar} ${model.percentage.toFixed(0)}%`);
|
console.log(` ${model.name.padEnd(20)} ${bar} ${model.percentage.toFixed(0)}% remaining`);
|
||||||
}
|
}
|
||||||
console.log('');
|
console.log('');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export function displayClaudeQuotaSection(
|
|||||||
? dim(' [warning]')
|
? dim(' [warning]')
|
||||||
: '';
|
: '';
|
||||||
console.log(
|
console.log(
|
||||||
` ${getClaudeWindowDisplayLabel(window).padEnd(24)} ${bar} ${window.remainingPercent.toFixed(0)}%${statusLabel}${resetLabel}`
|
` ${getClaudeWindowDisplayLabel(window).padEnd(24)} ${bar} ${window.remainingPercent.toFixed(0)}% remaining${statusLabel}${resetLabel}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export function displayCodexQuotaSection(
|
|||||||
const resetValue = formatCodexWindowReset(window);
|
const resetValue = formatCodexWindowReset(window);
|
||||||
const resetLabel = resetValue ? dim(` Resets ${resetValue}`) : '';
|
const resetLabel = resetValue ? dim(` Resets ${resetValue}`) : '';
|
||||||
console.log(
|
console.log(
|
||||||
` ${getCodexWindowDisplayLabel(window, orderedWindows).padEnd(24)} ${bar} ${window.remainingPercent.toFixed(0)}%${resetLabel}`
|
` ${getCodexWindowDisplayLabel(window, orderedWindows).padEnd(24)} ${bar} ${window.remainingPercent.toFixed(0)}% remaining${resetLabel}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export function displayGeminiCliQuotaSection(
|
|||||||
? dim(` Resets ${formatResetTimeISO(bucket.resetTime)}`)
|
? dim(` Resets ${formatResetTimeISO(bucket.resetTime)}`)
|
||||||
: '';
|
: '';
|
||||||
console.log(
|
console.log(
|
||||||
` ${bucket.label.padEnd(24)} ${bar} ${bucket.remainingPercent.toFixed(0)}%${tokenLabel}${amountLabel}${resetLabel}`
|
` ${bucket.label.padEnd(24)} ${bar} ${bucket.remainingPercent.toFixed(0)}% remaining${tokenLabel}${amountLabel}${resetLabel}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { describe, expect, it } from 'bun:test';
|
import { describe, expect, it } from 'bun:test';
|
||||||
import { displayClaudeQuotaSection } from '../../../src/commands/cliproxy/quota-subcommand/sections/claude';
|
import { displayClaudeQuotaSection } from '../../../src/commands/cliproxy/quota-subcommand/sections/claude';
|
||||||
|
import { displayCodexQuotaSection } from '../../../src/commands/cliproxy/quota-subcommand/sections/codex';
|
||||||
|
import { displayGeminiCliQuotaSection } from '../../../src/commands/cliproxy/quota-subcommand/sections/gemini-cli';
|
||||||
|
|
||||||
async function loadQuotaCommandTestExports() {
|
async function loadQuotaCommandTestExports() {
|
||||||
const moduleId = Date.now() + Math.random();
|
const moduleId = Date.now() + Math.random();
|
||||||
@@ -167,3 +169,104 @@ describe('cliproxy quota subcommand Codex label formatting', () => {
|
|||||||
expect(label).not.toContain('\u0007');
|
expect(label).not.toContain('\u0007');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function captureConsoleLog(fn: () => void): string {
|
||||||
|
const output: string[] = [];
|
||||||
|
const originalLog = console.log;
|
||||||
|
console.log = (...args: unknown[]) => output.push(args.map(String).join(' '));
|
||||||
|
try {
|
||||||
|
fn();
|
||||||
|
} finally {
|
||||||
|
console.log = originalLog;
|
||||||
|
}
|
||||||
|
return output.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('cliproxy quota remaining percent labels', () => {
|
||||||
|
it('renders Claude remaining percent with a remaining suffix', () => {
|
||||||
|
const text = captureConsoleLog(() => {
|
||||||
|
displayClaudeQuotaSection([
|
||||||
|
{
|
||||||
|
account: 'claude@example.com',
|
||||||
|
quota: {
|
||||||
|
success: true,
|
||||||
|
windows: [
|
||||||
|
{
|
||||||
|
rateLimitType: 'five_hour',
|
||||||
|
label: '5h usage limit',
|
||||||
|
status: 'allowed',
|
||||||
|
utilization: 0.28,
|
||||||
|
usedPercent: 28,
|
||||||
|
remainingPercent: 72,
|
||||||
|
resetAt: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
coreUsage: { fiveHour: null, weekly: null },
|
||||||
|
lastUpdated: 1,
|
||||||
|
accountId: 'claude@example.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(text).toContain('72% remaining');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders Codex remaining percent with a remaining suffix', () => {
|
||||||
|
const text = captureConsoleLog(() => {
|
||||||
|
displayCodexQuotaSection([
|
||||||
|
{
|
||||||
|
account: 'codex@example.com',
|
||||||
|
quota: {
|
||||||
|
success: true,
|
||||||
|
windows: [
|
||||||
|
{
|
||||||
|
label: 'Primary',
|
||||||
|
usedPercent: 28,
|
||||||
|
remainingPercent: 72,
|
||||||
|
resetAfterSeconds: null,
|
||||||
|
resetAt: null,
|
||||||
|
category: 'usage',
|
||||||
|
cadence: '5h',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
planType: 'pro',
|
||||||
|
lastUpdated: 1,
|
||||||
|
accountId: 'codex@example.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(text).toContain('72% remaining');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders Gemini CLI remaining percent with a remaining suffix', () => {
|
||||||
|
const text = captureConsoleLog(() => {
|
||||||
|
displayGeminiCliQuotaSection([
|
||||||
|
{
|
||||||
|
account: 'gemini@example.com',
|
||||||
|
quota: {
|
||||||
|
success: true,
|
||||||
|
buckets: [
|
||||||
|
{
|
||||||
|
id: 'gemini-flash-series',
|
||||||
|
label: 'Gemini Flash Series',
|
||||||
|
tokenType: null,
|
||||||
|
remainingFraction: 0.72,
|
||||||
|
remainingPercent: 72,
|
||||||
|
resetTime: null,
|
||||||
|
modelIds: ['gemini-flash'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
projectId: null,
|
||||||
|
lastUpdated: 1,
|
||||||
|
accountId: 'gemini@example.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(text).toContain('72% remaining');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user