Skip to content

Instantly share code, notes, and snippets.

@N0K0
Created April 6, 2026 07:56
Show Gist options
  • Select an option

  • Save N0K0/e8edcead8c93bff3845a9b37e4febf62 to your computer and use it in GitHub Desktop.

Select an option

Save N0K0/e8edcead8c93bff3845a9b37e4febf62 to your computer and use it in GitHub Desktop.
Claude Code statusline — II layout: 3-line split panel with truecolor bars, pace gauge, responsive truncation, and Nerd Font icons
#!/usr/bin/env bash
# ============================================================================
# Claude Code Status Line — "II" Layout
# ============================================================================
#
# A two-panel, 3-line status bar with truecolor gradients, a pace gauge,
# and context-aware annotations. Designed for terminals with Nerd Fonts.
#
# LAYOUT
# ------
# The display is split by a vertical ┃ separator into:
# Left panel: project info (variable width, content-driven)
# Right panel: usage meters + pace gauge (fixed structure)
#
# With git: Without git:
# ╭ ~/project/path ┃ 5h bar ╭ ~/path ┃ 5h bar
# │ branch +N ●M [󰙅] ┃ 7d bar │ Opus 4.6 │ 1.2K/340 ┃ 7d bar
# ╰ Opus │ tok ctx% │ $ ┃ pace ╰ ctx 32% │ $1.60 ┃ pace
#
# When there is no git repo, model name and token I/O move up to line 2
# (where git would be), and ctx/cost take line 3.
#
# ALIGNMENT
# ---------
# - The ┃ separator column is computed from plain-text segment widths.
# Every line follows the structure: prefix(3) + icon(ICO) + space + content.
# The separator is placed at the max width across all 3 lines.
# - In no-git mode, the inner │ separators (model│tokens, ctx│cost) are
# vertically aligned by padding the left-of-│ segments to equal width.
# - Colored output uses printf '%b' to interpret \033 escapes without
# treating content '%' as format specifiers.
# - ICO constant (default 1) controls assumed nerd font icon display width.
# Adjust if your terminal renders PUA glyphs wider.
#
# TRUNCATION
# ----------
# - Left panel budget = 80% of terminal width (from tput cols).
# - If content exceeds budget, cwd is truncated first (with …), then
# git branch. The info line (model/tokens/cost) is never truncated.
#
# RIGHT PANEL METERS
# ------------------
# - 5h bar: gradient fill (TC_MINT), percentage, reset countdown
# - 7d bar: gradient fill (TC_SKY), percentage, reset countdown
# - Pace gauge: ◆ marker on a zone-colored track.
# Center │ = 100% (on pace). Left = under, right = over.
# Green zone (80-120%), yellow (50-160%), red (outside).
# Annotated with human-readable label: "on pace", "under budget",
# "running hot", "over budget!"
#
# USAGE DATA
# ----------
# Fetched by probing the Anthropic API with a Haiku request and reading
# rate-limit headers. Cached to /tmp/claude-usage-cache.json for 5 minutes.
# Pace = (actual_7d_usage / ideal_linear_usage) * 100, where ideal is
# based on elapsed time in the 7-day window.
#
# TERMINAL TITLE
# --------------
# Set via OSC escape (or Konsole D-Bus). Format: project | branch | summary.
# Brainstorming summary is generated by a Haiku call and cached per session.
#
# FILES
# -----
# - ~/.claude/statusline-ii.sh this script (active)
# - ~/.claude/statusline-command.sh previous statusline (retained)
# - ~/.claude/settings.json statusLine.command points here
# - /tmp/claude-usage-cache.json cached API usage data
# - /tmp/claude-usage-cache.ts cache timestamp
# - /tmp/claude-brainstorm-summary-* cached brainstorm summaries
#
# CONFIGURATION
# -------------
# In ~/.claude/settings.json:
# "statusLine": {
# "type": "command",
# "command": "bash /home/nikolas/.claude/statusline-ii.sh"
# }
#
# ============================================================================
input=$(cat)
# ---- Extract fields (single jq call for performance) ----
eval "$(echo "$input" | jq -r '
"model_id=" + (.model.id // "claude-sonnet" | @sh),
"model_name=" + (.model.display_name // "Claude" | @sh),
"cwd_path=" + (.cwd // .workspace.current_dir // "" | @sh),
"transcript_path=" + (.transcript_path // "" | @sh),
"total_in=" + (.context_window.total_input_tokens // 0 | tostring),
"total_out=" + (.context_window.total_output_tokens // 0 | tostring),
"used_pct=" + (.context_window.used_percentage // empty | tostring | @sh),
"session_cost=" + (.cost.total_cost_usd // 0 | tostring),
"h5_pct=" + (.rate_limits.five_hour.used_percentage // empty | tostring | @sh),
"h5_reset=" + (.rate_limits.five_hour.resets_at // empty | tostring | @sh),
"h7_pct=" + (.rate_limits.seven_day.used_percentage // empty | tostring | @sh),
"h7_reset=" + (.rate_limits.seven_day.resets_at // empty | tostring | @sh)
' 2>/dev/null)"
creds_file="$HOME/.claude/.credentials.json"
# ---- ANSI colors ----
RST='\033[0m'
DIM='\033[2m'
ITALIC='\033[3m'
RED='\033[0;31m'
YEL='\033[0;33m'
GRN='\033[0;32m'
CYN='\033[0;36m'
MAG='\033[0;35m'
BLU='\033[0;34m'
GRAY='\033[38;5;242m'
# Truecolor
TC_MINT='\033[38;2;130;220;170m'
TC_SKY='\033[38;2;100;180;255m'
TC_GOLD='\033[38;2;255;200;60m'
TC_ROSE='\033[38;2;255;100;130m'
TC_LAVENDER='\033[38;2;180;160;255m'
TC_TEAL='\033[38;2;0;188;180m'
TC_CORAL='\033[38;2;255;127;80m'
TC_DARK='\033[38;2;50;50;50m'
# Pace zone colors for gauge
TC_ZONE_OK='\033[38;2;50;75;50m'
TC_ZONE_WARN='\033[38;2;50;35;35m'
TC_GAUGE_MID='\033[38;2;70;70;70m'
# ---- Nerd Font icons ----
ICON_FOLDER=""
ICON_GIT=""
ICON_MODEL=""
ICON_CTX="󰍛" # nf-md-memory (context/memory)
ICON_COST="" # nf-fa-dollar
ICON_DIRTY="●"
SEP_INNER="·" # inner separator (dot)
# ---- Helpers ----
fmt_time() {
local secs="${1:-0}"
if [ "$secs" -le 0 ] 2>/dev/null; then echo "now!"; return; fi
local d=$(( secs / 86400 ))
local h=$(( (secs % 86400) / 3600 ))
local m=$(( (secs % 3600) / 60 ))
if [ "$d" -gt 0 ]; then printf "%dd%dh" "$d" "$h"
elif [ "$h" -gt 0 ]; then printf "%dh%02dm" "$h" "$m"
else printf "%dm" "$m"
fi
}
fmt_k() {
awk -v n="$1" 'BEGIN {
if (n >= 1000) printf "%.1fK", n/1000
else printf "%d", n
}'
}
# Gradient bar: filled portion in color, empty in dark
gbar() {
local pct=$1 width=$2 color=$3
local filled=$(( pct * width / 100 ))
[ "$filled" -gt "$width" ] && filled=$width
[ "$filled" -lt 0 ] && filled=0
local empty=$(( width - filled ))
printf "${color}"
for ((i=0; i<filled; i++)); do printf "█"; done
printf "${TC_DARK}"
for ((i=0; i<empty; i++)); do printf "░"; done
printf "${RST}"
}
# Pace gauge: ◆ marker on a zone-colored track, center │ = 100%
pace_gauge() {
local pace=$1 width=$2
local pos=$(( pace * width / 200 ))
[ "$pos" -ge "$width" ] && pos=$(( width - 1 ))
[ "$pos" -lt 0 ] && pos=0
local mid=$(( width / 2 ))
# Pick marker color
local marker_color
if [ "$pace" -ge 80 ] && [ "$pace" -le 120 ]; then
marker_color="${TC_MINT}"
elif [ "$pace" -ge 50 ] && [ "$pace" -le 160 ]; then
marker_color="${TC_GOLD}"
else
marker_color="${TC_ROSE}"
fi
for ((i=0; i<width; i++)); do
if [ $i -eq $pos ]; then
printf "${marker_color}◆"
elif [ $i -eq $mid ]; then
printf "${TC_GAUGE_MID}│"
elif [ $i -ge $(( mid - 2 )) ] && [ $i -le $(( mid + 2 )) ]; then
printf "${TC_ZONE_OK}─"
else
printf "${TC_ZONE_WARN}─"
fi
done
printf "${RST}"
}
# Color a percentage value based on usage severity
color_pct() {
local pct="${1:-0}"
local color=$2
printf "${color}%.0f%%${RST}" "$pct"
}
tin_fmt=$(fmt_k "$total_in")
tout_fmt=$(fmt_k "$total_out")
# ---- Session cost ----
session_cost_str=$(awk -v c="$session_cost" 'BEGIN { printf "$%.2f", c }')
# ---- Context % ----
ctx_str=""
if [ -n "$used_pct" ]; then
ipct=${used_pct%.*}
if [ "$ipct" -ge 80 ] 2>/dev/null; then ctx_str="${RED}ctx ${ipct}%${RST}"
elif [ "$ipct" -ge 50 ] 2>/dev/null; then ctx_str="${YEL}ctx ${ipct}%${RST}"
else ctx_str="${GRN}ctx ${ipct}%${RST}"; fi
fi
# ---- Git status ----
git_branch=""
git_status_str=""
git_dirty_count=0
git_is_worktree=false
if [ -n "$cwd_path" ] && [ -d "$cwd_path" ]; then
git_branch=$(git -C "$cwd_path" symbolic-ref --short HEAD 2>/dev/null)
if [ -n "$git_branch" ]; then
git_toplevel=$(git -C "$cwd_path" rev-parse --show-toplevel 2>/dev/null)
git_commondir=$(git -C "$cwd_path" rev-parse --git-common-dir 2>/dev/null)
if [ "$git_commondir" != ".git" ] && [ "$git_commondir" != "$git_toplevel/.git" ]; then
git_is_worktree=true
fi
ahead=0; behind=0
if [ "$git_branch" != "main" ]; then
ahead_behind=$(git -C "$cwd_path" rev-list --left-right --count "$git_branch"...main 2>/dev/null)
else
ahead_behind=$(git -C "$cwd_path" rev-list --left-right --count main...origin/main 2>/dev/null)
fi
if [ -n "$ahead_behind" ]; then
ahead=$(echo "$ahead_behind" | awk '{print $1}')
behind=$(echo "$ahead_behind" | awk '{print $2}')
fi
git_dirty_count=$(git -C "$cwd_path" status --porcelain 2>/dev/null | wc -l | tr -d ' ')
git_status_str="${git_branch}"
[ "$ahead" -gt 0 ] 2>/dev/null && git_status_str="${git_status_str} +${ahead}"
[ "$behind" -gt 0 ] 2>/dev/null && git_status_str="${git_status_str} -${behind}"
[ "$git_dirty_count" -gt 0 ] 2>/dev/null && git_status_str="${git_status_str} ${ICON_DIRTY}${git_dirty_count}"
fi
fi
# ---- Brainstorming summary ----
brainstorm_summary=""
if [ -n "$transcript_path" ] && [ -f "$transcript_path" ]; then
session_hash=$(printf '%s' "$transcript_path" | md5sum | cut -d' ' -f1)
summary_cache="/tmp/claude-brainstorm-summary-${session_hash}.txt"
last_user_content=$(tac "$transcript_path" 2>/dev/null \
| jq -r 'select(.type == "user" and .userType == "external") | .message.content' 2>/dev/null \
| head -1)
is_brainstorming=false
echo "$last_user_content" | grep -q 'superpowers-extended-cc:brainstorming' 2>/dev/null && is_brainstorming=true
if [ "$is_brainstorming" = true ]; then
transcript_size=$(stat -c%s "$transcript_path" 2>/dev/null || echo "0")
cached_size=$(cat "${summary_cache}.size" 2>/dev/null || echo "-1")
if [ -f "$summary_cache" ] && [ "$transcript_size" = "$cached_size" ]; then
brainstorm_summary=$(cat "$summary_cache")
else
token=$(jq -r '.claudeAiOauth.accessToken // empty' "$creds_file" 2>/dev/null)
if [ -n "$token" ]; then
transcript_tail=$(tail -c 3000 "$transcript_path" 2>/dev/null || true)
request_body=$(jq -n \
--arg context "$transcript_tail" \
'{model: "claude-haiku-4-5-20251001", max_tokens: 30, messages: [{role: "user", content: ("Summarize what this brainstorming session is about in under 8 words for a terminal window title. Reply with ONLY the summary, no quotes or punctuation:\n\n" + $context)}]}')
summary_response=$(curl --silent --max-time 5 \
--header "Authorization: Bearer $token" \
--header "Content-Type: application/json" \
--header "User-Agent: claude-code/2.1.72" \
--header "anthropic-version: 2023-06-01" \
--header "anthropic-beta: oauth-2025-04-20" \
-d "$request_body" \
"https://api.anthropic.com/v1/messages" 2>/dev/null)
if [ -n "$summary_response" ]; then
brainstorm_summary=$(echo "$summary_response" | jq -r '.content[0].text // empty' 2>/dev/null | head -c 60)
if [ -n "$brainstorm_summary" ]; then
echo "$brainstorm_summary" > "$summary_cache"
echo "$transcript_size" > "${summary_cache}.size"
fi
fi
fi
fi
elif [ -f "$summary_cache" ]; then
brainstorm_summary=$(cat "$summary_cache")
fi
fi
# ---- Usage data (from CC JSON, fallback to cached API probe) ----
now=$(date +%s)
five_hour_pct=""
five_hour_reset=""
seven_day_pct=""
seven_day_reset=""
pace_value=""
pace_label=""
# Prefer rate_limits from CC JSON (instant, no API call)
if [ -n "$h5_pct" ] && [ "$h5_pct" != "null" ]; then
five_hour_pct=$(awk "BEGIN{printf \"%.0f\", $h5_pct}" 2>/dev/null)
fi
if [ -n "$h7_pct" ] && [ "$h7_pct" != "null" ]; then
seven_day_pct=$(awk "BEGIN{printf \"%.0f\", $h7_pct}" 2>/dev/null)
fi
if [ -n "$h5_reset" ] && [ "$h5_reset" != "null" ] && [ "$h5_reset" != "0" ]; then
h5r_epoch=$(date -d "@$h5_reset" +%s 2>/dev/null || date -d "$h5_reset" +%s 2>/dev/null || echo "0")
if [ "$h5r_epoch" -gt "$now" ] 2>/dev/null; then
five_hour_reset=$(fmt_time $(( h5r_epoch - now )))
fi
fi
if [ -n "$h7_reset" ] && [ "$h7_reset" != "null" ] && [ "$h7_reset" != "0" ]; then
h7r_epoch=$(date -d "@$h7_reset" +%s 2>/dev/null || date -d "$h7_reset" +%s 2>/dev/null || echo "0")
if [ "$h7r_epoch" -gt "$now" ] 2>/dev/null; then
seven_day_reset=$(fmt_time $(( h7r_epoch - now )))
fi
fi
# Fallback: Haiku API probe (commented out — CC now provides rate_limits natively)
# To re-enable, uncomment the block below. It probes the API every 5 minutes
# and caches results to /tmp/claude-usage-cache.json.
#
# if [ -z "$five_hour_pct" ] && [ -z "$seven_day_pct" ]; then
# usage_cache="/tmp/claude-usage-cache.json"
# usage_cache_ts="/tmp/claude-usage-cache.ts"
# if [ -f "$creds_file" ]; then
# cache_age=9999
# [ -f "$usage_cache_ts" ] && cache_age=$(( now - $(cat "$usage_cache_ts") ))
# if [ "$cache_age" -gt 300 ] || [ "$cache_age" -lt 0 ]; then
# token=$(jq -r '.claudeAiOauth.accessToken // empty' "$creds_file" 2>/dev/null)
# if [ -n "$token" ]; then
# headers=$(curl --silent --max-time 5 -D- -o /dev/null \
# --header "Authorization: Bearer $token" \
# --header "Content-Type: application/json" \
# --header "User-Agent: claude-code/2.1.72" \
# --header "anthropic-version: 2023-06-01" \
# --header "anthropic-beta: oauth-2025-04-20" \
# -d '{"model":"claude-haiku-4-5-20251001","max_tokens":1,"messages":[{"role":"user","content":"h"}]}' \
# "https://api.anthropic.com/v1/messages" 2>/dev/null)
# if [ -n "$headers" ]; then
# h5u=$(echo "$headers" | grep -i 'anthropic-ratelimit-unified-5h-utilization' | tr -d '\r' | awk '{print $2}')
# h5r=$(echo "$headers" | grep -i 'anthropic-ratelimit-unified-5h-reset' | tr -d '\r' | awk '{print $2}')
# h7u=$(echo "$headers" | grep -i 'anthropic-ratelimit-unified-7d-utilization' | tr -d '\r' | awk '{print $2}')
# h7r=$(echo "$headers" | grep -i 'anthropic-ratelimit-unified-7d-reset' | tr -d '\r' | awk '{print $2}')
# [ -n "$h5u" ] && jq -n --arg h5u "$h5u" --arg h5r "$h5r" --arg h7u "$h7u" --arg h7r "$h7r" \
# '{h5u:$h5u, h5r:$h5r, h7u:$h7u, h7r:$h7r}' > "$usage_cache" && echo "$now" > "$usage_cache_ts"
# fi
# fi
# fi
# if [ -f "$usage_cache" ]; then
# h5u=$(jq -r '.h5u // empty' "$usage_cache"); h5r=$(jq -r '.h5r // empty' "$usage_cache")
# h7u=$(jq -r '.h7u // empty' "$usage_cache"); h7r=$(jq -r '.h7r // empty' "$usage_cache")
# [ -n "$h5u" ] && [ "$h5u" != "null" ] && five_hour_pct=$(awk "BEGIN{printf \"%.0f\", $h5u * 100}")
# [ -n "$h7u" ] && [ "$h7u" != "null" ] && seven_day_pct=$(awk "BEGIN{printf \"%.0f\", $h7u * 100}")
# if [ -n "$h5r" ] && [ "$h5r" != "null" ] && [ "$h5r" != "0" ]; then
# h5r_epoch=$(date -d "@$h5r" +%s 2>/dev/null || date -d "$h5r" +%s 2>/dev/null || echo "0")
# [ "$h5r_epoch" -gt "$now" ] && five_hour_reset=$(fmt_time $(( h5r_epoch - now )))
# fi
# if [ -n "$h7r" ] && [ "$h7r" != "null" ] && [ "$h7r" != "0" ]; then
# h7r_epoch=$(date -d "@$h7r" +%s 2>/dev/null || date -d "$h7r" +%s 2>/dev/null || echo "0")
# [ "$h7r_epoch" -gt "$now" ] && seven_day_reset=$(fmt_time $(( h7r_epoch - now )))
# fi
# fi
# fi
# fi
# ---- Pace calculation ----
if [ -n "$seven_day_pct" ] && [ -n "$h7r_epoch" ] && [ "$h7r_epoch" -gt "$now" ] 2>/dev/null; then
pace_value=$(awk -v actual="${seven_day_pct}" -v remaining="$(( h7r_epoch - now ))" '
BEGIN {
window = 604800; elapsed = window - remaining
if (elapsed <= 0) { print ""; exit }
ideal = (elapsed / window) * 100
if (ideal < 0.01) { print ""; exit }
printf "%.0f", actual / ideal * 100
}')
if [ -n "$pace_value" ]; then
if [ "$pace_value" -ge 80 ] && [ "$pace_value" -le 120 ] 2>/dev/null; then pace_label="on pace"
elif [ "$pace_value" -lt 80 ] 2>/dev/null; then pace_label="under budget"
elif [ "$pace_value" -gt 160 ] 2>/dev/null; then pace_label="over budget!"
else pace_label="running hot"; fi
fi
fi
# ---- Compose status line (II layout) ----
# ---- Terminal geometry ----
# stdin is piped (JSON), so tput/stty on stdin won't work.
# Try /dev/tty first (the real terminal), then $COLUMNS, then tput, then fallback.
term_cols=""
if [ -z "$term_cols" ] && [ -e /dev/tty ]; then
term_cols=$(tput cols < /dev/tty 2>/dev/null)
fi
if [ -z "$term_cols" ] && [ -n "$COLUMNS" ]; then
term_cols=$COLUMNS
fi
if [ -z "$term_cols" ]; then
term_cols=$(tput cols 2>/dev/null)
fi
: "${term_cols:=120}"
BAR_WIDTH=14
GAUGE_WIDTH=14
# ---- Build content ----
short_cwd=""
[ -n "$cwd_path" ] && short_cwd="${cwd_path/#$HOME/\~}"
short_model=$(echo "$model_name" | sed 's/Claude //;s/ (.*)//')
wt_plain=""
if [ -n "$git_status_str" ] && [ "$git_is_worktree" = true ]; then
wt_plain=" 󰙅"
fi
git_color="${GRN}"
[ "$git_dirty_count" -gt 0 ] 2>/dev/null && git_color="${YEL}"
has_git=false
[ -n "$git_status_str" ] && has_git=true
# ---- Helpers ----
pad() {
local n=$1
[ "$n" -le 0 ] 2>/dev/null && return
printf "%*s" "$n" ""
}
truncate() {
local str="$1" max=$2
if [ "${#str}" -le "$max" ]; then
printf '%s' "$str"
else
printf '%s' "${str:0:$(( max - 1 ))}…"
fi
}
# ---- Calculate each line's plain-text width from its segments ----
# Each line: " X " (prefix=3) + icon(1) + " " + content
# Icons (,,,etc) are 1 display col each based on wcwidth
# Box-drawing (╭│╰┃│) are 1 display col each
ICO=1 # nerd font icon display width
# Segment lengths for each line (plain text, no ANSI)
if [ "$has_git" = true ]; then
# Line 1: " ╭ " + ICON + " " + cwd
# Line 2: " │ " + ICON + " " + git_status + wt
# Line 3: " ╰ " + ICON + " " + model + " │ " + tokens + [" ctx N%"] + [" │ $cost"]
seg1="${short_cwd}"
seg2="${git_status_str}${wt_plain}"
seg3="${short_model} ${SEP_INNER} ↓${tin_fmt} ↑${tout_fmt}"
[ -n "$used_pct" ] && seg3="${seg3} ${SEP_INNER} ${ICON_CTX} ${used_pct%.*}%"
if [ "$total_in" -gt 0 ] 2>/dev/null || [ "$total_out" -gt 0 ] 2>/dev/null; then
seg3="${seg3} ${SEP_INNER} ${session_cost_str}"
fi
prefix=3
segw() { echo $(( prefix + ICO + 1 + ${#1} )); }
w1=$(segw "$seg1")
w2=$(segw "$seg2")
w3=$(segw "$seg3")
else
# All 3 lines: " X " + ICON + " " + content (same structure)
# Line 1: folder icon + cwd
# Line 2: model icon + model │ tokens
# Line 3: cost icon + [ctx N%] [│ $cost]
#
# Align inner │: pad left-of-│ segments to same width
seg1="${short_cwd}"
# Split line 2 and 3 into left│right parts
s2_left="${short_model}"
s2_right="↓${tin_fmt} ↑${tout_fmt}"
s3_left=""
s3_right=""
ipct_val=${used_pct%.*}
[ -n "$used_pct" ] && s3_left="${ICON_CTX} ${ipct_val}%"
if [ "$total_in" -gt 0 ] 2>/dev/null || [ "$total_out" -gt 0 ] 2>/dev/null; then
s3_right="${session_cost_str}"
fi
# Pad left parts to same width for │ alignment
inner_w=${#s2_left}
[ ${#s3_left} -gt $inner_w ] && inner_w=${#s3_left}
s2_left_padded=$(printf "%-${inner_w}s" "$s2_left")
s3_left_padded=$(printf "%-${inner_w}s" "$s3_left")
# Reassemble segments
if [ -n "$s2_right" ]; then
seg2="${s2_left_padded} ${SEP_INNER} ${s2_right}"
else
seg2="${s2_left_padded}"
fi
if [ -n "$s3_left" ] && [ -n "$s3_right" ]; then
seg3="${s3_left_padded} ${SEP_INNER} ${s3_right}"
elif [ -n "$s3_left" ]; then
seg3="${s3_left_padded}"
elif [ -n "$s3_right" ]; then
seg3="${s3_right}"
else
seg3=""
fi
# Width: " X " (3) + ICON (ICO) + " " + content
prefix=3
segw() { echo $(( prefix + ICO + 1 + ${#1} )); }
w1=$(segw "$seg1")
w2=$(segw "$seg2")
w3=$(segw "$seg3")
fi
# ---- Find separator column ----
sep_col=$w1
[ $w2 -gt $sep_col ] && sep_col=$w2
[ $w3 -gt $sep_col ] && sep_col=$w3
# ---- Responsive right panel ----
# Progressive degradation based on available space:
# Wide: bar(14) + label(8) + annotation(20) = 42 (+ 3 for " ┃ " = 45)
# Medium: bar(14) + label(8) = 22 (+ 3 = 25)
# Narrow: bar(8) + label(8) = 16 (+ 3 = 19)
# Tiny: bar(4) + label(8) = 12 (+ 3 = 15)
# Minimal: no bars, just label(8) = 8 (+ 3 = 11)
available=$(( term_cols - sep_col ))
show_annotations=true
bar_w=14
gauge_w=14
if [ $available -lt 45 ]; then
show_annotations=false
fi
if [ $available -lt 25 ]; then
bar_w=8
gauge_w=8
fi
if [ $available -lt 19 ]; then
bar_w=4
gauge_w=4
fi
if [ $available -lt 15 ]; then
bar_w=0
gauge_w=0
fi
# ---- Truncation of left panel if still too tight ----
# Need at least 15 cols for the right panel (┃ + label + tiny bar)
min_right=15
budget=$(( term_cols - min_right ))
[ "$budget" -lt 15 ] && budget=15
if [ $sep_col -gt $budget ]; then
overshoot=$(( sep_col - budget ))
# Truncate cwd first
max_seg1=$(( ${#seg1} - overshoot ))
[ $max_seg1 -lt 5 ] && max_seg1=5
seg1=$(truncate "$seg1" $max_seg1)
w1=$(( prefix + ICO + 1 + ${#seg1} ))
# Truncate git branch if still over
if [ "$has_git" = true ] && [ $w2 -gt $budget ]; then
max_seg2=$(( budget - prefix - ICO - 1 ))
[ $max_seg2 -lt 5 ] && max_seg2=5
seg2=$(truncate "$seg2" $max_seg2)
w2=$(( prefix + ICO + 1 + ${#seg2} ))
fi
# Recalculate
sep_col=$w1
[ $w2 -gt $sep_col ] && sep_col=$w2
[ $w3 -gt $sep_col ] && sep_col=$w3
[ $sep_col -gt $budget ] && sep_col=$budget
# Recalculate available after truncation
available=$(( term_cols - sep_col ))
show_annotations=true
bar_w=14; gauge_w=14
if [ $available -lt 45 ]; then show_annotations=false; fi
if [ $available -lt 25 ]; then bar_w=8; gauge_w=8; fi
if [ $available -lt 19 ]; then bar_w=4; gauge_w=4; fi
if [ $available -lt 15 ]; then bar_w=0; gauge_w=0; fi
fi
# ---- Output helper: right panel meter ----
# Usage: emit_meter <pct> <bar_width> <color> <label> <reset_time>
emit_meter() {
local pct=$1 bw=$2 color=$3 label=$4 reset=$5
printf '%b' " ${GRAY}┃${RST} "
if [ "$bw" -gt 0 ]; then
gbar "$pct" "$bw" "$color"
printf " "
fi
printf "${color}${label} %s%%${RST}" "$pct"
if [ "$show_annotations" = true ] && [ -n "$reset" ]; then
printf " ${ITALIC}${GRAY}▸ resets in %s${RST}" "$reset"
fi
}
# ---- Output ----
# Line 1
printf '%b' " ${GRAY}╭${RST} ${BLU}${ICON_FOLDER} ${seg1}${RST}"
pad $(( sep_col - w1 ))
[ -n "$five_hour_pct" ] && emit_meter "$five_hour_pct" "$bar_w" "${TC_MINT}" "5h" "$five_hour_reset"
printf "\n"
# Line 2
if [ "$has_git" = true ]; then
printf '%b' " ${GRAY}│${RST} ${git_color}${ICON_GIT} ${seg2}${RST}"
else
printf '%b' " ${GRAY}│${RST} ${TC_LAVENDER}${ICON_MODEL} ${s2_left_padded}${RST} ${GRAY}${SEP_INNER}${RST} ${TC_TEAL}↓${tin_fmt}${RST} ${TC_CORAL}↑${tout_fmt}${RST}"
fi
pad $(( sep_col - w2 ))
[ -n "$seven_day_pct" ] && emit_meter "$seven_day_pct" "$bar_w" "${TC_SKY}" "7d" "$seven_day_reset"
printf "\n"
# Line 3 — colored version of seg3
ipct_val=${used_pct%.*}
if [ "$has_git" = true ]; then
c3="${TC_LAVENDER}${ICON_MODEL} ${short_model}${RST} ${GRAY}${SEP_INNER}${RST} ${TC_TEAL}↓${tin_fmt}${RST} ${TC_CORAL}↑${tout_fmt}${RST}"
if [ -n "$used_pct" ]; then
if [ "$ipct_val" -ge 80 ] 2>/dev/null; then c3="${c3} ${GRAY}${SEP_INNER}${RST} ${RED}${ICON_CTX} ${ipct_val}%${RST}"
elif [ "$ipct_val" -ge 50 ] 2>/dev/null; then c3="${c3} ${GRAY}${SEP_INNER}${RST} ${YEL}${ICON_CTX} ${ipct_val}%${RST}"
else c3="${c3} ${GRAY}${SEP_INNER}${RST} ${GRN}${ICON_CTX} ${ipct_val}%${RST}"; fi
fi
if [ "$total_in" -gt 0 ] 2>/dev/null || [ "$total_out" -gt 0 ] 2>/dev/null; then
c3="${c3} ${GRAY}${SEP_INNER}${RST} ${YEL}${session_cost_str}${RST}"
fi
printf '%b' " ${GRAY}╰${RST} ${c3}"
else
c3_left=""
if [ -n "$used_pct" ]; then
if [ "$ipct_val" -ge 80 ] 2>/dev/null; then c3_left="${RED}${s3_left_padded}${RST}"
elif [ "$ipct_val" -ge 50 ] 2>/dev/null; then c3_left="${YEL}${s3_left_padded}${RST}"
else c3_left="${GRN}${s3_left_padded}${RST}"; fi
else
c3_left="${s3_left_padded}"
fi
if [ -n "$s3_left" ] && [ -n "$s3_right" ]; then
c3="${c3_left} ${GRAY}${SEP_INNER}${RST} ${YEL}${s3_right}${RST}"
elif [ -n "$s3_right" ]; then
c3="${YEL}${s3_right}${RST}"
else
c3="${c3_left}"
fi
printf '%b' " ${GRAY}╰${RST} ${YEL}${ICON_COST}${RST} ${c3}"
fi
pad $(( sep_col - w3 ))
if [ -n "$pace_value" ]; then
printf '%b' " ${GRAY}┃${RST} "
if [ "$gauge_w" -gt 0 ]; then
pace_gauge "$pace_value" "$gauge_w"
printf " "
fi
if [ "$pace_value" -ge 80 ] && [ "$pace_value" -le 120 ] 2>/dev/null; then pace_color="${TC_MINT}"
elif [ "$pace_value" -ge 50 ] && [ "$pace_value" -le 160 ] 2>/dev/null; then pace_color="${TC_GOLD}"
else pace_color="${TC_ROSE}"; fi
printf "${pace_color}Pc %s%%${RST}" "$pace_value"
if [ "$show_annotations" = true ] && [ -n "$pace_label" ]; then
printf " ${ITALIC}${GRAY}▸ %s${RST}" "$pace_label"
fi
fi
printf "\n"
# ---- Terminal title ----
project_name=""
if [ -n "$cwd_path" ]; then
project_name=$(basename "$cwd_path")
fi
title="${project_name}"
[ -n "$git_status_str" ] && title="${title} | ${git_status_str}"
[ -n "$brainstorm_summary" ] && title="${title} | ${brainstorm_summary}"
if [ -n "$KONSOLE_DBUS_SESSION" ]; then
konsole_svc=$(qdbus6 2>/dev/null | grep konsole | head -1 | tr -d ' ')
if [ -n "$konsole_svc" ]; then
qdbus6 "$konsole_svc" "$KONSOLE_DBUS_SESSION" \
org.kde.konsole.Session.setTitle 1 "$title" 2>/dev/null || true
fi
else
printf "\033]0;%s\007" "$title" >&2
fi
exit 0
@N0K0
Copy link
Copy Markdown
Author

N0K0 commented Apr 6, 2026

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment