Bug
gr spawn down --agent <name> reports "force-killed (did not exit within 10s)" even when the agent exits cleanly after receiving /exit.
Root cause
Two issues:
1. Default timeout too short (10s)
Claude Code's /exit runs hooks (precompact, journal writes, session save) that can take 10-15s on an M2 Air. The polling loop expires while the agent is still gracefully shutting down.
Fix: Increase default from 10s to 30s.
2. Stale state in Phase 3
Phase 3 reports from the Phase 2 states[i] vector without re-checking. If the agent exits between the polling deadline and the kill-window call, it's reported as "force-killed" based on stale state.
Fix: For agents that timed out in Phase 2, do one final pane_exit_state() check before kill-window:
let final_state = if states[i] == PaneState::Running {
match pane_exit_state(session, name) {
Some(true) => PaneState::Exited,
_ => PaneState::Running,
}
} else {
states[i]
};
// Then kill-window, then report using final_state
Impact
Cosmetic only. Agents do exit cleanly; the output is misleading.
Location
src/cli/commands/spawn.rs lines 532-534 (timeout default), 620-680 (polling + reporting)
Bug
gr spawn down --agent <name>reports "force-killed (did not exit within 10s)" even when the agent exits cleanly after receiving/exit.Root cause
Two issues:
1. Default timeout too short (10s)
Claude Code's
/exitruns hooks (precompact, journal writes, session save) that can take 10-15s on an M2 Air. The polling loop expires while the agent is still gracefully shutting down.Fix: Increase default from 10s to 30s.
2. Stale state in Phase 3
Phase 3 reports from the Phase 2
states[i]vector without re-checking. If the agent exits between the polling deadline and thekill-windowcall, it's reported as "force-killed" based on stale state.Fix: For agents that timed out in Phase 2, do one final
pane_exit_state()check beforekill-window:Impact
Cosmetic only. Agents do exit cleanly; the output is misleading.
Location
src/cli/commands/spawn.rslines 532-534 (timeout default), 620-680 (polling + reporting)