From 8d09041634f0de4bb29e6a0bb57dc9c1948c0bb4 Mon Sep 17 00:00:00 2001 From: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com> Date: Thu, 15 Oct 2026 02:34:57 -0400 Subject: [PATCH] refactor(agent-launch): launching into a paired-server workspace stops closing local agent tabs (#29015) * refactor(agent-launch): a paired-workspace launch stops closing local agent tabs The prune existed because a local tab in a paired workspace once could not be closed (its close went only to the host). Today a local id closes locally and the host close no-ops, and every present-day launch into a paired workspace creates its tab through the host, under a host-surface id. Co-Authored-By: Claude Opus 5.5 * test(agent-launch): say how a local tab in a paired workspace closes Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- ...aunch-agent-in-new-tab-web-runtime.test.ts | 5 +++-- .../src/lib/launch-agent-web-host-tab.ts | 20 +------------------ 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/renderer/src/lib/launch-agent-in-new-tab-web-runtime.test.ts b/src/renderer/src/lib/launch-agent-in-new-tab-web-runtime.test.ts index 3fe745efeb5..903c7d51d13 100644 --- a/src/renderer/src/lib/launch-agent-in-new-tab-web-runtime.test.ts +++ b/src/renderer/src/lib/launch-agent-in-new-tab-web-runtime.test.ts @@ -82,7 +82,7 @@ describe('launchAgentInNewTab paired web runtime', () => { }) it('delegates agent quick launch to the host runtime', async () => { - store.tabsByWorktree['wt-1'].push({ id: 'stale-agent-tab', launchAgent: 'claude' }) + store.tabsByWorktree['wt-1'].push({ id: 'local-agent-tab', launchAgent: 'claude' }) const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab') const result = launchAgentInNewTab({ @@ -111,7 +111,8 @@ describe('launchAgentInNewTab paired web runtime', () => { await Promise.resolve() // Why: host creation is async, so the user may be viewing another worktree by the time it lands. expect(mocks.setActiveTabType).toHaveBeenCalledExactlyOnceWith('terminal', 'wt-1') - expect(mocks.closeTab).toHaveBeenCalledWith('stale-agent-tab', { reason: 'cleanup' }) + // A local tab closes locally (the host close no-ops), so a launch leaves it alone. + expect(mocks.closeTab).not.toHaveBeenCalled() }) it('forwards prompt launch env and captured config to the host runtime', async () => { diff --git a/src/renderer/src/lib/launch-agent-web-host-tab.ts b/src/renderer/src/lib/launch-agent-web-host-tab.ts index e23851eb3b9..16fb8da79bd 100644 --- a/src/renderer/src/lib/launch-agent-web-host-tab.ts +++ b/src/renderer/src/lib/launch-agent-web-host-tab.ts @@ -5,7 +5,6 @@ import { createWebRuntimeAgentSessionTerminalWithLaunchDraft, createWebRuntimeSessionTerminal } from '@/runtime/web-runtime-terminal-creation' -import { isWebTerminalSurfaceTabId } from '../../../shared/terminal-surface-id' import type { AgentStartupPlan } from '@/lib/tui-agent-startup' import type { Tab } from '../../../shared/tab-types' import type { TuiAgent } from '../../../shared/tui-agent' @@ -13,24 +12,11 @@ import type { AgentPromptDelivery } from '../../../shared/agent-session-host-aut import { translate } from '@/i18n/i18n' import { toAgentLaunchPreferences } from '../../../shared/agent-launch-preferences' -function removeStaleLocalAgentTabsForWebHostLaunch(worktreeId: string): void { - const state = useAppStore.getState() - for (const tab of state.tabsByWorktree[worktreeId] ?? []) { - if (tab.launchAgent && !isWebTerminalSurfaceTabId(tab.id)) { - // Why: pruning a stale local agent tab is a system close — keep it out of - // the Cmd+Shift+T reopen stack. - state.closeTab(tab.id, { reason: 'cleanup' }) - } - } -} - /** * Launch an agent terminal on the web runtime host instead of a local tab. * * Why: paired web tabs are host-owned, so this path never creates a local tab - * (callers return tabId: null). Local-only agent tabs cannot be closed because - * close routes through session.tabs.close on the host, so prune them before - * the host snapshot. + * (callers return tabId: null). */ export function launchAgentInWebHostTab(args: { agent: TuiAgent @@ -66,7 +52,6 @@ export function launchAgentInWebHostTab(args: { const launchPreferences = toAgentLaunchPreferences(startupPlan.sessionOptions) const structuredPromptDelivery: AgentPromptDelivery = promptDelivery === 'draft' ? 'draft' : 'auto-submit' - removeStaleLocalAgentTabsForWebHostLaunch(worktreeId) const launch = { worktreeId, environmentId, @@ -101,9 +86,6 @@ export function launchAgentInWebHostTab(args: { outcome: Awaited> promptDelivered: boolean }): { delivered: boolean; failureNotified: boolean } => { - // Why: created means the host accepted the launch, not that a local tab - // exists; keep pruning stale local rows until the snapshot mirrors. - removeStaleLocalAgentTabsForWebHostLaunch(worktreeId) if (outcome.status === 'failed') { toast.error( outcome.message ||