← back to Terminal Status
integrations/reap-dead-dots.sh
55 lines
#!/usr/bin/env bash
# reap-dead-dots.sh — remove color-dot state files for DEAD ttys (TK-11779 T2).
#
# The legacy .dot mirror (~/.claude/tab-dots, ~/.codex/tab-dots) and the canonical
# store (~/.local/state/abrams-terminal-status/ttysNNN.json) accumulate one file per
# tty that EVER had a dot, and nothing prunes them: ~118 .dot + ~121 .json vs ~63 live
# ttys. Stale files are mostly harmless (every live consumer already does a live-tty
# check) but they inflate scans and confuse any raw-glob reader. This reaps only files
# whose tty has NO process at all (authoritative liveness: `ps -o tty=`), so a live but
# momentarily-unpainted tty is NEVER reaped. Its file is regenerated on the tty's next
# paint, so reaping is reversible-tier; --apply additionally tars a backup first.
#
# Usage:
# reap-dead-dots.sh # DRY RUN (default): list dead-tty files + counts
# reap-dead-dots.sh --apply # tar a backup, then delete the dead-tty files
set -uo pipefail
APPLY=0; [ "${1:-}" = "--apply" ] && APPLY=1
DIRS=("$HOME/.claude/tab-dots" "$HOME/.codex/tab-dots" "$HOME/.local/state/abrams-terminal-status")
BACKDIR="$HOME/.local/state/abrams-terminal-status/reap-backups"
# LIVE = every tty with at least one running process. A tty absent here has no session.
LIVE="$(ps -o tty= -A 2>/dev/null | tr -d ' ' | grep -E '^ttys[0-9]+$' | sort -u)"
is_live(){ printf '%s\n' "$LIVE" | grep -qxF "$1"; }
CAND=()
for d in "${DIRS[@]}"; do
[ -d "$d" ] || continue
for f in "$d"/ttys*.dot "$d"/ttys*.json; do
[ -f "$f" ] || continue
base="$(basename "$f")"; tty="${base%.*}" # ttysNNN
case "$tty" in ttys[0-9]*) : ;; *) continue;; esac
is_live "$tty" || CAND+=("$f")
done
done
echo "── reap-dead-dots — live ttys: $(printf '%s\n' "$LIVE" | grep -c .) · dead-tty files: ${#CAND[@]} ──"
if [ "${#CAND[@]}" -eq 0 ]; then echo "nothing to reap."; exit 0; fi
printf ' %s\n' "${CAND[@]}" | sed "s#$HOME#~#" | head -80
[ "${#CAND[@]}" -gt 80 ] && echo " … and $(( ${#CAND[@]} - 80 )) more"
if [ "$APPLY" -ne 1 ]; then
echo "DRY RUN — nothing deleted. Re-run with --apply to tar-backup then delete."
exit 0
fi
mkdir -p "$BACKDIR"
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
TAR="$BACKDIR/reap-$STAMP.tar"
# Backup (reversible undo = `tar xf <TAR> -C /`), then delete.
tar -cf "$TAR" "${CAND[@]}" 2>/dev/null || { echo "backup tar failed — aborting, nothing deleted."; exit 1; }
rm -f "${CAND[@]}"
echo "reaped ${#CAND[@]} dead-tty files. backup: ${TAR/#$HOME/~}"
echo "undo: tar xf $TAR -C /"