|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Claude Code status line: PR, token usage, conversation context, session cost estimate |
| 3 | +# |
| 4 | +# Input JSON schema (from Claude Code docs) relevant fields: |
| 5 | +# .context_window.total_input_tokens - cumulative input tokens this session |
| 6 | +# .context_window.total_output_tokens - cumulative output tokens this session |
| 7 | +# .context_window.context_window_size - model's max context window size |
| 8 | +# .context_window.current_usage - last API call token breakdown (may be null) |
| 9 | +# .input_tokens - input tokens in current context |
| 10 | +# .output_tokens - output tokens generated |
| 11 | +# .cache_creation_input_tokens - tokens written to cache |
| 12 | +# .cache_read_input_tokens - tokens read from cache |
| 13 | +# .context_window.used_percentage - % of context window used (null until first message) |
| 14 | +# .context_window.remaining_percentage - % of context window remaining (null until first message) |
| 15 | +# |
| 16 | +# NOTE: The Claude Code status line input JSON does NOT include any session cost in dollars, |
| 17 | +# weekly cost, or usage budget fields. The only cost-proxy available is token counts. |
| 18 | +# Session cost is therefore estimated from cumulative token counts using approximate |
| 19 | +# pricing for claude-sonnet-4-6 (input: $3/MTok, output: $15/MTok, cache-read: $0.30/MTok). |
| 20 | +# Weekly cost tracking is not possible from this input JSON (no cross-session data). |
| 21 | + |
| 22 | +input=$(cat) |
| 23 | + |
| 24 | +# --- Git PR / branch info --- |
| 25 | +cwd=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // empty') |
| 26 | +branch="" |
| 27 | +pr_info="" |
| 28 | +if [ -n "$cwd" ] && git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then |
| 29 | + branch=$(git -C "$cwd" symbolic-ref --short HEAD 2>/dev/null) |
| 30 | + if [ -n "$branch" ] && command -v gh >/dev/null 2>&1; then |
| 31 | + pr_number=$(GIT_OPTIONAL_LOCKS=0 gh pr view --json number -q '.number' 2>/dev/null) |
| 32 | + if [ -n "$pr_number" ]; then |
| 33 | + pr_state=$(GIT_OPTIONAL_LOCKS=0 gh pr view --json state -q '.state' 2>/dev/null) |
| 34 | + pr_info="PR#${pr_number}(${pr_state})" |
| 35 | + fi |
| 36 | + fi |
| 37 | +fi |
| 38 | + |
| 39 | +# --- Token / context info --- |
| 40 | +used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty') |
| 41 | +remaining_pct=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty') |
| 42 | +total_input=$(echo "$input" | jq -r '.context_window.total_input_tokens // empty') |
| 43 | +total_output=$(echo "$input" | jq -r '.context_window.total_output_tokens // empty') |
| 44 | + |
| 45 | +# Cache tokens from current_usage (best available proxy for session cache activity) |
| 46 | +cache_read=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0') |
| 47 | +cache_create=$(echo "$input" | jq -r '.context_window.current_usage.cache_creation_input_tokens // 0') |
| 48 | + |
| 49 | +# --- Session cost estimate --- |
| 50 | +# Pricing (per million tokens): input=$3, output=$15, cache_read=$0.30, cache_create=$3.75 |
| 51 | +# Uses cumulative totals; cache tokens are from last call only (best available approximation). |
| 52 | +session_cost="" |
| 53 | +if [ -n "$total_input" ] && [ -n "$total_output" ]; then |
| 54 | + session_cost=$(awk -v tin="$total_input" -v tout="$total_output" \ |
| 55 | + -v tcr="$cache_read" -v tcc="$cache_create" ' |
| 56 | + BEGIN { |
| 57 | + cost = (tin / 1000000 * 3.00) \ |
| 58 | + + (tout / 1000000 * 15.00) \ |
| 59 | + + (tcr / 1000000 * 0.30) \ |
| 60 | + + (tcc / 1000000 * 3.75) |
| 61 | + if (cost < 0.01) |
| 62 | + printf "<$0.01" |
| 63 | + else |
| 64 | + printf "$%.2f", cost |
| 65 | + }') |
| 66 | +fi |
| 67 | + |
| 68 | +# --- Build output --- |
| 69 | +parts=() |
| 70 | + |
| 71 | +if [ -n "$branch" ]; then |
| 72 | + if [ -n "$pr_info" ]; then |
| 73 | + parts+=("${branch} ${pr_info}") |
| 74 | + else |
| 75 | + parts+=("${branch}") |
| 76 | + fi |
| 77 | +fi |
| 78 | + |
| 79 | +if [ -n "$total_input" ] && [ -n "$total_output" ]; then |
| 80 | + total_tokens=$((total_input + total_output)) |
| 81 | + if [ "$total_tokens" -ge 1000 ]; then |
| 82 | + token_k=$(echo "$total_tokens" | awk '{printf "%.1fk", $1/1000}') |
| 83 | + parts+=("tokens:${token_k}") |
| 84 | + else |
| 85 | + parts+=("tokens:${total_tokens}") |
| 86 | + fi |
| 87 | +fi |
| 88 | + |
| 89 | +# Session cost estimate (labeled as estimate since no dollar data in JSON) |
| 90 | +if [ -n "$session_cost" ]; then |
| 91 | + parts+=("session:~${session_cost}") |
| 92 | +fi |
| 93 | + |
| 94 | +# NOTE: weekly cost cannot be shown - the input JSON contains no cross-session |
| 95 | +# or billing period data. Only per-session token counts are available. |
| 96 | + |
| 97 | +# Conversation context window fill level (renamed from "ctx:X% used" for clarity) |
| 98 | +if [ -n "$used_pct" ] && [ "$used_pct" != "null" ]; then |
| 99 | + used_rounded=$(printf "%.0f" "$used_pct") |
| 100 | + remaining_rounded=$(printf "%.0f" "$remaining_pct") |
| 101 | + parts+=("conv:${used_rounded}% full (${remaining_rounded}% free)") |
| 102 | +fi |
| 103 | + |
| 104 | +# Join with separator |
| 105 | +printf "%s" "$(IFS=' | '; echo "${parts[*]}")" |
0 commit comments