Thanks to visit codestin.com
Credit goes to github.com

Skip to content

refactor(codex-manager): dispatch through a command registry (phase 2) - #535

Merged
ndycode merged 3 commits into
mainfrom
claude/audit-18-manager-registry
Jun 10, 2026
Merged

ndycode merged 3 commits into
mainfrom
claude/audit-18-manager-registry

Conversation

@ndycode

@ndycode ndycode commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Phase 2 of the codex-manager.ts decomposition — audit roadmap §4.1.1 (docs/audits/AUDIT_2026-06-10.md, PR #522): the if (command === …) dispatch chains become a CLI_COMMAND_HANDLERS: ReadonlyMap<string, CliCommandHandler> registry. Zero behavior change; the extensive CLI suites are the safety net (811 passing).

Stacked on #525 (formatter extraction, phase 1) — merge that first; this PR then shows only the registry commit.

Design

  • type CliCommandHandler = (rest: string[]) => number | Promise<number>rest is the parsed argument tail, the return is the exit code. No heavier context object was needed.
  • The registry lives in 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.
  • 28 keys = 27 commands + 1 alias (status/list share a handler), exactly matching ACCOUNT_MANAGER_COMMANDS (the routing test asserts alignment).

Dispatch quirks preserved exactly

  • auth-prefix compatibility rewrite; default subcommand login; --help/-h short-circuits ahead of registry lookup; non-auth root → usage + exit 1
  • --json/-j detection inside the shared list/status handler; nested config/debug sub-dispatch with their exact unknown-subcommand stderr + exit 1
  • Unknown command → stderr + usage + exit 1; repair deps still constructed per dispatch, not at module load
  • No order-shadowing existed in the chains, so the map is semantically identical

Validation

  • npm run typecheck; eslint --max-warnings=0
  • All 63 suites matching codex-manager/runCodexMultiAuthCli: 811 passed, 6 skipped, 3 failed — the 3 are the known Windows-path environment cases, identical on the base branch
  • Independently re-verified: codex-manager-cli + codex-routing, 205/205

Risk / 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.ts decomposition: the if (command === …) dispatch chain (~200 lines) is replaced by a CLI_COMMAND_HANDLERS: ReadonlyMap<string, CliCommandHandler> with 28 entries, and the formatter helpers extracted in phase 1 are moved into lib/codex-manager/formatters/ with a new vitest suite covering the newly-public contracts.

  • CLI_COMMAND_HANDLERS map mirrors all 27 commands + 1 alias exactly; per-dispatch factories (createRepairCommandDeps, buildSelectAccountTraced) remain lazy inside handler closures, preserving the original evaluation order.
  • Four formatter modules (text-style, quota-formatters, model-formatters, account-formatters) and a barrel index.ts promote previously-private helpers to exported symbols; codex-manager.ts re-exports only the two symbols that had prior external consumers.
  • test/codex-manager-formatters.test.ts adds 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

Filename Overview
lib/codex-manager.ts replaces ~200-line if/else dispatch chain with CLI_COMMAND_HANDLERS ReadonlyMap; all 28 keys (27 commands + status alias) match the old chain exactly, per-dispatch factories remain lazy inside handler closures
lib/codex-manager/formatters/quota-formatters.ts formatter helpers extracted from codex-manager.ts; fetchCodexQuotaSnapshot imported as a value but used only as a typeof type reference — should be type-only import
lib/codex-manager/formatters/account-formatters.ts styleAccountDetailText, riskTone, availabilityTone, formatRateLimitEntry, formatBackupSavedAt extracted here; doc-comment references test/codex-manager-detail-tone.test.ts which does not exist
lib/codex-manager/formatters/text-style.ts previously-private helpers extracted and exported; logic identical to the original codex-manager.ts implementations
lib/codex-manager/formatters/model-formatters.ts inspectRequestedModel and formatModelInspection extracted; ModelInspection interface promoted to exported, no logic changes
lib/codex-manager/formatters/index.ts barrel re-export of all four formatter modules; many previously-internal helpers are now part of the public surface
test/codex-manager-formatters.test.ts new vitest suite covering text-style, quota, and model formatter helpers; good edge-case coverage; styleAccountDetailText tone-precedence logic is not yet covered here

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)"]
Loading

Fix All in Codex

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
lib/codex-manager/formatters/quota-formatters.ts:3-7
`fetchCodexQuotaSnapshot` value import used only as a type

`fetchCodexQuotaSnapshot` is imported as a value but only ever appears in a `typeof` type annotation (`Awaited<ReturnType<typeof fetchCodexQuotaSnapshot>>`). this pulls the runtime value into the module graph unnecessarily; if the project ever enables `verbatimModuleSyntax` in tsconfig it will become a compile error. mark it `type` alongside `CodexQuotaSnapshot`.

```suggestion
import {
	type CodexQuotaSnapshot,
	type fetchCodexQuotaSnapshot,
	formatQuotaSnapshotLine,
} from "../../quota-probe.js";
```

### Issue 2 of 2
lib/codex-manager/formatters/account-formatters.ts:959-961
Comment references a test file that does not exist

The doc-comment says `// See test/codex-manager-detail-tone.test.ts` but that file is absent from both this PR and the repo. `test/codex-manager-formatters.test.ts` is the new suite, but it does not cover `styleAccountDetailText` at all. the reference will send future contributors on a dead-end search; either add the missing suite or update the pointer to the actual test file.

Reviews (2): Last reviewed commit: "test(codex-manager): unit-pin the extrac..." | Re-trigger Greptile

claude added 2 commits June 10, 2026 02:13
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
@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

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@ndycode, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f9a81112-39dd-4656-b005-698a48fd26f9

📥 Commits

Reviewing files that changed from the base of the PR and between 98d9819 and 4a09bcf.

📒 Files selected for processing (7)
  • lib/codex-manager.ts
  • lib/codex-manager/formatters/account-formatters.ts
  • lib/codex-manager/formatters/index.ts
  • lib/codex-manager/formatters/model-formatters.ts
  • lib/codex-manager/formatters/quota-formatters.ts
  • lib/codex-manager/formatters/text-style.ts
  • test/codex-manager-formatters.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/audit-18-manager-registry
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/audit-18-manager-registry

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.

Comment on lines +1 to +10
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();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 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!

Fix in Codex

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
@ndycode
ndycode merged commit af79ad4 into main Jun 10, 2026
1 of 2 checks passed
luo178 pushed a commit to luo178/codex-multi-auth that referenced this pull request Jun 23, 2026
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants