#!/usr/bin/env bash
# dispatch_watchdog.sh — Auto-approve permission prompts for an unattended
# Claude Code dispatch session.
#
# Usage:
#   dispatch_watchdog.sh <tmux_session_name> [--poll-seconds N] [--log FILE]
#
# Intended to run on Mac Studio AFTER /dispatch creates the tmux session.
# Polls `tmux capture-pane` every N seconds (default 10), pattern-matches
# against known permission prompts, and sends the appropriate keys to
# unblock the session. Exits when the tmux session no longer exists.
#
# Recognised patterns (case-insensitive):
#   - "Do you trust the files in this folder"    → send "1" + Enter (yes, trust)
#   - "Do you want to proceed?" / "(y/N)"         → send "1" + Enter
#   - "[1] Yes" visible near bottom of pane       → send "1" + Enter
#   - "❯ Yes, proceed"                            → send Enter (accept default)
#   - "[Pasted text" visible > 45s with no change → send Enter (unstick paste)
#   - Idle ❯ prompt with no thinking/tool activity > 90s → send Enter (unstick
#     post-response idle — Claude finished its turn but nobody submitted next)
#
# Safe-by-default: the watchdog only sends keys when a known prompt is
# visible and the pane has NOT changed since the last poll (avoids racing
# with content that is actively being written).

set -euo pipefail

SESSION="${1:-}"
POLL_SECONDS=10
LOG_FILE="/tmp/dispatch_watchdog_${SESSION}.log"

if [ -z "${SESSION}" ]; then
  echo "usage: $0 <tmux_session_name> [--poll-seconds N] [--log FILE]" >&2
  exit 2
fi

shift
while [ "$#" -gt 0 ]; do
  case "$1" in
    --poll-seconds) POLL_SECONDS="$2"; shift 2 ;;
    --log) LOG_FILE="$2"; shift 2 ;;
    *) echo "unknown arg: $1" >&2; exit 2 ;;
  esac
done

log() {
  printf '%s  %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$*" | tee -a "${LOG_FILE}" >&2
}

capture_pane() {
  tmux capture-pane -t "${SESSION}" -p 2>/dev/null || true
}

send_keys() {
  local keys="$1"
  log "  → send-keys: ${keys}"
  tmux send-keys -t "${SESSION}" "${keys}" 2>/dev/null || true
}

session_exists() {
  tmux has-session -t "${SESSION}" 2>/dev/null
}

log "watchdog start  session=${SESSION}  poll=${POLL_SECONDS}s"

prev_pane=""
paste_seen_at=0
idle_prompt_seen_at=0

while session_exists; do
  pane="$(capture_pane)"
  tail_pane="$(printf '%s' "${pane}" | tail -40)"

  # Pattern 1 — folder-trust prompt
  if [ -n "${prev_pane}" ] && [ "${pane}" = "${prev_pane}" ] && printf '%s' "${tail_pane}" | grep -qiE 'do you trust (the files|this folder)'; then
    log "pattern: folder-trust"
    send_keys "1"
    sleep 1
    send_keys "Enter"
    sleep 3
    continue
  fi

  # Pattern 2 — numbered prompt with "[1] Yes" or similar
  if [ -n "${prev_pane}" ] && [ "${pane}" = "${prev_pane}" ] && printf '%s' "${tail_pane}" | grep -qiE '^\s*\[1\]\s*(yes|proceed|approve)' ; then
    log "pattern: numbered-yes"
    send_keys "1"
    sleep 1
    send_keys "Enter"
    sleep 3
    continue
  fi

  # Pattern 3 — inline (y/N) or (Y/n) variants
  if [ -n "${prev_pane}" ] && [ "${pane}" = "${prev_pane}" ] && printf '%s' "${tail_pane}" | grep -qiE '\((y|Y)/(n|N)\)[[:space:]]*$|proceed\?[[:space:]]*(\(|$)'; then
    log "pattern: y/n inline"
    send_keys "y"
    sleep 1
    send_keys "Enter"
    sleep 3
    continue
  fi

  # Pattern 4 — cursor-selected prompt (e.g., ❯ Yes, proceed)
  if [ -n "${prev_pane}" ] && [ "${pane}" = "${prev_pane}" ] && printf '%s' "${tail_pane}" | grep -qiE '(>|❯)\s*Yes'; then
    log "pattern: cursor-yes"
    send_keys "Enter"
    sleep 3
    continue
  fi

  # Pattern 5 — idle prompt (Claude finished response, nobody submitted next turn)
  # Detects: ❯ prompt visible, pane unchanged, NO thinking/tool activity indicators.
  # Waits 90s of consecutive idle before nudging to avoid racing with long thinks.
  if printf '%s' "${tail_pane}" | grep -qE '(❯|^>)\s' && \
     ! printf '%s' "${tail_pane}" | grep -qiE 'Thinking|Stewing|Bloviating|Cogitat|Reading|Writing|Editing|Bash\(|Agent|tokens|Tool|⏺|✻|✶|✳'; then
    now="$(date +%s)"
    if [ "${idle_prompt_seen_at}" -eq 0 ]; then
      idle_prompt_seen_at="${now}"
      log "idle-prompt first seen (t0)"
    elif [ "${pane}" = "${prev_pane}" ] && [ "$((now - idle_prompt_seen_at))" -ge 90 ]; then
      log "pattern: idle-prompt (90s unchanged) — sending Enter"
      send_keys "Enter"
      sleep 5
      idle_prompt_seen_at=0
    fi
  else
    idle_prompt_seen_at=0
  fi

  # Pattern 6 — stuck paste mode (see feedback-dispatch-multiline)
  if printf '%s' "${tail_pane}" | grep -q '\[Pasted text'; then
    now="$(date +%s)"
    if [ "${paste_seen_at}" -eq 0 ]; then
      paste_seen_at="${now}"
      log "paste-mode first seen (t0)"
    elif [ "${pane}" = "${prev_pane}" ] && [ "$((now - paste_seen_at))" -ge 45 ]; then
      log "pattern: stuck paste-mode (45s idle) — sending Enter"
      send_keys "Enter"
      sleep 3
      paste_seen_at=0
    fi
  else
    paste_seen_at=0
  fi

  prev_pane="${pane}"
  sleep "${POLL_SECONDS}"
done

log "watchdog exit  session=${SESSION} no longer exists"
