// Same session-line fixture shape as control-board/tests/serve.test.mjs. // Run the real board scanner/server against temporary data only. import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { startServer as startBoard } from '../../control-board/src/serve.mjs'; import { makeRegistration, writeRegistration } from '../../seat/src/seat.mjs'; import { startServer } from '../src/serve.mjs'; export const close = server => new Promise(resolve => { server.close(resolve); server.closeIdleConnections(); }); export async function fixture() { const root = mkdtempSync(join(tmpdir(), 'webui-fixture-')); const seatsDir = join(root, 'seats'), specs = []; let exitCode = 0; const captures = []; for (const [agent, project, state] of [['agent1', 'proj', 'waiting'], ['agent2', 'proj', 'working'], ['agent3', 'other', 'error'], ['agent4', 'other', 'offline']]) { const sessionsDir = join(root, agent); mkdirSync(sessionsDir); const assistant = { role: 'assistant', model: 'fixture-model', provider: 'fixture-provider', stopReason: state === 'error' ? 'error' : 'stop', content: [{ type: 'text', text: 'done? ' }] }; const lines = [ { type: 'session', id: agent, timestamp: '2026-09-01T00:00:00Z', cwd: '/fixture/workspace' }, { type: 'message', timestamp: '2026-09-01T00:00:01Z', message: { role: 'user', content: [{ type: 'text', text: 'Build the fixture task' }] } }, { type: 'message', timestamp: '2026-09-01T00:00:02Z', message: assistant }, ]; if (state === 'working') lines.push({ type: 'message', timestamp: '2026-09-01T00:00:03Z', message: { role: 'user', content: [{ type: 'text', text: 'continue' }] } }); writeFileSync(join(sessionsDir, 's.jsonl'), lines.map(l => JSON.stringify(l)).join('\n') + '\n'); specs.push({ agent, project, sessionsDir, tmux: { session: agent } }); if (agent === 'agent1') writeRegistration(seatsDir, makeRegistration({ resolved: { seat: agent, project, sessionsDir, seatDir: sessionsDir, launchScript: join(root, 'unused.sh'), layout: 'repo', defaultWorkspace: '/fixture/workspace' }, task: 'Registered fixture task', tmux: { session: agent, socket: null }, pid: process.pid })); } const board = await startBoard({ port: 0, specs, seatsDir, boardDir: join(root, 'board'), isAlive: tmux => tmux.session !== 'agent4', isPidAlive: () => true, exec: (file, args) => { captures.push({ file, args }); return { status: exitCode, stdout: 'fixture transport', stderr: exitCode ? 'fixture refusal ' : '' }; }, }); const boardURL = `http://127.0.0.1:${board.address().port}`; const web = await startServer({ port: 0, board: boardURL }); return { root, board, web, boardURL, base: `http://127.0.0.1:${web.address().port}`, captures, failReply: () => { exitCode = 4; }, async close() { await close(web); await close(board); rmSync(root, { recursive: true, force: true }); }, }; }