Skip to content

refactor: split auth CLI help and command flows#142

Closed
ndycode wants to merge 7 commits intoplan/01-beginner-onboarding-docsfrom
plan/02-cli-help-and-login-split
Closed

refactor: split auth CLI help and command flows#142
ndycode wants to merge 7 commits intoplan/01-beginner-onboarding-docsfrom
plan/02-cli-help-and-login-split

Conversation

@ndycode
Copy link
Owner

@ndycode ndycode commented Mar 20, 2026

Summary

  • split auth CLI help text and arg parsing out of lib/codex-manager.ts
  • move auth login, auth switch, and auth best into a focused auth-command module
  • keep onboarding restore behavior aligned with the extracted modules and cover the new error paths directly in tests

What Changed

  • added lib/codex-manager/help.ts for CLI usage text plus login/best arg parsing
  • added lib/codex-manager/auth-commands.ts for runAuthLogin, runSwitch, runBest, and shared selected-account persistence/sync
  • trimmed lib/codex-manager.ts down to orchestration and shared helpers
  • expanded test/codex-manager-auth-commands.test.ts to cover runBest --help, hermetic live-best lease mocking, EBUSY save failures, and backup-restore error handling
  • updated test/documentation.test.ts so CLI usage assertions read from the extracted modules instead of the monolith

Validation

  • npm test -- test/codex-manager-auth-commands.test.ts
  • npm run typecheck
  • npm run lint
  • npm run build

Notes

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

this PR completes a focused extraction: runAuthLogin, runSwitch, runBest, and persistAndSyncSelectedAccount move out of the monolith into lib/codex-manager/auth-commands.ts, while help text and arg parsers land in lib/codex-manager/help.ts. the previous concern about dropped activeIndexByFamily bounds clamping on backup restore is fully addressed by the new clampPreservedActiveIndexByFamily helper, with a passing hermetic test confirming clamping to [0, maxIndex] for all MODEL_FAMILIES entries.

key points:

  • clamping fix confirmedclampPreservedActiveIndexByFamily iterates MODEL_FAMILIES, clamps out-of-range indices, and always writes codex = targetIndex; the restore-flow test at line 723 validates end-to-end
  • concurrencywithSerializedBestLiveRun correctly serializes concurrent --live writes per storage path via a mutable tail-promise queue; the concurrent test (line 627) verifies maxActiveSaves === 1; windows EBUSY/EPERM during the live-best save propagates correctly and blocks setCodexCliActiveSelection (tested at line 693)
  • windows token safetysaveAccounts is always called before setCodexCliActiveSelection; if the save throws (EBUSY, EPERM), the codex CLI state is never updated with a partially-written token — this is explicitly tested
  • missing coverageisBrowserLaunchSuppressed = true (headless / windows no-browser path) is mocked false in all tests; the branch that skips promptOAuthSignInMode and forces "manual" mode goes unexercised; see inline comment

Confidence Score: 4/5

  • safe to merge; prior clamping concern is resolved and windows save-before-sync invariant is tested
  • prior P0 clamping issue addressed, concurrency serialization verified, EBUSY/EPERM paths tested; one P2 gap remains — the isBrowserLaunchSuppressed=true branch in runAuthLogin has no coverage
  • test/codex-manager-auth-commands.test.ts — add a test for isBrowserLaunchSuppressed=true to cover the windows/headless manual-mode forced path

Important Files Changed

Filename Overview
lib/codex-manager/auth-commands.ts new module: runAuthLogin, runSwitch, runBest, and persistAndSyncSelectedAccount extracted from the monolith; clampPreservedActiveIndexByFamily addresses the previously flagged bounds issue; withSerializedBestLiveRun serialization logic is correct; one notable coverage gap on the isBrowserLaunchSuppressed=true path
lib/codex-manager/help.ts clean extraction of printUsage, printBestUsage, parseAuthLoginArgs, and parseBestArgs; help/error discriminated union on ParsedAuthLoginArgs/ParsedBestArgs is a clear improvement over the prior opaque boolean return
lib/codex-manager.ts monolith correctly trimmed to orchestration and shared helpers; imports are accurate; configureUnifiedSettings correctly moved to auth-commands dependency injection rather than a direct import
test/codex-manager-auth-commands.test.ts solid coverage of EBUSY save failures, live-best lease mocking, family index clamping, and backup-restore error paths; isBrowserLaunchSuppressed=true (headless/Windows manual mode) is not exercised in any test case
test/codex-manager-help.test.ts clean, focused unit coverage of both parsers including help discriminant, error paths, and flag combinations; correctly verifies no side-effects on --help
test/documentation.test.ts correctly updated to read CLI usage assertions from lib/codex-manager/help.ts and auth-commands.ts instead of the monolith; all path guards (existsSync) are in place

Sequence Diagram

sequenceDiagram
    participant CM as codex-manager.ts
    participant AC as auth-commands.ts
    participant H as help.ts
    participant S as storage.ts
    participant CW as codex-cli/writer.ts

    CM->>H: printUsage()
    CM->>AC: runAuthLoginCommand(args, deps)
    AC->>H: parseAuthLoginArgs(args)
    H-->>AC: ParsedAuthLoginArgs
    AC->>S: loadAccounts()
    AC->>S: getNamedBackups()
    AC->>S: restoreAccountsFromBackup(path, {persist:false})
    AC->>AC: persistAndSyncSelectedAccount(storage, targetIndex)
    AC->>AC: clampPreservedActiveIndexByFamily(storage, targetIndex)
    AC->>S: saveAccounts(storage)
    AC->>CW: setCodexCliActiveSelection(...)

    CM->>AC: runBestCommand(args, helpers)
    AC->>H: parseBestArgs(args)
    H-->>AC: ParsedBestArgs
    AC->>AC: withSerializedBestLiveRun(storagePath, execute)
    note over AC: lease acquired, queue serialized
    AC->>S: loadAccounts()
    AC->>S: saveAccounts(storage)
    AC->>AC: persistAndSyncSelectedAccount(...)
    AC->>CW: setCodexCliActiveSelection(...)

    CM->>AC: runSwitchCommand(args, helpers)
    AC->>S: loadAccounts()
    AC->>AC: persistAndSyncSelectedAccount(...)
    AC->>S: saveAccounts(storage)
    AC->>CW: setCodexCliActiveSelection(...)
Loading

Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: test/codex-manager-auth-commands.test.ts
Line: 74-76

Comment:
**missing coverage: `isBrowserLaunchSuppressed = true` path**

`isBrowserLaunchSuppressed` is hard-wired to `false` across every test, so the branch at `auth-commands.ts:746` that skips `promptOAuthSignInMode` and forces `signInMode = "manual"` is never exercised. this matters on windows/headless CI where the browser is suppressed — if that guard breaks, users get an unexpected sign-in mode prompt instead of going straight to manual flow.

worth adding a test like:

