Add claude statusline to my dotfiles

This commit is contained in:
Jonny Barnes 2026-03-28 16:51:14 +00:00
commit f9e4c65001
No known key found for this signature in database
2 changed files with 154 additions and 0 deletions

View file

@ -41,6 +41,10 @@ test -L $HOME/.config/nvim/init.lua || ln -f -s $BASEDIR/neovim/init.lua $HOME/.
test -d $HOME/.config/nvim/lsp || mkdir -p $HOME/.config/nvim/lsp
test -L $HOME/.config/nvim/lsp/phpactor.lua || ln -f -s $BASEDIR/neovim/lsp/phpactor.lua $HOME/.config/nvim/lsp/phpactor.lua
# Claude Code statusline
test -d $HOME/.claude || mkdir $HOME/.claude
test -L $HOME/.claude/statusline.sh || ln -f -s $BASEDIR/claude/statusline.sh $HOME/.claude/statusline.sh
# .gitconfig gets edited by .extra so we won't symlink it, but copy it
echo "For compatibility we shall copy the global gitconfig"
cp $BASEDIR/gitconfig $HOME/.gitconfig

150
claude/statusline.sh Executable file
View file

@ -0,0 +1,150 @@
#!/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"