* feat: support 256-color and hex color values in config
Extends the colors config to accept 256-color indices (0-255) and hex
strings (#rrggbb) in addition to the existing named color presets.
This allows full theme customization without patching source files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: allow number type in color config validation test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a static `display.customLine` config field that renders a user-defined
phrase (max 80 chars) in Claude orange on the project line, joined with
the standard │ separator.
- config.ts: add customLine to HudConfig.display with validation
- colors.ts: add claudeOrange() using 256-color (38;5;208)
- project.ts: append customLine to expanded mode project line
- session-line.ts: append customLine to compact mode parts
- setup.md: add "Custom line" option to Step 4
- configure.md: add Q5 Custom Line to both Flow A and Flow B
* fix: render showSpeed and showDuration in expanded layout
These config options were only implemented in the compact layout
(renderSessionLine in session-line.ts). When using lineLayout: "expanded",
enabling display.showSpeed or display.showDuration had no effect.
This adds both options to renderProjectLine (the expanded layout's
project line), matching the compact layout behavior:
- showSpeed: output token speed (tok/s)
- showDuration: session duration timer
Fixes#221
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add renderProjectLine tests for showSpeed and showDuration
Address Copilot review feedback by adding test coverage for the
new expanded layout rendering of speed and duration:
- duration shown when showDuration is true
- duration omitted when showDuration is false
- speed code path doesn't crash when showSpeed is true
- speed omitted when showSpeed is false
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: cover expanded layout speed rendering
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
* fix: detect macOS and show restart hint when HUD initializes without stdin (closes#213)
* fix: prompt user to restart Claude Code after config write for HUD setup
* fix: update assertion to check if output starts with initializing message
* Align restart messaging in docs
---------
Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
* fix: clarify usage time format — show 'resets in' instead of ambiguous elapsed/total
Fixes#240
The format `(2h 43m / 5h)` was confusing because it mimics the common
`(elapsed / total)` pattern, but actually showed time remaining until
reset. Changed to `(resets in 2h 43m)` which is unambiguous.
Before: `Usage █░░░░░░░░░ 7% (2h 43m / 5h)`
After: `Usage █░░░░░░░░░ 7% (resets in 2h 43m)`
* test: cover usage reset wording
---------
Co-authored-by: d 🔹 <258577966+voidborne-d@users.noreply.github.com>
Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
Users running Claude Code with a custom config directory (e.g.
CLAUDE_CONFIG_DIR=~/.claude-work) had the plugin installed to that
directory, but /claude-hud:setup always looked in the hardcoded
~/.claude path, causing it to report the plugin as not installed.
Replace all hardcoded ~/.claude/ references with
${CLAUDE_CONFIG_DIR:-$HOME/.claude} so that setup correctly resolves
the plugin cache, settings.json, and config.json under whatever config
directory Claude Code is using.
Also fix glob-inside-quotes bug in the temp_local_* cleanup commands
(quotes prevented wildcard expansion).
Co-authored-by: dennis <dennis@brevitydata.net>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: detect terminal width via stderr when stdout is piped
When Claude Code runs the statusLine as a subprocess, stdout is captured
(piped), so process.stdout.columns is undefined. With no terminal width,
long lines aren't wrapped by the HUD — the terminal wraps them silently
instead. Claude Code counts \n characters to determine how many lines to
erase on the next render, so the physical line count diverges from what
Claude Code expects. Over successive renders the cursor drifts upward into
the scrollback buffer, causing the terminal to jump to the top on every
tool execution (https://github.com/jarrodwatts/claude-hud/issues/209).
Fix: fall back to process.stderr.columns before the COLUMNS env var.
When the statusLine subprocess is spawned, only stdout is redirected;
stderr remains connected to the real TTY and returns the correct width.
With accurate width, lines are properly wrapped in the HUD output and
Claude Code's line count stays consistent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: drop dist artifacts and cover stderr width
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
* fix: scale progress bars based on terminal width
Resolves#231
Progress bars (coloredBar/quotaBar) were hardcoded to width 10,
causing line wrapping in narrow terminals.
Now bars scale dynamically based on process.stdout.columns:
- Wide terminal (>=100 cols): width 10 (default)
- Medium terminal (60-99 cols): width 6
- Narrow terminal (<60 cols): width 4
Affected files:
- src/render/session-line.ts (context bar + usage bars)
- src/render/lines/identity.ts (context bar in expanded layout)
- src/render/lines/usage.ts (quota bars in expanded layout)
* fix: also check COLUMNS env var as fallback for bar width
For cross-platform compatibility (zsh, macOS, Windows),
getBarWidth() now also checks process.env.COLUMNS when
process.stdout.columns is unavailable (non-TTY, piped output).
* refactor: extract getAdaptiveBarWidth to shared utility
- Remove duplicated getBarWidth() from 3 render files
- Add src/utils/terminal.ts with exported getAdaptiveBarWidth()
- Add Math.floor() for consistency with getTerminalWidth()
- All 3 render files now import from shared utility (DRY)
* test: add unit tests for getAdaptiveBarWidth
Tests cover:
- Narrow terminal (<60 cols) → 4
- Medium terminal (60-99 cols) → 6
- Wide terminal (>=100 cols) → 10
- Boundary values (59, 60, 99, 100)
- Non-TTY/piped output (undefined columns) → 10 (default)
- Fallback to COLUMNS env var
- No terminal info at all → 10 (default)
* style: simplify JSDoc to match project comment style
---------
Co-authored-by: Anna Terek <wabalabudabdab@users.noreply.github.com>
The --extra-cmd feature only rendered extraLabel in compact mode via
renderSessionLine. In the default expanded layout, extraLabel was
collected but never passed to any render function.
Append extraLabel to the project line in expanded mode, consistent
with its placement on the session line in compact mode.
Fixes#242