dotfiles/claude/statusline.original.sh
Jonny Barnes 644c52d4b4
Switch Claude Code statusline to burnrate variant
Keep the previous statusline as statusline.original.sh and add
statusline.burnrate.sh from Gui-Gou/claude-statusline-burnrate, which
shows weekly/5h plan usage and a sustainable burn rate.

bootstrap.sh now links the burnrate script unconditionally - the old
`test -L` guard would have left an existing symlink pointing at the
previous script. jq is a hard dependency of the new script, so add it
to brew.sh.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 14:40:40 +01:00

150 lines
4.8 KiB
Shell
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Status line command for Claude Code
# Two-line display:
# Line 1: [Opus 4.6] 📁 project-name | 🌿 branch
# Line 2: █████░░░░░ 42% | 19.8k tok | ✅ Max | ⏱️ 7m 3s (API thinking time, not wall-clock)
# Read JSON input from Claude Code
input=$(cat)
# Debug mode: set CLAUDE_STATUSLINE_DEBUG=1 to dump JSON input
if [ -n "$CLAUDE_STATUSLINE_DEBUG" ]; then
echo "$input" | jq '.' > /tmp/claude-statusline-debug.json 2>/dev/null
fi
# Extract data from JSON (single jq call for performance)
eval "$(echo "$input" | jq -r '
@sh "cwd=\(.workspace.current_dir)",
@sh "model_display=\(.model.display_name)",
@sh "model_id=\(.model.id)",
@sh "used_pct_raw=\(.context_window.used_percentage // 0)",
@sh "total_input=\(.context_window.total_input_tokens // 0)",
@sh "total_output=\(.context_window.total_output_tokens // 0)",
@sh "duration_ms=\(.cost.total_api_duration_ms // 0)",
@sh "total_cost=\(.cost.total_cost_usd // 0)"
')"
dir_name=$(basename "$cwd")
# Truncate percentage to integer
used_pct=${used_pct_raw%%.*}
: "${used_pct:=0}"
# Use display_name directly — it already includes the version (e.g. "Opus 4.6")
# Only extract from model_id as fallback if display_name has no version
if [[ "$model_display" =~ [0-9] ]]; then
model_full="$model_display"
else
version=""
if [[ "$model_id" =~ claude-[a-z]+-([0-9]+)-([0-9]+) ]]; then
version="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
fi
if [ -n "$version" ]; then
model_full="$model_display $version"
else
model_full="$model_display"
fi
fi
# Git branch with caching (5 second TTL)
git_branch=""
cache_dir="/tmp/claude-statusline"
cache_file="${cache_dir}/git-branch-$(echo "$cwd" | md5 -q)"
cache_ttl=5
if git -C "$cwd" rev-parse --git-dir > /dev/null 2>&1; then
now=$(date +%s)
file_mtime=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null || echo 0)
cache_age=$((now - file_mtime))
if [ -f "$cache_file" ] && [ "$cache_age" -lt "$cache_ttl" ]; then
git_branch=$(cat "$cache_file")
else
git_branch=$(git -C "$cwd" branch --show-current 2>/dev/null || echo 'detached')
mkdir -p "$cache_dir" && echo "$git_branch" > "$cache_file"
fi
fi
# Format tokens (pure bash integer math)
total_tokens=$(( ${total_input%%.*} + ${total_output%%.*} ))
if [ "$total_tokens" -ge 1000000 ]; then
whole=$((total_tokens / 1000000))
frac=$(( (total_tokens % 1000000) / 100000 ))
token_display="${whole}.${frac}M tok"
elif [ "$total_tokens" -ge 1000 ]; then
whole=$((total_tokens / 1000))
frac=$(( (total_tokens % 1000) / 100 ))
if [ "$whole" -ge 100 ]; then
token_display="${whole}k tok"
else
token_display="${whole}.${frac}k tok"
fi
else
token_display="${total_tokens} tok"
fi
# Billing mode detection (cached 60s)
billing_cache="/tmp/.claude-statusline-billing-cache"
billing_ttl=60
billing_mode=""
now_bill=$(date +%s)
bill_mtime=$(stat -c %Y "$billing_cache" 2>/dev/null || stat -f %m "$billing_cache" 2>/dev/null || echo 0)
bill_age=$((now_bill - bill_mtime))
if [ -f "$billing_cache" ] && [ "$bill_age" -lt "$billing_ttl" ]; then
billing_mode=$(cat "$billing_cache")
else
if security find-generic-password -s "Claude Code-credentials" >/dev/null 2>&1; then
billing_mode="max"
elif [ -n "$ANTHROPIC_API_KEY" ]; then
billing_mode="api"
else
billing_mode="unknown"
fi
echo "$billing_mode" > "$billing_cache"
fi
if [ "$billing_mode" = "max" ]; then
billing_display='\e[32m✅ Max\e[0m'
elif [ "$billing_mode" = "api" ]; then
billing_display='\e[1;31m⚠ API\e[0m'
else
billing_display='\e[33m? Auth\e[0m'
fi
# Format cost
cost_display=$(printf '$%.2f' "$total_cost")
# Format duration from milliseconds
duration_sec=$((${duration_ms%%.*} / 1000))
duration_min=$((duration_sec / 60))
duration_rem=$((duration_sec % 60))
# Build progress bar (10 chars wide)
filled=$((used_pct * 10 / 100))
empty=$((10 - filled))
# Color-code based on usage
if [ "$used_pct" -lt 70 ]; then
bar_color='\e[32m' # Green
elif [ "$used_pct" -lt 90 ]; then
bar_color='\e[33m' # Yellow
else
bar_color='\e[31m' # Red
fi
bar=""
for ((i=0; i<filled; i++)); do bar="${bar}"; done
for ((i=0; i<empty; i++)); do bar="${bar}"; done
# Line 1: [Opus 4.6] 📁 project-name | 🌿 branch
printf '\e[36m[%s]\e[0m 📁 %s' "$model_full" "$dir_name"
if [ -n "$git_branch" ]; then
printf ' \e[2m|\e[0m 🌿 %s' "$git_branch"
fi
printf '\n'
# Line 2: █████░░░░░ 42% | 19.8k tok | $1.23 | ✅ Max | ⏱️ 7m 3s
printf '%b%s\e[0m %d%% \e[2m|\e[0m \e[36m%s\e[0m \e[2m|\e[0m \e[33m%s\e[0m \e[2m|\e[0m %b \e[2m|\e[0m ⏱️ %dm %ds' \
"$bar_color" "$bar" "$used_pct" "$token_display" "$cost_display" "$billing_display" "$duration_min" "$duration_rem"