Skip to content

feat(cli): add codex auth best account switching#120

Merged
ndycode merged 10 commits intondycode:mainfrom
Microck:feat/auth-best-command
Mar 18, 2026
Merged

feat(cli): add codex auth best account switching#120
ndycode merged 10 commits intondycode:mainfrom
Microck:feat/auth-best-command

Conversation

@Microck
Copy link
Copy Markdown
Contributor

@Microck Microck commented Mar 17, 2026

Summary

  • adds codex auth best for forecast-driven account switching
  • hardens probe refresh and switch syncing so refreshed credentials and id tokens stay aligned
  • surfaces already-best --json sync state when the Codex CLI config update succeeds or fails
  • persists already-best probe refresh recency and broadens CLI coverage for the remaining auth best edge cases

Validation

  • npm run typecheck
  • npm run build
  • npm run lint
  • npm test

Docs

  • no docs files changed in this follow-up
  • CLI help and Vitest coverage were updated for the user-facing auth best behavior already under review

Risk

  • low
  • latest follow-up is limited to the already-best probe-save path and small deterministic test additions

Rollback

  • revert 04e6b3e from the PR branch if the recency timestamp update or added test assertions cause downstream issues

Notes

  • latest head: 04e6b3e
  • latest Greptile follow-up items addressed in this head:
    • already-best probe persistence now updates lastUsed before saving
    • loadAccounts() === null is covered in auth best --json
    • concurrent live best test now documents the current two-save contract explicitly

@Microck Microck requested a review from ndycode as a code owner March 17, 2026 18:31
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 17, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Severity: Minor — This PR adds a low-risk new feature (codex auth best subcommand) with solid test coverage, but contains a documented logic gap where the already-best probe path skips updating account.lastUsed when no token refreshes occur, potentially skewing forecast recency metrics.

Key Changes:

  • New CLI command codex auth best [--live] [--json] [--model] that evaluates account health via live quota probes and switches to the healthiest account
  • Refactored switch logic into persistAndSyncSelectedAccount() function, consolidating rotation and best-account paths to reduce duplication
  • Extended lastSwitchReason union type to include "best" across schemas, migrations, and storage types
  • 15 new test cases covering help, validation, live/offline probing, token refresh handling, already-best scenarios, and error paths
  • Added concurrent refresh deduping via queued probe results

Risk Assessment:

  • Logic gap (documented in PR objectives): The already-best path only updates lastUsed when changed === true (i.e., when tokens were refreshed). When the best account is already active with no token refreshes, lastUsed is not refreshed, which can skew forecast recency calculations. The fix commit "persist already-best probe recency" addresses this but warrants verification.
  • Regression risk: Low. The consolidation of runSwitch into persistAndSyncSelectedAccount() removes duplicate code, but existing rotation-based switch tests should confirm no behavioral regression (no explicit regression tests found in output).
  • Test coverage gaps (noted in PR objectives): While a null-storage test exists, explicit concurrent save-ordering assertions for the best command are absent (though the infrastructure exists in the test suite).

Architectural Notes:

  • The probe-phase token persistence model (updating tokens and syncing idTokens into setCodexCliActiveSelection calls) is sound for live quota evaluation
  • JSON output properly differentiates between already-best (idempotent) and switched (mutating) scenarios
  • The --model requires --live validation prevents incomplete option combinations

Validation: Typecheck, build, lint, and test suite passed; low rollback complexity (revert commit e44e0d7).

Walkthrough

adds a new codex auth best subcommand that probes live quotas, forecasts the healthiest account, and can auto-switch to it. extends lastSwitchReason and schema enums to include "best" across lib/accounts.ts:line, lib/schemas.ts:line, and lib/storage/migrations.ts:line. wires cli routing in scripts/codex-routing.js:line and implements core flow in lib/codex-manager.ts:line. tests added/updated in test/codex-manager-cli.test.ts:line and test/storage-flagged.test.ts:line.

Changes

