Skip to content

Scope usage per CLAUDE_CONFIG_DIR, includin authentication - #266

Merged
sirmalloc merged 2 commits into
sirmalloc:mainfrom
davidmgvaz:main
Oct 29, 2026
Merged

sirmalloc merged 2 commits into
sirmalloc:mainfrom
davidmgvaz:main

Conversation

@davidmgvaz

Copy link
Copy Markdown
Contributor

This pull request updates the usage tracking logic to support multiple configuration profiles by scoping the usage cache and lock files to the current config directory. It also improves the logic for retrieving API credentials, especially on macOS, by first checking for a config-directory-specific keychain entry. The test suite has been updated to reflect these changes and add coverage for the new fallback behavior.

The usage cache (usage.json) and lock file (usage.lock) were shared
across all Claude Code profiles, causing session-usage, weekly-usage,
reset-timer and weekly-reset-timer widgets to display data from the
wrong account when CLAUDE_CONFIG_DIR pointed to a non-default profile.

Replace the hardcoded file paths with per-profile paths using a
SHA-256 hash of the resolved CLAUDE_CONFIG_DIR, matching the existing
pattern used by getBlockCachePath() in jsonl-cache.ts.

Claude Code stores per-profile credentials in the macOS keychain using the service
name Claude Code-credentials-{sha256(configDir)[:8]}. For ~/.claude-boost, that's
Claude Code-credentials-ac4e02fa. The old code never looked up this specific entry —
it only tried the generic Claude Code-credentials service, then sorted all candidates by mtime.

…g token authentication

  The usage cache (usage.json) and lock file (usage.lock) were shared
  across all Claude Code profiles, causing session-usage, weekly-usage,
  reset-timer, and weekly-reset-timer widgets to display data from the
  wrong account when CLAUDE_CONFIG_DIR pointed to a non-default profile.

  Replace the hardcoded file paths with per-profile paths using a
  SHA-256 hash of the resolved CLAUDE_CONFIG_DIR, matching the existing
  pattern used by getBlockCachePath() in jsonl-cache.ts.

  Claude Code stores per-profile credentials in the macOS keychain using the service
  name Claude Code-credentials-{sha256(configDir)[:8]}. For ~/.claude-boost, that's
  Claude Code-credentials-ac4e02fa. The old code never looked up this specific entry —
  it only tried the generic Claude Code-credentials service, then sorted all candidates by mtime.
@eric-engberg

Copy link
Copy Markdown
Contributor

For reference, main has since picked up part of this. #573 now reads the Claude Code-credentials-<hash> keychain entry first when CLAUDE_CONFIG_DIR is set, and #460 and #536 tag the cached usage with a token fingerprint so another account's cache isn't shown. The per-profile cache and lock files still look new, though: main keeps a single usage.json and usage.lock, and #573's description even calls this PR the natural follow-up for that part. The branch has conflicts with main now, so trimming it down to just that split might make it easier to land.

@sirmalloc

Copy link
Copy Markdown
Owner

I merged current main and narrowed this PR to per-profile usage cache and lock files. Main now handles credential selection, including profile isolation, username retries, and Keychain timeouts, so I preserved that implementation.

Usage caches, request locks, and no-credentials backoff locks now use profile-specific filenames. Token fingerprints and existing backoff behavior are preserved. The old shared files are ignored and left untouched; each profile populates its own cache.

Added tests covering two profiles sharing one home, independent caches and backoffs, lock cleanup, and legacy-file handling.

