feat(claude): support multiple config dirs#227
Conversation
|
Reviewed end-to-end: pulled the branch, type-check + full vitest suite (483 tests pass), then ran 8 adversarial probes against Probe results
Issues to address before merge1. Aggregation vs attribution mismatch with the linked issueThe issue asks for tracking multiple accounts. The PR delivers aggregation across multiple dirs. That may or may not be what @ccrvlh wants. I posted the question on #208 — pausing the merge until they clarify. If aggregation is fine, we ship as-is plus a note. If they need per-account splits, the data model needs a 2. Tilde
|
|
Addressed the hold items from the earlier review:
Local verification before push:
|
|
@ozymandiashh thanks for the careful work on this — fixture-based tests, clean factory refactor for I want to flag a design mismatch before we merge, though, because it affects most of the diff. The conversation on #208 settled on option 1: total aggregation across dirs — sessions from expect(projects).toHaveLength(2)
expect(projects.map(p => p.totalApiCalls).sort()).toEqual([1, 1])For option 1 it should be: expect(projects).toHaveLength(1)
expect(projects[0].totalApiCalls).toBe(2)The README change at line 356 also documents the option-2 semantic ("keeps the same sanitized project path separate per account instead of merging usage"). What needs changingThe
What to keep
After the changes the diff should shrink from ~629 lines to roughly 150-200, mostly concentrated in Why we care about the designIf we ship option 2 today and a user later wants the simpler "I just have multiple dirs, please merge them" behavior, we have to rip out a public-facing field ( Sorry for the back-and-forth — the disconnect is on us, the issue thread had ccrvlh confirm option 1 but it wasn't pinned at the top of #208. Happy to mark this as approved for merge once the data-model changes land. Take whatever time you need. |
…) (#288) Adds an OS-delimited list env var so a user with more than one Claude account or profile can scan all of them in a single run. Sessions across every configured dir merge into one ProjectSummary per project, matching the option-1 design agreed on the issue thread (no per-account splitting in the data model or the UI). Format: `CLAUDE_CONFIG_DIRS=~/.claude-work:~/.claude-personal` on POSIX, `;`-separated on Windows. Precedence is CLAUDE_CONFIG_DIRS > CLAUDE_CONFIG_DIR > ~/.claude. Empty entries in the list are skipped, duplicates are deduped on resolved path, and a missing or unreadable dir does not abort the scan of the others. If the user explicitly set CLAUDE_CONFIG_DIRS but every listed entry is unreadable, a one-line stderr hint identifies the attempted paths and the platform's expected delimiter, so a Windows user typing the POSIX `:` does not get a silent zero-row result. `~` is now also expanded in CLAUDE_CONFIG_DIR for consistency. Implementation is intentionally narrow: only `claude.ts` changes, plus a small parser-cache key update so a stale cache from one config does not bleed into a run with a different config (matters for the macOS menubar and GNOME extension which run as long-lived processes). The merge happens for free in `src/parser.ts:scanProjectDirs`, which keys ProjectSummary entries by canonical cwd (or the sanitized slug as a fallback). Two SessionSource entries with the same `project` field land under the same key and combine their sessions, regardless of which dir they came from. No new fields on SessionSource / SessionSummary / ProjectSummary, and no UI changes. Tests: 12 fixture-based cases covering the unset path (default ~/.claude), single-dir override via CLAUDE_CONFIG_DIR, multi-dir override via CLAUDE_CONFIG_DIRS, ~ expansion, dedup of repeated entries, leading/trailing/doubled delimiters, missing dir tolerated, file-not-directory entry tolerated, empty CLAUDE_CONFIG_DIRS falls back to single-dir env, and two parser-level integration tests asserting (a) two sessions from two dirs sharing one cwd produce one ProjectSummary with combined totals and no `account`/`accountPath` fields anywhere, and (b) two sessions sharing a slug but with different canonical cwds still merge by slug at the project-rollup layer (option 1 behavior pinned so a future refactor cannot quietly swap to cwd-aware merging without an explicit opt-in). Supersedes the alternative implementation in #227, which builds per-account attribution (option 2) instead.
|
Closing in favor of #288, which shipped on @ozymandiashh thanks for the substantial work here — the fixture-based test infrastructure, The blocker was scope: this PR went past the option-1 (total aggregation) decision that ccrvlh confirmed in #208 and built option-2 (per-account attribution) on top, which threaded If per-account attribution is something you (or other users) want to revisit later, please open a fresh issue and we can spec it as an opt-in flag on top of the current implementation. Sorry for the back-and-forth on this one. |
Summary
CLAUDE_CONFIG_DIRSsupport for tracking multiple Claude Code config directoriesCLAUDE_CONFIG_DIRand default~/.claudebehavior as fallbackCloses #208.
Validation
npx tsc --noEmitnpx vitest run tests/providers/claude.test.ts tests/security/prototype-pollution.test.ts tests/provider-registry.test.tsnpx vitest runnpm run build