2026-06-02 16:02:03 +02:00
/ * *
* Rule Enforcer Extension
*
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
* Mechanismen :
2026-06-02 16:02:03 +02:00
*
* 1 . before_agent_start — injiziert Kern - Regeln in jeden System - Prompt - Turn
* + Selbstkorrektur wenn letzter Turn W06 verletzt hat
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
* + Subagenten - Lage aus Alert - File ( passiver Pfad )
2026-06-02 16:02:03 +02:00
*
* 2 . message_end — scannt Pi ' s Ausgabe auf W06 - Deliberations - Muster ,
* setzt Flag für nächsten before_agent_start
*
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
* 3 . setInterval ( 30 s ) — erzwingt die Invariante :
* "Solange ein Subagent läuft, darf der Orchestrator nicht idle sein."
* Erkennt laufende Subagenten per PROZESSBAUM ( lebt ein ` pi ` - Kind unter dem
* tmux - Pane ? ) , nicht per Keyword . Ist der Orchestrator idle , obwohl ein
* Subagent läuft , wird er AKTIV via pi . sendUserMessage ( ) geweckt — das löst
* garantiert einen Turn aus . Der passive Alert - File - Pfad allein reicht nicht ,
* weil before_agent_start bei einem idle Orchestrator nie feuert .
2026-06-02 16:02:03 +02:00
*
* Nur aktiv wenn PI_ORCHESTRATOR = 1 .
* /
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent" ;
import * as fs from "node:fs" ;
import { execSync } from "node:child_process" ;
const ORCHESTRATOR_AKTIV = ! ! process . env . PI_ORCHESTRATOR ;
const ALERT_FILE = "/tmp/.pi-subagent-alert" ;
const CHECK_INTERVAL_MS = 30 _000 ;
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
// Idle = seit so langer Zeit kein Pi-Event. 45s > 30s watch_subagents-Pollintervall,
// damit aktive Überwachung nicht fälschlich als idle gilt.
const IDLE_SCHWELLE_MS = 45 _000 ;
// Höchstens eine aktive Weckung in diesem Abstand.
const WECK_MIN_ABSTAND_MS = 60 _000 ;
const SUBAGENT_PFAD_MARKER = "/.pi/subagents/" ;
2026-06-02 16:02:03 +02:00
// ---------------------------------------------------------------------------
// Kern-Regeln — werden in jeden System-Prompt-Turn injiziert
// ---------------------------------------------------------------------------
const KERN_REGELN = `
# # PFLICHT - REGELN — gelten für JEDE Antwort ohne Ausnahme
* * W06 * * Kein Deliberieren : Niemals "Let me" , "Actually" , "I should" , "Ich sollte" , "Das liegt daran" , "Weil ich" in Antworten ausgeben . Nur Ergebnis oder Entscheidung .
* * W07 * * Subagenten nicht aufgeben : Bei Problemen Benutzer kurz informieren , auf Anweisung warten . Nie eigenständig auf direkte Ausführung umschwenken .
* * W09 * * sleep verboten : Stattdessen watch_subagents nutzen oder Benutzer informieren .
* * W10 * * Subagent nie doppelt starten : Einmal starten , dann watch_subagents abwarten .
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
* * WATCH * * watch_subagents SOFORT nach jeder Antwort erneut aufrufen — permanent , ohne Ausnahme . Solange ein Subagent läuft , darfst du NIE idle werden .
2026-06-02 16:02:03 +02:00
` .trim();
// ---------------------------------------------------------------------------
// W06-Deliberations-Muster
// ---------------------------------------------------------------------------
const DELIBERATIONS_MUSTER : RegExp [ ] = [
/\bLet me\b/ ,
/\bActually,?\s/ ,
/\bI should\b/ ,
/\bI need to\b/ ,
/\bI'll check\b/ ,
/\bI'll look\b/ ,
/\bLet me check\b/ ,
/\bLet me look\b/ ,
/\bLet me verify\b/ ,
/\bLet me first\b/ ,
/\bHmm,?\s/i ,
/\bWait,?\s/ ,
/\bIch sollte\b/ ,
/\bLass mich\b/ ,
/\bDas liegt daran\b/ ,
/\bWeil ich\b/ ,
/\bIch muss\b/ ,
/\bIch werde\b.*\bprüfen\b/ ,
] ;
function hatDeliberation ( text : string ) : boolean {
return DELIBERATIONS_MUSTER . some ( ( p ) = > p . test ( text ) ) ;
}
function textAusNachricht ( message : any ) : string {
const content = message ? . content ;
if ( ! Array . isArray ( content ) ) return "" ;
return content
. filter ( ( c : any ) = > c . type === "text" )
. map ( ( c : any ) = > String ( c . text ? ? "" ) )
. join ( " " ) ;
}
// ---------------------------------------------------------------------------
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
// Alert-File (passiver Pfad)
2026-06-02 16:02:03 +02:00
// ---------------------------------------------------------------------------
function leseAlerts ( ) : string | null {
try {
if ( ! fs . existsSync ( ALERT_FILE ) ) return null ;
const content = fs . readFileSync ( ALERT_FILE , "utf-8" ) . trim ( ) ;
if ( ! content ) return null ;
fs . writeFileSync ( ALERT_FILE , "" ) ;
return content ;
} catch {
return null ;
}
}
function schreibeAlert ( text : string ) : void {
try {
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
fs . writeFileSync ( ALERT_FILE , text ) ;
2026-06-02 16:02:03 +02:00
} catch { }
}
// ---------------------------------------------------------------------------
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
// Laufende Subagenten per PROZESSBAUM erkennen
//
// pane_current_command ist unbrauchbar (meldet "bash", obwohl pi als Kind läuft).
// Stattdessen: für jede tmux-Session unter ~/.pi/subagents/ prüfen, ob unter dem
// Pane-Shell-PID ein lebender `pi`-Prozess hängt.
2026-06-02 16:02:03 +02:00
// ---------------------------------------------------------------------------
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
interface LaufenderSubagent {
name : string ;
dialog : string | null ; // Pane-Auszug, falls ein Bestätigungs-Dialog erkennbar ist
}
function laeuftPiUnter ( panePid : number ) : boolean {
2026-06-02 16:02:03 +02:00
try {
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
const kids = execSync ( ` pgrep -P ${ panePid } 2>/dev/null || true ` , {
2026-06-02 16:02:03 +02:00
encoding : "utf-8" ,
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
timeout : 1500 ,
2026-06-02 16:02:03 +02:00
} ) . trim ( ) ;
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
const pids = kids . split ( /\s+/ ) . filter ( Boolean ) ;
for ( const k of pids ) {
const n = Number ( k ) ;
if ( ! Number . isInteger ( n ) ) continue ;
const comm = execSync ( ` ps -o comm= -p ${ n } 2>/dev/null || true ` , {
encoding : "utf-8" ,
timeout : 1000 ,
} ) . trim ( ) ;
if ( comm === "pi" ) return true ;
// pi könnte eine Ebene tiefer laufen (z.B. via node-Wrapper)
if ( laeuftPiUnter ( n ) ) return true ;
}
return false ;
} catch {
return false ;
}
}
2026-06-02 16:02:03 +02:00
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
function laufendeSubagenten ( ) : LaufenderSubagent [ ] {
try {
const raw = execSync (
"tmux list-panes -a -F '#{session_name}::#{pane_pid}::#{pane_current_path}' 2>/dev/null || true" ,
{ encoding : "utf-8" , timeout : 2500 } ,
) . trim ( ) ;
if ( ! raw ) return [ ] ;
const ergebnis : LaufenderSubagent [ ] = [ ] ;
const gesehen = new Set < string > ( ) ;
for ( const line of raw . split ( "\n" ) ) {
const teile = line . split ( "::" ) ;
if ( teile . length < 3 ) continue ;
const name = teile [ 0 ] . trim ( ) ;
const panePid = Number ( teile [ 1 ] . trim ( ) ) ;
const path = teile [ 2 ] . trim ( ) ;
if ( ! name || gesehen . has ( name ) ) continue ;
if ( ! path . includes ( SUBAGENT_PFAD_MARKER ) ) continue ;
if ( ! Number . isInteger ( panePid ) ) continue ;
if ( ! laeuftPiUnter ( panePid ) ) continue ; // Pi nicht (mehr) aktiv ⇒ kein laufender Subagent
gesehen . add ( name ) ;
2026-06-02 16:02:03 +02:00
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
// Optional: Dialog-Inhalt zur Anreicherung der Weckmeldung
let dialog : string | null = null ;
2026-06-02 16:02:03 +02:00
try {
const pane = execSync (
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
` tmux capture-pane -t ' ${ name } ' -p 2>/dev/null | tail -8 ` ,
2026-06-02 16:02:03 +02:00
{ encoding : "utf-8" , timeout : 1000 } ,
) . trim ( ) ;
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
if (
/Erlauben\?|→ Yes|Überschreiben\?|ACHTUNG:|Bestätigung/ . test ( pane )
) {
dialog = pane ;
2026-06-02 16:02:03 +02:00
}
} catch { }
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
ergebnis . push ( { name , dialog } ) ;
}
return ergebnis ;
2026-06-02 16:02:03 +02:00
} catch {
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
return [ ] ;
2026-06-02 16:02:03 +02:00
}
}
// ---------------------------------------------------------------------------
// Extension
// ---------------------------------------------------------------------------
export default function ( pi : ExtensionAPI ) {
if ( ! ORCHESTRATOR_AKTIV ) return ;
let letzterVerstoss : string | null = null ;
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
let letzterCtx : any = null ;
let letzteAktivitaet = Date . now ( ) ;
let letzteWeckung = 0 ;
function markAktiv ( ctx? : any ) : void {
letzteAktivitaet = Date . now ( ) ;
if ( ctx ) letzterCtx = ctx ;
}
2026-06-02 16:02:03 +02:00
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
// ── 30s Background-Check: Invariante erzwingen ───────────────────────────
2026-06-02 16:02:03 +02:00
const interval = setInterval ( ( ) = > {
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
const subagenten = laufendeSubagenten ( ) ;
if ( subagenten . length === 0 ) return ; // kein laufender Subagent ⇒ idle ist erlaubt
const dialoge = subagenten . filter ( ( s ) = > s . dialog ) ;
const beschreibung = subagenten
. map (
( s ) = >
` • ${ s . name } ${ s . dialog ? " — WARTET AUF BESTÄTIGUNG" : " — läuft" } ` ,
)
. join ( "\n" ) ;
// Passiver Pfad: greift, falls der Orchestrator gerade in einem Turn ist
schreibeAlert (
` [30s-Check] Laufende Subagenten — Orchestrator muss überwachen: \ n ${ beschreibung } ` ,
) ;
// Idle-Erkennung: primär zeitbasiert (ctx-unabhängig)
const idleMs = Date . now ( ) - letzteAktivitaet ;
if ( idleMs < IDLE_SCHWELLE_MS ) return ; // Orchestrator aktiv ⇒ nichts tun
// Zusätzliches Veto, falls ctx zuverlässig "beschäftigt" meldet
try {
if ( letzterCtx && typeof letzterCtx . isIdle === "function" ) {
if ( letzterCtx . isIdle ( ) === false ) return ;
}
} catch { }
const jetzt = Date . now ( ) ;
if ( jetzt - letzteWeckung < WECK_MIN_ABSTAND_MS ) return ;
letzteWeckung = jetzt ;
const dringlich = dialoge . length > 0 ;
const dialogText = dialoge
. map ( ( d ) = > ` --- ${ d . name } --- \ n ${ d . dialog } ` )
. join ( "\n" ) ;
try {
letzterCtx ? . ui ? . notify ? . (
dringlich
? "🚨 Subagent wartet auf Bestätigung — Orchestrator wird geweckt."
: "⏱️ Subagent läuft, Orchestrator war idle — wird geweckt." ,
"warning" ,
) ;
} catch { }
try {
pi . sendUserMessage (
` 🚨 [Auto-Weckung] Es läuft mindestens ein Subagent, aber du warst idle. ` +
` Das ist nicht erlaubt, solange Subagenten laufen. \ n ${ beschreibung } \ n ` +
( dringlich
? ` \ nEin Subagent wartet auf eine Bestätigung: \ n ${ dialogText } \ n→ Sofort watch_subagents aufrufen, den Dialog prüfen und nach Regel bestätigen ODER den Benutzer informieren. \ n `
: ` ` ) +
` → Nimm die watch_subagents-Überwachung sofort wieder auf und halte sie, bis ALLE Subagenten fertig sind. ` ,
) ;
} catch { }
2026-06-02 16:02:03 +02:00
} , CHECK_INTERVAL_MS ) ;
pi . on ( "session_shutdown" , async ( ) = > {
clearInterval ( interval ) ;
} ) ;
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
// ── Aktivitäts-Tracking für die zeitbasierte Idle-Erkennung ──────────────
pi . on ( "turn_start" , async ( _e , ctx ) = > markAktiv ( ctx ) ) ;
pi . on ( "turn_end" , async ( _e , ctx ) = > markAktiv ( ctx ) ) ;
pi . on ( "message_start" , async ( _e , ctx ) = > markAktiv ( ctx ) ) ;
pi . on ( "message_update" , async ( _e , ctx ) = > markAktiv ( ctx ) ) ;
pi . on ( "tool_execution_start" , async ( _e , ctx ) = > markAktiv ( ctx ) ) ;
pi . on ( "tool_execution_end" , async ( _e , ctx ) = > markAktiv ( ctx ) ) ;
// ── message_end: W06-Scan + Aktivität ────────────────────────────────────
pi . on ( "message_end" , async ( event , ctx ) = > {
markAktiv ( ctx ) ;
2026-06-02 16:02:03 +02:00
const text = textAusNachricht ( event . message ) ;
if ( hatDeliberation ( text ) ) {
letzterVerstoss = "W06 (Internes Deliberieren)" ;
}
} ) ;
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
// ── before_agent_start: System-Prompt-Injection ──────────────────────────
pi . on ( "before_agent_start" , async ( event , ctx ) = > {
markAktiv ( ctx ) ;
2026-06-02 16:02:03 +02:00
let zusatz = ` \ n \ n--- \ n ${ KERN_REGELN } ` ;
if ( letzterVerstoss ) {
zusatz += ` \ n \ n⚠️ REGELVERSTOSS erkannt ( ${ letzterVerstoss } ): Diese Antwort OHNE Gedankenkommentar. Nur Ergebnis oder Entscheidung. ` ;
letzterVerstoss = null ;
}
const alerts = leseAlerts ( ) ;
if ( alerts ) {
fix/extensions: rule-enforcer erzwingt Invariante — Orchestrator nie idle während Subagent läuft
Root Cause (log-belegt, 36,6-min-Lücke 15:25–16:01): watch_subagents ist
ein Polling-Tool; die Überwachung lebt nur solange das LLM es neu aufruft.
Eine User-Zwischenfrage riss die Schleife ab, der Orchestrator ging idle.
Der passive Alert-File-Pfad (nur in before_agent_start gelesen) feuert bei
idle nie → Orchestrator schlief 36 min bis der Mensch tippte.
Fix: 30s-Check erkennt laufende Subagenten per Prozessbaum (lebt ein pi-Kind
unter dem tmux-Pane?), nicht per Keyword. Idle + laufender Subagent → aktive
Weckung via pi.sendUserMessage() (löst garantiert einen Turn aus) + ui.notify.
Idle-Erkennung zeitbasiert (45s, > 30s Pollintervall), ctx-unabhängig.
Verifiziert: Syntax, Modul-Load, Handler-Registrierung, Prompt-Injection,
W06, Prozessbaum-Erkennung an echten Sessions. NICHT verifiziert: Live-Weckpfad
(erfordert Orchestrator-Test). Plan: doku/fix-plan-orchestrator-wecker-v2026-06-02-18-19.md
2026-06-02 18:33:02 +02:00
zusatz += ` \ n \ n🚨 SUBAGENT-LAGE: \ n ${ alerts } \ n→ watch_subagents aufrufen und die Überwachung halten, bis alle Subagenten fertig sind. ` ;
2026-06-02 16:02:03 +02:00
}
return { systemPrompt : event.systemPrompt + zusatz } ;
} ) ;
}