@sirmalloc
sirmalloc merged commit 7978598 into sirmalloc:main Oct 29, 2026
3 checks passed
pcvelz added a commit to pcvelz/ccstatusline-usage that referenced this pull request Oct 29, 2026
Upstream: Extra Usage Limit widget (sirmalloc#756), live widget preview while picking (sirmalloc#755), Fast Mode widget (sirmalloc#754), transcript block fallback fixes (sirmalloc#752), editor keys on a global install (sirmalloc#751), git cache TTL (sirmalloc#750), npx cached copy skip (sirmalloc#749), Block Usage hide at 100% (sirmalloc#747), Block Reset Timer hide until 100% (sirmalloc#697), fish-style branch abbreviation (sirmalloc#614), jj detached HEAD (sirmalloc#705), hooks save warning (sirmalloc#703), dev reload (sirmalloc#700), merge ends at a hidden widget (sirmalloc#698), Block Forecast and Block Limit Timer widgets (sirmalloc#699), contributor guide (sirmalloc#706), POSIX path case fix (sirmalloc#707), whitespace-distinct conflict filenames (sirmalloc#709), Quick Start reorder (sirmalloc#715), bunx launch guidance (sirmalloc#714), jj diff summary counts (sirmalloc#711), powerline manual separators (sirmalloc#713), keychain credential by account (sirmalloc#532), Keychain probe timeout (sirmalloc#760), usage cache scoped per CLAUDE_CONFIG_DIR (sirmalloc#266), test isolation (sirmalloc#717, sirmalloc#753), dev-dependency bumps (sirmalloc#745)

Conflicts resolved per the standard-resolution table; fork deletions re-applied.

Hand edits outside conflicts:
- src/utils/global-command-resolution.ts: fork-rename (ccstatusline@ -> ccstatusline-usage@ in upstream's new bunx pattern)
- src/utils/__tests__/global-package-manager.test.ts: fork-rename (package dir ccstatusline-usage in upstream's new tests)
- src/utils/usage-fetch.ts: compat fix - cacheUsageData gained a fetchedAtMs arg (upstream sirmalloc#266); adapted the fork-only fetchFreshUsageData call site
- src/utils/__tests__/usage-fetch.test.ts: compat fixes - cache/lock now hashed per CLAUDE_CONFIG_DIR (usageFilePath helper) in four fork tests; upstream fableUsage renamed to fork's weeklyFableUsage; seedUsageCache takes TokenHome
- src/utils/__tests__/usage-prefetch.test.ts: compat fix - mockFetchUsageData renamed to upstream's mockFetchUsage in cleanly-merged tests
- README.md: took upstream's Quick Start move (sirmalloc#715) and dropped the fork's old copy; fork-rename of its ccstatusline@ specifiers; links to fork-deleted docs (docs/USAGE.md, docs/WINDOWS.md) replaced with the fork's inline text
- CONTRIBUTING.md: links to the fork-deleted docs/DEVELOPMENT.md pointed at the README Development section
- docs/test-retirements.md: ledger entries for the 12 upstream test renames (sirmalloc#697, sirmalloc#698, sirmalloc#700, sirmalloc#705, sirmalloc#713, sirmalloc#760)
eric-engberg added a commit to eric-engberg/ccstatusline that referenced this pull request Oct 30, 2026
The usage lock held every fetch off, whichever login made it. A 429 for one
access token kept the usage widgets on cached numbers or "Rate limited" until
its Retry-After ran out, often an hour, even after Claude Code refreshed the
login: the new token got a 200 as soon as the lock file was deleted by hand.

A lock written for the API refusing a request, with a 429 or a lasting
answer such as a 401, now names the fingerprint of the access token the
request was sent with, and a fetch with another token skips it. That covers
both read paths: the known login's, which a token refresh leaves by changing
the login's stamp, and the one that reads the credentials. The fingerprint is
the access token's, since a refresh may keep the refresh token the cache's
fingerprint comes from. A lock without one (the in-flight record, a failure
of the server, the network or the response, a file from an older version)
still holds every login off.

Profiles used side by side share the lock file, so a request that replaces
another token's active lock with its in-flight record puts that lock back
once it succeeds, instead of ending the other login's backoff early.

Upstream sirmalloc#266 now gives each profile its own lock file, so the part about
profiles sharing one is moot; a token refresh within one profile still
needs the per-token lock.
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.

3 participants