#!/bin/bash # SubWatcher — Hintergrund-Wächter für Subagenten-Aktivität (W02) # # Überwacht alle tmux-Sessions alle 15 Sekunden auf neue Ausgabe. # Bei Änderung: zenity-Desktop-Notification + Alert-Datei für Guard. # Der Guard zeigt den Alert beim nächsten Tool-Call prominent an. # # Nutzung: SubWatcher & # Oder: SubWatcher --interval 10 (Sekunden) # Beenden: kill %SubWatcher oder pkill -f SubWatcher # # Stoppt automatisch wenn keine tmux-Sessions mehr laufen. INTERVAL="${2:-15}" [ "$1" = "--interval" ] && INTERVAL="${2:-15}" STATE_DIR="/tmp/.pi-subwatcher-state" ALERT_FILE="/tmp/.pi-subagent-alert" PID_FILE="/tmp/.pi-subwatcher.pid" mkdir -p "$STATE_DIR" echo $$ > "$PID_FILE" log() { echo "[SubWatcher $(date '+%H:%M:%S')] $1" } notify() { local msg="$1" # Alert-Datei für Guard (wird beim nächsten Tool-Call angezeigt) echo "$(date '+%H:%M:%S') $msg" >> "$ALERT_FILE" # Desktop-Notification zenity --notification --text="Pi SubWatcher: $msg" 2>/dev/null & # Terminal-Bell als Fallback echo -e "\a" 2>/dev/null || true } log "Gestartet (PID $$, Interval: ${INTERVAL}s)" log "Alert-Datei: $ALERT_FILE" log "Stopp: kill $$ oder pkill -f SubWatcher" while true; do SESSIONS=$(tmux ls -F '#{session_name}' 2>/dev/null || echo "") # Wenn keine Sessions: kurz warten, dann prüfen ob gestoppt werden soll if [ -z "$SESSIONS" ]; then sleep "$INTERVAL" continue fi while IFS= read -r session; do [ -z "$session" ] && continue # Aktuellen Output capturen CURRENT=$(tmux capture-pane -t "$session" -p 2>/dev/null | \ grep -v '^[[:space:]]*$' | tail -5 | tr '\n' '|') STATE_FILE="${STATE_DIR}/${session}" # Vorheriger State PREVIOUS=$(cat "$STATE_FILE" 2>/dev/null || echo "") if [ "$CURRENT" != "$PREVIOUS" ]; then # State aktualisieren echo "$CURRENT" > "$STATE_FILE" # Wichtige Muster erkennen LAST_LINE=$(echo "$CURRENT" | tr '|' '\n' | tail -1) if echo "$CURRENT" | grep -qE "Pi beendet|Fenster kann geschlossen werden"; then notify "[$session] FERTIG — Fenster kann geschlossen werden" elif echo "$CURRENT" | grep -qE "contact_supervisor|Waiting for reply|waiting for.*reply"; then notify "[$session] Wartet auf Antwort vom Orchestrator" elif echo "$CURRENT" | grep -qE "Error|error:|FEHLER|failed|Failed" && ! echo "$PREVIOUS" | grep -qE "Error|error:|FEHLER|failed|Failed"; then notify "[$session] Fehler erkannt: $LAST_LINE" fi # Einfache Aktivität (kein Spezialfall) — kein Alarm, nur State-Update fi done <<< "$SESSIONS" sleep "$INTERVAL" done