Skip to content

Instantly share code, notes, and snippets.

@cniska
Last active July 21, 2026 09:43
Show Gist options
  • Select an option

  • Save cniska/ac63274bd6f641bf66d784d06975a24a to your computer and use it in GitHub Desktop.

Select an option

Save cniska/ac63274bd6f641bf66d784d06975a24a to your computer and use it in GitHub Desktop.
Claude Code Statusline Script
#!/usr/bin/env bash
# Claude Code statusline: dir[/subdir] · worktree · branch[*↑↓] · model[↓] effort · pct%/size · $cur[ $tot] · ↑tok-in ↓tok-out
# dir is the repo name (cwd basename if not a repo); subdir/worktree/branch are optional.
# In a repo, if cwd is below the working-tree root, the cwd basename rides dim on dir (proj/subdir).
# The three fold left to right: a name already shown drops.
# Input: JSON on stdin (see https://docs.claude.com/en/docs/claude-code/statusline)
#
# One function per segment, each reading the parsed globals and echoing its rendered
# string (empty when there's nothing to show). main parses stdin, then joins the
# non-empty segments. Sourcing the script (the test suite) defines the helpers and
# returns before main runs, so each segment can be exercised in isolation.
set -u
# Pin numeric formatting to C: awk emits floats with a '.' decimal and bash printf reparses
# them (cost segment), which disagree under a comma-decimal LC_NUMERIC. C keeps both sides
# aligned regardless of the ambient locale.
export LC_NUMERIC=C
# Truecolor palette — One Dark dimmed ~15%, matched perceptual weight.
# Safe states stay the default foreground (RESET); color signals only warning/danger.
# DIM carries everything secondary — separators, effort, git ahead/behind, token
# throughput, the total cost — so it recedes beneath the primary content.
YELLOW=$'\033[38;2;195;163;105m'
RED=$'\033[38;2;190;92;99m'
DIM=$'\033[2m'
RESET=$'\033[0m'
SEP=" ${DIM}·${RESET} "
# Where a segment turns amber, then red. Context is window occupancy (%): red on
# the point good practice says to compact or clear, amber the approach. Cost is
# spend since the last /clear ($).
CONTEXT_YELLOW=50 CONTEXT_RED=60
COST_YELLOW=20 COST_RED=50
# Short count: 1234567 -> 1.2M, 1000000 -> 1M, 12345 -> 12k, 999 -> 999. Shared by
# token throughput and the context window size so the two never drift.
human() {
local n=${1:-0}
if [ "$n" -ge 1000000 ]; then awk -v n="$n" 'BEGIN{v=n/1000000; if (v==int(v)) printf "%dM", v; else printf "%.1fM", v}'
elif [ "$n" -ge 1000 ]; then awk -v n="$n" 'BEGIN{printf "%dk", n/1000}'
else printf '%d' "$n"; fi
}
# dir[ subdir] · worktree · branch, each optional, folded left to right (a name already
# shown drops; a worktree usually shares its branch's name). dir is the repo name in a git
# repo, else the cwd basename. When cwd is below the working-tree root, its basename rides
# on dir as a dim suffix (proj sub), the same shape as model + effort. The branch carries a
# dim suffix for dirty (*) and ahead/behind (↑↓). --no-optional-locks avoids fighting an
# active git command's lock.
seg_location() {
local dir wt="" branch="" suffix="" arrows="" agd="" main_root="" ab="" subdir=""
[ "$cwd" = "$HOME" ] && dir="~" || dir=$(basename "$cwd")
if [ -n "$cwd" ] && git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then
agd=$(git -C "$cwd" rev-parse --absolute-git-dir 2>/dev/null)
case "$agd" in */worktrees/*) wt=$(basename "$agd") ;; esac
main_root=${agd%/worktrees/*} # drop a linked-worktree tail (…/.git/worktrees/wt or …/proj.git/worktrees/wt)
main_root=${main_root%/.git} # normal repo: strip the /.git gitdir
main_root=${main_root%.git} # bare repo: strip the trailing .git (proj.git -> proj)
# Keep the ~ marker when $HOME is itself a repo root; below it, show the repo name.
[ -n "$main_root" ] && [ "$cwd" != "$HOME" ] && dir=$(basename "$main_root")
subdir=$(git -C "$cwd" --no-optional-locks rev-parse --show-prefix 2>/dev/null)
subdir=${subdir%/}; subdir=${subdir##*/} # cwd basename when below root, else empty
branch=$(git -C "$cwd" --no-optional-locks symbolic-ref --short HEAD 2>/dev/null \
|| git -C "$cwd" --no-optional-locks rev-parse --short HEAD 2>/dev/null)
if [ -n "$branch" ]; then
git -C "$cwd" --no-optional-locks status --porcelain 2>/dev/null | grep -q . && suffix="*"
ab=$(git -C "$cwd" --no-optional-locks rev-list --left-right --count '@{upstream}...HEAD' 2>/dev/null)
if [ -n "$ab" ]; then
local behind ahead
read -r behind ahead <<<"$ab" # rev-list --left-right --count: behind<TAB>ahead
[ "${ahead:-0}" -gt 0 ] && arrows="↑${ahead}"
[ "${behind:-0}" -gt 0 ] && arrows="${arrows:+$arrows }↓${behind}"
[ -n "$arrows" ] && suffix="${suffix} ${arrows}"
fi
fi
fi
local out="" seen="" n seg
for n in "$dir" "$wt" "$branch"; do
[ -z "$n" ] && continue
case " $seen " in *" $n "*) continue ;; esac
seen="$seen $n"
seg="$n"
{ [ "$n" = "$dir" ] && [ -n "$subdir" ]; } && seg="${seg} ${DIM}${subdir}${RESET}"
{ [ "$n" = "$branch" ] && [ -n "$suffix" ]; } && seg="${seg}${DIM}${suffix}${RESET}"
[ -n "$out" ] && out="${out}${SEP}"
out="${out}${seg}"
done
printf '%s' "$out"
}
# One forward pass over the transcript (JSONL) for the token segment: sum TOK_IN / TOK_OUT
# (session throughput) across every usage line, sidechain included, since it all costs.
# fromjson? drops a partial final line — a live session always has one — instead of failing
# the whole parse. Leaves the defaults (0/0) without jq or a readable transcript.
scan_transcript() {
TOK_IN=0; TOK_OUT=0
[ -n "$transcript" ] && [ -f "$transcript" ] || return 0
command -v jq >/dev/null 2>&1 || return 0
local out
out=$(jq -n -rRc '
reduce (inputs | fromjson?) as $l ({i:0,o:0};
if ($l.message.usage != null) then
.i += (($l.message.usage.input_tokens // 0) + ($l.message.usage.cache_creation_input_tokens // 0))
| .o += ($l.message.usage.output_tokens // 0)
else . end)
| "\(.i) \(.o)"' "$transcript" 2>/dev/null)
[ -n "$out" ] || return 0
TOK_IN=${out%% *}; TOK_OUT=${out##* }
}
# Model name with the "(1M context)"-style parenthetical stripped, effort/fast dim.
# fast_mode wins the label since it's the deliberate toggle.
#
# `model` is the live, currently-selected model (stdin .model.display_name), which the
# statusline docs define as the authoritative "current model" and which updates the
# instant a mid-session /model switch happens. That is what we display.
#
# We deliberately do NOT override it with the transcript's last-served model. The stdin
# JSON exposes no served-vs-selected signal, so the transcript is the only source of the
# served model — but the transcript lags the selection: right after the user switches
# (e.g. Sonnet→Opus) the last recorded turn is still the old model, and an override would
# render the stale label (`Sonnet 4.6 ↓`) over the model the user just chose. Since a
# genuine Opus→Sonnet cap fallback is byte-for-byte indistinguishable from that lag, we
# cannot tell them apart from the data, and showing the wrong model over a correct
# selection is the worse failure. Trust the selection.
seg_model() {
local m=${model%% (*} label="$effort" out
[ "$fast_mode" = "true" ] && label="fast"
[ -z "$m" ] && return
out="$m"
[ -n "$label" ] && out="$out ${DIM}${label}${RESET}"
printf '%s' "$out"
}
# Context: pct over the window size (15%/1M), pct colored by threshold, size dim — the
# size labels the segment, so no CTX tag is needed; fall back to one when size is
# unknown. Older clients without context_window: derive pct from the transcript vs 200K.
seg_context() {
local p="$pct" size="$ctx_size" used color sz
if [ -z "$p" ] && [ -n "$transcript" ] && [ -f "$transcript" ] && command -v jq >/dev/null 2>&1; then
# Forward read (fromjson? drops the partial final line a live session always has);
# take the last usage turn's occupancy. tail -r here would fuse that partial tail
# into the prior line and corrupt the JSON, blanking the segment.
used=$(jq -rRc 'fromjson? | select(.message.usage != null)
| .message.usage | ((.input_tokens // 0) + (.cache_creation_input_tokens // 0) + (.cache_read_input_tokens // 0))' \
"$transcript" 2>/dev/null | tail -1)
[ -n "$used" ] && [ "$used" != "null" ] && [ "$used" -gt 0 ] 2>/dev/null && { p=$(( used * 100 / 200000 )); size=200000; }
fi
p=${p%.*}; [ -z "$p" ] && p=0; [ "$p" -gt 100 ] && p=100
if [ "$p" -ge "$CONTEXT_RED" ]; then color=$RED
elif [ "$p" -ge "$CONTEXT_YELLOW" ]; then color=$YELLOW
else color=$RESET; fi
if [ "${size:-0}" -ge 1000 ] 2>/dev/null; then
sz=$(human "$size"); printf '%s%s%%%s%s/%s%s' "$color" "$p" "$RESET" "$DIM" "$sz" "$RESET"
else
printf '%s%s%%%s CTX' "$color" "$p" "$RESET"
fi
}
# Cost: current cost (spend since the last /clear) colored by threshold, with the
# total cost (dim) appended only once a /clear has split the two. total_cost_usd is
# cumulative over the CLI process; we reconstruct current by snapshotting it the first
# time we see a transcript (a /clear starts a fresh one) under ~/.claude/cost-baselines,
# keyed by session so parallel sessions never collide.
#
# Two "not ready" states show $0.00 untouched:
# - total null/empty or <= 0: client hasn't made its first API call yet.
# - transcript empty: session path unknown (brief window after /clear); without a keyed
# baseline there is no valid delta, and falling through with base=0 would leak the
# raw cumulative total as "session" cost.
seg_cost() {
local total="$cost_total" cur base="0" base_dir base_file color tier diverged
awk -v t="${total:-}" 'BEGIN{exit !(t=="" || t+0<=0)}' && { printf '%s$%.2f%s' "$RESET" 0 "$RESET"; return; }
[ -z "$transcript" ] && { printf '%s$%.2f%s' "$RESET" 0 "$RESET"; return; }
base_dir="$HOME/.claude/cost-baselines"; base_file="$base_dir/$(basename "$transcript" .jsonl)"
if [ -f "$base_file" ]; then
base=$(cat "$base_file" 2>/dev/null)
# Recapture when the stored baseline is unusable: a 0 poisoned by an earlier not-ready
# capture (heal), or a stale-high value from a resumed session whose cost counter
# restarted (clamp down, else the delta pins to 0 forever).
awk -v t="$total" -v b="${base:-0}" 'BEGIN{exit !(b+0<=0 || t+0 < b+0)}' \
&& { printf '%s' "$total" >"$base_file" 2>/dev/null; base="$total"; }
else
mkdir -p "$base_dir" 2>/dev/null; printf '%s' "$total" >"$base_file" 2>/dev/null; base="$total"
find "$base_dir" -type f -mtime +7 -delete 2>/dev/null # rare path: prune stale baselines
fi
# One awk derives all three: current (total - baseline, floored at 0), the color tier,
# and whether current and total have diverged enough to show both.
read -r cur tier diverged < <(awk -v t="$total" -v b="${base:-0}" -v y="$COST_YELLOW" -v r="$COST_RED" 'BEGIN{
d=t-b; if(d<0)d=0;
tier=(d>=r?"r":(d>=y?"y":"n"));
div=((t-d<0?d-t:t-d)>=0.005)?1:0;
printf "%.6f %s %d", d, tier, div}')
case "$tier" in r) color=$RED ;; y) color=$YELLOW ;; *) color=$RESET ;; esac
if [ "$diverged" = 1 ]; then
printf '%s$%.2f%s %s$%.2f%s' "$color" "$cur" "$RESET" "$DIM" "$total" "$RESET"
else
printf '%s$%.2f%s' "$color" "$cur" "$RESET"
fi
}
# Token throughput this session, from the scan_transcript pass: ↑ input (cache reads
# excluded, so it's the new input processed, not the cheap re-reads), ↓ output. Resets
# on /clear like the current cost, since a /clear starts a fresh transcript.
seg_tokens() {
{ [ "${TOK_IN:-0}" -gt 0 ] 2>/dev/null || [ "${TOK_OUT:-0}" -gt 0 ] 2>/dev/null; } || return
printf '%s↑%s ↓%s%s' "$DIM" "$(human "${TOK_IN:-0}")" "$(human "${TOK_OUT:-0}")" "$RESET"
}
# When sourced (by the test suite), stop here so only the helpers are defined.
(return 0 2>/dev/null) && return
# Single-pass parse: one jq emits every field as an @sh-quoted assignment we eval,
# instead of spawning a jq per field. Defaults first so set -u stays safe if jq fails.
input=$(cat)
cwd=""; model=""; cost_total=""; transcript=""; pct=""; ctx_size=""; effort=""; fast_mode="false"
TOK_IN=0; TOK_OUT=0
eval "$(jq -r '
@sh "cwd=\(.cwd // "")",
@sh "model=\(.model.display_name // "")",
@sh "cost_total=\(.cost.total_cost_usd // "")",
@sh "transcript=\(.transcript_path // "")",
@sh "pct=\(.context_window.used_percentage // "")",
@sh "ctx_size=\(.context_window.context_window_size // "")",
@sh "effort=\(.effort.level // "")",
@sh "fast_mode=\(.fast_mode // false)"
' <<<"$input" 2>/dev/null)"
# Scan the transcript once for token throughput, then collect every segment and join the
# non-empty ones with the dim middot.
scan_transcript
segs=("$(seg_location)" "$(seg_model)" "$(seg_context)" "$(seg_cost)" "$(seg_tokens)")
out=""
for p in "${segs[@]}"; do
[ -z "$p" ] && continue
[ -n "$out" ] && out="${out}${SEP}"
out="${out}${p}"
done
printf '%s' "$out"
#!/usr/bin/env bash
# Unit + behavior tests for statusline.sh. Pure bash, no external deps.
# Run: ./statusline.test.sh (exit 0 = all pass, 1 = failures)
#
# human() is tested directly by sourcing the script (it returns early when
# sourced). Everything else is black-box: feed JSON on stdin, assert the
# rendered line. HOME is redirected to a temp dir so the cost-baseline cache
# never touches the real one, and git cases run against throwaway repos.
set -u
HERE="$(cd "$(dirname "$0")" && pwd)"
SL="$HERE/statusline.sh"
ESC=$(printf '\033')
pass=0; fail=0
strip(){ sed "s/${ESC}\[[0-9;]*m//g"; } # drop ANSI for visible-text asserts
assert(){ # desc, got, want
if [ "$2" = "$3" ]; then pass=$((pass+1))
else fail=$((fail+1)); printf 'FAIL %s\n want: [%s]\n got: [%s]\n' "$1" "$3" "$2"; fi
}
contains(){ # desc, haystack, needle
case "$2" in *"$3"*) pass=$((pass+1)) ;;
*) fail=$((fail+1)); printf 'FAIL %s\n expected to contain: [%s]\n in: [%s]\n' "$1" "$3" "$2" ;; esac
}
TMPHOME=$(mktemp -d); FIX=""
trap 'rm -rf "$TMPHOME" ${FIX:+"$FIX"}' EXIT
render(){ HOME="$TMPHOME" bash "$SL" <<<"$1" | strip; } # visible text
render_raw(){ HOME="$TMPHOME" bash "$SL" <<<"$1"; } # with ANSI
# human(): number formatting
# Lowercase k, uppercase M, integer M drops the .0, sub-1000 stays raw.
h(){ ( source "$SL" >/dev/null 2>&1; human "$1" ); }
assert "human 0" "$(h 0)" "0"
assert "human 999" "$(h 999)" "999"
assert "human 1000" "$(h 1000)" "1k"
assert "human 12345" "$(h 12345)" "12k"
assert "human 200000" "$(h 200000)" "200k"
assert "human 999999" "$(h 999999)" "999k"
assert "human 1000000" "$(h 1000000)" "1M"
assert "human 1200000" "$(h 1200000)" "1.2M"
assert "human 1500000" "$(h 1500000)" "1.5M"
assert "human 8116275" "$(h 8116275)" "8.1M"
# model, context, cost (non-git cwd -> location falls back to basename)
NOGIT="$TMPHOME/nogit"; mkdir -p "$NOGIT"
base(){ printf '{"cwd":"%s","model":{"display_name":"%s"},"cost":{"total_cost_usd":%s}%s}' "$NOGIT" "$1" "$2" "$3"; }
assert "model parenthetical stripped, ctx size, cost collapsed" \
"$(render "$(base 'Opus 4.8 (1M context)' 1.11 ',"context_window":{"used_percentage":5,"context_window_size":1000000}')")" \
'nogit · Opus 4.8 · 5%/1M · $0.00'
assert "effort appended to model" \
"$(render '{"cwd":"'"$NOGIT"'","model":{"display_name":"Opus 4.8"},"effort":{"level":"high"},"cost":{"total_cost_usd":0},"context_window":{"used_percentage":5,"context_window_size":1000000}}')" \
'nogit · Opus 4.8 high · 5%/1M · $0.00'
assert "fast_mode wins the effort label" \
"$(render '{"cwd":"'"$NOGIT"'","model":{"display_name":"Opus 4.8"},"effort":{"level":"high"},"fast_mode":true,"cost":{"total_cost_usd":0},"context_window":{"used_percentage":5,"context_window_size":1000000}}')" \
'nogit · Opus 4.8 fast · 5%/1M · $0.00'
assert "200k window" \
"$(render "$(base 'Sonnet 4.6' 0 ',"context_window":{"used_percentage":42,"context_window_size":200000}')")" \
'nogit · Sonnet 4.6 · 42%/200k · $0.00'
assert "no window size falls back to CTX tag" \
"$(render "$(base 'X' 0 '')")" \
'nogit · X · 0% CTX · $0.00'
assert "pct over 100 clamps" \
"$(render "$(base 'X' 0 ',"context_window":{"used_percentage":150,"context_window_size":1000000}')")" \
'nogit · X · 100%/1M · $0.00'
assert "fractional pct truncates to whole" \
"$(render "$(base 'X' 0 ',"context_window":{"used_percentage":7.8,"context_window_size":1000000}')")" \
'nogit · X · 7%/1M · $0.00'
# context fallback: older clients omit context_window, so pct is derived from the last
# usage turn's occupancy over a 200K window. A live transcript's unterminated final line
# must not corrupt the read — forward fromjson?, not tail -r (which fused the partial tail
# into the prior line and blanked the segment). cache_read-only keeps the token segment
# silent so this isolates the occupancy path.
mkdir -p "$TMPHOME/cx"
{ printf '%s\n' '{"message":{"usage":{"cache_read_input_tokens":50000}}}'
printf '%s' '{"message":{"partial'; } > "$TMPHOME/cx/c.jsonl"
assert "context fallback derives pct over 200K, survives a partial final line" \
"$(render '{"cwd":"'"$NOGIT"'","model":{"display_name":"X"},"cost":{"total_cost_usd":0},"transcript_path":"'"$TMPHOME"'/cx/c.jsonl"}')" \
'nogit · X · 25%/200k · $0.00'
# model display: the segment always shows the live selected model (.model.display_name),
# which the docs define as the authoritative current model and which reflects a /model
# switch immediately. The transcript's last-served model must NOT override it — the
# stdin JSON gives no served-vs-selected signal, so a stale transcript turn (e.g. Sonnet
# recorded just before the user switched to Opus) is indistinguishable from an Opus→Sonnet
# cap, and overriding would render the wrong model over the user's own selection.
mkdir -p "$TMPHOME/mx"
mj(){ printf '{"cwd":"%s","model":{"display_name":"%s"},"cost":{"total_cost_usd":0},"context_window":{"used_percentage":1,"context_window_size":1000000},"transcript_path":"%s"}' "$NOGIT" "$1" "$2"; }
printf '%s\n' '{"message":{"model":"claude-sonnet-4-6","usage":{}}}' > "$TMPHOME/mx/fb.jsonl"
assert "selection wins over a stale/lower transcript model (no ↓ override)" \
"$(render "$(mj 'Opus 4.8' "$TMPHOME/mx/fb.jsonl")")" \
'nogit · Opus 4.8 · 1%/1M · $0.00'
printf '%s\n' '{"message":{"model":"claude-opus-4-8","usage":{}}}' > "$TMPHOME/mx/match.jsonl"
assert "selection shown when transcript matches it" \
"$(render "$(mj 'Opus 4.8' "$TMPHOME/mx/match.jsonl")")" \
'nogit · Opus 4.8 · 1%/1M · $0.00'
{ printf '%s\n' '{"message":{"model":"claude-opus-4-8","usage":{}}}'
printf '%s\n' '{"isSidechain":true,"message":{"model":"claude-sonnet-4-6","usage":{}}}'
} > "$TMPHOME/mx/side.jsonl"
assert "selection shown regardless of a sidechain turn" \
"$(render "$(mj 'Opus 4.8' "$TMPHOME/mx/side.jsonl")")" \
'nogit · Opus 4.8 · 1%/1M · $0.00'
{ printf '%s\n' '{"message":{"model":"claude-opus-4-8","usage":{}}}'
printf '%s\n' '{"message":{"model":"<synthetic>","usage":{}}}'
} > "$TMPHOME/mx/synth.jsonl"
assert "selection shown regardless of a synthetic turn" \
"$(render "$(mj 'Opus 4.8' "$TMPHOME/mx/synth.jsonl")")" \
'nogit · Opus 4.8 · 1%/1M · $0.00'
# cost: capture, divergence, threshold color, and the not-ready/heal guards
cb="$TMPHOME/.claude/cost-baselines"; mkdir -p "$cb"
costj(){ printf '{"cwd":"%s","model":{"display_name":"X"},"cost":{"total_cost_usd":%s},"context_window":{"used_percentage":1,"context_window_size":1000000},"transcript_path":"/none/%s.jsonl"}' "$NOGIT" "$1" "$2"; }
# cost omitted entirely: the client reports null before its first API response (on a fresh
# session and, transiently, mid-render), so total is "not ready" this pass.
costj_null(){ printf '{"cwd":"%s","model":{"display_name":"X"},"context_window":{"used_percentage":1,"context_window_size":1000000},"transcript_path":"/none/%s.jsonl"}' "$NOGIT" "$1"; }
printf '5.61' > "$cb/dv"; assert "diverged shows current then total" \
"$(render "$(costj 7.71 dv)")" 'nogit · X · 1%/1M · $2.10 $7.71'
printf '5.61' > "$cb/dim"; contains "diverged total is dim" \
"$(render_raw "$(costj 7.71 dim)")" "${ESC}[2m\$7.71"
printf '1' > "$cb/yl"; contains "current >= 20 turns yellow" \
"$(render_raw "$(costj 26.00 yl)")" "${ESC}[38;2;195;163;105m\$25.00"
printf '1' > "$cb/rd"; contains "current >= 50 turns red" \
"$(render_raw "$(costj 61.00 rd)")" "${ESC}[38;2;190;92;99m\$60.00"
# not-ready: cost is cumulative over the CLI process, so a baseline captured before the
# client reports cost freezes at 0 and makes the session report the whole process spend,
# not this window's. A null reading must show $0.00 and capture nothing.
assert "cost null shows current \$0.00" \
"$(render "$(costj_null nr)")" 'nogit · X · 1%/1M · $0.00'
assert "cost null captures no baseline" \
"$([ -e "$cb/nr" ] && echo yes || echo no)" 'no'
# Once cost populates, the first populated reading becomes the baseline (this window has
# spent ~nothing), so current is $0.00 and the dim cumulative rides alongside.
assert "first populated reading captures the cumulative as baseline" \
"$(render "$(costj 158.35 nr)")" 'nogit · X · 1%/1M · $0.00 $158.35'
assert "baseline written at the first populated total" "$(cat "$cb/nr")" '158.35'
contains "window spend then grows from the captured baseline" \
"$(render "$(costj 158.53 nr)")" '$0.18'
# no-transcript: cost_total is set but transcript_path is absent (the brief window after
# /clear before the new transcript is established). Must not bleed the process total
# through as "session" cost — floor to $0.00, same as the not-ready case.
assert "positive cost with no transcript floors to zero" \
"$(render "$(base 'X' 27.53 ',"context_window":{"used_percentage":1,"context_window_size":1000000}')")" \
'nogit · X · 1%/1M · $0.00'
# clobber guard: a transient null reading must not overwrite a good baseline. Parsed as 0
# by the old code, it tripped the resume-clamp (0 < base) and reset the baseline, so the
# next populated render reported the whole cumulative as "current".
printf '158.17' > "$cb/keep"; assert "null reading shows current \$0.00" \
"$(render "$(costj_null keep)")" 'nogit · X · 1%/1M · $0.00'
assert "null reading leaves the baseline untouched" "$(cat "$cb/keep")" '158.17'
contains "next populated render reports window spend, not the cumulative" \
"$(render "$(costj 158.35 keep)")" '$0.18'
# heal: a baseline already frozen at 0 (poisoned by the old bug) recaptures on the next
# populated render instead of reporting the whole cumulative forever.
printf '0' > "$cb/heal"; assert "stored-0 baseline heals to window \$0.00" \
"$(render "$(costj 158.35 heal)")" 'nogit · X · 1%/1M · $0.00 $158.35'
assert "healed baseline rewritten to the current total" "$(cat "$cb/heal")" '158.35'
# A resumed session reports a lower total than the stored baseline (cost counter
# restarts). Without clamping, cur = total - base floors at 0 forever. The baseline
# must clamp down to the current total so the delta resets and grows from there.
printf '20' > "$cb/clamp"; contains "stale-high baseline shows 0, not negative" \
"$(render "$(costj 5.5 clamp)")" '$0.00'
assert "baseline clamped down to current total" "$(cat "$cb/clamp")" "5.5"
contains "delta grows from the clamped baseline" \
"$(render "$(costj 8.5 clamp)")" '$3.00'
# token throughput: cache reads excluded, human-formatted
mkdir -p "$TMPHOME/tx"
{ printf '%s\n' '{"message":{"usage":{"input_tokens":1000,"cache_creation_input_tokens":500,"cache_read_input_tokens":40000,"output_tokens":2000}}}'
printf '%s\n' '{"message":{"usage":{"input_tokens":1000,"cache_read_input_tokens":45000,"output_tokens":3000}}}'
} > "$TMPHOME/tx/t.jsonl"
assert "token in (no cache reads) and out, human-formatted" \
"$(render '{"cwd":"'"$NOGIT"'","model":{"display_name":"X"},"cost":{"total_cost_usd":0},"context_window":{"used_percentage":1,"context_window_size":1000000},"transcript_path":"'"$TMPHOME"'/tx/t.jsonl"}')" \
'nogit · X · 1%/1M · $0.00 · ↑2k ↓5k'
# git: project / worktree / branch as optional folded segments
FIX=$(mktemp -d)
git init -q "$FIX/proj"
( cd "$FIX/proj"
git config user.email t@t; git config user.name t; git config commit.gpgsign false
git checkout -q -b main; mkdir sub; printf x > sub/f; git add .; git commit -qm init
git worktree add -q "$FIX/wt-feat" -b feat >/dev/null 2>&1 # name != branch
git worktree add -q "$FIX/mybr" -b mybr >/dev/null 2>&1 ) # name == branch
gitj(){ printf '{"cwd":"%s","model":{"display_name":"X"},"cost":{"total_cost_usd":0}}' "$1"; }
loc(){ render "$(gitj "$1")"; } # project leads; below the root, the cwd basename rides dim on it
assert "main checkout root: project · branch" "$(loc "$FIX/proj")" 'proj · main · X · 0% CTX · $0.00'
assert "main checkout subdir shows project sub" "$(loc "$FIX/proj/sub")" 'proj sub · main · X · 0% CTX · $0.00'
assert "worktree, name != branch" "$(loc "$FIX/wt-feat")" 'proj · wt-feat · feat · X · 0% CTX · $0.00'
assert "worktree subdir rides dim on project" "$(loc "$FIX/wt-feat/sub")" 'proj sub · wt-feat · feat · X · 0% CTX · $0.00'
assert "worktree, name == branch folds to one" "$(loc "$FIX/mybr")" 'proj · mybr · X · 0% CTX · $0.00'
assert "worktree subdir, name == branch: no double" "$(loc "$FIX/mybr/sub")" 'proj sub · mybr · X · 0% CTX · $0.00'
# the subdir basename is dim, mirroring model + effort
contains "subdir basename renders dim" \
"$(render_raw "$(gitj "$FIX/proj/sub")")" "proj ${ESC}[2msub${ESC}[0m"
# nested cwd shows only the deepest component (basename, not the full relative path)
mkdir -p "$FIX/proj/sub/deep"
assert "nested subdir shows the leaf basename only" \
"$(loc "$FIX/proj/sub/deep")" 'proj deep · main · X · 0% CTX · $0.00'
# fold collision: repo dir name == branch name, viewed dirty from a subdir. The subdir and
# the dirty marker must both survive — each attach-condition builds on the prior segment,
# not from the bare name (else the branch suffix would clobber the subdir).
git init -q "$FIX/main"
( cd "$FIX/main"
git config user.email t@t; git config user.name t; git config commit.gpgsign false
git checkout -q -b main; mkdir sub; printf x > sub/f; git add .; git commit -qm init
printf y >> sub/f ) # dirty
assert "dir == branch collision keeps both subdir and dirty marker" \
"$(loc "$FIX/main/sub")" 'main sub* · X · 0% CTX · $0.00'
# git: dirty + ahead/behind state, placement after fold
printf y >> "$FIX/proj/sub/f" # dirty the main checkout (tracked file)
assert "dirty marks the branch segment" "$(loc "$FIX/proj")" 'proj · main* · X · 0% CTX · $0.00'
printf z >> "$FIX/mybr/sub/f" # dirty a name==branch worktree, viewed from a subdir
assert "folded name carries the dirty state on the kept copy" \
"$(loc "$FIX/mybr/sub")" 'proj sub · mybr* · X · 0% CTX · $0.00'
# ahead/behind against an upstream
git init -q --bare "$FIX/remote.git"
( cd "$FIX/proj"
git checkout -q -- sub/f 2>/dev/null # drop the dirty edit so arrows test is clean
git remote add origin "$FIX/remote.git"
git push -q -u origin main >/dev/null 2>&1
printf a >> sub/f; git commit -qam ahead1 ) # 1 ahead of origin/main
assert "ahead of upstream shows ↑" "$(loc "$FIX/proj")" 'proj · main ↑1 · X · 0% CTX · $0.00'
( cd "$FIX/proj"
git reset -q --hard origin/main # back in sync
printf b >> sub/f; git commit -qam tmp; git push -q origin main
git reset -q --hard HEAD~1 ) # local now 1 behind origin/main
assert "behind upstream shows ↓" "$(loc "$FIX/proj")" 'proj · main ↓1 · X · 0% CTX · $0.00'
# diverged: a local commit on top of the behind state → both arrows, ahead before behind
( cd "$FIX/proj"; printf c >> sub/f; git commit -qam local ) # now 1 ahead AND 1 behind
assert "diverged shows ↑ then ↓" "$(loc "$FIX/proj")" 'proj · main ↑1 ↓1 · X · 0% CTX · $0.00'
# dirty combined with arrows: the * leads, arrows follow, all in one dim suffix
printf d >> "$FIX/proj/sub/f"
assert "dirty and arrows compose in order" "$(loc "$FIX/proj")" 'proj · main* ↑1 ↓1 · X · 0% CTX · $0.00'
# detached HEAD: symbolic-ref fails, so the branch falls back to the short sha
git init -q -b main "$FIX/det"
( cd "$FIX/det"
git config user.email t@t; git config user.name t; git config commit.gpgsign false
printf x > f; git add .; git commit -qm a; git checkout -q --detach HEAD )
dsha=$(git -C "$FIX/det" rev-parse --short HEAD)
assert "detached HEAD shows the short sha" "$(loc "$FIX/det")" "det · $dsha · X · 0% CTX · \$0.00"
# bare-repo worktree: git-dir is proj.git/worktrees/wt (no literal /.git/), so the project
# name comes from stripping the trailing .git, not a /.git/ component.
git clone -q --bare "$FIX/proj" "$FIX/bare.git" >/dev/null 2>&1
git -C "$FIX/bare.git" worktree add -q "$FIX/barewt" -b bw >/dev/null 2>&1
assert "bare-repo worktree resolves the project name" "$(loc "$FIX/barewt")" 'bare · barewt · bw · X · 0% CTX · $0.00'
# $HOME is itself a repo root: the ~ marker is kept rather than overwritten by the repo name
git init -q -b main "$FIX/homerepo"
homej(){ printf '{"cwd":"%s","model":{"display_name":"X"},"cost":{"total_cost_usd":0}}' "$FIX/homerepo"; }
assert "HOME as repo root keeps ~" \
"$(HOME="$FIX/homerepo" bash "$SL" <<<"$(homej)" | strip)" '~ · main · X · 0% CTX · $0.00'
# summary
total=$((pass + fail))
printf '\n%d/%d passed' "$pass" "$total"
[ "$fail" -eq 0 ] && { printf ' — all green\n'; exit 0; } || { printf ' — %d FAILED\n' "$fail"; exit 1; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment