#!/bin/bash # SubAgenten — Starte einen Subagenten mit Pi in einem isolierten Verzeichnis # # Nutzung: SubAgenten [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// 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 (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 [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