Cohort / File(s) Summary
type & schema updates
lib/accounts.ts, lib/schemas.ts, lib/storage/migrations.ts
extended lastSwitchReason and SwitchReasonSchema to include the new literal "best". primarily type/schema additions. see lib/accounts.ts:line, lib/schemas.ts:line, lib/storage/migrations.ts:line.
core feature implementation
lib/codex-manager.ts
added runBest(args), persistAndSyncSelectedAccount, parseBestArgs, printBestUsage, and BestCliOptions; added feature entry { id: 41, ... }; integrates live quota probing, forecast-based selection, token refresh, persistence, and sync flows. review concurrency and token refresh reuse at lib/codex-manager.ts:line.
storage normalization
lib/storage.ts
expanded runtime predicate to accept "best" for AccountMetadataV3["lastSwitchReason"] during normalizeFlaggedStorage. see lib/storage.ts:line.
routing configuration
scripts/codex-routing.js
added "best" to AUTH_SUBCOMMANDS to expose the subcommand to CLI routing. see scripts/codex-routing.js:line.
tests
test/codex-manager-cli.test.ts, test/storage-flagged.test.ts
large set of new tests for the best command, json output, live probing, quota fetch errors, concurrency/queued refresh behavior, and preservation of lastSwitchReason: "best" on load. see test/codex-manager-cli.test.ts:line and test/storage-flagged.test.ts:line.

Sequence Diagram(s)

sequenceDiagram
    actor user
    participant cli as codex cli
    participant manager as lib/codex-manager.ts
    participant storage as lib/...loader
    participant prober as quota prober
    participant forecast as forecast engine
    participant switcher as persistAndSyncSelectedAccount

    user->>cli: codex auth best [--live] [--json]
    cli->>manager: runBest(args)
    manager->>storage: load accounts (storage)
    storage-->>manager: accounts[]

    alt --live flag
        manager->>prober: probe live quotas
        prober-->>manager: quota snapshot / errors
    end

    manager->>forecast: compute forecast + recommendation
    forecast-->>manager: recommended account index

    alt recommended != current
        manager->>switcher: persistAndSyncSelectedAccount(targetIndex, switchReason="best")
        switcher-->>manager: { synced, wasDisabled }
        manager-->>user: output json/human result + probe notes
    else already best
        manager-->>user: report already-on-best
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

additional notes / concerns

  • missing regression tests: ensure targeted unit tests in lib/codex-manager.ts:line for edge error paths and non-live code paths beyond the large cli test test/codex-manager-cli.test.ts:line.
  • concurrency risk: persistAndSyncSelectedAccount and queued refresh logic in lib/codex-manager.ts:line can race when multiple codex auth best instances run concurrently. consider file locking or process coordination.
  • windows edge cases: token refresh, file writes, and path handling in lib/codex-manager.ts:line and lib/storage.ts:line should be verified on windows (permissions, separators).
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed title follows conventional commits format with feat type, lowercase scope and summary, and is well under 72 characters.
Description check ✅ Passed description covers summary, what changed, validation checklist completion, docs rationale, risk assessment, and rollback plan with sufficient detail.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/codex-manager.ts`:
- Around line 4008-4155: The runbest flow reads storage via loadAccounts, does
network refreshes, mutates bestAccount and then calls saveAccounts, creating a
TOCTOU race; fix by implementing an atomic switch helper (e.g.,
atomicSwitchToBest or commitAtomicSwitch) that reloads the latest storage just
before persisting, merges only the intended fields (activeIndex,
activeIndexByFamily entries,
bestAccount.enabled/refresh/access/expires/lastUsed/lastSwitchReason/accountId/accountIdSource/email)
and retries on conflict (use optimistic compare-and-replace or a short retry
loop), and route the existing logic to use queuedRefresh and this helper instead
of calling saveAccounts directly; ensure the helper handles filesystem EBUSY and
transient 429 errors with backoff and surface safe logs that never include raw
tokens/emails, and add/update vitest cases to cover concurrent runs and retry
behavior.
- Around line 3981-4182: Add vitest tests targeting runBest to cover missing
edge cases: create unit tests that invoke runBest with invalid args (missing
value after "--model", "--help" and unknown flags) and both Windows argument
forms ("--model=value" and "--model value") to ensure parsing sets options.model
correctly; add a test where resolveActiveIndex returns the best index to assert
idempotence (no switch, checks for the expected JSON/plain outputs); simulate
live probe failures by mocking fetchCodexQuotaSnapshot to throw (including an
error object with status 429) and assert errors are caught and recorded in
liveQuotaByIndex/refreshFailures without leaking tokens/emails in logs; create
concurrent-invocation tests that call runBest in parallel and mock queuedRefresh
to simulate EBUSY/429 and ensure the refresh queue serializes access and avoids
races (verify saveAccounts/setCodexCliActiveSelection called once as
appropriate); in mocks/stubs ensure queuedRefresh, fetchCodexQuotaSnapshot,
setCodexCliActiveSelection, resolveActiveIndex, and saveAccounts are referenced
so tests exercise auth rotation, concurrency, and syncing behavior and assert no
sensitive tokens/emails are emitted to console/logs.
- Around line 4125-4151: The refresh branch in runbest (inside the
hasUsableAccessToken check) currently ignores non-success results from
queuedRefresh; update it to mirror runswitch's behavior by detecting when
queuedRefresh returns a non-"success" type and emitting a clear warning (include
bestAccount.accountId and/or bestAccount.email and any available error details
from the refreshResult) so refresh failures are visible; keep the existing
token-update logic only for refreshResult.type === "success" and do not
overwrite credentials on failure.
- Around line 4153-4155: The persisted lastSwitchReason value "best" is being
overwritten on load because the storage deserialization/validator only allows
"rate-limit" | "initial" | "rotation"; update the storage-side type/guard that
validates account objects (the AccountSwitchReason union or the
deserialize/validateAccount function used during loadAccounts) to include "best"
as an allowed value and ensure the deserializer preserves unknown-but-valid
strings (or maps legacy values if needed); after updating the validator, run
existing saveAccounts/loadAccounts flows to confirm bestAccount.lastSwitchReason
("best") survives round-trip.
- Around line 3981-4006: The runBest function's args parsing currently ignores
unknown flags and accepts a bare "--model" without a value; update the loop in
runBest to validate flags: accept only the known flags ("--live"/"-l",
"--json"/"-j", "--model"/"-m" and "--model=..."), treat any arg starting with
"-" that isn't one of those as an error (reject and fail-fast), and require a
non-empty value for "--model" (if "--model" is followed by nothing or "--model="
yields an empty string, fail immediately). Implement the failure by returning a
non-zero exit code (or throwing) from runBest so malformed commands don't
silently succeed; adjust references to options.model accordingly when setting
the model value.
- Around line 4046-4055: The empty catch swallowing probe failures in the block
that calls fetchCodexQuotaSnapshot causes lost errors and biased account
selection; change the catch to capture the thrown error (catch (err)) and append
it to the same probeErrors collection used elsewhere (the one referenced by the
"Live check notes" logic and forecast paths), and also optionally call the
existing logger (or processLogger) with context including
probeAccountId/probeAccessToken and i so failures are recorded; ensure you still
skip setting liveQuotaByIndex on error but do not silently discard the error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 48ef9380-2250-4958-b435-7730747b1214

📥 Commits

Reviewing files that changed from the base of the PR and between 9ab3669 and 3247e6b.

📒 Files selected for processing (7)
  • lib/accounts.ts
  • lib/codex-manager.ts
  • lib/schemas.ts
  • lib/storage/migrations.ts
  • scripts/codex-multi-auth.js
  • scripts/codex-routing.js
  • scripts/codex.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (1)
lib/**

⚙️ CodeRabbit configuration file

focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

Files:

  • lib/accounts.ts
  • lib/storage/migrations.ts
  • lib/schemas.ts
  • lib/codex-manager.ts
🔇 Additional comments (5)
lib/accounts.ts (1)

94-94: "best" is correctly added to managed account switch reasons.

lib/accounts.ts:94 is consistent with the new command intent and keeps account state typing aligned.

lib/storage/migrations.ts (1)

28-29: migration metadata unions are updated consistently.

lib/storage/migrations.ts:28 and lib/storage/migrations.ts:53 correctly allow "best" so migrated records don’t get narrowed by type declarations.

Also applies to: 53-54

lib/schemas.ts (1)

85-85: switch reason schema update looks correct.

lib/schemas.ts:85 now accepts "best", which matches the new switch path behavior.

lib/codex-manager.ts (1)

4303-4305: dispatcher wiring for best looks correct.

lib/codex-manager.ts:4303 (Line 4303) correctly routes to runBest(rest).

scripts/codex-routing.js (1)

1-7: routing table update is correct for the new subcommand.

scripts/codex-routing.js:6 now includes "best", so auth routing will recognize codex auth best.

…witching

Adds a new CLI command that automatically switches to the best standing account
based on the forecast algorithm. Supports --live, --json, and --model flags.

- Add 'best' to AUTH_SUBCOMMANDS in codex-routing.js
- Implement runBest() function in codex-manager.ts
- Add 'best' switch reason to schemas and types
- Update help text and feature list

Usage: codex auth best [--live] [--json] [--model <model>]
@Microck Microck force-pushed the feat/auth-best-command branch from 3247e6b to 57fd770 Compare March 17, 2026 18:45
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/codex-manager.ts`:
- Around line 4105-4162: The duplicated account-switch logic in runBest()
(around bestIndex handling, token refresh and calling
setCodexCliActiveSelection) diverges from runSwitch() by not emitting the
refresh-failure warning; replace the duplicated block with a single reuse of
runSwitch() or extract a shared helper (e.g., switchToAccount(storage, index,
options)) and call it from both runBest() and runSwitch(); ensure the helper
preserves behavior from runSwitch() including calls to queuedRefresh(),
hasUsableAccessToken(), updating bestAccount fields (accessToken, refreshToken,
expiresAt, email, accountId, lastUsed, lastSwitchReason), saveAccounts(), and
finally setCodexCliActiveSelection(), and keep the refresh-failure warning path
identical to runSwitch().
- Around line 4028-4041: The live-probe refresh flow calls
queuedRefresh(account.refreshToken) but doesn't persist rotated tokens back into
storage, so subsequent refreshes use a stale refresh token; when
refreshResult.type === "success" (the block that sets probeAccessToken and
probeAccountId) persist the rotated tokens into the accounts store (e.g., update
storage.accounts[i].refreshToken = refreshResult.refresh and
storage.accounts[i].accessToken = refreshResult.access and accountId if
provided) and flush/save the storage or update the in-memory account used later
(so bestAccount.refreshToken won't remain stale); locate the logic around
hasUsableAccessToken, queuedRefresh, refreshResult and mirror the persistence
approach used by runFix().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 47a71baa-7ca0-4104-aba8-60f6d9da3c8f

📥 Commits

Reviewing files that changed from the base of the PR and between 3247e6b and 57fd770.

📒 Files selected for processing (7)
  • lib/accounts.ts
  • lib/codex-manager.ts
  • lib/schemas.ts
  • lib/storage/migrations.ts
  • scripts/codex-multi-auth.js
  • scripts/codex-routing.js
  • scripts/codex.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (1)
lib/**

⚙️ CodeRabbit configuration file

focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

Files:

  • lib/schemas.ts
  • lib/storage/migrations.ts
  • lib/accounts.ts
  • lib/codex-manager.ts
🔇 Additional comments (12)
lib/accounts.ts (1)

94-94: lgtm — type union extended consistently.

the "best" literal aligns with lib/schemas.ts:85 and lib/storage/migrations.ts:28,53. no runtime impact.

scripts/codex-routing.js (1)

6-6: lgtm — subcommand registered.

enables codex auth best routing. consistent with lib/codex-manager.ts:4301-4303 dispatcher.

lib/storage/migrations.ts (1)

28-28: lgtm — storage metadata types extended.

both v1 and v3 interfaces now accept "best". migration at line 92 passes through the value unchanged.

Also applies to: 53-53

lib/schemas.ts (1)

85-85: lgtm — zod schema updated.

SwitchReasonSchema now validates "best". both AccountMetadataV1Schema:154 and AccountMetadataV3Schema:110 inherit this via .optional().

lib/codex-manager.ts (8)

295-295: lgtm — help text and feature registry updated.

help at lib/codex-manager.ts:295 documents the command syntax. feature 41 at line 357 tracks implementation.

Also applies to: 357-357


3981-4006: args parsing still accepts invalid flags silently.

past review flagged this at lib/codex-manager.ts:3981-4006. parseForecastArgs() at line 1744 already handles validation, unknown-flag rejection, and --model value checks — reuse it.


4052-4054: probe errors still silently swallowed.

past review at lib/codex-manager.ts:4045-4054 flagged the empty catch. compare with runForecast() at lines 2095-2100 which collects errors into probeErrors and surfaces them.


4123-4149: refresh failure during switch still silent.

past review at lib/codex-manager.ts:4123-4149 flagged missing warning. runSwitch():3951 emits console.warn() on failure; this path doesn't.


4008-4009: toctou race window — concurrent cli runs can clobber each other.

past review at lib/codex-manager.ts:4008-4153 flagged the load→network→save pattern. on windows with slow ntfs, concurrent codex auth best invocations risk EBUSY or lost writes. as per coding guidelines, lib/** changes should handle EBUSY/429 scenarios.

Also applies to: 4153-4153


3981-4180: no vitest coverage for runBest() edge cases.

past review at lib/codex-manager.ts:3981-4180 flagged missing tests. as per coding guidelines, lib/**: "verify every change cites affected tests (vitest)". need coverage for:

  • --help flag
  • --model without value
  • idempotence (already on best account)
  • probe 429 handling
  • concurrent invocations / EBUSY

4301-4303: lgtm — dispatcher routes best command.

correctly calls runBest(rest) and returns exit code.


4151-4153: verify lib/storage.ts guard accepts "best".

past review at lib/codex-manager.ts:4151-4153 noted lib/storage.ts:1829 had a guard that stripped unknown switch reasons. the schemas are updated, but the storage module may have a separate runtime check.

#!/bin/bash
# check if lib/storage.ts has a switch-reason guard and whether it includes "best"
rg -n "isSwitchReason|lastSwitchReason" lib/storage.ts -B 2 -A 5

@ndycode ndycode added the enhancement New feature or request label Mar 17, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/codex-manager.ts (1)

1768-1808: 🧹 Nitpick | 🔵 Trivial

dedupe forecast/best arg parsing to avoid drift.

lib/codex-manager.ts:1768-1808 and lib/codex-manager.ts:1810-1849 duplicate nearly identical parsing logic. extracting a shared parser will keep behavior aligned and reduce future regression risk.

Also applies to: 1810-1849

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/codex-manager.ts`:
- Around line 4079-4182: The CLI currently accepts options.model but only uses
it when options.live is true, causing silent no-ops; after parsing args
(parseBestArgs) and obtaining options, add an explicit check: if options.model
is set and options.live is falsy, either print a clear warning (e.g.,
console.error(...) or console.log(...)) or return a non-zero error code so the
user knows --model requires --live; implement this check near where options is
read (immediately after const options = parsedArgs.options) and make sure
messaging references both options.model and options.live so behavior is
explicit.

In `@test/codex-manager-cli.test.ts`:
- Around line 944-1070: Add a deterministic regression test that verifies
parsing and behavior of "--model <value>" when "--live" is NOT passed by
invoking runCodexMultiAuthCli(["auth","best","--model","<model>"]) with
controlled mocks (loadAccountsMock, fetchCodexQuotaSnapshotMock,
setCodexCliActiveSelectionMock, saveAccountsMock); specifically, simulate
account(s) via loadAccountsMock, stub fetchCodexQuotaSnapshotMock to return a
200 snapshot for the given model, assert fetchCodexQuotaSnapshotMock was called
with expect.objectContaining({ model: "<model>" }), and then assert expected
side effects: when current account is already best ensure saveAccountsMock and
setCodexCliActiveSelectionMock are not called and a console.log message like
"Already on best account" was emitted, and when another account is better ensure
setCodexCliActiveSelectionMock is called once and exit code is 0—use vitest
spies and deterministic timestamps similar to the existing tests to avoid
flakiness.
- Around line 864-943: Add a deterministic JSON-path assertion for the success
switch branch by invoking runCodexMultiAuthCli with the --json flag (e.g.,
runCodexMultiAuthCli(["auth","best","--live","--json"])) and reusing the
existing console.log spy (logSpy) to capture output; parse the logged JSON and
assert it contains a success status and the switched-account object with
accountId, email, accessToken, refreshToken, and expiresAt matching
storageState.accounts[1] (and the previously asserted now + 3_600_000 / idToken
values), ensuring the machine-readable contract is verified alongside the
human-readable log checks in the test for runCodexMultiAuthCli.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 82ee9235-37e4-4ec2-bfde-d3927fa08d14

📥 Commits

Reviewing files that changed from the base of the PR and between 57fd770 and 38b1803.

📒 Files selected for processing (4)
  • lib/codex-manager.ts
  • lib/storage.ts
  • test/codex-manager-cli.test.ts
  • test/storage-flagged.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (2)
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/storage-flagged.test.ts
  • test/codex-manager-cli.test.ts
lib/**

⚙️ CodeRabbit configuration file

focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

Files:

  • lib/storage.ts
  • lib/codex-manager.ts
🔇 Additional comments (5)
lib/storage.ts (1)

1832-1835: good guard update for the new switch reason.

lib/storage.ts:1832-1835 correctly preserves lastSwitchReason: "best" during flagged storage normalization, so round-trips no longer drop this value.

lib/codex-manager.ts (1)

4073-4297: please confirm vitest regressions for the new best paths.

i can’t verify test coverage for this flow from the provided files. please confirm cases exist for zero-account json errors, already-on-best idempotence, and live probe failure handling (including 429/concurrency) for lib/codex-manager.ts:4073-4297.

run this read-only check:

#!/bin/bash
set -u

fd "codex-manager-cli.test.ts" test || true
rg -n --type ts -C2 "auth best|runBest|already on best|No accounts configured|--model|429|concurrent|ebusy" test || true

expected result: explicit vitest cases covering runBest edge paths and failure/concurrency behavior.
as per coding guidelines, lib/**: focus on auth rotation, windows filesystem io, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

test/storage-flagged.test.ts (1)

116-133: good targeted regression for "best" persistence.

test/storage-flagged.test.ts:116-133 adds a deterministic vitest check that lastSwitchReason: "best" survives save/load, which matches the runtime guard update in lib/storage.ts.

test/codex-manager-cli.test.ts (2)

531-601: good early-guard coverage for auth best cli parsing.

these tests in test/codex-manager-cli.test.ts: Line 531 through Line 601 correctly lock help, malformed args, unknown args, and no-account json error before mutation. this is solid defensive coverage for the new command surface.


1237-1342: nice concurrency regression for queued refresh reuse.

test/codex-manager-cli.test.ts: Line 1237 through Line 1342 is a good targeted race test. asserting one underlying refresh network call with two concurrent auth best --live --json runs directly covers the token refresh race class.

@ndycode ndycode changed the title feat(cli): add 'codex auth best' command for automatic best account switching feat(cli): add codex auth best account switching Mar 18, 2026
@ndycode ndycode merged commit 04c0151 into ndycode:main Mar 18, 2026
1 of 2 checks passed
ndycode pushed a commit that referenced this pull request Apr 6, 2026
feat(cli): add codex auth best account switching
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants