codex-multi-auth 2.12.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.
Files changed (35) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/README.md +7 -1
  3. package/dist/lib/accounts.d.ts +75 -0
  4. package/dist/lib/accounts.d.ts.map +1 -1
  5. package/dist/lib/accounts.js +213 -42
  6. package/dist/lib/codex-manager/account-manager-commands.d.ts.map +1 -1
  7. package/dist/lib/codex-manager/account-manager-commands.js +1 -0
  8. package/dist/lib/codex-manager/commands/limits.d.ts +21 -0
  9. package/dist/lib/codex-manager/commands/limits.d.ts.map +1 -0
  10. package/dist/lib/codex-manager/commands/limits.js +158 -0
  11. package/dist/lib/codex-manager/help.d.ts.map +1 -1
  12. package/dist/lib/codex-manager/help.js +1 -0
  13. package/dist/lib/codex-manager/persist-selected-account.d.ts.map +1 -1
  14. package/dist/lib/codex-manager/persist-selected-account.js +14 -0
  15. package/dist/lib/codex-manager.d.ts.map +1 -1
  16. package/dist/lib/codex-manager.js +12 -0
  17. package/dist/lib/forecast.d.ts.map +1 -1
  18. package/dist/lib/forecast.js +1 -14
  19. package/dist/lib/preemptive-quota-scheduler.d.ts +12 -0
  20. package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -1
  21. package/dist/lib/preemptive-quota-scheduler.js +21 -0
  22. package/dist/lib/redaction.d.ts +17 -0
  23. package/dist/lib/redaction.d.ts.map +1 -0
  24. package/dist/lib/redaction.js +28 -0
  25. package/dist/lib/runtime/rotation-storage-meta.d.ts.map +1 -1
  26. package/dist/lib/runtime/rotation-storage-meta.js +4 -1
  27. package/dist/lib/runtime-rotation-proxy.d.ts +13 -0
  28. package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
  29. package/dist/lib/runtime-rotation-proxy.js +47 -7
  30. package/dist/lib/storage.d.ts +20 -2
  31. package/dist/lib/storage.d.ts.map +1 -1
  32. package/dist/lib/storage.js +69 -25
  33. package/package.json +1 -1
  34. package/scripts/codex-routing.js +1 -0
  35. package/scripts/codex.js +157 -2
