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 <noreply@anthropic.com>

* test(agent-launch): say how a local tab in a paired workspace closes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jinwoo Hong
2026-10-15 02:34:57 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 89d0ed1fd2
commit 8d09041634
2 changed files with 4 additions and 21 deletions
@@ -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 () => {
@@ -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<ReturnType<typeof createWebRuntimeSessionTerminal>>
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 ||