ebccdda936
A chezmoi-based fleet-dotfiles template for macOS workstations: - Two-way auto-sync via launchd watcher + 5-min puller - Mesh SSH via modify_authorized_keys driven by .chezmoidata/fleet.yaml - age-encrypted secrets file - Bundled Claude Code agentic team (11 agents) + /lite + /lite-sub commands - Verify-before-claiming Stop hook - Generic statusline + project-boundary validate-path hook - Reference launchd plist for cross-fleet task-durations aggregation (companion repo: gitea.tojo.team/cardinale/task-durations) - AGENTS.md walks an agent through the entire setup Q&A interactively - docs/ covers architecture, security model, fleet onboarding
142 lines
5.0 KiB
Bash
142 lines
5.0 KiB
Bash
#!/bin/sh
|
||
# Claude Code statusLine script
|
||
# Format: user@host /path/base | Model ·effort | ctx:N% | 5h:N%→proj% 7d:N%→proj%
|
||
#
|
||
# The arrow/projection for 5h and 7d rate limits is a "quota pacer":
|
||
# - current usage % → projected final usage % (based on current burn rate)
|
||
# - color reflects projected exhaustion risk:
|
||
# green = projected ≤ 80% (safe)
|
||
# yellow = projected 80–100% (warning)
|
||
# red = projected > 100% (will exhaust before reset)
|
||
# - no projection shown until ≥5% of the window has elapsed (avoids noise)
|
||
#
|
||
# The effort meter shows the current reasoning effort level (low/med/high/max/auto).
|
||
# Source priority: $CLAUDE_CODE_EFFORT_LEVEL env var > .effortLevel in
|
||
# ~/.claude/settings.json. Omitted if neither is set. Note: /effort max does
|
||
# not persist to settings.json, so it will only appear if the env var is set.
|
||
|
||
input=$(cat)
|
||
user=$(whoami)
|
||
host=$(hostname -s)
|
||
dir=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // "?"')
|
||
base=$(basename "$dir")
|
||
parent=$(dirname "$dir")
|
||
if [ "$parent" = "/" ]; then
|
||
parent_prefix="/"
|
||
else
|
||
parent_prefix="$parent/"
|
||
fi
|
||
model=$(echo "$input" | jq -r '.model.display_name // "Claude"' | sed -E 's/\([^)]*1M[^)]*\)/(1M)/')
|
||
|
||
ctx_used=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
|
||
|
||
five_used=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
|
||
five_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
|
||
week_used=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
|
||
week_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
|
||
|
||
now=$(date +%s)
|
||
|
||
# Compute a pacer fragment: "label:NN%→MM%" with the arrow+projection colored
|
||
# by risk. Prints only the label+current if not enough data to project.
|
||
# If unit="m", appends " (Nm)" (minutes until reset) in dim gray.
|
||
# If unit="d", appends " (N.Nd)" (days until reset, one decimal) in dim gray.
|
||
# If unit="" (or anything else), no time suffix.
|
||
#
|
||
# Args: label, used%, resets_at_epoch, window_seconds, unit ("m"|"d"|"")
|
||
pacer() {
|
||
label="$1"
|
||
u="$2"
|
||
reset="$3"
|
||
window="$4"
|
||
unit="$5"
|
||
|
||
if [ -z "$u" ]; then
|
||
return
|
||
fi
|
||
if [ -z "$reset" ] || [ "$reset" = "null" ]; then
|
||
printf " %s:%.0f%%" "$label" "$u"
|
||
return
|
||
fi
|
||
|
||
awk -v label="$label" -v u="$u" -v reset="$reset" -v window="$window" -v now="$now" -v unit="$unit" 'BEGIN {
|
||
start = reset - window
|
||
elapsed = now - start
|
||
if (elapsed < 1) elapsed = 1
|
||
elapsed_pct = (elapsed / window) * 100
|
||
|
||
time_suffix = ""
|
||
if (unit == "m") {
|
||
mins_left = int((reset - now) / 60)
|
||
if (mins_left < 0) mins_left = 0
|
||
time_suffix = sprintf(" \033[0;90m(%dm)\033[0m", mins_left)
|
||
} else if (unit == "d") {
|
||
days_left = (reset - now) / 86400
|
||
if (days_left < 0) days_left = 0
|
||
time_suffix = sprintf(" \033[0;90m(%.1fd)\033[0m", days_left)
|
||
}
|
||
|
||
# Not enough data yet: show current only.
|
||
# 5% for short windows (5h → 15min blackout); 1% for the 7d window
|
||
# (drops blackout from 8.4h to 1.7h while keeping early projections sane).
|
||
threshold = (unit == "d") ? 1 : 5
|
||
if (elapsed_pct < threshold) {
|
||
printf " %s:%.0f%%%s", label, u, time_suffix
|
||
exit
|
||
}
|
||
|
||
# Burn rate per % of elapsed time, projected to end of window
|
||
burn = u / elapsed_pct
|
||
projected = u + (burn * (100 - elapsed_pct))
|
||
|
||
if (projected > 100) {
|
||
color = "0;31" # red — will exhaust
|
||
} else if (projected > 80) {
|
||
color = "0;33" # yellow — warning
|
||
} else {
|
||
color = "0;32" # green — safe
|
||
}
|
||
|
||
printf " %s:%.0f%%\033[%sm→%.0f%%\033[0m%s", label, u, color, projected, time_suffix
|
||
}'
|
||
}
|
||
|
||
# Effort level: env var wins, then settings.json, otherwise omit.
|
||
effort=""
|
||
if [ -n "$CLAUDE_CODE_EFFORT_LEVEL" ]; then
|
||
effort="$CLAUDE_CODE_EFFORT_LEVEL"
|
||
elif [ -f "$HOME/.claude/settings.json" ]; then
|
||
effort=$(jq -r '.effortLevel // empty' "$HOME/.claude/settings.json" 2>/dev/null)
|
||
fi
|
||
|
||
# No space between model and · when model already ends with ")",
|
||
# otherwise use a single space separator.
|
||
case "$model" in
|
||
*")") eff_sep="" ;;
|
||
*) eff_sep=" " ;;
|
||
esac
|
||
|
||
effort_part=""
|
||
case "$effort" in
|
||
low) effort_part=$(printf "%s\033[0;90m·low\033[0m" "$eff_sep") ;;
|
||
medium) effort_part=$(printf "%s\033[0;32m·med\033[0m" "$eff_sep") ;;
|
||
high) effort_part=$(printf "%s\033[0;33m·high\033[0m" "$eff_sep") ;;
|
||
max) effort_part=$(printf "%s\033[1;35m·max\033[0m" "$eff_sep") ;;
|
||
auto) effort_part=$(printf "%s\033[0;36m·auto\033[0m" "$eff_sep") ;;
|
||
esac
|
||
|
||
ctx_part=""
|
||
if [ -n "$ctx_used" ]; then
|
||
ctx_part=$(printf " | ctx:%.0f%%" "$ctx_used")
|
||
fi
|
||
|
||
rate_part=""
|
||
if [ -n "$five_used" ] || [ -n "$week_used" ]; then
|
||
rate_part=" |"
|
||
rate_part="${rate_part}$(pacer 5h "$five_used" "$five_reset" 18000 m)"
|
||
rate_part="${rate_part}$(pacer 7d "$week_used" "$week_reset" 604800 d)"
|
||
fi
|
||
|
||
printf "\033[1;32m%s@%s\033[0m \033[0;90m%s\033[0m\033[1;34m%s\033[0m | \033[0;33m%s\033[0m%s%s%s" \
|
||
"$user" "$host" "$parent_prefix" "$base" "$model" "$effort_part" "$ctx_part" "$rate_part"
|