82 lines
2.7 KiB
Text
82 lines
2.7 KiB
Text
|
|
#!/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
|