```ts
it("forces manual sign-in mode when browser launch is suppressed", async () => {
  const { isBrowserLaunchSuppressed } = await import("../lib/auth/browser.js");
  vi.mocked(isBrowserLaunchSuppressed).mockReturnValue(true);
  loadAccountsMock.mockResolvedValue(null);
  getNamedBackupsMock.mockResolvedValue([]);
  const deps = createAuthLoginDeps({
    runOAuthFlow: vi.fn(async () => ({ type: "failed", reason: "cancelled" } as TokenResult)),
  });

  const result = await runAuthLogin([], deps);

  expect(deps.promptOAuthSignInMode).not.toHaveBeenCalled();
  expect(deps.runOAuthFlow).toHaveBeenCalledWith(false, "manual");
  expect(result).toBe(0);
});
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (7): Last reviewed commit: "test: cover live lease failures" | Re-trigger Greptile

@chatgpt-codex-connector
Copy link

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
Contributor

coderabbitai bot commented Mar 20, 2026

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Review skipped — only excluded labels are configured. (1)
  • skip-review

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2af6a2ef-a131-495e-b51a-788ff2b52552

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

walkthrough

refactors auth command logic out of lib/codex-manager.ts into lib/codex-manager/auth-commands.ts and lib/codex-manager/help.ts; adds comprehensive vitest suites for the new modules and updates documentation test assertions to reference the new files (lib/codex-manager.ts:1, lib/codex-manager/auth-commands.ts:1, lib/codex-manager/help.ts:1).

changes

Cohort / File(s) Summary
main manager refactor
lib/codex-manager.ts
delegates runAuthLogin, runSwitch, runBest to new modules; removed in-file CLI/auth helpers and storage/ui imports.
auth commands module
lib/codex-manager/auth-commands.ts
new orchestration for login, switch, best, persistAndSyncSelectedAccount, plus exported AuthCommandHelpers / AuthLoginCommandDeps interfaces and refresh/lease/serialization logic.
help utilities module
lib/codex-manager/help.ts
new CLI help and argument parsers: printUsage, printBestUsage, parseAuthLoginArgs, parseBestArgs with discriminated-result types.
auth command tests
test/codex-manager-auth-commands.test.ts
new comprehensive tests that mock storage, refresh-queue, quota probing, CLI sync, and interactive flows; covers persist/sync, live probing, JSON output, and concurrency serialization.
help parsing tests
test/codex-manager-help.test.ts
new tests for parseAuthLoginArgs and parseBestArgs, help behavior, and error messages.
documentation test updates
test/documentation.test.ts
updated assertions to read help strings from lib/codex-manager/help.ts and lib/codex-manager/auth-commands.ts.

sequence diagram(s)

mermaid
sequenceDiagram
participant user as User
participant cli as codex cli
participant auth as auth-commands (lib/.../auth-commands.ts)
participant storage as storage (accounts file)
participant refresh as refresh-queue
participant quota as quota service
rect rgba(50,150,200,0.5)
user->>cli: invoke codex auth best|switch|login
end
cli->>auth: call runBest/runSwitch/runAuthLogin(args)
auth->>storage: load accounts
alt needs refresh
auth->>refresh: queuedRefresh(token)
refresh-->>auth: refreshed tokens / errors
end
opt live probing
auth->>quota: fetchCodexQuotaSnapshot
quota-->>auth: quota snapshots
end
auth->>storage: saveAccounts (if changed)
auth->>cli: setCodexCliActiveSelection (sync)
cli-->>user: exit code / printed output

estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

review notes

  • missing regression tests: add integration tests that perform real-file persistence and reload to validate activeIndexByFamily clamping and end-to-end save/restore behavior (test/codex-manager-auth-commands.test.ts:1).
  • windows edge cases: exercise browser suppression flags and StorageError behavior on windows paths/permissions for restore/save flows (lib/codex-manager/auth-commands.ts:1, lib/codex-manager/help.ts:1).
  • concurrency risk: audit serialization between runBest --live and runAuthLogin for the same storage path; ensure single-writer guarantees and refresh-queue lease correctness (lib/codex-manager/auth-commands.ts:1, test/codex-manager-auth-commands.test.ts:1).
🚥 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 (refactor type, lowercase, imperative, 47 chars) and accurately summarizes the main refactor: extraction of auth CLI help text and command flows into focused submodules.
Description check ✅ Passed PR description is comprehensive and aligns well with the template, covering summary, what changed, validation checklist, and additional notes.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch plan/02-cli-help-and-login-split
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch plan/02-cli-help-and-login-split

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.

coderabbitai[bot]
coderabbitai bot previously requested changes Mar 22, 2026
Copy link
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/auth-commands.ts`:
- Around line 290-294: The doc comment warns of a race when concurrent `codex
auth best --live` runs refresh the same account and both call `saveAccounts`;
add a runtime guard by acquiring the same refresh-lease/file-lock mechanism used
in `lib/codex-manager.ts` (the refresh-lease dedupe) around the live-probe +
refresh path in `lib/codex-manager/auth-commands.ts` so that the live probe
acquires the lease before mutating tokens and releases it after `saveAccounts`;
also add a regression test that spawns two concurrent invocations of the `auth
best --live` code path and asserts that only one process performs the
refresh/save while the other waits or skips, documenting expected serialized
behavior.

