Commit Graph

299 Commits

Author SHA1 Message Date
Jarrod Watts
0c2c68c04a milestone-3: respect explicit TLS override in proxy tunnel 2026-03-23 12:32:17 +11:00
Jarrod Watts
1c694a6f8f fix: respect NODE_TLS_REJECT_UNAUTHORIZED in proxy tunnel 2026-03-23 12:31:39 +11:00
Jarrod Watts
98d67565ca milestone-2: align docs with context mode and config dir support 2026-03-23 12:26:40 +11:00
Jarrod Watts
1273d7d3a3 milestone-2: stop bun setup command from loading project env 2026-03-23 12:20:03 +11:00
Jarrod Watts
6f6ba4c4d4 milestone-2: preserve cached plan names after OAuth refresh 2026-03-23 12:17:34 +11:00
Jarrod Watts
ff6f4524ee fix: preserve cached plan names after OAuth refresh 2026-03-23 12:14:38 +11:00
Jarrod Watts
51013bc15b milestone-3: align context percentage docs with stdin 2026-03-23 12:14:22 +11:00
Jarrod Watts
720e331edf docs: align context percentage reference with stdin 2026-03-23 12:14:05 +11:00
Jarrod Watts
9b3e08a9c9 milestone-2: add opt-in combined context display 2026-03-23 12:12:24 +11:00
Jarrod Watts
8a2c435db0 milestone-2: harden setup docs and shell guidance 2026-03-23 12:12:24 +11:00
Jarrod Watts
770fc5ecc5 docs: harden setup guidance for Windows shells 2026-03-23 12:11:22 +11:00
Jarrod Watts
bafe095025 feat: add opt-in combined context display mode 2026-03-23 12:10:53 +11:00
github-actions[bot]
26e38decd7 build: compile dist/ [auto] 2026-03-20 00:53:22 +00:00
Andrew Moore
40c4451d9c feat: support 256-color and hex color values in config (#236)
* 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>
2026-03-20 11:52:59 +11:00
github-actions[bot]
61a3769993 build: compile dist/ [auto] 2026-03-20 00:52:54 +00:00
Xy
cb407d0534 feat: add customLine display support (#223)
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
2026-03-20 11:52:29 +11:00
github-actions[bot]
15771700ea build: compile dist/ [auto] 2026-03-20 00:46:27 +00:00
hoklims
8e51163c96 fix: render showSpeed and showDuration in expanded layout (#232)
* 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>
2026-03-20 11:45:39 +11:00
Abhishek Tiwari
faacda01ee fix: hud not appearing after setup without restart (#213) (#250)
* 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>
2026-03-20 11:45:33 +11:00
github-actions[bot]
68f8909322 build: compile dist/ [auto] 2026-03-20 00:44:16 +00:00
d 🔹
2330284631 fix: clarify usage time format — show 'resets in' instead of ambiguous elapsed/total (#244)
* 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>
2026-03-20 11:43:34 +11:00
Kuo-Hao Huang
618ae8deb2 fix(setup): respect CLAUDE_CONFIG_DIR when detecting and configuring plugin (#247)
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>
2026-03-20 11:43:27 +11:00
github-actions[bot]
db7ea25186 build: compile dist/ [auto] 2026-03-20 00:42:28 +00:00
Pan Hu
e952a399f1 fix: stop terminal scrolling to top on tool execution (#248)
* 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>
2026-03-20 11:41:51 +11:00
Anna Terek
e5d384af35 fix: scale progress bars based on terminal width (#237)
* 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>
2026-03-20 11:41:40 +11:00
Salman Chishti
f5cd87db07 Upgrade GitHub Actions for Node 24 compatibility (#234)
Signed-off-by: Salman Muin Kayser Chishti <13schishti@gmail.com>
2026-03-20 11:41:27 +11:00
Chris Anthony
30f46e7fbd Fix extraLabel not displayed in expanded layout (#243)
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
2026-03-20 11:41:01 +11:00
Pratyush Sharma
f698b8ff9a fix: resolve unknown skill error for plugin commands (#222) (#224) 2026-03-20 11:40:41 +11:00
dependabot[bot]
e10c67db09 chore(deps-dev): bump @types/node from 25.3.5 to 25.5.0 (#211)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.3.5 to 25.5.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-15 14:29:53 +11:00
github-actions[bot]
235e0bd20c build: compile dist/ [auto] 2026-03-14 00:39:52 +00:00
Jarrod Watts
256b811156 chore: bump version to 0.0.10 (#208)
* chore: bump version to 0.0.10

* chore: sync lockfile version metadata

* docs: clarify 1M context window compatibility
2026-03-14 11:39:26 +11:00
github-actions[bot]
51e6e18ca4 build: compile dist/ [auto] 2026-03-14 00:26:03 +00:00
Jarrod Watts
a089537a11 fix: surface stale usage syncing during rate limits (#207) 2026-03-14 11:25:42 +11:00
github-actions[bot]
768346fb34 build: compile dist/ [auto] 2026-03-14 00:20:44 +00:00
Jarrod Watts
14763584eb feat: add configurable HUD color overrides (#206)
* feat: add configurable HUD color overrides

* docs: preserve manual color overrides in configure flow
2026-03-14 11:20:23 +11:00
github-actions[bot]
e71f578033 build: compile dist/ [auto] 2026-03-14 00:19:57 +00:00
Jarrod Watts
d4abb17a20 fix: prefer account-scoped keychain credentials (#205)
* fix: prefer account-scoped keychain credentials

* test: block generic fallback after empty account-scoped keychain lookup

* test: block generic fallback after account lookup errors

* fix: block cross-service keychain credential fallback
2026-03-14 11:19:35 +11:00
github-actions[bot]
b7306dae0d build: compile dist/ [auto] 2026-03-14 00:15:20 +00:00
Hwang In-wook
603e48f699 feat: show reset time for 7-day usage in text-only mode (#194)
* feat: show reset time for 7-day usage in text-only mode

- When usageBarEnabled is false, 7d usage now displays reset time,
- consistent with the existing 5h usage text-only behavior.

* test: cover text-mode 7-day reset countdown

---------

Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
2026-03-14 11:14:56 +11:00
github-actions[bot]
202707459f build: compile dist/ [auto] 2026-03-14 00:12:00 +00:00
Paul
e8d64924bc fix: resilient usage display under API rate limiting (#193)
* fix: resilient usage display under API rate limiting

The Anthropic usage API rate-limits to ~1 call per 5 minutes. With the
previous 60s cache TTL, 4 out of 5 API calls returned 429, causing the
HUD to permanently display "(429)" instead of actual usage data.

Three-layer fix:
- Increase cache TTL from 60s to 5 minutes to match rate limit window
- Preserve lastGoodData in cache across rate-limited periods so the HUD
  always shows the best available data instead of errors
- Exponential backoff (60s→120s→240s→5min cap) with Retry-After header
  support for consecutive 429 responses

Also show "syncing..." instead of raw HTTP status on first-run rate limit.

* Update usage-api.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: harden 429 cache fallback behavior

* test: stabilize usage cache suite after rebase

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
2026-03-14 11:11:36 +11:00
github-actions[bot]
98cde23e48 build: compile dist/ [auto] 2026-03-14 00:06:32 +00:00
Brandon Wie
086603e7ca fix: treat zero-byte lock file as stale to prevent permanent busy state (#203)
* fix: treat zero-byte lock file as stale to prevent permanent busy state

If the HUD process crashes between fs.openSync(lockPath, 'wx') and
fs.writeFileSync(fd, timestamp), a 0-byte .usage-cache.lock remains.
readLockTimestamp() returns null for unparseable content, and the
existing guard (lockTimestamp != null && expired) never fires, leaving
the cache permanently stuck in 'busy' state.

Add a lockTimestamp === null guard that uses fs.statSync().mtimeMs to
distinguish a crash leftover (old mtime → remove and retry) from an
active writer that is between openSync and writeFileSync (recent mtime
→ return busy). The original != null stale-timestamp path is unchanged.

Closes #202

* test: stabilize stale-lock regression coverage

* test: make usage-api suite self-build for source-only PRs

---------

Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
2026-03-14 11:06:09 +11:00
ruohan.chen
b99ae79764 fix: use version-based sorting instead of mtime for plugin selection (#199)
* fix: use version-based sorting instead of mtime for plugin selection

The statusline command used `ls -td` (sort by modification time) to
select the latest plugin version from the cache directory. When multiple
versions coexist after an upgrade, the older version can have a newer
mtime, causing the statusline to run the wrong version.

This led to a real issue where v0.0.7 (no proxy support) was selected
over v0.0.9, causing persistent 403 errors on the usage API for users
behind a required proxy.

Replace `ls -td | head -1` with `ls -d | sort -V | tail -1` to sort
by version number. Apply the equivalent fix for Windows PowerShell
using `[version]` casting.

Fixes #198

* docs: make setup version lookup portable

* docs: avoid login shell in setup command

---------

Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
2026-03-14 11:00:37 +11:00
github-actions[bot]
99ef599879 build: compile dist/ [auto] 2026-03-13 23:58:12 +00:00
Xingxing
069f194fb2 fix(context): scale autocompact buffer by raw usage (#190)
* 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>
2026-03-14 10:57:49 +11:00
github-actions[bot]
c02787bf0e build: compile dist/ [auto] 2026-03-09 04:13:43 +00:00
yelo
ce5960dcd8 Add configurable usage cache TTL settings (#175)
* feat(config): add configurable usage cache TTL settings

Add cacheTtlSeconds and failureCacheTtlSeconds to the usage section of
config.json, allowing users to control how often the Anthropic usage API
is fetched (default 60s) and how quickly failures are retried (default 15s).

* docs: document usage cache TTL config options

* refactor(usage): bundle cache TTL params into single CacheTtls object

Replace cacheTtlMs/failureCacheTtlMs pair with a CacheTtls type wherever
they appear together, reducing parameter count in readCacheState, readCache,
waitForFreshCache, and UsageApiDeps.

* chore(build): drop dist changes from pr

---------

Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
2026-03-09 15:13:22 +11:00
github-actions[bot]
b873caab2d build: compile dist/ [auto] 2026-03-09 03:58:10 +00:00
yelo
8c247a0ab2 Skip usage api for custom provider (#176)
* fix(usage): skip API call when using custom provider

Check ANTHROPIC_BASE_URL / ANTHROPIC_API_BASE_URL env vars and skip
OAuth usage API call when user is configured to use a custom provider
(e.g., via cc-switch). This prevents unnecessary API failures when
the user is not using Anthropic's default endpoint.

* test(usage): add tests for custom API endpoint detection

Cover isUsingCustomApiEndpoint behavior via getUsage integration:
- ANTHROPIC_BASE_URL with custom endpoint returns null without fetch
- ANTHROPIC_API_BASE_URL with custom endpoint returns null without fetch
- Empty ANTHROPIC_BASE_URL proceeds normally (falsy check)
- Default endpoint with/without trailing slash proceeds normally

* docs: note that custom API endpoints skip usage display

* fix(usage): tighten custom endpoint detection

---------

Co-authored-by: Jarrod Watts <jarrod@cubelabs.xyz>
2026-03-09 14:57:51 +11:00