diff --git a/.opencode/agents/product-builder.md b/.opencode/agents/product-builder.md index f3d8ae788..e74c75f5b 100644 --- a/.opencode/agents/product-builder.md +++ b/.opencode/agents/product-builder.md @@ -359,6 +359,55 @@ milestones = list of all milestones to complete (ordered) ref_summary = result from ca-ref-reader SERVER = "http://localhost:4096" +# ── PHASE C.0: Clean Up Stale Supervisor Sessions ─────────────── +# If the product-builder was previously interrupted (Ctrl+C, crash, +# session timeout, etc.), old supervisor sessions launched via +# prompt_async may still be running on the server. They are +# independent sessions that survive the product-builder's death. +# +# We MUST find and abort them before launching fresh supervisors, +# otherwise there will be duplicate supervisors competing for the +# same work — duplicate PR reviews, conflicting git pushes, etc. +# +# Identification: All supervisor sessions have titles starting with +# "[CA-AUTO] supervisor:". This prefix is unique to product-builder- +# managed supervisors and will not match user-created sessions. + +# Step 1: Query all sessions from the server +ALL_SESSIONS=$(bash("curl -s ${SERVER}/session", timeout=30000)) + +# Step 2: Extract sessions whose title starts with "[CA-AUTO] supervisor:" +# Use python3 to parse JSON and filter: +STALE_IDS=$(bash("echo '${ALL_SESSIONS}' | python3 -c \" +import sys, json +sessions = json.loads(sys.stdin.read()) +for s in sessions: + if s.get('title', '').startswith('[CA-AUTO] supervisor:'): + print(s['id']) +\"", timeout=30000)) + +# Step 3: Abort and delete each stale session +stale_count = 0 +for session_id in STALE_IDS (one per line): + # Abort if still running + bash("curl -s -X POST ${SERVER}/session/${session_id}/abort", timeout=15000) + # Delete the session entirely to avoid clutter + bash("curl -s -X DELETE ${SERVER}/session/${session_id}", timeout=15000) + stale_count += 1 + +# Step 4: Clean up tracking file from previous run +bash("rm -f /tmp/ca-supervisor-sessions.env", timeout=5000) + +# Step 5: Log cleanup results +if stale_count > 0: + invoke ca-session-persister with: + checkpoint: "Phase C.0: Cleaned up stale supervisor + sessions from a previous interrupted run. + All old supervisors aborted and deleted." +else: + # No stale sessions — first run or clean shutdown previously. + pass + # ── PHASE C.1: Planning (if needed) ───────────────────────────── # If there are milestones with no issues yet, plan them first. # This is the ONLY step that uses the Task tool (one-shot planners). @@ -411,7 +460,7 @@ function launch_supervisor(agent_name, display_name, prompt_text): # Step 1: Create a session SESSION_ID=$(curl -s -X POST "${SERVER}/session" \ -H "Content-Type: application/json" \ - -d "{\"title\": \"supervisor: ${display_name}\"}" \ + -d "{\"title\": \"[CA-AUTO] supervisor: ${display_name}\"}" \ | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['id'])") # Step 2: Fire-and-forget launch via prompt_async