In `@test/codex-manager-auth-commands.test.ts`:
- Around line 455-540: Add a regression test that reproduces concurrent
live-probe writes by invoking runBest(["--live"]) twice in parallel, using the
existing mocks (loadAccountsMock, saveAccountsMock,
setCodexCliActiveSelectionMock, createStorage) and delaying one save via a
Promise to force an interleaving; assert both runBest calls return successfully
and that storage is not corrupted (e.g., final storage.activeIndex and account
fields match an expected consistent state or that saveAccountsMock calls
preserve order/atomicity), or alternatively assert saveAccountsMock was
effectively serialized (no overlapping save starts) to prevent race conditions;
place this test alongside the other runBest tests and reference runBest and
saveAccounts in the test to make the concurrency regression explicit.
🪄 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: 15d3dd4e-403a-4917-85f6-6594b7f8a020

📥 Commits

Reviewing files that changed from the base of the PR and between 0a53738 and d48cfa8.

📒 Files selected for processing (6)
  • lib/codex-manager.ts
  • lib/codex-manager/auth-commands.ts
  • lib/codex-manager/help.ts
  • test/codex-manager-auth-commands.test.ts
  • test/codex-manager-help.test.ts
  • test/documentation.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/documentation.test.ts
  • test/codex-manager-help.test.ts
  • test/codex-manager-auth-commands.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/codex-manager/help.ts
  • lib/codex-manager.ts
  • lib/codex-manager/auth-commands.ts
🔇 Additional comments (14)
test/documentation.test.ts (1)

244-269: lgtm, the doc integrity test correctly tracks the new module locations.

the assertions now check lib/codex-manager/help.ts and lib/codex-manager/auth-commands.ts for usage text alignment, which matches the refactor's extraction of help and auth command logic.

test/codex-manager-help.test.ts (1)

1-63: good coverage of the pure arg parsers.

the test suite validates flag parsing for parseAuthLoginArgs and parseBestArgs including edge cases like missing model values and unknown flags. since these are synchronous, deterministic parsers, no concurrency tests are needed here.

lib/codex-manager.ts (3)

82-88: clean import wiring for the extracted modules.

the imports from ./codex-manager/help.js and ./codex-manager/auth-commands.js align with the refactor goals.


4239-4249: delegation to extracted command functions looks correct.

each of runAuthLogin, runSwitch, runBest now forwards to the corresponding module function with the appropriate dependency object.


4320-4349: dependency objects correctly wire the required helpers.

authCommandHelpers includes resolveActiveIndex, hasUsableAccessToken, applyTokenAccountIdentity, and normalizeFailureDetail as required by AuthCommandHelpers interface in lib/codex-manager/auth-commands.ts:62-76.

authLoginCommandDeps spreads authCommandHelpers and adds all the required fields from AuthLoginCommandDeps interface at lib/codex-manager/auth-commands.ts:78-135.

lib/codex-manager/help.ts (1)

1-153: the extracted help module is clean and well-typed.

parseAuthLoginArgs and parseBestArgs return discriminated unions that clearly separate success, help, and error states. no token or sensitive data handling here.

test/codex-manager-auth-commands.test.ts (2)

272-421: solid coverage of the core persistence and sync flows.

the tests validate:

  • re-enabling disabled accounts and refreshing stale tokens at test/codex-manager-auth-commands.test.ts:273-316
  • family index clamping for restored pools at test/codex-manager-auth-commands.test.ts:318-377
  • warning surfacing when refresh fails at test/codex-manager-auth-commands.test.ts:379-421

542-620: test covers restore-backup family index clamping well.

the assertions at lines 612-618 verify that out-of-bounds indices like 9 and -3 are clamped to valid bounds (2 and 0). this matches the clamping logic in clampPreservedActiveIndexByFamily at lib/codex-manager/auth-commands.ts:137-156.

lib/codex-manager/auth-commands.ts (6)

1-49: imports look correct for the extracted module.

the module imports the required dependencies from internal modules without any circular dependency risks.


137-156: clamping logic correctly bounds family indices.

