diff --git a/src/domain/quotaCache.ts b/src/domain/quotaCache.ts index e89f0849f5..616859da23 100644 --- a/src/domain/quotaCache.ts +++ b/src/domain/quotaCache.ts @@ -101,7 +101,8 @@ function clampPercent(value: number): number { return Math.max(0, Math.min(100, value)); } -function normalizeWindowKey(value: string): string { +function normalizeWindowKey(value: unknown): string { + if (typeof value !== "string") return ""; return value .toLowerCase() .replace(/[^a-z0-9]+/g, " ") @@ -118,13 +119,22 @@ function resolveQuotaWindow( const normalizedTarget = normalizeWindowKey(windowName); if (!normalizedTarget) return null; + const prefixMatches: Array<{ key: string; quota: QuotaInfo }> = []; for (const [key, quota] of Object.entries(quotas)) { const normalizedKey = normalizeWindowKey(key); if (!normalizedKey) continue; if (normalizedKey === normalizedTarget) return quota; // Support canonical selection of generic windows from labeled windows, // e.g. "weekly" from "weekly (7d)" or "session" from "session (5h)". - if (normalizedKey.startsWith(`${normalizedTarget} `)) return quota; + if (normalizedKey.startsWith(`${normalizedTarget} `)) { + prefixMatches.push({ key, quota }); + } + } + + // Deterministic fallback: choose the lexicographically first matching key. + if (prefixMatches.length > 0) { + prefixMatches.sort((a, b) => a.key.localeCompare(b.key)); + return prefixMatches[0].quota; } return null; diff --git a/src/sse/services/auth.ts b/src/sse/services/auth.ts index e77916c413..97ca748d7d 100644 --- a/src/sse/services/auth.ts +++ b/src/sse/services/auth.ts @@ -136,7 +136,8 @@ function uniqueWindows(windows: string[]): string[] { return [...new Set(windows)]; } -function normalizeCodexWindowName(windowName: string): string { +function normalizeCodexWindowName(windowName: unknown): string | null { + if (typeof windowName !== "string") return null; const normalized = windowName.trim().toLowerCase(); if (normalized === "session (5h)" || normalized === "5h" || normalized === "five_hour") { return "session"; @@ -149,7 +150,7 @@ function normalizeCodexWindowName(windowName: string): string { function applyCodexWindowPolicy(rawWindows: string[], providerSpecificData: JsonRecord): string[] { const codexPolicy = getCodexLimitPolicy(providerSpecificData); - const normalizedRaw = rawWindows.map(normalizeCodexWindowName).filter(Boolean); + const normalizedRaw = rawWindows.map(normalizeCodexWindowName).filter(Boolean) as string[]; // Preserve explicitly configured custom windows, but enforce canonical Codex windows // from toggles so weekly exhaustion is never skipped when useWeekly=true.