refactor(codex-manager): dispatch through a command registry (phase 2) - #535
Conversation
26 standalone, side-effect-free formatter/presentation functions (plus the
PromptTone and ModelInspection types) moved verbatim from lib/codex-manager.ts
into lib/codex-manager/formatters/{text-style,quota-formatters,
account-formatters,model-formatters}.ts with an index.ts barrel.
codex-manager.ts shrinks from 3810 to 3446 lines; the previously public
exports styleAccountDetailText and formatBackupSavedAt are re-exported from
lib/codex-manager.ts so every existing import path keeps working; zero
behavior change. Phase 1 of audit roadmap §4.1.1.
https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
…ase 2) Convert the sequential if (command === ...) chain in runCodexMultiAuthCli into CLI_COMMAND_HANDLERS, a module-level ReadonlyMap<string, CliCommandHandler> kept inside lib/codex-manager.ts (handlers closure- capture module-scope deps, so an adjacent module would have forced a large internal export surface and cycle risk). 27 commands + 1 alias (status shares the list handler) — exactly the ACCOUNT_MANAGER_COMMANDS set. Context shape: uniform (rest: string[]) => number | Promise<number>; rest is the already-parsed argument tail and the return value is the exit code (runFeaturesCommand is synchronous, hence the number arm). Preserved quirks, zero behavior change: - auth-prefix compatibility rewrite via ACCOUNT_MANAGER_COMMANDS untouched - default subcommand login (sub ?? "login") and --help/-h short-circuits stay ahead of registry lookup - --json / -j detection for list/status inside the shared handler - config/debug nested sub-dispatch (explain/template, bundle) with their "Unknown config|debug command: ... (missing)" stderr + exit 1 - unknown command: stderr message + printUsage() + exit 1 - createRepairCommandDeps()/buildSelectAccountTraced() still constructed per dispatch, not at module load - keys are unique exact matches, so chain order had no shadowing to lose Line count 3446 -> 3484 (+38, registry doc comments and map-entry wrapping). Suites: 811 passed / 6 skipped across the 63 codex-manager test files; the 3 failures in test/codex-bin-wrapper.test.ts (Windows path resolution) reproduce identically on the base branch. Audit roadmap §4.1.1 phase 2; stacked on the formatters extraction branch (PR #525). https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
Warning Review limit reached
More reviews will be available in 1 minute and 42 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (7)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
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. Comment |
| import { stdout as output } from "node:process"; | ||
| import { ANSI } from "../../ui/ansi.js"; | ||
| import { paintUiText } from "../../ui/format.js"; | ||
| import { getUiRuntimeOptions } from "../../ui/runtime.js"; | ||
|
|
||
| export type PromptTone = "accent" | "success" | "warning" | "danger" | "muted"; | ||
|
|
||
| export function stylePromptText(text: string, tone: PromptTone): string { | ||
| if (!output.isTTY) return text; | ||
| const ui = getUiRuntimeOptions(); |
There was a problem hiding this comment.
missing vitest coverage for formatter modules
the extraction promotes many previously-private helpers (normalizeFailureDetail, collapseWhitespace, formatReasonLabel, extractErrorMessageFromPayload, parseStructuredErrorMessage, joinStyledSegments) to exported symbols across four new files. the code comment in account-formatters.ts explicitly calls out that styleAccountDetailText's tone-precedence logic is "security/UX-relevant," yet there are no new test files scoped to these formatter modules. the 811 passing CLI suites cover behavior end-to-end, but isolated unit tests for the newly-public formatter functions (especially error message parsing and quota tone logic) would lock in the per-function contracts and make regressions easier to pin during phase 3 decomposition.
Prompt To Fix With AI
This is a comment left during a code review.
Path: lib/codex-manager/formatters/text-style.ts
Line: 1-10
Comment:
**missing vitest coverage for formatter modules**
the extraction promotes many previously-private helpers (`normalizeFailureDetail`, `collapseWhitespace`, `formatReasonLabel`, `extractErrorMessageFromPayload`, `parseStructuredErrorMessage`, `joinStyledSegments`) to exported symbols across four new files. the code comment in `account-formatters.ts` explicitly calls out that `styleAccountDetailText`'s tone-precedence logic is "security/UX-relevant," yet there are no new test files scoped to these formatter modules. the 811 passing CLI suites cover behavior end-to-end, but isolated unit tests for the newly-public formatter functions (especially error message parsing and quota tone logic) would lock in the per-function contracts and make regressions easier to pin during phase 3 decomposition.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Review follow-up on the formatters extraction: the newly-public helpers (failure-detail normalization incl. structured-JSON unwrapping and the 260-char bound, reason labels, quota summary tone segmentation and percent clamping, cache-entry snapshot mapping, model inspection) now have isolated unit coverage so phase-3 regressions localize instead of surfacing only through the end-to-end CLI suites. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Continue the lib/codex-manager.ts decomposition (audit roadmap §4.1.1 phase 3, stacked on the registry branch, PR ndycode#535). Moves 1,218 net lines out of codex-manager.ts (3,484 -> 2,266) by extracting the remaining inline handler bodies and the module-scope helpers they closure-captured. All moves are verbatim; zero behavior change. Every added line in codex-manager.ts is an import. Command-body extractions: - check: runHealthCheck (~325 lines) -> lib/codex-manager/health-check.ts. Also reused by the login dashboard quick/deep-check actions, so it lives beside repair-commands.ts rather than under commands/. Imports library deps directly, exactly like repair-commands.ts does. - best: parseBestArgs + printBestUsage (~60 lines) -> lib/codex-manager/commands/best.ts. Still injected through BestCommandDeps by the dispatcher, so the command interface and tests are untouched. - login (data layer, ~460 lines) -> lib/codex-manager/login-menu-data.ts: menu quota auto-refresh targeting (countMenuQuotaRefreshTargets, refreshQuotaCacheForMenu, DEFAULT_MENU_QUOTA_REFRESH_TTL_MS), the ExistingAccountInfo row mapping + ready-first ordering (toExistingAccountInfo), runtime current-account resolution, and the Codex CLI selection drift sync. Shared helpers relocated (were module-private, closure-captured by the repair/forecast/report/best dependency factories and the blocks above): - lib/codex-manager/quota-cache-helpers.ts (~145 lines): getPersistedQuotaViewForAccount, updateQuotaCacheForAccount, cloneQuotaCacheData, pruneUnsafeQuotaEmailCacheEntry, DEFAULT_LIVE_PROBE_MODEL. - lib/codex-manager/account-credentials.ts (~70 lines): hasUsableAccessToken, hasLikelyInvalidRefreshToken, resolveStoredAccountIdentity, applyTokenAccountIdentity. - lib/codex-manager/persist-selected-account.ts (~125 lines): persistAndSyncSelectedAccount, shared by switch/best (deps injection) and the login backup-restore flow. codex-manager.ts now imports these and keeps injecting them through the existing deps interfaces (createRepairCommandDeps, runForecast/runBest/ report wrappers), so no command-module interface changed. No new module imports codex-manager.ts (no cycles); nothing previously exported moved. Remaining for phase 4: the interactive login control loop and OAuth machinery (runAuthLogin/runAuthLoginFlow, handleManageAction + manage helpers, runOAuthFlow/runSignInFlow, the sign-in/backup prompts, runActionPanel/waitForMenuReturn, persistAccountPool). These share closure-mutable menu state (pending refresh promise, status string, skip/generation counters) and label-based control flow, so extracting them is a larger, riskier move that deserves its own PR. Verification: tsc clean; eslint --max-warnings=0 clean on touched files; the 64 suites matching codex-manager/runCodexMultiAuthCli show identical results to the base branch (822 passed, 6 skipped, 3 failed - the known Windows-path environment failures in codex-bin-wrapper.test.ts, present on base). https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Summary
Phase 2 of the
codex-manager.tsdecomposition — audit roadmap §4.1.1 (docs/audits/AUDIT_2026-06-10.md, PR #522): theif (command === …)dispatch chains become aCLI_COMMAND_HANDLERS: ReadonlyMap<string, CliCommandHandler>registry. Zero behavior change; the extensive CLI suites are the safety net (811 passing).Design
type CliCommandHandler = (rest: string[]) => number | Promise<number>—restis the parsed argument tail, the return is the exit code. No heavier context object was needed.codex-manager.ts, not a separate module: every handler closure-captures module-scope deps (persistAndSyncSelectedAccount,runAuthLogin, repair-deps factory, traced selection, storage fns); an adjacent file would have meant exporting ~30 internals from the entrypoint and inviting a cycle.status/listshare a handler), exactly matchingACCOUNT_MANAGER_COMMANDS(the routing test asserts alignment).Dispatch quirks preserved exactly
auth-prefix compatibility rewrite; default subcommandlogin;--help/-hshort-circuits ahead of registry lookup; non-authroot → usage + exit 1--json/-jdetection inside the shared list/status handler; nestedconfig/debugsub-dispatch with their exact unknown-subcommand stderr + exit 1Validation
npm run typecheck; eslint--max-warnings=0Risk / Rollback
Dispatch-only refactor (+38 lines net, from registry doc comments); handler bodies untouched. Revert the single commit. Phase 3 (moving remaining handler bodies into
commands/) follows the roadmap.https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Generated by Claude Code
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
phase 2 of the
codex-manager.tsdecomposition: theif (command === …)dispatch chain (~200 lines) is replaced by aCLI_COMMAND_HANDLERS: ReadonlyMap<string, CliCommandHandler>with 28 entries, and the formatter helpers extracted in phase 1 are moved intolib/codex-manager/formatters/with a new vitest suite covering the newly-public contracts.CLI_COMMAND_HANDLERSmap mirrors all 27 commands + 1 alias exactly; per-dispatch factories (createRepairCommandDeps,buildSelectAccountTraced) remain lazy inside handler closures, preserving the original evaluation order.text-style,quota-formatters,model-formatters,account-formatters) and a barrelindex.tspromote previously-private helpers to exported symbols;codex-manager.tsre-exports only the two symbols that had prior external consumers.test/codex-manager-formatters.test.tsadds unit contracts for the extracted helpers, including edge cases for cyclic log args, clamped quota percentages, and structured error payloads.Confidence Score: 5/5
safe to merge — purely mechanical dispatch refactor with no handler body changes and 811 passing CLI tests as the safety net.
the dispatch change is a direct key-lookup substitution for a sequential if/else chain; all 28 entries are verified against ACCOUNT_MANAGER_COMMANDS by the routing test. per-dispatch factories remain lazy inside handler closures. the two style nits (type-only import, stale test reference in a comment) have no runtime impact.
no files require special attention; the two nits are in lib/codex-manager/formatters/quota-formatters.ts (import style) and lib/codex-manager/formatters/account-formatters.ts (comment pointer).
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A["runCodexMultiAuthCli(rawArgs)"] --> B{auth-prefix\ncompat rewrite} B --> C[normalize command] C --> D{"--help / -h?"} D -->|yes| E[printUsage → exit 0] D -->|no| F{"non-auth root?"} F -->|yes| G[usage + exit 1] F -->|no| H["CLI_COMMAND_HANDLERS.get(command)"] H -->|found| I["handler(rest) → exit code"] H -->|not found| J["stderr + usage + exit 1"] I --> K["lazy factories at dispatch time\n(createRepairCommandDeps, buildSelectAccountTraced)"]Prompt To Fix All With AI
Reviews (2): Last reviewed commit: "test(codex-manager): unit-pin the extrac..." | Re-trigger Greptile