clampPreservedActiveIndexByFamily at lib/codex-manager/auth-commands.ts:141-155 iterates MODEL_FAMILIES and clamps each index to [0, maxIndex]. the test at test/codex-manager-auth-commands.test.ts:318-377 verifies this handles negative and out-of-range values.


158-236: persistAndSyncSelectedAccount handles token refresh and persistence correctly.

the function:

  1. re-enables disabled accounts at lines 180-183
  2. updates activeIndex and activeIndexByFamily at lines 185-191
  3. refreshes tokens if unusable at lines 199-221
  4. persists via saveAccounts at line 225
  5. syncs to codex cli at lines 227-234

the warning at line 217-219 uses normalizeFailureDetail which truncates and sanitizes error messages per lib/codex-manager.ts:177-187, so no token leakage.


674-692: backup discovery error handling is safe.

the debug log at lines 679-682 only logs code and error.message, not tokens or sensitive data. the warning at lines 684-686 is a generic user-facing message without secrets.


730-788: restore backup confirmation flow is well-structured.

the flow:

  1. prompts user confirmation at lines 731-736
  2. restores without persisting at line 749-752
  3. clamps family indices via preserveActiveIndexByFamily: true at line 759
  4. persists via persistAndSyncSelectedAccount at lines 754-761
  5. handles StorageError with formatted hints at lines 776-777

this addresses the behavioral regression mentioned in the pr summary regarding multi-family index bounds clamping.


343-420: saveAccounts already handles EBUSY with exponential backoff retry—concern addressed.

the probe loop at lib/codex-manager/auth-commands.ts:349-420 accumulates changes and calls persistProbeChangesIfNeeded to write them once. this is efficient. concurrent writes are already protected: saveAccounts at lib/storage.ts:2157 wraps the operation with withStorageLock for in-process serialization. the underlying saveAccountsUnlocked at lib/storage.ts:1997-2019 explicitly retries EBUSY on the final rename with exponential backoff (up to 5 attempts). renameFileWithRetry at lib/storage.ts:456-481 does the same for backup operations. test/storage.test.ts:2646 verifies the EBUSY retry behavior. the concern is valid but already mitigated.

coderabbitai[bot]
coderabbitai bot previously requested changes Mar 22, 2026
Copy link
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

