Skip to content

fix(statusline): account badge from label alone; context next to model - #18

Merged
mgiovani merged 3 commits into
mainfrom
fix/statusline-account-badge-and-context-order
Jul 22, 2026
Merged

fix(statusline): account badge from label alone; context next to model#18
mgiovani merged 3 commits into
mainfrom
fix/statusline-account-badge-and-context-order

Conversation

@mgiovani

@mgiovani mgiovani commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

Two statusline fixes, bundled:

  1. Account badge now renders without CLAUDE_CODE_OAUTH_TOKEN. The CLAUDE_STATUSLINE_ACCOUNT_LABEL badge was gated on the OAuth-token env var also being set (get_account_component required both). Accounts switched via a separate credential store — e.g. alias claude2='CLAUDE_STATUSLINE_ACCOUNT_LABEL=alt CLAUDE_SECURESTORAGE_CONFIG_DIR=~/.claude-alt claude' — never set that token, so no badge showed. The label is user-set display text and now renders whenever it's set, independent of how the account was selected. Per-account cache isolation and background OAuth refresh remain keyed on CLAUDE_CODE_OAUTH_TOKEN (unchanged).

  2. Context moved next to the model on line 1. The context-window percentage (📊) now renders immediately after the model instead of after git/worktree, so token usage sits next to what's consuming it:

    🤖 Opus │ 📊 22% │ 📁 cc-arsenal │ 🌿 main ● │ 💰 $0.043 │ ⏱️ 21m
    

    New default order: model → context → directory → git → worktree → cost → session.

Changes

  • lib/display/components.sh — badge guard now depends only on the label (root cause).
  • lib/display/builder.sh — context component moved right after model.
  • STATUSLINE.md, README.md, docs/features.md, CHANGELOG.md — docs updated to match.

Tests

  • Added a label-only badge test (test_multi_account.sh, test_display_components.sh) covering the CLAUDE_SECURESTORAGE_CONFIG_DIR switch case.
  • Updated the previously-stale "no badge with label but no token" assertion to the new behavior.
  • Added a line-1 order guard (🤖📊📁) to the integration test.
  • All 8 statusline suites pass, shellcheck clean, repo make check / make test / pre-commit green.

Security

Also resolves the two Dependabot alerts on the default branch (bundled per request): pytest <9.0.3 (moderate, tmpdir handling) → 9.1.1, and Pygments <2.20.0 (low, ReDoS) → 2.20.0, both dev/transitive deps in uv.lock. Full suite passes on the pytest 8→9 major bump.

…next to model

The account badge (CLAUDE_STATUSLINE_ACCOUNT_LABEL) was gated on
CLAUDE_CODE_OAUTH_TOKEN also being set, so accounts switched via a separate
credential store (CLAUDE_SECURESTORAGE_CONFIG_DIR) showed no badge. The label is
user-set display text and now renders whenever it is set, independent of how the
account was selected. Per-account cache isolation and background OAuth refresh
remain keyed on CLAUDE_CODE_OAUTH_TOKEN.

Also move the context-window component (context %) to immediately after the model
on line 1 — model -> context -> directory -> git -> worktree -> cost -> session —
so token usage stays glanceable next to what is consuming it.

Docs (STATUSLINE.md, README.md, docs/features.md, CHANGELOG) and tests updated:
added a label-only badge test in both suites and a line-1 order guard in the
integration test. All 8 statusline suites pass, shellcheck clean.
@claude

claude Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review: fix(statusline): account badge from label alone; context next to model

Small, well-scoped PR — two independent fixes bundled with matching doc/test updates. Went through the diff, the surrounding builder.sh/components.sh logic, and the test assertion helpers. Looks solid; a couple of minor nits below, nothing blocking.

Code quality / correctness

  • get_account_component (lib/display/components.sh): the fix is a one-line root-cause change — dropping the CLAUDE_CODE_OAUTH_TOKEN half of the gate. Matches the stated intent (label is just display text) and the comment explains why, not just what. 👍
  • build_line_one (lib/display/builder.sh): the context component block was moved verbatim right after the model block, before USED_PERCENTAGE is consumed. USED_PERCENTAGE is populated earlier in extract_statusline_data, which always runs before build_line_one in build_statusline — so no ordering hazard from the move.
  • No other callers of get_account_component or the old gating condition were found elsewhere in the tree, so this isn't a partial fix.

Test coverage

  • test_account_component (test_display_components.sh) and test_failsoft_render (test_multi_account.sh) both got a new case for "label set, no token" — and correctly switched from assert_equals "" to assert_contains, since the case now expects real output instead of nothing. Verified assert_contains's arg order (expected, actual, message) matches how it's called.
  • The integration test's component-order check changed from an unordered AND ("🤖"* && *"📁"* && *"📊"*) to a single ordered glob (*"🤖"*"📊"*"📁"*) — good, this actually catches order regressions instead of just presence.
  • The "no badge with token but no label" case is still covered, so the gate's other half wasn't accidentally loosened.

Docs

  • CHANGELOG, README, STATUSLINE.md, docs/features.md all updated consistently with the new example output and component order table. One very minor nit: STATUSLINE.md:155 still says multi-account support is "driven entirely by CLAUDE_CODE_OAUTH_TOKEN" — true for cache/lock isolation (which the PR correctly leaves keyed on the token), but a reader skimming just that line before reaching the badge section a few paragraphs later could momentarily read it as contradicting the new badge behavior. Not worth blocking on, just a possible clarity tweak.

Security

  • No concerns — the label is user-supplied display text rendered as-is (already the case pre-PR), no token/secret is ever put into the rendered string, and the test suite explicitly asserts the token never leaks into badge output (assert_not_contains "secret-tok" ...).

Performance

  • No measurable impact — this only reorders an existing array append and removes a boolean check; no new subprocesses or I/O introduced.

Overall: clean root-cause fix, matching test updates, docs kept in sync. LGTM.

Resolves two Dependabot alerts on the default branch:
- pytest <9.0.3 — vulnerable tmpdir handling (moderate)
- Pygments <2.20.0 — ReDoS via inefficient GUID-matching regex (low)

Both are dev/transitive deps in uv.lock. Full suite (27 tests, 90 subtests),
ruff, and pyright pass on the pytest 8->9 major bump.
@claude

claude Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review

