macOS compatibility: Keychain credential fallback + BSD-portable commands#1
Open
joelrodriguez-creator wants to merge 1 commit intoohugonnot:mainfrom
Open
Conversation
…ands Four issues prevented the statusline from working correctly on macOS: 1. **Credentials are in Keychain on newer Claude Code installs, not on disk.** `~/.claude/.credentials.json` is only created by older Claude Code versions. Current Darwin builds store the subscription OAuth token in macOS Keychain under service name `Claude Code-credentials` instead. With no fallback, `refresh_usage_api` returned 1 on every invocation and the cache was never populated — the session/weekly usage sections silently never rendered. Added a `read_oauth_token` helper that tries the legacy file path first, then falls back to `security find-generic-password` on Darwin. 2. **`flock` is not installed on macOS by default.** It's a GNU/Linux util from util-linux and isn't in the default Darwin toolchain. The `( flock -n 9 || exit 0; refresh_usage_api ) 9>"$LOCK_FILE"` line errored out on Mac and the refresh was skipped for a subtly different reason than ohugonnot#1. Added a `command -v flock` check; when absent, call `refresh_usage_api` directly. The `cache_age_sec` gate above already throttles refresh to one per `REFRESH_INTERVAL`, so the worst case for a single-user system is 1–2 duplicate API calls per interval. 3. **`sed 's/A\|B/C/'` alternation isn't portable.** BSD sed (macOS) treats `\|` as literal characters in basic regex; only GNU sed accepts it as alternation. The stale-indicator substitution silently became a no-op on Mac, so the ⚠ never replaced the color dot. Switched to `sed -E 's/(A|B|C)/.../ '` which works on both. 4. **Test-suite portability.** Two remaining macOS-compat quirks in test_statusline.sh: - `touch -d '30 minutes ago'` only works with GNU coreutils; BSD touch requires `-t [[CC]YY]MMDDhhmm[.SS]`. Added a `touch_minutes_ago` helper that tries GNU `date -d` first, falls back to BSD `date -v`. - `wc -l` right-pads output with whitespace on BSD but not on GNU; `count_char` returned `" 3"` instead of `"3"` on Mac, failing two make_bar assertions. Piped through `tr -d ' '`. Before: 53 passed / 3 failed on macOS. After: 56 passed / 0 failed on macOS. (Linux behavior unchanged — the fallbacks only activate when GNU tools are absent or the credentials file is missing.) Verified on macOS 25.3 (Darwin), bash 3.2 + jq 1.7.1. Not tested on Linux in this PR — but none of the changes alter the happy path where `$CREDENTIALS_FILE` exists, `flock` is installed, and GNU tools are available. Windows support (Credential Manager) is out of scope for this PR; would be a separate branch once someone with a Windows environment can test it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.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.
Summary
Four small changes that let
statusline.shandtest_statusline.shrun cleanly on macOS. All fallbacks are Darwin-only or use feature detection — Linux behavior is unchanged.The problems
On a clean macOS install of Claude Code, the tool installed fine but the session/weekly usage sections silently never rendered. Tracing it down turned up four distinct macOS-compat bugs, any one of which would have been enough to break the usage display:
Claude Code-credentialsinstead of~/.claude/.credentials.json.refresh_usage_apireturned 1 on every invocation because[ ! -f "$CREDENTIALS_FILE" ]was always true, and the cache was never written.flockisn't on macOS by default. It's a GNU util-linux tool.( flock -n 9 || exit 0; refresh_usage_api ) 9>"$LOCK_FILE"errors out on Darwin and skips the refresh entirely (so even if problem macOS compatibility: Keychain credential fallback + BSD-portable commands #1 were fixed, problem #2 would still block the usage display).sedalternation was non-portable.sed 's/🟢\|🟡\|🔴/⚠/'only works on GNU sed. BSD sed treats\|as literal backslash-pipe in basic regex, so the stale-indicator substitution silently became a no-op.touch -d '30 minutes ago'and unquotedwc -loutput. Three test failures on macOS before this PR.The fixes
read_oauth_tokenhelper tries$CREDENTIALS_FILEfirst, then falls back tosecurity find-generic-password -s "Claude Code-credentials" -a "$(whoami)" -won Darwin. Non-macOS systems without the file still fail fast as they did before.command -v flockcheck — use the lock when available, callrefresh_usage_apidirectly when not. Thecache_age_secgate above already throttles refresh to once perREFRESH_INTERVAL, so the worst case on a lockless system is 1–2 duplicate API calls per interval for a single user.sed -E 's/(🟢|🟡|🔴)/⚠/'— works on both GNU and BSD sed.touch_minutes_agohelper that tries GNUdate -dfirst, falls back to BSDdate -v.count_charpipes throughtr -d ' 'to strip BSDwc -l's whitespace padding.Test results
The Linux happy path is unaffected: if
$CREDENTIALS_FILEexists,flockis installed, and GNU tools are available, none of the new branches execute.Test plan
bash test_statusline.shpasses on macOS (56/56)⏳ 🟢 ▓▓░░░░ 29% ↻ 6h33m)Out of scope
cmdkey/Get-Credential). I didn't implement that branch — no Windows box to verify against. Would be a follow-up PR once someone with a Windows install can test it.🤖 Generated with Claude Code