🤖 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/auth-commands.ts`:
- Around line 824-837: Add direct vitest unit tests for runAuthLogin that
simulate its error branches by mocking the restore/persistence and storage
modules: create tests that (1) throw a StorageError with code "EBUSY" when the
restore is attempted and assert formatStorageErrorHint is used and flow
continues, (2) throw a StorageError with code "EACCES" and assert the same
hint-handling path, (3) throw a rate/429-equivalent error from the
persistence/restore call and assert the generic error path is taken, and (4)
simulate a failure followed by loadAccounts resolving to a non-empty accounts
array to verify the recovery branch (uses loadAccounts mock to return accounts
after the failed restore); reference runAuthLogin, StorageError,
formatStorageErrorHint, loadAccounts, and loadNamedBackupsForOnboarding when
locating code to mock and assert.

In `@test/codex-manager-auth-commands.test.ts`:
- Around line 272-700: Add regression tests that simulate Windows EBUSY
filesystem errors by making saveAccountsMock (and where relevant
persistProbeChangesIfNeeded/restoreAccountsFromBackupMock) reject with an Error
that has code "EBUSY" and an appropriate message; for
persistAndSyncSelectedAccount assert the promise rejects with the EBUSY error
and that setCodexCliActiveSelectionMock is not called, for runBest --live
simulate a mid-probe failure of persistProbeChangesIfNeeded and assert the
command handles/logs the failure and returns the expected exit code while not
corrupting concurrent saves, and for the backup-restore flow add a test where
restoreAccountsFromBackupMock rejects with code "EBUSY" and assert runAuthLogin
surfaces the error (or returns non-zero) and does not call saveAccountsMock;
reference test helpers and mocks: persistAndSyncSelectedAccount, runBest,
runAuthLogin, saveAccountsMock, persistProbeChangesIfNeeded,
restoreAccountsFromBackupMock, setCodexCliActiveSelectionMock when adding these
tests.
- Around line 608-686: Add a new test that simulates restoreAccountsFromBackup
throwing a StorageError and asserts the CLI handles it: mock
restoreAccountsFromBackupMock to reject with new StorageError("msg") (use the
same StorageError type imported in the code), call runAuthLogin with deps that
choose the restore flow (promptOAuthSignInMode -> "restore-backup",
promptBackupRestoreMode -> "latest"), then expect runAuthLogin to return a
non-zero error code, expect confirmMock to have been invoked, expect
saveAccountsMock not to be called, and assert the error was logged (spy on
console.error or the logger used). This tests the error path around
restoreAccountsFromBackup in runAuthLogin / auth-commands restore flow.
🪄 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: 78b7071d-a17a-418b-8870-f70f4a541894

📥 Commits

Reviewing files that changed from the base of the PR and between d48cfa8 and 2762012.

📒 Files selected for processing (2)
  • lib/codex-manager/auth-commands.ts
  • test/codex-manager-auth-commands.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)
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/codex-manager/auth-commands.ts
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/codex-manager-auth-commands.test.ts
🔇 Additional comments (11)
lib/codex-manager/auth-commands.ts (7)

65-66: lgtm: module-level serialization state.

the combination of liveBestLeaseCoordinator for cross-process lease coordination and serializedLiveBestByStorage for in-process queue serialization addresses the concurrency concern from the past review. tests at test/codex-manager-auth-commands.test.ts:542-606 validate the in-process serialization path.


143-179: solid serialization implementation.

the two-layer approach (in-process queue at line 147-158 + cross-process lease at line 162) correctly prevents concurrent --live probes from racing on the same storage path. the nested finally blocks at lines 165-177 ensure cleanup even when actions throw.


181-200: index clamping logic is correct.

properly handles out-of-bounds indices including negative values (clamped to 0) and values exceeding account count (clamped to maxIndex). tested at test/codex-manager-auth-commands.test.ts:318-377.


282-332: runSwitch validation flow is correct.

validates input before mutating storage, bounds-checks after loading, and warns on sync failure without blocking the local switch. tested at test/codex-manager-auth-commands.test.ts:423-438.


504-526: conditional sync for already-best accounts looks correct.

when the current account is already best but was refreshed during live probe, the code syncs updated tokens to codex cli at lines 513-522 without unnecessarily re-persisting unchanged storage. good optimization.


267-279: saveAccounts already implements EBUSY retry with exponential backoff.

lib/storage.ts:2001-2020 contains a 5-attempt retry loop for windows EPERM/EBUSY on the rename operation, with exponential backoff (10ms × 2^attempt). regression tests at test/storage.test.ts:2597 ("saveAccounts EPERM/EBUSY retry logic") explicitly cover this path—including success cases on second/third attempt and exhaustion after 5 failures. the coding guidelines requirement for windows filesystem IO EBUSY handling is already met.

			> Likely an incorrect or invalid review comment.

383-387: saveAccounts already retries EBUSY; the gap is test coverage for exhaustion in live best mode.

saveAccounts wraps saveAccountsUnlocked (lib/storage.ts:2078-2081), which implements EBUSY/EPERM retry with exponential backoff over 5 attempts. if all retries fail, the error propagates. persistProbeChangesIfNeeded at lib/codex-manager/auth-commands.ts:383-387 doesn't catch this, so a persistent EBUSY after exhausted retries would terminate the live best command.

regression test is missing: add a test in test/codex-manager-auth-commands.test.ts that mocks saveAccounts to reject with EBUSY after 5 attempts and verifies graceful failure or recovery in live mode. test/storage.test.ts already covers saveAccounts retry exhaustion (test/storage.test.ts:2646), but live best integration test coverage for this path is absent.

test/codex-manager-auth-commands.test.ts (4)

89-100: partial storage mock preserves real types.

using vi.importActual to keep StorageError and other types while mocking i/o functions is the right approach for these tests.


124-166: test factories are well-designed.

createStorage and createHelpers provide sensible defaults that tests can override. reduces boilerplate while keeping tests readable.


222-270: deterministic test setup with fake timers.

fixed system time at line 224 and vi.clearAllMocks() at line 225 ensure tests are reproducible and isolated.


542-606: concurrent serialization test is solid.

this test directly exercises the serialization added to address the past review comment. the maxActiveSaves === 1 assertion at line 602 confirms no overlapping saves occur. good coverage.

coderabbitai[bot]
coderabbitai bot previously requested changes Mar 22, 2026
Copy link
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: 1

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

Inline comments:
In `@test/codex-manager-auth-commands.test.ts`:
- Around line 279-285: Add a test that verifies runBest(["--live"]) propagates
lease acquisition failures: mock leaseAcquireMock to reject with an Error (e.g.,
with code "EACCES"), ensure loadAccountsMock resolves normally, then assert that
await runBest(["--live"], createHelpers()) rejects with that same error and that
saveAccountsMock and setCodexCliActiveSelectionMock were not called; target the
mocks and functions named leaseAcquireMock, RefreshLeaseCoordinator.acquire,
runBest, loadAccountsMock, saveAccountsMock, and setCodexCliActiveSelectionMock
when adding the test.
🪄 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: 7c60887f-863f-4a70-b1d2-ba7d0ef2c400

📥 Commits

Reviewing files that changed from the base of the PR and between 2762012 and 31fdf39.

📒 Files selected for processing (1)
  • test/codex-manager-auth-commands.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 (1)
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/codex-manager-auth-commands.test.ts
🔇 Additional comments (6)
test/codex-manager-auth-commands.test.ts (6)

107-125: good partial mock strategy for storage.js and refresh-lease.js.

preserving real StorageError and formatStorageErrorHint exports via vi.importActual at test/codex-manager-auth-commands.test.ts:107-108 lets error-path tests assert on actual hint formatting. lease coordinator mock at test/codex-manager-auth-commands.test.ts:121-125 with bypass role prevents filesystem writes during test runs.


149-191: helper factories are cleanly typed and avoid real secrets.

createStorage and createHelpers at test/codex-manager-auth-commands.test.ts:149-191 use placeholder tokens ("refresh-token-1", "access-token-1") rather than real credentials. the typed overrides pattern keeps test setup DRY while allowing per-test customization.


247-306: deterministic timer setup with proper cleanup.

fake timers pinned to 2026-03-22T19:30:00.000Z at test/codex-manager-auth-commands.test.ts:248-249 ensure reproducible behavior for expiry checks and lastUsed timestamps. vi.clearAllMocks() and vi.restoreAllMocks() maintain test isolation.


459-478: good regression coverage for windows EBUSY errors.

test/codex-manager-auth-commands.test.ts:459-478 verifies persistAndSyncSelectedAccount propagates the EBUSY error and skips the codex sync call. combined with the it.each at lines 788-839 covering both EBUSY and EACCES for restore paths, this addresses the past review concern about missing windows filesystem error tests.


612-676: concurrency regression test properly verifies serialized saves.

test/codex-manager-auth-commands.test.ts:612-676 blocks the first save, starts a second runBest(["--live"]), and asserts maxActiveSaves === 1 at line 672 proving no interleaved writes. this addresses the prior review concern about missing regression tests for concurrent live-probe writes per lib/codex-manager/auth-commands.ts:290-294.


708-786: backup-restore flow tested with clamping and error paths.

test/codex-manager-auth-commands.test.ts:708-786 validates the happy path with activeIndexByFamily clamping (out-of-range indices snapped to pool size). error paths at lines 788-923 cover StorageError hint formatting, generic failures, and branching back to the existing-account menu when restore fails post-login.

@ndycode ndycode dismissed stale reviews from coderabbitai[bot], coderabbitai[bot], and coderabbitai[bot] March 22, 2026 15:43

All review threads are resolved and follow-up commits addressed this stale automated change request.

@ndycode ndycode added the passed label Mar 22, 2026
@ndycode
Copy link
Owner Author

ndycode commented Mar 23, 2026

Closing because this work is now included in main via #318 and #319.

@ndycode ndycode closed this Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant