mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 16:02:56 +00:00
fix(terminal): reveal splits while the source pane binds (#23692)
* test(e2e): observe passive terminal restoration before activation * fix(terminal): reveal persisted splits during source binding publication * test(terminal): handle nullable persisted layout roots
This commit is contained in:
@@ -54,12 +54,13 @@ export class OrcaRuntimeWithResolveTerminalSplitSourceAuthority extends OrcaRunt
|
||||
)
|
||||
const rendererTab = this.tabs.get(tabId)
|
||||
const rendererLeaf = this.leaves.get(this.getLeafKey(tabId, leafId))
|
||||
// A mounted pane can publish before its PTY binds; persisted identity fences that gap.
|
||||
const rendererMounted = Boolean(
|
||||
rendererTab &&
|
||||
rendererLeaf &&
|
||||
runtimeWorktreeIdsEqual(rendererTab.worktreeId, worktreeId) &&
|
||||
runtimeWorktreeIdsEqual(rendererLeaf.worktreeId, worktreeId) &&
|
||||
rendererLeaf.ptyId === ptyId
|
||||
(rendererLeaf.ptyId === ptyId || (persisted && rendererLeaf.ptyId === null))
|
||||
)
|
||||
if (persisted && persistedLayout) {
|
||||
return {
|
||||
|
||||
@@ -78,6 +78,7 @@ function createHarness(
|
||||
deferSpawn?: boolean
|
||||
includePairedSnapshot?: boolean
|
||||
rendererMounted?: boolean
|
||||
rendererPtyId?: string | null
|
||||
graphOnlySource?: boolean
|
||||
sourceIncarnationId?: string
|
||||
stopAndWaitResult?: boolean
|
||||
@@ -169,7 +170,7 @@ function createHarness(
|
||||
worktreeId: WORKTREE_ID,
|
||||
leafId: SOURCE_LEAF_ID,
|
||||
paneRuntimeId: 1,
|
||||
ptyId: SOURCE_PTY_ID
|
||||
ptyId: options.rendererPtyId === undefined ? SOURCE_PTY_ID : options.rendererPtyId
|
||||
}
|
||||
]
|
||||
: [],
|
||||
@@ -283,6 +284,19 @@ describe('remote runtime terminal split authority', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('reveals a persisted split while its mounted source is still publishing its PTY binding', async () => {
|
||||
const harness = createHarness(true, { rendererMounted: true, rendererPtyId: null })
|
||||
await harness.runtime.splitTerminal(harness.handle, { direction: 'vertical' })
|
||||
expect(harness.revealTerminalSession).toHaveBeenCalledOnce()
|
||||
expect(harness.getSession().terminalLayoutsByTabId[TAB_ID]?.root?.type).toBe('split')
|
||||
})
|
||||
|
||||
it('does not reveal a persisted split into a renderer bound to a different PTY', async () => {
|
||||
const harness = createHarness(true, { rendererMounted: true, rendererPtyId: 'replacement' })
|
||||
await harness.runtime.splitTerminal(harness.handle, { direction: 'vertical' })
|
||||
expect(harness.revealTerminalSession).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('splits a persisted tab without consulting an unmounted host renderer', async () => {
|
||||
const harness = createHarness()
|
||||
|
||||
|
||||
@@ -137,8 +137,19 @@ test('durable whole-tab close removes a split tab across restart', async (// oxl
|
||||
const secondLaunch = await session.launch()
|
||||
secondApp = secondLaunch.app
|
||||
await waitForSessionReady(secondLaunch.page)
|
||||
const restoredWorktreeId = await attachRepoAndOpenTerminal(secondLaunch.page, repoPath)
|
||||
expect(restoredWorktreeId).toBe(worktreeId)
|
||||
// Activation deliberately creates a fresh terminal; observe passive hydration first.
|
||||
await expect
|
||||
.poll(() =>
|
||||
secondLaunch.page.evaluate(
|
||||
(id) =>
|
||||
window.__store
|
||||
?.getState()
|
||||
.allWorktrees()
|
||||
.some((worktree) => worktree.id === id),
|
||||
worktreeId
|
||||
)
|
||||
)
|
||||
.toBe(true)
|
||||
|
||||
// Why: wait past initial worktree effects so this checks resurrection, not
|
||||
// only the first hydrated frame before default-tab logic has run.
|
||||
|
||||
Reference in New Issue
Block a user