From 1d2ee827fe38204d8d4ceb376c604abcff130836 Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Sat, 14 Feb 2026 06:09:36 +0700 Subject: [PATCH] fix(codex): infer code review cadence from reset window --- src/commands/cliproxy/quota-subcommand.ts | 34 ++++++++++++++++--- .../shared/quota-tooltip-content.tsx | 2 +- ui/src/lib/utils.ts | 32 ++++++++++++++++- ui/tests/unit/ui/lib/quota-utils.test.ts | 29 ++++++++++++++++ 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/commands/cliproxy/quota-subcommand.ts b/src/commands/cliproxy/quota-subcommand.ts index 38a09c43..683e863a 100644 --- a/src/commands/cliproxy/quota-subcommand.ts +++ b/src/commands/cliproxy/quota-subcommand.ts @@ -103,20 +103,46 @@ function getCodexWindowKind(label: string): CodexWindowKind { return 'unknown'; } -function getCodexWindowDisplayLabel(label: string): string { - switch (getCodexWindowKind(label)) { +function getCodexWindowCadence( + resetAfterSeconds: number | null | undefined +): '5h' | 'weekly' | null { + if ( + typeof resetAfterSeconds !== 'number' || + !isFinite(resetAfterSeconds) || + resetAfterSeconds <= 0 + ) { + return null; + } + + if (resetAfterSeconds <= 6 * 60 * 60) return '5h'; + if (resetAfterSeconds >= 24 * 60 * 60) return 'weekly'; + return null; +} + +function getCodexWindowDisplayLabel( + window: Pick +): string { + const cadence = getCodexWindowCadence(window.resetAfterSeconds); + + switch (getCodexWindowKind(window.label)) { case 'usage-5h': + if (cadence === 'weekly') return 'Weekly usage limit'; return '5h usage limit'; case 'usage-weekly': + if (cadence === '5h') return '5h usage limit'; return 'Weekly usage limit'; case 'code-review-5h': + if (cadence === 'weekly') return 'Code review (weekly)'; return 'Code review (5h)'; case 'code-review-weekly': + if (cadence === '5h') return 'Code review (5h)'; return 'Code review (weekly)'; case 'code-review': + if (cadence === '5h') return 'Code review (5h)'; + if (cadence === 'weekly') return 'Code review (weekly)'; return 'Code review'; case 'unknown': - return label; + return window.label; } } @@ -255,7 +281,7 @@ function displayCodexQuotaSection(results: { account: string; quota: CodexQuotaR ? dim(` Resets ${formatResetTime(window.resetAfterSeconds)}`) : ''; console.log( - ` ${getCodexWindowDisplayLabel(window.label).padEnd(24)} ${bar} ${window.remainingPercent.toFixed(0)}%${resetLabel}` + ` ${getCodexWindowDisplayLabel(window).padEnd(24)} ${bar} ${window.remainingPercent.toFixed(0)}%${resetLabel}` ); } console.log(''); diff --git a/ui/src/components/shared/quota-tooltip-content.tsx b/ui/src/components/shared/quota-tooltip-content.tsx index 01826405..27ff1c3a 100644 --- a/ui/src/components/shared/quota-tooltip-content.tsx +++ b/ui/src/components/shared/quota-tooltip-content.tsx @@ -87,7 +87,7 @@ export function QuotaTooltipContent({ quota, resetTime }: QuotaTooltipContentPro className="flex justify-between gap-4" > - {getCodexWindowDisplayLabel(w.label)} + {getCodexWindowDisplayLabel(w)} {w.remainingPercent}% diff --git a/ui/src/lib/utils.ts b/ui/src/lib/utils.ts index 9959eb71..81387cea 100644 --- a/ui/src/lib/utils.ts +++ b/ui/src/lib/utils.ts @@ -337,17 +337,47 @@ export function getCodexWindowKind(label: string): CodexWindowKind { /** * Convert raw Codex window labels into user-facing labels. */ -export function getCodexWindowDisplayLabel(label: string): string { +function getCodexWindowCadence( + resetAfterSeconds: number | null | undefined +): '5h' | 'weekly' | null { + if ( + typeof resetAfterSeconds !== 'number' || + !isFinite(resetAfterSeconds) || + resetAfterSeconds <= 0 + ) { + return null; + } + + if (resetAfterSeconds <= 6 * 60 * 60) return '5h'; + if (resetAfterSeconds >= 24 * 60 * 60) return 'weekly'; + return null; +} + +export function getCodexWindowDisplayLabel( + labelOrWindow: string | Pick, + resetAfterSecondsOverride?: number | null +): string { + const label = typeof labelOrWindow === 'string' ? labelOrWindow : labelOrWindow.label; + const cadence = getCodexWindowCadence( + typeof labelOrWindow === 'string' ? resetAfterSecondsOverride : labelOrWindow.resetAfterSeconds + ); + switch (getCodexWindowKind(label)) { case 'usage-5h': + if (cadence === 'weekly') return 'Weekly usage limit'; return '5h usage limit'; case 'usage-weekly': + if (cadence === '5h') return '5h usage limit'; return 'Weekly usage limit'; case 'code-review-5h': + if (cadence === 'weekly') return 'Code review (weekly)'; return 'Code review (5h)'; case 'code-review-weekly': + if (cadence === '5h') return 'Code review (5h)'; return 'Code review (weekly)'; case 'code-review': + if (cadence === '5h') return 'Code review (5h)'; + if (cadence === 'weekly') return 'Code review (weekly)'; return 'Code review'; case 'unknown': return label; diff --git a/ui/tests/unit/ui/lib/quota-utils.test.ts b/ui/tests/unit/ui/lib/quota-utils.test.ts index 7735c853..338d5c17 100644 --- a/ui/tests/unit/ui/lib/quota-utils.test.ts +++ b/ui/tests/unit/ui/lib/quota-utils.test.ts @@ -9,6 +9,7 @@ import { getEarliestResetTime, getMinCodexQuota, getCodexResetTime, + getCodexWindowDisplayLabel, getMinGeminiQuota, getGeminiResetTime, getProviderMinQuota, @@ -526,6 +527,34 @@ describe('getCodexResetTime', () => { }); }); +describe('getCodexWindowDisplayLabel', () => { + it('labels code review primary window as weekly when reset cadence is weekly', () => { + expect( + getCodexWindowDisplayLabel({ + label: 'Code Review (Primary)', + resetAfterSeconds: 604800, + }) + ).toBe('Code review (weekly)'); + }); + + it('labels code review primary window as 5h when reset cadence is short', () => { + expect( + getCodexWindowDisplayLabel({ + label: 'Code Review (Primary)', + resetAfterSeconds: 18000, + }) + ).toBe('Code review (5h)'); + }); + + it('keeps secondary usage label as weekly by default', () => { + expect(getCodexWindowDisplayLabel('Secondary')).toBe('Weekly usage limit'); + }); + + it('uses cadence override when provided with string label', () => { + expect(getCodexWindowDisplayLabel('Primary', 604800)).toBe('Weekly usage limit'); + }); +}); + // ==================== Gemini Quota Functions ==================== describe('getMinGeminiQuota', () => {