codex-multi-auth 2.0.0 → 2.0.2
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 +13 -10
- package/config/README.md +4 -4
- package/config/codex-legacy.json +45 -120
- package/config/codex-modern.json +36 -52
- package/config/minimal-codex.json +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +85 -14
- package/dist/index.js.map +1 -1
- package/dist/lib/auth/device-auth.d.ts +46 -0
- package/dist/lib/auth/device-auth.d.ts.map +1 -0
- package/dist/lib/auth/device-auth.js +325 -0
- package/dist/lib/auth/device-auth.js.map +1 -0
- package/dist/lib/auth/index.d.ts +2 -0
- package/dist/lib/auth/index.d.ts.map +1 -1
- package/dist/lib/auth/index.js +1 -0
- package/dist/lib/auth/index.js.map +1 -1
- package/dist/lib/auto-update-checker.d.ts +23 -1
- package/dist/lib/auto-update-checker.d.ts.map +1 -1
- package/dist/lib/auto-update-checker.js +481 -8
- package/dist/lib/auto-update-checker.js.map +1 -1
- package/dist/lib/cli.d.ts +5 -0
- package/dist/lib/cli.d.ts.map +1 -1
- package/dist/lib/cli.js.map +1 -1
- package/dist/lib/codex-manager/commands/best.js +1 -1
- package/dist/lib/codex-manager/commands/best.js.map +1 -1
- package/dist/lib/codex-manager/commands/forecast.js +3 -3
- package/dist/lib/codex-manager/commands/forecast.js.map +1 -1
- package/dist/lib/codex-manager/commands/report.js +3 -3
- package/dist/lib/codex-manager/commands/report.js.map +1 -1
- package/dist/lib/codex-manager/commands/rotation.d.ts +4 -0
- package/dist/lib/codex-manager/commands/rotation.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/rotation.js +37 -11
- package/dist/lib/codex-manager/commands/rotation.js.map +1 -1
- package/dist/lib/codex-manager/commands/status.d.ts +6 -0
- package/dist/lib/codex-manager/commands/status.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/status.js +26 -3
- package/dist/lib/codex-manager/commands/status.js.map +1 -1
- package/dist/lib/codex-manager/forecast-report-commands.js +4 -4
- package/dist/lib/codex-manager/forecast-report-commands.js.map +1 -1
- package/dist/lib/codex-manager/help.d.ts +1 -0
- package/dist/lib/codex-manager/help.d.ts.map +1 -1
- package/dist/lib/codex-manager/help.js +20 -3
- package/dist/lib/codex-manager/help.js.map +1 -1
- package/dist/lib/codex-manager/rate-limit-markers.d.ts +2 -0
- package/dist/lib/codex-manager/rate-limit-markers.d.ts.map +1 -0
- package/dist/lib/codex-manager/rate-limit-markers.js +4 -0
- package/dist/lib/codex-manager/rate-limit-markers.js.map +1 -0
- package/dist/lib/codex-manager/repair-commands.js +3 -3
- package/dist/lib/codex-manager/repair-commands.js.map +1 -1
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +78 -91
- package/dist/lib/codex-manager.js.map +1 -1
- package/dist/lib/config.js +2 -2
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/prompts/codex.d.ts +1 -1
- package/dist/lib/prompts/codex.d.ts.map +1 -1
- package/dist/lib/prompts/codex.js +3 -3
- package/dist/lib/prompts/codex.js.map +1 -1
- package/dist/lib/quota-probe.js +1 -1
- package/dist/lib/quota-probe.js.map +1 -1
- package/dist/lib/quota-readiness.d.ts +16 -0
- package/dist/lib/quota-readiness.d.ts.map +1 -0
- package/dist/lib/quota-readiness.js +82 -0
- package/dist/lib/quota-readiness.js.map +1 -0
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +19 -8
- package/dist/lib/request/fetch-helpers.js.map +1 -1
- package/dist/lib/request/helpers/model-map.d.ts +2 -1
- package/dist/lib/request/helpers/model-map.d.ts.map +1 -1
- package/dist/lib/request/helpers/model-map.js +52 -60
- package/dist/lib/request/helpers/model-map.js.map +1 -1
- package/dist/lib/request/request-transformer.d.ts +2 -2
- package/dist/lib/request/request-transformer.js +4 -3
- package/dist/lib/request/request-transformer.js.map +1 -1
- package/dist/lib/runtime/login-menu-accounts.d.ts +5 -0
- package/dist/lib/runtime/login-menu-accounts.d.ts.map +1 -1
- package/dist/lib/runtime/login-menu-accounts.js +7 -2
- package/dist/lib/runtime/login-menu-accounts.js.map +1 -1
- package/dist/lib/runtime/quota-probe.js +1 -1
- package/dist/lib/runtime/quota-probe.js.map +1 -1
- package/dist/lib/runtime/runtime-current-account.d.ts +52 -0
- package/dist/lib/runtime/runtime-current-account.d.ts.map +1 -0
- package/dist/lib/runtime/runtime-current-account.js +252 -0
- package/dist/lib/runtime/runtime-current-account.js.map +1 -0
- package/dist/lib/runtime-rotation-proxy.js +1 -1
- package/dist/lib/runtime-rotation-proxy.js.map +1 -1
- package/dist/lib/schemas.d.ts +3 -0
- package/dist/lib/schemas.d.ts.map +1 -1
- package/dist/lib/schemas.js +1 -0
- package/dist/lib/schemas.js.map +1 -1
- package/dist/lib/ui/auth-menu.d.ts +6 -1
- package/dist/lib/ui/auth-menu.d.ts.map +1 -1
- package/dist/lib/ui/auth-menu.js +22 -2
- package/dist/lib/ui/auth-menu.js.map +1 -1
- package/package.json +1 -1
- package/scripts/bench-format/codex-host.mjs +142 -142
- package/scripts/bench-format/models.mjs +20 -22
- package/scripts/benchmark-edit-formats.mjs +9 -9
- package/scripts/codex-app-router.js +121 -121
- package/scripts/codex.js +3636 -3473
- package/scripts/postinstall.js +120 -14
|
@@ -2,6 +2,7 @@ import { stdin as input, stdout as output } from "node:process";
|
|
|
2
2
|
import { createInterface } from "node:readline/promises";
|
|
3
3
|
import { extractAccountEmail, extractAccountId, formatAccountLabel, formatWaitTime, getAccountIdCandidates, resolveRequestAccountId, sanitizeEmail, selectBestAccountCandidate, shouldUpdateAccountIdFromToken, } from "./accounts.js";
|
|
4
4
|
import { createAuthorizationFlow, exchangeAuthorizationCode, parseAuthorizationInput, redactOAuthUrlForLog, REDIRECT_URI, } from "./auth/auth.js";
|
|
5
|
+
import { runDeviceAuthFlow } from "./auth/device-auth.js";
|
|
5
6
|
import { copyTextToClipboard, isBrowserLaunchSuppressed, openBrowserUrl, } from "./auth/browser.js";
|
|
6
7
|
import { startLocalOAuthServer } from "./auth/server.js";
|
|
7
8
|
import { promptAddAnotherAccount, promptLoginMode, } from "./cli.js";
|
|
@@ -34,7 +35,9 @@ import { createLogger } from "./logger.js";
|
|
|
34
35
|
import { MODEL_FAMILIES } from "./prompts/codex.js";
|
|
35
36
|
import { getModelCapabilities, getModelProfile, resolveNormalizedModel, } from "./request/helpers/model-map.js";
|
|
36
37
|
import { formatRateLimitEntry as formatAccountRateLimitEntry, getRateLimitResetTimeForFamily, resolveActiveIndex, } from "./runtime/account-status.js";
|
|
38
|
+
import { buildQuotaEmailFallbackState, hasSafeQuotaEmailFallback, hasUniqueQuotaAccountId, isQuotaCacheEntryExhausted, normalizeQuotaAccountId, normalizeQuotaEmail, quotaLeftPercentFromUsed, } from "./quota-readiness.js";
|
|
37
39
|
import { loadQuotaCache, saveQuotaCache, } from "./quota-cache.js";
|
|
40
|
+
import { isDisplayCurrentAccount, readAppRuntimeHelperAccountSignal, resolveAccountCurrentMarkers, resolveRuntimeCurrentAccount, } from "./runtime/runtime-current-account.js";
|
|
38
41
|
import { fetchCodexQuotaSnapshot, formatQuotaSnapshotLine, } from "./quota-probe.js";
|
|
39
42
|
import { queuedRefresh } from "./refresh-queue.js";
|
|
40
43
|
import { clearAccounts, findMatchingAccountIndex, formatStorageErrorHint, inspectStorageHealth, getLastAccountsSaveTimestamp, getNamedBackups, getStoragePath, loadAccounts, loadFlaggedAccounts, restoreAccountsFromBackup, StorageError, saveAccounts, setStoragePath, withAccountStorageTransaction, } from "./storage.js";
|
|
@@ -318,70 +321,6 @@ const IMPLEMENTED_FEATURES = [
|
|
|
318
321
|
function formatRateLimitEntry(account, now, family = "codex") {
|
|
319
322
|
return formatAccountRateLimitEntry(account, now, formatWaitTime, family);
|
|
320
323
|
}
|
|
321
|
-
function normalizeQuotaEmail(email) {
|
|
322
|
-
const normalized = sanitizeEmail(email);
|
|
323
|
-
return normalized && normalized.length > 0 ? normalized : null;
|
|
324
|
-
}
|
|
325
|
-
function normalizeQuotaAccountId(accountId) {
|
|
326
|
-
if (typeof accountId !== "string")
|
|
327
|
-
return null;
|
|
328
|
-
const trimmed = accountId.trim();
|
|
329
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
330
|
-
}
|
|
331
|
-
function hasUniqueQuotaAccountId(accounts, account) {
|
|
332
|
-
const accountId = normalizeQuotaAccountId(account.accountId);
|
|
333
|
-
if (!accountId)
|
|
334
|
-
return false;
|
|
335
|
-
let matchCount = 0;
|
|
336
|
-
for (const candidate of accounts) {
|
|
337
|
-
if (normalizeQuotaAccountId(candidate.accountId) !== accountId)
|
|
338
|
-
continue;
|
|
339
|
-
matchCount += 1;
|
|
340
|
-
if (matchCount > 1)
|
|
341
|
-
return false;
|
|
342
|
-
}
|
|
343
|
-
return matchCount === 1;
|
|
344
|
-
}
|
|
345
|
-
function buildQuotaEmailFallbackState(accounts) {
|
|
346
|
-
const stateByEmail = new Map();
|
|
347
|
-
for (const account of accounts) {
|
|
348
|
-
const email = normalizeQuotaEmail(account.email);
|
|
349
|
-
if (!email)
|
|
350
|
-
continue;
|
|
351
|
-
const existing = stateByEmail.get(email);
|
|
352
|
-
if (existing) {
|
|
353
|
-
existing.matchingCount += 1;
|
|
354
|
-
const accountId = normalizeQuotaAccountId(account.accountId);
|
|
355
|
-
if (accountId) {
|
|
356
|
-
existing.distinctAccountIds.add(accountId);
|
|
357
|
-
}
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
const distinctAccountIds = new Set();
|
|
361
|
-
const accountId = normalizeQuotaAccountId(account.accountId);
|
|
362
|
-
if (accountId) {
|
|
363
|
-
distinctAccountIds.add(accountId);
|
|
364
|
-
}
|
|
365
|
-
stateByEmail.set(email, {
|
|
366
|
-
matchingCount: 1,
|
|
367
|
-
distinctAccountIds,
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
return stateByEmail;
|
|
371
|
-
}
|
|
372
|
-
function hasSafeQuotaEmailFallback(emailFallbackState, account) {
|
|
373
|
-
const email = normalizeQuotaEmail(account.email);
|
|
374
|
-
if (!email)
|
|
375
|
-
return false;
|
|
376
|
-
const state = emailFallbackState.get(email);
|
|
377
|
-
if (!state)
|
|
378
|
-
return false;
|
|
379
|
-
// size > 1 only matters when multiple accounts share the same email but
|
|
380
|
-
// disagree on accountId; a single matching account already implies size <= 1.
|
|
381
|
-
if (state.distinctAccountIds.size > 1)
|
|
382
|
-
return false;
|
|
383
|
-
return state.matchingCount === 1;
|
|
384
|
-
}
|
|
385
324
|
function quotaCacheEntryToSnapshot(entry) {
|
|
386
325
|
return {
|
|
387
326
|
status: entry.status,
|
|
@@ -417,13 +356,7 @@ function formatCompactQuotaPart(windowMinutes, usedPercent) {
|
|
|
417
356
|
const left = quotaLeftPercentFromUsed(usedPercent);
|
|
418
357
|
return `${label} ${left}%`;
|
|
419
358
|
}
|
|
420
|
-
function
|
|
421
|
-
if (typeof usedPercent !== "number" || !Number.isFinite(usedPercent)) {
|
|
422
|
-
return undefined;
|
|
423
|
-
}
|
|
424
|
-
return Math.max(0, Math.min(100, Math.round(100 - usedPercent)));
|
|
425
|
-
}
|
|
426
|
-
function formatCompactQuotaSnapshot(snapshot) {
|
|
359
|
+
function formatCompactQuotaSnapshot(snapshot, now = Date.now()) {
|
|
427
360
|
const parts = [
|
|
428
361
|
formatCompactQuotaPart(snapshot.primary.windowMinutes, snapshot.primary.usedPercent),
|
|
429
362
|
formatCompactQuotaPart(snapshot.secondary.windowMinutes, snapshot.secondary.usedPercent),
|
|
@@ -431,12 +364,15 @@ function formatCompactQuotaSnapshot(snapshot) {
|
|
|
431
364
|
if (snapshot.status === 429) {
|
|
432
365
|
parts.push("rate-limited");
|
|
433
366
|
}
|
|
367
|
+
if (isQuotaCacheEntryExhausted(snapshot, now)) {
|
|
368
|
+
parts.push("quota-exhausted");
|
|
369
|
+
}
|
|
434
370
|
if (parts.length > 0) {
|
|
435
371
|
return parts.join(" | ");
|
|
436
372
|
}
|
|
437
373
|
return formatQuotaSnapshotLine(snapshot);
|
|
438
374
|
}
|
|
439
|
-
function formatAccountQuotaSummary(entry) {
|
|
375
|
+
function formatAccountQuotaSummary(entry, now = Date.now()) {
|
|
440
376
|
const parts = [
|
|
441
377
|
formatCompactQuotaPart(entry.primary.windowMinutes, entry.primary.usedPercent),
|
|
442
378
|
formatCompactQuotaPart(entry.secondary.windowMinutes, entry.secondary.usedPercent),
|
|
@@ -444,6 +380,9 @@ function formatAccountQuotaSummary(entry) {
|
|
|
444
380
|
if (entry.status === 429) {
|
|
445
381
|
parts.push("rate-limited");
|
|
446
382
|
}
|
|
383
|
+
if (isQuotaCacheEntryExhausted(entry, now)) {
|
|
384
|
+
parts.push("quota-exhausted");
|
|
385
|
+
}
|
|
447
386
|
if (parts.length > 0) {
|
|
448
387
|
return parts.join(" | ");
|
|
449
388
|
}
|
|
@@ -481,7 +420,7 @@ function getPersistedQuotaViewForAccount(cache, account, accounts, now, emailFal
|
|
|
481
420
|
return {
|
|
482
421
|
updatedAt: cachedEntry?.updatedAt ?? now,
|
|
483
422
|
status: 429,
|
|
484
|
-
model: cachedEntry?.model ?? "gpt-5-codex",
|
|
423
|
+
model: cachedEntry?.model ?? "gpt-5.3-codex",
|
|
485
424
|
planType: cachedEntry?.planType,
|
|
486
425
|
primary: {
|
|
487
426
|
...cachedEntry?.primary,
|
|
@@ -549,7 +488,7 @@ function pruneUnsafeQuotaEmailCacheEntry(cache, email, accounts, emailFallbackSt
|
|
|
549
488
|
return true;
|
|
550
489
|
}
|
|
551
490
|
const DEFAULT_MENU_QUOTA_REFRESH_TTL_MS = 5 * 60_000;
|
|
552
|
-
const MENU_QUOTA_REFRESH_MODEL = "gpt-5-codex";
|
|
491
|
+
const MENU_QUOTA_REFRESH_MODEL = "gpt-5.3-codex";
|
|
553
492
|
function resolveMenuQuotaProbeInput(account, cache, maxAgeMs, now, accounts, emailFallbackState = buildQuotaEmailFallbackState(accounts)) {
|
|
554
493
|
if (account.enabled === false)
|
|
555
494
|
return null;
|
|
@@ -651,19 +590,22 @@ function hasLikelyInvalidRefreshToken(refreshToken) {
|
|
|
651
590
|
return true;
|
|
652
591
|
return trimmed.startsWith("token-");
|
|
653
592
|
}
|
|
654
|
-
function mapAccountStatus(account,
|
|
593
|
+
function mapAccountStatus(account, isCurrentAccount, now, persistedQuotaEntry) {
|
|
655
594
|
if (account.enabled === false)
|
|
656
595
|
return "disabled";
|
|
657
596
|
if (typeof account.coolingDownUntil === "number" &&
|
|
658
597
|
account.coolingDownUntil > now) {
|
|
659
598
|
return "cooldown";
|
|
660
599
|
}
|
|
661
|
-
if (
|
|
600
|
+
if (persistedQuotaEntry && isQuotaCacheEntryExhausted(persistedQuotaEntry, now)) {
|
|
601
|
+
return "quota-exhausted";
|
|
602
|
+
}
|
|
603
|
+
if (persistedQuotaEntry?.status === 429)
|
|
662
604
|
return "rate-limited";
|
|
663
605
|
const rateLimit = formatRateLimitEntry(account, now, "codex");
|
|
664
606
|
if (rateLimit)
|
|
665
607
|
return "rate-limited";
|
|
666
|
-
if (
|
|
608
|
+
if (isCurrentAccount)
|
|
667
609
|
return "active";
|
|
668
610
|
return "ok";
|
|
669
611
|
}
|
|
@@ -695,6 +637,7 @@ function accountStatusSortBucket(status) {
|
|
|
695
637
|
return 0;
|
|
696
638
|
case "unknown":
|
|
697
639
|
return 1;
|
|
640
|
+
case "quota-exhausted":
|
|
698
641
|
case "cooldown":
|
|
699
642
|
case "rate-limited":
|
|
700
643
|
return 2;
|
|
@@ -710,7 +653,7 @@ function accountReadinessSortBucket(account) {
|
|
|
710
653
|
const statusBucket = accountStatusSortBucket(account.status);
|
|
711
654
|
if (statusBucket >= 2)
|
|
712
655
|
return statusBucket;
|
|
713
|
-
return account.quotaRateLimited ? 2 : statusBucket;
|
|
656
|
+
return account.quotaRateLimited || account.quotaExhausted ? 2 : statusBucket;
|
|
714
657
|
}
|
|
715
658
|
function compareReadyFirstAccounts(left, right) {
|
|
716
659
|
const bucketDelta = accountReadinessSortBucket(left) - accountReadinessSortBucket(right);
|
|
@@ -765,13 +708,16 @@ function applyAccountMenuOrdering(accounts, displaySettings) {
|
|
|
765
708
|
}
|
|
766
709
|
return sorted;
|
|
767
710
|
}
|
|
768
|
-
function toExistingAccountInfo(storage, quotaCache, displaySettings) {
|
|
711
|
+
function toExistingAccountInfo(storage, quotaCache, displaySettings, runtimeCurrent = null) {
|
|
769
712
|
const now = Date.now();
|
|
770
713
|
const activeIndex = resolveActiveIndex(storage, "codex");
|
|
771
714
|
const layoutMode = resolveMenuLayoutMode(displaySettings);
|
|
772
715
|
const emailFallbackState = buildQuotaEmailFallbackState(storage.accounts);
|
|
773
716
|
const baseAccounts = storage.accounts.map((account, index) => {
|
|
774
717
|
const entry = getPersistedQuotaViewForAccount(quotaCache, account, storage.accounts, now, emailFallbackState);
|
|
718
|
+
const currentMarkers = resolveAccountCurrentMarkers(index, activeIndex, runtimeCurrent);
|
|
719
|
+
const isCurrentAccount = isDisplayCurrentAccount(index, activeIndex, runtimeCurrent);
|
|
720
|
+
const quotaExhausted = entry ? isQuotaCacheEntryExhausted(entry, now) : false;
|
|
775
721
|
return {
|
|
776
722
|
index,
|
|
777
723
|
sourceIndex: index,
|
|
@@ -780,16 +726,20 @@ function toExistingAccountInfo(storage, quotaCache, displaySettings) {
|
|
|
780
726
|
email: account.email,
|
|
781
727
|
addedAt: account.addedAt,
|
|
782
728
|
lastUsed: account.lastUsed,
|
|
783
|
-
status: mapAccountStatus(account,
|
|
729
|
+
status: mapAccountStatus(account, isCurrentAccount, now, entry),
|
|
784
730
|
quotaSummary: (displaySettings.menuShowQuotaSummary ?? true) && entry
|
|
785
|
-
? formatAccountQuotaSummary(entry)
|
|
731
|
+
? formatAccountQuotaSummary(entry, now)
|
|
786
732
|
: undefined,
|
|
787
733
|
quota5hLeftPercent: quotaLeftPercentFromUsed(entry?.primary.usedPercent),
|
|
788
734
|
quota5hResetAtMs: entry?.primary.resetAtMs,
|
|
789
735
|
quota7dLeftPercent: quotaLeftPercentFromUsed(entry?.secondary.usedPercent),
|
|
790
736
|
quota7dResetAtMs: entry?.secondary.resetAtMs,
|
|
791
737
|
quotaRateLimited: entry?.status === 429,
|
|
792
|
-
|
|
738
|
+
quotaExhausted,
|
|
739
|
+
isCurrentAccount,
|
|
740
|
+
isDefaultAccount: index === activeIndex,
|
|
741
|
+
isRuntimeCurrentAccount: runtimeCurrent?.index === index,
|
|
742
|
+
currentMarkers,
|
|
793
743
|
enabled: account.enabled !== false,
|
|
794
744
|
showStatusBadge: displaySettings.menuShowStatusBadge ?? true,
|
|
795
745
|
showCurrentBadge: displaySettings.menuShowCurrentBadge ?? true,
|
|
@@ -815,6 +765,19 @@ function toExistingAccountInfo(storage, quotaCache, displaySettings) {
|
|
|
815
765
|
: (account.sourceIndex ?? displayIndex) + 1,
|
|
816
766
|
}));
|
|
817
767
|
}
|
|
768
|
+
async function loadRuntimeCurrentSelectionForStorage(storage, now = Date.now()) {
|
|
769
|
+
const [runtimeSnapshot, appBindStatus] = await Promise.all([
|
|
770
|
+
loadPersistedRuntimeObservabilitySnapshot().catch(() => null),
|
|
771
|
+
getAppBindStatus()
|
|
772
|
+
.then((status) => (status.running ? status.router : null))
|
|
773
|
+
.catch(() => null),
|
|
774
|
+
]);
|
|
775
|
+
return resolveRuntimeCurrentAccount(storage, {
|
|
776
|
+
runtimeSnapshot,
|
|
777
|
+
appBindStatus,
|
|
778
|
+
appHelperStatus: readAppRuntimeHelperAccountSignal(),
|
|
779
|
+
}, { now });
|
|
780
|
+
}
|
|
818
781
|
function activeAccountMatchesCodexCliState(account, state) {
|
|
819
782
|
if (!state)
|
|
820
783
|
return true;
|
|
@@ -1473,6 +1436,18 @@ async function runOAuthFlow(forceNewLogin, signInMode) {
|
|
|
1473
1436
|
}
|
|
1474
1437
|
return exchangeAuthorizationCode(code, pkce.verifier, REDIRECT_URI);
|
|
1475
1438
|
}
|
|
1439
|
+
async function runSignInFlow(forceNewLogin, signInMode, options = {}) {
|
|
1440
|
+
if (signInMode === "device") {
|
|
1441
|
+
// OpenAI owns the device-code account picker; there is no force-new-login
|
|
1442
|
+
// equivalent to pass through for this mode.
|
|
1443
|
+
// TODO: Thread a manager-level AbortSignal when login cancellation exists.
|
|
1444
|
+
return runDeviceAuthFlow({
|
|
1445
|
+
log: console.log,
|
|
1446
|
+
timeoutMs: options.timeoutMs,
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
return runOAuthFlow(forceNewLogin, signInMode);
|
|
1450
|
+
}
|
|
1476
1451
|
async function persistAccountPool(results, replaceAll) {
|
|
1477
1452
|
if (results.length === 0)
|
|
1478
1453
|
return;
|
|
@@ -1572,7 +1547,7 @@ async function syncSelectionToCodex(tokens) {
|
|
|
1572
1547
|
async function runHealthCheck(options = {}) {
|
|
1573
1548
|
const forceRefresh = options.forceRefresh === true;
|
|
1574
1549
|
const liveProbe = options.liveProbe === true;
|
|
1575
|
-
const probeModel = options.model?.trim() || "gpt-5-codex";
|
|
1550
|
+
const probeModel = options.model?.trim() || "gpt-5.3-codex";
|
|
1576
1551
|
const modelInspection = inspectRequestedModel(probeModel);
|
|
1577
1552
|
const display = options.display ?? DEFAULT_DASHBOARD_DISPLAY_SETTINGS;
|
|
1578
1553
|
const quotaCache = liveProbe ? await loadQuotaCache() : null;
|
|
@@ -1788,7 +1763,7 @@ function printBestUsage() {
|
|
|
1788
1763
|
"Options:",
|
|
1789
1764
|
" --live, -l Probe live quota headers via Codex backend before switching",
|
|
1790
1765
|
" --json, -j Print machine-readable JSON output",
|
|
1791
|
-
" --model, -m Probe model for live mode (default: gpt-5-codex)",
|
|
1766
|
+
" --model, -m Probe model for live mode (default: gpt-5.3-codex)",
|
|
1792
1767
|
"",
|
|
1793
1768
|
"Behavior:",
|
|
1794
1769
|
" - Chooses the healthiest account using forecast scoring",
|
|
@@ -1799,7 +1774,7 @@ function parseBestArgs(args) {
|
|
|
1799
1774
|
const options = {
|
|
1800
1775
|
live: false,
|
|
1801
1776
|
json: false,
|
|
1802
|
-
model: "gpt-5-codex",
|
|
1777
|
+
model: "gpt-5.3-codex",
|
|
1803
1778
|
modelProvided: false,
|
|
1804
1779
|
};
|
|
1805
1780
|
for (let i = 0; i < args.length; i += 1) {
|
|
@@ -2101,7 +2076,8 @@ async function runAuthLogin(args) {
|
|
|
2101
2076
|
}
|
|
2102
2077
|
const flaggedStorage = await loadFlaggedAccounts();
|
|
2103
2078
|
await syncCodexCliActiveSelectionIfDrifted(currentStorage);
|
|
2104
|
-
const
|
|
2079
|
+
const runtimeCurrent = await loadRuntimeCurrentSelectionForStorage(currentStorage);
|
|
2080
|
+
const menuResult = await promptLoginMode(toExistingAccountInfo(currentStorage, quotaCache, displaySettings, runtimeCurrent), {
|
|
2105
2081
|
flaggedCount: flaggedStorage.accounts.length,
|
|
2106
2082
|
statusMessage: showFetchStatus
|
|
2107
2083
|
? () => menuQuotaRefreshStatus
|
|
@@ -2210,9 +2186,11 @@ async function runAuthLogin(args) {
|
|
|
2210
2186
|
while (true) {
|
|
2211
2187
|
const latestNamedBackup = namedBackups[0] ?? null;
|
|
2212
2188
|
const preferManualMode = loginOptions.manual || isBrowserLaunchSuppressed();
|
|
2213
|
-
const signInMode =
|
|
2214
|
-
? "
|
|
2215
|
-
:
|
|
2189
|
+
const signInMode = loginOptions.deviceAuth
|
|
2190
|
+
? "device"
|
|
2191
|
+
: preferManualMode
|
|
2192
|
+
? "manual"
|
|
2193
|
+
: await promptOAuthSignInMode(latestNamedBackup, onboardingBackupDiscoveryWarning);
|
|
2216
2194
|
if (signInMode === "cancel") {
|
|
2217
2195
|
if (existingCount > 0) {
|
|
2218
2196
|
console.log(stylePromptText(UI_COPY.oauth.cancelledBackToMenu, "muted"));
|
|
@@ -2280,10 +2258,12 @@ async function runAuthLogin(args) {
|
|
|
2280
2258
|
}
|
|
2281
2259
|
continue loginFlow;
|
|
2282
2260
|
}
|
|
2283
|
-
if (signInMode !== "browser" &&
|
|
2261
|
+
if (signInMode !== "browser" &&
|
|
2262
|
+
signInMode !== "manual" &&
|
|
2263
|
+
signInMode !== "device") {
|
|
2284
2264
|
continue;
|
|
2285
2265
|
}
|
|
2286
|
-
const tokenResult = await
|
|
2266
|
+
const tokenResult = await runSignInFlow(forceNewLogin, signInMode);
|
|
2287
2267
|
if (tokenResult.type !== "success") {
|
|
2288
2268
|
if (isOAuthCancellation(tokenResult)) {
|
|
2289
2269
|
if (existingCount > 0) {
|
|
@@ -2576,6 +2556,11 @@ export async function runCodexMultiAuthCli(rawArgs) {
|
|
|
2576
2556
|
resolveActiveIndex,
|
|
2577
2557
|
formatRateLimitEntry,
|
|
2578
2558
|
loadRuntimeObservabilitySnapshot: loadPersistedRuntimeObservabilitySnapshot,
|
|
2559
|
+
loadAppBindStatus: async () => getAppBindStatus()
|
|
2560
|
+
.then((status) => (status.running ? status.router : null))
|
|
2561
|
+
.catch(() => null),
|
|
2562
|
+
loadAppHelperStatus: readAppRuntimeHelperAccountSignal,
|
|
2563
|
+
loadQuotaCache,
|
|
2579
2564
|
});
|
|
2580
2565
|
}
|
|
2581
2566
|
if (command === "switch") {
|
|
@@ -2628,6 +2613,8 @@ export async function runCodexMultiAuthCli(rawArgs) {
|
|
|
2628
2613
|
bindCodexApp: bindCodexAppRuntimeRotation,
|
|
2629
2614
|
unbindCodexApp: unbindCodexAppRuntimeRotation,
|
|
2630
2615
|
getCodexAppBindStatus: getAppBindStatus,
|
|
2616
|
+
loadRuntimeObservabilitySnapshot: loadPersistedRuntimeObservabilitySnapshot,
|
|
2617
|
+
loadQuotaCache,
|
|
2631
2618
|
});
|
|
2632
2619
|
}
|
|
2633
2620
|
if (command === "why-selected") {
|