diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index 2e57c501d..e2052dc28 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -1091,6 +1091,7 @@ describe('TmuxSessionManager', () => { paneId: '%isolated-session-ses_first', sessionId: 'ses_first', }) + expect(Reflect.get(manager, 'isolatedContainerPaneId')).toBeUndefined() expect(Reflect.get(manager, 'isolatedWindowPaneId')).toBeUndefined() }) @@ -1177,18 +1178,25 @@ describe('TmuxSessionManager', () => { // then expect(mockExecuteAction).toHaveBeenCalledTimes(0) + expect(Reflect.get(manager, 'isolatedContainerPaneId')).toBe('%isolated-session-ses_first') expect(Reflect.get(manager, 'isolatedWindowPaneId')).toBe('%mock') // when await manager.onSessionDeleted({ sessionID: 'ses_second' }) // then - expect(mockExecuteAction).toHaveBeenCalledTimes(1) + expect(mockExecuteAction).toHaveBeenCalledTimes(2) expect(mockExecuteAction.mock.calls[0]?.[0]).toEqual({ type: 'close', paneId: '%mock', sessionId: 'ses_second', }) + expect(mockExecuteAction.mock.calls[1]?.[0]).toEqual({ + type: 'close', + paneId: '%isolated-session-ses_first', + sessionId: 'ses_second', + }) + expect(Reflect.get(manager, 'isolatedContainerPaneId')).toBeUndefined() expect(Reflect.get(manager, 'isolatedWindowPaneId')).toBeUndefined() }) diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index 5fd39cbe1..403efb7c5 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -70,6 +70,7 @@ export class TmuxSessionManager { private nullStateCount = 0 private deps: TmuxUtilDeps private pollingManager: TmuxPollingManager + private isolatedContainerPaneId: string | undefined private isolatedWindowPaneId: string | undefined constructor(ctx: PluginInput, tmuxConfig: TmuxConfig, deps: TmuxUtilDeps = defaultTmuxDeps) { this.client = ctx.client @@ -125,6 +126,7 @@ export class TmuxSessionManager { if (this.isolatedWindowPaneId) { const state = await queryWindowState(this.isolatedWindowPaneId).catch(() => null) if (state) return null + this.isolatedContainerPaneId = undefined this.isolatedWindowPaneId = undefined } @@ -136,6 +138,7 @@ export class TmuxSessionManager { : await spawnTmuxWindow(sessionId, title, this.tmuxConfig, this.serverUrl) if (result.success && result.paneId) { + this.isolatedContainerPaneId = result.paneId this.isolatedWindowPaneId = result.paneId log("[tmux-session-manager] isolated container created", { isolation, @@ -172,10 +175,10 @@ export class TmuxSessionManager { } } - private reassignIsolatedContainerAnchor(): boolean { + private reassignIsolatedContainerAnchor(): void { const nextAnchor = this.sessions.values().next().value if (!nextAnchor) { - return false + return } this.isolatedWindowPaneId = nextAnchor.paneId @@ -183,7 +186,6 @@ export class TmuxSessionManager { sessionId: nextAnchor.sessionId, paneId: nextAnchor.paneId, }) - return true } private async cleanupIsolatedContainerAfterSessionDeletion( @@ -196,22 +198,25 @@ export class TmuxSessionManager { } if (this.sessions.size > 0) { - if (this.reassignIsolatedContainerAnchor()) { - return - } - + this.reassignIsolatedContainerAnchor() return } + const isolatedContainerPaneId = this.isolatedContainerPaneId + this.isolatedContainerPaneId = undefined this.isolatedWindowPaneId = undefined - if (isolatedPaneAlreadyClosed) { + if (!isolatedContainerPaneId) { + return + } + + if (isolatedPaneAlreadyClosed && tracked.paneId === isolatedContainerPaneId) { return } try { const result = await executeAction( - { type: "close", paneId: tracked.paneId, sessionId: tracked.sessionId }, + { type: "close", paneId: isolatedContainerPaneId, sessionId: tracked.sessionId }, { config: this.tmuxConfig, serverUrl: this.serverUrl, @@ -223,13 +228,13 @@ export class TmuxSessionManager { if (!result.success) { log("[tmux-session-manager] failed to close isolated container pane after anchor session deletion", { sessionId: tracked.sessionId, - paneId: tracked.paneId, + paneId: isolatedContainerPaneId, }) } } catch (error) { log("[tmux-session-manager] failed to cleanup isolated container pane after anchor session deletion", { sessionId: tracked.sessionId, - paneId: tracked.paneId, + paneId: isolatedContainerPaneId, error: String(error), }) } @@ -855,6 +860,7 @@ export class TmuxSessionManager { } await this.retryPendingCloses() + this.isolatedContainerPaneId = undefined this.isolatedWindowPaneId = undefined log("[tmux-session-manager] cleanup complete")