Created
June 26, 2026 13:40
-
-
Save vilaca/2b8b2d6b819e4106d2e219ff3b34e4d5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/zsh | |
| input=$(cat) | |
| dir=$(echo "$input" | jq -r '.workspace.current_dir // .cwd') | |
| model=$(echo "$input" | jq -r '.model.display_name // empty') | |
| remaining=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty') | |
| cost=$(echo "$input" | jq -r '.cost.total_cost_usd // empty') | |
| transcript=$(echo "$input" | jq -r '.transcript_path // empty') | |
| # Message count - needed early for /clear detection | |
| msgs="" | |
| cache_pct="" | |
| if [ -n "$transcript" ] && [ -f "$transcript" ]; then | |
| msgs=$(wc -l < "$transcript" | tr -d ' ') | |
| cache_pct=$(tac "$transcript" 2>/dev/null | jq -r 'select(.message.usage) | .message.usage | (.cache_read_input_tokens // 0) as $r | (.cache_creation_input_tokens // 0) as $w | (.input_tokens // 0) as $i | if ($r + $w + $i) > 0 then (100 * $r / ($r + $w + $i)) | floor else empty end' 2>/dev/null | head -1) | |
| fi | |
| # Per-turn cost: delta of cumulative cost since last invocation, stashed per session | |
| # Also tracks a cost_baseline reset when /clear is detected (message count drops sharply) | |
| turn_cost="" | |
| cost_since_clear="" | |
| if [ -n "$cost" ] && [ -n "$transcript" ]; then | |
| session_id=$(basename "$transcript" .jsonl) | |
| cache_file="/tmp/claude-statusline-${session_id}.cost" | |
| prev_total=0 | |
| last_turn=0 | |
| prev_msgs=0 | |
| cost_baseline=0 | |
| if [ -f "$cache_file" ]; then | |
| read -r prev_total last_turn prev_msgs cost_baseline < "$cache_file" | |
| prev_total=${prev_total:-0} | |
| last_turn=${last_turn:-0} | |
| prev_msgs=${prev_msgs:-0} | |
| cost_baseline=${cost_baseline:-0} | |
| fi | |
| # Detect /clear: message count dropped to less than half of previous (and prev was meaningful) | |
| if [ -n "$msgs" ] && [ "$prev_msgs" -gt 5 ] 2>/dev/null; then | |
| half_prev=$(awk -v p="$prev_msgs" 'BEGIN{printf "%d", p/2}') | |
| if [ "$msgs" -lt "$half_prev" ] 2>/dev/null; then | |
| cost_baseline="$cost" | |
| last_turn=0 | |
| fi | |
| fi | |
| # Update only when cumulative cost has grown (a turn completed) | |
| delta=$(awk -v a="$cost" -v b="$prev_total" 'BEGIN{printf "%.6f", a-b}') | |
| if awk -v d="$delta" 'BEGIN{exit !(d > 0.0001)}'; then | |
| last_turn="$delta" | |
| printf "%s %s %s %s\n" "$cost" "$last_turn" "${msgs:-$prev_msgs}" "$cost_baseline" > "$cache_file" | |
| else | |
| printf "%s %s %s %s\n" "$prev_total" "$last_turn" "${msgs:-$prev_msgs}" "$cost_baseline" > "$cache_file" | |
| fi | |
| turn_cost="$last_turn" | |
| cost_since_clear=$(awk -v a="$cost" -v b="$cost_baseline" 'BEGIN{printf "%.6f", a-b}') | |
| fi | |
| # Git info (skip optional lock to avoid conflicts) | |
| branch="" | |
| dirty="" | |
| ahead_behind="" | |
| worktree="" | |
| if git -C "$dir" rev-parse --git-dir > /dev/null 2>&1; then | |
| branch=$(git -C "$dir" --no-optional-locks symbolic-ref --short HEAD 2>/dev/null) | |
| if [ -n "$(git -C "$dir" --no-optional-locks status --porcelain 2>/dev/null)" ]; then | |
| dirty="*" | |
| fi | |
| ab=$(git -C "$dir" --no-optional-locks rev-list --left-right --count '@{upstream}...HEAD' 2>/dev/null) | |
| if [ -n "$ab" ]; then | |
| behind=$(echo "$ab" | awk '{print $1}') | |
| ahead=$(echo "$ab" | awk '{print $2}') | |
| [ "$ahead" -gt 0 ] 2>/dev/null && ahead_behind="$ahead_behind⇡$ahead" | |
| [ "$behind" -gt 0 ] 2>/dev/null && ahead_behind="$ahead_behind⇣$behind" | |
| fi | |
| # .git is a file (not dir) when inside a worktree | |
| gitpath=$(git -C "$dir" rev-parse --git-dir 2>/dev/null) | |
| case "$gitpath" in | |
| *.git/worktrees/*) worktree=" (wt)" ;; | |
| esac | |
| fi | |
| # Build the status line | |
| printf "\033[33m%s\033[0m" "$dir" | |
| if [ -n "$branch" ]; then | |
| printf " \033[32m(%s%s%s)\033[0m" "$branch" "$dirty" "$ahead_behind" | |
| fi | |
| if [ -n "$worktree" ]; then | |
| printf " \033[36m%s\033[0m" "$worktree" | |
| fi | |
| if [ -n "$model" ]; then | |
| printf " \033[35m[%s]\033[0m" "$model" | |
| fi | |
| if [ -n "$remaining" ]; then | |
| printf " \033[90mctx:%s%%\033[0m" "$(printf '%.0f' "$remaining")" | |
| fi | |
| if [ -n "$msgs" ]; then | |
| if [ "$msgs" -gt 300 ] 2>/dev/null; then | |
| color="31" | |
| elif [ "$msgs" -gt 150 ] 2>/dev/null; then | |
| color="33" | |
| else | |
| color="90" | |
| fi | |
| printf " \033[%smmsgs:%s\033[0m" "$color" "$msgs" | |
| fi | |
| if [ -n "$cache_pct" ]; then | |
| printf " \033[90mcache:%s%%\033[0m" "$cache_pct" | |
| fi | |
| if [ -n "$turn_cost" ] && awk -v t="$turn_cost" 'BEGIN{exit !(t > 0)}'; then | |
| printf " \033[90mΔ\$%s\033[0m" "$(awk -v t="$turn_cost" 'BEGIN{printf "%.3f", t}')" | |
| fi | |
| if [ -n "$cost_since_clear" ] && awk -v c="$cost_since_clear" 'BEGIN{exit !(c >= 0)}'; then | |
| printf " \033[90m\$%s\033[0m" "$(awk -v c="$cost_since_clear" 'BEGIN{printf "%.2f", c}')" | |
| elif [ -n "$cost" ]; then | |
| printf " \033[90m\$%s\033[0m" "$(printf '%.2f' "$cost")" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment