From ce1a9d4cdf8991e574c8d2ed5186d554c589c76d Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Fri, 10 Jul 2026 15:49:41 -0700 Subject: [PATCH] Extract web-host agent launch path to fix max-lines lint break on main (#8174) launch-agent-in-new-tab.ts crossed the 300-line oxlint max-lines limit (303 counted lines) after #5510 and #7944 both grew it; verify only runs on PRs, so the over-limit state landed on main via a merge race and now fails lint for every open PR. Move the web-runtime host launch branch (stale-local-tab pruning plus createWebRuntimeSessionTerminal call) into launch-agent-web-host-tab.ts. No behavior change; the i18n key is kept so locale catalogs are untouched. Co-authored-by: Brennan Benson --- .../src/lib/launch-agent-in-new-tab.ts | 58 ++------------ .../src/lib/launch-agent-web-host-tab.ts | 75 +++++++++++++++++++ 2 files changed, 83 insertions(+), 50 deletions(-) create mode 100644 src/renderer/src/lib/launch-agent-web-host-tab.ts diff --git a/src/renderer/src/lib/launch-agent-in-new-tab.ts b/src/renderer/src/lib/launch-agent-in-new-tab.ts index 9ceca2e382a..52255ac16cf 100644 --- a/src/renderer/src/lib/launch-agent-in-new-tab.ts +++ b/src/renderer/src/lib/launch-agent-in-new-tab.ts @@ -14,11 +14,8 @@ import { initialAgentTabViewModeProps } from '@/lib/native-chat-initial-view-mod import { isNativeChatTranscriptLocalReadable } from '@/lib/native-chat-transcript-readability' import { getRuntimeEnvironmentIdForWorktree } from '@/lib/worktree-runtime-owner' import { getLocalProjectExecutionRuntimeContext } from '@/lib/local-preflight-context' -import { - createWebRuntimeSessionTerminal, - isWebRuntimeSessionActive, - isWebTerminalSurfaceTabId -} from '@/runtime/web-runtime-session' +import { isWebRuntimeSessionActive } from '@/runtime/web-runtime-session' +import { launchAgentInWebHostTab } from '@/lib/launch-agent-web-host-tab' import { resolveTuiAgentLaunchArgs, resolveTuiAgentLaunchEnv @@ -58,15 +55,6 @@ export type LaunchAgentInNewTabArgs = { onPromptDelivered?: () => void } -function removeStaleLocalAgentTabsForWebHostLaunch(worktreeId: string): void { - const state = useAppStore.getState() - for (const tab of state.tabsByWorktree[worktreeId] ?? []) { - if (tab.launchAgent && !isWebTerminalSurfaceTabId(tab.id)) { - state.closeTab(tab.id) - } - } -} - export type LaunchAgentInNewTabResult = { tabId: string | null startupPlan: AgentStartupPlan @@ -215,44 +203,14 @@ export function launchAgentInNewTab(args: LaunchAgentInNewTabArgs): LaunchAgentI const runtimeEnvironmentId = getRuntimeEnvironmentIdForWorktree(store, worktreeId) if (isWebRuntimeSessionActive(runtimeEnvironmentId) && pasteDraftAfterLaunch === null) { - // Why: paired web tabs are host-owned and return tabId: null on success. - // Local-only agent tabs cannot be closed because close routes through - // session.tabs.close on the host, so prune them before the host snapshot. - removeStaleLocalAgentTabsForWebHostLaunch(worktreeId) - void createWebRuntimeSessionTerminal({ + launchAgentInWebHostTab({ + agent, worktreeId, environmentId: runtimeEnvironmentId, - targetGroupId: groupId, - activate: true, - ...(hasPrompt - ? { - command: startupPlan.launchCommand, - ...(startupPlan.env ? { env: startupPlan.env } : {}), - launchConfig: startupPlan.launchConfig, - launchAgent: agent, - ...(startupPlan.startupCommandDelivery - ? { startupCommandDelivery: startupPlan.startupCommandDelivery } - : {}) - } - : { agent }) - }).then((created) => { - // 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 (!created) { - toast.error( - translate( - 'auto.lib.launch.agent.in.new.tab.11cce5cc77', - 'Could not launch {{value0}} in a new terminal.', - { value0: agent } - ) - ) - return - } - store.setActiveTabType('terminal') - if (hasPrompt) { - onPromptDelivered?.() - } + groupId, + hasPrompt, + startupPlan, + onPromptDelivered }) return { tabId: null, startupPlan, pasteDraftAfterLaunch: false } } diff --git a/src/renderer/src/lib/launch-agent-web-host-tab.ts b/src/renderer/src/lib/launch-agent-web-host-tab.ts new file mode 100644 index 00000000000..b95ccd8aba1 --- /dev/null +++ b/src/renderer/src/lib/launch-agent-web-host-tab.ts @@ -0,0 +1,75 @@ +import { toast } from 'sonner' +import { useAppStore } from '@/store' +import type { AgentStartupPlan } from '@/lib/tui-agent-startup' +import { + createWebRuntimeSessionTerminal, + isWebTerminalSurfaceTabId +} from '@/runtime/web-runtime-session' +import type { TuiAgent } from '../../../shared/types' +import { translate } from '@/i18n/i18n' + +function removeStaleLocalAgentTabsForWebHostLaunch(worktreeId: string): void { + const state = useAppStore.getState() + for (const tab of state.tabsByWorktree[worktreeId] ?? []) { + if (tab.launchAgent && !isWebTerminalSurfaceTabId(tab.id)) { + state.closeTab(tab.id) + } + } +} + +/** + * 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. + */ +export function launchAgentInWebHostTab(args: { + agent: TuiAgent + worktreeId: string + environmentId: string | null + groupId?: string + hasPrompt: boolean + startupPlan: AgentStartupPlan + onPromptDelivered?: () => void +}): void { + const { agent, worktreeId, environmentId, groupId, hasPrompt, startupPlan, onPromptDelivered } = + args + removeStaleLocalAgentTabsForWebHostLaunch(worktreeId) + void createWebRuntimeSessionTerminal({ + worktreeId, + environmentId, + targetGroupId: groupId, + activate: true, + ...(hasPrompt + ? { + command: startupPlan.launchCommand, + ...(startupPlan.env ? { env: startupPlan.env } : {}), + launchConfig: startupPlan.launchConfig, + launchAgent: agent, + ...(startupPlan.startupCommandDelivery + ? { startupCommandDelivery: startupPlan.startupCommandDelivery } + : {}) + } + : { agent }) + }).then((created) => { + // 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 (!created) { + toast.error( + translate( + 'auto.lib.launch.agent.in.new.tab.11cce5cc77', + 'Could not launch {{value0}} in a new terminal.', + { value0: agent } + ) + ) + return + } + useAppStore.getState().setActiveTabType('terminal') + if (hasPrompt) { + onPromptDelivered?.() + } + }) +}