codex-multi-auth 2.11.0 → 2.13.0
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/.codex-plugin/plugin.json +1 -1
- package/README.md +7 -1
- package/dist/lib/accounts.d.ts +75 -0
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/accounts.js +213 -42
- package/dist/lib/capability-policy.d.ts.map +1 -1
- package/dist/lib/capability-policy.js +2 -1
- package/dist/lib/codex-manager/account-manager-commands.d.ts.map +1 -1
- package/dist/lib/codex-manager/account-manager-commands.js +1 -0
- package/dist/lib/codex-manager/commands/limits.d.ts +21 -0
- package/dist/lib/codex-manager/commands/limits.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/limits.js +158 -0
- package/dist/lib/codex-manager/help.d.ts.map +1 -1
- package/dist/lib/codex-manager/help.js +1 -0
- package/dist/lib/codex-manager/persist-selected-account.d.ts.map +1 -1
- package/dist/lib/codex-manager/persist-selected-account.js +14 -0
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +12 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +2 -1
- package/dist/lib/constants.d.ts +9 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +29 -0
- package/dist/lib/entitlement-cache.d.ts.map +1 -1
- package/dist/lib/entitlement-cache.js +2 -1
- package/dist/lib/forecast.d.ts.map +1 -1
- package/dist/lib/forecast.js +1 -14
- package/dist/lib/policy/runtime-policy.d.ts +9 -1
- package/dist/lib/policy/runtime-policy.d.ts.map +1 -1
- package/dist/lib/policy/runtime-policy.js +1 -0
- package/dist/lib/preemptive-quota-scheduler.d.ts +12 -0
- package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -1
- package/dist/lib/preemptive-quota-scheduler.js +21 -0
- package/dist/lib/redaction.d.ts +17 -0
- package/dist/lib/redaction.d.ts.map +1 -0
- package/dist/lib/redaction.js +28 -0
- package/dist/lib/request/error-classification.js +2 -2
- package/dist/lib/runtime/rotation-storage-meta.d.ts.map +1 -1
- package/dist/lib/runtime/rotation-storage-meta.js +4 -1
- package/dist/lib/runtime-rotation-proxy.d.ts +13 -0
- package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
- package/dist/lib/runtime-rotation-proxy.js +47 -7
- package/dist/lib/storage.d.ts +20 -2
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +69 -25
- package/dist/lib/usage/ledger.d.ts +1 -1
- package/dist/lib/usage/ledger.d.ts.map +1 -1
- package/dist/lib/usage/ledger.js +9 -0
- package/dist/lib/usage/pricing.d.ts +16 -1
- package/dist/lib/usage/pricing.d.ts.map +1 -1
- package/dist/lib/usage/pricing.js +46 -8
- package/dist/lib/usage/redaction.d.ts +1 -1
- package/dist/lib/usage/redaction.d.ts.map +1 -1
- package/dist/lib/usage/redaction.js +13 -0
- package/dist/lib/usage/types.d.ts +33 -0
- package/dist/lib/usage/types.d.ts.map +1 -1
- package/dist/lib/usage/types.js +28 -1
- package/dist/lib/usage/usage-extraction.d.ts +2 -1
- package/dist/lib/usage/usage-extraction.d.ts.map +1 -1
- package/dist/lib/usage/usage-extraction.js +44 -4
- package/package.json +1 -1
- package/scripts/codex-routing.js +1 -0
- package/scripts/codex.js +157 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-multi-auth",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "Install and operate codex-multi-auth for the official @openai/codex CLI with multi-account OAuth rotation, switching, health checks, and recovery tools.",
|
|
5
5
|
"interface": {
|
|
6
6
|
"composerIcon": "./assets/codex-multi-auth-icon.svg"
|
package/README.md
CHANGED
|
@@ -214,6 +214,7 @@ which would rebind the row to a different workspace.
|
|
|
214
214
|
| Command | What it answers |
|
|
215
215
|
| --- | --- |
|
|
216
216
|
| `codex-multi-auth report --live --json` | How do I get the full machine-readable health report? |
|
|
217
|
+
| `codex-multi-auth limits --json [--refresh]` | How do I read account quota windows without parsing internal cache files or terminal text? |
|
|
217
218
|
| `codex-multi-auth fix --live --model gpt-5.5` | How do I run live repair probes with a chosen model? |
|
|
218
219
|
| `codex-multi-auth why-selected --json` | Which account does the selector pick now, and why? |
|
|
219
220
|
| `codex-multi-auth usage --since 24h --by project` | What local usage has been recorded recently? |
|
|
@@ -296,6 +297,7 @@ Selected runtime/environment overrides:
|
|
|
296
297
|
| `CODEX_MULTI_AUTH_FORCE_ACCOUNT=<index\|email\|id>` | Force one account for a single `codex-multi-auth-codex` run (ephemeral; requires rotation proxy) |
|
|
297
298
|
| `CODEX_MULTI_AUTH_BYPASS=1` | Skip multi-auth intercept and forward straight to official Codex |
|
|
298
299
|
| `CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY=0/1` | Opt out/in of live Responses proxy rotation for forwarded Codex CLI/app sessions |
|
|
300
|
+
| `CODEX_MULTI_AUTH_RUNTIME_PROXY_UPSTREAM_BASE_URL=http://127.0.0.1:<port>/<path>` | Route the runtime rotation proxy through an explicit loopback HTTP upstream; requires an explicit port and a numeric loopback host (`127.0.0.0/8` or `[::1]`), and rejects credentials, query strings, fragments, HTTPS, and every other host |
|
|
299
301
|
| `CODEX_MULTI_AUTH_APP_ROTATION_IDLE_MS=<ms>` | Override automatic Codex app helper idle shutdown |
|
|
300
302
|
| `CODEX_MULTI_AUTH_APP_BIND_INSTALL=0/1` | Opt out/in of packaged Codex app bind self-heal on first CLI run or rotation enable |
|
|
301
303
|
| `CODEX_MULTI_AUTH_APP_LAUNCHER_INSTALL=0/1` | Opt out/in of routing supported app shortcuts on first CLI run or rotation enable |
|
|
@@ -318,6 +320,10 @@ Responses background mode stays opt-in. Enable `backgroundResponses` in settings
|
|
|
318
320
|
|
|
319
321
|
Runtime rotation is enabled by default for request-bearing wrapper-launched Codex sessions. Package install scripts stay side-effect-free: npm postinstall only prints a short notice (and stays silent in CI or non-interactive installs). The first CLI run after an install self-heals supported packaged Codex app binds and user-level launcher routing when possible (recorded once in a `first-run-setup.json` marker under the multi-auth runtime root), while `codex-multi-auth rotation enable` remains the explicit repair command. `codex-multi-auth rotation disable` turns the setting off and removes the persistent app bind. Set `CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY=0`, `CODEX_MULTI_AUTH_APP_BIND_INSTALL=0`, or `CODEX_MULTI_AUTH_APP_LAUNCHER_INSTALL=0` to opt out of the matching default behavior.
|
|
320
322
|
|
|
323
|
+
Advanced local proxy chains can set `CODEX_MULTI_AUTH_RUNTIME_PROXY_UPSTREAM_BASE_URL` for one wrapper process. The wrapper passes that URL to both the shadow-runtime and interactive-helper rotation paths and fails closed if the configured upstream is invalid or unavailable; it never falls back silently to the direct backend while an explicit upstream is required. Because the request that reaches the upstream carries the managed OAuth bearer token, the host must be a numeric loopback literal: a name such as `localhost` is rejected, since a hosts-file entry can point it at a routable address. "Fails closed" also covers the case where runtime rotation itself is off (`CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY=0`, `CODEX_MULTI_AUTH_BYPASS=1`, or the setting disabled): a request-bearing invocation exits non-zero rather than bypassing the configured upstream. Subcommands that make no backend requests still run normally.
|
|
324
|
+
|
|
325
|
+
Trust boundary: the loopback check bounds exposure to the local machine, and nothing more. It does not authenticate the process listening on that port, and plaintext HTTP is what a local inspection proxy needs, so any process that can bind the port you name receives the managed bearer token in cleartext. Set this variable only on a machine where you trust every local process that can bind a loopback port, and only for as long as you need the chain.
|
|
326
|
+
|
|
321
327
|
Installed wrappers may perform a best-effort daily npm version check during normal forwarded Codex startup. When a newer package is detected, the wrapper only prints a manual notice on an interactive TTY or when `CODEX_MULTI_AUTH_DEBUG=1`: `npm install -g codex-multi-auth@latest`. It never runs npm install or update commands for you.
|
|
322
328
|
|
|
323
329
|
---
|
|
@@ -406,7 +412,7 @@ codex-multi-auth doctor --json
|
|
|
406
412
|
|
|
407
413
|
## Release Notes
|
|
408
414
|
|
|
409
|
-
- Current stable: [docs/releases/v2.
|
|
415
|
+
- Current stable: [docs/releases/v2.13.0.md](docs/releases/v2.13.0.md) — install via `npm i -g codex-multi-auth`
|
|
410
416
|
- Previous stable: [docs/releases/v2.8.3.md](docs/releases/v2.8.3.md)
|
|
411
417
|
- Previous stable: [docs/releases/v2.8.2.md](docs/releases/v2.8.2.md)
|
|
412
418
|
- Previous stable: [docs/releases/v2.7.1.md](docs/releases/v2.7.1.md)
|
package/dist/lib/accounts.d.ts
CHANGED
|
@@ -16,6 +16,26 @@ type AccountIdentityCandidate = Pick<ManagedAccount, "accountId" | "email" | "re
|
|
|
16
16
|
export type { Workspace } from "./storage/public-types.js";
|
|
17
17
|
/** Stable operator-facing marker for an explicitly invalidated OAuth token. */
|
|
18
18
|
export declare const AUTH_INVALIDATION_MARKER = "token-invalid \u2014 re-login needed";
|
|
19
|
+
/**
|
|
20
|
+
* How long a 429 recorded while the selection metadata was unreadable stays
|
|
21
|
+
* eligible to be replayed over a `switch` that clears the account's markers.
|
|
22
|
+
*
|
|
23
|
+
* The window only has to cover the gap between the CLI's atomic storage write
|
|
24
|
+
* and this process observing it, which is a single filesystem read away and in
|
|
25
|
+
* practice sub-second. 30s is generous for a stalled Windows volume while still
|
|
26
|
+
* guaranteeing that a 429 from minutes or hours earlier can never be
|
|
27
|
+
* resurrected by a later, unrelated switch.
|
|
28
|
+
*/
|
|
29
|
+
export declare const UNSEQUENCED_RATE_LIMIT_TTL_MS = 30000;
|
|
30
|
+
/**
|
|
31
|
+
* How many times a debounced save re-arms itself after a failure before giving
|
|
32
|
+
* up. A save can fail because the selection metadata was momentarily
|
|
33
|
+
* unreadable, and dropping it loses every rate-limit window, cooldown and
|
|
34
|
+
* rotated refresh token accumulated since the last successful save.
|
|
35
|
+
*/
|
|
36
|
+
export declare const MAX_DEBOUNCED_SAVE_RETRIES = 5;
|
|
37
|
+
/** Ceiling for the debounced-save retry backoff. */
|
|
38
|
+
export declare const MAX_SAVE_RETRY_DELAY_MS = 8000;
|
|
19
39
|
export interface ManagedAccount {
|
|
20
40
|
index: number;
|
|
21
41
|
recordId?: string;
|
|
@@ -50,6 +70,8 @@ export declare class AccountManager {
|
|
|
50
70
|
private lastToastTime;
|
|
51
71
|
private saveDebounceTimer;
|
|
52
72
|
private pendingSave;
|
|
73
|
+
/** Consecutive debounced-save failures; reset by the next success. */
|
|
74
|
+
private saveRetryCount;
|
|
53
75
|
private readonly storagePathState;
|
|
54
76
|
/**
|
|
55
77
|
* Manual pin set by the `switch` CLI command, hydrated from disk at
|
|
@@ -65,6 +87,7 @@ export declare class AccountManager {
|
|
|
65
87
|
* as `pinnedAccountIndex`. See #474.
|
|
66
88
|
*/
|
|
67
89
|
private affinityGeneration;
|
|
90
|
+
private readonly unsequencedRateLimits;
|
|
68
91
|
/**
|
|
69
92
|
* PR-N / R4: feature-flagged routing mutex mode.
|
|
70
93
|
* Defaults to `"legacy"` to preserve pre-PR-N behaviour for one release
|
|
@@ -92,6 +115,21 @@ export declare class AccountManager {
|
|
|
92
115
|
*/
|
|
93
116
|
getManagedAccountRuntimeSkipReason(account: ManagedAccount, family: ModelFamily, model?: string | null): string | null;
|
|
94
117
|
static resetVolatileRuntimeState(): void;
|
|
118
|
+
/**
|
|
119
|
+
* Apply each explicit selection once without erasing a subsequent 429.
|
|
120
|
+
*
|
|
121
|
+
* A `switch` asks for a fresh upstream attempt, so the selected account's
|
|
122
|
+
* rate-limit markers are cleared. The only markers that survive that clear
|
|
123
|
+
* are ones recorded while the selection metadata was unreadable AND recent
|
|
124
|
+
* enough to have raced this switch (see UNSEQUENCED_RATE_LIMIT_TTL_MS); an
|
|
125
|
+
* older unsequenced entry provably predates the switch and is discarded.
|
|
126
|
+
*
|
|
127
|
+
* @param meta Latest successfully read selection generation and pin.
|
|
128
|
+
*/
|
|
129
|
+
applyManualSelection(meta: {
|
|
130
|
+
pinnedAccountIndex?: number | null;
|
|
131
|
+
affinityGeneration: number;
|
|
132
|
+
}): void;
|
|
95
133
|
/**
|
|
96
134
|
* Wipe per-account transient state — active cooldowns and all rate-limit
|
|
97
135
|
* reset windows — across every managed account, then schedule a debounced
|
|
@@ -213,6 +251,14 @@ export declare class AccountManager {
|
|
|
213
251
|
setActiveIndexLocked(index: number): Promise<ManagedAccount | null>;
|
|
214
252
|
markRateLimited(account: ManagedAccount, retryAfterMs: number, family: ModelFamily, model?: string | null): void;
|
|
215
253
|
markRateLimitedWithReason(account: ManagedAccount, retryAfterMs: number, family: ModelFamily, reason: RateLimitReason, model?: string | null): void;
|
|
254
|
+
/**
|
|
255
|
+
* Storage file this manager owns, resolved through the path state captured
|
|
256
|
+
* at construction. Reading the ambient `getStoragePath()` instead would
|
|
257
|
+
* point a project-scoped pool at whichever storage file happens to be
|
|
258
|
+
* current on the calling async context. See `saveToDisk`, which wraps
|
|
259
|
+
* `runWithStoragePathState(this.storagePathState, ...)` for the same reason.
|
|
260
|
+
*/
|
|
261
|
+
private resolveSelectionStoragePath;
|
|
216
262
|
markAccountCoolingDown(account: ManagedAccount, cooldownMs: number, reason: CooldownReason): void;
|
|
217
263
|
isAccountCoolingDown(account: ManagedAccount): boolean;
|
|
218
264
|
clearAccountCooldown(account: ManagedAccount): void;
|
|
@@ -247,6 +293,29 @@ export declare class AccountManager {
|
|
|
247
293
|
* never undoes a refresh we just performed.
|
|
248
294
|
*/
|
|
249
295
|
private reconcileTokensFromDisk;
|
|
296
|
+
/**
|
|
297
|
+
* Re-read the on-disk selection and fold it into this manager's state.
|
|
298
|
+
*
|
|
299
|
+
* Race protection: a CLI `switch`/`unpin`/`best` may have written a NEW
|
|
300
|
+
* pin/gen between proxy startup (or the last save) and now. If we persisted
|
|
301
|
+
* our stale instance values, we'd silently clobber the CLI update on every
|
|
302
|
+
* routine save (rate-limit, cooldown, near-quota refund, etc.). See #474.
|
|
303
|
+
*
|
|
304
|
+
* This MUTATES `pinnedAccountIndex`, `affinityGeneration` and, when the
|
|
305
|
+
* generation advanced, the selected account's rate-limit markers, so it is a
|
|
306
|
+
* separate step from the pure `buildStorageSnapshot` serializer below rather
|
|
307
|
+
* than a hidden side effect of it. Callers must run it immediately before a
|
|
308
|
+
* snapshot they intend to persist. Applying it twice is a no-op.
|
|
309
|
+
*
|
|
310
|
+
* @throws when the metadata exists but cannot be observed (see
|
|
311
|
+
* `readPinAndGenFromDisk`), which is the one case where persisting would
|
|
312
|
+
* risk overwriting a newer pin.
|
|
313
|
+
*/
|
|
314
|
+
private reconcileSelectionFromDisk;
|
|
315
|
+
/**
|
|
316
|
+
* Serialize the live pool. Pure: it reads no files and mutates no state.
|
|
317
|
+
* Persisting callers must call `reconcileSelectionFromDisk()` first.
|
|
318
|
+
*/
|
|
250
319
|
private buildStorageSnapshot;
|
|
251
320
|
commitRefreshedAuth(source: Pick<ManagedAccount, "index" | "accountId" | "email" | "refreshToken">, auth: OAuthAuthDetails): Promise<ManagedAccount | null>;
|
|
252
321
|
toAuthDetails(account: ManagedAccount): Auth;
|
|
@@ -263,6 +332,12 @@ export declare class AccountManager {
|
|
|
263
332
|
setAccountEnabled(index: number, enabled: boolean): ManagedAccount | null;
|
|
264
333
|
saveToDisk(): Promise<void>;
|
|
265
334
|
saveToDiskDebounced(delayMs?: number): void;
|
|
335
|
+
/**
|
|
336
|
+
* Flush any debounced save. Never rejects: this runs on the proxy shutdown
|
|
337
|
+
* path (`RuntimeRotationProxy.close`), and a rejection there aborts the rest
|
|
338
|
+
* of the teardown. A failure is logged at error level instead, because the
|
|
339
|
+
* process is exiting and there is no later attempt to fall back to.
|
|
340
|
+
*/
|
|
266
341
|
flushPendingSave(): Promise<void>;
|
|
267
342
|
private resetWorkspaces;
|
|
268
343
|
getCurrentWorkspace(account: ManagedAccount): Workspace | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../lib/accounts.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../lib/accounts.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/accounts.js
CHANGED
|
@@ -126,6 +126,26 @@ function isRetryableAuthPersistenceError(error) {
|
|
|
126
126
|
}
|
|
127
127
|
/** Stable operator-facing marker for an explicitly invalidated OAuth token. */
|
|
128
128
|
export const AUTH_INVALIDATION_MARKER = "token-invalid — re-login needed";
|
|
129
|
+
/**
|
|
130
|
+
* How long a 429 recorded while the selection metadata was unreadable stays
|
|
131
|
+
* eligible to be replayed over a `switch` that clears the account's markers.
|
|
132
|
+
*
|
|
133
|
+
* The window only has to cover the gap between the CLI's atomic storage write
|
|
134
|
+
* and this process observing it, which is a single filesystem read away and in
|
|
135
|
+
* practice sub-second. 30s is generous for a stalled Windows volume while still
|
|
136
|
+
* guaranteeing that a 429 from minutes or hours earlier can never be
|
|
137
|
+
* resurrected by a later, unrelated switch.
|
|
138
|
+
*/
|
|
139
|
+
export const UNSEQUENCED_RATE_LIMIT_TTL_MS = 30_000;
|
|
140
|
+
/**
|
|
141
|
+
* How many times a debounced save re-arms itself after a failure before giving
|
|
142
|
+
* up. A save can fail because the selection metadata was momentarily
|
|
143
|
+
* unreadable, and dropping it loses every rate-limit window, cooldown and
|
|
144
|
+
* rotated refresh token accumulated since the last successful save.
|
|
145
|
+
*/
|
|
146
|
+
export const MAX_DEBOUNCED_SAVE_RETRIES = 5;
|
|
147
|
+
/** Ceiling for the debounced-save retry backoff. */
|
|
148
|
+
export const MAX_SAVE_RETRY_DELAY_MS = 8_000;
|
|
129
149
|
export class AccountManager {
|
|
130
150
|
accounts = [];
|
|
131
151
|
cursorByFamily = initFamilyState(0);
|
|
@@ -134,6 +154,8 @@ export class AccountManager {
|
|
|
134
154
|
lastToastTime = 0;
|
|
135
155
|
saveDebounceTimer = null;
|
|
136
156
|
pendingSave = null;
|
|
157
|
+
/** Consecutive debounced-save failures; reset by the next success. */
|
|
158
|
+
saveRetryCount = 0;
|
|
137
159
|
storagePathState;
|
|
138
160
|
/**
|
|
139
161
|
* Manual pin set by the `switch` CLI command, hydrated from disk at
|
|
@@ -149,6 +171,17 @@ export class AccountManager {
|
|
|
149
171
|
* as `pinnedAccountIndex`. See #474.
|
|
150
172
|
*/
|
|
151
173
|
affinityGeneration;
|
|
174
|
+
// A 429 observed while the selection metadata was unreadable must survive
|
|
175
|
+
// the next reconciliation, because we cannot tell whether it landed before
|
|
176
|
+
// or after the `switch` that reconciliation is about to apply. Keep only
|
|
177
|
+
// those new markers, not the stale account map.
|
|
178
|
+
//
|
|
179
|
+
// `recordedAtMs` bounds that ambiguity. Only a 429 recorded within
|
|
180
|
+
// UNSEQUENCED_RATE_LIMIT_TTL_MS of the reconciliation could have raced the
|
|
181
|
+
// switch we are applying; an older entry provably predates it and must NOT
|
|
182
|
+
// be replayed, or an arbitrarily stale 429 would be resurrected by the very
|
|
183
|
+
// command meant to revalidate the account.
|
|
184
|
+
unsequencedRateLimits = new WeakMap();
|
|
152
185
|
/**
|
|
153
186
|
* PR-N / R4: feature-flagged routing mutex mode.
|
|
154
187
|
* Defaults to `"legacy"` to preserve pre-PR-N behaviour for one release
|
|
@@ -248,7 +281,8 @@ export class AccountManager {
|
|
|
248
281
|
this.affinityGeneration =
|
|
249
282
|
typeof rawStoredGen === "number" &&
|
|
250
283
|
Number.isFinite(rawStoredGen) &&
|
|
251
|
-
|
|
284
|
+
// See readAffinityGenerationFromDisk: an unsafe integer wedges the bump.
|
|
285
|
+
Number.isSafeInteger(rawStoredGen) &&
|
|
252
286
|
rawStoredGen >= 0
|
|
253
287
|
? rawStoredGen
|
|
254
288
|
: 0;
|
|
@@ -492,6 +526,38 @@ export class AccountManager {
|
|
|
492
526
|
resetTrackers();
|
|
493
527
|
resetAllCircuitBreakers();
|
|
494
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* Apply each explicit selection once without erasing a subsequent 429.
|
|
531
|
+
*
|
|
532
|
+
* A `switch` asks for a fresh upstream attempt, so the selected account's
|
|
533
|
+
* rate-limit markers are cleared. The only markers that survive that clear
|
|
534
|
+
* are ones recorded while the selection metadata was unreadable AND recent
|
|
535
|
+
* enough to have raced this switch (see UNSEQUENCED_RATE_LIMIT_TTL_MS); an
|
|
536
|
+
* older unsequenced entry provably predates the switch and is discarded.
|
|
537
|
+
*
|
|
538
|
+
* @param meta Latest successfully read selection generation and pin.
|
|
539
|
+
*/
|
|
540
|
+
applyManualSelection(meta) {
|
|
541
|
+
if (meta.affinityGeneration <= this.affinityGeneration)
|
|
542
|
+
return;
|
|
543
|
+
const index = meta.pinnedAccountIndex;
|
|
544
|
+
const account = typeof index === "number"
|
|
545
|
+
? this.getAccountByIndex(index)
|
|
546
|
+
: null;
|
|
547
|
+
if (account) {
|
|
548
|
+
clearAllRateLimits(account);
|
|
549
|
+
const pending = this.unsequencedRateLimits.get(account);
|
|
550
|
+
const replayable = pending !== undefined &&
|
|
551
|
+
nowMs() - pending.recordedAtMs <= UNSEQUENCED_RATE_LIMIT_TTL_MS
|
|
552
|
+
? pending
|
|
553
|
+
: undefined;
|
|
554
|
+
Object.assign(account.rateLimitResetTimes, replayable?.limits);
|
|
555
|
+
account.lastRateLimitReason = replayable?.reason;
|
|
556
|
+
this.unsequencedRateLimits.delete(account);
|
|
557
|
+
}
|
|
558
|
+
this.pinnedAccountIndex = account ? index ?? undefined : undefined;
|
|
559
|
+
this.affinityGeneration = meta.affinityGeneration;
|
|
560
|
+
}
|
|
495
561
|
/**
|
|
496
562
|
* Wipe per-account transient state — active cooldowns and all rate-limit
|
|
497
563
|
* reset windows — across every managed account, then schedule a debounced
|
|
@@ -908,22 +974,74 @@ export class AccountManager {
|
|
|
908
974
|
this.markRateLimitedWithReason(account, retryAfterMs, family, "unknown", model);
|
|
909
975
|
}
|
|
910
976
|
markRateLimitedWithReason(account, retryAfterMs, family, reason, model) {
|
|
977
|
+
let selectionReadable = false;
|
|
978
|
+
try {
|
|
979
|
+
// Deliberately a fresh strict read rather than the proxy's cached
|
|
980
|
+
// `readStorageMetaFromDisk`: that reader falls back to its last good
|
|
981
|
+
// snapshot on failure, so it cannot tell this call site the one thing
|
|
982
|
+
// it needs to know, namely whether the selection was observable at all.
|
|
983
|
+
const meta = readPinAndGenFromDisk(this.resolveSelectionStoragePath(), {
|
|
984
|
+
strict: true,
|
|
985
|
+
});
|
|
986
|
+
// Observe a switch BEFORE recording this response, not at the later
|
|
987
|
+
// debounced save where it would erase a genuine post-switch 429.
|
|
988
|
+
this.applyManualSelection(meta);
|
|
989
|
+
selectionReadable = true;
|
|
990
|
+
}
|
|
991
|
+
catch {
|
|
992
|
+
// Fail closed: retain this new limit if the selection cannot be read.
|
|
993
|
+
log.warn("Rate limit recorded while account selection metadata is unavailable");
|
|
994
|
+
}
|
|
911
995
|
// Clamp to MAX_RATE_LIMIT_DELAY_MS so a bogus upstream retry-after value
|
|
912
996
|
// cannot wedge this account unavailable for years (see stress audit H1).
|
|
913
997
|
const retryMs = Math.min(Math.max(0, Math.floor(retryAfterMs)), MAX_RATE_LIMIT_DELAY_MS);
|
|
914
|
-
const
|
|
998
|
+
const observedAtMs = nowMs();
|
|
999
|
+
const resetAt = observedAtMs + retryMs;
|
|
1000
|
+
// Only carry forward an unsequenced entry that is still replayable.
|
|
1001
|
+
// Merging an expired one would give it a fresh `recordedAtMs` below and
|
|
1002
|
+
// keep resurrecting it indefinitely.
|
|
1003
|
+
const pending = this.unsequencedRateLimits.get(account);
|
|
1004
|
+
const carried = pending !== undefined &&
|
|
1005
|
+
observedAtMs - pending.recordedAtMs <= UNSEQUENCED_RATE_LIMIT_TTL_MS
|
|
1006
|
+
? pending
|
|
1007
|
+
: undefined;
|
|
1008
|
+
const newLimits = { ...carried?.limits };
|
|
915
1009
|
const baseKey = getQuotaKey(family);
|
|
916
1010
|
if (!model || reason === "quota" || reason === "unknown") {
|
|
917
1011
|
const currentResetAt = account.rateLimitResetTimes[baseKey] ?? 0;
|
|
918
1012
|
account.rateLimitResetTimes[baseKey] = Math.max(currentResetAt, resetAt);
|
|
1013
|
+
newLimits[baseKey] = Math.max(newLimits[baseKey] ?? 0, resetAt);
|
|
919
1014
|
}
|
|
920
1015
|
if (model &&
|
|
921
1016
|
(reason === "tokens" || reason === "concurrent" || reason === "unknown")) {
|
|
922
1017
|
const modelKey = getQuotaKey(family, model);
|
|
923
1018
|
const currentResetAt = account.rateLimitResetTimes[modelKey] ?? 0;
|
|
924
1019
|
account.rateLimitResetTimes[modelKey] = Math.max(currentResetAt, resetAt);
|
|
1020
|
+
newLimits[modelKey] = Math.max(newLimits[modelKey] ?? 0, resetAt);
|
|
925
1021
|
}
|
|
926
1022
|
account.lastRateLimitReason = reason;
|
|
1023
|
+
if (!selectionReadable) {
|
|
1024
|
+
this.unsequencedRateLimits.set(account, {
|
|
1025
|
+
limits: newLimits,
|
|
1026
|
+
reason,
|
|
1027
|
+
recordedAtMs: observedAtMs,
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
else {
|
|
1031
|
+
// The selection was observable, so this 429 is unambiguously ordered
|
|
1032
|
+
// against the current generation and needs no replay backup.
|
|
1033
|
+
this.unsequencedRateLimits.delete(account);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Storage file this manager owns, resolved through the path state captured
|
|
1038
|
+
* at construction. Reading the ambient `getStoragePath()` instead would
|
|
1039
|
+
* point a project-scoped pool at whichever storage file happens to be
|
|
1040
|
+
* current on the calling async context. See `saveToDisk`, which wraps
|
|
1041
|
+
* `runWithStoragePathState(this.storagePathState, ...)` for the same reason.
|
|
1042
|
+
*/
|
|
1043
|
+
resolveSelectionStoragePath() {
|
|
1044
|
+
return this.storagePathState.currentStoragePath ?? getStoragePath();
|
|
927
1045
|
}
|
|
928
1046
|
markAccountCoolingDown(account, cooldownMs, reason) {
|
|
929
1047
|
const ms = Math.max(0, Math.floor(cooldownMs));
|
|
@@ -1076,6 +1194,54 @@ export class AccountManager {
|
|
|
1076
1194
|
}
|
|
1077
1195
|
return snapshot;
|
|
1078
1196
|
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Re-read the on-disk selection and fold it into this manager's state.
|
|
1199
|
+
*
|
|
1200
|
+
* Race protection: a CLI `switch`/`unpin`/`best` may have written a NEW
|
|
1201
|
+
* pin/gen between proxy startup (or the last save) and now. If we persisted
|
|
1202
|
+
* our stale instance values, we'd silently clobber the CLI update on every
|
|
1203
|
+
* routine save (rate-limit, cooldown, near-quota refund, etc.). See #474.
|
|
1204
|
+
*
|
|
1205
|
+
* This MUTATES `pinnedAccountIndex`, `affinityGeneration` and, when the
|
|
1206
|
+
* generation advanced, the selected account's rate-limit markers, so it is a
|
|
1207
|
+
* separate step from the pure `buildStorageSnapshot` serializer below rather
|
|
1208
|
+
* than a hidden side effect of it. Callers must run it immediately before a
|
|
1209
|
+
* snapshot they intend to persist. Applying it twice is a no-op.
|
|
1210
|
+
*
|
|
1211
|
+
* @throws when the metadata exists but cannot be observed (see
|
|
1212
|
+
* `readPinAndGenFromDisk`), which is the one case where persisting would
|
|
1213
|
+
* risk overwriting a newer pin.
|
|
1214
|
+
*/
|
|
1215
|
+
reconcileSelectionFromDisk() {
|
|
1216
|
+
const onDisk = readPinAndGenFromDisk(this.resolveSelectionStoragePath(), {
|
|
1217
|
+
strict: true,
|
|
1218
|
+
});
|
|
1219
|
+
// A delayed save must not resurrect the markers the CLI just cleared.
|
|
1220
|
+
this.applyManualSelection(onDisk);
|
|
1221
|
+
let effectivePinnedAccountIndex = this.pinnedAccountIndex;
|
|
1222
|
+
let effectiveAffinityGeneration = this.affinityGeneration;
|
|
1223
|
+
if (onDisk.affinityGeneration > effectiveAffinityGeneration) {
|
|
1224
|
+
effectiveAffinityGeneration = onDisk.affinityGeneration;
|
|
1225
|
+
// The pin is part of the same atomic write the CLI performs when it
|
|
1226
|
+
// bumps the generation, so a strictly-greater on-disk gen is the
|
|
1227
|
+
// signal that the disk pin is the authoritative one.
|
|
1228
|
+
effectivePinnedAccountIndex = onDisk.pinnedAccountIndex;
|
|
1229
|
+
}
|
|
1230
|
+
// Validate the refreshed pin against the live account count.
|
|
1231
|
+
if (effectivePinnedAccountIndex !== undefined &&
|
|
1232
|
+
(effectivePinnedAccountIndex < 0 ||
|
|
1233
|
+
effectivePinnedAccountIndex >= this.accounts.length)) {
|
|
1234
|
+
effectivePinnedAccountIndex = undefined;
|
|
1235
|
+
}
|
|
1236
|
+
// Cache the refreshed values so subsequent saves start from the freshest
|
|
1237
|
+
// known state without re-reading every time.
|
|
1238
|
+
this.pinnedAccountIndex = effectivePinnedAccountIndex;
|
|
1239
|
+
this.affinityGeneration = effectiveAffinityGeneration;
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Serialize the live pool. Pure: it reads no files and mutates no state.
|
|
1243
|
+
* Persisting callers must call `reconcileSelectionFromDisk()` first.
|
|
1244
|
+
*/
|
|
1079
1245
|
buildStorageSnapshot() {
|
|
1080
1246
|
const activeIndexByFamily = {};
|
|
1081
1247
|
for (const family of MODEL_FAMILIES) {
|
|
@@ -1083,38 +1249,8 @@ export class AccountManager {
|
|
|
1083
1249
|
activeIndexByFamily[family] = clampNonNegativeInt(raw, 0);
|
|
1084
1250
|
}
|
|
1085
1251
|
const activeIndex = clampNonNegativeInt(activeIndexByFamily.codex, 0);
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
// persisted our stale instance values, we'd silently clobber the CLI
|
|
1089
|
-
// update on every routine save (rate-limit, cooldown, near-quota refund,
|
|
1090
|
-
// etc.). Re-read just before snapshotting and prefer the fresher value.
|
|
1091
|
-
// See #474.
|
|
1092
|
-
let effectivePinnedAccountIndex = this.pinnedAccountIndex;
|
|
1093
|
-
let effectiveAffinityGeneration = this.affinityGeneration;
|
|
1094
|
-
try {
|
|
1095
|
-
const onDisk = readPinAndGenFromDisk(getStoragePath());
|
|
1096
|
-
if (onDisk.affinityGeneration > effectiveAffinityGeneration) {
|
|
1097
|
-
effectiveAffinityGeneration = onDisk.affinityGeneration;
|
|
1098
|
-
// The pin is part of the same atomic write the CLI performs when
|
|
1099
|
-
// it bumps the generation, so a strictly-greater on-disk gen is
|
|
1100
|
-
// the signal that the disk pin is the authoritative one.
|
|
1101
|
-
effectivePinnedAccountIndex = onDisk.pinnedAccountIndex;
|
|
1102
|
-
}
|
|
1103
|
-
// Validate the refreshed pin against the live account count.
|
|
1104
|
-
if (effectivePinnedAccountIndex !== undefined &&
|
|
1105
|
-
(effectivePinnedAccountIndex < 0 ||
|
|
1106
|
-
effectivePinnedAccountIndex >= this.accounts.length)) {
|
|
1107
|
-
effectivePinnedAccountIndex = undefined;
|
|
1108
|
-
}
|
|
1109
|
-
// Cache the refreshed values so subsequent saves start from the
|
|
1110
|
-
// freshest known state without re-reading every time.
|
|
1111
|
-
this.pinnedAccountIndex = effectivePinnedAccountIndex;
|
|
1112
|
-
this.affinityGeneration = effectiveAffinityGeneration;
|
|
1113
|
-
}
|
|
1114
|
-
catch {
|
|
1115
|
-
// Disk read failures fall back to in-memory values; better than
|
|
1116
|
-
// dropping the snapshot save entirely.
|
|
1117
|
-
}
|
|
1252
|
+
const effectivePinnedAccountIndex = this.pinnedAccountIndex;
|
|
1253
|
+
const effectiveAffinityGeneration = this.affinityGeneration;
|
|
1118
1254
|
const snapshot = {
|
|
1119
1255
|
version: 3,
|
|
1120
1256
|
accounts: this.accounts.map((account) => {
|
|
@@ -1164,7 +1300,11 @@ export class AccountManager {
|
|
|
1164
1300
|
try {
|
|
1165
1301
|
return await withAccountStorageTransaction(async (_current, persist) => {
|
|
1166
1302
|
// Snapshot the live in-memory pool under the storage lock so refresh
|
|
1167
|
-
// persistence merges against the latest account state.
|
|
1303
|
+
// persistence merges against the latest account state. Reconcile the
|
|
1304
|
+
// selection first for the same reason `saveToDisk` does: this write
|
|
1305
|
+
// carries `pinnedAccountIndex`/`affinityGeneration` too, so a stale
|
|
1306
|
+
// pair here would clobber a `switch` that landed since the last save.
|
|
1307
|
+
this.reconcileSelectionFromDisk();
|
|
1168
1308
|
const nextStorage = structuredClone(this.buildStorageSnapshot());
|
|
1169
1309
|
const storageIndex = findAccountIndexByIdentity(nextStorage.accounts, source, auth);
|
|
1170
1310
|
if (storageIndex === undefined) {
|
|
@@ -1536,7 +1676,8 @@ export class AccountManager {
|
|
|
1536
1676
|
await withAccountStorageTransaction(async (current, persist) => {
|
|
1537
1677
|
// Reconcile against the disk state loaded under the storage lock so a
|
|
1538
1678
|
// routine save does not clobber a token another process just rotated
|
|
1539
|
-
// (stress audit H3).
|
|
1679
|
+
// (stress audit H3) or a pin the CLI just wrote (#474).
|
|
1680
|
+
this.reconcileSelectionFromDisk();
|
|
1540
1681
|
await persist(this.reconcileTokensFromDisk(this.buildStorageSnapshot(), current));
|
|
1541
1682
|
});
|
|
1542
1683
|
});
|
|
@@ -1556,24 +1697,54 @@ export class AccountManager {
|
|
|
1556
1697
|
this.pendingSave = null;
|
|
1557
1698
|
});
|
|
1558
1699
|
await this.pendingSave;
|
|
1700
|
+
this.saveRetryCount = 0;
|
|
1559
1701
|
}
|
|
1560
1702
|
catch (error) {
|
|
1561
1703
|
log.warn("Debounced save failed", {
|
|
1562
1704
|
error: error instanceof Error ? error.message : String(error),
|
|
1705
|
+
attempt: this.saveRetryCount + 1,
|
|
1563
1706
|
});
|
|
1707
|
+
// The debounce timer has already fired and cleared itself, so
|
|
1708
|
+
// without re-arming this save is simply lost, and with it every
|
|
1709
|
+
// rate-limit window, cooldown and rotated refresh token recorded
|
|
1710
|
+
// since the last successful write. Saves fail for transient
|
|
1711
|
+
// reasons (a Windows AV scanner or indexer holding accounts.json,
|
|
1712
|
+
// a torn read of a concurrent atomic rename), so back off and try
|
|
1713
|
+
// again instead of dropping the state.
|
|
1714
|
+
if (this.saveRetryCount < MAX_DEBOUNCED_SAVE_RETRIES) {
|
|
1715
|
+
this.saveRetryCount += 1;
|
|
1716
|
+
this.saveToDiskDebounced(Math.min(delayMs * 2, MAX_SAVE_RETRY_DELAY_MS));
|
|
1717
|
+
}
|
|
1718
|
+
else {
|
|
1719
|
+
this.saveRetryCount = 0;
|
|
1720
|
+
log.error("Dropping account state save after repeated failures; runtime state since the last successful save is lost");
|
|
1721
|
+
}
|
|
1564
1722
|
}
|
|
1565
1723
|
};
|
|
1566
1724
|
void doSave();
|
|
1567
1725
|
}, delayMs);
|
|
1568
1726
|
}
|
|
1727
|
+
/**
|
|
1728
|
+
* Flush any debounced save. Never rejects: this runs on the proxy shutdown
|
|
1729
|
+
* path (`RuntimeRotationProxy.close`), and a rejection there aborts the rest
|
|
1730
|
+
* of the teardown. A failure is logged at error level instead, because the
|
|
1731
|
+
* process is exiting and there is no later attempt to fall back to.
|
|
1732
|
+
*/
|
|
1569
1733
|
async flushPendingSave() {
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1734
|
+
try {
|
|
1735
|
+
if (this.saveDebounceTimer) {
|
|
1736
|
+
clearTimeout(this.saveDebounceTimer);
|
|
1737
|
+
this.saveDebounceTimer = null;
|
|
1738
|
+
await this.saveToDisk();
|
|
1739
|
+
}
|
|
1740
|
+
if (this.pendingSave) {
|
|
1741
|
+
await this.pendingSave;
|
|
1742
|
+
}
|
|
1574
1743
|
}
|
|
1575
|
-
|
|
1576
|
-
|
|
1744
|
+
catch (error) {
|
|
1745
|
+
log.error("Failed to flush pending account state save", {
|
|
1746
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1747
|
+
});
|
|
1577
1748
|
}
|
|
1578
1749
|
}
|
|
1579
1750
|
// Workspace management methods
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability-policy.d.ts","sourceRoot":"","sources":["../../lib/capability-policy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"capability-policy.d.ts","sourceRoot":"","sources":["../../lib/capability-policy.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,wBAAwB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAyED,qBAAa,qBAAqB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAE9D,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IAkBxE,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IAgBxE,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IAgB5E,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,MAAM;IAiBrE,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI;IAc/E,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAYxC,OAAO,CAAC,aAAa;CASrB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getNormalizedModel, resolveNormalizedModel, } from "./request/helpers/model-map.js";
|
|
2
|
+
import { stripModelEffortSuffix } from "./constants.js";
|
|
2
3
|
const MAX_ENTRIES = 2048;
|
|
3
4
|
const PASSIVE_RECOVERY_PER_MIN = 0.5;
|
|
4
5
|
/**
|
|
@@ -45,7 +46,7 @@ function normalizeModel(model) {
|
|
|
45
46
|
const trimmed = mapped.trim().toLowerCase();
|
|
46
47
|
if (!trimmed)
|
|
47
48
|
return null;
|
|
48
|
-
return trimmed
|
|
49
|
+
return stripModelEffortSuffix(trimmed);
|
|
49
50
|
}
|
|
50
51
|
/**
|
|
51
52
|
* Compose a storage key from an account key and a normalized model identifier.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-manager-commands.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/account-manager-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,
|
|
1
|
+
{"version":3,"file":"account-manager-commands.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/account-manager-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,aA+BnC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ModelFamily } from "../../prompts/codex.js";
|
|
2
|
+
import type { QuotaCacheData } from "../../quota-cache.js";
|
|
3
|
+
import type { AccountStorageV3 } from "../../storage.js";
|
|
4
|
+
export interface LimitsCommandDeps {
|
|
5
|
+
setStoragePath: (path: string | null) => void;
|
|
6
|
+
loadAccounts: () => Promise<AccountStorageV3 | null>;
|
|
7
|
+
loadQuotaCache: () => Promise<QuotaCacheData>;
|
|
8
|
+
refreshQuotaCache: (storage: AccountStorageV3, cache: QuotaCacheData, maxAgeMs: number) => Promise<QuotaCacheData>;
|
|
9
|
+
resolveActiveIndex: (storage: AccountStorageV3, family?: ModelFamily) => number;
|
|
10
|
+
getNow?: () => number;
|
|
11
|
+
logInfo?: (message: string) => void;
|
|
12
|
+
logError?: (message: string) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Emit configured accounts joined to safe cached quota records.
|
|
16
|
+
*
|
|
17
|
+
* Cached mode performs no provider requests. Refresh mode delegates to the
|
|
18
|
+
* existing sequential, age-gated refresh path before serializing the snapshot.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runLimitsCommand(args: string[], deps: LimitsCommandDeps): Promise<number>;
|
|
21
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../../../lib/codex-manager/commands/limits.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1E,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAE5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAMzD,MAAM,WAAW,iBAAiB;IACjC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,YAAY,EAAE,MAAM,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACrD,cAAc,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9C,iBAAiB,EAAE,CAClB,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,cAAc,EACrB,QAAQ,EAAE,MAAM,KACZ,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,kBAAkB,EAAE,CACnB,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,WAAW,KAChB,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAsDD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,EAAE,iBAAiB,GACrB,OAAO,CAAC,MAAM,CAAC,CAoFjB"}
|