fix(tmux-subagent): tighten serve/attach cleanup paths so panes and sessions are torn down reliably

Three defects observed with tmux.isolation="session" where the omo-agents
session was left with orphan fish panes after subagents finished:

1. cleanup() never ran 'tmux kill-session -t omo-agents'. If any pane
   lingered (for example because opencode attach stayed blocked on SSE),
   the isolated session survived process shutdown. Now we explicitly kill
   the shared session through killTmuxSessionIfExists when isolation is
   "session".

2. session.error events bypassed tmux cleanup entirely. Only session.deleted
   closed panes, so any provider error that did not escalate into a delete
   left the pane behind. Added onSessionError on TmuxSessionManager, wired
   from plugin/event.ts, which funnels through the same onSessionDeleted
   close path for tracked sessions only.

3. retryPendingCloses() only ran when a new session was created. If the
   main process went idle after a failed close, the pending session stayed
   pending forever. TmuxPollingManager now accepts the retry callback and
   fires it on every tick, alongside the existing stability-based close
   sweep.

Manager tests cover isolation=session kill invocation, inline/window
isolation skipping the kill, the onSessionError happy + untracked paths,
and an isolated-session kill failure that must not break cleanup.
This commit is contained in:
YeonGyu-Kim
2026-04-18 19:31:45 +09:00
parent de8a0167e6
commit 21554be870
4 changed files with 154 additions and 2 deletions
+4
View File
@@ -615,6 +615,10 @@ export function createEventHandler(args: {
const sessionID = props?.sessionID as string | undefined;
const error = props?.error;
if (tmuxIntegrationEnabled && sessionID) {
await managers.tmuxSessionManager.onSessionError({ sessionID });
}
const errorName = extractErrorName(error);
const errorMessage = extractErrorMessage(error);
const errorInfo = { name: errorName, message: errorMessage };