← back to Terminal Status
verification/install/after/.claude/skills/allcolordots/allcolordots.sh
115 lines
#!/usr/bin/env bash
# /allcolordots — scan EVERY active terminal's color dot + label in one shot,
# and (new) present a clickable single-window ROSTER per color that JUMPS focus
# to any tab — the "gather my yellows in one place" navigator (path A).
#
# Status comes from the shared session-bound terminal-status engine.
# Labels and dot files are presentation; exact main agent ownership is required.
#
# Usage:
# allcolordots.sh # grouped human table (orange > purple > yellow > green > pink)
# allcolordots.sh --json # JSON array: [{tty,color,label,live,pid}] (navbar app)
# allcolordots.sh --live # table, but only ACTIVE (live) terminals
# allcolordots.sh --yellow # numbered ROSTER of just the 🟡 needs-direction tabs
# allcolordots.sh --only <color> # numbered roster of one color (yellow|orange|purple|green|pink)
# allcolordots.sh jump <ttyNNN|N> # focus that tab (N = row# from the last roster)
set -u
set -o pipefail
# Emoji glob-matching (case *🟡*) needs a UTF-8 ctype; some launch contexts pass
# LC_CTYPE= empty which silently breaks the match -> every dot reads "none".
export LANG="${LANG:-en_US.UTF-8}" LC_ALL="en_US.UTF-8"
DOTS="$HOME/.claude/tab-dots"
ROSTER_CACHE="$DOTS/.last-roster"
color_of(){ case "$1" in *🟢*) echo green;; *🟡*) echo yellow;; *🟣*) echo purple;; *🟠*) echo orange;; *🩷*) echo pink;; *) echo none;; esac; }
emoji_of(){ case "$1" in orange) echo 🟠;; purple) echo 🟣;; yellow) echo 🟡;; green) echo 🟢;; pink) echo 🩷;; *) echo ⚪;; esac; }
# ---- JUMP: focus the tab whose tty matches (select + activate; NOT a reparent) ----
jump_to(){
local arg="$1" tty=""
# index into the last roster?
if printf '%s' "$arg" | grep -qE '^[0-9]+$' && [ -f "$ROSTER_CACHE" ]; then
tty="$(awk -F'\t' -v n="$arg" 'NR==n{print $1}' "$ROSTER_CACHE")"
fi
[ -z "$tty" ] && tty="$arg"
case "$tty" in /dev/*) :;; ttys*) tty="/dev/$tty";; *) tty="/dev/$tty";; esac
osascript 2>&1 <<OSA
tell application "iTerm2"
repeat with w in windows
repeat with t in tabs of w
repeat with s in sessions of t
if (tty of s) is "$tty" then
select w
select t
select s
activate
return "jumped -> $tty"
end if
end repeat
end repeat
end repeat
return "not found: $tty"
end tell
OSA
}
# ---- Shared state scanner: presentation never overrides canonical state ----
collect_rows(){
python3 "$HOME/Projects/terminal-status/terminal_status.py" scan --tsv
}
# ---- roster of ONE color: numbered, jump-ready, caches order for `jump N` ----
print_roster(){
local want="$1" rows; rows="$(collect_rows | awk -F'\t' -v c="$want" '$2==c')" || return $?
: > "$ROSTER_CACHE"
local e; e="$(emoji_of "$want")"
local n; n="$(printf '%s\n' "$rows" | grep -c .)"
echo "=== $e $want roster ($n) — jump with: allcolordots.sh jump <#|tty> ==="
[ "$n" = 0 ] && { echo " (none)"; return 0; }
local i=0
printf '%s\n' "$rows" | while IFS=$'\t' read -r tty color live pid label; do
i=$((i+1))
printf '%s\t%s\t%s\n' "$tty" "$label" "$live" >> "$ROSTER_CACHE"
local flag=""; [ "$live" = true ] && flag=" ·live"
printf ' %2d) %-9s %s%s\n' "$i" "$tty" "$label" "$flag"
done
}
# ---------------- dispatch ----------------
case "${1:-}" in
jump) shift; jump_to "${1:-}"; exit $? ;;
--yellow) print_roster yellow; exit $? ;;
--only) print_roster "${2:-yellow}"; exit $? ;;
--json)
collect_rows | python3 -c '
import sys,json
out=[]
for line in sys.stdin:
line=line.rstrip("\n")
if not line: continue
tty,color,live,pid,label=(line.split("\t")+["","","","",""])[:5]
out.append({"tty":tty,"color":color,"live":live=="true","pid":pid,"label":label})
pri={"orange":0,"purple":1,"yellow":2,"green":3,"pink":4,"none":5}
out.sort(key=lambda r:(pri.get(r["color"],9), r["tty"]))
print(json.dumps(out))
'
exit $? ;;
esac
# default / --live : grouped human table
LIVEONLY=0; [ "${1:-}" = "--live" ] && LIVEONLY=1
rows="$(collect_rows)" || exit $?
[ "$LIVEONLY" = 1 ] && rows="$(printf '%s\n' "$rows" | awk -F'\t' '$3=="true"')"
total="$(printf '%s\n' "$rows" | grep -c . )"
echo "=== active-terminal dots ($total) ==="
for c in orange purple yellow green pink none; do
block="$(printf '%s\n' "$rows" | awk -F'\t' -v c="$c" '$2==c')"
[ -z "$block" ] && continue
n="$(printf '%s\n' "$block" | grep -c .)"
echo "$(emoji_of "$c") ${c} ($n)"
printf '%s\n' "$block" | while IFS=$'\t' read -r tty color live pid label; do
flag=""; [ "$live" = true ] && flag=" ·live"
printf ' %-9s %s%s\n' "$tty" "$label" "$flag"
done
done