@coseung2/opencodex 2.8.0-cs.12 → 2.8.0-cs.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/gui/dist/assets/index-MUpaVatk.js +67 -0
- package/gui/dist/index.html +1 -1
- package/package.json +3 -3
- package/packages/ocx-notch/README.md +3 -2
- package/src/adapters/cursor/discovery.ts +6 -2
- package/src/adapters/cursor/effort-map.ts +3 -0
- package/src/adapters/google-antigravity-replay.ts +24 -0
- package/src/adapters/google.ts +16 -11
- package/src/chat/inbound.ts +5 -11
- package/src/cli/account-api.ts +9 -1
- package/src/cli/account-extended.ts +4 -1
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +12 -1
- package/src/codex/account-namespaces.ts +21 -0
- package/src/codex/account-priority.ts +49 -0
- package/src/codex/account-store.ts +73 -10
- package/src/codex/auth-api.ts +312 -45
- package/src/codex/auth-context.ts +61 -16
- package/src/codex/catalog/metadata.ts +34 -12
- package/src/codex/catalog/parsing.ts +8 -1
- package/src/codex/catalog/provider-fetch.ts +24 -6
- package/src/codex/catalog.ts +1 -1
- package/src/codex/pool-rotation.ts +51 -4
- package/src/codex/quota.ts +154 -35
- package/src/codex/routing.ts +133 -33
- package/src/codex/warmup.ts +204 -82
- package/src/config.ts +84 -1
- package/src/lib/bounded-body.ts +13 -6
- package/src/lib/bun-stream-caps.ts +5 -6
- package/src/lib/redact.ts +13 -0
- package/src/oauth/index.ts +79 -12
- package/src/oauth/log.ts +3 -1
- package/src/oauth/store.ts +31 -8
- package/src/oauth/token-guardian.ts +130 -9
- package/src/providers/antigravity-models.ts +53 -24
- package/src/providers/codex-capacity.ts +303 -0
- package/src/providers/model-rename-migration.ts +147 -0
- package/src/providers/model-rename-startup.ts +29 -0
- package/src/providers/quota.ts +126 -16
- package/src/providers/registry.ts +262 -38
- package/src/responses/parser.ts +19 -12
- package/src/responses/spill-store.ts +14 -1
- package/src/responses/state.ts +108 -14
- package/src/router.ts +6 -0
- package/src/server/index.ts +9 -1
- package/src/server/management/logs-usage-routes.ts +1 -0
- package/src/server/management/oauth-account-routes.ts +8 -1
- package/src/server/relay.ts +10 -42
- package/src/server/request-log.ts +42 -1
- package/src/server/responses/compact.ts +16 -4
- package/src/server/responses/core.ts +217 -59
- package/src/server/responses/empty-completion-guard.ts +275 -0
- package/src/server/responses/encrypted-payload.ts +54 -39
- package/src/server/responses/fetch-helpers.ts +24 -3
- package/src/server/responses/ws-upstream.ts +318 -0
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/ws-bridge.ts +17 -11
- package/src/types.ts +13 -1
- package/src/usage/log.ts +24 -0
- package/src/usage/summary.ts +152 -2
- package/vendor/ocx-notch/win32-x64/ocx-notch.exe +0 -0
- package/gui/dist/assets/index-GgF1IpQa.js +0 -67
package/src/codex/quota.ts
CHANGED
|
@@ -4,7 +4,9 @@ import { atomicWriteFile, getConfigDir } from "../config";
|
|
|
4
4
|
import { captureConfigGeneration, type GenerationContext } from "../lib/state-store-sweeper";
|
|
5
5
|
|
|
6
6
|
export type StoredAccountQuota = {
|
|
7
|
+
fiveHourPercent?: number;
|
|
7
8
|
weeklyPercent?: number;
|
|
9
|
+
fiveHourResetAt?: number;
|
|
8
10
|
monthlyPercent?: number;
|
|
9
11
|
weeklyResetAt?: number;
|
|
10
12
|
monthlyResetAt?: number;
|
|
@@ -41,13 +43,15 @@ export type WhamUsageResponse = {
|
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
type WhamUsageWindow = {
|
|
44
|
-
used_percent?: number;
|
|
45
|
-
reset_at?: number;
|
|
46
|
-
limit_window_seconds?: number;
|
|
46
|
+
used_percent?: number | string | null;
|
|
47
|
+
reset_at?: number | string | null;
|
|
48
|
+
limit_window_seconds?: number | string | null;
|
|
47
49
|
};
|
|
48
50
|
|
|
49
51
|
const MONTHLY_WINDOW_MIN_SECONDS = 28 * 24 * 60 * 60;
|
|
50
52
|
const MONTHLY_WINDOW_MIN_MINUTES = MONTHLY_WINDOW_MIN_SECONDS / 60;
|
|
53
|
+
const FIVE_HOUR_WINDOW_MIN_SECONDS = 2 * 60 * 60;
|
|
54
|
+
const FIVE_HOUR_WINDOW_MAX_SECONDS = 12 * 60 * 60;
|
|
51
55
|
|
|
52
56
|
const accountQuota = new Map<string, StoredAccountQuota>();
|
|
53
57
|
let lastReconciledGeneration = 0;
|
|
@@ -62,15 +66,26 @@ function mayCommitAccountQuota(accountId: string, writerGeneration: number): boo
|
|
|
62
66
|
export const CODEX_UNKNOWN_USAGE_SCORE = 101;
|
|
63
67
|
export const CODEX_EXHAUSTED_USAGE_PERCENT = 100;
|
|
64
68
|
|
|
69
|
+
/** Plans whose WHAM payloads expose a separate rolling five-hour window. */
|
|
70
|
+
export function isCodexFiveHourQuotaPlan(plan: string | null | undefined): boolean {
|
|
71
|
+
const normalized = plan?.trim().toLowerCase();
|
|
72
|
+
// Business is the current name for the older Team workspace plan.
|
|
73
|
+
return normalized === "plus" || normalized === "team" || normalized === "business";
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
export function isCodexQuotaExhausted(
|
|
66
|
-
quota: Pick<StoredAccountQuota, "weeklyPercent" | "monthlyPercent"> | null,
|
|
77
|
+
quota: Pick<StoredAccountQuota, "fiveHourPercent" | "weeklyPercent" | "monthlyPercent"> | null,
|
|
67
78
|
plan?: string | null,
|
|
68
79
|
): boolean {
|
|
69
80
|
if (!quota) return false;
|
|
70
81
|
const normalizedPlan = plan?.trim().toLowerCase();
|
|
71
82
|
const values = normalizedPlan === "go" || normalizedPlan === "free"
|
|
72
83
|
? [quota.monthlyPercent]
|
|
73
|
-
: [
|
|
84
|
+
: [
|
|
85
|
+
...(isCodexFiveHourQuotaPlan(plan) ? [quota.fiveHourPercent] : []),
|
|
86
|
+
quota.weeklyPercent,
|
|
87
|
+
quota.monthlyPercent,
|
|
88
|
+
];
|
|
74
89
|
return values.some(value => typeof value === "number"
|
|
75
90
|
&& Number.isFinite(value)
|
|
76
91
|
&& value >= CODEX_EXHAUSTED_USAGE_PERCENT);
|
|
@@ -97,15 +112,23 @@ function normalizeResetAt(value: unknown): number | undefined {
|
|
|
97
112
|
}
|
|
98
113
|
|
|
99
114
|
function hasKnownQuotaValue(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
|
|
100
|
-
return [quota.weeklyPercent, quota.monthlyPercent]
|
|
115
|
+
return [quota.fiveHourPercent, quota.weeklyPercent, quota.monthlyPercent]
|
|
101
116
|
.some(value => typeof value === "number" && Number.isFinite(value));
|
|
102
117
|
}
|
|
103
118
|
|
|
119
|
+
function windowDurationSeconds(window: WhamUsageWindow | null | undefined): number | undefined {
|
|
120
|
+
const raw: unknown = window?.limit_window_seconds;
|
|
121
|
+
const seconds = typeof raw === "number"
|
|
122
|
+
? raw
|
|
123
|
+
: typeof raw === "string" && raw.trim() !== ""
|
|
124
|
+
? Number(raw)
|
|
125
|
+
: undefined;
|
|
126
|
+
return typeof seconds === "number" && Number.isFinite(seconds) && seconds > 0 ? seconds : undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
104
129
|
function isExplicitMonthlyWindow(window: WhamUsageWindow | null | undefined): boolean {
|
|
105
|
-
const seconds = window
|
|
106
|
-
return
|
|
107
|
-
&& Number.isFinite(seconds)
|
|
108
|
-
&& seconds >= MONTHLY_WINDOW_MIN_SECONDS;
|
|
130
|
+
const seconds = windowDurationSeconds(window);
|
|
131
|
+
return seconds !== undefined && seconds >= MONTHLY_WINDOW_MIN_SECONDS;
|
|
109
132
|
}
|
|
110
133
|
|
|
111
134
|
function isExplicitMonthlyWindowMinutes(windowMinutes: unknown): boolean {
|
|
@@ -119,17 +142,39 @@ function isExplicitMonthlyWindowMinutes(windowMinutes: unknown): boolean {
|
|
|
119
142
|
&& minutes >= MONTHLY_WINDOW_MIN_MINUTES;
|
|
120
143
|
}
|
|
121
144
|
|
|
145
|
+
function isExplicitFiveHourWindow(window: WhamUsageWindow | null | undefined): boolean {
|
|
146
|
+
const seconds = windowDurationSeconds(window);
|
|
147
|
+
return seconds !== undefined
|
|
148
|
+
&& seconds >= FIVE_HOUR_WINDOW_MIN_SECONDS
|
|
149
|
+
&& seconds <= FIVE_HOUR_WINDOW_MAX_SECONDS;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function isExplicitFiveHourWindowMinutes(windowMinutes: unknown): boolean {
|
|
153
|
+
const minutes = typeof windowMinutes === "number"
|
|
154
|
+
? windowMinutes
|
|
155
|
+
: typeof windowMinutes === "string" && windowMinutes.trim() !== ""
|
|
156
|
+
? Number(windowMinutes)
|
|
157
|
+
: undefined;
|
|
158
|
+
return typeof minutes === "number"
|
|
159
|
+
&& Number.isFinite(minutes)
|
|
160
|
+
&& minutes >= FIVE_HOUR_WINDOW_MIN_SECONDS / 60
|
|
161
|
+
&& minutes <= FIVE_HOUR_WINDOW_MAX_SECONDS / 60;
|
|
162
|
+
}
|
|
122
163
|
|
|
123
164
|
function snapshotHasWeekly(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
|
|
124
165
|
return quota.weeklyPercent !== undefined || quota.weeklyResetAt !== undefined;
|
|
125
166
|
}
|
|
126
167
|
|
|
168
|
+
function snapshotHasFiveHour(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
|
|
169
|
+
return quota.fiveHourPercent !== undefined || quota.fiveHourResetAt !== undefined;
|
|
170
|
+
}
|
|
171
|
+
|
|
127
172
|
function snapshotHasMonthly(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
|
|
128
173
|
return quota.monthlyPercent !== undefined || quota.monthlyResetAt !== undefined;
|
|
129
174
|
}
|
|
130
175
|
|
|
131
176
|
function snapshotHasUsage(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
|
|
132
|
-
return snapshotHasWeekly(quota) || snapshotHasMonthly(quota);
|
|
177
|
+
return snapshotHasFiveHour(quota) || snapshotHasWeekly(quota) || snapshotHasMonthly(quota);
|
|
133
178
|
}
|
|
134
179
|
export function setAccountQuotaFromParsed(
|
|
135
180
|
accountId: string,
|
|
@@ -143,6 +188,8 @@ export function setAccountQuotaFromParsed(
|
|
|
143
188
|
const creditsOnly = quota.resetCredits !== undefined && !snapshotHasUsage(quota);
|
|
144
189
|
|
|
145
190
|
if (creditsOnly) {
|
|
191
|
+
if (existing?.fiveHourPercent !== undefined) next.fiveHourPercent = existing.fiveHourPercent;
|
|
192
|
+
if (existing?.fiveHourResetAt !== undefined) next.fiveHourResetAt = existing.fiveHourResetAt;
|
|
146
193
|
if (existing?.weeklyPercent !== undefined) next.weeklyPercent = existing.weeklyPercent;
|
|
147
194
|
if (existing?.weeklyResetAt !== undefined) next.weeklyResetAt = existing.weeklyResetAt;
|
|
148
195
|
if (existing?.monthlyPercent !== undefined) next.monthlyPercent = existing.monthlyPercent;
|
|
@@ -153,20 +200,32 @@ export function setAccountQuotaFromParsed(
|
|
|
153
200
|
return;
|
|
154
201
|
}
|
|
155
202
|
|
|
156
|
-
|
|
203
|
+
const hasFiveHour = snapshotHasFiveHour(quota);
|
|
204
|
+
const hasWeekly = snapshotHasWeekly(quota);
|
|
205
|
+
const hasMonthly = snapshotHasMonthly(quota);
|
|
206
|
+
|
|
207
|
+
if (hasFiveHour) {
|
|
208
|
+
if (quota.fiveHourPercent !== undefined) next.fiveHourPercent = quota.fiveHourPercent;
|
|
209
|
+
if (quota.fiveHourResetAt !== undefined) next.fiveHourResetAt = quota.fiveHourResetAt;
|
|
210
|
+
// A five-hour-only response can be a partial snapshot; retain a known
|
|
211
|
+
// weekly value until a later response supplies that window.
|
|
212
|
+
if (!hasWeekly && existing?.weeklyPercent !== undefined) {
|
|
213
|
+
next.weeklyPercent = existing.weeklyPercent;
|
|
214
|
+
if (existing.weeklyResetAt !== undefined) next.weeklyResetAt = existing.weeklyResetAt;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (hasWeekly) {
|
|
157
219
|
if (quota.weeklyPercent !== undefined) next.weeklyPercent = quota.weeklyPercent;
|
|
158
220
|
if (quota.weeklyResetAt !== undefined) next.weeklyResetAt = quota.weeklyResetAt;
|
|
159
|
-
} else if (
|
|
221
|
+
} else if (hasMonthly && !hasFiveHour) {
|
|
160
222
|
// Monthly-only snapshots intentionally clear stale weekly values (issue #382).
|
|
161
|
-
} else if (existing?.weeklyPercent !== undefined) {
|
|
162
|
-
next.weeklyPercent = existing.weeklyPercent;
|
|
163
|
-
if (existing.weeklyResetAt !== undefined) next.weeklyResetAt = existing.weeklyResetAt;
|
|
164
223
|
}
|
|
165
224
|
|
|
166
|
-
if (
|
|
225
|
+
if (hasMonthly) {
|
|
167
226
|
if (quota.monthlyPercent !== undefined) next.monthlyPercent = quota.monthlyPercent;
|
|
168
227
|
if (quota.monthlyResetAt !== undefined) next.monthlyResetAt = quota.monthlyResetAt;
|
|
169
|
-
} else if (
|
|
228
|
+
} else if ((hasWeekly || hasFiveHour) && existing?.monthlyPercent !== undefined) {
|
|
170
229
|
next.monthlyPercent = existing.monthlyPercent;
|
|
171
230
|
if (existing.monthlyResetAt !== undefined) next.monthlyResetAt = existing.monthlyResetAt;
|
|
172
231
|
}
|
|
@@ -178,7 +237,10 @@ export function setAccountQuotaFromParsed(
|
|
|
178
237
|
schedulePersistAccountQuotas();
|
|
179
238
|
}
|
|
180
239
|
|
|
181
|
-
export function parseUpstreamQuotaHeaders(
|
|
240
|
+
export function parseUpstreamQuotaHeaders(
|
|
241
|
+
headers: Headers,
|
|
242
|
+
plan?: string | null,
|
|
243
|
+
): Omit<StoredAccountQuota, "updatedAt"> | null {
|
|
182
244
|
const primaryRaw = headers.get("x-codex-primary-used-percent");
|
|
183
245
|
const secondaryRaw = headers.get("x-codex-secondary-used-percent");
|
|
184
246
|
const tertiaryRaw = headers.get("x-codex-tertiary-used-percent");
|
|
@@ -196,25 +258,52 @@ export function parseUpstreamQuotaHeaders(headers: Headers): Omit<StoredAccountQ
|
|
|
196
258
|
const secondaryResetAt = normalizeResetAt(secondaryResetRaw);
|
|
197
259
|
const tertiaryResetAt = normalizeResetAt(tertiaryResetRaw);
|
|
198
260
|
const primaryIsMonthly = primaryRaw !== null && isExplicitMonthlyWindowMinutes(primaryWindowMinutes);
|
|
261
|
+
const trackFiveHour = plan == null || isCodexFiveHourQuotaPlan(plan);
|
|
262
|
+
const primaryIsFiveHour = trackFiveHour && primaryRaw !== null && isExplicitFiveHourWindowMinutes(primaryWindowMinutes);
|
|
263
|
+
const secondaryIsFiveHour = trackFiveHour && secondaryRaw !== null && isExplicitFiveHourWindowMinutes(secondaryWindowMinutes);
|
|
199
264
|
|
|
200
265
|
if (primaryIsMonthly) {
|
|
201
266
|
if (primaryPercent !== undefined) {
|
|
202
267
|
quota.monthlyPercent = primaryPercent;
|
|
203
268
|
if (primaryResetAt !== undefined) quota.monthlyResetAt = primaryResetAt;
|
|
204
269
|
}
|
|
205
|
-
if (secondaryPercent !== undefined) {
|
|
270
|
+
if (secondaryIsFiveHour && secondaryPercent !== undefined) {
|
|
271
|
+
quota.fiveHourPercent = secondaryPercent;
|
|
272
|
+
if (secondaryResetAt !== undefined) quota.fiveHourResetAt = secondaryResetAt;
|
|
273
|
+
} else if (secondaryPercent !== undefined) {
|
|
206
274
|
quota.weeklyPercent = secondaryPercent;
|
|
207
275
|
if (secondaryResetAt !== undefined) quota.weeklyResetAt = secondaryResetAt;
|
|
208
276
|
}
|
|
209
277
|
} else {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
278
|
+
if (primaryIsFiveHour && primaryPercent !== undefined) {
|
|
279
|
+
quota.fiveHourPercent = primaryPercent;
|
|
280
|
+
if (primaryResetAt !== undefined) quota.fiveHourResetAt = primaryResetAt;
|
|
281
|
+
}
|
|
282
|
+
if (secondaryIsFiveHour && secondaryPercent !== undefined) {
|
|
283
|
+
quota.fiveHourPercent ??= secondaryPercent;
|
|
284
|
+
if (quota.fiveHourResetAt === undefined && secondaryResetAt !== undefined) {
|
|
285
|
+
quota.fiveHourResetAt = secondaryResetAt;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const weeklyPercent = primaryIsFiveHour ? secondaryPercent : primaryPercent ?? secondaryPercent;
|
|
289
|
+
const weeklyResetAt = primaryIsFiveHour
|
|
290
|
+
? secondaryResetAt
|
|
291
|
+
: primaryPercent !== undefined ? primaryResetAt : secondaryResetAt;
|
|
214
292
|
if (weeklyPercent !== undefined) {
|
|
215
293
|
quota.weeklyPercent = weeklyPercent;
|
|
216
294
|
if (weeklyResetAt !== undefined) quota.weeklyResetAt = weeklyResetAt;
|
|
217
295
|
}
|
|
296
|
+
if (trackFiveHour
|
|
297
|
+
&& !primaryIsFiveHour
|
|
298
|
+
&& primaryPercent !== undefined
|
|
299
|
+
&& secondaryPercent !== undefined
|
|
300
|
+
&& primaryWindowMinutes === null
|
|
301
|
+
&& secondaryWindowMinutes === null) {
|
|
302
|
+
quota.fiveHourPercent = primaryPercent;
|
|
303
|
+
if (primaryResetAt !== undefined) quota.fiveHourResetAt = primaryResetAt;
|
|
304
|
+
quota.weeklyPercent = secondaryPercent;
|
|
305
|
+
if (secondaryResetAt !== undefined) quota.weeklyResetAt = secondaryResetAt;
|
|
306
|
+
}
|
|
218
307
|
}
|
|
219
308
|
|
|
220
309
|
if (tertiaryPercent !== undefined && quota.monthlyPercent === undefined) {
|
|
@@ -229,8 +318,9 @@ export function applyAccountQuotaFromUpstreamHeaders(
|
|
|
229
318
|
accountId: string,
|
|
230
319
|
headers: Headers,
|
|
231
320
|
writerGeneration = captureConfigGeneration(),
|
|
321
|
+
plan?: string | null,
|
|
232
322
|
): void {
|
|
233
|
-
const quota = parseUpstreamQuotaHeaders(headers);
|
|
323
|
+
const quota = parseUpstreamQuotaHeaders(headers, plan);
|
|
234
324
|
if (!quota) return;
|
|
235
325
|
setAccountQuotaFromParsed(accountId, quota, writerGeneration);
|
|
236
326
|
}
|
|
@@ -251,7 +341,9 @@ export function updateAccountQuota(
|
|
|
251
341
|
if (nextWeekly === undefined && nextMonthly === undefined && resetCredits === undefined) return;
|
|
252
342
|
|
|
253
343
|
const quota: StoredAccountQuota = {
|
|
344
|
+
...(existing?.fiveHourPercent !== undefined ? { fiveHourPercent: existing.fiveHourPercent } : {}),
|
|
254
345
|
...(existing?.weeklyPercent !== undefined ? { weeklyPercent: existing.weeklyPercent } : {}),
|
|
346
|
+
...(existing?.fiveHourResetAt !== undefined ? { fiveHourResetAt: existing.fiveHourResetAt } : {}),
|
|
255
347
|
...(existing?.monthlyPercent !== undefined ? { monthlyPercent: existing.monthlyPercent } : {}),
|
|
256
348
|
...(existing?.weeklyResetAt !== undefined ? { weeklyResetAt: existing.weeklyResetAt } : {}),
|
|
257
349
|
...(existing?.monthlyResetAt !== undefined ? { monthlyResetAt: existing.monthlyResetAt } : {}),
|
|
@@ -378,20 +470,43 @@ export function parseUsageQuota(data: WhamUsageResponse): Omit<StoredAccountQuot
|
|
|
378
470
|
const secondaryResetAt = normalizeResetAt(secondaryWindow?.reset_at);
|
|
379
471
|
const tertiaryResetAt = normalizeResetAt(tertiaryWindow?.reset_at);
|
|
380
472
|
const primaryIsMonthly = isExplicitMonthlyWindow(primaryWindow);
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
//
|
|
385
|
-
//
|
|
386
|
-
//
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const weeklyPercent = primaryIsMonthly ? secondaryPercent : primaryPercent ?? secondaryPercent;
|
|
390
|
-
const weeklyResetAt = primaryIsMonthly
|
|
473
|
+
const primaryIsFiveHour = isExplicitFiveHourWindow(primaryWindow);
|
|
474
|
+
const secondaryIsFiveHour = isExplicitFiveHourWindow(secondaryWindow);
|
|
475
|
+
|
|
476
|
+
// Explicit durations win over positional assumptions. This matters because
|
|
477
|
+
// WHAM has shipped both a legacy primary=weekly shape and a dual-window
|
|
478
|
+
// primary=5h, secondary=weekly shape over time.
|
|
479
|
+
let weeklyPercent = primaryIsMonthly ? secondaryPercent : primaryPercent ?? secondaryPercent;
|
|
480
|
+
let weeklyResetAt = primaryIsMonthly
|
|
391
481
|
? secondaryResetAt
|
|
392
482
|
: primaryPercent !== undefined ? primaryResetAt : secondaryResetAt;
|
|
393
483
|
const monthlyPercent = primaryIsMonthly ? primaryPercent ?? tertiaryPercent : tertiaryPercent;
|
|
394
484
|
const monthlyResetAt = primaryIsMonthly && primaryPercent !== undefined ? primaryResetAt : tertiaryResetAt;
|
|
485
|
+
const trackFiveHour = !thirtyDayOnly
|
|
486
|
+
&& (isCodexFiveHourQuotaPlan(data.plan_type)
|
|
487
|
+
// If WHAM omitted plan_type, an explicit 5h duration is still
|
|
488
|
+
// unambiguous and should not be discarded from the display contract.
|
|
489
|
+
|| (data.plan_type == null && (primaryIsFiveHour || secondaryIsFiveHour)));
|
|
490
|
+
let fiveHourPercent = trackFiveHour && primaryIsFiveHour ? primaryPercent : undefined;
|
|
491
|
+
let fiveHourResetAt = trackFiveHour && primaryIsFiveHour ? primaryResetAt : undefined;
|
|
492
|
+
if (trackFiveHour && secondaryIsFiveHour && fiveHourPercent === undefined) {
|
|
493
|
+
fiveHourPercent = secondaryPercent;
|
|
494
|
+
fiveHourResetAt = secondaryResetAt;
|
|
495
|
+
}
|
|
496
|
+
// Older dual-window payloads omitted durations. For Plus/Team/Business,
|
|
497
|
+
// the primary+secondary pair is the legacy positional 5h+weekly shape.
|
|
498
|
+
if (trackFiveHour && !primaryIsMonthly && !primaryIsFiveHour
|
|
499
|
+
&& primaryPercent !== undefined && secondaryPercent !== undefined
|
|
500
|
+
&& windowDurationSeconds(primaryWindow) === undefined
|
|
501
|
+
&& windowDurationSeconds(secondaryWindow) === undefined) {
|
|
502
|
+
fiveHourPercent = primaryPercent;
|
|
503
|
+
fiveHourResetAt = primaryResetAt;
|
|
504
|
+
weeklyPercent = secondaryPercent;
|
|
505
|
+
weeklyResetAt = secondaryResetAt;
|
|
506
|
+
} else if (trackFiveHour && primaryIsFiveHour) {
|
|
507
|
+
weeklyPercent = secondaryPercent;
|
|
508
|
+
weeklyResetAt = secondaryResetAt;
|
|
509
|
+
}
|
|
395
510
|
if (thirtyDayOnly) {
|
|
396
511
|
if (monthlyPercent !== undefined) {
|
|
397
512
|
quota.monthlyPercent = monthlyPercent;
|
|
@@ -401,6 +516,10 @@ export function parseUsageQuota(data: WhamUsageResponse): Omit<StoredAccountQuot
|
|
|
401
516
|
quota.weeklyPercent = weeklyPercent;
|
|
402
517
|
if (weeklyResetAt !== undefined) quota.weeklyResetAt = weeklyResetAt;
|
|
403
518
|
}
|
|
519
|
+
if (trackFiveHour && fiveHourPercent !== undefined) {
|
|
520
|
+
quota.fiveHourPercent = fiveHourPercent;
|
|
521
|
+
if (fiveHourResetAt !== undefined) quota.fiveHourResetAt = fiveHourResetAt;
|
|
522
|
+
}
|
|
404
523
|
if (!thirtyDayOnly && monthlyPercent !== undefined) {
|
|
405
524
|
quota.monthlyPercent = monthlyPercent;
|
|
406
525
|
if (monthlyResetAt !== undefined) quota.monthlyResetAt = monthlyResetAt;
|