@@ -0,0 +1,158 @@
1
+ import { formatAccountLabel } from "../../accounts.js";
2
+ import { MODEL_FAMILIES } from "../../prompts/codex.js";
3
+ import { findQuotaCacheEntryForAccount } from "../../quota-readiness.js";
4
+ import { redactEmails } from "../../redaction.js";
5
+ const LIMITS_SCHEMA_VERSION = 1;
6
+ const LIMITS_REFRESH_MAX_AGE_MS = 5 * 60_000;
7
+ const LIMITS_USAGE = "Usage: codex-multi-auth limits --json [--refresh]";
8
+ /** Parse the intentionally small, JSON-only limits command surface. */
9
+ function parseLimitsOptions(args) {
10
+ const options = { json: false, refresh: false, help: false };
11
+ for (const arg of args) {
12
+ if (arg === "--json" || arg === "-j") {
13
+ options.json = true;
14
+ continue;
15
+ }
16
+ if (arg === "--refresh") {
17
+ options.refresh = true;
18
+ continue;
19
+ }
20
+ if (arg === "--help" || arg === "-h") {
21
+ options.help = true;
22
+ continue;
23
+ }
24
+ return { ok: false, message: `Unknown limits option: ${arg}` };
25
+ }
26
+ if (!options.json && !options.help) {
27
+ return { ok: false, message: LIMITS_USAGE };
28
+ }
29
+ return { ok: true, options };
30
+ }
31
+ /** Convert a cached quota window to the explicit-null public JSON contract. */
32
+ function publicWindow(window) {
33
+ return {
34
+ usedPercent: window.usedPercent ?? null,
35
+ windowMinutes: window.windowMinutes ?? null,
36
+ resetAtMs: window.resetAtMs ?? null,
37
+ };
38
+ }
39
+ /** Remove internal probe metadata and stabilize optional quota fields. */
40
+ function publicQuotaEntry(entry) {
41
+ return {
42
+ updatedAt: entry.updatedAt,
43
+ status: entry.status,
44
+ planType: entry.planType ?? null,
45
+ primary: publicWindow(entry.primary),
46
+ secondary: publicWindow(entry.secondary),
47
+ };
48
+ }
49
+ /**
50
+ * Emit configured accounts joined to safe cached quota records.
51
+ *
52
+ * Cached mode performs no provider requests. Refresh mode delegates to the
53
+ * existing sequential, age-gated refresh path before serializing the snapshot.
54
+ */
55
+ export async function runLimitsCommand(args, deps) {
56
+ const parsed = parseLimitsOptions(args);
57
+ const logInfo = deps.logInfo ?? console.log;
58
+ const logError = deps.logError ?? console.error;
59
+ if (!parsed.ok) {
60
+ logError(parsed.message);
61
+ return 1;
62
+ }
63
+ if (parsed.options.help) {
64
+ logInfo(LIMITS_USAGE);
65
+ return 0;
66
+ }
67
+ deps.setStoragePath(null);
68
+ const storage = await deps.loadAccounts();
69
+ if (!storage || storage.accounts.length === 0) {
70
+ const generatedAt = deps.getNow?.() ?? Date.now();
71
+ logInfo(JSON.stringify({
72
+ schemaVersion: LIMITS_SCHEMA_VERSION,
73
+ generatedAt,
74
+ mode: parsed.options.refresh ? "refresh" : "cached",
75
+ // Keep the key set identical for an empty pool so a consumer
76
+ // never has to branch on its presence. There is no account to
77
+ // route to, so `routedIndex` is null rather than a positional 0
78
+ // that addresses nothing.
79
+ selection: {
80
+ pinnedIndex: null,
81
+ routedIndex: null,
82
+ activeIndexByFamily: {},
83
+ },
84
+ accounts: [],
85
+ }, null, 2));
86
+ return 0;
87
+ }
88
+ let cache = await deps.loadQuotaCache();
89
+ if (parsed.options.refresh) {
90
+ cache = await deps.refreshQuotaCache(storage, cache, LIMITS_REFRESH_MAX_AGE_MS);
91
+ }
92
+ const generatedAt = deps.getNow?.() ?? Date.now();
93
+ const selection = resolveSelection(storage, deps.resolveActiveIndex);
94
+ const accounts = storage.accounts.map((account, index) => {
95
+ const quota = findQuotaCacheEntryForAccount(cache, account, storage.accounts);
96
+ return {
97
+ index,
98
+ // Labels are built from the account email. Mask it, exactly as
99
+ // `forecast --json` already does, so a snapshot written to a log
100
+ // shipper or a ticket does not carry the address.
101
+ label: redactEmails(formatAccountLabel(account, index)),
102
+ enabled: account.enabled !== false,
103
+ current: index === selection.routedIndex,
104
+ quota: quota ? publicQuotaEntry(quota) : null,
105
+ };
106
+ });
107
+ logInfo(JSON.stringify({
108
+ schemaVersion: LIMITS_SCHEMA_VERSION,
109
+ generatedAt,
110
+ mode: parsed.options.refresh ? "refresh" : "cached",
111
+ selection,
112
+ accounts,
113
+ }, null, 2));
114
+ return 0;
115
+ }
116
+ /**
117
+ * The CONFIGURED routing target, and the state that decides it.
118
+ *
119
+ * `current` cannot be `activeIndexByFamily.codex` alone. The runtime proxy
120
+ * routes on `pinnedAccountIndex` whenever a `switch` pin is set, and flows that
121
+ * move the active index without touching the pin (rotation saves, `unpin`, an
122
+ * ephemeral `--account`) would otherwise leave `current: true` on a row that is
123
+ * not the configured target. Both inputs are emitted so a consumer can tell
124
+ * which one applied, and the per-family map is emitted because a pool can hold
125
+ * a different active index per family.
126
+ *
127
+ * This is deliberately NOT a prediction of which account the next request
128
+ * lands on. The proxy skips an account that is disabled, inside a rate-limit
129
+ * window, cooling down, or behind an open circuit breaker, and it applies
130
+ * session affinity and an ephemeral `--account` override that never touch
131
+ * storage. Reproducing that here would mean a third copy of the selector
132
+ * (`why-selected` and `forecast` already own live selection), and a snapshot
133
+ * read from a cache cannot be authoritative about it in any case. Consumers
134
+ * that need liveness have `enabled` on every row and `why-selected --json`.
135
+ *
136
+ * `routedIndex` is null only for an empty pool, where no row is `current`.
137
+ */
138
+ function resolveSelection(storage, resolveActiveIndex) {
139
+ if (storage.accounts.length === 0) {
140
+ return { pinnedIndex: null, routedIndex: null, activeIndexByFamily: {} };
141
+ }
142
+ const activeIndexByFamily = {};
143
+ for (const family of MODEL_FAMILIES) {
144
+ activeIndexByFamily[family] = resolveActiveIndex(storage, family);
145
+ }
146
+ const rawPin = storage.pinnedAccountIndex;
147
+ const pinnedIndex = typeof rawPin === "number" &&
148
+ Number.isInteger(rawPin) &&
149
+ rawPin >= 0 &&
150
+ rawPin < storage.accounts.length
151
+ ? rawPin
152
+ : null;
153
+ return {
154
+ pinnedIndex,
155
+ routedIndex: pinnedIndex ?? activeIndexByFamily.codex ?? 0,
156
+ activeIndexByFamily,
157
+ };
158
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/help.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,IAAI,IAAI,CAsDjC;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GACvC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAuGtE;AAED,UAAU,cAAc;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,cAAc,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GACrC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,wBAAgB,cAAc,IAAI,IAAI,CAgBrC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,cAAc,CAyD5D"}
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/help.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,IAAI,IAAI,CAuDjC;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GACvC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAuGtE;AAED,UAAU,cAAc;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,cAAc,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GACrC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,wBAAgB,cAAc,IAAI,IAAI,CAgBrC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,cAAc,CAyD5D"}
@@ -8,6 +8,7 @@ export function printUsage() {
8
8
  " codex-multi-auth login [--device-auth|--manual|--no-browser] [--org <org_id>] [--preserve-selection] [--account <index|email|account_id>]",
9
9
  " codex-multi-auth status [--json] (list is the same command)",
10
10
  " codex-multi-auth check (always live-probes)",
11
+ " codex-multi-auth limits --json [--refresh] (structured quota windows; refresh is age-gated)",
11
12
  "",
12
13
  "Daily use:",
13
14
  " codex-multi-auth list [--json]",
@@ -1 +1 @@
1
- {"version":3,"file":"persist-selected-account.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/persist-selected-account.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACN,KAAK,gBAAgB,EAIrB,MAAM,eAAe,CAAC;AAQvB;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CAAC,EACnD,OAAO,EACP,WAAW,EACX,MAAM,EACN,YAAY,EACZ,kBAAkB,EAClB,2BAAmC,EACnC,MAAc,EACd,QAAgB,EAChB,sBAA8B,GAC9B,EAAE;IACF,OAAO,EAAE,gBAAgB,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACjC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CAqGrD"}
1
+ {"version":3,"file":"persist-selected-account.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/persist-selected-account.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACN,KAAK,gBAAgB,EAIrB,MAAM,eAAe,CAAC;AAQvB;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CAAC,EACnD,OAAO,EACP,WAAW,EACX,MAAM,EACN,YAAY,EACZ,kBAAkB,EAClB,2BAAmC,EACnC,MAAc,EACd,QAAgB,EAChB,sBAA8B,GAC9B,EAAE;IACF,OAAO,EAAE,gBAAgB,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACjC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CAmHrD"}
@@ -77,6 +77,20 @@ export async function persistAndSyncSelectedAccount({ storage, targetIndex, pars
77
77
  account.lastSwitchReason = switchReason;
78
78
  if (setPin) {
79
79
  storage.pinnedAccountIndex = targetIndex;
80
+ // A manual switch requests a fresh upstream attempt, including when
81
+ // reselecting the same account after an out-of-band quota reset. Real 429
82
+ // responses will populate these markers again.
83
+ //
84
+ // `setPin` is the right trigger because it is set only by `switch` (which
85
+ // the login dashboard's account picker also routes through), i.e. exactly
86
+ // the paths where a person picked this account. `best` passes `clearPin`
87
+ // and a backup restore passes neither, and neither of those is a request
88
+ // to revalidate a rate-limited account.
89
+ //
90
+ // Delete rather than assign `{}`: `AccountManager.buildStorageSnapshot`
91
+ // omits the field when the map is empty, so assigning would persist a
92
+ // second on-disk shape for the same state.
93
+ delete account.rateLimitResetTimes;
80
94
  }
81
95
  else if (clearPin) {
82
96
  delete storage.pinnedAccountIndex;
@@ -1 +1 @@
1
- {"version":3,"file":"codex-manager.d.ts","sourceRoot":"","sources":["../../lib/codex-manager.ts"],"names":[],"mappings":"AA2DA,OAAO,EAIN,yBAAyB,EACzB,MAAM,eAAe,CAAC;AA4BvB,OAAO,EAEN,mBAAmB,EAMnB,sBAAsB,EAGtB,MAAM,qCAAqC,CAAC;AA+B7C,OAAO,EAEN,KAAK,gBAAgB,EAWrB,MAAM,cAAc,CAAC;AAKtB,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;AA4IvD,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAuGrE;AACD,mFAAmF;AACnF,wBAAgB,wBAAwB,IAAI,CAC3C,OAAO,EAAE,gBAAgB,KACrB,OAAO,CAAC,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAwEzD;AAmPD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA4C7E"}
1
+ {"version":3,"file":"codex-manager.d.ts","sourceRoot":"","sources":["../../lib/codex-manager.ts"],"names":[],"mappings":"AA4DA,OAAO,EAIN,yBAAyB,EACzB,MAAM,eAAe,CAAC;AA6BvB,OAAO,EAEN,mBAAmB,EAMnB,sBAAsB,EAGtB,MAAM,qCAAqC,CAAC;AA+B7C,OAAO,EAEN,KAAK,gBAAgB,EAWrB,MAAM,cAAc,CAAC;AAKtB,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;AA4IvD,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAuGrE;AACD,mFAAmF;AACnF,wBAAgB,wBAAwB,IAAI,CAC3C,OAAO,EAAE,gBAAgB,KACrB,OAAO,CAAC,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC,CAwEzD;AA8PD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA4C7E"}
@@ -14,6 +14,7 @@ import { runBudgetCommand } from "./codex-manager/commands/budget.js";
14
14
  import { runBridgeCommand } from "./codex-manager/commands/bridge.js";
15
15
  import { runCheckCommand } from "./codex-manager/commands/check.js";
16
16
  import { runIntegrationsCommand } from "./codex-manager/commands/integrations.js";
17
+ import { runLimitsCommand } from "./codex-manager/commands/limits.js";
17
18
  import { runModelsCommand } from "./codex-manager/commands/models.js";
18
19
  import { runMonitorCommand } from "./codex-manager/commands/monitor.js";
19
20
  import { runConfigExplainCommand } from "./codex-manager/commands/config-explain.js";
@@ -37,6 +38,7 @@ import { runHistoryCommand } from "./codex-manager/commands/history.js";
37
38
  import { runUnpinCommand } from "./codex-manager/commands/unpin.js";
38
39
  import { runWorkspaceCommand } from "./codex-manager/commands/workspace.js";
39
40
  import { runUsageCommand } from "./codex-manager/commands/usage.js";
41
+ import { refreshQuotaCacheForMenu } from "./codex-manager/login-menu-data.js";
40
42
  import { printUsage } from "./codex-manager/help.js";
41
43
  import { availabilityTone, formatBackupSavedAt, formatCompactQuotaSnapshot, formatRateLimitEntry, formatResultSummary, normalizeFailureDetail, riskTone, styleAccountDetailText, stylePromptText, styleQuotaSummary, } from "./codex-manager/formatters/index.js";
42
44
  import { applyUiThemeFromDashboardSettings } from "./codex-manager/settings-hub.js";
@@ -376,6 +378,16 @@ const CLI_COMMAND_HANDLERS = new Map([
376
378
  ["login", (rest) => runAuthLogin(rest, { runForecast, createRepairCommandDeps })],
377
379
  ["list", runListOrStatusCommand],
378
380
  ["status", runListOrStatusCommand],
381
+ [
382
+ "limits",
383
+ (rest) => runLimitsCommand(rest, {
384
+ setStoragePath,
385
+ loadAccounts,
386
+ loadQuotaCache,
387
+ refreshQuotaCache: refreshQuotaCacheForMenu,
388
+ resolveActiveIndex,
389
+ }),
390
+ ],
379
391
  [
380
392
  "switch",
381
393
  (rest) => runSwitchCommand(rest, {
@@ -1 +1 @@
1
- {"version":3,"file":"forecast.d.ts","sourceRoot":"","sources":["../../lib/forecast.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"forecast.d.ts","sourceRoot":"","sources":["../../lib/forecast.ts"],"names":[],"mappings":"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"}
@@ -1,25 +1,12 @@
1
1
  import { AUTH_INVALIDATION_MARKER, formatAccountLabel, formatWaitTime, } from "./accounts.js";
2
2
  import { findQuotaCacheEntryForAccount, isQuotaCacheEntryExhausted, quotaUsedPercentIsExhausted, } from "./quota-readiness.js";
3
+ import { redactEmails } from "./redaction.js";
3
4
  import { getRateLimitResetTimeForFamily, getRateLimitResetTimeForModel, } from "./runtime/account-status.js";
4
5
  function clampRisk(score) {
5
6
  if (!Number.isFinite(score))
6
7
  return 100;
7
8
  return Math.max(0, Math.min(100, Math.round(score)));
8
9
  }
9
- function maskEmail(value) {
10
- const atIndex = value.indexOf("@");
11
- if (atIndex <= 0)
12
- return "***@***";
13
- const local = value.slice(0, atIndex);
14
- const domain = value.slice(atIndex + 1);
15
- const domainParts = domain.split(".");
16
- const tld = domainParts.pop() ?? "";
17
- const prefix = local.slice(0, Math.min(2, local.length));
18
- return `${prefix}***@***.${tld || "***"}`;
19
- }
20
- function redactEmails(value) {
21
- return value.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, (match) => maskEmail(match));
22
- }
23
10
  function redactSensitiveReason(value) {
24
11
  return redactEmails(value
25
12
  .replace(/Bearer\s+\S+/gi, "Bearer ***")
@@ -48,6 +48,18 @@ export declare class PreemptiveQuotaScheduler {
48
48
  update(key: string, snapshot: QuotaSchedulerSnapshot): void;
49
49
  markRateLimited(key: string, retryAfterMs: number, now?: number): void;
50
50
  getDeferral(key: string, now?: number): QuotaDeferralDecision;
51
+ /**
52
+ * Forget cached quota observations for one account across its model keys.
53
+ *
54
+ * @param prefix Account key INCLUDING its trailing separator, as produced by
55
+ * `buildQuotaScheduleAccountPrefix`. Without that separator the prefix also
56
+ * matches neighbouring identities (`account:email:foo` matches
57
+ * `account:email:foobar:codex`). An empty prefix is a no-op rather than a
58
+ * silent clear-all; use `clearAll()` when that is the intent.
59
+ */
60
+ clearByPrefix(prefix: string): void;
61
+ /** Forget every cached quota observation. */
62
+ clearAll(): void;
51
63
  prune(now?: number): number;
52
64
  }
53
65
  //# sourceMappingURL=preemptive-quota-scheduler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"preemptive-quota-scheduler.d.ts","sourceRoot":"","sources":["../../lib/preemptive-quota-scheduler.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;IAC9B,SAAS,EAAE,oBAAoB,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,GAAG,uBAAuB,CAAC;CAChD;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,kCAAkC,CAAC,EAAE,MAAM,CAAC;IAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AA6GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,sBAAsB,GAAG,IAAI,CAqB5H;AAED,qBAAa,wBAAwB;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6C;IACvE,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,gCAAgC,CAAS;IACjD,OAAO,CAAC,kCAAkC,CAAS;IACnD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAK;gBAEZ,OAAO,GAAE,qBAA0B;IAQ/C,SAAS,CAAC,OAAO,GAAE,qBAA0B,GAAG,IAAI;IA2CpD,OAAO,CAAC,UAAU;IAMlB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAM3D,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IA8B1E,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,qBAAqB;IAkEjE,KAAK,CAAC,GAAG,SAAa,GAAG,MAAM;CAW/B"}
1
+ {"version":3,"file":"preemptive-quota-scheduler.d.ts","sourceRoot":"","sources":["../../lib/preemptive-quota-scheduler.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;IAC9B,SAAS,EAAE,oBAAoB,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,GAAG,uBAAuB,CAAC;CAChD;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,kCAAkC,CAAC,EAAE,MAAM,CAAC;IAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AA6GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,sBAAsB,GAAG,IAAI,CAqB5H;AAED,qBAAa,wBAAwB;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6C;IACvE,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,gCAAgC,CAAS;IACjD,OAAO,CAAC,kCAAkC,CAAS;IACnD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAK;gBAEZ,OAAO,GAAE,qBAA0B;IAQ/C,SAAS,CAAC,OAAO,GAAE,qBAA0B,GAAG,IAAI;IA2CpD,OAAO,CAAC,UAAU;IAMlB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAM3D,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IA8B1E,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,qBAAqB;IAkEjE;;;;;;;;OAQG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAOnC,6CAA6C;IAC7C,QAAQ,IAAI,IAAI;IAIhB,KAAK,CAAC,GAAG,SAAa,GAAG,MAAM;CAW/B"}
@@ -264,6 +264,27 @@ export class PreemptiveQuotaScheduler {
264
264
  }
265
265
  return { defer: false, waitMs: 0 };
266
266
  }
267
+ /**
268
+ * Forget cached quota observations for one account across its model keys.
269
+ *
270
+ * @param prefix Account key INCLUDING its trailing separator, as produced by
271
+ * `buildQuotaScheduleAccountPrefix`. Without that separator the prefix also
272
+ * matches neighbouring identities (`account:email:foo` matches
273
+ * `account:email:foobar:codex`). An empty prefix is a no-op rather than a
274
+ * silent clear-all; use `clearAll()` when that is the intent.
275
+ */
276
+ clearByPrefix(prefix) {
277
+ if (!prefix)
278
+ return;
279
+ for (const key of this.snapshots.keys()) {
280
+ if (key.startsWith(prefix))
281
+ this.snapshots.delete(key);
282
+ }
283
+ }
284
+ /** Forget every cached quota observation. */
285
+ clearAll() {
286
+ this.snapshots.clear();
287
+ }
267
288
  prune(now = Date.now()) {
268
289
  let removed = 0;
269
290
  for (const [key, snapshot] of this.snapshots.entries()) {
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Email redaction for machine-readable command output.
3
+ *
4
+ * Account labels are built from the operator-visible email, so any command that
5
+ * emits them as JSON hands that address to whatever consumes the output: log
6
+ * shippers, dashboards, ticket attachments. `forecast --json` has masked them
7
+ * since it was written; this module is that same masking, shared so other JSON
8
+ * surfaces do not each re-derive it.
9
+ */
10
+ /**
11
+ * Mask one address, keeping just enough to tell two accounts apart: the first
12
+ * two characters of the local part and the TLD.
13
+ */
14
+ export declare function maskEmail(value: string): string;
15
+ /** Mask every address embedded in a free-text string. */
16
+ export declare function redactEmails(value: string): string;
17
+ //# sourceMappingURL=redaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../lib/redaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS/C;AAED,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Email redaction for machine-readable command output.
3
+ *
4
+ * Account labels are built from the operator-visible email, so any command that
5
+ * emits them as JSON hands that address to whatever consumes the output: log
6
+ * shippers, dashboards, ticket attachments. `forecast --json` has masked them
7
+ * since it was written; this module is that same masking, shared so other JSON
8
+ * surfaces do not each re-derive it.
9
+ */
10
+ /**
11
+ * Mask one address, keeping just enough to tell two accounts apart: the first
12
+ * two characters of the local part and the TLD.
13
+ */
14
+ export function maskEmail(value) {
15
+ const atIndex = value.indexOf("@");
16
+ if (atIndex <= 0)
17
+ return "***@***";
18
+ const local = value.slice(0, atIndex);
19
+ const domain = value.slice(atIndex + 1);
20
+ const domainParts = domain.split(".");
21
+ const tld = domainParts.pop() ?? "";
22
+ const prefix = local.slice(0, Math.min(2, local.length));
23
+ return `${prefix}***@***.${tld || "***"}`;
24
+ }
25
+ /** Mask every address embedded in a free-text string. */
26
+ export function redactEmails(value) {
27
+ return value.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, (match) => maskEmail(match));
28
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"rotation-storage-meta.d.ts","sourceRoot":"","sources":["../../../lib/runtime/rotation-storage-meta.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAqCnE,MAAM,WAAW,WAAW;IAC3B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,kBAAkB,EAAE,MAAM,CAAC;CAC3B;AA8BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACtC,WAAW,GAAE,MAAyB,GACpC,WAAW,CAmFb;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC7C,WAAW,GAAE,MAAyB,GACpC,MAAM,GAAG,IAAI,CAEf;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC9C,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,EACjD,sBAAsB,EAAE,MAAM,EAC9B,WAAW,GAAE,MAAyB,GACpC,MAAM,CAOR"}
1
+ {"version":3,"file":"rotation-storage-meta.d.ts","sourceRoot":"","sources":["../../../lib/runtime/rotation-storage-meta.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAqCnE,MAAM,WAAW,WAAW;IAC3B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,kBAAkB,EAAE,MAAM,CAAC;CAC3B;AA8BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACtC,WAAW,GAAE,MAAyB,GACpC,WAAW,CAsFb;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC7C,WAAW,GAAE,MAAyB,GACpC,MAAM,GAAG,IAAI,CAEf;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC9C,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,EACjD,sBAAsB,EAAE,MAAM,EAC9B,WAAW,GAAE,MAAyB,GACpC,MAAM,CAOR"}
@@ -90,7 +90,10 @@ export function readStorageMetaFromDisk(storagePath = getStoragePath()) {
90
90
  : null;
91
91
  const affinityGeneration = typeof parsed.affinityGeneration === "number" &&
92
92
  Number.isFinite(parsed.affinityGeneration) &&
93
- Number.isInteger(parsed.affinityGeneration) &&
93
+ // Safe, not merely integral: see readAffinityGenerationFromDisk. Past
94
+ // 2^53 the CLI's bump stops advancing, so a proxy that accepted the
95
+ // value would never observe another switch.
96
+ Number.isSafeInteger(parsed.affinityGeneration) &&
94
97
  parsed.affinityGeneration >= 0
95
98
  ? parsed.affinityGeneration
96
99
  : 0;
@@ -8,6 +8,19 @@ export { chooseAccount } from "./runtime/rotation-account-selection.js";
8
8
  export { maybeInvalidateAffinityFromDisk, readPinnedAccountIndexFromDisk, readStorageMetaFromDisk, resetPinCacheForTesting, } from "./runtime/rotation-storage-meta.js";
9
9
  export type { StorageMeta } from "./runtime/rotation-storage-meta.js";
10
10
  /** @internal Stable identity key for in-memory quota snapshots across reloads. */
11
+ /**
12
+ * Quota-scheduler key prefix identifying ONE account across every family and
13
+ * model key it owns.
14
+ *
15
+ * The trailing separator is part of the contract: without it the prefix
16
+ * `account:email:foo` also matches `account:email:foobar:codex`, so clearing
17
+ * one account's observations would silently clear a neighbour's.
18
+ */
19
+ export declare function buildQuotaScheduleAccountPrefix(account: Pick<ManagedAccount, "accountId" | "email" | "refreshToken"> & {
20
+ /** Stable per-record discriminator retained across token/account-id updates. */
21
+ addedAt?: number;
22
+ recordId?: string;
23
+ }): string;
11
24
  export declare function buildQuotaScheduleKey(account: Pick<ManagedAccount, "accountId" | "email" | "refreshToken"> & {
12
25
  /** Stable per-record discriminator retained across token/account-id updates. */
13
26
  addedAt?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AAkCvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAkDtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAmBR;AA8gBD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CAmLrC"}
1
+ {"version":3,"file":"runtime-rotation-proxy.d.ts","sourceRoot":"","sources":["../../lib/runtime-rotation-proxy.ts"],"names":[],"mappings":"AAGA,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,eAAe,CAAC;AAkCvB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAkDtE,OAAO,KAAK,EAKX,2BAA2B,EAC3B,0BAA0B,EAE1B,MAAM,oCAAoC,CAAC;AAe5C,YAAY,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACN,+BAA+B,EAC/B,0BAA0B,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EACN,+BAA+B,EAC/B,8BAA8B,EAC9B,uBAAuB,EACvB,uBAAuB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AA8DtE,kFAAkF;AAClF;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,GACC,MAAM,CAmBR;AAED,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC,GAAG;IACvE,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,EACD,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAER;AA8gBD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,MAAM,GAAG,IAAI,CAUf;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CAmLrC"}
@@ -80,7 +80,15 @@ const PINNED_PERMANENT_SKIP_REASONS = new Set([
80
80
  ]);
81
81
  const DEFAULT_QUOTA_REMAINING_THRESHOLD = 10;
82
82
  /** @internal Stable identity key for in-memory quota snapshots across reloads. */
83
- export function buildQuotaScheduleKey(account, family, model) {
83
+ /**
84
+ * Quota-scheduler key prefix identifying ONE account across every family and
85
+ * model key it owns.
86
+ *
87
+ * The trailing separator is part of the contract: without it the prefix
88
+ * `account:email:foo` also matches `account:email:foobar:codex`, so clearing
89
+ * one account's observations would silently clear a neighbour's.
90
+ */
91
+ export function buildQuotaScheduleAccountPrefix(account) {
84
92
  const emailKey = normalizeEmailKey(account.email);
85
93
  const accountId = account.accountId?.trim();
86
94
  const refreshToken = account.refreshToken?.trim() ?? "";
@@ -97,7 +105,10 @@ export function buildQuotaScheduleKey(account, family, model) {
97
105
  : accountId
98
106
  ? `id:${accountId}${recordDiscriminator}`
99
107
  : `refresh:${createHash("sha256").update(refreshToken).digest("hex")}${recordDiscriminator}`;
100
- return `account:${accountIdentity}:${model ?? family}`;
108
+ return `account:${accountIdentity}:`;
109
+ }
110
+ export function buildQuotaScheduleKey(account, family, model) {
111
+ return `${buildQuotaScheduleAccountPrefix(account)}${model ?? family}`;
101
112
  }
102
113
  const DEFAULT_MAX_RUNTIME_ACCOUNT_ATTEMPTS = 4;
103
114
  // This is a hard safety ceiling over every pinned selection pass, including
@@ -862,7 +873,37 @@ async function handleRequestInner(state, req, res, traceId) {
862
873
  // otherwise glue an in-flight chat thread to the previously selected
863
874
  // account. The proxy itself never bumps the generation, so its own
864
875
  // debounced disk writes do not clear affinity. See issue #474.
865
- const storageMeta = readStorageMetaFromDisk();
876
+ /** Reconcile once before selection or recording a new upstream observation. */
877
+ const reconcileManualSelection = () => {
878
+ const meta = readStorageMetaFromDisk();
879
+ for (const manager of state.knownAccountManagers) {
880
+ manager.applyManualSelection(meta);
881
+ }
882
+ if (meta.affinityGeneration > state.lastObservedAffinityGeneration) {
883
+ const switchedAccount = meta.pinnedAccountIndex === null
884
+ ? null
885
+ : accountManager.getAccountByIndex(meta.pinnedAccountIndex);
886
+ if (switchedAccount) {
887
+ state.preemptiveQuotaScheduler.clearByPrefix(buildQuotaScheduleAccountPrefix(switchedAccount));
888
+ }
889
+ else if (meta.pinnedAccountIndex !== null) {
890
+ // A pin we cannot resolve: this long-lived proxy re-reads only
891
+ // pin/gen, never the account list, so a `login` that appended an
892
+ // account before the `switch` leaves the new index out of range
893
+ // here. The generation only bumps on the NEXT user-initiated
894
+ // switch, so skipping the clear and advancing anyway would strand
895
+ // the pre-switch quota observation forever, which is the exact
896
+ // deferral this reconciliation exists to end. Drop every cached
897
+ // observation instead: it only costs a re-probe, and real 429
898
+ // windows live on the accounts themselves, not in this cache.
899
+ state.preemptiveQuotaScheduler.clearAll();
900
+ }
901
+ state.sessionAffinityStore?.clearAll();
902
+ state.lastObservedAffinityGeneration = meta.affinityGeneration;
903
+ }
904
+ return meta;
905
+ };
906
+ const storageMeta = reconcileManualSelection();
866
907
  // The ephemeral --account pin (issue #623) takes precedence over the
867
908
  // persisted `switch` pin for this invocation, without ever mutating disk
868
909
  // state. Use `??` (not `||`) so a forced index of 0 is honored. When set,
@@ -899,10 +940,6 @@ async function handleRequestInner(state, req, res, traceId) {
899
940
  if (isPinned) {
900
941
  transientAttemptLimit = Math.max(1, Math.min(state.maxRuntimeAccountAttempts, MAX_PINNED_TRANSIENT_ATTEMPTS));
901
942
  }
902
- if (storageMeta.affinityGeneration > state.lastObservedAffinityGeneration) {
903
- state.sessionAffinityStore?.clearAll();
904
- state.lastObservedAffinityGeneration = storageMeta.affinityGeneration;
905
- }
906
943
  let runtimeSelectionIterations = 0;
907
944
  while ((isPinned || attemptedIndexes.size < accountCount) &&
908
945
  transientAttempts < transientAttemptLimit &&
@@ -1153,6 +1190,7 @@ async function handleRequestInner(state, req, res, traceId) {
1153
1190
  noteRotation();
1154
1191
  continue;
1155
1192
  }
1193
+ reconcileManualSelection();
1156
1194
  const quotaSnapshot = readQuotaSchedulerSnapshot(upstream.headers, upstream.status, state.now());
1157
1195
  if (quotaSnapshot) {
1158
1196
  state.preemptiveQuotaScheduler.update(quotaScheduleKey, quotaSnapshot);
@@ -1162,6 +1200,8 @@ async function handleRequestInner(state, req, res, traceId) {
1162
1200
  const retryAfterMs = parseRetryAfterHeaderMs(upstream.headers, state.now()) ??
1163
1201
  parseRetryAfterBodyMs(bodyText, state.now()) ??
1164
1202
  60_000;
1203
+ // Reading the body awaited I/O; a switch may have landed meanwhile.
1204
+ reconcileManualSelection();
1165
1205
  state.preemptiveQuotaScheduler.markRateLimited(quotaScheduleKey, retryAfterMs, state.now());
1166
1206
  // A 429 is the upstream quota signal for the attempted account, so
1167
1207
  // keep the consumed runtime token drained.
@@ -109,9 +109,27 @@ export declare function bumpStorageAffinityGeneration(storage: {
109
109
  * persisting routine state (rate-limit hits, cooldowns, etc.) so a CLI
110
110
  * `switch`/`unpin` that landed between proxy startup and the save is not
111
111
  * clobbered. Returns `pinnedAccountIndex: undefined` and
112
- * `affinityGeneration: 0` on any failure. See issue #474.
112
+ * `affinityGeneration: 0` on any failure by default. See issue #474.
113
+ *
114
+ * `strict` callers additionally need to know when the metadata could not be
115
+ * OBSERVED AT ALL, because persisting a stale in-memory pin over a newer disk
116
+ * pin is exactly the #474 regression. Strict mode therefore throws for the two
117
+ * cases where a newer selection may be hiding behind the failure:
118
+ * - the file exists but cannot be read (EBUSY/EPERM/EACCES: on Windows an AV
119
+ * scanner or indexer can hold accounts.json open), and
120
+ * - the bytes are not valid JSON (a torn read of a concurrent atomic write).
121
+ *
122
+ * A MISSING file and a successfully parsed file with INVALID field values are
123
+ * deliberately not failures, in either mode. Neither can be concealing a newer
124
+ * pin (there is no file, or we can see the whole file and the field is
125
+ * unusable), and both are self-repaired by the very write that follows. Making
126
+ * them throw would wedge persistence permanently, since recreating or repairing
127
+ * storage goes through the same save path, and it would take every rate-limit
128
+ * window, cooldown and rotated refresh token in memory down with it.
113
129
  */
114
- export declare function readPinAndGenFromDisk(path: string): {
130
+ export declare function readPinAndGenFromDisk(path: string, options?: {
131
+ strict?: boolean;
132
+ }): {
115
133
  pinnedAccountIndex: number | undefined;
116
134
  affinityGeneration: number;
117
135
  };
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"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"}