codex-multi-auth 0.1.9 → 1.1.10

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/README.md CHANGED
@@ -50,7 +50,6 @@ Codex CLI-first multi-account OAuth manager for the official `@openai/codex` CLI
50
50
  ### Option A: Standard install
51
51
 
52
52
  ```bash
53
- npm i -g @openai/codex
54
53
  npm i -g codex-multi-auth
55
54
  ```
56
55
 
@@ -75,18 +74,16 @@ codex auth status
75
74
 
76
75
  ### Step-by-step
77
76
 
78
- 1. Install global packages:
79
- - `npm i -g @openai/codex`
77
+ 1. Install global package:
80
78
  - `npm i -g codex-multi-auth`
81
79
  2. Run first login flow with `codex auth login`
82
- 3. Validate state with `codex auth list` and `codex auth check`
80
+ 3. Validate state with `codex auth status` and `codex auth check`
83
81
  4. Confirm routing with `codex auth forecast --live`
84
82
 
85
83
  ### Verification
86
84
 
87
85
  ```bash
88
86
  codex auth status
89
- codex auth list
90
87
  codex auth check
91
88
  ```
92
89
 
@@ -98,7 +95,7 @@ codex auth check
98
95
 
99
96
  ```bash
100
97
  codex auth login
101
- codex auth list
98
+ codex auth status
102
99
  codex auth check
103
100
  codex auth forecast --live
104
101
  ```
@@ -278,9 +275,9 @@ codex auth doctor --json
278
275
 
279
276
  ## Release Notes
280
277
 
281
- - Current stable: [docs/releases/v0.1.9.md](docs/releases/v0.1.9.md)
282
- - Previous stable: [docs/releases/v0.1.8.md](docs/releases/v0.1.8.md)
283
- - Earlier stable: [docs/releases/v0.1.7.md](docs/releases/v0.1.7.md)
278
+ - Current stable: [docs/releases/v1.1.10.md](docs/releases/v1.1.10.md)
279
+ - Previous stable: [docs/releases/v0.1.9.md](docs/releases/v0.1.9.md)
280
+ - Earlier stable: [docs/releases/v0.1.8.md](docs/releases/v0.1.8.md)
284
281
  - Archived prerelease: [docs/releases/v0.1.0-beta.0.md](docs/releases/v0.1.0-beta.0.md)
285
282
 
286
283
  ## License
