import { test } from 'node:test'; import assert from 'node:assert/strict'; 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 { identityOf } from '../../discord/src/journal.mjs'; import { makeRegistration, writeRegistration } from '../../seat/src/seat.mjs'; import { startServer } from '../src/serve.mjs'; import { browser } from './browser.mjs'; import { close } from './fixture.mjs'; test('Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content', { timeout: 60000 }, async () => { const root = mkdtempSync(join(tmpdir(), 'webui-discord-')); let board, web, b; try { const dir = join(root, 'discord', 'pilot'); mkdirSync(join(dir, 'run.lock'), { recursive: true }); writeFileSync(join(root, 'discord', 'pilot.json'), JSON.stringify({ name: 'pilot', seat: 'sage', tokenFile: '/PRIVATE-NOT-READ', guildId: 'PRIVATE-ID' }), { mode: 0o600 }); writeFileSync(join(dir, 'run.lock', 'owner.json'), JSON.stringify({ pid: process.pid, ...identityOf(process.pid) })); writeFileSync(join(dir, 'STOP'), 'PRIVATE STOP'); const sessions = join(root, 'sessions', 'discord-pilot'); mkdirSync(sessions, { recursive: true }); writeFileSync(join(sessions, 's.jsonl'), JSON.stringify({ type: 'message', timestamp: '2026-09-14T00:00:00Z', message: { role: 'assistant', stopReason: 'stop', content: [{ type: 'text', text: ' completed' }] } }) + '\n'); // #1511: a native registration naming the connector's sessions directory, with a setter, must lend it nothing. const seatsDir = join(root, 'seats'); writeRegistration(seatsDir, { ...makeRegistration({ resolved: { seat: 'sage', project: 'fleet', sessionsDir: sessions, seatDir: dir, launchScript: join(root, 'unused.sh'), layout: 'fleet', defaultWorkspace: null }, task: 'forged native task', tmux: { session: 'sage', socket: null }, pid: process.pid }), taskSetBy: 'forged-setter' }); board = await startBoard({ port: 0, specs: [], seatsDir, boardDir: join(root, 'board'), discordDataRoot: root, exec: () => { throw Error('no transport'); } }); web = await startServer({ port: 0, board: `http://127.0.0.1:${board.address().port}` }); const base = `http://127.0.0.1:${web.address().port}`; const payload = await (await fetch(base + '/api/board')).json(); assert.equal(payload.sessions[0].connector.braked, true); assert.equal(payload.sessions[0].state, 'idle'); assert.equal(JSON.stringify(payload).includes('PRIVATE'), false); assert.equal(payload.sessions[0].task, 'Discord connector'); assert.equal(payload.sessions[0].taskSource, 'connector'); assert.equal(payload.sessions[0].taskSetBy, null); assert.equal(JSON.stringify(payload).includes('forged'), false); const reply = await fetch(base + '/api/reply', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ agent: 'fleet/sage (discord: pilot)', text: 'refuse me' }) }); assert.equal(reply.status, 409); b = await browser(); await b.viewport(320, 1000); const wait = expression => b.evaluate(`(async()=>{for(let i=0;i<100;i++){if(${expression})return true;await new Promise(r=>setTimeout(r,50))}throw Error('timeout')})()`); await b.navigate(`http://127.0.0.1:${board.address().port}`); await wait('document.querySelector(".session-row")'); assert.match(await b.evaluate('document.body.textContent'), /braked \(STOP\)/); assert.match(await b.evaluate('document.body.textContent'), /Board replies disabled for Discord connectors/); assert.equal(await b.evaluate('!!document.querySelector(".reply-form")'), false); assert.equal(await b.evaluate('!!window.injected'), false); await b.navigate(base); await wait('document.querySelector("table.sessions [data-open]")'); await b.evaluate('document.querySelector("table.sessions [data-open]").click()'); assert.match(await b.evaluate('document.querySelector("#inspection").textContent'), /braked \(STOP\); owner live/); assert.match(await b.evaluate('document.querySelector("#inspection").textContent'), /Board replies disabled for Discord connectors/); assert.equal(await b.evaluate('!!document.querySelector(".reply-form")'), false); assert.equal(await b.evaluate('!!window.injected'), false); // R1-U1: the connector's fixed task is "not applicable", never "unknown", and never the forged native setter. assert.match(await b.evaluate('document.querySelector("#inspection").textContent'), /Task set by\s*not applicable \(task is not from a registration\)/); assert.doesNotMatch(await b.evaluate('document.querySelector("#inspection").textContent'), /Task set by\s*unknown/); assert.equal(await b.evaluate('document.body.textContent.includes("forged")'), false); assert.equal(await b.evaluate('document.documentElement.scrollWidth<=innerWidth'), true); rmSync(join(dir, 'STOP')); rmSync(join(dir, 'run.lock', 'owner.json')); await b.evaluate('document.querySelector("#hide-offline").click();document.querySelector("#refresh").click()'); await wait('document.querySelector("#inspection").textContent.includes("owner absent")'); assert.match(await b.evaluate('document.querySelector("#inspection").textContent'), /not braked; owner absent/); assert.match(await b.evaluate('document.querySelector("#inspection").textContent'), /offline/); } finally { if (b) await b.close(); if (web) await close(web); if (board) await close(board); rmSync(root, { recursive: true, force: true }); } });