refactor(accounts): split account-service.ts into 12 focused modules (N2)#30
Merged
Conversation
…(N2) Reduce the 1,675-LOC god-file at src/lib/accounts/account-service.ts to a 164-LOC orchestrator that delegates every public method to a focused free-function module. No public API change: every signature on `AccountService` is preserved and the `accountService` singleton in `src/lib/accounts/index.ts` continues to work for `BaseCommand` and the existing direct importers (`commands/check.ts`, `commands/forecast.ts`, `commands/auto-switch.ts`, two test files). Target modules (per `docs/future/01-ARCHITECTURE.md` §2.1): - sync/external-sync.ts (216 LOC) — syncExternalAuthSnapshot... - read/listing.ts (211 LOC) — list/find + getCurrentAccountName - write/save.ts (159 LOC) — saveAccount + safety guard - write/use.ts (128 LOC) — useAccount + activateSnapshot - write/remove.ts (105 LOC) — remove one / by query / all - config/auto-switch-config.ts ( 82 LOC) — status + threshold setters - auto-switch/policy.ts (141 LOC) — runAutoSwitchOnce + daemon - usage/adapter.ts (192 LOC) — usage refresh + proxy shim - safety/snapshot-vault.ts (125 LOC) — backup + clobber recovery - session/pin.ts (243 LOC) — sessions.json + Linux PPID - identity/equality.ts ( 86 LOC) — snapshot identity comparisons - naming.ts ( 40 LOC) — normalizeAccountName + path Shared internal helpers under `_internal/`: - _internal/fs-helpers.ts — pathExists / filesMatch / auth-state read - _internal/auth-state.ts — symlink materialize, current-name file I/O - _internal/registry-ops.ts — persistRegistry + metadata hydration - _internal/name-resolution.ts — login/inferred name resolution Behavior is byte-identical: every existing test in the pre-N2 suite still passes. Wave-1 contracts honored — atomic writes via N1's `persistRegistryAtomic`/`secureWriteFile`, errors thrown via N3's `AuthmuxError` subclasses, paths resolved per-call via N4's `resolve*` getters. New tests (31 cases across 3 files): - src/tests/identity-equality.test.ts - src/tests/naming.test.ts - src/tests/accounts-modules.test.ts (covers listing, session/pin, snapshot-vault, auto-switch-config, auto-switch-policy, usage-adapter, write/use, write/remove, external-sync) Verification: - npm run build: clean - npm test: 129 passing, 0 failing (was 98 pre-extraction) - wc -l src/lib/accounts/account-service.ts → 164 (< 400 ceiling, ~150 goal) - singleton: all 21 public methods still resolve as functions - node dist/index.js --help: CLI boots and lists every command Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The accountFilePath test hardcoded "/tmp/authmux-test-accounts" and asserted equality against a forward-slash POSIX path. On Windows the resolved path comes back as "D:\tmp\authmux-test-accounts\..." which fails the strict-equal check across all 3 Node versions in CI. Build the expected path through os.tmpdir() + path.join() so both sides go through the same platform-aware joining and the test passes on Ubuntu, macOS, and Windows. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
NagyVikt
added a commit
that referenced
this pull request
May 18, 2026
Bumps package.json + package-lock.json from 0.1.24 to 0.1.25 and extends releases/v0.1.25.md to cover every theme that landed since v0.1.24: - N1 durability (#29): atomic writes, registry lock, fsync-before-rename - N2 account-service split (#30): 1675 LOC -> 164 LOC orchestrator + 12 modules - N3 error taxonomy + --json (#28): AuthmuxError base, stable codes, JSON envelope - N4 lazy path resolvers (#27): bare constants deprecated for v0.2.0 - P0 wave (#26): secure perms, [y/N] update prompt, kiro ENOENT, CI matrix, registry proxy-source round-trip, 18k-line improvement docs Notes follow the canonical 7-section shape from docs/future/17-ROADMAP.md (Added, Changed, Fixed, Deprecated, Removed, Security, Migration), with the prior Durability section folded into a "Theme deep-dives" appendix so the canonical shape is intact. No code changes. No npm publish. Verification: - npm run build: clean - npm test: 129/129 pass - node -e "require('./package.json').version" -> 0.1.25 - node -e "require('./package-lock.json').version" -> 0.1.25 Co-authored-by: NagyVikt <nagy.viktordp@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements Theme N2 from the 0–4 weeks Now horizon. Splits the 1,675-LOC
src/lib/accounts/account-service.tsgod-file into 12 focused modules perdocs/future/01-ARCHITECTURE.md§2.1. Branches off the wave-1 head (N1 #29, N3 #28, N4 #27 already merged).Exit criteria (verbatim from 17-ROADMAP.md)
account-service.tsis below 400 LOC. 1,675 → 164 LOC (close to the ~150 orchestrator goal).AccountServicechanges; the singleton insrc/lib/accounts/index.tsstill works. All 21 public methods preserved; verified bynode -e "..."probe and byBaseCommand.accountscontinuing to compile.Extracted modules (post-split LOC)
sync/external-sync.tsread/listing.tsgetCurrentAccountName+ findwrite/save.tssaveAccount+ safety guard + name inferencewrite/use.tsuseAccount+activateSnapshot+resolveUsableAccountNamewrite/remove.tsconfig/auto-switch-config.tsauto-switch/policy.tsrunAutoSwitchOnce+runDaemon+ candidate scoringusage/adapter.tsrefreshAccountUsage+refreshListUsageIfNeeded+ proxy shimsafety/snapshot-vault.tssession/pin.tsidentity/equality.tsnaming.tsnormalizeAccountName+accountFilePath+ percent guardShared helpers under
_internal/(not part of the public surface):_internal/fs-helpers.ts(64) —pathExists/filesMatch/ auth-state read_internal/auth-state.ts(70) — symlink materialize + current-name file I/O_internal/registry-ops.ts(50) —persistRegistry+ metadata hydration_internal/name-resolution.ts(196) — login/default/inferred name resolutionOrchestrator
account-service.ts: 164 LOC. Every public method delegates to a free function in one of the cluster modules.Behavior guarantees
persistRegistryAtomic/secureWriteFile.AuthmuxErrorsubclasses with the same codes/severity/hints.resolveCodexDir()/resolveAccountsDir()/ etc; no module-import-time path resolution introduced.commands/check.ts,commands/forecast.ts,commands/auto-switch.ts, and the two test files that importAccountServicedirectly compile without edits.Verification
Notes for reviewers
read/listing.tsandwrite/use.tstake agetCurrentAccountNamethunk to break a potential cycle throughsync/external-sync.ts. The orchestrator wires them with() => this.getCurrentAccountName().usage/directory deliberately sits next to the existingusage.ts(660 LOC). That file is the next refactor target (X2 in the roadmap); this PR does not touch it.git mvwas not used because every new module also has different content; preserving blame would require keeping the old file in place. The original was deleted and the orchestrator rewritten — historical blame is reachable viagit log --followon the deleted lines.🤖 Generated with Claude Code