|
#!/bin/bash |
|
|
|
# Status line - shows worktree, gitstatus-style git info, model, and context usage |
|
|
|
data=$(cat) |
|
|
|
# Get model name |
|
model=$(echo "$data" | jq -r '.model.display_name // .model.id // "unknown"') |
|
|
|
# Color codes |
|
GREEN='\033[32m' |
|
YELLOW='\033[33m' |
|
RED='\033[31m' |
|
BLUE='\033[34m' |
|
CYAN='\033[36m' |
|
BOLD='\033[1m' |
|
DIM='\033[2m' |
|
RESET='\033[0m' |
|
|
|
# Git info (gitstatus-style) |
|
git_info="" |
|
if git_dir_path=$(git rev-parse --git-dir 2>/dev/null); then |
|
worktree=$(basename "$(git rev-parse --show-toplevel 2>/dev/null)") |
|
|
|
# Branch / tag / commit |
|
branch=$(git symbolic-ref --short HEAD 2>/dev/null) |
|
if [ -n "$branch" ]; then |
|
ref="${GREEN}${branch}${RESET}" |
|
else |
|
# Detached HEAD — check for tag first, then show commit hash |
|
tag=$(git describe --tags --exact-match HEAD 2>/dev/null) |
|
if [ -n "$tag" ]; then |
|
ref="${GREEN}#${tag}${RESET}" |
|
else |
|
commit=$(git rev-parse --short HEAD 2>/dev/null) |
|
ref="${GREEN}@${commit}${RESET}" |
|
fi |
|
fi |
|
|
|
# Ahead/behind upstream |
|
upstream_info="" |
|
if upstream_counts=$(git rev-list --left-right --count @{upstream}...HEAD 2>/dev/null); then |
|
behind=$(echo "$upstream_counts" | cut -f1) |
|
ahead=$(echo "$upstream_counts" | cut -f2) |
|
[ "$behind" -gt 0 ] 2>/dev/null && upstream_info="${upstream_info} ${CYAN}⇣${behind}${RESET}" |
|
[ "$ahead" -gt 0 ] 2>/dev/null && upstream_info="${upstream_info} ${CYAN}⇡${ahead}${RESET}" |
|
fi |
|
|
|
# Ahead/behind push remote (only if explicit push remote configured) |
|
push_info="" |
|
push_remote=$(git config "branch.${branch}.pushRemote" 2>/dev/null || git config remote.pushDefault 2>/dev/null) |
|
if [ -n "$push_remote" ]; then |
|
if push_counts=$(git rev-list --left-right --count @{push}...HEAD 2>/dev/null); then |
|
push_behind=$(echo "$push_counts" | cut -f1) |
|
push_ahead=$(echo "$push_counts" | cut -f2) |
|
[ "$push_behind" -gt 0 ] 2>/dev/null && push_info="${push_info} ${CYAN}⇠${push_behind}${RESET}" |
|
[ "$push_ahead" -gt 0 ] 2>/dev/null && push_info="${push_info} ${CYAN}⇢${push_ahead}${RESET}" |
|
fi |
|
fi |
|
|
|
# Stashes |
|
stash_info="" |
|
stash_count=$(git stash list 2>/dev/null | wc -l | tr -d ' ') |
|
[ "$stash_count" -gt 0 ] && stash_info=" ${CYAN}*${stash_count}${RESET}" |
|
|
|
# Action (merge, rebase, cherry-pick, bisect) |
|
action_info="" |
|
if [ -f "$git_dir_path/MERGE_HEAD" ]; then |
|
action_info=" ${BOLD}${YELLOW}merge${RESET}" |
|
elif [ -d "$git_dir_path/rebase-merge" ] || [ -d "$git_dir_path/rebase-apply" ]; then |
|
action_info=" ${BOLD}${YELLOW}rebase${RESET}" |
|
elif [ -f "$git_dir_path/CHERRY_PICK_HEAD" ]; then |
|
action_info=" ${BOLD}${YELLOW}cherry-pick${RESET}" |
|
elif [ -f "$git_dir_path/BISECT_LOG" ]; then |
|
action_info=" ${BOLD}${YELLOW}bisect${RESET}" |
|
fi |
|
|
|
# Working tree status (single pass with awk) |
|
porcelain=$(git status --porcelain 2>/dev/null) |
|
if [ -n "$porcelain" ]; then |
|
read -r conflicts staged unstaged untracked <<< $(echo "$porcelain" | awk '{ |
|
xy = substr($0, 1, 2) |
|
if (xy == "DD" || xy == "AU" || xy == "UD" || xy == "UA" || xy == "DU" || xy == "AA" || xy == "UU") { c++; next } |
|
x = substr($0, 1, 1) |
|
y = substr($0, 2, 1) |
|
if (x == "?") { u++; next } |
|
if (x != " ") s++ |
|
if (y != " ") m++ |
|
} END { printf "%d %d %d %d", c+0, s+0, m+0, u+0 }') |
|
else |
|
conflicts=0 staged=0 unstaged=0 untracked=0 |
|
fi |
|
|
|
wt_info="" |
|
[ "$conflicts" -gt 0 ] && wt_info="${wt_info} ${RED}~${conflicts}${RESET}" |
|
[ "$staged" -gt 0 ] && wt_info="${wt_info} ${GREEN}+${staged}${RESET}" |
|
[ "$unstaged" -gt 0 ] && wt_info="${wt_info} ${YELLOW}!${unstaged}${RESET}" |
|
[ "$untracked" -gt 0 ] && wt_info="${wt_info} ${BLUE}?${untracked}${RESET}" |
|
|
|
git_info="${worktree} ${ref}${upstream_info}${push_info}${stash_info}${action_info}${wt_info} | " |
|
fi |
|
|
|
# Get context info |
|
max_ctx=$(echo "$data" | jq -r '.context_window.context_window_size // 200000') |
|
used_pct=$(echo "$data" | jq -r '.context_window.used_percentage // empty') |
|
|
|
# Format context display |
|
if [ -z "$used_pct" ] || [ "$used_pct" = "null" ]; then |
|
context_info="${DIM}||||||||||${RESET} loading..." |
|
else |
|
pct=$(printf "%.0f" "$used_pct" 2>/dev/null || echo "$used_pct") |
|
[ "$pct" -gt 100 ] 2>/dev/null && pct=100 |
|
|
|
used_k=$(( max_ctx * pct / 100 / 1000 )) |
|
max_k=$(( max_ctx / 1000 )) |
|
|
|
bar="" |
|
filled=$(( pct / 10 )) |
|
|
|
if [ "$pct" -gt 80 ]; then |
|
COLOR="$RED" |
|
elif [ "$pct" -gt 30 ]; then |
|
COLOR="$YELLOW" |
|
else |
|
COLOR="$GREEN" |
|
fi |
|
|
|
for i in 0 1 2 3 4 5 6 7 8 9; do |
|
if [ "$i" -lt "$filled" ]; then |
|
bar="${bar}${COLOR}|${RESET}" |
|
else |
|
bar="${bar}${DIM}|${RESET}" |
|
fi |
|
done |
|
|
|
context_info="${bar} ${used_k}k/${max_k}k (${pct}%)" |
|
fi |
|
|
|
printf '%b\n' "${git_info}${model} | ${context_info}" |