Prototype rich hidden terminal model restore

This commit is contained in:
Neil
2026-06-09 17:06:55 -07:00
parent 6f5c03f4c6
commit c050e7532f
5 changed files with 210 additions and 3 deletions
@@ -85,6 +85,19 @@ describe('shouldSkipHiddenRendererOutput', () => {
).toBe(false)
})
it('can opt synchronized chunks into model-backed restore for prototype coverage', () => {
expect(
shouldSkipHiddenRendererOutput({
foreground: false,
canRestoreHiddenOutput: true,
startupRendererQueryWindowActive: false,
synchronizedOutputActive: true,
allowSynchronizedModelRestore: true,
data: '\x1b[?2026h\x1b[2J\x1b[H╭ rich 😀 ╮\r\n\x1b[?2026l'
})
).toBe(true)
})
it('keeps startup query windows live', () => {
expect(
shouldSkipHiddenRendererOutput({
@@ -3,6 +3,7 @@ export type HiddenRendererSkipEligibility = {
canRestoreHiddenOutput: boolean
startupRendererQueryWindowActive: boolean
synchronizedOutputActive: boolean
allowSynchronizedModelRestore?: boolean
data: string
}
@@ -116,18 +117,21 @@ export function shouldSkipHiddenRendererOutput({
canRestoreHiddenOutput,
startupRendererQueryWindowActive,
synchronizedOutputActive,
allowSynchronizedModelRestore = false,
data
}: HiddenRendererSkipEligibility): boolean {
if (
foreground ||
!canRestoreHiddenOutput ||
startupRendererQueryWindowActive ||
// Why: DEC 2026 frames can arrive split across chunks; safe-looking rows
// may precede rich table/TUI bytes that need live xterm renderer state.
synchronizedOutputActive ||
data.length === 0
) {
return false
}
if (synchronizedOutputActive) {
// Why: release behavior keeps split DEC 2026 frames live. The override is
// only for proving model-backed replay before shipping richer hidden skips.
return allowSynchronizedModelRestore
}
return containsOnlyRestorableHiddenOutput(data)
}
@@ -533,6 +533,8 @@ describe('connectPanePty', () => {
}
delete (globalThis as unknown as { window?: unknown }).window
delete (globalThis as Record<string, unknown>).__ptyConnectDiag
delete (globalThis as Record<string, unknown>)
.__ORCA_TEST_ALLOW_SYNCHRONIZED_HIDDEN_MODEL_RESTORE__
})
it('does not retain PTY connect diagnostics unless e2e debug state is enabled', async () => {
@@ -3132,6 +3134,82 @@ describe('connectPanePty', () => {
}
})
it('can prototype hidden rich synchronized restore from the headless model', async () => {
;(globalThis as Record<string, unknown>).__ORCA_TEST_ALLOW_SYNCHRONIZED_HIDDEN_MODEL_RESTORE__ =
true
const { connectPanePty } = await import('./pty-connection')
const transport = createMockTransport('pty-id')
const capturedDataCallback: {
current: ((data: string, meta?: { seq?: number; rawLength?: number }) => void) | null
} = { current: null }
transport.connect.mockImplementation(async ({ callbacks }: { callbacks: ConnectCallbacks }) => {
capturedDataCallback.current = callbacks.onData ?? null
return 'pty-id'
})
transportFactoryQueue.push(transport)
const getMainBufferSnapshot = window.api.pty.getMainBufferSnapshot as unknown as ReturnType<
typeof vi.fn
>
const richHiddenFrame = [
'\x1b[?2026h',
'\x1b[?1049h',
'\x1b[2J\x1b[H',
'\x1b[?25l',
'\x1b[2;36m╭────────────────────────────╮\x1b[0m\r\n',
'\x1b[2;36m│ model-backed rich 😀 ███░ │\x1b[0m\r\n',
'\x1b[2;36m╰────────────────────────────╯\x1b[0m',
'\x1b[6;4H\x1b[?25h',
'\x1b[?2026l'
].join('')
const visibleTrigger = 'visible-trigger\r\n'
getMainBufferSnapshot.mockResolvedValue({
data: richHiddenFrame,
cols: 96,
rows: 18,
seq: richHiddenFrame.length + visibleTrigger.length,
source: 'headless'
})
const pane = createPane(1)
const refresh = vi.fn()
const terminal = pane.terminal as typeof pane.terminal & {
_core?: { refresh: typeof refresh }
}
terminal._core = { refresh }
terminal.write = vi.fn((_data: string, callback?: () => void) => {
callback?.()
})
const manager = createManager(1)
const deps = createDeps({
isVisibleRef: { current: false }
})
const disposable = connectPanePty(pane as never, manager as never, deps as never)
await flushAsyncTicks(6)
capturedDataCallback.current?.(richHiddenFrame, {
seq: richHiddenFrame.length,
rawLength: richHiddenFrame.length
})
await flushAsyncTicks(2)
expect(pane.terminal.write).not.toHaveBeenCalled()
expect(getMainBufferSnapshot).not.toHaveBeenCalled()
;(deps.isVisibleRef as { current: boolean }).current = true
capturedDataCallback.current?.(visibleTrigger, {
seq: richHiddenFrame.length + visibleTrigger.length,
rawLength: visibleTrigger.length
})
await flushAsyncTicks(20)
expect(getMainBufferSnapshot).toHaveBeenCalledWith('pty-id', { scrollbackRows: 5000 })
expect(pane.terminal.resize).toHaveBeenCalledWith(96, 18)
expect(pane.terminal.write).toHaveBeenCalledWith(richHiddenFrame, expect.any(Function))
expect(pane.terminal.write).not.toHaveBeenCalledWith(visibleTrigger, expect.any(Function))
expect(refresh).toHaveBeenCalledWith(0, 39, true)
disposable.dispose()
})
it('queues visible split-pane PTY bytes when the pane is not active', async () => {
const { connectPanePty } = await import('./pty-connection')
const transport = createMockTransport()
@@ -420,6 +420,15 @@ function recordPtyConnectDiagnostic(message: string): void {
}
}
function shouldAllowPrototypeSynchronizedHiddenModelRestore(): boolean {
const target = globalThis as {
__ORCA_TEST_ALLOW_SYNCHRONIZED_HIDDEN_MODEL_RESTORE__?: boolean
}
return (
import.meta.env.DEV && target.__ORCA_TEST_ALLOW_SYNCHRONIZED_HIDDEN_MODEL_RESTORE__ === true
)
}
// Why: when multiple panes/tabs need the same deferred SSH connection,
// the first one calls ssh.connect() and subsequent ones must wait for it
// rather than returning early (which would leave them disconnected). This
@@ -2609,6 +2618,7 @@ export function connectPanePty(
canRestoreHiddenOutput: canUseHiddenOutputSnapshot(transport.getPtyId()),
startupRendererQueryWindowActive: isHiddenStartupRendererQueryWindowActive(),
synchronizedOutputActive: synchronizedHiddenOutput,
allowSynchronizedModelRestore: shouldAllowPrototypeSynchronizedHiddenModelRestore(),
data
})
if (shouldSkipHiddenOutput) {
@@ -19,6 +19,7 @@ import {
} from './helpers/terminal'
type HiddenTuiWindow = Window & {
__ORCA_TEST_ALLOW_SYNCHRONIZED_HIDDEN_MODEL_RESTORE__?: boolean
__terminalPtyDataInjection?: {
inject: (paneKey: string, data: string, meta?: { seq?: number; rawLength?: number }) => boolean
}
@@ -82,6 +83,15 @@ async function resetHiddenDebug(page: Page): Promise<void> {
})
}
async function setPrototypeSynchronizedHiddenModelRestore(
page: Page,
enabled: boolean
): Promise<void> {
await page.evaluate((enabled) => {
;(window as HiddenTuiWindow).__ORCA_TEST_ALLOW_SYNCHRONIZED_HIDDEN_MODEL_RESTORE__ = enabled
}, enabled)
}
function writeHiddenFrameScript(scriptPath: string, runId: string): void {
const frames = Array.from({ length: 25 }, (_, frame) => tuiFrame(runId, frame))
writeFileSync(
@@ -379,6 +389,98 @@ test.describe('Hidden terminal TUI visual restore', () => {
rmSync(scriptPath, { force: true })
})
test('prototypes rich synchronized TUI restore from the headless model', async ({
orcaPage,
testRepoPath
}, testInfo: TestInfo) => {
await waitForSessionReady(orcaPage)
const firstWorktreeId = await waitForActiveWorktree(orcaPage)
const secondWorktreeId = (await getAllWorktreeIds(orcaPage)).find(
(id) => id !== firstWorktreeId
)
test.skip(!secondWorktreeId, 'hidden TUI restore needs the seeded secondary worktree')
if (!secondWorktreeId) {
return
}
await switchToWorktree(orcaPage, secondWorktreeId)
await ensureTerminalVisible(orcaPage)
await waitForActiveTerminalManager(orcaPage, 30_000)
const hiddenSnapshot = await waitForPaneIdentitySnapshot(orcaPage, 1)
const hiddenPane = hiddenSnapshot.panes[0]
if (!hiddenPane?.ptyId) {
throw new Error('hidden rich model prototype pane did not bind a PTY')
}
await switchToWorktree(orcaPage, firstWorktreeId)
await expect
.poll(() => getActiveWorktreeId(orcaPage), {
timeout: 10_000,
message: 'first worktree did not become active before hidden rich model prototype'
})
.toBe(firstWorktreeId)
const runId = randomUUID()
const finalMarker = `VISUAL_RESTORE_FINAL_${runId}_24`
const scriptPath = path.join(testRepoPath, `.orca-hidden-rich-model-${runId}.mjs`)
writeHiddenFrameScript(scriptPath, runId)
await resetHiddenDebug(orcaPage)
await setPrototypeSynchronizedHiddenModelRestore(orcaPage, true)
try {
await writeHiddenFrames(orcaPage, hiddenPane.ptyId, scriptPath)
await resetHiddenDebug(orcaPage)
await expect
.poll(async () => (await readHiddenDebug(orcaPage))?.hiddenRendererSkipCount ?? 0, {
timeout: 10_000,
message: 'prototype rich hidden TUI output should skip renderer writes'
})
.toBeGreaterThan(0)
await expect
.poll(() => readMainSnapshotSource(orcaPage, hiddenPane.ptyId!), {
timeout: 10_000,
message: 'prototype rich hidden TUI source did not come from headless model'
})
.toBe('headless')
await switchToWorktree(orcaPage, secondWorktreeId)
await ensureTerminalVisible(orcaPage)
await waitForActiveTerminalManager(orcaPage, 30_000)
await expect
.poll(() => getTerminalContent(orcaPage, 12_000), {
timeout: 10_000,
message: 'prototype rich headless TUI frame did not restore when visible'
})
.toContain(finalMarker)
const content = await getTerminalContent(orcaPage, 12_000)
expect(content).toContain(`Frame 024`)
expect(content).toContain('╭')
expect(content).toContain('├')
expect(content).toContain('█')
expect(content).not.toContain('Orca skipped hidden terminal output')
await expect
.poll(() => readTuiCursorState(orcaPage), {
timeout: 5_000,
message: 'prototype rich headless TUI cursor stayed hidden after restore'
})
.toMatchObject({
hidden: false,
initialized: true
})
const screenshotPath = testInfo.outputPath('hidden-rich-model-restore-final.png')
await orcaPage.screenshot({ path: screenshotPath, fullPage: true })
await testInfo.attach('hidden-rich-model-restore-final.png', {
path: screenshotPath,
contentType: 'image/png'
})
} finally {
await setPrototypeSynchronizedHiddenModelRestore(orcaPage, false)
rmSync(scriptPath, { force: true })
}
})
test('keeps hidden terminal side effects live while hidden output may restore', async ({
orcaPage
}) => {