mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix: keep paired tab updates live after runtime terminal fallback (#19022)
* fix: preserve session publication during runtime terminal fallback * refactor(runtime): align fallback epoch comment and test preamble Match the file's `// Why:` comment convention on the inherited publication epoch, and drop a redundant duplicate mocks import in the lineage regression test while keeping the required side-effect order. No behavior change.
This commit is contained in:
@@ -120,7 +120,8 @@ export class OrcaRuntimeWithCreateRuntimeOwnedMobileSessionTerminal extends Orca
|
||||
}
|
||||
const next: RuntimeMobileSessionTabsSnapshot = {
|
||||
worktree: worktreeId,
|
||||
publicationEpoch: `headless:${Date.now().toString(36)}`,
|
||||
// Why: a fresh epoch retires the current publisher, so clients drop its later tab updates.
|
||||
publicationEpoch: existing?.publicationEpoch ?? `headless:${Date.now().toString(36)}`,
|
||||
snapshotVersion: (existing?.snapshotVersion ?? 0) + 1,
|
||||
// Why: activating the new tab also focuses its group, so a "+" targeting a specific split group makes that group active too.
|
||||
activeGroupId:
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { expect, it, vi } from 'vitest'
|
||||
import type { RuntimeMobileSessionTabsResult } from '../../shared/runtime-types'
|
||||
|
||||
// Fragments stay side-effect ordered: mocks, then lifecycle, then fixtures.
|
||||
const { OrcaRuntimeService } = await import('./orca-runtime-test-mocks.spec')
|
||||
await import('./orca-runtime-test-lifecycle.spec')
|
||||
const { store, TEST_WORKTREE_ID } = await import('./orca-runtime-test-fixtures.spec')
|
||||
|
||||
it.each(['renderer:active-generation', 'headless:active-generation'])(
|
||||
'keeps %s live when runtime-owned creation supplements its inventory',
|
||||
async (publicationEpoch) => {
|
||||
const runtime = new OrcaRuntimeService(store)
|
||||
runtime.setPtyController({
|
||||
spawn: vi.fn().mockResolvedValue({ id: 'pty-runtime-fallback' }),
|
||||
write: () => true,
|
||||
kill: () => true,
|
||||
getForegroundProcess: async () => null
|
||||
})
|
||||
runtime.syncWindowGraph(0, {
|
||||
tabs: [],
|
||||
leaves: [],
|
||||
mobileSessionTabs: [
|
||||
{
|
||||
worktree: TEST_WORKTREE_ID,
|
||||
publicationEpoch,
|
||||
snapshotVersion: 7,
|
||||
activeGroupId: null,
|
||||
activeTabId: null,
|
||||
activeTabType: null,
|
||||
tabs: []
|
||||
}
|
||||
]
|
||||
})
|
||||
const events: RuntimeMobileSessionTabsResult[] = []
|
||||
const unsubscribe = runtime.onMobileSessionTabsChanged(
|
||||
(snapshot) => events.push(snapshot),
|
||||
'paired-client'
|
||||
)
|
||||
try {
|
||||
const created = await runtime.createMobileSessionTerminal(`id:${TEST_WORKTREE_ID}`, {
|
||||
activate: false,
|
||||
select: false,
|
||||
navigation: 'caller',
|
||||
clientNavigationId: 'paired-client'
|
||||
})
|
||||
expect(created.tab.status).toBe('ready')
|
||||
expect(created.publicationEpoch).toBe(publicationEpoch)
|
||||
expect(created.snapshotVersion).toBeGreaterThan(7)
|
||||
expect(events.at(-1)).toMatchObject({
|
||||
publicationEpoch: `${publicationEpoch}:client-navigation`,
|
||||
tabs: [expect.objectContaining({ id: created.tab.id, status: 'ready' })]
|
||||
})
|
||||
} finally {
|
||||
unsubscribe()
|
||||
}
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user