Skip to content

Releases

v0.9.6

Choose a tag to compare

@Astro-Han Astro-Han released this 10 Nov 01:21
  • Honor the autoCompactWindow setting from ~/.claude/settings.json (Claude Code 2.1.311+, also written by /autocompact): env var first, then the per-model modelSettings entry, then the top-level value. Previously only CLAUDE_CODE_AUTO_COMPACT_WINDOW was read, so line 2 kept measuring against the full window.

v0.9.5

Choose a tag to compare

@Astro-Han Astro-Han released this 24 Sep 18:47
  • Show the project name on Windows instead of a truncated, double-escaped full path. workspace.project_dir is normalized to forward slashes, which also fixes worktree detection on Windows (#18, diagnosis by @jestemkojak)

v0.9.4

Choose a tag to compare

@Astro-Han Astro-Han released this 28 Jul 06:23

Every install channel now ships from a tagged release instead of main.

Until now both the manual curl and /claude-pace:setup fetched raw.githubusercontent.com/.../main/claude-pace.sh, so what you installed was whatever main happened to be at that second — not a version anyone could name, reproduce, or roll back to. Releases, tags and the npm package recorded versions but were never what actually shipped.

The issue was reported against the manual curl only, but setup.md ran the same command, so the "recommended" plugin path was installing main too.

  • /claude-pace:setup makes no network calls. It copies ${CLAUDE_PLUGIN_ROOT}/claude-pace.sh, the script the plugin already bundles. The plugin was downloading a second copy of a file it was carrying — a package manager ignoring its own package. There is deliberately no curl fallback: a missing bundled script means a broken plugin install, and the command stops and says so.
  • Marketplace entry pins to the release tag. The previous "source": "./" served the default branch, so pinning setup.md alone would still have handed new installs the contents of main.
  • Manual install pulls releases/latest/download/claude-pace.sh, with releases/download/vX.Y.Z/claude-pace.sh documented for pinning an exact version.
  • The manual curl gained the -f it was missing. Without it a 404 exits 0 and writes the literal text Not Found into ~/.claude/statusline.sh, which the next line then chmod +x. This was a live defect independent of the version-pinning issue.

What this does and does not buy: bad code now has to pass through an explicit release action to reach users, which blocks accidental merges, unreviewed pushes, and force-pushes to main from shipping directly. It does not defend against anyone who can publish releases or a compromised maintainer account, and a lightweight tag remains a movable ref.

Upgrading an existing plugin install:

/plugin marketplace update claude-pace-marketplace
/plugin update claude-pace
/reload-plugins
/claude-pace:setup

Reported in #16.

v0.9.3

Choose a tag to compare

@Astro-Han Astro-Han released this 27 Jul 16:55
  • Stop stranding temp files in the cache directory. Cache records went through mktemp + mv for atomicity, but Claude Code cancels the status line script whenever a refresh arrives while it is still running, so every cancellation landing between the write and the mv left a uniquely named temp file behind permanently. On a slow machine that is the normal path, not an edge case: the reporter's ~/.cache/claude-pace/ had accumulated 3008 orphaned claude-sl-tmp-* files (1913 of them zero-byte) against 45 real cache records, and the directory size then fed back into mktemp and stat latency. Records are now written straight to their final path (#17, diagnosis and field data by @volkanncicek)
  • Rationale for dropping atomicity rather than bounding the temp files: a cache record is one short line of git metadata with a 5s TTL, so a torn write is simply a cache miss — the reader already sanitizes non-numeric fields and the next run recomputes from git. Removing the temp file makes the orphans impossible instead of merely bounded, drops two subprocess spawns per refresh (worth ~400ms on Git Bash, where each spawn costs 180-300ms), and shrinks the cancellable window from "across two process launches" to a single builtin write
  • Refuse symlinked cache paths explicitly: mv used to replace the symlink itself, while > follows it. Covered by the existing Test 16, which fails without the guard
  • Existing ~/.cache/claude-pace/claude-sl-tmp-* files from earlier versions are orphans, ignored by claude-pace, and safe to delete
  • Add regression coverage asserting the invariant directly — a cache write spawns neither mktemp nor mv — since a leftover-file check alone cannot catch this class of bug (a temp-file scheme also cleans up after itself whenever the run completes)

v0.9.2

Choose a tag to compare

@Astro-Han Astro-Han released this 16 Jun 03:57
  • Fix the auto-compact bar briefly showing the model's full window (e.g. 0% 1M) at the very start of a session. Claude Code sends context_window.total_input_tokens as 0 on a fresh session's first frame, and v0.9.1 only recomputed against the auto-compact window when that value was > 0 — so the bar (and its 1M label) fell back to the full window until the first API response landed, the exact 1M flash issue #15 set out to remove. The recompute now fires whenever the field is present, including a genuine 0, and falls back to the full window only when Claude Code omits the field entirely (older CC that predates total_input_tokens). jq now emits a -1 sentinel for the missing field so a real 0 (fresh-session first frame) and an absent field no longer collapse to the same value (follow-up to #15)
  • Add regression coverage for the present-zero first frame measuring against the compact window, plus an explicit guard that a missing field never relabels to the compact window

v0.9.1

Choose a tag to compare

@Astro-Han Astro-Han released this 25 May 16:18

Track context against CLAUDE_CODE_AUTO_COMPACT_WINDOW.

Since Claude Code 2.1.117 the statusline's context_window.context_window_size is the model's full window (e.g. 1M for Opus 4.7) and used_percentage is measured against it. On a context capped by CLAUDE_CODE_AUTO_COMPACT_WINDOW (e.g. 400K) the bar filled against 1M and looked nearly empty right as auto-compaction was about to fire.

When the env var is set and context_window.total_input_tokens (CC 2.1.132+) is available, the bar now measures used tokens against the auto-compact window and relabels the size (e.g. 15% 400K), matching the desktop app's context indicator. Clamped to the real window, capped at 100%, and falls back to full-window behavior when the env var is unset or token data is missing (early session). Line 1 keeps the model's full-window label (e.g. (1M)) because that reflects the model's capability, not the active budget.

Closes #15

v0.9.0

Choose a tag to compare

@Astro-Han Astro-Han released this 20 May 14:27

Breaking change

Removes the last-known quota cache fallback. When stdin rate_limits is absent, claude-pace now shows -- for 5h/7d quota and the session cost when available, instead of replaying a cached snapshot from a previous run.

Cross-provider contamination reported by @kvdb in #14 surfaced the underlying identity gap: stdin carries no provider/account identifier, so a cached account-level snapshot cannot be proven to belong to the current session. Multi-provider users (e.g. Claude Max + Microsoft Foundry) saw one account's quota leak into the other. Showing -- is an honest failure mode; replaying a wrong-account snapshot is a silent wrong answer.

The per-project cache key proposed in PR #14 would only paper over the most common collision pattern without restoring identity, so the fallback is removed entirely instead of re-keyed.

See docs/decisions/2026-05-20-quota-cache-removal.md for the full reasoning and the conditions under which a cache could be reintroduced.

What you need to know

  • Claude Code >=2.1.80 provides rate_limits in statusline stdin — the common case is unaffected
  • Sessions where rate_limits is absent now show -- for 5h/7d quota and the session cost when present
  • Existing ~/.cache/claude-pace/claude-sl-quota* files from v0.8.x are now orphans, ignored by claude-pace, and safe to delete manually

Diffstat

  • Drops ~250 lines covering quota cache write/read, snapshot validation, symlink and unreadable-file hardening, and expired-reset guards
  • Tests: Test 19-33 replaced with two tighter behavior contracts (absent rate_limits → placeholders + session cost without consulting any cache; legacy orphan quota cache files are ignored)

v0.8.6

Choose a tag to compare

@Astro-Han Astro-Han released this 01 May 13:10

Fixes

  • Windows Git Bash compatibility: replace jq --slurpfile + process substitution with --argjson. /proc/<pid>/fd/N is unavailable on Windows, which previously caused MODEL and DIR to render blank. Thanks @capraCoder in #13.
  • Settings validation: validate ~/.claude/settings.json with jq -e . before passing to --argjson, falling back to {} for empty, whitespace-only, or malformed JSON so settings parsing failures stay localized to effort level.

Verification

98 regression assertions pass on Linux/macOS. Windows Git Bash + jq 1.8.1 verified by the PR author.

Full diff: v0.8.5...v0.8.6

v0.8.5

Choose a tag to compare

@Astro-Han Astro-Han released this 27 Apr 07:49
  • Show the effort level as a word (low / medium / high / xhigh / max) on line 1 instead of a glyph, for readability (#12)
  • Bump model-name truncation budget on line 1 from 22 to 28 chars to fit the longest word (medium) without clipping
  • Update regression tests to assert effort word + pipe alignment for all five levels, and pin the new 28-char truncation budget so a Sonnet 4.6 (200K) medium line stays unclipped

v0.8.4

Choose a tag to compare

@Astro-Han Astro-Han released this 24 Apr 03:31
  • Read effort.level from stdin when available (Claude Code 2.1.119+), falling back to ~/.claude/settings.json effortLevel on older versions
  • Add regression coverage for stdin effort levels and stdin-over-settings precedence (thanks @lifebugz in #11)