diff --git a/src/features/tmux-subagent/action-executor.ts b/src/features/tmux-subagent/action-executor.ts index 0ebbd4378..afdddfbf8 100644 --- a/src/features/tmux-subagent/action-executor.ts +++ b/src/features/tmux-subagent/action-executor.ts @@ -61,13 +61,30 @@ async function enforceLayoutAndMainPane(ctx: ExecuteContext): Promise { await enforceMainPane(latestState, ctx.config) } +/** + * Returns true when the pane lives in the source window's tracked layout. + * + * The wrapper enforces the user's main-vertical layout against the source pane + * after destructive actions. That is correct when the affected pane was part of + * the source window (its removal changes the user's split arrangement) but + * actively harmful when the pane lived in a separate window — closing an + * isolated container in another window should not scramble the user's main + * window layout. Callers route both cases through the same close action, so we + * detect the relationship from `windowState`. + */ +function isPaneInSourceWindow(paneId: string, windowState: WindowState): boolean { + if (windowState.mainPane?.paneId === paneId) return true + return windowState.agentPanes.some((pane) => pane.paneId === paneId) +} + export async function executeAction( action: PaneAction, ctx: ExecuteContext ): Promise { if (action.type === "close") { + const closingPaneInSourceWindow = isPaneInSourceWindow(action.paneId, ctx.windowState) const success = await closeTmuxPane(action.paneId) - if (success) { + if (success && closingPaneInSourceWindow) { await enforceLayoutAndMainPane(ctx) } return { success }