mirror of
https://github.com/stablyai/orca.git
synced 2026-10-19 16:03:26 +00:00
fix(terminal): defer startup mounts until hydration
This commit is contained in:
@@ -4270,6 +4270,7 @@
|
||||
{
|
||||
"file": "src/renderer/src/components/terminal/background-terminal-worktree-mount.test.ts",
|
||||
"assertions": [
|
||||
"startup waits for hydration before mounting terminal panes while degraded mode remains interactive",
|
||||
"only an explicit local execution host can defer cold activation",
|
||||
"SSH, remote-runtime, and unresolved owners remain eager"
|
||||
]
|
||||
|
||||
@@ -69,6 +69,7 @@ import { scheduleBackgroundTerminalWorktreeMeasure } from './terminal/background
|
||||
import {
|
||||
applyBackgroundMountTabRestriction,
|
||||
canDeferColdActivationTabsForHost,
|
||||
canMountTerminalWorkspaceForStartup,
|
||||
planColdActivationTabDeferral,
|
||||
pruneClosedBackgroundMountTabs,
|
||||
revealActivationDeferredTabs,
|
||||
@@ -327,6 +328,7 @@ function Terminal(): React.JSX.Element | null {
|
||||
const expandedPaneByTabId = useAppStore((s) => s.expandedPaneByTabId)
|
||||
const workspaceSessionReady = useAppStore((s) => s.workspaceSessionReady)
|
||||
const hydrationSucceeded = useAppStore((s) => s.hydrationSucceeded)
|
||||
const startupWorktreeRefreshCompleted = useAppStore((s) => s.startupWorktreeRefreshCompleted)
|
||||
const openFiles = useAppStore((s) => s.openFiles)
|
||||
const activeFileId = useAppStore((s) => s.activeFileId)
|
||||
const activeBrowserTabId = useAppStore((s) => s.activeBrowserTabId)
|
||||
@@ -1152,8 +1154,15 @@ function Terminal(): React.JSX.Element | null {
|
||||
terminalSshParkingEnabled,
|
||||
workspaceSurfaces
|
||||
])
|
||||
// Why: gate on workspaceSessionReady so TerminalPane doesn't mount and spawn a duplicate PTY before reconnectPersistedTerminals() finishes.
|
||||
if (renderedActiveWorktreeId && workspaceSessionReady) {
|
||||
// Why: a slow post-reconnect step exposes workspaceSessionReady before hydration can populate snapshot capabilities.
|
||||
if (
|
||||
renderedActiveWorktreeId &&
|
||||
canMountTerminalWorkspaceForStartup({
|
||||
workspaceSessionReady,
|
||||
hydrationSucceeded,
|
||||
startupWorktreeRefreshCompleted
|
||||
})
|
||||
) {
|
||||
// Why: mounting every saved tab at once (scrollback replay + WebGL + sync-IPC snapshot per pane) freezes the renderer, so hidden tabs defer and mount on first reveal.
|
||||
const worktreeTabs = tabsByWorktree[renderedActiveWorktreeId] ?? []
|
||||
const coldActivationDeferralEnabled =
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
addBackgroundMountedTerminalWorktree,
|
||||
applyBackgroundMountTabRestriction,
|
||||
canDeferColdActivationTabsForHost,
|
||||
canMountTerminalWorkspaceForStartup,
|
||||
collectDeferredMountTabIds,
|
||||
hasRequestedBackgroundTerminalWorktreeMount,
|
||||
planColdActivationTabDeferral,
|
||||
@@ -22,6 +23,32 @@ import {
|
||||
shouldMountBackgroundWorktreeTab
|
||||
} from './background-terminal-worktree-mount'
|
||||
|
||||
describe('terminal workspace startup mount gate', () => {
|
||||
it('waits for hydration unless startup entered degraded mode', () => {
|
||||
expect(
|
||||
canMountTerminalWorkspaceForStartup({
|
||||
workspaceSessionReady: true,
|
||||
hydrationSucceeded: false,
|
||||
startupWorktreeRefreshCompleted: false
|
||||
})
|
||||
).toBe(false)
|
||||
expect(
|
||||
canMountTerminalWorkspaceForStartup({
|
||||
workspaceSessionReady: true,
|
||||
hydrationSucceeded: true,
|
||||
startupWorktreeRefreshCompleted: false
|
||||
})
|
||||
).toBe(true)
|
||||
expect(
|
||||
canMountTerminalWorkspaceForStartup({
|
||||
workspaceSessionReady: true,
|
||||
hydrationSucceeded: false,
|
||||
startupWorktreeRefreshCompleted: true
|
||||
})
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('background terminal mount request registry', () => {
|
||||
it('replays a request made before the Terminal listener mounts', () => {
|
||||
takeAllPendingBackgroundTerminalWorktreeMounts()
|
||||
|
||||
@@ -141,6 +141,16 @@ export function shouldMountBackgroundWorktreeTab(
|
||||
// until first reveal, parked byte watchers own their side effects meanwhile.
|
||||
export const COLD_ACTIVATION_TAB_DEFER_THRESHOLD = 4
|
||||
|
||||
export function canMountTerminalWorkspaceForStartup(args: {
|
||||
workspaceSessionReady: boolean
|
||||
hydrationSucceeded: boolean
|
||||
startupWorktreeRefreshCompleted: boolean
|
||||
}): boolean {
|
||||
return (
|
||||
args.workspaceSessionReady && (args.hydrationSucceeded || args.startupWorktreeRefreshCompleted)
|
||||
)
|
||||
}
|
||||
|
||||
export function canDeferColdActivationTabsForHost(args: {
|
||||
executionHostId: string | null
|
||||
}): boolean {
|
||||
|
||||
Reference in New Issue
Block a user