codex-multi-auth 2.3.0-beta.3 → 2.3.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-multi-auth",
3
- "version": "2.3.0-beta.3",
3
+ "version": "2.3.1",
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
@@ -383,8 +383,9 @@ codex-multi-auth doctor --json
383
383
 
384
384
  ## Release Notes
385
385
 
386
- - Current prerelease: [docs/releases/v2.3.0-beta.3.md](docs/releases/v2.3.0-beta.3.md) — install via `npm i -g codex-multi-auth@beta`
387
- - Current stable: [docs/releases/v2.2.2.md](docs/releases/v2.2.2.md) — install via `npm i -g codex-multi-auth`
386
+ - Current stable: [docs/releases/v2.3.1.md](docs/releases/v2.3.1.md) — install via `npm i -g codex-multi-auth`
387
+ - Previous stable: [docs/releases/v2.3.0.md](docs/releases/v2.3.0.md)
388
+ - Previous stable: [docs/releases/v2.2.2.md](docs/releases/v2.2.2.md)
388
389
  - Previous stable: [docs/releases/v2.2.1.md](docs/releases/v2.2.1.md)
389
390
  - Previous stable: [docs/releases/v2.2.0.md](docs/releases/v2.2.0.md)
390
391
  - Previous stable: [docs/releases/v2.1.12.md](docs/releases/v2.1.12.md)
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,kBAAkB,CAAC;AA2V5D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MAquI/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,KAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,kBAAkB,CAAC;AA2V5D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MA2uI/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,KAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -1360,6 +1360,12 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1360
1360
  // regardless of the cooldown mark (AUDIT-H3 / D-07).
1361
1361
  accountManager.markRateLimitedWithReason(account, cooldownMs, modelFamily, parseRateLimitReason(rateLimit?.code), model);
1362
1362
  accountManager.recordRateLimit(account, modelFamily, model);
1363
+ // Persist the rate-limit window like the full-rotation
1364
+ // branch below (line ~2327). markRateLimitedWithReason
1365
+ // mutates `rateLimitResetTimes`, which is serialized to
1366
+ // disk; without this a crash during the retry sleep loses
1367
+ // the cooldown and the account is re-selected on restart.
1368
+ accountManager.saveToDiskDebounced();
1363
1369
  if (accountManager.shouldShowAccountToast(account.index, rateLimitToastDebounceMs)) {
1364
1370
  await showRuntimeToast(client, `Rate limited. Retrying in ${waitLabel} (attempt ${shortRateLimitRetryCount})...`, "warning", { duration: toastDurationMs });
1365
1371
  accountManager.markToastShown(account.index);
@@ -16,6 +16,14 @@ export interface RateLimitedEntity {
16
16
  rateLimitResetTimes: RateLimitState;
17
17
  }
18
18
  export declare function clearExpiredRateLimits(entity: RateLimitedEntity): void;
19
+ /**
20
+ * Remove every rate-limit reset entry from `entity`, regardless of whether the
21
+ * window has expired. Unlike {@link clearExpiredRateLimits}, this drops
22
+ * still-future entries too. Used by the stale-runtime recovery path to give a
23
+ * reloaded account pool a clean slate so transient state persisted to disk
24
+ * cannot keep the pool wedged (issue #606).
25
+ */
26
+ export declare function clearAllRateLimits(entity: RateLimitedEntity): void;
19
27
  export declare function isRateLimitedForQuotaKey(entity: RateLimitedEntity, key: QuotaKey): boolean;
20
28
  export declare function isRateLimitedForFamily(entity: RateLimitedEntity, family: ModelFamily, model?: string | null): boolean;
21
29
  export declare function formatWaitTime(ms: number): string;
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limits.d.ts","sourceRoot":"","sources":["../../../lib/accounts/rate-limits.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC;AACvC,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,GAAG,YAAY,IAAI,MAAM,EAAE,CAAC;AAElE,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;AAE5E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,eAAe,CAO9E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAKhF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK5E;AAED,MAAM,WAAW,cAAc;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IACjC,mBAAmB,EAAE,cAAc,CAAC;CACpC;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAStE;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAG1F;AAED,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO,CAYT;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAMjD"}
1
+ {"version":3,"file":"rate-limits.d.ts","sourceRoot":"","sources":["../../../lib/accounts/rate-limits.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC;AACvC,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,GAAG,YAAY,IAAI,MAAM,EAAE,CAAC;AAElE,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;AAE5E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,eAAe,CAO9E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAKhF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK5E;AAED,MAAM,WAAW,cAAc;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IACjC,mBAAmB,EAAE,cAAc,CAAC;CACpC;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAStE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAKlE;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAG1F;AAED,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO,CAYT;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAMjD"}
@@ -37,6 +37,19 @@ export function clearExpiredRateLimits(entity) {
37
37
  }
38
38
  }
39
39
  }