Reviewed the diff between fee81aa and 5ec7b68 plus the surrounding statusline modules. This is a small, well-scoped, well-tested PR bundling two independent changes.

  1. Account badge fix (components.sh / get_account_component)
  • The core fix is correct: the badge is user-set display text, so gating it on CLAUDE_CODE_OAUTH_TOKEN was an unrelated coupling. Removing that gate is the right call.
  • Checked whether this could cause a stale/mismatched badge (e.g. showing work next to another account's usage data). It cannot: builder.sh only calls into the OAuth-fetch/cache path when CLAUDE_CODE_OAUTH_TOKEN is set; when unset (the securestorage case this PR targets), line-2 usage comes straight from the rate_limits block in the stdin JSON, so no cache-keying risk is introduced. Good that STATUSLINE.md documents this explicitly.
  • Test coverage is solid: the unit tests cover the full gating matrix (neither/token-only/label-only/both), and test_multi_account.sh adds an end-to-end case through the real statusline.sh entry point for the label-only/no-token path - the more valuable test since it exercises the full render path.
  • Minor nit: the updated unit-test comment duplicates the intent already stated inline in get_account_component - not an issue, just minor duplication across two files.
  1. Line-1 component reorder (context next to model)
  • Purely cosmetic reordering in build_line_one - no logic changes, just array-append order. Low risk.
  • Docs (STATUSLINE.md, README.md, docs/features.md, CHANGELOG.md) were all updated consistently, and I verified builder.sh actually produces the order the docs claim (model, context, directory, git, worktree, cost, session) - it matches.
  • The integration test in run_tests.sh was upgraded from an emoji-presence check to an actual ordering assertion - a good strengthening that would catch a regression the old test could not.
  1. Dependency bump (uv.lock: pytest 8.4.1 to 9.1.1, Pygments 2.19.2 to 2.20.0)
  • Reasonable to bundle given the small size, and it resolves real Dependabot alerts. Bumps like this are sometimes easier to review/revert in isolation from behavior changes, but at this size it's a non-issue.
  • Worth confirming CI actually ran green on the pytest 8 to 9 major bump (some deprecated APIs/plugins were dropped in pytest 9) rather than relying solely on the commit message's claim that the local suite passed.

Security
No security concerns. The account label was already rendered as plain text before this change (never a secret), and this PR changes only when it renders, not what is rendered. No new external input paths are introduced.

Nits / non-blocking

  • docs/features.md example line was updated to match the new order - good catch, easy to miss.
  • Follows the repo's stated conventions (shellcheck-clean scripts, STATUSLINE.md kept in sync with code); nothing to flag against CLAUDE.md/AGENTS.md guidance.

Verdict: LGTM. No blocking issues found; both behavioral changes are small, correctly scoped, and backed by tests that exercise the new behavior end-to-end rather than just the paths that already worked.

…adge

Addresses review nit — the 'driven entirely by CLAUDE_CODE_OAUTH_TOKEN' line
could read as contradicting the new token-independent badge behavior.
@mgiovani

Copy link
Copy Markdown
Owner Author

Thanks for the review. Addressed the actionable nit and confirmed the rest:

  • STATUSLINE.md:155 clarity — reworded the multi-account intro so it no longer reads as "driven entirely by `CLAUDE_CODE_OAUTH_TOKEN`"; it now separates per-account usage isolation (token-keyed) from the badge (renders from the label alone). Pushed in 0341d49.
  • pytest 8→9 CI confirmation — the test check ran green on this branch with pytest 9.1.1 (not just the local suite), so the major bump is verified in CI.
  • Comment duplication between components.sh and the unit test — left as-is intentionally: the inline code comment explains the runtime why, the test comment explains what the assertion pins; both are cheap and read independently.

@claude

claude Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review

Reviewed the diff directly (test execution wasn't available in this sandbox, so this is based on static reading of the changed files + the full get_account_component/build_line_one context).

Code quality

  • get_account_component (lib/display/components.sh) — the fix is minimal and correctly scoped: it drops the CLAUDE_CODE_OAUTH_TOKEN half of the gate and keeps the label-only check, matching the stated root cause (label is user-set display text, unrelated to how the account was selected). Confirmed via grep that no other code path conflates the two — cache/lock/backoff keying in oauth.sh and oauth_fetcher.sh still keys exclusively off CLAUDE_CODE_OAUTH_TOKEN, so per-account isolation is genuinely untouched.
  • build_line_one reorder (lib/display/builder.sh) — straightforward move of the context block to right after the model; no interaction with the separator-joining logic below it.
  • Docs (STATUSLINE.md, README.md, docs/features.md, CHANGELOG.md) are consistent with the new behavior and new example ordering — no stale examples left showing the old 📁 → 📊 order.

Bugs / correctness

  • None found. The test_multi_account.sh new case (label set, no token, via CLAUDE_SECURESTORAGE_CONFIG_DIR scenario) exercises the actual statusline.sh entrypoint end-to-end rather than just the unit function, which is a good belt-and-suspenders check.
  • The updated integration assertion in run_tests.sh[[ "$output" == *"🤖"*"📊"*"📁"* ]] — is a correct use of bash glob pattern matching to assert both presence and order, strictly stronger than the old &&-chained presence-only check it replaces.

Test coverage

  • Good: the previously-stale assertion ("no badge with label but no token") was correctly flipped to the new expected behavior rather than just deleted, and a fresh negative case (token-only, no label) is still covered alongside it.
  • Minor nit: test_display_components.sh's new/edited assertions set STATUSLINE_DISPLAY_MODE=emoji inline per-subshell, consistent with the existing style in that file — no issue, just noting the pattern is followed correctly.

Security

  • The bundled dependency bumps (pytest 8.4.1→9.1.1, Pygments 2.19.2→2.20.0) are dev/transitive only; pyproject.toml already constrains pytest>=7.4.0 so the major-version bump doesn't require a manifest change. Worth double-checking CI is green on the pytest 8→9 major bump specifically (deprecations/removed APIs in project's own test suite), since the PR body says it passed but that's the one change with real behavioral-break potential in this bundle.
  • No secrets, injection, or credential-handling concerns in the badge/order changes themselves — get_account_component only ever echoes the label text, never the token (and the test suite explicitly asserts the token never leaks into output).

Overall

Small, well-scoped, root-cause fix with matching doc updates and correctly-flipped test assertions. No blocking issues found. Only note is to confirm the pytest 9 bump is fully green in CI rather than just locally, since it's the one item in this bundle with a nonzero chance of subtle breakage unrelated to the statusline changes themselves.

@mgiovani
mgiovani merged commit fc05c65 into main Jul 22, 2026
4 checks passed
@mgiovani
mgiovani deleted the fix/statusline-account-badge-and-context-order branch July 22, 2026 19:43
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.

1 participant