#!/usr/bin/env bash
# Watch a fleet agent's tmux pane for report-worthy state and EXIT (which wakes
# voice_interface) when: the main agent stops "thinking" (turn ended), an
# error/stuck keyword appears, a permission/question prompt shows, or a
# heartbeat interval elapses. voice_interface re-arms this after each report
# until the dispatched task is done. Poll cadence ~12s per Cameron's ask.
#
# Usage: watch_agent.sh <window> [poll_s] [heartbeat_s]
set -u
WIN="${1:?window name required}"
POLL="${2:-12}"
HEARTBEAT="${3:-90}"
T="agents:${WIN}"

# Background-monitor spam + volatile spinner timers we must NOT treat as signal.
NOISE='Monitor event|finetune progress|Step [0-9]+,|for [0-9]+s · [0-9]+ shells|monitor still running|^ *tasks \(|^ *[◼◻✔…]|Running… \([0-9]|Running\.\.\. \([0-9]|ctrl\+b ctrl\+b|run in background\)|Compacting conversation|[▰▱]'

# Main agent is "thinking" iff a token-counter line is present: "(Ns · ↓ Nk ...)".
# The background monitor's spinner has "· NN shells", never "· ↓/↑", so this
# cleanly discriminates real main-loop work from monitor noise.
# Real generation indicator is a token counter "· ↓ 685 tokens" / "· ↑ 615".
# Require arrow + space + DIGIT so the status-bar hint "· ↓ to manage" (shown
# when background tasks exist) does NOT false-positive as "thinking".
thinking() { tmux capture-pane -p -t "$T" | grep -qE '· [↓↑] [0-9]'; }

# A permission / yes-no / question box is open and awaiting Cameron.
prompting() { tmux capture-pane -p -t "$T" | grep -qiE 'do you want|❯ 1\.|\(y/n\)|press enter to|approve\?'; }

# Signature of the de-noised, timer-stripped tail. Stable while the agent
# repeats the same state; changes only on genuinely new output (a captured URL,
# a new error, progress, a reply). Avoids re-firing on one persisting error.
sig() {
  tmux capture-pane -p -t "$T" -S -40 | grep -vE "$NOISE" \
    | sed -E 's/\([0-9]+m? ?[0-9]*s · [↓↑][^)]*\)//' | grep -vE '^\s*$' | md5sum
}

# VI_IDLE_ONLY=1 suppresses the "changed" trigger -- for long autonomous builds
# where only completion / a prompt / a stall matters, not every tool call.
base="$(sig)"
elapsed=0
while :; do
  sleep "$POLL"; elapsed=$((elapsed+POLL))
  if prompting;                      then REASON=waiting;   break; fi
  if ! thinking;                     then REASON=idle;      break; fi
  if [ "${VI_IDLE_ONLY:-0}" != "1" ] && [ "$(sig)" != "$base" ]; then REASON=changed; break; fi
  if [ "$elapsed" -ge "$HEARTBEAT" ]; then REASON=heartbeat; break; fi
done

echo "TRIGGER=${REASON} window=${WIN} after=${elapsed}s"
echo "--- de-noised tail (agents:${WIN}) ---"
tmux capture-pane -p -t "$T" -S -45 | grep -vE "$NOISE" | grep -vE '^\s*$' | tail -28
