claude-pace 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/claude-pace.sh +24 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,6 +57,14 @@ Restart Claude Code. Done.
|
|
|
57
57
|
|
|
58
58
|
To remove: delete the `statusLine` block from `~/.claude/settings.json`.
|
|
59
59
|
|
|
60
|
+
## Upgrade
|
|
61
|
+
|
|
62
|
+
- **Plugin:** `/claude-pace:setup` (pulls the latest from GitHub)
|
|
63
|
+
- **npx:** `npx claude-pace@latest`
|
|
64
|
+
- **Manual:** Re-run the `curl` command above.
|
|
65
|
+
|
|
66
|
+
Release notifications: Watch this repo → Custom → Releases.
|
|
67
|
+
|
|
60
68
|
## How It Compares
|
|
61
69
|
|
|
62
70
|
| | claude-pace | Node.js/TypeScript statuslines | Rust/Go statuslines |
|
|
@@ -80,11 +88,17 @@ Claude Code polls the statusline every ~300ms:
|
|
|
80
88
|
|------|--------|-------|
|
|
81
89
|
| Model, context, cost | stdin JSON (single `jq` call) | None needed |
|
|
82
90
|
| Quota (5h, 7d, pace) | stdin `rate_limits` (CC >= 2.1.80) | None needed (real-time) |
|
|
83
|
-
| Quota fallback | Anthropic Usage API (CC < 2.1.80) |
|
|
84
|
-
| Git branch + diff | `git` commands |
|
|
91
|
+
| Quota fallback | Anthropic Usage API (CC < 2.1.80) | Private cache dir, 300s TTL, async background refresh |
|
|
92
|
+
| Git branch + diff | `git` commands | Private cache dir, 5s TTL |
|
|
85
93
|
|
|
86
94
|
On Claude Code >= 2.1.80, usage data comes directly from stdin. No network calls. On older versions, it falls back to the Usage API in a background subshell so the statusline never blocks.
|
|
87
95
|
|
|
96
|
+
Cache files live in a private per-user directory (`$XDG_RUNTIME_DIR/claude-pace` or `~/.cache/claude-pace`, mode 700). All cache reads are validated before use. No files are ever written to shared `/tmp`.
|
|
97
|
+
|
|
98
|
+
## Also by the Author
|
|
99
|
+
|
|
100
|
+
[**diffpane**](https://github.com/Astro-Han/diffpane) - Real-time TUI diff viewer for AI coding agents. See what Claude Code changes as it happens.
|
|
101
|
+
|
|
88
102
|
## License
|
|
89
103
|
|
|
90
104
|
MIT
|
package/claude-pace.sh
CHANGED
|
@@ -94,6 +94,7 @@ _CD="" CACHE_OK=0
|
|
|
94
94
|
for _BASE in "${XDG_RUNTIME_DIR:-}" "${HOME}/.cache"; do
|
|
95
95
|
[ -n "$_BASE" ] || continue
|
|
96
96
|
_CAND="${_BASE%/}/claude-pace"
|
|
97
|
+
# shellcheck disable=SC2174 # -p only creates leaf here; parent already exists
|
|
97
98
|
[ -e "$_CAND" ] || mkdir -p -m 700 "$_CAND" 2>/dev/null || continue
|
|
98
99
|
_cache_dir_ok "$_CAND" || continue
|
|
99
100
|
_CD="$_CAND"
|
|
@@ -148,7 +149,7 @@ for ((i = F; i < 10; i++)); do BAR+='░'; done
|
|
|
148
149
|
# Atomic write: write to a temp file first, then mv to avoid partial reads.
|
|
149
150
|
BR="" FC=0 AD=0 DL=0
|
|
150
151
|
if [[ "$CACHE_OK" == "1" ]]; then
|
|
151
|
-
GC="${_CD}/claude-sl-git-${
|
|
152
|
+
GC="${_CD}/claude-sl-git-$(printf '%s' "$DIR" | { shasum 2>/dev/null || sha1sum; } | cut -c1-16)"
|
|
152
153
|
if _stale "$GC" 5; then
|
|
153
154
|
if _collect_git_info; then
|
|
154
155
|
_write_cache_record "$GC" "$BR" "$FC" "$AD" "$DL"
|
|
@@ -201,8 +202,8 @@ if [[ "$HAS_RL" == "1" ]]; then
|
|
|
201
202
|
RM5=$(_minutes_until "$R5")
|
|
202
203
|
RM7=$(_minutes_until "$R7")
|
|
203
204
|
# Extra usage (XO/XU/XL) only available via API fallback; stdin lacks this data
|
|
204
|
-
|
|
205
|
-
# ── API fallback (
|
|
205
|
+
elif [[ "${CLAUDE_PACE_API_FALLBACK:-1}" != "0" ]]; then
|
|
206
|
+
# ── API fallback (disable via CLAUDE_PACE_API_FALLBACK=0) ──
|
|
206
207
|
UC="" UL=""
|
|
207
208
|
[[ "$CACHE_OK" == "1" ]] && {
|
|
208
209
|
UC="${_CD}/claude-sl-usage"
|
|
@@ -213,7 +214,7 @@ else
|
|
|
213
214
|
# Check in order: env var → macOS Keychain → credentials file → secret-tool (Linux).
|
|
214
215
|
_get_token() {
|
|
215
216
|
[ -n "$CLAUDE_CODE_OAUTH_TOKEN" ] && {
|
|
216
|
-
|
|
217
|
+
printf '%s' "$CLAUDE_CODE_OAUTH_TOKEN"
|
|
217
218
|
return
|
|
218
219
|
}
|
|
219
220
|
local b=""
|
|
@@ -222,18 +223,30 @@ else
|
|
|
222
223
|
[ -z "$b" ] && [ -f ~/.claude/.credentials.json ] && b=$(<~/.claude/.credentials.json)
|
|
223
224
|
[ -z "$b" ] && command -v secret-tool >/dev/null &&
|
|
224
225
|
b=$(timeout 2 secret-tool lookup service "Claude Code-credentials" 2>/dev/null)
|
|
225
|
-
[ -n "$b" ] && jq -
|
|
226
|
+
[ -n "$b" ] && jq -j '.claudeAiOauth.accessToken//empty' <<<"$b" 2>/dev/null
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
# ── _fetch_usage_api: direct API read into usage globals ──
|
|
229
230
|
# Used by both the cached background refresh path and the no-cache fallback.
|
|
230
231
|
_fetch_usage_api() {
|
|
231
232
|
local tk resp
|
|
232
|
-
|
|
233
|
+
# Command substitution strips trailing newlines. Append a sentinel byte only
|
|
234
|
+
# on success so malformed tokens with a trailing LF remain detectable here.
|
|
235
|
+
tk=$(_get_token && printf '\001') || return 1
|
|
236
|
+
[[ "$tk" == *$'\001' ]] || return 1
|
|
237
|
+
tk=${tk%$'\001'}
|
|
233
238
|
[ -n "$tk" ] || return 1
|
|
239
|
+
# OAuth bearer tokens must remain a single header line. Reject malformed
|
|
240
|
+
# credentials up front instead of letting curl parse injected CR/LF bytes.
|
|
241
|
+
case "$tk" in *$'\n'* | *$'\r'*) return 1 ;; esac
|
|
242
|
+
# Feed headers through process substitution so the bearer token stays out
|
|
243
|
+
# of curl argv while preserving literal bytes like quotes and backslashes.
|
|
234
244
|
resp=$(curl -s --max-time 3 \
|
|
235
|
-
-H
|
|
236
|
-
|
|
245
|
+
-H @<(
|
|
246
|
+
printf 'Authorization: Bearer %s\n' "$tk"
|
|
247
|
+
printf '%s\n' 'anthropic-beta: oauth-2025-04-20'
|
|
248
|
+
printf '%s\n' 'Content-Type: application/json'
|
|
249
|
+
) \
|
|
237
250
|
"https://api.anthropic.com/api/oauth/usage" 2>/dev/null)
|
|
238
251
|
IFS=$'\t' read -r U5 U7 XO XU XL RM5 RM7 < <(jq -r '
|
|
239
252
|
def rmins: if . and . != "" then (sub("\\.[0-9]+"; "") | sub("\\+00:00$"; "Z") | fromdateiso8601) - (now|floor) | ./60|floor | if .<0 then 0 else . end else null end;
|
|
@@ -314,6 +327,9 @@ else
|
|
|
314
327
|
[[ "$XU" =~ ^[0-9]+$ ]] || XU=0
|
|
315
328
|
[[ "$XL" =~ ^[0-9]+$ ]] || XL=0
|
|
316
329
|
# ── End API fallback ──
|
|
330
|
+
else
|
|
331
|
+
# No stdin rate_limits and API fallback not enabled; show session cost only.
|
|
332
|
+
SHOW_COST=1
|
|
317
333
|
fi
|
|
318
334
|
|
|
319
335
|
# Combined usage formatter: used% [pace delta] (countdown)
|