diff --git a/pkg/agentic/dispatch_sync.go b/pkg/agentic/dispatch_sync.go index fb0776d..df46f8c 100644 --- a/pkg/agentic/dispatch_sync.go +++ b/pkg/agentic/dispatch_sync.go @@ -4,7 +4,6 @@ package agentic import ( "context" - "syscall" "time" core "dappco.re/go/core" @@ -80,7 +79,7 @@ func (s *PrepSubsystem) DispatchSync(ctx context.Context, input DispatchSyncInpu case <-ctx.Done(): return DispatchSyncResult{Error: "cancelled"} case <-ticker.C: - if pid > 0 && syscall.Kill(pid, 0) != nil { + if pid > 0 && !PIDAlive(pid) { // Process exited — read final status st, err := ReadStatus(wsDir) if err != nil { diff --git a/pkg/agentic/proc.go b/pkg/agentic/proc.go index 4e845db..d4c1410 100644 --- a/pkg/agentic/proc.go +++ b/pkg/agentic/proc.go @@ -65,20 +65,20 @@ func (s *PrepSubsystem) gitOutput(ctx context.Context, dir string, args ...strin // --- Process lifecycle helpers --- -// processIsRunning checks if a process is still alive via PID signal check. +// PIDAlive checks if an OS process is still alive via PID signal check. // -// if processIsRunning(st.ProcessID, st.PID) { ... } -func processIsRunning(processID string, pid int) bool { +// if agentic.PIDAlive(st.PID) { ... } +func PIDAlive(pid int) bool { if pid > 0 { return syscall.Kill(pid, 0) == nil } return false } -// processKill terminates a process via SIGTERM. +// PIDTerminate terminates a process via SIGTERM. // -// processKill(st.ProcessID, st.PID) -func processKill(processID string, pid int) bool { +// if agentic.PIDTerminate(st.PID) { ... } +func PIDTerminate(pid int) bool { if pid > 0 { return syscall.Kill(pid, syscall.SIGTERM) == nil } diff --git a/pkg/agentic/proc_test.go b/pkg/agentic/proc_test.go index c1a10fb..5186b33 100644 --- a/pkg/agentic/proc_test.go +++ b/pkg/agentic/proc_test.go @@ -179,38 +179,38 @@ func TestProc_GitOutput_Ugly(t *testing.T) { assert.Equal(t, "", out) } -// --- processIsRunning --- +// --- PIDAlive --- -func TestProc_ProcessIsRunning_Good(t *testing.T) { +func TestProc_PIDAlive_Good(t *testing.T) { // Own PID should be running pid, _ := strconv.Atoi(core.Env("PID")) - assert.True(t, processIsRunning("", pid)) + assert.True(t, PIDAlive(pid)) } -func TestProc_ProcessIsRunning_Bad(t *testing.T) { +func TestProc_PIDAlive_Bad(t *testing.T) { // PID 999999 should not be running (extremely unlikely to exist) - assert.False(t, processIsRunning("", 999999)) + assert.False(t, PIDAlive(999999)) } -func TestProc_ProcessIsRunning_Ugly(t *testing.T) { +func TestProc_PIDAlive_Ugly(t *testing.T) { // PID 0 — should return false (invalid PID guard: pid > 0 is false for 0) - assert.False(t, processIsRunning("", 0)) + assert.False(t, PIDAlive(0)) } -// --- processKill --- +// --- PIDTerminate --- -func TestProc_ProcessKill_Good(t *testing.T) { +func TestProc_PIDTerminate_Good(t *testing.T) { t.Skip("would need real process to kill") } -func TestProc_ProcessKill_Bad(t *testing.T) { +func TestProc_PIDTerminate_Bad(t *testing.T) { // PID 999999 should fail to kill - assert.False(t, processKill("", 999999)) + assert.False(t, PIDTerminate(999999)) } -func TestProc_ProcessKill_Ugly(t *testing.T) { +func TestProc_PIDTerminate_Ugly(t *testing.T) { // PID 0 — pid > 0 guard returns false - assert.False(t, processKill("", 0)) + assert.False(t, PIDTerminate(0)) } // --- initTestRepo creates a git repo with commits for proc tests --- diff --git a/pkg/agentic/queue.go b/pkg/agentic/queue.go index 3a3690e..f625329 100644 --- a/pkg/agentic/queue.go +++ b/pkg/agentic/queue.go @@ -4,7 +4,6 @@ package agentic import ( "strconv" - "syscall" "time" core "dappco.re/go/core" @@ -167,10 +166,8 @@ func (s *PrepSubsystem) countRunningByAgent(agent string) int { if s.workspaces != nil && s.workspaces.Len() > 0 { count := 0 s.workspaces.Each(func(_ string, st *WorkspaceStatus) { - if st.Status == "running" && baseAgent(st.Agent) == agent { - if st.PID > 0 && syscall.Kill(st.PID, 0) == nil { - count++ - } + if st.Status == "running" && baseAgent(st.Agent) == agent && PIDAlive(st.PID) { + count++ } }) return count @@ -192,7 +189,7 @@ func (s *PrepSubsystem) countRunningByAgentDisk(agent string) int { if baseAgent(st.Agent) != agent { continue } - if st.PID > 0 && syscall.Kill(st.PID, 0) == nil { + if PIDAlive(st.PID) { count++ } } @@ -207,10 +204,8 @@ func (s *PrepSubsystem) countRunningByModel(agent string) int { if s.workspaces != nil && s.workspaces.Len() > 0 { count := 0 s.workspaces.Each(func(_ string, st *WorkspaceStatus) { - if st.Status == "running" && st.Agent == agent { - if st.PID > 0 && syscall.Kill(st.PID, 0) == nil { - count++ - } + if st.Status == "running" && st.Agent == agent && PIDAlive(st.PID) { + count++ } }) return count @@ -226,7 +221,7 @@ func (s *PrepSubsystem) countRunningByModel(agent string) int { if st.Agent != agent { continue } - if st.PID > 0 && syscall.Kill(st.PID, 0) == nil { + if PIDAlive(st.PID) { count++ } } diff --git a/pkg/agentic/status.go b/pkg/agentic/status.go index d73e526..2d75ebe 100644 --- a/pkg/agentic/status.go +++ b/pkg/agentic/status.go @@ -4,7 +4,6 @@ package agentic import ( "context" - "syscall" "time" core "dappco.re/go/core" @@ -142,7 +141,7 @@ func (s *PrepSubsystem) status(ctx context.Context, _ *mcp.CallToolRequest, inpu // If status is "running", check if PID is still alive if st.Status == "running" && st.PID > 0 { - if err := syscall.Kill(st.PID, 0); err != nil { + if !PIDAlive(st.PID) { blockedPath := workspaceBlockedPath(wsDir) if r := fs.Read(blockedPath); r.OK { st.Status = "blocked" diff --git a/pkg/monitor/monitor.go b/pkg/monitor/monitor.go index 4af86f1..cf7e1b5 100644 --- a/pkg/monitor/monitor.go +++ b/pkg/monitor/monitor.go @@ -10,7 +10,6 @@ package monitor import ( "context" "sync" - "syscall" "time" "dappco.re/go/agent/pkg/agentic" @@ -297,10 +296,7 @@ func (m *Subsystem) countLiveWorkspaces() (running, queued int) { // pidAlive checks whether a process is still running. func pidAlive(pid int) bool { - if pid <= 0 { - return false - } - return syscall.Kill(pid, 0) == nil + return agentic.PIDAlive(pid) } func (m *Subsystem) loop(ctx context.Context) { diff --git a/pkg/runner/queue.go b/pkg/runner/queue.go index 895f73d..6be1080 100644 --- a/pkg/runner/queue.go +++ b/pkg/runner/queue.go @@ -4,7 +4,6 @@ package runner import ( "strconv" - "syscall" "time" "dappco.re/go/agent/pkg/agentic" @@ -170,7 +169,7 @@ func (s *Service) countRunningByAgent(agent string) int { switch { case st.PID < 0: count++ - case st.PID > 0 && syscall.Kill(st.PID, 0) == nil: + case st.PID > 0 && agentic.PIDAlive(st.PID): count++ } }) @@ -189,7 +188,7 @@ func (s *Service) countRunningByModel(agent string) int { switch { case st.PID < 0: count++ - case st.PID > 0 && syscall.Kill(st.PID, 0) == nil: + case st.PID > 0 && agentic.PIDAlive(st.PID): count++ } }) diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index f5b32bc..8115af6 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -10,7 +10,6 @@ package runner import ( "context" "sync" - "syscall" "time" "dappco.re/go/agent/pkg/agentic" @@ -338,7 +337,7 @@ func (s *Service) actionKill(_ context.Context, _ core.Options) core.Result { killed := 0 s.workspaces.Each(func(_ string, st *WorkspaceStatus) { if st.Status == "running" && st.PID > 0 { - if syscall.Kill(st.PID, syscall.SIGTERM) == nil { + if agentic.PIDTerminate(st.PID) { killed++ } st.Status = "failed"