40
+ /**
41
+ * Remove every rate-limit reset entry from `entity`, regardless of whether the
42
+ * window has expired. Unlike {@link clearExpiredRateLimits}, this drops
43
+ * still-future entries too. Used by the stale-runtime recovery path to give a
44
+ * reloaded account pool a clean slate so transient state persisted to disk
45
+ * cannot keep the pool wedged (issue #606).
46
+ */
47
+ export function clearAllRateLimits(entity) {
48
+ const keys = Object.keys(entity.rateLimitResetTimes);
49
+ for (const key of keys) {
50
+ delete entity.rateLimitResetTimes[key];
51
+ }
52
+ }
40
53
  export function isRateLimitedForQuotaKey(entity, key) {
41
54
  const resetTime = entity.rateLimitResetTimes[key];
42
55
  return resetTime !== undefined && nowMs() < resetTime;
@@ -6,7 +6,7 @@ import { type ModelFamily } from "./request/helpers/model-map.js";
6
6
  import { type HybridSelectionOptions } from "./rotation.js";
7
7
  import { type RoutingMutexMode, type SelectionRecord } from "./routing-mutex.js";
8
8
  export { extractAccountId, extractAccountEmail, getAccountIdCandidates, selectBestAccountCandidate, resolveRuntimeRequestIdentity, shouldUpdateAccountIdFromToken, resolveRequestAccountId, sanitizeEmail, type AccountIdCandidate, } from "./auth/token-utils.js";
9
- export { parseRateLimitReason, getQuotaKey, clampNonNegativeInt, clearExpiredRateLimits, isRateLimitedForQuotaKey, isRateLimitedForFamily, formatWaitTime, type QuotaKey, type BaseQuotaKey, type RateLimitReason, type RateLimitState, type RateLimitedEntity, } from "./accounts/rate-limits.js";
9
+ export { parseRateLimitReason, getQuotaKey, clampNonNegativeInt, clearExpiredRateLimits, clearAllRateLimits, isRateLimitedForQuotaKey, isRateLimitedForFamily, formatWaitTime, type QuotaKey, type BaseQuotaKey, type RateLimitReason, type RateLimitState, type RateLimitedEntity, } from "./accounts/rate-limits.js";
10
10
  export { lookupCodexCliTokensByEmail, isCodexCliSyncEnabled, type CodexCliTokenCacheEntry, } from "./codex-cli/state.js";
11
11
  import { type RateLimitReason } from "./accounts/rate-limits.js";
12
12
  export declare function getRuntimeTrackerKey(account: ManagedAccount): string | number;
@@ -80,6 +80,24 @@ export declare class AccountManager {
80
80
  isAccountAvailableForFamily(index: number, family: ModelFamily, model?: string | null): boolean;
81
81
  getAccountRuntimeSkipReason(index: number, family: ModelFamily, model?: string | null): string | null;
82
82
  static resetVolatileRuntimeState(): void;
83
+ /**
84
+ * Wipe per-account transient state — active cooldowns and all rate-limit
85
+ * reset windows — across every managed account, then schedule a debounced
86
+ * persist of the cleared pool.
87
+ *
88
+ * `resetVolatileRuntimeState` only clears process-global singletons (rotation
89
+ * trackers, circuit breakers); the cooldown timestamps and `rateLimitResetTimes`
90
+ * maps live on the `ManagedAccount` objects and are serialized to disk by
91
+ * `buildStorageSnapshot`. The stale-runtime recovery path reloads accounts
92
+ * from that snapshot, so without this the same transient state that wedged the
93
+ * pool is restored verbatim and recovery never escapes it (issue #606).
94
+ *
95
+ * The in-memory clear is immediate (it is what unblocks the live pool). The
96
+ * disk write is debounced via `saveToDiskDebounced`, so a caller that needs
97
+ * the cleared state to survive a restart should `await flushPendingSave()`
98
+ * afterwards rather than rely on the debounce window completing.
99
+ */
100
+ clearAccountTransientState(): void;
83
101
  setActiveIndex(index: number): ManagedAccount | null;
84
102
  syncCodexCliActiveSelectionForIndex(index: number): Promise<void>;
85
103
  getCurrentAccount(): ManagedAccount | 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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"}
@@ -14,10 +14,10 @@ import { getAccountIdentityKey, getRuntimeAccountIdentityKey, } from "./storage/
14
14
  import { getCircuitBreaker, resetAllCircuitBreakers, removeCircuitBreaker } from "./circuit-breaker.js";
15
15
  import { getStoragePathState, runWithStoragePathState, } from "./storage/path-state.js";
16
16
  export { extractAccountId, extractAccountEmail, getAccountIdCandidates, selectBestAccountCandidate, resolveRuntimeRequestIdentity, shouldUpdateAccountIdFromToken, resolveRequestAccountId, sanitizeEmail, } from "./auth/token-utils.js";
17
- export { parseRateLimitReason, getQuotaKey, clampNonNegativeInt, clearExpiredRateLimits, isRateLimitedForQuotaKey, isRateLimitedForFamily, formatWaitTime, } from "./accounts/rate-limits.js";
17
+ export { parseRateLimitReason, getQuotaKey, clampNonNegativeInt, clearExpiredRateLimits, clearAllRateLimits, isRateLimitedForQuotaKey, isRateLimitedForFamily, formatWaitTime, } from "./accounts/rate-limits.js";
18
18
  export { lookupCodexCliTokensByEmail, isCodexCliSyncEnabled, } from "./codex-cli/state.js";
19
19
  import { extractAccountId, extractAccountEmail, shouldUpdateAccountIdFromToken, sanitizeEmail, } from "./auth/token-utils.js";
20
- import { clampNonNegativeInt, getQuotaKey, clearExpiredRateLimits, isRateLimitedForFamily, formatWaitTime, } from "./accounts/rate-limits.js";
20
+ import { clampNonNegativeInt, getQuotaKey, clearExpiredRateLimits, clearAllRateLimits, isRateLimitedForFamily, formatWaitTime, } from "./accounts/rate-limits.js";
21
21
  const log = createLogger("accounts");
22
22
  let nextRuntimeCircuitKeyId = 0;
23
23
  function getAccountCircuitKey(account) {
@@ -449,6 +449,35 @@ export class AccountManager {
449
449
  resetTrackers();
450
450
  resetAllCircuitBreakers();
451
451
  }
452
+ /**
453
+ * Wipe per-account transient state — active cooldowns and all rate-limit
454
+ * reset windows — across every managed account, then schedule a debounced
455
+ * persist of the cleared pool.
456
+ *
457
+ * `resetVolatileRuntimeState` only clears process-global singletons (rotation
458
+ * trackers, circuit breakers); the cooldown timestamps and `rateLimitResetTimes`
459
+ * maps live on the `ManagedAccount` objects and are serialized to disk by
460
+ * `buildStorageSnapshot`. The stale-runtime recovery path reloads accounts
461
+ * from that snapshot, so without this the same transient state that wedged the
462
+ * pool is restored verbatim and recovery never escapes it (issue #606).
463
+ *
464
+ * The in-memory clear is immediate (it is what unblocks the live pool). The
465
+ * disk write is debounced via `saveToDiskDebounced`, so a caller that needs
466
+ * the cleared state to survive a restart should `await flushPendingSave()`
467
+ * afterwards rather than rely on the debounce window completing.
468
+ */
469
+ clearAccountTransientState() {
470
+ if (this.accounts.length === 0)
471
+ return;
472
+ // Snapshot the reference list so a concurrent mutation of `this.accounts`
473
+ // (e.g. removeAccount) cannot reshape the array mid-iteration.
474
+ for (const account of [...this.accounts]) {
475
+ this.clearAccountCooldown(account);
476
+ clearAllRateLimits(account);
477
+ account.lastRateLimitReason = undefined;
478
+ }
479
+ this.saveToDiskDebounced();
480
+ }
452
481
  setActiveIndex(index) {
453
482
  if (!Number.isFinite(index))
454
483
  return null;
@@ -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,aA6BnC,CAAC"}
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,aA8BnC,CAAC"}
@@ -36,6 +36,7 @@ export const ACCOUNT_MANAGER_COMMANDS = new Set([
36
36
  "monitor",
37
37
  "rotation",
38
38
  "why-selected",
39
+ "history",
39
40
  "config",
40
41
  "init-config",
41
42
  "debug",
@@ -0,0 +1,23 @@
1
+ export interface HistorySessionSummary {
2
+ id: string;
3
+ threadName: string;
4
+ updatedAt: string;
5
+ provider: string | null;
6
+ originator: string | null;
7
+ cwd: string | null;
8
+ path: string;
9
+ }
10
+ export interface HistorySessionDetail extends HistorySessionSummary {
11
+ cliVersion: string | null;
12
+ messages: string[];
13
+ }
14
+ export interface HistoryCommandDeps {
15
+ getCodexHome?: () => string;
16
+ readDirRecursive?: (dir: string) => string[];
17
+ readFile?: (path: string) => string;
18
+ statMtime?: (path: string) => Date;
19
+ logInfo?: (message: string) => void;
20
+ logError?: (message: string) => void;
21
+ }
22
+ export declare function runHistoryCommand(args: string[], deps?: HistoryCommandDeps): number;
23
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../../../lib/codex-manager/commands/history.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,qBAAqB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;IAClE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAClC,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAiVD,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,GAAE,kBAAuB,GAC3B,MAAM,CA2BR"}
@@ -0,0 +1,312 @@
1
+ import { readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { getCodexHomeDir } from "../../runtime-paths.js";
4
+ /**
5
+ * `codex-multi-auth history` — provider-agnostic local session browser.
6
+ *
7
+ * Codex CLI's `/resume` view filters local rollout threads by the model
8
+ * provider that is currently active in `config.toml`. When runtime rotation /
9
+ * app bind is enabled the active provider becomes
10
+ * `codex-multi-auth-runtime-proxy`, so sessions recorded under the native
11
+ * `openai` provider (or vice versa) become invisible in `/resume` even though
12
+ * the rollout files still live side-by-side under `~/.codex/sessions/`. Users
13
+ * perceive this as "history is not shared across accounts" (issue #612), but
14
+ * the split is by provider name, not by account.
15
+ *
16
+ * This command reads the rollout files directly and lists every local session
17
+ * regardless of the provider it was created under, giving a complete view that
18
+ * `/resume` cannot. It performs no network calls and never mutates state.
19
+ */
20
+ const ROLLOUT_FILENAME_PATTERN = /^rollout-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
21
+ const DEFAULT_PREVIEW_MESSAGE_COUNT = 3;
22
+ const MAX_THREAD_NAME_LENGTH = 80;
23
+ function readStringField(record, key) {
24
+ const value = record?.[key];
25
+ return typeof value === "string" && value.trim().length > 0
26
+ ? value.trim()
27
+ : null;
28
+ }
29
+ function defaultReadDirRecursive(dir) {
30
+ const results = [];
31
+ let entries = [];
32
+ try {
33
+ entries = readdirSync(dir, { withFileTypes: true });
34
+ }
35
+ catch {
36
+ return results;
37
+ }
38
+ for (const entry of entries) {
39
+ const entryPath = join(dir, entry.name);
40
+ if (entry.isDirectory()) {
41
+ results.push(...defaultReadDirRecursive(entryPath));
42
+ continue;
43
+ }
44
+ if (entry.isFile() && ROLLOUT_FILENAME_PATTERN.test(entry.name)) {
45
+ results.push(entryPath);
46
+ }
47
+ }
48
+ return results;
49
+ }
50
+ function extractIdFromFilename(fileName) {
51
+ const match = fileName.match(ROLLOUT_FILENAME_PATTERN);
52
+ return match?.[1] ?? null;
53
+ }
54
+ /**
55
+ * Separator-agnostic basename. Rollout paths may carry Windows separators even
56
+ * when this runs on POSIX (e.g. injected paths in tests, or a CODEX_HOME on a
57
+ * mounted Windows volume), so split on both `/` and `\` rather than relying on
58
+ * the platform-specific node:path basename.
59
+ */
60
+ function baseNameOf(filePath) {
61
+ const segments = filePath.split(/[\\/]/);
62
+ return segments[segments.length - 1] ?? filePath;
63
+ }
64
+ /**
65
+ * Parse a single rollout file into a session summary.
66
+ *
67
+ * Mirrors the index-building logic the wrapper uses (scripts/codex.js
68
+ * parseRolloutIndexEntry) but additionally surfaces the `model_provider` and
69
+ * `originator` from `session_meta`, which is the field that actually drives the
70
+ * `/resume` visibility split. Returns null for files without a `session_meta`
71
+ * record or that cannot be read, so partially-written rollouts are skipped
72
+ * rather than crashing the listing.
73
+ */
74
+ function parseRollout(rolloutPath, deps, previewLimit) {
75
+ const idFromName = extractIdFromFilename(baseNameOf(rolloutPath));
76
+ if (!idFromName)
77
+ return null;
78
+ let content;
79
+ try {
80
+ content = deps.readFile(rolloutPath);
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ const lines = content.split(/\r?\n/);
86
+ let id = idFromName;
87
+ let threadName = "";
88
+ let updatedAt = null;
89
+ let provider = null;
90
+ let originator = null;
91
+ let cwd = null;
92
+ let cliVersion = null;
93
+ let hasSessionMeta = false;
94
+ const messages = [];
95
+ for (const line of lines) {
96
+ if (line.trim().length === 0)
97
+ continue;
98
+ let record;
99
+ try {
100
+ record = JSON.parse(line);
101
+ }
102
+ catch {
103
+ // Tolerate malformed/partial lines; a single bad line must not drop
104
+ // the whole session from the listing.
105
+ continue;
106
+ }
107
+ if (typeof record.timestamp === "string") {
108
+ updatedAt = record.timestamp;
109
+ }
110
+ if (record.type === "session_meta") {
111
+ const payload = record.payload;
112
+ const metaId = readStringField(payload, "id");
113
+ if (metaId)
114
+ id = metaId;
115
+ provider = readStringField(payload, "model_provider") ?? provider;
116
+ originator = readStringField(payload, "originator") ?? originator;
117
+ cwd = readStringField(payload, "cwd") ?? cwd;
118
+ cliVersion = readStringField(payload, "cli_version") ?? cliVersion;
119
+ hasSessionMeta = true;
120
+ }
121
+ if (record.type === "event_msg") {
122
+ const payload = record.payload;
123
+ const payloadType = readStringField(payload, "type");
124
+ if (!threadName && payloadType) {
125
+ const message = readStringField(payload, "message");
126
+ if (message) {
127
+ threadName = message;
128
+ }
129
+ }
130
+ if (payloadType === "user_message" &&
131
+ messages.length < previewLimit) {
132
+ const message = readStringField(payload, "message");
133
+ if (message) {
134
+ messages.push(message);
135
+ }
136
+ }
137
+ }
138
+ }
139
+ if (!hasSessionMeta) {
140
+ return null;
141
+ }
142
+ if (!updatedAt) {
143
+ try {
144
+ updatedAt = deps.statMtime(rolloutPath).toISOString();
145
+ }
146
+ catch {
147
+ updatedAt = new Date().toISOString();
148
+ }
149
+ }
150
+ if (!threadName) {
151
+ threadName = "Codex session";
152
+ }
153
+ if (threadName.length > MAX_THREAD_NAME_LENGTH) {
154
+ threadName = `${threadName.slice(0, MAX_THREAD_NAME_LENGTH - 3)}...`;
155
+ }
156
+ return {
157
+ id,
158
+ threadName,
159
+ updatedAt,
160
+ provider,
161
+ originator,
162
+ cwd,
163
+ cliVersion,
164
+ messages,
165
+ path: rolloutPath,
166
+ };
167
+ }
168
+ function resolveDeps(deps) {
169
+ return {
170
+ getCodexHome: deps.getCodexHome ?? getCodexHomeDir,
171
+ readDirRecursive: deps.readDirRecursive ?? defaultReadDirRecursive,
172
+ readFile: deps.readFile ?? ((path) => readFileSync(path, "utf8")),
173
+ statMtime: deps.statMtime ?? ((path) => statSync(path).mtime),
174
+ logInfo: deps.logInfo ?? ((message) => console.log(message)),
175
+ logError: deps.logError ?? ((message) => console.error(message)),
176
+ };
177
+ }
178
+ function collectSessions(resolved, previewLimit) {
179
+ const sessionsDir = join(resolved.getCodexHome(), "sessions");
180
+ let files;
181
+ try {
182
+ files = resolved.readDirRecursive(sessionsDir);
183
+ }
184
+ catch {
185
+ // A missing or unreadable sessions directory is a normal "no history yet"
186
+ // state, not an error — return an empty listing rather than crashing.
187
+ files = [];
188
+ }
189
+ const sessions = [];
190
+ for (const file of files) {
191
+ const parsed = parseRollout(file, { readFile: resolved.readFile, statMtime: resolved.statMtime }, previewLimit);
192
+ if (parsed)
193
+ sessions.push(parsed);
194
+ }
195
+ // Most-recent first, matching how /resume presents threads.
196
+ sessions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
197
+ return sessions;
198
+ }
199
+ function toSummary(detail) {
200
+ const { cliVersion: _cliVersion, messages: _messages, ...summary } = detail;
201
+ void _cliVersion;
202
+ void _messages;
203
+ return summary;
204
+ }
205
+ function runHistoryList(args, resolved) {
206
+ const json = args.includes("--json") || args.includes("-j");
207
+ const sessions = collectSessions(resolved, DEFAULT_PREVIEW_MESSAGE_COUNT);
208
+ if (json) {
209
+ resolved.logInfo(JSON.stringify({ count: sessions.length, sessions: sessions.map(toSummary) }, null, 2));
210
+ return 0;
211
+ }
212
+ if (sessions.length === 0) {
213
+ resolved.logInfo(`No local Codex sessions found under ${join(resolved.getCodexHome(), "sessions")}.`);
214
+ return 0;
215
+ }
216
+ resolved.logInfo(`Local Codex sessions (${sessions.length}) — all providers, bypassing /resume provider filtering:`);
217
+ resolved.logInfo("");
218
+ for (const session of sessions) {
219
+ const provider = session.provider ?? "unknown-provider";
220
+ resolved.logInfo(` ${session.updatedAt} [${provider}]`);
221
+ resolved.logInfo(` id: ${session.id}`);
222
+ resolved.logInfo(` thread: ${session.threadName}`);
223
+ if (session.cwd) {
224
+ resolved.logInfo(` cwd: ${session.cwd}`);
225
+ }
226
+ }
227
+ resolved.logInfo("");
228
+ resolved.logInfo("Resume any session with: codex resume <id> (or `codex resume` for the picker).");
229
+ return 0;
230
+ }
231
+ function runHistoryShow(args, resolved) {
232
+ const json = args.includes("--json") || args.includes("-j");
233
+ const sessionId = args.find((arg) => !arg.startsWith("-"));
234
+ if (!sessionId) {
235
+ resolved.logError("Missing session id. Usage: codex-multi-auth history show <session-id> [--json]");
236
+ return 1;
237
+ }
238
+ const sessions = collectSessions(resolved, DEFAULT_PREVIEW_MESSAGE_COUNT);
239
+ const match = sessions.find((session) => session.id === sessionId);
240
+ if (!match) {
241
+ resolved.logError(`Session not found: ${sessionId}`);
242
+ return 1;
243
+ }
244
+ if (json) {
245
+ resolved.logInfo(JSON.stringify(match, null, 2));
246
+ return 0;
247
+ }
248
+ resolved.logInfo(`Session ${match.id}`);
249
+ resolved.logInfo(` provider: ${match.provider ?? "unknown"}`);
250
+ resolved.logInfo(` originator: ${match.originator ?? "unknown"}`);
251
+ resolved.logInfo(` updated: ${match.updatedAt}`);
252
+ if (match.cliVersion) {
253
+ resolved.logInfo(` cli: ${match.cliVersion}`);
254
+ }
255
+ if (match.cwd) {
256
+ resolved.logInfo(` cwd: ${match.cwd}`);
257
+ }
258
+ resolved.logInfo(` file: ${match.path}`);
259
+ resolved.logInfo("");
260
+ if (match.messages.length === 0) {
261
+ resolved.logInfo(" (no user messages recorded)");
262
+ }
263
+ else {
264
+ resolved.logInfo(" First messages:");
265
+ for (const message of match.messages) {
266
+ const firstLine = message.split(/\r?\n/, 1)[0] ?? "";
267
+ const preview = firstLine.length > 120 ? `${firstLine.slice(0, 117)}...` : firstLine;
268
+ resolved.logInfo(` - ${preview}`);
269
+ }
270
+ }
271
+ resolved.logInfo("");
272
+ resolved.logInfo(`Resume with: codex resume ${match.id}`);
273
+ return 0;
274
+ }
275
+ function printHistoryUsage(resolved) {
276
+ resolved.logInfo([
277
+ "Usage: codex-multi-auth history <list|show> [options]",
278
+ "",
279
+ " list [--json] List every local session across all providers",
280
+ " show <id> [--json] Show provider metadata and first messages for a session",
281
+ "",
282
+ "Lists rollout files under <codex-home>/sessions (default",
283
+ "~/.codex/sessions, honoring CODEX_HOME) directly, so sessions",
284
+ "created under a different model provider (e.g. while runtime rotation",
285
+ "or app bind is active) remain visible even when `codex resume` hides",
286
+ "them. See docs/troubleshooting.md for background.",
287
+ ].join("\n"));
288
+ }
289
+ export function runHistoryCommand(args, deps = {}) {
290
+ const resolved = resolveDeps(deps);
291
+ const [subcommand, ...rest] = args;
292
+ if (subcommand === "--help" || subcommand === "-h") {
293
+ printHistoryUsage(resolved);
294
+ return 0;
295
+ }
296
+ // Default to `list` when no subcommand is given, or when the first arg is a
297
+ // flag (e.g. `history --json`), so the documented `[list] [--json]` form
298
+ // works without an explicit `list`. A leading flag is forwarded as a list
299
+ // argument rather than mistaken for a subcommand.
300
+ if (!subcommand || subcommand === "list") {
301
+ return runHistoryList(rest, resolved);
302
+ }
303
+ if (subcommand.startsWith("-")) {
304
+ return runHistoryList([subcommand, ...rest], resolved);
305
+ }
306
+ if (subcommand === "show") {
307
+ return runHistoryShow(rest, resolved);
308
+ }
309
+ resolved.logError(`Unknown history command: ${subcommand}`);
310
+ printHistoryUsage(resolved);
311
+ return 1;
312
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../lib/codex-manager/help.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,IAAI,IAAI,CAiDjC;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,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,CAgEtE;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,CAkDjC;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,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,CAgEtE;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"}
@@ -35,6 +35,7 @@ export function printUsage() {
35
35
  " codex-multi-auth rotation <enable|disable|status|bind-app|unbind-app>",
36
36
  " codex-multi-auth rotation reset-rate-limits [--all | --account <idx>] [--dry-run] [--json]",
37
37
  " codex-multi-auth why-selected [--now | --last] [--json]",
38
+ " codex-multi-auth history [list|show <id>] [--json] (all local sessions, ignores /resume provider filtering)",
38
39
  "",
39
40
  "Advanced:",
40
41
  " codex-multi-auth report [--live] [--json] [--explain] [--model <model>] [--out <path>]",
@@ -1 +1 @@
1
- {"version":3,"file":"codex-manager.d.ts","sourceRoot":"","sources":["../../lib/codex-manager.ts"],"names":[],"mappings":"AAoFA,OAAO,EAEN,mBAAmB,EAMnB,sBAAsB,EAGtB,MAAM,qCAAqC,CAAC;AAiD7C,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;AA+HvD,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAuGrE;AAuRD,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":"AAqFA,OAAO,EAEN,mBAAmB,EAMnB,sBAAsB,EAGtB,MAAM,qCAAqC,CAAC;AAiD7C,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC;AA+HvD,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAuGrE;AAwRD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA4C7E"}
@@ -31,6 +31,7 @@ import { runRotationCommand } from "./codex-manager/commands/rotation.js";
31
31
  import { runFeaturesCommand, runStatusCommand, } from "./codex-manager/commands/status.js";
32
32
  import { loadPersistedRuntimeObservabilitySnapshot } from "./runtime/runtime-observability.js";
33
33
  import { runSwitchCommand } from "./codex-manager/commands/switch.js";
34
+ import { runHistoryCommand } from "./codex-manager/commands/history.js";
34
35
  import { runUnpinCommand } from "./codex-manager/commands/unpin.js";
35
36
  import { runWorkspaceCommand } from "./codex-manager/commands/workspace.js";
36
37
  import { runUsageCommand } from "./codex-manager/commands/usage.js";
@@ -450,6 +451,7 @@ const CLI_COMMAND_HANDLERS = new Map([
450
451
  sanitizeEmail,
451
452
  }),
452
453
  ],
454
+ ["history", (rest) => runHistoryCommand(rest)],
453
455
  [
454
456
  "verify",
455
457
  (rest) => runVerifyCommand(rest, {
@@ -1 +1 @@
1
- {"version":3,"file":"stream-failover-runtime.d.ts","sourceRoot":"","sources":["../../../lib/request/stream-failover-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAEtF,eAAO,MAAM,kBAAkB,aAW7B,CAAC;AAWH,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUzF;AAED,wBAAsB,WAAW,CAAC,CAAC,EAClC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,IAAI,EACrB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,CAAC,CAmBZ;AAED,wBAAsB,aAAa,CAClC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,SAAc,GACpB,OAAO,CAAC,MAAM,CAAC,CAuDjB;AAoBD,wBAAsB,wBAAwB,CAC7C,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,0BAA0B,EAClC,aAAa,EAAE,MAAM,IAAI,EACzB,oBAAoB,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC,CA+ClB"}
1
+ {"version":3,"file":"stream-failover-runtime.d.ts","sourceRoot":"","sources":["../../../lib/request/stream-failover-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AAEtF,eAAO,MAAM,kBAAkB,aAW7B,CAAC;AAWH,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUzF;AAED,wBAAsB,WAAW,CAAC,CAAC,EAClC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,IAAI,EACrB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,CAAC,CAmBZ;AAED,wBAAsB,aAAa,CAClC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,SAAc,GACpB,OAAO,CAAC,MAAM,CAAC,CAuDjB;AAoBD,wBAAsB,wBAAwB,CAC7C,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,0BAA0B,EAClC,aAAa,EAAE,MAAM,IAAI,EACzB,oBAAoB,EAAE,MAAM,GAC1B,OAAO,CAAC,OAAO,CAAC,CAqDlB"}
@@ -149,6 +149,13 @@ export async function forwardStreamingResponse(upstream, res, status, onStreamEr
149
149
  if (done)
150
150
  break;
151
151
  if (value && value.byteLength > 0) {
152
+ // If the response is already finished (clean end by a concurrent
153
+ // close-then-reader-cancel path), stop writing. Do NOT guard on
154
+ // res.destroyed here: a socket-error-during-backpressure scenario sets
155
+ // destroyed=true and then lets the next res.write() throw so the catch
156
+ // block can record the error and fire onStreamError correctly.
157
+ if (res.writableEnded)
158
+ break;
152
159
  // Respect backpressure: when the client's socket buffer is full,
153
160
  // pause upstream reads until it drains instead of buffering the
154
161
  // whole stream in memory for a slow consumer.
@@ -1 +1 @@
1
- {"version":3,"file":"rotation-proxy-state.d.ts","sourceRoot":"","sources":["../../../lib/runtime/rotation-proxy-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACtC,oBAAoB,EAAE,cAAc,CAAC;IACrC,gBAAgB,EAAE,SAAS,GAAG,QAAQ,CAAC;IACvC,kBAAkB,EAAE,QAAQ,GAAG,YAAY,CAAC;IAC5C,SAAS,EAAE,OAAO,KAAK,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,2BAA2B,EAAE,MAAM,CAAC;IACpC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,yBAAyB,EAAE,MAAM,CAAC;IAClC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,8BAA8B,EAAE,MAAM,CAAC;IACvC,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD,8BAA8B,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB;IACjE,QAAQ,CAAC,oBAAoB,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IACnD,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,QAAQ,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACzD,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,yBAAyB,EAAE,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACjE,wBAAwB,EAAE,MAAM,CAAC;CACjC;AAID,gBAAgB;AAChB,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,sBAAsB,GAC1B,kBAAkB,CAuBpB;AAED,gBAAgB;AAChB,wBAAsB,wBAAwB,CAC7C,KAAK,EAAE,kBAAkB,GACvB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA0BhC"}
1
+ {"version":3,"file":"rotation-proxy-state.d.ts","sourceRoot":"","sources":["../../../lib/runtime/rotation-proxy-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACtC,oBAAoB,EAAE,cAAc,CAAC;IACrC,gBAAgB,EAAE,SAAS,GAAG,QAAQ,CAAC;IACvC,kBAAkB,EAAE,QAAQ,GAAG,YAAY,CAAC;IAC5C,SAAS,EAAE,OAAO,KAAK,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,2BAA2B,EAAE,MAAM,CAAC;IACpC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,yBAAyB,EAAE,MAAM,CAAC;IAClC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,8BAA8B,EAAE,MAAM,CAAC;IACvC,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD,8BAA8B,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB;IACjE,QAAQ,CAAC,oBAAoB,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IACnD,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,QAAQ,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACzD,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,yBAAyB,EAAE,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACjE,wBAAwB,EAAE,MAAM,CAAC;CACjC;AAID,gBAAgB;AAChB,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,sBAAsB,GAC1B,kBAAkB,CAuBpB;AAED,gBAAgB;AAChB,wBAAsB,wBAAwB,CAC7C,KAAK,EAAE,kBAAkB,GACvB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAkDhC"}
@@ -39,6 +39,30 @@ export async function recoverStaleRuntimeState(state) {
39
39
  recordRuntimeReset("pool-exhausted-no-account");
40
40
  const reloaded = await AccountManager.loadFromDisk();
41
41
  reloaded.setRoutingMutexMode(state.routingMutexMode);
42
+ // Wipe per-account cooldowns and rate-limit windows on the freshly
43
+ // reloaded pool. `resetVolatileRuntimeState` above only cleared global
44
+ // singletons (trackers, circuit breakers); the per-account transient
45
+ // state is serialized to disk, so loadFromDisk restores the same state
46
+ // that wedged the pool. Clearing it here gives recovery a real clean
47
+ // slate before any request can pick up the manager (issue #606). Runs
48
+ // before the `state.activeAccountManager` assignment so no concurrent
49
+ // request can observe the reloaded manager with stale state.
50
+ //
51
+ // This also drops still-future rate-limit windows from genuine upstream
52
+ // 429s, not just stale ones from a dead prior process. That is the
53
+ // intended trade-off: recovery only runs at full pool exhaustion, where
54
+ // the alternative is a hard 503 anyway, and the 1s reload dedupe bounds
55
+ // re-probing to ~1/sec — the upstream simply re-429s and re-populates the
56
+ // window until the next exhaustion. Availability is preferred over
57
+ // honoring backoff in this already-degraded state.
58
+ reloaded.clearAccountTransientState();
59
+ // Force the cleared snapshot to disk now rather than waiting out the
60
+ // debounce window inside clearAccountTransientState. If the process
61
+ // exited during that window the next startup would reload the wedged
62
+ // snapshot; flushing here makes the "next reload starts clean" guarantee
63
+ // durable across a restart, not just best-effort. Recovery is rare
64
+ // (full-pool exhaustion), so the extra synchronous write is cheap.
65
+ await reloaded.flushPendingSave();
42
66
  state.activeAccountManager = reloaded;
43
67
  state.knownAccountManagers.add(reloaded);
44
68
  state.lastStaleRuntimeReloadAt = Date.now();
@@ -738,9 +738,16 @@ async function handleRequestInner(state, req, res, traceId) {
738
738
  accountCount > 0 &&
739
739
  exhaustionReason === "no-account" &&
740
740
  (policyDecision?.blockedAccountIndexes.size ?? 0) === 0 &&
741
- ![...accountSkipReasons.values()].some((reason) => reason === "rate-limited" ||
742
- reason.startsWith("cooling-down") ||
743
- reason === "policy-blocked")) {
741
+ ![...accountSkipReasons.values()].some(
742
+ // Only policy blocks still suppress stale-state recovery: a policy
743
+ // decision is external and won't change across a disk reload, so
744
+ // reloading cannot help. "rate-limited" and "cooling-down*" are
745
+ // transient states that recovery is *designed* to escape — they are
746
+ // persisted to disk (buildStorageSnapshot) and so survive a reload,
747
+ // which previously deadlocked the pool against the very recovery that
748
+ // would clear them. recoverStaleRuntimeState now wipes that transient
749
+ // state after reloading, so let those reasons through (issue #606).
750
+ (reason) => reason === "policy-blocked")) {
744
751
  reloadedAfterNoAccount = true;
745
752
  const reloadedManager = await recoverStaleRuntimeState(state);
746
753
  if (reloadedManager) {
@@ -802,6 +809,12 @@ async function handleRequestInner(state, req, res, traceId) {
802
809
  accountManager.refundToken(refreshed.account, context.family, context.model);
803
810
  accountManager.recordFailure(refreshed.account, context.family, context.model);
804
811
  accountManager.markAccountCoolingDown(refreshed.account, DEFAULT_AUTH_FAILURE_COOLDOWN_MS, "auth-failure");
812
+ // Persist the cooldown like every other cooldown branch in this loop
813
+ // (network-error, 429, server-error, 401). `coolingDownUntil`/
814
+ // `cooldownReason` are serialized in the V3 snapshot, so without this
815
+ // a restart inside the cooldown window loses it and immediately
816
+ // re-selects the still-broken account.
817
+ accountManager.saveToDiskDebounced();
805
818
  exhaustionReason = "auth-failure";
806
819
  transientAttempts += 1;
807
820
  transientExhaustionReason = "auth-failure";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-multi-auth",
3
- "version": "2.3.0-beta.3",
3
+ "version": "2.3.1",
4
4
  "description": "Codex CLI multi-account OAuth manager with account switching, health checks, runtime rotation, diagnostics, and recovery tools for @openai/codex",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -24,6 +24,7 @@ const AUTH_SUBCOMMANDS = new Set([
24
24
  "monitor",
25
25
  "rotation",
26
26
  "why-selected",
27
+ "history",
27
28
  "config",
28
29
  "init-config",
29
30
  "debug",