Files
orca/tests/e2e/structured-attention-headless-delivery.unit.test.ts
Neil 18bab90efa refactor(main): group client RPC pairing and host runtime owners (#38584)
* refactor(main): group client RPC pairing and host runtime owners

* test: target concrete mobile notification owner in headless fixture

* test: retarget dynamic quit mocks to runtime metadata owner
2026-11-05 09:16:47 -08:00

70 lines
3.2 KiB
TypeScript

import { build } from 'esbuild'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { expect, it } from 'vitest'
import { runProcess } from '@orca/process-host'
it('loads and delivers actual host notifications in plain Node without Electron installed', async () => {
const directory = mkdtempSync(join(tmpdir(), 'orca-headless-attention-'))
const bundle = join(directory, 'notification-host.cjs')
try {
await build({
stdin: {
resolveDir: process.cwd(),
sourcefile: 'structured-attention-headless-notification.ts',
contents: `
import {createStructuredAttentionMobileDelivery} from './src/main/runtime/agent-session/structured-agent-session-mobile-attention'
import {RuntimeMobileNotificationController} from './src/main/runtime/push/notifications/runtime-mobile-notification-controller'
import {getDefaultNotificationSettings} from './src/shared/notification-settings-defaults'
const controller = new RuntimeMobileNotificationController()
controller.configureDismissalStore(${JSON.stringify(join(directory, 'state'))})
const events = []
controller.onDispatched(event => events.push(event))
const delivery = createStructuredAttentionMobileDelivery({
readNotificationSettings: getDefaultNotificationSettings,
readWorkspaceLabels: () => ({worktreeLabel:'Notes'}),
isWorkspaceMuted: () => false,
readOrchestration: () => undefined,
dispatch: event => controller.dispatch(event),
reconcile: state => controller.reconcileStructuredPromptAttention(state),
now: () => 60_000
})
const scope = {executionHostId:'local',wslDistro:null,workspaceId:'folder-a',workspaceKind:'folder'}
const summary = {sessionId:'session-a',workspaceId:'folder-a',agent:'claude',status:'attention',updatedAt:1}
delivery.deliver({
type:'prompt',
prompt:{scope,sessionId:'session-a',promptId:'approval-a',raisedAt:1,journalCursor:{epoch:'journal-a',sequence:1}}
},summary)
for (const outcome of ['failure','success']) {
delivery.deliver({type:'completion',completion:{scope,sessionId:'session-a',turnId:outcome,outcome,completedAt:2}},summary)
}
console.log(JSON.stringify(events.map(({title,body,agentState}) => ({title,body,agentState}))))
`
},
bundle: true,
platform: 'node',
target: 'node18',
format: 'cjs',
external: ['electron'],
outfile: bundle,
logLevel: 'silent'
})
const result = await runProcess({
program: process.execPath,
args: [bundle],
cwd: directory
})
expect(result.stderr).toBe('')
expect(result.code).toBe(0)
expect(JSON.parse(result.stdout)).toEqual([
{ title: 'Notes - Claude needs input', body: 'Claude needs input.', agentState: 'blocked' },
{ title: 'Notes - Claude failed', body: 'Claude failed.', agentState: 'done' },
{ title: 'Notes - Claude finished', body: 'Claude finished.', agentState: 'done' }
])
} finally {
rmSync(directory, { recursive: true, force: true })
}
})