pi-system/bin/SubAgenten

201 lines
7.6 KiB
Text
Raw Normal View History

#!/bin/bash
# SubAgenten — Starte einen Subagenten mit Pi in einem isolierten Verzeichnis
#
# Nutzung: SubAgenten <aufgaben-name> <aufgaben-beschreibung> [MODELL_CMD]
#
# MODELL_CMD (optional): Welches Pi-Kommando starten (Default: GlmPi)
# Verfügbare Kommandos: TurboPi, MiniPi, GlmPi, DeepPi, FlashPi, GPTPi, GeminiPi
#
# Beispiel:
# SubAgenten "pi-sticks" "Pi auf stick2-5 installieren laut Runbook"
# SubAgenten "debug" "Debug Auth-Problem" TurboPi
# SubAgenten "quick-task" "Kurze Aufgabe" MiniPi
#
# Funktionsweise:
# 1. Isoliertes Verzeichnis in ~/.pi/subagents/<name>/ anlegen (persistent, kein /tmp)
# 2. tmux-Session starten (unsichtbar), Pi darin ausführen
# 3. Warten bis Pi bereit ist, dann /name + Aufgabe per tmux send-keys senden
# 4. gnome-terminal-Fenster öffnen und an tmux-Session attach-en
# 5. Du siehst das Fenster, Pi arbeitet — du kannst jederzeit reinschreiben
#
# Bei Rückfragen des Subagenten:
# - Das Fenster ist direkt sichtbar — einfach Antwort eintippen
# - Oder: tmux attach -t <session-name> (z.B. in einem zweiten Terminal)
# - Verlassen ohne Session zu beenden: Ctrl+B, dann D
#
# Umgebung:
# SUBAGENT_SILENT=1 — Keine Ausgabe, nur tmux-Session-Name auf stdout
set -euo pipefail
NAME="${1:-}"
TASK="${2:-}"
MODEL_CMD="${3:-GlmPi}" # Default: GlmPi (GLM 5.1)
if [ -z "$NAME" ] || [ -z "$TASK" ]; then
echo "Fehler: Name und Aufgabe erforderlich."
echo ""
echo "Nutzung: SubAgenten <aufgaben-name> <aufgaben-beschreibung> [MODELL_CMD]"
echo ""
echo "MODELL_CMD (optional): TurboPi, MiniPi, GlmPi, DeepPi, FlashPi, GPTPi, GeminiPi (Default: GlmPi)"
echo ""
echo "Beispiele:"
echo ' SubAgenten "pi-sticks" "Pi auf stick2-5 installieren"'
echo ' SubAgenten "debug" "Debug Auth-Problem" TurboPi'
exit 1
fi
# Prüfe ob das angegebene Kommando existiert
if ! command -v "$MODEL_CMD" &> /dev/null; then
echo "Warnung: '$MODEL_CMD' nicht gefunden. Verwende GlmPi als Fallback."
MODEL_CMD="GlmPi"
fi
# Slug aus dem Namen für tmux-Session + Arbeitsverzeichnis
SESSION_SLUG=$(echo "$NAME" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9' '-')
WORKDIR="${SUBAGENT_BASE_DIR:-$HOME/.pi/subagents}/${SESSION_SLUG}"
# Prüfen ob Session bereits existiert
if tmux has-session -t "$SESSION_SLUG" 2>/dev/null; then
echo "Fehler: tmux-Session '$SESSION_SLUG' existiert bereits."
echo " Zum Ansehen: tmux attach -t $SESSION_SLUG"
echo " Zum Beenden: tmux kill-session -t $SESSION_SLUG"
exit 1
fi
# Isoliertes Verzeichnis anlegen
mkdir -p "$WORKDIR"
if [ -z "${SUBAGENT_SILENT:-}" ]; then
echo ""
echo "╔══════════════════════════════════════════╗"
echo "║ 🚀 Subagent: $NAME"
echo "╚══════════════════════════════════════════╝"
echo ""
echo "📁 Arbeitsverzeichnis: $WORKDIR"
echo "🪟 Terminal-Fenster wird geöffnet..."
echo ""
fi
# tmux-Session im Hintergrund starten (ohne Fenster)
# PI_ORCHESTRATOR explizit entfernen — darf nicht an Subagenten vererbt werden,
# sonst blockiert der arbeitsweise-guard auch im Subagenten curl/wget/write.
# MODEL_CMD ist das Pi-Kommando (z.B. GlmPi, TurboPi, MiniPi)
tmux new-session -d -s "$SESSION_SLUG" -c "$WORKDIR" "unset PI_ORCHESTRATOR; ${MODEL_CMD}; echo '=== Pi beendet ==='; read"
if [ -z "${SUBAGENT_SILENT:-}" ]; then
echo "⏳ Warte auf Pi-Start..."
fi
# Warten bis Pi seinen Prompt anzeigt (max 30 Sekunden)
# Früherer Bugfix: Pattern auf Box-Drawing-Zeichen (╭─ ───) matchte nicht,
# weil Unicode-Zeichen in tmux-Capture anders kodiert sind.
# Stattdessen: Warten auf Pi-Prompt-Indikator (auto) oder Provider-Name
TIMEOUT=30
ELAPSED=0
while [ $ELAPSED -lt $TIMEOUT ]; do
# Prüfen ob tmux-Session noch lebt
if ! tmux has-session -t "$SESSION_SLUG" 2>/dev/null; then
echo "Fehler: tmux-Session '$SESSION_SLUG' ist abgestürzt."
exit 1
fi
# Prüfen ob Pi bereit ist — suche nach Prompt-Indikatoren:
# - (auto) = auto-modus aktiv
# - Provider-Kürzel wie (zai), (openrouter)
# - Arbeitsverzeichnis im Prompt
# -a = treat binary as text (tmux-capture liefert UTF-8 Bytes)
CAPTURE=$(tmux capture-pane -t "$SESSION_SLUG" -p 2>/dev/null | tail -3)
if echo "$CAPTURE" | grep -a -qE "\(auto\)|\(zai\)|\(openrouter\)" 2>/dev/null; then
break
fi
sleep 1
ELAPSED=$((ELAPSED + 1))
done
if [ $ELAPSED -ge $TIMEOUT ] && [ -z "${SUBAGENT_SILENT:-}" ]; then
echo "⚠️ Timeout beim Warten auf Pi-Start (${TIMEOUT}s), versuche trotzdem..."
fi
# Name setzen
tmux send-keys -t "$SESSION_SLUG" "/name ${SESSION_SLUG}" Enter
sleep 1
# Orchestrator-ID ermitteln
ORCHESTRATOR_ID=$(intercom list 2>/dev/null | grep -oP '\[self.*?\]\(([a-f0-9]+)' | grep -oP '[a-f0-9]+$' 2>/dev/null || echo "")
# Aufgabe senden
if [ -n "$ORCHESTRATOR_ID" ]; then
TASK_WITH_INTERCOM="${TASK}
INTERCOM:
Orchestrator-ID: $ORCHESTRATOR_ID
Nach Abschluss: intercom send an $ORCHESTRATOR_ID mit Ergebnis
Antwort nicht an \"orchestrator\" senden — das funktioniert nicht!"
tmux send-keys -t "$SESSION_SLUG" "$TASK_WITH_INTERCOM" Enter
else
tmux send-keys -t "$SESSION_SLUG" "AUFGABE: ${TASK}" Enter
fi
if [ -z "${SUBAGENT_SILENT:-}" ]; then
echo "✅ Name und Aufgabe gesendet."
echo ""
echo "📋 Fenster ist offen — du siehst alles live."
echo ""
echo " Bei Rückfragen:"
echo " - Direkt ins Fenster tippen (es hat den Fokus)"
echo " - Oder: tmux attach -t $SESSION_SLUG"
echo " - Verlassen: Ctrl+B, dann D (Session läuft weiter)"
echo ""
echo "🔑 Session: $SESSION_SLUG"
echo ""
fi
# Aktuelles Fenster merken (bevor gnome-terminal den Fokus stiehlt)
SAVED_WINDOW=$(xdotool getactivewindow 2>/dev/null || echo "")
# Fenster-Offset (20px pro SubAgent nach rechts, max 9 — Überlappung vermeiden)
SUBAGENT_COUNTER_FILE="/tmp/.subagent-geo-counter"
SUBAGENT_COUNT=$(cat "$SUBAGENT_COUNTER_FILE" 2>/dev/null || echo 0)
SUBAGENT_COUNT=$((SUBAGENT_COUNT + 1))
[ "$SUBAGENT_COUNT" -gt 9 ] && SUBAGENT_COUNT=1
echo "$SUBAGENT_COUNT" > "$SUBAGENT_COUNTER_FILE"
X_OFFSET=$((4652 + (SUBAGENT_COUNT - 1) * 20))
# gnome-terminal-Fenster öffnen und an tmux-Session attach-en
gnome-terminal \
--geometry=64x24+${X_OFFSET}+100 \
--title="Subagent: $NAME" \
--working-directory="$WORKDIR" \
-- bash -c "tmux attach-session -t '$SESSION_SLUG'; echo 'Fenster kann geschlossen werden.'; read"
# Attachment-Check: Session muss innerhalb von 5s sichtbar (attached) sein.
# Wenn gnome-terminal nicht geöffnet hat (kein DISPLAY, crash etc.), Session killen.
ATTACH_TIMEOUT=5
ATTACH_ELAPSED=0
while [ $ATTACH_ELAPSED -lt $ATTACH_TIMEOUT ]; do
if tmux ls -F '#{session_name}:#{session_attached}' 2>/dev/null | grep -q "^${SESSION_SLUG}:1$"; then
break
fi
sleep 1
ATTACH_ELAPSED=$((ATTACH_ELAPSED + 1))
done
if ! tmux ls -F '#{session_name}:#{session_attached}' 2>/dev/null | grep -q "^${SESSION_SLUG}:1$"; then
echo "FEHLER: Kein sichtbares Fenster für Session '${SESSION_SLUG}' nach ${ATTACH_TIMEOUT}s."
echo " Mögliche Ursache: DISPLAY nicht gesetzt oder gnome-terminal nicht verfügbar."
echo " Session wird beendet — keine unsichtbaren Hintergrundprozesse."
tmux kill-session -t "$SESSION_SLUG" 2>/dev/null
exit 1
fi
# Fokus zurück zum ursprünglichen Terminal holen
sleep 0.3
if [ -n "$SAVED_WINDOW" ]; then
xdotool windowactivate "$SAVED_WINDOW" 2>/dev/null || true
fi
if [ -z "${SUBAGENT_SILENT:-}" ]; then
echo "✨ Fertig."
fi