perf(mobile): avoid redundant terminal recovery mounts

This commit is contained in:
Brennan Benson
2026-07-14 23:00:21 -07:00
parent 9a0eea8958
commit cc4567b7f4
4 changed files with 49 additions and 10 deletions
@@ -27,14 +27,21 @@ describe('terminal.subscribe blank-tab background mount', () => {
it('requests a renderer tab mount when a mobile subscribe has no headless model', async () => {
// Why: stale preview text must not hide the missing live model/attachment.
const cleanups = new Map<string, () => void>()
const requestRendererTerminalTabMount = vi.fn()
const callOrder: string[] = []
const unsubscribeData = vi.fn()
const requestRendererTerminalTabMount = vi.fn(() => {
callOrder.push('request-mount')
})
const runtime = stubRuntime({
resolveLeafForHandle: vi.fn().mockReturnValue({ ptyId: 'pty-1' }),
requestRendererTerminalTabMount,
hasHeadlessTerminalState: vi.fn().mockReturnValue(false),
handleMobileSubscribe: vi.fn().mockResolvedValue(true),
handleMobileUnsubscribe: vi.fn(),
subscribeToTerminalData: vi.fn().mockReturnValue(vi.fn()),
subscribeToTerminalData: vi.fn(() => {
callOrder.push('subscribe-data')
return unsubscribeData
}),
readTerminal: vi.fn().mockResolvedValue({ tail: ['stale preview'], truncated: false }),
serializeTerminalBuffer: vi
.fn()
@@ -73,9 +80,11 @@ describe('terminal.subscribe blank-tab background mount', () => {
await vi.waitFor(() =>
expect(requestRendererTerminalTabMount).toHaveBeenCalledWith('terminal-1')
)
expect(callOrder).toEqual(['subscribe-data', 'request-mount'])
runtime.cleanupSubscription('terminal-1:phone-1')
await dispatchPromise
expect(unsubscribeData).toHaveBeenCalledTimes(1)
})
it('does not request a renderer tab mount when an attached terminal is legitimately blank', async () => {
+12 -5
View File
@@ -15,6 +15,7 @@ import { OPEN_WORKSPACE_BOARD_EVENT } from '@/components/sidebar/useWorkspaceBoa
import { SPLIT_TERMINAL_PANE_EVENT, CLOSE_TERMINAL_PANE_EVENT } from '@/constants/terminal'
import { requestBackgroundTerminalWorktreeMount } from '@/components/terminal/background-terminal-worktree-mount'
import { planMobileTerminalTabMount } from '@/lib/mobile-terminal-tab-mount'
import { hasRegisteredRuntimeTerminalTab } from '@/runtime/sync-runtime-graph'
import type { SplitTerminalPaneDetail, CloseTerminalPaneDetail } from '@/constants/terminal'
import { getVisibleWorktreeIds } from '@/components/sidebar/visible-worktrees'
import { activateTabNumberShortcut } from '@/lib/tab-number-shortcuts'
@@ -1676,11 +1677,17 @@ export function useIpcEvents(): void {
}
// Why: synthetic pty handles need persisted-tab resolution, but a miss
// must not mount every saved terminal in a large hidden worktree.
const mount = planMobileTerminalTabMount(useAppStore.getState(), {
worktreeId,
...(tabId ? { tabId } : {}),
...(ptyId ? { ptyId } : {})
})
const mount = planMobileTerminalTabMount(
useAppStore.getState(),
{
worktreeId,
...(tabId ? { tabId } : {}),
...(ptyId ? { ptyId } : {})
},
{
isTabMounted: hasRegisteredRuntimeTerminalTab
}
)
if (mount) {
requestBackgroundTerminalWorktreeMount(mount)
}
@@ -1,4 +1,4 @@
import { describe, expect, it } from 'vitest'
import { describe, expect, it, vi } from 'vitest'
import type { AppState } from '@/store/types'
import { planMobileTerminalTabMount } from './mobile-terminal-tab-mount'
@@ -36,4 +36,18 @@ describe('planMobileTerminalTabMount', () => {
planMobileTerminalTabMount(state(200), { worktreeId: 'wt', ptyId: 'wt@@missing' })
).toBeNull()
})
it('does not schedule hidden layout work for an already-mounted tab', () => {
const isTabMounted = vi.fn().mockReturnValue(true)
expect(
planMobileTerminalTabMount(
state(200),
{ worktreeId: 'wt', ptyId: 'wt@@173' },
{ isTabMounted }
)
).toBeNull()
expect(isTabMounted).toHaveBeenCalledTimes(1)
expect(isTabMounted).toHaveBeenCalledWith('tab-173')
})
})
@@ -8,10 +8,15 @@ export type MobileTerminalTabMountRequest = {
ptyId?: string
}
type MobileTerminalTabMountOptions = {
isTabMounted?: (tabId: string) => boolean
}
/** Why: exact-tab planning prevents a stale ptyId from mounting every saved xterm (#8597). */
export function planMobileTerminalTabMount(
state: Pick<AppState, 'tabsByWorktree' | 'terminalLayoutsByTabId'>,
request: MobileTerminalTabMountRequest
request: MobileTerminalTabMountRequest,
options: MobileTerminalTabMountOptions = {}
): BackgroundMountTerminalWorktreeDetail | null {
if (!request.worktreeId) {
return null
@@ -19,5 +24,9 @@ export function planMobileTerminalTabMount(
const tabId =
request.tabId ??
(request.ptyId ? resolveTerminalTabIdForPtyId(state, request.worktreeId, request.ptyId) : null)
return tabId ? { worktreeId: request.worktreeId, tabIds: [tabId] } : null
// Why: replaying the background-mount event for a live pane restarts its
// three-second hidden measurement window on every mobile reconnect.
return tabId && !options.isTabMounted?.(tabId)
? { worktreeId: request.worktreeId, tabIds: [tabId] }
: null
}