diff --git a/agent/AGENTS.md b/agent/AGENTS.md index 62cc07d..cdfb721 100644 --- a/agent/AGENTS.md +++ b/agent/AGENTS.md @@ -52,13 +52,10 @@ Zu Beginn einer komplexen Aufgabe (bevor eigene Lösungen gebaut werden): 6. **Arbeitsweise laden:** `~/.pi/agent/memory/arbeitsweise.md` — Orchestrator + SubAgenten-Workflow. Der Orchestrator delegiert alle Arbeiten, SubAgenten speichern Ergebnisse in aufgabenspezifischen Unterverzeichnissen. -7. **SubConfirm starten:** - ```bash - _ME=$(tmux display-message -p '#S') - SubConfirm --orchestrator "$_ME" --skip "$_ME" & - ``` - Startet den Stasis-Detektor. Bei Stasis: schreibt in Alert-Datei UND injiziert direkt in diese Session. - Läuft bereits? `pgrep -fa SubConfirm` prüfen — nicht doppelt starten. +7. **`watch_subagents` sofort aufrufen** — das ist der permanente Subagenten-Watcher. + Das Tool wartet 30 Sekunden, gibt dann den Status aller tmux-Sessions zurück. + **Nach dem Return SOFORT wieder aufrufen** — immer und ohne Ausnahme. + Das ist die Polling-Schleife. Sie stoppt nie während die Session läuft. 8. **SubAgent Auto-Check System laden:** `~/.pi/agent/memory/subagent-autocheck.md` — Hintergrundinformation; SubConfirm übernimmt die proaktive Erkennung automatisch. diff --git a/extensions/arbeitsweise-guard.ts b/extensions/arbeitsweise-guard.ts index daa241a..5e6be0b 100644 --- a/extensions/arbeitsweise-guard.ts +++ b/extensions/arbeitsweise-guard.ts @@ -25,6 +25,7 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { isToolCallEventType } from "@earendil-works/pi-coding-agent"; +import { Type } from "typebox"; import { execSync } from "node:child_process"; import { readFileSync, writeFileSync, existsSync } from "node:fs"; @@ -205,6 +206,46 @@ function tmuxSubagentenStatus(): string | null { export default function (pi: ExtensionAPI) { if (!ORCHESTRATOR_AKTIV) return; + // ------------------------------------------------------------------------- + // watch_subagents — Proaktiver 30s-Watcher + // + // Wartet 30 Sekunden, dann gibt es den aktuellen Status aller tmux-Sessions + // zurück. Der Orchestrator MUSS dieses Tool sofort nach dem Return neu + // aufrufen — so entsteht eine permanente 30s-Polling-Schleife ohne externen + // Prozess. AbortSignal wird respektiert: bei Nutzer-Input endet der Sleep + // sofort und der Status wird sofort zurückgegeben. + // ------------------------------------------------------------------------- + pi.registerTool({ + name: "watch_subagents", + label: "Subagenten-Watcher (30s)", + description: + "Wartet 30 Sekunden und prüft dann alle Subagenten-Sessions. " + + "PFLICHT: Nach dem Return sofort wieder aufrufen. " + + "Nur im Orchestrator aktiv. Nutzer-Input unterbricht den Sleep sofort.", + parameters: Type.Object({}), + execute: async (_toolCallId, _params, signal, _onUpdate, _ctx) => { + await new Promise((resolve) => { + const timer = setTimeout(resolve, 30_000); + signal?.addEventListener("abort", () => { + clearTimeout(timer); + resolve(); + }); + }); + + const status = tmuxSubagentenStatus(); + const alerts = leseSubWatcherAlerts(); + const parts = ["⏱️ [watch_subagents] 30s-Check:"]; + if (status) parts.push(status); + if (alerts) parts.push(alerts); + if (!status && !alerts) parts.push("Alle Sessions aktiv, kein Handlungsbedarf."); + + return { + content: [{ type: "text" as const, text: parts.join("\n\n") }], + details: {}, + }; + }, + }); + pi.on("tool_call", async (event, ctx) => { let grund: string | null = null;