15d995aa27
The brace-bounded grep truncated at the first nested "}" in the usage object, so the token segment silently rendered empty. Parse each transcript JSONL line as JSON instead, summing input + cache_read + cache_creation to match /context's window-occupancy figure. Show it as "X.Xk/<limit> tokens (Y%)" with the limit auto-sized to the model's context window (1m vs 200k), and color the segment red once context reaches 200k.
73 lines
2.7 KiB
Bash
Executable File
73 lines
2.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ~/.claude/statusline.sh
|
|
# Claude Code status line: dir | git branch | model | token count
|
|
|
|
input=$(cat)
|
|
|
|
# 1. Current directory (abbreviate $HOME to ~)
|
|
cwd=$(printf '%s' "$input" | jq -r '.workspace.current_dir // .cwd // empty' 2>/dev/null)
|
|
if [ -z "$cwd" ]; then
|
|
cwd="$PWD"
|
|
fi
|
|
cwd="${cwd/#$HOME/\~}"
|
|
|
|
# 2. Git branch (if in a git repo)
|
|
branch=""
|
|
if command -v git >/dev/null 2>&1; then
|
|
branch=$(git -C "${cwd/#\~/$HOME}" rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
[ "$branch" = "HEAD" ] && branch=$(git -C "${cwd/#\~/$HOME}" rev-parse --short HEAD 2>/dev/null)
|
|
fi
|
|
|
|
# 3. Model display name and id (id used to size the context window below)
|
|
model=$(printf '%s' "$input" | jq -r '.model.display_name // empty' 2>/dev/null)
|
|
model_id=$(printf '%s' "$input" | jq -r '.model.id // .model.display_name // empty' 2>/dev/null)
|
|
|
|
# 4. Context-window occupancy from transcript JSONL.
|
|
# Matches /context: input + cache_read + cache_creation of the most recent
|
|
# request is exactly what currently occupies the context window. The usage
|
|
# object nests sub-objects, so parse each JSONL line as JSON rather than
|
|
# grepping (a brace-bounded grep truncates at the first nested "}").
|
|
ctx=""
|
|
transcript=$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/null)
|
|
if [ -n "$transcript" ] && [ -r "$transcript" ] && command -v jq >/dev/null 2>&1; then
|
|
total=$(tail -n 300 "$transcript" 2>/dev/null | jq -rR '
|
|
fromjson? | (.message.usage // .usage) // empty
|
|
| select(.input_tokens != null)
|
|
| (.input_tokens + (.cache_read_input_tokens // 0) + (.cache_creation_input_tokens // 0))
|
|
' 2>/dev/null | tail -1)
|
|
if [ -n "$total" ] && [ "$total" -gt 0 ] 2>/dev/null; then
|
|
# 1M-context models report a [1m]/"1M" marker in the id/name; else 200k.
|
|
case "$model_id" in
|
|
*1m*|*1M*) limit=1000000; label="1m" ;;
|
|
*) limit=200000; label="200k" ;;
|
|
esac
|
|
ctx=$(awk -v t="$total" -v lim="$limit" -v lab="$label" 'BEGIN {
|
|
if (t >= 1000) ts = sprintf("%.1fk", t/1000); else ts = sprintf("%d", t);
|
|
printf "%s/%s tokens (%.0f%%)", ts, lab, t*100/lim
|
|
}')
|
|
# Turn the token segment red once context reaches 200k; reset after so the
|
|
# rest of the line keeps its default styling.
|
|
if [ "$total" -ge 200000 ] 2>/dev/null; then
|
|
ctx=$(printf '\033[31m%s\033[0m' "$ctx")
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Assemble the line, separating non-empty segments with " | "
|
|
parts=()
|
|
[ -n "$cwd" ] && parts+=("$cwd")
|
|
[ -n "$branch" ] && parts+=("$branch")
|
|
[ -n "$model" ] && parts+=("$model")
|
|
[ -n "$ctx" ] && parts+=("$ctx")
|
|
|
|
joined=""
|
|
for part in "${parts[@]}"; do
|
|
if [ -z "$joined" ]; then
|
|
joined="$part"
|
|
else
|
|
joined="$joined | $part"
|
|
fi
|
|
done
|
|
|
|
printf '%s' "$joined"
|