Repository navigation
fix(usage): read keychain credential by account, not service name alone - #532
Merged
sirmalloc merged 2 commits intoOct 29, 2026
Merged
Conversation
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
On macOS the usage credential lookup ran `security find-generic-password -s "Claude Code-credentials" -w`, naming no account. Claude Code reads and writes its login with `-a <account>` as well: $USER, the login name when that's unset or empty, and claude-code-user for a name with characters outside [a-zA-Z0-9._-]. A login keychain can hold more than one item for the service. Running Claude Code as root once leaves one under the account "root" that nothing refreshes again, and a lookup by service alone answers with whichever item macOS finds first. On one Mac that was root's. Its access token expired about 8 hours after it was saved, and from then on every usage request sent that expired token while Claude Code kept refreshing the user's own item. The usage widgets stopped updating for about two days, until the stale item was deleted by hand. Each service is now looked up under that account first. Only when no item is saved under it (exit status 44) does the lookup fall back to the service alone, so a setup whose item sits under another account keeps working. Any other failure of the first call still ends the keychain lookup and backs off as before, and each profile's service name is unchanged. Upstream sirmalloc#532 retries the service under the OS user name only after a service-only lookup finds no OAuth token, so a stale but well-formed item another account left still wins there. Looking up the account first, as here, covers its case too (an item holding only MCP tokens), so its retry is replaced.
This was referenced Oct 31, 2026
Closed
Closed
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.
On macOS, multiple Keychain items can share the service
Claude Code-credentialswhile differing by account. A service-only lookup can select an MCP-only item even when the OS-username item contains valid Claude Code OAuth credentials, leaving usage widgets showing[No credentials].Fixes #521's missing-token case.
Change
For the default service lookup,
getUsageCredentials()now tries:Claude Code-credentialsby service name, as before.os.userInfo().usernamewhen the first lookup yields no OAuth token.The account-scoped read returns both access and refresh tokens, preserving the current cache identity behavior. If the username cannot be resolved, that retry is skipped. Existing five-second subprocess timeouts and the profile-specific no-credentials backoff remain in place.
Main has been merged into this branch. Custom profiles retain main's isolation: they read their own suffixed service, then only their own
.credentials.json, without falling through to the default account. Suffixed services can contain profile credentials as well as MCP credentials; they are not exclusively MCP tokens.Scope and related work
A successful service-only lookup still wins. This does not resolve the variant where the first item contains a stale but well-formed OAuth token, or guess arbitrary account names. The new username retry applies to the default service lookup.
Validation
bun test: 3,507 passed, 0 failed across 191 files on macOS with Bun 1.4.4. The run required local socket access for the proxy integration tests.bun run lint,bun run build, andgit diff --check: passed.The original contributor reported a successful live reproduction on an affected machine. Validation of the main merge used mocks and the automated suite; it did not access a real Keychain or live usage API.