fix(tmux-subagent): retry pending pane closes to prevent zombie panes

When queryWindowState returned null during session deletion, the
session mapping was deleted but the real tmux pane stayed alive,
creating zombie panes.

- Add closePending/closeRetryCount fields to TrackedSession
- Mark sessions closePending instead of deleting on close failure
- Add retryPendingCloses() called from onSessionCreated and cleanup
- Force-remove mappings after 3 failed retry attempts
- Extract TrackedSessionState helper for field initialization

Tests: 3 pass, 9 expects
This commit is contained in:
YeonGyu-Kim
2026-03-11 20:09:56 +09:00
parent a2f030e699
commit fed720dd11
6 changed files with 437 additions and 73 deletions
@@ -6,6 +6,7 @@ import { queryWindowState } from "./pane-state-querier"
import { decideSpawnActions, type SessionMapping } from "./decision-engine"
import { executeActions } from "./action-executor"
import type { SessionCreatedEvent } from "./session-created-event"
import { createTrackedSession } from "./tracked-session-state"
type OpencodeClient = PluginInput["client"]
@@ -152,14 +153,14 @@ export async function handleSessionCreated(
return
}
const now = Date.now()
deps.sessions.set(sessionId, {
deps.sessions.set(
sessionId,
paneId: result.spawnedPaneId,
description: title,
createdAt: new Date(now),
lastSeenAt: new Date(now),
})
createTrackedSession({
sessionId,
paneId: result.spawnedPaneId,
description: title,
}),
)
log("[tmux-session-manager] pane spawned and tracked", {
sessionId,