From ac510fde196ae95e55da23b938cbec18e20a62a1 Mon Sep 17 00:00:00 2001 From: Snider Date: Thu, 26 Mar 2026 14:02:56 +0000 Subject: [PATCH] =?UTF-8?q?fix(agentic):=20handle=20SpawnQueued=20IPC=20?= =?UTF-8?q?=E2=80=94=20actually=20spawn=20agents=20from=20queue=20drain?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runner's drainOne sends SpawnQueued but agentic never handled it, creating ghost "running" entries with PID=0. Now agentic catches SpawnQueued, calls spawnAgent, and updates status with real PID. Co-Authored-By: Virgil --- pkg/agentic/handlers.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pkg/agentic/handlers.go b/pkg/agentic/handlers.go index 3954053..e4878b7 100644 --- a/pkg/agentic/handlers.go +++ b/pkg/agentic/handlers.go @@ -27,6 +27,27 @@ func (s *PrepSubsystem) HandleIPCEvents(c *core.Core, msg core.Message) core.Res s.ingestFindings(wsDir) } } + + case messages.SpawnQueued: + // Runner asks agentic to spawn a queued workspace + wsDir := resolveWorkspace(ev.Workspace) + if wsDir == "" { + break + } + prompt := core.Concat("TASK: ", ev.Task, "\n\nResume from where you left off. Read CODEX.md for conventions. Commit when done.") + pid, outputFile, err := s.spawnAgent(ev.Agent, prompt, wsDir) + if err != nil { + break + } + // Update status with real PID + if st, serr := ReadStatus(wsDir); serr == nil { + st.PID = pid + writeStatus(wsDir, st) + if runnerSvc, ok := core.ServiceFor[workspaceTracker](c, "runner"); ok { + runnerSvc.TrackWorkspace(core.PathBase(wsDir), st) + } + } + _ = outputFile } return core.Result{OK: true}