Two layers with a deliberate privilege split: setup.sh does the root work (apt, rustup, cargo tools, starship, chsh) and hands off to chezmoi, which owns everything under $HOME. Tools are built with `cargo install --locked` to match the versions currently running rather than whatever apt ships, at the cost of a 10-20 min cold setup. Excluded on purpose: the atuin sync key and ~/.git-credentials (secrets), ~/.claude/settings.json (per-box decision), fnm/opencode conf.d (out of scope), and fish_variables (machine-local). chezmoi tracks only the executable and private attributes and derives modes from the umask, so setup.sh pins umask 022 and atuin uses private_ to keep 0700/0600. Without both, a 002 umask silently relaxes them to 0775/0664. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
144 lines
5.0 KiB
Bash
144 lines
5.0 KiB
Bash
#!/usr/bin/env bash
|
|
# Claude Code status line - based on PS1 from ~/.bashrc
|
|
# Format: user@host:cwd | model | ctx: X% | 5h:X%↻Y | 7d:X%↻Y [CAVEMAN]
|
|
|
|
input=$(cat)
|
|
|
|
# Normalize reset timestamp: epoch int -> "@<epoch>", ISO string -> as-is
|
|
norm_ts() {
|
|
local v=$1
|
|
[ -z "$v" ] || [ "$v" = "null" ] && return
|
|
case "$v" in
|
|
''|*[!0-9]*) printf '%s' "$v" ;; # non-numeric => ISO
|
|
*) printf '@%s' "$v" ;; # all-digits => epoch
|
|
esac
|
|
}
|
|
|
|
model=$(echo "$input" | jq -r '.model.display_name // empty')
|
|
used=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
|
|
five_h_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
|
|
five_h_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
|
|
five_h_reset=$(norm_ts "$five_h_reset")
|
|
seven_d_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
|
|
seven_d_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
|
|
seven_d_reset=$(norm_ts "$seven_d_reset")
|
|
|
|
# PS1-derived portion: bold green user@host, reset, colon, bold blue cwd, reset
|
|
user=$(whoami)
|
|
host=$(hostname -s)
|
|
cwd=$(echo "$input" | jq -r '.workspace.current_dir // empty')
|
|
[ -z "$cwd" ] && cwd=$(pwd)
|
|
|
|
prompt_part=$(printf '\033[01;32m%s@%s\033[00m:\033[01;34m%s\033[00m' "$user" "$host" "$cwd")
|
|
|
|
# Color by usage pct: green <50, yellow 50-75, orange 75-90, red >=90
|
|
color_for_pct() {
|
|
local pct=$1
|
|
if [ "$pct" -ge 90 ]; then printf '\033[31m'
|
|
elif [ "$pct" -ge 75 ]; then printf '\033[38;5;172m'
|
|
elif [ "$pct" -ge 50 ]; then printf '\033[38;5;227m'
|
|
else printf '\033[32m'
|
|
fi
|
|
}
|
|
|
|
# Countdown ISO timestamp -> now (GNU date)
|
|
countdown() {
|
|
local reset_ts=$1
|
|
[ -z "$reset_ts" ] && return
|
|
local reset_epoch now_epoch diff_s
|
|
reset_epoch=$(date -d "$reset_ts" +%s 2>/dev/null) || return
|
|
now_epoch=$(date +%s)
|
|
diff_s=$((reset_epoch - now_epoch))
|
|
[ "$diff_s" -le 0 ] && printf "now" && return
|
|
local days=$((diff_s / 86400))
|
|
local hours=$(( (diff_s % 86400) / 3600 ))
|
|
local mins=$(( (diff_s % 3600) / 60 ))
|
|
if [ "$days" -gt 0 ]; then printf "%dd%dh" "$days" "$hours"
|
|
elif [ "$hours" -gt 0 ]; then printf "%dh%02dm" "$hours" "$mins"
|
|
else printf "%dm" "$mins"
|
|
fi
|
|
}
|
|
|
|
# Format reset timestamp as local clock time. fmt: GNU date format string
|
|
reset_clock() {
|
|
local reset_ts=$1
|
|
local fmt=$2
|
|
[ -z "$reset_ts" ] && return
|
|
date -d "$reset_ts" "+$fmt" 2>/dev/null
|
|
}
|
|
|
|
# Window elapsed pct: (window - time_until_reset) / window * 100, clamp 0-100
|
|
elapsed_pct() {
|
|
local reset_ts=$1
|
|
local window_s=$2
|
|
[ -z "$reset_ts" ] && return
|
|
local reset_epoch now_epoch diff_s elapsed
|
|
reset_epoch=$(date -d "$reset_ts" +%s 2>/dev/null) || return
|
|
now_epoch=$(date +%s)
|
|
diff_s=$((reset_epoch - now_epoch))
|
|
elapsed=$(( (window_s - diff_s) * 100 / window_s ))
|
|
[ "$elapsed" -lt 0 ] && elapsed=0
|
|
[ "$elapsed" -gt 100 ] && elapsed=100
|
|
printf '%d' "$elapsed"
|
|
}
|
|
|
|
# Claude info portion
|
|
info_parts=""
|
|
[ -n "$model" ] && info_parts="$model"
|
|
if [ -n "$used" ]; then
|
|
used_int=$(printf '%.0f' "$used")
|
|
[ -n "$info_parts" ] && info_parts="$info_parts | " || true
|
|
info_parts="${info_parts}ctx: ${used_int}%"
|
|
fi
|
|
|
|
# Rate limit segments (colored inside dim brackets via reset+recolor trick)
|
|
rate_segment=""
|
|
DIM='\033[02m'
|
|
PINK='\033[38;5;213m' # ~#EE6FF8, used for elapsed-pace pct
|
|
if [ -n "$five_h_pct" ]; then
|
|
five_int=${five_h_pct%.*}
|
|
five_color=$(color_for_pct "$five_int")
|
|
five_cd=$(countdown "$five_h_reset")
|
|
five_el=$(elapsed_pct "$five_h_reset" 18000)
|
|
five_clk=$(reset_clock "$five_h_reset" '%-l%P')
|
|
seg="${five_color}5h"
|
|
[ -n "$five_clk" ] && seg="${seg}(${five_clk})"
|
|
seg="${seg}:${five_int}%"
|
|
[ -n "$five_el" ] && seg="${seg}/${PINK}${five_el}%${five_color}"
|
|
[ -n "$five_cd" ] && seg="${seg}↻${five_cd}"
|
|
rate_segment="${rate_segment} | ${seg}\033[0m${DIM}"
|
|
fi
|
|
if [ -n "$seven_d_pct" ]; then
|
|
seven_int=${seven_d_pct%.*}
|
|
seven_color=$(color_for_pct "$seven_int")
|
|
seven_cd=$(countdown "$seven_d_reset")
|
|
seven_el=$(elapsed_pct "$seven_d_reset" 604800)
|
|
seven_clk=$(reset_clock "$seven_d_reset" '%a %-l%P')
|
|
seg="${seven_color}7d"
|
|
[ -n "$seven_clk" ] && seg="${seg}(${seven_clk})"
|
|
seg="${seg}:${seven_int}%"
|
|
[ -n "$seven_el" ] && seg="${seg}/${PINK}${seven_el}%${seven_color}"
|
|
[ -n "$seven_cd" ] && seg="${seg}↻${seven_cd}"
|
|
rate_segment="${rate_segment} | ${seg}\033[0m${DIM}"
|
|
fi
|
|
|
|
if [ -n "$info_parts" ] || [ -n "$rate_segment" ]; then
|
|
printf '%s \033[02m[%s' "$prompt_part" "$info_parts"
|
|
[ -n "$rate_segment" ] && printf '%b' "$rate_segment"
|
|
printf ']\033[00m'
|
|
else
|
|
printf '%s' "$prompt_part"
|
|
fi
|
|
|
|
#caveman
|
|
FLAG="$HOME/.claude/.caveman-active"
|
|
[ ! -f "$FLAG" ] && exit 0
|
|
|
|
MODE=$(cat "$FLAG" 2>/dev/null)
|
|
if [ -z "$MODE" ]; then
|
|
printf '\033[38;5;172m[CAVEMAN]\033[0m'
|
|
else
|
|
SUFFIX=$(echo "$MODE" | tr '[:lower:]' '[:upper:]')
|
|
printf '\033[38;5;172m[CAVEMAN:%s]\033[0m' "$SUFFIX"
|
|
fi
|