提交

提交图

320 次代码提交

作者 SHA1 备注 提交日期
Matthew Breedlove 30de97505f Version bump and docs update
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
Publish / Publish to npm (push) Has been cancelled
CI / Build (push) Has been cancelled
v2.2.22
2026-06-16 02:00:58 -04:00
Shawn Sorichetti cb2555d180 fix: honour flex-separator in powerline render path (#411)
* fix: honour flex-separator in powerline render path

renderPowerlineStatusLine filters out flex-separator widgets at the
start of the function and never restores their layout effect, so a
configured flex-separator silently has no effect when powerline mode
is enabled. The non-powerline render path correctly distributes
terminal-width minus content-width across each flex-separator
position; this commit teaches the powerline path to do the same.

How:

- Before filtering, compute a Set of filteredWidgets indices that are
  immediately followed by a flex-separator in the original widget
  array.
- During the render loop, when one of those indices is reached, emit
  a closing powerline cap (a triangle in the previous widget's bg
  colour with no bg of its own) followed by a sentinel string, and
  skip the regular between-widgets separator.
- After the render loop, if any flex positions were marked, split the
  result string on the sentinel, measure the visible width of each
  part, distribute the remaining terminal width evenly across the
  flex positions as spaces, and reassemble. When the terminal width
  is unknown the sentinels are stripped so they cannot leak.

Tests:

Four new tests in renderer-flex-width.test.ts cover
- single flex-separator in powerline mode
- multiple flex-separators in powerline mode
- sentinel cleanup when terminal width is unknown
- non-powerline path regression check

All 585 tests pass (581 existing + 4 new). Lint and tsc are clean.

* fix(powerline): honor flex separator segments

Preserve flex separators when enabling powerline mode and keep them available in the widget catalog while manual separators remain disabled.

Track powerline flex positions against rendered widgets so hidden or empty widgets do not move right-aligned segments. Reserve end caps before distributing flex space to avoid truncating visible content.

Advance start cap selection across flex-created segments and subsequent lines so each visible powerline segment uses the next configured cap.

Add regression coverage for hidden widgets before flex separators, end caps with flex spacing, powerline catalog/settings behavior, and multi-line start cap sequencing.

* fix(renderer): preserve powerline separator cycling across flex segments

Treat flex separators as boundaries between independent powerline segments instead of consuming configured separator glyphs as caps.

Each flex-delimited segment now receives the matching start and end cap, while intra-segment separators advance using the actual number of rendered separator slots. Separator glyph selection now cycles through the configured list instead of clamping to the last configured glyph, so multi-line layouts continue the expected sequence after flex splits.

Update separator index accounting to skip flex boundaries and count slots independently within each segment. Add regression coverage for segment caps, flex separator accounting, separator cycling across lines, and explicit separator widgets.

Tests: bun test

Tests: bun run lint

* fix(powerline): align separator and cap sequencing

* fix(renderer): respect separator merge boundaries

Treat explicit separators and flex separators as hard merge boundaries when calculating separator slots, powerline theme slots, and rendered powerline elements.

This prevents no-padding merges from crossing separators, keeps theme color advancement isolated on each side of a boundary, and keeps auto-alignment width groups from spanning flex separators.

When terminal width is unknown, render powerline flex separators as a single visible space instead of dropping the boundary entirely so adjacent segments remain separated.

Add regression coverage for separator indexing, powerline theme slot counting, powerline flex separator spacing, padding behavior, theme color advancement, and auto-align width grouping.

---------

Co-authored-by: Shawn Sorichetti <ssoriche@users.noreply.github.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-16 01:22:48 -04:00
Zach Landquist 50195e15ae test: make the suite pass on Windows hosts (#454)
Sixteen specs failed on a Windows host while passing on POSIX CI. The production code is already platform-aware; only the specs assumed a POSIX host. These changes are test-only.

terminal: pin process.platform for the probe specs via a defineProperty setter restored in afterEach (vi.spyOn on the getter did not re-apply reliably across specs); also consumes a leaked mockImplementationOnce. claude-settings: pin platform and stub getConfigPath to a literal POSIX path so the --config quoting specs avoid path.resolve drive-prefixing. usage-token: build the credentials path via path.join. config-dir: assert path.resolve of the input.

Closes #453

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-15 17:40:52 -04:00
Zach Landquist 7be789fa56 feat(compaction): make the reclaimed-tokens arrow an overridable glyph (#452)
The reclaimed-tokens suffix hardcoded its leading down-arrow. Route it through the existing symbol-override slot system (metadata slot symbolReclaimed) so it can be customized or cleared from the glyph editor, the same way the git widgets expose their symbols.

The default is unchanged, so existing configs render identically. An empty override drops the glyph but keeps the separating space.

Closes #448

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-15 17:22:30 -04:00
Zach Landquist e51b0027c6 fix(context-bar): render counts >= 1M as "1.0M" instead of "1000k" (#451)
ContextBar formatted used/total with Math.round(n / 1000) + 'k', so a 1M context window showed '1000k'. Add an optional decimals arg to formatTokens (default 1, behavior-preserving for all existing callers) and route the bar through it with decimals=0, so it keeps compact whole-number k and gains the existing M rollup.

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-15 17:08:31 -04:00
Matthew Breedlove b20296c008 fix(config): preserve symlinked settings on save
Resolve symlinked settings paths before performing the atomic temp-file rename. This keeps dotfile-managed settings.json files and custom --config links intact while still updating the linked target.

Write the temporary file beside the resolved target so the final rename remains atomic and avoids cross-device replacement issues. Fall back to the configured settings path when the file does not exist yet.

Add a regression test that saves through a symlinked settings file, verifies the link survives, verifies the target JSON updates, and checks temp cleanup in both directories.
2026-06-15 16:16:25 -04:00
CC f3ecfe8254 fix(config): non-destructive recovery + loud warning for invalid settings.json (#447)
* fix(config): stop overwriting invalid settings.json on load

On a parse or validation failure, loadSettings now returns defaults in
memory and leaves the user's file untouched instead of backing it up and
overwriting it with defaults. The render path runs loadSettings on every
prompt, so the old behavior silently reset a malformed config. Removes the
now-redundant .bak backup (the preserved original is the backup).

Closes #393

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(config): write settings atomically via temp file + rename

Route every config write through a write-to-temp-then-rename, so a reader
(the render path runs on every prompt) never observes a partially written
settings.json. Mirrors the existing atomic-write idiom in git.ts. The temp
is cleaned up if the write fails.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(config): show a loud warning when settings.json can't be loaded

When loadSettings falls back to defaults (invalid or unreadable settings.json),
the statusline now prepends a red "invalid config" badge so the failure is
visible instead of silent — previously the only signal was a stderr message the
piped statusline never surfaces. The detailed reason still goes to stderr.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(config): validate a migration before persisting it

Previously a versioned config was migrated and written back to disk *before*
the final schema validation, so a faulty migration could overwrite the user's
original file with invalid output. Now the migrated result is validated first
and persisted only if it passes; on failure the original file is left untouched
and defaults are used in memory. This makes the non-destructive guarantee total
and lets the schema-fail path honestly report "file left unchanged".

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(config): don't overwrite an unreadable settings.json when saving install metadata

saveInstallationMetadata loads settings then writes them back to record the
installation method. If the existing file was unreadable, loadSettings returns
defaults in memory, so the write would discard the user's (recoverable) file —
the last path still violating the non-destructive contract. It now skips the
write when the existing config could not be read, leaving the file untouched
(metadata is non-critical and is persisted on the next clean save).

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-15 15:35:00 -04:00
Zach Landquist 4f01094f21 feat: add per-widget dim styling, whole widget or parens-only (#433)
* feat: add per-widget dim styling, whole widget or parens-only

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(tui): scope dim styling in previews

Preserve parens dim styling when foreground gradients render in both regular and powerline paths.

Emit a combined intensity reset when restoring bold after dim so Ink preserves the dim reset in preview output.

Reset whole-widget dim before powerline separators and end caps, and render ColorMenu style indicators as one suffix to avoid badge wrapping.

Add regression coverage for gradient dim composition, powerline dim boundaries, Ink preview output, and ColorMenu indicator layout.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-15 15:05:40 -04:00
dependabot[bot] 2159379a3a chore(deps-dev): bump the dev-dependencies group with 4 updates (#446)
Bumps the dev-dependencies group with 4 updates: [@remotion/cli](https://github.com/remotion-dev/remotion), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react), [remotion](https://github.com/remotion-dev/remotion) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `@remotion/cli` from 4.0.472 to 4.0.475
- [Release notes](https://github.com/remotion-dev/remotion/releases)
- [Commits](https://github.com/remotion-dev/remotion/compare/v4.0.472...v4.0.475)

Updates `@types/react` from 19.2.16 to 19.2.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `remotion` from 4.0.472 to 4.0.475
- [Release notes](https://github.com/remotion-dev/remotion/releases)
- [Commits](https://github.com/remotion-dev/remotion/compare/v4.0.472...v4.0.475)

Updates `typescript-eslint` from 8.60.0 to 8.60.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@remotion/cli"
  dependency-version: 4.0.475
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: "@types/react"
  dependency-version: 19.2.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: remotion
  dependency-version: 4.0.475
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.60.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-15 04:46:23 -04:00
Matthew Breedlove 6d4f10a273 docs(thinking-effort): clarify ultracode xhigh reporting 2026-06-15 04:20:27 -04:00
Matthew Breedlove 29895206d7 Version bump and docs update
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
Publish / Publish to npm (push) Has been cancelled
CI / Build (push) Has been cancelled
v2.2.21
2026-06-15 02:45:16 -04:00
CC bfe86ab904 fix(renderer): render 999950-999999 tokens as '1.0M' not '1000.0k' (#444)
Values in [999950, 999999] hit the thousands branch where (count/1000).toFixed(1) rounds up to '1000.0', producing '1000.0k'. Lower the millions threshold to that exact rounding boundary so they render as '1.0M'. Adds a direct unit test for formatTokens (previously exercised only indirectly via widget spies).

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-15 02:35:26 -04:00
CC 3c1f472598 feat(compaction): opt-in trigger split and tokens reclaimed (#445)
* refactor(compaction): compute stats struct (count, byTrigger, tokensReclaimed) from markers

Parse compactMetadata.{trigger,preTokens,postTokens} during the existing
compact_boundary scan. No widget behavior change yet.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(compaction): freeze zero stats, floor reclaimed at 0, clarify naming

Address review feedback on the data layer: freeze the shared
ZERO_COMPACTION_STATS (incl. nested byTrigger); floor each marker's reclaimed
contribution with Math.max(0, ...) so postTokens>preTokens can't go negative;
rename metaObj -> metaRecord; add unknown-trigger and negative-reclaim tests.

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(compaction): opt-in trigger split via (s) keybind

Adds a per-item showTriggers toggle that appends '(2 auto, 1 manual)';
unknown bucket shown only when > 0; omitted at count 0. Rendering now flows
through formatStats, shared by live render and preview.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(compaction): clarify zero-suffix test name; cover manual-only bucket

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(compaction): opt-in tokens reclaimed via (t) keybind

Adds a per-item showReclaimed toggle that appends the reclaimed token total
(e.g. 887.0k) via the shared formatTokens humanizer; omitted when 0. Stacks
independently with the trigger split.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: extract formatTokens to a leaf module to avoid a circular import

CompactionCounter importing formatTokens from renderer.ts created a cycle
(renderer -> widget registry -> CompactionCounter) that broke isolated runs of
its test file with a TDZ error. Move formatTokens into src/utils/format-tokens.ts;
renderer re-exports it so existing importers are unaffected.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(compaction): cover tokens reclaimed with a non-default format

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(compaction): document trigger-split and tokens-reclaimed toggles

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(compaction): apply code-review feedback

- use shared isMetadataFlagEnabled/toggleMetadataFlag for the trigger/reclaimed
  flags instead of local copies
- freeze SAMPLE_STATS to match ZERO_COMPACTION_STATS
- guard tokensReclaimed against non-finite (overflow) marker differences
- docs: note the unknown trigger bucket and that reclaimed is floored/omitted at 0

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(compaction): carry the formatTokens rounding fix into the extracted leaf

The reclaimed display calls formatTokens; the extracted format-tokens.ts held the
pre-fix version, so a reclaimed total in [999950, 999999] rendered '1000.0k'
instead of '1.0M'. Apply the same threshold fix as PR #444 here, so the reclaimed
figure is correct and merging both PRs in either order cannot regress it.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-15 02:11:32 -04:00
dmsp 2fc4921b77 feat(widget): add Cache Hit / Read / Write widgets (#423)
* feat(widgets): add Cache Hit / Read / Write widgets

Adds a new "Cache" widget category that surfaces prompt-cache efficiency,
which previously was hidden: TokensCached summed cache_read and
cache_creation into one opaque number.

New widgets, each toggling between per-turn ("last action") and session
scope via the 't' keybind:
- Cache Hit   - read / (read + creation), %
- Cache Read  - cache_read tokens with context share, e.g. "88.0k (84.5%)"
- Cache Write - cache_creation tokens with context share, e.g. "12.0k (11.5%)"

No new data source: turn scope reads context_window.current_usage from the
live status JSON; session scope sums the transcript. TokenMetrics gains
optional cacheReadTokens / cacheCreationTokens (split of cachedTokens, which
is unchanged for backward compatibility).

Defaults: Cache Hit/Read green, Cache Write yellow (recolorable in the TUI).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(cache): add hide option for empty values

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-14 04:12:44 -04:00
Sebastian Szewczyk 6126ff75f2 feat(widget): add cache-hit-rate widget (#409)
Adds a Cache Hit Rate widget that mirrors the Anthropic Console's
prompt-cache hit-rate formula: cache_read / (cache_read + cache_creation
+ fresh_input). Returns null on empty transcripts so it does not flash
0% before any tokens are recorded.

Splits cacheReadTokens and cacheCreationTokens out of the existing
cachedTokens roll-up on TokenMetrics (both new fields are optional and
cachedTokens is preserved unchanged), so downstream widgets and configs
are unaffected.

Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-14 03:53:12 -04:00
CC dd820ea42f feat(custom-command): include terminal_width in stdin JSON (#396)
* feat(custom-command): include terminal_width in stdin JSON

Custom Command widgets receive context.data as JSON over stdin, but the
terminal width was not part of it, so scripts had no way to adapt their
output to the terminal (tput/stty/$COLUMNS all return 80 in the piped
context).

Populate context.terminalWidth once in the render pipeline via
getTerminalWidth() (which also lets the renderer reuse it instead of
re-probing per line) and add terminal_width to the JSON piped to custom
commands when a numeric width is known. The field name uses snake_case
to match the existing Claude Code payload (session_id, current_dir, ...).

Resolves the request in upstream issue #308.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(custom-command): document terminal_width in stdin JSON

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-14 03:44:17 -04:00
Martijn Riemers 7db0914856 feat: add Extra Usage Used widget showing spent overage budget (#417)
* fix: format extra usage in the currency reported by the usage API

The usage API reports the account's billing currency
(extra_usage.currency, e.g. "EUR"), but ExtraUsageRemaining always
formatted with a hardcoded dollar sign, showing non-USD budgets with
the wrong symbol.

Parse the currency field through the API response schema, file cache,
and prefetch merge, and format the remaining budget with
Intl-based currency formatting (falling back to USD when the field is
absent or invalid, preserving current output for USD accounts).

Fixes #415

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: add Extra Usage Used widget showing spent overage budget

The usage API's extra_usage.used_credits is already fetched and cached
(extraUsageUsed), but no widget could display it. Accounts with extra
usage enabled and no monthly limit configured get neither of the
existing widgets (both require limit-derived fields), so the spent
amount is the only displayable extra usage number for them.

Adds an extra-usage-used widget modeled on extra-usage-remaining,
including the hide-if-disabled toggle and raw value support.

Closes #414

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: format Extra Usage Used with the API-reported currency

Builds on the formatUsageCurrency helper from the currency fix so the
new widget shows the account's billing currency too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-14 03:39:02 -04:00
Martijn Riemers 2d85849476 fix: format extra usage in the currency reported by the usage API (#418)
The usage API reports the account's billing currency
(extra_usage.currency, e.g. "EUR"), but ExtraUsageRemaining always
formatted with a hardcoded dollar sign, showing non-USD budgets with
the wrong symbol.

Parse the currency field through the API response schema, file cache,
and prefetch merge, and format the remaining budget with
Intl-based currency formatting (falling back to USD when the field is
absent or invalid, preserving current output for USD accounts).

Fixes #415

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-14 03:33:25 -04:00
CC df25207d18 fix(compaction): count compact_boundary markers instead of inferring from context-% drops (#425)
* feat(compaction): add marker-based compaction counting

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(compaction): count markers instead of inferring from context-% drops

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(compaction): remove obsolete context-%-drop heuristic and cache

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(compaction): pin explicit isSidechain:false; docs: marker-count wording

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-14 03:12:56 -04:00
Zach 8ae6481f25 feat: allow overriding widget symbols with a custom glyph (#431)
* feat: allow overriding widget symbols with a custom glyph

Extends the item.character override (already honored by Git
Staged/Unstaged/Untracked) to every widget with a hardcoded symbol and
makes it editable in the TUI.

- Add src/widgets/shared/symbol-override.tsx: shared (g)lyph keybind,
  symbol/prefix helpers, and a slot-based editor (type a character or
  emoji, Backspace renders without a symbol, choosing the default clears
  the override); single-symbol widgets store on item.character,
  multi-symbol widgets keep per-part metadata keys
- Wire it into Git Branch (⎇), Git Worktree (𖠰), Git Worktree Mode (⎇),
  Git Conflicts (⚠), JJ Bookmarks (🔖), JJ Workspace (◆), the three
  presence widgets that already supported item.character, and the
  multi-symbol widgets Git Ahead/Behind (↑/↓) and Git Status (!+*?)
- Add preview-path render coverage for default/override/suppressed plus
  helper unit tests; document the keybind in docs/USAGE.md

Co-authored-by: Claude <noreply@anthropic.com>

* fix: align glyph editor labels

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-14 02:56:45 -04:00
BWM0223 887f786875 fix: add missing metadata fields to package.json (#443) 2026-06-14 01:52:09 -04:00
Pugsin 3df04e168e fix: point package module to published build (#442)
* fix: point package module to published build

Signed-off-by: Pugsin <sergio.icdlf@gmail.com>

* fix: expose published package entrypoints

---------

Signed-off-by: Pugsin <sergio.icdlf@gmail.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-14 01:49:02 -04:00
Matthew Breedlove 28d98e320c Version bump and README update
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
Publish / Publish to npm (push) Has been cancelled
CI / Build (push) Has been cancelled
v2.2.20
2026-06-13 23:53:36 -04:00
Zach 04b4026f1d fix: prefer cumulative transcript metrics for input/output token widgets (#435)
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-13 23:43:27 -04:00
Martijn Riemers bc34c3a97e fix: permanent [Timeout] in extra usage widgets when no monthly limit is set (#416)
* fix: treat enabled extra usage without a monthly limit as complete usage data

Accounts with extra usage enabled but no monthly limit configured
(monthly_limit: null) never receive extraUsageLimit/extraUsageUtilization
from the usage API. hasRequiredUsageField treated those absent fields as
incomplete data on every fetch - including successful ones - so cached
data was never accepted, the fetch loop re-fetched each cycle, and the
extra usage widgets surfaced the cached lock error as a permanent
[Timeout].

Extend the existing extraUsageEnabled === false special case to any
response where the extra usage state is known: once the API has told us
whether extra usage is enabled, absent detail fields are conclusive and
refetching cannot produce them.

Fixes #413

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test: drop currency from no-limit fixture to stay order-independent of #418

Once #418 teaches the parser about extra_usage.currency, a fixture
carrying the field would add extraUsageCurrency to the parsed result
and break this test's expectation depending on merge order. The field
is irrelevant to what this test covers (monthly_limit: null handling).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-13 20:24:14 -04:00
KorenKrita 96cb608294 fix: ignore transient 0% flashes in compaction counter (#370)
* fix: ignore transient 0% flashes in compaction counter

Ignore context percentage values below 1% to prevent false compaction
counts when Claude Code emits incomplete status JSON frames.

* test: clarify transient compaction glitches

---------

Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-13 20:16:21 -04:00
Zach 3058693a64 fix: keep usage-fetch tests from touching the real user cache (#432)
* fix: keep usage-fetch tests from touching the real user cache

The probe subprocesses overrode HOME but inherited the real USERPROFILE,
which os.homedir() prefers on Windows, so every test run read and wrote
the developer's live ~/.cache/ccstatusline: fixture data and stale locks
ended up in the running statusline, which showed [Timeout] until the
lock expired and fixture percentages until the cache aged out.

- Pin USERPROFILE alongside HOME in the probe environment
- Pin CLAUDE_CONFIG_DIR and both proxy variables so inherited developer
  settings never reach probes
- Report os.homedir() from every probe and assert it matches the sandbox
  home, so any future isolation escape fails loudly
- Make the lowercase https_proxy assertion platform-aware: Windows
  environment variables are case-insensitive, so it is indistinguishable
  from HTTPS_PROXY there

On Windows this takes the file from 0/11 passing to 11/11.

Co-authored-by: Claude <noreply@anthropic.com>

* fix(test): preserve lowercase proxy env in usage probes

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-13 20:05:18 -04:00
dependabot[bot] a221e8ab2c chore(deps-dev): bump the dev-dependencies group across 1 directory with 11 updates (#422)
Bumps the dev-dependencies group with 11 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@remotion/cli](https://github.com/remotion-dev/remotion) | `4.0.461` | `4.0.472` |
| [eslint](https://github.com/eslint/eslint) | `10.3.0` | `10.4.1` |
| [eslint-import-resolver-typescript](https://github.com/import-js/eslint-import-resolver-typescript) | `4.4.4` | `4.4.5` |
| [ink-gradient](https://github.com/sindresorhus/ink-gradient) | `4.0.0` | `4.0.1` |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.2.6` | `19.2.7` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.2.14` | `19.2.16` |
| [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.2.6` | `19.2.7` |
| [remotion](https://github.com/remotion-dev/remotion) | `4.0.461` | `4.0.472` |
| [tinyglobby](https://github.com/SuperchupuDev/tinyglobby) | `0.2.16` | `0.2.17` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.59.3` | `8.60.0` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.6` | `4.1.8` |



Updates `@remotion/cli` from 4.0.461 to 4.0.472
- [Release notes](https://github.com/remotion-dev/remotion/releases)
- [Commits](https://github.com/remotion-dev/remotion/compare/v4.0.461...v4.0.472)

Updates `eslint` from 10.3.0 to 10.4.1
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.3.0...v10.4.1)

Updates `eslint-import-resolver-typescript` from 4.4.4 to 4.4.5
- [Release notes](https://github.com/import-js/eslint-import-resolver-typescript/releases)
- [Changelog](https://github.com/import-js/eslint-import-resolver-typescript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-import-resolver-typescript/compare/v4.4.4...v4.4.5)

Updates `ink-gradient` from 4.0.0 to 4.0.1
- [Release notes](https://github.com/sindresorhus/ink-gradient/releases)
- [Commits](https://github.com/sindresorhus/ink-gradient/compare/v4.0.0...v4.0.1)

Updates `react` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react)

Updates `@types/react` from 19.2.14 to 19.2.16
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react-dom)

Updates `remotion` from 4.0.461 to 4.0.472
- [Release notes](https://github.com/remotion-dev/remotion/releases)
- [Commits](https://github.com/remotion-dev/remotion/compare/v4.0.461...v4.0.472)

Updates `tinyglobby` from 0.2.16 to 0.2.17
- [Release notes](https://github.com/SuperchupuDev/tinyglobby/releases)
- [Changelog](https://github.com/SuperchupuDev/tinyglobby/blob/main/CHANGELOG.md)
- [Commits](https://github.com/SuperchupuDev/tinyglobby/compare/0.2.16...0.2.17)

Updates `typescript-eslint` from 8.59.3 to 8.60.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.0/packages/typescript-eslint)

Updates `vitest` from 4.1.6 to 4.1.8
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.8/packages/vitest)

---
updated-dependencies:
- dependency-name: "@remotion/cli"
  dependency-version: 4.0.472
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: eslint
  dependency-version: 10.4.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: eslint-import-resolver-typescript
  dependency-version: 4.4.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: ink-gradient
  dependency-version: 4.0.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: react
  dependency-version: 19.2.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: "@types/react"
  dependency-version: 19.2.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: react-dom
  dependency-version: 19.2.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: remotion
  dependency-version: 4.0.472
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: tinyglobby
  dependency-version: 0.2.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.60.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: vitest
  dependency-version: 4.1.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-13 19:27:03 -04:00
Rayan Salhab 447e0e69eb fix: git-review detection with SSH host aliases (#424)
* Fix git review detection for SSH host aliases

* fix(git-review): preserve canonical SSH forge hosts

---------

Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-13 19:25:10 -04:00
Cameron Sjo 97108fc1ea feat: Gradient color support and line-spanning foreground gradient overrides (#406)
* feat: line-spanning foreground gradients via overrideForegroundColor

Add a `gradient:<stop>,<stop>,...` form for `overrideForegroundColor` that
paints the whole status line with a continuous gradient — each visible
character is colored by its column position, so the gradient spans the line
rather than restarting per widget. Applies to standard (non-powerline) lines;
powerline separators derive their color from adjacent backgrounds, so a
foreground gradient is intentionally not applied there.

- src/utils/gradient.ts: parse hex stops (`hex:RRGGBB` / `#RRGGBB` / bare),
  interpolate in OKLab for perceptually even, non-muddy blends, and map to
  truecolor or the nearest ansi256 index.
- src/utils/ansi.ts: applyLineGradient walks the assembled line with the
  existing escape/cluster tokenizer, so SGR styling and OSC-8 hyperlinks pass
  through untouched and visible width is unchanged (flex layout unaffected).
- src/utils/renderer.ts: applied after assembly and before truncation in the
  standard path. `overrideForegroundColor` accepts the new `gradient:` form
  alongside the existing `hex:` / `ansi256:` / named tagged-string forms; a
  gradient spec is not treated as a per-widget solid color and degrades to a
  no-op at ansi16 (keeping widgets' own colors).

Tests cover spec parsing, OKLab sampling, ansi256 quantization,
width-invariance, OSC-8 passthrough, and a renderer integration case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: add per-widget gradients + presets + TUI picker on the line-span core

Converges the two same-day gradient PRs into one coherent feature. #406
added line-spanning gradients via overrideForegroundColor (OKLab, zero-dep);
#404 (@akkaz) added gradient as a per-widget color with named presets and a
ColorMenu picker. Both created src/utils/gradient.ts and would conflict, so
this meshes them onto a single shared OKLab engine:

- gradient.ts: GRADIENT_PRESETS (akkaz's stops, gradient-string MIT;
  rainbow/pastel re-expressed as multi-stop hue wheels for OKLab); unified
  parseGradientSpec accepting presets, dash (RRGGBB-RRGGBB), and comma
  (hex:..,..) forms; applyGradientToText for the per-widget sweep.
- colors.ts: per-widget gradient hook in applyColors; getColorAnsiCode
  collapses a gradient to its first stop (powerline / ansi16 degrade).
- ColorMenu.tsx: 'g' opens a gradient picker (preset list + custom hex),
  foreground-only, colorLevel >= 2.
- No new dependency (tinygradient dropped in favor of OKLab).

Precedence: overrideForegroundColor gradient (line-span) > widget.color
gradient (per-widget) > solid. Gradients self-degrade at render time, so
color-sanitize leaves them untouched at every level.

Builds on the per-widget design from #404 by @akkaz.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: akkaz <giomarco@cleversoft.it>

* refactor: polish gradient feature — fix truncation reset-leak, tighten, document

Pre-PR polish pass over the gradient feature.

Fix (correctness):
- renderStatusLine now applies the line-span gradient AFTER truncation, not
  before. truncateStyledText cuts from the right and appends a raw "..." with no
  trailing reset, so a gradient applied earlier had its closing \x1b[39m sliced
  off, leaking the last color past the status line. Gradient codes are zero-width,
  so the truncation measurement is unaffected by deferring. Regression test added.

Simplify:
- Add exported isGradientSpec(); reuse it across colors.ts and renderer.ts instead
  of duplicating the 'gradient:' startsWith check. Drop the redundant prefix guard
  in applyColors (parseGradientSpec already self-guards).

Docs:
- Document applyGradientToText's code-point (vs grapheme-cluster) iteration as a
  known limitation, with the ZWJ/variation-selector consequence and the
  circular-import reason it isn't unified with applyLineGradient yet.
- Note that hex:/# /bare stops are valid in both comma and dash parse forms.
- Note getColorAnsiCode's ansi16 branch intentionally emits a truecolor first-stop
  escape (caller-degraded; never reached at a true ansi16 terminal).
- README + docs/USAGE.md: gradient color options (both scopes, presets, forms).

bun test 1433 pass / 0 fail; lint + tsc clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(gradient): preserve escape sequences in widget gradients

Keep ANSI and OSC control sequences byte-for-byte intact when applying per-widget gradients so hyperlinks and pre-styled widget output are not corrupted by inserted SGR codes.

Count and color only visible non-whitespace characters while passing escape sequences through unchanged. Add a regression covering styled OSC 8 link output.

* fix(colors): suppress gradient fallback at ansi16

Prevent stored gradient color specs from emitting 24-bit SGR codes when the active terminal color level has been reduced to Basic or No Color.

Leave gradient settings intact, but return no gradient ANSI fallback at ansi16 and cover the behavior in per-widget and raw-code regression tests.

* fix(renderer): detect truncated gradient lines visibly

Preserve truncation reporting after whole-line gradients insert SGR codes between the ellipsis characters.

Check the visible text for the truncation marker instead of the raw styled bytes, and add a regression where the rendered line no longer contains a literal contiguous ellipsis.

* feat(tui): add gradients to foreground overrides

Let Global Overrides assign a whole-line foreground gradient through the same preset/custom selector used by the color screen.

Move (g) to gradient selection, add (x) as the foreground override clear key, show gradient override values in the menu, and update usage docs for the new controls and Basic/No Color degradation behavior.

In Powerline mode, carry global gradient position continuously across widget text while leaving separators and caps under Powerline contrast rules. Surface an active foreground override warning on the Powerline Setup screen so theme masking is visible.

---------

Co-authored-by: Cameron Sjo <cameronsjo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: akkaz <giomarco@cleversoft.it>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-06-13 18:56:09 -04:00
Matthew Breedlove 54fce0903e fix: support Windows npm shim execution
Closes #401.
2026-06-02 09:53:25 -04:00
Kotob 9d4b6ee4f9 feat: add remote control status widget (#382)
* feat: add remote control status widget

Adds a widget that reads ~/.claude/sessions/<pid>.json and shows whether
the current session has a remote-control bridge attached, matched by
session_id from the Claude Code status payload.

Claude Code sets bridgeSessionId to null on disconnect and rewrites the
session file within ~1s, so the widget reflects connect/disconnect
transitions at the next status-line refresh.

* feat: add label-check format to remote control status widget

Renders "remote " when connected and "remote " when disconnected, so
the bar can be parsed by shape/color at a glance instead of reading "on"
or "off". Slots into the existing format cycle after word.

* feat: add label-mark format using text-mode check/cross

Renders "remote ✓" / "remote ✗" using U+2713 and U+2717. Unlike the
label-check emoji variant these are text-mode glyphs, so they stay
single-cell and pick up the widget color instead of drawing in the OS
emoji palette — less visually invasive while still parseable by shape.
2026-05-20 02:26:47 -04:00
dependabot[bot] cd2e41adc8 chore(deps-dev): bump the dev-dependencies group with 5 updates (#386)
Bumps the dev-dependencies group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@remotion/cli](https://github.com/remotion-dev/remotion) | `4.0.459` | `4.0.461` |
| [@types/bun](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/bun) | `1.3.13` | `1.3.14` |
| [remotion](https://github.com/remotion-dev/remotion) | `4.0.459` | `4.0.461` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.59.2` | `8.59.3` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.5` | `4.1.6` |


Updates `@remotion/cli` from 4.0.459 to 4.0.461
- [Release notes](https://github.com/remotion-dev/remotion/releases)
- [Commits](https://github.com/remotion-dev/remotion/compare/v4.0.459...v4.0.461)

Updates `@types/bun` from 1.3.13 to 1.3.14
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/bun)

Updates `remotion` from 4.0.459 to 4.0.461
- [Release notes](https://github.com/remotion-dev/remotion/releases)
- [Commits](https://github.com/remotion-dev/remotion/compare/v4.0.459...v4.0.461)

Updates `typescript-eslint` from 8.59.2 to 8.59.3
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.3/packages/typescript-eslint)

Updates `vitest` from 4.1.5 to 4.1.6
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.6/packages/vitest)

---
updated-dependencies:
- dependency-name: "@remotion/cli"
  dependency-version: 4.0.461
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: "@types/bun"
  dependency-version: 1.3.14
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: remotion
  dependency-version: 4.0.461
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.59.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: vitest
  dependency-version: 4.1.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 02:13:00 -04:00
Ronald E. Oribio R. 4b314d5fce fix(extra-usage): correct unit assumptions for usage API response (#388)
* fix(extra-usage): correct unit assumptions for usage API response

The Anthropic usage API returns `extra_usage.used_credits` in cents (not
dollars) and `extra_usage.utilization` as a percent 0-100 (not a 0-1
fraction). The current widget code assumed the inverse, which made:

- ExtraUsageUtilization always clamp to 100.0% (multiplying a percent
  by 100 and clamping to [0,100])
- ExtraUsageRemaining always show $0.00 (subtracting cents from dollars
  goes negative, clamped to 0)

Drop the `* 100` in ExtraUsageUtilization and divide `extraUsageUsed`
by 100 in ExtraUsageRemaining so both widgets render real values.

Verified locally against a live API response where util=6.74 and
used=27087/limit=400000 — now renders "Overage: 6.8% | Overage Left:
\$3,728.54" instead of "Overage: 100.0% | Overage Left: \$0.00".

* test(extra-usage): update fixtures for corrected unit assumptions

Adjust extraUsageUsed fixtures to cents and extraUsageUtilization
fixtures to 0-100 percentages so they exercise the corrected widget
math.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(extra-usage): align API unit fixtures

Update fetch and prefetch fixtures to reflect used credits as cents and extra usage utilization as a 0-100 percentage. Clarify the UsageData comments to match the widget contract.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-05-20 02:11:09 -04:00
Josi Aranda cc8e82f476 feat(weekly-reset): add weekday display mode for Weekly Reset Timer (#392)
Add a (w)eekday toggle to the Weekly Reset Timer widget in date mode.
When enabled, renders "Sun 11:00 PM GMT+9" instead of the full ISO date,
matching Claude web's weekly usage display style.

Co-authored-by: mm-aranda <aranda@macromill.com>
2026-05-20 01:49:42 -04:00
Matthew Breedlove 1b7cfb010b chore: bump version to 2.2.19
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
Publish / Publish to npm (push) Has been cancelled
CI / Build (push) Has been cancelled
v2.2.19
2026-05-17 03:07:31 -04:00
Daniel Naves de Carvalho ea97ddd69e feat(terminal): honor CCSTATUSLINE_WIDTH env var to override probe (#380)
* feat(terminal): honor CCSTATUSLINE_WIDTH env var to override probe

Provide an explicit width override so users can bypass the TTY probe
entirely when both ancestor-walk and `tput cols` fall through.

This is the fallback case the existing probe cannot solve on its own:
Claude Code >= 2.1.139 spawns statusline/hooks without terminal access,
and in some configurations (IDE integrations, nested shells, certain
agent-mode spawn paths) no ancestor process owns a TTY either. The
ancestor walk fails, `tput cols` returns 80, and the multi-line layout
truncates regardless of the actual iTerm2/terminal width.

PR #377 (`stty -F`/`stty -f`) covers the case where an ancestor does
hold a TTY but the legacy `< /dev/tty` form errors with ENOTTY. This
patch is complementary -- it handles the case where the ancestor walk
finds no TTY at all -- and gives users a knob today while upstream
work on passing `terminalWidth` via stdin JSON (#308) lands.

Change
------

`src/utils/terminal.ts` -- `probeTerminalWidth` now reads
`CCSTATUSLINE_WIDTH` before any platform check or probe. A valid
positive integer short-circuits with that value; anything else
(missing, empty, non-numeric, zero, negative) falls through to the
existing probe logic.

Usage
-----

Set the env var on the statusLine command in `~/.claude/settings.json`:

```json
"statusLine": {
  "type": "command",
  "command": "CCSTATUSLINE_WIDTH=200 ccstatusline"
}
```

Tests
-----

Four new cases in `src/utils/__tests__/terminal.test.ts`:

- override short-circuits probing entirely
- non-positive override (`0`) falls back to probing
- non-numeric override falls back to probing
- override applies on Windows where probing is otherwise disabled

`bunx vitest run src/utils/__tests__/terminal.test.ts` -> 12/12 pass.
Full-suite delta vs `main`: 4 new passing tests, zero new failures
(the pre-existing 105 env-specific failures in other suites are
unchanged on both branches).

`bun run lint` -> clean.

* docs: document terminal width override

---------

Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-05-17 03:01:58 -04:00
Matthew Breedlove 6a581e6c6a fix: cache git subprocess output for statusline
Add persistent git command caching under ~/.cache/ccstatusline/git-cache with command-only entries, cwd metadata, repo mtimes, and configurable TTL.

Expose Git Cache TTL in Configure Status Line, default it to 5s, and pass it through the real render context.

Make pinned global install the top/default option, clarify install wording, and add windowsHide to runtime child process options.

Closes #384.
2026-05-17 02:42:11 -04:00
Deepak Dewani 654802e4d6 fix(git): use compatible git commands for older git versions (#385)
* fix(git): use compatible git commands for older git versions

This commit updates git commands to be compatible with older versions of Git (e.g. 2.10.1). Specifically, it replaces branch --show-current with rev-parse --abbrev-ref HEAD and uses the GIT_OPTIONAL_LOCKS environment variable instead of the --no-optional-locks flag.

* fix(git): address review compatibility regressions

Use symbolic-ref --short HEAD for branch detection in the GitBranch widget and review cache so unborn branches keep rendering their branch name while detached HEAD still resolves as no branch.

Update git command assertions after replacing --no-optional-locks argv usage with GIT_OPTIONAL_LOCKS=0 in the exec environment, including shared coverage for widgets and git remote helpers.

Add a small test helper for asserting git exec options without depending on the full process environment.

Verification: bun test; bun run lint; git diff --check

---------

Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-05-17 01:33:09 -04:00
Matthew Breedlove cf5ab7be45 chore: Version bump and docs update
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
Publish / Publish to npm (push) Has been cancelled
CI / Build (push) Has been cancelled
v2.2.18
2026-05-15 09:42:38 -04:00
Bastian Staunstrup 861a2a0638 fix(git): always pass --no-optional-locks to prevent index.lock races (#381)
When the statusline refreshes while another git process is writing
.git/index.lock (e.g. a concurrent `git restore --staged`), commands
like `git diff --shortstat` fail with "Unable to create index.lock"
because diff tries to refresh the stat cache and races on the lock.

`runGitArgs` now prepends `--no-optional-locks` to every git
invocation so read-only commands cannot interfere with the user's
working git operations. The two call sites that already prefixed the
flag manually are simplified.
2026-05-15 09:38:40 -04:00
dependabot[bot] 4091574f52 chore(deps-dev): bump the dev-dependencies group across 1 directory with 4 updates (#368)
Bumps the dev-dependencies group with 4 updates in the / directory: [eslint](https://github.com/eslint/eslint), [globals](https://github.com/sindresorhus/globals), [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) and [zod](https://github.com/colinhacks/zod).


Updates `eslint` from 10.2.1 to 10.3.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.2.1...v10.3.0)

Updates `globals` from 17.5.0 to 17.6.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.5.0...v17.6.0)

Updates `typescript-eslint` from 8.59.0 to 8.59.2
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.2/packages/typescript-eslint)

Updates `zod` from 4.3.6 to 4.4.3
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Commits](https://github.com/colinhacks/zod/compare/v4.3.6...v4.4.3)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 10.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: globals
  dependency-version: 17.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.59.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: zod
  dependency-version: 4.4.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-14 09:52:19 -04:00
Ronald E. Oribio R. 196a370a2e feat: add extra usage widgets and fix null rate-limit buckets for pay-as-you-go plans (#375)
* feat: add extra usage widgets and fix null rate-limit buckets for pay-as-you-go plans

Add two new widgets for Anthropic pay-as-you-go (extra usage) plans:
- `extra-usage-utilization` — shows overage utilization as a percentage
- `extra-usage-remaining` — shows remaining monthly overage budget in dollars

Fix a Zod schema bug that caused all usage widgets to time out on PAYG plans.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: handle disabled extra usage widgets

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-05-14 09:41:24 -04:00
Matthew Breedlove 29908c266a fix: usage API parsing for nullable cohort response buckets
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
Publish / Publish to npm (push) Has been cancelled
CI / Build (push) Has been cancelled
v2.2.17
2026-05-14 08:58:50 -04:00
Matthew Breedlove b01336b1a7 chore: scope publish workflow to this repository so forks don't try to push to the ccstatusline npm 2026-05-13 14:42:03 -04:00
Pragy Agarwal 9eccca279e fix(terminal): use stty -F/-f to read tty size in detached spawn (#377)
The TTY-width probe walked ancestor processes to find a controlling
PTY and ran `stty size < /dev/${tty}` to read its dimensions. That
form fails with ENOTTY on Linux when the calling process has no
controlling terminal — which is now the case under Claude Code
>= 2.1.139, whose changelog reads "hooks now run without terminal
access". The statusLine spawn is hardened the same way. Probe falls
back to `tput cols` (= 80), flexMode "full-minus-40" collapses to
40 columns, and the statusline truncates regardless of the real
terminal width.

GNU coreutils `stty -F <path>` and BSD `stty -f <path>` open the
device themselves (with O_NOCTTY semantics) and succeed regardless
of controlling-tty status. Try `-F` then `-f` then the historical
redirect form so we keep working on every stty variant.

Verified: on a Linux+ptyxis spawn under Claude Code 2.1.140 the probe
goes from returning null to returning the real width (159 cols here)
without restarting the session.

Co-authored-by: Matthew Breedlove <sirmalloc@gmail.com>
2026-05-13 13:47:13 -04:00
Matthew Breedlove 9ab87c3f55 Adding publishing workflow for npm provenance attestation
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
Publish / Publish to npm (push) Has been cancelled
CI / Build (push) Has been cancelled
Closes #369
v2.2.16
2026-05-13 13:28:41 -04:00
Matthew Breedlove 1739572a96 fix: merge partial usage data for widgets
Use widget-specific requirements to fetch missing usage fields and merge rate_limits data with API results.

Preserve API errors alongside available usage data so widgets with fulfilled fields still render while missing fields surface fetch failures.
2026-05-13 13:09:37 -04:00
Matthew Breedlove b8821a7d83 fix: ignore bunx statusline shims
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Build (push) Has been cancelled
v2.2.15
2026-05-12 02:24:39 -04:00
Matthew Breedlove ed3ce5ba0b feat: Version pinning install support
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Build (push) Has been cancelled
Closes #298
Closes #103
v2.2.14
2026-05-12 02:14:02 -04:00