From 5c879bf79f142d2ebe2c1f116e149b383da13316 Mon Sep 17 00:00:00 2001 From: "buf0-bot[bot]" <252831055+buf0-bot[bot]@users.noreply.github.com> Date: Thu, 14 May 2026 12:41:53 -0700 Subject: [PATCH] fix: address pr-bug-scan validated finding from #1837 (#1856) Added leaveWorktreeIfEmpty follow-up in TerminalPaneOverlayLayer onPtyExit/onCloseTab so closing the last terminal deselects the worktree and returns to Landing. Co-authored-by: orca-bug-scan-bot --- .../TerminalPaneOverlayLayer.tsx | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/components/terminal-pane/TerminalPaneOverlayLayer.tsx b/src/renderer/src/components/terminal-pane/TerminalPaneOverlayLayer.tsx index dc37ff298b0..b734b8b7e18 100644 --- a/src/renderer/src/components/terminal-pane/TerminalPaneOverlayLayer.tsx +++ b/src/renderer/src/components/terminal-pane/TerminalPaneOverlayLayer.tsx @@ -32,6 +32,7 @@ type TerminalOverlaySlotProps = { onFocusOwningGroup: ((groupId: string) => void) | undefined consumeSuppressedPtyExit: (ptyId: string) => boolean closeTab: (tabId: string) => void + leaveWorktreeIfEmpty: () => void } const TerminalOverlaySlot = memo(function TerminalOverlaySlot({ @@ -45,7 +46,8 @@ const TerminalOverlaySlot = memo(function TerminalOverlaySlot({ activityTerminalPortal, onFocusOwningGroup, consumeSuppressedPtyExit, - closeTab + closeTab, + leaveWorktreeIfEmpty }: TerminalOverlaySlotProps): React.JSX.Element { const anchorName = groupId !== undefined ? tabGroupBodyAnchorName(groupId) : undefined const style: React.CSSProperties = useMemo( @@ -95,8 +97,12 @@ const TerminalOverlaySlot = memo(function TerminalOverlaySlot({ return } closeTab(terminalTabId) + leaveWorktreeIfEmpty() + }} + onCloseTab={() => { + closeTab(terminalTabId) + leaveWorktreeIfEmpty() }} - onCloseTab={() => closeTab(terminalTabId)} /> ) @@ -142,6 +148,25 @@ const TerminalPaneOverlayLayer = memo(function TerminalPaneOverlayLayer({ const focusGroup = useAppStore((state) => state.focusGroup) const consumeSuppressedPtyExit = useAppStore((state) => state.consumeSuppressedPtyExit) const closeTab = useAppStore((state) => state.closeTab) + const setActiveWorktree = useAppStore((state) => state.setActiveWorktree) + const reconcileWorktreeTabModel = useAppStore((state) => state.reconcileWorktreeTabModel) + + // Why: legacy TabGroupPanel routed terminal closes through + // commands.closeItem → leaveWorktreeIfEmpty, which deselected the worktree + // when the last renderable tab closed and sent the user back to Landing. + // The overlay layer calls store.closeTab directly, so replicate that + // post-close check here; otherwise closing the last terminal leaves an + // empty TabGroupPanel body selected. + const leaveWorktreeIfEmpty = useCallback(() => { + const state = useAppStore.getState() + if (state.activeWorktreeId !== worktreeId) { + return + } + const { renderableTabCount } = reconcileWorktreeTabModel(worktreeId) + if (renderableTabCount === 0) { + setActiveWorktree(null) + } + }, [reconcileWorktreeTabModel, setActiveWorktree, worktreeId]) const focusOwningGroup = useCallback( (groupId: string) => focusGroup(worktreeId, groupId), @@ -199,6 +224,7 @@ const TerminalPaneOverlayLayer = memo(function TerminalPaneOverlayLayer({ onFocusOwningGroup={focusOwningGroup} consumeSuppressedPtyExit={consumeSuppressedPtyExit} closeTab={closeTab} + leaveWorktreeIfEmpty={leaveWorktreeIfEmpty} /> ) })}