@@ -19,7 +19,7 @@ export interface ManagedAccount {
19
19
  expires?: number;
20
20
  addedAt: number;
21
21
  lastUsed: number;
22
- lastSwitchReason?: "rate-limit" | "initial" | "rotation";
22
+ lastSwitchReason?: "rate-limit" | "initial" | "rotation" | "best";
23
23
  lastRateLimitReason?: RateLimitReason;
24
24
  rateLimitResetTimes: RateLimitStateV3;
25
25
  coolingDownUntil?: number;
@@ -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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"codex-manager.d.ts","sourceRoot":"","sources":["../../lib/codex-manager.ts"],"names":[],"mappings":"AAg9HA,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAqErE;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA6D7E"}
1
+ {"version":3,"file":"codex-manager.d.ts","sourceRoot":"","sources":["../../lib/codex-manager.ts"],"names":[],"mappings":"AA01IA,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAmErE;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgE7E"}
@@ -6,7 +6,7 @@ import { createAuthorizationFlow, exchangeAuthorizationCode, parseAuthorizationI
6
6
  import { startLocalOAuthServer } from "./auth/server.js";
7
7
  import { copyTextToClipboard, openBrowserUrl } from "./auth/browser.js";
8
8
  import { promptAddAnotherAccount, promptLoginMode } from "./cli.js";
9
- import { extractAccountEmail, extractAccountId, formatAccountLabel, formatCooldown, formatWaitTime, getAccountIdCandidates, resolveRequestAccountId, sanitizeEmail, selectBestAccountCandidate, } from "./accounts.js";
9
+ import { extractAccountEmail, extractAccountId, formatAccountLabel, formatCooldown, formatWaitTime, getAccountIdCandidates, resolveRequestAccountId, sanitizeEmail, selectBestAccountCandidate, shouldUpdateAccountIdFromToken, } from "./accounts.js";
10
10
  import { ACCOUNT_LIMITS } from "./constants.js";
11
11
  import { loadDashboardDisplaySettings, DEFAULT_DASHBOARD_DISPLAY_SETTINGS, } from "./dashboard-settings.js";
12
12
  import { evaluateForecastAccounts, isHardRefreshFailure, recommendForecastAccount, summarizeForecast, } from "./forecast.js";
@@ -219,6 +219,7 @@ function printUsage() {
219
219
  " codex auth list",
220
220
  " codex auth status",
221
221
  " codex auth switch <index>",
222
+ " codex auth best [--live] [--json] [--model <model>]",
222
223
  " codex auth check",
223
224
  " codex auth features",
224
225
  " codex auth verify-flagged [--dry-run] [--json] [--no-restore]",
@@ -273,6 +274,7 @@ const IMPLEMENTED_FEATURES = [
273
274
  { id: 38, name: "Dashboard display customization" },
274
275
  { id: 39, name: "Unified color/theme runtime (v2 UI)" },
275
276
  { id: 40, name: "OAuth browser-first flow with manual callback fallback" },
277
+ { id: 41, name: "Auto-switch to best account command" },
276
278
  ];
277
279
  function runFeaturesReport() {
278
280
  console.log(`Implemented features (${IMPLEMENTED_FEATURES.length})`);
@@ -719,6 +721,35 @@ function resolveAccountSelection(tokens) {
719
721
  accountLabel: best.label,
720
722
  };
721
723
  }
724
+ function resolveStoredAccountIdentity(storedAccountId, storedAccountIdSource, tokenAccountId) {
725
+ const accountId = resolveRequestAccountId(storedAccountId, storedAccountIdSource, tokenAccountId);
726
+ if (!accountId) {
727
+ return {};
728
+ }
729
+ if (!shouldUpdateAccountIdFromToken(storedAccountIdSource, storedAccountId)) {
730
+ return {
731
+ accountId,
732
+ accountIdSource: storedAccountIdSource,
733
+ };
734
+ }
735
+ return {
736
+ accountId,
737
+ accountIdSource: accountId === tokenAccountId ? "token" : storedAccountIdSource,
738
+ };
739
+ }
740
+ function applyTokenAccountIdentity(account, tokenAccountId) {
741
+ const nextIdentity = resolveStoredAccountIdentity(account.accountId, account.accountIdSource, tokenAccountId);
742
+ if (!nextIdentity.accountId) {
743
+ return false;
744
+ }
745
+ if (nextIdentity.accountId === account.accountId
746
+ && nextIdentity.accountIdSource === account.accountIdSource) {
747
+ return false;
748
+ }
749
+ account.accountId = nextIdentity.accountId;
750
+ account.accountIdSource = nextIdentity.accountIdSource;
751
+ return true;
752
+ }
722
753
  async function promptManualCallback(state) {
723
754
  if (!input.isTTY || !output.isTTY) {
724
755
  return null;
@@ -1313,9 +1344,7 @@ async function runHealthCheck(options = {}) {
1313
1344
  account.email = nextEmail;
1314
1345
  changed = true;
1315
1346
  }
1316
- if (tokenAccountId && tokenAccountId !== account.accountId) {
1317
- account.accountId = tokenAccountId;
1318
- account.accountIdSource = "token";
1347
+ if (applyTokenAccountIdentity(account, tokenAccountId)) {
1319
1348
  changed = true;
1320
1349
  }
1321
1350
  if (account.enabled === false) {
@@ -1413,6 +1442,21 @@ function printForecastUsage() {
1413
1442
  " --model, -m Probe model for live mode (default: gpt-5-codex)",
1414
1443
  ].join("\n"));
1415
1444
  }
1445
+ function printBestUsage() {
1446
+ console.log([
1447
+ "Usage:",
1448
+ " codex auth best [--live] [--json] [--model <model>]",
1449
+ "",
1450
+ "Options:",
1451
+ " --live, -l Probe live quota headers via Codex backend before switching",
1452
+ " --json, -j Print machine-readable JSON output",
1453
+ " --model, -m Probe model for live mode (default: gpt-5-codex)",
1454
+ "",
1455
+ "Behavior:",
1456
+ " - Chooses the healthiest account using forecast scoring",
1457
+ " - Switches to the recommended account when it is not already active",
1458
+ ].join("\n"));
1459
+ }
1416
1460
  function printFixUsage() {
1417
1461
  console.log([
1418
1462
  "Usage:",
@@ -1486,6 +1530,48 @@ function parseForecastArgs(args) {
1486
1530
  }
1487
1531
  return { ok: true, options };
1488
1532
  }
1533
+ function parseBestArgs(args) {
1534
+ const options = {
1535
+ live: false,
1536
+ json: false,
1537
+ model: "gpt-5-codex",
1538
+ modelProvided: false,
1539
+ };
1540
+ for (let i = 0; i < args.length; i += 1) {
1541
+ const arg = args[i];
1542
+ if (!arg)
1543
+ continue;
1544
+ if (arg === "--live" || arg === "-l") {
1545
+ options.live = true;
1546
+ continue;
1547
+ }
1548
+ if (arg === "--json" || arg === "-j") {
1549
+ options.json = true;
1550
+ continue;
1551
+ }
1552
+ if (arg === "--model" || arg === "-m") {
1553
+ const value = args[i + 1];
1554
+ if (!value) {
1555
+ return { ok: false, message: "Missing value for --model" };
1556
+ }
1557
+ options.model = value;
1558
+ options.modelProvided = true;
1559
+ i += 1;
1560
+ continue;
1561
+ }
1562
+ if (arg.startsWith("--model=")) {
1563
+ const value = arg.slice("--model=".length).trim();
1564
+ if (!value) {
1565
+ return { ok: false, message: "Missing value for --model" };
1566
+ }
1567
+ options.model = value;
1568
+ options.modelProvided = true;
1569
+ continue;
1570
+ }
1571
+ return { ok: false, message: `Unknown option: ${arg}` };
1572
+ }
1573
+ return { ok: true, options };
1574
+ }
1489
1575
  function parseFixArgs(args) {
1490
1576
  const options = {
1491
1577
  dryRun: false,
@@ -2022,7 +2108,8 @@ function findExistingAccountIndexForFlagged(storage, flagged, nextRefreshToken,
2022
2108
  }
2023
2109
  function upsertRecoveredFlaggedAccount(storage, flagged, refreshResult, now) {
2024
2110
  const nextEmail = sanitizeEmail(extractAccountEmail(refreshResult.access, refreshResult.idToken)) ?? flagged.email;
2025
- const nextAccountId = extractAccountId(refreshResult.access) ?? flagged.accountId;
2111
+ const tokenAccountId = extractAccountId(refreshResult.access);
2112
+ const { accountId: nextAccountId, accountIdSource: nextAccountIdSource } = resolveStoredAccountIdentity(flagged.accountId, flagged.accountIdSource, tokenAccountId);
2026
2113
  const existingIndex = findExistingAccountIndexForFlagged(storage, flagged, refreshResult.refresh, nextAccountId, nextEmail);
2027
2114
  if (existingIndex >= 0) {
2028
2115
  const existing = storage.accounts[existingIndex];
@@ -2046,9 +2133,11 @@ function upsertRecoveredFlaggedAccount(storage, flagged, refreshResult, now) {
2046
2133
  existing.email = nextEmail;
2047
2134
  changed = true;
2048
2135
  }
2049
- if (nextAccountId && nextAccountId !== existing.accountId) {
2136
+ if (nextAccountId !== undefined &&
2137
+ ((nextAccountId !== existing.accountId)
2138
+ || (nextAccountIdSource !== existing.accountIdSource))) {
2050
2139
  existing.accountId = nextAccountId;
2051
- existing.accountIdSource = "token";
2140
+ existing.accountIdSource = nextAccountIdSource;
2052
2141
  changed = true;
2053
2142
  }
2054
2143
  if (existing.enabled === false) {
@@ -2078,7 +2167,7 @@ function upsertRecoveredFlaggedAccount(storage, flagged, refreshResult, now) {
2078
2167
  accessToken: refreshResult.access,
2079
2168
  expiresAt: refreshResult.expires,
2080
2169
  accountId: nextAccountId,
2081
- accountIdSource: nextAccountId ? "token" : flagged.accountIdSource,
2170
+ accountIdSource: nextAccountIdSource,
2082
2171
  accountLabel: flagged.accountLabel,
2083
2172
  email: nextEmail,
2084
2173
  addedAt: flagged.addedAt ?? now,
@@ -2146,13 +2235,15 @@ async function runVerifyFlagged(args) {
2146
2235
  const { index: i, flagged, label, result } = check;
2147
2236
  if (result.type === "success") {
2148
2237
  if (!options.restore) {
2238
+ const tokenAccountId = extractAccountId(result.access);
2239
+ const nextIdentity = resolveStoredAccountIdentity(flagged.accountId, flagged.accountIdSource, tokenAccountId);
2149
2240
  const nextFlagged = {
2150
2241
  ...flagged,
2151
2242
  refreshToken: result.refresh,
2152
2243
  accessToken: result.access,
2153
2244
  expiresAt: result.expires,
2154
- accountId: extractAccountId(result.access) ?? flagged.accountId,
2155
- accountIdSource: extractAccountId(result.access) ? "token" : flagged.accountIdSource,
2245
+ accountId: nextIdentity.accountId,
2246
+ accountIdSource: nextIdentity.accountIdSource,
2156
2247
  email: sanitizeEmail(extractAccountEmail(result.access, result.idToken)) ?? flagged.email,
2157
2248
  lastUsed: now,
2158
2249
  lastError: undefined,
@@ -2181,13 +2272,15 @@ async function runVerifyFlagged(args) {
2181
2272
  });
2182
2273
  continue;
2183
2274
  }
2275
+ const tokenAccountId = extractAccountId(result.access);
2276
+ const nextIdentity = resolveStoredAccountIdentity(flagged.accountId, flagged.accountIdSource, tokenAccountId);
2184
2277
  const updatedFlagged = {
2185
2278
  ...flagged,
2186
2279
  refreshToken: result.refresh,
2187
2280
  accessToken: result.access,
2188
2281
  expiresAt: result.expires,
2189
- accountId: extractAccountId(result.access) ?? flagged.accountId,
2190
- accountIdSource: extractAccountId(result.access) ? "token" : flagged.accountIdSource,
2282
+ accountId: nextIdentity.accountId,
2283
+ accountIdSource: nextIdentity.accountIdSource,
2191
2284
  email: sanitizeEmail(extractAccountEmail(result.access, result.idToken)) ?? flagged.email,
2192
2285
  lastUsed: now,
2193
2286
  lastError: upsertResult.message,
@@ -3027,10 +3120,7 @@ async function runDoctor(args) {
3027
3120
  activeAccount.expiresAt = refreshResult.expires;
3028
3121
  if (refreshedEmail)
3029
3122
  activeAccount.email = refreshedEmail;
3030
- if (refreshedAccountId) {
3031
- activeAccount.accountId = refreshedAccountId;
3032
- activeAccount.accountIdSource = "token";
3033
- }
3123
+ applyTokenAccountIdentity(activeAccount, refreshedAccountId);
3034
3124
  syncAccessToken = refreshResult.access;
3035
3125
  syncRefreshToken = refreshResult.refresh;
3036
3126
  syncExpiresAt = refreshResult.expires;
@@ -3349,6 +3439,23 @@ async function runSwitch(args) {
3349
3439
  console.error(`Account ${parsed} not found.`);
3350
3440
  return 1;
3351
3441
  }
3442
+ const { synced, wasDisabled } = await persistAndSyncSelectedAccount({
3443
+ storage,
3444
+ targetIndex,
3445
+ parsed,
3446
+ switchReason: "rotation",
3447
+ });
3448
+ if (!synced) {
3449
+ console.warn(`Switched account ${parsed} locally, but Codex auth sync did not complete. Multi-auth routing will still use this account.`);
3450
+ }
3451
+ console.log(`Switched to account ${parsed}: ${formatAccountLabel(account, targetIndex)}${wasDisabled ? " (re-enabled)" : ""}`);
3452
+ return 0;
3453
+ }
3454
+ async function persistAndSyncSelectedAccount({ storage, targetIndex, parsed, switchReason, initialSyncIdToken, }) {
3455
+ const account = storage.accounts[targetIndex];
3456
+ if (!account) {
3457
+ throw new Error(`Account ${parsed} not found.`);
3458
+ }
3352
3459
  storage.activeIndex = targetIndex;
3353
3460
  storage.activeIndexByFamily = storage.activeIndexByFamily ?? {};
3354
3461
  for (const family of MODEL_FAMILIES) {
@@ -3362,7 +3469,7 @@ async function runSwitch(args) {
3362
3469
  let syncAccessToken = account.accessToken;
3363
3470
  let syncRefreshToken = account.refreshToken;
3364
3471
  let syncExpiresAt = account.expiresAt;
3365
- let syncIdToken;
3472
+ let syncIdToken = initialSyncIdToken;
3366
3473
  if (!hasUsableAccessToken(account, switchNow)) {
3367
3474
  const refreshResult = await queuedRefresh(account.refreshToken);
3368
3475
  if (refreshResult.type === "success") {
@@ -3380,10 +3487,7 @@ async function runSwitch(args) {
3380
3487
  if (nextEmail && nextEmail !== account.email) {
3381
3488
  account.email = nextEmail;
3382
3489
  }
3383
- if (tokenAccountId && tokenAccountId !== account.accountId) {
3384
- account.accountId = tokenAccountId;
3385
- account.accountIdSource = "token";
3386
- }
3490
+ applyTokenAccountIdentity(account, tokenAccountId);
3387
3491
  syncAccessToken = refreshResult.access;
3388
3492
  syncRefreshToken = refreshResult.refresh;
3389
3493
  syncExpiresAt = refreshResult.expires;
@@ -3394,7 +3498,7 @@ async function runSwitch(args) {
3394
3498
  }
3395
3499
  }
3396
3500
  account.lastUsed = switchNow;
3397
- account.lastSwitchReason = "rotation";
3501
+ account.lastSwitchReason = switchReason;
3398
3502
  await saveAccounts(storage);
3399
3503
  const synced = await setCodexCliActiveSelection({
3400
3504
  accountId: account.accountId,
@@ -3404,10 +3508,224 @@ async function runSwitch(args) {
3404
3508
  expiresAt: syncExpiresAt,
3405
3509
  ...(syncIdToken ? { idToken: syncIdToken } : {}),
3406
3510
  });
3407
- if (!synced) {
3408
- console.warn(`Switched account ${parsed} locally, but Codex auth sync did not complete. Multi-auth routing will still use this account.`);
3511
+ return { synced, wasDisabled };
3512
+ }
3513
+ async function runBest(args) {
3514
+ if (args.includes("--help") || args.includes("-h")) {
3515
+ printBestUsage();
3516
+ return 0;
3517
+ }
3518
+ const parsedArgs = parseBestArgs(args);
3519
+ if (!parsedArgs.ok) {
3520
+ console.error(parsedArgs.message);
3521
+ printBestUsage();
3522
+ return 1;
3523
+ }
3524
+ const options = parsedArgs.options;
3525
+ if (options.modelProvided && !options.live) {
3526
+ console.error("--model requires --live for codex auth best");
3527
+ printBestUsage();
3528
+ return 1;
3529
+ }
3530
+ setStoragePath(null);
3531
+ const storage = await loadAccounts();
3532
+ if (!storage || storage.accounts.length === 0) {
3533
+ if (options.json) {
3534
+ console.log(JSON.stringify({ error: "No accounts configured." }, null, 2));
3535
+ }
3536
+ else {
3537
+ console.log("No accounts configured.");
3538
+ }
3539
+ return 1;
3540
+ }
3541
+ const now = Date.now();
3542
+ const refreshFailures = new Map();
3543
+ const liveQuotaByIndex = new Map();
3544
+ const probeIdTokenByIndex = new Map();
3545
+ const probeRefreshedIndices = new Set();
3546
+ const probeErrors = [];
3547
+ let changed = false;
3548
+ const printProbeNotes = () => {
3549
+ if (probeErrors.length === 0)
3550
+ return;
3551
+ console.log(`Live check notes (${probeErrors.length}):`);
3552
+ for (const error of probeErrors) {
3553
+ console.log(` - ${error}`);
3554
+ }
3555
+ };
3556
+ const persistProbeChangesIfNeeded = async () => {
3557
+ if (!changed)
3558
+ return;
3559
+ await saveAccounts(storage);
3560
+ changed = false;
3561
+ };
3562
+ for (let i = 0; i < storage.accounts.length; i += 1) {
3563
+ const account = storage.accounts[i];
3564
+ if (!account || !options.live)
3565
+ continue;
3566
+ if (account.enabled === false)
3567
+ continue;
3568
+ let probeAccessToken = account.accessToken;
3569
+ let probeAccountId = account.accountId ?? extractAccountId(account.accessToken);
3570
+ if (!hasUsableAccessToken(account, now)) {
3571
+ const refreshResult = await queuedRefresh(account.refreshToken);
3572
+ if (refreshResult.type !== "success") {
3573
+ refreshFailures.set(i, {
3574
+ ...refreshResult,
3575
+ message: normalizeFailureDetail(refreshResult.message, refreshResult.reason),
3576
+ });
3577
+ continue;
3578
+ }
3579
+ const refreshedEmail = sanitizeEmail(extractAccountEmail(refreshResult.access, refreshResult.idToken));
3580
+ const refreshedAccountId = extractAccountId(refreshResult.access);
3581
+ if (account.refreshToken !== refreshResult.refresh) {
3582
+ account.refreshToken = refreshResult.refresh;
3583
+ changed = true;
3584
+ }
3585
+ if (account.accessToken !== refreshResult.access) {
3586
+ account.accessToken = refreshResult.access;
3587
+ changed = true;
3588
+ }
3589
+ if (account.expiresAt !== refreshResult.expires) {
3590
+ account.expiresAt = refreshResult.expires;
3591
+ changed = true;
3592
+ }
3593
+ if (refreshedEmail && refreshedEmail !== account.email) {
3594
+ account.email = refreshedEmail;
3595
+ changed = true;
3596
+ }
3597
+ if (refreshedAccountId && refreshedAccountId !== account.accountId) {
3598
+ account.accountId = refreshedAccountId;
3599
+ account.accountIdSource = "token";
3600
+ changed = true;
3601
+ }
3602
+ if (refreshResult.idToken) {
3603
+ probeIdTokenByIndex.set(i, refreshResult.idToken);
3604
+ }
3605
+ probeRefreshedIndices.add(i);
3606
+ probeAccessToken = account.accessToken;
3607
+ probeAccountId = account.accountId ?? refreshedAccountId;
3608
+ }
3609
+ if (!probeAccessToken || !probeAccountId) {
3610
+ probeErrors.push(`${formatAccountLabel(account, i)}: missing accountId for live probe`);
3611
+ continue;
3612
+ }
3613
+ try {
3614
+ const liveQuota = await fetchCodexQuotaSnapshot({
3615
+ accountId: probeAccountId,
3616
+ accessToken: probeAccessToken,
3617
+ model: options.model,
3618
+ });
3619
+ liveQuotaByIndex.set(i, liveQuota);
3620
+ }
3621
+ catch (error) {
3622
+ const message = normalizeFailureDetail(error instanceof Error ? error.message : String(error), undefined);
3623
+ probeErrors.push(`${formatAccountLabel(account, i)}: ${message}`);
3624
+ }
3625
+ }
3626
+ const forecastInputs = storage.accounts.map((account, index) => ({
3627
+ index,
3628
+ account,
3629
+ isCurrent: index === resolveActiveIndex(storage, "codex"),
3630
+ now,
3631
+ refreshFailure: refreshFailures.get(index),
3632
+ liveQuota: liveQuotaByIndex.get(index),
3633
+ }));
3634
+ const forecastResults = evaluateForecastAccounts(forecastInputs);
3635
+ const recommendation = recommendForecastAccount(forecastResults);
3636
+ if (recommendation.recommendedIndex === null) {
3637
+ await persistProbeChangesIfNeeded();
3638
+ if (options.json) {
3639
+ console.log(JSON.stringify({
3640
+ error: recommendation.reason,
3641
+ ...(probeErrors.length > 0 ? { probeErrors } : {}),
3642
+ }, null, 2));
3643
+ }
3644
+ else {
3645
+ console.log(`No best account available: ${recommendation.reason}`);
3646
+ printProbeNotes();
3647
+ }
3648
+ return 1;
3649
+ }
3650
+ const bestIndex = recommendation.recommendedIndex;
3651
+ const bestAccount = storage.accounts[bestIndex];
3652
+ if (!bestAccount) {
3653
+ await persistProbeChangesIfNeeded();
3654
+ if (options.json) {
3655
+ console.log(JSON.stringify({ error: "Best account not found." }, null, 2));
3656
+ }
3657
+ else {
3658
+ console.log("Best account not found.");
3659
+ }
3660
+ return 1;
3661
+ }
3662
+ // Check if already on best account
3663
+ const currentIndex = resolveActiveIndex(storage, "codex");
3664
+ if (currentIndex === bestIndex) {
3665
+ const shouldSyncCurrentBest = probeRefreshedIndices.has(bestIndex) || probeIdTokenByIndex.has(bestIndex);
3666
+ let alreadyBestSynced;
3667
+ if (changed) {
3668
+ bestAccount.lastUsed = now;
3669
+ await persistProbeChangesIfNeeded();
3670
+ }
3671
+ if (shouldSyncCurrentBest) {
3672
+ alreadyBestSynced = await setCodexCliActiveSelection({
3673
+ accountId: bestAccount.accountId,
3674
+ email: bestAccount.email,
3675
+ accessToken: bestAccount.accessToken,
3676
+ refreshToken: bestAccount.refreshToken,
3677
+ expiresAt: bestAccount.expiresAt,
3678
+ ...(probeIdTokenByIndex.has(bestIndex)
3679
+ ? { idToken: probeIdTokenByIndex.get(bestIndex) }
3680
+ : {}),
3681
+ });
3682
+ if (!alreadyBestSynced && !options.json) {
3683
+ console.warn("Codex auth sync did not complete. Multi-auth routing will still use this account.");
3684
+ }
3685
+ }
3686
+ if (options.json) {
3687
+ console.log(JSON.stringify({
3688
+ message: `Already on best account: ${formatAccountLabel(bestAccount, bestIndex)}`,
3689
+ accountIndex: bestIndex + 1,
3690
+ reason: recommendation.reason,
3691
+ ...(alreadyBestSynced !== undefined ? { synced: alreadyBestSynced } : {}),
3692
+ ...(probeErrors.length > 0 ? { probeErrors } : {}),
3693
+ }, null, 2));
3694
+ }
3695
+ else {
3696
+ console.log(`Already on best account ${bestIndex + 1}: ${formatAccountLabel(bestAccount, bestIndex)}`);
3697
+ console.log(`Reason: ${recommendation.reason}`);
3698
+ printProbeNotes();
3699
+ }
3700
+ return 0;
3701
+ }
3702
+ const targetIndex = bestIndex;
3703
+ const parsed = targetIndex + 1;
3704
+ const { synced, wasDisabled } = await persistAndSyncSelectedAccount({
3705
+ storage,
3706
+ targetIndex,
3707
+ parsed,
3708
+ switchReason: "best",
3709
+ initialSyncIdToken: probeIdTokenByIndex.get(bestIndex),
3710
+ });
3711
+ if (options.json) {
3712
+ console.log(JSON.stringify({
3713
+ message: `Switched to best account: ${formatAccountLabel(bestAccount, targetIndex)}`,
3714
+ accountIndex: parsed,
3715
+ reason: recommendation.reason,
3716
+ synced,
3717
+ wasDisabled,
3718
+ ...(probeErrors.length > 0 ? { probeErrors } : {}),
3719
+ }, null, 2));
3720
+ }
3721
+ else {
3722
+ console.log(`Switched to best account ${parsed}: ${formatAccountLabel(bestAccount, targetIndex)}${wasDisabled ? " (re-enabled)" : ""}`);
3723
+ console.log(`Reason: ${recommendation.reason}`);
3724
+ printProbeNotes();
3725
+ if (!synced) {
3726
+ console.warn("Codex auth sync did not complete. Multi-auth routing will still use this account.");
3727
+ }
3409
3728
  }
3410
- console.log(`Switched to account ${parsed}: ${formatAccountLabel(account, targetIndex)}${wasDisabled ? " (re-enabled)" : ""}`);
3411
3729
  return 0;
3412
3730
  }
3413
3731
  export async function autoSyncActiveAccountToCodex() {
@@ -3451,9 +3769,7 @@ export async function autoSyncActiveAccountToCodex() {
3451
3769
  account.email = nextEmail;
3452
3770
  changed = true;
3453
3771
  }
3454
- if (tokenAccountId && tokenAccountId !== account.accountId) {
3455
- account.accountId = tokenAccountId;
3456
- account.accountIdSource = "token";
3772
+ if (applyTokenAccountIdentity(account, tokenAccountId)) {
3457
3773
  changed = true;
3458
3774
  }
3459
3775
  syncAccessToken = refreshResult.access;
@@ -3519,6 +3835,9 @@ export async function runCodexMultiAuthCli(rawArgs) {
3519
3835
  if (command === "forecast") {
3520
3836
  return runForecast(rest);
3521
3837
  }
3838
+ if (command === "best") {
3839
+ return runBest(rest);
3840
+ }
3522
3841
  if (command === "report") {
3523
3842
  return runReport(rest);
3524
3843
  }