From 60e7471cea9ab17aeba0defa36964a198bc420ec Mon Sep 17 00:00:00 2001 From: furiosa Date: Tue, 6 Jan 2026 13:17:40 -0800 Subject: [PATCH] fix(witness): Kill tmux session on Stop() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The witness manager's Stop() method was only updating runtime JSON state without killing the tmux session, causing 'gt rig shutdown' to leave witness sessions running. Added sessionName() method and tmux kill-session logic to match the refinery's existing implementation. Fixes: bd-gxaf 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/witness/manager.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/internal/witness/manager.go b/internal/witness/manager.go index 77933a04..588e6a0d 100644 --- a/internal/witness/manager.go +++ b/internal/witness/manager.go @@ -2,11 +2,13 @@ package witness import ( "errors" + "fmt" "os" "time" "github.com/steveyegge/gastown/internal/agent" "github.com/steveyegge/gastown/internal/rig" + "github.com/steveyegge/gastown/internal/tmux" "github.com/steveyegge/gastown/internal/util" ) @@ -52,6 +54,11 @@ func (m *Manager) saveState(w *Witness) error { return m.stateManager.Save(w) } +// sessionName returns the tmux session name for this witness. +func (m *Manager) sessionName() string { + return fmt.Sprintf("gt-%s-witness", m.rig.Name) +} + // Status returns the current witness status. // ZFC-compliant: trusts agent-reported state, no PID inference. // The daemon reads agent bead state for liveness checks. @@ -95,12 +102,23 @@ func (m *Manager) Stop() error { return err } - if w.State != StateRunning { + // Check if tmux session exists + t := tmux.NewTmux() + sessionID := m.sessionName() + sessionRunning, _ := t.HasSession(sessionID) + + // If neither state nor session indicates running, it's not running + if w.State != StateRunning && !sessionRunning { return ErrNotRunning } + // Kill tmux session if it exists (best-effort: may already be dead) + if sessionRunning { + _ = t.KillSession(sessionID) + } + // If we have a PID, try to stop it gracefully - if w.PID > 0 && w.PID != os.Getpid() { + if w.PID > 0 && w.PID != os.Getpid() && util.ProcessExists(w.PID) { // Send SIGTERM (best-effort graceful stop) if proc, err := os.FindProcess(w.PID); err == nil { _ = proc.Signal(os.Interrupt)