On a fresh session Claude Code emits used_percentage=0 before any user
input, while current_usage already holds the real initial-context tokens
(system prompt, tools, memory files — ~9% on a 200k model). The HUD
was treating 0 as a valid native value and skipping the token-based
fallback, so the context bar stayed at 0% even though /context showed 9%.
Treat used_percentage=0 the same as null: fall through to the manual
calculation from current_usage. When tokens are present the bar now
reflects the true initial usage; when both are zero it still shows 0%.
Fixes#417
When the Agent/Task tool is called without an explicit subagent_type
parameter, Claude Code's runtime defaults to the general-purpose agent
(per the Agent tool spec). The HUD only sees the transcript input and
previously fell back to the literal string 'unknown', which made
perfectly normal Agent launches look broken or untracked in the HUD's
agents line.
Flip the fallback to 'general-purpose' so the displayed label matches
the tool's actual runtime behavior.
Before: `✓ unknown: Build phase 2 agents`
After: `✓ general-purpose: Build phase 2 agents`
getProviderLabel was string-matching `anthropic.claude-` in model IDs,
which false-positived on cross-region IDs like `us.anthropic.claude-sonnet-4-6`.
Now checks `CLAUDE_CODE_USE_BEDROCK=1` env var instead.
Fixes#466
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the hardcoded Anthropic pricing table and estimateSessionCost()
logic with a direct read of stdin.cost.total_cost_usd — the native field
Claude Code provides after each API response.
- Add cost.* fields to StdinData type
- Extract costUsd in index.ts and pass through RenderContext
- Simplify renderCostEstimate to read ctx.costUsd directly
- Rename i18n key label.estimatedCost → label.cost
- Update label to "Cost ($USD)" / "耗油量(美元)" (zh)
- Remove dead estimateSessionCost, pricing table, and related helpers
- Update tests to use costUsd; add index.test.js coverage for the field
- Update README to reflect native field behavior
Closes#380
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When TodoWrite is called, the taskIdToIndex map was cleared and
rebuilt from scratch. However, TodoItem objects only contain content
and status fields — no taskId. This meant all taskId mappings from
prior TaskCreate calls were permanently lost, causing subsequent
TaskUpdate operations to silently fail.
Fix: Before clearing the map, build a reverse lookup of content →
taskIds from the existing state. After replacing latestTodos with the
new TodoWrite items, re-register taskId mappings for items whose
content matches a previously-known task. Stale mappings (for content
no longer present) are naturally dropped.
Adds two tests:
- TaskCreate → TodoWrite → TaskUpdate flow preserves taskId
- TodoWrite-only regression test (no TaskCreate involved)
Users can now set a fully custom model name in their config:
{ "display": { "modelOverride": "zane's intelligent opus 4.6" } }
When set, the override completely replaces the auto-detected model
name (while preserving the provider qualifier like "| Bedrock").
Follows the same pattern as customLine: string type, max 80 chars,
empty string means disabled (falls through to modelFormat).
Claude Code may include the context window size in display_name
(e.g. "Opus 4.6 (1M context)"), but the HUD already shows context
usage via the context bar — making the parenthetical redundant.
This adds stripContextSuffix() which removes any parenthetical
containing the word "context" from the display name. It handles
common variants like "(1M context)", "(200k context)",
"(with 1M context)", and "(extended context window)" while
preserving non-context parentheticals like "(beta)" or "(preview)".
Before: [Opus 4.6 (1M context) | Bedrock]
After: [Opus 4.6 | Bedrock]
countConfigs() performs ~15 file I/O operations on every invocation.
Since the statusLine plugin spawns a new process ~every 300ms, this means
~50 filesystem ops/sec per session. With multiple concurrent sessions,
this scales to ~1500 ops/sec for config data that rarely changes.
Add a sentinel-based mtime cache (following the pattern established in
transcript.ts) that stats ~4-10 sentinel paths and serves cached results
when no config files have changed. Steady-state cost drops from ~15
syscalls to ~4-10 stat calls + 1 cache read.
Cache files are stored under ~/.claude/plugins/claude-hud/config-cache/
with SHA-256 hashed keys for cwd+configDir isolation. Cache misses
trigger a fresh recompute and cache write.
Known limitation: nested rules/ subdirectory changes are not monitored
(only the top-level rules/ directory mtime is checked).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(context): scale autocompact buffer by raw usage to avoid inflated percentages at low context
Previously the buffered context percentage applied a flat 22.5% buffer
regardless of actual usage. This caused the HUD to show ~28% context
used immediately after /clear or at session start, when real usage was
only ~5%. The fix scales the buffer linearly: zero buffer at ≤5% raw
usage, ramping to full buffer at ≥50%, matching when autocompact
actually kicks in.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: harden autocompact buffer startup coverage
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
* fix: consolidate CLAUDE_CONFIG_DIR handling and keychain fallback
* chore: remove dist artifacts from this PR
* chore: bump version to 0.0.8
* docs: expand 0.0.8 changelog from post-0.0.7 commits
* feat: show session name in statusline
Reads the session slug (auto-generated) and custom title (set via
/rename) from the transcript JSONL and displays it in dim text after
the project/git info on both expanded and compact layouts.
Custom title takes priority over auto-generated slug when both exist.
* test: add session name coverage and harden integration spawn
---------
Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
* fix: prevent double-counting CLAUDE.md when cwd is home directory
When the working directory is the user's home directory, the project
scope check for {cwd}/.claude/CLAUDE.md resolves to the same path as
the user scope check (~/.claude/CLAUDE.md), causing the HUD to display
"2 CLAUDE.md" instead of "1 CLAUDE.md". Skip the project scope
.claude/ checks when cwd equals the home directory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: handle home cwd config counting edge cases
* fix: avoid home cwd double-counting for rules and settings
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
* fix: add autocompact buffer to context percentage calculation
Adds AUTOCOMPACT_BUFFER (45k tokens) to match /context output.
This accounts for the reserved space Claude Code uses for autocompact.
Changes:
- Add src/constants.ts with AUTOCOMPACT_BUFFER export
- Update getContextPercent to include buffer in calculation
- Add edge case guard for invalid context window sizes
- Update tests to use realistic 200k context sizes
Closes#4🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add native context percentage support for Claude Code v2.1.6+
Use `used_percentage` field from stdin when available, providing accurate
context percentage that matches `/context` output. Falls back automatically
to manual calculation for older Claude Code versions.
- Add `used_percentage` and `remaining_percentage` to StdinData type
- Add `getNativePercent()` helper with edge case handling (NaN, <0, >100)
- Update both `getContextPercent()` and `getBufferedPercent()` to prefer native
- Add 8 comprehensive tests for native percentage behavior
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: melon-hub <melon-hub@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: use percentage-based autocompact buffer with config toggle
- Change hardcoded 45k buffer to 22.5% of context window
- Scales correctly for enterprise windows (>200k)
- Add `display.autocompactBuffer` config option ('enabled' | 'disabled')
- Default 'enabled' preserves current behavior (buffered %)
- 'disabled' shows raw % for users with autocompact off
Fixes#48, #16
Related: #4, #30, #43, #49
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test: add autocompactBuffer tests for renderSessionLine
Address review feedback:
- Add tests verifying autocompactBuffer: 'enabled' uses buffered %
- Add tests verifying autocompactBuffer: 'disabled' uses raw %
- Add autocompactBuffer check to loadConfig test
- Update baseContext() to include autocompactBuffer
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add clickable GitHub URLs to CHANGELOG credits
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add debug log for autocompactBuffer mode
When DEBUG=claude-hud is set and autocompactBuffer='disabled',
logs both raw and buffered percentages to help troubleshoot mismatches.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: exclude disabled MCP servers from count
Fixes#3 - MCP count was showing all servers regardless of
enabled/disabled state.
## Root Cause
The HUD was counting all MCP server keys from config files without
checking if they were in the disabled lists:
- `disabledMcpServers` in `~/.claude.json` (user-scope)
- `disabledMcpjsonServers` in `settings.local.json` (project .mcp.json)
## Changes
- Add `getDisabledMcpServers()` function to read disabled arrays
- Add `DisabledMcpKey` union type for compile-time safety
- Filter disabled servers when counting MCPs
- Add debug logging (enable via `DEBUG=claude-hud`)
- Add 8 new tests including Issue #3 regression test
## Test Coverage
- User-scope disabled filtering
- Project .mcp.json disabled filtering
- All MCPs disabled → 0
- Non-string values in disabled arrays (ignored)
- Cross-scope duplicate counting behavior
- Case-sensitive server name matching
- Issue #3 exact scenario (6 MCPs, disable progressively)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: extract debug logging into shared helper module
Per PR feedback, consolidate duplicate debug logging code from
config-reader.ts and usage-api.ts into a shared debug.ts helper.
- Add src/debug.ts with createDebug() factory function
- Update config-reader.ts to use createDebug('config')
- Update usage-api.ts to use createDebug('usage')
- Same functionality, better DRY compliance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: melon-hub <melon-hub@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Adds AUTOCOMPACT_BUFFER (45k tokens) to match /context output.
This accounts for the reserved space Claude Code uses for autocompact.
Changes:
- Add src/constants.ts with AUTOCOMPACT_BUFFER export
- Update getContextPercent to include buffer in calculation
- Add edge case guard for invalid context window sizes
- Update tests to use realistic 200k context sizes
Closes#4🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: melon-hub <melon-hub@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>