mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 00:03:45 +00:00
test(codex): cover the runtime controller's resume-pinned account recording
The runtime controller's spawn path repeats the same recordCodexPaneAccountForSpawn call the ipc handler makes, but nothing exercised it: reverting either pinnedByResume or launchCodexHomePath at that site left all 392 tests green. That site is the CLI/relay resume path (terminal.ts accepts resumeProviderSession, orca-runtime threads it into ptyController.spawn), so an unnoticed revert there would silently restore the bug for those clients. Also corrects the guard's rationale. The shared runtime mirror only hot-swaps to the current selection on the legacy flag-OFF lane; with the real-home routing that ships unconditionally, syncForCurrentSelection early-returns through syncSelfContainedManagedSelection and never rewrites the mirror's auth.json. Declining to attribute is still right — an unowned home cannot be named — but not for the stated reason, and a pane resumed into the mirror after the per-account rollout is genuinely stale and stays unreported.
This commit is contained in:
@@ -66,8 +66,11 @@ function resolveCodexHomeOwnerAccountId(args: {
|
||||
getCodexSelectionLaneKey(getCodexSelectionTargetForAccount(account)) === laneKey &&
|
||||
normalizeRuntimePathForComparison(account.managedHomePath) === launchHome
|
||||
)
|
||||
// Why: the shared runtime mirror hot-swaps to whichever account is selected, so
|
||||
// an unattributable home is no evidence the pane is on a different one. A
|
||||
// wrong restart notice silently drops every keystroke in that terminal.
|
||||
// Why: an unowned home cannot be named, and naming the account a pane is stuck
|
||||
// on is the prompt's whole job — so decline rather than guess. A wrong notice
|
||||
// silently drops every keystroke in that terminal. Note the shared runtime
|
||||
// mirror only hot-swaps to the current selection on the legacy flag-OFF lane;
|
||||
// a pane resumed into it after the per-account rollout is genuinely stale but
|
||||
// still unnameable, so that cohort stays unreported.
|
||||
return owner ? owner.id : undefined
|
||||
}
|
||||
|
||||
@@ -13638,6 +13638,126 @@ describe('registerPtyHandlers', () => {
|
||||
expect(forgetCodexPaneAccountMock).toHaveBeenCalledWith('pty-resumed')
|
||||
})
|
||||
|
||||
// Why: the runtime controller is the CLI/relay resume path, and it repeats the
|
||||
// same recording call the ipc handler makes. Without its own coverage a revert
|
||||
// there is invisible.
|
||||
it('records the origin account for a resumed Codex pane spawned by the runtime controller', async () => {
|
||||
type RuntimeSpawnController = {
|
||||
spawn(args: Record<string, unknown>): Promise<{ id: string }>
|
||||
}
|
||||
setLocalPtyProvider({
|
||||
spawn: vi.fn(async () => ({ id: 'pty-runtime-resumed' })),
|
||||
write: vi.fn(),
|
||||
resize: vi.fn(),
|
||||
kill: vi.fn(),
|
||||
shutdown: vi.fn(),
|
||||
onData: vi.fn(() => vi.fn()),
|
||||
onExit: vi.fn(() => vi.fn()),
|
||||
listProcesses: vi.fn(async () => []),
|
||||
getForegroundProcess: vi.fn(async () => null)
|
||||
} as never)
|
||||
const runtime = {
|
||||
setPtyController: vi.fn(),
|
||||
registerPty: vi.fn(),
|
||||
noteTerminalSpawnCommand: vi.fn(),
|
||||
onPtySpawned: vi.fn(),
|
||||
onPtyExit: vi.fn(),
|
||||
onPtyData: vi.fn()
|
||||
}
|
||||
const getSettings = vi.fn().mockReturnValue({
|
||||
activeCodexManagedAccountId: 'account-b',
|
||||
codexManagedAccounts: [
|
||||
{ id: 'account-a', managedHomePath: '/managed/origin/home' },
|
||||
{ id: 'account-b', managedHomePath: '/managed/current/home' }
|
||||
]
|
||||
})
|
||||
handlers.clear()
|
||||
registerPtyHandlers(
|
||||
mainWindow as never,
|
||||
runtime as never,
|
||||
vi.fn(() => '/managed/current/home'),
|
||||
getSettings as never,
|
||||
undefined,
|
||||
undefined,
|
||||
{ prepareCodexSessionResume: async () => ({ codexHomePath: '/managed/origin/home' }) }
|
||||
)
|
||||
const controller = runtime.setPtyController.mock.calls[0]?.[0] as RuntimeSpawnController
|
||||
|
||||
await controller.spawn({
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
worktreeId: 'wt-runtime',
|
||||
command: 'codex resume session-a',
|
||||
launchAgent: 'codex',
|
||||
resumeProviderSession: {
|
||||
key: 'session_id',
|
||||
id: 'session-a',
|
||||
transcriptPath: '/managed/origin/home/sessions/2026/07/20/rollout-a.jsonl'
|
||||
}
|
||||
})
|
||||
|
||||
expect(recordCodexPaneAccountMock.mock.calls).toEqual([
|
||||
['pty-runtime-resumed', { selectionKey: 'host', accountId: 'account-a' }]
|
||||
])
|
||||
expect(forgetCodexPaneAccountMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('leaves a runtime-controller resumed Codex pane unattributed when no account owns its home', async () => {
|
||||
type RuntimeSpawnController = {
|
||||
spawn(args: Record<string, unknown>): Promise<{ id: string }>
|
||||
}
|
||||
setLocalPtyProvider({
|
||||
spawn: vi.fn(async () => ({ id: 'pty-runtime-resumed' })),
|
||||
write: vi.fn(),
|
||||
resize: vi.fn(),
|
||||
kill: vi.fn(),
|
||||
shutdown: vi.fn(),
|
||||
onData: vi.fn(() => vi.fn()),
|
||||
onExit: vi.fn(() => vi.fn()),
|
||||
listProcesses: vi.fn(async () => []),
|
||||
getForegroundProcess: vi.fn(async () => null)
|
||||
} as never)
|
||||
const runtime = {
|
||||
setPtyController: vi.fn(),
|
||||
registerPty: vi.fn(),
|
||||
noteTerminalSpawnCommand: vi.fn(),
|
||||
onPtySpawned: vi.fn(),
|
||||
onPtyExit: vi.fn(),
|
||||
onPtyData: vi.fn()
|
||||
}
|
||||
const getSettings = vi.fn().mockReturnValue({
|
||||
activeCodexManagedAccountId: 'account-b',
|
||||
codexManagedAccounts: [{ id: 'account-b', managedHomePath: '/managed/current/home' }]
|
||||
})
|
||||
handlers.clear()
|
||||
registerPtyHandlers(
|
||||
mainWindow as never,
|
||||
runtime as never,
|
||||
vi.fn(() => '/managed/current/home'),
|
||||
getSettings as never,
|
||||
undefined,
|
||||
undefined,
|
||||
{ prepareCodexSessionResume: async () => ({ codexHomePath: '/managed/shared-mirror/home' }) }
|
||||
)
|
||||
const controller = runtime.setPtyController.mock.calls[0]?.[0] as RuntimeSpawnController
|
||||
|
||||
await controller.spawn({
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
worktreeId: 'wt-runtime',
|
||||
command: 'codex resume session-a',
|
||||
launchAgent: 'codex',
|
||||
resumeProviderSession: {
|
||||
key: 'session_id',
|
||||
id: 'session-a',
|
||||
transcriptPath: '/managed/shared-mirror/home/sessions/2026/07/20/rollout-a.jsonl'
|
||||
}
|
||||
})
|
||||
|
||||
expect(recordCodexPaneAccountMock).not.toHaveBeenCalled()
|
||||
expect(forgetCodexPaneAccountMock).toHaveBeenCalledWith('pty-runtime-resumed')
|
||||
})
|
||||
|
||||
it('seeds cold restore at recovered dimensions with a legacy dimensionless fallback', async () => {
|
||||
const oscLinks = [{ row: 0, startCol: 0, endCol: 8, uri: 'https://example.com/restored' }]
|
||||
const coldRestore = {
|
||||
|
||||
Reference in New Issue
Block a user