Files
orca/src/relay/agent-hook-server-codex-subagent-transcript.test.ts
T
Brennan Benson 48e31b3fc0 fix(agent-status): show Codex v2 subagents (#11059)
* fix(agent-status): track Codex rollout subagents

* fix(agent-status): resolve cross-day Codex child rollouts and unblock CI gate

Codex files each rollout under its own local start date, so a session that
runs past midnight spawns children into a sibling day directory. Scanning
only the parent's directory left 13% of real subagent spawns (48/371 across
local rollouts) permanently unresolved, which pinned a phantom "working" row
and re-ran readdirSync every poll tick forever. Resolve the child's own day
directory from occurred_at_ms, and time-box a child whose rollout stays
unreadable so a deleted or never-written file can't leak a working row.

Also make the hook HTTP handler return void: the changed-code quality gate
keys findings by span overlap, so this PR's added line inside the pre-existing
async createServer callback resurfaced no-misused-promises as a new finding.

Tests cover cross-day resolution, grace-period retirement, and that the poll
re-arms across successive roster changes (the prior tests passed even when
the poll died after its first change).

* fix(agent-status): keep the Codex subagent poll alive across nested hooks

A nested non-codex CLI inherits its parent's ORCA_PANE_KEY, so its hook
POST reached scheduleCodexSubagentPoll and tore the timer down before the
source guard, silently ending polling while a rollout child was still live.
2026-07-27 23:50:25 -07:00

86 lines
2.8 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from 'vitest'
import { appendFileSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { RelayAgentHookServer } from './agent-hook-server'
import type { AgentHookRelayEnvelope } from '../shared/agent-hook-relay'
import { makePaneKey } from '../shared/stable-pane-id'
const PANE_KEY = makePaneKey('tab-1', '11111111-1111-4111-8111-111111111111')
const CHILD_ID = '019fa65f-3144-7151-9c02-cff7a28f316f'
function line(record: unknown): string {
return `${JSON.stringify(record)}\n`
}
describe('RelayAgentHookServer Codex subagent transcript polling', () => {
const dirs: string[] = []
afterEach(() => {
for (const dir of dirs) {
rmSync(dir, { recursive: true, force: true })
}
dirs.length = 0
})
it('forwards completion discovered from a child rollout', async () => {
const dir = mkdtempSync(join(tmpdir(), 'relay-hook-codex-subagent-'))
dirs.push(dir)
const parentPath = join(dir, 'rollout-parent.jsonl')
const childPath = join(dir, `rollout-child-${CHILD_ID}.jsonl`)
writeFileSync(
parentPath,
line({
type: 'event_msg',
payload: {
type: 'sub_agent_activity',
occurred_at_ms: 1234,
agent_thread_id: CHILD_ID,
agent_path: '/root/pr_review',
kind: 'started'
}
})
)
writeFileSync(childPath, line({ type: 'event_msg', payload: { type: 'task_started' } }))
const forward = vi.fn<(envelope: AgentHookRelayEnvelope) => void>()
const server = new RelayAgentHookServer({ endpointDir: dir, forward })
await server.start()
try {
const { port, token } = server.getCoordinates()
const response = await fetch(`http://127.0.0.1:${port}/hook/codex`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Orca-Agent-Hook-Token': token
},
body: JSON.stringify({
paneKey: PANE_KEY,
tabId: 'tab-1',
worktreeId: 'wt-1',
payload: {
hook_event_name: 'PostToolUse',
session_id: 'root-session',
transcript_path: parentPath,
tool_name: 'collaborationspawn_agent'
}
})
})
expect(response.status).toBe(204)
expect(forward.mock.calls[0]?.[0].payload.subagents).toHaveLength(1)
appendFileSync(childPath, line({ type: 'event_msg', payload: { type: 'task_complete' } }))
await vi.waitFor(
() => {
expect(forward.mock.calls.at(-1)?.[0].payload.subagents).toBeUndefined()
expect(forward).toHaveBeenCalledTimes(2)
},
{ timeout: 2_000, interval: 50 }
)
} finally {
server.stop()
}
})
})