fix(cliproxy): fall back from invalid Codex feature labels

This commit is contained in:
Tam Nhu Tran
2026-05-30 15:38:50 -04:00
parent 457412277b
commit a0870aa404
3 changed files with 40 additions and 17 deletions
+7 -3
View File
@@ -11,8 +11,8 @@ const TERMINAL_CONTROL_CHARS_REGEX = /[\u0000-\u001f\u007f-\u009f]/g;
* labels must be constrained to safe, printable strings before they reach the * labels must be constrained to safe, printable strings before they reach the
* terminal. * terminal.
*/ */
export function sanitizeCodexFeatureLabel(value: unknown): string { export function sanitizeCodexFeatureLabelOrNull(value: unknown): string | null {
if (typeof value !== 'string') return CODEX_FEATURE_LABEL_FALLBACK; if (typeof value !== 'string') return null;
const sanitized = value const sanitized = value
.replace(TERMINAL_ESCAPE_SEQUENCE_REGEX, '') .replace(TERMINAL_ESCAPE_SEQUENCE_REGEX, '')
@@ -21,5 +21,9 @@ export function sanitizeCodexFeatureLabel(value: unknown): string {
.slice(0, CODEX_FEATURE_LABEL_MAX_LENGTH) .slice(0, CODEX_FEATURE_LABEL_MAX_LENGTH)
.trimEnd(); .trimEnd();
return sanitized.length > 0 ? sanitized : CODEX_FEATURE_LABEL_FALLBACK; return sanitized.length > 0 ? sanitized : null;
}
export function sanitizeCodexFeatureLabel(value: unknown): string {
return sanitizeCodexFeatureLabelOrNull(value) ?? CODEX_FEATURE_LABEL_FALLBACK;
} }
+11 -5
View File
@@ -18,7 +18,10 @@ import {
} from '../../cliproxy/accounts/account-manager'; } from '../../cliproxy/accounts/account-manager';
import { fetchAllProviderQuotas } from '../../cliproxy/quota/quota-fetcher'; import { fetchAllProviderQuotas } from '../../cliproxy/quota/quota-fetcher';
import { fetchAllCodexQuotas } from '../../cliproxy/quota/quota-fetcher-codex'; import { fetchAllCodexQuotas } from '../../cliproxy/quota/quota-fetcher-codex';
import { sanitizeCodexFeatureLabel } from '../../cliproxy/quota/quota-label-sanitizer'; import {
sanitizeCodexFeatureLabel,
sanitizeCodexFeatureLabelOrNull,
} from '../../cliproxy/quota/quota-label-sanitizer';
import { fetchAllClaudeQuotas } from '../../cliproxy/quota/quota-fetcher-claude'; import { fetchAllClaudeQuotas } from '../../cliproxy/quota/quota-fetcher-claude';
import { pickMostRestrictiveClaudeWeeklyWindow } from '../../cliproxy/quota/quota-fetcher-claude-normalizer'; import { pickMostRestrictiveClaudeWeeklyWindow } from '../../cliproxy/quota/quota-fetcher-claude-normalizer';
import { fetchAllGeminiCliQuotas } from '../../cliproxy/quota/quota-fetcher-gemini-cli'; import { fetchAllGeminiCliQuotas } from '../../cliproxy/quota/quota-fetcher-gemini-cli';
@@ -280,9 +283,12 @@ function inferCodeReviewCadence(
* Strip a leading "GPT-X.Y-Codex-" prefix from a feature label and turn the * Strip a leading "GPT-X.Y-Codex-" prefix from a feature label and turn the
* remainder into a Codex-prefixed display name. Other labels pass through unchanged. * remainder into a Codex-prefixed display name. Other labels pass through unchanged.
*/ */
function prettifyCodexFeatureLabel(featureLabel: unknown): string { function prettifyCodexFeatureLabel(featureLabel: unknown, fallbackLabel?: unknown): string {
const trimmed = sanitizeCodexFeatureLabel(featureLabel); const trimmed =
if (!trimmed) return 'Additional'; sanitizeCodexFeatureLabelOrNull(featureLabel) ??
(fallbackLabel === undefined
? sanitizeCodexFeatureLabel(featureLabel)
: sanitizeCodexFeatureLabel(fallbackLabel));
const stripped = trimmed.replace(/^GPT-[\d.]+-Codex-/i, ''); const stripped = trimmed.replace(/^GPT-[\d.]+-Codex-/i, '');
if (stripped !== trimmed && stripped.length > 0) { if (stripped !== trimmed && stripped.length > 0) {
return `Codex ${stripped}`; return `Codex ${stripped}`;
@@ -303,7 +309,7 @@ function getCodexWindowDisplayLabel(
} }
if (window.category === 'additional') { if (window.category === 'additional') {
const pretty = prettifyCodexFeatureLabel(window.featureLabel ?? window.label); const pretty = prettifyCodexFeatureLabel(window.featureLabel, window.label);
if (window.cadence === '5h') return `${pretty} (5h)`; if (window.cadence === '5h') return `${pretty} (5h)`;
if (window.cadence === 'weekly') return `${pretty} (weekly)`; if (window.cadence === 'weekly') return `${pretty} (weekly)`;
return pretty; return pretty;
@@ -86,18 +86,31 @@ describe('cliproxy quota subcommand failure formatting', () => {
}); });
describe('cliproxy quota subcommand Codex label formatting', () => { describe('cliproxy quota subcommand Codex label formatting', () => {
it('falls back for non-string cached Codex feature labels', async () => { it('falls back to the cached window label for invalid Codex feature labels', async () => {
const { getCodexWindowDisplayLabel } = await loadQuotaCommandTestExports(); const { getCodexWindowDisplayLabel } = await loadQuotaCommandTestExports();
const label = getCodexWindowDisplayLabel({ const cases = [
label: 'ignored', { featureLabel: '', cadence: '5h', expected: 'Codex Spark (5h)' },
resetAfterSeconds: 3600, { featureLabel: ' ', cadence: 'weekly', expected: 'Codex Spark (weekly)' },
category: 'additional', {
cadence: '5h', featureLabel: '\u001b[2J\u001b]52;c;payload\u0007',
featureLabel: { unexpected: true }, cadence: '5h',
} as never); expected: 'Codex Spark (5h)',
},
{ featureLabel: { unexpected: true }, cadence: '5h', expected: 'Codex Spark (5h)' },
] as const;
expect(label).toBe('Additional (5h)'); for (const { featureLabel, cadence, expected } of cases) {
const label = getCodexWindowDisplayLabel({
label: 'GPT-5.3-Codex-Spark',
resetAfterSeconds: 3600,
category: 'additional',
cadence,
featureLabel,
} as never);
expect(label).toBe(expected);
}
}); });
it('removes terminal control characters from cached Codex feature labels', async () => { it('removes terminal control characters from cached Codex feature labels', async () => {