@vostride/agent-qa-dashboard 0.1.21 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index-Ds4Lv4mT.d.cts +2094 -0
- package/dist/index-Ds4Lv4mT.d.ts +2094 -0
- package/dist/index.cjs +10276 -7913
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +546 -83
- package/dist/index.d.ts +546 -83
- package/dist/index.js +10280 -7912
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs +8508 -6180
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +4 -4
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +8614 -6228
- package/dist/server/index.js.map +1 -1
- package/package.json +17 -14
- package/dist/index-ygQLgXzT.d.cts +0 -1168
- package/dist/index-ygQLgXzT.d.ts +0 -1168
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/index.ts","../../src/server/server.ts","../../src/server/routes.ts","../../src/memory/memory-catalog-manager.ts","../../src/tests/test-file-manager.ts","../../src/hooks/hook-registry-manager.ts","../../src/hooks/hook-reference-scan.ts","../../src/server/body-parser.ts","../../src/execution/test-runner.ts","../../src/queue/job-queue.ts","../../src/tests/suite-file-manager.ts","../../src/config/config-manager.ts","../../src/execution/appium-manager.ts","../../src/live-editor/session-manager.ts","../../src/live-editor/live-session.ts","../../src/live-editor/mobile-bootstrap.ts","../../src/live-editor/ws-handler.ts"],"sourcesContent":["export { startServer } from './server.js'\nexport { createRouter } from './routes.js'\nexport { readJsonBody } from './body-parser.js'\n","import { createServer, type Server } from 'node:http'\nimport { readFile, stat } from 'node:fs/promises'\nimport { join, extname, resolve } from 'node:path'\nimport { cpus } from 'node:os'\nimport type { DashboardDatabase } from '../db/database.js'\nimport { createRouter } from './routes.js'\nimport { TestRunner } from '../execution/test-runner.js'\nimport { JobQueue } from '../queue/job-queue.js'\nimport { TestFileManager } from '../tests/test-file-manager.js'\nimport { SuiteFileManager } from '../tests/suite-file-manager.js'\nimport { ConfigManager } from '../config/index.js'\nimport { AppiumManager } from '../execution/appium-manager.js'\nimport { WebSocketServer } from 'ws'\nimport { SessionManager } from '../live-editor/session-manager.js'\nimport { createSessionHandler } from '../live-editor/ws-handler.js'\nimport {\n buildAnalyticsEvent,\n captureAnalytics,\n resolveAnalyticsStandardProperties,\n type ModelConfig,\n type ResolvedWorkspacePaths,\n} from '@vostride/agent-qa-core'\nimport {\n createLocalMcpHttpHandler,\n resolveLocalMcpEndpoint,\n resolveMcpEndpointShape,\n type LocalMcpEndpointConfig,\n type LocalMcpTransport,\n} from '@vostride/agent-qa-mcp'\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript',\n '.mjs': 'application/javascript',\n '.css': 'text/css',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.svg': 'image/svg+xml',\n '.json': 'application/json',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n '.ttf': 'font/ttf',\n '.ico': 'image/x-icon',\n '.map': 'application/json',\n '.webp': 'image/webp',\n}\n\nfunction isAnalyticsPrivacyEnabled(config: unknown): boolean {\n if (!config || typeof config !== 'object') return false\n const analytics = (config as { analytics?: unknown }).analytics\n return Boolean(analytics && typeof analytics === 'object'\n && (analytics as { privacy?: unknown }).privacy === true)\n}\n\ninterface StartServerOptions {\n db: DashboardDatabase\n port?: number\n uiDir?: string\n artifactsDir?: string\n workspacePaths?: ResolvedWorkspacePaths\n configPath?: string\n mcp?: LocalMcpEndpointConfig\n llmConfig?: Pick<\n ModelConfig,\n 'provider' | 'model' | 'apiKey' | 'authToken' | 'baseURL' | 'providerHeaders'\n > & {\n screenshotSize?: number\n effectiveResolution?: number\n }\n authFetch?: typeof globalThis.fetch\n}\n\ninterface McpStartupInfo {\n enabled: boolean\n transport: LocalMcpTransport\n host?: string\n port?: number\n path?: string\n url?: string\n}\n\nexport async function startServer(opts: StartServerOptions): Promise<{\n server: Server\n port: number\n mcp: McpStartupInfo\n close: () => void\n}> {\n const { db, port = 3470, uiDir, artifactsDir, workspacePaths, configPath, mcp, llmConfig, authFetch } = opts\n\n const resolvedConfigPath = configPath ?? resolve('agent-qa.config.yaml')\n const configManager = new ConfigManager(resolvedConfigPath)\n\n // Read concurrency from config (defaults to os.cpus().length)\n const config = await configManager.read().catch(() => ({}))\n const concurrency = typeof (config as any).concurrency === 'number'\n ? (config as any).concurrency\n : cpus().length\n\n let testRunner: TestRunner | undefined\n\n const finalizeRunArtifactBestEffort = (\n runId: string,\n code: string,\n phase: string,\n message: string,\n runtime: Record<string, unknown> = {},\n ): void => {\n try {\n const artifact = db.getRunArtifact(runId)\n if (!artifact || artifact.finalizedAt) return\n db.finalizeRunArtifact(runId, {\n runtime,\n errors: [{ code, phase, message }],\n } as any)\n } catch { /* best-effort cleanup */ }\n }\n\n // Resolve CLI binary once — used by TestRunner\n let cliBin: string | undefined\n try {\n cliBin = TestRunner.resolveCliBin()\n } catch {\n console.warn('Warning: Could not resolve agent-qa CLI binary. Execution will not work.')\n }\n\n // TestRunner for live test execution\n if (cliBin) {\n testRunner = new TestRunner({\n cliBin,\n onProcessClose: (runId, status) => {\n // If the child process exited but the DB row is still 'running',\n // update it so the dashboard doesn't show a stuck run.\n try {\n const run = db.getRun(runId)\n const handle = testRunner!.getHandle(runId)\n const isBrowserDisconnect = handle?.output.some(line =>\n line.includes('Target page, context or browser has been closed') ||\n line.includes('Browser closed by user')\n )\n if (run && (run.status === 'running' || run.status === 'cancelled')) {\n const duration = run.startedAt\n ? Date.now() - new Date(run.startedAt).getTime()\n : 0\n\n let dbStatus: string\n let failureSummary: string | undefined\n let errorLog: string | undefined\n const explicitCancellation = run.status === 'cancelled' || status === 'cancelled'\n if (explicitCancellation) {\n dbStatus = 'cancelled'\n failureSummary = undefined\n } else if (status === 'timeout') {\n dbStatus = 'failed'\n failureSummary = 'Test timed out -- process was killed'\n } else if (status === 'completed') {\n dbStatus = 'failed'\n failureSummary = 'Process exited before test completed'\n } else if (isBrowserDisconnect) {\n dbStatus = 'cancelled'\n failureSummary = 'Browser closed by user'\n } else {\n dbStatus = 'failed'\n const outputLines = handle?.output.map(l => l.replace(/\\x1b\\[[0-9;]*m/g, '')) ?? []\n const meaningfulLine = [...outputLines].reverse().find(l =>\n /error/i.test(l) || l.includes('Parse') || l.includes('not found') || l.includes('rejected')\n )\n failureSummary = meaningfulLine\n ? meaningfulLine.slice(0, 300)\n : 'Process exited before test completed'\n }\n\n if (dbStatus === 'failed' && handle?.output.length) {\n errorLog = handle.output\n .join('\\n')\n .replace(/\\x1b\\[[0-9;]*m/g, '')\n .slice(-10000) || undefined\n }\n\n // Suite parent: derive status from child test runs\n if (run.suiteId && !run.parentRunId) {\n const children = db.getRunsByParent(runId)\n const incompleteChildStatus = dbStatus === 'cancelled' ? 'cancelled' : 'failed'\n const incompleteChildSummary = incompleteChildStatus === 'cancelled'\n ? 'Suite cancelled'\n : failureSummary ?? 'Suite process terminated'\n\n for (const child of children) {\n if (child.status === 'running' || child.status === 'pending') {\n db.updateRun(child.id, {\n status: incompleteChildStatus,\n endedAt: new Date().toISOString(),\n failureSummary: incompleteChildSummary,\n })\n finalizeRunArtifactBestEffort(\n child.id,\n 'suite-process-close',\n 'process-close',\n incompleteChildSummary,\n { status: incompleteChildStatus, finalStatus: incompleteChildStatus, processStatus: status },\n )\n }\n }\n\n const updatedChildren = db.getRunsByParent(runId)\n\n const statusPriority: Record<string, number> = {\n failed: 4,\n cancelled: 3,\n flaky: 2,\n passed: 1,\n skipped: 0,\n pending: 0,\n running: 0,\n }\n\n let worstStatus = 'passed'\n let worstPriority = 0\n for (const child of updatedChildren) {\n const p = statusPriority[child.status] ?? 0\n if (p > worstPriority) {\n worstPriority = p\n worstStatus = child.status\n }\n }\n\n if (updatedChildren.length === 0) {\n if (isBrowserDisconnect) {\n worstStatus = 'cancelled'\n } else {\n worstStatus = dbStatus\n }\n }\n\n db.updateRun(runId, {\n status: worstStatus,\n duration,\n endedAt: new Date().toISOString(),\n failureSummary: worstStatus === 'failed' ? 'Suite test(s) failed'\n : worstStatus === 'cancelled' ? (isBrowserDisconnect ? 'Browser closed by user' : 'Suite cancelled')\n : undefined,\n })\n finalizeRunArtifactBestEffort(\n runId,\n 'suite-process-close',\n 'process-close',\n worstStatus === 'cancelled' ? (isBrowserDisconnect ? 'Browser closed by user' : 'Suite cancelled') : 'Suite process closed',\n { status: worstStatus, finalStatus: worstStatus, processStatus: status, duration },\n )\n\n releaseMobileAppiumLease(runId, 'suite-process-close')\n jobQueue.onSlotFreed(runId)\n return\n }\n\n // Check for retry child runs and classify accordingly\n const childRuns = db.getRunsByParent(runId)\n if (childRuns.length > 0) {\n const incompleteChildStatus = dbStatus === 'cancelled' ? 'cancelled' : 'failed'\n const incompleteChildSummary = incompleteChildStatus === 'cancelled'\n ? 'Retry cancelled'\n : failureSummary ?? 'Retry process terminated'\n for (const child of childRuns) {\n if (child.status === 'running' || child.status === 'pending') {\n db.updateRun(child.id, {\n status: incompleteChildStatus,\n endedAt: new Date().toISOString(),\n failureSummary: incompleteChildSummary,\n })\n finalizeRunArtifactBestEffort(\n child.id,\n 'retry-process-close',\n 'process-close',\n incompleteChildSummary,\n { status: incompleteChildStatus, finalStatus: incompleteChildStatus, processStatus: status },\n )\n }\n }\n\n const updatedChildRuns = db.getRunsByParent(runId)\n const anyPassed = updatedChildRuns.some(r => r.status === 'passed')\n const firstPassed = updatedChildRuns[0]?.status === 'passed'\n if (anyPassed && !firstPassed) {\n dbStatus = 'flaky'\n } else if (anyPassed && firstPassed) {\n dbStatus = 'passed'\n } else if (dbStatus === 'cancelled' || updatedChildRuns.some(r => r.status === 'cancelled')) {\n dbStatus = 'cancelled'\n } else {\n dbStatus = 'failed'\n }\n const lastChild = updatedChildRuns[updatedChildRuns.length - 1]\n db.updateRun(runId, {\n status: dbStatus,\n duration,\n endedAt: new Date().toISOString(),\n failureSummary: dbStatus === 'failed' ? 'All retry attempts failed'\n : dbStatus === 'cancelled' ? 'Retry cancelled'\n : undefined,\n })\n finalizeRunArtifactBestEffort(\n runId,\n 'retry-process-close',\n 'process-close',\n dbStatus === 'failed' ? 'All retry attempts failed'\n : dbStatus === 'cancelled' ? 'Retry cancelled'\n : 'Retry process closed',\n { status: dbStatus, finalStatus: dbStatus, processStatus: status, duration },\n )\n db.updateRunRetryInfo(runId, {\n retryCount: updatedChildRuns.length,\n maxRetries: lastChild?.maxRetries ?? run.maxRetries,\n })\n releaseMobileAppiumLease(runId, 'retry-process-close')\n jobQueue.onSlotFreed(runId)\n return\n }\n\n db.updateRun(runId, {\n status: dbStatus,\n duration,\n endedAt: new Date().toISOString(),\n failureSummary,\n errorLog,\n })\n finalizeRunArtifactBestEffort(\n runId,\n isBrowserDisconnect ? 'browser-disconnect' : 'process-close',\n 'process-close',\n failureSummary ?? 'Process closed',\n { status: dbStatus, finalStatus: dbStatus, processStatus: status, duration },\n )\n }\n } catch { /* best-effort */ }\n\n releaseMobileAppiumLease(runId, status)\n jobQueue.onSlotFreed(runId)\n },\n })\n }\n\n // Clean up orphaned runs from previous server sessions — any run still\n // marked 'running' in the DB has no live process and should be failed.\n // Suite parents with active children are skipped (CLI process may still be running).\n const orphaned = db.getRuns({ status: 'running' })\n let cleaned = 0\n for (const run of orphaned) {\n if (run.suiteId && !run.parentRunId) {\n const children = db.getRunsByParent(run.id)\n if (children.some(c => c.status === 'running')) {\n continue\n }\n }\n const duration = run.startedAt\n ? Date.now() - new Date(run.startedAt).getTime()\n : 0\n db.updateRun(run.id, {\n status: 'failed',\n duration,\n endedAt: new Date().toISOString(),\n failureSummary: 'Process terminated unexpectedly (server restarted)',\n })\n finalizeRunArtifactBestEffort(run.id, 'server-restart', 'startup-cleanup', 'Process terminated unexpectedly (server restarted)', { status: 'failed', duration })\n cleaned++\n }\n if (cleaned > 0) {\n console.log(`Cleaned up ${cleaned} orphaned run(s) stuck in 'running' state`)\n }\n\n // Log any pending rows left from previous session (benign — picked up when queue starts)\n const pendingOrphans = db.getRuns({ status: 'pending' })\n if (pendingOrphans.length > 0) {\n console.log(`Found ${pendingOrphans.length} pending run(s) from previous session — will be processed when queue starts`)\n }\n\n // Appium lifecycle manager — auto-starts Appium for mobile tests\n const appiumManager = new AppiumManager()\n const mobileRuns = new Map<string, 'android' | 'ios'>()\n\n const releaseMobileAppiumLease = (runId: string, reason: string): void => {\n const platform = mobileRuns.get(runId)\n if (!platform) return\n mobileRuns.delete(runId)\n appiumManager.releaseLease(runId, reason)\n }\n\n const releaseAllMobileAppiumLeases = (reason: string): void => {\n for (const runId of [...mobileRuns.keys()]) {\n releaseMobileAppiumLease(runId, reason)\n }\n }\n\n // Persistent job queue — all triggers route through this\n const jobQueue = new JobQueue({ db, concurrency })\n console.log(`Job queue started with ${concurrency} concurrency slot(s)`)\n console.log('Appium lifecycle manager initialized (auto-start on first mobile test)')\n\n // Wire JobQueue 'execute' event to TestRunner\n jobQueue.on('execute', async (run) => {\n if (!testRunner) return\n\n const platform = run.platform ?? 'web'\n const isMobile = platform === 'ios' || platform === 'android'\n\n // Ensure Appium is running before mobile test execution\n if (isMobile) {\n try {\n await appiumManager.acquireLease({ runId: run.id, platform })\n mobileRuns.set(run.id, platform)\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n console.error(`Failed to start Appium for run ${run.id}: ${message}`)\n db.updateRun(run.id, {\n status: 'failed',\n failureSummary: `Appium server failed to start: ${message}`,\n endedAt: new Date().toISOString(),\n })\n finalizeRunArtifactBestEffort(run.id, 'appium-startup', 'appium-startup', `Appium server failed to start: ${message}`, { status: 'failed' })\n jobQueue.onSlotFreed(run.id)\n return\n }\n }\n\n const meta = (run.metadata ?? {}) as Record<string, unknown>\n const args = Array.isArray(meta.args)\n ? meta.args.filter((arg): arg is string => typeof arg === 'string')\n : []\n if (args.length === 0 && run.filePath) {\n args.push(run.filePath)\n }\n testRunner.execute({\n runId: run.id,\n args,\n source: meta.isSuite ? 'suite' : 'dashboard',\n attributes: run.attributes,\n timeout: meta.timeout as number | undefined,\n maxRetries: run.maxRetries,\n env: isMobile ? { AGENT_QA_APPIUM_URL: appiumManager.getUrl() } : undefined,\n })\n })\n\n // Wire cancellation — running jobs need process kill via TestRunner\n jobQueue.on('cancel-running', (runId: string) => {\n testRunner?.kill(runId)\n })\n\n // Start the queue polling loop\n jobQueue.start()\n\n // TestFileManager for test file CRUD\n const testFileManager = workspacePaths ? new TestFileManager(workspacePaths) : undefined\n\n const suiteFileManager = workspacePaths ? new SuiteFileManager(workspacePaths, testFileManager) : undefined\n\n const sessionManager = new SessionManager({\n appiumManager,\n configManager,\n configPath: resolvedConfigPath,\n })\n\n const apiRouter = createRouter({\n db,\n artifactsDir,\n workspacePaths,\n testRunner,\n jobQueue,\n testFileManager,\n suiteFileManager,\n configManager,\n configPath: resolvedConfigPath,\n llmConfig,\n authFetch,\n sessionManager,\n })\n\n const server = createServer(async (req, res) => {\n const url = new URL(req.url ?? '/', 'http://localhost')\n const path = url.pathname\n\n // API routes\n if (path.startsWith('/api/')) {\n apiRouter(req, res)\n return\n }\n\n // OPTIONS preflight\n if (req.method === 'OPTIONS') {\n res.writeHead(204, {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type',\n })\n res.end()\n return\n }\n\n // Static file serving\n if (uiDir) {\n const filePath = path === '/' ? join(uiDir, 'index.html') : join(uiDir, path)\n\n try {\n const fileStat = await stat(filePath)\n if (fileStat.isFile()) {\n const content = await readFile(filePath)\n const ext = extname(filePath)\n const contentType = MIME_TYPES[ext] || 'application/octet-stream'\n res.writeHead(200, {\n 'Content-Type': contentType,\n 'Content-Length': content.length,\n 'Access-Control-Allow-Origin': '*',\n })\n res.end(content)\n return\n }\n } catch {\n // File not found — fall through to SPA fallback\n }\n\n // SPA fallback: serve index.html for non-file paths\n try {\n const indexPath = join(uiDir, 'index.html')\n const content = await readFile(indexPath)\n res.writeHead(200, {\n 'Content-Type': 'text/html',\n 'Content-Length': content.length,\n 'Access-Control-Allow-Origin': '*',\n })\n res.end(content)\n return\n } catch {\n // No index.html available\n }\n }\n\n res.writeHead(404, { 'Content-Type': 'text/plain' })\n res.end('Not Found')\n })\n\n const wss = new WebSocketServer({ noServer: true })\n\n server.on('upgrade', (request, socket, head) => {\n const url = new URL(request.url ?? '/', 'http://localhost')\n if (url.pathname === '/api/live-editor/ws') {\n const sessionId = url.searchParams.get('sessionId')\n if (!sessionId) {\n socket.destroy()\n return\n }\n const session = sessionManager.getSession(sessionId)\n if (!session) {\n socket.destroy()\n return\n }\n\n wss.handleUpgrade(request, socket, head, (ws) => {\n session.clearIdleTimer()\n const handler = createSessionHandler(session, () => {\n sessionManager.terminateSession(sessionId)\n }, (event) => {\n db.insertTokenEvent(event)\n }, testFileManager)\n handler(ws)\n })\n } else {\n socket.destroy()\n }\n })\n\n const gracefulShutdown = () => {\n sessionManager.cleanupAll()\n }\n process.on('SIGTERM', gracefulShutdown)\n process.on('SIGINT', gracefulShutdown)\n\n const configuredMcp = (mcp ?? (config as any).services?.mcp ?? {}) as LocalMcpEndpointConfig\n const effectiveMcpConfig = configuredMcp.port === undefined && port === 0\n ? { ...configuredMcp, port: 0 }\n : configuredMcp\n const resolvedMcp = resolveLocalMcpEndpoint(effectiveMcpConfig)\n let mcpHttpServer: Server | undefined\n let mcpInfo: McpStartupInfo\n const captureMcpLifecycle = async (\n properties: {\n mcp_server_state: 'started' | 'disabled'\n mcp_transport: LocalMcpTransport\n mcp_host_kind?: 'loopback' | 'other'\n mcp_port_kind?: 'default' | 'custom'\n mcp_path_kind?: 'default' | 'custom'\n },\n ): Promise<void> => {\n if (isAnalyticsPrivacyEnabled(config)) return\n\n try {\n const standardProperties = await resolveAnalyticsStandardProperties({ surface: 'dashboard-server' })\n await captureAnalytics(buildAnalyticsEvent({\n name: 'agent-qa.mcp.server.lifecycle',\n properties: {\n ...standardProperties,\n surface: 'dashboard-server',\n ...properties,\n },\n }), { config }).catch(() => {})\n } catch {\n // Dashboard MCP lifecycle analytics must not alter startup behavior.\n }\n }\n const cleanupRuntimeResources = () => {\n jobQueue.stop()\n if (testRunner) {\n testRunner.killAll()\n }\n releaseAllMobileAppiumLeases('server-startup-error')\n appiumManager.shutdown()\n sessionManager.cleanupAll()\n db.close()\n }\n\n if (!resolvedMcp.enabled) {\n mcpInfo = {\n enabled: false,\n transport: resolvedMcp.transport,\n }\n await captureMcpLifecycle({\n mcp_server_state: 'disabled',\n mcp_transport: resolvedMcp.transport,\n })\n console.log('MCP disabled by services.mcp.enabled: false')\n } else if (resolvedMcp.transport === 'stdio') {\n mcpInfo = {\n enabled: false,\n transport: 'stdio',\n }\n console.log('MCP stdio transport selected; start editor MCP with `agent-qa mcp`')\n } else {\n let mcpHttpHandler = createLocalMcpHttpHandler({\n endpoint: resolvedMcp,\n dashboardUrl: `http://localhost:${port}`,\n configPath: resolvedConfigPath,\n analyticsConfig: config,\n })\n mcpHttpServer = createServer((req, res) => {\n void mcpHttpHandler(req, res)\n })\n\n try {\n await new Promise<void>((resolveMcp, rejectMcp) => {\n const onError = (err: Error) => {\n rejectMcp(err)\n }\n mcpHttpServer!.once('error', onError)\n mcpHttpServer!.listen(resolvedMcp.port, resolvedMcp.host, () => {\n mcpHttpServer!.off('error', onError)\n resolveMcp()\n })\n })\n } catch (err) {\n mcpHttpServer.close()\n cleanupRuntimeResources()\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to start MCP endpoint at ${resolvedMcp.url}: ${message}`)\n }\n\n const mcpAddress = mcpHttpServer.address()\n const actualMcpPort = typeof mcpAddress === 'object' && mcpAddress\n ? mcpAddress.port\n : resolvedMcp.port\n const actualMcp = resolveLocalMcpEndpoint({\n ...resolvedMcp,\n port: actualMcpPort,\n })\n if (actualMcpPort !== resolvedMcp.port) {\n mcpHttpHandler = createLocalMcpHttpHandler({\n endpoint: actualMcp,\n dashboardUrl: `http://localhost:${port}`,\n configPath: resolvedConfigPath,\n analyticsConfig: config,\n })\n }\n\n mcpInfo = {\n enabled: true,\n transport: 'http',\n host: actualMcp.host,\n port: actualMcp.port,\n path: actualMcp.path,\n url: actualMcp.url,\n }\n await captureMcpLifecycle({\n mcp_server_state: 'started',\n mcp_transport: 'http',\n ...resolveMcpEndpointShape(actualMcp),\n })\n console.log(`MCP running locally at ${actualMcp.url} (Streamable HTTP, loopback only)`)\n }\n\n return new Promise((resolve, reject) => {\n const onError = (err: Error) => {\n mcpHttpServer?.close()\n cleanupRuntimeResources()\n reject(err)\n }\n server.once('error', onError)\n server.listen(port, () => {\n server.off('error', onError)\n console.log(`Dashboard running at http://localhost:${port}`)\n resolve({\n server,\n port,\n mcp: mcpInfo,\n close: () => {\n jobQueue.stop()\n if (testRunner) {\n testRunner.killAll()\n }\n releaseAllMobileAppiumLeases('server-close')\n appiumManager.shutdown()\n sessionManager.cleanupAll()\n mcpHttpServer?.close()\n server.close()\n db.close()\n },\n })\n })\n })\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { randomUUID } from 'node:crypto'\nimport { readFile, writeFile, stat, readdir, rm } from 'node:fs/promises'\nimport { createReadStream } from 'node:fs'\nimport { join, isAbsolute, basename, resolve, dirname, relative } from 'node:path'\n\nimport type { AttributePredicate, DashboardDatabase, InsightsBreakdownDimension, RunArtifactRow, RunRow, StepRow } from '../db/database.js'\nimport type { TestRunner } from '../execution/test-runner.js'\nimport type { JobQueue } from '../queue/job-queue.js'\nimport { MemoryCatalogManager, isValidMemoryScopeId, type MemoryScope } from '../memory/memory-catalog-manager.js'\nimport { extractTestFileMetadata, type SupportedPlatform, type TestFileManager } from '../tests/test-file-manager.js'\nimport type { SuiteFileManager } from '../tests/suite-file-manager.js'\nimport type { ConfigManager } from '../config/index.js'\nimport { HookRegistryManager, isHookRegistryMutationError } from '../hooks/hook-registry-manager.js'\nimport { readJsonBody } from './body-parser.js'\nimport type { AnalyticsServiceConfig, LLMAuthProviderPlugin, ModelConfig, OAuthTokens } from '@vostride/agent-qa-core'\nimport { AuthStateNameSchema, buildAnalyticsEvent, buildInternalRunAttributes, captureAnalytics, mergeRunAttributes, readAuth, writeAuth, removeAuth, getAgentQaVersion, getAgentQaUpdateStatus, getProviderOptions, getLLMAuthProviderPlugin, listAuthStateMetadata, listLLMAuthProviderPlugins, ModelConfigSchema, NamedLLMConfigSchema, WorkspaceSchema, ServicesSchema, RegistrySchema, UseSchema, MobileAppStateSchema, hashStepInstruction, TimeoutConfigSchema, CacheConfigSchema, HealingConfigSchema, PlannerConfigSchema, LoggingConfigSchema, LogCaptureConfigSchema, AccessibilityConfigSchema, DashboardConfigSchema, McpConfigSchema, RecordingConfigSchema, BrowserConfigSchema, AnalyticsSchema, AgentQaConfigSchema, TestDefinitionSchema, SuiteDefinitionSchema, parseEnvFile, serializeEnvFile, parseHooksFile, runHookInSandbox, RUNTIME_IMAGE_MAP, SecretStore, SecretRedactor, redactAuthStateValue, validateUserRunAttributes, discoverWorkspaceFiles, isWorkspacePathMatch, resolveAnalyticsStandardProperties, resolveMemoryRoot, resolveWorkspaceFileTarget } from '@vostride/agent-qa-core'\nimport type { ResolvedWorkspacePaths, RunAttributes, WorkspaceFileKind, WorkspaceFileRecord } from '@vostride/agent-qa-core'\nimport { parse as parseYaml } from 'yaml'\n\nconst LLM_PROVIDER_MODES = new Set([\n 'openai-compatible',\n 'anthropic-compatible',\n 'gemini',\n])\nconst API_KEY_CREDENTIAL_PROVIDERS = new Set([\n 'openai-compatible',\n 'anthropic-compatible',\n 'gemini',\n])\nconst LLM_TEST_UNAUTHENTICATED_MESSAGE = 'Testing without a saved credential.'\nconst LLM_TEST_AUTH_ERROR_MESSAGE = 'Authentication failed. Check the saved credential for this config.'\nconst LLM_TEST_MODEL_NOT_FOUND_MESSAGE = 'Model not found. Check the model name.'\nconst LLM_TEST_NETWORK_ERROR_MESSAGE = 'Network error. Check the exact base URL and try again.'\nconst DASHBOARD_EXECUTION_TIMEOUT_BUFFER_MS = 60_000\nconst REMOTE_LLM_CONNECTION_TEST_TIMEOUT_MS = 10_000\nconst LOCAL_COMPATIBLE_LLM_CONNECTION_TEST_TIMEOUT_MS = 120_000\nconst LOCAL_COMPATIBLE_LLM_PROVIDERS = new Set(['openai-compatible', 'anthropic-compatible'])\nconst PLUGIN_OAUTH_SESSION_TTL_MS = 10 * 60 * 1000\nconst DASHBOARD_PRODUCT_EVENT_NAMES = [\n 'agent-qa.dashboard.opened',\n 'agent-qa.dashboard.live_mode.started',\n 'agent-qa.dashboard.entity.created',\n] as const\ntype DashboardProductEventName = typeof DASHBOARD_PRODUCT_EVENT_NAMES[number]\nconst DASHBOARD_PRODUCT_EVENT_NAME_SET = new Set<DashboardProductEventName>(DASHBOARD_PRODUCT_EVENT_NAMES)\nconst DASHBOARD_PRODUCT_EVENT_PROPERTY_KEYS = {\n 'agent-qa.dashboard.opened': [],\n 'agent-qa.dashboard.live_mode.started': ['platform', 'entity_type'],\n 'agent-qa.dashboard.entity.created': ['entity_type', 'outcome'],\n} as const satisfies Record<DashboardProductEventName, readonly string[]>\n\ntype DashboardExecutionTimeoutSource =\n | 'test.use.timeout.test'\n | 'suite.use.timeout.test'\n | 'config.use.timeout.test'\n | 'none'\n\ntype ConfigSectionValidationResult =\n | { success: true }\n | { success: false; error: { issues: { message: string; path: PropertyKey[] }[] } }\n\ninterface DashboardExecutionTimeout {\n timeoutMs?: number\n source: DashboardExecutionTimeoutSource\n baseTimeoutMs?: number\n bufferMs?: number\n}\n\nfunction toProductProviderLabel(provider: string): string {\n const plugin = listLLMAuthProviderPlugins()\n .find((candidate) => candidate.credentialProviderId === provider)\n return plugin?.providerId ?? provider\n}\n\nfunction isKnownLLMProvider(provider: string): boolean {\n return LLM_PROVIDER_MODES.has(provider) || Boolean(getLLMAuthProviderPlugin(provider))\n}\n\nasync function requirePluginAuthConfig(\n configManager: ConfigManager | undefined,\n configName: unknown,\n plugin: LLMAuthProviderPlugin,\n): Promise<{ ok: true; configName: string } | { ok: false; error: string }> {\n const targetConfigName = typeof configName === 'string' ? configName.trim() : ''\n if (!targetConfigName) {\n return { ok: false, error: 'configName is required' }\n }\n if (!configManager) {\n return { ok: false, error: 'Config manager is required to save OAuth credentials' }\n }\n\n const config = await configManager.read() as { registry?: { llms?: unknown[] } }\n const llms = Array.isArray(config.registry?.llms) ? config.registry.llms : []\n const match = llms.find((item) => {\n return Boolean(item)\n && typeof item === 'object'\n && !Array.isArray(item)\n && (item as { name?: unknown }).name === targetConfigName\n }) as { provider?: unknown } | undefined\n\n if (!match) {\n return { ok: false, error: `LLM config \"${targetConfigName}\" not found` }\n }\n if (match.provider !== plugin.providerId) {\n return { ok: false, error: `LLM config \"${targetConfigName}\" uses ${String(match.provider)}, not ${plugin.providerId}` }\n }\n\n return { ok: true, configName: targetConfigName }\n}\n\nasync function requireCredentialConfig(\n configManager: ConfigManager | undefined,\n configName: unknown,\n provider: string,\n): Promise<{ ok: true; configName: string } | { ok: false; error: string }> {\n const targetConfigName = typeof configName === 'string' ? configName.trim() : ''\n if (!targetConfigName) {\n return { ok: false, error: 'configName is required' }\n }\n if (!API_KEY_CREDENTIAL_PROVIDERS.has(provider)) {\n return { ok: false, error: 'provider must support typed credentials' }\n }\n if (!configManager) {\n return { ok: false, error: 'Config manager is required to save credentials' }\n }\n\n const config = await configManager.read() as { registry?: { llms?: unknown[] } }\n const llms = Array.isArray(config.registry?.llms) ? config.registry.llms : []\n const match = llms.find((item) => {\n return Boolean(item)\n && typeof item === 'object'\n && !Array.isArray(item)\n && (item as { name?: unknown }).name === targetConfigName\n }) as { provider?: unknown } | undefined\n\n if (!match) {\n return { ok: false, error: `LLM config \"${targetConfigName}\" not found` }\n }\n if (match.provider !== provider) {\n return { ok: false, error: `LLM config \"${targetConfigName}\" uses ${String(match.provider)}, not ${provider}` }\n }\n\n return { ok: true, configName: targetConfigName }\n}\n\ntype DashboardAuthCredential =\n | { type: 'oauth'; provider?: string; tokens: { expires: number } }\n | { type: 'api'; provider?: string; key?: string }\n | { type: 'bearer'; provider: string; token?: string }\n\ninterface DashboardLLMProviderMetadata {\n id: string\n label: string\n auth:\n | { kind: 'api-key'; credentialTypes: Array<'api-key' | 'bearer-token'>; optional?: boolean }\n | { kind: 'oauth-plugin'; mode: 'browser-poll' | 'manual-code'; buttonLabel?: string }\n modelAdapter?: 'openai-responses' | 'anthropic-messages'\n}\n\ninterface PluginOAuthSession {\n providerId: string\n credentialProviderId: string\n configName: string\n sessionState?: unknown\n cleanup?: () => void\n status: 'pending' | 'completed' | 'error'\n expiresAt: number\n error?: string\n}\n\nfunction builtinLLMProviderMetadata(): DashboardLLMProviderMetadata[] {\n return [\n {\n id: 'openai-compatible',\n label: 'OpenAI-compatible',\n auth: { kind: 'api-key', credentialTypes: ['api-key'], optional: true },\n modelAdapter: 'openai-responses',\n },\n {\n id: 'anthropic-compatible',\n label: 'Anthropic-compatible',\n auth: { kind: 'api-key', credentialTypes: ['api-key', 'bearer-token'], optional: true },\n modelAdapter: 'anthropic-messages',\n },\n {\n id: 'gemini',\n label: 'Gemini',\n auth: { kind: 'api-key', credentialTypes: ['api-key'] },\n },\n ]\n}\n\nfunction serializeAuthProviderPlugin(plugin: LLMAuthProviderPlugin): DashboardLLMProviderMetadata {\n return {\n id: plugin.providerId,\n label: plugin.label,\n modelAdapter: plugin.modelAdapter,\n auth: {\n kind: 'oauth-plugin',\n mode: plugin.dashboardAuth.mode,\n ...(plugin.dashboardAuth.buttonLabel ? { buttonLabel: plugin.dashboardAuth.buttonLabel } : {}),\n },\n }\n}\n\ntype DashboardRuntimeLLMConfig = Pick<\n ModelConfig,\n 'provider' | 'model' | 'apiKey' | 'authToken' | 'baseURL' | 'providerHeaders'\n> & {\n screenshotSize?: number\n effectiveResolution?: number\n modelAdapter?: 'openai-responses' | 'anthropic-messages'\n}\n\nconst writeDashboardAuth = writeAuth as unknown as (\n provider: string,\n credential: DashboardAuthCredential,\n) => Promise<void>\n\ntype DashboardResolvedRuntimeLLM =\n | { ok: true; llmConfig: DashboardRuntimeLLMConfig; authFetch?: typeof globalThis.fetch }\n | { ok: false; error: string }\n\nfunction normalizeRuntimeLLMConfig(raw: unknown): { configName: string; config: DashboardRuntimeLLMConfig } | undefined {\n if (!isPlainRecord(raw)) return undefined\n if (typeof raw.name !== 'string' || !raw.name.trim()) return undefined\n if (typeof raw.provider !== 'string' || !raw.provider.trim()) return undefined\n if (typeof raw.model !== 'string' || !raw.model.trim()) return undefined\n\n const config: DashboardRuntimeLLMConfig = {\n provider: raw.provider,\n model: raw.model,\n }\n if (typeof raw.baseURL === 'string') config.baseURL = raw.baseURL\n if (isPlainRecord(raw.providerHeaders)) {\n const headers: Record<string, string> = {}\n for (const [key, value] of Object.entries(raw.providerHeaders)) {\n if (typeof value === 'string') headers[key] = value\n }\n config.providerHeaders = headers\n }\n if (typeof raw.screenshotSize === 'number') config.screenshotSize = raw.screenshotSize\n if (typeof raw.effectiveResolution === 'number') config.effectiveResolution = raw.effectiveResolution\n\n return { configName: raw.name, config }\n}\n\nasync function resolveDashboardRuntimeLLM(\n configManager: ConfigManager | undefined,\n fallbackLLMConfig: DashboardRuntimeLLMConfig | undefined,\n fallbackAuthFetch: typeof globalThis.fetch | undefined,\n): Promise<DashboardResolvedRuntimeLLM> {\n if (!configManager) {\n if (!fallbackLLMConfig) {\n return { ok: false, error: 'LLM not configured. Set up LLM provider in settings.' }\n }\n return { ok: true, llmConfig: fallbackLLMConfig, authFetch: fallbackAuthFetch }\n }\n\n const rawConfig = await configManager.read()\n const registry = isPlainRecord(rawConfig.registry) ? rawConfig.registry : {}\n const use = isPlainRecord(rawConfig.use) ? rawConfig.use : {}\n const llms = Array.isArray(registry.llms) ? registry.llms : []\n const selectedName = typeof use.llm === 'string' ? use.llm : undefined\n const selected = selectedName\n ? llms.find((candidate) => isPlainRecord(candidate) && candidate.name === selectedName)\n : llms[0]\n\n const normalized = normalizeRuntimeLLMConfig(selected)\n if (!normalized) {\n if (!fallbackLLMConfig) {\n return { ok: false, error: 'LLM not configured. Set up LLM provider in settings.' }\n }\n return { ok: true, llmConfig: fallbackLLMConfig, authFetch: fallbackAuthFetch }\n }\n\n const coreAuth = await import('@vostride/agent-qa-core') as typeof import('@vostride/agent-qa-core') & {\n resolveLLMAuth: (\n configName: string,\n config: DashboardRuntimeLLMConfig,\n ) => Promise<\n | { kind: 'api-key'; apiKey: string }\n | { kind: 'bearer-token'; token: string }\n | { kind: 'auth-fetch'; fetch: typeof globalThis.fetch; modelAdapter: 'openai-responses' | 'anthropic-messages' }\n | { kind: 'unauthenticated'; message: string }\n | { kind: 'missing'; message: string }\n >\n }\n const auth = await coreAuth.resolveLLMAuth(normalized.configName, normalized.config)\n if (auth.kind === 'missing') {\n return { ok: false, error: auth.message }\n }\n\n const runtimeConfig: DashboardRuntimeLLMConfig = { ...normalized.config }\n let resolvedAuthFetch: typeof globalThis.fetch | undefined\n if (auth.kind === 'api-key') {\n runtimeConfig.apiKey = auth.apiKey\n } else if (auth.kind === 'bearer-token') {\n runtimeConfig.authToken = auth.token\n } else if (auth.kind === 'auth-fetch') {\n runtimeConfig.modelAdapter = auth.modelAdapter\n resolvedAuthFetch = auth.fetch\n }\n\n return { ok: true, llmConfig: runtimeConfig, authFetch: resolvedAuthFetch }\n}\n\nfunction cleanupPluginOAuthSession(session: PluginOAuthSession): void {\n const cleanup = session.cleanup\n session.cleanup = undefined\n if (!cleanup) return\n try {\n cleanup()\n } catch {\n // Best-effort cleanup for plugin-owned local callback servers.\n }\n}\n\nfunction pruneExpiredPluginOAuthSessions(sessions: Map<string, PluginOAuthSession>, now = Date.now()): void {\n for (const [sessionId, session] of sessions) {\n if (session.expiresAt <= now) {\n cleanupPluginOAuthSession(session)\n sessions.delete(sessionId)\n }\n }\n}\n\nfunction extractProviderErrorMessage(err: unknown): { message: string; statusCode?: number } {\n const errObj = err as Record<string, unknown>\n const statusCode = errObj?.statusCode as number | undefined\n const responseBody = errObj?.responseBody as string | undefined\n const data = errObj?.data as Record<string, unknown> | undefined\n const apiError = data?.error as Record<string, string> | undefined\n\n let message = err instanceof Error ? err.message : String(err)\n\n if (apiError?.message && apiError.message !== 'Error') {\n message = apiError.message\n } else if (data?.detail && typeof data.detail === 'string') {\n message = data.detail\n } else if (responseBody) {\n try {\n const body = JSON.parse(responseBody)\n if (body?.detail) message = body.detail\n else if (body?.error?.message && body.error.message !== 'Error') message = body.error.message\n } catch {\n // response body was not JSON\n }\n }\n\n return { message, statusCode }\n}\n\nfunction classifyProviderError(message: string, statusCode?: number): string {\n const fullContext = `${message} ${statusCode ?? ''}`\n if (/auth|unauthorized|401|invalid.*key|permission/i.test(fullContext)) {\n return 'auth_error'\n }\n if (/model.*not.*support|model.*not.*found|not found|404|does not exist/i.test(fullContext)) {\n return 'model_not_found'\n }\n if (/ECONNREFUSED|ENOTFOUND|timeout|abort|fetch failed|network/i.test(fullContext)) {\n return 'network_error'\n }\n if (/rate|429|quota|limit/i.test(fullContext)) {\n return 'rate_limit'\n }\n if (/invalid_request|400|bad request/i.test(fullContext)) {\n return 'invalid_request'\n }\n return 'provider_error'\n}\n\nfunction publicLLMTestMessage(category: string, providerMessage: string): string {\n switch (category) {\n case 'auth_error':\n return LLM_TEST_AUTH_ERROR_MESSAGE\n case 'model_not_found':\n return LLM_TEST_MODEL_NOT_FOUND_MESSAGE\n case 'network_error':\n return LLM_TEST_NETWORK_ERROR_MESSAGE\n case 'provider_error':\n return `Connection failed. ${providerMessage}`\n default:\n return providerMessage\n }\n}\n\nfunction isLocalLLMBaseURL(baseURL: unknown): boolean {\n if (typeof baseURL !== 'string' || !baseURL.trim()) return false\n try {\n const url = new URL(baseURL)\n const hostname = url.hostname.toLowerCase()\n return hostname === 'localhost'\n || hostname === '0.0.0.0'\n || hostname === '::1'\n || hostname === '[::1]'\n || hostname.startsWith('127.')\n || hostname.endsWith('.local')\n } catch {\n return false\n }\n}\n\nfunction llmConnectionTestTimeoutMs(config: { provider?: unknown; baseURL?: unknown }): number {\n // Connectivity probes are config-screen smoke checks only; real run execution\n // uses configured test timeout metadata and does not read this value.\n if (LOCAL_COMPATIBLE_LLM_PROVIDERS.has(String(config.provider)) && isLocalLLMBaseURL(config.baseURL)) {\n return LOCAL_COMPATIBLE_LLM_CONNECTION_TEST_TIMEOUT_MS\n }\n return REMOTE_LLM_CONNECTION_TEST_TIMEOUT_MS\n}\n\nfunction parseUrl(req: IncomingMessage): URL {\n return new URL(req.url ?? '/', 'http://localhost')\n}\n\nfunction json(res: ServerResponse, data: unknown, status = 200): void {\n const body = JSON.stringify(data)\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type',\n })\n res.end(body)\n}\n\nfunction notFound(res: ServerResponse, message = 'Not found'): void {\n json(res, { error: message }, 404)\n}\n\nfunction cors(res: ServerResponse): void {\n res.writeHead(204, {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type',\n })\n res.end()\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction getConfiguredAuthStateDir(config: Record<string, unknown>): string | undefined {\n const services = isPlainRecord(config.services) ? config.services : undefined\n const authState = services && isPlainRecord(services.authState) ? services.authState : undefined\n return typeof authState?.dir === 'string' ? authState.dir : undefined\n}\n\nfunction getSessionTargetNameForAuthState(session: { getState?: () => unknown } | undefined): string {\n if (!session || typeof session.getState !== 'function') return 'selected target'\n try {\n const state = session.getState()\n if (isPlainRecord(state) && typeof state.targetName === 'string' && state.targetName.trim().length > 0) {\n return state.targetName.trim()\n }\n } catch {\n // Do not let state serialization failures leak into auth-state responses.\n }\n return 'selected target'\n}\n\nfunction buildAuthStateSaveErrorMessage(\n stateName: string,\n targetName: string,\n error: unknown,\n): { status: number; message: string } {\n const raw = error instanceof Error ? error.message : String(error)\n if (/already exists/i.test(raw)) {\n return {\n status: 409,\n message: `Auth state \"${stateName}\" for target \"${targetName}\" already exists. Use replace=true to replace it.`,\n }\n }\n\n if (/web Live Mode|not ready|executing|busy/i.test(raw)) {\n return {\n status: 409,\n message: `Could not save auth state \"${stateName}\" for target \"${targetName}\".`,\n }\n }\n\n return {\n status: 500,\n message: `Could not save auth state \"${stateName}\" for target \"${targetName}\".`,\n }\n}\n\nfunction isDashboardProductEventName(value: unknown): value is DashboardProductEventName {\n return typeof value === 'string' && DASHBOARD_PRODUCT_EVENT_NAME_SET.has(value as DashboardProductEventName)\n}\n\nfunction filterDashboardProductEventProperties(\n name: DashboardProductEventName,\n properties: Record<string, unknown>,\n): Record<string, unknown> {\n const allowedKeys = DASHBOARD_PRODUCT_EVENT_PROPERTY_KEYS[name]\n const filtered: Record<string, unknown> = {}\n for (const key of allowedKeys) {\n if (Object.prototype.hasOwnProperty.call(properties, key)) {\n filtered[key] = properties[key]\n }\n }\n return filtered\n}\n\nasync function readAnalyticsServiceConfig(configManager: ConfigManager | undefined): Promise<AnalyticsServiceConfig> {\n if (!configManager) return {}\n\n try {\n const config = await configManager.read() as { analytics?: { privacy?: unknown } } | undefined\n if (config?.analytics?.privacy === true) {\n return { analytics: { privacy: true } }\n }\n } catch {\n // Fail closed for telemetry while keeping the HTTP route non-blocking.\n return { analytics: { privacy: true } }\n }\n return {}\n}\n\nfunction getPathInsideDir(candidatePath: string, rootDir: string): string | null {\n const relativePath = relative(rootDir, candidatePath)\n if (!relativePath || relativePath.startsWith('..') || isAbsolute(relativePath)) {\n return null\n }\n return relativePath\n}\n\nfunction isPlainFileName(value: string): boolean {\n const fileName = value.trim()\n return fileName.length > 0\n && fileName !== '.'\n && fileName !== '..'\n && !isAbsolute(fileName)\n && fileName === basename(fileName)\n && !/[\\\\/\\0]/.test(fileName)\n}\n\nfunction createHookRegistryManager(configManager?: ConfigManager, configPath?: string): HookRegistryManager | null {\n if (!configManager || !configPath) {\n return null\n }\n return new HookRegistryManager(configManager, configPath)\n}\n\nfunction normalizeRunFilterValue(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim().toLowerCase()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction buildRunRequestAttributes(input: {\n trigger: 'dashboard' | 'api' | 'mcp'\n runner?: 'local' | 'browserstack'\n userAttributes?: unknown\n}): RunAttributes {\n const internal = buildInternalRunAttributes({\n trigger: input.trigger,\n runner: input.runner ?? 'local',\n })\n const user = validateUserRunAttributes(input.userAttributes, 'run attributes')\n return mergeRunAttributes(internal, user)\n}\n\nfunction parseDashboardRunTriggerSource(value: unknown): { ok: true; trigger: 'dashboard' | 'mcp' } | { ok: false; error: string } {\n if (value === undefined || value === null) return { ok: true, trigger: 'dashboard' }\n if (value === 'dashboard' || value === 'mcp') return { ok: true, trigger: value }\n return { ok: false, error: 'triggerSource must be one of: dashboard, mcp' }\n}\n\nfunction parseAttributePredicates(searchParams: URLSearchParams): { ok: true; predicates: AttributePredicate[] } | { ok: false; error: string } {\n const predicates = new Map<string, AttributePredicate>()\n for (const [paramKey, value] of searchParams.entries()) {\n const match = /^attributes\\[([^\\]]*)\\](?:\\[(regex)\\])?$/.exec(paramKey)\n if (!match) continue\n const key = match[1]\n const mode = match[2] === 'regex' ? 'regex' : 'exact'\n if (!key.trim()) return { ok: false, error: 'Attribute key must be non-empty' }\n if (!value.trim()) return { ok: false, error: 'Attribute value must be non-empty' }\n const existing = predicates.get(key)\n if (existing && existing.mode !== mode) {\n return { ok: false, error: `Cannot combine exact and regex attribute filters for \"${key}\"` }\n }\n if (mode === 'regex') {\n try {\n new RegExp(value)\n } catch {\n return { ok: false, error: `Invalid attribute regex for \"${key}\"` }\n }\n }\n predicates.set(key, { key, value, mode })\n }\n return { ok: true, predicates: [...predicates.values()] }\n}\n\nfunction parseAnalyticsScopePredicates(config: Record<string, unknown> | undefined): { ok: true; predicates: AttributePredicate[] } | { ok: false; error: string } {\n const analytics = config?.analytics\n if (!analytics || typeof analytics !== 'object' || Array.isArray(analytics)) return { ok: true, predicates: [] }\n const passRateScope = (analytics as Record<string, unknown>).passRateScope\n if (!passRateScope || typeof passRateScope !== 'object' || Array.isArray(passRateScope)) return { ok: true, predicates: [] }\n const attributes = (passRateScope as Record<string, unknown>).attributes\n if (!attributes || typeof attributes !== 'object' || Array.isArray(attributes)) return { ok: true, predicates: [] }\n\n const predicates: AttributePredicate[] = []\n for (const [key, rawValue] of Object.entries(attributes)) {\n if (!key.trim()) return { ok: false, error: 'analytics.passRateScope attribute key must be non-empty' }\n if (typeof rawValue === 'string') {\n if (!rawValue.trim()) return { ok: false, error: `analytics.passRateScope attribute \"${key}\" must be non-empty` }\n predicates.push({ key, value: rawValue, mode: 'exact' })\n continue\n }\n if (rawValue && typeof rawValue === 'object' && !Array.isArray(rawValue) && typeof (rawValue as { regex?: unknown }).regex === 'string') {\n const regex = (rawValue as { regex: string }).regex\n if (!regex.trim()) return { ok: false, error: `analytics.passRateScope attribute \"${key}\" regex must be non-empty` }\n try {\n new RegExp(regex)\n } catch {\n return { ok: false, error: `Invalid analytics.passRateScope regex for \"${key}\"` }\n }\n predicates.push({ key, value: regex, mode: 'regex' })\n }\n }\n return { ok: true, predicates }\n}\n\nfunction validateAnalyticsPassRateScope(value: unknown): ConfigSectionValidationResult {\n const result = AnalyticsSchema.shape.passRateScope.safeParse(value)\n if (result.success) return { success: true }\n return {\n success: false,\n error: {\n issues: result.error.issues.map((issue) => ({\n message: issue.message,\n path: issue.path,\n })),\n },\n }\n}\n\nasync function readAnalyticsScopePredicates(configManager: ConfigManager | undefined): Promise<{ ok: true; predicates: AttributePredicate[] } | { ok: false; error: string }> {\n if (!configManager) return { ok: true, predicates: [] }\n const config = await configManager.read()\n const parsedConfig = AgentQaConfigSchema.safeParse(config)\n if (!parsedConfig.success) {\n return { ok: true, predicates: [] }\n }\n return parseAnalyticsScopePredicates(parsedConfig.data as Record<string, unknown>)\n}\n\nfunction calculateFlakyMetrics(runs: RunRow[]): { score: number; statusCount: number } {\n const statuses = runs\n .filter(r => r.status === 'passed' || r.status === 'failed')\n .map(r => r.status)\n let alternations = 0\n for (let i = 1; i < statuses.length; i++) {\n if (statuses[i] !== statuses[i - 1]) alternations++\n }\n return {\n score: statuses.length > 1 ? alternations / (statuses.length - 1) : 0,\n statusCount: statuses.length,\n }\n}\n\nfunction normalizeSupportedPlatform(value: unknown): SupportedPlatform | null {\n if (value !== 'web' && value !== 'android' && value !== 'ios') return null\n return value\n}\n\nfunction parseIsoDateQueryParam(\n value: string | null,\n field: 'from' | 'to',\n): { ok: true; value?: string } | { ok: false; error: string } {\n if (!value) return { ok: true, value: undefined }\n return Number.isNaN(Date.parse(value))\n ? { ok: false, error: `${field} must be a valid ISO date` }\n : { ok: true, value }\n}\n\nfunction parseBoundedIntegerQueryParam(\n value: string | null,\n field: string,\n min: number,\n max: number,\n fallback: number,\n): { ok: true; value: number } | { ok: false; error: string } {\n if (!value) return { ok: true, value: fallback }\n const parsed = Number.parseInt(value, 10)\n if (!Number.isFinite(parsed)) {\n return { ok: false, error: `${field} must be an integer` }\n }\n return { ok: true, value: Math.min(max, Math.max(min, parsed)) }\n}\n\nfunction getTargetPlatformMap(config: unknown): Map<string, SupportedPlatform> {\n const targetsValue = (config as {\n registry?: { targets?: Record<string, { platform?: unknown }> }\n }).registry?.targets\n\n const targetPlatforms = new Map<string, SupportedPlatform>()\n if (!targetsValue || typeof targetsValue !== 'object') return targetPlatforms\n\n for (const [targetName, targetConfig] of Object.entries(targetsValue)) {\n const platform = normalizeSupportedPlatform(targetConfig?.platform)\n if (platform) targetPlatforms.set(targetName, platform)\n }\n\n return targetPlatforms\n}\n\nasync function readTargetPlatformMap(configManager?: ConfigManager): Promise<Map<string, SupportedPlatform>> {\n if (!configManager) return new Map()\n try {\n const config = await configManager.read()\n return getTargetPlatformMap(config)\n } catch {\n return new Map()\n }\n}\n\nfunction parseTimeoutConfigTestTimeoutMs(timeoutConfig: unknown): number | undefined {\n if (timeoutConfig && typeof timeoutConfig === 'object' && !Array.isArray(timeoutConfig)) {\n const transformedTimeout = (timeoutConfig as { test?: unknown }).test\n if (typeof transformedTimeout === 'number' && Number.isFinite(transformedTimeout) && transformedTimeout > 0) {\n return transformedTimeout\n }\n }\n const parsed = TimeoutConfigSchema.partial().safeParse(timeoutConfig)\n if (!parsed.success) return undefined\n const testTimeout = parsed.data.test\n return typeof testTimeout === 'number' && Number.isFinite(testTimeout) && testTimeout > 0\n ? testTimeout\n : undefined\n}\n\nfunction parseUseTestTimeoutMs(useConfig: unknown): number | undefined {\n if (!useConfig || typeof useConfig !== 'object' || Array.isArray(useConfig)) return undefined\n return parseTimeoutConfigTestTimeoutMs((useConfig as { timeout?: unknown }).timeout)\n}\n\nasync function readConfigTestTimeoutMs(configManager?: ConfigManager): Promise<number | undefined> {\n if (!configManager) return undefined\n try {\n const config = await configManager.read()\n const parsed = AgentQaConfigSchema.safeParse(config)\n if (parsed.success) {\n return parseUseTestTimeoutMs(parsed.data.use)\n }\n return parseUseTestTimeoutMs((config as { use?: unknown }).use)\n } catch {\n return undefined\n }\n}\n\nfunction readTestYamlTimeoutMs(content: string): number | undefined {\n try {\n const parsedYaml = parseYaml(content)\n const parsedTest = TestDefinitionSchema.safeParse(parsedYaml)\n if (parsedTest.success) {\n return parseUseTestTimeoutMs(parsedTest.data.use)\n }\n return parseUseTestTimeoutMs((parsedYaml as { use?: unknown } | null | undefined)?.use)\n } catch {\n return undefined\n }\n}\n\nfunction readSuiteYamlTimeoutMs(content: string): number | undefined {\n try {\n const parsedYaml = parseYaml(content)\n const parsedSuite = SuiteDefinitionSchema.safeParse(parsedYaml)\n if (parsedSuite.success) {\n return parseUseTestTimeoutMs(parsedSuite.data.use)\n }\n return parseUseTestTimeoutMs((parsedYaml as { use?: unknown } | null | undefined)?.use)\n } catch {\n return undefined\n }\n}\n\nfunction parseUseParallel(useConfig: unknown): boolean | undefined {\n if (!isRecord(useConfig)) return undefined\n return typeof useConfig.parallel === 'boolean' ? useConfig.parallel : undefined\n}\n\nasync function readConfigUseParallel(configManager?: ConfigManager): Promise<boolean | undefined> {\n if (!configManager) return undefined\n try {\n const config = await configManager.read()\n const parsed = AgentQaConfigSchema.safeParse(config)\n if (parsed.success) {\n return parseUseParallel(parsed.data.use)\n }\n return parseUseParallel((config as { use?: unknown }).use)\n } catch {\n return undefined\n }\n}\n\nfunction readSuiteYamlParallel(content: string): boolean | undefined {\n try {\n const parsedYaml = parseYaml(content)\n const parsedSuite = SuiteDefinitionSchema.safeParse(parsedYaml)\n if (parsedSuite.success) {\n return parseUseParallel(parsedSuite.data.use)\n }\n return parseUseParallel((parsedYaml as { use?: unknown } | null | undefined)?.use)\n } catch {\n return undefined\n }\n}\n\nfunction withDashboardExecutionBuffer(\n baseTimeoutMs: number | undefined,\n source: DashboardExecutionTimeoutSource,\n): DashboardExecutionTimeout {\n if (!baseTimeoutMs) {\n return { source: 'none' }\n }\n return {\n timeoutMs: baseTimeoutMs + DASHBOARD_EXECUTION_TIMEOUT_BUFFER_MS,\n source,\n baseTimeoutMs,\n bufferMs: DASHBOARD_EXECUTION_TIMEOUT_BUFFER_MS,\n }\n}\n\nasync function resolveDashboardExecutionTimeout(opts: {\n isSuite: boolean\n file?: string\n normalizedTestPath?: string\n testFileManager?: TestFileManager\n suiteFileManager?: SuiteFileManager\n configManager?: ConfigManager\n}): Promise<DashboardExecutionTimeout> {\n if (opts.file) {\n if (opts.isSuite && opts.suiteFileManager) {\n try {\n const suiteContent = await opts.suiteFileManager.read(opts.file)\n const suiteTimeout = readSuiteYamlTimeoutMs(suiteContent)\n if (suiteTimeout) {\n return withDashboardExecutionBuffer(suiteTimeout, 'suite.use.timeout.test')\n }\n } catch {\n // Fall through to config timeout for draft or unreadable suite files.\n }\n } else if (!opts.isSuite && opts.testFileManager) {\n try {\n const testContent = await opts.testFileManager.read(opts.normalizedTestPath ?? opts.file)\n const testTimeout = readTestYamlTimeoutMs(testContent)\n if (testTimeout) {\n return withDashboardExecutionBuffer(testTimeout, 'test.use.timeout.test')\n }\n } catch {\n // Fall through to config timeout for draft or unreadable test files.\n }\n }\n }\n\n const configTimeout = await readConfigTestTimeoutMs(opts.configManager)\n return withDashboardExecutionBuffer(configTimeout, configTimeout ? 'config.use.timeout.test' : 'none')\n}\n\nfunction toExecutionTimeoutMetadata(timeout: DashboardExecutionTimeout): Record<string, unknown> {\n if (!timeout.timeoutMs) {\n return { timeoutSource: timeout.source }\n }\n return {\n timeout: timeout.timeoutMs,\n timeoutSource: timeout.source,\n timeoutBaseMs: timeout.baseTimeoutMs,\n timeoutBufferMs: timeout.bufferMs,\n }\n}\n\nfunction resolveEffectivePlatform(\n platform: string | null | undefined,\n targetName: string | null | undefined,\n targetPlatforms: Map<string, SupportedPlatform>,\n fallbackPlatform?: string | null,\n): SupportedPlatform | null {\n const explicitPlatform = normalizeSupportedPlatform(platform)\n if (explicitPlatform) return explicitPlatform\n\n if (targetName) {\n const targetPlatform = targetPlatforms.get(targetName)\n if (targetPlatform) return targetPlatform\n }\n\n return normalizeSupportedPlatform(fallbackPlatform)\n}\n\nfunction extractRunTargetName(testFileContent: string | null | undefined): string | null {\n if (!testFileContent) return null\n return extractTestFileMetadata(testFileContent).targetName\n}\n\ntype EnrichedRunRow = RunRow & {\n targetName: string | null\n tests?: EnrichedRunRow[]\n}\n\nfunction enrichRunRow(\n run: RunRow,\n targetPlatforms: Map<string, SupportedPlatform>,\n tests?: EnrichedRunRow[],\n): EnrichedRunRow {\n const metadata = run.testFileContent ? extractTestFileMetadata(run.testFileContent) : null\n let targetName = metadata?.targetName ?? extractRunTargetName(run.testFileContent)\n if (!targetName && tests && tests.length > 0) {\n const uniqueChildTargets = [...new Set(\n tests\n .map((test) => test.targetName)\n .filter((value): value is string => typeof value === 'string' && value.length > 0),\n )]\n if (uniqueChildTargets.length === 1) {\n targetName = uniqueChildTargets[0]\n }\n }\n\n const uniqueChildPlatforms = tests\n ? [...new Set(\n tests\n .map((test) => normalizeSupportedPlatform(test.platform))\n .filter((value): value is SupportedPlatform => value !== null),\n )]\n : []\n\n const platform = resolveEffectivePlatform(\n metadata?.platform,\n targetName,\n targetPlatforms,\n uniqueChildPlatforms.length === 1 ? uniqueChildPlatforms[0] : run.platform,\n )\n\n return {\n ...run,\n platform: platform ?? run.platform,\n targetName,\n ...(tests ? { tests } : {}),\n }\n}\n\nfunction matchesTargetFilter(run: EnrichedRunRow, filterValue: string | null): boolean {\n if (!filterValue) return true\n if (normalizeRunFilterValue(run.targetName) === filterValue) return true\n return run.tests?.some((test) => normalizeRunFilterValue(test.targetName) === filterValue) ?? false\n}\n\nfunction matchesPlatformFilter(run: EnrichedRunRow, filterValue: SupportedPlatform | null): boolean {\n if (!filterValue) return true\n if (normalizeSupportedPlatform(run.platform) === filterValue) return true\n return run.tests?.some((test) => normalizeSupportedPlatform(test.platform) === filterValue) ?? false\n}\n\nfunction getArtifactMissingSections(artifact: RunArtifactRow | null): string[] {\n if (!artifact) return ['artifact']\n const missing: string[] = []\n const payload = artifact.payload\n if (!('config' in payload)) missing.push('config')\n if (!('source' in payload)) missing.push('source')\n if (!('memory' in payload)) missing.push('memory')\n return missing\n}\n\nconst SECRET_TEMPLATE_RE = /\\{\\{secret:(\\w+)\\}\\}/g\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction sanitizeSecretTemplates(value: unknown): unknown {\n if (typeof value === 'string') {\n return value.replace(SECRET_TEMPLATE_RE, (_match, name: string) => `[secret:${name}]`)\n }\n if (Array.isArray(value)) {\n return value.map((item) => sanitizeSecretTemplates(item))\n }\n if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {\n return value\n }\n if (isRecord(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [key, sanitizeSecretTemplates(item)]),\n )\n }\n return value\n}\n\nfunction sanitizeSecretsFileMetadata(value: unknown): unknown {\n if (value === null || value === undefined) return value\n if (!isRecord(value)) return value\n return {\n path: typeof value.path === 'string' || value.path === null ? value.path : null,\n status: typeof value.status === 'string' ? value.status : 'loaded',\n ...(typeof value.count === 'number' ? { count: value.count } : {}),\n }\n}\n\nfunction sanitizeArtifactPayloadForResponse(payload: RunArtifactRow['payload']): RunArtifactRow['payload'] {\n const sanitized = redactAuthStateValue(sanitizeSecretTemplates(payload))\n if (!isRecord(sanitized)) return payload\n const config = sanitized.config\n if (!isRecord(config) || !('secretsFile' in config)) return sanitized as unknown as RunArtifactRow['payload']\n return {\n ...sanitized,\n config: {\n ...config,\n secretsFile: sanitizeSecretsFileMetadata(config.secretsFile),\n },\n } as RunArtifactRow['payload']\n}\n\nfunction sanitizeArtifactForResponse(artifact: RunArtifactRow | null): RunArtifactRow | null {\n if (!artifact) return null\n return {\n ...artifact,\n payload: sanitizeArtifactPayloadForResponse(artifact.payload),\n }\n}\n\nfunction sanitizeAuthStateForResponse<T>(value: T): T {\n return redactAuthStateValue(value)\n}\n\nasync function normalizeDashboardWorkspacePath(\n filePath: string,\n workspacePaths: ResolvedWorkspacePaths | undefined,\n kind: WorkspaceFileKind,\n requireExisting = true,\n): Promise<{ storagePath: string; executionPath: string }> {\n if (!workspacePaths) {\n throw new Error('Workspace path resolution is required for dashboard-triggered runs')\n }\n\n const record = await resolveWorkspaceFileTarget({\n workspace: workspacePaths,\n kind,\n filePath,\n requireExisting,\n })\n\n return { storagePath: record.workspaceRelativePath, executionPath: record.absolutePath }\n}\n\nfunction workspaceRecordToPath(record: WorkspaceFileRecord): { storagePath: string; executionPath: string } {\n return { storagePath: record.workspaceRelativePath, executionPath: record.absolutePath }\n}\n\nasync function resolveDashboardTestPattern(\n pattern: string,\n workspacePaths: ResolvedWorkspacePaths | undefined,\n): Promise<Array<{ storagePath: string; executionPath: string }>> {\n if (!workspacePaths) {\n throw new Error('Workspace path resolution is required for dashboard-triggered runs')\n }\n\n const normalizedPattern = pattern.replace(/\\\\/g, '/')\n if (isAbsolute(pattern) || normalizedPattern.split('/').includes('..')) {\n throw new Error(`Workspace test pattern is not allowed: ${pattern}`)\n }\n\n const candidates = await discoverWorkspaceFiles({ workspace: workspacePaths, kind: 'test' })\n const patternWorkspace: ResolvedWorkspacePaths = {\n ...workspacePaths,\n testMatch: [pattern],\n suiteMatch: [],\n }\n return candidates\n .filter((record) => isWorkspacePathMatch({\n workspace: patternWorkspace,\n kind: 'test',\n workspaceRelativePath: record.workspaceRelativePath,\n }))\n .map(workspaceRecordToPath)\n}\n\nfunction isSuiteFilePath(filePath: string | undefined): boolean {\n if (!filePath) return false\n const normalized = filePath.toLowerCase()\n return normalized.endsWith('.suite.yaml') || normalized.endsWith('.suite.yml')\n}\n\nasync function normalizeDashboardSuitePath(\n filePath: string,\n suiteFileManager?: SuiteFileManager,\n): Promise<{ storagePath: string; executionPath: string }> {\n if (!suiteFileManager) {\n throw new Error('Suite file management is required for dashboard-triggered suite runs')\n }\n\n return suiteFileManager.resolvePath(filePath)\n}\n\nfunction sanitizeQueuedRunMetadata(metadata: Record<string, unknown> | undefined): Record<string, unknown> {\n const { args: _args, target: _target, isSuite: _isSuite, ...safeMetadata } = metadata ?? {}\n return safeMetadata\n}\n\nfunction resolveArtifactPath(\n candidatePath: string,\n rootDir: string,\n apiPrefix: '/api/screenshots/' | '/api/videos/',\n): string | null {\n const normalizedCandidate = candidatePath.trim()\n if (!normalizedCandidate) return null\n const resolvedRootDir = resolve(rootDir)\n\n if (isAbsolute(normalizedCandidate)) {\n const resolvedAbsolute = resolve(normalizedCandidate)\n return getPathInsideDir(resolvedAbsolute, resolvedRootDir) ? resolvedAbsolute : null\n }\n\n const relativePath = normalizedCandidate.startsWith(apiPrefix)\n ? normalizedCandidate.slice(apiPrefix.length)\n : normalizedCandidate\n const resolvedPath = resolve(resolvedRootDir, relativePath)\n return getPathInsideDir(resolvedPath, resolvedRootDir) ? resolvedPath : null\n}\n\nasync function cleanupDeletedRunArtifacts(\n deletedRunIds: string[],\n screenshotPaths: string[],\n videoPaths: string[],\n dirs: {\n screenshotsDir?: string\n videosDir?: string\n },\n): Promise<void> {\n const cleanupTargets = new Set<string>()\n\n for (const runId of deletedRunIds) {\n if (dirs.screenshotsDir) cleanupTargets.add(join(dirs.screenshotsDir, runId))\n if (dirs.videosDir) cleanupTargets.add(join(dirs.videosDir, runId))\n }\n\n if (dirs.screenshotsDir) {\n for (const screenshotPath of screenshotPaths) {\n const resolvedPath = resolveArtifactPath(screenshotPath, dirs.screenshotsDir, '/api/screenshots/')\n if (resolvedPath) cleanupTargets.add(resolvedPath)\n }\n }\n\n if (dirs.videosDir) {\n for (const videoPath of videoPaths) {\n const resolvedPath = resolveArtifactPath(videoPath, dirs.videosDir, '/api/videos/')\n if (resolvedPath) cleanupTargets.add(resolvedPath)\n }\n }\n\n await Promise.allSettled(\n [...cleanupTargets].map((targetPath) => rm(targetPath, { recursive: true, force: true })),\n )\n}\n\nasync function readWorkspaceHooks(\n configManager: ConfigManager | undefined,\n configPath: string | undefined,\n): Promise<{\n hooks: Array<{ name: string }>\n filePath: string\n resolvedHooks: Map<string, import('@vostride/agent-qa-core').HookDefinition>\n errors: string[]\n missing: boolean\n hookRegistryError?: string\n}> {\n const hookRegistryManager = createHookRegistryManager(configManager, configPath)\n if (!hookRegistryManager) {\n return {\n hooks: [],\n filePath: '',\n resolvedHooks: new Map(),\n errors: ['Config management not available'],\n missing: true,\n hookRegistryError: 'Config management not available',\n }\n }\n\n const [hookCatalog, prepareResult] = await Promise.all([\n hookRegistryManager.readCatalog(),\n hookRegistryManager.prepareForExecution(),\n ])\n\n return {\n hooks: hookCatalog.hooks.map((hook) => ({ name: hook.name })),\n filePath: hookCatalog.filePath,\n resolvedHooks: prepareResult.resolvedHooks,\n errors: hookCatalog.errors,\n missing: hookCatalog.missing,\n hookRegistryError: prepareResult.hookRegistryError,\n }\n}\n\nasync function readWorkspaceEnvVars(\n workspacePaths: ResolvedWorkspacePaths | undefined,\n): Promise<Record<string, string>> {\n if (!workspacePaths) {\n return {}\n }\n\n try {\n const content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n return parseEnvFile(content)\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error(`workspace.envFile not found: ${workspacePaths.envFile.absolutePath}`)\n }\n throw error\n }\n}\n\nfunction validateHookRunRequest(body: unknown): {\n overrides: Record<string, string>\n fieldErrors: Array<{ field: 'registry'; code: string; message: string }>\n} {\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n return {\n overrides: {},\n fieldErrors: [\n {\n field: 'registry',\n code: 'invalid_payload',\n message: 'Hook run payload is required',\n },\n ],\n }\n }\n\n const rawOverrides = (body as { overrides?: unknown }).overrides\n if (rawOverrides === undefined) {\n return { overrides: {}, fieldErrors: [] }\n }\n\n if (!Array.isArray(rawOverrides)) {\n return {\n overrides: {},\n fieldErrors: [\n {\n field: 'registry',\n code: 'invalid_overrides',\n message: 'Hook run overrides must be an array',\n },\n ],\n }\n }\n\n const fieldErrors: Array<{ field: 'registry'; code: string; message: string }> = []\n const overrides: Record<string, string> = {}\n const seenKeys = new Set<string>()\n\n rawOverrides.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n fieldErrors.push({\n field: 'registry',\n code: 'invalid_override',\n message: `Override ${index + 1} must be an object with key and value`,\n })\n return\n }\n\n const key = typeof (entry as { key?: unknown }).key === 'string'\n ? (entry as { key: string }).key.trim()\n : ''\n const value = (entry as { value?: unknown }).value\n\n if (!key) {\n fieldErrors.push({\n field: 'registry',\n code: 'invalid_override_key',\n message: `Override ${index + 1} must include a non-empty key`,\n })\n return\n }\n\n if (seenKeys.has(key)) {\n fieldErrors.push({\n field: 'registry',\n code: 'duplicate_override_key',\n message: `Override key \"${key}\" is duplicated`,\n })\n return\n }\n\n if (typeof value !== 'string') {\n fieldErrors.push({\n field: 'registry',\n code: 'invalid_override_value',\n message: `Override \"${key}\" must have a string value`,\n })\n return\n }\n\n seenKeys.add(key)\n overrides[key] = value\n })\n\n return { overrides, fieldErrors }\n}\n\nfunction summarizeHookNetworkLogs(\n networkLogs: Array<{\n url: string\n method: string\n status: number\n startTime: number\n endTime: number\n }> | undefined,\n): import('../hooks/hook-registry-types.js').HookRunNetworkLogEntry[] {\n return (networkLogs ?? []).map((entry, index) => ({\n id: `network-${index + 1}`,\n method: entry.method,\n url: entry.url,\n statusCode: Number.isFinite(entry.status) ? entry.status : null,\n durationMs: Number.isFinite(entry.endTime - entry.startTime)\n ? Math.max(0, entry.endTime - entry.startTime)\n : null,\n error: null,\n }))\n}\n\ninterface RouterDeps {\n db: DashboardDatabase\n artifactsDir?: string\n workspacePaths?: ResolvedWorkspacePaths\n testRunner?: TestRunner\n jobQueue?: JobQueue\n testFileManager?: TestFileManager\n suiteFileManager?: SuiteFileManager\n configManager?: ConfigManager\n configPath?: string\n\n llmConfig?: DashboardRuntimeLLMConfig\n authFetch?: typeof globalThis.fetch\n sessionManager?: import('../live-editor/session-manager.js').SessionManager\n analyticsBridge?: {\n buildAnalyticsEvent: typeof buildAnalyticsEvent\n captureAnalytics: typeof captureAnalytics\n resolveAnalyticsStandardProperties: typeof resolveAnalyticsStandardProperties\n }\n}\n\nexport function createRouter(deps: RouterDeps): (req: IncomingMessage, res: ServerResponse) => void\nexport function createRouter(db: DashboardDatabase, artifactsDir?: string): (req: IncomingMessage, res: ServerResponse) => void\nexport function createRouter(dbOrDeps: DashboardDatabase | RouterDeps, artifactsDir?: string): (req: IncomingMessage, res: ServerResponse) => void {\n const deps: RouterDeps = 'db' in dbOrDeps && typeof (dbOrDeps as RouterDeps).db === 'object' && 'getRuns' in ((dbOrDeps as RouterDeps).db ?? {})\n ? dbOrDeps as RouterDeps\n : { db: dbOrDeps as DashboardDatabase, artifactsDir }\n const { db, testRunner, jobQueue, testFileManager, suiteFileManager, configManager, workspacePaths, llmConfig, authFetch, sessionManager } = deps\n const pluginOAuthSessions = new Map<string, PluginOAuthSession>()\n const analyticsBridge = deps.analyticsBridge ?? {\n buildAnalyticsEvent,\n captureAnalytics,\n resolveAnalyticsStandardProperties,\n }\n const ssDir = deps.artifactsDir ? join(deps.artifactsDir, 'screenshots') : undefined\n const vidDir = deps.artifactsDir ? join(deps.artifactsDir, 'videos') : undefined\n const memoryCatalogManager = new MemoryCatalogManager({ configManager, configPath: deps.configPath })\n\n return (req: IncomingMessage, res: ServerResponse) => {\n if (req.method === 'OPTIONS') {\n cors(res)\n return\n }\n\n const url = parseUrl(req)\n const path = url.pathname\n\n // GET /api/auth-states — list safe auth-state metadata only\n if (path === '/api/auth-states' && req.method === 'GET') {\n if (!configManager || !deps.configPath) {\n json(res, { error: 'Auth-state metadata not available' }, 503)\n return\n }\n ;(async () => {\n try {\n const config = await configManager.read()\n const targetName = url.searchParams.get('target') ?? undefined\n const authStates = await listAuthStateMetadata({\n configDir: dirname(resolve(deps.configPath!)),\n authStateDir: getConfiguredAuthStateDir(config),\n targetName,\n })\n json(res, { authStates })\n } catch {\n json(res, { error: 'Could not list auth states.' }, 500)\n }\n })()\n return\n }\n\n // POST /api/analytics/events — best-effort dashboard product analytics bridge\n if (path === '/api/analytics/events' && req.method === 'POST') {\n readJsonBody<{ name?: unknown; properties?: unknown }>(req)\n .then((body) => {\n if (\n !isPlainRecord(body)\n || !isDashboardProductEventName(body.name)\n || (\n Object.prototype.hasOwnProperty.call(body, 'properties')\n && body.properties !== undefined\n && !isPlainRecord(body.properties)\n )\n ) {\n json(res, { error: 'Invalid analytics event' }, 400)\n return\n }\n\n const name = body.name\n const browserProperties = isPlainRecord(body.properties) ? body.properties : {}\n json(res, { accepted: true }, 202)\n\n void (async () => {\n try {\n const config = await readAnalyticsServiceConfig(configManager)\n if (config.analytics?.privacy === true) {\n return\n }\n\n const standardProperties = await analyticsBridge.resolveAnalyticsStandardProperties({ surface: 'dashboard-ui' })\n const event = analyticsBridge.buildAnalyticsEvent({\n name,\n properties: {\n ...filterDashboardProductEventProperties(name, browserProperties),\n ...standardProperties,\n },\n })\n await analyticsBridge.captureAnalytics(event, { config })\n } catch {\n // Analytics is intentionally best-effort and invisible to dashboard users.\n }\n })()\n })\n .catch(() => json(res, { error: 'Invalid analytics event' }, 400))\n return\n }\n\n // GET /api/runs\n if (path === '/api/runs' && req.method === 'GET') {\n const status = url.searchParams.get('status') ?? undefined\n const name = url.searchParams.get('name') ?? undefined\n const platform = url.searchParams.get('platform') ?? undefined\n const target = normalizeRunFilterValue(url.searchParams.get('target'))\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 50\n const offset = url.searchParams.has('offset') ? parseInt(url.searchParams.get('offset')!, 10) : 0\n const attributePredicatesResult = parseAttributePredicates(url.searchParams)\n if (!attributePredicatesResult.ok) {\n json(res, { error: attributePredicatesResult.error }, 400)\n return\n }\n\n void readTargetPlatformMap(configManager)\n .then((targetPlatforms) => {\n const allRuns = db.getRuns({\n status,\n name,\n from,\n to,\n attributePredicates: attributePredicatesResult.predicates,\n })\n const enrichedRuns = allRuns.map(run => {\n if (run.suiteId && !run.parentRunId) {\n const tests = db.getRunsByParent(run.id).map(test => enrichRunRow(test, targetPlatforms))\n return enrichRunRow(run, targetPlatforms, tests)\n }\n return enrichRunRow(run, targetPlatforms)\n })\n const platformFilteredRuns = enrichedRuns.filter(run =>\n matchesPlatformFilter(run, normalizeSupportedPlatform(platform)),\n )\n const targetOptions = Array.from(new Set(\n platformFilteredRuns\n .flatMap(run => [run.targetName, ...(run.tests?.map(test => test.targetName) ?? [])])\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0),\n )).sort((a, b) => a.localeCompare(b))\n const filtered = platformFilteredRuns.filter(run => matchesTargetFilter(run, target))\n\n const runs = filtered.slice(offset, offset + limit)\n json(res, { runs, total: filtered.length, targets: targetOptions })\n })\n .catch(() => json(res, { error: 'Failed to list runs' }, 500))\n return\n }\n\n // GET /api/runs/attributes/keys\n if (path === '/api/runs/attributes/keys' && req.method === 'GET') {\n const limitResult = parseBoundedIntegerQueryParam(url.searchParams.get('limit'), 'limit', 1, 100, 50)\n if (!limitResult.ok) {\n json(res, { error: limitResult.error }, 400)\n return\n }\n json(res, {\n keys: db.listRunAttributeKeys({\n limit: limitResult.value,\n q: url.searchParams.get('q') ?? undefined,\n }),\n })\n return\n }\n\n // GET /api/runs/attributes/values\n if (path === '/api/runs/attributes/values' && req.method === 'GET') {\n const key = url.searchParams.get('key')?.trim()\n if (!key) {\n json(res, { error: 'key is required' }, 400)\n return\n }\n const limitResult = parseBoundedIntegerQueryParam(url.searchParams.get('limit'), 'limit', 1, 100, 50)\n if (!limitResult.ok) {\n json(res, { error: limitResult.error }, 400)\n return\n }\n json(res, {\n values: db.listRunAttributeValues(key, {\n limit: limitResult.value,\n q: url.searchParams.get('q') ?? undefined,\n }),\n })\n return\n }\n\n // GET /api/runs/:id/artifact\n const runArtifactMatch = path.match(/^\\/api\\/runs\\/([^/]+)\\/artifact$/)\n if (runArtifactMatch && req.method === 'GET') {\n const runId = decodeURIComponent(runArtifactMatch[1])\n const run = db.getRun(runId)\n if (!run) {\n notFound(res, 'Run not found')\n return\n }\n const bundle = db.getRunArtifactBundle(runId)\n json(res, sanitizeAuthStateForResponse({\n run,\n artifact: sanitizeArtifactForResponse(bundle.artifact),\n children: bundle.children.map((child) => ({\n ...child,\n artifact: sanitizeArtifactForResponse(child.artifact),\n })),\n missingSections: getArtifactMissingSections(bundle.artifact),\n }))\n return\n }\n\n // GET /api/runs/:id/accessibility\n if (path.startsWith('/api/runs/') && path.endsWith('/accessibility') && req.method === 'GET') {\n const segments = path.split('/')\n const id = segments[3]\n const run = db.getRun(id)\n if (!run) {\n notFound(res, 'Run not found')\n return\n }\n const summary = db.getAccessibilitySummary(id)\n json(res, summary)\n return\n }\n\n // GET /api/runs/:id/steps/:n/reasoning — structured reasoning trace for a step\n const reasoningMatch = path.match(/^\\/api\\/runs\\/([^/]+)\\/steps\\/(\\d+)\\/reasoning$/)\n if (reasoningMatch && req.method === 'GET') {\n const [, runId, stepOrderStr] = reasoningMatch\n const run = db.getRun(runId)\n if (!run) { notFound(res, 'Run not found'); return }\n const stepOrder = parseInt(stepOrderStr, 10)\n const trace = db.getReasoningTrace(runId, stepOrder)\n if (trace) {\n json(res, sanitizeAuthStateForResponse({ trace }))\n return\n }\n // Fallback: construct legacy trace from step data for backward compatibility\n const steps = db.getSteps(runId)\n const step = steps.find(s => s.stepOrder === stepOrder)\n if (!step) { notFound(res, 'Step not found'); return }\n json(res, sanitizeAuthStateForResponse({\n trace: {\n id: null,\n stepId: step.id,\n observeText: step.observation,\n observeDuration: null,\n planReasoning: step.reasoning,\n planConfidence: step.confidence,\n planAction: step.plannedAction,\n planDuration: null,\n executeAction: step.action,\n executeDuration: null,\n verifyReasoning: null,\n verifySuccess: step.result === 'success' ? true : step.result === 'failure' ? false : null,\n verifyDuration: null,\n healAttempts: step.healingAttempts,\n totalDuration: step.duration,\n screenStateBefore: null,\n screenStateAfter: null,\n createdAt: step.createdAt,\n },\n }))\n return\n }\n\n // GET /api/runs/:id/execution-logs\n if (path.startsWith('/api/runs/') && path.endsWith('/execution-logs') && req.method === 'GET') {\n const segments = path.split('/')\n const id = segments[3]\n const run = db.getRun(id)\n if (!run) {\n notFound(res, 'Run not found')\n return\n }\n const stepId = url.searchParams.get('stepId') ?? undefined\n const type = url.searchParams.get('type') ?? undefined\n\n if (run.suiteId && !run.parentRunId) {\n const childRuns = db.getRunsByParent(id)\n const allRunIds = [id, ...childRuns.map((c: any) => c.id)]\n let allLogs: any[] = []\n for (const rid of allRunIds) {\n allLogs.push(...db.getExecutionLogs({ runId: rid, stepId, type }))\n }\n json(res, sanitizeAuthStateForResponse({ logs: allLogs }))\n return\n }\n\n const logs = db.getExecutionLogs({ runId: id, stepId, type })\n json(res, sanitizeAuthStateForResponse({ logs }))\n return\n }\n\n // GET /api/runs/:id/logs\n if (path.startsWith('/api/runs/') && path.endsWith('/logs') && req.method === 'GET') {\n const segments = path.split('/')\n const id = segments[3]\n const run = db.getRun(id)\n if (!run) {\n notFound(res, 'Run not found')\n return\n }\n const stepId = url.searchParams.get('stepId') ?? undefined\n const level = url.searchParams.get('level') ?? undefined\n const source = url.searchParams.get('source') ?? undefined\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 500\n const offset = url.searchParams.has('offset') ? parseInt(url.searchParams.get('offset')!, 10) : 0\n const logs = db.getLogs({ runId: id, stepId, level, source, limit, offset })\n json(res, sanitizeAuthStateForResponse({ logs, total: logs.length }))\n return\n }\n\n // GET /api/runs/:id/steps\n if (path.startsWith('/api/runs/') && path.endsWith('/steps') && req.method === 'GET') {\n const segments = path.split('/')\n const id = segments[3]\n const run = db.getRun(id)\n if (!run) {\n notFound(res, 'Run not found')\n return\n }\n const steps = db.getSteps(id)\n json(res, sanitizeAuthStateForResponse({ steps }))\n return\n }\n\n // POST /api/runs/:id/cancel — cancel a pending or running execution\n if (path.startsWith('/api/runs/') && path.endsWith('/cancel') && req.method === 'POST') {\n if (!jobQueue) {\n json(res, { error: 'Queue not available' }, 503)\n return\n }\n const runId = path.slice('/api/runs/'.length, path.length - '/cancel'.length)\n const cancelled = jobQueue.cancel(runId)\n if (cancelled) {\n // For pending jobs, JobQueue already set status='cancelled'.\n // For running jobs, JobQueue emits 'cancel-running' which triggers executionManager.kill().\n // Update DB with cancel metadata for running jobs.\n try {\n const run = db.getRun(runId)\n if (run && run.status === 'cancelled') {\n const duration = run.startedAt\n ? Date.now() - new Date(run.startedAt).getTime()\n : 0\n db.updateRun(runId, {\n duration,\n endedAt: new Date().toISOString(),\n failureSummary: 'Test cancelled by user',\n })\n }\n } catch { /* best-effort */ }\n json(res, { cancelled: true })\n } else {\n json(res, { error: 'Run not found or not cancellable' }, 404)\n }\n return\n }\n\n // DELETE /api/runs/:id\n if (path.startsWith('/api/runs/') && req.method === 'DELETE') {\n const segments = path.split('/')\n if (segments.length !== 4) {\n notFound(res)\n return\n }\n\n const id = segments[3]\n\n try {\n const deletedRun = db.deleteRun(id)\n if (!deletedRun.deleted) {\n notFound(res, 'Run not found')\n return\n }\n\n void cleanupDeletedRunArtifacts(\n deletedRun.deletedRunIds,\n deletedRun.screenshotPaths,\n deletedRun.videoPaths,\n {\n screenshotsDir: ssDir,\n videosDir: vidDir,\n },\n ).finally(() => {\n json(res, { deleted: true, deletedRunIds: deletedRun.deletedRunIds })\n })\n } catch {\n json(res, { error: 'Failed to delete run' }, 500)\n }\n return\n }\n\n // GET /api/runs/:id\n if (path.startsWith('/api/runs/') && req.method === 'GET') {\n const segments = path.split('/')\n if (segments.length !== 4) {\n notFound(res)\n return\n }\n const id = segments[3]\n const run = db.getRun(id)\n if (!run) {\n notFound(res, 'Run not found')\n return\n }\n const steps = db.getSteps(id)\n const attempts = db.getRunsByParent(id)\n if (run.suiteId && !run.parentRunId) {\n const tests = db.getRunsByParent(id)\n json(res, sanitizeAuthStateForResponse({ run, steps, attempts, tests }))\n } else {\n json(res, sanitizeAuthStateForResponse({ run, steps, attempts }))\n }\n return\n }\n\n // GET /api/stats/costs\n if (path === '/api/stats/costs' && req.method === 'GET') {\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const costStats = db.getCostStats({ from, to })\n json(res, costStats)\n return\n }\n\n // GET /api/token-events/stats\n if (path === '/api/token-events/stats' && req.method === 'GET') {\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const stats = db.getTokenEventStats({ from, to })\n json(res, stats)\n return\n }\n\n // GET /api/stats\n if (path === '/api/stats' && req.method === 'GET') {\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const scope = url.searchParams.get('scope') ?? undefined\n if (scope !== undefined && scope !== 'passRate') {\n json(res, { error: 'scope must be passRate when provided' }, 400)\n return\n }\n\n void readAnalyticsScopePredicates(configManager)\n .then((scopeResult) => {\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n const configured = scopeResult.predicates.length > 0\n const allStats = db.getStats({ from, to })\n const scopedStats = configured\n ? db.getStats({ from, to, attributePredicates: scopeResult.predicates })\n : allStats\n const stats = scope === 'passRate' && configured ? scopedStats : allStats\n\n json(res, {\n ...stats,\n scope: {\n configured,\n predicates: scopeResult.predicates,\n scopedCount: configured ? scopedStats.totalRuns : 0,\n totalCount: allStats.totalRuns,\n },\n })\n })\n .catch(() => {\n json(res, { error: 'Unable to read analytics scope' }, 500)\n })\n return\n }\n\n // GET /api/screenshots/:runId/:filename\n if (path.startsWith('/api/screenshots/') && req.method === 'GET') {\n const segments = path.split('/')\n if (segments.length !== 5 || !ssDir) {\n notFound(res)\n return\n }\n const runId = segments[3]\n const filename = segments[4]\n\n if (runId.includes('..') || filename.includes('..') || runId.includes('/') || filename.includes('/')) {\n notFound(res, 'Invalid path')\n return\n }\n\n const filePath = join(ssDir, runId, filename)\n const resolvedPath = resolve(filePath)\n if (!resolvedPath.startsWith(resolve(ssDir))) {\n notFound(res, 'Invalid path')\n return\n }\n\n stat(filePath).then(s => {\n if (!s.isFile()) {\n notFound(res, 'Screenshot not found')\n return\n }\n readFile(filePath).then(buffer => {\n res.writeHead(200, {\n 'Content-Type': 'image/png',\n 'Content-Length': buffer.length,\n 'Access-Control-Allow-Origin': '*',\n })\n res.end(buffer)\n }).catch(() => notFound(res, 'Screenshot not found'))\n }).catch(() => notFound(res, 'Screenshot not found'))\n return\n }\n\n // GET /api/videos/:runId/:filename\n if (path.startsWith('/api/videos/') && req.method === 'GET') {\n const segments = path.split('/')\n if (segments.length !== 5 || !vidDir) {\n notFound(res)\n return\n }\n const runId = segments[3]\n const filename = segments[4]\n\n if (runId.includes('..') || filename.includes('..') || runId.includes('/') || filename.includes('/')) {\n notFound(res, 'Invalid path')\n return\n }\n\n const videoPath = join(vidDir, runId, filename)\n const resolvedVideo = resolve(videoPath)\n const resolvedVidDir = resolve(vidDir)\n if (!getPathInsideDir(resolvedVideo, resolvedVidDir)) {\n notFound(res, 'Invalid path')\n return\n }\n\n const tryServe = (filePath: string) => stat(filePath).then(s => {\n if (!s.isFile()) {\n notFound(res, 'Video not found')\n return\n }\n\n const contentType = filePath.endsWith('.mp4') ? 'video/mp4' : 'video/webm'\n const range = req.headers.range\n if (range) {\n const parts = range.replace(/bytes=/, '').split('-')\n const start = parseInt(parts[0], 10)\n const end = parts[1] ? parseInt(parts[1], 10) : s.size - 1\n const chunkSize = end - start + 1\n\n res.writeHead(206, {\n 'Content-Range': `bytes ${start}-${end}/${s.size}`,\n 'Accept-Ranges': 'bytes',\n 'Content-Length': chunkSize,\n 'Content-Type': contentType,\n 'Access-Control-Allow-Origin': '*',\n })\n createReadStream(filePath, { start, end }).pipe(res)\n } else {\n res.writeHead(200, {\n 'Content-Type': contentType,\n 'Content-Length': s.size,\n 'Accept-Ranges': 'bytes',\n 'Access-Control-Allow-Origin': '*',\n })\n createReadStream(filePath).pipe(res)\n }\n })\n tryServe(videoPath).catch(() => notFound(res, 'Video not found'))\n return\n }\n\n // GET /api/execution/active — list currently running tests\n if (path === '/api/execution/active' && req.method === 'GET') {\n const active = testRunner ? testRunner.getActiveExecutions() : []\n json(res, { executions: active })\n return\n }\n\n // POST /api/queue/enqueue — external API to enqueue a test run\n if (path === '/api/queue/enqueue' && req.method === 'POST') {\n if (!jobQueue) {\n json(res, { error: 'Queue not available' }, 503)\n return\n }\n readJsonBody<{ name: string; file?: string; priority?: number; platform?: string; parallel?: boolean; metadata?: Record<string, unknown>; attributes?: unknown }>(req)\n .then(async (body) => {\n if (!body.name || typeof body.name !== 'string') {\n json(res, { error: 'name is required' }, 400)\n return\n }\n let normalizedFileTarget: { storagePath: string; executionPath: string } | null = null\n const isSuiteFile = isSuiteFilePath(body.file)\n if (body.file) {\n try {\n normalizedFileTarget = isSuiteFile\n ? await normalizeDashboardSuitePath(body.file, suiteFileManager)\n : await normalizeDashboardWorkspacePath(body.file, workspacePaths, 'test')\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : String(err) }, 400)\n return\n }\n }\n let attributes: RunAttributes\n try {\n attributes = buildRunRequestAttributes({\n trigger: 'api',\n runner: 'local',\n userAttributes: body.attributes,\n })\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : String(err) }, 400)\n return\n }\n const runId = jobQueue.enqueue({\n name: body.name,\n filePath: normalizedFileTarget?.storagePath,\n kind: isSuiteFile ? 'suite-parent' : 'test',\n attributes,\n priority: body.priority,\n platform: body.platform,\n parallel: body.parallel,\n metadata: {\n ...sanitizeQueuedRunMetadata(body.metadata),\n args: normalizedFileTarget ? [normalizedFileTarget.executionPath] : [],\n ...(isSuiteFile ? { isSuite: true } : {}),\n },\n })\n const pending = db.getPendingRuns()\n const position = pending.findIndex(r => r.id === runId) + 1\n json(res, { runId, status: 'queued', position }, 202)\n })\n .catch(() => {\n json(res, { error: 'Invalid request body' }, 400)\n })\n return\n }\n\n // GET /api/queue/status — queue status with pending/running jobs\n if (path === '/api/queue/status' && req.method === 'GET') {\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 20\n const completed = url.searchParams.get('completed') === 'true'\n const pending = db.getPendingRuns()\n const allRuns = db.getRuns({ limit: 100 })\n const running = allRuns.filter(r => r.status === 'running')\n const response: Record<string, unknown> = {\n pending: { count: pending.length, jobs: pending },\n running: { count: running.length, jobs: running },\n concurrency: jobQueue?.getConcurrency() ?? 0,\n activeSlots: jobQueue?.getActiveCount() ?? 0,\n }\n if (completed) {\n const recent = allRuns\n .filter(r => r.status !== 'pending' && r.status !== 'running')\n .slice(0, limit)\n response.recent = recent\n }\n json(res, response)\n return\n }\n\n // POST /api/runs/trigger — enqueue a live test execution\n if (path === '/api/runs/trigger' && req.method === 'POST') {\n if (!jobQueue) {\n json(res, { error: 'Queue not available' }, 503)\n return\n }\n readJsonBody<{ file?: string; patterns?: string[]; tags?: unknown; noCache?: boolean; noMemory?: boolean; local?: boolean; triggerSource?: unknown }>(req)\n .then(async (body) => {\n if (body.tags !== undefined) {\n json(res, { error: 'tags are not supported for dashboard-triggered runs' }, 400)\n return\n }\n const triggerSource = parseDashboardRunTriggerSource(body.triggerSource)\n if (!triggerSource.ok) {\n json(res, { error: triggerSource.error }, 400)\n return\n }\n const args: string[] = []\n const isSuiteFile = isSuiteFilePath(body.file)\n let normalizedFileTarget: { storagePath: string; executionPath: string } | null = null\n try {\n normalizedFileTarget = body.file\n ? isSuiteFile\n ? await normalizeDashboardSuitePath(body.file, suiteFileManager)\n : await normalizeDashboardWorkspacePath(body.file, workspacePaths, 'test')\n : null\n\n if (body.file) {\n args.push(normalizedFileTarget?.executionPath ?? body.file)\n }\n if (body.patterns) {\n if (!Array.isArray(body.patterns)) {\n throw new Error('patterns must be an array')\n }\n for (const pattern of body.patterns) {\n if (typeof pattern !== 'string') {\n throw new Error('patterns must be strings')\n }\n const matches = await resolveDashboardTestPattern(pattern, workspacePaths)\n args.push(...matches.map((match) => match.executionPath))\n }\n }\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : String(err) }, 400)\n return\n }\n const normalizedTestTarget = body.file && !isSuiteFile\n ? normalizedFileTarget\n : null\n if (body.noCache) {\n args.push('--no-cache')\n }\n if (body.noMemory) {\n args.push('--no-memory')\n }\n const isSuite = Boolean(isSuiteFile)\n\n let testName = body.file\n ? basename(normalizedFileTarget?.storagePath ?? body.file, '.yaml')\n : 'unknown'\n\n let fileParallel: boolean | undefined\n let platform: string | undefined\n\n if (isSuite && body.file && suiteFileManager) {\n // Parse suite YAML for name and platform\n try {\n const content = await suiteFileManager.read(normalizedFileTarget?.storagePath ?? body.file)\n fileParallel = readSuiteYamlParallel(content)\n const parsed = parseYaml(content)\n if (parsed?.name) testName = parsed.name\n platform = parsed?.config?.platform ?? undefined\n } catch { /* fall back to defaults */ }\n } else if (body.file && testFileManager) {\n // Parse test YAML for name, use.parallel, and platform metadata\n try {\n const readPath = normalizedTestTarget?.storagePath ?? body.file\n const content = await testFileManager.read(readPath)\n const metadata = extractTestFileMetadata(content)\n const targetPlatforms = await readTargetPlatformMap(configManager)\n if (metadata.name) testName = metadata.name\n if (metadata.parallel !== null) fileParallel = metadata.parallel\n platform = resolveEffectivePlatform(\n metadata.platform,\n metadata.targetName,\n targetPlatforms,\n platform,\n ) ?? undefined\n } catch { /* fall back to defaults */ }\n }\n\n const configParallel = await readConfigUseParallel(configManager)\n const effectiveParallel = fileParallel ?? configParallel ?? false\n const executionTimeout = await resolveDashboardExecutionTimeout({\n isSuite,\n file: normalizedFileTarget?.storagePath ?? body.file,\n normalizedTestPath: normalizedTestTarget?.storagePath,\n testFileManager,\n suiteFileManager,\n configManager,\n })\n\n const runId = jobQueue.enqueue({\n name: testName,\n filePath: normalizedFileTarget?.storagePath ?? body.file,\n kind: isSuite ? 'suite-parent' : 'test',\n attributes: buildRunRequestAttributes({\n trigger: triggerSource.trigger,\n runner: body.local === false ? 'browserstack' : 'local',\n }),\n platform,\n parallel: effectiveParallel,\n metadata: {\n args,\n isSuite: isSuite || undefined,\n ...toExecutionTimeoutMetadata(executionTimeout),\n },\n })\n json(res, { runId, status: 'queued' }, 202)\n })\n .catch(() => {\n json(res, { error: 'Invalid request body' }, 400)\n })\n return\n }\n\n // GET /api/execution/events — SSE stream for live execution events\n if (path === '/api/execution/events' && req.method === 'GET') {\n if (!testRunner) {\n json(res, { error: 'Execution not available' }, 503)\n return\n }\n\n const runId = url.searchParams.get('runId') ?? undefined\n const lastEventId = req.headers['last-event-id'] as string | undefined\n\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n })\n res.write(':ok\\n\\n')\n\n // Replay buffered events for reconnection\n if (lastEventId && runId) {\n const lastId = parseInt(lastEventId, 10)\n const buffered = testRunner.getBufferedEvents(runId)\n for (const evt of buffered) {\n if (evt.id > lastId) {\n res.write(`id: ${evt.id}\\nevent: ${evt.type}\\ndata: ${JSON.stringify(evt)}\\n\\n`)\n }\n }\n } else if (runId) {\n // New connection — replay all buffered events\n const buffered = testRunner.getBufferedEvents(runId)\n for (const evt of buffered) {\n res.write(`id: ${evt.id}\\nevent: ${evt.type}\\ndata: ${JSON.stringify(evt)}\\n\\n`)\n }\n }\n\n const onEvent = (evtRunId: string, event: { id: number; type: string; [key: string]: unknown }) => {\n if (runId && evtRunId !== runId) return\n res.write(`id: ${event.id}\\nevent: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`)\n }\n\n testRunner.on('execution-event', onEvent)\n\n const heartbeat = setInterval(() => {\n res.write(':\\n\\n')\n }, 15_000)\n\n req.on('close', () => {\n clearInterval(heartbeat)\n testRunner.removeListener('execution-event', onEvent)\n })\n return\n }\n\n // POST /api/suites/validate — validate suite YAML content\n if (path === '/api/suites/validate' && req.method === 'POST') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n readJsonBody<{ content: string }>(req)\n .then(async (body) => {\n const result = await suiteFileManager.validate(body.content ?? '')\n json(res, result)\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // GET /api/suites — list all suite files\n if (path === '/api/suites' && req.method === 'GET') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n suiteFileManager.list()\n .then(files => json(res, { files }))\n .catch(() => json(res, { error: 'Failed to list suite files' }, 500))\n return\n }\n\n // POST /api/suites — create a new suite file\n if (path === '/api/suites' && req.method === 'POST') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n readJsonBody<{ path: string; content: string }>(req)\n .then(async (body) => {\n if (!body.path || typeof body.path !== 'string' || !body.content || typeof body.content !== 'string') {\n json(res, { error: 'Both path and content are required' }, 400)\n return\n }\n const validation = await suiteFileManager.validate(body.content)\n if (!validation.valid) {\n json(res, {\n error: 'Invalid suite content',\n details: validation.errors,\n missingTests: validation.missingTests,\n }, 400)\n return\n }\n try {\n await suiteFileManager.write(body.path, body.content)\n json(res, { path: body.path, created: true }, 201)\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to create suite file' }, 400)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // DELETE /api/suites/:path — delete a suite file\n if (path.startsWith('/api/suites/') && req.method === 'DELETE') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n const decodedPath = decodeURIComponent(path.slice('/api/suites/'.length))\n suiteFileManager.delete(decodedPath)\n .then(() => json(res, { deleted: true }))\n .catch((err: any) => {\n if (err.code === 'ENOENT') {\n notFound(res, 'Suite file not found')\n return\n }\n json(res, { error: err.message }, 500)\n })\n return\n }\n\n // PUT /api/suites/:suite-id — update suite file by suite-id (hard break D-02/D-04)\n if (path.startsWith('/api/suites/') && req.method === 'PUT') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n const sId = decodeURIComponent(path.slice('/api/suites/'.length))\n readJsonBody<{ content: string }>(req)\n .then(async (body) => {\n if (!body.content || typeof body.content !== 'string') {\n json(res, { error: 'Content is required' }, 400)\n return\n }\n const found = await suiteFileManager.findBySuiteId(sId)\n if (!found) {\n notFound(res, 'Suite not found')\n return\n }\n const validation = await suiteFileManager.validate(body.content)\n if (!validation.valid) {\n json(res, {\n error: 'Invalid suite content',\n details: validation.errors,\n missingTests: validation.missingTests,\n }, 400)\n return\n }\n try {\n await suiteFileManager.write(found.path, body.content)\n json(res, { path: found.path, updated: true })\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to update suite file' }, 400)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // GET /api/suites/:suite-id — read suite file by suite-id (hard break D-02/D-04/D-05)\n if (path.startsWith('/api/suites/') && req.method === 'GET') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n const sId = decodeURIComponent(path.slice('/api/suites/'.length))\n suiteFileManager.findBySuiteId(sId)\n .then(result => {\n if (!result) {\n notFound(res, 'Suite not found')\n return\n }\n json(res, { path: result.path, content: result.content, suiteId: sId })\n })\n .catch(() => notFound(res, 'Suite not found'))\n return\n }\n\n // POST /api/tests/validate — validate YAML content (must be before parameterized /api/tests/:path)\n if (path === '/api/tests/validate' && req.method === 'POST') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n readJsonBody<{ content: string; filePath?: string }>(req)\n .then(async (body) => {\n const isSuite = body.filePath?.endsWith('.suite.yaml') || body.filePath?.endsWith('.suite.yml')\n if (isSuite && suiteFileManager) {\n const result = await suiteFileManager.validate(body.content ?? '')\n json(res, result)\n } else {\n const result = await testFileManager.validate(body.content ?? '')\n json(res, result)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // GET /api/tests — list all test files\n if (path === '/api/tests' && req.method === 'GET') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n testFileManager.list()\n .then(async files => {\n const targetPlatforms = await readTargetPlatformMap(configManager)\n const resolvedFiles = files.map((file) => ({\n ...file,\n platform: resolveEffectivePlatform(file.platform, file.targetName, targetPlatforms),\n }))\n const targets = Array.from(\n new Set(\n resolvedFiles\n .map((file) => file.targetName)\n .filter((value): value is string => typeof value === 'string' && value.length > 0),\n ),\n )\n json(res, { files: resolvedFiles, targets })\n })\n .catch(() => json(res, { error: 'Failed to list test files' }, 500))\n return\n }\n\n // POST /api/tests — create a new test file\n if (path === '/api/tests' && req.method === 'POST') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n readJsonBody<{ path: string; content: string }>(req)\n .then(async (body) => {\n if (!body.path || typeof body.path !== 'string' || !body.content || typeof body.content !== 'string') {\n json(res, { error: 'Both path and content are required' }, 400)\n return\n }\n try {\n await testFileManager.write(body.path, body.content)\n json(res, { path: body.path, created: true }, 201)\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to create test file' }, 400)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // DELETE /api/tests/:t_id — delete test file by test-id\n if (path.startsWith('/api/tests/') && req.method === 'DELETE') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n const tId = decodeURIComponent(path.slice('/api/tests/'.length))\n testFileManager.findByTestId(tId)\n .then(async (found) => {\n if (!found) {\n notFound(res, 'Test not found')\n return\n }\n await testFileManager.delete(found.path)\n json(res, { deleted: true, path: found.path })\n })\n .catch((err: unknown) => {\n const code = (err as NodeJS.ErrnoException)?.code\n if (code === 'ENOENT') {\n notFound(res, 'Test not found')\n return\n }\n json(res, { error: err instanceof Error ? err.message : 'Failed to delete test file' }, 500)\n })\n return\n }\n\n // PUT /api/tests/:t_id — update test file by test-id\n if (path.startsWith('/api/tests/') && req.method === 'PUT') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n const tId = decodeURIComponent(path.slice('/api/tests/'.length))\n readJsonBody<{ content: string }>(req)\n .then(async (body) => {\n if (!body.content || typeof body.content !== 'string') {\n json(res, { error: 'Content is required' }, 400)\n return\n }\n const found = await testFileManager.findByTestId(tId)\n if (!found) {\n notFound(res, 'Test not found')\n return\n }\n try {\n await testFileManager.write(found.path, body.content)\n json(res, { path: found.path, updated: true })\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to update test file' }, 400)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // GET /api/tests/:t_id — read test file by test-id\n if (path.startsWith('/api/tests/') && req.method === 'GET') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n const tId = decodeURIComponent(path.slice('/api/tests/'.length))\n testFileManager.findByTestId(tId)\n .then(result => {\n if (!result) {\n notFound(res, 'Test not found')\n return\n }\n json(res, { path: result.path, content: result.content, testId: tId })\n })\n .catch(() => notFound(res, 'Test not found'))\n return\n }\n\n // GET /api/analytics/tests\n if (path === '/api/analytics/tests' && req.method === 'GET') {\n const minRuns = url.searchParams.has('minRuns') ? parseInt(url.searchParams.get('minRuns')!, 10) : 3\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 50\n const tests = db.getFlakyTests({ minRuns, limit })\n const result = tests.map(t => {\n return { ...t, isFlaky: t.flakyScore >= 0.4 }\n })\n json(res, { tests: result })\n return\n }\n\n // GET /api/analytics/tests/:name\n if (path.startsWith('/api/analytics/tests/') && req.method === 'GET') {\n const name = decodeURIComponent(path.slice('/api/analytics/tests/'.length))\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 50\n const offset = url.searchParams.has('offset') ? parseInt(url.searchParams.get('offset')!, 10) : 0\n const from = url.searchParams.get('from') ?? undefined\n void readAnalyticsScopePredicates(configManager)\n .then((scopeResult) => {\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n\n const runs = db.getRunsByTestName(name, { limit, offset })\n const total = db.getRunsByTestNameCount(name)\n const trends = db.getTestTrends(name, { from })\n const allRunsForFlakiness = db.getRunsByTestName(name, { limit: 100 })\n const flakyMetrics = calculateFlakyMetrics(allRunsForFlakiness)\n const flakyScore = flakyMetrics.score\n const configured = scopeResult.predicates.length > 0\n const scopedRuns = configured\n ? db.getRunsByTestName(name, { limit, offset, attributePredicates: scopeResult.predicates })\n : runs\n const scopedTotal = configured\n ? db.getRunsByTestNameCount(name, { attributePredicates: scopeResult.predicates })\n : total\n const scopedTrends = configured\n ? db.getTestTrends(name, { from, attributePredicates: scopeResult.predicates })\n : trends\n const scopedRunsForFlakiness = configured\n ? db.getRunsByTestName(name, { limit: 100, attributePredicates: scopeResult.predicates })\n : allRunsForFlakiness\n const scopedFlakyScore = calculateFlakyMetrics(scopedRunsForFlakiness).score\n\n json(res, {\n name,\n runs,\n total,\n trends,\n isFlaky: flakyScore >= 0.4 && flakyMetrics.statusCount >= 3,\n flakyScore,\n scope: {\n configured,\n predicates: scopeResult.predicates,\n scopedCount: scopedTotal,\n totalCount: total,\n },\n ...(configured ? {\n scopedRuns,\n scopedTrends,\n scopedFlakyScore,\n } : {}),\n })\n })\n .catch(() => json(res, { error: 'Failed to read analytics scope' }, 500))\n return\n }\n\n // GET /api/analytics/suites/:suiteId\n if (path.startsWith('/api/analytics/suites/') && req.method === 'GET') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n\n const suiteId = decodeURIComponent(path.slice('/api/analytics/suites/'.length))\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 50\n const offset = url.searchParams.has('offset') ? parseInt(url.searchParams.get('offset')!, 10) : 0\n const from = url.searchParams.get('from') ?? undefined\n\n Promise.all([suiteFileManager.findBySuiteId(suiteId), readAnalyticsScopePredicates(configManager)])\n .then(([result, scopeResult]) => {\n if (!result) {\n notFound(res, 'Suite not found')\n return\n }\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n\n const runs = db.getRunsBySuiteId(suiteId, { limit, offset })\n const total = db.getRunsBySuiteIdCount(suiteId)\n const trends = db.getSuiteTrends(suiteId, { from })\n const allRunsForFlakiness = db.getRunsBySuiteId(suiteId, { limit: 100 })\n const flakyMetrics = calculateFlakyMetrics(allRunsForFlakiness)\n const flakyScore = flakyMetrics.score\n const configured = scopeResult.predicates.length > 0\n const scopedRuns = configured\n ? db.getRunsBySuiteId(suiteId, { limit, offset, attributePredicates: scopeResult.predicates })\n : runs\n const scopedTotal = configured\n ? db.getRunsBySuiteIdCount(suiteId, { attributePredicates: scopeResult.predicates })\n : total\n const scopedTrends = configured\n ? db.getSuiteTrends(suiteId, { from, attributePredicates: scopeResult.predicates })\n : trends\n const scopedRunsForFlakiness = configured\n ? db.getRunsBySuiteId(suiteId, { limit: 100, attributePredicates: scopeResult.predicates })\n : allRunsForFlakiness\n const scopedFlakyScore = calculateFlakyMetrics(scopedRunsForFlakiness).score\n\n json(res, {\n suiteId,\n runs,\n total,\n trends,\n isFlaky: flakyScore >= 0.4 && flakyMetrics.statusCount >= 3,\n flakyScore,\n scope: {\n configured,\n predicates: scopeResult.predicates,\n scopedCount: scopedTotal,\n totalCount: total,\n },\n ...(configured ? {\n scopedRuns,\n scopedTrends,\n scopedFlakyScore,\n } : {}),\n })\n })\n .catch(() => notFound(res, 'Suite not found'))\n return\n }\n\n // GET /api/analytics/breakdowns\n if (path === '/api/analytics/breakdowns' && req.method === 'GET') {\n const dimension = url.searchParams.get('dimension')\n if (dimension !== 'test' && dimension !== 'suite' && dimension !== 'platform') {\n json(res, { error: 'dimension must be one of: test, suite, platform' }, 400)\n return\n }\n\n const limitResult = parseBoundedIntegerQueryParam(url.searchParams.get('limit'), 'limit', 1, 100, 25)\n if (!limitResult.ok) {\n json(res, { error: limitResult.error }, 400)\n return\n }\n\n const fromResult = parseIsoDateQueryParam(url.searchParams.get('from'), 'from')\n if (!fromResult.ok) {\n json(res, { error: fromResult.error }, 400)\n return\n }\n\n const toResult = parseIsoDateQueryParam(url.searchParams.get('to'), 'to')\n if (!toResult.ok) {\n json(res, { error: toResult.error }, 400)\n return\n }\n\n const scope = url.searchParams.get('scope') ?? undefined\n if (scope !== undefined && scope !== 'passRate') {\n json(res, { error: 'scope must be passRate when provided' }, 400)\n return\n }\n\n void readAnalyticsScopePredicates(configManager)\n .then(async (scopeResult) => {\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n\n const configured = scopeResult.predicates.length > 0\n const attributePredicates = scope === 'passRate' && configured ? scopeResult.predicates : undefined\n const rows = db.getInsightsBreakdown(dimension as InsightsBreakdownDimension, {\n from: fromResult.value,\n to: toResult.value,\n limit: limitResult.value,\n attributePredicates,\n })\n const scopedCount = configured\n ? db.getInsightsBreakdown(dimension as InsightsBreakdownDimension, {\n from: fromResult.value,\n to: toResult.value,\n limit: 100,\n attributePredicates: scopeResult.predicates,\n }).reduce((sum, row) => sum + row.runs, 0)\n : 0\n const totalCount = db.getInsightsBreakdown(dimension as InsightsBreakdownDimension, {\n from: fromResult.value,\n to: toResult.value,\n limit: 100,\n }).reduce((sum, row) => sum + row.runs, 0)\n const payload = {\n dimension,\n rows,\n scope: {\n configured,\n predicates: scopeResult.predicates,\n scopedCount,\n totalCount,\n },\n }\n\n if (dimension !== 'suite' || !suiteFileManager) {\n json(res, payload)\n return\n }\n\n const files = await suiteFileManager.list()\n const suiteNames = new Map(\n files\n .filter((file) => typeof file.suiteId === 'string' && file.suiteId.length > 0)\n .map((file) => [file.suiteId as string, file.name]),\n )\n\n json(res, {\n ...payload,\n rows: rows.map((row) => ({\n ...row,\n label: row.suiteId ? (suiteNames.get(row.suiteId) ?? row.label) : row.label,\n })),\n })\n })\n .catch(() => {\n json(res, { error: 'Unable to read analytics breakdown scope' }, 500)\n })\n return\n }\n\n // GET /api/app-metadata — return narrow non-sensitive app metadata\n if (path === '/api/app-metadata' && req.method === 'GET') {\n const version = getAgentQaVersion().trim() || '0.0.0'\n ;(async () => {\n try {\n const status = await getAgentQaUpdateStatus()\n const latestVersion = typeof status.latestVersion === 'string'\n ? status.latestVersion.trim()\n : ''\n if (status.updateAvailable === true && latestVersion) {\n json(res, { version, update: { latestVersion } })\n return\n }\n } catch {\n // Keep app metadata available even when update checks fail.\n }\n\n json(res, { version })\n })().catch(() => {\n json(res, { version })\n })\n return\n }\n\n // GET /api/config/targets — return registered target names\n if (path === '/api/config/targets' && req.method === 'GET') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const config = await configManager.read()\n const configObj = config as Record<string, unknown>\n const registry = configObj.registry as Record<string, unknown> | undefined\n const targets = registry?.targets as Record<string, unknown> | undefined\n const names = targets ? Object.keys(targets) : []\n json(res, { targets: names })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read targets' }, 500)\n }\n })()\n return\n }\n\n // GET /api/config — return masked config with active provider info\n if (path === '/api/config' && req.method === 'GET') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const config = await configManager.readMasked()\n const configObj = config as Record<string, unknown>\n const registry = configObj.registry as Record<string, unknown> | undefined\n const llms = (registry?.llms ?? configObj.llms) as Array<Record<string, unknown>> | undefined\n const use = configObj.use as Record<string, unknown> | undefined\n const activeLlm = (use?.llm ?? configObj.defaultLLM) as string | undefined\n const defaultCfg = llms?.find((c) => c.name === activeLlm)\n const provider = (defaultCfg?.provider as string) ?? null\n json(res, { config, provider })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read config' }, 500)\n }\n })()\n return\n }\n\n // PUT /api/config/llms — update registry.llms array + use.llm\n if (path === '/api/config/llms' && req.method === 'PUT') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody<{ llms: unknown[]; defaultLLM?: string; activeLlm?: string }>(req)\n .then(async (body) => {\n try {\n if (!Array.isArray(body.llms) || body.llms.length === 0) {\n json(res, { error: 'llms array is required and must not be empty' }, 400)\n return\n }\n const selectedLlm = body.activeLlm ?? body.defaultLLM\n const errors: string[] = []\n const names: string[] = []\n const sanitizedArray: Array<ReturnType<typeof NamedLLMConfigSchema.parse>> = []\n for (const item of body.llms) {\n const result = NamedLLMConfigSchema.safeParse(item)\n if (!result.success) {\n for (const issue of result.error.issues) {\n errors.push(`${issue.path.join('.')}: ${issue.message}`)\n }\n } else {\n names.push(result.data.name)\n sanitizedArray.push(result.data)\n }\n }\n const dupes = names.filter((n, i) => names.indexOf(n) !== i)\n if (dupes.length > 0) {\n errors.push(`Duplicate config names: ${[...new Set(dupes)].join(', ')}`)\n }\n if (!selectedLlm || !names.includes(selectedLlm)) {\n errors.push(`use.llm \"${selectedLlm}\" does not match any name in registry.llms`)\n }\n if (errors.length > 0) {\n json(res, { error: 'Validation failed', details: errors }, 400)\n return\n }\n await configManager.replaceSectionRaw('registry.llms', sanitizedArray)\n await configManager.replaceSectionRaw('use.llm', selectedLlm)\n json(res, { updated: true })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to update LLM config' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // PUT /api/config/default-llm — switch active LLM (use.llm)\n if (path === '/api/config/default-llm' && req.method === 'PUT') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody<{ defaultLLM?: string; llm?: string }>(req)\n .then(async (body) => {\n try {\n const llmName = body.llm ?? body.defaultLLM\n if (!llmName || typeof llmName !== 'string') {\n json(res, { error: 'use.llm string is required' }, 400)\n return\n }\n const config = await configManager.readMasked()\n const configObj = config as Record<string, unknown>\n const registry = configObj.registry as Record<string, unknown> | undefined\n const llms = (registry?.llms ?? configObj.llms) as Array<Record<string, unknown>> | undefined\n const names = (llms ?? []).map((c) => c.name as string)\n if (!names.includes(llmName)) {\n json(res, { error: `use.llm \"${llmName}\" does not match any name in registry.llms` }, 400)\n return\n }\n await configManager.replaceSectionRaw('use.llm', llmName)\n json(res, { updated: true })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to update use.llm' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // POST /api/config/farm/test-connection — test farm provider credentials\n if (path === '/api/config/farm/test-connection' && req.method === 'POST') {\n readJsonBody<{ provider: string; username: string; accessKey: string }>(req)\n .then(async (body) => {\n if (body.provider !== 'browserstack') {\n json(res, { error: 'Only BrowserStack is currently supported' }, 400)\n return\n }\n try {\n const auth = Buffer.from(`${body.username}:${body.accessKey}`).toString('base64')\n const response = await fetch('https://api-cloud.browserstack.com/app-automate/devices.json', {\n headers: { Authorization: `Basic ${auth}` },\n })\n if (response.ok) {\n json(res, { success: true })\n } else if (response.status === 401) {\n json(res, { success: false, error: 'Invalid credentials' })\n } else {\n json(res, { success: false, error: `BrowserStack API returned ${response.status}` })\n }\n } catch (err) {\n json(res, { success: false, error: err instanceof Error ? err.message : 'Connection failed' })\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // PUT /api/config/settings — update config sections\n if (path === '/api/config/settings' && req.method === 'PUT') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody<Record<string, unknown>>(req)\n .then(async (body) => {\n try {\n const sectionValidators: Record<string, { safeParse: (v: unknown) => ConfigSectionValidationResult }> = {\n 'use.timeout': TimeoutConfigSchema,\n 'use.healing': HealingConfigSchema,\n 'use.planner': PlannerConfigSchema,\n 'use.logCapture': LogCaptureConfigSchema,\n 'use.browser': BrowserConfigSchema,\n 'use.browser.headless': BrowserConfigSchema.shape.headless,\n 'services.memory': ServicesSchema.shape.memory,\n 'services.cache': CacheConfigSchema,\n 'services.logging': LoggingConfigSchema,\n 'services.recording': RecordingConfigSchema,\n 'services.accessibility': AccessibilityConfigSchema,\n 'services.dashboard': DashboardConfigSchema,\n 'services.mcp': McpConfigSchema,\n 'registry.targets': RegistrySchema.shape.targets,\n 'registry.devices': RegistrySchema.shape.devices,\n 'registry.providers': RegistrySchema.shape.providers,\n 'analytics.passRateScope': { safeParse: validateAnalyticsPassRateScope },\n 'workspace.testMatch': WorkspaceSchema.shape.testMatch,\n 'workspace.suiteMatch': WorkspaceSchema.shape.suiteMatch,\n 'workspace.hooksFile': WorkspaceSchema.shape.hooksFile,\n 'workspace.agentRules': WorkspaceSchema.shape.agentRules,\n 'workspace.envFile': WorkspaceSchema.shape.envFile,\n 'workspace.secretsFile': WorkspaceSchema.shape.secretsFile,\n 'use.mobile': UseSchema.shape.mobile,\n 'use.mobile.appState': MobileAppStateSchema,\n 'use.parallel': UseSchema.shape.parallel,\n }\n const objectSections = [\n 'use.timeout',\n 'use.healing',\n 'use.planner',\n 'use.logCapture',\n 'use.browser',\n 'use.mobile',\n 'services.memory',\n 'services.cache',\n 'services.logging',\n 'services.recording',\n 'services.accessibility',\n 'services.dashboard',\n 'services.mcp',\n 'registry.targets',\n 'registry.devices',\n 'registry.providers',\n 'analytics.passRateScope',\n ] as const\n const arraySections = ['workspace.testMatch', 'workspace.testPathIgnore', 'workspace.suiteMatch', 'registry.llms'] as const\n const scalarSections = [\n 'workspace.agentRules',\n 'workspace.hooksFile',\n 'workspace.envFile',\n 'workspace.secretsFile',\n 'use.llm',\n 'use.mobile.appState',\n 'use.browser.headless',\n 'use.parallel',\n ] as const\n\n const currentConfig = await configManager.read()\n const currentUse = isRecord(currentConfig.use) ? currentConfig.use : {}\n const currentBrowser = isRecord(currentUse.browser) ? currentUse.browser : {}\n const currentHasRootHeadless = typeof currentUse.headless === 'boolean'\n const currentHasBrowserHeadless = typeof currentBrowser.headless === 'boolean'\n const requestHasRootHeadless = Object.prototype.hasOwnProperty.call(body, 'use.headless')\n const requestHasBrowserHeadlessScalar = Object.prototype.hasOwnProperty.call(body, 'use.browser.headless')\n const requestBrowserBlock = body['use.browser']\n const requestHasBrowserHeadlessObject = isRecord(requestBrowserBlock) && typeof requestBrowserBlock.headless === 'boolean'\n if (\n currentHasRootHeadless\n && !currentHasBrowserHeadless\n && !requestHasBrowserHeadlessScalar\n && !requestHasBrowserHeadlessObject\n ) {\n body['use.browser.headless'] = currentUse.headless\n }\n\n const allowedSettingsPaths = new Set<string>([\n ...Object.keys(sectionValidators),\n ...objectSections,\n ...arraySections,\n ...scalarSections,\n 'use.headless',\n ])\n const unsupportedKeys = Object.keys(body).filter((key) => !allowedSettingsPaths.has(key))\n if (unsupportedKeys.length > 0) {\n json(res, { error: 'Unsupported setting path', details: unsupportedKeys }, 400)\n return\n }\n\n const errors: string[] = []\n for (const [section, validator] of Object.entries(sectionValidators)) {\n const value = body[section]\n if (value !== undefined) {\n const result = validator.safeParse(value)\n if (!result.success) {\n for (const issue of result.error!.issues) {\n const path = issue.path.length ? `${section}.${issue.path.map(String).join('.')}` : section\n errors.push(`${path}: ${issue.message}`)\n }\n }\n }\n }\n\n if (Array.isArray(body['registry.llms'])) {\n for (const [idx, item] of (body['registry.llms'] as unknown[]).entries()) {\n const result = NamedLLMConfigSchema.safeParse(item)\n if (!result.success) {\n for (const issue of result.error!.issues) {\n const p = issue.path.length ? `registry.llms[${idx}].${issue.path.join('.')}` : `registry.llms[${idx}]`\n errors.push(`${p}: ${issue.message}`)\n }\n }\n }\n }\n\n if (errors.length > 0) {\n json(res, { error: 'Validation failed', details: errors }, 400)\n return\n }\n\n for (const section of objectSections) {\n if (body[section] && typeof body[section] === 'object') {\n await configManager.replaceSection(section, body[section] as Record<string, unknown>)\n }\n }\n for (const section of arraySections) {\n if (body[section] !== undefined) {\n await configManager.replaceSectionRaw(section, body[section])\n }\n }\n for (const section of scalarSections) {\n if (body[section] !== undefined) {\n await configManager.replaceSectionRaw(section, body[section])\n }\n }\n if (currentHasRootHeadless || requestHasRootHeadless) {\n await configManager.deleteSectionRaw('use.headless')\n }\n json(res, { updated: true })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to update settings' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // DELETE /api/auth/:configName — remove stored credential\n if (path.startsWith('/api/auth/') && req.method === 'DELETE') {\n const segments = path.split('/')\n if (segments.length === 4 && segments[2] === 'auth') {\n const providerName = decodeURIComponent(segments[3])\n if (providerName === 'status' || providerName === 'credential' || providerName === 'oauth') {\n // Fall through to other handlers\n } else {\n ;(async () => {\n try {\n await removeAuth(providerName)\n json(res, { deleted: true })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to delete credential' }, 500)\n }\n })()\n return\n }\n }\n }\n\n // GET /api/auth/status — return credential info from auth store\n if (path === '/api/auth/status' && req.method === 'GET') {\n ;(async () => {\n try {\n const credentials: Array<{\n type: string\n provider: string\n configName: string\n expires: number | null\n source: string\n }> = []\n const store = await readAuth() as Record<string, DashboardAuthCredential>\n for (const [key, cred] of Object.entries(store)) {\n if (cred) {\n let provider = cred.provider ?? key\n if (cred.type === 'oauth') {\n provider = toProductProviderLabel(provider)\n } else if (cred.type === 'bearer') {\n provider = cred.provider\n }\n credentials.push({\n type: cred.type,\n provider,\n configName: key,\n expires: cred.type === 'oauth' ? cred.tokens.expires : null,\n source: 'auth-store',\n })\n }\n }\n json(res, { credentials })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read auth status' }, 500)\n }\n })()\n return\n }\n\n // GET /api/llm/providers — built-in and plugin-provided LLM provider metadata\n if (path === '/api/llm/providers' && req.method === 'GET') {\n json(res, {\n providers: [\n ...builtinLLMProviderMetadata(),\n ...listLLMAuthProviderPlugins().map(serializeAuthProviderPlugin),\n ],\n })\n return\n }\n\n if (path.startsWith('/api/auth/plugin/')) {\n pruneExpiredPluginOAuthSessions(pluginOAuthSessions)\n const segments = path.split('/')\n const provider = segments.length >= 6 ? decodeURIComponent(segments[4] ?? '') : ''\n const action = segments.length >= 6 ? segments[5] : ''\n const plugin = provider ? getLLMAuthProviderPlugin(provider) : undefined\n\n if (!plugin) {\n json(res, { error: `Auth plugin provider \"${provider}\" is not registered` }, 404)\n return\n }\n\n if (action === 'start' && req.method === 'POST') {\n readJsonBody<{ configName?: string; callbackUrl?: string }>(req)\n .then(async (body) => {\n if (!plugin.startAuth) {\n json(res, { error: `Provider \"${provider}\" does not support dashboard auth start` }, 400)\n return\n }\n\n try {\n const target = await requirePluginAuthConfig(configManager, body.configName, plugin)\n if (!target.ok) {\n json(res, { error: target.error }, 400)\n return\n }\n const started = await plugin.startAuth({\n configName: target.configName,\n callbackUrl: typeof body.callbackUrl === 'string' ? body.callbackUrl : undefined,\n })\n const sessionId = randomUUID()\n const session: PluginOAuthSession = {\n providerId: plugin.providerId,\n credentialProviderId: plugin.credentialProviderId,\n configName: target.configName,\n sessionState: started.sessionState,\n cleanup: started.cleanup,\n status: 'pending',\n expiresAt: Date.now() + PLUGIN_OAUTH_SESSION_TTL_MS,\n }\n pluginOAuthSessions.set(sessionId, session)\n\n if (started.waitForTokens) {\n started.waitForTokens\n .then(async (tokens: OAuthTokens) => {\n await writeDashboardAuth(target.configName, {\n type: 'oauth',\n provider: plugin.credentialProviderId,\n tokens,\n })\n session.status = 'completed'\n })\n .catch((err: unknown) => {\n session.status = 'error'\n session.error = err instanceof Error ? err.message : 'Authentication failed'\n })\n .finally(() => cleanupPluginOAuthSession(session))\n }\n\n json(res, {\n authorizeUrl: started.authorizeUrl,\n sessionId,\n mode: plugin.dashboardAuth.mode,\n })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to start auth plugin flow' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n if (action === 'result' && req.method === 'GET') {\n const sessionId = url.searchParams.get('session') ?? ''\n const session = pluginOAuthSessions.get(sessionId)\n if (!session || session.providerId !== provider) {\n json(res, { error: 'Auth session not found' }, 404)\n return\n }\n if (session.status === 'completed') {\n cleanupPluginOAuthSession(session)\n pluginOAuthSessions.delete(sessionId)\n json(res, { status: 'completed', saved: true })\n return\n }\n if (session.status === 'error') {\n cleanupPluginOAuthSession(session)\n pluginOAuthSessions.delete(sessionId)\n json(res, { status: 'error', error: session.error ?? 'Authentication failed' })\n return\n }\n json(res, { status: 'pending' })\n return\n }\n\n if (action === 'exchange' && req.method === 'POST') {\n readJsonBody<{ sessionId?: string; code?: string }>(req)\n .then(async (body) => {\n if (!plugin.exchangeCode) {\n json(res, { error: `Provider \"${provider}\" does not support code exchange` }, 400)\n return\n }\n const sessionId = typeof body.sessionId === 'string' ? body.sessionId.trim() : ''\n const code = typeof body.code === 'string' ? body.code.trim() : ''\n if (!sessionId || !code) {\n json(res, { error: 'sessionId and code are required' }, 400)\n return\n }\n const session = pluginOAuthSessions.get(sessionId)\n if (!session || session.providerId !== provider) {\n json(res, { error: 'Auth session not found' }, 404)\n return\n }\n if (session.status !== 'pending') {\n json(res, { error: 'Auth session is no longer pending' }, 409)\n return\n }\n\n try {\n const tokens = await plugin.exchangeCode({\n code,\n sessionState: session.sessionState,\n })\n await writeDashboardAuth(session.configName, {\n type: 'oauth',\n provider: session.credentialProviderId,\n tokens,\n })\n session.status = 'completed'\n cleanupPluginOAuthSession(session)\n pluginOAuthSessions.delete(sessionId)\n json(res, { status: 'completed', saved: true })\n } catch (err: unknown) {\n session.status = 'error'\n session.error = err instanceof Error ? err.message : 'Token exchange failed'\n cleanupPluginOAuthSession(session)\n pluginOAuthSessions.delete(sessionId)\n json(res, { error: session.error }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n json(res, { error: 'Auth plugin route not found' }, 404)\n return\n }\n\n // POST /api/auth/credential — store typed credentials from dashboard\n if (path === '/api/auth/credential' && req.method === 'POST') {\n readJsonBody<{\n configName?: string\n provider?: string\n type?: string\n secret?: string\n }>(req)\n .then(async (body) => {\n const provider = typeof body.provider === 'string' ? body.provider.trim() : ''\n const credentialType = typeof body.type === 'string' ? body.type.trim() : ''\n const secret = typeof body.secret === 'string' ? body.secret.trim() : ''\n\n if (typeof body.configName !== 'string' || body.configName.trim() === '') {\n json(res, { error: 'configName is required' }, 400)\n return\n }\n if (!provider || !isKnownLLMProvider(provider)) {\n json(res, { error: 'valid provider is required' }, 400)\n return\n }\n if (credentialType !== 'api-key' && credentialType !== 'bearer-token') {\n json(res, { error: 'type must be api-key or bearer-token' }, 400)\n return\n }\n if (!secret) {\n json(res, { error: 'secret is required' }, 400)\n return\n }\n\n if (getLLMAuthProviderPlugin(provider)) {\n json(res, { error: 'Subscription providers use OAuth login' }, 400)\n return\n }\n\n if (credentialType === 'bearer-token' && provider !== 'anthropic-compatible') {\n json(res, { error: 'bearer-token credentials are only supported for anthropic-compatible configs' }, 400)\n return\n }\n\n if (credentialType === 'api-key' && !API_KEY_CREDENTIAL_PROVIDERS.has(provider)) {\n json(res, { error: 'api-key credentials are not supported for this provider' }, 400)\n return\n }\n\n try {\n const target = await requireCredentialConfig(configManager, body.configName, provider)\n if (!target.ok) {\n json(res, { error: target.error }, 400)\n return\n }\n\n if (credentialType === 'bearer-token') {\n await writeDashboardAuth(target.configName, { type: 'bearer', provider, token: secret })\n } else {\n await writeDashboardAuth(target.configName, { type: 'api', provider, key: secret })\n }\n json(res, { saved: true })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to save credential' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // POST /api/llm/test — test LLM connection\n if (path === '/api/llm/test' && req.method === 'POST') {\n readJsonBody<{\n configName?: string\n provider?: string\n model?: string\n baseURL?: string\n providerHeaders?: Record<string, string>\n }>(req)\n .then(async (body) => {\n const rawBody = body as Record<string, unknown>\n if ('apiKey' in rawBody) {\n json(res, {\n success: false,\n error: 'invalid_request',\n message: 'apiKey is not accepted in LLM test requests. Save credentials for the named config instead.',\n }, 400)\n return\n }\n const providerName = typeof body.provider === 'string' ? body.provider.trim() : ''\n const modelName = typeof body.model === 'string' ? body.model.trim() : ''\n if (!providerName || !modelName) {\n json(res, { success: false, error: 'invalid_request', message: 'provider and model are required' }, 400)\n return\n }\n const configName = typeof body.configName === 'string' ? body.configName.trim() : ''\n\n const llmCandidate: Record<string, unknown> = {\n provider: providerName,\n model: modelName,\n }\n if (typeof body.baseURL === 'string') {\n llmCandidate.baseURL = body.baseURL\n }\n if (body.providerHeaders !== undefined) {\n llmCandidate.providerHeaders = body.providerHeaders\n }\n\n const parsedConfig = ModelConfigSchema.safeParse(llmCandidate)\n if (!parsedConfig.success) {\n json(res, {\n success: false,\n error: 'invalid_request',\n message: parsedConfig.error.issues\n .map((issue: { path: PropertyKey[]; message: string }) => `${issue.path.map(String).join('.') || 'config'}: ${issue.message}`)\n .join('; '),\n }, 400)\n return\n }\n\n const start = Date.now()\n const llmConfig = parsedConfig.data\n const coreAuth = await import('@vostride/agent-qa-core') as typeof import('@vostride/agent-qa-core') & {\n resolveLLMAuth: (name: string, config: typeof llmConfig) => Promise<\n | { kind: 'api-key'; apiKey: string }\n | { kind: 'bearer-token'; token: string }\n | { kind: 'auth-fetch'; fetch: typeof globalThis.fetch; modelAdapter: 'openai-responses' | 'anthropic-messages' }\n | { kind: 'unauthenticated'; message: string }\n | { kind: 'missing'; message: string }\n >\n }\n const resolvedAuth = await coreAuth.resolveLLMAuth(configName, llmConfig)\n if (resolvedAuth.kind === 'missing') {\n json(res, {\n success: false,\n error: 'missing_credential',\n message: resolvedAuth.message,\n })\n return\n }\n\n const modelConfig: Record<string, unknown> = { ...llmConfig }\n let unauthenticated = false\n let authMessage: string | undefined\n\n if (resolvedAuth.kind === 'api-key') {\n modelConfig.apiKey = resolvedAuth.apiKey\n } else if (resolvedAuth.kind === 'bearer-token') {\n modelConfig.authToken = resolvedAuth.token\n } else if (resolvedAuth.kind === 'auth-fetch') {\n modelConfig.fetch = resolvedAuth.fetch\n modelConfig.modelAdapter = resolvedAuth.modelAdapter\n } else if (resolvedAuth.kind === 'unauthenticated') {\n unauthenticated = true\n authMessage = resolvedAuth.message\n }\n\n try {\n const { createModel } = await import('@vostride/agent-qa-core')\n const model = await createModel(modelConfig as unknown as Parameters<typeof createModel>[0])\n\n const testProviderOpts = getProviderOptions(modelConfig as unknown as Parameters<typeof getProviderOptions>[0])\n const connectionTimeoutMs = llmConnectionTestTimeoutMs(llmConfig)\n\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), connectionTimeoutMs)\n try {\n const { generateText } = await import('ai')\n await generateText({\n model,\n prompt: 'Say \"ok\"',\n abortSignal: controller.signal,\n providerOptions: testProviderOpts,\n })\n } finally {\n clearTimeout(timeout)\n }\n\n json(res, {\n success: true,\n model: modelName,\n provider: providerName,\n timeoutMs: connectionTimeoutMs,\n responseTime: Date.now() - start,\n ...(unauthenticated ? { unauthenticated: true, message: authMessage ?? LLM_TEST_UNAUTHENTICATED_MESSAGE } : {}),\n })\n } catch (err: unknown) {\n const connectionTimeoutMs = llmConnectionTestTimeoutMs(llmConfig)\n const { message: providerMessage, statusCode } = extractProviderErrorMessage(err)\n const errorCategory = classifyProviderError(providerMessage, statusCode)\n const message = publicLLMTestMessage(errorCategory, providerMessage)\n\n json(res, {\n success: false,\n error: errorCategory,\n message,\n timeoutMs: connectionTimeoutMs,\n ...(statusCode ? { statusCode } : {}),\n ...(message !== providerMessage ? { details: providerMessage } : {}),\n ...(unauthenticated ? { unauthenticated: true, authMessage: authMessage ?? LLM_TEST_UNAUTHENTICATED_MESSAGE } : {}),\n })\n }\n })\n .catch(() => json(res, { success: false, error: 'invalid_request', message: 'Invalid request body' }, 400))\n return\n }\n\n // POST /api/cache/purge — purge cached action plans for a test or all tests\n if (path === '/api/cache/purge' && req.method === 'POST') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 503)\n return\n }\n readJsonBody<{ file?: string; all?: boolean }>(req)\n .then(async (body) => {\n if (!body.file && !body.all) {\n json(res, { error: 'Either file or all is required' }, 400)\n return\n }\n try {\n const cfg = await configManager.read()\n const targetPlatforms = getTargetPlatformMap(cfg)\n const cacheDir = (cfg as {\n services?: { cache?: { dir?: string } }\n cache?: { dir?: string }\n }).services?.cache?.dir\n ?? (cfg as { cache?: { dir?: string } }).cache?.dir\n if (!cacheDir) {\n json(res, { error: 'Cache directory not configured' }, 400)\n return\n }\n if (body.file) {\n // Read raw config file content for cache key scoping\n let configContent = ''\n if (deps.configPath) {\n try { configContent = await readFile(deps.configPath, 'utf-8') } catch { /* best-effort */ }\n }\n const resolvedPath = (await normalizeDashboardWorkspacePath(body.file, workspacePaths, 'test')).executionPath\n const content = await readFile(resolvedPath, 'utf-8')\n const doc = parseYaml(content)\n const metadata = extractTestFileMetadata(content)\n const platform = resolveEffectivePlatform(\n metadata.platform,\n metadata.targetName,\n targetPlatforms,\n 'web',\n ) ?? 'web'\n const steps: string[] = (doc.steps ?? []).map((s: unknown) =>\n typeof s === 'string' ? s : (s as Record<string, string>).step,\n )\n const configDir = deps.configPath ? dirname(resolve(deps.configPath)) : process.cwd()\n const resolvedCacheDir = resolve(configDir, cacheDir)\n let purged = 0\n for (const step of steps) {\n const stepHash = hashStepInstruction(step, platform, configContent, content)\n const dirPath = join(resolvedCacheDir, stepHash)\n try {\n await stat(dirPath)\n await rm(dirPath, { recursive: true, force: true })\n purged++\n } catch {\n // directory doesn't exist — skip\n }\n }\n json(res, { purged })\n } else {\n const configDir = deps.configPath ? dirname(resolve(deps.configPath)) : process.cwd()\n const resolvedDir = resolve(configDir, cacheDir)\n let entries: string[]\n try {\n entries = await readdir(resolvedDir)\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n json(res, { purged: 0 })\n return\n }\n throw err\n }\n for (const entry of entries) {\n await rm(join(resolvedDir, entry), { recursive: true, force: true })\n }\n json(res, { purged: entries.length })\n }\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Cache purge failed' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // Agent Rules API\n if (path === '/api/agent-rules' && req.method === 'GET') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n let content: string\n try {\n content = await readFile(workspacePaths.agentRules.absolutePath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n json(res, { content: null, filePath: workspacePaths.agentRules.workspaceRelativePath, error: 'workspace.agentRules file_not_found' }, 500)\n return\n }\n throw err\n }\n json(res, { content, filePath: workspacePaths.agentRules.workspaceRelativePath })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read agent rules' }, 500)\n }\n })()\n return\n }\n\n // Hooks API\n if (path === '/api/hooks' && req.method === 'GET') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n json(res, await hookRegistryManager.readCatalog())\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read hooks' }, 500)\n }\n })()\n return\n }\n\n if (path === '/api/hooks' && req.method === 'POST') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody(req)\n .then(async (body) => {\n try {\n const result = await hookRegistryManager.createHook(body as import('../hooks/hook-registry-types.js').HookMutationRequest)\n json(res, result, 201)\n } catch (err: unknown) {\n if (isHookRegistryMutationError(err) && err.code === 'validation_failed') {\n json(res, { error: 'validation_failed', fieldErrors: err.fieldErrors }, 400)\n return\n }\n json(res, { error: err instanceof Error ? err.message : 'Failed to create hook' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n const hookRunMatch = path.match(/^\\/api\\/hooks\\/([^/]+)\\/run$/)\n if (hookRunMatch && req.method === 'POST') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody<import('../hooks/hook-registry-types.js').HookRunRequest>(req)\n .then(async (body) => {\n try {\n const validation = validateHookRunRequest(body)\n if (validation.fieldErrors.length > 0) {\n json(res, { error: 'validation_failed', fieldErrors: validation.fieldErrors }, 400)\n return\n }\n\n const hookId = decodeURIComponent(hookRunMatch[1])\n const prepareResult = await hookRegistryManager.prepareForExecution()\n if (prepareResult.hookRegistryError) {\n json(res, { error: 'hook_registry_error', message: prepareResult.hookRegistryError }, 409)\n return\n }\n\n const resolvedHook = prepareResult.resolvedHooks.get(hookId)\n if (!resolvedHook) {\n const detail = await hookRegistryManager.readHook(hookId)\n if (!detail) {\n notFound(res, 'Hook not found')\n return\n }\n\n const fieldErrors = prepareResult.authoringIssuesById.get(hookId) ?? detail.fieldErrors\n if (fieldErrors.length > 0) {\n json(res, { error: 'hook_not_runnable', fieldErrors }, 409)\n return\n }\n\n json(res, { error: 'hook_not_runnable', message: 'Hook is not executable' }, 409)\n return\n }\n\n const workspaceEnv = await readWorkspaceEnvVars(workspacePaths)\n const result = await runHookInSandbox(resolvedHook, {\n envVars: {\n ...workspaceEnv,\n ...validation.overrides,\n },\n })\n const networkLogs = summarizeHookNetworkLogs(\n (result as { networkLogs?: Array<{ url: string; method: string; status: number; startTime: number; endTime: number }> }).networkLogs,\n )\n\n json(res, sanitizeAuthStateForResponse({\n success: result.success,\n status: result.success ? 'passed' : 'failed',\n executedAt: new Date().toISOString(),\n duration: result.duration,\n output: result.output,\n stdout: result.stdout,\n stderr: result.stderr,\n error: result.error ?? null,\n variables: result.variables,\n sandbox: {\n runtime: resolvedHook.runtime,\n image: RUNTIME_IMAGE_MAP[resolvedHook.runtime],\n networkMode: resolvedHook.network ? 'enabled' : 'disabled',\n dockerVersion: null,\n networkLogsAvailable: networkLogs.length > 0,\n networkLogs,\n },\n } satisfies import('../hooks/hook-registry-types.js').HookRunResponse))\n } catch (err: unknown) {\n json(res, sanitizeAuthStateForResponse({ error: err instanceof Error ? err.message : 'Failed to run hook' }), 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n const hookDetailMatch = path.match(/^\\/api\\/hooks\\/([^/]+)$/)\n if (hookDetailMatch && req.method === 'GET') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const detail = await hookRegistryManager.readHook(decodeURIComponent(hookDetailMatch[1]))\n if (!detail) {\n notFound(res, 'Hook not found')\n return\n }\n json(res, detail)\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read hook' }, 500)\n }\n })()\n return\n }\n\n if (hookDetailMatch && req.method === 'PUT') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody(req)\n .then(async (body) => {\n try {\n const result = await hookRegistryManager.updateHook(\n decodeURIComponent(hookDetailMatch[1]),\n body as import('../hooks/hook-registry-types.js').HookMutationRequest,\n )\n json(res, result)\n } catch (err: unknown) {\n if (isHookRegistryMutationError(err) && err.code === 'hook_not_found') {\n notFound(res, 'Hook not found')\n return\n }\n if (isHookRegistryMutationError(err) && err.code === 'validation_failed') {\n json(res, { error: 'validation_failed', fieldErrors: err.fieldErrors }, 400)\n return\n }\n json(res, { error: err instanceof Error ? err.message : 'Failed to update hook' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n if (hookDetailMatch && req.method === 'DELETE') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const result = await hookRegistryManager.deleteHook(\n decodeURIComponent(hookDetailMatch[1]),\n { force: url.searchParams.get('force') === 'true' },\n )\n if (!result.deleted) {\n json(res, { error: 'hook_in_use', references: result.references }, 409)\n return\n }\n json(res, result)\n } catch (err: unknown) {\n if (isHookRegistryMutationError(err) && err.code === 'hook_not_found') {\n notFound(res, 'Hook not found')\n return\n }\n if (isHookRegistryMutationError(err) && err.code === 'validation_failed') {\n json(res, { error: 'validation_failed', fieldErrors: err.fieldErrors }, 400)\n return\n }\n json(res, { error: err instanceof Error ? err.message : 'Failed to delete hook' }, 500)\n }\n })()\n return\n }\n\n if (path === '/api/agent-rules' && req.method === 'PUT') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody<{ content: string }>(req)\n .then(async (body) => {\n try {\n if (typeof body.content !== 'string') {\n json(res, { error: 'Missing required field: content' }, 400)\n return\n }\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n await writeFile(workspacePaths.agentRules.absolutePath, body.content, 'utf-8')\n json(res, { updated: true })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to save agent rules' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n if (path === '/api/agent-rules/create' && req.method === 'POST') {\n if (!configManager || !deps.configPath) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n const configPath = deps.configPath\n readJsonBody<{ fileName?: string }>(req)\n .then(async (body) => {\n try {\n const fileName = typeof body.fileName === 'string' && body.fileName.trim()\n ? body.fileName.trim()\n : 'agent-rules.md'\n if (!isPlainFileName(fileName)) {\n json(res, { error: 'fileName must be a plain file name' }, 400)\n return\n }\n\n const configDir = dirname(configPath)\n const resolvedPath = resolve(configDir, fileName)\n if (!getPathInsideDir(resolvedPath, configDir)) {\n json(res, { error: 'Invalid agent rules path' }, 400)\n return\n }\n\n await writeFile(resolvedPath, '', { encoding: 'utf-8', flag: 'wx' })\n await configManager!.replaceSectionRaw('workspace.agentRules', `./${fileName}`)\n json(res, { created: true, filePath: `./${fileName}` })\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'EEXIST') {\n json(res, { error: 'Agent rules file already exists' }, 409)\n return\n }\n json(res, { error: err instanceof Error ? err.message : 'Failed to create agent rules file' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // Variables API\n if (path === '/api/variables' && req.method === 'GET') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n let content: string\n try {\n content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n json(res, { error: `workspace.envFile not found: ${workspacePaths.envFile.workspaceRelativePath}` }, 500)\n return\n }\n throw err\n }\n const parsed = parseEnvFile(content)\n const variables = Object.entries(parsed).map(([key, value]) => ({ key, value }))\n json(res, { variables, filePath: workspacePaths.envFile.workspaceRelativePath })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read variables' }, 500)\n }\n })()\n return\n }\n\n if (path === '/api/variables' && req.method === 'PUT') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody<{ oldKey?: string; key: string; value: string }>(req)\n .then(async (body) => {\n try {\n if (!body.key || typeof body.key !== 'string') {\n json(res, { error: 'Missing required field: key' }, 400)\n return\n }\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(body.key)) {\n json(res, { error: 'Variable names must contain only letters, numbers, and underscores' }, 400)\n return\n }\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n let content = ''\n try {\n content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n json(res, { error: `workspace.envFile not found: ${workspacePaths.envFile.workspaceRelativePath}` }, 500)\n return\n }\n throw err\n }\n const vars = parseEnvFile(content)\n if (body.oldKey && body.oldKey !== body.key) {\n delete vars[body.oldKey]\n }\n vars[body.key] = body.value ?? ''\n await writeFile(workspacePaths.envFile.absolutePath, serializeEnvFile(vars), 'utf-8')\n json(res, { updated: true })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to update variable' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n const varDeleteMatch = path.match(/^\\/api\\/variables\\/(.+)$/)\n if (varDeleteMatch && req.method === 'DELETE') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const varKey = decodeURIComponent(varDeleteMatch[1])\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n let content = ''\n try {\n content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n json(res, { error: `workspace.envFile not found: ${workspacePaths.envFile.workspaceRelativePath}` }, 500)\n return\n }\n throw err\n }\n const vars = parseEnvFile(content)\n const existed = varKey in vars\n delete vars[varKey]\n await writeFile(workspacePaths.envFile.absolutePath, serializeEnvFile(vars), 'utf-8')\n json(res, { deleted: existed })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to delete variable' }, 500)\n }\n })()\n return\n }\n\n // POST /api/live-editor/sessions/:id/auth-state — save auth state from active web Live Mode context\n const liveEditorAuthStateMatch = path.match(/^\\/api\\/live-editor\\/sessions\\/([^/]+)\\/auth-state$/)\n if (liveEditorAuthStateMatch && req.method === 'POST') {\n if (!sessionManager) {\n json(res, { error: 'Live editor not available' }, 503)\n return\n }\n ;(async () => {\n let stateName = ''\n let session: { captureWebAuthState?: (name: string, options: { replace: boolean }) => Promise<unknown>; getState?: () => unknown } | undefined\n try {\n const body = await readJsonBody<{ name?: unknown; replace?: unknown }>(req)\n const parsedName = AuthStateNameSchema.safeParse(typeof body?.name === 'string' ? body.name : '')\n if (!parsedName.success) {\n json(res, { error: 'Auth state name must be a lowercase slug.' }, 400)\n return\n }\n\n stateName = parsedName.data\n session = sessionManager.getSession(decodeURIComponent(liveEditorAuthStateMatch[1]))\n if (!session) {\n notFound(res, 'Session not found')\n return\n }\n\n if (typeof session.captureWebAuthState !== 'function') {\n json(res, {\n error: `Could not save auth state \"${stateName}\" for target \"${getSessionTargetNameForAuthState(session)}\".`,\n }, 500)\n return\n }\n\n const authState = await session.captureWebAuthState(stateName, { replace: body?.replace === true })\n json(res, { authState })\n } catch (err: unknown) {\n const targetName = getSessionTargetNameForAuthState(session)\n const response = buildAuthStateSaveErrorMessage(stateName || 'unknown', targetName, err)\n json(res, { error: response.message }, response.status)\n }\n })()\n return\n }\n\n // POST /api/live-editor/sessions — create a new live editor session\n if (path === '/api/live-editor/sessions' && req.method === 'POST') {\n if (!sessionManager) {\n json(res, { error: 'Live editor not available' }, 503)\n return\n }\n ;(async () => {\n try {\n const body = await readJsonBody<{\n platform?: string\n targetName?: string\n url?: string\n headless?: boolean\n device?: Record<string, unknown>\n useDeviceName?: string\n appState?: string\n bundleId?: string\n appPackage?: string\n appActivity?: string\n setupHooks?: unknown\n teardownHooks?: unknown\n entity?: { type?: string; id?: string }\n }>(req)\n const platform = body?.platform ?? 'web'\n const runtimeLLM = await resolveDashboardRuntimeLLM(configManager, llmConfig, authFetch)\n if (!runtimeLLM.ok) {\n json(res, { error: runtimeLLM.error }, 400)\n return\n }\n const setupHooks = Array.isArray(body?.setupHooks)\n ? body.setupHooks.filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n : []\n const teardownHooks = Array.isArray(body?.teardownHooks)\n ? body.teardownHooks.filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n : []\n // Validate entity (ASVS V5). Only 'suite' | 'test' with a non-empty id\n // are honoured; malformed shapes are silently ignored — client may\n // send {} during the test-editor retrofit before entity threading\n // lands (downgrades to sessionNumber=null instead of a 400 error).\n let entityRef: { type: 'suite' | 'test'; id: string } | undefined\n if (body?.entity && typeof body.entity === 'object') {\n const t = body.entity.type\n const id = body.entity.id\n if ((t === 'suite' || t === 'test') && typeof id === 'string' && id.length > 0) {\n entityRef = { type: t, id }\n }\n }\n let agentRules: string | undefined\n let envVars: Record<string, string> | undefined\n let secretStore: SecretStore | undefined\n let secretRedactor: SecretRedactor | undefined\n let resolvedHooks = new Map<string, import('@vostride/agent-qa-core').HookDefinition>()\n let hookRegistryError: string | undefined\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 500)\n return\n }\n\n try {\n agentRules = await readFile(workspacePaths.agentRules.absolutePath, 'utf-8')\n } catch {\n json(res, { error: `workspace.agentRules file could not be loaded: ${workspacePaths.agentRules.workspaceRelativePath}` }, 400)\n return\n }\n\n try {\n const envContent = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n envVars = parseEnvFile(envContent)\n } catch {\n json(res, { error: `workspace.envFile file could not be loaded: ${workspacePaths.envFile.workspaceRelativePath}` }, 400)\n return\n }\n\n try {\n const secretsContent = await readFile(workspacePaths.secretsFile.absolutePath, 'utf-8')\n secretStore = SecretStore.fromEnvContent(secretsContent)\n secretRedactor = new SecretRedactor(secretStore)\n } catch {\n json(res, { error: `workspace.secretsFile file could not be loaded: ${workspacePaths.secretsFile.workspaceRelativePath}` }, 400)\n return\n }\n\n const hookCatalog = await readWorkspaceHooks(configManager, deps.configPath)\n resolvedHooks = hookCatalog.resolvedHooks\n hookRegistryError = hookCatalog.hookRegistryError\n const { sessionId, sessionNumber } = await sessionManager.createSession(\n {\n platform: platform as 'web' | 'android' | 'ios',\n targetName: typeof body?.targetName === 'string' ? body.targetName : undefined,\n llmConfig: runtimeLLM.llmConfig,\n authFetch: runtimeLLM.authFetch,\n agentRules,\n envVars,\n secretStore,\n secretRedactor,\n setupHooks,\n teardownHooks,\n resolvedHooks,\n hookRegistryError,\n url: body?.url,\n headless: body?.headless ?? false,\n useDeviceName: typeof body?.useDeviceName === 'string' ? body.useDeviceName : undefined,\n appState: body?.appState === 'preserve' || body?.appState === 'reset' ? body.appState : undefined,\n bundleId: typeof body?.bundleId === 'string' ? body.bundleId : undefined,\n appPackage: typeof body?.appPackage === 'string' ? body.appPackage : undefined,\n appActivity: typeof body?.appActivity === 'string' ? body.appActivity : undefined,\n device: body?.device as import('../live-editor/types.js').LiveSessionConfig['device'],\n },\n entityRef,\n )\n json(res, { sessionId, sessionNumber }, 201)\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n json(res, { error: message }, 500)\n }\n })()\n return\n }\n\n // GET /api/live-editor/sessions — list all active live editor sessions\n if (path === '/api/live-editor/sessions' && req.method === 'GET') {\n if (!sessionManager) {\n json(res, { error: 'Live editor not available' }, 503)\n return\n }\n json(res, { sessions: sessionManager.listSessions() })\n return\n }\n\n // DELETE /api/live-editor/sessions/:id — terminate a live editor session\n const liveEditorSessionMatch = path.match(/^\\/api\\/live-editor\\/sessions\\/([^/]+)$/)\n if (liveEditorSessionMatch && req.method === 'DELETE') {\n if (!sessionManager) {\n json(res, { error: 'Live editor not available' }, 503)\n return\n }\n const sessionId = liveEditorSessionMatch[1]\n ;(async () => {\n const terminated = await sessionManager.terminateSession(sessionId)\n if (terminated) {\n json(res, { ok: true })\n } else {\n notFound(res, 'Session not found')\n }\n })()\n return\n }\n\n // Variable suggestions: env keys\n if (path === '/api/variables/env' && req.method === 'GET') {\n if (!configManager) {\n json(res, { keys: [] })\n return\n }\n ;(async () => {\n try {\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n const content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n const parsed = parseEnvFile(content)\n json(res, { keys: Object.keys(parsed) })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read env variables' }, 500)\n }\n })()\n return\n }\n\n // Variable suggestions: hook names\n if (path === '/api/variables/hooks' && req.method === 'GET') {\n ;(async () => {\n try {\n const { hooks } = await readWorkspaceHooks(configManager, deps.configPath)\n json(res, { names: hooks.map((hook) => hook.name) })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read hooks' }, 500)\n }\n })()\n return\n }\n\n // Variable suggestions: captured variable names from prior runs\n const capturedMatch = path.match(/^\\/api\\/variables\\/captured\\/([^/]+)$/)\n if (capturedMatch && req.method === 'GET') {\n ;(async () => {\n try {\n const testId = decodeURIComponent(capturedMatch[1])\n const names = db.getCapturedVariableNames(testId)\n json(res, { names })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read captured variables' }, 500)\n }\n })()\n return\n }\n\n if (path === '/api/memory/catalog' && req.method === 'GET') {\n ;(async () => {\n try {\n json(res, await memoryCatalogManager.readCatalog())\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read memory catalog' }, 500)\n }\n })()\n return\n }\n\n const memoryProductMatch = path.match(/^\\/api\\/memory\\/products\\/([^/]+)$/)\n if (memoryProductMatch && req.method === 'GET') {\n ;(async () => {\n try {\n const productKey = decodeURIComponent(memoryProductMatch[1])\n if (!isValidMemoryScopeId(productKey)) {\n json(res, { error: 'Invalid memory product id' }, 400)\n return\n }\n const product = await memoryCatalogManager.readProductDetail(productKey)\n if (!product) {\n json(res, { error: 'Memory product not found' }, 404)\n return\n }\n json(res, { product })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read memory product' }, 500)\n }\n })()\n return\n }\n\n const memoryScopeMatch = path.match(/^\\/api\\/memory\\/scopes\\/([^/]+)\\/([^/]+)$/)\n if (memoryScopeMatch && req.method === 'GET') {\n ;(async () => {\n try {\n const scope = decodeURIComponent(memoryScopeMatch[1])\n const scopeId = decodeURIComponent(memoryScopeMatch[2])\n if (!isMemoryScope(scope)) {\n json(res, { error: 'Invalid memory scope' }, 400)\n return\n }\n if (!isValidMemoryScopeId(scopeId)) {\n json(res, { error: 'Invalid memory scope id' }, 400)\n return\n }\n const payload = await memoryCatalogManager.readScopedObservations(scope, scopeId)\n if (!payload) {\n json(res, { error: 'Memory scope not found' }, 404)\n return\n }\n json(res, payload)\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read memory scope' }, 500)\n }\n })()\n return\n }\n\n // Memory observations: list for a test\n const obsListMatch = path.match(/^\\/api\\/memory\\/observations\\/([^/]+)$/)\n if (obsListMatch && req.method === 'GET') {\n ;(async () => {\n try {\n const testId = decodeURIComponent(obsListMatch[1])\n const payload = await memoryCatalogManager.readScopedObservations('test', testId)\n json(res, {\n observations: payload?.observations ?? [],\n invalidFiles: payload?.invalidFiles ?? [],\n })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read observations' }, 500)\n }\n })()\n return\n }\n\n // Memory observations: delete\n const obsDeleteMatch = path.match(/^\\/api\\/memory\\/observations\\/([^/]+)\\/([^/]+)$/)\n if (obsDeleteMatch && req.method === 'DELETE') {\n ;(async () => {\n try {\n const testId = decodeURIComponent(obsDeleteMatch[1])\n const obsId = decodeURIComponent(obsDeleteMatch[2])\n if (!isValidMemoryScopeId(testId) || !isValidMemoryScopeId(obsId)) {\n json(res, { error: 'Invalid memory observation id' }, 400)\n return\n }\n\n const configDir = deps.configPath ? dirname(resolve(deps.configPath)) : process.cwd()\n const cfg = configManager ? await configManager.read().catch(() => undefined) : undefined\n const parsedConfig = AgentQaConfigSchema.safeParse(cfg ?? {})\n const memoryRoot = parsedConfig.success\n ? resolveMemoryRoot(parsedConfig.data, configDir)\n : resolveMemoryRoot(undefined, configDir)\n const testsRoot = join(memoryRoot, 'tests')\n const resolved = resolve(testsRoot, testId, `${obsId}.md`)\n if (!getPathInsideDir(resolved, testsRoot)) {\n json(res, { error: 'Invalid path' }, 400)\n return\n }\n\n await rm(resolved, { force: true })\n json(res, { deleted: true })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to delete observation' }, 500)\n }\n })()\n return\n }\n\n // Unknown API route\n if (path.startsWith('/api/')) {\n notFound(res)\n return\n }\n\n // Non-API routes handled by server.ts (static files)\n notFound(res)\n }\n}\n\nfunction isMemoryScope(value: string): value is MemoryScope {\n return value === 'product' || value === 'suite' || value === 'test'\n}\n","import { readdir, readFile, stat } from 'node:fs/promises'\nimport { dirname, join, resolve, sep } from 'node:path'\n\nimport {\n AgentQaConfigSchema,\n discoverWorkspaceFiles,\n listObservations,\n parseObservation,\n resolveMemoryRoot,\n resolveWorkspacePaths,\n scanContent,\n type BaseObservation,\n type SuiteObservation,\n} from '@vostride/agent-qa-core'\nimport { parse as parseYaml } from 'yaml'\n\nimport type { ConfigManager } from '../config/index.js'\nimport { extractTestFileMetadata } from '../tests/test-file-manager.js'\n\nexport type MemoryScope = 'product' | 'suite' | 'test'\n\ntype MemoryTier = 'products' | 'suites' | 'tests'\ntype MemoryObservation = BaseObservation | SuiteObservation\n\nexport interface MemoryScopeCounts {\n product: number\n suite: number\n test: number\n}\n\nexport interface MemoryCatalogSourceCounts {\n suite: number\n test: number\n}\n\nexport interface MemoryCatalogProduct {\n productKey: string\n observationCount: number\n scopeCounts: MemoryScopeCounts\n targetReferences: string[]\n sourceCounts: MemoryCatalogSourceCounts\n freshness: string | null\n sourceCoverage: number\n}\n\nexport interface MemoryScopeSummary {\n scope: MemoryScope\n observationCount: number\n freshness: string | null\n sourceCoverage: number\n scopeIds: string[]\n}\n\nexport interface MemoryAtlasObservation {\n id: string\n title: string\n content: string\n trust: number\n created: string\n last_confirmed: string\n confirmed_count: number\n contradicted_count: number\n source_test: string\n scope: MemoryScope\n scopeId: string\n}\n\nexport interface MemoryObservationReference {\n kind: 'suite' | 'test' | 'source_test'\n id: string\n label: string\n targetName: string | null\n href: string | null\n}\n\nexport interface MemoryWorkspaceObservation extends MemoryAtlasObservation {\n updated: string\n scopeRef: MemoryObservationReference | null\n sourceTestRef: MemoryObservationReference | null\n}\n\nexport interface MemoryInvalidFile {\n scope: MemoryScope\n scopeId: string\n filename: string\n code: string\n message: string\n}\n\nexport interface MemoryProductDetail extends MemoryCatalogProduct {\n scopes: Record<MemoryScope, MemoryScopeSummary>\n observations: MemoryWorkspaceObservation[]\n invalidFiles: MemoryInvalidFile[]\n}\n\nexport interface MemoryCatalogResponse {\n products: MemoryCatalogProduct[]\n}\n\nexport interface MemoryScopeReadResponse {\n scope: MemoryScope\n scopeId: string\n observations: MemoryObservation[]\n invalidFiles: MemoryInvalidFile[]\n}\n\ninterface MemoryCatalogManagerOptions {\n configManager?: ConfigManager\n configPath?: string\n}\n\ninterface WorkspaceContext {\n workspaceDir: string\n memoryRoot: string\n targetToProduct: Map<string, string>\n productToTargets: Map<string, string[]>\n suiteMetadataById: Map<string, WorkspaceEntityMetadata>\n testMetadataById: Map<string, WorkspaceEntityMetadata>\n}\n\ninterface WorkspaceEntityMetadata {\n id: string\n label: string\n targetName: string | null\n productKey: string | null\n href: string | null\n}\n\ninterface ProductAccumulator {\n productKey: string\n observationCount: number\n scopeCounts: MemoryScopeCounts\n targetReferences: string[]\n freshness: string | null\n sourceTests: Set<string>\n scopes: Record<MemoryScope, ScopeAccumulator>\n observations: MemoryWorkspaceObservation[]\n invalidFiles: MemoryInvalidFile[]\n}\n\ninterface ObservationRecord {\n observation: MemoryObservation\n updated: string\n}\n\ninterface ScopeAccumulator {\n observationCount: number\n freshness: string | null\n sourceTests: Set<string>\n scopeIds: Set<string>\n}\n\nconst MEMORY_SCOPE_TO_TIER: Record<MemoryScope, MemoryTier> = {\n product: 'products',\n suite: 'suites',\n test: 'tests',\n}\n\nconst MEMORY_SCOPE_ORDER: Record<MemoryScope, number> = {\n product: 0,\n suite: 1,\n test: 2,\n}\n\nconst EMPTY_SCOPE_COUNTS: MemoryScopeCounts = {\n product: 0,\n suite: 0,\n test: 0,\n}\n\nexport class MemoryCatalogManager {\n private readonly configManager?: ConfigManager\n private readonly configPath?: string\n\n constructor(options: MemoryCatalogManagerOptions = {}) {\n this.configManager = options.configManager\n this.configPath = options.configPath\n }\n\n async readCatalog(): Promise<MemoryCatalogResponse> {\n const products = await this.readProducts()\n return {\n products: products\n .map((product) => this.toProductSummary(product))\n .sort(compareProducts),\n }\n }\n\n async readProductDetail(productKey: string): Promise<MemoryProductDetail | null> {\n if (!isValidMemoryScopeId(productKey)) {\n return null\n }\n\n const products = await this.readProducts()\n const match = products.find((product) => product.productKey === productKey)\n return match ? this.toProductDetail(match) : null\n }\n\n async readScopedObservations(scope: MemoryScope, scopeId: string): Promise<MemoryScopeReadResponse | null> {\n if (!isValidMemoryScopeId(scopeId)) {\n return null\n }\n\n const { memoryRoot } = await this.loadWorkspaceContext()\n const tierRoot = resolve(join(memoryRoot, MEMORY_SCOPE_TO_TIER[scope]))\n const dir = resolve(join(tierRoot, scopeId))\n if (!dir.startsWith(`${tierRoot}${sep}`)) {\n return null\n }\n\n try {\n const info = await stat(dir)\n if (!info.isDirectory()) {\n return null\n }\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return null\n }\n throw error\n }\n\n const context = await this.loadWorkspaceContext()\n const { observations, invalidFiles } = await readObservationDirectory(scope, scopeId, dir)\n\n return {\n scope,\n scopeId,\n observations: observations.map((record) => toMemoryWorkspaceObservation(scope, scopeId, record, context)),\n invalidFiles,\n }\n }\n\n private async readProducts(): Promise<ProductAccumulator[]> {\n const context = await this.loadWorkspaceContext()\n const products = new Map<string, ProductAccumulator>()\n\n await this.collectTier(context.memoryRoot, context.productToTargets, 'products', (scopeId) => scopeId, products, context)\n await this.collectTier(\n context.memoryRoot,\n context.productToTargets,\n 'suites',\n (scopeId) => context.suiteMetadataById.get(scopeId)?.productKey ?? null,\n products,\n context,\n )\n await this.collectTier(\n context.memoryRoot,\n context.productToTargets,\n 'tests',\n (scopeId) => context.testMetadataById.get(scopeId)?.productKey ?? null,\n products,\n context,\n )\n\n return Array.from(products.values())\n }\n\n private async collectTier(\n memoryRoot: string,\n productToTargets: Map<string, string[]>,\n tier: MemoryTier,\n resolveProductKey: (scopeId: string) => string | null,\n products: Map<string, ProductAccumulator>,\n context: WorkspaceContext,\n ): Promise<void> {\n const tierRoot = join(memoryRoot, tier)\n let entries: Array<{ isDirectory(): boolean; name: string }>\n try {\n const dirEntries = await readdir(tierRoot, { withFileTypes: true, encoding: 'utf8' })\n entries = dirEntries.map((entry) => ({\n isDirectory: () => entry.isDirectory(),\n name: String(entry.name),\n }))\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return\n }\n throw error\n }\n\n const scope = tierToScope(tier)\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const scopeId = entry.name\n const productKey = resolveProductKey(scopeId)\n if (!productKey || !isValidMemoryScopeId(productKey)) continue\n\n const { observations, invalidFiles } = await readObservationDirectory(scope, scopeId, join(tierRoot, scopeId))\n if (observations.length === 0 && invalidFiles.length === 0) continue\n\n const accumulator = products.get(productKey) ?? createProductAccumulator(\n productKey,\n productToTargets.get(productKey) ?? [],\n )\n accumulator.invalidFiles.push(...invalidFiles)\n for (const record of observations) {\n const observation = toMemoryWorkspaceObservation(scope, scopeId, record, context)\n accumulator.observationCount += 1\n accumulator.scopeCounts[scope] += 1\n accumulator.freshness = pickFreshest(accumulator.freshness, observation.last_confirmed)\n accumulator.sourceTests.add(observation.source_test)\n accumulator.observations.push(observation)\n\n const scopeAccumulator = accumulator.scopes[scope]\n scopeAccumulator.observationCount += 1\n scopeAccumulator.freshness = pickFreshest(scopeAccumulator.freshness, observation.last_confirmed)\n scopeAccumulator.sourceTests.add(observation.source_test)\n scopeAccumulator.scopeIds.add(scopeId)\n }\n\n products.set(productKey, accumulator)\n }\n }\n\n private async loadWorkspaceContext(): Promise<WorkspaceContext> {\n const workspaceDir = this.configPath ? dirname(resolve(this.configPath)) : process.cwd()\n const config = await this.readConfig()\n const targetToProduct = getTargetToProductMap(config)\n const productToTargets = getProductToTargetsMap(targetToProduct)\n const configResult = AgentQaConfigSchema.safeParse(config)\n const memoryRoot = configResult.success\n ? resolveMemoryRoot(configResult.data, workspaceDir)\n : resolveMemoryRoot(undefined, workspaceDir)\n const workspacePaths = configResult.success\n ? resolveWorkspacePaths({\n config: configResult.data,\n configPath: this.configPath ? resolve(this.configPath) : resolve(workspaceDir, 'agent-qa.config.yaml'),\n })\n : null\n const [testFiles, suiteFiles] = workspacePaths\n ? await Promise.all([\n discoverWorkspaceFiles({ workspace: workspacePaths, kind: 'test' }),\n discoverWorkspaceFiles({ workspace: workspacePaths, kind: 'suite' }),\n ])\n : [[], []]\n\n const testMetadataById = new Map<string, WorkspaceEntityMetadata>()\n for (const file of testFiles) {\n const content = await readFile(file.absolutePath, 'utf-8').catch(() => null)\n if (!content) continue\n const metadata = extractTestFileMetadata(content)\n if (!metadata.testId) continue\n const targetName = metadata.targetName ?? null\n const productKey = targetName ? targetToProduct.get(targetName) ?? null : null\n testMetadataById.set(metadata.testId, {\n id: metadata.testId,\n label: metadata.name?.trim() || metadata.testId,\n targetName,\n productKey,\n href: `/test/${metadata.testId}`,\n })\n }\n\n const suiteMetadataById = new Map<string, WorkspaceEntityMetadata>()\n for (const file of suiteFiles) {\n const content = await readFile(file.absolutePath, 'utf-8').catch(() => null)\n if (!content) continue\n const metadata = extractSuiteFileMetadata(content)\n if (!metadata.suiteId) continue\n const targetName = metadata.targetName ?? null\n const productKey = targetName ? targetToProduct.get(targetName) ?? null : null\n suiteMetadataById.set(metadata.suiteId, {\n id: metadata.suiteId,\n label: metadata.name?.trim() || metadata.suiteId,\n targetName,\n productKey,\n href: `/suite/${metadata.suiteId}`,\n })\n }\n\n return {\n workspaceDir,\n memoryRoot,\n targetToProduct,\n productToTargets,\n suiteMetadataById,\n testMetadataById,\n }\n }\n\n private async readConfig(): Promise<Record<string, unknown>> {\n if (!this.configManager) {\n return {}\n }\n\n try {\n return await this.configManager.read()\n } catch {\n return {}\n }\n }\n\n private toProductSummary(product: ProductAccumulator): MemoryCatalogProduct {\n return {\n productKey: product.productKey,\n observationCount: product.observationCount,\n scopeCounts: { ...product.scopeCounts },\n targetReferences: [...product.targetReferences],\n sourceCounts: {\n suite: product.scopes.suite.scopeIds.size,\n test: product.sourceTests.size,\n },\n freshness: product.freshness,\n sourceCoverage: product.sourceTests.size,\n }\n }\n\n private toProductDetail(product: ProductAccumulator): MemoryProductDetail {\n return {\n ...this.toProductSummary(product),\n scopes: {\n product: toScopeSummary('product', product.scopes.product),\n suite: toScopeSummary('suite', product.scopes.suite),\n test: toScopeSummary('test', product.scopes.test),\n },\n observations: [...product.observations].sort(compareMemoryWorkspaceObservations),\n invalidFiles: [...product.invalidFiles].sort(compareInvalidFiles),\n }\n }\n}\n\nfunction tierToScope(tier: MemoryTier): MemoryScope {\n switch (tier) {\n case 'products':\n return 'product'\n case 'suites':\n return 'suite'\n case 'tests':\n return 'test'\n }\n}\n\nfunction createProductAccumulator(productKey: string, targetReferences: string[]): ProductAccumulator {\n return {\n productKey,\n observationCount: 0,\n scopeCounts: { ...EMPTY_SCOPE_COUNTS },\n targetReferences: [...targetReferences],\n freshness: null,\n sourceTests: new Set<string>(),\n scopes: {\n product: createScopeAccumulator(),\n suite: createScopeAccumulator(),\n test: createScopeAccumulator(),\n },\n observations: [],\n invalidFiles: [],\n }\n}\n\nfunction createScopeAccumulator(): ScopeAccumulator {\n return {\n observationCount: 0,\n freshness: null,\n sourceTests: new Set<string>(),\n scopeIds: new Set<string>(),\n }\n}\n\nfunction toScopeSummary(scope: MemoryScope, accumulator: ScopeAccumulator): MemoryScopeSummary {\n return {\n scope,\n observationCount: accumulator.observationCount,\n freshness: accumulator.freshness,\n sourceCoverage: accumulator.sourceTests.size,\n scopeIds: Array.from(accumulator.scopeIds).sort((left, right) => left.localeCompare(right)),\n }\n}\n\nfunction compareProducts(left: MemoryCatalogProduct, right: MemoryCatalogProduct): number {\n const freshnessCompare = compareFreshness(right.freshness, left.freshness)\n if (freshnessCompare !== 0) {\n return freshnessCompare\n }\n\n const sourceCoverageCompare = right.sourceCoverage - left.sourceCoverage\n if (sourceCoverageCompare !== 0) {\n return sourceCoverageCompare\n }\n\n return left.productKey.localeCompare(right.productKey)\n}\n\nfunction compareFreshness(left: string | null, right: string | null): number {\n if (left === right) return 0\n if (!left) return -1\n if (!right) return 1\n return left.localeCompare(right)\n}\n\nfunction toMemoryWorkspaceObservation(\n scope: MemoryScope,\n scopeId: string,\n record: ObservationRecord,\n context: WorkspaceContext,\n): MemoryWorkspaceObservation {\n const observation = record.observation\n return {\n id: observation.id,\n title: observation.title,\n content: observation.content,\n trust: observation.trust,\n created: observation.created,\n last_confirmed: observation.last_confirmed,\n confirmed_count: observation.confirmed_count,\n contradicted_count: observation.contradicted_count,\n source_test: observation.source_test,\n scope,\n scopeId,\n updated: record.updated,\n scopeRef: resolveScopeReference(scope, scopeId, context),\n sourceTestRef: resolveReference('source_test', context.testMetadataById.get(observation.source_test)),\n }\n}\n\nfunction compareMemoryWorkspaceObservations(left: MemoryWorkspaceObservation, right: MemoryWorkspaceObservation): number {\n const scopeCompare = MEMORY_SCOPE_ORDER[left.scope] - MEMORY_SCOPE_ORDER[right.scope]\n if (scopeCompare !== 0) {\n return scopeCompare\n }\n\n const lastConfirmedCompare = right.last_confirmed.localeCompare(left.last_confirmed)\n if (lastConfirmedCompare !== 0) {\n return lastConfirmedCompare\n }\n\n const createdCompare = right.created.localeCompare(left.created)\n if (createdCompare !== 0) {\n return createdCompare\n }\n\n return left.id.localeCompare(right.id)\n}\n\nfunction compareInvalidFiles(left: MemoryInvalidFile, right: MemoryInvalidFile): number {\n return (\n MEMORY_SCOPE_ORDER[left.scope] - MEMORY_SCOPE_ORDER[right.scope] ||\n left.scopeId.localeCompare(right.scopeId) ||\n left.filename.localeCompare(right.filename)\n )\n}\n\nfunction pickFreshest(current: string | null, candidate: string): string {\n if (!current) return candidate\n return candidate.localeCompare(current) > 0 ? candidate : current\n}\n\nasync function readObservationDirectory(\n scope: MemoryScope,\n scopeId: string,\n dir: string,\n): Promise<{ observations: ObservationRecord[]; invalidFiles: MemoryInvalidFile[] }> {\n const filenames = await listObservations(dir)\n const observations: ObservationRecord[] = []\n const invalidFiles: MemoryInvalidFile[] = []\n\n for (const filename of filenames) {\n const filePath = join(dir, filename)\n const raw = await readFile(filePath, 'utf-8').catch(() => null)\n if (!raw) continue\n\n const parsed = parseObservation(raw, filename)\n if (!parsed.data || parsed.error) {\n invalidFiles.push({\n scope,\n scopeId,\n filename,\n code: 'parse_error',\n message: parsed.error ?? 'Observation file could not be parsed',\n })\n continue\n }\n\n const scanned = scanObservationPayload(parsed.data.title, parsed.data.content)\n if (!scanned.safe) {\n invalidFiles.push({\n scope,\n scopeId,\n filename,\n code: 'security_scan_failed',\n message: `Security scan blocked: ${scanned.matchedPattern}`,\n })\n continue\n }\n\n const fileInfo = await stat(filePath).catch(() => null)\n if (!fileInfo) continue\n\n observations.push({\n observation: parsed.data,\n updated: fileInfo.mtime.toISOString(),\n })\n }\n\n return {\n observations: observations.sort((left, right) => right.observation.last_confirmed.localeCompare(left.observation.last_confirmed)),\n invalidFiles: invalidFiles.sort(compareInvalidFiles),\n }\n}\n\nfunction scanObservationPayload(title: string, content: string) {\n return scanContent([title, content].filter(Boolean).join('\\n'))\n}\n\nfunction getTargetToProductMap(config: Record<string, unknown>): Map<string, string> {\n const registry = (config.registry ?? {}) as {\n targets?: Record<string, { product?: unknown }>\n }\n const map = new Map<string, string>()\n\n for (const [targetName, targetConfig] of Object.entries(registry.targets ?? {})) {\n const productValue = typeof targetConfig?.product === 'string' && targetConfig.product.trim().length > 0\n ? targetConfig.product.trim()\n : targetName\n if (isValidMemoryScopeId(productValue)) {\n map.set(targetName, productValue)\n }\n }\n\n return map\n}\n\nfunction getProductToTargetsMap(targetToProduct: Map<string, string>): Map<string, string[]> {\n const map = new Map<string, string[]>()\n\n for (const [targetName, productKey] of targetToProduct.entries()) {\n const targets = map.get(productKey) ?? []\n targets.push(targetName)\n map.set(productKey, targets)\n }\n\n for (const targets of map.values()) {\n targets.sort((left, right) => left.localeCompare(right))\n }\n\n return map\n}\n\nfunction extractSuiteFileMetadata(content: string): { suiteId: string | null; name: string | null; targetName: string | null } {\n let parsed: Record<string, unknown> | null = null\n\n try {\n const yamlValue = parseYaml(content)\n if (yamlValue && typeof yamlValue === 'object' && !Array.isArray(yamlValue)) {\n parsed = yamlValue as Record<string, unknown>\n }\n } catch {\n // Fall back to regex extraction for partially-authored files.\n }\n\n const name = typeof parsed?.name === 'string' && parsed.name.trim().length > 0\n ? parsed.name.trim()\n : content.match(/^name:\\s*(.+)$/m)?.[1]?.trim().replace(/^[\"'](.*)[\"']$/, '$1') ?? null\n\n const suiteId = typeof parsed?.['suite-id'] === 'string' && parsed['suite-id'].trim().length > 0\n ? parsed['suite-id'].trim()\n : content.match(/^suite-id:\\s*(.+)$/m)?.[1]?.trim().replace(/^[\"'](.*)[\"']$/, '$1') ?? null\n\n const targetName = typeof parsed?.target === 'string' && parsed.target.trim().length > 0\n ? parsed.target.trim()\n : content.match(/^target:\\s*(.+)$/m)?.[1]?.trim().replace(/^[\"'](.*)[\"']$/, '$1') ?? null\n\n return { suiteId, name, targetName }\n}\n\nfunction resolveScopeReference(\n scope: MemoryScope,\n scopeId: string,\n context: WorkspaceContext,\n): MemoryObservationReference | null {\n switch (scope) {\n case 'product':\n return null\n case 'suite':\n return resolveReference('suite', context.suiteMetadataById.get(scopeId))\n case 'test':\n return resolveReference('test', context.testMetadataById.get(scopeId))\n }\n}\n\nfunction resolveReference(\n kind: MemoryObservationReference['kind'],\n metadata: WorkspaceEntityMetadata | undefined,\n): MemoryObservationReference | null {\n if (!metadata) {\n return null\n }\n\n return {\n kind,\n id: metadata.id,\n label: metadata.label,\n targetName: metadata.targetName,\n href: metadata.href,\n }\n}\n\nexport function isValidMemoryScopeId(value: string): boolean {\n return value.trim().length > 0 && !/\\.\\./.test(value) && !/[/\\\\]/.test(value) && !/\\0/.test(value)\n}\n","import { readFile, writeFile, mkdir, rm, stat } from 'node:fs/promises'\nimport { dirname, basename } from 'node:path'\nimport { generateTestId } from '@vostride/agent-qa-ids'\nimport { parse as parseYaml } from 'yaml'\nimport {\n discoverWorkspaceFiles,\n resolveWorkspaceFileTarget,\n type ResolvedWorkspacePaths,\n} from '@vostride/agent-qa-core'\n\nexport interface TestFileInfo {\n path: string\n name: string\n testId: string | null\n targetName: string | null\n platform: string | null\n modified: string\n}\n\nexport type SupportedPlatform = 'web' | 'android' | 'ios'\n\nexport interface TestFileMetadata {\n name: string | null\n testId: string | null\n targetName: string | null\n platform: SupportedPlatform | null\n parallel: boolean | null\n}\n\nexport interface TestValidationError {\n message: string\n line?: number\n column?: number\n suggestion?: string\n}\n\nexport interface TestValidationResult {\n valid: boolean\n errors: TestValidationError[]\n}\n\nfunction normalizeQuotedString(value: string): string {\n return value.trim().replace(/^[\"'](.*)[\"']$/, '$1')\n}\n\nfunction normalizePlatform(value: unknown): SupportedPlatform | null {\n if (value !== 'web' && value !== 'android' && value !== 'ios') return null\n return value\n}\n\nexport function extractTestFileMetadata(content: string): TestFileMetadata {\n let parsed: Record<string, unknown> | null = null\n\n try {\n const yamlValue = parseYaml(content)\n if (yamlValue && typeof yamlValue === 'object' && !Array.isArray(yamlValue)) {\n parsed = yamlValue as Record<string, unknown>\n }\n } catch {\n // fall back to regex extraction for partially-authored files\n }\n\n const config = parsed?.config\n const parsedConfig = config && typeof config === 'object' && !Array.isArray(config)\n ? config as Record<string, unknown>\n : null\n const use = parsed?.use\n const parsedUse = use && typeof use === 'object' && !Array.isArray(use)\n ? use as Record<string, unknown>\n : null\n\n const nameMatch = content.match(/^name:\\s*(.+)$/m)\n const targetMatch = content.match(/^\\s*target:\\s*(.+)$/m)\n const testIdMatch = content.match(/^test-id:\\s*(.+)$/m)\n const platformMatch = content.match(/^\\s*platform:\\s*(web|android|ios)\\s*$/m)\n const parallelMatch = content.match(/^\\s*parallel:\\s*(true|false)\\s*$/m)\n\n const name = typeof parsed?.name === 'string' && parsed.name.trim().length > 0\n ? parsed.name.trim()\n : nameMatch\n ? normalizeQuotedString(nameMatch[1])\n : null\n\n const targetName = typeof parsed?.target === 'string' && parsed.target.trim().length > 0\n ? parsed.target.trim()\n : targetMatch\n ? normalizeQuotedString(targetMatch[1])\n : null\n\n const testId = typeof parsed?.['test-id'] === 'string' && parsed['test-id'].trim().length > 0\n ? parsed['test-id'].trim()\n : testIdMatch\n ? normalizeQuotedString(testIdMatch[1])\n : null\n\n const platform = normalizePlatform(parsed?.platform)\n ?? normalizePlatform(parsedConfig?.platform)\n ?? normalizePlatform(platformMatch?.[1])\n\n const parallel = typeof parsedUse?.parallel === 'boolean'\n ? parsedUse.parallel\n : typeof parsed?.parallel === 'boolean'\n ? parsed.parallel\n : typeof parsedConfig?.parallel === 'boolean'\n ? parsedConfig.parallel\n : parallelMatch\n ? parallelMatch[1] === 'true'\n : null\n\n return {\n name,\n testId,\n targetName,\n platform,\n parallel,\n }\n}\n\nexport class TestFileManager {\n constructor(private readonly workspace: ResolvedWorkspacePaths) {}\n\n async list(): Promise<TestFileInfo[]> {\n const records = await discoverWorkspaceFiles({ workspace: this.workspace, kind: 'test' })\n const files: TestFileInfo[] = []\n\n for (const record of records) {\n try {\n const s = await stat(record.absolutePath)\n if (s.isFile()) {\n let testName = basename(record.workspaceRelativePath)\n let platform: string | null = null\n let targetName: string | null = null\n let testId: string | null = null\n try {\n let content = await readFile(record.absolutePath, 'utf-8')\n const metadata = extractTestFileMetadata(content)\n if (metadata.name) testName = metadata.name\n if (metadata.targetName) targetName = metadata.targetName\n if (metadata.platform) platform = metadata.platform\n if (metadata.testId) {\n testId = metadata.testId\n } else {\n testId = generateTestId()\n content = `test-id: ${testId}\\n${content}`\n await writeFile(record.absolutePath, content, 'utf-8')\n }\n } catch { /* fall back to filename */ }\n files.push({\n path: record.workspaceRelativePath,\n name: testName,\n testId,\n targetName,\n platform,\n modified: s.mtime.toISOString(),\n })\n }\n } catch {\n // skip inaccessible files\n }\n }\n\n files.sort((a, b) => b.modified.localeCompare(a.modified))\n return files\n }\n\n async read(relativePath: string): Promise<string> {\n const target = await this.resolveTarget(relativePath, true)\n return readFile(target.absolutePath, 'utf-8')\n }\n\n async findByTestId(testId: string): Promise<{ path: string; content: string } | null> {\n const files = await this.list()\n const match = files.find(f => f.testId === testId)\n if (!match) return null\n const content = await this.read(match.path)\n return { path: match.path, content }\n }\n\n async write(relativePath: string, content: string): Promise<void> {\n const target = await this.resolveTarget(relativePath, false)\n await mkdir(dirname(target.absolutePath), { recursive: true })\n await writeFile(target.absolutePath, content, 'utf-8')\n }\n\n async delete(relativePath: string): Promise<void> {\n const target = await this.resolveTarget(relativePath, true)\n await rm(target.absolutePath)\n }\n\n async validate(content: string): Promise<TestValidationResult> {\n try {\n const { parseTestFile } = await import('@vostride/agent-qa-core')\n const result = parseTestFile(content, '<editor>')\n\n if (result.errors.length === 0) {\n return { valid: true, errors: [] }\n }\n\n return {\n valid: false,\n errors: result.errors.map(e => ({\n message: e.message,\n line: e.line,\n column: e.column,\n suggestion: e.suggestion,\n })),\n }\n } catch (err) {\n return {\n valid: false,\n errors: [{ message: err instanceof Error ? err.message : 'Failed to validate' }],\n }\n }\n }\n\n private async resolveTarget(relativePath: string, requireExisting: boolean) {\n return resolveWorkspaceFileTarget({\n workspace: this.workspace,\n kind: 'test',\n filePath: relativePath,\n requireExisting,\n })\n }\n}\n","import { mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises'\nimport { basename, dirname, isAbsolute, relative, resolve } from 'node:path'\n\nimport { HooksFileSchema, isPathInsideDir, parseHooksFile, resolveWorkspacePaths } from '@vostride/agent-qa-core'\nimport type { AgentQaConfig, HooksFileConfig } from '@vostride/agent-qa-core'\nimport { generateHookId } from '@vostride/agent-qa-ids'\nimport { parse as parseYaml, parseDocument } from 'yaml'\n\nimport type { ConfigManager } from '../config/config-manager.js'\nimport type {\n HookCatalogResponse,\n HookCatalogRow,\n HookDeleteResult,\n HookDetailResponse,\n HookDraftValidationResult,\n HookFieldError,\n HookFieldName,\n HookMutationRequest,\n HookPrepareResult,\n HookRegistryReadError,\n} from './hook-registry-types.js'\nimport { scanHookReferences } from './hook-reference-scan.js'\n\ntype ParsedHookDefinition = HooksFileConfig['hooks'][number]\ntype AuthoredHookDefinition = Omit<ParsedHookDefinition, 'timeout'> & {\n timeout: string\n}\ntype HooksFileParseData = { hooks: ParsedHookDefinition[] }\ntype ZodIssueLike = { path: PropertyKey[]; message: string }\n\ninterface HookRegistryLocation {\n filePath: string\n resolvedFilePath: string\n hooksBaseDir: string\n}\n\ninterface HookRegistryState extends HookRegistryLocation {\n hooks: ParsedHookDefinition[]\n errors: HookRegistryReadError[]\n missing: boolean\n}\n\ninterface HookRegistryMutationState extends HookRegistryLocation {\n hooks: AuthoredHookDefinition[]\n raw: string | null\n existed: boolean\n}\n\ninterface HookFileState {\n resolvedFilePath: string | null\n fileMissing: boolean\n fieldErrors: HookFieldError[]\n}\n\ninterface HookMutationResolvedPayload {\n hook: Record<string, unknown> & { id: string }\n source: string\n}\n\ninterface HookMutationPlan {\n nextHook: ParsedHookDefinition\n nextSourcePath: string\n oldSourcePath: string | null\n oldSourceContent: string | null\n oldSourceExisted: boolean\n removeOldSourcePath: boolean\n projectedHooks: AuthoredHookDefinition[]\n}\n\nclass HookRegistryMutationError extends Error {\n readonly code: string\n readonly fieldErrors: HookFieldError[]\n\n constructor(code: string, fieldErrors: HookFieldError[], message = code) {\n super(message)\n this.code = code\n this.fieldErrors = fieldErrors\n }\n}\n\nexport function isHookRegistryMutationError(error: unknown): error is {\n code: string\n fieldErrors: HookFieldError[]\n} {\n return error instanceof HookRegistryMutationError\n}\n\nexport class HookRegistryManager {\n constructor(\n private readonly configManager: ConfigManager,\n private readonly configPath: string,\n ) {}\n\n async readCatalog(): Promise<HookCatalogResponse> {\n const registry = await this.readRegistryState()\n if (registry.missing || registry.errors.length > 0) {\n return {\n hooks: [],\n filePath: registry.filePath,\n errors: registry.errors.map((error) => error.message),\n missing: registry.missing,\n }\n }\n\n const hooks = await Promise.all(\n registry.hooks.map(async (hook) => {\n const fileState = await this.inspectHookFile(hook.file, registry.hooksBaseDir)\n return this.toCatalogRow(hook, fileState.fileMissing)\n }),\n )\n\n return {\n hooks,\n filePath: registry.filePath,\n errors: [],\n missing: false,\n }\n }\n\n async readHook(hookId: string): Promise<HookDetailResponse | null> {\n const registry = await this.readRegistryState()\n if (registry.missing || registry.errors.length > 0) {\n return null\n }\n\n const hook = registry.hooks.find((candidate) => candidate.id === hookId)\n if (!hook) {\n return null\n }\n\n const fileState = await this.inspectHookFile(hook.file, registry.hooksBaseDir)\n let source: string | null = null\n\n if (fileState.resolvedFilePath && fileState.fieldErrors.length === 0) {\n source = await readFile(fileState.resolvedFilePath, 'utf-8')\n }\n\n return {\n hook: this.toCatalogRow(hook, fileState.fileMissing),\n source,\n fieldErrors: fileState.fieldErrors,\n }\n }\n\n async createHook(payload: HookMutationRequest): Promise<HookDetailResponse> {\n const registry = await this.readRegistryForMutation()\n const resolvedPayload = this.resolveMutationPayload(payload, {\n generatedId: generateHookId(),\n })\n const plan = await this.planHookMutation(registry, resolvedPayload.hook.id, resolvedPayload, 'create')\n\n await this.persistHookMutation(registry, plan, resolvedPayload.source)\n\n return {\n hook: this.toCatalogRow(plan.nextHook, false),\n source: resolvedPayload.source,\n fieldErrors: [],\n }\n }\n\n async updateHook(hookId: string, payload: HookMutationRequest): Promise<HookDetailResponse> {\n const registry = await this.readRegistryForMutation()\n const existingHook = registry.hooks.find((candidate) => candidate.id === hookId)\n if (!existingHook) {\n throw new HookRegistryMutationError('hook_not_found', [\n {\n field: 'id',\n code: 'hook_not_found',\n message: 'Hook not found',\n },\n ])\n }\n\n const resolvedPayload = this.resolveMutationPayload(payload, {\n expectedId: hookId,\n generatedId: hookId,\n })\n const plan = await this.planHookMutation(registry, hookId, resolvedPayload, 'update')\n\n await this.persistHookMutation(registry, plan, resolvedPayload.source)\n\n return {\n hook: this.toCatalogRow(plan.nextHook, false),\n source: resolvedPayload.source,\n fieldErrors: [],\n }\n }\n\n async deleteHook(\n hookId: string,\n options: { force?: boolean } = {},\n ): Promise<HookDeleteResult> {\n const registry = await this.readRegistryForMutation()\n const existingHook = registry.hooks.find((candidate) => candidate.id === hookId)\n if (!existingHook) {\n throw new HookRegistryMutationError('hook_not_found', [\n {\n field: 'id',\n code: 'hook_not_found',\n message: 'Hook not found',\n },\n ])\n }\n\n const references = await scanHookReferences(dirname(this.configPath), this.configPath, hookId)\n if (references.length > 0 && !options.force) {\n return {\n deleted: false,\n references,\n }\n }\n\n const nextHooks = registry.hooks.filter((candidate) => candidate.id !== hookId)\n const nextRegistryContent = nextHooks.length > 0\n ? this.serializeHooksDocument(registry.raw, nextHooks)\n : null\n const sourcePath = resolve(registry.hooksBaseDir, existingHook.file)\n const sourceSnapshot = await this.readOptionalFile(sourcePath)\n const sourcePathStillReferenced = nextHooks.some(\n (candidate) => resolve(registry.hooksBaseDir, candidate.file) === sourcePath,\n )\n\n try {\n if (nextRegistryContent === null) {\n await rm(registry.resolvedFilePath, { force: true })\n } else {\n await mkdir(dirname(registry.resolvedFilePath), { recursive: true })\n await writeFile(registry.resolvedFilePath, nextRegistryContent, 'utf-8')\n }\n\n if (sourceSnapshot.exists && !sourcePathStillReferenced) {\n await rm(sourcePath, { force: true })\n }\n\n return {\n deleted: true,\n references,\n }\n } catch (error) {\n await this.restoreRegistrySnapshot(registry)\n\n if (sourceSnapshot.exists && sourceSnapshot.content !== null) {\n await mkdir(dirname(sourcePath), { recursive: true })\n await writeFile(sourcePath, sourceSnapshot.content, 'utf-8')\n }\n\n throw error\n }\n }\n\n async validateDraft(draft: unknown): Promise<HookDraftValidationResult> {\n const location = await this.resolveRegistryLocation()\n const normalizedDraft = this.normalizeDraftForSchema(draft)\n const result = HooksFileSchema.safeParse(normalizedDraft)\n\n if (!result.success) {\n return {\n valid: false,\n fieldErrors: result.error.issues.map((issue: ZodIssueLike) => this.toValidationFieldError(issue.path, issue.message)),\n warnings: [],\n }\n }\n const hooksFile = result.data as HooksFileParseData\n\n const fieldErrors: HookFieldError[] = []\n const warnings: HookFieldError[] = []\n\n for (const hook of hooksFile.hooks) {\n if (isAbsolute(hook.file)) {\n fieldErrors.push({\n field: 'file',\n code: 'absolute_path',\n message: 'Hook file must be relative to the configured hooks file',\n })\n continue\n }\n\n if (!isPathInsideDir(hook.file, location.hooksBaseDir)) {\n fieldErrors.push({\n field: 'file',\n code: 'unsafe_path',\n message: 'Hook file must stay inside the configured hooks file directory',\n })\n continue\n }\n\n const fileState = await this.inspectHookFile(hook.file, location.hooksBaseDir)\n warnings.push(...fileState.fieldErrors.filter((error) => error.code === 'file_missing'))\n }\n\n return {\n valid: fieldErrors.length === 0,\n fieldErrors,\n warnings,\n }\n }\n\n async prepareForExecution(): Promise<HookPrepareResult> {\n const registry = await this.readRegistryState()\n if (registry.missing) {\n return {\n resolvedHooks: new Map(),\n authoringIssuesById: new Map(),\n }\n }\n\n if (registry.errors.length > 0) {\n return {\n resolvedHooks: new Map(),\n hookRegistryError: registry.errors.map((error) => error.message).join('; '),\n authoringIssuesById: new Map(),\n }\n }\n\n const parsedHooks = await parseHooksFile(registry.resolvedFilePath)\n if (parsedHooks.errors.length > 0) {\n return {\n resolvedHooks: new Map(),\n hookRegistryError: parsedHooks.errors.join('; '),\n authoringIssuesById: new Map(),\n }\n }\n\n const resolvedHooksById = new Map(parsedHooks.hooks.map((hook) => [hook.id, hook]))\n const resolvedHooks = new Map<typeof resolvedHooksById extends Map<infer K, infer V> ? K : never, typeof resolvedHooksById extends Map<infer K, infer V> ? V : never>()\n const authoringIssuesById = new Map<string, HookFieldError[]>()\n\n for (const hook of registry.hooks) {\n const fileState = await this.inspectHookFile(hook.file, registry.hooksBaseDir)\n const resolvedHook = resolvedHooksById.get(hook.id)\n if (!resolvedHook) {\n continue\n }\n\n if (fileState.fieldErrors.length > 0) {\n authoringIssuesById.set(hook.id, fileState.fieldErrors)\n continue\n }\n\n resolvedHooks.set(hook.id, resolvedHook)\n }\n\n return {\n resolvedHooks,\n authoringIssuesById,\n }\n }\n\n private async readRegistryForMutation(): Promise<HookRegistryMutationState> {\n const location = await this.resolveRegistryLocation()\n\n let raw: string | null = null\n try {\n raw = await readFile(location.resolvedFilePath, 'utf-8')\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n ...location,\n hooks: [],\n raw: null,\n existed: false,\n }\n }\n throw error\n }\n\n let parsed: unknown\n try {\n parsed = parseYaml(raw)\n } catch (error: unknown) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_registry',\n message: `Invalid YAML in hooks file: ${(error as Error).message}`,\n },\n ])\n }\n\n const result = HooksFileSchema.safeParse(parsed)\n if (!result.success) {\n throw new HookRegistryMutationError(\n 'validation_failed',\n result.error.issues.map((issue: ZodIssueLike) => this.toValidationFieldError(issue.path, issue.message)),\n )\n }\n\n const hooksFile = result.data as HooksFileParseData\n const pathErrors = hooksFile.hooks.flatMap((hook, index) => {\n const error = this.getAuthoredPathReadError(hook.file, location.hooksBaseDir, index)\n return error ? [this.toMutationFieldError(error)] : []\n })\n if (pathErrors.length > 0) {\n throw new HookRegistryMutationError('validation_failed', pathErrors)\n }\n\n return {\n ...location,\n hooks: this.toAuthoredHookDefinitions(parsed, hooksFile.hooks),\n raw,\n existed: true,\n }\n }\n\n private resolveMutationPayload(\n payload: HookMutationRequest,\n options: { expectedId?: string; generatedId: string },\n ): HookMutationResolvedPayload {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_payload',\n message: 'Hook mutation payload is required',\n },\n ])\n }\n\n if (typeof payload.source !== 'string') {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_source',\n message: 'Hook source must be a string',\n },\n ])\n }\n\n const hookValue = payload.hook\n if (!hookValue || typeof hookValue !== 'object' || Array.isArray(hookValue)) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_hook',\n message: 'Hook payload is required',\n },\n ])\n }\n\n const providedId = typeof hookValue.id === 'string' && hookValue.id.trim().length > 0\n ? hookValue.id.trim()\n : undefined\n if (options.expectedId && providedId && providedId !== options.expectedId) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'id',\n code: 'id_mismatch',\n message: 'Hook id in body must match the route parameter',\n },\n ])\n }\n\n return {\n hook: {\n id: providedId ?? options.generatedId,\n name: hookValue.name as string,\n runtime: hookValue.runtime as ParsedHookDefinition['runtime'],\n file: hookValue.file as string,\n timeout: hookValue.timeout as string | number,\n network: hookValue.network as boolean | undefined,\n },\n source: payload.source,\n }\n }\n\n private async planHookMutation(\n registry: HookRegistryMutationState,\n hookId: string,\n payload: HookMutationResolvedPayload,\n mode: 'create' | 'update',\n ): Promise<HookMutationPlan> {\n const existingHook = mode === 'update'\n ? registry.hooks.find((candidate) => candidate.id === hookId) ?? null\n : null\n\n const projectedHooks: Array<Record<string, unknown> | AuthoredHookDefinition> = mode === 'update'\n ? [...registry.hooks.filter((candidate) => candidate.id !== hookId), payload.hook]\n : [...registry.hooks, payload.hook]\n const validated = this.validateProjectedHooks(projectedHooks, registry.hooksBaseDir)\n if (!validated.valid) {\n throw new HookRegistryMutationError('validation_failed', validated.fieldErrors)\n }\n\n const nextHook = validated.parsedHooks.find((candidate) => candidate.id === payload.hook.id)\n if (!nextHook) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_registry',\n message: 'Hook could not be projected into the configured hooks file',\n },\n ])\n }\n\n const nextSourcePath = resolve(registry.hooksBaseDir, nextHook.file)\n const oldSourcePath = existingHook ? resolve(registry.hooksBaseDir, existingHook.file) : null\n const oldSourceSnapshot = existingHook && oldSourcePath\n ? await this.readOptionalFile(oldSourcePath)\n : { exists: false, content: null as string | null }\n\n if (mode === 'create') {\n const nextExists = await this.readOptionalFile(nextSourcePath)\n if (nextExists.exists) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'file',\n code: 'collision',\n message: 'Hook file already exists at that path',\n },\n ])\n }\n }\n\n if (mode === 'update' && oldSourcePath !== nextSourcePath) {\n const nextExists = await this.readOptionalFile(nextSourcePath)\n if (nextExists.exists) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'file',\n code: 'collision',\n message: 'Hook file already exists at that path',\n },\n ])\n }\n }\n\n return {\n nextHook,\n nextSourcePath,\n oldSourcePath,\n oldSourceContent: oldSourceSnapshot.content,\n oldSourceExisted: oldSourceSnapshot.exists,\n removeOldSourcePath: Boolean(\n oldSourcePath &&\n oldSourcePath !== nextSourcePath &&\n oldSourceSnapshot.exists &&\n !validated.authoredHooks.some(\n (candidate) =>\n candidate.id !== hookId &&\n resolve(registry.hooksBaseDir, candidate.file) === oldSourcePath,\n ),\n ),\n projectedHooks: validated.authoredHooks,\n }\n }\n\n private validateProjectedHooks(\n hooks: Array<Record<string, unknown> | AuthoredHookDefinition>,\n hooksBaseDir: string,\n ): {\n valid: boolean\n parsedHooks: ParsedHookDefinition[]\n authoredHooks: AuthoredHookDefinition[]\n fieldErrors: HookFieldError[]\n } {\n const rawFieldErrors = this.collectRawHookFieldErrors(hooks, hooksBaseDir)\n const normalizedDraft = this.normalizeDraftForSchema({ hooks })\n const result = HooksFileSchema.safeParse(normalizedDraft)\n\n if (!result.success) {\n return {\n valid: false,\n parsedHooks: [],\n authoredHooks: [],\n fieldErrors: this.dedupeFieldErrors([\n ...rawFieldErrors,\n ...result.error.issues.map((issue: ZodIssueLike) => this.toValidationFieldError(issue.path, issue.message)),\n ]),\n }\n }\n\n const hooksFile = result.data as HooksFileParseData\n const pathErrors = hooksFile.hooks.flatMap((hook, index) => {\n const error = this.getAuthoredPathReadError(hook.file, hooksBaseDir, index)\n return error ? [this.toMutationFieldError(error)] : []\n })\n\n return {\n valid: pathErrors.length === 0,\n parsedHooks: hooksFile.hooks,\n authoredHooks: this.toAuthoredHookDefinitions({ hooks }, hooksFile.hooks),\n fieldErrors: this.dedupeFieldErrors([\n ...rawFieldErrors,\n ...pathErrors,\n ]),\n }\n }\n\n private async persistHookMutation(\n registry: HookRegistryMutationState,\n plan: HookMutationPlan,\n source: string,\n ): Promise<void> {\n const nextRegistryContent = this.serializeHooksDocument(registry.raw, plan.projectedHooks)\n\n try {\n await mkdir(dirname(plan.nextSourcePath), { recursive: true })\n await writeFile(plan.nextSourcePath, source, 'utf-8')\n await mkdir(dirname(registry.resolvedFilePath), { recursive: true })\n await writeFile(registry.resolvedFilePath, nextRegistryContent, 'utf-8')\n\n if (plan.removeOldSourcePath && plan.oldSourcePath) {\n await rm(plan.oldSourcePath)\n }\n } catch (error) {\n await this.restoreRegistrySnapshot(registry)\n await this.restoreSourceSnapshot(plan)\n throw error\n }\n }\n\n private async restoreRegistrySnapshot(registry: HookRegistryMutationState): Promise<void> {\n if (!registry.existed || registry.raw === null) {\n await rm(registry.resolvedFilePath, { force: true })\n return\n }\n\n await writeFile(registry.resolvedFilePath, registry.raw, 'utf-8')\n }\n\n private async restoreSourceSnapshot(plan: HookMutationPlan): Promise<void> {\n if (plan.oldSourcePath === plan.nextSourcePath) {\n if (plan.oldSourceExisted && plan.oldSourceContent !== null) {\n await mkdir(dirname(plan.nextSourcePath), { recursive: true })\n await writeFile(plan.nextSourcePath, plan.oldSourceContent, 'utf-8')\n return\n }\n\n await rm(plan.nextSourcePath, { force: true })\n return\n }\n\n await rm(plan.nextSourcePath, { force: true })\n }\n\n private serializeHooksDocument(\n raw: string | null,\n hooks: AuthoredHookDefinition[],\n ): string {\n const doc = parseDocument(raw ?? '{}')\n doc.setIn(['hooks'], doc.createNode(hooks))\n return doc.toString()\n }\n\n private async readOptionalFile(path: string): Promise<{ exists: boolean; content: string | null }> {\n try {\n return {\n exists: true,\n content: await readFile(path, 'utf-8'),\n }\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n exists: false,\n content: null,\n }\n }\n throw error\n }\n }\n\n private collectRawHookFieldErrors(\n hooks: Array<Record<string, unknown> | AuthoredHookDefinition>,\n hooksBaseDir: string,\n ): HookFieldError[] {\n const fieldErrors: HookFieldError[] = []\n const ids = new Set<string>()\n const names = new Set<string>()\n\n for (const hook of hooks) {\n if (!hook || typeof hook !== 'object' || Array.isArray(hook)) {\n continue\n }\n\n const hookRecord = hook as Record<string, unknown>\n if (typeof hookRecord.id === 'string') {\n if (ids.has(hookRecord.id)) {\n fieldErrors.push({\n field: 'id',\n code: 'duplicate_id',\n message: `Duplicate hook id: \"${hookRecord.id}\"`,\n })\n } else {\n ids.add(hookRecord.id)\n }\n }\n\n if (typeof hookRecord.name === 'string') {\n if (names.has(hookRecord.name)) {\n fieldErrors.push({\n field: 'name',\n code: 'duplicate_name',\n message: `Duplicate hook name: \"${hookRecord.name}\"`,\n })\n } else {\n names.add(hookRecord.name)\n }\n }\n\n if (typeof hookRecord.file === 'string') {\n if (isAbsolute(hookRecord.file)) {\n fieldErrors.push({\n field: 'file',\n code: 'absolute_path',\n message: 'Hook file must be relative to the configured hooks file',\n })\n } else if (!isPathInsideDir(hookRecord.file, hooksBaseDir)) {\n fieldErrors.push({\n field: 'file',\n code: 'unsafe_path',\n message: 'Hook file must stay inside the configured hooks file directory',\n })\n }\n }\n }\n\n return fieldErrors\n }\n\n private dedupeFieldErrors(fieldErrors: HookFieldError[]): HookFieldError[] {\n const seen = new Set<string>()\n return fieldErrors.filter((error) => {\n const key = `${error.field}:${error.code}:${error.message}`\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n }\n\n private async readRegistryState(): Promise<HookRegistryState> {\n const location = await this.resolveRegistryLocation()\n\n try {\n await stat(location.resolvedFilePath)\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n ...location,\n hooks: [],\n errors: [{ code: 'hooks_file_missing', message: `configured hooks file not found: ${location.filePath}` }],\n missing: true,\n }\n }\n throw err\n }\n\n const raw = await readFile(location.resolvedFilePath, 'utf-8')\n\n let parsed: unknown\n try {\n parsed = parseYaml(raw)\n } catch (err: unknown) {\n return {\n ...location,\n hooks: [],\n errors: [{ code: 'invalid_yaml', message: `Invalid YAML in hooks file: ${(err as Error).message}` }],\n missing: false,\n }\n }\n\n const result = HooksFileSchema.safeParse(parsed)\n if (!result.success) {\n return {\n ...location,\n hooks: [],\n errors: result.error.issues.map((issue: ZodIssueLike) => ({\n code: 'invalid_registry',\n message: `${issue.path.map(String).join('.')}: ${issue.message}`,\n })),\n missing: false,\n }\n }\n\n const hooksFile = result.data as HooksFileParseData\n const pathErrors = hooksFile.hooks\n .map((hook, index) => this.getAuthoredPathReadError(hook.file, location.hooksBaseDir, index))\n .filter((error): error is HookRegistryReadError => error !== null)\n\n if (pathErrors.length > 0) {\n return {\n ...location,\n hooks: [],\n errors: pathErrors,\n missing: false,\n }\n }\n\n return {\n ...location,\n hooks: hooksFile.hooks,\n errors: [],\n missing: false,\n }\n }\n\n private async resolveRegistryLocation(): Promise<HookRegistryLocation> {\n const config = await this.configManager.read() as AgentQaConfig\n const workspacePaths = resolveWorkspacePaths({ config, configPath: this.configPath })\n const configuredPath = workspacePaths.hooksFile.configuredPath\n const resolvedFilePath = workspacePaths.hooksFile.absolutePath\n\n return {\n filePath: this.toDisplayPath(configuredPath, resolvedFilePath),\n resolvedFilePath,\n hooksBaseDir: dirname(resolvedFilePath),\n }\n }\n\n private getAuthoredPathReadError(filePath: string, hooksBaseDir: string, index: number): HookRegistryReadError | null {\n if (isAbsolute(filePath)) {\n return {\n code: 'absolute_path',\n message: `hooks.${index}.file: Hook file must be relative to the configured hooks file`,\n }\n }\n\n if (!isPathInsideDir(filePath, hooksBaseDir)) {\n return {\n code: 'unsafe_path',\n message: `hooks.${index}.file: Hook file must stay inside the configured hooks file directory`,\n }\n }\n\n return null\n }\n\n private async inspectHookFile(filePath: string, hooksBaseDir: string): Promise<HookFileState> {\n if (isAbsolute(filePath) || !isPathInsideDir(filePath, hooksBaseDir)) {\n return {\n resolvedFilePath: null,\n fileMissing: true,\n fieldErrors: [\n {\n field: 'file',\n code: 'unsafe_path',\n message: 'Hook file must stay inside the configured hooks file directory',\n },\n ],\n }\n }\n\n const resolvedFilePath = resolve(hooksBaseDir, filePath)\n try {\n await stat(resolvedFilePath)\n return {\n resolvedFilePath,\n fileMissing: false,\n fieldErrors: [],\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n resolvedFilePath: null,\n fileMissing: true,\n fieldErrors: [\n {\n field: 'file',\n code: 'file_missing',\n message: 'Hook file missing',\n },\n ],\n }\n }\n throw err\n }\n }\n\n private normalizeDraftForSchema(draft: unknown): unknown {\n const rawHooks = this.getRawHooksFromDraft(draft)\n if (rawHooks === null) {\n return draft\n }\n\n return {\n ...(draft as Record<string, unknown>),\n hooks: rawHooks.map((hook) => {\n if (!hook || typeof hook !== 'object' || Array.isArray(hook)) {\n return hook\n }\n\n const hookRecord = hook as Record<string, unknown>\n return {\n ...hookRecord,\n timeout: this.normalizeTimeoutValue(hookRecord.timeout),\n }\n }),\n }\n }\n\n private toAuthoredHookDefinitions(\n draft: unknown,\n parsedHooks: ParsedHookDefinition[],\n ): AuthoredHookDefinition[] {\n const rawHooks = this.getRawHooksFromDraft(draft) ?? []\n return parsedHooks.map((hook, index) => this.toAuthoredHookDefinition(rawHooks[index], hook))\n }\n\n private toAuthoredHookDefinition(\n rawHook: unknown,\n parsedHook: ParsedHookDefinition,\n ): AuthoredHookDefinition {\n const rawTimeout = rawHook && typeof rawHook === 'object' && !Array.isArray(rawHook)\n ? (rawHook as Record<string, unknown>).timeout\n : parsedHook.timeout\n const normalizedTimeout = this.normalizeTimeoutValue(rawTimeout)\n\n return {\n ...parsedHook,\n timeout: typeof normalizedTimeout === 'string'\n ? normalizedTimeout\n : this.formatDurationToken(parsedHook.timeout),\n }\n }\n\n private getRawHooksFromDraft(draft: unknown): unknown[] | null {\n if (!draft || typeof draft !== 'object' || Array.isArray(draft)) {\n return null\n }\n\n const hooks = (draft as { hooks?: unknown }).hooks\n return Array.isArray(hooks) ? hooks : null\n }\n\n private normalizeTimeoutValue(timeout: unknown): unknown {\n if (typeof timeout === 'number') {\n return this.formatDurationToken(timeout)\n }\n\n if (typeof timeout !== 'string') {\n return timeout\n }\n\n const trimmedTimeout = timeout.trim()\n if (trimmedTimeout.length === 0) {\n return trimmedTimeout\n }\n\n if (/^\\d+$/.test(trimmedTimeout)) {\n return this.formatDurationToken(Number.parseInt(trimmedTimeout, 10))\n }\n\n const millisecondTimeout = trimmedTimeout.match(/^(\\d+)ms$/i)\n if (millisecondTimeout) {\n return this.formatDurationToken(Number.parseInt(millisecondTimeout[1], 10))\n }\n\n return trimmedTimeout\n }\n\n private formatDurationToken(durationMs: number): string {\n if (!Number.isFinite(durationMs) || durationMs < 0) {\n return `${durationMs}`\n }\n\n if (durationMs === 0) {\n return '0ms'\n }\n\n const durationUnits = [\n { suffix: 'd', value: 86_400_000 },\n { suffix: 'h', value: 3_600_000 },\n { suffix: 'm', value: 60_000 },\n { suffix: 's', value: 1_000 },\n ] as const\n\n for (const unit of durationUnits) {\n if (durationMs % unit.value === 0) {\n return `${durationMs / unit.value}${unit.suffix}`\n }\n }\n\n return `${durationMs}ms`\n }\n\n private toValidationFieldError(path: PropertyKey[], message: string): HookFieldError {\n const field = this.getFieldName(path)\n\n if (field === 'id' && message.includes('Duplicate hook id')) {\n return { field, code: 'duplicate_id', message }\n }\n\n if (field === 'name' && message.includes('Duplicate hook name')) {\n return { field, code: 'duplicate_name', message }\n }\n\n if (field === 'runtime') {\n return { field, code: 'invalid_runtime', message }\n }\n\n if (field === 'timeout') {\n return { field, code: 'invalid_timeout', message }\n }\n\n if (field === 'network') {\n return { field, code: 'invalid_network', message }\n }\n\n if (field === 'file') {\n return { field, code: 'invalid_file', message }\n }\n\n if (field === 'id') {\n return { field, code: 'invalid_id', message }\n }\n\n if (field === 'name') {\n return { field, code: 'invalid_name', message }\n }\n\n return { field, code: 'invalid_registry', message }\n }\n\n private toMutationFieldError(error: HookRegistryReadError): HookFieldError {\n if (error.code === 'absolute_path') {\n return {\n field: 'file',\n code: 'absolute_path',\n message: 'Hook file must be relative to the configured hooks file',\n }\n }\n\n if (error.code === 'unsafe_path') {\n return {\n field: 'file',\n code: 'unsafe_path',\n message: 'Hook file must stay inside the configured hooks file directory',\n }\n }\n\n return {\n field: 'registry',\n code: error.code,\n message: error.message,\n }\n }\n\n private getFieldName(path: PropertyKey[]): HookFieldName {\n const field = path[path.length - 1]\n if (\n field === 'id' ||\n field === 'name' ||\n field === 'runtime' ||\n field === 'file' ||\n field === 'timeout' ||\n field === 'network'\n ) {\n return field\n }\n\n return 'registry'\n }\n\n private toCatalogRow(hook: ParsedHookDefinition, fileMissing: boolean): HookCatalogRow {\n return {\n id: hook.id,\n name: hook.name,\n runtime: hook.runtime,\n file: hook.file,\n timeout: hook.timeout,\n network: hook.network,\n fileMissing,\n }\n }\n\n private toDisplayPath(configuredPath: string, resolvedFilePath: string): string {\n if (!isAbsolute(configuredPath)) {\n return configuredPath\n }\n\n const relativeToConfig = relative(dirname(this.configPath), resolvedFilePath)\n if (relativeToConfig && !relativeToConfig.startsWith('..') && !isAbsolute(relativeToConfig)) {\n return relativeToConfig.startsWith('.') ? relativeToConfig : `./${relativeToConfig}`\n }\n\n return `./${basename(resolvedFilePath)}`\n }\n}\n","import { readFile } from 'node:fs/promises'\nimport { basename } from 'node:path'\n\nimport {\n AgentQaConfigSchema,\n discoverWorkspaceFiles,\n resolveWorkspacePaths,\n type WorkspaceFileRecord,\n} from '@vostride/agent-qa-core'\nimport { parse as parseYaml } from 'yaml'\n\nimport type { HookDeleteReference } from './hook-registry-types.js'\n\nconst HOOK_INLINE_RE = /\\{\\{runHook:\"([^\"]+)\"\\}\\}/g\n\nfunction getLabel(parsed: unknown, filePath: string): string {\n if (parsed && typeof parsed === 'object' && typeof (parsed as { name?: unknown }).name === 'string') {\n const name = (parsed as { name: string }).name.trim()\n if (name.length > 0) {\n return name\n }\n }\n\n return basename(filePath)\n}\n\nfunction collectHookListReferences(\n parsed: Record<string, unknown>,\n filePath: string,\n label: string,\n kind: 'test' | 'suite',\n key: 'setup' | 'teardown',\n hookId: string,\n): HookDeleteReference[] {\n const entries = parsed[key]\n if (!Array.isArray(entries)) {\n return []\n }\n\n return entries.flatMap((entry) => {\n if (entry !== hookId) {\n return []\n }\n\n return [{\n kind,\n label,\n path: filePath,\n context: key,\n }]\n })\n}\n\nfunction collectInlineReferences(\n parsed: Record<string, unknown>,\n filePath: string,\n label: string,\n hookId: string,\n): HookDeleteReference[] {\n const steps = parsed.steps\n if (!Array.isArray(steps)) {\n return []\n }\n\n return steps.flatMap((entry, index) => {\n const text = typeof entry === 'string'\n ? entry\n : entry && typeof entry === 'object' && typeof (entry as { step?: unknown }).step === 'string'\n ? (entry as { step: string }).step\n : null\n\n if (!text) {\n return []\n }\n\n const matches = [...text.matchAll(HOOK_INLINE_RE)]\n if (!matches.some((match) => match[1] === hookId)) {\n return []\n }\n\n return [{\n kind: 'inline-runHook',\n label,\n path: filePath,\n context: typeof entry === 'string' ? `steps[${index}]` : `steps[${index}].step`,\n }]\n })\n}\n\nasync function scanYamlFile(\n record: WorkspaceFileRecord,\n hookId: string,\n): Promise<HookDeleteReference[]> {\n let parsed: unknown\n\n try {\n parsed = parseYaml(await readFile(record.absolutePath, 'utf-8'))\n } catch {\n return []\n }\n\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return []\n }\n\n const parsedRecord = parsed as Record<string, unknown>\n const label = getLabel(parsed, record.workspaceRelativePath)\n const kind = record.kind\n\n return [\n ...collectHookListReferences(parsedRecord, record.workspaceRelativePath, label, kind, 'setup', hookId),\n ...collectHookListReferences(parsedRecord, record.workspaceRelativePath, label, kind, 'teardown', hookId),\n ...collectInlineReferences(parsedRecord, record.workspaceRelativePath, label, hookId),\n ]\n}\n\nfunction dedupeReferences(references: HookDeleteReference[]): HookDeleteReference[] {\n const seen = new Set<string>()\n\n return references.filter((reference) => {\n const key = `${reference.kind}:${reference.path}:${reference.context}:${reference.label}`\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n}\n\nexport async function scanHookReferences(\n _workspaceDir: string,\n configPath: string,\n hookId: string,\n): Promise<HookDeleteReference[]> {\n let parsedConfig: unknown\n\n try {\n parsedConfig = parseYaml(await readFile(configPath, 'utf-8'))\n } catch {\n return []\n }\n\n const configResult = AgentQaConfigSchema.safeParse(parsedConfig)\n if (!configResult.success) {\n return []\n }\n\n const workspace = resolveWorkspacePaths({ config: configResult.data, configPath })\n const records = await Promise.all([\n discoverWorkspaceFiles({ workspace, kind: 'test' }),\n discoverWorkspaceFiles({ workspace, kind: 'suite' }),\n ])\n const references = await Promise.all(\n records\n .flat()\n .sort((left, right) => left.workspaceRelativePath.localeCompare(right.workspaceRelativePath))\n .map((record) => scanYamlFile(record, hookId)),\n )\n\n return dedupeReferences(references.flat()).sort((left, right) =>\n left.path.localeCompare(right.path) ||\n left.context.localeCompare(right.context) ||\n left.kind.localeCompare(right.kind) ||\n left.label.localeCompare(right.label),\n )\n}\n","import type { IncomingMessage } from 'node:http'\n\nconst DEFAULT_MAX_BYTES = 1024 * 1024 // 1MB\n\nexport function readJsonBody<T>(req: IncomingMessage, maxBytes = DEFAULT_MAX_BYTES): Promise<T> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = []\n let totalBytes = 0\n\n req.on('data', (chunk: Buffer) => {\n totalBytes += chunk.length\n if (totalBytes > maxBytes) {\n req.destroy()\n reject(new Error(`Body exceeds maximum size of ${maxBytes} bytes`))\n return\n }\n chunks.push(chunk)\n })\n\n req.on('end', () => {\n const body = Buffer.concat(chunks).toString('utf-8')\n if (!body) {\n reject(new Error('Empty request body'))\n return\n }\n try {\n resolve(JSON.parse(body) as T)\n } catch {\n reject(new Error('Invalid JSON in request body'))\n }\n })\n\n req.on('error', (err) => {\n reject(err)\n })\n })\n}\n","import { EventEmitter } from 'node:events'\nimport { spawn, execSync, type ChildProcess } from 'node:child_process'\nimport treeKill from 'tree-kill'\nimport type { ExecutionBackend, ExecuteOptions } from './execution-backend.js'\n\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 10_000\nconst DEFAULT_STALE_THRESHOLD_MS = 30_000\nconst PROCESS_TERMINATION_GRACE_MS = 5_000\nconst HANDLE_RETENTION_MS = 5 * 60 * 1000\n\nexport interface LiveExecutionEvent {\n id: number\n type: string\n [key: string]: unknown\n}\n\nexport interface TestRunHandle {\n runId: string\n process: ChildProcess\n status: 'running' | 'completed' | 'failed' | 'cancelled' | 'timeout'\n output: string[]\n startedAt: Date\n lastEventAt: number\n completionReason?: string\n}\n\nexport class TestRunner extends EventEmitter implements ExecutionBackend {\n private cliBin: string\n private defaultTimeout: number | undefined\n private handles = new Map<string, TestRunHandle>()\n private eventBuffers = new Map<string, LiveExecutionEvent[]>()\n private eventCounters = new Map<string, number>()\n private onProcessClose?: (runId: string, status: 'completed' | 'failed' | 'cancelled' | 'timeout') => void\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null\n private heartbeatIntervalMs: number\n private staleThresholdMs: number\n\n constructor(opts: {\n cliBin: string\n defaultTimeout?: number\n onProcessClose?: (runId: string, status: 'completed' | 'failed' | 'cancelled' | 'timeout') => void\n heartbeatIntervalMs?: number\n staleThresholdMs?: number\n }) {\n super()\n this.cliBin = opts.cliBin\n this.defaultTimeout = opts.defaultTimeout\n this.onProcessClose = opts.onProcessClose\n this.heartbeatIntervalMs = opts.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS\n this.staleThresholdMs = Math.max(\n opts.staleThresholdMs ?? DEFAULT_STALE_THRESHOLD_MS,\n this.heartbeatIntervalMs + 1,\n )\n }\n\n static resolveCliBin(): string {\n const envBin = process.env.AGENT_QA_CLI_BIN\n if (envBin) return envBin\n\n try {\n const which = execSync('which agent-qa', { encoding: 'utf-8' }).trim()\n if (which) return which\n } catch {\n // not found in PATH\n }\n\n return './node_modules/.bin/agent-qa'\n }\n\n execute(opts: ExecuteOptions): void {\n const spawnArgs = ['run', ...opts.args]\n const maxRetries = opts.maxRetries ?? 0\n\n const env: Record<string, string | undefined> = {\n ...process.env,\n ...opts.env,\n AGENT_QA_LIVE_EVENTS: 'true',\n }\n if (opts.attributes) {\n env.AGENT_QA_RUN_ATTRIBUTES_JSON = JSON.stringify(opts.attributes)\n }\n\n if (opts.source === 'suite') {\n // Suites create their own parent row via DashboardReporter.onSuiteStart\n // Pass the enqueued run ID so the suite can update it instead of creating a duplicate\n env.AGENT_QA_SUITE_QUEUE_ID = opts.runId\n } else if (maxRetries > 0) {\n // Retry-enabled: parent run stays in 'running', reporter creates child runs\n env.AGENT_QA_PARENT_RUN_ID = opts.runId\n env.AGENT_QA_MAX_RETRIES = String(maxRetries)\n } else {\n // No retries: reporter updates the existing run row directly\n env.AGENT_QA_RUN_ID = opts.runId\n }\n\n const child = spawn(this.cliBin, spawnArgs, {\n stdio: ['ignore', 'pipe', 'pipe'],\n env,\n detached: process.platform !== 'win32',\n })\n\n const handle: TestRunHandle = {\n runId: opts.runId,\n process: child,\n status: 'running',\n output: [],\n startedAt: new Date(),\n lastEventAt: Date.now(),\n }\n this.handles.set(opts.runId, handle)\n this.eventBuffers.set(opts.runId, [])\n this.eventCounters.set(opts.runId, 0)\n\n this.startHeartbeatChecker()\n\n const processTimeoutMs = opts.timeout ?? this.defaultTimeout\n let forceKillTimer: ReturnType<typeof setTimeout> | null = null\n const timer = typeof processTimeoutMs === 'number' && Number.isFinite(processTimeoutMs) && processTimeoutMs > 0\n ? setTimeout(() => {\n if (handle.status !== 'running') return\n handle.status = 'timeout'\n handle.completionReason = `process timeout after ${processTimeoutMs}ms`\n this.signalHandle(handle, 'SIGTERM')\n forceKillTimer = setTimeout(() => {\n this.signalHandle(handle, 'SIGKILL')\n }, PROCESS_TERMINATION_GRACE_MS)\n forceKillTimer.unref()\n }, processTimeoutMs)\n : null\n timer?.unref()\n\n this.pushEvent(opts.runId, { type: 'run-start', runId: opts.runId, status: 'running' })\n\n let stdoutBuffer = ''\n // Capture the actual test result status from the reporter (test-complete event).\n // This is the ground truth — process exit code can be misleading (e.g., mobile\n // tests exit non-zero from Appium cleanup even when all steps pass).\n let testResultStatus: string | undefined\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdoutBuffer += chunk.toString()\n const lines = stdoutBuffer.split('\\n')\n stdoutBuffer = lines.pop() ?? ''\n\n for (const line of lines) {\n if (!line) continue\n if (line.startsWith('AGENT_QA_EVENT:')) {\n try {\n const payload = JSON.parse(line.slice('AGENT_QA_EVENT:'.length))\n handle.lastEventAt = Date.now()\n if (payload.type === 'test-complete' && payload.status) {\n testResultStatus = payload.status\n }\n this.pushEvent(opts.runId, payload)\n } catch {\n handle.output.push(line)\n this.emit('output', opts.runId, line)\n }\n } else {\n handle.output.push(line)\n this.emit('output', opts.runId, line)\n }\n }\n })\n\n child.stderr?.on('data', (chunk: Buffer) => {\n const lines = chunk.toString().split('\\n').filter(Boolean)\n for (const line of lines) {\n handle.output.push(line)\n }\n })\n\n child.on('close', (code) => {\n if (timer) clearTimeout(timer)\n if (forceKillTimer) clearTimeout(forceKillTimer)\n if (stdoutBuffer) {\n if (stdoutBuffer.startsWith('AGENT_QA_EVENT:')) {\n try {\n const payload = JSON.parse(stdoutBuffer.slice('AGENT_QA_EVENT:'.length))\n if (payload.type === 'test-complete' && payload.status) {\n testResultStatus = payload.status\n }\n this.pushEvent(opts.runId, payload)\n } catch {\n handle.output.push(stdoutBuffer)\n }\n } else {\n handle.output.push(stdoutBuffer)\n }\n stdoutBuffer = ''\n }\n\n if (handle.status !== 'timeout' && handle.status !== 'cancelled' && handle.status !== 'failed') {\n // Use the actual test result from the reporter (test-complete event) as\n // ground truth. A clean process exit without reporter completion is incomplete.\n if (testResultStatus) {\n handle.status = testResultStatus === 'passed'\n ? 'completed'\n : testResultStatus === 'cancelled'\n ? 'cancelled'\n : 'failed'\n } else {\n handle.status = 'failed'\n handle.completionReason = 'process exited before test completed'\n }\n }\n\n const duration = Date.now() - handle.startedAt.getTime()\n this.pushEvent(opts.runId, {\n type: 'run-complete',\n runId: opts.runId,\n status: handle.status,\n duration,\n ...(handle.completionReason ? { reason: handle.completionReason } : {}),\n })\n\n if (this.onProcessClose) {\n this.onProcessClose(opts.runId, handle.status)\n }\n\n const cleanupTimer = setTimeout(() => {\n this.handles.delete(opts.runId)\n this.eventBuffers.delete(opts.runId)\n this.eventCounters.delete(opts.runId)\n }, HANDLE_RETENTION_MS)\n cleanupTimer.unref()\n })\n }\n\n getBufferedEvents(runId: string): LiveExecutionEvent[] {\n return this.eventBuffers.get(runId) ?? []\n }\n\n getHandle(runId: string): TestRunHandle | undefined {\n return this.handles.get(runId)\n }\n\n getActiveExecutions(): { runId: string; status: string; startedAt: string; duration: number; testName?: string }[] {\n const active: { runId: string; status: string; startedAt: string; duration: number; testName?: string }[] = []\n for (const handle of this.handles.values()) {\n if (handle.status === 'running') {\n const events = this.eventBuffers.get(handle.runId) ?? []\n const testStart = events.find(e => e.type === 'test-start')\n active.push({\n runId: handle.runId,\n status: handle.status,\n startedAt: handle.startedAt.toISOString(),\n duration: Date.now() - handle.startedAt.getTime(),\n testName: testStart?.testName as string | undefined,\n })\n }\n }\n return active\n }\n\n kill(runId: string): boolean {\n const handle = this.handles.get(runId)\n if (handle && handle.status === 'running') {\n this.signalHandle(handle, 'SIGINT')\n const forceTimer = setTimeout(() => {\n this.signalHandle(handle, 'SIGKILL')\n }, PROCESS_TERMINATION_GRACE_MS)\n forceTimer.unref()\n handle.process.once('close', () => clearTimeout(forceTimer))\n handle.status = 'cancelled'\n return true\n }\n return false\n }\n\n killAll(): void {\n for (const handle of this.handles.values()) {\n if (handle.status === 'running') {\n handle.status = 'cancelled'\n this.signalHandle(handle, 'SIGKILL')\n }\n }\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer)\n this.heartbeatTimer = null\n }\n }\n\n private startHeartbeatChecker(): void {\n if (this.heartbeatTimer) return\n this.heartbeatTimer = setInterval(() => {\n for (const handle of this.handles.values()) {\n if (handle.status !== 'running') continue\n if (Date.now() - handle.lastEventAt > this.staleThresholdMs) {\n handle.status = 'failed'\n handle.completionReason = 'stale process — no heartbeat'\n this.signalHandle(handle, 'SIGKILL')\n }\n }\n }, this.heartbeatIntervalMs)\n this.heartbeatTimer.unref()\n }\n\n private pushEvent(runId: string, payload: Record<string, unknown>): void {\n const counter = (this.eventCounters.get(runId) ?? 0) + 1\n this.eventCounters.set(runId, counter)\n\n const event: LiveExecutionEvent = { ...payload, id: counter } as LiveExecutionEvent\n const buffer = this.eventBuffers.get(runId)\n if (buffer) {\n buffer.push(event)\n }\n this.emit('execution-event', runId, event)\n }\n\n private signalHandle(handle: TestRunHandle, signal: NodeJS.Signals): void {\n const pid = handle.process.pid\n if (!pid) return\n\n if (process.platform === 'win32') {\n treeKill(pid, signal, () => {})\n return\n }\n\n try {\n process.kill(-pid, signal)\n return\n } catch {\n // Fall back to direct child signaling when the process group is unavailable.\n }\n\n try {\n handle.process.kill(signal)\n return\n } catch {\n // Fall back to tree-kill as a last resort.\n }\n\n treeKill(pid, signal, () => {})\n }\n}\n","import { EventEmitter } from 'node:events'\nimport { cpus } from 'node:os'\nimport type { RunArtifactKind, RunAttributes } from '@vostride/agent-qa-core'\nimport type { DashboardDatabase, RunRow } from '../db/database.js'\n\ninterface EnqueueOptions {\n name: string\n filePath?: string\n kind?: RunArtifactKind\n attributes?: RunAttributes\n priority?: number\n platform?: string\n testFileContent?: string\n modelName?: string\n llmProvider?: string\n metadata?: Record<string, unknown>\n parallel?: boolean\n}\n\nexport class JobQueue extends EventEmitter {\n private db: DashboardDatabase\n private pollInterval: ReturnType<typeof setInterval> | null = null\n private isProcessing = false\n private concurrency: number\n private activeCount = 0\n private activePlatforms = new Set<string>()\n private activeRuns = new Map<string, { platform: string }>()\n\n constructor(opts: { db: DashboardDatabase; concurrency?: number }) {\n super()\n this.db = opts.db\n this.concurrency = opts.concurrency ?? cpus().length\n }\n\n start(intervalMs = 1000): void {\n this.pollInterval = setInterval(() => this.processNext(), intervalMs)\n this.on('enqueued', () => this.processNext())\n }\n\n stop(): void {\n if (this.pollInterval) {\n clearInterval(this.pollInterval)\n this.pollInterval = null\n }\n this.removeAllListeners('enqueued')\n }\n\n enqueue(opts: EnqueueOptions): string {\n const runId = this.db.insertPendingRun({\n name: opts.name,\n filePath: opts.filePath,\n attributes: opts.attributes,\n priority: opts.priority ?? 0,\n platform: opts.platform,\n testFileContent: opts.testFileContent,\n modelName: opts.modelName,\n llmProvider: opts.llmProvider,\n metadata: opts.metadata,\n parallel: opts.parallel,\n })\n this.db.insertRunArtifact({\n runId,\n kind: opts.kind ?? 'test',\n payload: {\n runtime: {\n platform: opts.platform ?? 'web',\n queued: true,\n },\n source: {\n name: opts.name,\n filePath: opts.filePath ?? null,\n loadStatus: 'queued',\n },\n metadata: {\n ...opts.metadata,\n attributes: opts.attributes ?? {},\n },\n },\n })\n this.emit('enqueued', runId)\n return runId\n }\n\n processNext(): void {\n if (this.isProcessing) return\n this.isProcessing = true\n try {\n while (true) {\n const next = this.findNextEligible()\n if (!next) break\n\n const isParallel = Boolean(next.parallel)\n const platform = next.platform ?? 'web'\n const isMobile = platform === 'ios' || platform === 'android'\n\n this.activeCount++\n if (isMobile) this.activePlatforms.add(platform)\n this.activeRuns.set(next.id, { platform })\n\n this.db.updateRunStatus(next.id, 'running')\n this.db.updateRun(next.id, { startedAt: new Date().toISOString() })\n this.emit('execute', next)\n\n // Sequential jobs get exclusive access — stop filling slots after dequeue\n if (!isParallel && !isMobile) break\n }\n } finally {\n this.isProcessing = false\n }\n }\n\n onSlotFreed(runId: string): void {\n const info = this.activeRuns.get(runId)\n if (!info) return\n this.activeCount--\n if (info.platform === 'ios' || info.platform === 'android') {\n this.activePlatforms.delete(info.platform)\n }\n this.activeRuns.delete(runId)\n this.processNext()\n }\n\n getActiveCount(): number {\n return this.activeCount\n }\n\n getConcurrency(): number {\n return this.concurrency\n }\n\n cancel(runId: string): boolean {\n const run = this.db.getRun(runId)\n if (!run) return false\n const now = new Date().toISOString()\n if (run.status === 'pending') {\n this.db.updateRun(runId, { status: 'cancelled', endedAt: now })\n this.cancelChildRuns(runId, now)\n this.db.finalizeRunArtifact(runId, {\n errors: [{ code: 'cancelled', phase: 'queue', message: 'Run cancelled before execution' }],\n runtime: { status: 'cancelled' },\n })\n return true\n }\n if (run.status === 'running') {\n this.db.updateRun(runId, { status: 'cancelled', endedAt: now })\n this.cancelChildRuns(runId, now)\n try {\n const artifact = this.db.getRunArtifact(runId)\n if (artifact && !artifact.finalizedAt) {\n this.db.finalizeRunArtifact(runId, {\n errors: [{ code: 'cancelled', phase: 'queue', message: 'Run cancellation requested' }],\n runtime: { status: 'cancelled' },\n })\n }\n } catch { /* cancellation still proceeds */ }\n this.emit('cancel-running', runId)\n return true\n }\n return false\n }\n\n private cancelChildRuns(parentRunId: string, endedAt: string): void {\n for (const child of this.db.getRunsByParent(parentRunId)) {\n if (child.status !== 'running' && child.status !== 'pending') continue\n this.db.updateRun(child.id, {\n status: 'cancelled',\n endedAt,\n failureSummary: 'Run cancelled by user',\n })\n try {\n const artifact = this.db.getRunArtifact(child.id)\n if (artifact && !artifact.finalizedAt) {\n this.db.finalizeRunArtifact(child.id, {\n errors: [{ code: 'cancelled', phase: 'queue', message: 'Run cancelled by user' }],\n runtime: { status: 'cancelled' },\n })\n }\n } catch { /* best-effort child cancellation */ }\n }\n }\n\n private findNextEligible(): RunRow | undefined {\n if (this.activeCount >= this.concurrency) return undefined\n\n const pending = this.db.getPendingRuns()\n for (const run of pending) {\n const isParallel = Boolean(run.parallel)\n const platform = run.platform ?? 'web'\n const isMobile = platform === 'ios' || platform === 'android'\n\n if (isMobile) {\n // Mobile: needs a slot AND its platform not already active\n // parallel flag is ignored — mobile tests serialize per platform via device mutex\n if (this.activePlatforms.has(platform)) continue\n return run\n }\n\n if (!isParallel) {\n // Sequential web: needs ALL slots free (exclusive access)\n if (this.activeCount > 0) continue\n return run\n }\n\n // Parallel web: just needs an available slot\n return run\n }\n\n return undefined\n }\n}\n","import { readFile, writeFile, mkdir, stat, rm } from 'node:fs/promises'\nimport { dirname, basename } from 'node:path'\nimport { generateSuiteId } from '@vostride/agent-qa-ids'\nimport { parse as parseYaml } from 'yaml'\nimport { discoverWorkspaceFiles, resolveWorkspaceFileTarget, SuiteDefinitionSchema } from '@vostride/agent-qa-core'\nimport type { ResolvedWorkspacePaths, SuiteDefinition } from '@vostride/agent-qa-core'\nimport type { TestFileManager } from './test-file-manager.js'\n\ninterface SuiteFileInfo {\n path: string\n suiteId: string | null\n name: string\n testCount: number\n modified: string\n platform: string | null\n}\n\ninterface SuiteValidationResult {\n valid: boolean\n errors: { message: string; line?: number; column?: number; suggestion?: string }[]\n missingTests?: Array<{ index: number; test: string; id: string }>\n}\n\nexport class SuiteFileManager {\n private testFileManager: TestFileManager | undefined\n\n constructor(\n private readonly workspace: ResolvedWorkspacePaths,\n testFileManager?: TestFileManager,\n ) {\n this.testFileManager = testFileManager\n }\n\n async list(): Promise<SuiteFileInfo[]> {\n const records = await discoverWorkspaceFiles({ workspace: this.workspace, kind: 'suite' })\n const files: SuiteFileInfo[] = []\n\n for (const record of records) {\n try {\n const s = await stat(record.absolutePath)\n if (s.isFile()) {\n let suiteName = basename(record.workspaceRelativePath)\n let testCount = 0\n let platform: string | null = null\n let suiteId: string | null = null\n try {\n let content = await readFile(record.absolutePath, 'utf-8')\n const parsed = parseYaml(content)\n if (parsed?.name) suiteName = parsed.name\n if (Array.isArray(parsed?.tests)) testCount = parsed.tests.length\n platform = parsed?.config?.platform ?? null\n const suiteIdMatch = content.match(/^suite-id:\\s*(.+)$/m)\n if (suiteIdMatch) {\n suiteId = suiteIdMatch[1].trim().replace(/^[\"'](.*)[\"']$/, '$1')\n } else {\n suiteId = generateSuiteId()\n content = `suite-id: ${suiteId}\\n${content}`\n await writeFile(record.absolutePath, content, 'utf-8')\n }\n } catch { /* fall back to filename */ }\n files.push({\n path: record.workspaceRelativePath,\n suiteId,\n name: suiteName,\n testCount,\n modified: s.mtime.toISOString(),\n platform,\n })\n }\n } catch {\n // skip inaccessible files\n }\n }\n\n files.sort((a, b) => b.modified.localeCompare(a.modified))\n return files\n }\n\n async findBySuiteId(suiteId: string): Promise<{ path: string; content: string } | null> {\n const files = await this.list()\n const match = files.find(f => f.suiteId === suiteId)\n if (!match) return null\n const content = await this.read(match.path)\n return { path: match.path, content }\n }\n\n async resolvePath(filePath: string, requireExisting = true): Promise<{ storagePath: string; executionPath: string }> {\n const trimmedPath = filePath.trim()\n if (!trimmedPath) {\n throw new Error('Suite path is required')\n }\n\n const target = await resolveWorkspaceFileTarget({\n workspace: this.workspace,\n kind: 'suite',\n filePath: trimmedPath,\n requireExisting,\n })\n return { storagePath: target.workspaceRelativePath, executionPath: target.absolutePath }\n }\n\n async read(relativePath: string): Promise<string> {\n const target = await this.resolveTarget(relativePath, true)\n return readFile(target.absolutePath, 'utf-8')\n }\n\n async write(relativePath: string, content: string): Promise<void> {\n const target = await this.resolveTarget(relativePath, false)\n await mkdir(dirname(target.absolutePath), { recursive: true })\n await writeFile(target.absolutePath, content, 'utf-8')\n }\n\n async delete(relativePath: string): Promise<void> {\n const target = await this.resolveTarget(relativePath, true)\n await rm(target.absolutePath)\n }\n\n async validate(content: string): Promise<SuiteValidationResult> {\n try {\n const parsed = parseYaml(content)\n const result = SuiteDefinitionSchema.safeParse(parsed)\n\n if (!result.success) {\n return {\n valid: false,\n errors: result.error.issues.map((issue: { path: PropertyKey[]; message: string }) => ({\n message: `${issue.path.map(String).join('.')}: ${issue.message}`,\n })),\n }\n }\n\n // Save-time fail-fast: verify every referenced test path resolves (Phase 181 D-32/D-33)\n if (this.testFileManager) {\n const suite = result.data as SuiteDefinition\n const available = await this.testFileManager.list()\n const availablePaths = new Set(available.map((f) => f.path))\n const missingTests: Array<{ index: number; test: string; id: string }> = []\n suite.tests.forEach((entry: SuiteDefinition['tests'][number], index: number) => {\n if (!availablePaths.has(entry.test)) {\n // Report the ORIGINAL entry.test so the user sees what they wrote\n missingTests.push({ index, test: entry.test, id: entry.id })\n }\n })\n if (missingTests.length > 0) {\n return {\n valid: false,\n errors: [{\n message: `Cannot save — referenced tests not found: ${missingTests.map(m => m.test).join(', ')}`,\n }],\n missingTests,\n }\n }\n }\n\n return { valid: true, errors: [] }\n } catch (err) {\n return {\n valid: false,\n errors: [{ message: err instanceof Error ? err.message : 'Failed to parse YAML' }],\n }\n }\n }\n\n private async resolveTarget(relativePath: string, requireExisting: boolean) {\n return resolveWorkspaceFileTarget({\n workspace: this.workspace,\n kind: 'suite',\n filePath: relativePath,\n requireExisting,\n })\n }\n}\n","import { readFile, writeFile, mkdir } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport { parseDocument, stringify, type Document } from 'yaml'\n\nconst SENSITIVE_KEYS = new Set(['apikey', 'token', 'key', 'accesskey'])\n\nfunction isSensitiveKey(key: string): boolean {\n return SENSITIVE_KEYS.has(key.toLowerCase())\n}\n\nfunction maskValue(value: string): string {\n if (value.length >= 8) {\n return value.slice(0, 3) + '****...' + value.slice(-4)\n }\n return '****'\n}\n\nfunction deepMask(obj: unknown, parentKey = ''): unknown {\n if (typeof obj === 'string' && isSensitiveKey(parentKey)) {\n return maskValue(obj)\n }\n if (Array.isArray(obj)) {\n return obj.map((item, i) => deepMask(item, String(i)))\n }\n if (typeof obj === 'object' && obj !== null) {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[key] = deepMask(value, key)\n }\n return result\n }\n return obj\n}\n\nexport class ConfigManager {\n constructor(private configPath: string) {}\n\n async read(): Promise<Record<string, unknown>> {\n try {\n const content = await readFile(this.configPath, 'utf-8')\n const doc = parseDocument(content)\n return (doc.toJSON() as Record<string, unknown>) ?? {}\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return {}\n throw err\n }\n }\n\n async readMasked(): Promise<Record<string, unknown>> {\n const config = await this.read()\n return deepMask(config) as Record<string, unknown>\n }\n\n private sectionPath(section: string): string[] {\n return section.includes('.') ? section.split('.') : [section]\n }\n\n async updateSection(section: string, value: Record<string, unknown>): Promise<void> {\n const path = this.sectionPath(section)\n let content: string\n try {\n content = await readFile(this.configPath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n await mkdir(dirname(this.configPath), { recursive: true })\n await writeFile(this.configPath, stringify({ [section]: value }))\n return\n }\n throw err\n }\n\n const doc = parseDocument(content)\n for (const [key, val] of Object.entries(value)) {\n doc.setIn([...path, key], val)\n }\n await writeFile(this.configPath, doc.toString())\n }\n\n async replaceSection(section: string, value: Record<string, unknown>): Promise<void> {\n const path = this.sectionPath(section)\n let content: string\n try {\n content = await readFile(this.configPath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n await mkdir(dirname(this.configPath), { recursive: true })\n await writeFile(this.configPath, stringify({ [section]: value }))\n return\n }\n throw err\n }\n const doc = parseDocument(content)\n // Overwrite in-place to preserve key ordering in the YAML file\n doc.setIn(path, doc.createNode(value))\n await writeFile(this.configPath, doc.toString())\n }\n\n async replaceSectionRaw(section: string, value: unknown): Promise<void> {\n const path = this.sectionPath(section)\n let content: string\n try {\n content = await readFile(this.configPath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n await mkdir(dirname(this.configPath), { recursive: true })\n await writeFile(this.configPath, stringify({ [section]: value }))\n return\n }\n throw err\n }\n const doc = parseDocument(content)\n // Overwrite in-place to preserve key ordering in the YAML file\n doc.setIn(path, doc.createNode(value))\n await writeFile(this.configPath, doc.toString())\n }\n\n async deleteSectionRaw(section: string): Promise<void> {\n const path = this.sectionPath(section)\n let content: string\n try {\n content = await readFile(this.configPath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n await mkdir(dirname(this.configPath), { recursive: true })\n await writeFile(this.configPath, stringify({}))\n return\n }\n throw err\n }\n const doc = parseDocument(content)\n doc.deleteIn(path)\n await writeFile(this.configPath, doc.toString())\n }\n\n async readDocument(): Promise<Document> {\n const content = await readFile(this.configPath, 'utf-8')\n return parseDocument(content)\n }\n}\n","import { request } from 'node:http'\nimport { spawn, type ChildProcess } from 'node:child_process'\nimport {\n formatAppiumInstallGuidance,\n resolveAppiumExecutable,\n type ResolvedAppiumExecutable,\n} from '@vostride/agent-qa-core'\nimport treeKill from 'tree-kill'\nimport pc from 'picocolors'\n\nconst APPIUM_PREFIX = pc.magenta('[appium]')\n\nexport interface AppiumLeaseOwner {\n runId: string\n platform: 'android' | 'ios'\n}\n\nexport interface AppiumLease extends AppiumLeaseOwner {\n acquiredAt: string\n}\n\nexport class AppiumManager {\n private process: ChildProcess | null = null\n private port: number\n private ready = false\n private startPromise: Promise<void> | null = null\n private managed = false\n private startupTimeoutMs: number\n private pollIntervalMs: number\n private anonymousRefCount = 0\n private leases = new Map<string, AppiumLease>()\n private logLevel: 'normal' | 'debug'\n private appiumResolver: () => ResolvedAppiumExecutable\n\n constructor(opts?: {\n port?: number\n startupTimeoutMs?: number\n pollIntervalMs?: number\n logLevel?: 'normal' | 'debug'\n appiumResolver?: () => ResolvedAppiumExecutable\n }) {\n this.port = opts?.port ?? 4723\n this.startupTimeoutMs = opts?.startupTimeoutMs ?? 30_000\n this.pollIntervalMs = opts?.pollIntervalMs ?? 500\n this.logLevel = opts?.logLevel ?? 'normal'\n this.appiumResolver = opts?.appiumResolver ?? resolveAppiumExecutable\n }\n\n async acquire(): Promise<void> {\n await this.ensureRunning()\n this.anonymousRefCount++\n }\n\n release(): void {\n if (this.anonymousRefCount > 0) this.anonymousRefCount--\n this.maybeShutdownAfterRelease()\n }\n\n async acquireLease(owner: AppiumLeaseOwner): Promise<void> {\n await this.ensureRunning()\n if (!this.leases.has(owner.runId)) {\n this.leases.set(owner.runId, {\n runId: owner.runId,\n platform: owner.platform,\n acquiredAt: new Date().toISOString(),\n })\n }\n console.log(`${APPIUM_PREFIX} lease acquired run=${owner.runId} platform=${owner.platform} leases=${this.getLeaseCount()} managed=${this.managed}`)\n }\n\n releaseLease(runId: string, reason = 'completed'): boolean {\n const lease = this.leases.get(runId)\n if (!lease) return false\n\n this.leases.delete(runId)\n console.log(`${APPIUM_PREFIX} lease released run=${runId} platform=${lease.platform} reason=${reason} leases=${this.getLeaseCount()} managed=${this.managed}`)\n this.maybeShutdownAfterRelease()\n return true\n }\n\n releaseAllLeases(reason = 'shutdown'): string[] {\n const runIds = [...this.leases.keys()]\n for (const runId of runIds) {\n this.releaseLease(runId, reason)\n }\n return runIds\n }\n\n async ensureRunning(): Promise<void> {\n if (this.ready) {\n const still = await this.checkStatus()\n if (still) return\n this.ready = false\n }\n\n if (this.startPromise) {\n await this.startPromise\n return\n }\n\n this.startPromise = (async () => {\n const alive = await this.checkStatus()\n if (alive) {\n this.ready = true\n this.managed = false\n return\n }\n await this.startAndWait()\n })()\n\n try {\n await this.startPromise\n } finally {\n this.startPromise = null\n }\n }\n\n async checkStatus(): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n const req = request(\n {\n hostname: 'localhost',\n port: this.port,\n path: '/status',\n method: 'GET',\n timeout: 3000,\n },\n (res) => {\n let data = ''\n res.on('data', (chunk: Buffer) => {\n data += chunk.toString()\n })\n res.on('end', () => {\n try {\n const parsed = JSON.parse(data)\n resolve(parsed?.value?.ready === true)\n } catch {\n resolve(false)\n }\n })\n },\n )\n req.on('error', () => resolve(false))\n req.on('timeout', () => {\n req.destroy()\n resolve(false)\n })\n req.end()\n })\n }\n\n private async startAndWait(): Promise<void> {\n const appium = this.appiumResolver()\n const child = spawn(appium.command, ['-p', String(this.port), '--relaxed-security', '--log-no-colors'], {\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n\n this.process = child\n this.managed = true\n\n child.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'ENOENT') {\n console.error(`${APPIUM_PREFIX} Appium not found. ${formatAppiumInstallGuidance()}`)\n } else {\n console.error(`${APPIUM_PREFIX} Error: ${err.message}`)\n }\n })\n\n child.stdout?.on('data', (chunk: Buffer) => {\n if (this.logLevel !== 'debug') return\n const lines = chunk.toString().split('\\n').filter(Boolean)\n for (const line of lines) {\n console.log(`${APPIUM_PREFIX} ${pc.dim(line)}`)\n }\n })\n\n child.stderr?.on('data', (chunk: Buffer) => {\n if (this.logLevel !== 'debug') return\n const lines = chunk.toString().split('\\n').filter(Boolean)\n for (const line of lines) {\n console.error(`${APPIUM_PREFIX} ${pc.dim(line)}`)\n }\n })\n\n const start = Date.now()\n while (Date.now() - start < this.startupTimeoutMs) {\n const ok = await this.checkStatus()\n if (ok) {\n this.ready = true\n console.log(`${APPIUM_PREFIX} ${pc.green(`started on :${this.port}`)}`)\n return\n }\n await new Promise((r) => setTimeout(r, this.pollIntervalMs))\n }\n\n // Timeout — kill and throw\n if (child.pid) {\n treeKill(child.pid, 'SIGKILL', () => {})\n }\n this.process = null\n this.managed = false\n throw new Error(`Appium server did not become ready within ${this.startupTimeoutMs}ms`)\n }\n\n private performShutdown(): void {\n if (this.process?.pid && this.managed) {\n treeKill(this.process.pid, 'SIGKILL', () => {})\n console.log(`${APPIUM_PREFIX} ${pc.yellow('stopped')}`)\n }\n this.process = null\n this.ready = false\n this.managed = false\n }\n\n private maybeShutdownAfterRelease(): void {\n if (this.getRefCount() > 0) {\n console.log(`${APPIUM_PREFIX} server kept alive leases=${this.getLeaseCount()} managed=${this.managed}`)\n return\n }\n if (this.managed) {\n this.performShutdown()\n return\n }\n if (this.ready) {\n console.log(`${APPIUM_PREFIX} external server left running leases=0 managed=false`)\n }\n }\n\n shutdown(): void {\n this.anonymousRefCount = 0\n this.leases.clear()\n this.performShutdown()\n }\n\n getUrl(): string {\n return `http://localhost:${this.port}`\n }\n\n getPort(): number {\n return this.port\n }\n\n isManaged(): boolean {\n return this.managed\n }\n\n getRefCount(): number {\n return this.anonymousRefCount + this.leases.size\n }\n\n getLeaseCount(): number {\n return this.leases.size\n }\n\n getLeases(): AppiumLease[] {\n return [...this.leases.values()]\n }\n\n hasLease(runId: string): boolean {\n return this.leases.has(runId)\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { LiveSession } from './live-session.js'\nimport type { SessionState, LiveSessionConfig, EntityRef } from './types.js'\nimport type { AppiumManager } from '../execution/appium-manager.js'\nimport type { ConfigManager } from '../config/index.js'\n\nexport interface SessionManagerDeps {\n appiumManager?: AppiumManager\n configManager?: ConfigManager\n configPath?: string\n}\n\nexport class SessionManager {\n private sessions = new Map<string, LiveSession>()\n // Per-entity counter keyed by `${entityType}:${entityId}`.\n // Monotonic and ephemeral: resets on server restart per CONTEXT D-30.\n // Never decremented on terminate — a re-open of a terminated entity yields\n // the next number so \"Session #3\" after \"#2\" ends does not confuse users.\n private counters = new Map<string, number>()\n\n constructor(private deps: SessionManagerDeps = {}) {}\n\n async createSession(\n config: LiveSessionConfig,\n entity?: EntityRef,\n ): Promise<{ sessionId: string; sessionNumber: number | null }> {\n if (!config.llmConfig) {\n throw new Error('LLM not configured')\n }\n\n const sessionId = randomUUID()\n const session = new LiveSession(sessionId, this.deps)\n await session.initialize(config)\n this.sessions.set(sessionId, session)\n\n // sessionNumber is used for display only; never for authorization lookups\n // (always use sessionId UUID for that — see threat T-181.1-07).\n let sessionNumber: number | null = null\n if (entity && entity.id) {\n const key = `${entity.type}:${entity.id}`\n sessionNumber = (this.counters.get(key) ?? 0) + 1\n this.counters.set(key, sessionNumber)\n }\n\n return { sessionId, sessionNumber }\n }\n\n getSession(sessionId: string): LiveSession | undefined {\n return this.sessions.get(sessionId)\n }\n\n listSessions(): SessionState[] {\n return Array.from(this.sessions.values()).map(s => s.getState())\n }\n\n async terminateSession(sessionId: string): Promise<boolean> {\n const session = this.sessions.get(sessionId)\n if (!session) return false\n await session.cleanup()\n this.sessions.delete(sessionId)\n // Note: `counters` intentionally left untouched — per D-30 the counter is\n // monotonic per-restart.\n return true\n }\n\n async cleanupAll(): Promise<void> {\n for (const session of this.sessions.values()) {\n try { await session.cleanup() } catch {}\n }\n this.sessions.clear()\n }\n\n getCounter(entity: EntityRef): number {\n return this.counters.get(`${entity.type}:${entity.id}`) ?? 0\n }\n\n get size(): number {\n return this.sessions.size\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { dirname, resolve as resolvePath } from 'node:path'\nimport {\n AUTH_STATE_SCHEMA_VERSION,\n executeStep,\n createModel,\n getProviderOptions,\n LLMPlanner,\n LLMVerifier,\n VariableStore,\n interpolateVariables,\n findUnresolvedTemplates,\n parseHookInline,\n stripHookInline,\n runHooks,\n runHookInSandbox,\n MobileSetupError,\n readAuthStateMetadata,\n redactAuthStateValue,\n resolveAuthStatePaths,\n resolveSecretTemplatesInValue,\n writeAuthStateFiles,\n} from '@vostride/agent-qa-core'\nimport type {\n AgentLoopConfig,\n AuthStateMetadata,\n StepContext,\n PlatformAdapter,\n PlatformConfig,\n StepResult,\n StepPhaseEvent,\n HookDefinition,\n MobilePlatform,\n SecretRedactor,\n SecretStore,\n} from '@vostride/agent-qa-core'\nimport type { LanguageModel } from 'ai'\nimport { prepareMobileLiveSession } from './mobile-bootstrap.js'\nimport type { MobileLiveAppiumLease } from './mobile-bootstrap.js'\nimport type { AppiumManager } from '../execution/appium-manager.js'\nimport type { ConfigManager } from '../config/index.js'\nimport type {\n SessionState,\n LiveDraftMetadata,\n LiveExecutionLog,\n LiveHookOwner,\n LiveSessionConfig,\n LiveStepResultPayload,\n LiveSubActionData,\n LiveHookPayload,\n LiveTestExecutionPayload,\n LiveTestResultPayload,\n LiveTestStepPayload,\n ServerMessage,\n} from './types.js'\n\nconst IDLE_TIMEOUT_MS = 5 * 60 * 1000\n\nconst RUNJS_DBL_RE = /\\{\\{runJS:\"((?:[^\"\\\\]|\\\\.)*)\"\\}\\}/g\nconst RUNJS_SGL_RE = /\\{\\{runJS:'((?:[^'\\\\]|\\\\.)*)'\\}\\}/g\n\nexport interface LiveSessionDeps {\n appiumManager?: AppiumManager\n configManager?: ConfigManager\n configPath?: string\n}\n\nexport interface LiveStepExecutionResult extends StepResult {\n executionLogs?: LiveExecutionLog[]\n subActionsData?: LiveSubActionData[]\n}\n\ninterface WebStorageStateContext {\n storageState(options?: { indexedDB?: boolean }): Promise<unknown>\n}\n\ninterface WebStorageStatePage {\n context(): WebStorageStateContext\n}\n\n// Shared with ws-handler.ts toStepResultPayload. Kept in-module so that\n// executeTestCommand can assemble its stepResults array without a\n// cross-module import that would create a circular dependency.\nfunction toStepResultPayload(result: LiveStepExecutionResult): LiveStepResultPayload {\n const status = result.status === 'passed'\n ? 'passed'\n : result.status === 'cancelled'\n ? 'cancelled'\n : 'failed'\n\n return {\n status,\n duration: result.duration,\n error: result.error,\n capturedVariables: result.capturedVariables,\n variableSnapshot: result.variableSnapshot,\n originalStepName: result.originalStepName,\n consoleLogs: result.consoleLogs,\n networkLogs: result.networkLogs,\n executionLogs: result.executionLogs,\n subActionsData: result.subActionsData,\n }\n}\n\ninterface RunJSMatch {\n fullMatch: string\n code: string\n}\n\nfunction parseRunJSInline(text: string): RunJSMatch[] {\n const matches: RunJSMatch[] = []\n for (const match of text.matchAll(RUNJS_DBL_RE)) {\n matches.push({ fullMatch: match[0], code: match[1] })\n }\n for (const match of text.matchAll(RUNJS_SGL_RE)) {\n matches.push({ fullMatch: match[0], code: match[1] })\n }\n return matches.sort((a, b) => text.indexOf(a.fullMatch) - text.indexOf(b.fullMatch))\n}\n\nfunction coerceRunJSResult(value: unknown): string {\n if (value === undefined) return 'undefined'\n if (value === null) return 'null'\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n return String(value)\n }\n return JSON.stringify(value)\n}\n\nfunction getWebStorageStateContext(adapter: PlatformAdapter | null): WebStorageStateContext | null {\n if (!adapter || !('getPage' in adapter)) return null\n const page = (adapter as { getPage?: () => unknown }).getPage?.()\n if (!page || typeof page !== 'object') return null\n\n const contextFactory = (page as Partial<WebStorageStatePage>).context\n if (typeof contextFactory !== 'function') return null\n\n const context = contextFactory.call(page)\n if (!context || typeof context !== 'object') return null\n\n const storageState = (context as Partial<WebStorageStateContext>).storageState\n if (typeof storageState !== 'function') return null\n return context as WebStorageStateContext\n}\n\nfunction getConfiguredAuthStateDir(config: Record<string, unknown>): string | undefined {\n const services = config.services\n if (!services || typeof services !== 'object') return undefined\n const authState = (services as Record<string, unknown>).authState\n if (!authState || typeof authState !== 'object') return undefined\n const dir = (authState as Record<string, unknown>).dir\n return typeof dir === 'string' ? dir : undefined\n}\n\nfunction toLiveSubActionData(result: StepResult): LiveSubActionData[] | undefined {\n return result.trace?.subActions?.map((subAction) => ({\n index: subAction.index,\n observation: subAction.observation,\n reasoning: subAction.reasoning,\n plannedAction: subAction.plannedAction,\n result: subAction.result,\n error: subAction.error,\n screenStateBefore: subAction.screenStateBefore,\n screenStateAfter: subAction.screenStateAfter,\n confidence: subAction.confidence,\n verifierReasoning: subAction.verifierReasoning,\n cached: subAction.cached,\n tokenUsage: subAction.tokenUsage,\n phaseDurations: subAction.phaseDurations,\n annotation: subAction.annotation,\n screenContextBefore: subAction.screenContextBefore,\n screenContextAfter: subAction.screenContextAfter,\n data: subAction.data,\n }))\n}\n\nfunction mobileSetupMessage(err: MobileSetupError): string {\n return `${err.category}: ${err.message}`\n}\n\nfunction classifyAdapterSetupError(err: unknown): MobileSetupError['category'] {\n const message = err instanceof Error ? err.message : String(err)\n if (/appium|ECONNREFUSED|connect|\\/session|status/i.test(message)) {\n return 'appium-startup'\n }\n return 'device-readiness'\n}\n\nfunction wrapAdapterSetupError(\n err: unknown,\n platform: MobilePlatform,\n config: PlatformConfig,\n): MobileSetupError {\n if (err instanceof MobileSetupError) return err\n const appId = platform === 'android'\n ? config.appPackage\n : config.bundleId\n return new MobileSetupError({\n category: classifyAdapterSetupError(err),\n message: `Failed to create ${platform} adapter session: ${err instanceof Error ? err.message : String(err)}`,\n platform,\n deviceName: config.device?.name,\n appId,\n cause: err,\n })\n}\n\nfunction buildHookExecutionLog(hook: LiveHookPayload): LiveExecutionLog {\n return {\n id: hook.executionId,\n type: 'hook',\n name: hook.hookName,\n hookId: hook.hookId,\n phase: hook.phase,\n status: hook.status === 'failed' ? 'failed' : 'passed',\n duration: hook.duration ?? 0,\n stdout: hook.stdout ?? null,\n stderr: hook.stderr ?? null,\n returnData: null,\n variables: hook.variables ?? null,\n createdAt: hook.createdAt,\n }\n}\n\nexport class LiveSession {\n readonly sessionId: string\n status: 'idle' | 'executing' | 'disconnected' | 'terminated' = 'idle'\n private abortController: AbortController | null = null\n stepsExecuted = 0\n createdAt = 0\n\n private adapter: PlatformAdapter | null = null\n private planner: LLMPlanner | null = null\n private verifier: LLMVerifier | null = null\n private model: LanguageModel | null = null\n private variableStore: VariableStore | null = null\n private previousSteps: { instruction: string; outcome: string; reasoning?: string; plannedAction?: string; verifierResponse?: string }[] = []\n private currentStep: string | null = null\n private platform: 'web' | 'android' | 'ios' = 'web'\n private targetName: string | null = null\n private currentUrl: string | null = null\n private executing = false\n private idleTimer: ReturnType<typeof setTimeout> | null = null\n private _modelName = 'unknown'\n private screenshotSize: number | undefined\n private effectiveResolution: number | undefined\n private readyForInteraction = false\n private terminalError: string | null = null\n private setupHooks: string[] = []\n private teardownHooks: string[] = []\n private resolvedHooks = new Map<string, HookDefinition>()\n private hookRegistryError: string | null = null\n private pendingMessages: ServerMessage[] = []\n private messageSink: ((message: ServerMessage) => void) | null = null\n private mobileAppiumLease: MobileLiveAppiumLease | null = null\n private secretStore: SecretStore | undefined\n private secretRedactor: SecretRedactor | undefined\n\n constructor(sessionId: string, private deps: LiveSessionDeps = {}) {\n this.sessionId = sessionId\n }\n\n get modelName(): string {\n return this._modelName\n }\n\n attachMessageSink(sink: ((message: ServerMessage) => void) | null): void {\n this.messageSink = sink\n if (!sink || this.pendingMessages.length === 0) return\n\n for (const message of this.pendingMessages) {\n sink(message)\n }\n this.pendingMessages = []\n }\n\n private dispatch(message: ServerMessage): void {\n message = this.redact(message)\n if (this.messageSink) {\n this.messageSink(message)\n return\n }\n this.pendingMessages.push(message)\n }\n\n private redact<T>(value: T): T {\n return redactAuthStateValue(value, { secretRedactor: this.secretRedactor })\n }\n\n private resolveSecrets<T>(value: T): T {\n return resolveSecretTemplatesInValue(value, this.secretStore)\n }\n\n private emitHookStart(\n hookDef: Pick<HookDefinition, 'id' | 'name'>,\n phase: 'setup' | 'teardown',\n owner: LiveHookOwner = { scope: 'suite' },\n ): LiveHookPayload {\n const hook: LiveHookPayload = {\n executionId: randomUUID(),\n hookId: hookDef.id,\n hookName: hookDef.name,\n phase,\n owner,\n status: 'running',\n createdAt: new Date().toISOString(),\n }\n this.dispatch({ type: 'hook-start', hook })\n return hook\n }\n\n private emitHookComplete(\n started: LiveHookPayload,\n updates: Omit<LiveHookPayload, 'executionId' | 'hookId' | 'hookName' | 'phase' | 'owner' | 'createdAt'>,\n ): LiveHookPayload {\n const hook: LiveHookPayload = this.redact({\n ...started,\n ...updates,\n })\n this.dispatch({ type: 'hook-complete', hook })\n return hook\n }\n\n private emitTestStepStart(step: LiveTestStepPayload): void {\n this.dispatch({ type: 'test-step-start', step })\n }\n\n private emitTestStepPhase(step: LiveTestStepPayload, event: StepPhaseEvent): void {\n this.dispatch({\n type: 'test-step-phase',\n step,\n phase: event.phase,\n data: {\n text: event.text,\n confidence: event.confidence,\n action: event.action,\n success: event.success,\n duration: event.duration,\n },\n })\n }\n\n private emitTestStepComplete(step: LiveTestStepPayload, result: LiveStepExecutionResult): void {\n if (result.status === 'cancelled') {\n this.dispatch({ type: 'test-step-cancelled', step })\n return\n }\n\n this.dispatch({\n type: 'test-step-complete',\n step,\n result: toStepResultPayload(result),\n })\n }\n\n private emitTestStepError(step: LiveTestStepPayload, error: string): void {\n this.dispatch({ type: 'test-step-error', step, error })\n }\n\n private getHookEnvVars(): Record<string, string> {\n const envVars: Record<string, string> = {}\n if (!this.variableStore) return envVars\n\n for (const [key, value] of this.variableStore.getAll()) {\n envVars[key] = value\n }\n\n return envVars\n }\n\n private async runLifecycleHooks(\n phase: 'setup' | 'teardown',\n hookIds: string[],\n owner: LiveHookOwner = { scope: 'suite' },\n ): Promise<{ allPassed: boolean; logs: LiveExecutionLog[] }> {\n const logs: LiveExecutionLog[] = []\n\n for (const hookId of hookIds) {\n const hookDef = this.resolvedHooks.get(hookId)\n const started = this.emitHookStart(\n hookDef ?? { id: hookId, name: hookId },\n phase,\n owner,\n )\n\n if (!hookDef) {\n const registryHint = this.hookRegistryError ? ` (${this.hookRegistryError})` : ''\n const completed = this.emitHookComplete(started, {\n status: 'failed',\n duration: 0,\n stdout: null,\n stderr: this.hookRegistryError ?? null,\n variables: null,\n error: `Hook ID \"${hookId}\" is not defined in hooks.yaml${registryHint}`,\n })\n logs.push(buildHookExecutionLog(completed))\n if (phase === 'setup') {\n return { allPassed: false, logs }\n }\n continue\n }\n\n const result = await runHooks([hookDef], {\n envVars: this.getHookEnvVars(),\n secretStore: this.secretStore,\n secretRedactor: this.secretRedactor,\n })\n const hookResult = result.results.get(hookDef.name)\n const completed = this.emitHookComplete(started, {\n status: hookResult?.success ? 'passed' : 'failed',\n duration: hookResult?.duration ?? 0,\n stdout: hookResult?.stdout ?? null,\n stderr: hookResult?.stderr ?? null,\n variables: hookResult && Object.keys(hookResult.variables).length > 0 ? hookResult.variables : null,\n error: hookResult?.error,\n })\n logs.push(buildHookExecutionLog(completed))\n\n if (hookResult?.success && hookResult.variables && this.variableStore) {\n this.variableStore.setAll(hookResult.variables, 'hook')\n }\n\n if (!hookResult?.success && phase === 'setup') {\n return { allPassed: false, logs }\n }\n }\n\n return { allPassed: true, logs }\n }\n\n async executeHookCommand(\n phase: 'setup' | 'teardown',\n hookId: string,\n ): Promise<LiveExecutionLog> {\n if (!this.readyForInteraction || !this.variableStore) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n\n if (this.executing) {\n throw new Error('Live session is busy')\n }\n\n this.executing = true\n this.status = 'executing'\n const hookName = this.resolvedHooks.get(hookId)?.name ?? hookId\n this.currentStep = `${phase} hook: ${hookName}`\n\n try {\n const { logs } = await this.runLifecycleHooks(phase, [hookId])\n return logs[0] ?? {\n id: randomUUID(),\n type: 'hook',\n name: hookName,\n hookId,\n phase,\n status: 'failed',\n duration: 0,\n stdout: null,\n stderr: null,\n returnData: null,\n variables: null,\n createdAt: new Date().toISOString(),\n }\n } finally {\n this.executing = false\n this.currentStep = null\n this.status = 'idle'\n }\n }\n\n private releaseMobileAppiumLease(reason: string): void {\n if (!this.mobileAppiumLease) return\n this.mobileAppiumLease.release(reason)\n this.mobileAppiumLease = null\n }\n\n private legacyMobilePlatformConfig(config: LiveSessionConfig): PlatformConfig {\n const platform = config.platform as MobilePlatform\n return {\n platform,\n bundleId: config.bundleId,\n appPackage: config.appPackage,\n appActivity: config.appActivity,\n deepLinkAppId: platform === 'android' ? config.appPackage : config.bundleId,\n appState: config.appState,\n device: config.device\n ? {\n name: config.device.name,\n platform,\n transport: 'local',\n match: config.device,\n }\n : undefined,\n }\n }\n\n private async resolveMobilePlatformConfig(config: LiveSessionConfig): Promise<PlatformConfig> {\n if (\n this.deps.appiumManager\n && this.deps.configManager\n && this.deps.configPath\n && config.targetName\n ) {\n const prepared = await prepareMobileLiveSession({\n sessionId: this.sessionId,\n platform: config.platform as MobilePlatform,\n targetName: config.targetName,\n useDeviceName: config.useDeviceName,\n appState: config.appState,\n appiumManager: this.deps.appiumManager,\n configManager: this.deps.configManager,\n configPath: this.deps.configPath,\n })\n this.mobileAppiumLease = prepared.appiumLease\n return prepared.platformConfig\n }\n\n return this.legacyMobilePlatformConfig(config)\n }\n\n private async setupMobileAdapter(platform: MobilePlatform, config: LiveSessionConfig): Promise<void> {\n let adapter: PlatformAdapter | null = null\n try {\n const platformConfig = await this.resolveMobilePlatformConfig(config)\n const platformLabel = platform === 'android' ? 'Android' : 'iOS'\n try {\n if (platform === 'android') {\n const { AndroidPlatformAdapter } = await import('@vostride/agent-qa-android')\n adapter = new AndroidPlatformAdapter()\n } else {\n const { IOSPlatformAdapter } = await import('@vostride/agent-qa-ios')\n adapter = new IOSPlatformAdapter()\n }\n } catch (err) {\n throw new MobileSetupError({\n category: 'adapter-load',\n message: `Failed to load ${platformLabel} adapter (@vostride/agent-qa-${platform}). Is the package installed? ${err instanceof Error ? err.message : String(err)}`,\n platform,\n targetName: config.targetName,\n deviceName: platformConfig.device?.name,\n appId: platform === 'android' ? platformConfig.appPackage : platformConfig.bundleId,\n cause: err,\n })\n }\n\n try {\n await adapter.setup(platformConfig)\n } catch (err) {\n throw wrapAdapterSetupError(err, platform, platformConfig)\n }\n this.adapter = adapter\n } catch (err) {\n try {\n await adapter?.cleanup()\n } catch {}\n this.releaseMobileAppiumLease('setup-failed')\n if (err instanceof MobileSetupError) {\n throw new Error(mobileSetupMessage(err))\n }\n throw err\n }\n }\n\n async initialize(config: LiveSessionConfig): Promise<void> {\n this.platform = config.platform\n this.targetName = typeof config.targetName === 'string' && config.targetName.trim().length > 0\n ? config.targetName.trim()\n : null\n this._modelName = config.llmConfig.model ?? 'unknown'\n this.variableStore = new VariableStore()\n this.secretStore = config.secretStore\n this.secretRedactor = config.secretRedactor\n if (config.envVars) {\n this.variableStore.setAll(config.envVars, 'env')\n }\n this.setupHooks = [...(config.setupHooks ?? [])]\n this.teardownHooks = [...(config.teardownHooks ?? [])]\n this.resolvedHooks = new Map(config.resolvedHooks ?? [])\n this.hookRegistryError = config.hookRegistryError ?? null\n this.screenshotSize = config.llmConfig.screenshotSize\n this.effectiveResolution = config.llmConfig.effectiveResolution\n this.readyForInteraction = false\n this.terminalError = null\n\n const setupResult = await this.runLifecycleHooks('setup', this.setupHooks)\n if (!setupResult.allPassed) {\n this.status = 'idle'\n this.createdAt = Date.now()\n this.terminalError = 'Setup hooks failed. End the session or fix the hook configuration and reconnect.'\n return\n }\n\n if (config.platform === 'android') {\n await this.setupMobileAdapter('android', config)\n this.currentUrl = null\n } else if (config.platform === 'ios') {\n await this.setupMobileAdapter('ios', config)\n this.currentUrl = null\n } else {\n const { WebPlatformAdapter } = await import('@vostride/agent-qa-web')\n const adapter = new WebPlatformAdapter()\n await adapter.setup({ platform: 'web', browser: { name: 'chromium', headless: config.headless ?? true } })\n this.adapter = adapter\n\n if (config.url) {\n const resolvedUrl = this.resolveSecrets(config.url)\n await adapter.execute({ type: 'navigate', url: resolvedUrl })\n this.currentUrl = resolvedUrl\n } else {\n this.currentUrl = 'about:blank'\n }\n }\n\n const modelConfig = {\n ...config.llmConfig,\n ...(config.authFetch ? { fetch: config.authFetch } : {}),\n }\n this.model = await createModel(modelConfig)\n const providerOptions = getProviderOptions(modelConfig)\n this.planner = new LLMPlanner(this.model, config.platform, providerOptions, undefined, config.agentRules)\n this.verifier = new LLMVerifier(this.model, providerOptions)\n\n this.status = 'idle'\n this.createdAt = Date.now()\n this.readyForInteraction = true\n }\n\n private async resolveStepInstruction(stepInstruction: string): Promise<{\n instruction: string\n originalStepName?: string\n executionLogs: LiveExecutionLog[]\n preparationError?: string\n }> {\n const originalStepName = stepInstruction\n let instruction = stepInstruction\n let hasTemplateVars = false\n const executionLogs: LiveExecutionLog[] = []\n\n const inlineHookCalls = parseHookInline(stepInstruction)\n if (inlineHookCalls.length > 0) {\n let inlineHookFailed = false\n\n for (const call of inlineHookCalls) {\n const hookDef = this.resolvedHooks.get(call.hookId)\n if (!hookDef) {\n return {\n instruction: stepInstruction,\n originalStepName,\n executionLogs,\n preparationError: `Inline hook \"${call.hookId}\" is not defined in hooks.yaml`,\n }\n }\n\n const startedAt = performance.now()\n try {\n const result = await runHookInSandbox(hookDef, {\n envVars: this.getHookEnvVars(),\n secretStore: this.secretStore,\n secretRedactor: this.secretRedactor,\n })\n executionLogs.push({\n id: randomUUID(),\n type: 'hook',\n name: hookDef.name,\n hookId: hookDef.id,\n phase: 'inline',\n status: result.success ? 'passed' : 'failed',\n duration: result.duration,\n stdout: this.redact(result.stdout),\n stderr: this.redact(result.stderr),\n returnData: null,\n variables: Object.keys(result.variables).length > 0 ? this.redact(result.variables) : null,\n createdAt: new Date().toISOString(),\n })\n\n if (result.success) {\n if (Object.keys(result.variables).length > 0) {\n this.variableStore!.setAll(result.variables, 'hook')\n }\n } else {\n inlineHookFailed = true\n break\n }\n } catch (error) {\n executionLogs.push({\n id: randomUUID(),\n type: 'hook',\n name: hookDef.name,\n hookId: hookDef.id,\n phase: 'inline',\n status: 'failed',\n duration: performance.now() - startedAt,\n stdout: null,\n stderr: this.redact(error instanceof Error ? error.message : String(error)),\n returnData: null,\n variables: null,\n createdAt: new Date().toISOString(),\n })\n inlineHookFailed = true\n break\n }\n }\n\n instruction = stripHookInline(stepInstruction)\n hasTemplateVars = true\n\n if (inlineHookFailed) {\n return {\n instruction,\n originalStepName,\n executionLogs,\n preparationError: 'Inline hook execution failed',\n }\n }\n }\n\n instruction = interpolateVariables(instruction, this.variableStore!)\n hasTemplateVars = hasTemplateVars || originalStepName !== instruction\n\n const runJSMatches = parseRunJSInline(instruction)\n if (runJSMatches.length > 0) {\n if (this.adapter?.platform === 'web') {\n const page = 'getPage' in this.adapter\n ? (this.adapter as { getPage?: () => { evaluate: (code: string) => Promise<unknown> } | undefined }).getPage?.()\n : undefined\n\n if (page) {\n for (const match of runJSMatches) {\n const startedAt = performance.now()\n let status: 'passed' | 'failed' = 'passed'\n let stderr: string | null = null\n let stdout: string\n let returnData: unknown = null\n\n try {\n returnData = await page.evaluate(match.code)\n returnData = this.redact(returnData)\n stdout = this.redact(coerceRunJSResult(returnData))\n instruction = instruction.replace(match.fullMatch, stdout)\n } catch (err) {\n status = 'failed'\n stderr = this.redact(err instanceof Error ? err.message : String(err))\n stdout = `[runJS error: ${stderr}]`\n instruction = instruction.replace(match.fullMatch, stdout)\n }\n\n executionLogs.push({\n id: randomUUID(),\n type: 'runjs',\n name: match.code.slice(0, 200),\n phase: 'inline',\n status,\n duration: performance.now() - startedAt,\n stdout: status === 'passed' ? stdout : '',\n stderr,\n returnData,\n variables: null,\n createdAt: new Date().toISOString(),\n })\n }\n } else {\n for (const match of runJSMatches) {\n const stdout = '[runJS error: no browser page available]'\n instruction = instruction.replace(\n match.fullMatch,\n stdout,\n )\n executionLogs.push({\n id: randomUUID(),\n type: 'runjs',\n name: match.code.slice(0, 200),\n phase: 'inline',\n status: 'failed',\n duration: 0,\n stdout: null,\n stderr: 'no browser page available',\n returnData: null,\n variables: null,\n createdAt: new Date().toISOString(),\n })\n }\n }\n } else {\n for (const match of runJSMatches) {\n const stdout = '[runJS error: runJS is only supported on web platform]'\n instruction = instruction.replace(\n match.fullMatch,\n stdout,\n )\n executionLogs.push({\n id: randomUUID(),\n type: 'runjs',\n name: match.code.slice(0, 200),\n phase: 'inline',\n status: 'failed',\n duration: 0,\n stdout: null,\n stderr: 'runJS is only supported on web platform',\n returnData: null,\n variables: null,\n createdAt: new Date().toISOString(),\n })\n }\n }\n hasTemplateVars = true\n }\n\n return {\n instruction,\n originalStepName: hasTemplateVars ? originalStepName : undefined,\n executionLogs,\n }\n }\n\n private buildPreparationFailureResult(\n instruction: string,\n error: string,\n originalStepName: string | undefined,\n executionLogs: LiveExecutionLog[],\n ): LiveStepExecutionResult {\n const result: LiveStepExecutionResult = {\n name: instruction,\n status: 'failed',\n duration: 0,\n error,\n trace: {\n observation: '',\n reasoning: error,\n plannedAction: { type: 'waitFor', condition: 'none', timeout: 0 },\n result: 'failure',\n error,\n screenStateBefore: '',\n },\n variableSnapshot: this.variableStore!.snapshot(),\n executionLogs,\n originalStepName,\n }\n return this.redact(result)\n }\n\n // Inner step execution — no gating. Callers must own the executing/status\n // lifecycle (executeStepCommand for single steps, executeTestCommand for\n // the per-test loop that runs many steps under one outer gate).\n private async executeStepInternal(\n stepInstruction: string,\n stepIndex: number | undefined,\n onPhase: ((event: StepPhaseEvent) => void) | undefined,\n draft: LiveDraftMetadata | undefined,\n ): Promise<LiveStepExecutionResult> {\n this.abortController = new AbortController()\n try {\n const prepared = await this.resolveStepInstruction(stepInstruction)\n if (prepared.preparationError) {\n const result = this.buildPreparationFailureResult(\n prepared.instruction,\n prepared.preparationError,\n prepared.originalStepName,\n prepared.executionLogs,\n )\n this.stepsExecuted++\n return result\n }\n const unresolvedTemplates = findUnresolvedTemplates(prepared.instruction)\n if (unresolvedTemplates.length > 0) {\n const errorLines = unresolvedTemplates.map((template) => ` - ${template.pattern}: ${template.message}`)\n const error = `Unresolved template variable(s):\\n${errorLines.join('\\n')}`\n const result = this.buildPreparationFailureResult(\n prepared.instruction,\n error,\n prepared.originalStepName,\n prepared.executionLogs,\n )\n this.stepsExecuted++\n return result\n }\n\n const loopConfig: AgentLoopConfig = {\n adapter: this.adapter!,\n planner: this.planner!,\n verifier: this.verifier!,\n healingConfig: { maxAttempts: 3 },\n plannerConfig: { maxSubActions: 50, previousStepCount: 5 },\n screenshotSize: this.screenshotSize,\n effectiveResolution: this.effectiveResolution,\n onSetVariable: (name, value) => this.variableStore!.set(name, value, 'step'),\n onPhase,\n stepIndex,\n abortSignal: this.abortController.signal,\n secretStore: this.secretStore,\n secretRedactor: this.secretRedactor,\n }\n\n const allVars = this.variableStore!.getAll()\n const variables: Record<string, string> = {}\n for (const [k, v] of allVars) variables[k] = v\n\n const stepContext: StepContext = {\n stepInstruction: prepared.instruction,\n testName: draft?.testName?.trim() || 'Unnamed live draft',\n testContext: draft?.testContext?.trim() || undefined,\n previousSteps: this.previousSteps,\n plannerModel: this.model!,\n verifierModel: this.model!,\n healingConfig: { maxAttempts: 3 },\n variables: this.redact(variables),\n }\n\n let result = await executeStep(prepared.instruction, loopConfig, stepContext) as LiveStepExecutionResult\n result.originalStepName = prepared.originalStepName\n result.variableSnapshot = this.variableStore!.snapshot()\n result.executionLogs = this.redact(prepared.executionLogs)\n result.subActionsData = toLiveSubActionData(result)\n if ('pollDeviceLogs' in this.adapter! && typeof (this.adapter as { pollDeviceLogs?: () => Promise<void> }).pollDeviceLogs === 'function') {\n await (this.adapter as { pollDeviceLogs: () => Promise<void> }).pollDeviceLogs()\n }\n result.consoleLogs = this.adapter!.drainConsoleLogs?.()\n result.networkLogs = this.adapter!.drainNetworkLogs?.()\n result = this.redact(result)\n\n if (result.status !== 'cancelled') {\n this.previousSteps.push({ instruction: prepared.instruction, outcome: result.status })\n }\n this.stepsExecuted++\n return result\n } finally {\n this.abortController = null\n }\n }\n\n async executeStepCommand(\n stepInstruction: string,\n stepIndex?: number,\n onPhase?: (event: StepPhaseEvent) => void,\n draft?: LiveDraftMetadata,\n ): Promise<LiveStepExecutionResult> {\n if (!this.readyForInteraction || !this.adapter || !this.model || !this.planner || !this.verifier || !this.variableStore) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n\n if (this.executing) {\n throw new Error('Step already executing')\n }\n\n this.executing = true\n this.status = 'executing'\n this.currentStep = stepInstruction\n try {\n return await this.executeStepInternal(stepInstruction, stepIndex, onPhase, draft)\n } finally {\n this.executing = false\n this.currentStep = null\n this.status = 'idle'\n }\n }\n\n async executeTestCommand(\n testExecutionId: string,\n testDraft: {\n testIndex: number\n testId: string\n testName: string\n testContext?: string\n steps: string[]\n setup: string[]\n teardown: string[]\n },\n onPhase?: (event: StepPhaseEvent) => void,\n ): Promise<LiveTestResultPayload> {\n if (!this.readyForInteraction || !this.adapter || !this.model || !this.planner || !this.verifier || !this.variableStore) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n\n if (this.executing) {\n throw new Error('Test already executing')\n }\n\n this.executing = true\n this.status = 'executing'\n this.currentStep = `test: ${testDraft.testName}`\n const start = performance.now()\n const testExecution: LiveTestExecutionPayload = {\n testExecutionId,\n testIndex: testDraft.testIndex,\n testId: testDraft.testId,\n testName: testDraft.testName,\n }\n const testOwner: LiveHookOwner = {\n scope: 'test',\n testExecutionId,\n testIndex: testDraft.testIndex,\n testId: testDraft.testId,\n testName: testDraft.testName,\n }\n\n try {\n // Per-test setup (D-09). Per-test setup failure short-circuits the\n // test AND skips per-test teardown, matching suite/runner.ts:230 break\n // (Pitfall 2). Suite-level teardown still fires at session cleanup.\n const setupHookPayloads: LiveHookPayload[] = []\n const setupResult = await this.runLifecycleHooksCapturing(\n 'setup',\n testDraft.setup,\n setupHookPayloads,\n testOwner,\n )\n if (!setupResult.allPassed) {\n const failedHook = setupHookPayloads.find((h) => h.status === 'failed')\n const detail = failedHook\n ? `Setup hook \"${failedHook.hookName}\" failed${failedHook.error ? `: ${failedHook.error}` : ''}${failedHook.stderr ? ` — ${failedHook.stderr.split('\\n')[0].slice(0, 200)}` : ''}`\n : 'Per-test setup hook failed'\n console.warn(`[live-session] executeTestCommand: ${detail}`, {\n testName: testDraft.testName,\n setupHooks: testDraft.setup,\n failedHook: failedHook ? { name: failedHook.hookName, stderr: failedHook.stderr, error: failedHook.error } : null,\n })\n return {\n status: 'failed',\n duration: performance.now() - start,\n error: detail,\n setupHookExecutions: setupHookPayloads,\n stepResults: [],\n teardownHookExecutions: [],\n }\n }\n\n // Shared browser context (D-01): each step reuses the same adapter\n // instance. Per-step context carries the TEST's name/context, not\n // the suite's, so the LLMPlanner matches production runTest behaviour.\n const stepResults: LiveStepResultPayload[] = []\n const perStepDraft: LiveDraftMetadata = {\n testName: testDraft.testName,\n testContext: testDraft.testContext,\n }\n let anyCancelled = false\n let anyFailed = false\n for (let i = 0; i < testDraft.steps.length; i++) {\n const stepPayload: LiveTestStepPayload = {\n ...testExecution,\n stepIndex: i,\n stepInstruction: testDraft.steps[i],\n }\n this.emitTestStepStart(stepPayload)\n\n let execResult: LiveStepExecutionResult\n try {\n execResult = await this.executeStepInternal(\n testDraft.steps[i],\n i,\n (event) => {\n this.emitTestStepPhase(stepPayload, event)\n onPhase?.(event)\n },\n perStepDraft,\n )\n } catch (error) {\n const message = this.redact(error instanceof Error ? error.message : String(error))\n this.emitTestStepError(stepPayload, message)\n stepResults.push({\n status: 'failed',\n duration: 0,\n error: message,\n })\n anyFailed = true\n break\n }\n\n this.emitTestStepComplete(stepPayload, execResult)\n stepResults.push(toStepResultPayload(execResult))\n if (execResult.status === 'cancelled') {\n anyCancelled = true\n break\n }\n if (execResult.status === 'failed') {\n anyFailed = true\n break\n }\n }\n\n // Per-test teardown always fires when steps began (D-09 + D-25).\n const teardownHookPayloads: LiveHookPayload[] = []\n const teardownResult = await this.runLifecycleHooksCapturing(\n 'teardown',\n testDraft.teardown,\n teardownHookPayloads,\n testOwner,\n )\n\n const finalStatus: LiveTestResultPayload['status'] = anyCancelled\n ? 'cancelled'\n : anyFailed || !teardownResult.allPassed\n ? 'failed'\n : 'passed'\n\n let topLevelError: string | undefined\n if (anyFailed) {\n const failedStep = stepResults.find((s) => s.status === 'failed')\n if (failedStep) {\n const stepIdx = stepResults.indexOf(failedStep)\n topLevelError = `Step ${stepIdx + 1} (${testDraft.steps[stepIdx] ?? '<unknown>'}) failed${failedStep.error ? `: ${failedStep.error}` : ''}`\n }\n } else if (!teardownResult.allPassed) {\n const failedHook = teardownHookPayloads.find((h) => h.status === 'failed')\n topLevelError = failedHook\n ? `Teardown hook \"${failedHook.hookName}\" failed${failedHook.error ? `: ${failedHook.error}` : ''}`\n : 'Teardown hook failed'\n }\n if (topLevelError) {\n console.warn(`[live-session] executeTestCommand: ${topLevelError}`, { testName: testDraft.testName })\n }\n\n return this.redact({\n status: finalStatus,\n duration: performance.now() - start,\n error: topLevelError,\n setupHookExecutions: setupHookPayloads,\n stepResults,\n teardownHookExecutions: teardownHookPayloads,\n })\n } finally {\n this.executing = false\n this.currentStep = null\n this.status = 'idle'\n }\n }\n\n // Thin wrapper around runLifecycleHooks that also captures the dispatched\n // hook payloads (hook-start / hook-complete) for inclusion in the\n // LiveTestResultPayload. Uses a sink intercept so existing callers of\n // runLifecycleHooks (executeHookCommand, initialize, cleanup) keep their\n // current behaviour unchanged.\n private async runLifecycleHooksCapturing(\n phase: 'setup' | 'teardown',\n hookIds: string[],\n sink: LiveHookPayload[],\n owner: LiveHookOwner = { scope: 'suite' },\n ): Promise<{ allPassed: boolean; logs: LiveExecutionLog[] }> {\n const originalSink = this.messageSink\n const wrappedSink = (message: ServerMessage) => {\n if (message.type === 'hook-complete') {\n sink.push(message.hook)\n }\n if (originalSink) originalSink(message)\n else this.pendingMessages.push(message)\n }\n this.messageSink = wrappedSink\n try {\n return await this.runLifecycleHooks(phase, hookIds, owner)\n } finally {\n this.messageSink = originalSink\n }\n }\n\n async captureWebAuthState(\n name: string,\n options: { replace?: boolean } = {},\n ): Promise<AuthStateMetadata> {\n if (this.platform !== 'web') {\n throw new Error('Auth-state capture is only available for web Live Mode sessions.')\n }\n\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready for auth-state capture.')\n }\n\n if (this.adapter.platform !== 'web') {\n throw new Error('Auth-state capture is only available for web Live Mode sessions.')\n }\n\n if (this.executing) {\n throw new Error('Cannot save auth state while the Live Mode session is executing.')\n }\n\n if (!this.targetName) {\n throw new Error('Cannot save auth state because this Live Mode session has no configured target.')\n }\n\n if (!this.deps.configManager || !this.deps.configPath) {\n throw new Error('Cannot save auth state because workspace config is unavailable.')\n }\n\n const context = getWebStorageStateContext(this.adapter)\n if (!context) {\n throw new Error('Cannot save auth state because the active browser context is unavailable.')\n }\n\n const config = await this.deps.configManager.read()\n const authStateDir = getConfiguredAuthStateDir(config)\n const paths = resolveAuthStatePaths({\n configDir: dirname(resolvePath(this.deps.configPath)),\n authStateDir,\n targetName: this.targetName,\n stateName: name,\n target: { platform: 'web' },\n })\n\n let existing: AuthStateMetadata | null = null\n try {\n existing = await readAuthStateMetadata(paths)\n } catch {\n existing = null\n }\n if (existing && options.replace !== true) {\n throw new Error(`Auth state \"${paths.stateName}\" for target \"${paths.targetName}\" already exists. Use replace=true to replace it.`)\n }\n\n const payload = await context.storageState({ indexedDB: true })\n const metadata: AuthStateMetadata = {\n version: AUTH_STATE_SCHEMA_VERSION,\n kind: 'web',\n target: paths.targetName,\n name: paths.stateName,\n capturedAt: new Date().toISOString(),\n }\n\n try {\n await writeAuthStateFiles(paths, { payload, metadata })\n } catch {\n throw new Error(`Could not save auth state \"${paths.stateName}\" for target \"${paths.targetName}\".`)\n }\n\n return metadata\n }\n\n cancelStep(): void {\n this.abortController?.abort()\n }\n\n async navigate(url: string): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n const resolvedUrl = this.resolveSecrets(url)\n await this.adapter!.execute({ type: 'navigate', url: resolvedUrl })\n if (this.platform === 'web') {\n this.currentUrl = resolvedUrl\n } else {\n this.currentUrl = null\n }\n return this.currentUrl\n }\n\n async refreshPage(): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n if (this.platform !== 'web') return this.currentUrl\n await this.adapter!.execute({ type: 'refresh' })\n const page = (this.adapter as any).getPage?.()\n if (page) this.currentUrl = page.url()\n return this.currentUrl ?? 'about:blank'\n }\n\n async goBack(): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n if (this.platform !== 'web') return this.currentUrl\n await this.adapter!.execute({ type: 'navigateHistory', direction: 'back' })\n const page = (this.adapter as any).getPage?.()\n if (page) this.currentUrl = page.url()\n return this.currentUrl ?? 'about:blank'\n }\n\n async goForward(): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n if (this.platform !== 'web') return this.currentUrl\n await this.adapter!.execute({ type: 'navigateHistory', direction: 'forward' })\n const page = (this.adapter as any).getPage?.()\n if (page) this.currentUrl = page.url()\n return this.currentUrl ?? 'about:blank'\n }\n\n async drainDeviceLogs(): Promise<Array<{ level: string; message: string; timestamp: number }>> {\n if (!this.adapter) return []\n if (typeof (this.adapter as any).pollDeviceLogs === 'function') {\n await (this.adapter as any).pollDeviceLogs()\n }\n if (typeof this.adapter.drainConsoleLogs === 'function') {\n return this.redact(this.adapter.drainConsoleLogs().map((e) => ({ level: e.level, message: e.text, timestamp: e.timestamp })))\n }\n return []\n }\n\n getState(): SessionState {\n return {\n sessionId: this.sessionId,\n platform: (this.adapter?.platform ?? this.platform) as 'web' | 'android' | 'ios',\n targetName: this.targetName,\n status: this.status === 'terminated' ? 'idle' : this.status === 'executing' ? 'executing' : this.status,\n currentStep: this.currentStep,\n currentUrl: this.currentUrl,\n stepsExecuted: this.stepsExecuted,\n createdAt: this.createdAt,\n interactive: this.readyForInteraction,\n terminalError: this.terminalError,\n }\n }\n\n async getScreenshot(): Promise<Buffer | undefined> {\n if (!this.readyForInteraction) return undefined\n return this.adapter?.screenshot?.()\n }\n\n async getAriaTree(): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) return null\n if (!this.adapter) return null\n const screenState = await this.adapter.observe()\n return screenState.tree\n }\n\n startIdleTimer(onExpire: () => void): void {\n this.clearIdleTimer()\n this.idleTimer = setTimeout(onExpire, IDLE_TIMEOUT_MS)\n }\n\n clearIdleTimer(): void {\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = null\n }\n }\n\n async cleanup(): Promise<void> {\n this.clearIdleTimer()\n this.readyForInteraction = false\n try {\n await this.adapter?.cleanup()\n } finally {\n try {\n await this.runLifecycleHooks('teardown', this.teardownHooks)\n } finally {\n this.releaseMobileAppiumLease('session-cleanup')\n this.messageSink = null\n this.status = 'terminated'\n }\n }\n }\n}\n","import { readFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { parse as parseYaml } from 'yaml'\nimport {\n MobileSetupError,\n resolveMobileRunConfig,\n} from '@vostride/agent-qa-core'\nimport type {\n MobilePlatform,\n PlatformConfig,\n ResolvedMobileRunConfig,\n} from '@vostride/agent-qa-core'\nimport type { AppiumManager } from '../execution/appium-manager.js'\nimport type { ConfigManager } from '../config/index.js'\n\ninterface LocalMobileBindings {\n devices?: Record<string, Record<string, unknown>>\n providers?: Record<string, Record<string, unknown>>\n apps?: Record<string, { path?: string; browserstack?: string }>\n filePath?: string\n}\n\nexport interface MobileLiveAppiumLease {\n runId: string\n url: string\n release: (reason?: string) => boolean\n}\n\nexport interface PreparedMobileLiveSession {\n platformConfig: PlatformConfig\n appiumLease: MobileLiveAppiumLease\n resolved: ResolvedMobileRunConfig\n}\n\nexport interface PrepareMobileLiveSessionInput {\n sessionId: string\n platform: MobilePlatform\n targetName?: string\n useDeviceName?: string\n appState?: 'preserve' | 'reset'\n configManager: ConfigManager\n configPath: string\n appiumManager: AppiumManager\n}\n\nasync function loadLocalBindings(configPath: string): Promise<LocalMobileBindings | null> {\n const filePath = join(dirname(configPath), 'agent-qa.local.yaml')\n try {\n const content = await readFile(filePath, 'utf-8')\n const parsed = parseYaml(content) as LocalMobileBindings | null\n return parsed && typeof parsed === 'object'\n ? {\n devices: parsed.devices,\n providers: parsed.providers,\n apps: parsed.apps,\n filePath,\n }\n : { filePath }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null\n throw err\n }\n}\n\nfunction asMobileSetupError(\n err: unknown,\n category: MobileSetupError['category'],\n message: string,\n input: Pick<PrepareMobileLiveSessionInput, 'platform' | 'targetName'>,\n): MobileSetupError {\n if (err instanceof MobileSetupError) return err\n return new MobileSetupError({\n category,\n message: `${message}: ${err instanceof Error ? err.message : String(err)}`,\n platform: input.platform,\n targetName: input.targetName,\n cause: err,\n })\n}\n\nexport async function prepareMobileLiveSession(\n input: PrepareMobileLiveSessionInput,\n): Promise<PreparedMobileLiveSession> {\n if (!input.targetName) {\n throw new MobileSetupError({\n category: 'device-resolution',\n message: `No targetName provided for ${input.platform} live session`,\n platform: input.platform,\n })\n }\n\n const config = await input.configManager.read()\n let localBindings: LocalMobileBindings | null = null\n\n try {\n localBindings = await loadLocalBindings(input.configPath)\n } catch (err) {\n throw asMobileSetupError(err, 'device-resolution', 'Failed to read local device bindings', input)\n }\n\n const configuredAppState = (config.use as { mobile?: { appState?: 'preserve' | 'reset' } } | undefined)?.mobile?.appState\n\n let resolved: ResolvedMobileRunConfig\n try {\n resolved = resolveMobileRunConfig({\n config,\n targetName: input.targetName,\n platform: input.platform,\n useDeviceName: input.useDeviceName,\n appState: input.appState ?? configuredAppState,\n localBindings,\n configFilePath: input.configPath,\n localConfigFilePath: localBindings?.filePath,\n })\n } catch (err) {\n throw asMobileSetupError(err, 'device-resolution', 'Failed to resolve mobile live target', input)\n }\n\n try {\n await input.appiumManager.acquireLease({ runId: input.sessionId, platform: input.platform })\n } catch (err) {\n throw new MobileSetupError({\n category: 'appium-startup',\n message: `Failed to acquire Appium for ${input.platform} live session: ${err instanceof Error ? err.message : String(err)}`,\n platform: input.platform,\n targetName: input.targetName,\n deviceName: resolved.deviceName,\n appId: resolved.app.deepLinkAppId,\n sourceTrace: resolved.sourceTrace,\n cause: err,\n })\n }\n\n const appiumUrl = input.appiumManager.getUrl()\n let released = false\n const appiumLease: MobileLiveAppiumLease = {\n runId: input.sessionId,\n url: appiumUrl,\n release: (reason = 'completed') => {\n if (released) return false\n released = true\n return input.appiumManager.releaseLease(input.sessionId, reason)\n },\n }\n\n return {\n resolved: {\n ...resolved,\n appium: {\n url: appiumUrl,\n managed: true,\n },\n },\n appiumLease,\n platformConfig: {\n platform: input.platform,\n device: resolved.device,\n appiumUrl,\n bundleId: resolved.app.bundleId,\n appPackage: resolved.app.appPackage,\n appActivity: resolved.app.appActivity,\n deepLinkAppId: resolved.app.deepLinkAppId,\n appPath: resolved.app.install?.path,\n browserstackApp: resolved.app.install?.browserstack,\n appState: resolved.appState,\n },\n }\n}\n","import type WebSocket from 'ws'\nimport { parseTestFile } from '@vostride/agent-qa-core'\nimport type { LiveSession } from './live-session.js'\nimport type {\n LiveStepResultPayload,\n ServerMessage,\n} from './types.js'\nimport type { TestFileManager } from '../tests/test-file-manager.js'\n\nfunction send(ws: WebSocket, msg: ServerMessage): void {\n if (ws.readyState === ws.OPEN) {\n ws.send(JSON.stringify(msg))\n }\n}\n\nfunction toStepResultPayload(result: Awaited<ReturnType<LiveSession['executeStepCommand']>>): LiveStepResultPayload {\n const status = result.status === 'passed'\n ? 'passed'\n : result.status === 'cancelled'\n ? 'cancelled'\n : 'failed'\n\n return {\n status,\n duration: result.duration,\n error: result.error,\n capturedVariables: result.capturedVariables,\n variableSnapshot: result.variableSnapshot,\n originalStepName: result.originalStepName,\n consoleLogs: result.consoleLogs,\n networkLogs: result.networkLogs,\n executionLogs: result.executionLogs,\n subActionsData: result.subActionsData,\n }\n}\n\nexport function createSessionHandler(\n session: LiveSession,\n onTerminate: () => void,\n onTokenUsage?: (event: { modelName: string; promptTokens: number; completionTokens: number; source: 'live-editor' }) => void,\n testFileManager?: TestFileManager,\n): (ws: WebSocket) => void {\n return (ws: WebSocket) => {\n let cleanedUp = false\n\n async function cleanupSession(): Promise<void> {\n if (cleanedUp) return\n cleanedUp = true\n if (logPollInterval) clearInterval(logPollInterval)\n if (session.status !== 'terminated') {\n await session.cleanup()\n }\n onTerminate()\n }\n\n session.clearIdleTimer()\n\n const state = session.getState()\n send(ws, {\n type: 'session-ready',\n sessionId: session.sessionId,\n platform: state.platform,\n interactive: state.interactive,\n error: state.terminalError,\n })\n session.attachMessageSink((message) => {\n send(ws, message)\n })\n send(ws, { type: 'session-state', state })\n\n let logPollInterval: ReturnType<typeof setInterval> | null = null\n const platform = state.platform\n if (platform !== 'web' && state.interactive) {\n logPollInterval = setInterval(async () => {\n if (session.status === 'executing') {\n return\n }\n try {\n const entries = await session.drainDeviceLogs()\n if (entries.length > 0) {\n send(ws, { type: 'device-logs', entries })\n }\n } catch {}\n }, 2000)\n }\n\n ws.on('message', async (data) => {\n let msg: any\n try {\n msg = JSON.parse(data.toString())\n } catch {\n send(ws, { type: 'error', message: 'Invalid JSON' })\n return\n }\n\n switch (msg.type) {\n case 'execute-step': {\n if (session.status === 'executing') {\n send(ws, {\n type: 'step-busy',\n currentStep: session.getState().currentStep ?? 'unknown',\n })\n return\n }\n try {\n const result = await session.executeStepCommand(\n msg.stepInstruction,\n msg.stepIndex,\n (phase) => {\n send(ws, {\n type: 'step-phase',\n phase: phase.phase,\n data: {\n text: phase.text,\n confidence: phase.confidence,\n action: phase.action,\n success: phase.success,\n duration: phase.duration,\n },\n })\n },\n msg.draft,\n )\n if (result.status === 'cancelled') {\n send(ws, { type: 'step-cancelled' })\n } else {\n send(ws, {\n type: 'step-complete',\n result: toStepResultPayload(result),\n })\n if (onTokenUsage && result.trace?.tokenUsage &&\n (result.trace.tokenUsage.promptTokens > 0 || result.trace.tokenUsage.completionTokens > 0)) {\n onTokenUsage({\n modelName: session.modelName,\n promptTokens: result.trace.tokenUsage.promptTokens,\n completionTokens: result.trace.tokenUsage.completionTokens,\n source: 'live-editor',\n })\n }\n try {\n const tree = await session.getAriaTree()\n if (tree) send(ws, { type: 'aria-tree', tree })\n } catch {}\n }\n send(ws, { type: 'session-state', state: session.getState() })\n const adapter = (session as any).adapter\n if (adapter && typeof adapter.isBrowserDisconnected === 'boolean' && adapter.isBrowserDisconnected) {\n send(ws, { type: 'browser-disconnected' })\n }\n } catch (err: any) {\n send(ws, { type: 'step-error', error: err.message })\n const adapter = (session as any).adapter\n if (adapter && typeof adapter.isBrowserDisconnected === 'boolean' && adapter.isBrowserDisconnected) {\n send(ws, { type: 'browser-disconnected' })\n }\n }\n break\n }\n\n case 'execute-hook': {\n if (session.status === 'executing') {\n send(ws, {\n type: 'step-busy',\n currentStep: session.getState().currentStep ?? 'unknown',\n })\n return\n }\n try {\n await session.executeHookCommand(msg.phase, msg.hookId)\n send(ws, { type: 'session-state', state: session.getState() })\n } catch (err: any) {\n send(ws, { type: 'error', message: err.message })\n }\n break\n }\n\n case 'execute-test': {\n if (session.status === 'executing') {\n send(ws, {\n type: 'step-busy',\n currentStep: session.getState().currentStep ?? 'unknown',\n })\n return\n }\n try {\n if (!testFileManager) {\n throw new Error('Test file manager unavailable — configure workspace.testMatch to run tests live')\n }\n\n let raw: string\n try {\n raw = await testFileManager.read(msg.path)\n } catch (readErr: any) {\n console.error(`[ws-handler] execute-test: read failed for path=${msg.path}`, readErr)\n throw new Error(`Cannot read test file \"${msg.path}\": ${readErr?.message ?? String(readErr)}`)\n }\n\n const parsed = parseTestFile(raw, msg.path)\n if (parsed.errors.length > 0) {\n console.error(`[ws-handler] execute-test: parse errors for ${msg.path}`, parsed.errors)\n throw new Error(`Parse error in ${msg.path}: ${parsed.errors[0].message}`)\n }\n const testDef = parsed.tests[0]\n if (!testDef) {\n throw new Error(`Test file \"${msg.path}\" is empty or has no valid test documents`)\n }\n const stepInstructions: string[] = testDef.steps.map((s: string | { step: string }) =>\n typeof s === 'string' ? s : s.step,\n )\n console.log(`[ws-handler] execute-test: starting \"${testDef.name}\" (${stepInstructions.length} steps, setup=${(testDef.setup ?? []).length}, teardown=${(testDef.teardown ?? []).length})`)\n\n send(ws, {\n type: 'test-start',\n test: {\n testExecutionId: msg.testExecutionId,\n testIndex: msg.testIndex ?? 0,\n testId: msg.testId,\n testName: testDef.name,\n },\n })\n\n const result = await session.executeTestCommand(\n msg.testExecutionId,\n {\n testIndex: msg.testIndex ?? 0,\n testId: msg.testId,\n testName: testDef.name,\n testContext: testDef.context,\n steps: stepInstructions,\n setup: testDef.setup ?? [],\n teardown: testDef.teardown ?? [],\n },\n )\n\n console.log(`[ws-handler] execute-test: finished \"${testDef.name}\" status=${result.status} duration=${result.duration}ms${result.error ? ` error=${result.error}` : ''}`)\n send(ws, {\n type: 'test-complete',\n test: {\n testExecutionId: msg.testExecutionId,\n testIndex: msg.testIndex ?? 0,\n testId: msg.testId,\n testName: testDef.name,\n },\n result,\n })\n send(ws, { type: 'session-state', state: session.getState() })\n } catch (err: any) {\n console.error(`[ws-handler] execute-test: caught error for path=${msg.path}`, {\n message: err?.message,\n stack: err?.stack,\n code: err?.code,\n })\n send(ws, {\n type: 'test-error',\n test: {\n testExecutionId: msg.testExecutionId,\n testIndex: msg.testIndex ?? 0,\n testId: msg.testId,\n testName: msg.path.split(/[\\\\/]/).pop() ?? msg.path,\n },\n error: err?.message ?? String(err),\n })\n send(ws, { type: 'session-state', state: session.getState() })\n }\n break\n }\n\n case 'cancel-step': {\n session.cancelStep()\n break\n }\n\n case 'terminate-session': {\n await cleanupSession()\n send(ws, { type: 'session-terminated' })\n ws.close(1000, 'Session terminated')\n break\n }\n\n case 'get-screenshot': {\n const buf = await session.getScreenshot()\n if (buf) {\n send(ws, { type: 'screenshot', data: buf.toString('base64') })\n } else {\n send(ws, { type: 'error', message: 'Screenshot unavailable' })\n }\n break\n }\n\n case 'get-state': {\n send(ws, { type: 'session-state', state: session.getState() })\n break\n }\n\n case 'navigate': {\n if (session.status === 'executing') {\n send(ws, { type: 'step-busy', currentStep: session.getState().currentStep ?? 'unknown' })\n return\n }\n try {\n const url = await session.navigate(msg.url)\n send(ws, { type: 'navigate-complete', url })\n send(ws, { type: 'session-state', state: session.getState() })\n } catch (err: any) {\n send(ws, { type: 'error', message: err.message })\n }\n break\n }\n\n case 'refresh-page': {\n if (session.status === 'executing') {\n send(ws, { type: 'step-busy', currentStep: session.getState().currentStep ?? 'unknown' })\n return\n }\n try {\n const url = await session.refreshPage()\n send(ws, { type: 'navigate-complete', url })\n send(ws, { type: 'session-state', state: session.getState() })\n } catch (err: any) {\n send(ws, { type: 'error', message: err.message })\n }\n break\n }\n\n case 'go-back': {\n if (session.status === 'executing') {\n send(ws, { type: 'step-busy', currentStep: session.getState().currentStep ?? 'unknown' })\n return\n }\n try {\n const url = await session.goBack()\n send(ws, { type: 'navigate-complete', url })\n send(ws, { type: 'session-state', state: session.getState() })\n } catch (err: any) {\n send(ws, { type: 'error', message: err.message })\n }\n break\n }\n\n case 'go-forward': {\n if (session.status === 'executing') {\n send(ws, { type: 'step-busy', currentStep: session.getState().currentStep ?? 'unknown' })\n return\n }\n try {\n const url = await session.goForward()\n send(ws, { type: 'navigate-complete', url })\n send(ws, { type: 'session-state', state: session.getState() })\n } catch (err: any) {\n send(ws, { type: 'error', message: err.message })\n }\n break\n }\n\n case 'get-aria-tree': {\n if (session.status === 'executing') {\n send(ws, { type: 'error', message: 'Cannot inspect ARIA tree while step is executing' })\n return\n }\n try {\n const tree = await session.getAriaTree()\n if (tree) {\n send(ws, { type: 'aria-tree', tree })\n } else {\n send(ws, { type: 'error', message: 'ARIA tree unavailable' })\n }\n } catch (err: any) {\n send(ws, { type: 'error', message: err.message })\n }\n break\n }\n\n default: {\n send(ws, { type: 'error', message: `Unknown message type: ${msg.type}` })\n break\n }\n }\n })\n\n ws.on('close', () => {\n session.attachMessageSink(null)\n void cleanupSession()\n })\n\n ws.on('error', () => {\n session.attachMessageSink(null)\n void cleanupSession()\n })\n }\n}\n"],"mappings":"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","names":["import_node_http","import_promises","import_node_path","import_node_os","import_promises","import_node_path","import_promises","import_node_path","import_agent_qa_core","import_yaml","parseYaml","parseTestFile","parseYaml","import_promises","import_node_path","import_agent_qa_core","import_agent_qa_ids","import_yaml","import_promises","import_node_path","import_agent_qa_core","import_yaml","parseYaml","parseYaml","resolve","import_agent_qa_core","import_yaml","parseYaml","path","llmConfig","createModel","treeKill","import_node_events","import_promises","import_node_path","import_agent_qa_ids","import_yaml","import_agent_qa_core","parseYaml","import_promises","import_node_path","import_yaml","import_node_child_process","import_agent_qa_core","import_tree_kill","pc","resolve","treeKill","import_node_crypto","import_node_crypto","import_node_path","import_agent_qa_core","import_promises","import_node_path","import_yaml","import_agent_qa_core","parseYaml","getConfiguredAuthStateDir","completed","result","resolvePath","import_agent_qa_core","toStepResultPayload","import_agent_qa_core","request","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/index.ts","../../src/server/server.ts","../../src/db/run-owner-host.ts","../../src/db/run-owner.ts","../../src/server/routes.ts","../../src/db/run-status-class.ts","../../src/tests/test-file-manager.ts","../../src/tests/replace-file-atomic.ts","../../src/config/config-manager.ts","../../src/config/undo-store.ts","../../src/hooks/hook-registry-manager.ts","../../src/hooks/hook-reference-scan.ts","../../src/server/body-parser.ts","../../src/live-editor/live-session.ts","../../src/llm-model-mapping.ts","../../src/live-editor/mobile-bootstrap.ts","../../src/server/cross-site.ts","../../src/server/request-url.ts","../../src/run-service/run-service-routes.ts","../../src/run-service/run-detail-routes.ts","../../src/run-service/run-analysis-routes.ts","../../src/run-service/post-processing-routes.ts","../../src/run-service/run-knowledge-routes.ts","../../src/run-service/run-mark-routes.ts","../../src/server/config-routes.ts","../../src/server/llm-connect-route.ts","../../src/queue/job-queue.ts","../../src/tests/suite-file-manager.ts","../../src/execution/appium-manager.ts","../../src/live-editor/session-manager.ts","../../src/live-editor/ws-handler.ts","../../src/live-editor/types.ts","../../src/live-view/protocol.ts","../../src/live-view/embed-page.ts","../../src/live-view/frame-proxy.ts"],"sourcesContent":["export { startServer } from './server.js'\nexport { createRouter } from './routes.js'\nexport { readJsonBody } from './body-parser.js'\n// 400-16 (gap 7): the ONE guarded request-URL parse, published so a cell can drive the producer\n// itself rather than a re-implementation of it, and so a future frame that needs to parse a request\n// URL has somewhere to import the only parse there is.\nexport {\n backstopServerError,\n refuseUnparseableRequest,\n tryParseRequestUrl,\n} from './request-url.js'\n\n// The injected-host seam, published because the CLI command that starts this server composes the\n// host. 2026-10-01 (432-14, D-14): the run-confirm router, its route table and the confirm registry\n// that were published beside it are deleted.\nexport type { AgentHost, AgentRegistryHandle } from '../chat/host.js'\n","import { createServer, type Server } from 'node:http'\nimport { randomBytes } from 'node:crypto'\nimport { readFile, stat } from 'node:fs/promises'\nimport { join, extname, resolve } from 'node:path'\nimport { cpus } from 'node:os'\nimport type { DashboardDatabase } from '../db/database.js'\nimport { classifyRunOwner } from '../db/run-owner.js'\nimport { createRouter, sanitizeQueuedExecutionTimeout } from './routes.js'\nimport { backstopServerError, refuseUnparseableRequest, tryParseRequestUrl } from './request-url.js'\nimport type { ExecutionBackend, RunSettledDetails, RunSettledStatus } from '../execution/execution-backend.js'\nimport { JobQueue } from '../queue/job-queue.js'\nimport { TestFileManager } from '../tests/test-file-manager.js'\nimport { SuiteFileManager } from '../tests/suite-file-manager.js'\nimport { ConfigManager, readConfigValues } from '../config/index.js'\nimport { AppiumManager } from '../execution/appium-manager.js'\nimport { WebSocketServer } from 'ws'\nimport { SessionManager } from '../live-editor/session-manager.js'\nimport { createSessionHandler } from '../live-editor/ws-handler.js'\nimport { LIVE_EMBED_PATH_PREFIX, LIVE_VIEW_WS_PATH } from '../live-view/protocol.js'\nimport { renderLiveEmbedPage } from '../live-view/embed-page.js'\nimport { createFrameProxy } from '../live-view/frame-proxy.js'\nimport { refuseCrossSiteRequest, refuseNonLoopbackHost } from './cross-site.js'\nimport { LIVE_EDITOR_UNKNOWN_SESSION_CLOSE_CODE } from '../live-editor/types.js'\nimport type { LiveEditorSubjects } from '../live-view/editor-subjects.js'\nimport type {\n EditorLiveUrlResult,\n LiveUrlVerdict,\n LiveViewSubjectRef,\n MaskFn,\n RunSession,\n RunsLiveUrlResult,\n} from '@vostride/agent-qa-schema'\nimport {\n isLoopbackHost,\n type ResolvedWorkspacePaths,\n} from '@vostride/agent-qa-core'\nimport type { DashboardLLMConfig } from '../llm-model-mapping.js'\nimport type { AgentHost } from '../chat/host.js'\nimport type { PostProcessingRelay } from '../execution/post-processing-relay.js'\nimport {\n createRunServiceRoutes,\n ownsRunServicePath,\n type RunServicePorts,\n} from '../run-service/run-service-routes.js'\nimport type { RunServiceReadiness } from '@vostride/agent-qa-schema'\n// 396-01 D-10: the `@vostride/agent-qa-mcp` import is GONE, together with the MCP endpoint this\n// server used to start beside the dashboard. The v2 server is composed per-caller by the CLI's own\n// host (`agent-qa mcp`) over the function registry, so a dashboard that mounted its own copy would\n// be a second composition root for the same surface — the private power the milestone abolishes.\n// M5's dashboard rebuild decides whether it wants a mount back, via `/hono` and its own decision.\n//\n// 2026-08-24 — THE HONO RESERVATION IS RETIRED (Phase 402 D-03). The question this file reserved\n// (\"would a framework earn its place here?\") is answered: no. The run service mounted below is\n// hand-rolled `node:http`, like the daemon server and the MCP listener — zero new dependencies at a\n// network boundary, one routing idiom per process. A framework added later would\n// have to argue against that, not inherit an open reservation.\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript',\n '.mjs': 'application/javascript',\n '.css': 'text/css',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.svg': 'image/svg+xml',\n '.json': 'application/json',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n '.ttf': 'font/ttf',\n '.ico': 'image/x-icon',\n '.map': 'application/json',\n '.webp': 'image/webp',\n}\n\nfunction isAnalyticsPrivacyEnabled(config: unknown): boolean {\n if (!config || typeof config !== 'object') return false\n const analytics = (config as { analytics?: unknown }).analytics\n return Boolean(analytics && typeof analytics === 'object'\n && (analytics as { privacy?: unknown }).privacy === true)\n}\n\n/**\n * The refusal that keeps the dashboard surface off the network (402-05, D-07; 432 D-13).\n *\n * NAMES THE HOST AND THE CONFIG KEY, AND NOTHING ELSE (395-16 measured Node's default uncaught\n * printer walking a `cause` chain with `util.inspect`, which is how a config file's contents once\n * reached a person's terminal). There is deliberately no `cause` attached.\n *\n * WHY A REFUSAL AND NOT A WARNING. Nothing this server mounts asks for a credential: the run\n * trigger, the queue enqueue, the run service, the artifact serving, the config reads. 2026-10-01\n * (432-21, D-12/D-13): that is now true of the run service too — its bearer tokens are deleted — so\n * the loopback bind is the whole of what keeps another machine off every one of them.\n *\n * AND WHY THE REFUSAL IS UNCONDITIONAL. This guard originally exempted a process that had declared\n * a run-service credential, on the premise that \"the operator who genuinely wants remote access\n * declares a credential — which is the same act that makes the remote surface an authed one\".\n * Phase-402 verification measured that premise FALSE off a real interface: a credential\n * authenticates exactly `ownsRunServicePath` — `POST /run`, `GET /run/:runId/events`, `GET /ok` —\n * and declaring one was precisely what unlocked the bind. With `host: 0.0.0.0` and one token,\n * `POST /api/runs/trigger` carrying no Authorization header answered `202` and started a run, and\n * `GET /api/runs` answered `200` with the run list. The token count was never evidence about the\n * surface this guard protects, so it is no longer consulted. Since 432-21 there is no credential to\n * consult at all. Publishing this server to a network needs a front-door login first (432 D-13's\n * forward note); until there is one, the honest answer is no.\n */\nexport class DashboardRemoteBindRefusedError extends Error {\n constructor(readonly host: string) {\n super(\n `The dashboard was asked to bind ${host}, which is not a loopback interface. Nothing this `\n + 'server serves — the run trigger, the queue enqueue, the run service, the artifact '\n + 'serving, the config reads — asks for a credential, so a non-loopback bind would publish '\n + 'an anonymous run trigger to the network. Leave '\n + `services.dashboard.host unset (it defaults to ${DEFAULT_DASHBOARD_HOST}), and reach a `\n + 'remote dashboard through an authenticating proxy or a tunnel you control.',\n )\n this.name = 'DashboardRemoteBindRefusedError'\n }\n}\n\n/** Where this server binds when nothing says otherwise (402-05, D-07). BREAKING since v2. */\nexport const DEFAULT_DASHBOARD_HOST = '127.0.0.1'\n\ninterface StartServerOptions {\n db: DashboardDatabase\n port?: number\n /**\n * The interface this server binds (402-05, D-07 — INVK-03).\n *\n * DEFAULTS TO LOOPBACK, and a non-loopback value is REFUSED before anything listens — with no\n * exemption. This is BREAKING for anyone who relied on the previous `server.listen(port)`, which\n * bound every interface, and there is no migration flag: the v2 ethos ships no back-compat shim\n * for a hole. Remote access goes through an authenticating proxy (432 D-13's forward note).\n */\n host?: string\n uiDir?: string\n /**\n * Where this workspace writes run artifacts (`services.dashboard.artifactsDir`).\n *\n * ACCEPTED AND NOT READ BY THIS SERVER SINCE 405-07 (D-14). It used to be resolved into a\n * screenshots and a videos root that two path-serving routes and the run-deletion sweep read.\n * Refs are the only artifact addressing now, and the bytes are reached through the\n * `runs.artifact` op over the evidence store's own layout. The option stays declared because it\n * is a user-facing config key the RECORDING path still writes under; the dashboard simply no\n * longer serves or deletes anything by path.\n */\n artifactsDir?: string\n workspacePaths?: ResolvedWorkspacePaths\n configPath?: string\n // 441-21 (D-29): every config read this server serves passes through the declared mask.\n declaredSecretMask: MaskFn\n llmConfig?: DashboardLLMConfig & {\n vision?: { screenshotSize?: number; effectiveResolution?: number }\n }\n authFetch?: typeof globalThis.fetch\n /**\n * The composed agent host the chat door dispatches through (400-01, D-01).\n *\n * INJECTED by whoever starts this server — in production `agent-qa dashboard`, which composes the\n * SAME port set `agent-qa chat` does and hands it over, so the two interactive doors have one\n * answer to \"what can a conversation do\" (D-08). Absent leaves the chat routes answering 501 by\n * name: the door exists, this process was started without a host. See `chat/host.ts`.\n */\n agentHost?: AgentHost\n /**\n * The backend every dashboard run executes through (401-07, D-01/D-09/D-10 — INVK-01).\n *\n * INJECTED, ON `agentHost`'s OWN IDIOM AND FOR ITS OWN REASON. The implementation that starts a\n * run names `runs.start`, `invokeFunction` and the composed local host — all of it\n * `@vostride/agent-qa-agent*` vocabulary this package may not import (validate:arch). So\n * `agent-qa dashboard` composes it in the process that runs this server and hands it over, which\n * is what makes the run button one more caller of the op chat already uses rather than a\n * dashboard carve-out around the gates.\n *\n * ABSENT DEGRADES BY NAME, exactly as it did when the CLI binary could not be resolved: the\n * execution routes answer 503 and the queue's execute handler does nothing. A dashboard started\n * without a run door is a dashboard that cannot run tests, and it says so.\n */\n executionBackend?: ExecutionBackend\n /**\n * The run service's ports (402-01, D-02/D-06 — INVK-03).\n *\n * INJECTED, ON `agentHost`'s AND `executionBackend`'s OWN IDIOM AND FOR THEIR OWN REASON. The\n * implementations name `runs.start`, `invokeFunction` and the composed local host — all of it\n * vocabulary this package may not import (validate:arch). So `agent-qa dashboard` composes them\n * in the process that runs this server and hands them over, which is what makes the run service\n * a mountable module rather than a fourth process.\n *\n * ABSENT MEANS THE SERVICE IS NOT MOUNTED, and `/run` and its neighbours reach whatever the\n * static/SPA handling below does with an unknown path. 2026-10-01 (432-21, D-12): `agent-qa\n * dashboard` supplies it unconditionally now. It used to mount only when a run-service credential\n * was declared, and those credentials are deleted; the door is guarded by the same-site check\n * and the loopback bind like every other door here. Absent is a bare in-process mount's posture.\n */\n runService?: RunServicePorts\n /**\n * The run service's readiness predicate, served WITHOUT a token on the local dashboard API\n * (402-05, D-15 — `GET /api/run-readiness`).\n *\n * SEPARATE FROM `runService` ABOVE AND NOT DERIVED FROM IT, because a mount without the service\n * still has a browser that needs an honest readiness answer rather than a 404. `agent-qa\n * dashboard` supplies the very same function object it put on `runService.readiness`: one\n * predicate, two doors. (Until 432-21 the service was absent whenever no credential was declared.)\n */\n runServiceReadiness?: () => RunServiceReadiness\n /**\n * The run id → live `RunSession` lookup, as a FIRST-CLASS option (403 D-14 — WINDOWS #264).\n *\n * SEPARATE FROM `runService` AND NOT DERIVED FROM IT, on `runServiceReadiness`'s exact argument\n * one field up. The derivation `runService?.attach` is what made the local run-stream door\n * answer 503 about runs this very process was executing: until 432-21 `composeRunServicePorts`\n * ran only when `runServiceTokens` were declared, so the DEFAULT zero-token dashboard composed no\n * registry at all and the local door had nothing to attach to. `agent-qa dashboard` supplies this\n * from a registry hoisted above the door.\n *\n * The legacy derivation still applies when this is absent, so an in-process caller that only\n * passes `runService` keeps working byte-for-byte.\n */\n runServiceAttach?: (runId: string) => RunSession | undefined\n /**\n * The live-view seam (403 D-03/D-06): the function layer's validator, by reference, and the\n * mint dispatched through the registry.\n *\n * ABSENT MEANS NO LIVE VIEW IS SERVED — the embed route is not registered, the frame socket\n * refuses the upgrade, and `GET /api/runs/:runId/live-url` answers 503 by name. This server\n * holds NO signing key and NO token parse of its own; both are the function layer's, handed in.\n */\n liveView?: {\n validate(token: string, expect: { subject: LiveViewSubjectRef; now: number }): LiveUrlVerdict\n mintLiveUrl(runId: string, handle: number): Promise<RunsLiveUrlResult>\n /**\n * The `editor.liveurl` mint, dispatched through the registry (428 D-07). ABSENT MEANS NO\n * EDITOR VIEW IS MINTED, and `GET /api/live-editor/sessions/:id/live-url` answers 503 by name.\n */\n mintEditorLiveUrl?(sessionId: string): Promise<EditorLiveUrlResult>\n }\n /**\n * The editor-subject registry (428 D-07): the session manager registers each live editor session\n * here and the frame socket attaches editor subjects through it.\n *\n * ABSENT MEANS NO EDITOR SUBJECT IS SERVED ON THE FRAME SOCKET. `agent-qa dashboard` creates one\n * registry and hands the same object to the live-view composition and to this server.\n */\n liveEditorSubjects?: LiveEditorSubjects\n /**\n * The in-process post-processing chip relay (404-05, D-16).\n *\n * INJECTED, ON `agentHost`'s OWN IDIOM AND FOR ITS OWN REASON. The PUBLISHER is the CLI's\n * post-run chip emitter, in this same process, and this package may not import it — so\n * `agent-qa dashboard` creates one relay, hands `relay.publish` to the run door's bridge as the\n * emitter's second sink and hands the relay itself here. It has to be the SAME object: a relay\n * built inside this function would be a registry nothing publishes to, and the stream door would\n * heartbeat forever at a page whose chips are demonstrably moving.\n *\n * ABSENT MEANS NO PUSH CHANNEL, and `GET /api/runs/:id/post-processing/stream` answers 503 by\n * name. The READ route needs none of this and keeps working: polling is the floor the whole\n * design rests on, and the stream is the optimisation over it.\n */\n postProcessingRelay?: PostProcessingRelay\n}\n\nexport async function startServer(opts: StartServerOptions): Promise<{\n server: Server\n port: number\n close: () => void\n}> {\n const { db, port = 3470, uiDir, workspacePaths, configPath, llmConfig, authFetch, agentHost, executionBackend, runService, runServiceReadiness, liveView, liveEditorSubjects, postProcessingRelay } = opts\n // 403 D-14: the explicit port wins; the pre-403 derivation is the fallback for legacy callers.\n const runServiceAttach = opts.runServiceAttach ?? runService?.attach\n const host = opts.host?.trim() || DEFAULT_DASHBOARD_HOST\n\n // ---- THE BIND GUARD (402-05, D-07 — T-402-16) ---------------------------------------------\n //\n // FIRST STATEMENT WITH ANY EFFECT, and that placement is the whole mechanism. Below this line the\n // function opens a database, starts a queue, acquires Appium leases and constructs a WebSocket\n // server; a guard placed after any of them would be a guard that has to tear down what it just\n // built, and the tear-down path is where a refusal turns into a half-started process. Refusing\n // here means the refused configuration allocates nothing and listens on nothing.\n //\n // MEMBERSHIP IS `isLoopbackHost`, IMPORTED — the same predicate `LoopbackHostSchema` refines on,\n // never a second literal list (T-402-18). `services.dashboard.host` is deliberately a plain\n // string in the config schema so this decision is reachable at all, and so a loopback SPELLING\n // other than the default (`localhost`, `::1`) stays configurable.\n //\n // NO EXEMPTION — see `DashboardRemoteBindRefusedError`. A run-service credential once exempted a\n // non-loopback bind and never authenticated `/api/runs/trigger`; since 432-21 no credential\n // exists to consult.\n if (!isLoopbackHost(host)) {\n throw new DashboardRemoteBindRefusedError(host)\n }\n\n const resolvedConfigPath = configPath ?? resolve('agent-qa.config.yaml')\n const configManager = new ConfigManager(resolvedConfigPath, opts.declaredSecretMask)\n\n // Read concurrency from config (defaults to os.cpus().length)\n const config = await readConfigValues(configManager).catch(() => ({}))\n const concurrency = typeof (config as any).concurrency === 'number'\n ? (config as any).concurrency\n : cpus().length\n\n const finalizeRunArtifactBestEffort = (\n runId: string,\n code: string,\n phase: string,\n message: string,\n runtime: Record<string, unknown> = {},\n ): void => {\n try {\n const artifact = db.getRunArtifact(runId)\n if (!artifact || artifact.finalizedAt) return\n db.finalizeRunArtifact(runId, {\n runtime,\n errors: [{ code, phase, message }],\n } as any)\n } catch { /* best-effort cleanup */ }\n }\n\n // THE RUN'S TERMINAL STATE, RECONCILED WHERE THE CHILD'S EXIT USED TO BE (401-07, D-04/D-09).\n //\n // This body is the `onProcessClose` reconciliation, unchanged in what it writes. What changed is\n // where the facts come from: the status is the bus's own ground truth rather than an exit code\n // read through a scrape, and the diagnostic lines are the failure's OWN message rather than a\n // tail of the child's stderr. The three things it does — reconcile a db row still reading\n // `running`, release the run's Appium lease, free the queue slot — are the three things the\n // process exit was load-bearing for, and all three still need doing.\n executionBackend?.on('run-settled', (\n runId: string,\n status: RunSettledStatus,\n details: RunSettledDetails,\n ) => {\n // The run settled but the DB row is still 'running' — update it so the dashboard does not\n // show a stuck run. 2026-10-17 (444-06, D-31): a row the run already finished is never rewritten.\n try {\n const run = db.getRun(runId)\n const output = details.output\n if (run && run.status === 'running') {\n const duration = run.startedAt\n ? Date.now() - new Date(run.startedAt).getTime()\n : 0\n\n let dbStatus: string\n let failureSummary: string | undefined\n let errorLog: string | undefined\n // 401-18 (G-401-16): the neutral prose a REFUSAL is carrying, held aside so the errorLog\n // composition below can prefer it over the diagnostic lines. Undefined on every other arm,\n // which is what keeps those arms byte-identical.\n let refusalProse: string | undefined\n if (status === 'cancelled') {\n dbStatus = 'cancelled'\n failureSummary = undefined\n } else if (status === 'timeout') {\n dbStatus = 'failed'\n failureSummary = 'Test timed out -- process was killed'\n } else if (details.refusedBeforeStart) {\n // A REFUSAL IS NOT A PROCESS EXIT (401-18, G-401-16).\n //\n // Branched on the FACT the settle carries, above the `completed` arm and above the regex\n // fallback, because both of those describe a run that ran. A run the gate refused before\n // anything started has no exit to report — and the summary is the line a runs list shows,\n // so it was the sentence a person read about every denied dashboard run.\n //\n // THE PROSE IS THE GATE'S NEUTRAL FORM, NOT ITS CANONICAL ONE. The canonical sentence\n // named the session trust flag, declared on one CLI command, and this reader is in a\n // browser. Where the rejection carries no neutral form — an unrecognised request field, an\n // input error — its own message is used, which names no surface's affordance either.\n //\n // 2026-09-30, 432-09 (D-15): the refusal is this plain sentence. No remedy list rides it.\n dbStatus = 'failed'\n refusalProse = details.neutralReason ?? details.reason\n failureSummary = refusalProse\n ? `Refused before the run started: ${refusalProse}`.slice(0, 300)\n : 'Refused before the run started'\n } else if (status === 'completed') {\n dbStatus = 'failed'\n failureSummary = 'Process exited before test completed'\n } else {\n dbStatus = 'failed'\n const outputLines = output.map(l => l.replace(/\\x1b\\[[0-9;]*m/g, ''))\n const meaningfulLine = [...outputLines].reverse().find(l =>\n /error/i.test(l) || l.includes('Parse') || l.includes('not found') || l.includes('rejected')\n )\n failureSummary = meaningfulLine\n ? meaningfulLine.slice(0, 300)\n : 'Process exited before test completed'\n }\n\n if (refusalProse !== undefined) {\n // The refused run's ONLY record of why it never happened. The diagnostic lines it\n // replaces are the rejection's canonical message — the one carrying the CLI flag.\n errorLog = refusalProse.replace(/\\x1b\\[[0-9;]*m/g, '').slice(-10000) || undefined\n } else if (dbStatus === 'failed' && output.length) {\n errorLog = [...output]\n .join('\\n')\n .replace(/\\x1b\\[[0-9;]*m/g, '')\n .slice(-10000) || undefined\n }\n\n // 2026-08-24 (Phase 402 plan 09, D-11): THE SUITE-PARENT STATUS FOLD IS RETIRED WITH THE\n // CHILDREN IT FOLDED — the same retirement, at the same site, as the retry-child block\n // below, for the same reason.\n //\n // ~75 lines stood here: force every `running`/`pending` child terminal, re-read them, and\n // derive the parent's status as the worst child status. A suite is now ONE run row with\n // member handles (D-11, 402-04); nothing writes the run row's parent-link column, so the\n // fold's own `updatedChildren.length === 0` branch was the only branch it could still take,\n // and that is what the common path below does. What a suite run GAINS by falling through\n // is the diagnostic `failureSummary` and the captured `errorLog` the fold discarded in\n // favour of the constant sentence \"Suite test(s) failed\".\n //\n // HISTORICAL ROWS ARE UNAFFECTED: this fold only ever ran when a live process closed, and\n // no live process owns pre-402 children. The read side that renders them is untouched.\n\n // 2026-08-23 (Phase 401 plan 07, D-12): THE RETRY-CHILD CLASSIFICATION IS RETIRED WITH\n // THE MACHINERY THAT CREATED THE CHILDREN.\n //\n // Retry children were minted by the RUNNER PROCESS, off variables the queue put in a\n // child's environment. There is no child, and nothing mints a retry child any more. The\n // ~60 lines that stood here folded those children into a `flaky` / `passed` / `cancelled`\n // verdict on the parent; with no children to fold they could only ever have been dead\n // code that read as live policy.\n //\n // WHERE RETRY-ON-FAILURE LIVES NOW: the runner's own re-run machinery (runner.md §7). It is\n // the runner's concern and always was — a queue that re-spawns a process is retrying the\n // WRAPPER, which is why a dashboard retry could report `flaky` for a run whose flakiness\n // nothing had measured.\n //\n // WHAT DEGRADES, HONESTLY (DETL-06-adjacent debris, recorded rather than hidden): the\n // `runs.retry_count` / `runs.max_retries` COLUMNS and the dashboard UI that reads them\n // stay, and stop receiving new writes. Historical rows keep their values. A successor retry\n // UX, if one is wanted, is M5's to design against the runner's machinery — it is filed in\n // `.planning/phases/401-.../deferred-items.md` rather than left as an empty affordance\n // somebody re-implements at the queue.\n\n db.updateRun(runId, {\n status: dbStatus,\n duration,\n endedAt: new Date().toISOString(),\n failureSummary,\n errorLog,\n })\n finalizeRunArtifactBestEffort(\n runId,\n 'process-close',\n 'process-close',\n failureSummary ?? 'Process closed',\n { status: dbStatus, finalStatus: dbStatus, processStatus: status, duration },\n )\n }\n } catch { /* best-effort */ }\n\n releaseMobileAppiumLease(runId, status)\n jobQueue.onSlotFreed(runId)\n })\n\n // 2026-10-16 (442-04, D-05/D-04): only runs whose owning process is provably gone are finalized.\n let finalized = 0\n for (const { id, owner } of db.listRunningRunOwners()) {\n if (classifyRunOwner(owner, db.runOwnership) === 'gone' && db.finalizeOrphanRun(id, owner)) {\n finalized++\n }\n }\n if (finalized > 0) {\n console.log(`Finalized ${finalized} run(s) whose agent-qa process had ended`)\n }\n\n // Log any pending rows left from previous session (benign — picked up when queue starts)\n const pendingOrphans = db.getRuns({ statuses: ['pending'] })\n if (pendingOrphans.length > 0) {\n console.log(`Found ${pendingOrphans.length} pending run(s) from previous session — will be processed when queue starts`)\n }\n\n // Appium lifecycle manager — auto-starts Appium for mobile tests\n const appiumManager = new AppiumManager()\n const mobileRuns = new Map<string, 'android' | 'ios'>()\n\n const releaseMobileAppiumLease = (runId: string, reason: string): void => {\n const platform = mobileRuns.get(runId)\n if (!platform) return\n mobileRuns.delete(runId)\n appiumManager.releaseLease(runId, reason)\n }\n\n const releaseAllMobileAppiumLeases = (reason: string): void => {\n for (const runId of [...mobileRuns.keys()]) {\n releaseMobileAppiumLease(runId, reason)\n }\n }\n\n // The persistent RUN QUEUE — all run triggers route through this. Named per D-21: it is not\n // the curation queue and not the agent job queue. The `JobQueue` class name is v1 vocabulary\n // that D-21 leaves unrenamed; only what an operator reads carries the qualifier.\n const jobQueue = new JobQueue({\n db,\n concurrency,\n requestStop: (runId) => executionBackend?.kill(runId) ?? false,\n })\n console.log(`Run queue started with ${concurrency} concurrency slot(s)`)\n console.log('Appium lifecycle manager initialized (auto-start on first mobile test)')\n\n // Wire the run queue's 'execute' event to the injected execution backend (401-07, D-09/D-10).\n //\n // THE QUEUE ITSELF IS UNTOUCHED — its slots, its polling, its ordering and its cancel signal are\n // the same object they were, which is D-09's build-order pin in one line: what changed underneath\n // it is who executes, not who schedules.\n jobQueue.on('execute', async (run) => {\n if (!executionBackend) return\n\n const platform = run.platform ?? 'web'\n const isMobile = platform === 'ios' || platform === 'android'\n\n // Ensure Appium is running before mobile test execution\n if (isMobile) {\n try {\n await appiumManager.acquireLease({ runId: run.id, platform })\n mobileRuns.set(run.id, platform)\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n console.error(`Failed to start Appium for run ${run.id}: ${message}`)\n db.updateRun(run.id, {\n status: 'failed',\n failureSummary: `Appium server failed to start: ${message}`,\n endedAt: new Date().toISOString(),\n })\n finalizeRunArtifactBestEffort(run.id, 'appium-startup', 'appium-startup', `Appium server failed to start: ${message}`, { status: 'failed' })\n jobQueue.onSlotFreed(run.id)\n return\n }\n }\n\n const meta = (run.metadata ?? {}) as Record<string, unknown>\n const args = Array.isArray(meta.args)\n ? meta.args.filter((arg): arg is string => typeof arg === 'string')\n : []\n if (args.length === 0 && run.filePath) {\n args.push(run.filePath)\n }\n executionBackend.execute({\n runId: run.id,\n args,\n source: meta.isSuite ? 'suite' : 'dashboard',\n // 2026-10-01 (432-14, D-14): no confirm scope is read off the row any more. The browser that\n // triggered a run is not asked anything, so nothing about it has to survive the wait.\n attributes: run.attributes,\n // T-401-G26 (401-23): a persisted row's timeout is VALIDATED at the seam that consumes it.\n // `in-process-backend.ts:211` reads `opts.timeout ?? defaultTimeout` and validates AFTER, so\n // any non-nullish nonsense here skips the default and leaves the run with no reclamation\n // timer at all. An unusable value falls back to the backend's default rather than a number\n // this call invented.\n timeout: sanitizeQueuedExecutionTimeout(meta.timeout),\n // THE LEASE ABOVE IS UNCHANGED; ONLY ITS DELIVERY IS. `acquireLease` still runs where it ran,\n // still keys on this run id and still owns the bundled Appium's lifecycle (design-of-record).\n // What used to ride `AGENT_QA_APPIUM_URL` in a child's environment now travels as an\n // argument, because there is no child to carry an environment.\n ...(isMobile ? { appiumUrl: appiumManager.getUrl() } : {}),\n })\n })\n\n // Start the queue polling loop\n jobQueue.start()\n\n // TestFileManager for test file CRUD\n const testFileManager = workspacePaths ? new TestFileManager(workspacePaths) : undefined\n\n const suiteFileManager = workspacePaths ? new SuiteFileManager(workspacePaths, testFileManager) : undefined\n\n const sessionManager = new SessionManager({\n appiumManager,\n configManager,\n configPath: resolvedConfigPath,\n // 428 D-07: each created session registers here, which is what the frame socket attaches.\n ...(liveEditorSubjects === undefined ? {} : { liveEditorSubjects }),\n })\n\n // 428 D-07: the embed route and the frame socket serve a live view when the seam is bound and at\n // least one subject registry is present. The proxy dispatches on the token's signed kind, so a\n // missing registry is only a lookup that answers nothing.\n const servesLiveView = liveView !== undefined\n && (runServiceAttach !== undefined || liveEditorSubjects !== undefined)\n\n const apiRouter = createRouter({\n db,\n workspacePaths,\n // 401-07: conditionally spread on the same house rule `agentHost` follows — an absent\n // dependency is an ABSENT field, never a present `undefined`, so the router's own 503 arm is\n // what decides, in one place.\n ...(executionBackend === undefined ? {} : { executionBackend }),\n jobQueue,\n testFileManager,\n suiteFileManager,\n configManager,\n configPath: resolvedConfigPath,\n declaredSecretMask: opts.declaredSecretMask,\n llmConfig,\n authFetch,\n sessionManager,\n // 400-01: conditionally spread on the house rule an absent dependency is an ABSENT field and\n // never a present `undefined` — the router's own 501 arm is what decides, in one place.\n ...(agentHost === undefined ? {} : { agentHost }),\n // 402-05 (D-15): the same conditional-spread house rule. Absent means a legacy mount rather\n // than an unconfigured service, and the router's own 503 arm is what decides, in one place.\n ...(runServiceReadiness === undefined ? {} : { runServiceReadiness }),\n // 402-08 (D-01): the LOCAL run-stream door's attach port, READ OFF `runService` rather than\n // composed again. That derivation is the \"one session registry serves both doors\" claim in its\n // structural form — there is no second wiring a composition root could forget or point\n // somewhere else, and the two doors cannot end up attached to different registries. Absent\n // `runService` means no registry exists at all, so the same conditional-spread house rule\n // applies and the router's own 503 arm decides.\n ...(runServiceAttach === undefined ? {} : { runServiceAttach }),\n // 403 D-03: the mint route's port, on the same conditional-spread house rule — absent means\n // this host serves no live view and the route's own 503 arm decides, in one place.\n ...(liveView === undefined ? {} : { mintLiveUrl: liveView.mintLiveUrl }),\n // 428 D-07: the editor mint, on the same house rule — absent means the editor mint route's own\n // 503 decides.\n ...(liveView?.mintEditorLiveUrl === undefined\n ? {}\n : { mintEditorLiveUrl: liveView.mintEditorLiveUrl }),\n // 404-05 (D-16): the same conditional-spread house rule — absent means this host serves no\n // post-processing push channel and the stream arm's own 503 decides, in one place.\n ...(postProcessingRelay === undefined ? {} : { postProcessingRelay }),\n })\n\n // 402-01: composed once, at start, on `apiRouter`'s own idiom. Absent ports mean no router and\n // therefore no mount — the path check below is skipped entirely and this server behaves as today.\n const runServiceRouter = runService === undefined ? undefined : createRunServiceRoutes(runService)\n\n // THE PROCESS-LEVEL BACKSTOP AND THE GUARDED PARSE (400-16, gap 7). Every request enters here, so\n // this is the choke point: an unparseable request line is answered 400 before any frame below can\n // see it, and the whole body runs inside a `try` so a synchronous throw out of `apiRouter` — or a\n // rejection of anything awaited below — becomes a 500 instead of an unhandled rejection that ends\n // the process. `server.ts`'s listener is `async`, which is why the ONE `catch` covers both. The\n // full throw-path enumeration, and what each frame owns, lives in `./request-url.ts`.\n const server = createServer(async (req, res) => {\n try {\n const url = tryParseRequestUrl(req)\n if (url === undefined) {\n refuseUnparseableRequest(res)\n return\n }\n const path = url.pathname\n\n // THE RUN SERVICE, CONSULTED FIRST (402-01, D-02/D-06 — INVK-03).\n //\n // ABOVE EVERYTHING, INCLUDING THE `OPTIONS` PREFLIGHT ARM AND THE SPA FALLBACK, and the\n // order is the guard. The preflight arm below writes a wildcard `Access-Control-Allow-Origin`\n // and the SPA fallback answers 200 with an HTML page for any unknown path; either reaching\n // this surface would be a grant nobody decided. `ownsRunServicePath` is METHOD-BLIND for\n // exactly that reason — every request to a service path is this door's to refuse, and its\n // same-site guard runs before its route table (432-21, D-13).\n if (runServiceRouter !== undefined && ownsRunServicePath(path)) {\n runServiceRouter(req, res)\n return\n }\n\n // API routes\n if (path.startsWith('/api/')) {\n apiRouter(req, res)\n return\n }\n\n // OPTIONS preflight\n if (req.method === 'OPTIONS') {\n res.writeHead(204, {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type',\n })\n res.end()\n return\n }\n\n // GET /live/:runId — THE SERVED EMBED PAGE (403 D-06).\n //\n // REGISTERED ABOVE THE STATIC/SPA ARM, and the ORDER IS THE MECHANISM (RESEARCH Pitfall 10).\n // The SPA fallback below answers `index.html` for ANY unknown path, so a `/live/` arm placed\n // after it would render the React dashboard inside every embedding iframe — a failure that\n // looks like a styling bug and is actually the contract being unreachable. `live-view-anchors`\n // and the tracer cell both assert this route's answer is a live-view document.\n //\n // NO `X-Frame-Options` — the whole point of this page is that a host embeds it. What replaces\n // it is a CSP that permits exactly one nonce'd inline script and nothing else, plus\n // `Referrer-Policy: no-referrer` so the fragment-carried token cannot ride a `Referer` out\n // (T-403-12).\n if (req.method === 'GET' && path.startsWith(LIVE_EMBED_PATH_PREFIX)) {\n if (!servesLiveView) {\n res.writeHead(503, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify({ error: 'live_view_unavailable' }))\n return\n }\n let embedRunId: string\n try {\n embedRunId = decodeURIComponent(path.slice(LIVE_EMBED_PATH_PREFIX.length))\n } catch {\n res.writeHead(404, { 'Content-Type': 'text/plain' })\n res.end('Not Found')\n return\n }\n if (embedRunId === '' || embedRunId.includes('/')) {\n res.writeHead(404, { 'Content-Type': 'text/plain' })\n res.end('Not Found')\n return\n }\n const nonce = randomBytes(16).toString('base64')\n const body = renderLiveEmbedPage({ runId: embedRunId, nonce })\n res.writeHead(200, {\n 'Content-Type': 'text/html; charset=utf-8',\n 'Cache-Control': 'no-store',\n 'Referrer-Policy': 'no-referrer',\n 'Content-Security-Policy':\n `default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; `\n + \"connect-src 'self' ws: wss:; img-src blob: data:\",\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n return\n }\n\n // Static file serving\n if (uiDir) {\n const filePath = path === '/' ? join(uiDir, 'index.html') : join(uiDir, path)\n\n try {\n const fileStat = await stat(filePath)\n if (fileStat.isFile()) {\n const content = await readFile(filePath)\n const ext = extname(filePath)\n const contentType = MIME_TYPES[ext] || 'application/octet-stream'\n res.writeHead(200, {\n 'Content-Type': contentType,\n 'Content-Length': content.length,\n 'Access-Control-Allow-Origin': '*',\n })\n res.end(content)\n return\n }\n } catch {\n // File not found — fall through to SPA fallback\n }\n\n // SPA fallback: serve index.html for non-file paths\n try {\n const indexPath = join(uiDir, 'index.html')\n const content = await readFile(indexPath)\n res.writeHead(200, {\n 'Content-Type': 'text/html',\n 'Content-Length': content.length,\n 'Access-Control-Allow-Origin': '*',\n })\n res.end(content)\n return\n } catch {\n // No index.html available\n }\n }\n\n res.writeHead(404, { 'Content-Type': 'text/plain' })\n res.end('Not Found')\n } catch (error) {\n backstopServerError(res, req, error)\n }\n })\n\n // Bytes Node's own parser rejects never reach the listener above, and an unhandled `clientError`\n // is an uncaught error on the server. Answering it in fixed bytes keeps that class inside the\n // same posture as the rest of the enumeration.\n server.on('clientError', (_error, socket) => {\n if (socket.destroyed) return\n if (socket.writable) {\n socket.end('HTTP/1.1 400 Bad Request\\r\\nConnection: close\\r\\nContent-Length: 0\\r\\n\\r\\n')\n return\n }\n socket.destroy()\n })\n\n const wss = new WebSocketServer({ noServer: true })\n\n server.on('upgrade', (request, socket, head) => {\n // SYNCHRONOUS, so a throw here is an uncaught EXCEPTION the listener's backstop cannot reach.\n // The guarded parse is the only thing standing between `GET //%` with an `Upgrade` header and a\n // dead process; `undefined` takes this handler's existing refusal idiom.\n const url = tryParseRequestUrl(request)\n if (url === undefined) {\n socket.destroy()\n return\n }\n // 403 D-06: the frame socket. The run id is the ONLY query parameter — the token arrives in\n // the first text message and nowhere else, so a refused upgrade has never seen a credential.\n if (url.pathname === LIVE_VIEW_WS_PATH) {\n const hostRefusal = refuseNonLoopbackHost(request)\n if (hostRefusal !== undefined) {\n socket.destroy()\n return\n }\n\n // DEFENSE IN DEPTH, AND NOT THE CREDENTIAL — 403 gap round 1, T-403-21.\n //\n // A WebSocket upgrade is exempt from CORS entirely, so the mint door's same-site guard is not\n // inherited here. This rung refuses the ONE shape it can honestly refuse: a present `Origin`\n // that names another host. It is explicitly NOT a credential, and the reason is worth writing\n // down rather than rediscovering. The legitimate embed page runs in an iframe sandboxed\n // WITHOUT `allow-same-origin` (`live-preview.tsx`), so its upgrade carries the literal\n // `null` — and a sandboxed ATTACKER iframe sends exactly the same thing. Accepting `null` is\n // therefore mandatory for the real embed and worthless as a gate, and dropping the sandbox to\n // make this check \"real\" would hand the embed same-origin access to the dashboard, which is a\n // worse trade than the one this rung declines to make.\n //\n // THE CREDENTIAL REMAINS THE TOKEN validated in the first `hello` message, minted only by a\n // door that now refuses a cross-site caller. An absent `Origin` is the non-browser client and\n // is accepted, on the mint door's own reasoning.\n const upgradeOrigin = request.headers.origin\n if (typeof upgradeOrigin === 'string' && upgradeOrigin !== '' && upgradeOrigin !== 'null') {\n const upgradeHost = typeof request.headers.host === 'string' ? request.headers.host.toLowerCase() : ''\n let upgradeOriginHost = ''\n try {\n upgradeOriginHost = new URL(upgradeOrigin).host.toLowerCase()\n } catch {\n upgradeOriginHost = ''\n }\n // Hosts, not schemes — the same reasoning the mint door's guard records: the bound door\n // speaks `http` on loopback and an operator may put an `https` terminator in front of it.\n if (upgradeOriginHost === '' || upgradeHost === '' || upgradeOriginHost !== upgradeHost) {\n socket.destroy()\n return\n }\n }\n const liveRunId = url.searchParams.get('runId')\n if (liveRunId === null || liveRunId === '' || liveView === undefined || !servesLiveView) {\n socket.destroy()\n return\n }\n const proxy = createFrameProxy({\n validate: liveView.validate,\n attach: runServiceAttach ?? ((): undefined => undefined),\n ...(liveEditorSubjects === undefined ? {} : { attachEditor: liveEditorSubjects.attach }),\n })\n wss.handleUpgrade(request, socket, head, (ws) => { proxy(ws, liveRunId) })\n return\n }\n if (url.pathname === '/api/live-editor/ws') {\n // THE SAME-SITE GUARD, FIRST (428 D-08 — WINDOWS #275). This socket drives a browser, and a\n // WebSocket upgrade is exempt from CORS, so a page on another origin could otherwise open it.\n // Unlike the frame socket there is no sandboxed embed to admit, so the literal `null` is\n // refused with every other foreign origin. A refusal is a bare destroy: nothing is written\n // back to a cross-site caller, not even a status line.\n const crossSite = refuseCrossSiteRequest(request)\n if (crossSite !== undefined) {\n socket.destroy()\n return\n }\n const sessionId = url.searchParams.get('sessionId')\n if (!sessionId) {\n socket.destroy()\n return\n }\n const session = sessionManager.getSession(sessionId)\n if (!session) {\n // 428 P5: an admitted caller asking for a session this process does not hold is told so by\n // name, so the page can say the session ended instead of \"Disconnected\".\n wss.handleUpgrade(request, socket, head, (ws) => {\n ws.close(LIVE_EDITOR_UNKNOWN_SESSION_CLOSE_CODE, 'unknown_session')\n })\n return\n }\n\n wss.handleUpgrade(request, socket, head, (ws) => {\n session.clearIdleTimer()\n const handler = createSessionHandler(session, () => {\n void sessionManager.terminateSession(sessionId).catch((error: unknown) => {\n console.error(`[live-editor] could not end session ${sessionId}`, error)\n })\n }, (event) => {\n db.insertTokenEvent(event)\n }, testFileManager)\n handler(ws)\n })\n } else {\n socket.destroy()\n }\n })\n\n const gracefulShutdown = () => {\n sessionManager.cleanupAll()\n }\n process.on('SIGTERM', gracefulShutdown)\n process.on('SIGINT', gracefulShutdown)\n\n // 396-01 D-10: the `services.mcp` read, the endpoint resolution, the `node:http` MCP listener and\n // the `agent-qa.mcp.server.lifecycle` analytics that reported on it all lived here and are gone.\n // The config KEY itself is deliberately retained in `ServicesSchema` — that object is `.strict()`,\n // so deleting the key would make every existing project that declares `services.mcp` fail to\n // parse.\n const cleanupRuntimeResources = () => {\n jobQueue.stop()\n executionBackend?.killAll()\n releaseAllMobileAppiumLeases('server-startup-error')\n appiumManager.shutdown()\n sessionManager.cleanupAll()\n db.close()\n }\n\n return new Promise((resolve, reject) => {\n const onError = (err: Error) => {\n cleanupRuntimeResources()\n reject(err)\n }\n server.once('error', onError)\n server.listen(port, host, () => {\n server.off('error', onError)\n // A LOOPBACK BIND PRINTS THE LINE IT ALWAYS PRINTED, BYTE FOR BYTE. That is not cosmetic\n // conservatism: this line is the readiness signal three shipped conformance harnesses parse\n // a port out of. The non-loopback arm is unreachable since the bind guard above lost its\n // credential exemption (402 verification); it is kept so the line never names a `localhost`\n // that is not where the server is.\n console.log(\n isLoopbackHost(host)\n ? `Dashboard running at http://localhost:${port}`\n : `Dashboard running at http://${host.includes(':') ? `[${host}]` : host}:${port}`,\n )\n resolve({\n server,\n port,\n close: () => {\n jobQueue.stop()\n executionBackend?.killAll()\n releaseAllMobileAppiumLeases('server-close')\n appiumManager.shutdown()\n sessionManager.cleanupAll()\n server.close()\n db.close()\n },\n })\n })\n })\n}\n","import { spawnSync } from 'node:child_process'\nimport { createHash, randomUUID } from 'node:crypto'\nimport { readlinkSync } from 'node:fs'\nimport { hostname as osHostname } from 'node:os'\n\nconst PLATFORM_UUID_LINE = /\"IOPlatformUUID\" = \"([^\"]*)\"/\nconst UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\nconst PID_NAMESPACE_LINK = /^pid:\\[(\\d+)\\]$/\n\nfunction readIoregPlatformUuid(): string | undefined {\n const result = spawnSync('/usr/sbin/ioreg', ['-rd1', '-c', 'IOPlatformExpertDevice'], {\n encoding: 'utf8',\n env: { LC_ALL: 'C', LANG: 'C' },\n timeout: 1_000,\n windowsHide: true,\n })\n if (result.status !== 0 || typeof result.stdout !== 'string') return undefined\n return PLATFORM_UUID_LINE.exec(result.stdout)?.[1]\n}\n\nfunction readUuidOrUndefined(read: () => string | undefined): string | undefined {\n try {\n const uuid = read()\n return uuid !== undefined && UUID_SHAPE.test(uuid) ? uuid : undefined\n } catch {\n return undefined\n }\n}\n\nfunction readProcPidNamespace(): string | undefined {\n return readlinkSync('/proc/self/ns/pid')\n}\n\nfunction readNamespaceInodeOrUndefined(read: () => string | undefined): string | undefined {\n try {\n const link = read()\n return link === undefined ? undefined : PID_NAMESPACE_LINK.exec(link)?.[1]\n } catch {\n return undefined\n }\n}\n\n// 2026-10-16 (442-17, GAP-D4): macOS host names follow the network; the hardware UUID does not.\n// 2026-10-16 (442-21, GAP-D9): Linux names its pid namespace; one it cannot read matches no other process.\nexport function createRunOwnerHostResolver({\n platform = process.platform,\n hostname = osHostname,\n readPlatformUuid = readIoregPlatformUuid,\n readPidNamespace = readProcPidNamespace,\n}: {\n platform?: NodeJS.Platform\n hostname?: () => string\n readPlatformUuid?: () => string | undefined\n readPidNamespace?: () => string | undefined\n} = {}): () => string {\n let identity: string | undefined\n let unreadNamespace: string | undefined\n return () => {\n if (platform === 'linux') {\n if (identity !== undefined) return identity\n const inode = readNamespaceInodeOrUndefined(readPidNamespace)\n if (inode === undefined) {\n unreadNamespace ??= `linux-pidns-unread:${randomUUID()}`\n return unreadNamespace\n }\n identity = `linux-pidns:${inode}:${hostname()}`\n return identity\n }\n if (platform !== 'darwin') return hostname()\n if (identity !== undefined) return identity\n const uuid = readUuidOrUndefined(readPlatformUuid)\n if (uuid === undefined) return `hostname:${hostname()}`\n identity = `macos-uuid-sha256:${createHash('sha256').update(uuid.toUpperCase()).digest('hex')}`\n return identity\n }\n}\n\nexport const resolveRunOwnerHost = createRunOwnerHostResolver()\n","import { resolveRunOwnerHost } from './run-owner-host.js'\n\nexport interface RunOwner {\n readonly pid: number\n readonly incarnation: string | null\n readonly host: string\n}\n\nexport interface RunOwnerProbe {\n isAlive(pid: number): boolean\n incarnationOf(pid: number): string | undefined\n}\n\nexport interface RunOwnership {\n readonly self: RunOwner\n readonly probe: RunOwnerProbe\n}\n\nexport interface RunOwnershipInput {\n readonly self: Omit<RunOwner, 'host'> & { readonly host?: string }\n readonly probe: RunOwnerProbe\n}\n\nexport function completeRunOwnership(input: RunOwnershipInput): RunOwnership {\n return {\n get self() {\n const { pid, incarnation, host } = input.self\n return { pid, incarnation, host: host ?? resolveRunOwnerHost() }\n },\n probe: input.probe,\n }\n}\n\nexport type RunOwnerState = 'self' | 'alive' | 'gone' | 'unknown'\n\nfunction incarnationFormat(token: string): string {\n const separator = token.indexOf(':')\n return separator < 0 ? '' : token.slice(0, separator)\n}\n\n// 2026-10-16 (442-01, D-02): gone only on proof (a dead pid or a changed start time); else unknown.\n// 442-14 (GAP-D1): a start time stamped in another format is not proof.\n// 442-15 (GAP-D2): a missing start time is never an identity; self needs two equal non-null ones.\n// 442-16 (GAP-D3): a start-time read that throws is unknown, like a liveness probe that throws.\nexport function classifyRunOwner(owner: RunOwner, ownership: RunOwnership): RunOwnerState {\n const { self, probe } = ownership\n if (owner.host !== self.host) return 'unknown'\n if (\n owner.pid === self.pid\n && owner.incarnation !== null\n && owner.incarnation === self.incarnation\n ) return 'self'\n let alive: boolean\n try {\n alive = probe.isAlive(owner.pid)\n } catch {\n return 'unknown'\n }\n if (!alive) return 'gone'\n if (owner.incarnation === null) return 'unknown'\n let current: string | undefined\n try {\n current = probe.incarnationOf(owner.pid)\n } catch {\n return 'unknown'\n }\n if (current === undefined) return 'unknown'\n const stampedFormat = incarnationFormat(owner.incarnation)\n if (incarnationFormat(current) !== stampedFormat) return 'unknown'\n return current === owner.incarnation ? 'alive' : 'gone'\n}\n\nexport const orphanSummary = (pid: number): string =>\n `The process running this run (pid ${pid}) ended before it finished.`\n\nexport const ownedElsewhere = (pid: number): string =>\n `This run belongs to another agent-qa process (pid ${pid}). Stop it there with Ctrl+C.`\n\nfunction signalZeroIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code\n if (code === 'ESRCH') return false\n if (code === 'EPERM') return true\n throw error\n }\n}\n\n// 2026-10-16 (442-01, D-02): with no incarnation reader, a live pid can only classify as unknown.\nexport function defaultRunOwnership(): RunOwnership {\n return {\n self: { pid: process.pid, incarnation: null, host: resolveRunOwnerHost() },\n probe: { isAlive: signalZeroIsAlive, incarnationOf: () => undefined },\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { randomUUID } from 'node:crypto'\nimport { readFile, writeFile, stat, readdir, rm } from 'node:fs/promises'\nimport { join, isAbsolute, basename, resolve, dirname } from 'node:path'\n\nimport type { AttributePredicate, DashboardDatabase, InsightsBreakdownDimension, RunArtifactRow, RunRow } from '../db/database.js'\nimport { isRunStatusWord, memberOutcomeClass, runStatusClass, type RunStatusClass } from '../db/run-status-class.js'\nimport type { ExecutionBackend } from '../execution/execution-backend.js'\nimport type { JobQueue } from '../queue/job-queue.js'\nimport {\n extractTestFileMetadata,\n targetsForMarkerCheck,\n type SupportedPlatform,\n type TestFileManager,\n} from '../tests/test-file-manager.js'\nimport type { SuiteFileManager } from '../tests/suite-file-manager.js'\nimport { readConfigValues, type ConfigManager } from '../config/index.js'\nimport { holdsShownMarker } from '../config/config-manager.js'\nimport { createUndoStore, UNDO_RETENTION_MS } from '../config/undo-store.js'\nimport { HookRegistryManager, isHookRegistryMutationError } from '../hooks/hook-registry-manager.js'\nimport { readJsonBody } from './body-parser.js'\nimport {\n LivePlannerLimitsRefusedError,\n LiveProductionRefusedError,\n liveProductionRefusal,\n resolveLivePlannerLimits,\n resolveLiveTargetProduction,\n} from '../live-editor/live-session.js'\nimport { refuseCrossSiteRequest } from './cross-site.js'\nimport { tryParseRequestUrl } from './request-url.js'\nimport type { AgentHost } from '../chat/host.js'\nimport {\n classifyProviderError,\n extractProviderError,\n LlmCredentialMoveRequestSchema,\n MARKER_WRITTEN_BACK_SENTENCE,\n maskPayloadStrings,\n maskPayloadTree,\n parseHandleParam,\n providerErrorSentence,\n RecordChangeSchema,\n RunsPostProcessingInputSchema,\n} from '@vostride/agent-qa-schema'\nimport type {\n EditorLiveUrlResult,\n MaskFn,\n PostProcessingStatus,\n RunServiceReadiness,\n RunSession,\n RunsLiveUrlResult,\n} from '@vostride/agent-qa-schema'\nimport {\n handleParamOf,\n lastEventIdParamOf,\n resumePointOf,\n runDenialOf,\n serveRunEventStream,\n} from '../run-service/run-service-routes.js'\n// 404-05 (D-16/D-18): the post-processing pair — the read a page polls and the dedicated live\n// channel. Two arms below, both above the `/api/runs/:id` catch-all, both formatting nothing.\nimport {\n servePostProcessingRead,\n servePostProcessingStream,\n} from '../run-service/post-processing-routes.js'\n// 405-05 (D-12/D-13): the ref-resolving artifact read, on the arm below's own footing — the bytes\n// cross the function layer and this file constructs no evidence store.\n// 405-01 (D-03): the durable run-detail read. One arm below, above the `/api/runs/:id` catch-all,\n// formatting nothing and opening no database.\nimport {\n serveRunArtifact,\n serveRunDetailRead,\n serveRunEvidenceRead,\n serveRunMarkPreviewRead,\n serveRunMarksHistoryRead,\n} from '../run-service/run-detail-routes.js'\n// 406-01 (D-04): the failure view's read. One arm below, beside the detail arm and above the\n// `/api/runs/:id` catch-all, formatting nothing and opening no database.\nimport { serveRunAnalysisRead } from '../run-service/run-analysis-routes.js'\n// 407-01 (D-05): the Knowledge panel's read — what a run used and learned. One arm below, beside\n// the analysis arm and above the `/api/runs/:id` catch-all, formatting nothing and opening no\n// database.\nimport { readRunKnowledge, serveRunKnowledgeRead } from '../run-service/run-knowledge-routes.js'\nimport { registerRunMarkRoute } from '../run-service/run-mark-routes.js'\nimport {\n registerConfigRevisionRoute,\n registerConfigUndoRoute,\n registerConfigWriteRoute,\n} from './config-routes.js'\nimport { createConnectInFlight, registerLlmConnectRoute } from './llm-connect-route.js'\nimport type { PostProcessingRelay } from '../execution/post-processing-relay.js'\nimport type { LLMAuthProviderPlugin, OAuthTokens } from '@vostride/agent-qa-core'\nimport { AuthStateNameSchema, buildInternalRunAttributes, mergeRunAttributes, readAuth, writeAuth, removeAuth, getAgentQaVersion, getAgentQaUpdateStatus, getLLMAuthProviderPlugin, listAuthStateMetadata, listLLMAuthProviderPlugins, ModelConfigSchema, NameSlugSchema, TimeoutConfigSchema, AgentQaConfigSchema, TestDefinitionSchema, SuiteDefinitionSchema, parseEnvFile, serializeEnvFile, parseHooksFile, RUNTIME_IMAGE_MAP, validateUserRunAttributes, discoverWorkspaceFiles, isWorkspacePathMatch, resolveWorkspaceFileTarget, SizeString } from '@vostride/agent-qa-core'\nimport { SecretStore, SecretRedactor } from '@vostride/agent-qa-runner'\nimport { DockerHookExecutor } from '@vostride/agent-qa-runner-local'\nimport type { ResolvedWorkspacePaths, RunAttributes, WorkspaceFileKind, WorkspaceFileRecord } from '@vostride/agent-qa-core'\nimport { createModel, fetchLiveModels, getModelCatalog, listProviders, mergeCatalog, resolveVisionConfig, type ProviderDescriptor } from '@vostride/agent-qa-model'\nimport { parse as parseYaml } from 'yaml'\nimport { toModelProfileAndAuth, type DashboardLLMConfig } from '../llm-model-mapping.js'\n\nconst LLM_PROVIDER_MODES = new Set([\n 'openai-compatible',\n 'anthropic-compatible',\n 'gemini',\n])\nconst API_KEY_CREDENTIAL_PROVIDERS = new Set([\n 'openai-compatible',\n 'anthropic-compatible',\n 'gemini',\n])\nconst DASHBOARD_EXECUTION_TIMEOUT_BUFFER_MS = 60_000\nconst REMOTE_LLM_CONNECTION_TEST_TIMEOUT_MS = 10_000\nconst LOCAL_COMPATIBLE_LLM_CONNECTION_TEST_TIMEOUT_MS = 120_000\nconst LOCAL_COMPATIBLE_LLM_PROVIDERS = new Set(['openai-compatible', 'anthropic-compatible'])\nconst PLUGIN_OAUTH_SESSION_TTL_MS = 10 * 60 * 1000\n// 2026-08-17 (Phase 398 plan 11, D-18/D-20): the three v33 dashboard product events, the\n// `POST /api/analytics/events` ingest route that took them and the core-analytics bridge it\n// captured through are all GONE. `routes.analytics-events.test.ts` holds the drop: the path 404s\n// and this file is pinned against the capture vocabulary returning. The dashboard's own run-history\n// reporting under `/api/analytics/tests|suites|breakdowns` is unrelated and stays. M5's dashboard\n// rebuild decides what it wants to emit, against the new `AnalyticsPort`.\n\ntype DashboardExecutionTimeoutSource =\n | 'test.use.timeout.test'\n | 'suite.use.timeout.test'\n | 'config.use.timeout.test'\n | 'none'\n\ninterface DashboardExecutionTimeout {\n timeoutMs?: number\n source: DashboardExecutionTimeoutSource\n baseTimeoutMs?: number\n bufferMs?: number\n}\n\nfunction toProductProviderLabel(provider: string): string {\n const plugin = listLLMAuthProviderPlugins()\n .find((candidate) => candidate.credentialProviderId === provider)\n return plugin?.providerId ?? provider\n}\n\nfunction isKnownLLMProvider(provider: string): boolean {\n return LLM_PROVIDER_MODES.has(provider) || Boolean(getLLMAuthProviderPlugin(provider))\n}\n\ntype CredentialTarget =\n | { ok: true; configName: string; created: boolean }\n | { ok: false; status: number; error: string; message?: string }\n\ntype CredentialNameCheck =\n | { ok: true; name: string }\n | { ok: false; status: number; error: string; message?: string }\n\n// 429-09 D-15/D-16: auth.json is machine-wide and keyed by name, so every name passes core's\n// name rule before the store is read or written.\nfunction checkCredentialName(configName: unknown): CredentialNameCheck {\n const name = typeof configName === 'string' ? configName.trim() : ''\n if (!name) return { ok: false, status: 400, error: 'configName is required' }\n const parsed = NameSlugSchema.safeParse(name)\n if (!parsed.success) {\n return { ok: false, status: 400, error: 'name_invalid', message: parsed.error.issues[0]?.message ?? 'Invalid name' }\n }\n return { ok: true, name }\n}\n\nasync function findRegistryLlm(\n configManager: ConfigManager,\n name: string,\n): Promise<SavedRegistryLlm | undefined> {\n const config = await readConfigValues(configManager) as { registry?: { llms?: unknown[] } }\n const llms = Array.isArray(config.registry?.llms) ? config.registry.llms : []\n return llms.find((item) => {\n return Boolean(item)\n && typeof item === 'object'\n && !Array.isArray(item)\n && (item as { name?: unknown }).name === name\n }) as SavedRegistryLlm | undefined\n}\n\ntype SavedRegistryLlm = { provider?: unknown; baseURL?: unknown; providerHeaders?: unknown }\n\nconst TEST_REDACTED = '[redacted]'\nconst MIN_REDACTED_HEADER_LENGTH = 4\n\nfunction trimmedString(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n\n// 429-43: a saved model's header values are read from the file on the server, and only for the\n// endpoint the saved model names; a read failure means no saved headers.\nasync function savedHeadersFor(\n configManager: ConfigManager | undefined,\n configName: string,\n provider: string,\n baseURL: string,\n): Promise<Record<string, string>> {\n if (!configManager || !configName) return {}\n let saved: SavedRegistryLlm | undefined\n try {\n saved = await findRegistryLlm(configManager, configName)\n } catch {\n return {}\n }\n if (!saved || saved.provider !== provider || trimmedString(saved.baseURL) !== baseURL) return {}\n const headers = saved.providerHeaders\n if (!headers || typeof headers !== 'object' || Array.isArray(headers)) return {}\n const kept: Record<string, string> = {}\n for (const [name, value] of Object.entries(headers)) {\n if (typeof value === 'string') kept[name] = value\n }\n return kept\n}\n\n// Body headers override their saved namesake (HTTP names compare case-insensitively). The model row\n// leaves out a header it showed as a marker, so the saved value is the one sent.\nfunction mergeTestHeaders(\n saved: Record<string, string>,\n body: Record<string, unknown>,\n): { headers: Record<string, unknown>; savedValues: string[] } {\n const headers: Record<string, unknown> = { ...saved }\n for (const [name, value] of Object.entries(body)) {\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === name.toLowerCase()) delete headers[key]\n }\n headers[name] = value\n }\n const savedValues = Object.entries(saved)\n .filter(([name, value]) => headers[name] === value)\n .map(([, value]) => value)\n return { headers, savedValues }\n}\n\nfunction withoutSavedValues(text: string, savedValues: readonly string[]): string {\n return [...savedValues]\n .filter((value) => value.length >= MIN_REDACTED_HEADER_LENGTH)\n .sort((a, b) => b.length - a.length)\n .reduce((redacted, value) => redacted.split(value).join(TEST_REDACTED), text)\n}\n\n// 441 GAP-D5: undefined when no declared mask is bound or it throws, so a caller leaves the text out.\nfunction withDeclaredMask<T>(mask: MaskFn | undefined, build: (mask: MaskFn) => T): T | undefined {\n if (mask === undefined) return undefined\n try {\n return build(mask)\n } catch {\n return undefined\n }\n}\n\n// 441 GAP2-D5 (WR-G03): the target list answers masked names, so a save whose target holds one\n// would write the marker into the file. A suite that does not parse is left to validation.\nfunction suiteFileTarget(content: string): unknown {\n try {\n const parsed: unknown = parseYaml(content)\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return undefined\n return (parsed as Record<string, unknown>).target\n } catch {\n return undefined\n }\n}\n\nfunction refusedShownMarkerTarget(res: ServerResponse, target: unknown): boolean {\n if (!holdsShownMarker(target)) return false\n json(res, {\n error: 'marker_written_back',\n message: MARKER_WRITTEN_BACK_SENTENCE,\n issues: [{ path: ['target'], message: MARKER_WRITTEN_BACK_SENTENCE }],\n }, 422)\n return true\n}\n\n// The product provider an auth.json entry belongs to, mapped the way GET /api/auth/status maps it.\nfunction credentialProductProvider(key: string, credential: DashboardAuthCredential): string {\n if (credential.type === 'oauth') return toProductProviderLabel(credential.provider ?? key)\n if (credential.type === 'bearer') return credential.provider\n return credential.provider ?? key\n}\n\nfunction ownAuthEntry(\n store: Record<string, DashboardAuthCredential | undefined>,\n name: string,\n): DashboardAuthCredential | undefined {\n return Object.prototype.hasOwnProperty.call(store, name) ? store[name] : undefined\n}\n\nasync function readAuthEntry(name: string): Promise<DashboardAuthCredential | undefined> {\n return ownAuthEntry(await readAuth() as Record<string, DashboardAuthCredential | undefined>, name)\n}\n\nconst CREDENTIAL_PROVIDER_CONFLICT = {\n status: 409,\n error: 'credential_provider_conflict',\n message: 'A saved credential under this name belongs to a different provider.',\n} as const\n\nasync function requireCredentialTarget(\n configManager: ConfigManager,\n name: string,\n provider: string,\n): Promise<CredentialTarget> {\n const match = await findRegistryLlm(configManager, name)\n if (match && match.provider !== provider) {\n return { ok: false, status: 400, error: `LLM config \"${name}\" uses ${String(match.provider)}, not ${provider}` }\n }\n const existing = await readAuthEntry(name)\n if (existing && credentialProductProvider(name, existing) !== provider) {\n return { ok: false, ...CREDENTIAL_PROVIDER_CONFLICT }\n }\n return { ok: true, configName: name, created: existing === undefined }\n}\n\nasync function requirePluginAuthConfig(\n configManager: ConfigManager | undefined,\n configName: unknown,\n plugin: LLMAuthProviderPlugin,\n): Promise<CredentialTarget> {\n const name = checkCredentialName(configName)\n if (!name.ok) return name\n if (!configManager) {\n return { ok: false, status: 400, error: 'Config manager is required to save OAuth credentials' }\n }\n return requireCredentialTarget(configManager, name.name, plugin.providerId)\n}\n\nasync function requireCredentialConfig(\n configManager: ConfigManager | undefined,\n configName: unknown,\n provider: string,\n): Promise<CredentialTarget> {\n const name = checkCredentialName(configName)\n if (!name.ok) return name\n if (!API_KEY_CREDENTIAL_PROVIDERS.has(provider)) {\n return { ok: false, status: 400, error: 'provider must support typed credentials' }\n }\n if (!configManager) {\n return { ok: false, status: 400, error: 'Config manager is required to save credentials' }\n }\n return requireCredentialTarget(configManager, name.name, provider)\n}\n\nfunction credentialRefusalBody(refusal: { error: string; message?: string }): { error: string; message?: string } {\n return refusal.message === undefined ? { error: refusal.error } : { error: refusal.error, message: refusal.message }\n}\n\nasync function credentialConflictAt(name: string, provider: string): Promise<boolean> {\n const existing = await readAuthEntry(name)\n return existing !== undefined && credentialProductProvider(name, existing) !== provider\n}\n\nexport type CredentialLock = <T>(work: () => Promise<T>) => Promise<T>\n\n// 429-09: one queue per router for every auth.json write and removal, so a save, a move, a delete\n// and a sign-in completion never interleave their read-modify-write of the machine-wide store.\nexport function createCredentialLock(): CredentialLock {\n let tail: Promise<unknown> = Promise.resolve()\n return <T>(work: () => Promise<T>): Promise<T> => {\n const run = tail.then(work)\n tail = run.catch(() => undefined)\n return run\n }\n}\n\ntype DashboardAuthCredential =\n | { type: 'oauth'; provider?: string; tokens: { expires: number } }\n | { type: 'api'; provider?: string; key?: string }\n | { type: 'bearer'; provider: string; token?: string }\n\ninterface DashboardLLMProviderMetadata {\n id: string\n label: string\n auth:\n | { kind: 'api-key'; credentialTypes: Array<'api-key' | 'bearer-token'>; optional?: boolean }\n | { kind: 'oauth-plugin'; mode: 'browser-poll' | 'manual-code'; buttonLabel?: string }\n modelAdapter?: 'openai-responses' | 'anthropic-messages'\n needsBaseURL?: boolean\n authModes?: Array<'api-key' | 'bearer-token' | 'subscription' | 'none'>\n subscription?: boolean\n baseURLPlaceholder?: string\n defaultModel?: string\n}\n\ninterface PluginOAuthSession {\n providerId: string\n credentialProviderId: string\n configName: string\n sessionState?: unknown\n cleanup?: () => void\n status: 'pending' | 'completed' | 'error'\n expiresAt: number\n error?: string\n}\n\nfunction serializeProviderDescriptor(descriptor: ProviderDescriptor): DashboardLLMProviderMetadata {\n return {\n id: descriptor.id,\n label: descriptor.label,\n auth: {\n kind: 'api-key',\n credentialTypes: descriptor.authModes.filter(\n mode => mode === 'api-key' || mode === 'bearer-token',\n ),\n ...(descriptor.credentialOptional ? { optional: true } : {}),\n },\n ...(descriptor.modelAdapter ? { modelAdapter: descriptor.modelAdapter } : {}),\n needsBaseURL: descriptor.needsBaseURL,\n authModes: descriptor.authModes,\n ...(descriptor.subscription ? { subscription: true } : {}),\n ...(descriptor.baseURLPlaceholder ? { baseURLPlaceholder: descriptor.baseURLPlaceholder } : {}),\n ...(descriptor.defaultModel ? { defaultModel: descriptor.defaultModel } : {}),\n }\n}\n\nfunction builtinLLMProviderMetadata(): DashboardLLMProviderMetadata[] {\n return listProviders()\n .filter(descriptor => !descriptor.subscription)\n .map(serializeProviderDescriptor)\n}\n\nfunction serializeAuthProviderPlugin(plugin: LLMAuthProviderPlugin): DashboardLLMProviderMetadata {\n return {\n id: plugin.providerId,\n label: plugin.label,\n modelAdapter: plugin.modelAdapter,\n auth: {\n kind: 'oauth-plugin',\n mode: plugin.dashboardAuth.mode,\n ...(plugin.dashboardAuth.buttonLabel ? { buttonLabel: plugin.dashboardAuth.buttonLabel } : {}),\n },\n }\n}\n\ntype DashboardRuntimeLLMConfig = DashboardLLMConfig & {\n vision?: DashboardVisionConfig\n modelVision?: boolean\n}\n\ntype DashboardVisionConfig = {\n screenshotSize?: number\n effectiveResolution?: number\n}\n\nconst writeDashboardAuth = writeAuth as unknown as (\n provider: string,\n credential: DashboardAuthCredential,\n) => Promise<void>\n\ntype DashboardResolvedRuntimeLLM =\n | { ok: true; llmConfig: DashboardRuntimeLLMConfig; authFetch?: typeof globalThis.fetch }\n | { ok: false; error: string }\n\nfunction normalizeRuntimeLLMConfig(raw: unknown): { configName: string; config: DashboardRuntimeLLMConfig } | undefined {\n if (!isPlainRecord(raw)) return undefined\n if (typeof raw.name !== 'string' || !raw.name.trim()) return undefined\n if (typeof raw.provider !== 'string' || !raw.provider.trim()) return undefined\n if (typeof raw.model !== 'string' || !raw.model.trim()) return undefined\n\n const config: DashboardRuntimeLLMConfig = {\n provider: raw.provider,\n model: raw.model,\n }\n if (typeof raw.baseURL === 'string') config.baseURL = raw.baseURL\n if (isPlainRecord(raw.providerHeaders)) {\n const headers: Record<string, string> = {}\n for (const [key, value] of Object.entries(raw.providerHeaders)) {\n if (typeof value === 'string') headers[key] = value\n }\n config.providerHeaders = headers\n }\n if (typeof raw.vision === 'boolean') config.modelVision = raw.vision\n\n return { configName: raw.name, config }\n}\n\nfunction normalizeDashboardVisionConfig(raw: unknown): DashboardVisionConfig | undefined {\n if (!isPlainRecord(raw)) return undefined\n const config: DashboardVisionConfig = {}\n if (typeof raw.screenshotSize === 'number') {\n config.screenshotSize = raw.screenshotSize\n } else if (typeof raw.screenshotSize === 'string') {\n const parsedSize = SizeString.safeParse(raw.screenshotSize)\n if (parsedSize.success) config.screenshotSize = parsedSize.data\n }\n if (typeof raw.effectiveResolution === 'number' && Number.isInteger(raw.effectiveResolution) && raw.effectiveResolution > 0) {\n config.effectiveResolution = raw.effectiveResolution\n }\n return config.screenshotSize !== undefined || config.effectiveResolution !== undefined ? config : undefined\n}\n\nasync function resolveDashboardRuntimeLLM(\n configManager: ConfigManager | undefined,\n fallbackLLMConfig: DashboardRuntimeLLMConfig | undefined,\n fallbackAuthFetch: typeof globalThis.fetch | undefined,\n): Promise<DashboardResolvedRuntimeLLM> {\n if (!configManager) {\n if (!fallbackLLMConfig) {\n return { ok: false, error: 'LLM not configured. Set up LLM provider in settings.' }\n }\n return { ok: true, llmConfig: fallbackLLMConfig, authFetch: fallbackAuthFetch }\n }\n\n const rawConfig = await readConfigValues(configManager)\n const registry = isPlainRecord(rawConfig.registry) ? rawConfig.registry : {}\n const use = isPlainRecord(rawConfig.use) ? rawConfig.use : {}\n const llms = Array.isArray(registry.llms) ? registry.llms : []\n const selectedName = typeof use.llm === 'string' ? use.llm : undefined\n const selected = selectedName\n ? llms.find((candidate) => isPlainRecord(candidate) && candidate.name === selectedName)\n : llms[0]\n\n const normalized = normalizeRuntimeLLMConfig(selected)\n if (!normalized) {\n if (!fallbackLLMConfig) {\n return { ok: false, error: 'LLM not configured. Set up LLM provider in settings.' }\n }\n return { ok: true, llmConfig: fallbackLLMConfig, authFetch: fallbackAuthFetch }\n }\n\n const coreAuth = await import('@vostride/agent-qa-core') as typeof import('@vostride/agent-qa-core') & {\n resolveLLMAuth: (\n configName: string,\n config: DashboardRuntimeLLMConfig,\n ) => Promise<\n | { kind: 'api-key'; apiKey: string }\n | { kind: 'bearer-token'; token: string }\n | { kind: 'auth-fetch'; fetch: typeof globalThis.fetch; modelAdapter: 'openai-responses' | 'anthropic-messages' }\n | { kind: 'unauthenticated'; message: string }\n | { kind: 'missing'; message: string }\n >\n }\n const auth = await coreAuth.resolveLLMAuth(normalized.configName, normalized.config)\n if (auth.kind === 'missing') {\n return { ok: false, error: auth.message }\n }\n\n const servicesVision = isPlainRecord(rawConfig.services)\n ? normalizeDashboardVisionConfig(rawConfig.services.vision)\n : undefined\n const runtimeConfig: DashboardRuntimeLLMConfig = {\n ...normalized.config,\n vision: resolveVisionConfig(servicesVision),\n }\n let resolvedAuthFetch: typeof globalThis.fetch | undefined\n if (auth.kind === 'api-key') {\n runtimeConfig.apiKey = auth.apiKey\n } else if (auth.kind === 'bearer-token') {\n runtimeConfig.authToken = auth.token\n } else if (auth.kind === 'auth-fetch') {\n runtimeConfig.modelAdapter = auth.modelAdapter\n resolvedAuthFetch = auth.fetch\n }\n\n return { ok: true, llmConfig: runtimeConfig, authFetch: resolvedAuthFetch }\n}\n\nfunction cleanupPluginOAuthSession(session: PluginOAuthSession): void {\n const cleanup = session.cleanup\n session.cleanup = undefined\n if (!cleanup) return\n try {\n cleanup()\n } catch {\n // Best-effort cleanup for plugin-owned local callback servers.\n }\n}\n\nfunction pruneExpiredPluginOAuthSessions(sessions: Map<string, PluginOAuthSession>, now = Date.now()): void {\n for (const [sessionId, session] of sessions) {\n if (session.expiresAt <= now) {\n cleanupPluginOAuthSession(session)\n sessions.delete(sessionId)\n }\n }\n}\n\nfunction isLocalLLMBaseURL(baseURL: unknown): boolean {\n if (typeof baseURL !== 'string' || !baseURL.trim()) return false\n try {\n const url = new URL(baseURL)\n const hostname = url.hostname.toLowerCase()\n return hostname === 'localhost'\n || hostname === '0.0.0.0'\n || hostname === '::1'\n || hostname === '[::1]'\n || hostname.startsWith('127.')\n || hostname.endsWith('.local')\n } catch {\n return false\n }\n}\n\nfunction llmConnectionTestTimeoutMs(config: { provider?: unknown; baseURL?: unknown }): number {\n // Connectivity probes are config-screen smoke checks only; real run execution\n // uses configured test timeout metadata and does not read this value.\n if (LOCAL_COMPATIBLE_LLM_PROVIDERS.has(String(config.provider)) && isLocalLLMBaseURL(config.baseURL)) {\n return LOCAL_COMPATIBLE_LLM_CONNECTION_TEST_TIMEOUT_MS\n }\n return REMOTE_LLM_CONNECTION_TEST_TIMEOUT_MS\n}\n\nfunction json(res: ServerResponse, data: unknown, status = 200): void {\n const body = JSON.stringify(data)\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type',\n })\n res.end(body)\n}\n\n/**\n * An answer that carries NO cross-origin read grant.\n *\n * ADDITIVE, and `json()` above is untouched on purpose: its wildcard posture serves the legacy\n * read routes and re-platforming those is Phase 402's question, not this one's. What this writer\n * exists for is the narrow class of answers that hand out a CAPABILITY. `Access-Control-Allow-Origin: *`\n * on such an answer means a document on any origin may READ the token out of the response — the\n * refusal beside it would be worthless if the body were still readable through a redirect or a\n * misconfigured proxy. No wildcard, no allow-methods: the dashboard's own page is same-origin and\n * needs neither, and every non-browser client ignores both.\n */\nfunction jsonNoCors(res: ServerResponse, data: unknown, status = 200): void {\n const body = JSON.stringify(data)\n res.writeHead(status, { 'Content-Type': 'application/json' })\n res.end(body)\n}\n\n/**\n * Refuse a cross-site driver on a run-text read, and refuse it with NO cross-origin grant on the\n * refusal either.\n *\n * WHY THESE ARMS AND NOT THE OTHERS (405 CR-01). They answer a run's stored text, served as it\n * was stored (441 D-07), and they keep the no-grant posture CR-01 gave them.\n *\n * WHY THE REFUSAL AND NOT ONLY THE MISSING HEADER. Dropping the wildcard stops a page on another\n * ORIGIN from READING the body. It does not stop DNS rebinding, where the attacker's own name\n * resolves to a loopback address and the browser therefore treats the read as same-origin and asks\n * for no grant at all. `refuseCrossSiteRequest` carries the Host check that closes that, and it\n * ADMITS the caller that sends no `Origin` — the CLI, `curl`, the conformance harness — which is\n * the local drive these arms exist for.\n *\n * SCOPE, DELIBERATELY NARROW. Only the run-text arms. `json()` above keeps its wildcard\n * for the legacy read routes, whose whole-server posture is the re-platform question its own\n * docstring defers; widening it here would change the posture of routes this fix does not own.\n *\n * THE SHARED PREFLIGHT ARM IS LEFT ALONE, and that is a decision rather than an oversight. `cors()`\n * still answers every OPTIONS with the wildcard. All four arms here are SIMPLE GETs, so a browser\n * needs no preflight to send them and a preflight grant confers no read; what confers the read is\n * the grant on the ACTUAL response, and that is the one removed. A preflighted variant now gets a\n * permissive OPTIONS followed by a response the browser refuses to hand to the page — it fails\n * closed. Excluding these paths from `cors()` would mean claiming the `/api/runs/` prefix ahead of\n * the shared arm the way the run-confirm prefix used to claim its own (deleted in 432-14), which\n * would capture the trigger, cancel, delete, live-url, detail and post-processing routes too: the\n * whole-server posture change this fix is deliberately not making.\n */\nfunction refuseCrossSiteDisplayRead(req: IncomingMessage, res: ServerResponse): boolean {\n if (refuseCrossSiteRequest(req) === undefined) return false\n jsonNoCors(res, { error: 'cross_site_refused' }, 403)\n return true\n}\n\nconst INSIGHTS_KNOWLEDGE_RUN_CAP = 200\nconst INSIGHTS_KNOWLEDGE_CONCURRENCY = 4\n\ntype KnowledgeChangeKind = (typeof RecordChangeSchema.shape.change.options)[number]\n\ninterface InsightsKnowledgeChanges {\n status: 'read'\n /** The window's settled runs: started, and neither queued nor running. */\n runsInWindow: number\n runsRead: number\n runsUnreadable: number\n runsCurationFailed: number\n runsCurationUnfinished: number\n /** The window's runs still queued or running; they are not read. */\n runsInFlight: number\n truncated?: { read: number; total: number }\n byKind: Record<KnowledgeChangeKind, number>\n}\n\ntype InsightsRunCuration = 'read' | 'unreadable' | 'failed' | 'unfinished'\n\n/**\n * `pending` is ambiguous: the chain may be queued, or it was never enqueued because the run was\n * skipped by design (a gate run, an excluded outcome). Only the post-processing read can tell,\n * and only its `skipped` fact is used.\n */\nasync function isPostProcessingSkipped(host: AgentHost, runId: string): Promise<boolean> {\n const parsed = RunsPostProcessingInputSchema.safeParse({ runId })\n if (!parsed.success) return false\n try {\n const status = await host.invokeFunction(\n host.registry,\n host.runsPostProcessingFunctionId,\n parsed.data,\n host.caller,\n ) as PostProcessingStatus\n return status?.skipped !== undefined\n } catch {\n return false\n }\n}\n\n/**\n * Tally the window's knowledge changes by kind, one `runs.knowledge` read per settled run\n * (433-30, 433-42).\n *\n * A run is read only when its curation finished (`complete`), or when its curation reads `pending`\n * because the run's post-processing was skipped by design, so there was nothing to curate.\n * Only read runs' changes are counted. Every other run is counted apart and never as a run that\n * changed nothing:\n * - unreadable: the read was refused or threw, the handoff is gone (`evidence-incomplete`), or the\n * store scan behind its changes was incomplete;\n * - curation failed: `failed`;\n * - curation unfinished: `running`, or `pending` with no skipped fact (or an unreadable one).\n * Runs still queued or running are not read at all; they are counted as in flight. The latest\n * {@link INSIGHTS_KNOWLEDGE_RUN_CAP} settled runs are read; a larger window says so.\n */\nasync function readInsightsKnowledgeChanges(\n host: AgentHost,\n db: DashboardDatabase,\n window: { from?: string; to?: string },\n): Promise<InsightsKnowledgeChanges> {\n const { runIds, total, inFlight } = db.listInsightsWindowRunIds({ ...window, limit: INSIGHTS_KNOWLEDGE_RUN_CAP })\n const byKind = Object.fromEntries(\n RecordChangeSchema.shape.change.options.map((kind) => [kind, 0]),\n ) as Record<KnowledgeChangeKind, number>\n const tally: Record<InsightsRunCuration, number> = { read: 0, unreadable: 0, failed: 0, unfinished: 0 }\n const classify = async (runId: string): Promise<InsightsRunCuration> => {\n const outcome = await readRunKnowledge(host, runId).catch(() => undefined)\n if (outcome?.kind !== 'ok' || outcome.body.kind !== 'ready' || outcome.body.learned.scanIncomplete) {\n return 'unreadable'\n }\n const curation = outcome.body.curation.status\n let state: InsightsRunCuration\n if (curation === 'complete') state = 'read'\n else if (curation === 'failed') state = 'failed'\n else if (curation === 'pending' && await isPostProcessingSkipped(host, runId)) state = 'read'\n else state = 'unfinished'\n if (state === 'read') {\n for (const change of outcome.body.learned.changes) {\n if (Object.hasOwn(byKind, change.change)) byKind[change.change] += 1\n }\n }\n return state\n }\n let next = 0\n const worker = async (): Promise<void> => {\n while (next < runIds.length) {\n tally[await classify(runIds[next++])] += 1\n }\n }\n await Promise.all(Array.from({ length: Math.min(INSIGHTS_KNOWLEDGE_CONCURRENCY, runIds.length) }, worker))\n return {\n status: 'read',\n runsInWindow: total,\n runsRead: tally.read,\n runsUnreadable: tally.unreadable,\n runsCurationFailed: tally.failed,\n runsCurationUnfinished: tally.unfinished,\n runsInFlight: inFlight,\n ...(total > runIds.length ? { truncated: { read: runIds.length, total } } : {}),\n byKind,\n }\n}\n\nfunction notFound(res: ServerResponse, message = 'Not found'): void {\n json(res, { error: message }, 404)\n}\n\nfunction cors(res: ServerResponse): void {\n res.writeHead(204, {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': 'Content-Type',\n })\n res.end()\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction getConfiguredAuthStateDir(config: Record<string, unknown>): string | undefined {\n const services = isPlainRecord(config.services) ? config.services : undefined\n const authState = services && isPlainRecord(services.authState) ? services.authState : undefined\n return typeof authState?.dir === 'string' ? authState.dir : undefined\n}\n\nfunction getSessionTargetNameForAuthState(session: { getState?: () => unknown } | undefined): string {\n if (!session || typeof session.getState !== 'function') return 'selected target'\n try {\n const state = session.getState()\n if (isPlainRecord(state) && typeof state.targetName === 'string' && state.targetName.trim().length > 0) {\n return state.targetName.trim()\n }\n } catch {\n // Do not let state serialization failures leak into auth-state responses.\n }\n return 'selected target'\n}\n\nfunction buildAuthStateSaveErrorMessage(\n stateName: string,\n targetName: string,\n error: unknown,\n): { status: number; message: string } {\n const raw = error instanceof Error ? error.message : String(error)\n if (/already exists/i.test(raw)) {\n return {\n status: 409,\n message: `Auth state \"${stateName}\" for target \"${targetName}\" already exists. Use replace=true to replace it.`,\n }\n }\n\n if (/web Live Mode|not ready|executing|busy/i.test(raw)) {\n return {\n status: 409,\n message: `Could not save auth state \"${stateName}\" for target \"${targetName}\".`,\n }\n }\n\n return {\n status: 500,\n message: `Could not save auth state \"${stateName}\" for target \"${targetName}\".`,\n }\n}\n\n// 2026-08-27 (405-07, D-14): a containment predicate and a plain-filename predicate stood here.\n// Both existed for the deleted path-serving routes and the deleted run-deletion sweep, which were\n// their only callers. The containment rule for artifact bytes is the evidence store's own now,\n// reached through the `runs.artifact` op — one rule, in the place that owns the layout.\n\nfunction createHookRegistryManager(configManager?: ConfigManager, configPath?: string): HookRegistryManager | null {\n if (!configManager || !configPath) {\n return null\n }\n return new HookRegistryManager(configManager, configPath)\n}\n\nfunction normalizeRunFilterValue(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim().toLowerCase()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction buildRunRequestAttributes(input: {\n trigger: 'dashboard' | 'api' | 'mcp'\n runner?: 'local' | 'browserstack'\n userAttributes?: unknown\n}): RunAttributes {\n const internal = buildInternalRunAttributes({\n trigger: input.trigger,\n runner: input.runner ?? 'local',\n })\n const user = validateUserRunAttributes(input.userAttributes, 'run attributes')\n return mergeRunAttributes(internal, user)\n}\n\nfunction parseDashboardRunTriggerSource(value: unknown): { ok: true; trigger: 'dashboard' | 'mcp' } | { ok: false; error: string } {\n if (value === undefined || value === null) return { ok: true, trigger: 'dashboard' }\n if (value === 'dashboard' || value === 'mcp') return { ok: true, trigger: value }\n return { ok: false, error: 'triggerSource must be one of: dashboard, mcp' }\n}\n\nfunction parseAttributePredicates(searchParams: URLSearchParams): { ok: true; predicates: AttributePredicate[] } | { ok: false; error: string } {\n const predicates = new Map<string, AttributePredicate>()\n for (const [paramKey, value] of searchParams.entries()) {\n const match = /^attributes\\[([^\\]]*)\\](?:\\[(regex)\\])?$/.exec(paramKey)\n if (!match) continue\n const key = match[1]\n const mode = match[2] === 'regex' ? 'regex' : 'exact'\n if (!key.trim()) return { ok: false, error: 'Attribute key must be non-empty' }\n if (!value.trim()) return { ok: false, error: 'Attribute value must be non-empty' }\n const existing = predicates.get(key)\n if (existing && existing.mode !== mode) {\n return { ok: false, error: `Cannot combine exact and regex attribute filters for \"${key}\"` }\n }\n if (mode === 'regex') {\n try {\n new RegExp(value)\n } catch {\n return { ok: false, error: `Invalid attribute regex for \"${key}\"` }\n }\n }\n predicates.set(key, { key, value, mode })\n }\n return { ok: true, predicates: [...predicates.values()] }\n}\n\nfunction parseAnalyticsScopePredicates(config: Record<string, unknown> | undefined): { ok: true; predicates: AttributePredicate[] } | { ok: false; error: string } {\n const analytics = config?.analytics\n if (!analytics || typeof analytics !== 'object' || Array.isArray(analytics)) return { ok: true, predicates: [] }\n const passRateScope = (analytics as Record<string, unknown>).passRateScope\n if (!passRateScope || typeof passRateScope !== 'object' || Array.isArray(passRateScope)) return { ok: true, predicates: [] }\n const attributes = (passRateScope as Record<string, unknown>).attributes\n if (!attributes || typeof attributes !== 'object' || Array.isArray(attributes)) return { ok: true, predicates: [] }\n\n const predicates: AttributePredicate[] = []\n for (const [key, rawValue] of Object.entries(attributes)) {\n if (!key.trim()) return { ok: false, error: 'analytics.passRateScope attribute key must be non-empty' }\n if (typeof rawValue === 'string') {\n if (!rawValue.trim()) return { ok: false, error: `analytics.passRateScope attribute \"${key}\" must be non-empty` }\n predicates.push({ key, value: rawValue, mode: 'exact' })\n continue\n }\n if (rawValue && typeof rawValue === 'object' && !Array.isArray(rawValue) && typeof (rawValue as { regex?: unknown }).regex === 'string') {\n const regex = (rawValue as { regex: string }).regex\n if (!regex.trim()) return { ok: false, error: `analytics.passRateScope attribute \"${key}\" regex must be non-empty` }\n try {\n new RegExp(regex)\n } catch {\n return { ok: false, error: `Invalid analytics.passRateScope regex for \"${key}\"` }\n }\n predicates.push({ key, value: regex, mode: 'regex' })\n }\n }\n return { ok: true, predicates }\n}\n\nasync function readAnalyticsScopePredicates(configManager: ConfigManager | undefined): Promise<{ ok: true; predicates: AttributePredicate[] } | { ok: false; error: string }> {\n if (!configManager) return { ok: true, predicates: [] }\n const config = await readConfigValues(configManager)\n const parsedConfig = AgentQaConfigSchema.safeParse(config)\n if (!parsedConfig.success) {\n return { ok: true, predicates: [] }\n }\n return parseAnalyticsScopePredicates(parsedConfig.data as Record<string, unknown>)\n}\n\nfunction calculateFlakyMetrics(classes: ReadonlyArray<RunStatusClass | 'skipped' | undefined>): { score: number; statusCount: number } {\n const statuses = classes.filter(c => c === 'pass' || c === 'fail')\n let alternations = 0\n for (let i = 1; i < statuses.length; i++) {\n if (statuses[i] !== statuses[i - 1]) alternations++\n }\n return {\n score: statuses.length > 1 ? alternations / (statuses.length - 1) : 0,\n statusCount: statuses.length,\n }\n}\n\n// 2026-10-18 (444-31, D-64): a list row's rate is its viewer's own fold; passed and decided are\n// that fold's pass and pass-or-fail counts.\nfunction passRateOf(trends: {\n passRate: number | null\n daily: ReadonlyArray<{ passed: number; failed: number }>\n}): { passRate: number | null; passed: number; decided: number } {\n return {\n passRate: trends.passRate,\n passed: trends.daily.reduce((sum, day) => sum + day.passed, 0),\n decided: trends.daily.reduce((sum, day) => sum + day.passed + day.failed, 0),\n }\n}\n\nfunction lastRunOf(run: RunRow | undefined): {\n id: string\n status: string\n startedAt: string | null\n createdAt: string\n duration: number\n} | null {\n if (!run) return null\n return { id: run.id, status: run.status, startedAt: run.startedAt, createdAt: run.createdAt, duration: run.duration }\n}\n\nfunction normalizeSupportedPlatform(value: unknown): SupportedPlatform | null {\n if (value !== 'web' && value !== 'android' && value !== 'ios') return null\n return value\n}\n\nfunction parseIsoDateQueryParam(\n value: string | null,\n field: 'from' | 'to',\n): { ok: true; value?: string } | { ok: false; error: string } {\n if (!value) return { ok: true, value: undefined }\n return Number.isNaN(Date.parse(value))\n ? { ok: false, error: `${field} must be a valid ISO date` }\n : { ok: true, value }\n}\n\nfunction parseBoundedIntegerQueryParam(\n value: string | null,\n field: string,\n min: number,\n max: number,\n fallback: number,\n): { ok: true; value: number } | { ok: false; error: string } {\n if (!value) return { ok: true, value: fallback }\n const parsed = Number.parseInt(value, 10)\n if (!Number.isFinite(parsed)) {\n return { ok: false, error: `${field} must be an integer` }\n }\n return { ok: true, value: Math.min(max, Math.max(min, parsed)) }\n}\n\nfunction getTargetPlatformMap(config: unknown): Map<string, SupportedPlatform> {\n const targetsValue = (config as {\n registry?: { targets?: Record<string, { platform?: unknown }> }\n }).registry?.targets\n\n const targetPlatforms = new Map<string, SupportedPlatform>()\n if (!targetsValue || typeof targetsValue !== 'object') return targetPlatforms\n\n for (const [targetName, targetConfig] of Object.entries(targetsValue)) {\n const platform = normalizeSupportedPlatform(targetConfig?.platform)\n if (platform) targetPlatforms.set(targetName, platform)\n }\n\n return targetPlatforms\n}\n\nasync function readTargetPlatformMap(configManager?: ConfigManager): Promise<Map<string, SupportedPlatform>> {\n if (!configManager) return new Map()\n try {\n const config = await readConfigValues(configManager)\n return getTargetPlatformMap(config)\n } catch {\n return new Map()\n }\n}\n\nfunction parseTimeoutConfigTestTimeoutMs(timeoutConfig: unknown): number | undefined {\n if (timeoutConfig && typeof timeoutConfig === 'object' && !Array.isArray(timeoutConfig)) {\n const transformedTimeout = (timeoutConfig as { test?: unknown }).test\n if (typeof transformedTimeout === 'number' && Number.isFinite(transformedTimeout) && transformedTimeout > 0) {\n return transformedTimeout\n }\n }\n const parsed = TimeoutConfigSchema.partial().safeParse(timeoutConfig)\n if (!parsed.success) return undefined\n const testTimeout = parsed.data.test\n return typeof testTimeout === 'number' && Number.isFinite(testTimeout) && testTimeout > 0\n ? testTimeout\n : undefined\n}\n\nfunction parseUseTestTimeoutMs(useConfig: unknown): number | undefined {\n if (!useConfig || typeof useConfig !== 'object' || Array.isArray(useConfig)) return undefined\n return parseTimeoutConfigTestTimeoutMs((useConfig as { timeout?: unknown }).timeout)\n}\n\nasync function readConfigTestTimeoutMs(configManager?: ConfigManager): Promise<number | undefined> {\n if (!configManager) return undefined\n try {\n const config = await readConfigValues(configManager)\n const parsed = AgentQaConfigSchema.safeParse(config)\n if (parsed.success) {\n return parseUseTestTimeoutMs(parsed.data.use)\n }\n return parseUseTestTimeoutMs((config as { use?: unknown }).use)\n } catch {\n return undefined\n }\n}\n\nfunction readTestYamlTimeoutMs(content: string): number | undefined {\n try {\n const parsedYaml = parseYaml(content)\n const parsedTest = TestDefinitionSchema.safeParse(parsedYaml)\n if (parsedTest.success) {\n return parseUseTestTimeoutMs(parsedTest.data.use)\n }\n return parseUseTestTimeoutMs((parsedYaml as { use?: unknown } | null | undefined)?.use)\n } catch {\n return undefined\n }\n}\n\nfunction readSuiteYamlTimeoutMs(content: string): number | undefined {\n try {\n const parsedYaml = parseYaml(content)\n const parsedSuite = SuiteDefinitionSchema.safeParse(parsedYaml)\n if (parsedSuite.success) {\n return parseUseTestTimeoutMs(parsedSuite.data.use)\n }\n return parseUseTestTimeoutMs((parsedYaml as { use?: unknown } | null | undefined)?.use)\n } catch {\n return undefined\n }\n}\n\nfunction parseUseParallel(useConfig: unknown): boolean | undefined {\n if (!isRecord(useConfig)) return undefined\n return typeof useConfig.parallel === 'boolean' ? useConfig.parallel : undefined\n}\n\nasync function readConfigUseParallel(configManager?: ConfigManager): Promise<boolean | undefined> {\n if (!configManager) return undefined\n try {\n const config = await readConfigValues(configManager)\n const parsed = AgentQaConfigSchema.safeParse(config)\n if (parsed.success) {\n return parseUseParallel(parsed.data.use)\n }\n return parseUseParallel((config as { use?: unknown }).use)\n } catch {\n return undefined\n }\n}\n\nfunction readSuiteYamlParallel(content: string): boolean | undefined {\n try {\n const parsedYaml = parseYaml(content)\n const parsedSuite = SuiteDefinitionSchema.safeParse(parsedYaml)\n if (parsedSuite.success) {\n return parseUseParallel(parsedSuite.data.use)\n }\n return parseUseParallel((parsedYaml as { use?: unknown } | null | undefined)?.use)\n } catch {\n return undefined\n }\n}\n\nfunction withDashboardExecutionBuffer(\n baseTimeoutMs: number | undefined,\n source: DashboardExecutionTimeoutSource,\n): DashboardExecutionTimeout {\n if (!baseTimeoutMs) {\n return { source: 'none' }\n }\n return {\n timeoutMs: baseTimeoutMs + DASHBOARD_EXECUTION_TIMEOUT_BUFFER_MS,\n source,\n baseTimeoutMs,\n bufferMs: DASHBOARD_EXECUTION_TIMEOUT_BUFFER_MS,\n }\n}\n\nasync function resolveDashboardExecutionTimeout(opts: {\n isSuite: boolean\n file?: string\n normalizedTestPath?: string\n testFileManager?: TestFileManager\n suiteFileManager?: SuiteFileManager\n configManager?: ConfigManager\n}): Promise<DashboardExecutionTimeout> {\n if (opts.file) {\n if (opts.isSuite && opts.suiteFileManager) {\n try {\n const suiteContent = await opts.suiteFileManager.read(opts.file)\n const suiteTimeout = readSuiteYamlTimeoutMs(suiteContent)\n if (suiteTimeout) {\n return withDashboardExecutionBuffer(suiteTimeout, 'suite.use.timeout.test')\n }\n } catch {\n // Fall through to config timeout for draft or unreadable suite files.\n }\n } else if (!opts.isSuite && opts.testFileManager) {\n try {\n const testContent = await opts.testFileManager.read(opts.normalizedTestPath ?? opts.file)\n const testTimeout = readTestYamlTimeoutMs(testContent)\n if (testTimeout) {\n return withDashboardExecutionBuffer(testTimeout, 'test.use.timeout.test')\n }\n } catch {\n // Fall through to config timeout for draft or unreadable test files.\n }\n }\n }\n\n const configTimeout = await readConfigTestTimeoutMs(opts.configManager)\n return withDashboardExecutionBuffer(configTimeout, configTimeout ? 'config.use.timeout.test' : 'none')\n}\n\nfunction toExecutionTimeoutMetadata(timeout: DashboardExecutionTimeout): Record<string, unknown> {\n if (!timeout.timeoutMs) {\n return { timeoutSource: timeout.source }\n }\n return {\n timeout: timeout.timeoutMs,\n timeoutSource: timeout.source,\n timeoutBaseMs: timeout.baseTimeoutMs,\n timeoutBufferMs: timeout.bufferMs,\n }\n}\n\nfunction resolveEffectivePlatform(\n platform: string | null | undefined,\n targetName: string | null | undefined,\n targetPlatforms: Map<string, SupportedPlatform>,\n fallbackPlatform?: string | null,\n): SupportedPlatform | null {\n const explicitPlatform = normalizeSupportedPlatform(platform)\n if (explicitPlatform) return explicitPlatform\n\n if (targetName) {\n const targetPlatform = targetPlatforms.get(targetName)\n if (targetPlatform) return targetPlatform\n }\n\n return normalizeSupportedPlatform(fallbackPlatform)\n}\n\nfunction extractRunTargetName(testFileContent: string | null | undefined): string | null {\n if (!testFileContent) return null\n return extractTestFileMetadata(testFileContent).targetName\n}\n\ntype EnrichedRunRow = RunRow & {\n targetName: string | null\n tests?: EnrichedRunRow[]\n}\n\nfunction enrichRunRow(\n run: RunRow,\n targetPlatforms: Map<string, SupportedPlatform>,\n tests?: EnrichedRunRow[],\n): EnrichedRunRow {\n const metadata = run.testFileContent ? extractTestFileMetadata(run.testFileContent) : null\n let targetName = metadata?.targetName ?? extractRunTargetName(run.testFileContent)\n if (!targetName && tests && tests.length > 0) {\n const uniqueChildTargets = [...new Set(\n tests\n .map((test) => test.targetName)\n .filter((value): value is string => typeof value === 'string' && value.length > 0),\n )]\n if (uniqueChildTargets.length === 1) {\n targetName = uniqueChildTargets[0]\n }\n }\n\n const uniqueChildPlatforms = tests\n ? [...new Set(\n tests\n .map((test) => normalizeSupportedPlatform(test.platform))\n .filter((value): value is SupportedPlatform => value !== null),\n )]\n : []\n\n const platform = resolveEffectivePlatform(\n metadata?.platform,\n targetName,\n targetPlatforms,\n uniqueChildPlatforms.length === 1 ? uniqueChildPlatforms[0] : run.platform,\n )\n\n return {\n ...run,\n platform: platform ?? run.platform,\n targetName,\n ...(tests ? { tests } : {}),\n }\n}\n\n// 2026-10-18 (444-31, D-64): a suite row's target and platform come from its own history, newest\n// first: the newest run with a target names both, else its last run does.\nfunction suiteTargetOf(\n runs: readonly RunRow[],\n targetPlatforms: Map<string, SupportedPlatform>,\n): { platform: string | null; targetName: string | null } {\n let last: EnrichedRunRow | undefined\n for (const run of runs) {\n const enriched = enrichRunRow(run, targetPlatforms)\n last ??= enriched\n const targetName = enriched.targetName?.trim()\n if (targetName) return { platform: enriched.platform, targetName }\n }\n if (!last) return { platform: null, targetName: null }\n return { platform: last.platform, targetName: last.targetName?.trim() || null }\n}\n\nfunction matchesTargetFilter(run: EnrichedRunRow, filterValue: string | null): boolean {\n if (!filterValue) return true\n if (normalizeRunFilterValue(run.targetName) === filterValue) return true\n return run.tests?.some((test) => normalizeRunFilterValue(test.targetName) === filterValue) ?? false\n}\n\nfunction matchesPlatformFilter(run: EnrichedRunRow, filterValue: SupportedPlatform | null): boolean {\n if (!filterValue) return true\n if (normalizeSupportedPlatform(run.platform) === filterValue) return true\n return run.tests?.some((test) => normalizeSupportedPlatform(test.platform) === filterValue) ?? false\n}\n\nfunction getArtifactMissingSections(artifact: RunArtifactRow | null): string[] {\n if (!artifact) return ['artifact']\n const missing: string[] = []\n const payload = artifact.payload\n if (!('config' in payload)) missing.push('config')\n if (!('source' in payload)) missing.push('source')\n return missing\n}\n\nconst SECRET_TEMPLATE_RE = /\\{\\{secret:(\\w+)\\}\\}/g\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction sanitizeSecretTemplates(value: unknown): unknown {\n if (typeof value === 'string') {\n return value.replace(SECRET_TEMPLATE_RE, (_match, name: string) => `[secret:${name}]`)\n }\n if (Array.isArray(value)) {\n return value.map((item) => sanitizeSecretTemplates(item))\n }\n if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {\n return value\n }\n if (isRecord(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [key, sanitizeSecretTemplates(item)]),\n )\n }\n return value\n}\n\nfunction sanitizeSecretsFileMetadata(value: unknown): unknown {\n if (value === null || value === undefined) return value\n if (!isRecord(value)) return value\n return {\n path: typeof value.path === 'string' || value.path === null ? value.path : null,\n status: typeof value.status === 'string' ? value.status : 'loaded',\n ...(typeof value.count === 'number' ? { count: value.count } : {}),\n }\n}\n\nfunction sanitizeArtifactPayloadForResponse(payload: RunArtifactRow['payload']): RunArtifactRow['payload'] {\n const sanitized = sanitizeSecretTemplates(payload)\n if (!isRecord(sanitized)) return payload\n // G-401-18-CR01: the SEVENTH door. `JobQueue.enqueue` writes the caller's `metadata` object into\n // `run_artifacts.payload.metadata` as well as `runs.metadata`, and this response is what serves\n // it. The strip is the SAME allowlist the run rows go through — see `sanitizeRunMetadataForResponse`.\n const withSafeMetadata = sanitizeArtifactPayloadMetadata(sanitized)\n const config = withSafeMetadata.config\n if (!isRecord(config) || !('secretsFile' in config)) return withSafeMetadata as unknown as RunArtifactRow['payload']\n return {\n ...withSafeMetadata,\n config: {\n ...config,\n secretsFile: sanitizeSecretsFileMetadata(config.secretsFile),\n },\n } as RunArtifactRow['payload']\n}\n\nfunction sanitizeArtifactForResponse(artifact: RunArtifactRow | null): RunArtifactRow | null {\n if (!artifact) return null\n return {\n ...artifact,\n payload: sanitizeArtifactPayloadForResponse(artifact.payload),\n }\n}\n\nasync function normalizeDashboardWorkspacePath(\n filePath: string,\n workspacePaths: ResolvedWorkspacePaths | undefined,\n kind: WorkspaceFileKind,\n requireExisting = true,\n): Promise<{ storagePath: string; executionPath: string }> {\n if (!workspacePaths) {\n throw new Error('Workspace path resolution is required for dashboard-triggered runs')\n }\n\n const record = await resolveWorkspaceFileTarget({\n workspace: workspacePaths,\n kind,\n filePath,\n requireExisting,\n })\n\n return { storagePath: record.workspaceRelativePath, executionPath: record.absolutePath }\n}\n\nfunction workspaceRecordToPath(record: WorkspaceFileRecord): { storagePath: string; executionPath: string } {\n return { storagePath: record.workspaceRelativePath, executionPath: record.absolutePath }\n}\n\nasync function resolveDashboardTestPattern(\n pattern: string,\n workspacePaths: ResolvedWorkspacePaths | undefined,\n): Promise<Array<{ storagePath: string; executionPath: string }>> {\n if (!workspacePaths) {\n throw new Error('Workspace path resolution is required for dashboard-triggered runs')\n }\n\n const normalizedPattern = pattern.replace(/\\\\/g, '/')\n if (isAbsolute(pattern) || normalizedPattern.split('/').includes('..')) {\n throw new Error(`Workspace test pattern is not allowed: ${pattern}`)\n }\n\n const candidates = await discoverWorkspaceFiles({ workspace: workspacePaths, kind: 'test' })\n const patternWorkspace: ResolvedWorkspacePaths = {\n ...workspacePaths,\n testMatch: [pattern],\n suiteMatch: [],\n }\n return candidates\n .filter((record) => isWorkspacePathMatch({\n workspace: patternWorkspace,\n kind: 'test',\n workspaceRelativePath: record.workspaceRelativePath,\n }))\n .map(workspaceRecordToPath)\n}\n\nfunction isSuiteFilePath(filePath: string | undefined): boolean {\n if (!filePath) return false\n const normalized = filePath.toLowerCase()\n return normalized.endsWith('.suite.yaml') || normalized.endsWith('.suite.yml')\n}\n\nasync function normalizeDashboardSuitePath(\n filePath: string,\n suiteFileManager?: SuiteFileManager,\n): Promise<{ storagePath: string; executionPath: string }> {\n if (!suiteFileManager) {\n throw new Error('Suite file management is required for dashboard-triggered suite runs')\n }\n\n return suiteFileManager.resolvePath(filePath)\n}\n\n/**\n * The `metadata` keys a CLIENT may write through `POST /api/queue/enqueue` (401-23, G-401-18-CR01).\n *\n * IT IS EMPTY, AND THE EMPTINESS IS THE DERIVATION'S ANSWER, not a placeholder. Every key that ever\n * appears in a run's `metadata` is written by this server: `args`/`isSuite` by the enqueue routes,\n * `timeout`/`timeoutSource`/`timeoutBaseMs`/`timeoutBufferMs` by `toExecutionTimeoutMetadata`,\n * `confirmScope` by `/api/runs/trigger` until 432-14 deleted the run-confirm pair (a row written\n * before then may still carry it), and `suiteIndex`/`farmSessionUrl`/`runDevice` by the CLI runner. A caller's OWN labels have their own\n * first-class door on this route — `attributes`, validated by `buildRunRequestAttributes` and\n * persisted in its own column. There is nothing left for a client to legitimately put here.\n *\n * WHAT IT REPLACED, AND WHY THE SHAPE MATTERS. It was a three-key DENYLIST (`args`/`target`/\n * `isSuite`), which is why `POST /api/queue/enqueue { metadata: { confirmScope } }` planted an\n * arbitrary confirm scope on a persisted run row with none of the validation `/api/runs/trigger`\n * applies. Paired with the artifact-payload leak this plan also closes, that bought an attacker the\n * whole escalation: read one browser's scope off `/artifact`, plant it on a run of your choosing,\n * and the confirm for that run is raised in the victim's own dialog. A read-side strip with an open\n * write door is half a fix, and this project has measured one-sided hardening minting regressions\n * three times (388/390/392).\n *\n * IF THIS SET EVER GAINS A KEY, `routes.runs.test.ts` holds the invariant it must satisfy: a\n * client-writable key must also be response-safe (or it is write-only dead weight nobody can read\n * back) and must not be one the server itself writes (or the client can overwrite the server).\n */\nexport const CLIENT_WRITABLE_QUEUED_RUN_METADATA_KEYS: ReadonlySet<string> = new Set<string>([])\n\n/**\n * The `metadata` keys this SERVER writes onto a run row — never a client.\n *\n * `confirmScope` stays on the list after 432-14 (D-14, D-22): nothing writes it now, but a row this\n * server wrote before then can still hold it, and it is still the server's key rather than one a\n * client may claim.\n */\nexport const SERVER_OWNED_RUN_METADATA_KEYS: ReadonlySet<string> = new Set<string>([\n 'args',\n 'confirmScope',\n 'farmSessionUrl',\n 'isSuite',\n 'runDevice',\n 'suiteIndex',\n 'target',\n 'timeout',\n 'timeoutBaseMs',\n 'timeoutBufferMs',\n 'timeoutSource',\n])\n\ntype QueuedRunMetadataResult =\n | { readonly ok: true; readonly metadata: Record<string, unknown> }\n | { readonly ok: false; readonly rejected: readonly string[] }\n\n/**\n * The write door's allowlist, and it REFUSES rather than silently dropping.\n *\n * ONE MECHANISM, NOT TWO. A filter that quietly deletes what it will not accept and a validator\n * that rejects it are the same decision made twice, and the version that keeps both is the version\n * where one of them stops being reached. This is the validator; the admitted subset it returns is\n * what reaches `enqueue`. A caller that sends a key the server owns learns so.\n */\nfunction sanitizeQueuedRunMetadata(metadata: unknown): QueuedRunMetadataResult {\n if (metadata === undefined || metadata === null) return { ok: true, metadata: {} }\n if (!isRecord(metadata)) return { ok: false, rejected: ['metadata'] }\n const rejected = Object.keys(metadata)\n .filter((key) => !CLIENT_WRITABLE_QUEUED_RUN_METADATA_KEYS.has(key))\n .sort()\n if (rejected.length > 0) return { ok: false, rejected }\n return { ok: true, metadata: { ...metadata } }\n}\n\n/**\n * The largest execution timeout a persisted run row may carry into `executionBackend.execute`.\n *\n * THE CEILING IS NOT THE POINT; THE FLOOR IS. `in-process-backend.ts:211` reads\n * `opts.timeout ?? this.options.defaultTimeout` and then validates — so ANY non-nullish nonsense\n * (`-1`, `NaN`, `'soon'`) skips the default and leaves the run with no reclamation timer at all. A\n * client that could write that key could pin a queue slot open forever. The ceiling closes the same\n * hole from the other side, where a finite but absurd value is a timer that will never fire; a day\n * is well past any dashboard-queued test (the largest the server itself computes is a YAML timeout\n * plus `DASHBOARD_EXECUTION_TIMEOUT_BUFFER_MS`), and the point is to keep reclamation reachable,\n * not to second-guess a long suite.\n */\nexport const MAX_QUEUED_EXECUTION_TIMEOUT_MS = 24 * 60 * 60 * 1000\n\n/**\n * Validate a persisted row's `metadata.timeout` at the seam that consumes it (401-23, T-401-G26).\n *\n * FALLS BACK, NEVER CLAMPS. An unusable value means \"this row says nothing about the timeout\", and\n * the honest answer to that is the backend's own default — not a number this function invented.\n */\nexport function sanitizeQueuedExecutionTimeout(value: unknown): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value)) return undefined\n if (value <= 0 || value > MAX_QUEUED_EXECUTION_TIMEOUT_MS) return undefined\n return value\n}\n\n// ---- CR-02 (401-18): the confirm scope stops leaving on the READ path ---------------------------\n\n/**\n * The `runs.metadata` keys a RESPONSE may carry.\n *\n * AN ALLOWLIST, NOT A KEYED REMOVAL, and the choice is the whole point of the repair. `confirmScope`\n * is the field that was measured leaving, but a `delete metadata.confirmScope` is one future\n * `metadata.<anything> = <a capability>` away from the identical defect — and this phase has spent\n * four rounds on precisely that class of half-fix. An allowlist fails CLOSED: a field nobody has\n * invented yet does not leave, and adding it here is a deliberate act with this comment attached.\n *\n * WHAT IS ON IT, and why each one:\n * - `args`, `isSuite`, `target` — what the queue was asked to run. Already published on every\n * run-reading response since v1; the write path's `sanitizeQueuedRunMetadata` refuses them from\n * a CLIENT, which is a different question from whether a reader may see the server's own.\n * - `timeout`, `timeoutSource`, `timeoutBaseMs`, `timeoutBufferMs` — the resolved execution\n * budget and where it came from, written by `toExecutionTimeoutMetadata`.\n * - `suiteIndex` — which member of a suite this run's queued row belongs to. (2026-08-27,\n * 405-07: this line used to name the run-detail timeline module that read it, which 405-03\n * deleted; that plan's scope boundary kept it out of server code, so the dangling reference\n * was carried here as a deferred item and is scrubbed with the rest of the retired feed.)\n * - `farmSessionUrl`, `runDevice` — read by the run navbar for a device-farm run.\n *\n * WHAT IS DELIBERATELY OFF IT: `confirmScope`, the leak this closes — and everything a caller\n * stuffed into `POST /api/queue/enqueue`'s free-form `metadata`, which used to round-trip verbatim\n * to any cross-origin reader. A queue API that accepts arbitrary keys and a run API that hands them\n * back is a self-service exfiltration channel; that it never carried anything sensitive in practice\n * is not a property anything checks.\n */\nexport const RESPONSE_SAFE_RUN_METADATA_KEYS: ReadonlySet<string> = new Set([\n 'args',\n 'isSuite',\n 'target',\n 'timeout',\n 'timeoutSource',\n 'timeoutBaseMs',\n 'timeoutBufferMs',\n 'suiteIndex',\n 'farmSessionUrl',\n 'runDevice',\n])\n\n/**\n * `sanitizeQueuedRunMetadata`'s READ-PATH counterpart (401-18, CR-02).\n *\n * Built in its shape and pointed the other way: that one refuses fields a CLIENT may WRITE, this\n * one refuses fields a RESPONSE may CARRY. `null` and absence round-trip unchanged, so a run with no\n * metadata is serialized exactly as it was.\n */\nfunction sanitizeRunMetadataForResponse(\n metadata: Record<string, unknown> | null | undefined,\n): Record<string, unknown> | null {\n if (metadata === null || metadata === undefined) return metadata ?? null\n const safe: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(metadata)) {\n if (RESPONSE_SAFE_RUN_METADATA_KEYS.has(key)) safe[key] = value\n }\n return safe\n}\n\n/**\n * The artifact payload's own copy of the caller's run metadata (G-401-18-CR01).\n *\n * ONE ALLOWLIST, APPLIED AT A SECOND SERIALIZATION SITE — not a second allowlist. `JobQueue.enqueue`\n * writes the SAME `opts.metadata` object into two places (`job-queue.ts:75-78`): the run row, and\n * `run_artifacts.payload.metadata`. 401-18 scrubbed the first and missed the second, and two\n * parallel allowlists is precisely the shape that would let them drift apart again — so this reuses\n * `sanitizeRunMetadataForResponse` rather than declaring keys of its own.\n *\n * `attributes` IS CARRIED THROUGH, and it is the one key that is: the queue MINTS it beside the\n * caller's keys (`job-queue.ts:77`) rather than accepting it, and the run-detail drawer reads it.\n * A blanket delete of `payload.metadata` would close the leak by deleting a shipped field.\n */\nfunction sanitizeArtifactPayloadMetadata(payload: Record<string, unknown>): Record<string, unknown> {\n const metadata = payload.metadata\n if (!isRecord(metadata)) return payload\n const safe = sanitizeRunMetadataForResponse(metadata) ?? {}\n return {\n ...payload,\n metadata: 'attributes' in metadata ? { ...safe, attributes: metadata.attributes } : safe,\n }\n}\n\n/**\n * Every `DashboardDatabase` read that hands this router a run row or a run artifact row.\n *\n * EXPORTED SO THE CENSUS CAN SCORE IT. `routes.runs.test.ts` parses `database.ts` for the public\n * READS whose return annotation names `RunRow`, `RunArtifactBundle` or `RunArtifactRow` and asserts\n * SET EQUALITY with this list — so a run-row read added to the database, or one dropped from here,\n * reds rather than quietly opening another door.\n *\n * `getRunArtifact` JOINED IN 401-23, AND WHY THE CENSUS HAD TO WIDEN TO SEE IT. The 401-18\n * predicate keyed on `RunRow|RunArtifactBundle` alone, and `getRunArtifact(runId): RunArtifactRow |\n * null` structurally cannot match either name — which is exactly how the artifact payload became\n * the door nobody wrote the strip into. The predicate's SHAPE was the gap, not its diligence.\n */\nexport const RESPONSE_SAFE_RUN_READ_METHODS = [\n 'getNextPendingRun',\n 'getPendingRuns',\n 'getRun',\n 'getRunArtifact',\n 'getRunArtifactBundle',\n 'getRuns',\n 'getRunsBySuiteId',\n 'getRunsByTest',\n] as const\n\n/**\n * Run-NAMED database members that hand the response layer no run metadata at all (401-23, WR-08).\n *\n * THE OTHER HALF OF A TOTAL FUNCTION. `withResponseSafeRunReads` asserts at CONSTRUCTION that every\n * `/run/i`-named method on the database it is given is accounted for — either wrapped above, or\n * named here with the reason it needs no wrapping. Anything else throws. Before this the wrapper\n * was `Object.create(db, {…overrides…})`, transparent by default, so an unlisted or FUTURE\n * run-reading method reached the response layer through the prototype and returned raw rows.\n *\n * Each name and why it carries no run metadata to a reader:\n * - `insertRun`, `insertPendingRun`, `insertRunArtifact`, `updateRun`, `updateRunMetadata`,\n * `updateRunStatus`, `deleteRun` — WRITES. They return an id, a delete tally, a boolean, or\n * nothing.\n * - `stageRunArtifact`, `finalizeRunArtifact` — writes that ECHO the row they just wrote, to the\n * writer that supplied it (`server.ts`, on the raw handle). This router never calls them;\n * `routes.runs.test.ts` pins that absence, because the echo would otherwise be a door.\n * - `getRunsByTestCount`, `getRunsBySuiteIdCount` — a `number`.\n * - `listRunAttributeKeys`, `listRunAttributeValues` — attribute-name/value suggestions built by\n * the database from the `attributes` column; they never touch `metadata`.\n */\nconst RUN_READS_WITHOUT_ROWS: ReadonlySet<string> = new Set([\n // 2026-08-27 (405-01, D-01/D-03): the v2 projection's six members.\n //\n // The five WRITES return nothing; they are here for the same reason `insertRun` is.\n //\n // `readRunDetailRows` IS A READ AND IS STILL HERE, and that is the judgement this set exists to\n // make explicit rather than to hide. It returns members, steps and sub-actions — the bus\n // payloads as the subscriber MASKED them (T-363-05) — and NO `RunRow` and no\n // `RunArtifactRow`. It therefore carries none of the run metadata the 401-23 scrub law exists\n // to strip, so wrapping it would be wrapping a shape that has nothing to strip. This router\n // does not call it either: the detail arm dispatches through the injected host, which is the\n // whole of D-03.\n 'deleteMemberProjection',\n 'incrementRunMemberAttempts',\n 'insertRunStep',\n 'insertRunSubAction',\n 'readRunDetailRows',\n 'upsertRunMember',\n 'deleteRun',\n 'finalizeRunArtifact',\n 'getRunsBySuiteIdCount',\n 'getRunsByTestCount',\n // 433-30: run ids and a count, no row; each id is dispatched through the agent host.\n 'listInsightsWindowRunIds',\n 'insertPendingRun',\n 'insertRun',\n 'insertRunArtifact',\n 'listRunAttributeKeys',\n 'listRunAttributeValues',\n // 2026-10-16 (442-01, D-01): an owner (pid, incarnation, host), no run metadata.\n 'readRunOwner',\n // 2026-10-16 (442-01, D-04): ids and owners only, no run metadata.\n 'listRunningRunOwners',\n // 2026-10-16 (442-01, D-04): compare-and-set writes that return a boolean.\n 'finalizeOrphanRun',\n 'finalizeOwnRun',\n // 2026-10-17 (443-13, GAP-D1): a compare-and-set write that returns a boolean, no run metadata.\n 'closeOwnRun',\n // 2026-10-17 (443-02, D-07): a compare-and-set write that returns a boolean, no run metadata.\n 'claimRunningRow',\n 'stageRunArtifact',\n 'updateRun',\n 'updateRunMetadata',\n 'updateRunStatus',\n])\n\n/**\n * Run-named members that are not on `DashboardDatabase`'s TYPE at all (401-23, WR-08).\n *\n * WHY THIS SET HAS TO EXIST. TypeScript's `private` is erased at emit, so every private helper is\n * a live own-property of the prototype and the runtime census below sees all of them. They are not\n * response-layer doors — nothing typed as a `DashboardDatabase` can name them — but a census that\n * ranges the live surface has to say so out loud rather than quietly skipping a shape it does not\n * like. Skipping is how 401-18's predicate came to be blind.\n *\n * A NEW PRIVATE HELPER WITH `run` IN ITS NAME WILL RED THE BUILD until it is added here. That is\n * the intended cost: the alternative is a filter that guesses which names are internal, and a\n * guess is what this whole class of census keeps getting wrong.\n */\nconst RUN_MEMBERS_NOT_ON_THE_TYPE: ReadonlySet<string> = new Set([\n 'buildTrendsFromRuns',\n 'getHealedRunIds',\n 'getRunAccessibilityEnabled',\n 'listRunsForInsights',\n 'mapRunArtifactRow',\n 'mapRunRow',\n 'parseRunAttributes',\n 'queryRunsWithAttributePredicates',\n 'runMigrations',\n 'summarizeAnalyticsRuns',\n])\n\n/**\n * Refuse to build a response-layer projection over a database with an unaccounted run-named read.\n *\n * IT RANGES THE LIVE OBJECT, not a source file — the axis the 401-18 census could not reach. A\n * return-annotation grep can only see what an annotation spells; this sees what the router will\n * actually be able to call, including a method inherited from a prototype or attached at runtime.\n */\nfunction assertRunReadsAccountedFor(db: DashboardDatabase, wrapped: ReadonlySet<string>): void {\n const surface = new Set<string>()\n let layer: object | null = db as unknown as object\n while (layer !== null && layer !== Object.prototype) {\n for (const name of Object.getOwnPropertyNames(layer)) {\n if (name === 'constructor' || !/run/i.test(name)) continue\n const descriptor = Object.getOwnPropertyDescriptor(layer, name)\n if (descriptor === undefined || typeof descriptor.value !== 'function') continue\n surface.add(name)\n }\n layer = Object.getPrototypeOf(layer) as object | null\n }\n const unaccounted = [...surface]\n .filter((name) => !wrapped.has(name)\n && !RUN_READS_WITHOUT_ROWS.has(name)\n && !RUN_MEMBERS_NOT_ON_THE_TYPE.has(name))\n .sort()\n if (unaccounted.length > 0) {\n throw new Error(\n 'withResponseSafeRunReads: unaccounted run-named database method(s): '\n + `${unaccounted.join(', ')}. Add each to RESPONSE_SAFE_RUN_READ_METHODS with a scrubbing `\n + 'override, to RUN_READS_WITHOUT_ROWS with the reason it hands out no run metadata, or to '\n + 'RUN_MEMBERS_NOT_ON_THE_TYPE if it is a private helper no typed caller can reach.',\n )\n }\n}\n\n/**\n * The database as the RESPONSE LAYER may read it (401-18, CR-02).\n *\n * WHY A WRAPPER AT THE ROUTER AND NOT A STRIP AT EACH DOOR. The re-derived census found SIX\n * run-serializing responses, not the two the ruling named — the run list, the run detail, the\n * artifact bundle's `run` and `children[].run`, queue status's `pending`/`running`/`recent`, and\n * both analytics run lists. Six doors is a strong argument that the seventh is the one nobody\n * writes the strip into. This is the choke point they all pass through, so a door added next phase\n * is covered by construction rather than by remembering.\n *\n * AND WHY NOT `mapRunRow`, WHICH IS THE OTHER CHOKE POINT. The queue consumer reads the\n * persisted row's own metadata to dispatch the run (`server.ts`); stripping at the DB→row boundary\n * would take from that reader what only a RESPONSE must not carry. `server.ts` and `job-queue.ts`\n * hold the RAW handle and are untouched — this projection exists only inside `createRouter`, which\n * is exactly the layer that serializes.\n *\n * THE PERSISTED VALUE IS NEVER TOUCHED. This is a read projection. 2026-10-01 (432-14, D-14/D-22):\n * the trigger no longer writes a confirm scope and the queue consumer no longer reads one; a row\n * written before then may still hold it, and this projection keeps it from leaving.\n *\n * AND IT FAILS LOUDLY RATHER THAN TRANSPARENTLY (401-23, WR-08). `Object.create(db, {…})` forwards\n * everything it does not override, so before this an unlisted — or merely NEW — run-reading method\n * reached the response layer through the prototype and returned raw rows. That is the structural\n * root of G-401-18-CR01, not a footnote to it: the artifact payload leaked for exactly as long as\n * nobody remembered to write a strip for a door the wrapper was happy to forward. The construction\n * assertion below makes forgetting a build error instead of a leak.\n */\nfunction withResponseSafeRunReads(db: DashboardDatabase): DashboardDatabase {\n const scrubRow = <T>(row: T): T => {\n if (row === null || row === undefined || typeof row !== 'object') return row\n const record = row as unknown as { metadata?: Record<string, unknown> | null }\n if (!('metadata' in record)) return row\n return { ...record, metadata: sanitizeRunMetadataForResponse(record.metadata) } as unknown as T\n }\n const scrubRows = <T>(rows: readonly T[]): T[] => rows.map(scrubRow)\n // ONE artifact scrub, named once and reached by both artifact reads below, so the bare-row door\n // and the bundle door cannot drift into two allowlists.\n const scrubArtifact = (artifact: RunArtifactRow | null): RunArtifactRow | null => {\n if (artifact === null || !isRecord(artifact.payload)) return artifact\n return {\n ...artifact,\n payload: sanitizeArtifactPayloadMetadata(artifact.payload) as unknown as RunArtifactRow['payload'],\n }\n }\n const overrides: Record<string, PropertyDescriptor> = {\n getNextPendingRun: { value: () => scrubRow(db.getNextPendingRun()) },\n getPendingRuns: { value: () => scrubRows(db.getPendingRuns()) },\n getRun: { value: (id: string) => scrubRow(db.getRun(id)) },\n getRuns: {\n value: (...args: Parameters<DashboardDatabase['getRuns']>) => scrubRows(db.getRuns(...args)),\n },\n getRunsBySuiteId: {\n value: (...args: Parameters<DashboardDatabase['getRunsBySuiteId']>) =>\n scrubRows(db.getRunsBySuiteId(...args)),\n },\n getRunsByTest: {\n value: (...args: Parameters<DashboardDatabase['getRunsByTest']>) =>\n scrubRows(db.getRunsByTest(...args)),\n },\n // THE ROUTER HAS NO SERIALIZER OF ITS OWN FOR THIS ONE. `GET /api/runs/:id/artifact` reaches\n // the payload through `getRunArtifactBundle` and serializes it with\n // `sanitizeArtifactForResponse`; a caller reaching for the bare row has no such step, so the\n // projection is its only choke point. Same allowlist, so the two cannot drift.\n getRunArtifact: { value: (runId: string) => scrubArtifact(db.getRunArtifact(runId)) },\n // 405-07 (D-02): the bundle is ONE artifact now. It used to carry the child runs of a suite\n // parent, whose `run` rows this override scrubbed; nothing has written a child row since\n // 402-09, and the shape went with the column. `getRunArtifact` above remains the choke point\n // for the payload itself, and this wrapper delegates to it.\n getRunArtifactBundle: {\n value: (runId: string) => ({ artifact: scrubArtifact(db.getRunArtifactBundle(runId).artifact) }),\n },\n }\n // OVERRIDE ONLY WHAT THE GIVEN DATABASE ACTUALLY HAS. Defining a descriptor for an absent method\n // would MINT one that throws on call — a projection that adds doors is not a projection.\n const present: Record<string, PropertyDescriptor> = {}\n for (const [name, descriptor] of Object.entries(overrides)) {\n if (typeof (db as unknown as Record<string, unknown>)[name] === 'function') present[name] = descriptor\n }\n assertRunReadsAccountedFor(db, new Set(RESPONSE_SAFE_RUN_READ_METHODS))\n return Object.create(db, present) as DashboardDatabase\n}\n\n// 2026-08-27 (405-07, D-14) — THE PATH-BASED ARTIFACT MACHINERY IS DELETED.\n//\n// Four functions and a cleanup routine stood here: a containment resolver, a three-door serving\n// verdict over an encoded `:runId/:filename` pair, its fixed-shape refusal, and the filesystem\n// sweep a run deletion performed. All five existed to serve or remove artifacts ADDRESSED BY PATH.\n//\n// Refs are the only artifact addressing now (D-14). A sub-action carries `artifactRefs`, the page\n// mints `\\`/api/runs/<runId>/artifacts/<sha>\\`` from one total route map, and the bytes are reached\n// through the `runs.artifact` op — whose containment rule is the evidence store's own, written\n// once, rather than a second path assembly in this file that is free to be the weaker one.\n//\n// AND THE DELETION SWEEP IS NOT REPLACED. `DELETE /api/runs/:id` removes rows and touches nothing\n// under the run directory: the event log and the content-addressed blobs there are the run's own\n// record, which this server projects and does not own (T-405-27).\n\nasync function readWorkspaceHooks(\n configManager: ConfigManager | undefined,\n configPath: string | undefined,\n): Promise<{\n hooks: Array<{ name: string }>\n filePath: string\n resolvedHooks: Map<string, import('@vostride/agent-qa-core').HookDefinition>\n errors: string[]\n missing: boolean\n hookRegistryError?: string\n}> {\n const hookRegistryManager = createHookRegistryManager(configManager, configPath)\n if (!hookRegistryManager) {\n return {\n hooks: [],\n filePath: '',\n resolvedHooks: new Map(),\n errors: ['Config management not available'],\n missing: true,\n hookRegistryError: 'Config management not available',\n }\n }\n\n const [hookCatalog, prepareResult] = await Promise.all([\n hookRegistryManager.readCatalog(),\n hookRegistryManager.prepareForExecution(),\n ])\n\n return {\n hooks: hookCatalog.hooks.map((hook) => ({ name: hook.name })),\n filePath: hookCatalog.filePath,\n resolvedHooks: prepareResult.resolvedHooks,\n errors: hookCatalog.errors,\n missing: hookCatalog.missing,\n hookRegistryError: prepareResult.hookRegistryError,\n }\n}\n\nasync function readWorkspaceEnvVars(\n workspacePaths: ResolvedWorkspacePaths | undefined,\n): Promise<Record<string, string>> {\n if (!workspacePaths) {\n return {}\n }\n\n try {\n const content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n return parseEnvFile(content)\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new Error(`workspace.envFile not found: ${workspacePaths.envFile.absolutePath}`)\n }\n throw error\n }\n}\n\nfunction validateHookRunRequest(body: unknown): {\n overrides: Record<string, string>\n fieldErrors: Array<{ field: 'registry'; code: string; message: string }>\n} {\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n return {\n overrides: {},\n fieldErrors: [\n {\n field: 'registry',\n code: 'invalid_payload',\n message: 'Hook run payload is required',\n },\n ],\n }\n }\n\n const rawOverrides = (body as { overrides?: unknown }).overrides\n if (rawOverrides === undefined) {\n return { overrides: {}, fieldErrors: [] }\n }\n\n if (!Array.isArray(rawOverrides)) {\n return {\n overrides: {},\n fieldErrors: [\n {\n field: 'registry',\n code: 'invalid_overrides',\n message: 'Hook run overrides must be an array',\n },\n ],\n }\n }\n\n const fieldErrors: Array<{ field: 'registry'; code: string; message: string }> = []\n const overrides: Record<string, string> = {}\n const seenKeys = new Set<string>()\n\n rawOverrides.forEach((entry, index) => {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n fieldErrors.push({\n field: 'registry',\n code: 'invalid_override',\n message: `Override ${index + 1} must be an object with key and value`,\n })\n return\n }\n\n const key = typeof (entry as { key?: unknown }).key === 'string'\n ? (entry as { key: string }).key.trim()\n : ''\n const value = (entry as { value?: unknown }).value\n\n if (!key) {\n fieldErrors.push({\n field: 'registry',\n code: 'invalid_override_key',\n message: `Override ${index + 1} must include a non-empty key`,\n })\n return\n }\n\n if (seenKeys.has(key)) {\n fieldErrors.push({\n field: 'registry',\n code: 'duplicate_override_key',\n message: `Override key \"${key}\" is duplicated`,\n })\n return\n }\n\n if (typeof value !== 'string') {\n fieldErrors.push({\n field: 'registry',\n code: 'invalid_override_value',\n message: `Override \"${key}\" must have a string value`,\n })\n return\n }\n\n seenKeys.add(key)\n overrides[key] = value\n })\n\n return { overrides, fieldErrors }\n}\n\nfunction summarizeHookNetworkLogs(\n networkLogs: Array<{\n url: string\n method: string\n status: number\n startTime: number\n endTime: number\n }> | undefined,\n): import('../hooks/hook-registry-types.js').HookRunNetworkLogEntry[] {\n return (networkLogs ?? []).map((entry, index) => ({\n id: `network-${index + 1}`,\n method: entry.method,\n url: entry.url,\n statusCode: Number.isFinite(entry.status) ? entry.status : null,\n durationMs: Number.isFinite(entry.endTime - entry.startTime)\n ? Math.max(0, entry.endTime - entry.startTime)\n : null,\n error: null,\n }))\n}\n\ninterface RouterDeps {\n db: DashboardDatabase\n workspacePaths?: ResolvedWorkspacePaths\n /**\n * The injected run backend (401-07, D-09).\n *\n * TYPED AGAINST THE INTERFACE, AND NOW ACTUALLY SEPARABLE. It always meant to be, and was not:\n * the retired live-event route reached past the interface for a per-run replay buffer only the\n * concrete class declared, so the seam had exactly one possible implementation. That route and\n * that buffer are gone (405-07, D-19); what this router asks of a backend is the interface.\n */\n executionBackend?: ExecutionBackend\n jobQueue?: JobQueue\n testFileManager?: TestFileManager\n suiteFileManager?: SuiteFileManager\n configManager?: ConfigManager\n configPath?: string\n // 441 GAP-D5: hook output, provider error text and target names leave through this mask. Absent,\n // the router uses the config manager's; with neither, those answers carry no such text.\n declaredSecretMask?: MaskFn\n\n llmConfig?: DashboardRuntimeLLMConfig\n authFetch?: typeof globalThis.fetch\n sessionManager?: import('../live-editor/session-manager.js').SessionManager\n /**\n * The composed agent host (400-01, D-01). It serves run detail, marks, analysis, knowledge and\n * post-processing. (The run-confirm pair it also served is deleted, 432-14.)\n *\n * INJECTED, and optional because a router built the legacy two-argument way\n * (`createRouter(db)`) has none. Each arm that needs it then answers by name rather than 404 —\n * the route exists, this server was started without a host. See `chat/host.ts` for why the\n * composition happens in the CLI command that starts this server rather than here.\n */\n agentHost?: AgentHost\n /**\n * The run service's readiness predicate, served on the LOCAL door (402-05, D-15).\n *\n * THE SAME FUNCTION THE RUN SERVICE'S `/ok` SERVES — one readiness spelling behind two doors,\n * which is the whole of D-15. It is passed in rather than computed here for the reason `agentHost`\n * is: every fact in it (is a host composed) is known only to the process that composed it, and a\n * copy made here is how the run service and the dashboard start disagreeing about whether this\n * process can run anything.\n *\n * ABSENT IS THE LEGACY MOUNT, NOT AN UNCONFIGURED SERVICE. `agent-qa dashboard` ALWAYS supplies\n * this, because the browser preflight needs an honest answer and a 404 is not one. A router built the legacy\n * two-argument way has none, and that arm answers 503 by name on `agentHost`'s idiom.\n */\n runServiceReadiness?: () => RunServiceReadiness\n /**\n * The started run's session, or nothing — the LOCAL door's attach port (402-08, D-01).\n *\n * THE SAME PORT THE AUTHED DOOR USES, and `server.ts` supplies it by reading\n * `runService.attach` rather than by composing a second lookup: one session registry serves both\n * doors, so a run the remote door can attach to is a run this door can attach to, and there is\n * no second retention window to disagree about.\n *\n * ABSENT MEANS NO RUN SERVICE WAS MOUNTED, which is the same fact as \"this process composed no\n * session registry\" — unlike `runServiceReadiness` above, whose absence is a legacy mount rather\n * than an unconfigured service. The route then answers 503 BY NAME on the execution routes' own\n * degradation idiom, never a 404 (the route exists) and never an empty stream (which would look\n * like a run that emitted nothing).\n */\n runServiceAttach?: (runId: string) => RunSession | undefined\n /**\n * The `runs.liveurl` mint, DISPATCHED THROUGH THE REGISTRY by the composition root (403 D-03).\n *\n * A FUNCTION, not a signer: this router holds no key and mints nothing. What it does is turn one\n * HTTP shape into one op call and the op's refusals into status codes — which is the whole of a\n * thin client over the function layer.\n *\n * ABSENT MEANS THIS HOST SERVES NO LIVE VIEW, and the route answers 503 BY NAME on\n * `runServiceReadiness`'s idiom — never a 404 (the route exists) and never a URL to nowhere.\n */\n mintLiveUrl?: (runId: string, handle: number) => Promise<RunsLiveUrlResult>\n /**\n * The `editor.liveurl` mint, dispatched through the registry by the composition root (428 D-07).\n * The editor counterpart of `mintLiveUrl`: a function, never a signer. ABSENT MEANS THIS HOST\n * MINTS NO EDITOR VIEW, and the route answers 503 by name.\n */\n mintEditorLiveUrl?: (sessionId: string) => Promise<EditorLiveUrlResult>\n /**\n * The in-process chip sink the post-processing stream relays from (404-05, D-16).\n *\n * INJECTED ON `agentHost`'s OWN IDIOM. The publisher is the CLI's post-run chip emitter — a\n * package this one may not import — so `agent-qa dashboard` creates the relay, hands\n * `relay.publish` to the run door's bridge and hands the relay itself here. One object, two\n * halves of the same process; a relay composed here instead would be a registry the emitter\n * never reaches, and the stream would heartbeat forever at a page whose chips do move.\n *\n * ABSENT MEANS THIS SERVER HAS NO PUSH CHANNEL and the stream arm answers 503 BY NAME — never a\n * 404 (the route exists) and never an empty stream, which would look like a chain that never\n * ticked. The READ route is unaffected: polling works with no relay at all.\n */\n postProcessingRelay?: PostProcessingRelay\n}\n\nexport function createRouter(deps: RouterDeps): (req: IncomingMessage, res: ServerResponse) => void\nexport function createRouter(db: DashboardDatabase): (req: IncomingMessage, res: ServerResponse) => void\nexport function createRouter(dbOrDeps: DashboardDatabase | RouterDeps): (req: IncomingMessage, res: ServerResponse) => void {\n const deps: RouterDeps = 'db' in dbOrDeps && typeof (dbOrDeps as RouterDeps).db === 'object' && 'getRuns' in ((dbOrDeps as RouterDeps).db ?? {})\n ? dbOrDeps as RouterDeps\n : { db: dbOrDeps as DashboardDatabase }\n const { executionBackend, jobQueue, testFileManager, suiteFileManager, configManager, workspacePaths, llmConfig, authFetch, sessionManager } = deps\n const declaredMask = deps.declaredSecretMask ?? configManager?.mask\n // CR-02 (401-18): the response layer reads run rows through the projection, never raw. The host's\n // own reconciliation and the queue keep `deps.db` — see `withResponseSafeRunReads`.\n const db = withResponseSafeRunReads(deps.db)\n const pluginOAuthSessions = new Map<string, PluginOAuthSession>()\n const withCredentialLock = createCredentialLock()\n const connectsInFlight = createConnectInFlight()\n const undoStore = createUndoStore({ retentionMs: UNDO_RETENTION_MS })\n\n return (req: IncomingMessage, res: ServerResponse) => {\n // 400-16 (gap 7): the SAME guarded parse `server.ts`'s listener uses, not a second copy. In the\n // shipped process the listener has already refused an unparseable request line, so this arm is\n // defence in depth — but this router is EXPORTED and mounted directly (the conformance suite\n // stands it up on its own `node:http` server), and on that mount an unguarded parse is a live\n // throw. The refusal is answered before every route, so no frame below ever sees a URL that\n // could not be parsed.\n const url = tryParseRequestUrl(req)\n if (url === undefined) {\n json(res, { error: 'Bad Request' }, 400)\n return\n }\n const path = url.pathname\n\n // 2026-10-01 (432-14, D-14): the run-confirm prefix is no longer dispatched. It was mounted\n // here, ahead of the shared OPTIONS arm, so its answers carried no wildcard grant. Its two paths\n // now fall to the same arms as any path this server does not serve — the shared preflight and\n // the generic 404 — not redirected and not stubbed.\n\n // 429-01 D-19: the field-merge config write, ahead of the shared OPTIONS arm so its answers\n // never pass through the wildcard grant.\n if (path === '/api/config' && req.method === 'PATCH') {\n if (!configManager) {\n jsonNoCors(res, { error: 'config_unavailable' }, 503)\n return\n }\n registerConfigWriteRoute(req, res, { configManager, undoStore })\n return\n }\n\n // 429-11 D-24: the Undo door answers every method itself, so no preflight grant reaches it.\n if (path === '/api/config/undo') {\n registerConfigUndoRoute(req, res, {\n configManager,\n undoStore,\n restoreCredential: (name, credential) => withCredentialLock(async () => {\n if (await readAuthEntry(name) !== undefined) return false\n await writeDashboardAuth(name, credential as DashboardAuthCredential)\n return true\n }),\n })\n return\n }\n\n // 429-06 D-22: the cheap revision read the page polls to notice an outside edit.\n if (path === '/api/config/revision' && req.method === 'GET') {\n if (!configManager) {\n jsonNoCors(res, { error: 'config_unavailable' }, 503)\n return\n }\n registerConfigRevisionRoute(req, res, { configManager })\n return\n }\n\n // 429-10 D-15/D-17: the draft connect transaction, ahead of the shared OPTIONS arm so its\n // answers never pass through the wildcard grant.\n if (path === '/api/llm/connect' && req.method === 'POST') {\n if (!configManager) {\n jsonNoCors(res, { error: 'config_unavailable' }, 503)\n return\n }\n registerLlmConnectRoute(req, res, {\n configManager,\n withCredentialLock,\n credentialProvider: (name, credential) => credentialProductProvider(name, credential as DashboardAuthCredential),\n connectionTimeoutMs: llmConnectionTestTimeoutMs,\n inFlight: connectsInFlight,\n })\n return\n }\n\n // 2026-10-01 (432-21, owner decision recorded in 432-14 #4): THE RUN TRIGGER AND THE QUEUE\n // ENQUEUE ARE SAME-SITE ONLY, AHEAD OF THE SHARED OPTIONS ARM. With the run approval gone\n // (432-13/14), a page on another origin could start any non-production run with a simple\n // cross-site POST to either path; these two never had the refusal the mark, config-write,\n // live-editor and credential doors carry. The guard runs for every method on exactly these two\n // paths, so a cross-site preflight is refused too and gets no wildcard grant, and it runs before\n // the queue is consulted or a body is read, so a refused request queues and starts nothing.\n // The dashboard's own Run (same origin) and a local client that sends no `Origin` — the CLI,\n // `curl`, the conformance harness, `dashboard-smoke.mjs` — are admitted. The whole-server CORS\n // posture (WINDOWS CR-01) is unchanged.\n if (path === '/api/runs/trigger' || path === '/api/queue/enqueue') {\n if (refuseCrossSiteRequest(req) !== undefined) {\n jsonNoCors(res, { error: 'cross_site_refused' }, 403)\n return\n }\n }\n\n if (req.method === 'OPTIONS') {\n cors(res)\n return\n }\n\n // GET /api/auth-states — list safe auth-state metadata only\n if (path === '/api/auth-states' && req.method === 'GET') {\n if (!configManager || !deps.configPath) {\n json(res, { error: 'Auth-state metadata not available' }, 503)\n return\n }\n ;(async () => {\n try {\n const config = await readConfigValues(configManager)\n const targetName = url.searchParams.get('target') ?? undefined\n const authStates = await listAuthStateMetadata({\n configDir: dirname(resolve(deps.configPath!)),\n authStateDir: getConfiguredAuthStateDir(config),\n targetName,\n })\n json(res, { authStates })\n } catch {\n json(res, { error: 'Could not list auth states.' }, 500)\n }\n })()\n return\n }\n\n // GET /api/runs\n if (path === '/api/runs' && req.method === 'GET') {\n // THE SAME-SITE GUARD, FIRST (405 CR-01) — see `refuseCrossSiteDisplayRead`.\n if (refuseCrossSiteDisplayRead(req, res)) return\n const statuses = url.searchParams.getAll('status')\n const unknownStatus = statuses.find((word) => !isRunStatusWord(word))\n if (unknownStatus !== undefined) {\n jsonNoCors(res, { error: `Unknown run status: ${unknownStatus}.` }, 400)\n return\n }\n const name = url.searchParams.get('name') ?? undefined\n const platform = url.searchParams.get('platform') ?? undefined\n const target = normalizeRunFilterValue(url.searchParams.get('target'))\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 50\n const offset = url.searchParams.has('offset') ? parseInt(url.searchParams.get('offset')!, 10) : 0\n const attributePredicatesResult = parseAttributePredicates(url.searchParams)\n if (!attributePredicatesResult.ok) {\n json(res, { error: attributePredicatesResult.error }, 400)\n return\n }\n\n void readTargetPlatformMap(configManager)\n .then((targetPlatforms) => {\n const allRuns = db.getRuns({\n statuses,\n name,\n from,\n to,\n attributePredicates: attributePredicatesResult.predicates,\n })\n // 405-07 (D-02): a suite row used to be enriched with its child runs as `tests`. Nothing\n // has written a child run row since 402-09 — the members of a suite run are `run_members`\n // on the one row — so this branch could only ever attach an empty array.\n const enrichedRuns = allRuns.map(run => enrichRunRow(run, targetPlatforms))\n const platformFilteredRuns = enrichedRuns.filter(run =>\n matchesPlatformFilter(run, normalizeSupportedPlatform(platform)),\n )\n const targetOptions = Array.from(new Set(\n platformFilteredRuns\n .flatMap(run => [run.targetName, ...(run.tests?.map(test => test.targetName) ?? [])])\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0),\n )).sort((a, b) => a.localeCompare(b))\n const filtered = platformFilteredRuns.filter(run => matchesTargetFilter(run, target))\n\n const runs = filtered.slice(offset, offset + limit)\n jsonNoCors(res, {\n runs,\n total: filtered.length,\n targets: targetOptions,\n })\n })\n .catch(() => jsonNoCors(res, { error: 'Failed to list runs' }, 500))\n return\n }\n\n // GET /api/runs/attributes/keys\n if (path === '/api/runs/attributes/keys' && req.method === 'GET') {\n const limitResult = parseBoundedIntegerQueryParam(url.searchParams.get('limit'), 'limit', 1, 100, 50)\n if (!limitResult.ok) {\n json(res, { error: limitResult.error }, 400)\n return\n }\n json(res, {\n keys: db.listRunAttributeKeys({\n limit: limitResult.value,\n q: url.searchParams.get('q') ?? undefined,\n }),\n })\n return\n }\n\n // GET /api/runs/attributes/values\n if (path === '/api/runs/attributes/values' && req.method === 'GET') {\n const key = url.searchParams.get('key')?.trim()\n if (!key) {\n json(res, { error: 'key is required' }, 400)\n return\n }\n const limitResult = parseBoundedIntegerQueryParam(url.searchParams.get('limit'), 'limit', 1, 100, 50)\n if (!limitResult.ok) {\n json(res, { error: limitResult.error }, 400)\n return\n }\n json(res, {\n values: db.listRunAttributeValues(key, {\n limit: limitResult.value,\n q: url.searchParams.get('q') ?? undefined,\n }),\n })\n return\n }\n\n // GET /api/runs/:id/artifact\n const runArtifactMatch = path.match(/^\\/api\\/runs\\/([^/]+)\\/artifact$/)\n if (runArtifactMatch && req.method === 'GET') {\n // THE SAME-SITE GUARD, FIRST (405 CR-01) — see `refuseCrossSiteDisplayRead`.\n if (refuseCrossSiteDisplayRead(req, res)) return\n const runId = decodeURIComponent(runArtifactMatch[1])\n const run = db.getRun(runId)\n if (!run) {\n notFound(res, 'Run not found')\n return\n }\n const bundle = db.getRunArtifactBundle(runId)\n jsonNoCors(res, {\n run,\n artifact: sanitizeArtifactForResponse(bundle.artifact),\n missingSections: getArtifactMissingSections(bundle.artifact),\n })\n return\n }\n\n // 2026-08-27 (405-07, D-03/D-19) — FOUR READ ARMS WERE DELETED FROM THIS BLOCK.\n //\n // The accessibility summary, the per-step reasoning trace, the log page and the step list each\n // answered off a v1 projection table with no producer left. `runs.detail` supersedes them: it is ONE read,\n // through the function layer, over the bus-shaped projection the subscriber actually writes —\n // which is D-03's whole point, that the page's read is a read the CLI, MCP and chat can make\n // too. Keeping these beside it would have kept a second, private read path the function layer\n // cannot see, answering from tables nothing fills.\n //\n // They are not redirected and not stubbed. The router's generic 404 answers them, because a\n // route that no longer exists is the honest thing for a client to discover.\n\n // GET /api/runs/:id/execution-logs\n if (path.startsWith('/api/runs/') && path.endsWith('/execution-logs') && req.method === 'GET') {\n // THE SAME-SITE GUARD, FIRST (405 CR-01) — see `refuseCrossSiteDisplayRead`.\n if (refuseCrossSiteDisplayRead(req, res)) return\n const segments = path.split('/')\n const id = segments[3]\n const run = db.getRun(id)\n if (!run) {\n notFound(res, 'Run not found')\n return\n }\n const stepId = url.searchParams.get('stepId') ?? undefined\n const type = url.searchParams.get('type') ?? undefined\n\n // 405-07 (D-02): a suite run's logs used to be gathered across its child run rows. There are\n // no child rows — one `runs` row per run since 402-09 — and a suite's hook logs are written\n // against that one id, carrying `test_index`/`step_index` to say where in the run they ran.\n const logs = db.getExecutionLogs({ runId: id, stepId, type })\n jsonNoCors(res, { logs })\n return\n }\n\n // 419 D-13: register before the run catch-all; no private feedback implementation here.\n if (path.startsWith('/api/runs/') && path.endsWith('/mark') && req.method === 'POST') {\n if (deps.agentHost === undefined) {\n jsonNoCors(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n let runId: string\n try {\n runId = decodeURIComponent(path.slice('/api/runs/'.length, -'/mark'.length))\n } catch {\n jsonNoCors(res, { error: 'invalid_mark_input' }, 400)\n return\n }\n registerRunMarkRoute(req, res, { host: deps.agentHost, runId, boundary: 'human' })\n return\n }\n\n // 423-21 D-18: the read-tier consequence preview. POST carries runs.mark's exact input; the\n // adapter guards, parses and dispatches the registered op, and this arm owns no feedback logic.\n if (req.method === 'POST' && /^\\/api\\/runs\\/[^/]+\\/mark-preview$/.test(path)) {\n if (deps.agentHost === undefined) {\n jsonNoCors(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n let runId: string\n try {\n runId = decodeURIComponent(path.slice('/api/runs/'.length, -'/mark-preview'.length))\n } catch {\n jsonNoCors(res, { error: 'invalid_run_id' }, 400)\n return\n }\n serveRunMarkPreviewRead(req, res, { runId, host: deps.agentHost, boundary: 'human' })\n return\n }\n\n // POST /api/runs/:id/cancel — cancel a pending or running execution\n if (path.startsWith('/api/runs/') && path.endsWith('/cancel') && req.method === 'POST') {\n if (!jobQueue) {\n json(res, { error: 'Queue not available' }, 503)\n return\n }\n let runId: string\n try {\n runId = decodeURIComponent(path.slice('/api/runs/'.length, path.length - '/cancel'.length))\n } catch {\n json(res, { error: 'invalid_run_id' }, 400)\n return\n }\n // 2026-10-17 (444-06, D-31): each answer in plain words; the route writes nothing.\n const outcome = jobQueue.cancel(runId)\n switch (outcome.kind) {\n case 'cancelled':\n json(res, { outcome: 'cancelled', message: 'Run cancelled before it started.' })\n return\n case 'stop-requested':\n json(\n res,\n { outcome: 'stop-requested', message: 'Stop requested. The run will end with its own verdict.' },\n 202,\n )\n return\n case 'not-stoppable-here':\n json(\n res,\n {\n error: \"This run can't be stopped from the dashboard. Stop it where it was started.\",\n reason: 'not-stoppable-here',\n },\n 409,\n )\n return\n case 'finished':\n json(res, {\n outcome: 'finished',\n status: outcome.status,\n message: `This run already finished: ${outcome.status}.`,\n })\n return\n case 'orphan-finalized':\n json(res, { cancelled: false, message: outcome.message })\n return\n case 'owned-elsewhere':\n json(\n res,\n { error: outcome.message, reason: 'owned-by-live-process', ownerPid: outcome.ownerPid },\n 409,\n )\n return\n case 'not-cancellable':\n json(res, { error: 'Run not found or not cancellable' }, 404)\n return\n }\n }\n\n // DELETE /api/runs/:id\n if (path.startsWith('/api/runs/') && req.method === 'DELETE') {\n const segments = path.split('/')\n if (segments.length !== 4) {\n notFound(res)\n return\n }\n\n const id = segments[3]\n\n try {\n const deletedRun = db.deleteRun(id)\n if (!deletedRun.deleted) {\n notFound(res, 'Run not found')\n return\n }\n\n // 405-07 (D-14 · T-405-27): ROWS ONLY. A filesystem sweep ran here first, removing the\n // run's screenshot and video directories and every path the step rows named. Both the\n // paths and the sweep are gone: what lives under the run directory is the event log and\n // the content-addressed blobs — the run's own record, which this server projects and does\n // not own. A dashboard delete removes the dashboard's projection of a run, nothing more.\n json(res, { deleted: true, deletedRunIds: deletedRun.deletedRunIds })\n } catch {\n json(res, { error: 'Failed to delete run' }, 500)\n }\n return\n }\n\n // GET /api/runs/:runId/live-url — the LOCAL door onto the mint (403 D-03).\n //\n // ABOVE THE `GET /api/runs/:id` ARM BELOW, and the order is the mechanism: that arm claims\n // every GET under the prefix and answers `Not found` for anything that is not exactly four\n // segments. A live-url route registered after it is a route that never runs — measured, not\n // assumed (the tracer cell's first run answered 404 from precisely that arm).\n //\n // IT DISPATCHES THE OP AND FORMATS NOTHING. The body is the op's result verbatim: a second\n // shaping here would be a second contract for what a `liveUrl` is, free to disagree with the\n // one the function layer published. The refusals are the op's own, mapped by ERROR NAME rather\n // than by matching a message — a message is prose and prose gets rewritten.\n if (req.method === 'GET' && /^\\/api\\/runs\\/[^/]+\\/live-url$/.test(path)) {\n // THE SAME-SITE GUARD, FIRST — before the door decides anything else about this request.\n //\n // 403 gap round 1 (SC-2, T-403-20). This route hands out the frame socket's ONLY credential,\n // so it is the choke point: a page that cannot obtain a token cannot open the socket. Before\n // this check, a page on any origin open in the developer's own browser could `fetch` a view\n // token and stream the app under test. The loopback bind is not a defence against that — it\n // stops a remote HOST, and the attacker here is the developer's own browser reaching another\n // ORIGIN. The predicate is the chat door's, shared rather than re-derived, and it ADMITS the\n // caller that sends no `Origin` at all (the CLI, `curl`, the conformance harness), which is\n // the local drive this door exists for.\n const crossSite = refuseCrossSiteRequest(req)\n if (crossSite !== undefined) {\n jsonNoCors(res, { error: 'cross_site_refused' }, 403)\n return\n }\n if (!deps.mintLiveUrl) {\n jsonNoCors(res, { error: 'live_view_unavailable' }, 503)\n return\n }\n let liveUrlRunId: string\n try {\n liveUrlRunId = decodeURIComponent(path.slice('/api/runs/'.length, -'/live-url'.length))\n } catch {\n jsonNoCors(res, { error: 'unknown_run' }, 404)\n return\n }\n // THE RAW `handle` PARAMETER THROUGH THE SCHEMA'S OWN READER, on the run-stream door's\n // reasoning one route up: `url.searchParams` resolves `?handle=1&handle=2` to `1`, which is\n // the one answer that reader exists to refuse.\n const rawHandle = handleParamOf(req)\n const parsedHandle = parseHandleParam(rawHandle)\n if (parsedHandle.kind === 'invalid') {\n jsonNoCors(res, { error: 'invalid_handle' }, 400)\n return\n }\n const handle = parsedHandle.kind === 'absent' ? 0 : parsedHandle.index\n // EVERY ARM THROUGH `jsonNoCors`, the success one most of all: the success body IS the token.\n // The refusals go the same way so that the door has one posture rather than a posture per\n // outcome — an arm left on `json()` would be the one a later reader copies.\n void deps.mintLiveUrl(liveUrlRunId, handle).then(\n (result) => { jsonNoCors(res, result) },\n (error: unknown) => {\n const name = error instanceof Error ? error.name : ''\n if (name === 'UnknownRunError') { jsonNoCors(res, { error: 'unknown_run' }, 404); return }\n if (name === 'LiveViewUnavailableError') { jsonNoCors(res, { error: 'live_view_unavailable' }, 503); return }\n jsonNoCors(res, { error: 'live_url_mint_failed' }, 500)\n },\n )\n return\n }\n\n // GET /api/runs/:runId/artifacts/:sha — a minted ref, resolved to bytes (405-05, D-12/D-13).\n //\n // ABOVE THE DETAIL ARM AND THEREFORE ABOVE THE `/api/runs/:id` CATCH-ALL, on the same\n // measured precedent (RESEARCH Pitfall 2): that arm claims EVERY GET under the prefix.\n //\n // AN ANCHORED TWO-CAPTURE REGEX, and `[^/]+` on both segments so a path with an extra\n // separator matches nothing here rather than being reassembled into something that does.\n //\n // THE RUN ID IS DECODED AND THE SHA IS NOT. A content address is 64 characters drawn from\n // `[0-9a-f]`, none of which percent-encoding can represent differently — so a sha segment that\n // needed decoding is already not a sha, and decoding it would turn `%2e%2e%2f` into a string\n // the contract has to refuse a second time. It is passed RAW to a schema whose regex refuses\n // everything that is not a content address.\n //\n // IT DISPATCHES AND FORMATS NOTHING. The concrete evidence store is not imported by this file\n // and must never be — a source cell in `run-detail-routes.test.ts` asserts that its NAME does\n // not occur here at all, which is why this comment does not spell it either. The containment\n // rule for these bytes is the store's own, reached through the op; a second path assembly here\n // would be a second rule, free to be the weaker one.\n if (req.method === 'GET') {\n const artifactMatch = /^\\/api\\/runs\\/([^/]+)\\/artifacts\\/([^/]+)$/.exec(path)\n if (artifactMatch) {\n if (!deps.agentHost) {\n json(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n let artifactRunId: string\n try {\n artifactRunId = decodeURIComponent(artifactMatch[1] ?? '')\n } catch {\n // An undecodable segment names no run, and the honest answer is the one the op's own\n // input schema gives for an id it refuses.\n json(res, { error: 'invalid_run_id' }, 400)\n return\n }\n serveRunArtifact(req, res, {\n runId: artifactRunId,\n sha: artifactMatch[2] ?? '',\n host: deps.agentHost,\n })\n return\n }\n }\n\n if (req.method === 'GET' && /^\\/api\\/runs\\/[^/]+\\/evidence$/.test(path)) {\n if (!deps.agentHost) {\n jsonNoCors(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n let runId: string\n try {\n runId = decodeURIComponent(path.slice('/api/runs/'.length, -'/evidence'.length))\n } catch {\n jsonNoCors(res, { error: 'invalid_run_id' }, 400)\n return\n }\n serveRunEvidenceRead(req, res, { runId, host: deps.agentHost, boundary: 'human' })\n return\n }\n\n // 423-21 D-18: marks history, above the `/api/runs/:id` catch-all like its read siblings.\n if (req.method === 'GET' && /^\\/api\\/runs\\/[^/]+\\/marks$/.test(path)) {\n if (!deps.agentHost) {\n jsonNoCors(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n let runId: string\n try {\n runId = decodeURIComponent(path.slice('/api/runs/'.length, -'/marks'.length))\n } catch {\n jsonNoCors(res, { error: 'invalid_run_id' }, 400)\n return\n }\n serveRunMarksHistoryRead(req, res, { runId, host: deps.agentHost, boundary: 'human' })\n return\n }\n\n // GET /api/runs/:id/detail — the durable run-detail projection (405-01, D-03).\n //\n // ABOVE THE `GET /api/runs/:id` CATCH-ALL BELOW, on the live-url and post-processing arms'\n // measured precedent (RESEARCH Pitfall 2): that arm claims EVERY GET under the prefix and\n // answers `Not found` for anything that is not exactly four segments — and\n // `/api/runs/<id>/detail` is four segments, so registered after it this route would be looked\n // up as a run id and refused.\n //\n // IT DISPATCHES AND FORMATS NOTHING. No `db.` call appears in this arm, deliberately: the\n // whole point of D-03 is that the page's read crosses the function layer, where it can be\n // audited and where the CLI and MCP can reach the same answer. Everything below the 503 is\n // `serveRunDetailRead`'s — the op call, the refusal vocabulary, the body.\n if (req.method === 'GET' && /^\\/api\\/runs\\/[^/]+\\/detail$/.test(path)) {\n if (!deps.agentHost) {\n json(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n let detailRunId: string\n try {\n detailRunId = decodeURIComponent(path.slice('/api/runs/'.length, -'/detail'.length))\n } catch {\n // An undecodable segment names no run, and the honest answer is the one the op's own\n // input schema gives for an id it refuses.\n json(res, { error: 'invalid_run_id' }, 400)\n return\n }\n // THE LOCAL HUMAN DOOR (405-10, D-09): `boundary: 'human'` turns on the same-site guard. The\n // authed REMOTE door's `/run/:runId/detail` passes nothing; both serve the body as stored.\n serveRunDetailRead(req, res, { runId: detailRunId, host: deps.agentHost, boundary: 'human' })\n return\n }\n\n // GET /api/runs/:id/analysis — one run's resolved verdicts, sentences and clusters (406-01, D-04).\n //\n // ABOVE THE `GET /api/runs/:id` CATCH-ALL BELOW, on the detail arm's measured precedent\n // (RESEARCH Pitfall 2): that arm claims EVERY GET under the prefix and answers `Not found` for\n // anything that is not exactly four segments — and `/api/runs/<id>/analysis` is four segments,\n // so registered after it this route would be looked up as a run id and refused.\n //\n // IT DISPATCHES AND FORMATS NOTHING. `analysis.get` is THE single producer of a run's verdicts\n // and sentences (389 D-11); everything below the 503 is `serveRunAnalysisRead`'s.\n if (req.method === 'GET' && /^\\/api\\/runs\\/[^/]+\\/analysis$/.test(path)) {\n if (!deps.agentHost) {\n json(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n let analysisRunId: string\n try {\n analysisRunId = decodeURIComponent(path.slice('/api/runs/'.length, -'/analysis'.length))\n } catch {\n // An undecodable segment names no run, and the honest answer is the one the op's own\n // input schema gives for an id it refuses.\n json(res, { error: 'invalid_run_id' }, 400)\n return\n }\n // THE HUMAN DOOR (D-04): `boundary: 'human'` turns on the same-site guard. The authed REMOTE\n // row passes no `boundary`; both serve the body as stored (441 D-07).\n serveRunAnalysisRead(req, res, { runId: analysisRunId, host: deps.agentHost, boundary: 'human' })\n return\n }\n\n // GET /api/runs/:id/knowledge — what this run used and learned (407-01, D-05/D-06).\n //\n // ABOVE THE `GET /api/runs/:id` CATCH-ALL BELOW, on the detail and analysis arms' measured\n // precedent (RESEARCH Pitfall 2): that arm claims EVERY GET under the prefix and answers\n // `Not found` for anything that is not exactly four segments — and `/api/runs/<id>/knowledge`\n // is four segments, so registered after it this route would be looked up as a run id and\n // refused.\n //\n // IT DISPATCHES AND FORMATS NOTHING. `runs.knowledge` is THE single producer of the Knowledge\n // tab's whole view (407 D-05) — served brief channels, serve-time traces, procedure use, the\n // recorded rung, curator deltas — and everything below the 503 is `serveRunKnowledgeRead`'s.\n // A run whose handoff has been pruned comes back 200 with `kind: 'evidence-incomplete'`, not\n // a 404: D-06 makes that a state the page renders rather than a refusal it has to catch.\n if (req.method === 'GET' && /^\\/api\\/runs\\/[^/]+\\/knowledge$/.test(path)) {\n if (!deps.agentHost) {\n json(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n let knowledgeRunId: string\n try {\n knowledgeRunId = decodeURIComponent(path.slice('/api/runs/'.length, -'/knowledge'.length))\n } catch {\n // An undecodable segment names no run, and the honest answer is the one the op's own\n // input schema gives for an id it refuses.\n json(res, { error: 'invalid_run_id' }, 400)\n return\n }\n // THE HUMAN DOOR (405-10 D-09): `boundary: 'human'` turns on the same-site guard, as on its\n // two neighbours. The body is served as stored (441 D-07).\n serveRunKnowledgeRead(req, res, {\n runId: knowledgeRunId,\n host: deps.agentHost,\n boundary: 'human',\n })\n return\n }\n\n // GET /api/runs/:id/post-processing[/stream] — chip truth and its live channel (404-05).\n //\n // ABOVE THE `GET /api/runs/:id` ARM BELOW, on the live-url arm's measured precedent: that arm\n // claims EVERY GET under the prefix and answers `Not found` for anything that is not exactly\n // four segments — and `/api/runs/<id>/post-processing` is four segments, so it would be looked\n // up as a run id and refused. Registered after it, these two routes would never run.\n //\n // THE STREAM ARM IS FIRST, because `/post-processing/stream` also ends with nothing the read\n // arm's own regex would reject if the read arm were written loosely. Both are anchored regexes\n // over a single segment, so neither can claim the other's path whatever the order.\n //\n // THEY DISPATCH AND FORMAT NOTHING. Everything below the 503 arms is\n // `servePostProcessingRead`/`servePostProcessingStream`'s: the op calls, the join, the framing,\n // the 204 and the refusal vocabulary. A second spelling here would be a second answer to what a\n // chip is, which is exactly what D-16/D-17 exist to prevent.\n if (req.method === 'GET' && /^\\/api\\/runs\\/[^/]+\\/post-processing\\/stream$/.test(path)) {\n if (!deps.agentHost) {\n json(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n if (!deps.postProcessingRelay) {\n json(res, { error: 'post_processing_relay_unavailable' }, 503)\n return\n }\n let streamRunId: string\n try {\n streamRunId = decodeURIComponent(\n path.slice('/api/runs/'.length, -'/post-processing/stream'.length),\n )\n } catch {\n // An undecodable segment names no run, and the honest answer is the one the core gives for\n // an id the op's own input schema refuses.\n json(res, { error: 'invalid_run_id' }, 400)\n return\n }\n servePostProcessingStream(req, res, {\n runId: streamRunId,\n host: deps.agentHost,\n relay: deps.postProcessingRelay,\n })\n return\n }\n\n if (req.method === 'GET' && /^\\/api\\/runs\\/[^/]+\\/post-processing$/.test(path)) {\n if (!deps.agentHost) {\n json(res, { error: 'agent_host_unavailable' }, 503)\n return\n }\n let readRunId: string\n try {\n readRunId = decodeURIComponent(path.slice('/api/runs/'.length, -'/post-processing'.length))\n } catch {\n json(res, { error: 'invalid_run_id' }, 400)\n return\n }\n servePostProcessingRead(req, res, { runId: readRunId, host: deps.agentHost })\n return\n }\n\n // GET /api/runs/:id\n if (path.startsWith('/api/runs/') && req.method === 'GET') {\n const segments = path.split('/')\n if (segments.length !== 4) {\n notFound(res)\n return\n }\n // THE SAME-SITE GUARD (405 CR-01) — see `refuseCrossSiteDisplayRead`. It sits AFTER the shape\n // check and not above it because this arm is the `/api/runs/` catch-all: the length test is\n // what decides whether this request is the single-run door at all, and a path that is not\n // that door should keep answering the generic 404 rather than a refusal about a door it\n // never reached.\n if (refuseCrossSiteDisplayRead(req, res)) return\n const id = segments[3]\n const run = db.getRun(id)\n if (!run) {\n notFound(res, 'Run not found')\n return\n }\n // 405-07 (D-03/D-02): `{ run }` AND NOTHING ELSE. This body carried three more keys —\n // `steps` off a v1 projection with no producer, and `attempts`/`tests` off a child-run walk\n // over a column nothing writes. Every one of them was structurally empty on a run this build\n // produced, so a page rendering them rendered an empty tree that looked like a bug rather\n // than like an absence. The run's members, steps and sub-actions are `GET /api/runs/:id/detail`'s,\n // through `runs.detail`.\n jsonNoCors(res, { run })\n return\n }\n\n // GET /api/stats/costs\n if (path === '/api/stats/costs' && req.method === 'GET') {\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const costStats = db.getCostStats({ from, to })\n json(res, costStats)\n return\n }\n\n // GET /api/insights/knowledge-changes — what curation changed across the window's runs (433-30,\n // F-433-26). Each run is read through `runs.knowledge`, the op the Knowledge tab reads, on the\n // machine boundary: only counts leave this arm.\n if (path === '/api/insights/knowledge-changes' && req.method === 'GET') {\n if (refuseCrossSiteDisplayRead(req, res)) return\n if (!deps.agentHost) {\n jsonNoCors(res, { status: 'unavailable', reason: 'agent_host_unavailable' }, 503)\n return\n }\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n void readInsightsKnowledgeChanges(deps.agentHost, db, { from, to }).then(\n (body) => { jsonNoCors(res, body) },\n () => { jsonNoCors(res, { status: 'unavailable', reason: 'read_failed' }, 500) },\n )\n return\n }\n\n // GET /api/token-events/stats\n if (path === '/api/token-events/stats' && req.method === 'GET') {\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const stats = db.getTokenEventStats({ from, to })\n json(res, stats)\n return\n }\n\n // GET /api/stats\n if (path === '/api/stats' && req.method === 'GET') {\n const from = url.searchParams.get('from') ?? undefined\n const to = url.searchParams.get('to') ?? undefined\n const scope = url.searchParams.get('scope') ?? undefined\n if (scope !== undefined && scope !== 'passRate') {\n json(res, { error: 'scope must be passRate when provided' }, 400)\n return\n }\n\n void readAnalyticsScopePredicates(configManager)\n .then((scopeResult) => {\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n const configured = scopeResult.predicates.length > 0\n const allStats = db.getStats({ from, to })\n const scopedStats = configured\n ? db.getStats({ from, to, attributePredicates: scopeResult.predicates })\n : allStats\n const stats = scope === 'passRate' && configured ? scopedStats : allStats\n\n json(res, {\n ...stats,\n scope: {\n configured,\n predicates: scopeResult.predicates,\n scopedCount: configured ? scopedStats.totalRuns : 0,\n totalCount: allStats.totalRuns,\n },\n })\n })\n .catch(() => {\n json(res, { error: 'Unable to read analytics scope' }, 500)\n })\n return\n }\n\n // 2026-08-27 (405-07, D-14) — THE TWO PATH-SERVING ARMS ARE DELETED.\n //\n // They served bytes addressed as `<runId>/<filename>` under a screenshots or a videos root.\n // Refs are the only artifact addressing now: `GET /api/runs/:runId/artifacts/:sha` above\n // resolves a content address through the `runs.artifact` op, and the store's own containment\n // rule is the one rule those bytes are reached through. There is no video surface at all,\n // because no producer mints a recording ref — an honest absence rather than a surviving path\n // (T-405-28).\n\n // GET /api/run-readiness — the LOCAL half of D-15's one-predicate-two-doors.\n //\n // NO TOKEN, DELIBERATELY, and that is not a hole in D-06's no-anonymous law: that law governs\n // the SERVICE routes, whose whole premise is a caller from another machine. This is the local\n // dashboard API, and what keeps it local is the 402-05 bind guard — an unauthenticated surface\n // structurally cannot be remote, so the browser preflight does not need a credential to ask\n // whether the run service is configured. The answer carries readiness FACTS and no secret: no\n // token, no count, no entry name.\n if (path === '/api/run-readiness' && req.method === 'GET') {\n if (!deps.runServiceReadiness) {\n json(res, { error: 'This server was started without a run-service readiness predicate' }, 503)\n return\n }\n json(res, deps.runServiceReadiness())\n return\n }\n\n // GET /api/run-stream/:runId — the LOCAL door onto the run event stream (402-08, D-01/D-13).\n //\n // ONE STREAM CORE BEHIND TWO DOORS. Everything below the 503 arm is `serveRunEventStream`'s:\n // the attach, the handle validation, the filter, the framing, the heartbeat and the close.\n // This handler formats no frame and reads no envelope, deliberately — a second spelling here\n // would agree with the authed door on the day it was written and drift the first time either\n // moves, and the drift would be invisible until somebody diffed them (T-402-27). The parity is\n // measured rather than asserted: `routes.run-stream.test.ts` drives one planted session\n // through BOTH doors over a corpus that includes every refusal class and compares the bytes.\n //\n // NO TOKEN, ON `/api/run-readiness`'s EXACT ARGUMENT (402-05). This is the local dashboard API\n // and what keeps it local is the bind guard, not a credential. The routes that assume a caller\n // from another machine live behind `ownsRunServicePath`, above this router entirely.\n //\n // THE RAW `handle` PARAMETER IS READ BY THE CORE'S OWN READER, not by `url.searchParams`,\n // which resolves `?handle=1&handle=2` to `1` — the one answer that reader exists to refuse.\n if (req.method === 'GET' && path.startsWith('/api/run-stream/')) {\n if (!deps.runServiceAttach) {\n json(res, { error: 'This server was started without a run service to stream from' }, 503)\n return\n }\n let runId: string\n try {\n runId = decodeURIComponent(path.slice('/api/run-stream/'.length))\n } catch {\n // An undecodable id names no run, and the honest answer is the one the core gives for a\n // run this process never started.\n json(res, { error: 'unknown_run' }, 404)\n return\n }\n serveRunEventStream(req, res, {\n runId,\n handleParam: handleParamOf(req),\n // 403-03 (D-13 · INVK-05): the resume point, read from the SAME pair the authed door reads\n // it from. `url.searchParams.get('lastEventId')` would resolve a repeated parameter to its\n // first value — the one answer `lastEventIdParamOf` exists to refuse — and a second\n // header/query precedence rule here would be a second contract for where a client resumes.\n resume: resumePointOf(req.headers['last-event-id'], lastEventIdParamOf(req)),\n attach: deps.runServiceAttach,\n })\n return\n }\n\n // GET /api/execution/active — list currently running tests\n if (path === '/api/execution/active' && req.method === 'GET') {\n const active = executionBackend ? executionBackend.getActiveExecutions() : []\n json(res, { executions: active })\n return\n }\n\n // POST /api/queue/enqueue — external API to enqueue a test run\n if (path === '/api/queue/enqueue' && req.method === 'POST') {\n if (!jobQueue) {\n json(res, { error: 'Queue not available' }, 503)\n return\n }\n readJsonBody<{ name: string; file?: string; priority?: number; platform?: string; parallel?: boolean; metadata?: Record<string, unknown>; attributes?: unknown }>(req)\n .then(async (body) => {\n if (!body.name || typeof body.name !== 'string') {\n json(res, { error: 'name is required' }, 400)\n return\n }\n // G-401-18-CR01 (write half): `metadata` is SERVER-DERIVED. Refused before any path is\n // normalized or any attribute built, because the only thing a client can achieve by\n // sending it is overwriting a decision this server already made.\n const queuedMetadata = sanitizeQueuedRunMetadata(body.metadata)\n if (!queuedMetadata.ok) {\n json(res, {\n error: 'metadata is server-derived; these keys are not client-writable: '\n + `${queuedMetadata.rejected.join(', ')}. Use \\`attributes\\` for caller-supplied labels.`,\n }, 400)\n return\n }\n let normalizedFileTarget: { storagePath: string; executionPath: string } | null = null\n const isSuiteFile = isSuiteFilePath(body.file)\n if (body.file) {\n try {\n normalizedFileTarget = isSuiteFile\n ? await normalizeDashboardSuitePath(body.file, suiteFileManager)\n : await normalizeDashboardWorkspacePath(body.file, workspacePaths, 'test')\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : String(err) }, 400)\n return\n }\n }\n let attributes: RunAttributes\n try {\n attributes = buildRunRequestAttributes({\n trigger: 'api',\n runner: 'local',\n userAttributes: body.attributes,\n })\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : String(err) }, 400)\n return\n }\n const args = normalizedFileTarget ? [normalizedFileTarget.executionPath] : []\n const source = isSuiteFile ? 'suite' : 'dashboard'\n // 2026-10-16 (442 D-12, WINDOWS #550): the trigger's preflight, before anything queues.\n try {\n await executionBackend?.preflight?.({ args, source })\n } catch (error) {\n const denial = runDenialOf(error)\n if (denial !== undefined) {\n json(res, denial, 403)\n return\n }\n json(res, { error: error instanceof Error ? error.message : String(error) }, 400)\n return\n }\n const runId = jobQueue.enqueue({\n name: body.name,\n filePath: normalizedFileTarget?.storagePath,\n // 2026-08-24 (402-09, D-11): NO PARENT KIND IS MINTED. A suite run is ONE run row\n // with member handles, so a parent artifact kind would claim parenthood over rows\n // nothing creates. `isSuiteFile` still travels in `metadata.isSuite` below, and the run's\n // own `suite_id` plus the artifact's `source.kind` snapshot still say it is a suite.\n kind: 'test',\n attributes,\n priority: body.priority,\n platform: body.platform,\n parallel: body.parallel,\n metadata: {\n ...queuedMetadata.metadata,\n args,\n ...(isSuiteFile ? { isSuite: true } : {}),\n },\n })\n const pending = db.getPendingRuns()\n const position = pending.findIndex(r => r.id === runId) + 1\n json(res, { runId, status: 'queued', position }, 202)\n })\n .catch(() => {\n json(res, { error: 'Invalid request body' }, 400)\n })\n return\n }\n\n // GET /api/queue/status — queue status with pending/running jobs\n if (path === '/api/queue/status' && req.method === 'GET') {\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 20\n const completed = url.searchParams.get('completed') === 'true'\n const pending = db.getPendingRuns()\n const allRuns = db.getRuns({ limit: 100 })\n const running = allRuns.filter(r => r.status === 'running')\n const response: Record<string, unknown> = {\n pending: { count: pending.length, jobs: pending },\n running: { count: running.length, jobs: running },\n concurrency: jobQueue?.getConcurrency() ?? 0,\n activeSlots: jobQueue?.getActiveCount() ?? 0,\n }\n if (completed) {\n const recent = allRuns\n .filter(r => r.status !== 'pending' && r.status !== 'running')\n .slice(0, limit)\n response.recent = recent\n }\n json(res, response)\n return\n }\n\n // POST /api/runs/trigger — enqueue a live test execution\n if (path === '/api/runs/trigger' && req.method === 'POST') {\n if (!jobQueue) {\n json(res, { error: 'Queue not available' }, 503)\n return\n }\n readJsonBody<{ file?: string; patterns?: string[]; tags?: unknown; noCache?: boolean; local?: boolean; triggerSource?: unknown }>(req)\n .then(async (body) => {\n if (body.tags !== undefined) {\n json(res, { error: 'tags are not supported for dashboard-triggered runs' }, 400)\n return\n }\n // 2026-10-01 (432-14, D-14): the click is the whole request. The confirm scope this body\n // used to name, and the validation and persistence that went with it, are deleted with the\n // run-confirm pair; nothing on this road asks a browser anything.\n const triggerSource = parseDashboardRunTriggerSource(body.triggerSource)\n if (!triggerSource.ok) {\n json(res, { error: triggerSource.error }, 400)\n return\n }\n const args: string[] = []\n const isSuiteFile = isSuiteFilePath(body.file)\n let normalizedFileTarget: { storagePath: string; executionPath: string } | null = null\n try {\n normalizedFileTarget = body.file\n ? isSuiteFile\n ? await normalizeDashboardSuitePath(body.file, suiteFileManager)\n : await normalizeDashboardWorkspacePath(body.file, workspacePaths, 'test')\n : null\n\n if (body.file) {\n args.push(normalizedFileTarget?.executionPath ?? body.file)\n }\n if (body.patterns) {\n if (!Array.isArray(body.patterns)) {\n throw new Error('patterns must be an array')\n }\n for (const pattern of body.patterns) {\n if (typeof pattern !== 'string') {\n throw new Error('patterns must be strings')\n }\n const matches = await resolveDashboardTestPattern(pattern, workspacePaths)\n args.push(...matches.map((match) => match.executionPath))\n }\n }\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : String(err) }, 400)\n return\n }\n const normalizedTestTarget = body.file && !isSuiteFile\n ? normalizedFileTarget\n : null\n if (body.noCache) {\n args.push('--disable-cache')\n }\n const isSuite = Boolean(isSuiteFile)\n\n // 2026-10-04 (433-34, G-433-10): the run core's own refusal, asked BEFORE anything is\n // recorded. A production target the config has not opted into used to be enqueued here,\n // minting a row the core then refused, so the click read \"Run started\" and the refusal was\n // recorded as a failed run. The composing host answers with the core's rule; this route\n // only renders the denial in the run service door's shape.\n try {\n await executionBackend?.preflight?.({ args, source: isSuite ? 'suite' : 'dashboard' })\n } catch (error) {\n const denial = runDenialOf(error)\n if (denial !== undefined) {\n json(res, denial, 403)\n return\n }\n json(res, { error: error instanceof Error ? error.message : String(error) }, 400)\n return\n }\n\n let testName = body.file\n ? basename(normalizedFileTarget?.storagePath ?? body.file, '.yaml')\n : 'unknown'\n\n let fileParallel: boolean | undefined\n let platform: string | undefined\n\n if (isSuite && body.file && suiteFileManager) {\n // Parse suite YAML for name and platform\n try {\n const content = await suiteFileManager.read(normalizedFileTarget?.storagePath ?? body.file)\n fileParallel = readSuiteYamlParallel(content)\n const parsed = parseYaml(content)\n if (parsed?.name) testName = parsed.name\n platform = parsed?.config?.platform ?? undefined\n } catch { /* fall back to defaults */ }\n } else if (body.file && testFileManager) {\n // Parse test YAML for name, use.parallel, and platform metadata\n try {\n const readPath = normalizedTestTarget?.storagePath ?? body.file\n const content = await testFileManager.read(readPath)\n const metadata = extractTestFileMetadata(content)\n const targetPlatforms = await readTargetPlatformMap(configManager)\n if (metadata.name) testName = metadata.name\n if (metadata.parallel !== null) fileParallel = metadata.parallel\n platform = resolveEffectivePlatform(\n metadata.platform,\n metadata.targetName,\n targetPlatforms,\n platform,\n ) ?? undefined\n } catch { /* fall back to defaults */ }\n }\n\n const configParallel = await readConfigUseParallel(configManager)\n const effectiveParallel = fileParallel ?? configParallel ?? false\n const executionTimeout = await resolveDashboardExecutionTimeout({\n isSuite,\n file: normalizedFileTarget?.storagePath ?? body.file,\n normalizedTestPath: normalizedTestTarget?.storagePath,\n testFileManager,\n suiteFileManager,\n configManager,\n })\n\n const runId = jobQueue.enqueue({\n name: testName,\n filePath: normalizedFileTarget?.storagePath ?? body.file,\n // 2026-08-24 (402-09, D-11): no parent kind minted — see the enqueue route above.\n kind: 'test',\n attributes: buildRunRequestAttributes({\n trigger: triggerSource.trigger,\n runner: body.local === false ? 'browserstack' : 'local',\n }),\n platform,\n parallel: effectiveParallel,\n metadata: {\n args,\n isSuite: isSuite || undefined,\n ...toExecutionTimeoutMetadata(executionTimeout),\n },\n })\n json(res, { runId, status: 'queued' }, 202)\n })\n .catch(() => {\n json(res, { error: 'Invalid request body' }, 400)\n })\n return\n }\n\n // 2026-08-27 (405-07, D-19) — THE LEGACY LIVE-EVENT SSE ARM IS DELETED.\n //\n // It streamed a re-minted frame shape out of the backend's per-run replay buffer, with a\n // `Last-Event-ID` replay and a heartbeat. 405-03 removed the browser half; this removes the\n // route, the buffer and the emission behind it. A live reader attaches to\n // `GET /api/run-stream/:runId`, which frames the run's OWN frozen envelopes; a finished run is\n // read durably through `runs.detail`. One live wire, one durable read — and no second spelling\n // of the wire to drift from the first.\n\n // POST /api/suites/validate — validate suite YAML content\n if (path === '/api/suites/validate' && req.method === 'POST') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n readJsonBody<{ content: string }>(req)\n .then(async (body) => {\n const result = await suiteFileManager.validate(body.content ?? '')\n json(res, result)\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // GET /api/suites — list all suite files\n if (path === '/api/suites' && req.method === 'GET') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n suiteFileManager.list()\n .then(files => json(res, { files }))\n .catch(() => json(res, { error: 'Failed to list suite files' }, 500))\n return\n }\n\n // POST /api/suites — create a new suite file\n if (path === '/api/suites' && req.method === 'POST') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n readJsonBody<{ path: string; content: string }>(req)\n .then(async (body) => {\n if (!body.path || typeof body.path !== 'string' || !body.content || typeof body.content !== 'string') {\n json(res, { error: 'Both path and content are required' }, 400)\n return\n }\n if (refusedShownMarkerTarget(res, suiteFileTarget(body.content))) return\n const validation = await suiteFileManager.validate(body.content)\n if (!validation.valid) {\n json(res, {\n error: 'Invalid suite content',\n details: validation.errors,\n missingTests: validation.missingTests,\n }, 400)\n return\n }\n try {\n await suiteFileManager.write(body.path, body.content)\n json(res, { path: body.path, created: true }, 201)\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to create suite file' }, 400)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // DELETE /api/suites/:path — delete a suite file\n if (path.startsWith('/api/suites/') && req.method === 'DELETE') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n const decodedPath = decodeURIComponent(path.slice('/api/suites/'.length))\n suiteFileManager.delete(decodedPath)\n .then(() => json(res, { deleted: true }))\n .catch((err: any) => {\n if (err.code === 'ENOENT') {\n notFound(res, 'Suite file not found')\n return\n }\n json(res, { error: err.message }, 500)\n })\n return\n }\n\n // PUT /api/suites/:suite-id — update suite file by suite-id (hard break D-02/D-04)\n if (path.startsWith('/api/suites/') && req.method === 'PUT') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n const sId = decodeURIComponent(path.slice('/api/suites/'.length))\n readJsonBody<{ content: string }>(req)\n .then(async (body) => {\n if (!body.content || typeof body.content !== 'string') {\n json(res, { error: 'Content is required' }, 400)\n return\n }\n if (refusedShownMarkerTarget(res, suiteFileTarget(body.content))) return\n const found = await suiteFileManager.findBySuiteId(sId)\n if (!found) {\n notFound(res, 'Suite not found')\n return\n }\n const validation = await suiteFileManager.validate(body.content)\n if (!validation.valid) {\n json(res, {\n error: 'Invalid suite content',\n details: validation.errors,\n missingTests: validation.missingTests,\n }, 400)\n return\n }\n try {\n await suiteFileManager.write(found.path, body.content)\n json(res, { path: found.path, updated: true })\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to update suite file' }, 400)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // GET /api/suites/:suite-id — read suite file by suite-id (hard break D-02/D-04/D-05)\n if (path.startsWith('/api/suites/') && req.method === 'GET') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n const sId = decodeURIComponent(path.slice('/api/suites/'.length))\n suiteFileManager.findBySuiteId(sId)\n .then(result => {\n if (!result) {\n notFound(res, 'Suite not found')\n return\n }\n json(res, { path: result.path, content: result.content, suiteId: sId })\n })\n .catch(() => notFound(res, 'Suite not found'))\n return\n }\n\n // POST /api/tests/validate — validate YAML content (must be before parameterized /api/tests/:path)\n if (path === '/api/tests/validate' && req.method === 'POST') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n readJsonBody<{ content: string; filePath?: string }>(req)\n .then(async (body) => {\n const isSuite = body.filePath?.endsWith('.suite.yaml') || body.filePath?.endsWith('.suite.yml')\n if (isSuite && suiteFileManager) {\n const result = await suiteFileManager.validate(body.content ?? '')\n json(res, result)\n } else {\n const result = await testFileManager.validate(body.content ?? '')\n json(res, result)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // GET /api/tests — list all test files\n if (path === '/api/tests' && req.method === 'GET') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n testFileManager.list()\n .then(async files => {\n const targetPlatforms = await readTargetPlatformMap(configManager)\n const resolvedFiles = files.map((file) => ({\n ...file,\n platform: resolveEffectivePlatform(file.platform, file.targetName, targetPlatforms),\n }))\n const targets = Array.from(\n new Set(\n resolvedFiles\n .map((file) => file.targetName)\n .filter((value): value is string => typeof value === 'string' && value.length > 0),\n ),\n )\n json(res, { files: resolvedFiles, targets })\n })\n .catch(() => json(res, { error: 'Failed to list test files' }, 500))\n return\n }\n\n // POST /api/tests — create a new test file\n if (path === '/api/tests' && req.method === 'POST') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n readJsonBody<{ path: string; content: string }>(req)\n .then(async (body) => {\n if (!body.path || typeof body.path !== 'string' || !body.content || typeof body.content !== 'string') {\n json(res, { error: 'Both path and content are required' }, 400)\n return\n }\n if (refusedShownMarkerTarget(res, targetsForMarkerCheck(body.content))) return\n const validation = await testFileManager.validate(body.content)\n if (!validation.valid) {\n json(res, { error: 'invalid_test_file', errors: validation.errors }, 400)\n return\n }\n try {\n await testFileManager.write(body.path, body.content)\n json(res, { path: body.path, created: true }, 201)\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to create test file' }, 400)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // DELETE /api/tests/:t_id — delete test file by test-id\n if (path.startsWith('/api/tests/') && req.method === 'DELETE') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n const tId = decodeURIComponent(path.slice('/api/tests/'.length))\n testFileManager.findByTestId(tId)\n .then(async (found) => {\n if (!found) {\n notFound(res, 'Test not found')\n return\n }\n await testFileManager.delete(found.path)\n json(res, { deleted: true, path: found.path })\n })\n .catch((err: unknown) => {\n const code = (err as NodeJS.ErrnoException)?.code\n if (code === 'ENOENT') {\n notFound(res, 'Test not found')\n return\n }\n json(res, { error: err instanceof Error ? err.message : 'Failed to delete test file' }, 500)\n })\n return\n }\n\n // PUT /api/tests/:t_id — update test file by test-id\n if (path.startsWith('/api/tests/') && req.method === 'PUT') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n const tId = decodeURIComponent(path.slice('/api/tests/'.length))\n readJsonBody<{ content: string }>(req)\n .then(async (body) => {\n if (!body.content || typeof body.content !== 'string') {\n json(res, { error: 'Content is required' }, 400)\n return\n }\n if (refusedShownMarkerTarget(res, targetsForMarkerCheck(body.content))) return\n const found = await testFileManager.findByTestId(tId)\n if (!found) {\n notFound(res, 'Test not found')\n return\n }\n const validation = await testFileManager.validate(body.content)\n if (!validation.valid) {\n json(res, { error: 'invalid_test_file', errors: validation.errors }, 400)\n return\n }\n try {\n await testFileManager.write(found.path, body.content)\n json(res, { path: found.path, updated: true })\n } catch (err) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to update test file' }, 400)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // GET /api/tests/:t_id — read test file by test-id\n if (path.startsWith('/api/tests/') && req.method === 'GET') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n const tId = decodeURIComponent(path.slice('/api/tests/'.length))\n testFileManager.findByTestId(tId)\n .then(result => {\n if (!result) {\n notFound(res, 'Test not found')\n return\n }\n json(res, { path: result.path, content: result.content, testId: tId })\n })\n .catch(() => notFound(res, 'Test not found'))\n return\n }\n\n // GET /api/analytics/tests\n if (path === '/api/analytics/tests' && req.method === 'GET') {\n const minRuns = url.searchParams.has('minRuns') ? parseInt(url.searchParams.get('minRuns')!, 10) : 3\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 50\n const tests = db.getFlakyTests({ minRuns, limit })\n const result = tests.map(t => {\n return { ...t, isFlaky: t.flakyScore >= 0.4 }\n })\n json(res, { tests: result })\n return\n }\n\n // GET /api/analytics/test-summaries — each listed test's rate and last run, as its viewer reads them\n if (path === '/api/analytics/test-summaries' && req.method === 'GET') {\n if (!testFileManager) {\n json(res, { error: 'Test file management not configured' }, 501)\n return\n }\n Promise.all([testFileManager.list(), readAnalyticsScopePredicates(configManager)])\n .then(([files, scopeResult]) => {\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n // The rate is the figure the viewer opens on; the last run stays unscoped, as its run list is.\n const scope = scopeResult.predicates.length > 0 ? { attributePredicates: scopeResult.predicates } : undefined\n const tests = files.map((file) => {\n const test = { ...(file.testId ? { testId: file.testId } : {}), filePath: file.path }\n const [last] = db.getRunsByTest(test, { limit: 1 })\n const lastRun = lastRunOf(last)\n return {\n path: file.path,\n testId: file.testId,\n ...passRateOf(db.getTestTrends(test, scope)),\n lastRun: lastRun ? { ...lastRun, memberOutcome: last?.memberOutcome ?? null } : null,\n }\n })\n json(res, { tests })\n })\n .catch(() => json(res, { error: 'Failed to read run summaries' }, 500))\n return\n }\n\n // GET /api/analytics/suite-summaries — each listed suite's rate, last run, target and platform\n if (path === '/api/analytics/suite-summaries' && req.method === 'GET') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n Promise.all([suiteFileManager.list(), readTargetPlatformMap(configManager), readAnalyticsScopePredicates(configManager)])\n .then(([files, targetPlatforms, scopeResult]) => {\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n const scope = scopeResult.predicates.length > 0 ? { attributePredicates: scopeResult.predicates } : undefined\n const suites = files.map((file) => {\n if (!file.suiteId) {\n return { path: file.path, suiteId: null, passRate: null, passed: 0, decided: 0, lastRun: null, platform: null, targetName: null }\n }\n const runs = db.getRunsBySuiteId(file.suiteId)\n return {\n path: file.path,\n suiteId: file.suiteId,\n ...passRateOf(db.getSuiteTrends(file.suiteId, scope)),\n lastRun: lastRunOf(runs[0]),\n ...suiteTargetOf(runs, targetPlatforms),\n }\n })\n json(res, { suites })\n })\n .catch(() => json(res, { error: 'Failed to read run summaries' }, 500))\n return\n }\n\n // GET /api/analytics/tests/:name\n if (path.startsWith('/api/analytics/tests/') && req.method === 'GET') {\n const name = decodeURIComponent(path.slice('/api/analytics/tests/'.length))\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 50\n const offset = url.searchParams.has('offset') ? parseInt(url.searchParams.get('offset')!, 10) : 0\n const from = url.searchParams.get('from') ?? undefined\n const testId = url.searchParams.get('testId') || undefined\n const filePath = url.searchParams.get('filePath') || undefined\n if (!testId && !filePath) {\n json(res, { error: 'testId or filePath is required' }, 400)\n return\n }\n const test = { ...(testId ? { testId } : {}), ...(filePath ? { filePath } : {}) }\n const memberClasses = (runs: RunRow[]) => runs.map(r => memberOutcomeClass(r.memberOutcome ?? null))\n void readAnalyticsScopePredicates(configManager)\n .then((scopeResult) => {\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n\n const runs = db.getRunsByTest(test, { limit, offset })\n const total = db.getRunsByTestCount(test)\n const trends = db.getTestTrends(test, { from })\n const allRunsForFlakiness = db.getRunsByTest(test, { limit: 100 })\n const flakyMetrics = calculateFlakyMetrics(memberClasses(allRunsForFlakiness))\n const flakyScore = flakyMetrics.score\n const configured = scopeResult.predicates.length > 0\n const scopedRuns = configured\n ? db.getRunsByTest(test, { limit, offset, attributePredicates: scopeResult.predicates })\n : runs\n const scopedTotal = configured\n ? db.getRunsByTestCount(test, { attributePredicates: scopeResult.predicates })\n : total\n const scopedTrends = configured\n ? db.getTestTrends(test, { from, attributePredicates: scopeResult.predicates })\n : trends\n const scopedRunsForFlakiness = configured\n ? db.getRunsByTest(test, { limit: 100, attributePredicates: scopeResult.predicates })\n : allRunsForFlakiness\n const scopedFlakyScore = calculateFlakyMetrics(memberClasses(scopedRunsForFlakiness)).score\n\n json(res, {\n name,\n runs,\n total,\n trends,\n isFlaky: flakyScore >= 0.4 && flakyMetrics.statusCount >= 3,\n flakyScore,\n scope: {\n configured,\n predicates: scopeResult.predicates,\n scopedCount: scopedTotal,\n totalCount: total,\n },\n ...(configured ? {\n scopedRuns,\n scopedTrends,\n scopedFlakyScore,\n } : {}),\n })\n })\n .catch(() => json(res, { error: 'Failed to read analytics scope' }, 500))\n return\n }\n\n // GET /api/analytics/suites/:suiteId\n if (path.startsWith('/api/analytics/suites/') && req.method === 'GET') {\n if (!suiteFileManager) {\n json(res, { error: 'Suite file management not configured' }, 501)\n return\n }\n\n const suiteId = decodeURIComponent(path.slice('/api/analytics/suites/'.length))\n const limit = url.searchParams.has('limit') ? parseInt(url.searchParams.get('limit')!, 10) : 50\n const offset = url.searchParams.has('offset') ? parseInt(url.searchParams.get('offset')!, 10) : 0\n const from = url.searchParams.get('from') ?? undefined\n\n Promise.all([suiteFileManager.findBySuiteId(suiteId), readAnalyticsScopePredicates(configManager)])\n .then(([result, scopeResult]) => {\n if (!result) {\n notFound(res, 'Suite not found')\n return\n }\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n\n const runs = db.getRunsBySuiteId(suiteId, { limit, offset })\n const total = db.getRunsBySuiteIdCount(suiteId)\n const trends = db.getSuiteTrends(suiteId, { from })\n const allRunsForFlakiness = db.getRunsBySuiteId(suiteId, { limit: 100 })\n const flakyMetrics = calculateFlakyMetrics(allRunsForFlakiness.map(r => runStatusClass(r.status)))\n const flakyScore = flakyMetrics.score\n const configured = scopeResult.predicates.length > 0\n const scopedRuns = configured\n ? db.getRunsBySuiteId(suiteId, { limit, offset, attributePredicates: scopeResult.predicates })\n : runs\n const scopedTotal = configured\n ? db.getRunsBySuiteIdCount(suiteId, { attributePredicates: scopeResult.predicates })\n : total\n const scopedTrends = configured\n ? db.getSuiteTrends(suiteId, { from, attributePredicates: scopeResult.predicates })\n : trends\n const scopedRunsForFlakiness = configured\n ? db.getRunsBySuiteId(suiteId, { limit: 100, attributePredicates: scopeResult.predicates })\n : allRunsForFlakiness\n const scopedFlakyScore = calculateFlakyMetrics(scopedRunsForFlakiness.map(r => runStatusClass(r.status))).score\n\n json(res, {\n suiteId,\n runs,\n total,\n trends,\n isFlaky: flakyScore >= 0.4 && flakyMetrics.statusCount >= 3,\n flakyScore,\n scope: {\n configured,\n predicates: scopeResult.predicates,\n scopedCount: scopedTotal,\n totalCount: total,\n },\n ...(configured ? {\n scopedRuns,\n scopedTrends,\n scopedFlakyScore,\n } : {}),\n })\n })\n .catch(() => notFound(res, 'Suite not found'))\n return\n }\n\n // GET /api/analytics/breakdowns\n if (path === '/api/analytics/breakdowns' && req.method === 'GET') {\n const dimension = url.searchParams.get('dimension')\n if (dimension !== 'test' && dimension !== 'suite' && dimension !== 'platform') {\n json(res, { error: 'dimension must be one of: test, suite, platform' }, 400)\n return\n }\n\n const limitResult = parseBoundedIntegerQueryParam(url.searchParams.get('limit'), 'limit', 1, 100, 25)\n if (!limitResult.ok) {\n json(res, { error: limitResult.error }, 400)\n return\n }\n\n const fromResult = parseIsoDateQueryParam(url.searchParams.get('from'), 'from')\n if (!fromResult.ok) {\n json(res, { error: fromResult.error }, 400)\n return\n }\n\n const toResult = parseIsoDateQueryParam(url.searchParams.get('to'), 'to')\n if (!toResult.ok) {\n json(res, { error: toResult.error }, 400)\n return\n }\n\n const scope = url.searchParams.get('scope') ?? undefined\n if (scope !== undefined && scope !== 'passRate') {\n json(res, { error: 'scope must be passRate when provided' }, 400)\n return\n }\n\n void readAnalyticsScopePredicates(configManager)\n .then(async (scopeResult) => {\n if (!scopeResult.ok) {\n json(res, { error: scopeResult.error }, 400)\n return\n }\n\n const configured = scopeResult.predicates.length > 0\n const attributePredicates = scope === 'passRate' && configured ? scopeResult.predicates : undefined\n const rows = db.getInsightsBreakdown(dimension as InsightsBreakdownDimension, {\n from: fromResult.value,\n to: toResult.value,\n limit: limitResult.value,\n attributePredicates,\n })\n const scopedCount = configured\n ? db.getInsightsBreakdown(dimension as InsightsBreakdownDimension, {\n from: fromResult.value,\n to: toResult.value,\n limit: 100,\n attributePredicates: scopeResult.predicates,\n }).reduce((sum, row) => sum + row.runs, 0)\n : 0\n const totalCount = db.getInsightsBreakdown(dimension as InsightsBreakdownDimension, {\n from: fromResult.value,\n to: toResult.value,\n limit: 100,\n }).reduce((sum, row) => sum + row.runs, 0)\n const payload = {\n dimension,\n rows,\n scope: {\n configured,\n predicates: scopeResult.predicates,\n scopedCount,\n totalCount,\n },\n }\n\n if (dimension !== 'suite' || !suiteFileManager) {\n json(res, payload)\n return\n }\n\n const files = await suiteFileManager.list()\n const suiteNames = new Map(\n files\n .filter((file) => typeof file.suiteId === 'string' && file.suiteId.length > 0)\n .map((file) => [file.suiteId as string, file.name]),\n )\n\n json(res, {\n ...payload,\n rows: rows.map((row) => ({\n ...row,\n label: row.suiteId ? (suiteNames.get(row.suiteId) ?? row.label) : row.label,\n })),\n })\n })\n .catch(() => {\n json(res, { error: 'Unable to read analytics breakdown scope' }, 500)\n })\n return\n }\n\n // GET /api/app-metadata — return narrow non-sensitive app metadata\n if (path === '/api/app-metadata' && req.method === 'GET') {\n const version = getAgentQaVersion().trim() || '0.0.0'\n ;(async () => {\n try {\n const status = await getAgentQaUpdateStatus()\n const latestVersion = typeof status.latestVersion === 'string'\n ? status.latestVersion.trim()\n : ''\n if (status.updateAvailable === true && latestVersion) {\n json(res, { version, update: { latestVersion } })\n return\n }\n } catch {\n // Keep app metadata available even when update checks fail.\n }\n\n json(res, { version })\n })().catch(() => {\n json(res, { version })\n })\n return\n }\n\n // GET /api/config/targets — return registered target names\n if (path === '/api/config/targets' && req.method === 'GET') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const config = await readConfigValues(configManager)\n const configObj = config as Record<string, unknown>\n const registry = configObj.registry as Record<string, unknown> | undefined\n const targets = registry?.targets as Record<string, unknown> | undefined\n const names = targets ? Object.keys(targets) : []\n const shown = withDeclaredMask(declaredMask, (mask) => names.map((name) => mask(name)))\n if (shown === undefined) {\n json(res, { error: 'masking_unavailable' }, 500)\n return\n }\n json(res, { targets: shown })\n } catch (err: unknown) {\n const message = err instanceof Error\n ? withDeclaredMask(declaredMask, (mask) => mask(err.message))\n : undefined\n json(res, { error: message ?? 'Failed to read targets' }, 500)\n }\n })()\n return\n }\n\n // GET /api/config — return masked config with active provider info\n if (path === '/api/config' && req.method === 'GET') {\n // 429-41 (CR-02): the answer carries file text and the file's absolute path, so it is read\n // same-site only and no outcome grants a cross-origin read.\n if (refuseCrossSiteDisplayRead(req, res)) return\n if (!configManager) {\n jsonNoCors(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const read = await configManager.readMasked()\n if (read.kind === 'file_invalid') {\n jsonNoCors(res, { error: 'file_invalid', message: read.message }, 409)\n return\n }\n const { config, revision, lines, fileIssues } = read\n const registry = config.registry as Record<string, unknown> | undefined\n const llms = (registry?.llms ?? config.llms) as Array<Record<string, unknown>> | undefined\n const use = config.use as Record<string, unknown> | undefined\n const activeLlm = (use?.llm ?? config.defaultLLM) as string | undefined\n const defaultCfg = Array.isArray(llms)\n ? llms.find((c) => c?.name === activeLlm)\n : undefined\n const provider = (defaultCfg?.provider as string) ?? null\n jsonNoCors(res, {\n config,\n provider,\n revision,\n file: { path: deps.configPath ?? null, lines },\n ...(fileIssues.length > 0 ? { fileIssues } : {}),\n })\n } catch (err: unknown) {\n jsonNoCors(res, { error: err instanceof Error ? err.message : 'Failed to read config' }, 500)\n }\n })()\n return\n }\n\n // POST /api/config/farm/test-connection — test farm provider credentials\n if (path === '/api/config/farm/test-connection' && req.method === 'POST') {\n readJsonBody<{ provider: string; username: string; accessKey: string }>(req)\n .then(async (body) => {\n if (body.provider !== 'browserstack') {\n json(res, { error: 'Only BrowserStack is currently supported' }, 400)\n return\n }\n try {\n const auth = Buffer.from(`${body.username}:${body.accessKey}`).toString('base64')\n const response = await fetch('https://api-cloud.browserstack.com/app-automate/devices.json', {\n headers: { Authorization: `Basic ${auth}` },\n })\n if (response.ok) {\n json(res, { success: true })\n } else if (response.status === 401) {\n json(res, { success: false, error: 'Invalid credentials' })\n } else {\n json(res, { success: false, error: `BrowserStack API returned ${response.status}` })\n }\n } catch (err) {\n json(res, { success: false, error: err instanceof Error ? err.message : 'Connection failed' })\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // DELETE /api/auth/:configName — remove stored credential\n if (path.startsWith('/api/auth/') && req.method === 'DELETE') {\n const segments = path.split('/')\n if (segments.length === 4 && segments[2] === 'auth') {\n const providerName = decodeURIComponent(segments[3])\n if (providerName === 'status' || providerName === 'credential' || providerName === 'oauth') {\n // Fall through to other handlers\n } else {\n if (refuseCrossSiteRequest(req) !== undefined) {\n jsonNoCors(res, { error: 'cross_site_refused' }, 403)\n return\n }\n // 429-11 D-24: the removed entry is held server-side for Undo; the answer never carries it.\n ;(async () => {\n try {\n const removed = await withCredentialLock(async () => {\n const credential = await readAuthEntry(providerName)\n if (credential === undefined) return undefined\n await removeAuth(providerName)\n return credential\n })\n if (removed === undefined) {\n jsonNoCors(res, { deleted: false })\n return\n }\n const undo = undoStore.put({ kind: 'credential', name: providerName, credential: removed }, Date.now())\n jsonNoCors(res, { deleted: true, undo })\n } catch (err: unknown) {\n jsonNoCors(res, { error: err instanceof Error ? err.message : 'Failed to delete credential' }, 500)\n }\n })()\n return\n }\n }\n }\n\n // GET /api/auth/status — return credential info from auth store\n if (path === '/api/auth/status' && req.method === 'GET') {\n ;(async () => {\n try {\n const credentials: Array<{\n type: string\n provider: string\n configName: string\n expires: number | null\n source: string\n }> = []\n const store = await readAuth() as Record<string, DashboardAuthCredential>\n for (const [key, cred] of Object.entries(store)) {\n if (cred) {\n let provider = cred.provider ?? key\n if (cred.type === 'oauth') {\n provider = toProductProviderLabel(provider)\n } else if (cred.type === 'bearer') {\n provider = cred.provider\n }\n credentials.push({\n type: cred.type,\n provider,\n configName: key,\n expires: cred.type === 'oauth' ? cred.tokens.expires : null,\n source: 'auth-store',\n })\n }\n }\n json(res, { credentials })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read auth status' }, 500)\n }\n })()\n return\n }\n\n // GET /api/llm/providers — built-in and plugin-provided LLM provider metadata\n if (path === '/api/llm/providers' && req.method === 'GET') {\n json(res, {\n providers: [\n ...builtinLLMProviderMetadata(),\n ...listLLMAuthProviderPlugins().map(serializeAuthProviderPlugin),\n ],\n })\n return\n }\n\n if (path === '/api/llm/catalog' && req.method === 'GET') {\n json(res, { catalog: getModelCatalog() })\n return\n }\n\n if (path === '/api/llm/catalog/live' && req.method === 'POST') {\n readJsonBody<{\n configName?: string\n baseURL?: string\n providerHeaders?: Record<string, string>\n }>(req)\n .then(async (body) => {\n const rawBody = body as Record<string, unknown>\n if ('apiKey' in rawBody) {\n json(res, {\n error: 'invalid_request',\n message: 'apiKey is not accepted; save credentials for the named config instead.',\n }, 400)\n return\n }\n\n const staticOpenAI = getModelCatalog()['openai-compatible']\n const baseURL = typeof body.baseURL === 'string' ? body.baseURL.trim() : ''\n if (!baseURL) {\n json(res, { models: staticOpenAI })\n return\n }\n\n const headers: Record<string, string> = {}\n if (body.providerHeaders !== undefined) {\n for (const [key, value] of Object.entries(body.providerHeaders)) {\n if (typeof value === 'string') headers[key] = value\n }\n }\n\n const llmCandidate: Record<string, unknown> = {\n provider: 'openai-compatible',\n model: 'catalog-live-probe',\n baseURL,\n }\n if (Object.keys(headers).length > 0) {\n llmCandidate.providerHeaders = headers\n }\n\n const parsedConfig = ModelConfigSchema.safeParse(llmCandidate)\n if (!parsedConfig.success) {\n json(res, {\n error: 'invalid_request',\n message: parsedConfig.error.issues\n .map((issue: { path: PropertyKey[]; message: string }) => `${issue.path.map(String).join('.') || 'config'}: ${issue.message}`)\n .join('; '),\n }, 400)\n return\n }\n\n const configName = typeof body.configName === 'string' ? body.configName.trim() : ''\n const llmConfig = parsedConfig.data\n const coreAuth = await import('@vostride/agent-qa-core') as typeof import('@vostride/agent-qa-core') & {\n resolveLLMAuth: (name: string, config: typeof llmConfig) => Promise<\n | { kind: 'api-key'; apiKey: string }\n | { kind: 'bearer-token'; token: string }\n | { kind: 'auth-fetch'; fetch: typeof globalThis.fetch; modelAdapter: 'openai-responses' | 'anthropic-messages' }\n | { kind: 'unauthenticated'; message: string }\n | { kind: 'missing'; message: string }\n >\n }\n const resolvedAuth = await coreAuth.resolveLLMAuth(configName, llmConfig)\n if (resolvedAuth.kind === 'api-key') {\n headers.Authorization ??= `Bearer ${resolvedAuth.apiKey}`\n } else if (resolvedAuth.kind === 'bearer-token') {\n headers.Authorization ??= `Bearer ${resolvedAuth.token}`\n }\n\n const live = await fetchLiveModels({\n baseURL,\n headers: Object.keys(headers).length > 0 ? headers : undefined,\n })\n json(res, { models: mergeCatalog(staticOpenAI, live) })\n })\n .catch(() => json(res, { error: 'invalid_request' }, 400))\n return\n }\n\n if (path.startsWith('/api/auth/plugin/')) {\n pruneExpiredPluginOAuthSessions(pluginOAuthSessions)\n const segments = path.split('/')\n const provider = segments.length >= 6 ? decodeURIComponent(segments[4] ?? '') : ''\n const action = segments.length >= 6 ? segments[5] : ''\n // 429-09: start and code exchange plant a machine-wide credential, so both are same-site only\n // and no answer on them carries a cross-origin grant.\n const authDoor = req.method === 'POST' && (action === 'start' || action === 'exchange')\n if (authDoor && refuseCrossSiteRequest(req) !== undefined) {\n jsonNoCors(res, { error: 'cross_site_refused' }, 403)\n return\n }\n const plugin = provider ? getLLMAuthProviderPlugin(provider) : undefined\n\n if (!plugin) {\n ;(authDoor ? jsonNoCors : json)(res, { error: `Auth plugin provider \"${provider}\" is not registered` }, 404)\n return\n }\n\n if (action === 'start' && req.method === 'POST') {\n readJsonBody<{ configName?: string; callbackUrl?: string }>(req)\n .then(async (body) => {\n if (!plugin.startAuth) {\n jsonNoCors(res, { error: `Provider \"${provider}\" does not support dashboard auth start` }, 400)\n return\n }\n\n try {\n const target = await requirePluginAuthConfig(configManager, body.configName, plugin)\n if (!target.ok) {\n jsonNoCors(res, credentialRefusalBody(target), target.status)\n return\n }\n const started = await plugin.startAuth({\n configName: target.configName,\n callbackUrl: typeof body.callbackUrl === 'string' ? body.callbackUrl : undefined,\n })\n const sessionId = randomUUID()\n const session: PluginOAuthSession = {\n providerId: plugin.providerId,\n credentialProviderId: plugin.credentialProviderId,\n configName: target.configName,\n sessionState: started.sessionState,\n cleanup: started.cleanup,\n status: 'pending',\n expiresAt: Date.now() + PLUGIN_OAUTH_SESSION_TTL_MS,\n }\n pluginOAuthSessions.set(sessionId, session)\n\n if (started.waitForTokens) {\n started.waitForTokens\n .then(async (tokens: OAuthTokens) => {\n const conflict = await withCredentialLock(async () => {\n if (await credentialConflictAt(target.configName, plugin.providerId)) return true\n await writeDashboardAuth(target.configName, {\n type: 'oauth',\n provider: plugin.credentialProviderId,\n tokens,\n })\n return false\n })\n if (conflict) throw new Error(CREDENTIAL_PROVIDER_CONFLICT.message)\n session.status = 'completed'\n })\n .catch((err: unknown) => {\n session.status = 'error'\n session.error = err instanceof Error ? err.message : 'Authentication failed'\n })\n .finally(() => cleanupPluginOAuthSession(session))\n }\n\n jsonNoCors(res, {\n authorizeUrl: started.authorizeUrl,\n sessionId,\n mode: plugin.dashboardAuth.mode,\n created: target.created,\n })\n } catch (err: unknown) {\n jsonNoCors(res, { error: err instanceof Error ? err.message : 'Failed to start auth plugin flow' }, 500)\n }\n })\n .catch(() => jsonNoCors(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n if (action === 'result' && req.method === 'GET') {\n const sessionId = url.searchParams.get('session') ?? ''\n const session = pluginOAuthSessions.get(sessionId)\n if (!session || session.providerId !== provider) {\n json(res, { error: 'Auth session not found' }, 404)\n return\n }\n if (session.status === 'completed') {\n cleanupPluginOAuthSession(session)\n pluginOAuthSessions.delete(sessionId)\n json(res, { status: 'completed', saved: true })\n return\n }\n if (session.status === 'error') {\n cleanupPluginOAuthSession(session)\n pluginOAuthSessions.delete(sessionId)\n json(res, { status: 'error', error: session.error ?? 'Authentication failed' })\n return\n }\n json(res, { status: 'pending' })\n return\n }\n\n if (action === 'exchange' && req.method === 'POST') {\n readJsonBody<{ sessionId?: string; code?: string }>(req)\n .then(async (body) => {\n if (!plugin.exchangeCode) {\n jsonNoCors(res, { error: `Provider \"${provider}\" does not support code exchange` }, 400)\n return\n }\n const sessionId = typeof body.sessionId === 'string' ? body.sessionId.trim() : ''\n const code = typeof body.code === 'string' ? body.code.trim() : ''\n if (!sessionId || !code) {\n jsonNoCors(res, { error: 'sessionId and code are required' }, 400)\n return\n }\n const session = pluginOAuthSessions.get(sessionId)\n if (!session || session.providerId !== provider) {\n jsonNoCors(res, { error: 'Auth session not found' }, 404)\n return\n }\n if (session.status !== 'pending') {\n jsonNoCors(res, { error: 'Auth session is no longer pending' }, 409)\n return\n }\n\n try {\n const tokens = await plugin.exchangeCode({\n code,\n sessionState: session.sessionState,\n })\n const conflict = await withCredentialLock(async () => {\n if (await credentialConflictAt(session.configName, session.providerId)) return true\n await writeDashboardAuth(session.configName, {\n type: 'oauth',\n provider: session.credentialProviderId,\n tokens,\n })\n return false\n })\n if (conflict) {\n session.status = 'error'\n session.error = CREDENTIAL_PROVIDER_CONFLICT.message\n cleanupPluginOAuthSession(session)\n pluginOAuthSessions.delete(sessionId)\n jsonNoCors(res, credentialRefusalBody(CREDENTIAL_PROVIDER_CONFLICT), CREDENTIAL_PROVIDER_CONFLICT.status)\n return\n }\n session.status = 'completed'\n cleanupPluginOAuthSession(session)\n pluginOAuthSessions.delete(sessionId)\n jsonNoCors(res, { status: 'completed', saved: true })\n } catch (err: unknown) {\n session.status = 'error'\n session.error = err instanceof Error ? err.message : 'Token exchange failed'\n cleanupPluginOAuthSession(session)\n pluginOAuthSessions.delete(sessionId)\n jsonNoCors(res, { error: session.error }, 500)\n }\n })\n .catch(() => jsonNoCors(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n json(res, { error: 'Auth plugin route not found' }, 404)\n return\n }\n\n // POST /api/auth/credential — store typed credentials from dashboard\n if (path === '/api/auth/credential' && req.method === 'POST') {\n if (refuseCrossSiteRequest(req) !== undefined) {\n jsonNoCors(res, { error: 'cross_site_refused' }, 403)\n return\n }\n readJsonBody<{\n configName?: string\n provider?: string\n type?: string\n secret?: string\n }>(req)\n .then(async (body) => {\n const provider = typeof body.provider === 'string' ? body.provider.trim() : ''\n const credentialType = typeof body.type === 'string' ? body.type.trim() : ''\n const secret = typeof body.secret === 'string' ? body.secret.trim() : ''\n\n if (typeof body.configName !== 'string' || body.configName.trim() === '') {\n jsonNoCors(res, { error: 'configName is required' }, 400)\n return\n }\n if (!provider || !isKnownLLMProvider(provider)) {\n jsonNoCors(res, { error: 'valid provider is required' }, 400)\n return\n }\n if (credentialType !== 'api-key' && credentialType !== 'bearer-token') {\n jsonNoCors(res, { error: 'type must be api-key or bearer-token' }, 400)\n return\n }\n if (!secret) {\n jsonNoCors(res, { error: 'secret is required' }, 400)\n return\n }\n\n if (getLLMAuthProviderPlugin(provider)) {\n jsonNoCors(res, { error: 'Subscription providers use OAuth login' }, 400)\n return\n }\n\n if (credentialType === 'bearer-token' && provider !== 'anthropic-compatible') {\n jsonNoCors(res, { error: 'bearer-token credentials are only supported for anthropic-compatible configs' }, 400)\n return\n }\n\n if (credentialType === 'api-key' && !API_KEY_CREDENTIAL_PROVIDERS.has(provider)) {\n jsonNoCors(res, { error: 'api-key credentials are not supported for this provider' }, 400)\n return\n }\n\n try {\n const target = await withCredentialLock(async () => {\n const checked = await requireCredentialConfig(configManager, body.configName, provider)\n if (!checked.ok) return checked\n if (credentialType === 'bearer-token') {\n await writeDashboardAuth(checked.configName, { type: 'bearer', provider, token: secret })\n } else {\n await writeDashboardAuth(checked.configName, { type: 'api', provider, key: secret })\n }\n return checked\n })\n if (!target.ok) {\n jsonNoCors(res, credentialRefusalBody(target), target.status)\n return\n }\n jsonNoCors(res, { saved: true, created: target.created })\n } catch (err: unknown) {\n jsonNoCors(res, { error: err instanceof Error ? err.message : 'Failed to save credential' }, 500)\n }\n })\n .catch(() => jsonNoCors(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // POST /api/auth/credential/move — 429-09 D-15: a draft's credential follows its name while the\n // name is still editable. Only between names that are not in registry.llms, and never onto a\n // name that already holds a credential.\n if (path === '/api/auth/credential/move' && req.method === 'POST') {\n if (refuseCrossSiteRequest(req) !== undefined) {\n jsonNoCors(res, { error: 'cross_site_refused' }, 403)\n return\n }\n readJsonBody<unknown>(req)\n .then(async (raw) => {\n const parsed = LlmCredentialMoveRequestSchema.safeParse(raw)\n if (!parsed.success) {\n jsonNoCors(res, { error: 'invalid_setup_input' }, 400)\n return\n }\n const from = checkCredentialName(parsed.data.from)\n const to = checkCredentialName(parsed.data.to)\n if (!from.ok || !to.ok) {\n jsonNoCors(res, { error: 'name_invalid' }, 400)\n return\n }\n if (!configManager) {\n jsonNoCors(res, { error: 'Config manager is required to move credentials' }, 400)\n return\n }\n try {\n const refusal = await withCredentialLock(async (): Promise<{ status: number; error: string; message?: string } | undefined> => {\n if (await findRegistryLlm(configManager, from.name) || await findRegistryLlm(configManager, to.name)) {\n return { status: 409, error: 'name_taken' }\n }\n const store = await readAuth() as Record<string, DashboardAuthCredential | undefined>\n const entry = ownAuthEntry(store, from.name)\n if (!entry) return { status: 404, error: 'credential_missing' }\n if (credentialProductProvider(from.name, entry) !== parsed.data.provider) return CREDENTIAL_PROVIDER_CONFLICT\n if (ownAuthEntry(store, to.name)) return { status: 409, error: 'credential_exists' }\n await writeDashboardAuth(to.name, entry)\n await removeAuth(from.name)\n return undefined\n })\n if (refusal) {\n jsonNoCors(res, credentialRefusalBody(refusal), refusal.status)\n return\n }\n jsonNoCors(res, { moved: true })\n } catch (err: unknown) {\n jsonNoCors(res, { error: err instanceof Error ? err.message : 'Failed to move credential' }, 500)\n }\n })\n .catch(() => jsonNoCors(res, { error: 'invalid_setup_input' }, 400))\n return\n }\n\n // POST /api/llm/test — test LLM connection\n // Same-site only and no wildcard grant on any answer: this arm spends a saved credential\n // against a provider, so a page on another origin must not be able to drive it.\n if (path === '/api/llm/test' && req.method === 'POST') {\n if (refuseCrossSiteRequest(req) !== undefined) {\n jsonNoCors(res, { error: 'cross_site_refused' }, 403)\n return\n }\n readJsonBody<{\n configName?: string\n provider?: string\n model?: string\n baseURL?: string\n providerHeaders?: Record<string, string>\n }>(req)\n .then(async (body) => {\n const rawBody = body as Record<string, unknown>\n if ('apiKey' in rawBody) {\n jsonNoCors(res, {\n success: false,\n error: 'invalid_request',\n message: 'apiKey is not accepted in LLM test requests. Save credentials for the named config instead.',\n }, 400)\n return\n }\n const providerName = typeof body.provider === 'string' ? body.provider.trim() : ''\n const modelName = typeof body.model === 'string' ? body.model.trim() : ''\n if (!providerName || !modelName) {\n jsonNoCors(res, { success: false, error: 'invalid_request', message: 'provider and model are required' }, 400)\n return\n }\n const configName = typeof body.configName === 'string' ? body.configName.trim() : ''\n\n const llmCandidate: Record<string, unknown> = {\n provider: providerName,\n model: modelName,\n }\n if (typeof body.baseURL === 'string') {\n llmCandidate.baseURL = body.baseURL\n }\n let savedHeaderValues: string[] = []\n const bodyHeaders: unknown = body.providerHeaders\n const headerRecord = bodyHeaders !== null\n && typeof bodyHeaders === 'object'\n && !Array.isArray(bodyHeaders)\n if (bodyHeaders === undefined || headerRecord) {\n const baseURL = trimmedString(body.baseURL)\n const saved = await savedHeadersFor(configManager, configName, providerName, baseURL)\n const merged = mergeTestHeaders(saved, (bodyHeaders ?? {}) as Record<string, unknown>)\n savedHeaderValues = merged.savedValues\n if (Object.keys(merged.headers).length > 0) llmCandidate.providerHeaders = merged.headers\n } else {\n llmCandidate.providerHeaders = bodyHeaders\n }\n\n const parsedConfig = ModelConfigSchema.safeParse(llmCandidate)\n if (!parsedConfig.success) {\n jsonNoCors(res, {\n success: false,\n error: 'invalid_request',\n message: parsedConfig.error.issues\n .map((issue: { path: PropertyKey[]; message: string }) => `${issue.path.map(String).join('.') || 'config'}: ${issue.message}`)\n .join('; '),\n }, 400)\n return\n }\n\n const start = Date.now()\n const llmConfig = parsedConfig.data\n const coreAuth = await import('@vostride/agent-qa-core') as typeof import('@vostride/agent-qa-core') & {\n resolveLLMAuth: (name: string, config: typeof llmConfig) => Promise<\n | { kind: 'api-key'; apiKey: string }\n | { kind: 'bearer-token'; token: string }\n | { kind: 'auth-fetch'; fetch: typeof globalThis.fetch; modelAdapter: 'openai-responses' | 'anthropic-messages' }\n | { kind: 'unauthenticated'; message: string }\n | { kind: 'missing'; message: string }\n >\n }\n const resolvedAuth = await coreAuth.resolveLLMAuth(configName, llmConfig)\n if (resolvedAuth.kind === 'missing') {\n jsonNoCors(res, {\n success: false,\n error: 'missing_credential',\n message: resolvedAuth.message,\n })\n return\n }\n\n let unauthenticated = false\n let authMessage: string | undefined\n if (resolvedAuth.kind === 'unauthenticated') {\n unauthenticated = true\n authMessage = resolvedAuth.message\n }\n\n try {\n const { profile, auth } = toModelProfileAndAuth(llmConfig, resolvedAuth)\n // 2026-10-12 (441-04, D-06): fixed probe text, nothing to mask.\n const model = createModel(profile, auth, (text) => text)\n const connectionTimeoutMs = llmConnectionTestTimeoutMs(llmConfig)\n\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), connectionTimeoutMs)\n try {\n const { generateText } = await import('ai')\n await generateText({\n model,\n prompt: 'Say \"ok\"',\n abortSignal: controller.signal,\n })\n } finally {\n clearTimeout(timeout)\n }\n\n jsonNoCors(res, {\n success: true,\n model: modelName,\n provider: providerName,\n timeoutMs: connectionTimeoutMs,\n responseTime: Date.now() - start,\n ...(unauthenticated ? { unauthenticated: true, message: authMessage } : {}),\n })\n } catch (err: unknown) {\n const connectionTimeoutMs = llmConnectionTestTimeoutMs(llmConfig)\n const { message: rawProviderMessage, statusCode } = extractProviderError(err)\n const unsavedMessage = withoutSavedValues(rawProviderMessage, savedHeaderValues)\n const providerMessage = withDeclaredMask(declaredMask, (mask) => mask(unsavedMessage))\n const errorClass = classifyProviderError(providerMessage ?? unsavedMessage, statusCode)\n const message = providerMessage === undefined\n ? providerErrorSentence(errorClass, '').trimEnd()\n : providerErrorSentence(errorClass, providerMessage)\n\n jsonNoCors(res, {\n success: false,\n error: errorClass,\n message,\n timeoutMs: connectionTimeoutMs,\n ...(statusCode ? { statusCode } : {}),\n ...(providerMessage !== undefined && message !== providerMessage ? { details: providerMessage } : {}),\n ...(unauthenticated ? { unauthenticated: true, authMessage } : {}),\n })\n }\n })\n .catch(() => jsonNoCors(res, { success: false, error: 'invalid_request', message: 'Invalid request body' }, 400))\n return\n }\n\n // POST /api/cache/purge — purge cached action plans for a test or all tests\n if (path === '/api/cache/purge' && req.method === 'POST') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 503)\n return\n }\n readJsonBody<{ file?: string; all?: boolean }>(req)\n .then(async (body) => {\n if (!body.file && !body.all) {\n json(res, { error: 'Either file or all is required' }, 400)\n return\n }\n try {\n const cfg = await readConfigValues(configManager)\n const cacheDir = (cfg as {\n services?: { cache?: { dir?: string } }\n cache?: { dir?: string }\n }).services?.cache?.dir\n ?? (cfg as { cache?: { dir?: string } }).cache?.dir\n if (!cacheDir) {\n json(res, { error: 'Cache directory not configured' }, 400)\n return\n }\n // Redesigned cache layout (Phase 356): <cacheRoot>/<branch-slug>/<cacheKey>.json.\n // The 16-hex cacheKey is opaque and content-addressed over masked step text + a\n // runtime screenIdentityHash, carrying no raw step text on disk (D-06). Per-test\n // targeting can no longer be recomputed statically, so a `file` purge clears the\n // whole branch-namespaced cache — the requested test's stale plans are guaranteed\n // gone. Both `file` and `all` therefore remove all `<branch-slug>/*.json` entries.\n const configDir = deps.configPath ? dirname(resolve(deps.configPath)) : process.cwd()\n const resolvedCacheDir = resolve(configDir, cacheDir)\n let branchDirs: string[]\n try {\n branchDirs = await readdir(resolvedCacheDir)\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n json(res, { purged: 0 })\n return\n }\n throw err\n }\n let purged = 0\n for (const branch of branchDirs) {\n const branchPath = join(resolvedCacheDir, branch)\n let entryStat\n try {\n entryStat = await stat(branchPath)\n } catch {\n continue\n }\n if (!entryStat.isDirectory()) {\n await rm(branchPath, { force: true })\n continue\n }\n let files: string[]\n try {\n files = await readdir(branchPath)\n } catch {\n continue\n }\n for (const file of files) {\n if (!file.endsWith('.json')) continue\n await rm(join(branchPath, file), { force: true })\n purged++\n }\n await rm(branchPath, { recursive: true, force: true }).catch(() => {})\n }\n json(res, { purged })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Cache purge failed' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n // Agent Rules API removed: the workspace agent-rules config surface was retired in\n // Phase 373 (KDIR-03); policy serving returns via Reader L0 policies in Phase 380.\n\n // Hooks API\n if (path === '/api/hooks' && req.method === 'GET') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n json(res, await hookRegistryManager.readCatalog())\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read hooks' }, 500)\n }\n })()\n return\n }\n\n if (path === '/api/hooks' && req.method === 'POST') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody(req)\n .then(async (body) => {\n try {\n const result = await hookRegistryManager.createHook(body as import('../hooks/hook-registry-types.js').HookMutationRequest)\n json(res, result, 201)\n } catch (err: unknown) {\n if (isHookRegistryMutationError(err) && err.code === 'validation_failed') {\n json(res, { error: 'validation_failed', fieldErrors: err.fieldErrors }, 400)\n return\n }\n json(res, { error: err instanceof Error ? err.message : 'Failed to create hook' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n const hookRunMatch = path.match(/^\\/api\\/hooks\\/([^/]+)\\/run$/)\n if (hookRunMatch && req.method === 'POST') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody<import('../hooks/hook-registry-types.js').HookRunRequest>(req)\n .then(async (body) => {\n try {\n const validation = validateHookRunRequest(body)\n if (validation.fieldErrors.length > 0) {\n json(res, { error: 'validation_failed', fieldErrors: validation.fieldErrors }, 400)\n return\n }\n\n const hookId = decodeURIComponent(hookRunMatch[1])\n const prepareResult = await hookRegistryManager.prepareForExecution()\n if (prepareResult.hookRegistryError) {\n json(res, { error: 'hook_registry_error', message: prepareResult.hookRegistryError }, 409)\n return\n }\n\n const resolvedHook = prepareResult.resolvedHooks.get(hookId)\n if (!resolvedHook) {\n const detail = await hookRegistryManager.readHook(hookId)\n if (!detail) {\n notFound(res, 'Hook not found')\n return\n }\n\n const fieldErrors = prepareResult.authoringIssuesById.get(hookId) ?? detail.fieldErrors\n if (fieldErrors.length > 0) {\n json(res, { error: 'hook_not_runnable', fieldErrors }, 409)\n return\n }\n\n json(res, { error: 'hook_not_runnable', message: 'Hook is not executable' }, 409)\n return\n }\n\n if (declaredMask === undefined) {\n json(res, { error: 'masking_unavailable' }, 503)\n return\n }\n const workspaceEnv = await readWorkspaceEnvVars(workspacePaths)\n const result = await new DockerHookExecutor().execute(resolvedHook, {\n env: {\n ...workspaceEnv,\n ...validation.overrides,\n },\n secretEnv: {},\n })\n const networkLogs = summarizeHookNetworkLogs(\n (result as { networkLogs?: Array<{ url: string; method: string; status: number; startTime: number; endTime: number }> }).networkLogs,\n )\n const shown = withDeclaredMask(declaredMask, (mask) => ({\n ...maskPayloadStrings({\n output: result.output,\n stdout: result.stdout,\n stderr: result.stderr,\n error: result.error ?? null,\n }, mask),\n variables: maskPayloadTree(result.variables, mask),\n networkLogs: networkLogs.map((entry) => ({ ...entry, url: mask(entry.url) })),\n }))\n if (shown === undefined) {\n json(res, { error: 'masking_unavailable' }, 503)\n return\n }\n\n json(res, {\n success: result.success,\n status: result.success ? 'passed' : 'failed',\n executedAt: new Date().toISOString(),\n duration: result.duration,\n output: shown.output,\n stdout: shown.stdout,\n stderr: shown.stderr,\n error: shown.error,\n variables: shown.variables,\n sandbox: {\n runtime: resolvedHook.runtime,\n image: RUNTIME_IMAGE_MAP[resolvedHook.runtime],\n networkMode: resolvedHook.network ? 'enabled' : 'disabled',\n dockerVersion: null,\n networkLogsAvailable: shown.networkLogs.length > 0,\n networkLogs: shown.networkLogs,\n },\n } satisfies import('../hooks/hook-registry-types.js').HookRunResponse)\n } catch (err: unknown) {\n const message = err instanceof Error\n ? withDeclaredMask(declaredMask, (mask) => mask(err.message))\n : undefined\n json(res, { error: message ?? 'Failed to run hook' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n const hookDetailMatch = path.match(/^\\/api\\/hooks\\/([^/]+)$/)\n if (hookDetailMatch && req.method === 'GET') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const detail = await hookRegistryManager.readHook(decodeURIComponent(hookDetailMatch[1]))\n if (!detail) {\n notFound(res, 'Hook not found')\n return\n }\n json(res, detail)\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read hook' }, 500)\n }\n })()\n return\n }\n\n if (hookDetailMatch && req.method === 'PUT') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody(req)\n .then(async (body) => {\n try {\n const result = await hookRegistryManager.updateHook(\n decodeURIComponent(hookDetailMatch[1]),\n body as import('../hooks/hook-registry-types.js').HookMutationRequest,\n )\n json(res, result)\n } catch (err: unknown) {\n if (isHookRegistryMutationError(err) && err.code === 'hook_not_found') {\n notFound(res, 'Hook not found')\n return\n }\n if (isHookRegistryMutationError(err) && err.code === 'validation_failed') {\n json(res, { error: 'validation_failed', fieldErrors: err.fieldErrors }, 400)\n return\n }\n json(res, { error: err instanceof Error ? err.message : 'Failed to update hook' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n if (hookDetailMatch && req.method === 'DELETE') {\n const hookRegistryManager = createHookRegistryManager(configManager, deps.configPath)\n if (!hookRegistryManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const result = await hookRegistryManager.deleteHook(\n decodeURIComponent(hookDetailMatch[1]),\n { force: url.searchParams.get('force') === 'true' },\n )\n if (!result.deleted) {\n json(res, { error: 'hook_in_use', references: result.references }, 409)\n return\n }\n json(res, result)\n } catch (err: unknown) {\n if (isHookRegistryMutationError(err) && err.code === 'hook_not_found') {\n notFound(res, 'Hook not found')\n return\n }\n if (isHookRegistryMutationError(err) && err.code === 'validation_failed') {\n json(res, { error: 'validation_failed', fieldErrors: err.fieldErrors }, 400)\n return\n }\n json(res, { error: err instanceof Error ? err.message : 'Failed to delete hook' }, 500)\n }\n })()\n return\n }\n\n // Variables API\n if (path === '/api/variables' && req.method === 'GET') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n let content: string\n try {\n content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n json(res, { error: `workspace.envFile not found: ${workspacePaths.envFile.workspaceRelativePath}` }, 500)\n return\n }\n throw err\n }\n const parsed = parseEnvFile(content)\n const variables = Object.entries(parsed).map(([key, value]) => ({ key, value }))\n json(res, { variables, filePath: workspacePaths.envFile.workspaceRelativePath })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read variables' }, 500)\n }\n })()\n return\n }\n\n if (path === '/api/variables' && req.method === 'PUT') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n readJsonBody<{ oldKey?: string; key: string; value: string }>(req)\n .then(async (body) => {\n try {\n if (!body.key || typeof body.key !== 'string') {\n json(res, { error: 'Missing required field: key' }, 400)\n return\n }\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(body.key)) {\n json(res, { error: 'Variable names must contain only letters, numbers, and underscores' }, 400)\n return\n }\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n let content = ''\n try {\n content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n json(res, { error: `workspace.envFile not found: ${workspacePaths.envFile.workspaceRelativePath}` }, 500)\n return\n }\n throw err\n }\n const vars = parseEnvFile(content)\n if (body.oldKey && body.oldKey !== body.key) {\n delete vars[body.oldKey]\n }\n vars[body.key] = body.value ?? ''\n await writeFile(workspacePaths.envFile.absolutePath, serializeEnvFile(vars), 'utf-8')\n json(res, { updated: true })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to update variable' }, 500)\n }\n })\n .catch(() => json(res, { error: 'Invalid request body' }, 400))\n return\n }\n\n const varDeleteMatch = path.match(/^\\/api\\/variables\\/(.+)$/)\n if (varDeleteMatch && req.method === 'DELETE') {\n if (!configManager) {\n json(res, { error: 'Config management not available' }, 501)\n return\n }\n ;(async () => {\n try {\n const varKey = decodeURIComponent(varDeleteMatch[1])\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n let content = ''\n try {\n content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n json(res, { error: `workspace.envFile not found: ${workspacePaths.envFile.workspaceRelativePath}` }, 500)\n return\n }\n throw err\n }\n const vars = parseEnvFile(content)\n const existed = varKey in vars\n delete vars[varKey]\n await writeFile(workspacePaths.envFile.absolutePath, serializeEnvFile(vars), 'utf-8')\n json(res, { deleted: existed })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to delete variable' }, 500)\n }\n })()\n return\n }\n\n // GET /api/live-editor/sessions/:id/live-url — the editor mint door (428 D-07).\n //\n // A copy of the run mint door above, arm for arm: the same-site guard first, 503 when unbound,\n // the op's result verbatim and its refusals mapped by error name. Every arm answers through\n // `jsonNoCors`, because the success body is the token. The DELETE arm below matches one path\n // segment after the id, so it never sees a `/live-url` suffix.\n if (req.method === 'GET' && /^\\/api\\/live-editor\\/sessions\\/[^/]+\\/live-url$/.test(path)) {\n if (refuseCrossSiteRequest(req) !== undefined) {\n jsonNoCors(res, { error: 'cross_site_refused' }, 403)\n return\n }\n if (!deps.mintEditorLiveUrl) {\n jsonNoCors(res, { error: 'live_view_unavailable' }, 503)\n return\n }\n let editorSessionId: string\n try {\n editorSessionId = decodeURIComponent(\n path.slice('/api/live-editor/sessions/'.length, -'/live-url'.length),\n )\n } catch {\n jsonNoCors(res, { error: 'unknown_session' }, 404)\n return\n }\n void deps.mintEditorLiveUrl(editorSessionId).then(\n (result) => { jsonNoCors(res, result) },\n (error: unknown) => {\n const name = error instanceof Error ? error.name : ''\n if (name === 'UnknownLiveEditorSessionError') { jsonNoCors(res, { error: 'unknown_session' }, 404); return }\n if (name === 'LiveViewUnavailableError') { jsonNoCors(res, { error: 'live_view_unavailable' }, 503); return }\n jsonNoCors(res, { error: 'live_url_mint_failed' }, 500)\n },\n )\n return\n }\n\n // THE LIVE-EDITOR DOORS (428 D-08 — WINDOWS #275). These four arms create, list, end and read\n // auth state out of sessions that drive a real browser, which is more than the live-url grants.\n // Each runs the one same-site predicate first and answers every arm, success and refusal alike,\n // through `jsonNoCors`: a wildcard grant on an admitted answer would leave a readable session\n // list behind for any origin (RESEARCH P6). The rest of this router keeps its posture.\n // POST /api/live-editor/sessions/:id/auth-state — save auth state from active web Live Mode context\n const liveEditorAuthStateMatch = path.match(/^\\/api\\/live-editor\\/sessions\\/([^/]+)\\/auth-state$/)\n if (liveEditorAuthStateMatch && req.method === 'POST') {\n // 428 D-08 (WINDOWS #275): the same-site guard first, and no wildcard grant on any answer.\n if (refuseCrossSiteDisplayRead(req, res)) return\n if (!sessionManager) {\n jsonNoCors(res, { error: 'Live editor not available' }, 503)\n return\n }\n ;(async () => {\n let stateName = ''\n let session: { captureWebAuthState?: (name: string, options: { replace: boolean }) => Promise<unknown>; getState?: () => unknown } | undefined\n try {\n const body = await readJsonBody<{ name?: unknown; replace?: unknown }>(req)\n const parsedName = AuthStateNameSchema.safeParse(typeof body?.name === 'string' ? body.name : '')\n if (!parsedName.success) {\n jsonNoCors(res, { error: 'Auth state name must be a lowercase slug.' }, 400)\n return\n }\n\n stateName = parsedName.data\n session = sessionManager.getSession(decodeURIComponent(liveEditorAuthStateMatch[1]))\n if (!session) {\n jsonNoCors(res, { error: 'Session not found' }, 404)\n return\n }\n\n if (typeof session.captureWebAuthState !== 'function') {\n jsonNoCors(res, {\n error: `Could not save auth state \"${stateName}\" for target \"${getSessionTargetNameForAuthState(session)}\".`,\n }, 500)\n return\n }\n\n const authState = await session.captureWebAuthState(stateName, { replace: body?.replace === true })\n jsonNoCors(res, { authState })\n } catch (err: unknown) {\n const targetName = getSessionTargetNameForAuthState(session)\n const response = buildAuthStateSaveErrorMessage(stateName || 'unknown', targetName, err)\n jsonNoCors(res, { error: response.message }, response.status)\n }\n })()\n return\n }\n\n // POST /api/live-editor/sessions — create a new live editor session\n if (path === '/api/live-editor/sessions' && req.method === 'POST') {\n // 428 D-08 (WINDOWS #275): the same-site guard first, and no wildcard grant on any answer.\n if (refuseCrossSiteDisplayRead(req, res)) return\n if (!sessionManager) {\n jsonNoCors(res, { error: 'Live editor not available' }, 503)\n return\n }\n ;(async () => {\n try {\n const body = await readJsonBody<{\n platform?: string\n targetName?: string\n url?: string\n headless?: boolean\n device?: Record<string, unknown>\n useDeviceName?: string\n appState?: string\n bundleId?: string\n appPackage?: string\n appActivity?: string\n setupHooks?: unknown\n teardownHooks?: unknown\n entity?: { type?: string; id?: string }\n }>(req)\n const targetName = typeof body?.targetName === 'string' ? body.targetName : undefined\n // 432 D-18: a production target is refused here, before the session and any of its\n // setup. The request names the target; the environment and the opt-in are read from\n // the current config, never from the request.\n const production = await resolveLiveTargetProduction(configManager, targetName)\n const productionRefusal = liveProductionRefusal(production)\n if (productionRefusal !== undefined) {\n jsonNoCors(res, { error: productionRefusal.message }, 403)\n return\n }\n const platform = body?.platform ?? 'web'\n const runtimeLLM = await resolveDashboardRuntimeLLM(configManager, llmConfig, authFetch)\n if (!runtimeLLM.ok) {\n jsonNoCors(res, { error: runtimeLLM.error }, 400)\n return\n }\n const setupHooks = Array.isArray(body?.setupHooks)\n ? body.setupHooks.filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n : []\n const teardownHooks = Array.isArray(body?.teardownHooks)\n ? body.teardownHooks.filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n : []\n // Validate entity (ASVS V5). Only 'suite' | 'test' with a non-empty id\n // are honoured; malformed shapes are silently ignored — client may\n // send {} during the test-editor retrofit before entity threading\n // lands (downgrades to sessionNumber=null instead of a 400 error).\n let entityRef: { type: 'suite' | 'test'; id: string } | undefined\n if (body?.entity && typeof body.entity === 'object') {\n const t = body.entity.type\n const id = body.entity.id\n if ((t === 'suite' || t === 'test') && typeof id === 'string' && id.length > 0) {\n entityRef = { type: t, id }\n }\n }\n let envVars: Record<string, string> | undefined\n let secretStore: SecretStore | undefined\n let secretRedactor: SecretRedactor | undefined\n let resolvedHooks = new Map<string, import('@vostride/agent-qa-core').HookDefinition>()\n let hookRegistryError: string | undefined\n if (!workspacePaths) {\n jsonNoCors(res, { error: 'Workspace path resolution not available' }, 500)\n return\n }\n\n try {\n const envContent = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n envVars = parseEnvFile(envContent)\n } catch {\n jsonNoCors(res, { error: `workspace.envFile file could not be loaded: ${workspacePaths.envFile.workspaceRelativePath}` }, 400)\n return\n }\n\n try {\n const secretsContent = await readFile(workspacePaths.secretsFile.absolutePath, 'utf-8')\n secretStore = SecretStore.fromEnvContent(secretsContent)\n secretRedactor = new SecretRedactor(secretStore)\n } catch {\n jsonNoCors(res, { error: `workspace.secretsFile file could not be loaded: ${workspacePaths.secretsFile.workspaceRelativePath}` }, 400)\n return\n }\n\n const hookCatalog = await readWorkspaceHooks(configManager, deps.configPath)\n resolvedHooks = hookCatalog.resolvedHooks\n hookRegistryError = hookCatalog.hookRegistryError\n // 436 D-03: the limits come from the project config and the edited entity's own `use`,\n // read through the workspace managers by canonical id; never from the request.\n const entityReaders = {\n ...(testFileManager === undefined ? {} : { findTest: (id: string) => testFileManager.findByTestId(id) }),\n ...(suiteFileManager === undefined ? {} : { findSuite: (id: string) => suiteFileManager.findBySuiteId(id) }),\n }\n const plannerLimits = await resolveLivePlannerLimits(configManager, entityRef, entityReaders)\n // Each test a session runs gets project, then the session's suite, then its own `use`:\n // the chain the CLI suite producer resolves per member.\n const sessionSuiteRef = entityRef?.type === 'suite' ? entityRef : undefined\n const plannerLimitsForTest = (testId: string) =>\n resolveLivePlannerLimits(\n configManager,\n sessionSuiteRef === undefined\n ? [{ type: 'test', id: testId }]\n : [sessionSuiteRef, { type: 'test', id: testId }],\n entityReaders,\n )\n const { sessionId, sessionNumber } = await sessionManager.createSession(\n {\n platform: platform as 'web' | 'android' | 'ios',\n targetName,\n production: { productionTargetNames: production.productionTargetNames },\n plannerLimits,\n plannerLimitsForTest,\n llmConfig: runtimeLLM.llmConfig,\n authFetch: runtimeLLM.authFetch,\n envVars,\n secretStore,\n secretRedactor,\n setupHooks,\n teardownHooks,\n resolvedHooks,\n hookRegistryError,\n url: body?.url,\n headless: body?.headless ?? false,\n useDeviceName: typeof body?.useDeviceName === 'string' ? body.useDeviceName : undefined,\n appState: body?.appState === 'preserve' || body?.appState === 'reset' ? body.appState : undefined,\n bundleId: typeof body?.bundleId === 'string' ? body.bundleId : undefined,\n appPackage: typeof body?.appPackage === 'string' ? body.appPackage : undefined,\n appActivity: typeof body?.appActivity === 'string' ? body.appActivity : undefined,\n device: body?.device as import('../live-editor/types.js').LiveSessionConfig['device'],\n },\n entityRef,\n )\n jsonNoCors(res, { sessionId, sessionNumber }, 201)\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n // The config changed between the door's read and `initialize`'s: the same refusal.\n // 436 D-03: a limit the CLI refuses is refused here, before any session exists.\n const status = err instanceof LiveProductionRefusedError\n ? 403\n : err instanceof LivePlannerLimitsRefusedError ? 400 : 500\n jsonNoCors(res, { error: message }, status)\n }\n })()\n return\n }\n\n // GET /api/live-editor/sessions — list all active live editor sessions\n if (path === '/api/live-editor/sessions' && req.method === 'GET') {\n // 428 D-08 (WINDOWS #275): the same-site guard first, and no wildcard grant on any answer.\n if (refuseCrossSiteDisplayRead(req, res)) return\n if (!sessionManager) {\n jsonNoCors(res, { error: 'Live editor not available' }, 503)\n return\n }\n jsonNoCors(res, { sessions: sessionManager.listSessions() })\n return\n }\n\n // DELETE /api/live-editor/sessions/:id — terminate a live editor session\n const liveEditorSessionMatch = path.match(/^\\/api\\/live-editor\\/sessions\\/([^/]+)$/)\n if (liveEditorSessionMatch && req.method === 'DELETE') {\n // 428 D-08 (WINDOWS #275): the same-site guard first, and no wildcard grant on any answer.\n if (refuseCrossSiteDisplayRead(req, res)) return\n if (!sessionManager) {\n jsonNoCors(res, { error: 'Live editor not available' }, 503)\n return\n }\n const sessionId = liveEditorSessionMatch[1]\n ;(async () => {\n const terminated = await sessionManager.terminateSession(sessionId)\n if (terminated) {\n jsonNoCors(res, { ok: true })\n } else {\n jsonNoCors(res, { error: 'Session not found' }, 404)\n }\n })()\n return\n }\n\n // Variable suggestions: env keys\n if (path === '/api/variables/env' && req.method === 'GET') {\n if (!configManager) {\n json(res, { keys: [] })\n return\n }\n ;(async () => {\n try {\n if (!workspacePaths) {\n json(res, { error: 'Workspace path resolution not available' }, 503)\n return\n }\n const content = await readFile(workspacePaths.envFile.absolutePath, 'utf-8')\n const parsed = parseEnvFile(content)\n json(res, { keys: Object.keys(parsed) })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read env variables' }, 500)\n }\n })()\n return\n }\n\n // Variable suggestions: hook names\n if (path === '/api/variables/hooks' && req.method === 'GET') {\n ;(async () => {\n try {\n const { hooks } = await readWorkspaceHooks(configManager, deps.configPath)\n json(res, { names: hooks.map((hook) => hook.name) })\n } catch (err: unknown) {\n json(res, { error: err instanceof Error ? err.message : 'Failed to read hooks' }, 500)\n }\n })()\n return\n }\n\n // 2026-08-27 (405-07, D-02): the captured-variable-name suggestion arm was deleted with its\n // reader. It scanned a `captured_variables` column on the v1 projection, which no producer has\n // filled since the subscriber was rebuilt on the bus payloads — so the endpoint answered an\n // empty list on every real workspace while looking like a working suggestion source. The hook\n // and workspace suggestion arms above are unaffected: their producers are live.\n\n // Unknown API route\n if (path.startsWith('/api/')) {\n notFound(res)\n return\n }\n\n // Non-API routes handled by server.ts (static files)\n notFound(res)\n }\n}\n","export const RUN_STATUS_WORDS = [\n 'pending',\n 'running',\n 'passed',\n 'healed',\n 'failed',\n 'timeout',\n 'cancelled',\n] as const\n\nexport type RunStatusWord = (typeof RUN_STATUS_WORDS)[number]\n\nexport type RunStatusClass = 'pass' | 'fail' | 'cancelled' | 'live'\n\nconst CLASS_OF: Record<RunStatusWord, RunStatusClass> = {\n pending: 'live',\n running: 'live',\n passed: 'pass',\n healed: 'pass',\n failed: 'fail',\n timeout: 'fail',\n cancelled: 'cancelled',\n}\n\nexport function isRunStatusWord(word: string): word is RunStatusWord {\n return Object.hasOwn(CLASS_OF, word)\n}\n\nexport function runStatusClass(status: string): RunStatusClass {\n if (!isRunStatusWord(status)) throw new Error(`runStatusClass: unknown run status \"${status}\"`)\n return CLASS_OF[status]\n}\n\n// 2026-10-17 (444-05, D-35): a member outcome is a run word or `skipped`; a member with none is live.\n// 2026-10-18 (444-27, D-62 IN-05): run_members.outcome has no CHECK, so any other word is\n// unclassified (`undefined`) and every reader skips it; runs.status has one, so runStatusClass throws.\nexport function memberOutcomeClass(outcome: string | null): RunStatusClass | 'skipped' | undefined {\n if (outcome === null) return 'live'\n if (outcome === 'skipped') return 'skipped'\n if (isRunStatusWord(outcome)) return runStatusClass(outcome)\n return undefined\n}\n","import { readFile, mkdir, rm, stat } from 'node:fs/promises'\nimport { dirname, basename } from 'node:path'\nimport { isDeepStrictEqual } from 'node:util'\nimport { generateTestId } from '@vostride/agent-qa-ids'\nimport { parseAllDocuments, parse as parseYaml } from 'yaml'\nimport {\n discoverWorkspaceFiles,\n resolveWorkspaceFileTarget,\n type ResolvedWorkspacePaths,\n} from '@vostride/agent-qa-core'\nimport { createPathLock, replaceFileAtomic } from './replace-file-atomic.js'\n\nexport interface TestFileInfo {\n path: string\n name: string\n testId: string | null\n targetName: string | null\n platform: string | null\n modified: string\n}\n\nexport type SupportedPlatform = 'web' | 'android' | 'ios'\n\nexport interface TestFileMetadata {\n name: string | null\n testId: string | null\n targetName: string | null\n platform: SupportedPlatform | null\n parallel: boolean | null\n}\n\nexport interface TestValidationError {\n message: string\n line?: number\n column?: number\n suggestion?: string\n}\n\nexport interface TestValidationResult {\n valid: boolean\n errors: TestValidationError[]\n}\n\nfunction normalizeQuotedString(value: string): string {\n return value.trim().replace(/^[\"'](.*)[\"']$/, '$1')\n}\n\nfunction normalizePlatform(value: unknown): SupportedPlatform | null {\n if (value !== 'web' && value !== 'android' && value !== 'ios') return null\n return value\n}\n\nfunction isMapping(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nexport function presentText(value: unknown): string | null {\n if (typeof value !== 'string') return null\n const text = value.trim()\n return text === '' ? null : text\n}\n\n// 2026-10-19 (444-37, D-68): only a file that does not parse is read line by line, each key from its own line.\nfunction valueOnLine(match: RegExpMatchArray | null): string | null {\n if (match === null) return null\n const value = normalizeQuotedString(match[1])\n return value.trim() === '' ? null : value\n}\n\n// 2026-10-19 (444-37, D-68): a bare, blank or comment-only id key is filled in place; otherwise the id line goes after a\n// leading byte-order mark and the stream's first --- marker, or first, in the file's own line ending.\nexport function withIdLine(content: string, key: 'test-id' | 'suite-id', id: string): string {\n const bom = content.startsWith('\\uFEFF') ? '\\uFEFF' : ''\n const rest = content.slice(bom.length)\n const firstBreak = rest.indexOf('\\n')\n const eol = firstBreak > 0 && rest[firstBreak - 1] === '\\r' ? '\\r\\n' : '\\n'\n const line = `${key}: ${id}`\n const blankKey = new RegExp(`^${key}:(?:[ \\\\t]*([\"'])[ \\\\t]*\\\\1)?(?:[ \\\\t]+#[^\\\\r\\\\n]*)?[ \\\\t]*$`, 'm')\n if (blankKey.test(rest)) return bom + rest.replace(blankKey, () => line)\n const marker = rest.match(/^(?:(?:[ \\t]*(?:#[^\\r\\n]*)?|%[^\\r\\n]*)\\r?\\n)*---[ \\t]*(?:#[^\\r\\n]*)?(?:\\r?\\n|$)/)\n if (marker === null) return `${bom}${line}${eol}${rest}`\n const head = marker[0].endsWith('\\n') ? marker[0] : `${marker[0]}${eol}`\n return `${bom}${head}${line}${eol}${rest.slice(marker[0].length)}`\n}\n\n// 2026-10-19 (444-37, D-68): an id write lands only if it parses, as one document, to the old mapping plus the id.\nexport function idWriteText(content: string, key: 'test-id' | 'suite-id', id: string): string | null {\n let old: unknown\n try {\n old = parseYaml(content)\n } catch {\n return null\n }\n if (!isMapping(old)) return null\n const next = withIdLine(content, key, id)\n let written: unknown\n try {\n written = parseYaml(next)\n } catch {\n return null\n }\n return isDeepStrictEqual(written, { ...old, [key]: id }) ? next : null\n}\n\nfunction lineMetadata(content: string): TestFileMetadata {\n const nameMatch = content.match(/^name:[ \\t]*(\\S.*)$/m)\n const targetMatch = content.match(/^[ \\t]*target:[ \\t]*(\\S.*)$/m)\n const testIdMatch = content.match(/^test-id:[ \\t]*(\\S.*)$/m)\n const platformMatch = content.match(/^[ \\t]*platform:[ \\t]*(web|android|ios)[ \\t]*$/m)\n const parallelMatch = content.match(/^[ \\t]*parallel:[ \\t]*(true|false)[ \\t]*$/m)\n return {\n name: valueOnLine(nameMatch),\n testId: valueOnLine(testIdMatch),\n targetName: valueOnLine(targetMatch),\n platform: normalizePlatform(platformMatch?.[1]),\n parallel: parallelMatch ? parallelMatch[1] === 'true' : null,\n }\n}\n\n// 2026-10-19 (444-37, D-68): a file that parses is read from its mapping, where a null, empty or blank value is absent.\nexport function extractTestFileMetadata(content: string): TestFileMetadata {\n let parsed: unknown\n try {\n parsed = parseYaml(content)\n } catch {\n return lineMetadata(content.replace(/^\\uFEFF/, ''))\n }\n if (!isMapping(parsed)) return { name: null, testId: null, targetName: null, platform: null, parallel: null }\n\n const config = isMapping(parsed.config) ? parsed.config : null\n const use = isMapping(parsed.use) ? parsed.use : null\n const parallel = typeof use?.parallel === 'boolean'\n ? use.parallel\n : typeof parsed.parallel === 'boolean'\n ? parsed.parallel\n : typeof config?.parallel === 'boolean'\n ? config.parallel\n : null\n\n return {\n name: presentText(parsed.name),\n testId: presentText(parsed['test-id']),\n targetName: presentText(parsed.target),\n platform: normalizePlatform(parsed.platform) ?? normalizePlatform(config?.platform),\n parallel,\n }\n}\n\n// 2026-10-19 (444.1-11, D-18): a mint reads bytes that decode losslessly, or it does not write.\nexport function decodeUtf8(bytes: Uint8Array): string | undefined {\n try {\n return new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes)\n } catch (err) {\n if (err instanceof TypeError) return undefined\n throw err\n }\n}\n\n// 2026-10-19 (444.1-11, D-19, D-21): every document's target is read, and the line pattern reads only top-level target lines.\nexport function targetsForMarkerCheck(content: string): unknown[] {\n const targets: unknown[] = []\n try {\n for (const doc of parseAllDocuments(content)) {\n if (doc.errors.length === 0) {\n const value: unknown = doc.toJS()\n if (isMapping(value)) targets.push(value.target)\n }\n }\n } catch { /* the line pattern below still reads it */ }\n for (const match of content.matchAll(/^target:[ \\t]*(\\S.*)$/gm)) targets.push(match[1])\n return targets\n}\n\nexport class TestFileManager {\n constructor(private readonly workspace: ResolvedWorkspacePaths) {}\n\n // 2026-10-18 (444-33, D-65; 444-35, D-66): each list call reads the workspace itself; each file is written whole and one writer at a time.\n private readonly underLock = createPathLock()\n\n async list(): Promise<TestFileInfo[]> {\n const records = await discoverWorkspaceFiles({ workspace: this.workspace, kind: 'test' })\n const files: TestFileInfo[] = []\n\n for (const record of records) {\n try {\n const s = await stat(record.absolutePath)\n if (s.isFile()) {\n let testName = basename(record.workspaceRelativePath)\n let platform: string | null = null\n let targetName: string | null = null\n let testId: string | null = null\n const take = (metadata: TestFileMetadata): void => {\n testName = metadata.name || basename(record.workspaceRelativePath)\n targetName = metadata.targetName || null\n platform = metadata.platform\n testId = metadata.testId\n }\n try {\n const first = extractTestFileMetadata(await readFile(record.absolutePath, 'utf-8'))\n take(first)\n if (!first.testId) {\n take(await this.underLock(record.absolutePath, async () => {\n const content = decodeUtf8(await readFile(record.absolutePath))\n if (content === undefined) return first\n const current = extractTestFileMetadata(content)\n if (current.testId) return current\n // 2026-10-18 (444-35, IN-20): an empty file may be an outside save mid-write; it is never minted.\n if (content.trim() === '') return current\n const minted = generateTestId()\n const next = idWriteText(content, 'test-id', minted)\n if (next === null) return current\n await replaceFileAtomic(record.absolutePath, next)\n return { ...current, testId: minted }\n }))\n }\n } catch { /* fall back to filename */ }\n files.push({\n path: record.workspaceRelativePath,\n name: testName,\n testId,\n targetName,\n platform,\n modified: s.mtime.toISOString(),\n })\n }\n } catch {\n // skip inaccessible files\n }\n }\n\n files.sort((a, b) => b.modified.localeCompare(a.modified))\n return files\n }\n\n async read(relativePath: string): Promise<string> {\n const target = await this.resolveTarget(relativePath, true)\n return readFile(target.absolutePath, 'utf-8')\n }\n\n async findByTestId(testId: string): Promise<{ path: string; content: string } | null> {\n const files = await this.list()\n const match = files.find(f => f.testId === testId)\n if (!match) return null\n const content = await this.read(match.path)\n return { path: match.path, content }\n }\n\n async write(relativePath: string, content: string): Promise<void> {\n const target = await this.resolveTarget(relativePath, false)\n await mkdir(dirname(target.absolutePath), { recursive: true })\n await this.underLock(target.absolutePath, () => replaceFileAtomic(target.absolutePath, content))\n }\n\n async delete(relativePath: string): Promise<void> {\n const target = await this.resolveTarget(relativePath, true)\n await this.underLock(target.absolutePath, () => rm(target.absolutePath))\n }\n\n async validate(content: string): Promise<TestValidationResult> {\n try {\n const { parseTestFile } = await import('@vostride/agent-qa-core')\n const result = parseTestFile(content, '<editor>')\n\n if (result.errors.length === 0) {\n return { valid: true, errors: [] }\n }\n\n return {\n valid: false,\n errors: result.errors.map(e => ({\n message: e.message,\n line: e.line,\n column: e.column,\n suggestion: e.suggestion,\n })),\n }\n } catch (err) {\n return {\n valid: false,\n errors: [{ message: err instanceof Error ? err.message : 'Failed to validate' }],\n }\n }\n }\n\n private async resolveTarget(relativePath: string, requireExisting: boolean) {\n return resolveWorkspaceFileTarget({\n workspace: this.workspace,\n kind: 'test',\n filePath: relativePath,\n requireExisting,\n })\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { constants } from 'node:fs'\nimport { access, chmod, lstat, realpath, rename, rm, stat, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\n// 2026-10-18 (444-33, D-65; 444-35, IN-17): a whole fixed-length temp file renamed over the target, through a symlink, with its mode.\nexport async function replaceFileAtomic(absolutePath: string, content: string): Promise<void> {\n const isLink = await lstat(absolutePath).then(\n (stats) => stats.isSymbolicLink(),\n (err: unknown) => {\n if (isMissingFile(err)) return false\n throw err\n },\n )\n const target = isLink ? await realpath(absolutePath) : absolutePath\n let mode: number | undefined\n try {\n await access(target, constants.W_OK)\n mode = (await stat(target)).mode & 0o777\n } catch (err) {\n if (!isMissingFile(err)) throw err\n }\n const tempPath = join(dirname(target), `.agent-qa-${randomUUID()}.tmp`)\n try {\n await writeFile(tempPath, content, { encoding: 'utf-8', flag: 'wx', ...(mode === undefined ? {} : { mode }) })\n if (mode !== undefined) await chmod(tempPath, mode)\n await rename(tempPath, target)\n } catch (error) {\n await rm(tempPath, { force: true }).catch(() => undefined)\n throw error\n }\n}\n\nexport function createPathLock(): <T>(key: string, work: () => Promise<T>) => Promise<T> {\n const tails = new Map<string, Promise<void>>()\n return <T>(key: string, work: () => Promise<T>): Promise<T> => {\n const result = (tails.get(key) ?? Promise.resolve()).then(work)\n const tail = result.then(\n () => undefined,\n () => undefined,\n )\n tails.set(key, tail)\n void tail.then(() => {\n if (tails.get(key) === tail) tails.delete(key)\n })\n return result\n }\n}\n\nfunction isMissingFile(err: unknown): boolean {\n return (err as NodeJS.ErrnoException | undefined)?.code === 'ENOENT'\n}\n","import { createHash, randomUUID } from 'node:crypto'\nimport { chmod, lstat, readFile, realpath, writeFile, mkdir, rename, rm, stat } from 'node:fs/promises'\nimport { realpathSync } from 'node:fs'\nimport { basename, dirname, join, resolve } from 'node:path'\nimport { isDeepStrictEqual } from 'node:util'\nimport {\n Document,\n isMap,\n isNode,\n isScalar,\n isSeq,\n parseDocument,\n visit,\n type Node,\n} from 'yaml'\nimport { AgentQaConfigSchema } from '@vostride/agent-qa-core'\nimport {\n CONFIG_NAMED_ARRAYS,\n CONFIG_REVISION_ABSENT,\n MARKER_WRITTEN_BACK_SENTENCE,\n maskPayloadTree,\n type ConfigChange,\n type ConfigPathSegment,\n type ConfigWriteIssue,\n type ConfigWriteRefusal,\n type MaskFn,\n} from '@vostride/agent-qa-schema'\n\nexport type ApplyChangesOutcome =\n | { kind: 'ok'; revision: string; baseRevision: string; priors?: ConfigPriors }\n | {\n kind: 'refused'\n error: Exclude<ConfigWriteRefusal, 'write_failed'>\n issues?: ConfigWriteIssue[]\n /** The field an `expect` found changed. */\n path?: ConfigPathSegment[]\n }\n\ntype FieldState = { present: false } | { present: true; value: unknown }\n\n/**\n * What one change found and left at the field it touched (429-11 D-24). The nodes are the file's\n * own, so a restore brings back real secrets and comments rather than anything the page holds.\n */\nexport type ConfigPrior =\n | { kind: 'entry'; array: ConfigPathSegment[]; name: string; index: number; node: Node }\n | { kind: 'path'; path: ConfigPathSegment[]; before: Node | null | undefined; after: FieldState }\n\nexport type ConfigPriors = readonly ConfigPrior[]\n\n/** A whole-document replacement, checked against the bytes the caller read (432-07 D-05). */\nexport type ReplaceDocumentOutcome =\n | { kind: 'ok'; revision: string; baseRevision: string }\n | { kind: 'refused'; error: 'file_changed'; revision: string }\n | { kind: 'refused'; error: 'marker_written_back'; message: string }\n\nexport type RestorePriorsOutcome =\n | { kind: 'ok'; revision: string }\n | { kind: 'refused'; error: 'undo_conflict' | 'file_invalid' }\n\nexport type ConfigReadOutcome =\n | { kind: 'ok'; config: Record<string, unknown>; raw: string; revision: string }\n | { kind: 'absent' }\n | { kind: 'file_invalid'; message: string; revision: string }\n\n/** One line of the config file, as the declared mask shows it. */\nexport interface ConfigFileLine {\n n: number\n text: string\n}\n\nexport type MaskedConfigOutcome =\n | {\n kind: 'ok'\n config: Record<string, unknown>\n revision: string\n lines: ConfigFileLine[]\n fileIssues: ConfigWriteIssue[]\n }\n | { kind: 'file_invalid'; message: string; revision: string }\n\n// 2026-09-30, 432-07 D-05 (EDGE-12): one write queue per resolved config path, shared by every\n// ConfigManager and direct writer in this process, so the dashboard and a co-hosted writer never\n// read the same bytes and drop each other's field. Kept on globalThis so a second copy of this\n// module still joins the same queue. It is not a cross-process lock.\nconst CONFIG_WRITE_QUEUES = Symbol.for('agent-qa.config-write-queues')\n\nfunction configWriteQueues(): Map<string, Promise<void>> {\n const holder = globalThis as { [CONFIG_WRITE_QUEUES]?: Map<string, Promise<void>> }\n holder[CONFIG_WRITE_QUEUES] ??= new Map()\n return holder[CONFIG_WRITE_QUEUES]\n}\n\n// The file itself when it exists, so a symlink and a directory alias share its queue; otherwise\n// its real directory, so a file created by the first writer keeps the key the second one used.\nfunction configWriteQueueKey(configPath: string): string {\n const absolute = resolve(configPath)\n try {\n return realpathSync(absolute)\n } catch {\n try {\n return join(realpathSync(dirname(absolute)), basename(absolute))\n } catch {\n return absolute\n }\n }\n}\n\n/** Run `work` in this path's turn. The queue moves on however `work` settles. */\nexport function serializeConfigWrite<T>(configPath: string, work: () => Promise<T>): Promise<T> {\n const queues = configWriteQueues()\n const key = configWriteQueueKey(configPath)\n const next = (queues.get(key) ?? Promise.resolve()).then(work)\n const tail = next.then(() => undefined, () => undefined)\n queues.set(key, tail)\n void tail.then(() => {\n if (queues.get(key) === tail) queues.delete(key)\n })\n return next\n}\n\nfunction isMissingFile(err: unknown): boolean {\n return (err as NodeJS.ErrnoException | undefined)?.code === 'ENOENT'\n}\n\nexport class ConfigFileInvalidError extends Error {\n constructor(message: string) {\n super(`The config file does not parse: ${message}`)\n this.name = 'ConfigFileInvalidError'\n }\n}\n\n/**\n * The config's values for a reader that only needs them (429-32, Pitfall 3): a missing file reads\n * as empty, and a file that does not parse is an error rather than the part of it yaml recovers.\n */\nexport async function readConfigValues(manager: ConfigManager): Promise<Record<string, unknown>> {\n const read = await manager.readWithRevision()\n if (read.kind === 'ok') return read.config\n if (read.kind === 'absent') return {}\n throw new ConfigFileInvalidError(read.message)\n}\n\nexport class ConfigManager {\n constructor(private configPath: string, readonly mask: MaskFn) {}\n\n // 441 GAP3-D5: a whole document may keep a marker the file already holds, as often, but never\n // add one. A missing file holds none.\n static addsShownMarker(current: Uint8Array | undefined, next: Uint8Array): boolean {\n const held = shownMarkerCounts(current)\n for (const [marker, count] of shownMarkerCounts(next)) {\n if (count > (held.get(marker) ?? 0)) return true\n }\n return false\n }\n\n // 429-05 Pitfall 3: a half-edited file is named, never served as the partial config yaml recovers.\n async readWithRevision(): Promise<ConfigReadOutcome> {\n const read = await this.readParsed()\n if (read.kind !== 'ok') return read\n return { kind: 'ok', config: read.config, raw: read.raw, revision: read.revision }\n }\n\n // 441-21 D-29: the payload and the file view pass through the declared mask and nothing else.\n async readMasked(): Promise<MaskedConfigOutcome> {\n const read = await this.readParsed()\n if (read.kind === 'absent') {\n return { kind: 'ok', config: {}, revision: CONFIG_REVISION_ABSENT, lines: [], fileIssues: [] }\n }\n if (read.kind === 'file_invalid') return { ...read, message: this.maskSummary(read.message) }\n const masked = maskDocument(read.doc, this.mask)\n const config = (masked.toJSON() as Record<string, unknown> | null) ?? {}\n const parsed = AgentQaConfigSchema.safeParse(normalizeForValidation(read.config))\n const fileIssues = parsed.success\n ? []\n : parsed.error.issues.map((issue) => maskedIssue(issue, this.mask))\n const lines = fileLines(this.mask(read.raw))\n return { kind: 'ok', config, revision: read.revision, lines, fileIssues }\n }\n\n // A file that does not parse can leave the declared secrets unreadable; its message is then withheld.\n private maskSummary(message: string): string {\n try {\n return this.mask(message)\n } catch {\n return 'The config file is not valid YAML.'\n }\n }\n\n private async readParsed(): Promise<\n | { kind: 'ok'; doc: Document; config: Record<string, unknown>; raw: string; revision: string }\n | { kind: 'absent' }\n | { kind: 'file_invalid'; message: string; revision: string }\n > {\n let bytes: Buffer\n try {\n bytes = await readFile(this.configPath)\n } catch (err: unknown) {\n if (isMissingFile(err)) return { kind: 'absent' }\n throw err\n }\n const revision = createHash('sha256').update(bytes).digest('hex')\n const raw = bytes.toString('utf-8')\n const doc = parseDocument(raw)\n if (doc.errors.length > 0) {\n return { kind: 'file_invalid', message: parseErrorSummary(doc), revision }\n }\n return {\n kind: 'ok',\n doc,\n config: (doc.toJSON() as Record<string, unknown> | null) ?? {},\n raw,\n revision,\n }\n }\n\n // 429-01 D-19/D-22: one transaction per request, serialised so overlapping autosaves never\n // read the same bytes and drop each other's field.\n async applyChanges(\n changes: readonly ConfigChange[],\n options: { capturePriors?: boolean } = {},\n ): Promise<ApplyChangesOutcome> {\n const marked = changeWithShownMarker(changes)\n if (marked !== undefined) {\n return {\n kind: 'refused',\n error: 'marker_written_back',\n issues: [{\n path: marked.path.map((segment) => (typeof segment === 'object' ? segment.name : segment)),\n message: MARKER_WRITTEN_BACK_SENTENCE,\n }],\n }\n }\n return this.serialized(() => this.applyChangesOnce(changes, options.capturePriors === true))\n }\n\n // 429-11 D-24: an Undo is one more transaction on the same mutex, newest change first. A field\n // that no longer holds what the change left there was written since, and is never overwritten.\n async restorePriors(priors: ConfigPriors): Promise<RestorePriorsOutcome> {\n return this.serialized(() => this.restorePriorsOnce(priors))\n }\n\n // 432-07 D-05: a generated whole-file change (a scaffold, a hooks file) publishes only over the\n // bytes it was built from, read again in this path's turn. Anything else is somebody's edit.\n async replaceDocument(expectedRevision: string, content: Uint8Array): Promise<ReplaceDocumentOutcome> {\n return this.serialized(async () => {\n let current: Buffer | undefined\n try {\n current = await readFile(this.configPath)\n } catch (err: unknown) {\n if (!isMissingFile(err)) throw err\n }\n const revision = current === undefined\n ? CONFIG_REVISION_ABSENT\n : createHash('sha256').update(current).digest('hex')\n if (revision !== expectedRevision) return { kind: 'refused', error: 'file_changed', revision }\n if (ConfigManager.addsShownMarker(current, content)) {\n return { kind: 'refused', error: 'marker_written_back', message: MARKER_WRITTEN_BACK_SENTENCE }\n }\n await this.writeAtomic(content)\n return { kind: 'ok', revision: createHash('sha256').update(content).digest('hex'), baseRevision: revision }\n })\n }\n\n private serialized<T>(work: () => Promise<T>): Promise<T> {\n return serializeConfigWrite(this.configPath, work)\n }\n\n private async restorePriorsOnce(priors: ConfigPriors): Promise<RestorePriorsOutcome> {\n let doc: Document\n try {\n doc = parseDocument(await readFile(this.configPath, 'utf-8'))\n } catch (err: unknown) {\n if (isMissingFile(err)) return { kind: 'refused', error: 'undo_conflict' }\n throw err\n }\n if (doc.errors.length > 0) return { kind: 'refused', error: 'file_invalid' }\n let next: string\n try {\n for (const prior of [...priors].reverse()) {\n if (!restorePrior(doc, prior)) return { kind: 'refused', error: 'undo_conflict' }\n }\n const parsed = AgentQaConfigSchema.safeParse(normalizeForValidation(doc.toJSON()))\n if (!parsed.success) return { kind: 'refused', error: 'undo_conflict' }\n next = doc.toString()\n } catch {\n // A restored node that no longer fits the file (an alias whose anchor is gone) is not restorable.\n return { kind: 'refused', error: 'undo_conflict' }\n }\n await this.writeAtomic(next)\n return { kind: 'ok', revision: revisionOf(next) }\n }\n\n private async applyChangesOnce(\n changes: readonly ConfigChange[],\n capturePriors: boolean,\n ): Promise<ApplyChangesOutcome> {\n let doc: Document\n // 429-37 CR-01: the revision of the bytes this write merges onto, so the page can tell when an\n // outside edit it never read was absorbed.\n let baseRevision: string\n try {\n const bytes = await readFile(this.configPath)\n baseRevision = createHash('sha256').update(bytes).digest('hex')\n doc = parseDocument(bytes.toString('utf-8'))\n } catch (err: unknown) {\n if (!isMissingFile(err)) throw err\n // Pitfall 2: a missing file starts empty and goes through setIn like any other, so a dotted\n // top-level key such as `use.timeout:` can never be written.\n baseRevision = CONFIG_REVISION_ABSENT\n doc = new Document()\n }\n // yaml recovers a partial tree from a broken file and refuses to stringify it: never rewrite one.\n if (doc.errors.length > 0) return { kind: 'refused', error: 'file_invalid' }\n // 429-42 CR-01: every expect is checked against the file as read, before anything applies.\n const expects = changes.filter((change) => change.op === 'expect')\n for (const change of expects) {\n if (!expectHolds(doc, change.path, change.value ?? null, this.mask)) {\n return { kind: 'refused', error: 'field_changed', path: [...change.path] }\n }\n }\n let writesBrowserHeadless = false\n const priors: ConfigPrior[] = []\n for (const change of changes) {\n if (change.op === 'expect') continue\n if (change.op === 'move') {\n const moved = moveField(doc, change.from, change.path, capturePriors)\n if (moved.kind === 'refused') return moved\n priors.push(...moved.priors)\n continue\n }\n const path = resolvePath(doc, change.path)\n if (path === undefined) return { kind: 'refused', error: 'path_not_found' }\n const entry = capturePriors ? namedEntryPrior(doc, change, path) : undefined\n const before = capturePriors && entry === undefined ? nodeAt(doc, path) : undefined\n let legacyPrior: ConfigPrior | undefined\n try {\n if (change.op === 'set') {\n doc.setIn(path, doc.createNode(change.value))\n writesBrowserHeadless ||= setsLeaf(path, change.value, BROWSER_HEADLESS_PATH)\n } else if (change.op === 'set-if-absent') {\n // Required-sibling completion is decided by the file at this point of the transaction.\n if (doc.hasIn(path)) continue\n if (samePath(path, BROWSER_HEADLESS_PATH) && doc.hasIn(LEGACY_HEADLESS_PATH)) {\n // The owner's root use.headless is the value completion keeps, under its new key.\n const legacy = nodeAt(doc, LEGACY_HEADLESS_PATH)\n doc.setIn(path, legacy === undefined || legacy === null ? null : legacy)\n if (capturePriors) {\n legacyPrior = { kind: 'path', path: [...LEGACY_HEADLESS_PATH], before: legacy, after: { present: false } }\n }\n doc.deleteIn(LEGACY_HEADLESS_PATH)\n } else {\n doc.setIn(path, doc.createNode(change.value))\n }\n } else if (change.op === 'unset') {\n unsetAndPrune(doc, path)\n } else if (!appendTo(doc, path, change.value)) {\n return { kind: 'refused', error: 'path_not_found' }\n }\n } catch {\n // yaml throws when a path walks through a scalar: the field the change names is not there.\n return { kind: 'refused', error: 'path_not_found' }\n }\n if (entry !== undefined) priors.push(entry)\n else if (capturePriors) {\n priors.push({ kind: 'path', path: [...change.path], before, after: fieldState(doc, path) })\n }\n if (legacyPrior !== undefined) priors.push(legacyPrior)\n }\n // The browser-scoped key replaces a root use.headless in the same write.\n if (writesBrowserHeadless && doc.hasIn(LEGACY_HEADLESS_PATH)) {\n const before = capturePriors ? nodeAt(doc, LEGACY_HEADLESS_PATH) : undefined\n doc.deleteIn(LEGACY_HEADLESS_PATH)\n if (capturePriors) {\n priors.push({ kind: 'path', path: [...LEGACY_HEADLESS_PATH], before, after: { present: false } })\n }\n }\n\n const parsed = AgentQaConfigSchema.safeParse(normalizeForValidation(doc.toJSON()))\n if (!parsed.success) {\n return {\n kind: 'refused',\n error: 'validation_failed',\n issues: parsed.error.issues.map((issue) => maskedIssue(issue, this.mask)),\n }\n }\n\n const next = doc.toString()\n await this.writeAtomic(next)\n return capturePriors\n ? { kind: 'ok', revision: revisionOf(next), baseRevision, priors }\n : { kind: 'ok', revision: revisionOf(next), baseRevision }\n }\n\n // 429-05 Pitfall 8 / Pattern 1 step 6: the temp file sits beside the real file, keeps its mode\n // (chmod, because writeFile's mode is filtered by the umask), and replaces it in one rename.\n private async writeAtomic(content: string | Uint8Array): Promise<void> {\n const target = await this.writeTarget()\n const directory = dirname(target)\n const tempPath = join(directory, `.${basename(target)}.${process.pid}.${randomUUID()}.tmp`)\n const mode = await stat(target).then(\n (stats) => stats.mode & 0o777,\n (err: unknown) => {\n if (isMissingFile(err)) return undefined\n throw err\n },\n )\n await mkdir(directory, { recursive: true })\n try {\n await writeFile(tempPath, content, mode === undefined ? undefined : { mode })\n if (mode !== undefined) await chmod(tempPath, mode)\n await rename(tempPath, target)\n } catch (error) {\n await rm(tempPath, { force: true }).catch(() => undefined)\n throw error\n }\n }\n\n // A symlinked config keeps its link: the file it points at is the one replaced.\n private async writeTarget(): Promise<string> {\n const isLink = await lstat(this.configPath).then(\n (stats) => stats.isSymbolicLink(),\n (err: unknown) => {\n if (isMissingFile(err)) return false\n throw err\n },\n )\n return isLink ? await realpath(this.configPath) : this.configPath\n }\n}\n\n// 441 GAP-D7 (CR-D01): a read shows a declared secret as `[secret:<name>]`. A change carrying that\n// text would write the marker over the real value, or address an entry by a name the file lacks.\nconst SHOWN_MARKER = /\\[secret:\\w+\\]/\n\nexport function holdsShownMarker(value: unknown): boolean {\n if (typeof value === 'string') return SHOWN_MARKER.test(value)\n if (Array.isArray(value)) return value.some(holdsShownMarker)\n if (value !== null && typeof value === 'object') {\n return Object.entries(value).some(\n ([key, entry]) => SHOWN_MARKER.test(key) || holdsShownMarker(entry),\n )\n }\n return false\n}\n\nfunction shownMarkerCounts(bytes: Uint8Array | undefined): Map<string, number> {\n const counts = new Map<string, number>()\n if (bytes === undefined) return counts\n for (const [marker] of Buffer.from(bytes).toString('utf-8').matchAll(/\\[secret:\\w+\\]/g)) {\n counts.set(marker, (counts.get(marker) ?? 0) + 1)\n }\n return counts\n}\n\nfunction pathHoldsShownMarker(path: readonly ConfigPathSegment[]): boolean {\n return path.some((segment) => (typeof segment === 'object'\n ? SHOWN_MARKER.test(segment.name)\n : typeof segment === 'string' && SHOWN_MARKER.test(segment)))\n}\n\n// 441 GAP2-D4: an expect writes nothing, so only the ops that write are checked.\nfunction changeWithShownMarker(changes: readonly ConfigChange[]): ConfigChange | undefined {\n return changes.find((change) => {\n if (change.op === 'expect') return false\n if (pathHoldsShownMarker(change.path)) return true\n if (change.op === 'move') return pathHoldsShownMarker(change.from)\n return change.op !== 'unset' && holdsShownMarker(change.value)\n })\n}\n\n// 441 GAP-D5: a key segment is config text, so it passes the declared mask with the message.\nfunction maskedIssue(\n issue: { path: readonly PropertyKey[]; message: string },\n mask: MaskFn,\n): ConfigWriteIssue {\n return {\n path: issue.path.map((key) => (typeof key === 'number' ? key : mask(String(key)))),\n message: mask(issue.message),\n }\n}\n\ntype ResolvedPath = (string | number)[]\n\nconst NAMED_ARRAY_PATHS: readonly (readonly string[])[] = CONFIG_NAMED_ARRAYS.map((named) => named.split('.'))\nconst BROWSER_HEADLESS_PATH = ['use', 'browser', 'headless']\nconst LEGACY_HEADLESS_PATH = ['use', 'headless']\n\nfunction samePath(a: readonly (string | number)[], b: readonly (string | number)[]): boolean {\n return a.length === b.length && a.every((segment, i) => segment === b[i])\n}\n\n// A { name } segment is resolved to the index its entry has in the file now, and only inside the\n// named arrays, so an outside reorder can never redirect a change to another entry.\nfunction resolvePath(doc: Document, path: readonly ConfigPathSegment[]): ResolvedPath | undefined {\n const resolved: ResolvedPath = []\n for (const segment of path) {\n if (typeof segment !== 'object') {\n resolved.push(segment)\n continue\n }\n if (!NAMED_ARRAY_PATHS.some((named) => samePath(named, resolved))) return undefined\n const seq = doc.getIn(resolved, true)\n if (!isSeq(seq)) return undefined\n const index = seq.items.findIndex((item) => isMap(item) && item.get('name') === segment.name)\n if (index < 0) return undefined\n resolved.push(index)\n }\n return resolved\n}\n\n// Deleting a leaf leaves `parent: {}`, which a section schema can reject, so every ancestor map the\n// delete empties goes too. A sequence entry is never pruned: that would shift its siblings.\nfunction unsetAndPrune(doc: Document, path: ResolvedPath): void {\n if (!doc.hasIn(path)) return\n doc.deleteIn(path)\n for (let depth = path.length - 1; depth >= 1; depth--) {\n const ancestor = path.slice(0, depth)\n if (typeof ancestor[depth - 1] !== 'string') return\n const node = doc.getIn(ancestor, true)\n if (!isMap(node) || node.items.length > 0) return\n doc.deleteIn(ancestor)\n }\n}\n\n// 429-52: a rename re-keys the file's own node, which lands before from is pruned.\nfunction moveField(\n doc: Document,\n from: readonly ConfigPathSegment[],\n to: readonly ConfigPathSegment[],\n capturePriors: boolean,\n): { kind: 'ok'; priors: ConfigPrior[] } | { kind: 'refused'; error: 'path_not_found' | 'path_not_writable' } {\n const fromPath = resolvePath(doc, from)\n const toPath = resolvePath(doc, to)\n if (fromPath === undefined || toPath === undefined) return { kind: 'refused', error: 'path_not_found' }\n const node = nodeAt(doc, fromPath)\n if (node === undefined) return { kind: 'refused', error: 'path_not_found' }\n if (samePath(fromPath, toPath)) return { kind: 'ok', priors: [] }\n // A field moved inside itself, or onto an ancestor, would be deleted with its old key.\n if (isPrefix(fromPath, toPath) || isPrefix(toPath, fromPath)) {\n return { kind: 'refused', error: 'path_not_writable' }\n }\n const before = capturePriors ? nodeAt(doc, toPath) : undefined\n try {\n doc.setIn(toPath, node)\n } catch {\n return { kind: 'refused', error: 'path_not_found' }\n }\n unsetAndPrune(doc, fromPath)\n if (!capturePriors) return { kind: 'ok', priors: [] }\n return {\n kind: 'ok',\n priors: [\n { kind: 'path', path: [...from], before: node === null ? null : node.clone() as Node, after: { present: false } },\n { kind: 'path', path: [...to], before, after: fieldState(doc, toPath) },\n ],\n }\n}\n\nfunction isPrefix(prefix: ResolvedPath, path: ResolvedPath): boolean {\n return prefix.length < path.length && samePath(prefix, path.slice(0, prefix.length))\n}\n\n// An unset of one named-array entry is recorded as the entry itself, so Undo re-inserts it by\n// name at its index instead of comparing the whole list.\nfunction namedEntryPrior(doc: Document, change: ConfigChange, path: ResolvedPath): ConfigPrior | undefined {\n const last = change.path[change.path.length - 1]\n if (change.op !== 'unset' || typeof last !== 'object') return undefined\n const index = path[path.length - 1]\n const node = doc.getIn(path, true)\n if (typeof index !== 'number' || !isNode(node)) return undefined\n return { kind: 'entry', array: change.path.slice(0, -1), name: last.name, index, node: node.clone() as Node }\n}\n\n// undefined: the field is absent. null: the key is there with no value.\nfunction nodeAt(doc: Document, path: ResolvedPath): Node | null | undefined {\n if (!doc.hasIn(path)) return undefined\n const node = doc.getIn(path, true)\n if (isNode(node)) return node.clone() as Node\n return node === undefined || node === null ? null : doc.createNode(node)\n}\n\nfunction fieldState(doc: Document, path: ResolvedPath): FieldState {\n if (!doc.hasIn(path)) return { present: false }\n const node = doc.getIn(path, true)\n return { present: true, value: isNode(node) ? node.toJS(doc) : node ?? null }\n}\n\n// What an expect compares against: the field's value as the file holds it, null when absent. A\n// selector naming no entry, or a path through a scalar, reads as absent.\nfunction expectedFieldValue(doc: Document, path: readonly ConfigPathSegment[]): unknown {\n const resolved = resolvePath(doc, path)\n if (resolved === undefined) return null\n const state = fieldState(doc, resolved)\n return state.present ? state.value : null\n}\n\n// 441 GAP2-D4: the page builds an expect from the masked read, so it also holds when it equals the\n// field as the declared mask shows it. A mask that throws matches nothing.\nfunction expectHolds(\n doc: Document,\n path: readonly ConfigPathSegment[],\n offered: unknown,\n mask: MaskFn,\n): boolean {\n const held = expectedFieldValue(doc, path)\n if (isDeepStrictEqual(held, offered)) return true\n try {\n return isDeepStrictEqual(maskPayloadTree(held, mask), offered)\n } catch {\n return false\n }\n}\n\nfunction restorePrior(doc: Document, prior: ConfigPrior): boolean {\n if (prior.kind === 'entry') {\n const arrayPath = resolvePath(doc, prior.array)\n if (arrayPath === undefined) return false\n const seq = doc.getIn(arrayPath, true)\n if (seq === undefined || seq === null || (isScalar(seq) && seq.value === null)) {\n doc.setIn(arrayPath, doc.createNode([]))\n return restorePrior(doc, prior)\n }\n if (!isSeq(seq)) return false\n if (seq.items.some((item) => isMap(item) && item.get('name') === prior.name)) return false\n seq.items.splice(Math.min(prior.index, seq.items.length), 0, prior.node.clone())\n return true\n }\n const path = resolvePath(doc, prior.path)\n if (path === undefined) return false\n if (!isDeepStrictEqual(fieldState(doc, path), prior.after)) return false\n if (prior.before === undefined) unsetAndPrune(doc, path)\n else doc.setIn(path, prior.before === null ? null : prior.before.clone())\n return true\n}\n\nfunction appendTo(doc: Document, path: ResolvedPath, value: unknown): boolean {\n const existing = doc.getIn(path, true)\n if (existing === undefined || existing === null || (isScalar(existing) && existing.value === null)) {\n doc.setIn(path, doc.createNode([value]))\n return true\n }\n if (!isSeq(existing)) return false\n existing.add(doc.createNode(value))\n return true\n}\n\nfunction setsLeaf(path: ResolvedPath, value: unknown, leaf: readonly string[]): boolean {\n if (path.length > leaf.length || !samePath(path, leaf.slice(0, path.length))) return false\n let cursor = value\n for (const key of leaf.slice(path.length)) {\n if (typeof cursor !== 'object' || cursor === null || Array.isArray(cursor)) return false\n cursor = (cursor as Record<string, unknown>)[key]\n }\n return cursor !== undefined\n}\n\n// The first line only: yaml's message goes on to quote the offending source line, which can be a\n// secret the page must not be served.\nfunction parseErrorSummary(doc: Document): string {\n const first = doc.errors[0]?.message ?? 'The config file is not valid YAML.'\n return first.split('\\n')[0]!.replace(/:\\s*$/, '')\n}\n\n// Every scalar, key or value, is replaced by what the mask shows for it. An alias reads its masked anchor.\nfunction maskDocument(doc: Document, mask: MaskFn): Document {\n const masked = doc.clone()\n visit(masked, {\n Scalar(_key, node) {\n if (node.value === null || node.value === undefined) return\n const text = String(node.value)\n const shown = mask(text)\n if (shown !== text) node.value = shown\n },\n })\n return masked\n}\n\nfunction fileLines(text: string): ConfigFileLine[] {\n const texts = text.split('\\n')\n if (texts.length > 0 && texts[texts.length - 1] === '') texts.pop()\n return texts.map((lineText, i) => ({ n: i + 1, text: lineText }))\n}\n\nfunction revisionOf(content: string): string {\n return createHash('sha256').update(content, 'utf-8').digest('hex')\n}\n\n// Mirrors cli/src/config.ts normalizeConfigForValidation: a root use.headless is read by the CLI\n// and dropped before validation, so it must not fail a dashboard write either.\nfunction normalizeForValidation(config: unknown): unknown {\n if (typeof config !== 'object' || config === null || Array.isArray(config)) return config\n const normalized = { ...(config as Record<string, unknown>) }\n const use = normalized.use\n if (typeof use === 'object' && use !== null && !Array.isArray(use)) {\n const rest = { ...(use as Record<string, unknown>) }\n delete rest.headless\n normalized.use = rest\n }\n return normalized\n}\n","// 2026-09-26, 429-11 D-24: the server half of Undo. A payload can hold a removed secret, so it\n// stays in this process's memory, is handed out once, and is never serialized into a response.\nimport { randomUUID } from 'node:crypto'\n\nimport type { ConfigPriors } from './config-manager.js'\n\n/** How long a token stays redeemable: longer than the page's 10 s Undo link, so a late click lands. */\nexport const UNDO_RETENTION_MS = 30_000\n\n/** What a token redeems: the priors of an undoable config write, or a removed auth.json entry. */\nexport type UndoPayload =\n | { kind: 'config'; priors: ConfigPriors }\n | { kind: 'credential'; name: string; credential: unknown }\n\nexport interface UndoTicket {\n token: string\n expiresAt: number\n}\n\nexport interface UndoStore {\n put(payload: UndoPayload, now: number): UndoTicket\n /** The payload once; a second take, an unknown token or an expired one answers undefined. */\n take(token: string, now: number): UndoPayload | undefined\n}\n\nexport function createUndoStore(options: { retentionMs: number }): UndoStore {\n const entries = new Map<string, { payload: UndoPayload; expiresAt: number }>()\n\n function prune(now: number): void {\n for (const [token, entry] of entries) {\n if (entry.expiresAt <= now) entries.delete(token)\n }\n }\n\n return {\n put(payload, now) {\n prune(now)\n const token = randomUUID()\n const expiresAt = now + options.retentionMs\n entries.set(token, { payload, expiresAt })\n return { token, expiresAt }\n },\n take(token, now) {\n prune(now)\n const entry = entries.get(token)\n if (entry === undefined) return undefined\n entries.delete(token)\n return entry.payload\n },\n }\n}\n","import { mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises'\nimport { basename, dirname, isAbsolute, relative, resolve } from 'node:path'\n\nimport { HooksFileSchema, isPathInsideDir, parseHooksFile, resolveWorkspacePaths } from '@vostride/agent-qa-core'\nimport type { AgentQaConfig, HooksFileConfig } from '@vostride/agent-qa-core'\nimport { generateHookId } from '@vostride/agent-qa-ids'\nimport { parse as parseYaml, parseDocument } from 'yaml'\n\nimport { readConfigValues, type ConfigManager } from '../config/config-manager.js'\nimport type {\n HookCatalogResponse,\n HookCatalogRow,\n HookDeleteResult,\n HookDetailResponse,\n HookDraftValidationResult,\n HookFieldError,\n HookFieldName,\n HookMutationRequest,\n HookPrepareResult,\n HookRegistryReadError,\n} from './hook-registry-types.js'\nimport { scanHookReferences } from './hook-reference-scan.js'\n\ntype ParsedHookDefinition = HooksFileConfig['hooks'][number]\ntype AuthoredHookDefinition = Omit<ParsedHookDefinition, 'timeout'> & {\n timeout: string\n}\ntype HooksFileParseData = { hooks: ParsedHookDefinition[] }\ntype ZodIssueLike = { path: PropertyKey[]; message: string }\n\ninterface HookRegistryLocation {\n filePath: string\n resolvedFilePath: string\n hooksBaseDir: string\n}\n\ninterface HookRegistryState extends HookRegistryLocation {\n hooks: ParsedHookDefinition[]\n errors: HookRegistryReadError[]\n missing: boolean\n}\n\ninterface HookRegistryMutationState extends HookRegistryLocation {\n hooks: AuthoredHookDefinition[]\n raw: string | null\n existed: boolean\n}\n\ninterface HookFileState {\n resolvedFilePath: string | null\n fileMissing: boolean\n fieldErrors: HookFieldError[]\n}\n\ninterface HookMutationResolvedPayload {\n hook: Record<string, unknown> & { id: string }\n source: string\n}\n\ninterface HookMutationPlan {\n nextHook: ParsedHookDefinition\n nextSourcePath: string\n oldSourcePath: string | null\n oldSourceContent: string | null\n oldSourceExisted: boolean\n removeOldSourcePath: boolean\n projectedHooks: AuthoredHookDefinition[]\n}\n\nclass HookRegistryMutationError extends Error {\n readonly code: string\n readonly fieldErrors: HookFieldError[]\n\n constructor(code: string, fieldErrors: HookFieldError[], message = code) {\n super(message)\n this.code = code\n this.fieldErrors = fieldErrors\n }\n}\n\nexport function isHookRegistryMutationError(error: unknown): error is {\n code: string\n fieldErrors: HookFieldError[]\n} {\n return error instanceof HookRegistryMutationError\n}\n\nexport class HookRegistryManager {\n constructor(\n private readonly configManager: ConfigManager,\n private readonly configPath: string,\n ) {}\n\n async readCatalog(): Promise<HookCatalogResponse> {\n const registry = await this.readRegistryState()\n if (registry.missing || registry.errors.length > 0) {\n return {\n hooks: [],\n filePath: registry.filePath,\n errors: registry.errors.map((error) => error.message),\n missing: registry.missing,\n }\n }\n\n const hooks = await Promise.all(\n registry.hooks.map(async (hook) => {\n const fileState = await this.inspectHookFile(hook.file, registry.hooksBaseDir)\n return this.toCatalogRow(hook, fileState.fileMissing)\n }),\n )\n\n return {\n hooks,\n filePath: registry.filePath,\n errors: [],\n missing: false,\n }\n }\n\n async readHook(hookId: string): Promise<HookDetailResponse | null> {\n const registry = await this.readRegistryState()\n if (registry.missing || registry.errors.length > 0) {\n return null\n }\n\n const hook = registry.hooks.find((candidate) => candidate.id === hookId)\n if (!hook) {\n return null\n }\n\n const fileState = await this.inspectHookFile(hook.file, registry.hooksBaseDir)\n let source: string | null = null\n\n if (fileState.resolvedFilePath && fileState.fieldErrors.length === 0) {\n source = await readFile(fileState.resolvedFilePath, 'utf-8')\n }\n\n return {\n hook: this.toCatalogRow(hook, fileState.fileMissing),\n source,\n fieldErrors: fileState.fieldErrors,\n }\n }\n\n async createHook(payload: HookMutationRequest): Promise<HookDetailResponse> {\n const registry = await this.readRegistryForMutation()\n const resolvedPayload = this.resolveMutationPayload(payload, {\n generatedId: generateHookId(),\n })\n const plan = await this.planHookMutation(registry, resolvedPayload.hook.id, resolvedPayload, 'create')\n\n await this.persistHookMutation(registry, plan, resolvedPayload.source)\n\n return {\n hook: this.toCatalogRow(plan.nextHook, false),\n source: resolvedPayload.source,\n fieldErrors: [],\n }\n }\n\n async updateHook(hookId: string, payload: HookMutationRequest): Promise<HookDetailResponse> {\n const registry = await this.readRegistryForMutation()\n const existingHook = registry.hooks.find((candidate) => candidate.id === hookId)\n if (!existingHook) {\n throw new HookRegistryMutationError('hook_not_found', [\n {\n field: 'id',\n code: 'hook_not_found',\n message: 'Hook not found',\n },\n ])\n }\n\n const resolvedPayload = this.resolveMutationPayload(payload, {\n expectedId: hookId,\n generatedId: hookId,\n })\n const plan = await this.planHookMutation(registry, hookId, resolvedPayload, 'update')\n\n await this.persistHookMutation(registry, plan, resolvedPayload.source)\n\n return {\n hook: this.toCatalogRow(plan.nextHook, false),\n source: resolvedPayload.source,\n fieldErrors: [],\n }\n }\n\n async deleteHook(\n hookId: string,\n options: { force?: boolean } = {},\n ): Promise<HookDeleteResult> {\n const registry = await this.readRegistryForMutation()\n const existingHook = registry.hooks.find((candidate) => candidate.id === hookId)\n if (!existingHook) {\n throw new HookRegistryMutationError('hook_not_found', [\n {\n field: 'id',\n code: 'hook_not_found',\n message: 'Hook not found',\n },\n ])\n }\n\n const references = await scanHookReferences(dirname(this.configPath), this.configPath, hookId)\n if (references.length > 0 && !options.force) {\n return {\n deleted: false,\n references,\n }\n }\n\n const nextHooks = registry.hooks.filter((candidate) => candidate.id !== hookId)\n const nextRegistryContent = nextHooks.length > 0\n ? this.serializeHooksDocument(registry.raw, nextHooks)\n : null\n const sourcePath = resolve(registry.hooksBaseDir, existingHook.file)\n const sourceSnapshot = await this.readOptionalFile(sourcePath)\n const sourcePathStillReferenced = nextHooks.some(\n (candidate) => resolve(registry.hooksBaseDir, candidate.file) === sourcePath,\n )\n\n try {\n if (nextRegistryContent === null) {\n await rm(registry.resolvedFilePath, { force: true })\n } else {\n await mkdir(dirname(registry.resolvedFilePath), { recursive: true })\n await writeFile(registry.resolvedFilePath, nextRegistryContent, 'utf-8')\n }\n\n if (sourceSnapshot.exists && !sourcePathStillReferenced) {\n await rm(sourcePath, { force: true })\n }\n\n return {\n deleted: true,\n references,\n }\n } catch (error) {\n await this.restoreRegistrySnapshot(registry)\n\n if (sourceSnapshot.exists && sourceSnapshot.content !== null) {\n await mkdir(dirname(sourcePath), { recursive: true })\n await writeFile(sourcePath, sourceSnapshot.content, 'utf-8')\n }\n\n throw error\n }\n }\n\n async validateDraft(draft: unknown): Promise<HookDraftValidationResult> {\n const location = await this.resolveRegistryLocation()\n const normalizedDraft = this.normalizeDraftForSchema(draft)\n const result = HooksFileSchema.safeParse(normalizedDraft)\n\n if (!result.success) {\n return {\n valid: false,\n fieldErrors: result.error.issues.map((issue: ZodIssueLike) => this.toValidationFieldError(issue.path, issue.message)),\n warnings: [],\n }\n }\n const hooksFile = result.data as HooksFileParseData\n\n const fieldErrors: HookFieldError[] = []\n const warnings: HookFieldError[] = []\n\n for (const hook of hooksFile.hooks) {\n if (isAbsolute(hook.file)) {\n fieldErrors.push({\n field: 'file',\n code: 'absolute_path',\n message: 'Hook file must be relative to the configured hooks file',\n })\n continue\n }\n\n if (!isPathInsideDir(hook.file, location.hooksBaseDir)) {\n fieldErrors.push({\n field: 'file',\n code: 'unsafe_path',\n message: 'Hook file must stay inside the configured hooks file directory',\n })\n continue\n }\n\n const fileState = await this.inspectHookFile(hook.file, location.hooksBaseDir)\n warnings.push(...fileState.fieldErrors.filter((error) => error.code === 'file_missing'))\n }\n\n return {\n valid: fieldErrors.length === 0,\n fieldErrors,\n warnings,\n }\n }\n\n async prepareForExecution(): Promise<HookPrepareResult> {\n const registry = await this.readRegistryState()\n if (registry.missing) {\n return {\n resolvedHooks: new Map(),\n authoringIssuesById: new Map(),\n }\n }\n\n if (registry.errors.length > 0) {\n return {\n resolvedHooks: new Map(),\n hookRegistryError: registry.errors.map((error) => error.message).join('; '),\n authoringIssuesById: new Map(),\n }\n }\n\n const parsedHooks = await parseHooksFile(registry.resolvedFilePath)\n if (parsedHooks.errors.length > 0) {\n return {\n resolvedHooks: new Map(),\n hookRegistryError: parsedHooks.errors.join('; '),\n authoringIssuesById: new Map(),\n }\n }\n\n const resolvedHooksById = new Map(parsedHooks.hooks.map((hook) => [hook.id, hook]))\n const resolvedHooks = new Map<typeof resolvedHooksById extends Map<infer K, infer V> ? K : never, typeof resolvedHooksById extends Map<infer K, infer V> ? V : never>()\n const authoringIssuesById = new Map<string, HookFieldError[]>()\n\n for (const hook of registry.hooks) {\n const fileState = await this.inspectHookFile(hook.file, registry.hooksBaseDir)\n const resolvedHook = resolvedHooksById.get(hook.id)\n if (!resolvedHook) {\n continue\n }\n\n if (fileState.fieldErrors.length > 0) {\n authoringIssuesById.set(hook.id, fileState.fieldErrors)\n continue\n }\n\n resolvedHooks.set(hook.id, resolvedHook)\n }\n\n return {\n resolvedHooks,\n authoringIssuesById,\n }\n }\n\n private async readRegistryForMutation(): Promise<HookRegistryMutationState> {\n const location = await this.resolveRegistryLocation()\n\n let raw: string | null = null\n try {\n raw = await readFile(location.resolvedFilePath, 'utf-8')\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n ...location,\n hooks: [],\n raw: null,\n existed: false,\n }\n }\n throw error\n }\n\n let parsed: unknown\n try {\n parsed = parseYaml(raw)\n } catch (error: unknown) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_registry',\n message: `Invalid YAML in hooks file: ${(error as Error).message}`,\n },\n ])\n }\n\n const result = HooksFileSchema.safeParse(parsed)\n if (!result.success) {\n throw new HookRegistryMutationError(\n 'validation_failed',\n result.error.issues.map((issue: ZodIssueLike) => this.toValidationFieldError(issue.path, issue.message)),\n )\n }\n\n const hooksFile = result.data as HooksFileParseData\n const pathErrors = hooksFile.hooks.flatMap((hook, index) => {\n const error = this.getAuthoredPathReadError(hook.file, location.hooksBaseDir, index)\n return error ? [this.toMutationFieldError(error)] : []\n })\n if (pathErrors.length > 0) {\n throw new HookRegistryMutationError('validation_failed', pathErrors)\n }\n\n return {\n ...location,\n hooks: this.toAuthoredHookDefinitions(parsed, hooksFile.hooks),\n raw,\n existed: true,\n }\n }\n\n private resolveMutationPayload(\n payload: HookMutationRequest,\n options: { expectedId?: string; generatedId: string },\n ): HookMutationResolvedPayload {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_payload',\n message: 'Hook mutation payload is required',\n },\n ])\n }\n\n if (typeof payload.source !== 'string') {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_source',\n message: 'Hook source must be a string',\n },\n ])\n }\n\n const hookValue = payload.hook\n if (!hookValue || typeof hookValue !== 'object' || Array.isArray(hookValue)) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_hook',\n message: 'Hook payload is required',\n },\n ])\n }\n\n const providedId = typeof hookValue.id === 'string' && hookValue.id.trim().length > 0\n ? hookValue.id.trim()\n : undefined\n if (options.expectedId && providedId && providedId !== options.expectedId) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'id',\n code: 'id_mismatch',\n message: 'Hook id in body must match the route parameter',\n },\n ])\n }\n\n return {\n hook: {\n id: providedId ?? options.generatedId,\n name: hookValue.name as string,\n runtime: hookValue.runtime as ParsedHookDefinition['runtime'],\n file: hookValue.file as string,\n timeout: hookValue.timeout as string | number,\n network: hookValue.network as boolean | undefined,\n },\n source: payload.source,\n }\n }\n\n private async planHookMutation(\n registry: HookRegistryMutationState,\n hookId: string,\n payload: HookMutationResolvedPayload,\n mode: 'create' | 'update',\n ): Promise<HookMutationPlan> {\n const existingHook = mode === 'update'\n ? registry.hooks.find((candidate) => candidate.id === hookId) ?? null\n : null\n\n const projectedHooks: Array<Record<string, unknown> | AuthoredHookDefinition> = mode === 'update'\n ? [...registry.hooks.filter((candidate) => candidate.id !== hookId), payload.hook]\n : [...registry.hooks, payload.hook]\n const validated = this.validateProjectedHooks(projectedHooks, registry.hooksBaseDir)\n if (!validated.valid) {\n throw new HookRegistryMutationError('validation_failed', validated.fieldErrors)\n }\n\n const nextHook = validated.parsedHooks.find((candidate) => candidate.id === payload.hook.id)\n if (!nextHook) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'registry',\n code: 'invalid_registry',\n message: 'Hook could not be projected into the configured hooks file',\n },\n ])\n }\n\n const nextSourcePath = resolve(registry.hooksBaseDir, nextHook.file)\n const oldSourcePath = existingHook ? resolve(registry.hooksBaseDir, existingHook.file) : null\n const oldSourceSnapshot = existingHook && oldSourcePath\n ? await this.readOptionalFile(oldSourcePath)\n : { exists: false, content: null as string | null }\n\n if (mode === 'create') {\n const nextExists = await this.readOptionalFile(nextSourcePath)\n if (nextExists.exists) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'file',\n code: 'collision',\n message: 'Hook file already exists at that path',\n },\n ])\n }\n }\n\n if (mode === 'update' && oldSourcePath !== nextSourcePath) {\n const nextExists = await this.readOptionalFile(nextSourcePath)\n if (nextExists.exists) {\n throw new HookRegistryMutationError('validation_failed', [\n {\n field: 'file',\n code: 'collision',\n message: 'Hook file already exists at that path',\n },\n ])\n }\n }\n\n return {\n nextHook,\n nextSourcePath,\n oldSourcePath,\n oldSourceContent: oldSourceSnapshot.content,\n oldSourceExisted: oldSourceSnapshot.exists,\n removeOldSourcePath: Boolean(\n oldSourcePath &&\n oldSourcePath !== nextSourcePath &&\n oldSourceSnapshot.exists &&\n !validated.authoredHooks.some(\n (candidate) =>\n candidate.id !== hookId &&\n resolve(registry.hooksBaseDir, candidate.file) === oldSourcePath,\n ),\n ),\n projectedHooks: validated.authoredHooks,\n }\n }\n\n private validateProjectedHooks(\n hooks: Array<Record<string, unknown> | AuthoredHookDefinition>,\n hooksBaseDir: string,\n ): {\n valid: boolean\n parsedHooks: ParsedHookDefinition[]\n authoredHooks: AuthoredHookDefinition[]\n fieldErrors: HookFieldError[]\n } {\n const rawFieldErrors = this.collectRawHookFieldErrors(hooks, hooksBaseDir)\n const normalizedDraft = this.normalizeDraftForSchema({ hooks })\n const result = HooksFileSchema.safeParse(normalizedDraft)\n\n if (!result.success) {\n return {\n valid: false,\n parsedHooks: [],\n authoredHooks: [],\n fieldErrors: this.dedupeFieldErrors([\n ...rawFieldErrors,\n ...result.error.issues.map((issue: ZodIssueLike) => this.toValidationFieldError(issue.path, issue.message)),\n ]),\n }\n }\n\n const hooksFile = result.data as HooksFileParseData\n const pathErrors = hooksFile.hooks.flatMap((hook, index) => {\n const error = this.getAuthoredPathReadError(hook.file, hooksBaseDir, index)\n return error ? [this.toMutationFieldError(error)] : []\n })\n\n return {\n valid: pathErrors.length === 0,\n parsedHooks: hooksFile.hooks,\n authoredHooks: this.toAuthoredHookDefinitions({ hooks }, hooksFile.hooks),\n fieldErrors: this.dedupeFieldErrors([\n ...rawFieldErrors,\n ...pathErrors,\n ]),\n }\n }\n\n private async persistHookMutation(\n registry: HookRegistryMutationState,\n plan: HookMutationPlan,\n source: string,\n ): Promise<void> {\n const nextRegistryContent = this.serializeHooksDocument(registry.raw, plan.projectedHooks)\n\n try {\n await mkdir(dirname(plan.nextSourcePath), { recursive: true })\n await writeFile(plan.nextSourcePath, source, 'utf-8')\n await mkdir(dirname(registry.resolvedFilePath), { recursive: true })\n await writeFile(registry.resolvedFilePath, nextRegistryContent, 'utf-8')\n\n if (plan.removeOldSourcePath && plan.oldSourcePath) {\n await rm(plan.oldSourcePath)\n }\n } catch (error) {\n await this.restoreRegistrySnapshot(registry)\n await this.restoreSourceSnapshot(plan)\n throw error\n }\n }\n\n private async restoreRegistrySnapshot(registry: HookRegistryMutationState): Promise<void> {\n if (!registry.existed || registry.raw === null) {\n await rm(registry.resolvedFilePath, { force: true })\n return\n }\n\n await writeFile(registry.resolvedFilePath, registry.raw, 'utf-8')\n }\n\n private async restoreSourceSnapshot(plan: HookMutationPlan): Promise<void> {\n if (plan.oldSourcePath === plan.nextSourcePath) {\n if (plan.oldSourceExisted && plan.oldSourceContent !== null) {\n await mkdir(dirname(plan.nextSourcePath), { recursive: true })\n await writeFile(plan.nextSourcePath, plan.oldSourceContent, 'utf-8')\n return\n }\n\n await rm(plan.nextSourcePath, { force: true })\n return\n }\n\n await rm(plan.nextSourcePath, { force: true })\n }\n\n private serializeHooksDocument(\n raw: string | null,\n hooks: AuthoredHookDefinition[],\n ): string {\n const doc = parseDocument(raw ?? '{}')\n doc.setIn(['hooks'], doc.createNode(hooks))\n return doc.toString()\n }\n\n private async readOptionalFile(path: string): Promise<{ exists: boolean; content: string | null }> {\n try {\n return {\n exists: true,\n content: await readFile(path, 'utf-8'),\n }\n } catch (error: unknown) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n exists: false,\n content: null,\n }\n }\n throw error\n }\n }\n\n private collectRawHookFieldErrors(\n hooks: Array<Record<string, unknown> | AuthoredHookDefinition>,\n hooksBaseDir: string,\n ): HookFieldError[] {\n const fieldErrors: HookFieldError[] = []\n const ids = new Set<string>()\n const names = new Set<string>()\n\n for (const hook of hooks) {\n if (!hook || typeof hook !== 'object' || Array.isArray(hook)) {\n continue\n }\n\n const hookRecord = hook as Record<string, unknown>\n if (typeof hookRecord.id === 'string') {\n if (ids.has(hookRecord.id)) {\n fieldErrors.push({\n field: 'id',\n code: 'duplicate_id',\n message: `Duplicate hook id: \"${hookRecord.id}\"`,\n })\n } else {\n ids.add(hookRecord.id)\n }\n }\n\n if (typeof hookRecord.name === 'string') {\n if (names.has(hookRecord.name)) {\n fieldErrors.push({\n field: 'name',\n code: 'duplicate_name',\n message: `Duplicate hook name: \"${hookRecord.name}\"`,\n })\n } else {\n names.add(hookRecord.name)\n }\n }\n\n if (typeof hookRecord.file === 'string') {\n if (isAbsolute(hookRecord.file)) {\n fieldErrors.push({\n field: 'file',\n code: 'absolute_path',\n message: 'Hook file must be relative to the configured hooks file',\n })\n } else if (!isPathInsideDir(hookRecord.file, hooksBaseDir)) {\n fieldErrors.push({\n field: 'file',\n code: 'unsafe_path',\n message: 'Hook file must stay inside the configured hooks file directory',\n })\n }\n }\n }\n\n return fieldErrors\n }\n\n private dedupeFieldErrors(fieldErrors: HookFieldError[]): HookFieldError[] {\n const seen = new Set<string>()\n return fieldErrors.filter((error) => {\n const key = `${error.field}:${error.code}:${error.message}`\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n }\n\n private async readRegistryState(): Promise<HookRegistryState> {\n const location = await this.resolveRegistryLocation()\n\n try {\n await stat(location.resolvedFilePath)\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n ...location,\n hooks: [],\n errors: [{ code: 'hooks_file_missing', message: `configured hooks file not found: ${location.filePath}` }],\n missing: true,\n }\n }\n throw err\n }\n\n const raw = await readFile(location.resolvedFilePath, 'utf-8')\n\n let parsed: unknown\n try {\n parsed = parseYaml(raw)\n } catch (err: unknown) {\n return {\n ...location,\n hooks: [],\n errors: [{ code: 'invalid_yaml', message: `Invalid YAML in hooks file: ${(err as Error).message}` }],\n missing: false,\n }\n }\n\n const result = HooksFileSchema.safeParse(parsed)\n if (!result.success) {\n return {\n ...location,\n hooks: [],\n errors: result.error.issues.map((issue: ZodIssueLike) => ({\n code: 'invalid_registry',\n message: `${issue.path.map(String).join('.')}: ${issue.message}`,\n })),\n missing: false,\n }\n }\n\n const hooksFile = result.data as HooksFileParseData\n const pathErrors = hooksFile.hooks\n .map((hook, index) => this.getAuthoredPathReadError(hook.file, location.hooksBaseDir, index))\n .filter((error): error is HookRegistryReadError => error !== null)\n\n if (pathErrors.length > 0) {\n return {\n ...location,\n hooks: [],\n errors: pathErrors,\n missing: false,\n }\n }\n\n return {\n ...location,\n hooks: hooksFile.hooks,\n errors: [],\n missing: false,\n }\n }\n\n private async resolveRegistryLocation(): Promise<HookRegistryLocation> {\n const config = await readConfigValues(this.configManager) as AgentQaConfig\n const workspacePaths = resolveWorkspacePaths({ config, configPath: this.configPath })\n const configuredPath = workspacePaths.hooksFile.configuredPath\n const resolvedFilePath = workspacePaths.hooksFile.absolutePath\n\n return {\n filePath: this.toDisplayPath(configuredPath, resolvedFilePath),\n resolvedFilePath,\n hooksBaseDir: dirname(resolvedFilePath),\n }\n }\n\n private getAuthoredPathReadError(filePath: string, hooksBaseDir: string, index: number): HookRegistryReadError | null {\n if (isAbsolute(filePath)) {\n return {\n code: 'absolute_path',\n message: `hooks.${index}.file: Hook file must be relative to the configured hooks file`,\n }\n }\n\n if (!isPathInsideDir(filePath, hooksBaseDir)) {\n return {\n code: 'unsafe_path',\n message: `hooks.${index}.file: Hook file must stay inside the configured hooks file directory`,\n }\n }\n\n return null\n }\n\n private async inspectHookFile(filePath: string, hooksBaseDir: string): Promise<HookFileState> {\n if (isAbsolute(filePath) || !isPathInsideDir(filePath, hooksBaseDir)) {\n return {\n resolvedFilePath: null,\n fileMissing: true,\n fieldErrors: [\n {\n field: 'file',\n code: 'unsafe_path',\n message: 'Hook file must stay inside the configured hooks file directory',\n },\n ],\n }\n }\n\n const resolvedFilePath = resolve(hooksBaseDir, filePath)\n try {\n await stat(resolvedFilePath)\n return {\n resolvedFilePath,\n fileMissing: false,\n fieldErrors: [],\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return {\n resolvedFilePath: null,\n fileMissing: true,\n fieldErrors: [\n {\n field: 'file',\n code: 'file_missing',\n message: 'Hook file missing',\n },\n ],\n }\n }\n throw err\n }\n }\n\n private normalizeDraftForSchema(draft: unknown): unknown {\n const rawHooks = this.getRawHooksFromDraft(draft)\n if (rawHooks === null) {\n return draft\n }\n\n return {\n ...(draft as Record<string, unknown>),\n hooks: rawHooks.map((hook) => {\n if (!hook || typeof hook !== 'object' || Array.isArray(hook)) {\n return hook\n }\n\n const hookRecord = hook as Record<string, unknown>\n return {\n ...hookRecord,\n timeout: this.normalizeTimeoutValue(hookRecord.timeout),\n }\n }),\n }\n }\n\n private toAuthoredHookDefinitions(\n draft: unknown,\n parsedHooks: ParsedHookDefinition[],\n ): AuthoredHookDefinition[] {\n const rawHooks = this.getRawHooksFromDraft(draft) ?? []\n return parsedHooks.map((hook, index) => this.toAuthoredHookDefinition(rawHooks[index], hook))\n }\n\n private toAuthoredHookDefinition(\n rawHook: unknown,\n parsedHook: ParsedHookDefinition,\n ): AuthoredHookDefinition {\n const rawTimeout = rawHook && typeof rawHook === 'object' && !Array.isArray(rawHook)\n ? (rawHook as Record<string, unknown>).timeout\n : parsedHook.timeout\n const normalizedTimeout = this.normalizeTimeoutValue(rawTimeout)\n\n return {\n ...parsedHook,\n timeout: typeof normalizedTimeout === 'string'\n ? normalizedTimeout\n : this.formatDurationToken(parsedHook.timeout),\n }\n }\n\n private getRawHooksFromDraft(draft: unknown): unknown[] | null {\n if (!draft || typeof draft !== 'object' || Array.isArray(draft)) {\n return null\n }\n\n const hooks = (draft as { hooks?: unknown }).hooks\n return Array.isArray(hooks) ? hooks : null\n }\n\n private normalizeTimeoutValue(timeout: unknown): unknown {\n if (typeof timeout === 'number') {\n return this.formatDurationToken(timeout)\n }\n\n if (typeof timeout !== 'string') {\n return timeout\n }\n\n const trimmedTimeout = timeout.trim()\n if (trimmedTimeout.length === 0) {\n return trimmedTimeout\n }\n\n if (/^\\d+$/.test(trimmedTimeout)) {\n return this.formatDurationToken(Number.parseInt(trimmedTimeout, 10))\n }\n\n const millisecondTimeout = trimmedTimeout.match(/^(\\d+)ms$/i)\n if (millisecondTimeout) {\n return this.formatDurationToken(Number.parseInt(millisecondTimeout[1], 10))\n }\n\n return trimmedTimeout\n }\n\n private formatDurationToken(durationMs: number): string {\n if (!Number.isFinite(durationMs) || durationMs < 0) {\n return `${durationMs}`\n }\n\n if (durationMs === 0) {\n return '0ms'\n }\n\n const durationUnits = [\n { suffix: 'd', value: 86_400_000 },\n { suffix: 'h', value: 3_600_000 },\n { suffix: 'm', value: 60_000 },\n { suffix: 's', value: 1_000 },\n ] as const\n\n for (const unit of durationUnits) {\n if (durationMs % unit.value === 0) {\n return `${durationMs / unit.value}${unit.suffix}`\n }\n }\n\n return `${durationMs}ms`\n }\n\n private toValidationFieldError(path: PropertyKey[], message: string): HookFieldError {\n const field = this.getFieldName(path)\n\n if (field === 'id' && message.includes('Duplicate hook id')) {\n return { field, code: 'duplicate_id', message }\n }\n\n if (field === 'name' && message.includes('Duplicate hook name')) {\n return { field, code: 'duplicate_name', message }\n }\n\n if (field === 'runtime') {\n return { field, code: 'invalid_runtime', message }\n }\n\n if (field === 'timeout') {\n return { field, code: 'invalid_timeout', message }\n }\n\n if (field === 'network') {\n return { field, code: 'invalid_network', message }\n }\n\n if (field === 'file') {\n return { field, code: 'invalid_file', message }\n }\n\n if (field === 'id') {\n return { field, code: 'invalid_id', message }\n }\n\n if (field === 'name') {\n return { field, code: 'invalid_name', message }\n }\n\n return { field, code: 'invalid_registry', message }\n }\n\n private toMutationFieldError(error: HookRegistryReadError): HookFieldError {\n if (error.code === 'absolute_path') {\n return {\n field: 'file',\n code: 'absolute_path',\n message: 'Hook file must be relative to the configured hooks file',\n }\n }\n\n if (error.code === 'unsafe_path') {\n return {\n field: 'file',\n code: 'unsafe_path',\n message: 'Hook file must stay inside the configured hooks file directory',\n }\n }\n\n return {\n field: 'registry',\n code: error.code,\n message: error.message,\n }\n }\n\n private getFieldName(path: PropertyKey[]): HookFieldName {\n const field = path[path.length - 1]\n if (\n field === 'id' ||\n field === 'name' ||\n field === 'runtime' ||\n field === 'file' ||\n field === 'timeout' ||\n field === 'network'\n ) {\n return field\n }\n\n return 'registry'\n }\n\n private toCatalogRow(hook: ParsedHookDefinition, fileMissing: boolean): HookCatalogRow {\n return {\n id: hook.id,\n name: hook.name,\n runtime: hook.runtime,\n file: hook.file,\n timeout: hook.timeout,\n network: hook.network,\n fileMissing,\n }\n }\n\n private toDisplayPath(configuredPath: string, resolvedFilePath: string): string {\n if (!isAbsolute(configuredPath)) {\n return configuredPath\n }\n\n const relativeToConfig = relative(dirname(this.configPath), resolvedFilePath)\n if (relativeToConfig && !relativeToConfig.startsWith('..') && !isAbsolute(relativeToConfig)) {\n return relativeToConfig.startsWith('.') ? relativeToConfig : `./${relativeToConfig}`\n }\n\n return `./${basename(resolvedFilePath)}`\n }\n}\n","import { readFile } from 'node:fs/promises'\nimport { basename } from 'node:path'\n\nimport {\n AgentQaConfigSchema,\n discoverWorkspaceFiles,\n resolveWorkspacePaths,\n type WorkspaceFileRecord,\n} from '@vostride/agent-qa-core'\nimport { parse as parseYaml } from 'yaml'\n\nimport type { HookDeleteReference } from './hook-registry-types.js'\n\nconst HOOK_INLINE_RE = /\\{\\{runHook:\"([^\"]+)\"\\}\\}/g\n\nfunction getLabel(parsed: unknown, filePath: string): string {\n if (parsed && typeof parsed === 'object' && typeof (parsed as { name?: unknown }).name === 'string') {\n const name = (parsed as { name: string }).name.trim()\n if (name.length > 0) {\n return name\n }\n }\n\n return basename(filePath)\n}\n\nfunction collectHookListReferences(\n parsed: Record<string, unknown>,\n filePath: string,\n label: string,\n kind: 'test' | 'suite',\n key: 'setup' | 'teardown',\n hookId: string,\n): HookDeleteReference[] {\n const entries = parsed[key]\n if (!Array.isArray(entries)) {\n return []\n }\n\n return entries.flatMap((entry) => {\n if (entry !== hookId) {\n return []\n }\n\n return [{\n kind,\n label,\n path: filePath,\n context: key,\n }]\n })\n}\n\nfunction collectInlineReferences(\n parsed: Record<string, unknown>,\n filePath: string,\n label: string,\n hookId: string,\n): HookDeleteReference[] {\n const steps = parsed.steps\n if (!Array.isArray(steps)) {\n return []\n }\n\n return steps.flatMap((entry, index) => {\n const text = typeof entry === 'string'\n ? entry\n : entry && typeof entry === 'object' && typeof (entry as { step?: unknown }).step === 'string'\n ? (entry as { step: string }).step\n : null\n\n if (!text) {\n return []\n }\n\n const matches = [...text.matchAll(HOOK_INLINE_RE)]\n if (!matches.some((match) => match[1] === hookId)) {\n return []\n }\n\n return [{\n kind: 'inline-runHook',\n label,\n path: filePath,\n context: typeof entry === 'string' ? `steps[${index}]` : `steps[${index}].step`,\n }]\n })\n}\n\nasync function scanYamlFile(\n record: WorkspaceFileRecord,\n hookId: string,\n): Promise<HookDeleteReference[]> {\n let parsed: unknown\n\n try {\n parsed = parseYaml(await readFile(record.absolutePath, 'utf-8'))\n } catch {\n return []\n }\n\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return []\n }\n\n const parsedRecord = parsed as Record<string, unknown>\n const label = getLabel(parsed, record.workspaceRelativePath)\n const kind = record.kind\n\n return [\n ...collectHookListReferences(parsedRecord, record.workspaceRelativePath, label, kind, 'setup', hookId),\n ...collectHookListReferences(parsedRecord, record.workspaceRelativePath, label, kind, 'teardown', hookId),\n ...collectInlineReferences(parsedRecord, record.workspaceRelativePath, label, hookId),\n ]\n}\n\nfunction dedupeReferences(references: HookDeleteReference[]): HookDeleteReference[] {\n const seen = new Set<string>()\n\n return references.filter((reference) => {\n const key = `${reference.kind}:${reference.path}:${reference.context}:${reference.label}`\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n}\n\nexport async function scanHookReferences(\n _workspaceDir: string,\n configPath: string,\n hookId: string,\n): Promise<HookDeleteReference[]> {\n let parsedConfig: unknown\n\n try {\n parsedConfig = parseYaml(await readFile(configPath, 'utf-8'))\n } catch {\n return []\n }\n\n const configResult = AgentQaConfigSchema.safeParse(parsedConfig)\n if (!configResult.success) {\n return []\n }\n\n const workspace = resolveWorkspacePaths({ config: configResult.data, configPath })\n const records = await Promise.all([\n discoverWorkspaceFiles({ workspace, kind: 'test' }),\n discoverWorkspaceFiles({ workspace, kind: 'suite' }),\n ])\n const references = await Promise.all(\n records\n .flat()\n .sort((left, right) => left.workspaceRelativePath.localeCompare(right.workspaceRelativePath))\n .map((record) => scanYamlFile(record, hookId)),\n )\n\n return dedupeReferences(references.flat()).sort((left, right) =>\n left.path.localeCompare(right.path) ||\n left.context.localeCompare(right.context) ||\n left.kind.localeCompare(right.kind) ||\n left.label.localeCompare(right.label),\n )\n}\n","import type { IncomingMessage } from 'node:http'\n\nconst DEFAULT_MAX_BYTES = 1024 * 1024 // 1MB\n\nexport function readJsonBody<T>(req: IncomingMessage, maxBytes = DEFAULT_MAX_BYTES): Promise<T> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = []\n let totalBytes = 0\n\n req.on('data', (chunk: Buffer) => {\n totalBytes += chunk.length\n if (totalBytes > maxBytes) {\n req.destroy()\n reject(new Error(`Body exceeds maximum size of ${maxBytes} bytes`))\n return\n }\n chunks.push(chunk)\n })\n\n req.on('end', () => {\n const body = Buffer.concat(chunks).toString('utf-8')\n if (!body) {\n reject(new Error('Empty request body'))\n return\n }\n try {\n resolve(JSON.parse(body) as T)\n } catch {\n reject(new Error('Invalid JSON in request body'))\n }\n })\n\n req.on('error', (err) => {\n reject(err)\n })\n })\n}\n","import { randomUUID } from 'node:crypto'\nimport { dirname, resolve as resolvePath } from 'node:path'\nimport {\n AUTH_STATE_SCHEMA_VERSION,\n MobileSetupError,\n PlannerConfigSchema,\n SuiteDefinitionSchema,\n TestDefinitionSchema,\n readAuthStateMetadata,\n resolveAuthStatePaths,\n writeAuthStateFiles,\n} from '@vostride/agent-qa-core'\nimport {\n VariableStore,\n interpolateVariables,\n findUnresolvedTemplates,\n executeStep,\n LLMPlanner,\n LLMVerifier,\n resolveSecretTemplatesInValue,\n redactSecretValue,\n runHooks,\n resolveSecretEnv,\n parseHookInline,\n stripHookInline,\n createLiveStreamHub,\n liveStreamFor,\n} from '@vostride/agent-qa-runner'\nimport { DockerHookExecutor } from '@vostride/agent-qa-runner-local'\nimport {\n createModel,\n createTokenAccounting,\n resolveCapabilities,\n resolveVisionGate,\n visionFromConfig,\n type VisionGate,\n} from '@vostride/agent-qa-model'\nimport type {\n AuthStateMetadata,\n HookDefinition,\n MobilePlatform,\n} from '@vostride/agent-qa-core'\nimport { buildProductionRefusal, distinctInFirstOccurrenceOrder, resolvePlannerLimits } from '@vostride/agent-qa-schema'\nimport type { DeclaredModelProfile, PlannerLimits } from '@vostride/agent-qa-schema'\nimport { parse as parseYaml } from 'yaml'\nimport type {\n PlatformAdapter,\n PlatformConfig,\n StepResult,\n StepPhaseEvent,\n LoopPorts,\n StepContext,\n SecretRedactor,\n SecretStore,\n StorageStatePort,\n LiveStreamHub,\n} from '@vostride/agent-qa-runner'\nimport type { LanguageModel } from 'ai'\nimport { authFromFetch, authFromRuntimeConfig, toModelProfileAndAuth } from '../llm-model-mapping.js'\nimport { prepareMobileLiveSession } from './mobile-bootstrap.js'\nimport type { MobileLiveAppiumLease } from './mobile-bootstrap.js'\nimport type { AppiumManager } from '../execution/appium-manager.js'\nimport { readConfigValues, type ConfigManager } from '../config/index.js'\nimport type { LiveEditorAttachment } from '../live-view/editor-subjects.js'\nimport type {\n EntityRef,\n SessionState,\n LiveDraftMetadata,\n LiveExecutionLog,\n LiveHookOwner,\n LiveSessionConfig,\n LiveStepResultPayload,\n LiveSubActionData,\n LiveHookPayload,\n LiveTestExecutionPayload,\n LiveTestResultPayload,\n LiveTestStepPayload,\n ServerMessage,\n} from './types.js'\n\n/**\n * What the current config declares about the one target a live session names (432 D-18).\n *\n * A session drives at most one target. It is production only when the request names a target the\n * config declares `environment: production`; a raw URL with no target name, or a name the config\n * does not declare, is not production. `allowProduction` is the config's top-level key, and only\n * the literal `true` opts in.\n */\nexport interface LiveTargetProduction {\n readonly productionTargetNames: readonly string[]\n readonly allowProduction: boolean\n}\n\n/** A live session refused because its target is production and the config has not opted in. */\nexport class LiveProductionRefusedError extends Error {\n readonly productionTargetNames: readonly string[]\n\n constructor(productionTargetNames: readonly string[]) {\n super(buildProductionRefusal(productionTargetNames))\n this.name = 'LiveProductionRefusedError'\n this.productionTargetNames = distinctInFirstOccurrenceOrder(productionTargetNames)\n }\n}\n\nfunction isConfigRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\n/** The target name a session is labelled with: trimmed, and absent when blank. */\nfunction liveTargetName(targetName: unknown): string | undefined {\n if (typeof targetName !== 'string') return undefined\n const trimmed = targetName.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\n/**\n * Read the current config for the target a session names. The request supplies the name only;\n * the environment and the opt-in come from the config file as it is now.\n */\nexport async function resolveLiveTargetProduction(\n configManager: ConfigManager | undefined,\n targetName: string | undefined,\n): Promise<LiveTargetProduction> {\n const name = liveTargetName(targetName)\n if (name === undefined || configManager === undefined) {\n return { productionTargetNames: [], allowProduction: false }\n }\n const config = await readConfigValues(configManager)\n const registry = isConfigRecord(config.registry) ? config.registry : undefined\n const targets = registry !== undefined && isConfigRecord(registry.targets) ? registry.targets : undefined\n const declared = targets !== undefined && Object.hasOwn(targets, name) ? targets[name] : undefined\n const production = isConfigRecord(declared) && declared.environment === 'production'\n return {\n productionTargetNames: production ? [name] : [],\n allowProduction: config.allowProduction === true,\n }\n}\n\n/** The workspace readers the create door already holds, by canonical id. */\nexport interface LiveEntityDefinitionReaders {\n findTest?(testId: string): Promise<{ content: string } | null>\n findSuite?(suiteId: string): Promise<{ content: string } | null>\n}\n\nasync function readEntityUse(\n entity: EntityRef | undefined,\n readers: LiveEntityDefinitionReaders,\n): Promise<unknown> {\n if (entity === undefined) return undefined\n const find = entity.type === 'suite' ? readers.findSuite : readers.findTest\n if (find === undefined) return undefined\n try {\n const found = await find(entity.id)\n if (found === null) return undefined\n const parsed: unknown = parseYaml(found.content)\n return isConfigRecord(parsed) ? parsed.use : undefined\n } catch {\n return undefined\n }\n}\n\n/** 436 D-02/D-05: a layer sets a planner limit the CLI refuses, so the live editor refuses it too. */\nexport class LivePlannerLimitsRefusedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'LivePlannerLimitsRefusedError'\n }\n}\n\nconst LIVE_LIMIT_LEAVES = ['maxActions', 'maxPlanningTurns'] as const\ntype LiveLimitLeaf = (typeof LIVE_LIMIT_LEAVES)[number]\ntype EntityUseSchema = typeof TestDefinitionSchema.shape.use | typeof SuiteDefinitionSchema.shape.use\n\nfunction shownLimitValue(value: unknown): string {\n return typeof value === 'number' ? String(value) : JSON.stringify(value) ?? String(value)\n}\n\n// Only the limit leaves are checked, with the core schemas the CLI applies to them; other `use`\n// keys are not the live editor's to refuse.\nfunction useLeafIssue(schema: EntityUseSchema, key: LiveLimitLeaf, value: unknown): string | undefined {\n const parsed = schema.safeParse({ planner: { [key]: value } })\n return parsed.success ? undefined : parsed.error.issues[0]?.message ?? 'invalid value'\n}\n\nfunction projectLeafIssue(key: LiveLimitLeaf, value: unknown): string | undefined {\n const parsed = PlannerConfigSchema.shape[key].safeParse(value)\n return parsed.success ? undefined : parsed.error.issues[0]?.message ?? 'invalid value'\n}\n\n// A planner key core retired is named only by core's retired-key scan, as a custom issue at\n// ['planner', key]; the live editor asks core rather than spelling the key (436 D-18 census).\nfunction retiredPlannerKeyIssue(schema: EntityUseSchema, key: string, value: unknown): string | undefined {\n const parsed = schema.safeParse({ planner: { [key]: value } })\n if (parsed.success) return undefined\n return parsed.error.issues.find(issue => issue.code === 'custom'\n && issue.path.length === 2 && issue.path[0] === 'planner' && issue.path[1] === key)?.message\n}\n\nfunction refuseInvalidLimits(\n layer: string,\n use: unknown,\n issueOf: (key: LiveLimitLeaf, value: unknown) => string | undefined,\n retiredSchema: () => EntityUseSchema,\n): void {\n if (!isConfigRecord(use) || !isConfigRecord(use.planner)) return\n const planner = use.planner\n const refuse = (key: string, issue: string): never => {\n throw new LivePlannerLimitsRefusedError(\n `${layer} sets use.planner.${key} to ${shownLimitValue(planner[key])}: ${issue}. The CLI refuses this file too.`,\n )\n }\n for (const key of LIVE_LIMIT_LEAVES) {\n if (!Object.hasOwn(planner, key)) continue\n const issue = issueOf(key, planner[key])\n if (issue !== undefined) refuse(key, issue)\n }\n for (const key of Object.keys(planner)) {\n if ((LIVE_LIMIT_LEAVES as readonly string[]).includes(key)) continue\n const issue = retiredPlannerKeyIssue(retiredSchema(), key, planner[key])\n if (issue !== undefined) refuse(key, issue)\n }\n}\n\n/**\n * 436 D-03: the limits a live session runs under — the project config's `use` block, then each\n * entity's `use` in order (a suite, then a test of it) when the door can load it. An entity it\n * cannot load contributes nothing.\n */\nexport async function resolveLivePlannerLimits(\n configManager: ConfigManager | undefined,\n entities: EntityRef | readonly EntityRef[] | undefined,\n readers: LiveEntityDefinitionReaders,\n): Promise<PlannerLimits> {\n const config = configManager === undefined ? {} : await readConfigValues(configManager)\n refuseInvalidLimits('project config', config.use, projectLeafIssue, () => TestDefinitionSchema.shape.use)\n const uses: unknown[] = []\n for (const entity of ([] as EntityRef[]).concat(entities ?? [])) {\n const use = await readEntityUse(entity, readers)\n const schema = (): EntityUseSchema =>\n entity.type === 'suite' ? SuiteDefinitionSchema.shape.use : TestDefinitionSchema.shape.use\n refuseInvalidLimits(`${entity.type} file ${entity.id}`, use, (key, value) => useLeafIssue(schema(), key, value), schema)\n uses.push(use)\n }\n return resolvePlannerLimits(config.use, ...uses)\n}\n\n/** The refusal a finding calls for, or nothing when the target is not production or is opted in. */\nexport function liveProductionRefusal(\n found: LiveTargetProduction,\n): LiveProductionRefusedError | undefined {\n if (found.productionTargetNames.length === 0 || found.allowProduction) return undefined\n return new LiveProductionRefusedError(found.productionTargetNames)\n}\n\nexport const IDLE_TIMEOUT_MS = 5 * 60 * 1000\n\n/** How long teardown waits for the live hub to close before it tears the browser down anyway. */\nexport const LIVE_HUB_CLOSE_LIMIT_MS = 2_000\n\n/** Why the session let go of a control socket: a newer one replaced it, or the session ended. */\nexport type LiveAttachmentRelease = 'superseded' | 'ended'\n\nconst RUNJS_DBL_RE = /\\{\\{runJS:\"((?:[^\"\\\\]|\\\\.)*)\"\\}\\}/g\nconst RUNJS_SGL_RE = /\\{\\{runJS:'((?:[^'\\\\]|\\\\.)*)'\\}\\}/g\n\nexport interface LiveSessionDeps {\n appiumManager?: AppiumManager\n configManager?: ConfigManager\n configPath?: string\n}\n\nexport interface LiveStepExecutionResult extends StepResult {\n executionLogs?: LiveExecutionLog[]\n subActionsData?: LiveSubActionData[]\n}\n\ninterface WebStorageStateContext {\n storageState(options?: { indexedDB?: boolean }): Promise<unknown>\n}\n\ninterface WebStorageStatePage {\n context(): WebStorageStateContext\n}\n\n// Shared with ws-handler.ts toStepResultPayload. Kept in-module so that\n// executeTestCommand can assemble its stepResults array without a\n// cross-module import that would create a circular dependency.\nfunction toStepResultPayload(result: LiveStepExecutionResult): LiveStepResultPayload {\n const status = result.status === 'passed'\n ? 'passed'\n : result.status === 'cancelled'\n ? 'cancelled'\n : 'failed'\n\n return {\n status,\n duration: result.duration,\n error: result.error,\n capturedVariables: result.capturedVariables,\n variableSnapshot: result.variableSnapshot,\n originalStepName: result.originalStepName,\n consoleLogs: result.consoleLogs,\n networkLogs: result.networkLogs,\n executionLogs: result.executionLogs,\n subActionsData: result.subActionsData,\n }\n}\n\ninterface RunJSMatch {\n fullMatch: string\n code: string\n}\n\nfunction parseRunJSInline(text: string): RunJSMatch[] {\n const matches: RunJSMatch[] = []\n for (const match of text.matchAll(RUNJS_DBL_RE)) {\n matches.push({ fullMatch: match[0], code: match[1] })\n }\n for (const match of text.matchAll(RUNJS_SGL_RE)) {\n matches.push({ fullMatch: match[0], code: match[1] })\n }\n return matches.sort((a, b) => text.indexOf(a.fullMatch) - text.indexOf(b.fullMatch))\n}\n\nfunction coerceRunJSResult(value: unknown): string {\n if (value === undefined) return 'undefined'\n if (value === null) return 'null'\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n return String(value)\n }\n return JSON.stringify(value)\n}\n\nfunction getWebStorageStateContext(adapter: PlatformAdapter | null): WebStorageStateContext | null {\n if (!adapter || !('getPage' in adapter)) return null\n const page = (adapter as { getPage?: () => unknown }).getPage?.()\n if (!page || typeof page !== 'object') return null\n\n const contextFactory = (page as Partial<WebStorageStatePage>).context\n if (typeof contextFactory !== 'function') return null\n\n const context = contextFactory.call(page)\n if (!context || typeof context !== 'object') return null\n\n const storageState = (context as Partial<WebStorageStateContext>).storageState\n if (typeof storageState !== 'function') return null\n return context as WebStorageStateContext\n}\n\nfunction getConfiguredAuthStateDir(config: Record<string, unknown>): string | undefined {\n const services = config.services\n if (!services || typeof services !== 'object') return undefined\n const authState = (services as Record<string, unknown>).authState\n if (!authState || typeof authState !== 'object') return undefined\n const dir = (authState as Record<string, unknown>).dir\n return typeof dir === 'string' ? dir : undefined\n}\n\nexport function toLiveSubActionData(result: StepResult): LiveSubActionData[] | undefined {\n return result.trace?.subActions?.map((subAction) => ({\n index: subAction.index,\n observation: subAction.observation,\n reasoning: subAction.reasoning,\n plannedAction: subAction.plannedAction,\n result: subAction.result,\n error: subAction.error,\n screenStateBefore: subAction.screenStateBefore,\n screenStateAfter: subAction.screenStateAfter,\n confidence: subAction.confidence,\n verifierReasoning: subAction.verifierReasoning,\n cached: subAction.cached,\n tokenUsage: subAction.tokenUsage,\n phaseDurations: subAction.phaseDurations,\n annotation: subAction.annotation,\n screenContextBefore: subAction.screenContextBefore,\n screenContextAfter: subAction.screenContextAfter,\n data: subAction.data,\n }))\n}\n\nfunction mobileSetupMessage(err: MobileSetupError): string {\n return `${err.category}: ${err.message}`\n}\n\nfunction classifyAdapterSetupError(err: unknown): MobileSetupError['category'] {\n const message = err instanceof Error ? err.message : String(err)\n if (/appium|ECONNREFUSED|connect|\\/session|status/i.test(message)) {\n return 'appium-startup'\n }\n return 'device-readiness'\n}\n\nfunction wrapAdapterSetupError(\n err: unknown,\n platform: MobilePlatform,\n config: PlatformConfig,\n): MobileSetupError {\n if (err instanceof MobileSetupError) return err\n const appId = platform === 'android'\n ? config.appPackage\n : config.bundleId\n return new MobileSetupError({\n category: classifyAdapterSetupError(err),\n message: `Failed to create ${platform} adapter session: ${err instanceof Error ? err.message : String(err)}`,\n platform,\n deviceName: config.device?.name,\n appId,\n cause: err,\n })\n}\n\nfunction buildHookExecutionLog(hook: LiveHookPayload): LiveExecutionLog {\n return {\n id: hook.executionId,\n type: 'hook',\n name: hook.hookName,\n hookId: hook.hookId,\n phase: hook.phase,\n status: hook.status === 'failed' ? 'failed' : 'passed',\n duration: hook.duration ?? 0,\n stdout: hook.stdout ?? null,\n stderr: hook.stderr ?? null,\n returnData: null,\n variables: hook.variables ?? null,\n createdAt: hook.createdAt,\n }\n}\n\nexport class LiveSession {\n readonly sessionId: string\n status: 'idle' | 'executing' | 'disconnected' | 'terminated' = 'idle'\n private abortController: AbortController | null = null\n stepsExecuted = 0\n createdAt = 0\n\n private adapter: PlatformAdapter | null = null\n private planner: LLMPlanner | null = null\n private verifier: LLMVerifier | null = null\n private modelProfiles: { planner: DeclaredModelProfile; verifier: DeclaredModelProfile } | null = null\n // D-14 (Phase 360): the run-scoped storage-state store, constructed lazily on first use and\n // rooted at the session's `.agent-qa` runtime dir (the FsStorageStateStore rooting idiom).\n private storageStateStore: StorageStatePort | null = null\n private model: LanguageModel | null = null\n private variableStore: VariableStore | null = null\n private previousSteps: { instruction: string; outcome: string; reasoning?: string; plannedAction?: string; verifierResponse?: string }[] = []\n private currentStep: string | null = null\n private platform: 'web' | 'android' | 'ios' = 'web'\n private targetName: string | null = null\n private currentUrl: string | null = null\n private executing = false\n private idleTimer: ReturnType<typeof setTimeout> | null = null\n private _modelName = 'unknown'\n private vision: { screenshotSize?: number; effectiveResolution?: number } | undefined\n private visionGate: VisionGate | undefined\n private plannerLimits: PlannerLimits | undefined\n private plannerLimitsForTest: ((testId: string) => Promise<PlannerLimits>) | undefined\n private readyForInteraction = false\n private terminalError: string | null = null\n private setupHooks: string[] = []\n private teardownHooks: string[] = []\n private resolvedHooks = new Map<string, HookDefinition>()\n private hookRegistryError: string | null = null\n private pendingMessages: ServerMessage[] = []\n private messageSink: ((message: ServerMessage) => void) | null = null\n private hookCaptures = new Set<LiveHookPayload[]>()\n private mobileAppiumLease: MobileLiveAppiumLease | null = null\n private secretStore: SecretStore | undefined\n private secretRedactor: SecretRedactor | undefined\n // 428 D-07: one hub per session, handle 0, created once the adapter exists. A session whose\n // setup hooks failed has no adapter and therefore no hub; its subject declares `none`.\n private liveHub: LiveStreamHub | null = null\n private attachment: LiveEditorAttachment | null = null\n private resolveEnded: () => void = () => {}\n private readonly ended: Promise<void>\n private cleanupRun: Promise<void> | null = null\n // RESEARCH P4: which control socket is the current one. Only its close may detach the session.\n private attachmentGeneration = 0\n private releaseAttachment: ((reason: LiveAttachmentRelease) => void) | null = null\n\n constructor(sessionId: string, private deps: LiveSessionDeps = {}) {\n this.sessionId = sessionId\n this.ended = new Promise<void>((resolve) => {\n this.resolveEnded = resolve\n })\n }\n\n get modelName(): string {\n return this._modelName\n }\n\n /** What the editor-subject registry holds for this session: its hub, read at call time. */\n liveAttachment(): LiveEditorAttachment {\n this.attachment ??= {\n streamCapabilityOf: (handle) => this.liveHub?.capabilityOf(handle) ?? { kind: 'none' },\n subscribeFrames: (handle, onFrame, onEnd) => this.liveHub?.subscribe(handle, onFrame, onEnd),\n ended: this.ended,\n }\n return this.attachment\n }\n\n private openLiveHub(): void {\n if (!this.adapter || this.liveHub) return\n const hub = createLiveStreamHub()\n const registration = liveStreamFor(this.adapter)\n hub.register(0, registration?.capability, registration?.fallback)\n this.liveHub = hub\n }\n\n /**\n * Make a control socket the current one. `release` is how the session lets go of it later: the\n * previous attachment's is called with `superseded` here (428 WR-01), so one socket drives the\n * session at a time.\n */\n beginAttachment(release?: (reason: LiveAttachmentRelease) => void): number {\n const previous = this.releaseAttachment\n this.attachmentGeneration += 1\n this.releaseAttachment = release ?? null\n previous?.('superseded')\n return this.attachmentGeneration\n }\n\n isCurrentAttachment(generation: number): boolean {\n return generation === this.attachmentGeneration\n }\n\n attachMessageSink(sink: ((message: ServerMessage) => void) | null): void {\n this.messageSink = sink\n if (!sink || this.pendingMessages.length === 0) return\n\n for (const message of this.pendingMessages) {\n sink(message)\n }\n this.pendingMessages = []\n }\n\n /**\n * A command's reply, for whichever control socket is attached now (428 CR-01). A command can\n * outlive the socket that issued it, and its outcome belongs to the page, not to that socket:\n * with none attached it is held and flushed to the next one.\n */\n deliver(message: ServerMessage): void {\n if (this.messageSink) {\n this.messageSink(message)\n return\n }\n this.pendingMessages.push(message)\n }\n\n private dispatch(message: ServerMessage): void {\n message = this.redact(message)\n if (message.type === 'hook-complete') {\n for (const capture of this.hookCaptures) capture.push(message.hook)\n }\n if (this.messageSink) {\n this.messageSink(message)\n return\n }\n this.pendingMessages.push(message)\n }\n\n private redact<T>(value: T): T {\n return redactSecretValue(value, this.secretRedactor)\n }\n\n private resolveSecrets<T>(value: T): T {\n return resolveSecretTemplatesInValue(value, this.secretStore)\n }\n\n private emitHookStart(\n hookDef: Pick<HookDefinition, 'id' | 'name'>,\n phase: 'setup' | 'teardown',\n owner: LiveHookOwner = { scope: 'suite' },\n ): LiveHookPayload {\n const hook: LiveHookPayload = {\n executionId: randomUUID(),\n hookId: hookDef.id,\n hookName: hookDef.name,\n phase,\n owner,\n status: 'running',\n createdAt: new Date().toISOString(),\n }\n this.dispatch({ type: 'hook-start', hook })\n return hook\n }\n\n private emitHookComplete(\n started: LiveHookPayload,\n updates: Omit<LiveHookPayload, 'executionId' | 'hookId' | 'hookName' | 'phase' | 'owner' | 'createdAt'>,\n ): LiveHookPayload {\n const hook: LiveHookPayload = this.redact({\n ...started,\n ...updates,\n })\n this.dispatch({ type: 'hook-complete', hook })\n return hook\n }\n\n private emitTestStepStart(step: LiveTestStepPayload): void {\n this.dispatch({ type: 'test-step-start', step })\n }\n\n private emitTestStepPhase(step: LiveTestStepPayload, event: StepPhaseEvent): void {\n this.dispatch({\n type: 'test-step-phase',\n step,\n phase: event.phase,\n data: {\n text: event.text,\n confidence: event.confidence,\n action: event.action,\n success: event.success,\n duration: event.duration,\n },\n })\n }\n\n private emitTestStepComplete(step: LiveTestStepPayload, result: LiveStepExecutionResult): void {\n if (result.status === 'cancelled') {\n this.dispatch({ type: 'test-step-cancelled', step })\n return\n }\n\n this.dispatch({\n type: 'test-step-complete',\n step,\n result: toStepResultPayload(result),\n })\n }\n\n private emitTestStepError(step: LiveTestStepPayload, error: string): void {\n this.dispatch({ type: 'test-step-error', step, error })\n }\n\n private getHookEnvVars(): Record<string, string> {\n const envVars: Record<string, string> = {}\n if (!this.variableStore) return envVars\n\n for (const [key, value] of this.variableStore.getAll()) {\n envVars[key] = value\n }\n\n return envVars\n }\n\n private async runLifecycleHooks(\n phase: 'setup' | 'teardown',\n hookIds: string[],\n owner: LiveHookOwner = { scope: 'suite' },\n ): Promise<{ allPassed: boolean; logs: LiveExecutionLog[] }> {\n const logs: LiveExecutionLog[] = []\n\n for (const hookId of hookIds) {\n const hookDef = this.resolvedHooks.get(hookId)\n const started = this.emitHookStart(\n hookDef ?? { id: hookId, name: hookId },\n phase,\n owner,\n )\n\n if (!hookDef) {\n const registryHint = this.hookRegistryError ? ` (${this.hookRegistryError})` : ''\n const completed = this.emitHookComplete(started, {\n status: 'failed',\n duration: 0,\n stdout: null,\n stderr: this.hookRegistryError ?? null,\n variables: null,\n error: `Hook ID \"${hookId}\" is not defined in hooks.yaml${registryHint}`,\n })\n logs.push(buildHookExecutionLog(completed))\n if (phase === 'setup') {\n return { allPassed: false, logs }\n }\n continue\n }\n\n const result = await runHooks([hookDef], {\n executor: new DockerHookExecutor(),\n env: this.getHookEnvVars(),\n secretStore: this.secretStore,\n secretRedactor: this.secretRedactor,\n })\n const hookResult = result.results.get(hookDef.name)\n const completed = this.emitHookComplete(started, {\n status: hookResult?.success ? 'passed' : 'failed',\n duration: hookResult?.duration ?? 0,\n stdout: hookResult?.stdout ?? null,\n stderr: hookResult?.stderr ?? null,\n variables: hookResult && Object.keys(hookResult.variables).length > 0 ? hookResult.variables : null,\n error: hookResult?.error,\n })\n logs.push(buildHookExecutionLog(completed))\n\n if (hookResult?.success && hookResult.variables && this.variableStore) {\n this.variableStore.setAll(hookResult.variables, 'hook')\n }\n\n if (!hookResult?.success && phase === 'setup') {\n return { allPassed: false, logs }\n }\n }\n\n return { allPassed: true, logs }\n }\n\n async executeHookCommand(\n phase: 'setup' | 'teardown',\n hookId: string,\n ): Promise<LiveExecutionLog> {\n if (!this.readyForInteraction || !this.variableStore) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n\n if (this.executing) {\n throw new Error('Live session is busy')\n }\n\n this.executing = true\n this.status = 'executing'\n const hookName = this.resolvedHooks.get(hookId)?.name ?? hookId\n this.currentStep = `${phase} hook: ${hookName}`\n\n try {\n const { logs } = await this.runLifecycleHooks(phase, [hookId])\n return logs[0] ?? {\n id: randomUUID(),\n type: 'hook',\n name: hookName,\n hookId,\n phase,\n status: 'failed',\n duration: 0,\n stdout: null,\n stderr: null,\n returnData: null,\n variables: null,\n createdAt: new Date().toISOString(),\n }\n } finally {\n this.executing = false\n this.currentStep = null\n this.status = 'idle'\n }\n }\n\n private releaseMobileAppiumLease(reason: string): void {\n if (!this.mobileAppiumLease) return\n this.mobileAppiumLease.release(reason)\n this.mobileAppiumLease = null\n }\n\n private legacyMobilePlatformConfig(config: LiveSessionConfig): PlatformConfig {\n const platform = config.platform as MobilePlatform\n return {\n platform,\n bundleId: config.bundleId,\n appPackage: config.appPackage,\n appActivity: config.appActivity,\n deepLinkAppId: platform === 'android' ? config.appPackage : config.bundleId,\n appState: config.appState,\n device: config.device\n ? {\n name: config.device.name,\n platform,\n transport: 'local',\n match: config.device,\n }\n : undefined,\n }\n }\n\n private async resolveMobilePlatformConfig(config: LiveSessionConfig): Promise<PlatformConfig> {\n if (\n this.deps.appiumManager\n && this.deps.configManager\n && this.deps.configPath\n && config.targetName\n ) {\n const prepared = await prepareMobileLiveSession({\n sessionId: this.sessionId,\n platform: config.platform as MobilePlatform,\n targetName: config.targetName,\n useDeviceName: config.useDeviceName,\n appState: config.appState,\n appiumManager: this.deps.appiumManager,\n configManager: this.deps.configManager,\n configPath: this.deps.configPath,\n })\n this.mobileAppiumLease = prepared.appiumLease\n return prepared.platformConfig\n }\n\n return this.legacyMobilePlatformConfig(config)\n }\n\n private async setupMobileAdapter(platform: MobilePlatform, config: LiveSessionConfig): Promise<void> {\n let adapter: PlatformAdapter | null = null\n try {\n const platformConfig = await this.resolveMobilePlatformConfig(config)\n const platformLabel = platform === 'android' ? 'Android' : 'iOS'\n try {\n if (platform === 'android') {\n const { AndroidPlatformAdapter } = await import('@vostride/agent-qa-android')\n adapter = new AndroidPlatformAdapter()\n } else {\n const { IOSPlatformAdapter } = await import('@vostride/agent-qa-ios')\n adapter = new IOSPlatformAdapter()\n }\n } catch (err) {\n throw new MobileSetupError({\n category: 'adapter-load',\n message: `Failed to load ${platformLabel} adapter (@vostride/agent-qa-${platform}). Is the package installed? ${err instanceof Error ? err.message : String(err)}`,\n platform,\n targetName: config.targetName,\n deviceName: platformConfig.device?.name,\n appId: platform === 'android' ? platformConfig.appPackage : platformConfig.bundleId,\n cause: err,\n })\n }\n\n try {\n await adapter.setup(platformConfig)\n } catch (err) {\n throw wrapAdapterSetupError(err, platform, platformConfig)\n }\n this.adapter = adapter\n } catch (err) {\n try {\n await adapter?.cleanup()\n } catch {}\n this.releaseMobileAppiumLease('setup-failed')\n if (err instanceof MobileSetupError) {\n throw new Error(mobileSetupMessage(err))\n }\n throw err\n }\n }\n\n async initialize(config: LiveSessionConfig): Promise<void> {\n // 432 D-18: refuse a production target before the first setup effect. The door has already\n // asked, and this asks again because `initialize` is callable apart from it. A name the door\n // found production stays refused here unless the config read now opts in.\n const found = await resolveLiveTargetProduction(this.deps.configManager, config.targetName)\n const refusal = liveProductionRefusal({\n productionTargetNames: distinctInFirstOccurrenceOrder([\n ...(config.production?.productionTargetNames ?? []),\n ...found.productionTargetNames,\n ]),\n allowProduction: found.allowProduction,\n })\n if (refusal !== undefined) throw refusal\n\n this.platform = config.platform\n this.targetName = typeof config.targetName === 'string' && config.targetName.trim().length > 0\n ? config.targetName.trim()\n : null\n this._modelName = config.llmConfig.model ?? 'unknown'\n this.variableStore = new VariableStore()\n this.secretStore = config.secretStore\n this.secretRedactor = config.secretRedactor\n if (config.envVars) {\n this.variableStore.setAll(config.envVars, 'env')\n }\n this.setupHooks = [...(config.setupHooks ?? [])]\n this.teardownHooks = [...(config.teardownHooks ?? [])]\n this.resolvedHooks = new Map(config.resolvedHooks ?? [])\n this.hookRegistryError = config.hookRegistryError ?? null\n this.vision = config.llmConfig.vision\n this.plannerLimits = config.plannerLimits\n this.plannerLimitsForTest = config.plannerLimitsForTest\n this.readyForInteraction = false\n this.terminalError = null\n\n const setupResult = await this.runLifecycleHooks('setup', this.setupHooks)\n if (!setupResult.allPassed) {\n this.status = 'idle'\n this.createdAt = Date.now()\n this.terminalError = 'Setup hooks failed. End the session or fix the hook configuration and reconnect.'\n return\n }\n\n if (config.platform === 'android') {\n await this.setupMobileAdapter('android', config)\n this.currentUrl = null\n } else if (config.platform === 'ios') {\n await this.setupMobileAdapter('ios', config)\n this.currentUrl = null\n } else {\n const { WebPlatformAdapter } = await import('@vostride/agent-qa-web')\n const adapter = new WebPlatformAdapter()\n await adapter.setup({ platform: 'web', browser: { name: 'chromium', headless: config.headless ?? true } })\n this.adapter = adapter\n\n if (config.url) {\n const resolvedUrl = this.resolveSecrets(config.url)\n await adapter.execute({ type: 'navigate', to: 'url', url: resolvedUrl })\n this.currentUrl = resolvedUrl\n } else {\n this.currentUrl = 'about:blank'\n }\n }\n this.openLiveHub()\n\n const { vision: _visionSizing, modelVision, ...modelIdentity } = config.llmConfig\n void _visionSizing\n const runtimeAuth = authFromRuntimeConfig(\n modelIdentity,\n authFromFetch(modelIdentity.provider, config.authFetch),\n )\n const { profile, auth } = toModelProfileAndAuth(modelIdentity, runtimeAuth)\n const capabilities = resolveCapabilities(profile)\n // 439 D-19: the live editor resolves vision as the CLI does, from the model it uses.\n this.visionGate = resolveVisionGate({ vision: visionFromConfig(modelVision, capabilities) })\n const plannerDeclared: DeclaredModelProfile = {\n provider: profile.provider,\n modelId: profile.model,\n vision: capabilities.vision,\n maxOutputTokens: capabilities.maxOutput,\n }\n const verifierDeclared: DeclaredModelProfile = {\n provider: profile.provider,\n modelId: profile.model,\n vision: capabilities.vision,\n maxOutputTokens: capabilities.maxOutput,\n }\n this.modelProfiles = { planner: plannerDeclared, verifier: verifierDeclared }\n this.model = createModel(profile, auth, (text) => this.secretRedactor?.redactString(text) ?? text)\n // Both roles share this.model here, but hold separate accounting instances per role so\n // each owns its own cache anchor (D-11); the D-04 lazy thunk re-reads `profile` per call.\n const plannerAccounting = createTokenAccounting({ getCapabilities: () => resolveCapabilities(profile) })\n const verifierAccounting = createTokenAccounting({ getCapabilities: () => resolveCapabilities(profile) })\n this.planner = new LLMPlanner(this.model, config.platform, undefined, undefined, plannerAccounting, plannerDeclared)\n this.verifier = new LLMVerifier(this.model, verifierAccounting, verifierDeclared)\n\n this.status = 'idle'\n this.createdAt = Date.now()\n this.readyForInteraction = true\n }\n\n private async resolveStepInstruction(stepInstruction: string): Promise<{\n instruction: string\n originalStepName?: string\n executionLogs: LiveExecutionLog[]\n preparationError?: string\n }> {\n const originalStepName = stepInstruction\n let instruction = stepInstruction\n let hasTemplateVars = false\n const executionLogs: LiveExecutionLog[] = []\n\n const inlineHookCalls = parseHookInline(stepInstruction)\n if (inlineHookCalls.length > 0) {\n let inlineHookFailed = false\n\n for (const call of inlineHookCalls) {\n const hookDef = this.resolvedHooks.get(call.hookId)\n if (!hookDef) {\n return {\n instruction: stepInstruction,\n originalStepName,\n executionLogs,\n preparationError: `Inline hook \"${call.hookId}\" is not defined in hooks.yaml`,\n }\n }\n\n const startedAt = performance.now()\n try {\n const result = await new DockerHookExecutor().execute(hookDef, {\n env: this.getHookEnvVars(),\n secretEnv: resolveSecretEnv(this.secretStore),\n secretRedactor: this.secretRedactor,\n })\n executionLogs.push({\n id: randomUUID(),\n type: 'hook',\n name: hookDef.name,\n hookId: hookDef.id,\n phase: 'inline',\n status: result.success ? 'passed' : 'failed',\n duration: result.duration,\n stdout: this.redact(result.stdout),\n stderr: this.redact(result.stderr),\n returnData: null,\n variables: Object.keys(result.variables).length > 0 ? this.redact(result.variables) : null,\n createdAt: new Date().toISOString(),\n })\n\n if (result.success) {\n if (Object.keys(result.variables).length > 0) {\n this.variableStore!.setAll(result.variables, 'hook')\n }\n } else {\n inlineHookFailed = true\n break\n }\n } catch (error) {\n executionLogs.push({\n id: randomUUID(),\n type: 'hook',\n name: hookDef.name,\n hookId: hookDef.id,\n phase: 'inline',\n status: 'failed',\n duration: performance.now() - startedAt,\n stdout: null,\n stderr: this.redact(error instanceof Error ? error.message : String(error)),\n returnData: null,\n variables: null,\n createdAt: new Date().toISOString(),\n })\n inlineHookFailed = true\n break\n }\n }\n\n instruction = stripHookInline(stepInstruction)\n hasTemplateVars = true\n\n if (inlineHookFailed) {\n return {\n instruction,\n originalStepName,\n executionLogs,\n preparationError: 'Inline hook execution failed',\n }\n }\n }\n\n instruction = interpolateVariables(instruction, this.variableStore!)\n hasTemplateVars = hasTemplateVars || originalStepName !== instruction\n\n const runJSMatches = parseRunJSInline(instruction)\n if (runJSMatches.length > 0) {\n if (this.adapter?.platform === 'web') {\n const page = 'getPage' in this.adapter\n ? (this.adapter as { getPage?: () => { evaluate: (code: string) => Promise<unknown> } | undefined }).getPage?.()\n : undefined\n\n if (page) {\n for (const match of runJSMatches) {\n const startedAt = performance.now()\n let status: 'passed' | 'failed' = 'passed'\n let stderr: string | null = null\n let stdout: string\n let returnData: unknown = null\n\n try {\n returnData = await page.evaluate(match.code)\n returnData = this.redact(returnData)\n stdout = this.redact(coerceRunJSResult(returnData))\n instruction = instruction.replace(match.fullMatch, stdout)\n } catch (err) {\n status = 'failed'\n stderr = this.redact(err instanceof Error ? err.message : String(err))\n stdout = `[runJS error: ${stderr}]`\n instruction = instruction.replace(match.fullMatch, stdout)\n }\n\n executionLogs.push({\n id: randomUUID(),\n type: 'runjs',\n name: match.code.slice(0, 200),\n phase: 'inline',\n status,\n duration: performance.now() - startedAt,\n stdout: status === 'passed' ? stdout : '',\n stderr,\n returnData,\n variables: null,\n createdAt: new Date().toISOString(),\n })\n }\n } else {\n for (const match of runJSMatches) {\n const stdout = '[runJS error: no browser page available]'\n instruction = instruction.replace(\n match.fullMatch,\n stdout,\n )\n executionLogs.push({\n id: randomUUID(),\n type: 'runjs',\n name: match.code.slice(0, 200),\n phase: 'inline',\n status: 'failed',\n duration: 0,\n stdout: null,\n stderr: 'no browser page available',\n returnData: null,\n variables: null,\n createdAt: new Date().toISOString(),\n })\n }\n }\n } else {\n for (const match of runJSMatches) {\n const stdout = '[runJS error: runJS is only supported on web platform]'\n instruction = instruction.replace(\n match.fullMatch,\n stdout,\n )\n executionLogs.push({\n id: randomUUID(),\n type: 'runjs',\n name: match.code.slice(0, 200),\n phase: 'inline',\n status: 'failed',\n duration: 0,\n stdout: null,\n stderr: 'runJS is only supported on web platform',\n returnData: null,\n variables: null,\n createdAt: new Date().toISOString(),\n })\n }\n }\n hasTemplateVars = true\n }\n\n return {\n instruction,\n originalStepName: hasTemplateVars ? originalStepName : undefined,\n executionLogs,\n }\n }\n\n private buildPreparationFailureResult(\n instruction: string,\n error: string,\n originalStepName: string | undefined,\n executionLogs: LiveExecutionLog[],\n ): LiveStepExecutionResult {\n const result: LiveStepExecutionResult = {\n name: instruction,\n status: 'failed',\n duration: 0,\n error,\n trace: {\n observation: '',\n reasoning: error,\n plannedAction: { type: 'waitFor', on: 'text', text: '', timeoutMs: 0 },\n result: 'failure',\n error,\n screenStateBefore: '',\n },\n variableSnapshot: this.variableStore!.snapshot(),\n executionLogs,\n originalStepName,\n }\n return this.redact(result)\n }\n\n // Inner step execution — no gating. Callers must own the executing/status\n // lifecycle (executeStepCommand for single steps, executeTestCommand for\n // the per-test loop that runs many steps under one outer gate).\n // D-14 (Phase 360): lazily construct the run-scoped storage-state store, rooted at the session's\n // `.agent-qa` runtime dir. All fs writes live in runner-local (validate:arch storageNeutral);\n // the loop records only { name, fingerprint }. Absent configPath falls back to the cwd root.\n private async getStorageStateStore(): Promise<StorageStatePort> {\n let store = this.storageStateStore\n if (!store) {\n const { FsStorageStateStore } = await import('@vostride/agent-qa-runner-local')\n const root = resolvePath(this.deps.configPath ? dirname(this.deps.configPath) : process.cwd(), '.agent-qa')\n store = new FsStorageStateStore({ root })\n this.storageStateStore = store\n }\n return store\n }\n\n private async executeStepInternal(\n stepInstruction: string,\n stepIndex: number | undefined,\n onPhase: ((event: StepPhaseEvent) => void) | undefined,\n draft: LiveDraftMetadata | undefined,\n limits: PlannerLimits,\n ): Promise<LiveStepExecutionResult> {\n this.abortController = new AbortController()\n try {\n const prepared = await this.resolveStepInstruction(stepInstruction)\n if (prepared.preparationError) {\n const result = this.buildPreparationFailureResult(\n prepared.instruction,\n prepared.preparationError,\n prepared.originalStepName,\n prepared.executionLogs,\n )\n this.stepsExecuted++\n return result\n }\n const unresolvedTemplates = findUnresolvedTemplates(prepared.instruction)\n if (unresolvedTemplates.length > 0) {\n const errorLines = unresolvedTemplates.map((template) => ` - ${template.pattern}: ${template.message}`)\n const error = `Unresolved template variable(s):\\n${errorLines.join('\\n')}`\n const result = this.buildPreparationFailureResult(\n prepared.instruction,\n error,\n prepared.originalStepName,\n prepared.executionLogs,\n )\n this.stepsExecuted++\n return result\n }\n\n const ports: LoopPorts = {\n adapter: this.adapter!,\n planner: this.planner!,\n verifier: this.verifier!,\n modelProfiles: this.modelProfiles ?? undefined,\n plannerConfig: { ...limits, previousStepCount: 5 },\n vision: this.vision,\n visionGate: this.visionGate,\n onSetVariable: (name, value) => this.variableStore!.set(name, value, 'step'),\n abortSignal: this.abortController.signal,\n secretStore: this.secretStore,\n secretRedactor: this.secretRedactor,\n storageState: await this.getStorageStateStore(),\n }\n\n const allVars = this.variableStore!.getAll()\n const variables: Record<string, string> = {}\n for (const [k, v] of allVars) variables[k] = v\n\n const stepContext: StepContext = {\n stepInstruction: prepared.instruction,\n testName: draft?.testName?.trim() || 'Unnamed live draft',\n testContext: draft?.testContext?.trim() || undefined,\n previousSteps: this.previousSteps,\n plannerModel: this.model!,\n verifierModel: this.model!,\n variables: this.redact(variables),\n }\n\n let result = await executeStep(prepared.instruction, ports, stepContext) as LiveStepExecutionResult\n result.originalStepName = prepared.originalStepName\n result.variableSnapshot = this.variableStore!.snapshot()\n result.executionLogs = this.redact(prepared.executionLogs)\n result.subActionsData = toLiveSubActionData(result)\n if ('pollDeviceLogs' in this.adapter! && typeof (this.adapter as { pollDeviceLogs?: () => Promise<void> }).pollDeviceLogs === 'function') {\n await (this.adapter as { pollDeviceLogs: () => Promise<void> }).pollDeviceLogs()\n }\n result.consoleLogs = this.adapter!.drainConsoleLogs?.()\n result.networkLogs = this.adapter!.drainNetworkLogs?.()\n result = this.redact(result)\n\n if (result.status !== 'cancelled') {\n this.previousSteps.push({ instruction: prepared.instruction, outcome: result.status })\n }\n this.stepsExecuted++\n return result\n } finally {\n this.abortController = null\n }\n }\n\n async executeStepCommand(\n stepInstruction: string,\n stepIndex?: number,\n onPhase?: (event: StepPhaseEvent) => void,\n draft?: LiveDraftMetadata,\n ): Promise<LiveStepExecutionResult> {\n if (!this.readyForInteraction || !this.adapter || !this.model || !this.planner || !this.verifier || !this.variableStore) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n\n if (this.executing) {\n throw new Error('Step already executing')\n }\n\n this.executing = true\n this.status = 'executing'\n this.currentStep = stepInstruction\n try {\n return await this.executeStepInternal(\n stepInstruction,\n stepIndex,\n onPhase,\n draft,\n this.plannerLimits ?? resolvePlannerLimits(),\n )\n } finally {\n this.executing = false\n this.currentStep = null\n this.status = 'idle'\n }\n }\n\n async executeTestCommand(\n testExecutionId: string,\n testDraft: {\n testIndex: number\n testId: string\n testName: string\n testContext?: string\n steps: string[]\n setup: string[]\n teardown: string[]\n },\n onPhase?: (event: StepPhaseEvent) => void,\n ): Promise<LiveTestResultPayload> {\n if (!this.readyForInteraction || !this.adapter || !this.model || !this.planner || !this.verifier || !this.variableStore) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n\n if (this.executing) {\n throw new Error('Test already executing')\n }\n\n this.executing = true\n this.status = 'executing'\n this.currentStep = `test: ${testDraft.testName}`\n const start = performance.now()\n const testExecution: LiveTestExecutionPayload = {\n testExecutionId,\n testIndex: testDraft.testIndex,\n testId: testDraft.testId,\n testName: testDraft.testName,\n }\n const testOwner: LiveHookOwner = {\n scope: 'test',\n testExecutionId,\n testIndex: testDraft.testIndex,\n testId: testDraft.testId,\n testName: testDraft.testName,\n }\n\n try {\n // 436 D-03: a test runs at its own effective limits (project, suite, then its own `use`),\n // resolved once before its first step, exactly as the CLI suite producer resolves a member.\n let testLimits: PlannerLimits\n try {\n testLimits = this.plannerLimitsForTest !== undefined && testDraft.testId.length > 0\n ? await this.plannerLimitsForTest(testDraft.testId)\n : this.plannerLimits ?? resolvePlannerLimits()\n } catch (error) {\n if (!(error instanceof LivePlannerLimitsRefusedError)) throw error\n console.warn(`[live-session] executeTestCommand: ${error.message}`, { testName: testDraft.testName })\n return this.redact({\n status: 'failed',\n duration: performance.now() - start,\n error: error.message,\n setupHookExecutions: [],\n stepResults: [],\n teardownHookExecutions: [],\n })\n }\n\n // Per-test setup (D-09). Per-test setup failure short-circuits the\n // test AND skips per-test teardown, matching suite/runner.ts:230 break\n // (Pitfall 2). Suite-level teardown still fires at session cleanup.\n const setupHookPayloads: LiveHookPayload[] = []\n const setupResult = await this.runLifecycleHooksCapturing(\n 'setup',\n testDraft.setup,\n setupHookPayloads,\n testOwner,\n )\n if (!setupResult.allPassed) {\n const failedHook = setupHookPayloads.find((h) => h.status === 'failed')\n const detail = failedHook\n ? `Setup hook \"${failedHook.hookName}\" failed${failedHook.error ? `: ${failedHook.error}` : ''}${failedHook.stderr ? ` — ${failedHook.stderr.split('\\n')[0].slice(0, 200)}` : ''}`\n : 'Per-test setup hook failed'\n console.warn(`[live-session] executeTestCommand: ${detail}`, {\n testName: testDraft.testName,\n setupHooks: testDraft.setup,\n failedHook: failedHook ? { name: failedHook.hookName, stderr: failedHook.stderr, error: failedHook.error } : null,\n })\n return {\n status: 'failed',\n duration: performance.now() - start,\n error: detail,\n setupHookExecutions: setupHookPayloads,\n stepResults: [],\n teardownHookExecutions: [],\n }\n }\n\n // Shared browser context (D-01): each step reuses the same adapter\n // instance. Per-step context carries the TEST's name/context, not\n // the suite's, so the LLMPlanner matches production runTest behaviour.\n const stepResults: LiveStepResultPayload[] = []\n const perStepDraft: LiveDraftMetadata = {\n testName: testDraft.testName,\n testContext: testDraft.testContext,\n }\n let anyCancelled = false\n let anyFailed = false\n for (let i = 0; i < testDraft.steps.length; i++) {\n const stepPayload: LiveTestStepPayload = {\n ...testExecution,\n stepIndex: i,\n stepInstruction: testDraft.steps[i],\n }\n this.emitTestStepStart(stepPayload)\n\n let execResult: LiveStepExecutionResult\n try {\n execResult = await this.executeStepInternal(\n testDraft.steps[i],\n i,\n (event) => {\n this.emitTestStepPhase(stepPayload, event)\n onPhase?.(event)\n },\n perStepDraft,\n testLimits,\n )\n } catch (error) {\n const message = this.redact(error instanceof Error ? error.message : String(error))\n this.emitTestStepError(stepPayload, message)\n stepResults.push({\n status: 'failed',\n duration: 0,\n error: message,\n })\n anyFailed = true\n break\n }\n\n this.emitTestStepComplete(stepPayload, execResult)\n stepResults.push(toStepResultPayload(execResult))\n if (execResult.status === 'cancelled') {\n anyCancelled = true\n break\n }\n if (execResult.status === 'failed') {\n anyFailed = true\n break\n }\n }\n\n // Per-test teardown always fires when steps began (D-09 + D-25).\n const teardownHookPayloads: LiveHookPayload[] = []\n const teardownResult = await this.runLifecycleHooksCapturing(\n 'teardown',\n testDraft.teardown,\n teardownHookPayloads,\n testOwner,\n )\n\n const finalStatus: LiveTestResultPayload['status'] = anyCancelled\n ? 'cancelled'\n : anyFailed || !teardownResult.allPassed\n ? 'failed'\n : 'passed'\n\n let topLevelError: string | undefined\n if (anyFailed) {\n const failedStep = stepResults.find((s) => s.status === 'failed')\n if (failedStep) {\n const stepIdx = stepResults.indexOf(failedStep)\n topLevelError = `Step ${stepIdx + 1} (${testDraft.steps[stepIdx] ?? '<unknown>'}) failed${failedStep.error ? `: ${failedStep.error}` : ''}`\n }\n } else if (!teardownResult.allPassed) {\n const failedHook = teardownHookPayloads.find((h) => h.status === 'failed')\n topLevelError = failedHook\n ? `Teardown hook \"${failedHook.hookName}\" failed${failedHook.error ? `: ${failedHook.error}` : ''}`\n : 'Teardown hook failed'\n }\n if (topLevelError) {\n console.warn(`[live-session] executeTestCommand: ${topLevelError}`, { testName: testDraft.testName })\n }\n\n return this.redact({\n status: finalStatus,\n duration: performance.now() - start,\n error: topLevelError,\n setupHookExecutions: setupHookPayloads,\n stepResults,\n teardownHookExecutions: teardownHookPayloads,\n })\n } finally {\n this.executing = false\n this.currentStep = null\n this.status = 'idle'\n }\n }\n\n // Thin wrapper around runLifecycleHooks that also captures the dispatched\n // hook payloads (hook-complete) for inclusion in the LiveTestResultPayload.\n // The capture sits beside the message sink rather than wrapping it, so a\n // control socket that reattaches mid-hook keeps its sink (428 CR-01).\n private async runLifecycleHooksCapturing(\n phase: 'setup' | 'teardown',\n hookIds: string[],\n sink: LiveHookPayload[],\n owner: LiveHookOwner = { scope: 'suite' },\n ): Promise<{ allPassed: boolean; logs: LiveExecutionLog[] }> {\n this.hookCaptures.add(sink)\n try {\n return await this.runLifecycleHooks(phase, hookIds, owner)\n } finally {\n this.hookCaptures.delete(sink)\n }\n }\n\n async captureWebAuthState(\n name: string,\n options: { replace?: boolean } = {},\n ): Promise<AuthStateMetadata> {\n if (this.platform !== 'web') {\n throw new Error('Auth-state capture is only available for web Live Mode sessions.')\n }\n\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready for auth-state capture.')\n }\n\n if (this.adapter.platform !== 'web') {\n throw new Error('Auth-state capture is only available for web Live Mode sessions.')\n }\n\n if (this.executing) {\n throw new Error('Cannot save auth state while the Live Mode session is executing.')\n }\n\n if (!this.targetName) {\n throw new Error('Cannot save auth state because this Live Mode session has no configured target.')\n }\n\n if (!this.deps.configManager || !this.deps.configPath) {\n throw new Error('Cannot save auth state because workspace config is unavailable.')\n }\n\n const context = getWebStorageStateContext(this.adapter)\n if (!context) {\n throw new Error('Cannot save auth state because the active browser context is unavailable.')\n }\n\n const config = await readConfigValues(this.deps.configManager)\n const authStateDir = getConfiguredAuthStateDir(config)\n const paths = resolveAuthStatePaths({\n configDir: dirname(resolvePath(this.deps.configPath)),\n authStateDir,\n targetName: this.targetName,\n stateName: name,\n target: { platform: 'web' },\n })\n\n let existing: AuthStateMetadata | null = null\n try {\n existing = await readAuthStateMetadata(paths)\n } catch {\n existing = null\n }\n if (existing && options.replace !== true) {\n throw new Error(`Auth state \"${paths.stateName}\" for target \"${paths.targetName}\" already exists. Use replace=true to replace it.`)\n }\n\n const payload = await context.storageState({ indexedDB: true })\n const metadata: AuthStateMetadata = {\n version: AUTH_STATE_SCHEMA_VERSION,\n kind: 'web',\n target: paths.targetName,\n name: paths.stateName,\n capturedAt: new Date().toISOString(),\n }\n\n try {\n await writeAuthStateFiles(paths, { payload, metadata })\n } catch {\n throw new Error(`Could not save auth state \"${paths.stateName}\" for target \"${paths.targetName}\".`)\n }\n\n return metadata\n }\n\n cancelStep(): void {\n this.abortController?.abort()\n }\n\n async navigate(url: string): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n const resolvedUrl = this.resolveSecrets(url)\n await this.adapter!.execute({ type: 'navigate', to: 'url', url: resolvedUrl })\n if (this.platform === 'web') {\n this.currentUrl = resolvedUrl\n } else {\n this.currentUrl = null\n }\n return this.currentUrl\n }\n\n async refreshPage(): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n if (this.platform !== 'web') return this.currentUrl\n await this.adapter!.execute({ type: 'navigate', to: 'reload' })\n const page = (this.adapter as any).getPage?.()\n if (page) this.currentUrl = page.url()\n return this.currentUrl ?? 'about:blank'\n }\n\n async goBack(): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n if (this.platform !== 'web') return this.currentUrl\n await this.adapter!.execute({ type: 'navigate', to: 'back' })\n const page = (this.adapter as any).getPage?.()\n if (page) this.currentUrl = page.url()\n return this.currentUrl ?? 'about:blank'\n }\n\n async goForward(): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) {\n throw new Error(this.terminalError ?? 'Live session is not ready')\n }\n if (this.platform !== 'web') return this.currentUrl\n await this.adapter!.execute({ type: 'navigate', to: 'forward' })\n const page = (this.adapter as any).getPage?.()\n if (page) this.currentUrl = page.url()\n return this.currentUrl ?? 'about:blank'\n }\n\n async drainDeviceLogs(): Promise<Array<{ level: string; message: string; timestamp: number }>> {\n if (!this.adapter) return []\n if (typeof (this.adapter as any).pollDeviceLogs === 'function') {\n await (this.adapter as any).pollDeviceLogs()\n }\n if (typeof this.adapter.drainConsoleLogs === 'function') {\n return this.redact(this.adapter.drainConsoleLogs().map((e) => ({ level: e.level, message: e.text, timestamp: e.timestamp })))\n }\n return []\n }\n\n getState(): SessionState {\n return {\n sessionId: this.sessionId,\n platform: (this.adapter?.platform ?? this.platform) as 'web' | 'android' | 'ios',\n targetName: this.targetName,\n status: this.status === 'terminated' ? 'idle' : this.status === 'executing' ? 'executing' : this.status,\n currentStep: this.currentStep,\n currentUrl: this.currentUrl,\n stepsExecuted: this.stepsExecuted,\n createdAt: this.createdAt,\n interactive: this.readyForInteraction,\n terminalError: this.terminalError,\n }\n }\n\n async getAriaTree(): Promise<string | null> {\n if (!this.readyForInteraction || !this.adapter) return null\n if (!this.adapter) return null\n const screenState = await this.adapter.observe()\n return screenState.tree\n }\n\n startIdleTimer(onExpire: () => void): void {\n this.clearIdleTimer()\n // 428 WR-02: an ended session has nothing left to expire, and the window never holds the\n // process open on its own.\n if (this.cleanupRun !== null) return\n this.idleTimer = setTimeout(onExpire, IDLE_TIMEOUT_MS)\n this.idleTimer.unref?.()\n }\n\n clearIdleTimer(): void {\n if (this.idleTimer) {\n clearTimeout(this.idleTimer)\n this.idleTimer = null\n }\n }\n\n /** Idempotent: every later or concurrent call shares the first run, so teardown happens once. */\n cleanup(): Promise<void> {\n if (this.status === 'terminated') return Promise.resolve()\n this.cleanupRun ??= this.runCleanup()\n return this.cleanupRun\n }\n\n private async runCleanup(): Promise<void> {\n this.clearIdleTimer()\n this.readyForInteraction = false\n // 428 WR-02: the attached control socket is told the session is gone, however it ended.\n const release = this.releaseAttachment\n this.releaseAttachment = null\n release?.('ended')\n // The hub closes first, so subscribers hear 'closed' and the screencast stops before the\n // browser that produces it goes away. Its close waits on the screencast's CDP stop, which a\n // wedged renderer never answers, so the wait is bounded and teardown always goes on (428 WR-03).\n const hub = this.liveHub\n this.liveHub = null\n if (hub) {\n let limit: ReturnType<typeof setTimeout> | undefined\n await Promise.race([\n hub.close().catch(() => undefined),\n new Promise<void>((resolve) => {\n limit = setTimeout(resolve, LIVE_HUB_CLOSE_LIMIT_MS)\n }),\n ])\n clearTimeout(limit)\n }\n this.resolveEnded()\n try {\n await this.adapter?.cleanup()\n } finally {\n try {\n await this.runLifecycleHooks('teardown', this.teardownHooks)\n } finally {\n this.releaseMobileAppiumLease('session-cleanup')\n this.messageSink = null\n this.status = 'terminated'\n }\n }\n }\n}\n","import { getProviderOptions } from '@vostride/agent-qa-model'\n\nimport type { ModelAuthDeclaration, ModelProfile, ResolvedModelAuth } from '@vostride/agent-qa-model'\n\ntype ModelAdapter = 'openai-responses' | 'anthropic-messages'\n\nexport interface DashboardLLMConfig {\n provider: string\n model: string\n baseURL?: string\n providerHeaders?: Record<string, string>\n apiKey?: string\n authToken?: string\n modelAdapter?: ModelAdapter\n}\n\nexport type DashboardResolvedAuth =\n | { kind: 'api-key'; apiKey: string }\n | { kind: 'bearer-token'; token: string }\n | { kind: 'auth-fetch'; fetch: typeof globalThis.fetch; modelAdapter: ModelAdapter }\n | { kind: 'unauthenticated'; message?: string }\n | { kind: 'missing'; message: string }\n | ResolvedModelAuth\n\nexport function toModelProfileAndAuth(\n llmConfig: DashboardLLMConfig,\n resolvedAuth: DashboardResolvedAuth,\n): { profile: ModelProfile; auth: ResolvedModelAuth } {\n if (resolvedAuth.kind === 'missing') {\n throw new Error(resolvedAuth.message)\n }\n\n const auth = toResolvedModelAuth(resolvedAuth)\n const providerOptions = getProviderOptions({\n provider: llmConfig.provider,\n modelAdapter: auth.kind === 'auth-fetch' ? auth.modelAdapter : llmConfig.modelAdapter,\n fetch: auth.kind === 'auth-fetch' ? auth.fetch : undefined,\n })\n\n const profile: ModelProfile = {\n provider: llmConfig.provider,\n model: llmConfig.model,\n ...(llmConfig.baseURL !== undefined ? { baseURL: llmConfig.baseURL } : {}),\n ...(llmConfig.providerHeaders !== undefined ? { headers: llmConfig.providerHeaders } : {}),\n ...(providerOptions ? { providerOptions } : {}),\n auth: toAuthDeclaration(auth),\n }\n\n return { profile, auth }\n}\n\nexport function authFromFetch(\n provider: string,\n authFetch?: typeof globalThis.fetch,\n): ResolvedModelAuth {\n if (authFetch) {\n return {\n kind: 'auth-fetch',\n modelAdapter: adapterForProvider(provider),\n fetch: authFetch,\n }\n }\n return { kind: 'none' }\n}\n\nexport function authFromRuntimeConfig(\n llmConfig: Pick<DashboardLLMConfig, 'apiKey' | 'authToken'>,\n fallback: ResolvedModelAuth = { kind: 'none' },\n): ResolvedModelAuth {\n if (fallback.kind !== 'none') return fallback\n if (llmConfig.apiKey) return { kind: 'api-key', apiKey: llmConfig.apiKey }\n if (llmConfig.authToken) return { kind: 'bearer-token', token: llmConfig.authToken }\n return fallback\n}\n\nfunction toResolvedModelAuth(auth: DashboardResolvedAuth): ResolvedModelAuth {\n switch (auth.kind) {\n case 'api-key':\n return { kind: 'api-key', apiKey: auth.apiKey }\n case 'bearer-token':\n return { kind: 'bearer-token', token: auth.token }\n case 'auth-fetch':\n return { kind: 'auth-fetch', modelAdapter: auth.modelAdapter, fetch: auth.fetch }\n case 'unauthenticated':\n case 'none':\n return { kind: 'none' }\n case 'missing':\n throw new Error(auth.message)\n }\n}\n\nfunction toAuthDeclaration(auth: ResolvedModelAuth): ModelAuthDeclaration {\n switch (auth.kind) {\n case 'api-key':\n return { mode: 'api-key' }\n case 'bearer-token':\n return { mode: 'bearer-token' }\n case 'auth-fetch':\n return { mode: 'subscription', plugin: auth.modelAdapter }\n case 'none':\n return { mode: 'none' }\n }\n}\n\nfunction adapterForProvider(provider: string): ModelAdapter {\n if (provider === 'anthropic-subscription') return 'anthropic-messages'\n return 'openai-responses'\n}\n","import { readFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { parse as parseYaml } from 'yaml'\nimport {\n MobileSetupError,\n resolveMobileRunConfig,\n} from '@vostride/agent-qa-core'\nimport type {\n MobilePlatform,\n ResolvedMobileRunConfig,\n} from '@vostride/agent-qa-core'\nimport type { PlatformConfig } from '@vostride/agent-qa-runner'\nimport type { AppiumManager } from '../execution/appium-manager.js'\nimport { readConfigValues, type ConfigManager } from '../config/index.js'\n\ninterface LocalMobileBindings {\n devices?: Record<string, Record<string, unknown>>\n providers?: Record<string, Record<string, unknown>>\n apps?: Record<string, { path?: string; browserstack?: string }>\n filePath?: string\n}\n\nexport interface MobileLiveAppiumLease {\n runId: string\n url: string\n release: (reason?: string) => boolean\n}\n\nexport interface PreparedMobileLiveSession {\n platformConfig: PlatformConfig\n appiumLease: MobileLiveAppiumLease\n resolved: ResolvedMobileRunConfig\n}\n\nexport interface PrepareMobileLiveSessionInput {\n sessionId: string\n platform: MobilePlatform\n targetName?: string\n useDeviceName?: string\n appState?: 'preserve' | 'reset'\n configManager: ConfigManager\n configPath: string\n appiumManager: AppiumManager\n}\n\nasync function loadLocalBindings(configPath: string): Promise<LocalMobileBindings | null> {\n const filePath = join(dirname(configPath), 'agent-qa.local.yaml')\n try {\n const content = await readFile(filePath, 'utf-8')\n const parsed = parseYaml(content) as LocalMobileBindings | null\n return parsed && typeof parsed === 'object'\n ? {\n devices: parsed.devices,\n providers: parsed.providers,\n apps: parsed.apps,\n filePath,\n }\n : { filePath }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null\n throw err\n }\n}\n\nfunction asMobileSetupError(\n err: unknown,\n category: MobileSetupError['category'],\n message: string,\n input: Pick<PrepareMobileLiveSessionInput, 'platform' | 'targetName'>,\n): MobileSetupError {\n if (err instanceof MobileSetupError) return err\n return new MobileSetupError({\n category,\n message: `${message}: ${err instanceof Error ? err.message : String(err)}`,\n platform: input.platform,\n targetName: input.targetName,\n cause: err,\n })\n}\n\nexport async function prepareMobileLiveSession(\n input: PrepareMobileLiveSessionInput,\n): Promise<PreparedMobileLiveSession> {\n if (!input.targetName) {\n throw new MobileSetupError({\n category: 'device-resolution',\n message: `No targetName provided for ${input.platform} live session`,\n platform: input.platform,\n })\n }\n\n const config = await readConfigValues(input.configManager)\n let localBindings: LocalMobileBindings | null = null\n\n try {\n localBindings = await loadLocalBindings(input.configPath)\n } catch (err) {\n throw asMobileSetupError(err, 'device-resolution', 'Failed to read local device bindings', input)\n }\n\n const configuredAppState = (config.use as { mobile?: { appState?: 'preserve' | 'reset' } } | undefined)?.mobile?.appState\n\n let resolved: ResolvedMobileRunConfig\n try {\n resolved = resolveMobileRunConfig({\n config,\n targetName: input.targetName,\n platform: input.platform,\n useDeviceName: input.useDeviceName,\n appState: input.appState ?? configuredAppState,\n localBindings,\n configFilePath: input.configPath,\n localConfigFilePath: localBindings?.filePath,\n })\n } catch (err) {\n throw asMobileSetupError(err, 'device-resolution', 'Failed to resolve mobile live target', input)\n }\n\n try {\n await input.appiumManager.acquireLease({ runId: input.sessionId, platform: input.platform })\n } catch (err) {\n throw new MobileSetupError({\n category: 'appium-startup',\n message: `Failed to acquire Appium for ${input.platform} live session: ${err instanceof Error ? err.message : String(err)}`,\n platform: input.platform,\n targetName: input.targetName,\n deviceName: resolved.deviceName,\n appId: resolved.app.deepLinkAppId,\n sourceTrace: resolved.sourceTrace,\n cause: err,\n })\n }\n\n const appiumUrl = input.appiumManager.getUrl()\n let released = false\n const appiumLease: MobileLiveAppiumLease = {\n runId: input.sessionId,\n url: appiumUrl,\n release: (reason = 'completed') => {\n if (released) return false\n released = true\n return input.appiumManager.releaseLease(input.sessionId, reason)\n },\n }\n\n return {\n resolved: {\n ...resolved,\n appium: {\n url: appiumUrl,\n managed: true,\n },\n },\n appiumLease,\n platformConfig: {\n platform: input.platform,\n device: resolved.device,\n appiumUrl,\n bundleId: resolved.app.bundleId,\n appPackage: resolved.app.appPackage,\n appActivity: resolved.app.appActivity,\n deepLinkAppId: resolved.app.deepLinkAppId,\n appPath: resolved.app.install?.path,\n browserstackApp: resolved.app.install?.browserstack,\n appState: resolved.appState,\n },\n }\n}\n","// The same-site predicate every same-site capability door of this server shares: the mark door,\n// the config and credential writes, the live editor and the `live-url` mint routes. CR-01 records\n// the remaining posture in a filed WINDOWS row owned by the phase that takes whole-server CORS\n// posture, not as solved here.\n//\n// WHY THIS FILE EXISTS. The predicate below was written for the chat door in 400-14 and lived\n// private inside that door's router. Phase 403's verification found the live-url MINT door\n// standing open with the identical shape of hole, and a second door needs the identical answer:\n// two spellings of \"is this cross-site\" is two policies, free to disagree the first time either is\n// edited. The chat door, and later the run-confirm pair that inherited its router, were deleted\n// (430 D-02, 432-14 D-14); the predicate stayed here, rung for rung.\n//\n// THE POLICY IS UNCHANGED BY THE MOVE. What follows is the chat door's recorded policy verbatim,\n// rung for rung, comment for comment.\n\nimport type { IncomingMessage } from 'node:http'\nimport { isLoopbackHost } from '@vostride/agent-qa-core'\n\nexport const NON_LOOPBACK_HOST_REFUSAL =\n 'Cross-site request refused: Host must name a loopback interface this server agreed to answer to.'\n\n/**\n * Parse the authority from an HTTP Host header without treating the value as trustworthy.\n *\n * Brackets are required around an IPv6 literal because an unbracketed second colon is ambiguous\n * with the optional port. Anything outside the complete authority shape is deliberately invalid.\n */\nexport function hostnameOfHostHeader(hostHeader: string | undefined): string {\n if (hostHeader === undefined) return ''\n const normalized = hostHeader.trim().toLowerCase()\n const parsed = /^(?:\\[([0-9a-f:.]*:[0-9a-f:.]*)\\]|([a-z0-9.]+))(?::\\d+)?$/u.exec(normalized)\n return parsed?.[1] ?? parsed?.[2] ?? ''\n}\n\n/**\n * Refuse a claimed Host this loopback-only server never agreed to answer to.\n *\n * An absent Host is refused rather than falling through: a name that was not stated cannot be\n * validated. The compatibility cost is limited to an HTTP/1.0 client that omits Host; HTTP/1.1\n * clients and browsers state it.\n */\nexport function refuseNonLoopbackHost(req: IncomingMessage): string | undefined {\n return isLoopbackHost(hostnameOfHostHeader(req.headers.host))\n ? undefined\n : NON_LOOPBACK_HOST_REFUSAL\n}\n\n/**\n * Refuse a request that a page on another origin drove (400-14, gap 6 — T-400-G6-01/02).\n *\n * THE RECORDED POLICY, and each rung is a decision rather than a default:\n *\n * - An ABSENT `Origin` is ALLOWED. This is a localhost door and its shipped norm is a person with a\n * terminal: `curl`, a script, the CLI. No browser omits `Origin` on a cross-origin POST, so\n * absence is evidence of a non-browser caller, and refusing it would brick every local drive to\n * defend against nothing.\n * - An `Origin` whose HOST equals the request's own `Host` is allowed — that is the dashboard's own\n * page driving its own door, which is exactly what must keep working.\n * - The literal `null` and every other value are REFUSED. `null` is what a sandboxed iframe, a\n * `data:` document and a redirected cross-origin request send; it is not \"no origin\", it is an\n * origin that declined to name itself.\n * - `Sec-Fetch-Site`, when the browser sends it, must say `same-origin` or `none`. It is checked\n * BESIDE `Origin` and not instead of it: it is unforgeable by page script where `Origin` is only\n * unforgeable by fetch, and it is absent on every non-browser client, so neither alone is total.\n *\n * WHY THE SCHEME IS NOT COMPARED. The bound door speaks `http` on loopback and the header carries\n * an absolute origin; comparing hosts keeps the check honest behind the `https` terminator an\n * operator may put in front of it, which is the deployment shape Phase 402 owns.\n *\n * WHY THIS LIVES HERE AND NOT IN `body-parser.ts`. That parser also serves the legacy read routes\n * whose wildcard-CORS posture is Phase 402's re-platform question. Widening it here would change\n * the posture of routes this phase does not own.\n */\nexport function refuseCrossSiteRequest(req: IncomingMessage): string | undefined {\n const hostRefusal = refuseNonLoopbackHost(req)\n if (hostRefusal !== undefined) return hostRefusal\n\n const refusal = 'Cross-site request refused: this door is driven from its own origin or from a '\n + 'local client that sends no Origin'\n const origin = req.headers.origin\n if (typeof origin === 'string' && origin !== '') {\n const host = typeof req.headers.host === 'string' ? req.headers.host.toLowerCase() : ''\n let originHost: string\n try {\n originHost = new URL(origin).host.toLowerCase()\n } catch {\n // Includes the literal `null`, which parses as no URL at all — a sandboxed frame, a\n // `data:` document, or a cross-origin redirect. Refused with everything else.\n return refusal\n }\n if (originHost === '' || host === '' || originHost !== host) return refusal\n }\n\n const site = req.headers['sec-fetch-site']\n if (typeof site === 'string' && site !== 'same-origin' && site !== 'none') return refusal\n\n return undefined\n}\n","// The frames that must answer a request without trusting a byte of it (Phase 400 plan 16, gap 7).\n//\n// WHY THIS IS ONE MODULE AND NOT THREE GUARDS. `server.ts`'s async request listener, `server.ts`'s\n// `upgrade` handler and `routes.ts`'s router head each parsed the request URL with their own\n// `new URL(req.url ?? '/', 'http://localhost')`. Three copies is three chances to add a fourth, and\n// gap round 1 already paid for the door-enumeration shape once: a fix that guards the arms somebody\n// remembered to name cannot be driven to zero by naming more of them. So there is ONE producer of\n// \"parse the request URL safely\" and the three frames import it. A fourth frame added later gets the\n// guard by importing the only parse there is.\n//\n// ---- THE THROW-PATH ENUMERATION -------------------------------------------------------------\n//\n// Every way a request can end this process, and which mechanism here owns it. EXTEND THIS LIST\n// rather than re-deriving it; the reason the list is written down is that the previous round's plan\n// text enumerated these sites in prose, guarded one of them, and shipped.\n//\n// 1. THE REQUEST-LINE PARSE, request listener. `GET //%` and `GET http://[` are request targets\n// `node:http` accepts and the WHATWG URL parser rejects (`//%` reads as protocol-relative with\n// host `%`; `http://[` is an unterminated IPv6 literal). The listener is `async`, so the throw\n// became an UNHANDLED REJECTION and Node ended the process. Owned by `tryParseRequestUrl` +\n// `refuseUnparseableRequest`, which answer 400.\n// 2. THE REQUEST-LINE PARSE, `upgrade` handler. The same two request targets, arriving with\n// `Connection: Upgrade`. This handler is SYNCHRONOUS, so its throw is an uncaught EXCEPTION\n// rather than a rejection: the listener's backstop below cannot see it and neither can\n// `clientError`. Owned by `tryParseRequestUrl` alone, whose `undefined` the handler answers\n// with its existing `socket.destroy()` idiom. This is the one path where the guarded parse and\n// nothing else is what keeps the process alive.\n// 3. THE ROUTER-HEAD PARSE. `routes.ts` parsed the identical URL a second time. Unreachable in\n// production once (1) answers first, and guarded anyway: the router is exported and mounted\n// directly by the conformance suite, so an unguarded copy there is a live throw on a real\n// mount. Owned by `tryParseRequestUrl` + a 400 through the router's own `json` helper.\n// 4. SYNCHRONOUS THROWS OUT OF A ROUTE. `%` inside a PATH is lenient — `/api/suites/%` parses\n// fine — and then `decodeURIComponent` throws a `URIError` inside the route arm. There are\n// ~18 such decode sites and there is no useful sense in which the next one is knowable, which\n// is exactly why they are NOT guarded one by one. Owned by `backstopServerError`, the\n// try/catch around the whole listener body, which answers 500.\n// 5. REJECTED PROMISES THE LISTENER AWAITS. Same owner as (4) — the listener is `async`, so its\n// `catch` covers what it awaits as well as what it throws.\n// 6. BYTES NODE'S OWN PARSER REJECTS, before any handler runs. Owned by the `clientError`\n// listener installed in `server.ts`.\n//\n// NOT owned here: a rejection from a promise a route arm starts and never awaits (a bare `.then()`\n// with no `.catch`). That is a real class, it is upstream of this plan's fence, and it is called\n// out so the next author does not read this list as complete.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\n/**\n * The request URL, or `undefined` when the request line is not one.\n *\n * THE ONE PRODUCER. Its whole contract is that it never throws, which is what lets each caller\n * answer in its own vocabulary — a 400 body, a JSON envelope, a destroyed socket — instead of\n * every frame growing its own `try`.\n */\nexport function tryParseRequestUrl(req: Pick<IncomingMessage, 'url'>): URL | undefined {\n try {\n return new URL(req.url ?? '/', 'http://localhost')\n } catch {\n return undefined\n }\n}\n\n/**\n * Refuse a request whose target could not be parsed, in FIXED BYTES.\n *\n * NOTHING FROM THE REQUEST REACHES THIS RESPONSE, and that is deliberate rather than terse. The\n * refusal exists precisely because the request target is malformed and attacker-chosen; echoing it\n * would put attacker bytes into a body, and formatting it would give the refusal its own way to\n * throw. The previous round recorded the same lesson one layer down: a backstop that answers\n * through the door's own responder can re-enter the fault it was catching.\n */\nexport function refuseUnparseableRequest(res: ServerResponse): void {\n if (res.headersSent) {\n res.destroy()\n return\n }\n const body = 'Bad Request'\n res.writeHead(400, {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n}\n\n/**\n * The process-level backstop's answer: a 500 in fixed bytes, or a destroyed socket if it is late.\n *\n * THE ERROR IS NOT PRINTED AND NOT SERIALIZED. Phase 395 measured a planted credential leaving this\n * product through an error's serialization rather than its `message`, so what goes to stderr here\n * is the error's CONSTRUCTOR NAME and the request METHOD — two values with no attacker- or\n * secret-derived content — and never the URL, which is attacker-chosen, or the error itself, whose\n * `cause` chain is exactly the surface that leaked.\n */\nexport function backstopServerError(\n res: ServerResponse,\n req: Pick<IncomingMessage, 'method'>,\n error: unknown,\n): void {\n const kind = error instanceof Error ? error.constructor.name : typeof error\n console.error(\n `Dashboard: a ${req.method ?? 'request'} handler threw (${kind}); answered 500 rather than `\n + 'ending the process',\n )\n if (res.headersSent) {\n res.destroy()\n return\n }\n const body = 'Internal Server Error'\n res.writeHead(500, {\n 'Content-Type': 'text/plain; charset=utf-8',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n}\n","// The run service's HTTP surface (Phase 402 plan 01, D-02 / D-06 / D-13 / D-15 · INVK-03).\n//\n// 2026-10-01 (432-21, D-12/D-13): TOKENLESS. The bearer verdict this door put first on every route,\n// its `verifyBearer` port and the trust scope a matched token carried into the caller are deleted\n// with `services.dashboard.runServiceTokens`. What stands first on every route now is the\n// dashboard's own same-site guard (`refuseCrossSiteRequest`): a Host this loopback server never\n// agreed to answer to, a foreign `Origin` or a cross-site `Sec-Fetch-Site` is refused before the\n// route table. The paragraphs below that describe the bearer are kept as history and say so.\n//\n// A MOUNTABLE MODULE, NOT A SERVER (D-02). Everything this door needs from the world arrives as\n// {@link RunServicePorts}: how to start a run, how to reach a started run's session, and how to\n// answer readiness. It imports the shared schema vocabulary and\n// node built-ins and NOTHING from `@vostride/agent-qa-agent`, `-agent-local` or `-safety` — those\n// are the packages `packages/dashboard-server` may not name, and `pnpm validate:arch` is the\n// mechanical proof. 402 mounts this in the shipped dashboard process so there is no fourth process\n// and no daemon TCP exposure; a future cloud host mounts the same unit with different ports.\n//\n// THE SAME-SITE GUARD IS FIRST ON EVERY ROUTE, AND ABOVE THE ROUTE TABLE (D-06, D-15; 432-21 D-13).\n// Not per handler — per REQUEST, before dispatch is even attempted. A route added tomorrow inherits\n// the refusal by construction rather than by somebody remembering, and a refused caller cannot\n// learn WHICH paths exist, because a valid path and a nonsense one are refused identically. `/ok` is\n// inside this rule and not an exception to it (D-15). Until 432-21 the rung here was the bearer\n// verdict, whose two-arm type had no permissive arm; the guard that replaced it has none either —\n// a request it does not admit is refused, never served a weaker answer.\n//\n// EVERY REFUSAL WRITES THE SAME BODY SHAPE — one key, a closed code (see\n// `RunServiceErrorBodySchema`). Nothing echoes the caller's input or names a run id.\n//\n// WITH EXACTLY ONE EXCEPTION, AND IT IS ON THE OTHER SIDE OF THE GUARD (402-06). A run DENIAL is\n// answered 403 with the run core's plain refusal sentence (`RunServiceDenialBodySchema`). The\n// one-key law's whole argument is about what a caller refused at the door may learn; a run denial is\n// reached only by a caller the guard admitted, and a bare word would turn a decidable situation into\n// a failure they will retry forever. Since 432 the one run denial is production without the config\n// opt-in (D-18), and since 432-19 the body carries no remedy list.\n//\n// THE STREAM SERVES THE FROZEN BUS ENVELOPE VERBATIM (D-13). SSE `id` is the envelope's `seq`,\n// `event` is its `type`, and `data` is the envelope's own JSON. There is no projection layer and\n// no re-mint: the bus IS the wire contract, so there is no second event vocabulary to drift, and\n// payloads were masked at emit. `Last-Event-ID` resume falls out of seq-as-id nearly free, but the\n// full replay/attach acceptance is 403's (INVK-05); 402 claims delivery, not the attach contract.\n//\n// NO CROSS-ORIGIN GRANT, AT ALL. This file writes no `Access-Control-Allow-Origin`, following the\n// chat door's adjudication rather than the legacy run stream's wildcard. Until 432-21 that was the\n// whole of this door's CSRF story: every route required an `Authorization` header, which made every\n// request non-simple. With no header required, a page could send a SIMPLE cross-site POST, so the\n// same-site guard above the table is what refuses it now, preflight or not.\n//\n// THE `?handle=` FILTER IS SERVER-SIDE, AND ITS PREDICATE LIVES IN THE SCHEMA (402-04, D-14).\n// A parallel run is ONE run id with N attachable per-member handles. The optional `handle` query\n// parameter selects one member's slice; run-scoped envelopes (verdict, `runFinished`, `heartbeat`,\n// the diagnostics, and `runStarted` carrying the roster) ALWAYS pass it, so a handle subscriber\n// still learns that the run ended. This file re-derives none of that: `passesHandleFilter` is\n// imported from `@vostride/agent-qa-schema`, which is the only place an event type's scope is\n// declared. A second spelling here would be a classification that drifts silently (T-402-15),\n// because the two would agree on the day it was written and disagree the first time an event type\n// is appended.\n//\n// THE HANDLE IS VALIDATED BEFORE ANY STREAM HEADER, on the same rule as the run id and for the\n// same reason: a `200 text/event-stream` cannot be told it failed. Validation is in two parts, and\n// the two answers are kept apart — a malformed parameter is `invalid_handle`, a well-formed one\n// naming no member of this run is `unknown_handle`. Neither echoes the value.\n//\n// THE ROSTER IS READ OFF THE SESSION'S OWN REPLAYED `runStarted`, deliberately, rather than from\n// bookkeeping the attach port could keep. The run's own header IS the roster announcement, so\n// reading it here means the door validates against exactly what the stream is about to serve\n// rather than against a second copy that could disagree. `runStarted` is seq 1 and `subscribe`\n// replays synchronously from `REPLAY_FROM_START`, so the roster is in hand before `writeHead`.\n// A run whose `runStarted` announces no roster cannot answer a per-handle question at all, and the\n// honest answer to one is a refusal — not an unfiltered stream (which would serve every member's\n// data to a caller who asked for one) and not an empty one (which would look like a member that\n// did nothing).\n//\n// 2026-10-01 (432-21): no bearer is carried at all, in a header or a URL. This door's clients are\n// still `curl`, `fetch` and CI; none of them sends an `Origin`, which is what the guard admits.\n//\n// BACKPRESSURE POSTURE, STATED RATHER THAN OVERLOOKED: writes are fire-and-forget with no `drain`\n// handling, matching both shipped SSE streams in this package. A client that reads slower than a\n// run emits grows this process's socket buffer. That is the shipped posture for run streaming and\n// this door does not change it; a bounded-writer policy is one decision for all three streams, not\n// a thing to invent here for one of them.\n//\n// REMOTE CANCEL IS DEFERRED (2026-08-24, Phase 402 · D-01 discretion note). Criterion 1 requires\n// start + stream only. Cancel is a control affordance and belongs with 403's attach/detach world,\n// where detach, reconnect and multi-surface addressing decide together what \"stop it\" means for a\n// run several surfaces are watching. Nothing here forecloses it: it is a fourth row in the table\n// below and a fifth port.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport {\n RUN_SERVICE_REFUSED_REQUEST_FIELDS,\n RunServiceStartRequestSchema,\n handleRosterOf,\n parseHandleParam,\n passesHandleFilter,\n type RunEventEnvelope,\n type RunServiceDenialBody,\n type RunServiceErrorCode,\n type RunServiceReadiness,\n type RunsLiveUrlResult,\n type RunSession,\n type RunStartAcknowledgement,\n} from '@vostride/agent-qa-schema'\n\nimport type { AgentHost } from '../chat/host.js'\nimport { readJsonBody } from '../server/body-parser.js'\nimport { refuseCrossSiteRequest } from '../server/cross-site.js'\n// 405-05 (D-12 / 402 D-16): THE SAME TWO ADAPTERS THE LOCAL DOOR CALLS. Imported rather than\n// re-implemented, because \"both doors answer the same bytes\" is a claim about there being one\n// implementation — two that agree today are two that can stop agreeing.\nimport {\n serveRunArtifact,\n serveRunDetailRead,\n serveRunEvidenceRead,\n serveRunMarkPreviewRead,\n serveRunMarksHistoryRead,\n} from './run-detail-routes.js'\nimport { serveRunAnalysisRead } from './run-analysis-routes.js'\n\n/**\n * The seq a subscriber attaches at to receive the whole run.\n *\n * NEVER 0. The bus numbers from 1 and REFUSES to serve a prefix it cannot produce, so 0 is not\n * \"earlier\", it is unserveable — `subscribe(0, …)` raises `ReplayIncompleteError` on every run,\n * empty window or not. Same constant and same value as `in-process-backend.ts`'s.\n */\nconst REPLAY_FROM_START = 1\n\n/** The comment-frame keepalive interval, matching both shipped SSE streams in this package. */\nconst HEARTBEAT_MS = 15_000\n\n/**\n * The largest request body this door reads.\n *\n * TIGHTER THAN THE SHARED 1 MB DEFAULT, deliberately: the only thing a caller may send is a list\n * of test patterns, and a door that accepts a megabyte of it is a door that will one day be asked\n * to buffer a megabyte of it.\n */\nconst MAX_REQUEST_BYTES = 64 * 1024\n\n/**\n * What starting a run needs from the composition, as data rather than as a live handle.\n *\n * 2026-10-01 (432-21, D-12): the matched token's `trustScope` and `clientId` are deleted with the\n * token. A start carries the caller's pattern set and nothing about who the caller is.\n */\nexport interface RunServiceStartInput {\n /** The pattern set the caller asked for; absent means the configured default set. */\n readonly patterns?: readonly string[]\n}\n\n/**\n * Everything this door reaches the world through (D-02).\n *\n * ALL ARE INJECTED, and the injection is what makes the module mountable: the implementations name\n * `invokeFunction`, `runs.start` and a composed local host, all of it vocabulary this package may\n * not import. `InProcessRunStarter` is the shape precedent one directory over. 2026-10-01 (432-21,\n * D-12): `verifyBearer` is deleted; the same-site guard needs no port.\n */\nexport interface RunServicePorts {\n /**\n * Start a run and return the acknowledgment.\n *\n * REJECTION IS NOT \"the run failed\" — a failing run still acknowledges. A rejection is a denial,\n * a refused request field, an input error or a crash.\n */\n invokeRunStart(input: RunServiceStartInput): Promise<RunStartAcknowledgement>\n /** The started run's session, or nothing if this process never started that run. */\n attach(runId: string): RunSession | undefined\n /** The measured readiness facts `/ok` reports (D-15). */\n readiness(): RunServiceReadiness\n /**\n * Mint a live-view URL for one handle of a run (403 D-03).\n *\n * REQUIRED, NOT OPTIONAL, and that is a decision rather than an oversight. An optional member is\n * a member a composition can forget, and the failure mode of forgetting it here is a 404 that\n * reads exactly like \"no such route\" — which is what a door with no live view is indistinguishable\n * from. A composition that cannot mint supplies a function that REJECTS with a\n * `LiveViewUnavailableError`-named error, which the arm maps to 503 `live_view_unavailable`: an\n * honest host fact, said out loud, once, in the vocabulary the local door already uses.\n *\n * The minted token's own subject (run, handle) and expiry are checked by the live-view validator\n * independently of who asked (D-13). 2026-10-01 (432-21, D-12): the bearer's trust scope this mint\n * used to run under is deleted; the composition supplies the one caller it runs under.\n */\n mintLiveUrl(input: MintLiveUrlInput): Promise<RunsLiveUrlResult>\n /**\n * The injected agent host the two READ rows dispatch through (405-05, D-12/D-13).\n *\n * OPTIONAL, unlike `mintLiveUrl` above, and the asymmetry is deliberate rather than an\n * oversight. `mintLiveUrl` is required because a composition that forgot it would answer a 404\n * indistinguishable from an unserved path — but the argument runs the other way here: a host\n * genuinely composed without a function registry (a bare mount, this file's own fixtures) has no\n * capability to reach, and the honest answer is the SAME 503 `agent_host_unavailable` the local\n * door already gives for exactly this state. One word, one meaning, both doors.\n *\n * It is a HANDLE and nothing else — this package may not name the agent packages, so what\n * crosses is the seam `chat/host.ts` declares and the op ids the composition supplies as data.\n */\n readonly agentHost?: AgentHost\n}\n\n/** What minting one `liveUrl` needs from a request, as data: the subject, and nothing else. */\nexport interface MintLiveUrlInput {\n readonly runId: string\n readonly handle: number\n}\n\n/** Which handler a table row reaches. A closed union, so a row with no arm is a type error. */\nexport type RunServiceRouteHandlerName =\n | 'start'\n | 'events'\n | 'liveUrl'\n // 405-05 (D-12 / 402 D-16): the two READ rows. 402 D-16 said \"405's ref-resolving sha-keyed\n // route mounts behind the same authed door\", and mounting it here rather than beside it is what\n // makes that literal: the guard above the table applies to these rows by construction, and the\n // census that drives every row cross-site inherits them the day they land.\n | 'detail'\n | 'evidence'\n | 'artifact'\n // 406-01 (D-04): the failure view's read, on the two rows above's exact footing — the local\n // door's `GET /api/runs/:id/analysis` mounts the SAME adapter, so 408's embed and every thin\n // client parse one path shape whichever door they call.\n | 'analysis'\n // 2026-09-15, 423-21 D-18: the two feedback reads, masked on this door like the rows above.\n | 'marks'\n | 'markPreview'\n | 'ok'\n\nexport interface RunServiceRouteRow {\n readonly method: 'GET' | 'POST'\n /** The literal path, or — for a templated route — its `:param` shape. */\n readonly path: string\n readonly handler: RunServiceRouteHandlerName\n /** Present only on a templated route; the matcher uses it instead of `path`. */\n readonly pattern?: RegExp\n}\n\nexport const RUN_SERVICE_START_ROUTE = '/run'\nexport const RUN_SERVICE_EVENTS_TEMPLATE = '/run/:runId/events'\nconst RUN_SERVICE_EVENTS_PATTERN = /^\\/run\\/([^/]+)\\/events$/\n/**\n * The MINT (403 D-03, Q3) — the remote half of the pair whose local half is\n * `GET /api/runs/:runId/live-url`.\n *\n * SAME SHAPE AS THE EVENTS ROUTE ONE LINE UP, deliberately: a caller addresses a run it started by\n * id and asks this door for one thing about it per route. Since 432-21 the two doors differ in\n * nothing but the path — the same op, the same caller shape, the same result and fragment carriage.\n */\nexport const RUN_SERVICE_LIVE_URL_TEMPLATE = '/run/:runId/live-url'\nconst RUN_SERVICE_LIVE_URL_PATTERN = /^\\/run\\/([^/]+)\\/live-url$/\n/**\n * Readiness (D-15) — behind the same-site guard, like every other route on this door.\n *\n * An `/ok` that answered before the guard would tell a page on another origin that this process is\n * an agent-qa run service and that it is up. (Until 432-21 the guard here was the bearer verdict,\n * and the preflight was liveness and early token validation in one round-trip.)\n */\n/**\n * The durable run-detail READ (405-05, D-12 / 402 D-16) — the remote twin of the local door's\n * `GET /api/runs/:id/detail`.\n *\n * IT DISPATCHES THROUGH THE SAME ADAPTER THE LOCAL DOOR CALLS. `serveRunDetailRead` is one\n * function, so the two doors cannot come to disagree about what a run's projection is; a second\n * spelling here would agree on the day it was written and be a wire-contract fork thereafter.\n *\n * THIS ROW IS MASKED, and deliberately. It is a machine wire like `/run/:runId/events` one line up\n * — its consumer (the CLI's own `emitHuman`, 408's embed) is where a person meets the text, and\n * that consumer is the display boundary. The alternative would restore declared secrets onto a\n * machine wire, extending the disclosure surface to every client and every intermediary, which is\n * not what \"the browser is never the boundary\" (400-06) asks for. 405-10\n * applies the unmask seam to the LOCAL door only and enrols this row on the masked side.\n */\nexport const RUN_SERVICE_DETAIL_TEMPLATE = '/run/:runId/detail'\nconst RUN_SERVICE_DETAIL_PATTERN = /^\\/run\\/([^/]+)\\/detail$/\nexport const RUN_SERVICE_EVIDENCE_TEMPLATE = '/run/:runId/evidence'\nconst RUN_SERVICE_EVIDENCE_PATTERN = /^\\/run\\/([^/]+)\\/evidence$/\n/**\n * The ref-resolving artifact READ (405-05, D-12 / 402 D-16) — the remote twin of the local door's\n * `GET /api/runs/:runId/artifacts/:sha`, and the row 402 D-16 named by anticipation.\n *\n * TWO CAPTURES, `[^/]+` ON BOTH. The runId is decoded and the sha is not: a content address is 64\n * characters from `[0-9a-f]`, none of which percent-encoding can represent differently, so a sha\n * segment that needed decoding is already not one.\n *\n * MASKED, LIKE ITS SIBLING AND MORE SO: these are BYTES. The unmask seam never touches an artifact\n * body on any door (D-09) — a screenshot is not text and there is nothing in it to restore.\n */\nexport const RUN_SERVICE_ARTIFACT_TEMPLATE = '/run/:runId/artifacts/:sha'\nconst RUN_SERVICE_ARTIFACT_PATTERN = /^\\/run\\/([^/]+)\\/artifacts\\/([^/]+)$/\n/**\n * The run-ANALYSIS read (406-01, D-04) — the remote twin of the local door's\n * `GET /api/runs/:id/analysis`.\n *\n * IT DISPATCHES THROUGH THE SAME ADAPTER THE LOCAL DOOR CALLS, for the reason its detail sibling\n * does: `serveRunAnalysisRead` is one function, so the two doors cannot come to disagree about\n * what a run's analysis is.\n *\n * THIS ROW IS MASKED, AND FOR THE REASON ITS SIBLING IS. The verdict sentence quotes the failing\n * step's recorded error, which carries declared placeholders at rest; restoring them onto a\n * machine wire would hand them to every client and every intermediary, and this row's\n * consumer — the CLI's own emit, 408's embed — is where a person meets the text. The dispatch\n * below passes no `boundary`, and the option's `'machine'` default is what keeps it masked.\n */\nexport const RUN_SERVICE_ANALYSIS_TEMPLATE = '/run/:runId/analysis'\nconst RUN_SERVICE_ANALYSIS_PATTERN = /^\\/run\\/([^/]+)\\/analysis$/\n/** 2026-09-15, 423-21 D-18: runs.marks.history and runs.mark.preview behind the same guard. */\nexport const RUN_SERVICE_MARKS_TEMPLATE = '/run/:runId/marks'\nconst RUN_SERVICE_MARKS_PATTERN = /^\\/run\\/([^/]+)\\/marks$/\nexport const RUN_SERVICE_MARK_PREVIEW_TEMPLATE = '/run/:runId/mark-preview'\nconst RUN_SERVICE_MARK_PREVIEW_PATTERN = /^\\/run\\/([^/]+)\\/mark-preview$/\nexport const RUN_SERVICE_OK_ROUTE = '/ok'\n\n/**\n * EVERY PATH THIS DOOR ANSWERS, as data the dispatch reads (the chat door's own idiom).\n *\n * WHY A TABLE AND NOT THREE ARMS. The same-site guard below is applied to the REQUEST, above this\n * table, so a route added tomorrow inherits it by construction. The table is what makes that\n * inheritance AUDITABLE from outside: because dispatch reads it, a route not in it is unreachable,\n * so a census cell can enumerate this array and drive every row cross-site — and a newly added\n * route cannot escape that corpus by nobody noticing it.\n */\nexport const RUN_SERVICE_ROUTE_TABLE: readonly RunServiceRouteRow[] = Object.freeze([\n { method: 'POST', path: RUN_SERVICE_START_ROUTE, handler: 'start' },\n {\n method: 'GET',\n path: RUN_SERVICE_EVENTS_TEMPLATE,\n handler: 'events',\n pattern: RUN_SERVICE_EVENTS_PATTERN,\n },\n {\n method: 'GET',\n path: RUN_SERVICE_LIVE_URL_TEMPLATE,\n handler: 'liveUrl',\n pattern: RUN_SERVICE_LIVE_URL_PATTERN,\n },\n {\n method: 'GET',\n path: RUN_SERVICE_DETAIL_TEMPLATE,\n handler: 'detail',\n pattern: RUN_SERVICE_DETAIL_PATTERN,\n },\n { method: 'GET', path: RUN_SERVICE_EVIDENCE_TEMPLATE, handler: 'evidence',\n pattern: RUN_SERVICE_EVIDENCE_PATTERN },\n {\n method: 'GET',\n path: RUN_SERVICE_ARTIFACT_TEMPLATE,\n handler: 'artifact',\n pattern: RUN_SERVICE_ARTIFACT_PATTERN,\n },\n {\n method: 'GET',\n path: RUN_SERVICE_ANALYSIS_TEMPLATE,\n handler: 'analysis',\n pattern: RUN_SERVICE_ANALYSIS_PATTERN,\n },\n { method: 'GET', path: RUN_SERVICE_MARKS_TEMPLATE, handler: 'marks', pattern: RUN_SERVICE_MARKS_PATTERN },\n { method: 'POST', path: RUN_SERVICE_MARK_PREVIEW_TEMPLATE, handler: 'markPreview',\n pattern: RUN_SERVICE_MARK_PREVIEW_PATTERN },\n { method: 'GET', path: RUN_SERVICE_OK_ROUTE, handler: 'ok' },\n] as const)\n\n/** What a matched row carries: the row itself and whatever its pattern captured. */\nexport interface RunServiceRouteMatch {\n readonly row: RunServiceRouteRow\n /** The raw, still-ENCODED capture groups. Decoding is the handler's business, and it can throw. */\n readonly params: readonly string[]\n}\n\n/** Resolve a request to a table row, or to nothing. The dispatch's only route lookup. */\nexport function matchRunServiceRoute(\n method: string | undefined,\n path: string,\n): RunServiceRouteMatch | undefined {\n for (const row of RUN_SERVICE_ROUTE_TABLE) {\n if (row.method !== method) continue\n if (row.pattern === undefined) {\n if (path === row.path) return { row, params: [] }\n continue\n }\n const matched = row.pattern.exec(path)\n if (matched !== null) return { row, params: matched.slice(1).map((part) => part ?? '') }\n }\n return undefined\n}\n\n/**\n * Whether a path belongs to this door — the MOUNT's whole question, and method-blind on purpose.\n *\n * A host consults this before its own routing so that every request to a service path, including\n * an `OPTIONS` preflight and a method this table has no row for, is answered by this door rather\n * than by the host's generic handling. That is what keeps the host's wildcard CORS preflight and\n * its SPA fallback away from this surface.\n *\n * DERIVED FROM THE TABLE, never a second list: the prefixes are read off the rows, so a route\n * added above is mounted the same commit.\n */\nexport function ownsRunServicePath(path: string): boolean {\n for (const row of RUN_SERVICE_ROUTE_TABLE) {\n if (row.pattern === undefined) {\n if (path === row.path) return true\n continue\n }\n if (row.pattern.test(path)) return true\n }\n // A path UNDER a declared literal route is this door's too, so `/run/anything` is refused here\n // rather than falling into the host's SPA fallback and answering 200 with an HTML page.\n return RUN_SERVICE_ROUTE_TABLE.some((row) => row.pattern === undefined\n && path.startsWith(`${row.path}/`))\n}\n\nexport interface RunServiceRouter {\n (req: IncomingMessage, res: ServerResponse): void\n /** Live SSE connections — so a host can assert this door leaks none on teardown. */\n openStreamCount(): number\n}\n\n/** The one non-2xx body this door writes: a single key carrying a closed code. */\nfunction refuse(res: ServerResponse, status: number, error: RunServiceErrorCode): void {\n if (res.headersSent || res.writableEnded) {\n res.destroy()\n return\n }\n const body = JSON.stringify({ error })\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n}\n\n/**\n * The ONE non-2xx body on this door wider than a single key besides `run_denied` (403-03, D-13).\n *\n * The shape is `RunServiceReplayFloorBodySchema`'s — see that schema for why the second key is\n * sound exactly here: `earliestAvailableSeq` is a fact about the CALLER'S OWN request, and without\n * it the refusal tells a caller nothing it can act on.\n */\nfunction refuseWithFloor(res: ServerResponse, earliestAvailableSeq: number): void {\n if (res.headersSent || res.writableEnded) {\n res.destroy()\n return\n }\n const body = JSON.stringify({ error: 'replay_floor', earliestAvailableSeq })\n res.writeHead(410, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n}\n\nfunction respondJson(res: ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data)\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n}\n\n/**\n * The `handle` query parameter, exactly as it arrived, or `null` when absent.\n *\n * Read off the query substring with `URLSearchParams` rather than `new URL(...)`: this is\n * untrusted input on a path that has already matched, and a constructor that can throw does not\n * belong between a matched route and its handler.\n *\n * A REPEATED parameter is not resolved to one of its values — the values are joined, which cannot\n * parse, so `?handle=1&handle=2` is refused rather than silently answered as handle 1: a request\n * that says two different things is not a request that said the first one.\n *\n * EXPORTED FOR THE SECOND DOOR (402-08), on {@link serveRunEventStream}'s own reasoning. The local\n * loopback route reads the parameter through THIS function rather than through the host router's\n * `url.searchParams.get('handle')`, which would return `1` for `?handle=1&handle=2` — that is, the\n * one wrong answer this reader exists to refuse. The core takes the RAW parameter, so which reader\n * produced it is exactly the seam a second spelling would slip into.\n */\nexport function handleParamOf(req: IncomingMessage): string | null {\n const query = (req.url ?? '').split('?').slice(1).join('?')\n if (query === '') return null\n const values = new URLSearchParams(query).getAll('handle')\n if (values.length === 0) return null\n if (values.length === 1) return values[0] ?? null\n return values.join(',')\n}\n\n/**\n * The `lastEventId` query parameter, exactly as it arrived, or `null` when absent (403-03, D-13).\n *\n * SPELLED `lastEventId` AND NEVER `fromSeq`. The SSE header, the `runs.events` op input and this\n * door's query all mean the same thing — \"the last envelope the caller already observed\" — so they\n * carry the same word, and the `+ 1` that turns it into a subscribe point lives in exactly one\n * place per reader. A second spelling would be a second arithmetic somebody has to keep in step.\n *\n * READ OFF THE RAW QUERY, on {@link handleParamOf}'s reasoning and by the same mechanics: a\n * REPEATED parameter is joined rather than resolved to one of its values, so `?lastEventId=1&\n * lastEventId=7` cannot parse and is refused rather than silently answered as 1. A request that\n * says two different things about where to resume is not a request that said the first one — and\n * on a resume the consequence of guessing is a gap or a duplicate, which is exactly what INVK-05\n * exists to prevent.\n */\nexport function lastEventIdParamOf(req: IncomingMessage): string | null {\n const query = (req.url ?? '').split('?').slice(1).join('?')\n if (query === '') return null\n const values = new URLSearchParams(query).getAll('lastEventId')\n if (values.length === 0) return null\n if (values.length === 1) return values[0] ?? null\n return values.join(',')\n}\n\n/**\n * Where a stream request asked to resume from. Three arms, and the count is the contract.\n *\n * `start` is \"the caller has observed nothing\", `after` carries the last seq it DID observe, and\n * `invalid` is a fact about the caller's own input. There is deliberately no fourth arm meaning\n * \"unparseable, serve them from the beginning\": silently restarting a resume at seq 1 would\n * re-deliver every envelope the caller already has, and silently serving from the floor would hide\n * a gap — the two answers D-13 refuses by name.\n */\nexport type ResumePoint =\n | { readonly kind: 'start' }\n | { readonly kind: 'after'; readonly seq: number }\n | { readonly kind: 'invalid' }\n\n/** Canonical non-negative decimal integers only — `parseHandleParam`'s own form, one package over. */\nconst CANONICAL_LAST_EVENT_ID = /^(?:0|[1-9][0-9]*)$/\n\n/**\n * Resolve the `Last-Event-ID` header and the `?lastEventId=` parameter to one resume point.\n *\n * THE HEADER DECIDES WHEN BOTH ARE PRESENT, and that is not arbitrary. The query parameter exists\n * for clients that cannot set a header; the header is what a BROWSER's own automatic EventSource\n * reconnect carries, and it carries the freshest id the browser actually received. A URL, by\n * contrast, is whatever the page was opened with — possibly minutes and hundreds of envelopes ago.\n * Preferring the stale value would re-deliver the difference on every reconnect.\n *\n * DELIBERATELY NOT `Number(raw)`, on `parseHandleParam`'s reasoning: that accepts `' 7 '`, `'0x7'`,\n * `'1e1'`, `'-0'` and `''` (→ 0), so a caller could name one resume point several ways and an\n * empty header would silently become \"from the beginning\". An EMPTY header is `invalid` rather\n * than absent precisely because it is present — the caller said something, and it did not parse.\n */\nexport function resumePointOf(\n header: string | readonly string[] | null | undefined,\n param: string | null,\n): ResumePoint {\n const headerValue = Array.isArray(header)\n // A repeated `Last-Event-ID` is joined, never resolved to one of its values — the repeated-\n // parameter law above, applied to the header Node folds into an array.\n ? (header as readonly string[]).join(',')\n : (header as string | null | undefined)\n const raw = headerValue ?? param\n if (raw === null || raw === undefined) return { kind: 'start' }\n if (!CANONICAL_LAST_EVENT_ID.test(raw)) return { kind: 'invalid' }\n const seq = Number(raw)\n if (!Number.isSafeInteger(seq)) return { kind: 'invalid' }\n return { kind: 'after', seq }\n}\n\n/**\n * The REPLAY FLOOR this rejection reports, if it is one — read structurally, never by class.\n *\n * ON `runDenialOf`S EXACT PRECEDENT one function down, and for a reason that is stronger here than\n * a package boundary. `@vostride/agent-qa-runner` IS a declared dependency of this package, so an\n * `instanceof ReplayIncompleteError` would compile — and it would still be the wrong instrument.\n * The error arrives through {@link RunSession.subscribe}, a schema-declared port whose implementer\n * this module does not choose: a cloud host, a test fixture or a future replay source can all\n * satisfy that port without sharing this process's copy of the runner's class object, and\n * `instanceof` answers false across every one of those seams while the caller's situation is\n * identical. What is stable is the SHAPE the bus documents: the name and the floor.\n *\n * BOTH FIELDS ARE CHECKED. A rejection carrying the right name and no usable number cannot be\n * answered with a recovery point, and a 410 whose advertised recovery point is missing or nonsense\n * is worse than no 410 at all — the caller is told to re-attach somewhere unreachable. That case\n * falls through to the 500 arm, which is the honest answer for \"the replay could not be served and\n * this door cannot say where it could have been\".\n */\nexport function replayFloorOf(error: unknown): number | undefined {\n if (typeof error !== 'object' || error === null) return undefined\n if ((error as { name?: unknown }).name !== 'ReplayIncompleteError') return undefined\n const floor = (error as { earliestAvailableSeq?: unknown }).earliestAvailableSeq\n if (typeof floor !== 'number' || !Number.isSafeInteger(floor) || floor < 0) return undefined\n return floor\n}\n\n/**\n * Which REFUSED request fields a body carries (D-07 / D-12).\n *\n * Checked as a KEY test rather than by parsing, so `{\"runId\": null}` is refused too: the offense is\n * naming the field at all, not the value put in it. `RunServiceStartRequestSchema` is `.strict()`\n * and would refuse these keys as unrecognised a line later — this check exists so the answer says\n * WHICH kind of refusal it was, and so the door's own law is legible where the door enforces it.\n */\nfunction refusedFieldsIn(body: Record<string, unknown>): readonly string[] {\n return RUN_SERVICE_REFUSED_REQUEST_FIELDS.filter((field) => Object.hasOwn(body, field))\n}\n\n/**\n * The run service's router: total over its own paths, and never anything else.\n *\n * TOTAL BY DESIGN. It answers every path {@link ownsRunServicePath} claims, including ones no row\n * matches, because the fall-through it would otherwise land in is the host's SPA fallback — which\n * answers 200 with an HTML page for any unknown path.\n */\n/** What the exported stream core reaches the world through. */\nexport interface RunEventStreamDeps {\n /** The DECODED run id. Decoding can throw, and that throw is the caller's 404 to answer. */\n readonly runId: string\n /** The raw `handle` query parameter, exactly as it arrived; `null` means the firehose. */\n readonly handleParam: string | null\n /**\n * WHERE TO RESUME, ALREADY RESOLVED FROM THE HEADER AND THE QUERY (403-03, D-13).\n *\n * Resolved by the CALLER rather than read here, on `handleParam`'s own reasoning inverted: the\n * handle arrives raw because there is exactly one parse of it and it lives in this core, while\n * the resume point arrives resolved because it is read from TWO places — a header and a query —\n * and only the host holds the request object both live on. {@link resumePointOf} and\n * {@link lastEventIdParamOf} are exported so each door resolves it with the same pair.\n *\n * Absent is `{ kind: 'start' }`, which is what a door that has not learned about resume yet\n * would have meant anyway.\n */\n readonly resume?: ResumePoint\n /** The started run's session, or nothing if this process never started that run. */\n attach(runId: string): RunSession | undefined\n /** Live teardowns, so a host can count open streams and a close removes exactly one. */\n readonly openStreams?: {\n add(teardown: () => void): void\n delete(teardown: () => void): void\n }\n}\n\n/**\n * THE RUN STREAM, AS ONE UNIT: attach, validate the handle, filter, frame, heartbeat, close.\n *\n * Exported because there is going to be a SECOND door onto the same stream — 402-08 mounts the\n * local door, which differed from this one only in what it did about credentials (and since 432-21\n * differs in nothing but the path). Two doors\n * calling one function is the only shape in which the filter has exactly one implementation; two\n * copies of the serving body would be two places `?handle=` could drift, and the drift would be\n * invisible until somebody diffed them.\n *\n * The ORDER below is the contract, not an implementation detail. Every refusal — unknown run,\n * malformed handle, unknown handle, unavailable replay — happens before `writeHead`, because a\n * response that has already written `200 text/event-stream` cannot be told it failed.\n */\nexport function serveRunEventStream(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RunEventStreamDeps,\n): void {\n const parsedHandle = parseHandleParam(deps.handleParam)\n if (parsedHandle.kind === 'invalid') {\n // Refused before the run is even looked up: a malformed parameter is a fact about the\n // caller's own input, so answering it early leaks nothing about which runs exist.\n refuse(res, 400, 'invalid_handle')\n return\n }\n\n const resume = deps.resume ?? { kind: 'start' }\n if (resume.kind === 'invalid') {\n // Same posture and same position as the handle refusal above, and for the same reason.\n refuse(res, 400, 'invalid_last_event_id')\n return\n }\n\n const session = deps.attach(deps.runId)\n if (session === undefined) {\n refuse(res, 404, 'unknown_run')\n return\n }\n\n // THE ONE PLACE THE `+ 1` LIVES on this door (`runs.events` holds the other, for the durable\n // reader). `Last-Event-ID` names the last envelope the caller ALREADY observed, so the replay\n // opens at the next one — which is what makes \"no id at or below the resume point is ever\n // re-sent\" a property of the arithmetic rather than of a filter somewhere downstream.\n const fromSeq = resume.kind === 'after' ? resume.seq + 1 : REPLAY_FROM_START\n const isDeepResume = fromSeq > REPLAY_FROM_START\n\n // ---- The roster on a DEEP resume (403-03, D-14) ------------------------------------------\n //\n // THE ROSTER RIDES `runStarted`, AND `runStarted` IS SEQ 1. Below, on a `subscribe(1, …)`, it is\n // the first envelope delivered and the roster is in hand before the handle is checked. On\n // `subscribe(N + 1, …)` with N >= 1 it is NOT delivered at all — so a door that only derived the\n // roster from what it was served would answer `unknown_handle` for EVERY deep resume on a member\n // stream, which is a correct handle refused because the door forgot who was in the run.\n //\n // The peek is a second `subscribe(1, …)` whose handler records the first envelope's roster and\n // which unsubscribes immediately. It costs one extra replay walk on the deep-resume path only,\n // and it is the price of not touching the bus: stopping the walk early would mean THROWING out\n // of the handler, which the bus reads as a detached subscriber and answers with a published\n // `runWarning` — a side effect on the run's own event log, caused by reading it.\n //\n // WHEN THE PEEK ITSELF HITS THE FLOOR THE ROSTER IS UNKNOWABLE, and the handle validation is\n // SKIPPED with the filter still applied. Refusing instead would turn every deep resume on a\n // member stream of a long run into `unknown_handle` the moment seq 1 fell out of the window —\n // punishing the caller for the bus's retention. The filter is what carries the security claim\n // (T-403-14): `passesHandleFilter` still runs on every envelope, so an unknown handle sees the\n // run-scoped events and nothing else, which is a strictly smaller set than the firehose it could\n // have asked for with no handle at all.\n let rosterKnown = true\n let peekedRoster: readonly number[] | undefined\n if (parsedHandle.kind === 'handle' && isDeepResume) {\n try {\n let first = true\n const stopPeek = session.subscribe(REPLAY_FROM_START, (event) => {\n if (!first) return\n first = false\n peekedRoster = handleRosterOf(event)\n })\n stopPeek()\n } catch (peekError) {\n if (replayFloorOf(peekError) === undefined) {\n refuse(res, 500, 'replay_unavailable')\n return\n }\n rosterKnown = false\n }\n if (rosterKnown && !(peekedRoster ?? []).includes(parsedHandle.index)) {\n refuse(res, 400, 'unknown_handle')\n return\n }\n }\n\n // The frame writer BUFFERS until the head is out, because `subscribe` delivers the replay\n // synchronously and can also THROW (`ReplayIncompleteError`). Subscribing first and writing the\n // head after is what keeps a failed attach answerable as a typed JSON error instead of a\n // half-open stream nobody can be told about. It is ALSO what puts the roster in hand before the\n // head: `runStarted` is seq 1, so the replay has already delivered it by the time the handle is\n // checked against the roster below.\n const pending: string[] = []\n let open = false\n const write = (frame: string): void => {\n if (open) res.write(frame)\n else pending.push(frame)\n }\n const frameOf = (event: RunEventEnvelope): string =>\n // D-13, all three parts: the id IS the seq, the event name IS the envelope type, and the\n // data IS the envelope's own JSON. No projection, no rename, no second vocabulary. The filter\n // DROPS envelopes; it never edits one, so a filtered stream's frames are byte-identical to the\n // firehose's — with gaps in the ids, which is what seq-as-id means once a filter exists.\n `id: ${String(event.seq)}\\nevent: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`\n\n let roster: readonly number[] | undefined\n\n let closed = false\n let unsubscribe: (() => void) | undefined\n let heartbeat: ReturnType<typeof setInterval> | undefined\n const teardown = (): void => {\n if (closed) return\n closed = true\n if (heartbeat !== undefined) clearInterval(heartbeat)\n unsubscribe?.()\n deps.openStreams?.delete(teardown)\n // ONLY ONCE THE HEAD IS OUT. `subscribe` delivers the replay SYNCHRONOUSLY, so a run that\n // was already over reaches `runFinished` — and therefore this teardown — before `writeHead`\n // has run. Ending here would let Node send its own default 200 with no `Content-Type` and no\n // body, so a client asking for a finished run's whole log would get an empty, untyped 200.\n // The flush below the head handles that case, and this guard is what leaves it to it.\n if (open && !res.writableEnded) res.end()\n }\n\n try {\n unsubscribe = session.subscribe(fromSeq, (event) => {\n if (closed) return\n roster = roster ?? handleRosterOf(event)\n // THE FILTER, and the ONE call to it. `passesHandleFilter` is the schema's predicate over\n // the schema's total scope classification — this module states no opinion about which event\n // types belong to a member.\n if (parsedHandle.kind === 'handle' && !passesHandleFilter(event, parsedHandle.index)) return\n write(frameOf(event))\n // THE STREAM ENDS AT `runFinished`. The run's event log is complete at that point and the\n // bus closes behind it, so holding the socket open would deliver nothing but heartbeats.\n // What a reconnect after this means is 403's attach contract to decide. `runFinished` is\n // run-scoped, so it reaches every handle and this arm is filter-independent.\n if (event.type === 'runFinished') teardown()\n })\n } catch (error) {\n // THE FLOOR IS A NAMED REFUSAL, NOT A CRASH (403-03, D-13 · INVK-05). The bus refuses to serve\n // a prefix it cannot produce; this door refuses to hide that, and answers WHERE the replay\n // could have started so the caller can re-attach rather than retry the same request forever.\n // A gap the viewer is not told about is the one thing D-13 forbids by name.\n const floor = replayFloorOf(error)\n if (floor !== undefined) {\n refuseWithFloor(res, floor)\n return\n }\n refuse(res, 500, 'replay_unavailable')\n return\n }\n\n // On a deep resume the roster came from the peek above (or is unknowable), and the check has\n // already been made — re-running it here would refuse on the empty roster this walk derived.\n if (!isDeepResume && parsedHandle.kind === 'handle' && !(roster ?? []).includes(parsedHandle.index)) {\n // A well-formed handle no member of this run answers to — including every handle on a run\n // whose `runStarted` announced no roster at all. Nothing has been written yet, so this is\n // still a typed JSON refusal rather than a stream that quietly carries only run-scoped events\n // and looks like a member that did nothing.\n closed = true\n unsubscribe?.()\n refuse(res, 400, 'unknown_handle')\n return\n }\n\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n })\n res.write(':ok\\n\\n')\n open = true\n for (const frame of pending) res.write(frame)\n pending.length = 0\n if (closed) {\n // The whole run was already in the replay: the head and every frame are out, so all that is\n // left is to close the socket the teardown above could not reach.\n if (!res.writableEnded) res.end()\n return\n }\n\n // D-15: A RESUME THAT LANDS PAST THE END CLOSES RATHER THAN HANGING.\n //\n // The arm above closes a stream that was SERVED `runFinished`. A resume whose point is at or past\n // the final seq is served nothing at all, so that arm never fires — and without this one the\n // socket would stay open on a finished run, heartbeating forever at a viewer whose run is over.\n //\n // `done` IS THE HONEST SIGNAL AND `status` IS NOT. The shell sets `status` to the aggregate\n // verdict at the `verdict` event, which is published BEFORE `runFinished` and before an awaited\n // handoff write — so a door that closed on a terminal `status` would truncate a stream in the\n // window between them, which is the silent gap this whole plan exists to refuse. `done` resolves\n // after `runFinished` is published and after `bus.close()`: it means nothing more will ever\n // arrive, which is exactly the fact this arm needs. A REJECTED `done` says the same thing about\n // a run that ended badly, so both settlements tear down.\n //\n // Harmless on a live stream: a run still running has an unsettled `done`, and a subscriber that\n // was served `runFinished` has already torn down (the teardown is idempotent).\n void Promise.resolve(session.done).then(teardown, teardown)\n\n heartbeat = setInterval(() => { res.write(':\\n\\n') }, HEARTBEAT_MS)\n deps.openStreams?.add(teardown)\n req.on('close', teardown)\n}\n\n/**\n * The DENIAL this rejection is, if it is one — read structurally, never by class (402-06, T-402-22).\n *\n * ON `dashboardNeutralReasonOf`'S EXACT PRECEDENT (`execution/in-process-backend.ts`), and for the\n * same architectural reason: the rejection is a `RunDeniedError` minted in `agent-local`, and this\n * package may not import `agent`, `agent-local` or `safety` — `pnpm validate:arch` is the\n * mechanical proof.\n *\n * THE DISCRIMINATOR IS `neutralReason`, DELIBERATELY. Only a run denial carries it: an\n * unrecognised request field, an input error and \"the host was asked to start a run before it was\n * composed\" carry none, and those are exactly the rejections that must stay a 500 with no words on\n * them. Keying on the class NAME would be a string compare against another package's private\n * vocabulary.\n *\n * 2026-10-01 (432-19, D-15): there is no remedy list to validate or project. The production refusal\n * never carried one, and the remedy vocabulary left with the execution gate.\n */\nexport function runDenialOf(error: unknown): RunServiceDenialBody | undefined {\n if (typeof error !== 'object' || error === null) return undefined\n const neutralReason = (error as { neutralReason?: unknown }).neutralReason\n if (typeof neutralReason !== 'string' || neutralReason.trim().length === 0) return undefined\n return { error: 'run_denied', neutralReason }\n}\n\nexport function createRunServiceRoutes(ports: RunServicePorts): RunServiceRouter {\n /** Every live stream's teardown, so a host can count them and a close removes exactly one. */\n const openStreams = new Set<() => void>()\n\n function handleStart(req: IncomingMessage, res: ServerResponse): void {\n void (async () => {\n let raw: unknown\n try {\n raw = await readJsonBody<unknown>(req, MAX_REQUEST_BYTES)\n } catch {\n refuse(res, 400, 'invalid_request_body')\n return\n }\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n refuse(res, 400, 'invalid_request_body')\n return\n }\n const refused = refusedFieldsIn(raw as Record<string, unknown>)\n if (refused.length > 0) {\n // A caller may not name the terms of its own authorization, may not choose the identity\n // its run is addressed by, and may not tune a target's concurrency. The door composes\n // context and the core mints the id.\n refuse(res, 400, 'refused_request_field')\n return\n }\n const parsed = RunServiceStartRequestSchema.safeParse(raw)\n if (!parsed.success) {\n refuse(res, 400, 'invalid_request_body')\n return\n }\n\n let ack: RunStartAcknowledgement\n try {\n ack = await ports.invokeRunStart(\n parsed.data.patterns === undefined ? {} : { patterns: parsed.data.patterns },\n )\n } catch (error) {\n // A POLICY DENIAL IS A DECISION, NOT A CRASH, and it is the one rejection this door\n // RENDERS rather than flattens. Read structurally — see `runDenialOf`.\n const denial = runDenialOf(error)\n if (denial !== undefined) {\n respondJson(res, 403, denial)\n return\n }\n // Everything else keeps its words to itself: a crash message is composed from this\n // process's own state and is not this caller's to read. The run's own diagnostics reach\n // whoever reads the run.\n refuse(res, 500, 'run_start_failed')\n return\n }\n // 202 rather than 200: an acknowledgment is a START, not an outcome. Every field of it came\n // off the durable record — the op raises `RunNotRecordedError` rather than fabricating one.\n respondJson(res, 202, ack)\n })()\n }\n\n function handleEvents(\n runIdParam: string,\n handleParam: string | null,\n req: IncomingMessage,\n res: ServerResponse,\n ): void {\n let runId: string\n try {\n runId = decodeURIComponent(runIdParam)\n } catch {\n refuse(res, 404, 'unknown_run')\n return\n }\n serveRunEventStream(req, res, {\n runId,\n handleParam,\n // BOTH SOURCES, RESOLVED BY THE ONE PAIR. The local door in `routes.ts` calls the identical\n // two functions on the identical two inputs — that is what makes the parity corpus a claim\n // about one implementation rather than about two readers that agree today.\n resume: resumePointOf(req.headers['last-event-id'], lastEventIdParamOf(req)),\n attach: ports.attach,\n openStreams,\n })\n }\n\n /**\n * The MINT arm (403 D-03, Q3) — the remote twin of `routes.ts`'s `/api/runs/:runId/live-url`.\n *\n * IT DISPATCHES THROUGH THE PORT AND FORMATS NOTHING. The body is the port's result verbatim: a\n * second shaping here would be a second contract for what a `liveUrl` is, free to disagree with\n * the one the function layer published — and the two doors' parity corpus would then be\n * comparing two shapings rather than one result.\n *\n * THE REFUSALS ARE MAPPED BY ERROR NAME, never by matching a message. A message is prose and\n * prose gets rewritten; the same reading `routes.ts` does, so both doors answer the same word for\n * the same situation.\n *\n * THE RESULT IS NEVER LOGGED, HERE OR ANYWHERE ON THIS PATH (LIVE-02, T-403-02). The token rides\n * the URL fragment and this arm's only job is to put it on the wire the caller asked for.\n */\n function handleLiveUrl(\n runIdParam: string,\n req: IncomingMessage,\n res: ServerResponse,\n ): void {\n let runId: string\n try {\n runId = decodeURIComponent(runIdParam)\n } catch {\n refuse(res, 404, 'unknown_run')\n return\n }\n // THE RAW `handle` PARAMETER THROUGH THE SAME READER THE STREAM USES. `url.searchParams` would\n // resolve `?handle=1&handle=2` to `1`, which is the one answer that reader exists to refuse —\n // and minting a viewing credential for a handle the caller did not unambiguously name is worse\n // than refusing to mint at all.\n const parsedHandle = parseHandleParam(handleParamOf(req))\n if (parsedHandle.kind === 'invalid') {\n refuse(res, 400, 'invalid_handle')\n return\n }\n const handle = parsedHandle.kind === 'absent' ? 0 : parsedHandle.index\n void ports.mintLiveUrl({ runId, handle }).then(\n (result) => { respondJson(res, 200, result) },\n (error: unknown) => {\n const name = typeof error === 'object' && error !== null\n ? (error as { name?: unknown }).name\n : undefined\n if (name === 'UnknownRunError') { refuse(res, 404, 'unknown_run'); return }\n if (name === 'LiveViewUnavailableError') {\n refuse(res, 503, 'live_view_unavailable')\n return\n }\n refuse(res, 500, 'live_url_mint_failed')\n },\n )\n }\n\n /**\n * The two READ arms (405-05, D-12 / 402 D-16) — the remote twins of `routes.ts`'s own.\n *\n * THEY CALL THE LOCAL DOOR'S ADAPTERS AND FORMAT NOTHING, on `handleLiveUrl`'s rule and for its\n * reason: a second shaping here would be a second contract for what a run's projection or an\n * artifact's headers ARE, and the parity corpus would then compare two shapings rather than one.\n *\n * NO `boundary` OPTION IS PASSED, and that is this door's masked posture stated by omission:\n * 405-10 gives `serveRunDetailRead` a `boundary` that DEFAULTS to machine (masked), and only the\n * LOCAL arm opts into `'human'`. A row that wanted the human boundary would have to say so.\n *\n * AN UNCOMPOSED HOST IS 503 IN THE ADAPTERS' OWN VOCABULARY, not this door's closed error set.\n * These two rows serve a shape the closed `RunServiceErrorCode` set was never written for — a\n * whole projection, a PNG — so their refusals are the adapters' and are byte-identical to the\n * local door's. What the closed set still owns is everything a caller refused at the door can see,\n * and that is settled above the table, before either of these arms is reachable at all.\n */\n function handleAgentRead(\n req: IncomingMessage,\n res: ServerResponse,\n runIdParam: string,\n serve: (runId: string, host: AgentHost) => void,\n ): void {\n const host = ports.agentHost\n if (host === undefined) {\n respondJson(res, 503, { error: 'agent_host_unavailable' })\n return\n }\n let runId: string\n try {\n runId = decodeURIComponent(runIdParam)\n } catch {\n // An undecodable segment names no run, and the honest answer is the one the ops' own input\n // schemas give for an id they refuse — the local door's word, not a second one.\n respondJson(res, 400, { error: 'invalid_run_id' })\n return\n }\n serve(runId, host)\n }\n\n const router = ((req: IncomingMessage, res: ServerResponse): void => {\n try {\n const path = (req.url ?? '/').split('?')[0] ?? '/'\n\n // THE SAME-SITE GUARD, FIRST, ABOVE THE ROUTE TABLE (D-06 / D-15; 432-21 D-13). Every route,\n // every method, every path this door owns — including a path no row matches, and a preflight.\n // Nothing below this line runs, and no body is read, for a request naming a non-loopback Host,\n // a foreign `Origin` or a cross-site `Sec-Fetch-Site`. The predicate is the dashboard's one\n // shared spelling (`server/cross-site.ts`), so this door and the mark, config and live-url\n // doors cannot disagree about what cross-site means. Until 432-21 this rung was the bearer\n // verdict; the credential is deleted (D-12) and the network boundary is what remains.\n if (refuseCrossSiteRequest(req) !== undefined) {\n refuse(res, 403, 'cross_site_refused')\n return\n }\n\n const matched = matchRunServiceRoute(req.method, path)\n if (matched === undefined) {\n refuse(res, 404, 'unknown_route')\n return\n }\n\n switch (matched.row.handler) {\n case 'start':\n handleStart(req, res)\n return\n case 'events':\n handleEvents(matched.params[0] ?? '', handleParamOf(req), req, res)\n return\n case 'liveUrl':\n handleLiveUrl(matched.params[0] ?? '', req, res)\n return\n case 'detail':\n handleAgentRead(req, res, matched.params[0] ?? '', (runId, host) => {\n serveRunDetailRead(req, res, { runId, host })\n })\n return\n case 'artifact':\n handleAgentRead(req, res, matched.params[0] ?? '', (runId, host) => {\n serveRunArtifact(req, res, { runId, sha: matched.params[1] ?? '', host })\n })\n return\n case 'evidence':\n handleAgentRead(req, res, matched.params[0] ?? '', (runId, host) => {\n serveRunEvidenceRead(req, res, { runId, host })\n })\n return\n case 'analysis':\n handleAgentRead(req, res, matched.params[0] ?? '', (runId, host) => {\n // NO DISPLAY OPT-IN, AND THAT IS THE WHOLE DECISION (406 D-04, 405-10's precedent).\n // The shared adapter's option defaults to `'machine'`; this door's callers are machine\n // clients, not a person's browser session, so this body stays masked. Opting this arm\n // in reds the roll-call's `machine:remote-run-analysis` row and a source cell in\n // `run-service-routes.test.ts` that greps this very block — which is the review the\n // reversal deserves.\n serveRunAnalysisRead(req, res, { runId, host })\n })\n return\n case 'marks':\n handleAgentRead(req, res, matched.params[0] ?? '', (runId, host) => {\n serveRunMarksHistoryRead(req, res, { runId, host })\n })\n return\n case 'markPreview':\n handleAgentRead(req, res, matched.params[0] ?? '', (runId, host) => {\n serveRunMarkPreviewRead(req, res, { runId, host })\n })\n return\n case 'ok':\n respondJson(res, 200, ports.readiness())\n return\n }\n } catch {\n // The door's LAST answer. Fixed bytes carrying no host value; once a stream's head is out the\n // only honest answer is to hang up, which `refuse` does.\n refuse(res, 500, 'run_start_failed')\n }\n }) as RunServiceRouter\n\n router.openStreamCount = () => openStreams.size\n return router\n}\n","// The run-detail READ route (Phase 405 plan 01, D-03).\n//\n// `GET /api/runs/:id/detail` is what the rebuilt run-detail page reads, and this module is the\n// whole of the HTTP half: validate the id with the OP'S OWN input schema, dispatch through the\n// injected host, map the op's named refusals onto status codes. It formats nothing. It opens no\n// database. There is no SQLite read in `routes.ts` for this arm and there must never be one —\n// that was the shipped v1 arrangement, and a private store read is a capability the function\n// layer cannot see, cannot audit and cannot offer to the CLI, MCP or chat (D-03, the fourth-door\n// law of 404 D-16).\n//\n// EVERY REFUSAL IS NAMED, on `post-processing-routes.ts`'s measured precedent. A page unable to\n// distinguish an unrecorded run and a composition that binds no run-detail port renders one grey\n// error for two completely different operator actions. Names are read STRUCTURALLY off\n// `error.name` because this package may not import the packages that mint those classes\n// (validate:arch), and comparing messages would be comparing against prose somebody will rewrite.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport {\n RunsArtifactInputSchema,\n RunsDetailInputSchema,\n RunsEvidenceInputSchema,\n RunsEvidenceResultSchema,\n RunsMarkInputSchema,\n RunsMarkPreviewResultSchema,\n RunsMarksHistoryInputSchema,\n RunsMarksHistoryResultSchema,\n type RunDetailProjection,\n type RunsArtifactInput,\n type RunsArtifactResult,\n} from '@vostride/agent-qa-schema'\n\nimport type { AgentHost } from '../chat/host.js'\nimport { readJsonBody } from '../server/body-parser.js'\nimport { refuseCrossSiteRequest } from '../server/cross-site.js'\n\n/** A refusal, already carrying its status and its single-key body. */\nexport interface RunDetailRefusal {\n readonly kind: 'refused'\n readonly status: number\n readonly body: Record<string, string>\n}\n\nexport type RunDetailReadOutcome =\n | { readonly kind: 'ok'; readonly body: RunDetailProjection }\n | RunDetailRefusal\n\n/** The name a rejection carries, read structurally — never by class, never by message. */\nfunction errorNameOf(error: unknown): string {\n if (typeof error !== 'object' || error === null) return 'UnknownError'\n const name = (error as { name?: unknown }).name\n return typeof name === 'string' && name.length > 0 ? name : 'UnknownError'\n}\n\nfunction errorMessageOf(error: unknown): string {\n if (typeof error !== 'object' || error === null) return ''\n const message = (error as { message?: unknown }).message\n return typeof message === 'string' ? message : ''\n}\n\n/**\n * The op's refusals, classified into this door's vocabulary.\n *\n * `FunctionNotBoundError` CARRIES ITS MESSAGE because that text tells an operator what to do —\n * which op this host does not bind. `RunNotFoundError` does NOT: it would echo the requested id\n * back into a response body, and a refusal that quotes untrusted input is a reflection this door\n * has no reason to offer. Anything else is an unclassified throw from inside the store, whose\n * message may name a path or quote a row; that one travels as a NAME, which is a classification\n * rather than a disclosure.\n *\n * EXPORTED SINCE 406-01 (D-04). `run-analysis-routes.ts` dispatches `analysisGetFunctionId` through\n * the same host and meets the same three refusals; a second spelling of `unknown_run` /\n * `agent_host_unavailable` / `read_failed` there would be a second vocabulary for one door, free to\n * drift the first time either side gains a class.\n */\nexport function refusalFor(error: unknown): RunDetailRefusal {\n const name = errorNameOf(error)\n if (name === 'RunNotFoundError') {\n return { kind: 'refused', status: 404, body: { error: 'unknown_run' } }\n }\n if (name === 'FunctionNotBoundError') {\n return {\n kind: 'refused',\n status: 503,\n body: { error: 'agent_host_unavailable', reason: errorMessageOf(error) },\n }\n }\n return { kind: 'refused', status: 500, body: { error: 'read_failed', reason: name } }\n}\n\n/**\n * THE READ. Exported so a cell can measure the outcome without a socket, and so any second door\n * (405-05's authed remote row) answers with byte-identical bytes by CALLING this rather than by a\n * second spelling that agrees today.\n */\nexport async function readRunDetail(\n host: AgentHost,\n runId: string,\n): Promise<RunDetailReadOutcome> {\n // THE ID IS VALIDATED BY THE OP'S OWN INPUT SCHEMA, HERE, BEFORE THE DOOR IS TOUCHED\n // (T-405-01). Not a second regex: `runIdSchema` refuses exactly the ids the path layer would\n // have to REWRITE before using them, and the whole point of that codec is that there is one of\n // it. Refusing early also means an untrusted path segment never reaches a dispatch at all.\n const parsed = RunsDetailInputSchema.safeParse({ runId })\n if (!parsed.success) {\n return { kind: 'refused', status: 400, body: { error: 'invalid_run_id' } }\n }\n\n try {\n const projection = await host.invokeFunction(\n host.registry,\n host.runsDetailFunctionId,\n parsed.data,\n host.caller,\n ) as RunDetailProjection\n return { kind: 'ok', body: projection }\n } catch (error) {\n return refusalFor(error)\n }\n}\n\n/**\n * This door's JSON writer — and the ABSENCE of a cross-origin grant on it is load-bearing (405 CR-01).\n *\n * `serveRunDetailRead` answers a run's whole stored projection. `Content-Type` and `Content-Length`\n * are the whole header set on purpose: no `Access-Control-Allow-Origin`, because a page on another\n * origin that the operator happens to have open must not be able to read a run out of this\n * response. Until CR-01 that posture was\n * an accident of which writer this file inherited rather than a decision, and the sibling arms in\n * `server/routes.ts` — which answered through the wildcard-writing `json()` — proved how easily the\n * accident goes the other way. If a later refactor wants one JSON writer across both files, the one\n * it converges on must be the no-grant one.\n *\n * EXPORTED SINCE 406-01: `run-analysis-routes.ts` is that later refactor's first caller, and it\n * converged on this writer rather than minting a second one.\n */\nexport function respondJson(res: ServerResponse, status: number, data: unknown): void {\n if (res.headersSent || res.writableEnded) {\n res.destroy()\n return\n }\n const body = JSON.stringify(data)\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n}\n\nexport interface RunDetailReadDeps {\n /** The DECODED run id. Decoding can throw, and that throw is the caller's refusal to answer. */\n readonly runId: string\n /** The injected host. Its absence is the ROUTER'S 503, not this function's. */\n readonly host: AgentHost\n /**\n * WHO IS ON THE OTHER END OF THIS SOCKET (405-10, D-09). Both doors serve the same body, masked\n * at write, and nothing restores it (441 D-07); `'human'` only turns on the same-site guard.\n *\n * `'human'` IS PASSED BY THE LOCAL door's arms in `routes.ts`. The authed REMOTE door's\n * `GET /run/:runId/detail` (`run-service-routes.ts`, 405-05) passes nothing, because it is\n * legitimately reached at a non-loopback Host.\n */\n readonly boundary?: 'human' | 'machine'\n}\n\n/** Parsed evidence shares the guarded human boundary; raw artifacts never enter this path. */\nexport function serveRunEvidenceRead(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RunDetailReadDeps,\n): void {\n if (deps.boundary === 'human' && refuseCrossSiteRequest(req)) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n const query = new URL(req.url ?? '/', 'http://localhost').searchParams\n const entries: Array<[string, unknown]> = [['runId', deps.runId]]\n const seen = new Set(['runId'])\n for (const [key, value] of query) {\n if (seen.has(key)) {\n respondJson(res, 400, { error: 'invalid_evidence_input' })\n return\n }\n seen.add(key)\n if (key === 'testIndex' || key === 'stepIndex' || key === 'subActionIndex') {\n // Do not coerce blanks, fractions, exponents or signed values into a recorded index.\n entries.push([key, /^(0|[1-9][0-9]*)$/.test(value) ? Number(value) : value])\n } else entries.push([key, value])\n }\n const parsed = RunsEvidenceInputSchema.safeParse(Object.fromEntries(entries))\n if (!parsed.success) {\n respondJson(res, 400, { error: 'invalid_evidence_input' })\n return\n }\n void deps.host.invokeFunction(deps.host.registry, deps.host.runsEvidenceFunctionId,\n parsed.data, deps.host.caller).then(result => {\n const body = RunsEvidenceResultSchema.parse(result)\n respondJson(res, 200, body)\n }).catch((error: unknown) => {\n const refusal = refusalFor(error)\n respondJson(res, refusal.status, refusal.body)\n })\n}\n\n/**\n * Answer one feedback read's typed result. Its outcomes, refusals included, are the op's result\n * and travel as 200; only thrown classes map to status codes. Every door answers the op's body as\n * stored.\n */\nfunction respondFeedbackRead(\n res: ServerResponse,\n deps: RunDetailReadDeps,\n functionId: string,\n input: unknown,\n parse: (result: unknown) => unknown,\n): void {\n void deps.host.invokeFunction(deps.host.registry, functionId, input, deps.host.caller).then(result => {\n const body = parse(result)\n respondJson(res, 200, body)\n }).catch((error: unknown) => {\n const refusal = refusalFor(error)\n respondJson(res, refusal.status, refusal.body)\n })\n}\n\n/** 2026-09-15, 423-21 D-18: `GET …/:runId/marks` — runs.marks.history on either door. */\nexport function serveRunMarksHistoryRead(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RunDetailReadDeps,\n): void {\n if (deps.boundary === 'human' && refuseCrossSiteRequest(req) !== undefined) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n // The op's input is the run id alone; a query string is a second, unvalidated address.\n if (new URL(req.url ?? '/', 'http://localhost').search !== '') {\n respondJson(res, 400, { error: 'invalid_marks_input' })\n return\n }\n const parsed = RunsMarksHistoryInputSchema.safeParse({ runId: deps.runId })\n if (!parsed.success) {\n respondJson(res, 400, { error: 'invalid_run_id' })\n return\n }\n respondFeedbackRead(res, deps, deps.host.runsMarksHistoryFunctionId, parsed.data,\n result => RunsMarksHistoryResultSchema.parse(result))\n}\n\n/**\n * 2026-09-15, 423-21 D-18: `POST …/:runId/mark-preview` — runs.mark.preview on either door.\n *\n * POST carries the exact runs.mark input, but the op is read-tier: it plans and writes nothing, so\n * no confirm scope is accepted. The body's runId must name the URL's run, so a page cannot preview\n * one run under another run's address.\n */\nexport function serveRunMarkPreviewRead(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RunDetailReadDeps,\n): void {\n if (deps.boundary === 'human' && refuseCrossSiteRequest(req) !== undefined) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n void readJsonBody<unknown>(req).then((body) => {\n const parsed = RunsMarkInputSchema.safeParse(body)\n if (!parsed.success) {\n respondJson(res, 400, { error: 'invalid_mark_preview_input' })\n return\n }\n if (parsed.data.runId !== deps.runId) {\n respondJson(res, 400, { error: 'run_id_mismatch' })\n return\n }\n respondFeedbackRead(res, deps, deps.host.runsMarkPreviewFunctionId, parsed.data,\n result => RunsMarkPreviewResultSchema.parse(result))\n }, () => { respondJson(res, 400, { error: 'invalid_mark_preview_input' }) })\n}\n\n/** `GET /api/runs/:id/detail` — what the rebuilt run-detail page reads (D-03). */\nexport function serveRunDetailRead(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RunDetailReadDeps,\n): void {\n // THE SAME-SITE GUARD, AND IT IS GATED ON `boundary` BECAUSE THIS FUNCTION SERVES TWO DOORS\n // (405 CR-01, second pass).\n //\n // WHY IT LIVES HERE AND NOT AT THE ROUTER'S DISPATCH. This arm answers the richest body on the\n // door — the whole run-detail projection — from this file, so the guard sits beside that answer.\n // A future caller that opts into `'human'` inherits the guard instead of having to remember it.\n //\n // WHY `boundary === 'human'` AND NOT UNCONDITIONALLY. The authed REMOTE door dispatches this same\n // function with no `boundary`, and that door is legitimately reached at a NON-loopback Host. An\n // unconditional loopback check here would refuse every real remote read — a guard that breaks the\n // door it was not written for. Gating on `boundary` makes the refusal fire on the local human\n // arm, and only it.\n //\n // WHAT IT IS FOR, GIVEN CORS IS ALREADY CLOSED HERE. `respondJson` writes no cross-origin grant,\n // so a page on another ORIGIN already cannot read this body. What the grant's absence does NOT\n // stop is DNS rebinding — the attacker's own name resolves to loopback, so the browser treats the\n // read as same-origin and asks for no grant at all. The Host check inside `refuseCrossSiteRequest`\n // is the rung that closes that, and it ADMITS the caller that sends no `Origin` at all, which is\n // the local non-browser drive this door also serves.\n //\n // ORDERING. The router decodes the run id before calling this function, so a cross-site caller\n // with an undecodable id still meets that 400 first. That is left as it is: the 400 is a statement\n // about the caller's own input and discloses nothing about any run, where every answer this\n // function can give does.\n if (deps.boundary === 'human' && refuseCrossSiteRequest(req) !== undefined) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n void readRunDetail(deps.host, deps.runId).then(\n (outcome) => {\n if (outcome.kind === 'refused') {\n respondJson(res, outcome.status, outcome.body)\n return\n }\n respondJson(res, 200, outcome.body)\n },\n // The read classifies every refusal it can name; anything reaching here is this module\n // failing, which is a 500 by name and never a body that looks like an answer.\n (error: unknown) => { respondJson(res, 500, refusalFor(error).body) },\n )\n}\n\n// ---- 405-05 (D-12/D-13/D-15 · DETL-03): the ref-RESOLVING arm, on both doors ---------------------\n//\n// `GET /api/runs/:runId/artifacts/:sha` locally, `GET /run/:runId/artifacts/:sha` on the authed\n// remote door, and BOTH call the one function below. The run-detail read hands a page a `sha`; this\n// is where that sha becomes an image, and if the two doors resolved it through two implementations\n// then \"the same artifact\" would mean two things depending on which credential asked.\n//\n// THE BYTES CROSS THE FUNCTION LAYER (D-13). This module constructs no store, joins no path and\n// imports nothing that can read a file. Containment is `FsEvidenceArtifactStore`'s own rule —\n// `slugBranch` over the runId, a 64-lowercase-hex check over the sha — reached through the op, so\n// there is exactly one place in the product where a caller-supplied string becomes a path segment.\n//\n// THE SHA IS VALIDATED BY THE OP'S OWN INPUT SCHEMA, AND WHICH FIELD FAILED IS THE ANSWER. A\n// malformed run id and a malformed sha are different mistakes a caller can fix, so the parse's\n// failure paths are read apart rather than collapsed into one 400.\n//\n// NOTHING ECHOES THE REQUEST. Every refusal body is a fixed shape carrying a closed word; a body\n// that quoted the sha would reflect attacker-chosen bytes back through a door that has no reason\n// to offer one (T-405-18).\n\n/** The immutable-caching header set a CONTENT ADDRESS earns (D-12). */\nconst ARTIFACT_CACHE_CONTROL = 'public, max-age=31536000, immutable'\n\nexport function parseSingleByteRange(header: string | undefined): RunsArtifactInput['range'] {\n const match = header === undefined ? null : /^bytes=(\\d+)-(\\d*)$/.exec(header)\n if (match === null) return undefined\n const start = Number(match[1])\n const end = match[2] === '' ? undefined : Number(match[2])\n if (!Number.isSafeInteger(start) ||\n (end !== undefined && (!Number.isSafeInteger(end) || end < start))) return undefined\n return { start, ...(end === undefined ? {} : { end }) }\n}\n\nexport type RunArtifactReadOutcome =\n | {\n readonly kind: 'ok'\n readonly sha: string\n readonly contentType: string\n readonly bytes: Buffer\n readonly range?: RunsArtifactResult['range']\n readonly totalLength?: number\n }\n | { readonly kind: 'range-not-satisfiable'; readonly totalLength: number }\n | RunDetailRefusal\n\n/**\n * The op's refusals, classified into this door's vocabulary.\n *\n * `EvidenceBlobAbsentError` AND `RunNotFoundError` ARE BOTH 404 AND THEY ARE NOT THE SAME 404\n * (D-15). One says the link names a run nothing recorded; the other says the run is right there and\n * holds no blob under that address — a screenshot the evidence diet collected, a ref that declared\n * itself incomplete, or an artifact never written. The page renders the second as a visible\n * \"unavailable\" state and the first as a broken link, and it can only do that because the words\n * differ. Neither body carries the sha.\n */\nfunction artifactRefusalFor(error: unknown): RunDetailRefusal {\n const name = errorNameOf(error)\n if (name === 'RunNotFoundError') {\n return { kind: 'refused', status: 404, body: { error: 'unknown_run' } }\n }\n if (name === 'EvidenceBlobAbsentError') {\n return { kind: 'refused', status: 404, body: { error: 'blob_absent' } }\n }\n if (name === 'FunctionNotBoundError') {\n return {\n kind: 'refused',\n status: 503,\n body: { error: 'agent_host_unavailable', reason: errorMessageOf(error) },\n }\n }\n return { kind: 'refused', status: 500, body: { error: 'read_failed', reason: name } }\n}\n\n/**\n * THE READ. Exported so a cell can measure the outcome without a socket, and so the authed remote\n * door answers with byte-identical bytes by CALLING this rather than by a second spelling.\n */\nexport async function readRunArtifact(\n host: AgentHost,\n runId: string,\n sha: string,\n range?: RunsArtifactInput['range'],\n): Promise<RunArtifactReadOutcome> {\n const parsed = RunsArtifactInputSchema.safeParse({ runId, sha })\n if (!parsed.success) {\n // WHICH FIELD, not merely THAT it failed. `runIdSchema` refuses exactly the ids the path layer\n // would have to rewrite, and the sha regex refuses everything that is not a content address;\n // telling a caller which of the two it got wrong costs one issue-path read and is the whole\n // difference between an actionable 400 and a shrug.\n const blamesSha = parsed.error.issues.some((issue) => issue.path[0] === 'sha')\n return {\n kind: 'refused',\n status: 400,\n body: { error: blamesSha ? 'malformed_sha' : 'invalid_run_id' },\n }\n }\n\n try {\n const result = await host.invokeFunction(\n host.registry,\n host.runsArtifactFunctionId,\n { ...parsed.data, ...(range === undefined ? {} : { range }) },\n host.caller,\n ) as RunsArtifactResult\n return {\n kind: 'ok',\n sha: result.sha,\n contentType: result.contentType,\n // The ONE decode in the product. The op encodes without a host API because its package may\n // not name one; this package may, and this is the layer whose job is bytes on a socket.\n bytes: Buffer.from(result.bytesBase64, 'base64'),\n ...(result.range === undefined ? {} : { range: result.range, totalLength: result.totalLength }),\n }\n } catch (error) {\n if (errorNameOf(error) === 'ArtifactRangeNotSatisfiableError') {\n const totalLength = (error as { totalLength?: unknown }).totalLength\n if (typeof totalLength === 'number' && Number.isSafeInteger(totalLength) && totalLength >= 0) {\n return { kind: 'range-not-satisfiable', totalLength }\n }\n }\n return artifactRefusalFor(error)\n }\n}\n\nexport interface RunArtifactReadDeps {\n /** The DECODED run id. Decoding can throw, and that throw is the caller's refusal to answer. */\n readonly runId: string\n /** The RAW sha segment. Never decoded: a content address contains nothing percent-encoding\n * could represent, so a segment that needed decoding is already not one. */\n readonly sha: string\n /** The injected host. Its absence is the ROUTER'S 503, not this function's. */\n readonly host: AgentHost\n}\n\n/**\n * `GET /api/runs/:runId/artifacts/:sha` — a ref, resolved (D-12).\n *\n * THE HEADERS ARE THE FEATURE AS MUCH AS THE BYTES.\n * - `ETag: \"<sha>\"` — the content address IS the validator; there is nothing else it could be, and\n * nothing that could make it stale, because bytes cannot change under a hash of themselves.\n * - `Cache-Control: public, max-age=31536000, immutable` — for the same reason. A revalidation of\n * an immutable resource is a round trip that can only ever answer \"yes, still\".\n * - `X-Content-Type-Options: nosniff` — the second half of the T-405-15 mitigation. The op refuses\n * to NAME a type a browser executes; this refuses to let the browser guess one anyway.\n * - `Content-Length` — from the op's own declared `byteLength` by way of the decoded buffer.\n *\n * `If-None-Match` IS HONOURED because it is three lines against a header set that promises a year\n * of caching, and a client that revalidates anyway should not be made to re-download a screenshot.\n */\nexport function serveRunArtifact(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RunArtifactReadDeps,\n): void {\n const revalidating = req.headers['if-none-match'] === `\"${deps.sha}\"`\n const range = revalidating ? undefined : parseSingleByteRange(req.headers.range)\n void readRunArtifact(deps.host, deps.runId, deps.sha, range).then(\n (outcome) => {\n if (outcome.kind === 'refused') {\n respondJson(res, outcome.status, outcome.body)\n return\n }\n if (res.headersSent || res.writableEnded) {\n res.destroy()\n return\n }\n const etag = `\"${deps.sha}\"`\n const headers = {\n ETag: etag,\n 'Cache-Control': ARTIFACT_CACHE_CONTROL,\n 'X-Content-Type-Options': 'nosniff',\n 'Accept-Ranges': 'bytes',\n }\n // THE VALIDATOR IS COMPARED WHOLE, against the quoted form this door writes. No weak-match\n // and no list parse: this door mints exactly one validator per resource and a request that\n // presents anything else has not seen this resource.\n if (req.headers['if-none-match'] === etag) {\n res.writeHead(304, headers)\n res.end()\n return\n }\n if (outcome.kind === 'range-not-satisfiable') {\n res.writeHead(416, {\n ...headers,\n 'Content-Range': `bytes */${outcome.totalLength}`,\n 'Content-Length': 0,\n })\n res.end()\n return\n }\n res.writeHead(outcome.range === undefined ? 200 : 206, {\n ...headers,\n 'Content-Type': outcome.contentType,\n 'Content-Length': outcome.bytes.byteLength,\n ...(outcome.range === undefined ? {} : {\n 'Content-Range': `bytes ${outcome.range.start}-${outcome.range.end}/${outcome.totalLength}`,\n }),\n })\n res.end(outcome.bytes)\n },\n // The read classifies every refusal it can name; anything reaching here is this module\n // failing, which is a 500 by name and never a body that looks like an answer.\n (error: unknown) => { respondJson(res, 500, artifactRefusalFor(error).body) },\n )\n}\n","// The run-ANALYSIS read route (Phase 406 plan 01, D-04).\n//\n// `GET /api/runs/:id/analysis` locally, `GET /run/:runId/analysis` on the authed remote door, and\n// BOTH call the one function below. This module is the whole of the HTTP half: validate the id\n// with the OP'S OWN input schema, dispatch through the injected host, map the op's named refusals\n// onto status codes. IT FORMATS NOTHING. It composes no sentence, folds no cluster and opens no\n// database — `analysis.get` is THE single producer of a run's verdicts, sentences and clusters\n// (389 D-11), and a second producer on this door is the 405 D-01 anti-pattern restated.\n//\n// BOTH DOORS, ONE ADAPTER (D-04). 405 D-12/D-13 established the shape and 405-05 proved why: two\n// doors resolving one read through two implementations means \"the same analysis\" depends on which\n// credential asked. The sibling detail adapter's own note says a second spelling agrees on the day\n// it is written and is a wire-contract fork thereafter.\n//\n// BOTH DOORS SERVE THE STORED BODY (441 D-07). The verdict sentence quotes the failing step's\n// recorded error, which was masked at write, and neither door restores anything. The local arm's\n// `boundary: 'human'` only turns on the same-site guard below.\n//\n// THE REFUSAL VOCABULARY IS IMPORTED, NEVER RESPELLED. `refusalFor` is the detail adapter's, made\n// exported for this file; `unknown_run` / `agent_host_unavailable` / `read_failed` mean here\n// exactly what they mean one module away.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport {\n AnalysisGetInputSchema,\n type AnalysisGetOutput,\n} from '@vostride/agent-qa-schema'\n\nimport type { AgentHost } from '../chat/host.js'\nimport { refuseCrossSiteRequest } from '../server/cross-site.js'\nimport { refusalFor, respondJson, type RunDetailRefusal } from './run-detail-routes.js'\n\nexport type RunAnalysisReadOutcome =\n | { readonly kind: 'ok'; readonly body: AnalysisGetOutput }\n | RunDetailRefusal\n\n/**\n * THE READ. Exported so a cell can measure the outcome without a socket, and so both doors answer\n * with byte-identical bytes by CALLING this rather than by a second spelling that agrees today.\n */\nexport async function readRunAnalysis(\n host: AgentHost,\n runId: string,\n): Promise<RunAnalysisReadOutcome> {\n // THE ID IS VALIDATED BY THE OP'S OWN INPUT SCHEMA, HERE, BEFORE THE DOOR IS TOUCHED. Not a\n // second regex: `runIdSchema` refuses exactly the ids the path layer would have to REWRITE\n // before using them, and the whole point of that codec is that there is one of it.\n const parsed = AnalysisGetInputSchema.safeParse({ runId })\n if (!parsed.success) {\n return { kind: 'refused', status: 400, body: { error: 'invalid_run_id' } }\n }\n\n try {\n const analysis = await host.invokeFunction(\n host.registry,\n host.analysisGetFunctionId,\n parsed.data,\n host.caller,\n ) as AnalysisGetOutput\n return { kind: 'ok', body: analysis }\n } catch (error) {\n return refusalFor(error)\n }\n}\n\nexport interface RunAnalysisReadDeps {\n /** The DECODED run id. Decoding can throw, and that throw is the caller's refusal to answer. */\n readonly runId: string\n /** The injected host. Its absence is the ROUTER'S 503, not this function's. */\n readonly host: AgentHost\n /**\n * WHO IS ON THE OTHER END OF THIS SOCKET. Both values serve the same stored body (441 D-07);\n * `'human'` only turns on the same-site guard. It is passed by exactly one arm, the LOCAL door's\n * `GET /api/runs/:id/analysis` in `routes.ts`; the remote `GET /run/:runId/analysis` row passes\n * nothing.\n */\n readonly boundary?: 'human' | 'machine'\n}\n\n/** `GET /api/runs/:id/analysis` — the failure view's one read (D-04). */\nexport function serveRunAnalysisRead(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RunAnalysisReadDeps,\n): void {\n // THE SAME-SITE GUARD, GATED ON `boundary` FOR THE REASON THE DETAIL ADAPTER RECORDS (405 CR-01):\n // the remote door dispatches the same function from a legitimately non-loopback Host, and an\n // unconditional check would refuse the door it was not written for.\n if (deps.boundary === 'human' && refuseCrossSiteRequest(req) !== undefined) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n void readRunAnalysis(deps.host, deps.runId).then(\n (outcome) => {\n if (outcome.kind === 'refused') {\n respondJson(res, outcome.status, outcome.body)\n return\n }\n respondJson(res, 200, outcome.body)\n },\n // The read classifies every refusal it can name; anything reaching here is this module\n // failing, which is a 500 by name and never a body that looks like an answer.\n (error: unknown) => { respondJson(res, 500, refusalFor(error).body) },\n )\n}\n","// The post-processing READ route and its dedicated live channel (Phase 404 plan 05,\n// D-16/D-17/D-18/D-22/D-23 · LIFE-03/LIFE-04).\n//\n// TWO DOORS ONTO ONE ANSWER, AND THE ANSWER IS ALWAYS A RE-READ. `GET /api/runs/:id/post-processing`\n// is what a page polls; `…/post-processing/stream` opens with the SAME body as a `snapshot` frame\n// and then relays chip envelopes as they are appended. The envelopes are TRIGGERS (D-17): a\n// consumer that derived a chip from one would be a second projection of chip truth, free to\n// disagree with `runs.postprocessing` over the durable rows — which is the one thing 388 D-14 and\n// 404 D-16 rule out by name. Nothing in this file reads a job store, opens `agent-jobs.db` or\n// composes a chip; every fact on the wire arrived through the injected host's one door.\n//\n// WHY THE READ JOINS TWO RECORDS. The chain's chips live in the durable job store and are read\n// through `runs.postprocessing`. The run's POSTURE — `drained` / `handedOff` / `detached`, i.e. who\n// was going to pump that chain — is a decision made at the verdict and written on the\n// `runFinished` line of the run's own event log, and the last per-stage failure TEXT rides the chip\n// envelopes on that same log (404-03 D-21: the durable notification row deliberately carries no\n// failure prose). So the read invokes `runs.events` as well and folds the record. That fold is\n// STRICTLY A FORWARD: a failed stage whose log holds no `*Failed` envelope — a daemon-drained run,\n// or one drained after this process last saw it — gets NO `failures` entry, because the record\n// declined to say and this route does not compose prose on the record's behalf.\n//\n// EVERY REFUSAL IS NAMED (D-23). The alternative that actually shipped in surfaces like this one is\n// an all-pending body: a page that cannot tell \"the chain has not started\" from \"the composition\n// bound no such op\" renders two grey chips forever and calls it a state. So an unbound function, a\n// job store stamped by another build, an id the op refuses and a missing host each have their own\n// word, and the words are read STRUCTURALLY off `error.name` — this package may not import the\n// packages that mint those classes (validate:arch), and a message compare would be a compare\n// against prose somebody will rewrite.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport {\n RunsPostProcessingInputSchema,\n type ChipEventPayload,\n type PostProcessingDisposition,\n type PostProcessingStatus,\n type RunEventEnvelope,\n type RunFinishedPayload,\n} from '@vostride/agent-qa-schema'\n\nimport type { AgentHost } from '../chat/host.js'\nimport type { PostProcessingRelay } from '../execution/post-processing-relay.js'\n\n/**\n * The comment-frame keepalive interval, matching every other SSE this package serves.\n *\n * EXPORTED so a cell can name the number rather than sleep past it, and so the client (404-07)\n * can size its own liveness expectation off the server's constant instead of a second guess.\n */\nexport const POST_PROCESSING_STREAM_HEARTBEAT_MS = 15_000\n\n/**\n * The SSE event name the joined read travels under.\n *\n * DELIBERATELY NOT A BUS EVENT TYPE (T-404-03). Every other frame on this stream is an envelope\n * whose `event:` is its own `type`, so the one frame that is NOT an envelope must be unmistakable:\n * a client switching on the frame name can never confuse the whole-state answer with a chip tick.\n */\nconst SNAPSHOT_EVENT = 'snapshot'\n\n/** The last failure the record holds for one stage — the emitter's masked, bounded text, forwarded. */\nexport interface PostProcessingStageFailure {\n readonly error?: string\n readonly willRetry?: boolean\n}\n\n/** What both doors answer with: the op result, plus what the run's own record says about it. */\nexport interface PostProcessingReadBody {\n /** The `runs.postprocessing` result, VERBATIM. A reshaping here would be a second contract. */\n readonly status: PostProcessingStatus\n /** The `runFinished` posture, when the record has one. Absent while the run is still in flight. */\n readonly disposition?: PostProcessingDisposition\n /**\n * The last `analysisFailed` / `curationFailed` payload per stage.\n *\n * PRESENT AND POSSIBLY EMPTY when the record was read; ABSENT ENTIRELY when the events read\n * refused. The difference is a fact a client can act on — \"this run wrote no failure line\" is not\n * the same claim as \"this door could not read the log\".\n */\n readonly failures?: {\n readonly analysis?: PostProcessingStageFailure\n readonly curation?: PostProcessingStageFailure\n }\n}\n\n/** A refusal, already carrying its status and its single-key body. */\ninterface PostProcessingRefusal {\n readonly kind: 'refused'\n readonly status: number\n readonly body: Record<string, string>\n}\n\ntype PostProcessingReadOutcome =\n | { readonly kind: 'ok'; readonly body: PostProcessingReadBody }\n | PostProcessingRefusal\n\n/**\n * Has this chain finished, whatever became of it?\n *\n * TWO CLAUSES BECAUSE THERE ARE TWO TERMINALS AND THE ROW OUTRANKS THE CHIPS. A chain that wrote\n * its one `RunNotification` is over by definition — that row IS the chain's terminal receipt — and\n * a projection that disagreed with it would be a chain that ended twice. Absent the row, both chips\n * having settled (`complete` or `failed`, the only two settled words in the four-word vocabulary) is\n * the same fact read one layer down.\n */\nexport function isPostProcessingTerminal(status: PostProcessingStatus): boolean {\n if (status.notification !== undefined) return true\n const settled = (chip: PostProcessingStatus['chips']['analysis']): boolean =>\n chip === 'complete' || chip === 'failed'\n return settled(status.chips.analysis) && settled(status.chips.curation)\n}\n\n/** The name a rejection carries, read structurally — never by class, never by message. */\nfunction errorNameOf(error: unknown): string {\n if (typeof error !== 'object' || error === null) return 'UnknownError'\n const name = (error as { name?: unknown }).name\n return typeof name === 'string' && name.length > 0 ? name : 'UnknownError'\n}\n\nfunction errorMessageOf(error: unknown): string {\n if (typeof error !== 'object' || error === null) return ''\n const message = (error as { message?: unknown }).message\n return typeof message === 'string' ? message : ''\n}\n\n/**\n * The op's refusals, classified into this door's vocabulary.\n *\n * THE TWO NAMED ARMS CARRY THEIR MESSAGE AND THE FALLBACK CARRIES ONLY THE NAME, and the asymmetry\n * is the point. `FunctionNotBoundError` and `JobStoreSchemaVersionError` are both minted with text\n * that tells an operator what to DO — which op was not bound, that the queue database must be\n * cleared — and withholding it would leave a 503 nobody can act on. Anything else is an unclassified\n * throw from somewhere inside the store, whose message is arbitrary prose that may name a path or\n * quote a row; that one travels as a NAME, which is a classification rather than a disclosure.\n */\nfunction refusalFor(error: unknown): PostProcessingRefusal {\n const name = errorNameOf(error)\n if (name === 'FunctionNotBoundError') {\n return { kind: 'refused', status: 503, body: { error: 'function_not_bound', reason: errorMessageOf(error) } }\n }\n if (name === 'JobStoreSchemaVersionError') {\n return { kind: 'refused', status: 503, body: { error: 'job_store_schema_version', reason: errorMessageOf(error) } }\n }\n return { kind: 'refused', status: 500, body: { error: 'post_processing_unavailable', reason: name } }\n}\n\n/** What the record says, folded out of one drain of the events stream. */\ninterface RecordFold {\n readonly disposition?: PostProcessingDisposition\n readonly failures: {\n analysis?: PostProcessingStageFailure\n curation?: PostProcessingStageFailure\n }\n}\n\nfunction stageFailureOf(payload: ChipEventPayload): PostProcessingStageFailure {\n return {\n ...(payload.error === undefined ? {} : { error: payload.error }),\n ...(payload.willRetry === undefined ? {} : { willRetry: payload.willRetry }),\n }\n}\n\n/**\n * Drain the whole recorded log once and keep the two facts the chips cannot carry.\n *\n * THE LAST ENVELOPE PER STAGE WINS, deliberately: a stage that failed, was retried and failed again\n * has two lines, and the honest answer to \"why is this chip red\" is the reason it is red NOW. The\n * whole iterable is consumed rather than stopped early — abandoning a stream mid-delivery is a side\n * effect on a producer this route does not own, and the recorded log of one run is bounded.\n */\nasync function foldRecord(events: AsyncIterable<RunEventEnvelope>): Promise<RecordFold> {\n const failures: RecordFold['failures'] = {}\n let disposition: PostProcessingDisposition | undefined\n for await (const envelope of events) {\n if (envelope.type === 'runFinished') {\n disposition = (envelope.payload as RunFinishedPayload).disposition\n continue\n }\n if (envelope.type === 'analysisFailed') {\n failures.analysis = stageFailureOf(envelope.payload as ChipEventPayload)\n continue\n }\n if (envelope.type === 'curationFailed') {\n failures.curation = stageFailureOf(envelope.payload as ChipEventPayload)\n }\n }\n return { ...(disposition === undefined ? {} : { disposition }), failures }\n}\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterable<RunEventEnvelope> {\n return (\n typeof value === 'object'\n && value !== null\n && typeof (value as AsyncIterable<RunEventEnvelope>)[Symbol.asyncIterator] === 'function'\n )\n}\n\n/**\n * THE JOINED READ — the one place chip truth and run posture are put beside each other.\n *\n * Exported so the stream door and the read door answer with byte-identical bodies by CALLING one\n * function rather than by two spellings that agree today. `routes.post-processing-stream.test.ts`\n * compares the snapshot frame against the read route's body for exactly that reason.\n */\nexport async function readPostProcessing(\n host: AgentHost,\n runId: string,\n): Promise<PostProcessingReadOutcome> {\n // THE ID IS VALIDATED BY THE OP'S OWN INPUT SCHEMA, HERE, BEFORE THE DOOR IS TOUCHED (T-404-07).\n // Not a second regex: `runIdSchema` refuses exactly the ids the path layer would have to REWRITE\n // before using them as a directory name, and the whole point of that codec is that there is one\n // of it. Refusing early also means an untrusted path segment never reaches a dispatch at all.\n const parsed = RunsPostProcessingInputSchema.safeParse({ runId })\n if (!parsed.success) {\n return { kind: 'refused', status: 400, body: { error: 'invalid_run_id' } }\n }\n\n let status: PostProcessingStatus\n try {\n status = await host.invokeFunction(\n host.registry,\n host.runsPostProcessingFunctionId,\n parsed.data,\n host.caller,\n ) as PostProcessingStatus\n } catch (error) {\n return refusalFor(error)\n }\n\n // THE RECORD IS THE WEAKER OF THE TWO SOURCES AND DEGRADES ALONE. A run whose log fell out of the\n // replay window, or whose events op is unbound, still has durable chip truth — and a route that\n // 500ed on the log would hide the answer it already has in hand. Both joined fields go absent\n // together, which is what tells a client the record was not read rather than that it was empty.\n try {\n const events = await host.invokeFunction(\n host.registry,\n host.runsEventsFunctionId,\n { runId: parsed.data.runId },\n host.caller,\n )\n if (!isAsyncIterable(events)) return { kind: 'ok', body: { status } }\n const record = await foldRecord(events)\n return {\n kind: 'ok',\n body: {\n status,\n ...(record.disposition === undefined ? {} : { disposition: record.disposition }),\n failures: record.failures,\n },\n }\n } catch {\n return { kind: 'ok', body: { status } }\n }\n}\n\nfunction respondJson(res: ServerResponse, status: number, data: unknown): void {\n if (res.headersSent || res.writableEnded) {\n res.destroy()\n return\n }\n const body = JSON.stringify(data)\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Content-Length': Buffer.byteLength(body),\n })\n res.end(body)\n}\n\nexport interface PostProcessingReadDeps {\n /** The DECODED run id. Decoding can throw, and that throw is the caller's refusal to answer. */\n readonly runId: string\n /** The injected host. Its absence is the ROUTER'S 503, not this function's. */\n readonly host: AgentHost\n}\n\n/** `GET /api/runs/:id/post-processing` — what the page polls (D-18). */\nexport function servePostProcessingRead(\n _req: IncomingMessage,\n res: ServerResponse,\n deps: PostProcessingReadDeps,\n): void {\n void readPostProcessing(deps.host, deps.runId).then(\n (outcome) => {\n if (outcome.kind === 'refused') {\n respondJson(res, outcome.status, outcome.body)\n return\n }\n respondJson(res, 200, outcome.body)\n },\n // The read swallows what it can degrade past; anything reaching here is this module failing,\n // which is a 500 by name and never a body that looks like an answer.\n (error: unknown) => { respondJson(res, 500, refusalFor(error).body) },\n )\n}\n\nexport interface PostProcessingStreamDeps extends PostProcessingReadDeps {\n /** The in-process chip sink this browser's frames come from. */\n readonly relay: PostProcessingRelay\n /** Live teardowns, so a host can count open streams and a close removes exactly one. */\n readonly openStreams?: {\n add(teardown: () => void): void\n delete(teardown: () => void): void\n }\n}\n\n/**\n * `GET /api/runs/:id/post-processing/stream` — the DEDICATED live channel (D-16).\n *\n * THE ORDER IS THE CONTRACT, on `serveRunEventStream`'s own law: every refusal happens before\n * `writeHead`, because a response that has already written `200 text/event-stream` cannot be told\n * it failed. So the joined read runs FIRST — it is the snapshot's content and the open-time\n * decision both — and only then does a head go out.\n *\n * THE 204 IS THE SSE SPEC'S NO-RECONNECT CLOSE, and it is the whole answer to Pitfall 6. An\n * `EventSource` reconnects after ANY close except a 204, so a door that answered `200` with an\n * immediate end to a run whose chain is over would be answering the same request every few seconds\n * for as long as the tab is open. Three states get it:\n *\n * - the chain is already terminal — there is nothing left to relay, ever;\n * - the run says `handedOff` — a lease-holder in ANOTHER process is draining it, and this\n * process's emitter will therefore never publish a single envelope for it;\n * - the run says `detached` — nothing is draining it in-process either.\n *\n * The last two are D-16's \"closes immediately on hand-off / detach\" and they are one decision with\n * two words, because the fact that matters is identical: this relay cannot ever fire for that run,\n * so the honest channel is the page's poll and holding a socket open would be a promise this\n * process cannot keep. A snapshot with NO disposition at all is the opposite case — the run has not\n * reached `runFinished` yet, which is exactly when a live channel is worth having — and it opens.\n */\nexport function servePostProcessingStream(\n req: IncomingMessage,\n res: ServerResponse,\n deps: PostProcessingStreamDeps,\n): void {\n /**\n * The half-built stream's resource release, hoisted so the failure arm can unwind it (UF-01).\n *\n * Assigned in the same breath the stream's state is declared and BEFORE the head goes out, so a\n * throw anywhere from `writeHead(200)` onwards is unwound rather than abandoned: without it a\n * failure between the head and `req.on('close', …)` leaves the 15s heartbeat ticking, the relay\n * subscription registered and this stream's teardown inside `openStreams`, behind a socket\n * nothing will ever close. It releases resources and TOUCHES THE RESPONSE NOT AT ALL — ending it\n * here would answer an empty 200 to a request the arm below still owes a refusal.\n */\n let unwindStream: (() => void) | undefined\n\n /**\n * THE ARM UF-01 NAMED, and the sibling read door at `servePostProcessingRead` already carries.\n *\n * `void promise.then(onOk)` with no failure arm turns any throw inside `onOk` into an unhandled\n * rejection — process-fatal by default on Node ≥ 15, so one closed tab takes the whole dashboard\n * server down with it. The throw is ordinary rather than exotic: two awaited op calls sit between\n * the request arriving and the head going out, and a client that aborts inside that window leaves\n * a response a later `writeHead`/`write` throws on.\n *\n * IT ANSWERS THE SAME FAILURE SHAPE THE SIBLING DOOR ANSWERS WITH, for the same reason — anything\n * reaching here is this module failing, and `refusalFor`'s unclassified arm travels as a NAME and\n * never a message (T-404-01), because an arbitrary throw's prose may quote a path or a row.\n *\n * AND IT LEAVES NOTHING HALF-OPEN. A response already carrying `200 text/event-stream` cannot be\n * told it failed, so once headers are out the only honest close is `destroy()`; before they are\n * out the request still gets its named refusal.\n */\n const failStream = (error: unknown): void => {\n try {\n unwindStream?.()\n } catch {\n // An unwind that throws may not become the second rejection this arm exists to prevent —\n // and the request below is still owed an answer.\n }\n try {\n if (res.headersSent || res.writableEnded) {\n res.destroy()\n return\n }\n respondJson(res, 500, refusalFor(error).body)\n } catch {\n try {\n res.destroy()\n } catch {\n // The socket is already past answering. There is nothing left to do and nothing left to\n // throw at: this function is the end of the chain.\n }\n }\n }\n\n void readPostProcessing(deps.host, deps.runId).then((outcome) => {\n if (outcome.kind === 'refused') {\n respondJson(res, outcome.status, outcome.body)\n return\n }\n const snapshot = outcome.body\n if (\n isPostProcessingTerminal(snapshot.status)\n || snapshot.disposition === 'handedOff'\n || snapshot.disposition === 'detached'\n ) {\n if (res.headersSent || res.writableEnded) {\n res.destroy()\n return\n }\n res.writeHead(204, { 'Cache-Control': 'no-cache' })\n res.end()\n return\n }\n\n // THE SAME GUARD THE 204 ARM ABOVE CARRIES, on the arm that OPENS a socket rather than closing\n // one (UF-01). The asymmetry was the bug: both arms are reached after the same two awaited op\n // calls, so both face the same already-answered response — and `writeHead` on one throws\n // `ERR_HTTP_HEADERS_SENT`, which is the throw that became the process-fatal rejection. Guarded\n // before any state is built, so this leg registers nothing it would then have to unwind.\n if (res.headersSent || res.writableEnded) {\n res.destroy()\n return\n }\n\n let closed = false\n let unsubscribe: (() => void) | undefined\n let heartbeat: ReturnType<typeof setInterval> | undefined\n // What `teardown` releases, with no opinion about the response — the failure arm needs exactly\n // this half, because it decides `destroy()` vs a named refusal for itself.\n const releaseStream = (): void => {\n if (closed) return\n closed = true\n if (heartbeat !== undefined) clearInterval(heartbeat)\n unsubscribe?.()\n deps.openStreams?.delete(teardown)\n }\n const teardown = (): void => {\n if (closed) return\n releaseStream()\n if (!res.writableEnded) res.end()\n }\n unwindStream = releaseStream\n\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n })\n // THE SNAPSHOT IS THE FIRST FRAME AND IT IS THE WHOLE ANSWER. A stream that opened with nothing\n // would leave the page holding whatever it last polled, for as long as no chip moved — which on\n // a chain between stages is minutes.\n res.write(`event: ${SNAPSHOT_EVENT}\\ndata: ${JSON.stringify(snapshot)}\\n\\n`)\n\n unsubscribe = deps.relay.subscribe(deps.runId, (envelope: RunEventEnvelope) => {\n if (closed) return\n // D-13's three parts, exactly as the run stream frames them: the id IS the seq, the event\n // name IS the envelope type, and the data IS the envelope's own JSON. No projection and no\n // second vocabulary — a client that can read one of this product's streams can read both.\n res.write(\n `id: ${String(envelope.seq)}\\nevent: ${envelope.type}\\ndata: ${JSON.stringify(envelope)}\\n\\n`,\n )\n if (!STAGE_SETTLING_EVENTS.has(envelope.type)) return\n // THE TRIGGER, ANSWERED BY A RE-READ (D-17). The envelope says a stage settled; whether the\n // CHAIN is over is a fact about durable rows, and this door asks the op rather than deriving\n // it from the tick it just wrote.\n void readPostProcessing(deps.host, deps.runId).then(\n (again) => {\n if (closed || again.kind !== 'ok') return\n if (!isPostProcessingTerminal(again.body.status)) return\n res.write(`event: ${SNAPSHOT_EVENT}\\ndata: ${JSON.stringify(again.body)}\\n\\n`)\n teardown()\n },\n // A failed re-read is not a reason to close a live channel: the next envelope will trigger\n // another, and the page's own poll is the floor underneath both.\n () => undefined,\n // …but a throw from the arm ABOVE is not a failed re-read, it is a dead socket, and `.then`'s\n // failure arm never sees its own fulfilment arm's throw (UF-01, on the nested chain).\n ).catch(failStream)\n })\n\n heartbeat = setInterval(() => { res.write(':\\n\\n') }, POST_PROCESSING_STREAM_HEARTBEAT_MS)\n deps.openStreams?.add(teardown)\n req.on('close', teardown)\n // THE SECOND ARGUMENT is the READ's own rejection — `readPostProcessing` swallows what it can\n // degrade past, so anything arriving there is this module failing. THE TRAILING `.catch` is the\n // FULFILMENT ARM'S OWN THROW, and it is a separate arm because `.then(onOk, onError)` answers\n // only for the promise it is attached to: a throw inside `onOk` rejects the DERIVED promise,\n // which `void` would strand as the process-fatal unhandled rejection UF-01 named.\n }, failStream).catch(failStream)\n}\n\n/**\n * The four envelope types that can move a chain to its terminal.\n *\n * `*Started` is excluded because a stage starting can never end a chain, and a re-read per tick\n * would double this door's op traffic to learn nothing. The set is spelled from the bus vocabulary\n * rather than derived by string surgery on the type name — a `curationCancelled` minted later would\n * be silently included by a `.endsWith('ed')` rule and silently excluded by this one, and being\n * excluded from a re-read is the safe direction (the page still polls).\n */\nconst STAGE_SETTLING_EVENTS = new Set<RunEventEnvelope['type']>([\n 'analysisCompleted',\n 'analysisFailed',\n 'curationCompleted',\n 'curationFailed',\n])\n","// The run-KNOWLEDGE read route (Phase 407 plan 01, LERN-01 / LERN-02 · D-05).\n//\n// `GET /api/runs/:id/knowledge` is what the Knowledge tab reads, and this module is the whole of\n// the HTTP half: validate the id with the OP'S OWN input schema, dispatch through the injected\n// host, map the op's named refusals onto status codes. IT FORMATS NOTHING. It composes no summary\n// line, folds no channel and opens no database — `runs.knowledge` is THE single producer of what\n// a run used and learned (407 D-05), and a second producer on this door is the 405 D-01\n// anti-pattern restated one surface later.\n//\n// ONE ADAPTER, ON THE ANALYSIS ARM'S FOOTING (406 D-04). The local door is the only door that\n// serves this today, and the function is still written as an adapter both doors could call\n// because that is what stopped `runs.detail` and `analysis.get` from forking: two doors resolving\n// one read through two implementations means \"the same run's knowledge\" depends on which\n// credential asked.\n//\n// BOTH DOORS SERVE THE STORED BODY (441 D-07). The projection carries producer text throughout,\n// masked at write, and neither door restores anything. The local arm's `boundary: 'human'` only\n// turns on the same-site guard below.\n//\n// THE REFUSAL VOCABULARY IS IMPORTED, NEVER RESPELLED. `refusalFor` is the detail adapter's;\n// `unknown_run` / `agent_host_unavailable` / `read_failed` mean here exactly what they mean two\n// modules away. Note that `unknown_run` is nearly unreachable through THIS op by design: a run\n// whose handoff is gone answers `kind: 'evidence-incomplete'` with a 200, because D-06 makes a\n// pruned handoff a RESULT the page renders rather than a refusal it has to catch.\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport {\n RunsKnowledgeInputSchema,\n type RunKnowledgeProjection,\n} from '@vostride/agent-qa-schema'\n\nimport type { AgentHost } from '../chat/host.js'\nimport { refuseCrossSiteRequest } from '../server/cross-site.js'\nimport { refusalFor, respondJson, type RunDetailRefusal } from './run-detail-routes.js'\n\nexport type RunKnowledgeReadOutcome =\n | { readonly kind: 'ok'; readonly body: RunKnowledgeProjection }\n | RunDetailRefusal\n\n/**\n * THE READ. Exported so a cell can measure the outcome without a socket, and so any second door\n * answers with byte-identical bytes by CALLING this rather than by a second spelling that agrees\n * on the day it is written.\n */\nexport async function readRunKnowledge(\n host: AgentHost,\n runId: string,\n): Promise<RunKnowledgeReadOutcome> {\n // THE ID IS VALIDATED BY THE OP'S OWN INPUT SCHEMA, HERE, BEFORE THE DOOR IS TOUCHED\n // (T-407-01). Not a second regex: `runIdSchema` refuses exactly the ids the path layer would\n // have to REWRITE before using them, and the whole point of that codec is that there is one of\n // it. Refusing early also means an untrusted path segment never reaches a dispatch at all.\n const parsed = RunsKnowledgeInputSchema.safeParse({ runId })\n if (!parsed.success) {\n return { kind: 'refused', status: 400, body: { error: 'invalid_run_id' } }\n }\n\n try {\n const projection = await host.invokeFunction(\n host.registry,\n host.runsKnowledgeFunctionId,\n parsed.data,\n host.caller,\n ) as RunKnowledgeProjection\n return { kind: 'ok', body: projection }\n } catch (error) {\n return refusalFor(error)\n }\n}\n\nexport interface RunKnowledgeReadDeps {\n /** The DECODED run id. Decoding can throw, and that throw is the caller's refusal to answer. */\n readonly runId: string\n /** The injected host. Its absence is the ROUTER'S 503, not this function's. */\n readonly host: AgentHost\n /**\n * WHO IS ON THE OTHER END OF THIS SOCKET. Both values serve the same stored body (441 D-07);\n * `'human'` only turns on the same-site guard. It is passed by exactly one arm, the LOCAL door's\n * `GET /api/runs/:id/knowledge` in `routes.ts`; any authed remote row passes nothing.\n */\n readonly boundary?: 'human' | 'machine'\n}\n\n/** `GET /api/runs/:id/knowledge` — the Knowledge tab's one read (D-05). */\nexport function serveRunKnowledgeRead(\n req: IncomingMessage,\n res: ServerResponse,\n deps: RunKnowledgeReadDeps,\n): void {\n // THE SAME-SITE GUARD, GATED ON `boundary` FOR THE REASON THE DETAIL ADAPTER RECORDS (405\n // CR-01): any remote door dispatches the same function from a legitimately non-loopback Host, and\n // an unconditional check would refuse the door it was not written for.\n //\n // `respondJson` already writes no cross-origin grant, so a page on another ORIGIN cannot read\n // this body. What that does not stop is DNS rebinding — the attacker's own name resolves to\n // loopback, so the browser treats the read as same-origin and asks for no grant at all. The Host\n // check inside `refuseCrossSiteRequest` is the rung that closes it, and it ADMITS the caller\n // that sends no `Origin`, which is the local non-browser drive this door also serves.\n if (deps.boundary === 'human' && refuseCrossSiteRequest(req) !== undefined) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n void readRunKnowledge(deps.host, deps.runId).then(\n (outcome) => {\n if (outcome.kind === 'refused') {\n respondJson(res, outcome.status, outcome.body)\n return\n }\n respondJson(res, 200, outcome.body)\n },\n // The read classifies every refusal it can name; anything reaching here is this module\n // failing, which is a 500 by name and never a body that looks like an answer.\n (error: unknown) => { respondJson(res, 500, refusalFor(error).body) },\n )\n}\n","// 2026-09-08, 419 D-13: the browser mark door dispatches the same op as the CLI.\n// 2026-10-01, 432-14 (D-14): one request, one dispatch. The confirm scope it used to carry, and the\n// frame it entered around the call, are deleted with the run-confirm pair.\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport {\n RunsMarkInputSchema,\n type RunsMarkOutcome,\n} from '@vostride/agent-qa-schema'\n\nimport type { AgentHost } from '../chat/host.js'\nimport { readJsonBody } from '../server/body-parser.js'\nimport { refuseCrossSiteRequest } from '../server/cross-site.js'\nimport { refusalFor, respondJson, type RunDetailRefusal } from './run-detail-routes.js'\n\n// 2026-10-02 (432-42, D-15): no 403 refusal arm. It carried the `mark_denied` body the execution\n// gate's denial produced; nothing produces it since 432-19, and its DTO is deleted.\nexport type RunMarkOutcome =\n | { readonly kind: 'ok'; readonly body: RunsMarkOutcome }\n | RunDetailRefusal\n\n/**\n * Address comes from the route; the body may never replace it or claim a caller identity. The body\n * is the op's own strict input minus `runId`, so a field the op does not declare is refused here\n * before anything is dispatched.\n */\nexport async function markRun(\n host: AgentHost,\n runId: string,\n body: unknown,\n): Promise<RunMarkOutcome> {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) {\n return { kind: 'refused', status: 400, body: { error: 'invalid_mark_input' } }\n }\n const input = body as Record<string, unknown>\n const parsed = RunsMarkInputSchema.safeParse({ ...input, runId })\n if (!parsed.success || 'runId' in input) {\n return { kind: 'refused', status: 400, body: { error: 'invalid_mark_input' } }\n }\n try {\n const result = await host.invokeFunction(\n host.registry, host.runsMarkFunctionId, parsed.data, host.caller,\n )\n return { kind: 'ok', body: result as RunsMarkOutcome }\n } catch (error) {\n // 2026-10-01 (432-19, D-15): no `mark_denied` arm. It classified the execution gate's denial\n // error, which nothing raises any more; every rejection takes `refusalFor`.\n return refusalFor(error)\n }\n}\n\n/** POST /api/runs/:id/mark. Both doors answer the op's outcome as it is; `'human'` adds the same-site guard. */\nexport function registerRunMarkRoute(\n req: IncomingMessage,\n res: ServerResponse,\n deps: {\n readonly host: AgentHost\n readonly runId: string\n readonly boundary?: 'human' | 'machine'\n },\n): void {\n if (deps.boundary === 'human' && refuseCrossSiteRequest(req) !== undefined) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n void readJsonBody<unknown>(req).then(async (body) => {\n const outcome = await markRun(deps.host, deps.runId, body)\n if (outcome.kind === 'refused') {\n respondJson(res, outcome.status, outcome.body)\n return\n }\n respondJson(res, 200, outcome.body)\n }, () => { respondJson(res, 400, { error: 'invalid_mark_input' }) })\n .catch(() => { respondJson(res, 500, { error: 'read_failed' }) })\n}\n","// 2026-09-26, 429-01 D-19/D-22: the field-merge config write. A page on another site may never\n// drive it, and no answer carries a cross-origin read grant.\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport {\n CONFIG_REVISION_ABSENT,\n ConfigUndoRequestSchema,\n ConfigWriteRequestSchema,\n isPageWritableConfigPath,\n} from '@vostride/agent-qa-schema'\n\nimport type { ConfigManager } from '../config/index.js'\nimport type { UndoStore } from '../config/undo-store.js'\nimport { respondJson } from '../run-service/run-detail-routes.js'\nimport { readJsonBody } from './body-parser.js'\nimport { refuseCrossSiteRequest } from './cross-site.js'\n\n/**\n * PATCH /api/config. The body is a change set; the answer is the revision now on disk, and for an\n * undoable change set a single-use Undo token (429-11 D-24).\n */\nexport function registerConfigWriteRoute(\n req: IncomingMessage,\n res: ServerResponse,\n deps: { readonly configManager: ConfigManager; readonly undoStore: UndoStore },\n): void {\n if (refuseCrossSiteRequest(req) !== undefined) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n void readJsonBody<unknown>(req).then(async (body) => {\n const parsed = ConfigWriteRequestSchema.safeParse(body)\n if (!parsed.success) {\n respondJson(res, 400, { error: 'invalid_write_input' })\n return\n }\n // 429-44 WR-01: this door changes only what the page renders a field for.\n const refused = parsed.data.changes.some((change) =>\n !isPageWritableConfigPath(change.path)\n || (change.op === 'move' && !isPageWritableConfigPath(change.from)))\n if (refused) {\n respondJson(res, 422, { error: 'path_not_writable' })\n return\n }\n const undoable = parsed.data.undoable === true\n let outcome: Awaited<ReturnType<ConfigManager['applyChanges']>>\n try {\n outcome = await deps.configManager.applyChanges(parsed.data.changes, { capturePriors: undoable })\n } catch {\n respondJson(res, 500, { error: 'write_failed' })\n return\n }\n if (outcome.kind === 'ok') {\n if (undoable && outcome.priors !== undefined) {\n const undo = deps.undoStore.put({ kind: 'config', priors: outcome.priors }, Date.now())\n respondJson(res, 200, { revision: outcome.revision, baseRevision: outcome.baseRevision, undo })\n return\n }\n respondJson(res, 200, { revision: outcome.revision, baseRevision: outcome.baseRevision })\n return\n }\n if (outcome.error === 'invalid_write_input') {\n respondJson(res, 400, { error: outcome.error })\n return\n }\n // 429-42: an expect found the field moved; the page recomputes from a fresh read.\n if (outcome.error === 'field_changed') {\n respondJson(res, 409, { error: outcome.error, path: outcome.path })\n return\n }\n respondJson(res, 422, outcome.issues === undefined\n ? { error: outcome.error }\n : { error: outcome.error, issues: outcome.issues })\n }, () => { respondJson(res, 400, { error: 'invalid_write_input' }) })\n .catch(() => { respondJson(res, 500, { error: 'write_failed' }) })\n}\n\n/** GET /api/config/revision. The sha256 of the file's bytes, even when they do not parse. */\nexport function registerConfigRevisionRoute(\n _req: IncomingMessage,\n res: ServerResponse,\n deps: { readonly configManager: ConfigManager },\n): void {\n deps.configManager.readWithRevision().then((read) => {\n res.setHeader('Cache-Control', 'no-store')\n const revision = read.kind === 'absent' ? CONFIG_REVISION_ABSENT : read.revision\n respondJson(res, 200, { revision })\n }, () => { respondJson(res, 500, { error: 'read_failed' }) })\n}\n\n/**\n * POST /api/config/undo (429-11 D-24). Redeems a token once and restores on the server, so the\n * page never writes back a copy it holds only masked. Same-site only; a newer write always wins.\n */\nexport function registerConfigUndoRoute(\n req: IncomingMessage,\n res: ServerResponse,\n deps: {\n readonly configManager?: ConfigManager\n readonly undoStore: UndoStore\n /** Writes the credential back under the credential lock; false when the name is taken again. */\n readonly restoreCredential: (name: string, credential: unknown) => Promise<boolean>\n },\n): void {\n if (req.method !== 'POST') {\n respondJson(res, 405, { error: 'method_not_allowed' })\n return\n }\n if (refuseCrossSiteRequest(req) !== undefined) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n void readJsonBody<unknown>(req).then(async (body) => {\n const parsed = ConfigUndoRequestSchema.safeParse(body)\n if (!parsed.success) {\n respondJson(res, 400, { error: 'invalid_write_input' })\n return\n }\n const payload = deps.undoStore.take(parsed.data.token, Date.now())\n if (payload === undefined) {\n respondJson(res, 410, { error: 'undo_expired' })\n return\n }\n if (payload.kind === 'credential') {\n const restored = await deps.restoreCredential(payload.name, payload.credential)\n if (restored) respondJson(res, 200, { restored: true })\n else respondJson(res, 409, { error: 'undo_conflict' })\n return\n }\n if (deps.configManager === undefined) {\n respondJson(res, 503, { error: 'config_unavailable' })\n return\n }\n const outcome = await deps.configManager.restorePriors(payload.priors)\n if (outcome.kind === 'ok') {\n respondJson(res, 200, { restored: true, revision: outcome.revision })\n return\n }\n respondJson(res, outcome.error === 'undo_conflict' ? 409 : 422, { error: outcome.error })\n }, () => { respondJson(res, 400, { error: 'invalid_write_input' }) })\n .catch(() => { respondJson(res, 500, { error: 'write_failed' }) })\n}\n","// 2026-09-26, 429-10 D-15/D-17: POST /api/llm/connect. A draft model is tested with its typed\n// secret inline and nothing is persisted first; only a pass, or the explicit skipTest behind\n// \"Save without testing\", writes the credential and then the definition (plus the default when the\n// project had none) in one config write. Same-site only; the secret is never logged or echoed.\nimport type { IncomingMessage, ServerResponse } from 'node:http'\n\nimport {\n getLLMAuthProviderPlugin,\n ModelConfigSchema,\n NameSlugSchema,\n readAuth,\n removeAuth,\n resolveLLMAuth,\n writeAuth,\n type AuthCredential,\n} from '@vostride/agent-qa-core'\nimport { createModel, getProvider, type ResolvedModelAuth } from '@vostride/agent-qa-model'\nimport {\n classifyProviderError,\n extractProviderError,\n LlmConnectRequestSchema,\n providerErrorSentence,\n type ConfigChange,\n type LlmConnectRequest,\n type LlmConnectResult,\n} from '@vostride/agent-qa-schema'\n\nimport type { ConfigManager } from '../config/index.js'\nimport {\n authFromFetch,\n authFromRuntimeConfig,\n toModelProfileAndAuth,\n type DashboardLLMConfig,\n} from '../llm-model-mapping.js'\nimport { respondJson } from '../run-service/run-detail-routes.js'\nimport { readJsonBody } from './body-parser.js'\nimport { refuseCrossSiteRequest } from './cross-site.js'\n\nexport interface LlmConnectDeps {\n readonly configManager: ConfigManager\n /** The router's one queue for every auth.json write and removal (429-09). */\n readonly withCredentialLock: <T>(work: () => Promise<T>) => Promise<T>\n /** The product provider an auth.json entry belongs to, mapped as GET /api/auth/status maps it. */\n readonly credentialProvider: (name: string, credential: AuthCredential) => string\n /** The test route's probe budget for this model. */\n readonly connectionTimeoutMs: (config: { provider?: unknown; baseURL?: unknown }) => number\n /** The router's names with a connect in flight: a second connect for one answers name_taken at once. */\n readonly inFlight: Set<string>\n}\n\n/** One set per router, shared by every connect it answers. */\nexport function createConnectInFlight(): Set<string> {\n return new Set<string>()\n}\n\ntype Answer = { readonly status: number; readonly body: unknown }\n\nconst refuse = (status: number, error: string, extra: Record<string, unknown> = {}): Answer => ({\n status,\n body: { error, ...extra },\n})\n\nconst COMPATIBLE_KEY_PROVIDERS = new Set(['openai-compatible', 'anthropic-compatible', 'gemini'])\nconst REDACTED = '[redacted]'\n\nfunction isKnownProvider(provider: string): boolean {\n return getProvider(provider) !== undefined || getLLMAuthProviderPlugin(provider) !== undefined\n}\n\nfunction isSubscriptionProvider(provider: string): boolean {\n return getLLMAuthProviderPlugin(provider) !== undefined || getProvider(provider)?.subscription === true\n}\n\n// The same rules POST /api/auth/credential applies to a typed secret.\nfunction credentialAccepted(provider: string, type: 'api-key' | 'bearer-token'): boolean {\n if (isSubscriptionProvider(provider)) return false\n if (type === 'bearer-token') return provider === 'anthropic-compatible'\n return COMPATIBLE_KEY_PROVIDERS.has(provider)\n}\n\nfunction ownEntry(store: Record<string, AuthCredential | undefined>, name: string): AuthCredential | undefined {\n return Object.prototype.hasOwnProperty.call(store, name) ? store[name] : undefined\n}\n\nfunction registryNames(config: Record<string, unknown>): string[] {\n const registry = config.registry as { llms?: unknown } | undefined\n const llms = Array.isArray(registry?.llms) ? registry.llms : []\n return llms.flatMap((item) => {\n const name = (item as { name?: unknown } | null)?.name\n return typeof name === 'string' ? [name] : []\n })\n}\n\nfunction hasValidDefault(config: Record<string, unknown>): boolean {\n const selected = (config.use as { llm?: unknown } | undefined)?.llm\n return typeof selected === 'string' && registryNames(config).includes(selected)\n}\n\ntype ConfigState = { kind: 'ok'; config: Record<string, unknown> } | { kind: 'file_invalid' }\n\nasync function readConfig(configManager: ConfigManager): Promise<ConfigState> {\n const read = await configManager.readWithRevision()\n if (read.kind === 'file_invalid') return { kind: 'file_invalid' }\n return { kind: 'ok', config: read.kind === 'ok' ? read.config : {} }\n}\n\nfunction withoutSecret(text: string, secret: string | undefined): string {\n return secret ? text.split(secret).join(REDACTED) : text\n}\n\nfunction toStoredCredential(\n provider: string,\n credential: NonNullable<LlmConnectRequest['credential']>,\n): AuthCredential {\n return credential.type === 'bearer-token'\n ? { type: 'bearer', provider, token: credential.secret }\n : { type: 'api', provider, key: credential.secret }\n}\n\ntype ResolvedTestAuth =\n | { kind: 'ok'; auth: ResolvedModelAuth; usedCredential: boolean }\n | { kind: 'missing' }\n\n// D-16: a typed secret is used inline; otherwise the saved credential under the name, or the\n// draft's completed sign-in, composed exactly as the live session composes it.\nasync function resolveTestAuth(\n name: string,\n provider: string,\n llmConfig: DashboardLLMConfig,\n credential: LlmConnectRequest['credential'],\n): Promise<ResolvedTestAuth> {\n if (credential) {\n const auth = authFromRuntimeConfig(\n credential.type === 'api-key' ? { apiKey: credential.secret } : { authToken: credential.secret },\n )\n return { kind: 'ok', auth, usedCredential: true }\n }\n const resolved = await resolveLLMAuth(name, llmConfig)\n switch (resolved.kind) {\n case 'api-key':\n return { kind: 'ok', auth: authFromRuntimeConfig({ apiKey: resolved.apiKey }), usedCredential: true }\n case 'bearer-token':\n return { kind: 'ok', auth: authFromRuntimeConfig({ authToken: resolved.token }), usedCredential: true }\n case 'auth-fetch':\n return {\n kind: 'ok',\n auth: authFromRuntimeConfig({}, authFromFetch(provider, resolved.fetch)),\n usedCredential: true,\n }\n case 'unauthenticated':\n case 'missing':\n if (getProvider(provider)?.credentialOptional === true) {\n return { kind: 'ok', auth: { kind: 'none' }, usedCredential: false }\n }\n return { kind: 'missing' }\n }\n}\n\nasync function probe(\n llmConfig: DashboardLLMConfig,\n auth: ResolvedModelAuth,\n timeoutMs: number,\n): Promise<void> {\n const { profile, auth: modelAuth } = toModelProfileAndAuth(llmConfig, auth)\n // 2026-10-12 (441-04, D-06): fixed probe text, nothing to mask.\n const model = createModel(profile, modelAuth, (text) => text)\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), timeoutMs)\n try {\n const { generateText } = await import('ai')\n await generateText({ model, prompt: 'Say \"ok\"', abortSignal: controller.signal })\n } finally {\n clearTimeout(timeout)\n }\n}\n\nasync function connectLlm(raw: unknown, deps: LlmConnectDeps): Promise<Answer> {\n const parsed = LlmConnectRequestSchema.safeParse(raw)\n if (!parsed.success) return refuse(400, 'invalid_setup_input')\n const request = parsed.data\n const { name } = request\n if (!NameSlugSchema.safeParse(name).success) return refuse(400, 'name_invalid')\n if (deps.inFlight.has(name)) return refuse(409, 'name_taken')\n deps.inFlight.add(name)\n try {\n return await connectName(request, deps)\n } finally {\n deps.inFlight.delete(name)\n }\n}\n\nasync function connectName(request: LlmConnectRequest, deps: LlmConnectDeps): Promise<Answer> {\n const { name, credential } = request\n const provider = request.provider.trim()\n const modelId = request.model.trim()\n if (!isKnownProvider(provider) || !modelId) return refuse(400, 'invalid_setup_input')\n if (credential && !credentialAccepted(provider, credential.type)) return refuse(400, 'credential_not_accepted')\n\n const definition: Record<string, unknown> = { provider, model: modelId }\n if (request.baseURL !== undefined) definition.baseURL = request.baseURL\n if (request.providerHeaders !== undefined) definition.providerHeaders = request.providerHeaders\n const candidate = ModelConfigSchema.safeParse(definition)\n if (!candidate.success) {\n return refuse(400, 'invalid_setup_input', {\n issues: candidate.error.issues.map((issue) => ({\n path: issue.path.map((key) => (typeof key === 'number' ? key : String(key))),\n message: issue.message,\n })),\n })\n }\n const llmConfig = candidate.data as DashboardLLMConfig\n\n const before = await readConfig(deps.configManager)\n if (before.kind === 'file_invalid') return refuse(409, 'file_invalid')\n if (registryNames(before.config).includes(name)) return refuse(409, 'name_taken')\n\n const existing = ownEntry(await readAuth() as Record<string, AuthCredential | undefined>, name)\n if (existing && deps.credentialProvider(name, existing) !== provider) {\n return refuse(409, 'credential_provider_conflict')\n }\n\n let usedCredential = credential !== undefined\n if (!request.skipTest) {\n const resolved = await resolveTestAuth(name, provider, llmConfig, credential)\n if (resolved.kind === 'missing') return refuse(400, 'credential_missing')\n usedCredential = resolved.usedCredential\n try {\n await probe(llmConfig, resolved.auth, deps.connectionTimeoutMs(llmConfig))\n } catch (err: unknown) {\n const { message, statusCode } = extractProviderError(err)\n const providerMessage = withoutSecret(message, credential?.secret)\n const errorClass = classifyProviderError(providerMessage, statusCode)\n const failed: LlmConnectResult = {\n success: false,\n errorClass,\n message: providerErrorSentence(errorClass, providerMessage),\n }\n return { status: 200, body: failed }\n }\n }\n\n return deps.withCredentialLock(async () => {\n const current = await readConfig(deps.configManager)\n if (current.kind === 'file_invalid') return refuse(409, 'file_invalid')\n if (registryNames(current.config).includes(name)) return refuse(409, 'name_taken')\n\n let previous: AuthCredential | undefined\n let wroteCredential = false\n if (credential) {\n previous = ownEntry(await readAuth() as Record<string, AuthCredential | undefined>, name)\n if (previous && deps.credentialProvider(name, previous) !== provider) {\n return refuse(409, 'credential_provider_conflict')\n }\n await writeAuth(name, toStoredCredential(provider, credential))\n wroteCredential = true\n }\n // A credential this request created goes; one that was there before gets its old value back.\n const undoCredential = async (): Promise<void> => {\n if (!wroteCredential) return\n if (previous) await writeAuth(name, previous)\n else await removeAuth(name)\n }\n\n const becameDefault = !hasValidDefault(current.config)\n const changes: ConfigChange[] = [\n { op: 'append', path: ['registry', 'llms'], value: { name, ...definition } },\n ...(becameDefault ? [{ op: 'set' as const, path: ['use', 'llm'], value: name }] : []),\n ]\n let outcome: Awaited<ReturnType<ConfigManager['applyChanges']>>\n try {\n outcome = await deps.configManager.applyChanges(changes)\n } catch (err: unknown) {\n await undoCredential()\n throw err\n }\n if (outcome.kind !== 'ok') {\n await undoCredential()\n if (outcome.error === 'file_invalid') return refuse(409, 'file_invalid')\n return refuse(422, outcome.error, outcome.issues === undefined ? {} : { issues: outcome.issues })\n }\n const saved: LlmConnectResult = {\n success: true,\n saved: true,\n becameDefault,\n usedCredential,\n revision: outcome.revision,\n }\n return { status: 200, body: saved }\n })\n}\n\n/** POST /api/llm/connect. The body is an LlmConnectRequest; the answer is an LlmConnectResult or a named refusal. */\nexport function registerLlmConnectRoute(\n req: IncomingMessage,\n res: ServerResponse,\n deps: LlmConnectDeps,\n): void {\n if (refuseCrossSiteRequest(req) !== undefined) {\n respondJson(res, 403, { error: 'cross_site_refused' })\n return\n }\n void readJsonBody<unknown>(req).then(async (body) => {\n const answer = await connectLlm(body, deps)\n respondJson(res, answer.status, answer.body)\n }, () => { respondJson(res, 400, { error: 'invalid_setup_input' }) })\n .catch(() => { respondJson(res, 500, { error: 'connect_failed' }) })\n}\n","import { EventEmitter } from 'node:events'\nimport { cpus } from 'node:os'\nimport type { RunAttributes } from '@vostride/agent-qa-core'\nimport type { RunArtifactKind } from '@vostride/agent-qa-schema'\nimport type { DashboardDatabase, RunRow } from '../db/database.js'\nimport { classifyRunOwner, orphanSummary, ownedElsewhere } from '../db/run-owner.js'\n\ninterface EnqueueOptions {\n name: string\n filePath?: string\n kind?: RunArtifactKind\n attributes?: RunAttributes\n priority?: number\n platform?: string\n testFileContent?: string\n modelName?: string\n llmProvider?: string\n metadata?: Record<string, unknown>\n parallel?: boolean\n}\n\nexport type RunCancelOutcome =\n | { kind: 'cancelled' }\n | { kind: 'stop-requested' }\n | { kind: 'not-stoppable-here' }\n | { kind: 'finished'; status: string }\n | { kind: 'orphan-finalized'; message: string }\n | { kind: 'owned-elsewhere'; message: string; ownerPid: number }\n | { kind: 'not-cancellable' }\n\nconst NOT_CANCELLABLE: RunCancelOutcome = { kind: 'not-cancellable' }\n\nexport class JobQueue extends EventEmitter {\n private db: DashboardDatabase\n private pollInterval: ReturnType<typeof setInterval> | null = null\n private isProcessing = false\n private concurrency: number\n private activeCount = 0\n private activePlatforms = new Set<string>()\n private activeRuns = new Map<string, { platform: string }>()\n private requestStop: ((runId: string) => boolean) | undefined\n private stopped = false\n\n constructor(opts: {\n db: DashboardDatabase\n concurrency?: number\n requestStop?: (runId: string) => boolean\n }) {\n super()\n this.db = opts.db\n this.concurrency = opts.concurrency ?? cpus().length\n this.requestStop = opts.requestStop\n }\n\n start(intervalMs = 1000): void {\n this.stopped = false\n this.pollInterval = setInterval(() => this.dispatchReported('a poll'), intervalMs)\n // 2026-10-18 (444-27, D-62 IN-06): a dispatch that fails here never escapes enqueue().\n this.on('enqueued', () => this.dispatchReported('an enqueue'))\n }\n\n // 2026-10-17 (444-16, D-50): the server closes the database after this; a run that settles later\n // still frees its slot, and nothing reads the closed database.\n stop(): void {\n this.stopped = true\n if (this.pollInterval) {\n clearInterval(this.pollInterval)\n this.pollInterval = null\n }\n this.removeAllListeners('enqueued')\n }\n\n enqueue(opts: EnqueueOptions): string {\n // 2026-10-01 (432-14, D-14): the belt that refused an unminted confirm scope here is deleted\n // with the run-confirm pair. A confirm scope addressed a browser's dialog; there is no dialog and\n // no reader of the key, so the queue attaches no meaning to it. The allowlist at\n // `/api/queue/enqueue` still refuses every client-supplied metadata key.\n const runId = this.db.insertPendingRun({\n name: opts.name,\n filePath: opts.filePath,\n attributes: opts.attributes,\n priority: opts.priority ?? 0,\n platform: opts.platform,\n testFileContent: opts.testFileContent,\n modelName: opts.modelName,\n llmProvider: opts.llmProvider,\n metadata: opts.metadata,\n parallel: opts.parallel,\n })\n this.db.insertRunArtifact({\n runId,\n kind: opts.kind ?? 'test',\n payload: {\n runtime: {\n platform: opts.platform ?? 'web',\n queued: true,\n },\n source: {\n name: opts.name,\n filePath: opts.filePath ?? null,\n loadStatus: 'queued',\n },\n metadata: {\n ...opts.metadata,\n attributes: opts.attributes ?? {},\n },\n },\n })\n this.emit('enqueued', runId)\n return runId\n }\n\n processNext(): void {\n if (this.stopped || this.isProcessing) return\n this.isProcessing = true\n try {\n while (true) {\n const next = this.findNextEligible()\n if (!next) break\n\n const isParallel = Boolean(next.parallel)\n const platform = next.platform ?? 'web'\n const isMobile = platform === 'ios' || platform === 'android'\n\n this.activeCount++\n if (isMobile) this.activePlatforms.add(platform)\n this.activeRuns.set(next.id, { platform })\n\n // 2026-10-17 (443-02, D-07): a row that left pending before the flip is not dispatched.\n if (!this.db.updateRunStatus(next.id, 'running')) {\n this.activeCount--\n if (isMobile) this.activePlatforms.delete(platform)\n this.activeRuns.delete(next.id)\n continue\n }\n this.db.updateRun(next.id, { startedAt: new Date().toISOString() })\n this.emit('execute', next)\n\n // Sequential jobs get exclusive access — stop filling slots after dequeue\n if (!isParallel && !isMobile) break\n }\n } finally {\n this.isProcessing = false\n }\n }\n\n onSlotFreed(runId: string): void {\n const info = this.activeRuns.get(runId)\n if (!info) return\n this.activeCount--\n if (info.platform === 'ios' || info.platform === 'android') {\n this.activePlatforms.delete(info.platform)\n }\n this.activeRuns.delete(runId)\n this.dispatchReported(`run ${runId} finished`)\n }\n\n private dispatchReported(trigger: string): void {\n try {\n this.processNext()\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n console.error(`Queue could not dispatch the next run after ${trigger}: ${message}`)\n }\n }\n\n getActiveCount(): number {\n return this.activeCount\n }\n\n getConcurrency(): number {\n return this.concurrency\n }\n\n // 2026-10-16 (442-05, D-06 to D-08): only the owner cancels a running row; gone is an orphan.\n // 442-15 (GAP-D2): own is the stamp this handle wrote, or equal non-null start times.\n // 2026-10-17 (444-06, D-11): a running row is never written here; the run answers with its verdict.\n cancel(runId: string): RunCancelOutcome {\n const run = this.db.getRun(runId)\n if (!run) return NOT_CANCELLABLE\n if (run.status === 'pending') {\n this.db.updateRun(runId, { status: 'cancelled', endedAt: new Date().toISOString() })\n this.db.finalizeRunArtifact(runId, {\n errors: [{ code: 'cancelled', phase: 'queue', message: 'Run cancelled before execution' }],\n runtime: { status: 'cancelled' },\n })\n return { kind: 'cancelled' }\n }\n if (run.status !== 'running') return { kind: 'finished', status: run.status }\n const owner = this.db.readRunOwner(runId)\n if (owner === undefined) return NOT_CANCELLABLE\n const own = this.db.isOwnStamp(runId, owner)\n switch (own ? 'self' : classifyRunOwner(owner, this.db.runOwnership)) {\n case 'self':\n return this.requestStop?.(runId) === true\n ? { kind: 'stop-requested' }\n : { kind: 'not-stoppable-here' }\n case 'gone':\n return this.db.finalizeOrphanRun(runId, owner)\n ? { kind: 'orphan-finalized', message: orphanSummary(owner.pid) }\n : this.finishedOrMissing(runId)\n case 'alive':\n case 'unknown':\n return { kind: 'owned-elsewhere', message: ownedElsewhere(owner.pid), ownerPid: owner.pid }\n }\n }\n\n private finishedOrMissing(runId: string): RunCancelOutcome {\n const run = this.db.getRun(runId)\n return run && run.status !== 'running' && run.status !== 'pending'\n ? { kind: 'finished', status: run.status }\n : NOT_CANCELLABLE\n }\n\n // 2026-08-24 (Phase 402 plan 09, D-11): THE CHILD-RUN CANCELLATION FAN-OUT IS DELETED WITH THE\n // MODEL THAT MINTED ITS CHILDREN.\n //\n // ~19 lines stood here walking the run's child rows and cancelling each member row. Under\n // the one-run model a parallel suite is ONE run row with member handles (402-04) — nothing writes\n // the run row's parent-link column any more (405-07 then deleted the column outright), so the\n // walk could only ever have read an empty list while reading as live cancellation policy.\n // Cancelling the run cancels the run.\n //\n // WHAT THIS DOES NOT TOUCH: `parallel` below. D-11 keeps the queue's parallel flag as CROSS-RUN\n // concurrency of INDEPENDENT jobs, which is what `findNextEligible` has always used it for. What\n // was deleted is parallel-SUITE semantics, not the queue's ability to run two unrelated jobs.\n //\n // HISTORICAL ROWS: a pre-402 suite run still lists its members on the read side; cancelling\n // such a run now leaves those member rows in whatever state their own process left them.\n\n private findNextEligible(): RunRow | undefined {\n if (this.activeCount >= this.concurrency) return undefined\n\n const pending = this.db.getPendingRuns()\n for (const run of pending) {\n const isParallel = Boolean(run.parallel)\n const platform = run.platform ?? 'web'\n const isMobile = platform === 'ios' || platform === 'android'\n\n if (isMobile) {\n // Mobile: needs a slot AND its platform not already active\n // parallel flag is ignored — mobile tests serialize per platform via device mutex\n if (this.activePlatforms.has(platform)) continue\n return run\n }\n\n if (!isParallel) {\n // Sequential web: needs ALL slots free (exclusive access)\n if (this.activeCount > 0) continue\n return run\n }\n\n // Parallel web: just needs an available slot\n return run\n }\n\n return undefined\n }\n}\n","import { readFile, mkdir, stat, rm } from 'node:fs/promises'\nimport { dirname, basename } from 'node:path'\nimport { generateSuiteId } from '@vostride/agent-qa-ids'\nimport { parse as parseYaml } from 'yaml'\nimport { discoverWorkspaceFiles, resolveWorkspaceFileTarget, SuiteDefinitionSchema } from '@vostride/agent-qa-core'\nimport type { ResolvedWorkspacePaths, SuiteDefinition } from '@vostride/agent-qa-core'\nimport { decodeUtf8, idWriteText, presentText, type TestFileManager } from './test-file-manager.js'\nimport { createPathLock, replaceFileAtomic } from './replace-file-atomic.js'\n\ninterface SuiteFileInfo {\n path: string\n suiteId: string | null\n name: string\n testCount: number\n modified: string\n platform: string | null\n}\n\ninterface SuiteValidationResult {\n valid: boolean\n errors: { message: string; line?: number; column?: number; suggestion?: string }[]\n missingTests?: Array<{ index: number; test: string; id: string }>\n}\n\nexport class SuiteFileManager {\n private testFileManager: TestFileManager | undefined\n\n constructor(\n private readonly workspace: ResolvedWorkspacePaths,\n testFileManager?: TestFileManager,\n ) {\n this.testFileManager = testFileManager\n }\n\n // 2026-10-18 (444-33, D-65; 444-35, D-66): each list call reads the workspace itself; each file is written whole and one writer at a time.\n private readonly underLock = createPathLock()\n\n async list(): Promise<SuiteFileInfo[]> {\n const records = await discoverWorkspaceFiles({ workspace: this.workspace, kind: 'suite' })\n const files: SuiteFileInfo[] = []\n\n for (const record of records) {\n try {\n const s = await stat(record.absolutePath)\n if (s.isFile()) {\n let suiteName = basename(record.workspaceRelativePath)\n let testCount = 0\n let platform: string | null = null\n let suiteId: string | null = null\n const take = (content: string): string | null => {\n const parsed = parseYaml(content)\n // 2026-10-19 (444-37, D-68): name, platform and id come from the parsed mapping, and a blank value is no value.\n suiteName = presentText(parsed?.name) ?? basename(record.workspaceRelativePath)\n testCount = Array.isArray(parsed?.tests) ? parsed.tests.length : 0\n platform = presentText(parsed?.config?.platform)\n return presentText(parsed?.['suite-id'])\n }\n try {\n suiteId = take(await readFile(record.absolutePath, 'utf-8'))\n if (suiteId === null) {\n suiteId = await this.underLock(record.absolutePath, async () => {\n const content = decodeUtf8(await readFile(record.absolutePath))\n if (content === undefined) return null\n const current = take(content)\n if (current !== null) return current\n // 2026-10-18 (444-35, IN-20): an empty file may be an outside save mid-write; it is never minted.\n if (content.trim() === '') return current\n const minted = generateSuiteId()\n const next = idWriteText(content, 'suite-id', minted)\n if (next === null) return current\n await replaceFileAtomic(record.absolutePath, next)\n return minted\n })\n }\n } catch { /* fall back to filename */ }\n files.push({\n path: record.workspaceRelativePath,\n suiteId,\n name: suiteName,\n testCount,\n modified: s.mtime.toISOString(),\n platform,\n })\n }\n } catch {\n // skip inaccessible files\n }\n }\n\n files.sort((a, b) => b.modified.localeCompare(a.modified))\n return files\n }\n\n async findBySuiteId(suiteId: string): Promise<{ path: string; content: string } | null> {\n const files = await this.list()\n const match = files.find(f => f.suiteId === suiteId)\n if (!match) return null\n const content = await this.read(match.path)\n return { path: match.path, content }\n }\n\n async resolvePath(filePath: string, requireExisting = true): Promise<{ storagePath: string; executionPath: string }> {\n const trimmedPath = filePath.trim()\n if (!trimmedPath) {\n throw new Error('Suite path is required')\n }\n\n const target = await resolveWorkspaceFileTarget({\n workspace: this.workspace,\n kind: 'suite',\n filePath: trimmedPath,\n requireExisting,\n })\n return { storagePath: target.workspaceRelativePath, executionPath: target.absolutePath }\n }\n\n async read(relativePath: string): Promise<string> {\n const target = await this.resolveTarget(relativePath, true)\n return readFile(target.absolutePath, 'utf-8')\n }\n\n async write(relativePath: string, content: string): Promise<void> {\n const target = await this.resolveTarget(relativePath, false)\n await mkdir(dirname(target.absolutePath), { recursive: true })\n await this.underLock(target.absolutePath, () => replaceFileAtomic(target.absolutePath, content))\n }\n\n async delete(relativePath: string): Promise<void> {\n const target = await this.resolveTarget(relativePath, true)\n await this.underLock(target.absolutePath, () => rm(target.absolutePath))\n }\n\n async validate(content: string): Promise<SuiteValidationResult> {\n try {\n const parsed = parseYaml(content)\n const result = SuiteDefinitionSchema.safeParse(parsed)\n\n if (!result.success) {\n return {\n valid: false,\n errors: result.error.issues.map((issue: { path: PropertyKey[]; message: string }) => ({\n message: `${issue.path.map(String).join('.')}: ${issue.message}`,\n })),\n }\n }\n\n // Save-time fail-fast: verify every referenced test path resolves (Phase 181 D-32/D-33)\n if (this.testFileManager) {\n const suite = result.data as SuiteDefinition\n const available = await this.testFileManager.list()\n const availablePaths = new Set(available.map((f) => f.path))\n const missingTests: Array<{ index: number; test: string; id: string }> = []\n suite.tests.forEach((entry: SuiteDefinition['tests'][number], index: number) => {\n if (!availablePaths.has(entry.test)) {\n // Report the ORIGINAL entry.test so the user sees what they wrote\n missingTests.push({ index, test: entry.test, id: entry.id })\n }\n })\n if (missingTests.length > 0) {\n return {\n valid: false,\n errors: [{\n message: `Cannot save — referenced tests not found: ${missingTests.map(m => m.test).join(', ')}`,\n }],\n missingTests,\n }\n }\n }\n\n return { valid: true, errors: [] }\n } catch (err) {\n return {\n valid: false,\n errors: [{ message: err instanceof Error ? err.message : 'Failed to parse YAML' }],\n }\n }\n }\n\n private async resolveTarget(relativePath: string, requireExisting: boolean) {\n return resolveWorkspaceFileTarget({\n workspace: this.workspace,\n kind: 'suite',\n filePath: relativePath,\n requireExisting,\n })\n }\n}\n","import { request } from 'node:http'\nimport { spawn, type ChildProcess } from 'node:child_process'\nimport {\n formatAppiumInstallGuidance,\n resolveAppiumExecutable,\n type ResolvedAppiumExecutable,\n} from '@vostride/agent-qa-core'\nimport treeKill from 'tree-kill'\nimport pc from 'picocolors'\n\nconst APPIUM_PREFIX = pc.magenta('[appium]')\n\nexport interface AppiumLeaseOwner {\n runId: string\n platform: 'android' | 'ios'\n}\n\nexport interface AppiumLease extends AppiumLeaseOwner {\n acquiredAt: string\n}\n\nexport class AppiumManager {\n private process: ChildProcess | null = null\n private port: number\n private ready = false\n private startPromise: Promise<void> | null = null\n private managed = false\n private startupTimeoutMs: number\n private pollIntervalMs: number\n private anonymousRefCount = 0\n private leases = new Map<string, AppiumLease>()\n private logLevel: 'normal' | 'debug'\n private appiumResolver: () => ResolvedAppiumExecutable\n\n constructor(opts?: {\n port?: number\n startupTimeoutMs?: number\n pollIntervalMs?: number\n logLevel?: 'normal' | 'debug'\n appiumResolver?: () => ResolvedAppiumExecutable\n }) {\n this.port = opts?.port ?? 4723\n this.startupTimeoutMs = opts?.startupTimeoutMs ?? 30_000\n this.pollIntervalMs = opts?.pollIntervalMs ?? 500\n this.logLevel = opts?.logLevel ?? 'normal'\n this.appiumResolver = opts?.appiumResolver ?? resolveAppiumExecutable\n }\n\n async acquire(): Promise<void> {\n await this.ensureRunning()\n this.anonymousRefCount++\n }\n\n release(): void {\n if (this.anonymousRefCount > 0) this.anonymousRefCount--\n this.maybeShutdownAfterRelease()\n }\n\n async acquireLease(owner: AppiumLeaseOwner): Promise<void> {\n await this.ensureRunning()\n if (!this.leases.has(owner.runId)) {\n this.leases.set(owner.runId, {\n runId: owner.runId,\n platform: owner.platform,\n acquiredAt: new Date().toISOString(),\n })\n }\n console.log(`${APPIUM_PREFIX} lease acquired run=${owner.runId} platform=${owner.platform} leases=${this.getLeaseCount()} managed=${this.managed}`)\n }\n\n releaseLease(runId: string, reason = 'completed'): boolean {\n const lease = this.leases.get(runId)\n if (!lease) return false\n\n this.leases.delete(runId)\n console.log(`${APPIUM_PREFIX} lease released run=${runId} platform=${lease.platform} reason=${reason} leases=${this.getLeaseCount()} managed=${this.managed}`)\n this.maybeShutdownAfterRelease()\n return true\n }\n\n releaseAllLeases(reason = 'shutdown'): string[] {\n const runIds = [...this.leases.keys()]\n for (const runId of runIds) {\n this.releaseLease(runId, reason)\n }\n return runIds\n }\n\n async ensureRunning(): Promise<void> {\n if (this.ready) {\n const still = await this.checkStatus()\n if (still) return\n this.ready = false\n }\n\n if (this.startPromise) {\n await this.startPromise\n return\n }\n\n this.startPromise = (async () => {\n const alive = await this.checkStatus()\n if (alive) {\n this.ready = true\n this.managed = false\n return\n }\n await this.startAndWait()\n })()\n\n try {\n await this.startPromise\n } finally {\n this.startPromise = null\n }\n }\n\n async checkStatus(): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n const req = request(\n {\n hostname: 'localhost',\n port: this.port,\n path: '/status',\n method: 'GET',\n timeout: 3000,\n },\n (res) => {\n let data = ''\n res.on('data', (chunk: Buffer) => {\n data += chunk.toString()\n })\n res.on('end', () => {\n try {\n const parsed = JSON.parse(data)\n resolve(parsed?.value?.ready === true)\n } catch {\n resolve(false)\n }\n })\n },\n )\n req.on('error', () => resolve(false))\n req.on('timeout', () => {\n req.destroy()\n resolve(false)\n })\n req.end()\n })\n }\n\n private async startAndWait(): Promise<void> {\n const appium = this.appiumResolver()\n const child = spawn(appium.command, ['-p', String(this.port), '--relaxed-security', '--log-no-colors'], {\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n\n this.process = child\n this.managed = true\n\n child.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'ENOENT') {\n console.error(`${APPIUM_PREFIX} Appium not found. ${formatAppiumInstallGuidance()}`)\n } else {\n console.error(`${APPIUM_PREFIX} Error: ${err.message}`)\n }\n })\n\n child.stdout?.on('data', (chunk: Buffer) => {\n if (this.logLevel !== 'debug') return\n const lines = chunk.toString().split('\\n').filter(Boolean)\n for (const line of lines) {\n console.log(`${APPIUM_PREFIX} ${pc.dim(line)}`)\n }\n })\n\n child.stderr?.on('data', (chunk: Buffer) => {\n if (this.logLevel !== 'debug') return\n const lines = chunk.toString().split('\\n').filter(Boolean)\n for (const line of lines) {\n console.error(`${APPIUM_PREFIX} ${pc.dim(line)}`)\n }\n })\n\n const start = Date.now()\n while (Date.now() - start < this.startupTimeoutMs) {\n const ok = await this.checkStatus()\n if (ok) {\n this.ready = true\n console.log(`${APPIUM_PREFIX} ${pc.green(`started on :${this.port}`)}`)\n return\n }\n await new Promise((r) => setTimeout(r, this.pollIntervalMs))\n }\n\n // Timeout — kill and throw\n if (child.pid) {\n treeKill(child.pid, 'SIGKILL', () => {})\n }\n this.process = null\n this.managed = false\n throw new Error(`Appium server did not become ready within ${this.startupTimeoutMs}ms`)\n }\n\n private performShutdown(): void {\n if (this.process?.pid && this.managed) {\n treeKill(this.process.pid, 'SIGKILL', () => {})\n console.log(`${APPIUM_PREFIX} ${pc.yellow('stopped')}`)\n }\n this.process = null\n this.ready = false\n this.managed = false\n }\n\n private maybeShutdownAfterRelease(): void {\n if (this.getRefCount() > 0) {\n console.log(`${APPIUM_PREFIX} server kept alive leases=${this.getLeaseCount()} managed=${this.managed}`)\n return\n }\n if (this.managed) {\n this.performShutdown()\n return\n }\n if (this.ready) {\n console.log(`${APPIUM_PREFIX} external server left running leases=0 managed=false`)\n }\n }\n\n shutdown(): void {\n this.anonymousRefCount = 0\n this.leases.clear()\n this.performShutdown()\n }\n\n getUrl(): string {\n return `http://localhost:${this.port}`\n }\n\n getPort(): number {\n return this.port\n }\n\n isManaged(): boolean {\n return this.managed\n }\n\n getRefCount(): number {\n return this.anonymousRefCount + this.leases.size\n }\n\n getLeaseCount(): number {\n return this.leases.size\n }\n\n getLeases(): AppiumLease[] {\n return [...this.leases.values()]\n }\n\n hasLease(runId: string): boolean {\n return this.leases.has(runId)\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { LiveSession } from './live-session.js'\nimport type { SessionState, LiveSessionConfig, EntityRef } from './types.js'\nimport type { AppiumManager } from '../execution/appium-manager.js'\nimport type { ConfigManager } from '../config/index.js'\nimport type { LiveEditorSubjects } from '../live-view/editor-subjects.js'\n\nexport interface SessionManagerDeps {\n appiumManager?: AppiumManager\n configManager?: ConfigManager\n configPath?: string\n liveEditorSubjects?: LiveEditorSubjects\n}\n\nexport class SessionManager {\n private sessions = new Map<string, LiveSession>()\n // Per-entity counter keyed by `${entityType}:${entityId}`.\n // Monotonic and ephemeral: resets on server restart per CONTEXT D-30.\n // Never decremented on terminate — a re-open of a terminated entity yields\n // the next number so \"Session #3\" after \"#2\" ends does not confuse users.\n private counters = new Map<string, number>()\n\n constructor(private deps: SessionManagerDeps = {}) {}\n\n async createSession(\n config: LiveSessionConfig,\n entity?: EntityRef,\n ): Promise<{ sessionId: string; sessionNumber: number | null }> {\n if (!config.llmConfig) {\n throw new Error('LLM not configured')\n }\n\n const sessionId = randomUUID()\n const session = new LiveSession(sessionId, this.deps)\n await session.initialize(config)\n this.sessions.set(sessionId, session)\n // 428 D-07: the session is an editor subject for exactly its lifetime.\n this.deps.liveEditorSubjects?.register(sessionId, session.liveAttachment())\n // RESEARCH P1: the idle window runs until the first control socket attaches (the upgrade\n // clears it), so a session nobody ever opens cannot hold a browser or a lease forever.\n session.startIdleTimer(() => {\n void this.terminateSession(sessionId).catch((error: unknown) => {\n console.error(`[live-editor] idle expiry could not end session ${sessionId}`, error)\n })\n })\n\n // sessionNumber is used for display only; never for authorization lookups\n // (always use sessionId UUID for that — see threat T-181.1-07).\n let sessionNumber: number | null = null\n if (entity && entity.id) {\n const key = `${entity.type}:${entity.id}`\n sessionNumber = (this.counters.get(key) ?? 0) + 1\n this.counters.set(key, sessionNumber)\n }\n\n return { sessionId, sessionNumber }\n }\n\n getSession(sessionId: string): LiveSession | undefined {\n return this.sessions.get(sessionId)\n }\n\n listSessions(): SessionState[] {\n return Array.from(this.sessions.values()).map(s => s.getState())\n }\n\n async terminateSession(sessionId: string): Promise<boolean> {\n const session = this.sessions.get(sessionId)\n if (!session) return false\n // Forgotten before the await, so a concurrent second terminate answers false.\n this.sessions.delete(sessionId)\n this.deps.liveEditorSubjects?.unregister(sessionId)\n await session.cleanup()\n // Note: `counters` intentionally left untouched — per D-30 the counter is\n // monotonic per-restart.\n return true\n }\n\n async cleanupAll(): Promise<void> {\n for (const [sessionId, session] of this.sessions) {\n this.deps.liveEditorSubjects?.unregister(sessionId)\n try { await session.cleanup() } catch {}\n }\n this.sessions.clear()\n }\n\n getCounter(entity: EntityRef): number {\n return this.counters.get(`${entity.type}:${entity.id}`) ?? 0\n }\n\n get size(): number {\n return this.sessions.size\n }\n}\n","import type WebSocket from 'ws'\nimport { parseTestFile } from '@vostride/agent-qa-core'\nimport type { LiveSession } from './live-session.js'\nimport { LIVE_EDITOR_SUPERSEDED_CLOSE_CODE, LIVE_EDITOR_UNKNOWN_SESSION_CLOSE_CODE } from './types.js'\nimport type {\n LiveStepResultPayload,\n ServerMessage,\n} from './types.js'\nimport type { TestFileManager } from '../tests/test-file-manager.js'\n\nfunction send(ws: WebSocket, msg: ServerMessage): void {\n if (ws.readyState === ws.OPEN) {\n ws.send(JSON.stringify(msg))\n }\n}\n\nfunction toStepResultPayload(result: Awaited<ReturnType<LiveSession['executeStepCommand']>>): LiveStepResultPayload {\n const status = result.status === 'passed'\n ? 'passed'\n : result.status === 'cancelled'\n ? 'cancelled'\n : 'failed'\n\n return {\n status,\n duration: result.duration,\n error: result.error,\n capturedVariables: result.capturedVariables,\n variableSnapshot: result.variableSnapshot,\n originalStepName: result.originalStepName,\n consoleLogs: result.consoleLogs,\n networkLogs: result.networkLogs,\n executionLogs: result.executionLogs,\n subActionsData: result.subActionsData,\n }\n}\n\nexport function createSessionHandler(\n session: LiveSession,\n onTerminate: () => void,\n onTokenUsage?: (event: { modelName: string; promptTokens: number; completionTokens: number; source: 'live-editor' }) => void,\n testFileManager?: TestFileManager,\n): (ws: WebSocket) => void {\n return (ws: WebSocket) => {\n let cleanedUp = false\n let detached = false\n\n async function cleanupSession(): Promise<void> {\n if (cleanedUp) return\n cleanedUp = true\n if (logPollInterval) clearInterval(logPollInterval)\n if (session.status !== 'terminated') {\n await session.cleanup()\n }\n onTerminate()\n }\n\n session.clearIdleTimer()\n // 428 WR-01: a newer socket replaces this one. It is closed by name, its log poll stops, and\n // any command it still sends is ignored, so one page drives the session at a time.\n // 428 WR-02: a session ended elsewhere (DELETE, idle expiry) closes this socket as gone, so the\n // page leaves \"connected\". A terminate-session from this socket closes it itself.\n const generation = session.beginAttachment((reason) => {\n if (detached || cleanedUp) return\n detached = true\n if (logPollInterval) clearInterval(logPollInterval)\n if (reason === 'superseded') ws.close(LIVE_EDITOR_SUPERSEDED_CLOSE_CODE, 'superseded')\n else ws.close(LIVE_EDITOR_UNKNOWN_SESSION_CLOSE_CODE, 'session_ended')\n })\n\n const state = session.getState()\n send(ws, {\n type: 'session-ready',\n sessionId: session.sessionId,\n platform: state.platform,\n interactive: state.interactive,\n error: state.terminalError,\n })\n session.attachMessageSink((message) => {\n send(ws, message)\n })\n send(ws, { type: 'session-state', state })\n\n // 428 CR-01: a command outlives the socket that issued it. While this socket is the attached\n // one its replies go straight to it; once it has dropped or been superseded they go through the\n // session to the socket attached now, or wait for the next one.\n function reply(message: ServerMessage): void {\n if (!detached && session.isCurrentAttachment(generation)) {\n send(ws, message)\n return\n }\n session.deliver(message)\n }\n\n let logPollInterval: ReturnType<typeof setInterval> | null = null\n const platform = state.platform\n if (platform !== 'web' && state.interactive) {\n logPollInterval = setInterval(async () => {\n if (session.status === 'executing') {\n return\n }\n try {\n const entries = await session.drainDeviceLogs()\n if (entries.length > 0) {\n send(ws, { type: 'device-logs', entries })\n }\n } catch {}\n }, 2000)\n }\n\n ws.on('message', async (data) => {\n if (detached || !session.isCurrentAttachment(generation)) return\n let msg: any\n try {\n msg = JSON.parse(data.toString())\n } catch {\n send(ws, { type: 'error', message: 'Invalid JSON' })\n return\n }\n\n switch (msg.type) {\n case 'execute-step': {\n if (session.status === 'executing') {\n reply({\n type: 'step-busy',\n currentStep: session.getState().currentStep ?? 'unknown',\n })\n return\n }\n try {\n const result = await session.executeStepCommand(\n msg.stepInstruction,\n msg.stepIndex,\n (phase) => {\n reply({\n type: 'step-phase',\n phase: phase.phase,\n data: {\n text: phase.text,\n confidence: phase.confidence,\n action: phase.action,\n success: phase.success,\n duration: phase.duration,\n },\n })\n },\n msg.draft,\n )\n if (result.status === 'cancelled') {\n reply({ type: 'step-cancelled' })\n } else {\n reply({\n type: 'step-complete',\n result: toStepResultPayload(result),\n })\n if (onTokenUsage && result.trace?.tokenUsage &&\n (result.trace.tokenUsage.promptTokens > 0 || result.trace.tokenUsage.completionTokens > 0)) {\n onTokenUsage({\n modelName: session.modelName,\n promptTokens: result.trace.tokenUsage.promptTokens,\n completionTokens: result.trace.tokenUsage.completionTokens,\n source: 'live-editor',\n })\n }\n try {\n const tree = await session.getAriaTree()\n if (tree) reply({ type: 'aria-tree', tree })\n } catch {}\n }\n reply({ type: 'session-state', state: session.getState() })\n const adapter = (session as any).adapter\n if (adapter && typeof adapter.isBrowserDisconnected === 'boolean' && adapter.isBrowserDisconnected) {\n reply({ type: 'browser-disconnected' })\n }\n } catch (err: any) {\n reply({ type: 'step-error', error: err.message })\n const adapter = (session as any).adapter\n if (adapter && typeof adapter.isBrowserDisconnected === 'boolean' && adapter.isBrowserDisconnected) {\n reply({ type: 'browser-disconnected' })\n }\n }\n break\n }\n\n case 'execute-hook': {\n if (session.status === 'executing') {\n reply({\n type: 'step-busy',\n currentStep: session.getState().currentStep ?? 'unknown',\n })\n return\n }\n try {\n await session.executeHookCommand(msg.phase, msg.hookId)\n reply({ type: 'session-state', state: session.getState() })\n } catch (err: any) {\n reply({ type: 'error', message: err.message })\n }\n break\n }\n\n case 'execute-test': {\n if (session.status === 'executing') {\n reply({\n type: 'step-busy',\n currentStep: session.getState().currentStep ?? 'unknown',\n })\n return\n }\n try {\n if (!testFileManager) {\n throw new Error('Test file manager unavailable — configure workspace.testMatch to run tests live')\n }\n\n let raw: string\n try {\n raw = await testFileManager.read(msg.path)\n } catch (readErr: any) {\n console.error(`[ws-handler] execute-test: read failed for path=${msg.path}`, readErr)\n throw new Error(`Cannot read test file \"${msg.path}\": ${readErr?.message ?? String(readErr)}`)\n }\n\n const parsed = parseTestFile(raw, msg.path)\n if (parsed.errors.length > 0) {\n console.error(`[ws-handler] execute-test: parse errors for ${msg.path}`, parsed.errors)\n throw new Error(`Parse error in ${msg.path}: ${parsed.errors[0].message}`)\n }\n const testDef = parsed.tests[0]\n if (!testDef) {\n throw new Error(`Test file \"${msg.path}\" is empty or has no valid test documents`)\n }\n const stepInstructions: string[] = testDef.steps.map((s: string | { step: string }) =>\n typeof s === 'string' ? s : s.step,\n )\n console.log(`[ws-handler] execute-test: starting \"${testDef.name}\" (${stepInstructions.length} steps, setup=${(testDef.setup ?? []).length}, teardown=${(testDef.teardown ?? []).length})`)\n\n reply({\n type: 'test-start',\n test: {\n testExecutionId: msg.testExecutionId,\n testIndex: msg.testIndex ?? 0,\n testId: msg.testId,\n testName: testDef.name,\n },\n })\n\n const result = await session.executeTestCommand(\n msg.testExecutionId,\n {\n testIndex: msg.testIndex ?? 0,\n testId: msg.testId,\n testName: testDef.name,\n testContext: testDef.context,\n steps: stepInstructions,\n setup: testDef.setup ?? [],\n teardown: testDef.teardown ?? [],\n },\n )\n\n console.log(`[ws-handler] execute-test: finished \"${testDef.name}\" status=${result.status} duration=${result.duration}ms${result.error ? ` error=${result.error}` : ''}`)\n reply({\n type: 'test-complete',\n test: {\n testExecutionId: msg.testExecutionId,\n testIndex: msg.testIndex ?? 0,\n testId: msg.testId,\n testName: testDef.name,\n },\n result,\n })\n reply({ type: 'session-state', state: session.getState() })\n } catch (err: any) {\n console.error(`[ws-handler] execute-test: caught error for path=${msg.path}`, {\n message: err?.message,\n stack: err?.stack,\n code: err?.code,\n })\n reply({\n type: 'test-error',\n test: {\n testExecutionId: msg.testExecutionId,\n testIndex: msg.testIndex ?? 0,\n testId: msg.testId,\n testName: msg.path.split(/[\\\\/]/).pop() ?? msg.path,\n },\n error: err?.message ?? String(err),\n })\n reply({ type: 'session-state', state: session.getState() })\n }\n break\n }\n\n case 'cancel-step': {\n session.cancelStep()\n break\n }\n\n case 'terminate-session': {\n await cleanupSession()\n send(ws, { type: 'session-terminated' })\n ws.close(1000, 'Session terminated')\n break\n }\n\n case 'get-state': {\n reply({ type: 'session-state', state: session.getState() })\n break\n }\n\n case 'navigate': {\n if (session.status === 'executing') {\n reply({ type: 'step-busy', currentStep: session.getState().currentStep ?? 'unknown' })\n return\n }\n try {\n const url = await session.navigate(msg.url)\n reply({ type: 'navigate-complete', url })\n reply({ type: 'session-state', state: session.getState() })\n } catch (err: any) {\n reply({ type: 'error', message: err.message })\n }\n break\n }\n\n case 'refresh-page': {\n if (session.status === 'executing') {\n reply({ type: 'step-busy', currentStep: session.getState().currentStep ?? 'unknown' })\n return\n }\n try {\n const url = await session.refreshPage()\n reply({ type: 'navigate-complete', url })\n reply({ type: 'session-state', state: session.getState() })\n } catch (err: any) {\n reply({ type: 'error', message: err.message })\n }\n break\n }\n\n case 'go-back': {\n if (session.status === 'executing') {\n reply({ type: 'step-busy', currentStep: session.getState().currentStep ?? 'unknown' })\n return\n }\n try {\n const url = await session.goBack()\n reply({ type: 'navigate-complete', url })\n reply({ type: 'session-state', state: session.getState() })\n } catch (err: any) {\n reply({ type: 'error', message: err.message })\n }\n break\n }\n\n case 'go-forward': {\n if (session.status === 'executing') {\n reply({ type: 'step-busy', currentStep: session.getState().currentStep ?? 'unknown' })\n return\n }\n try {\n const url = await session.goForward()\n reply({ type: 'navigate-complete', url })\n reply({ type: 'session-state', state: session.getState() })\n } catch (err: any) {\n reply({ type: 'error', message: err.message })\n }\n break\n }\n\n case 'get-aria-tree': {\n if (session.status === 'executing') {\n reply({ type: 'error', message: 'Cannot inspect ARIA tree while step is executing' })\n return\n }\n try {\n const tree = await session.getAriaTree()\n if (tree) {\n reply({ type: 'aria-tree', tree })\n } else {\n reply({ type: 'error', message: 'ARIA tree unavailable' })\n }\n } catch (err: any) {\n reply({ type: 'error', message: err.message })\n }\n break\n }\n\n default: {\n reply({ type: 'error', message: `Unknown message type: ${msg.type}` })\n break\n }\n }\n })\n\n // 428 D-09: an unexpected drop DETACHES the session for the idle window so the page can\n // reconnect to the same browser, draft, page, hook state and lease. Explicit ends go through\n // terminate-session or DELETE and stay immediate. A superseded socket's late close is inert\n // (RESEARCH P4), and an in-flight step is cancelled so the reconnected page and the server\n // agree it was cancelled (RESEARCH P3, A3 taken as the default).\n function detach(): void {\n if (logPollInterval) clearInterval(logPollInterval)\n if (detached || cleanedUp) return\n detached = true\n if (!session.isCurrentAttachment(generation)) return\n session.attachMessageSink(null)\n if (session.status === 'executing') session.cancelStep()\n session.startIdleTimer(() => {\n onTerminate()\n })\n }\n\n ws.on('close', detach)\n ws.on('error', detach)\n }\n}\n","import type {\n HookDefinition,\n} from '@vostride/agent-qa-core'\nimport type {\n ConsoleLogEntry,\n NetworkLogEntry,\n StepAnnotation,\n SecretRedactor,\n SecretStore,\n} from '@vostride/agent-qa-runner'\nimport type { DashboardLLMConfig } from '../llm-model-mapping.js'\nimport type { PlannerLimits } from '@vostride/agent-qa-schema'\n\nexport type LiveSessionLLMConfig = DashboardLLMConfig & {\n vision?: { screenshotSize?: number; effectiveResolution?: number }\n /** The model entry's own `vision` flag, when the config sets it (439 D-19). */\n modelVision?: boolean\n}\n\nexport interface LiveDraftMetadata {\n testName: string\n testContext?: string\n}\n\n// EntityRef — passed to SessionManager.createSession to enable the per-entity\n// counter assignment. Ephemeral; counters live on the SessionManager map.\n// [Phase 181.1 D-27, D-30]\nexport interface EntityRef {\n type: 'suite' | 'test'\n id: string\n}\n\n// LiveSuiteDraft — metadata the suite builder sends alongside execute-test\n// events. Parallels LiveDraftMetadata at the suite level.\nexport interface LiveSuiteDraft {\n suiteName: string\n suiteContext?: string\n}\n\nexport interface LiveExecutionLog {\n id: string\n type: 'hook' | 'appium-script' | 'runjs'\n name: string\n hookId?: string | null\n phase: 'setup' | 'teardown' | 'inline'\n status: 'passed' | 'failed'\n duration: number\n stdout: string | null\n stderr: string | null\n returnData: unknown | null\n variables: Record<string, string> | null\n createdAt: string\n}\n\nexport interface LiveSubActionData {\n index: number\n observation: string\n reasoning: string\n plannedAction: unknown\n result: 'success' | 'failure' | 'no-input' | 'in-progress'\n error?: string\n screenStateBefore: string\n screenStateAfter?: string\n confidence?: number\n verifierReasoning?: string\n cached: boolean\n tokenUsage?: { promptTokens: number; completionTokens: number; totalTokens: number }\n phaseDurations?: { observe?: number; plan?: number; execute?: number; verify?: number }\n annotation?: StepAnnotation\n screenContextBefore?: string\n screenContextAfter?: string\n data?: unknown\n}\n\nexport interface LiveStepResultPayload {\n status: 'passed' | 'failed' | 'cancelled'\n duration?: number\n error?: string\n capturedVariables?: Record<string, string>\n variableSnapshot?: Record<string, { value: string; source: string }>\n originalStepName?: string\n consoleLogs?: ConsoleLogEntry[]\n networkLogs?: NetworkLogEntry[]\n executionLogs?: LiveExecutionLog[]\n subActionsData?: LiveSubActionData[]\n}\n\nexport interface LiveSuiteHookOwner {\n scope: 'suite'\n}\n\nexport interface LiveTestOwner {\n scope: 'test'\n testExecutionId: string\n testIndex: number\n testId: string\n testName: string\n}\n\nexport type LiveHookOwner = LiveSuiteHookOwner | LiveTestOwner\n\nexport interface LiveHookPayload {\n executionId: string\n hookId: string\n hookName: string\n phase: 'setup' | 'teardown'\n owner: LiveHookOwner\n status: 'running' | 'passed' | 'failed'\n duration?: number\n stdout?: string | null\n stderr?: string | null\n variables?: Record<string, string> | null\n error?: string\n createdAt: string\n}\n\nexport interface LiveTestExecutionPayload {\n testExecutionId: string\n testIndex: number\n testId: string\n testName: string\n}\n\nexport interface LiveTestStepPayload extends LiveTestExecutionPayload {\n stepIndex: number\n stepInstruction: string\n}\n\n// Result emitted from LiveSession.executeTestCommand and forwarded on the\n// test-complete WS message. [Phase 181.1 D-09, D-25]\nexport interface LiveTestResultPayload {\n status: 'passed' | 'failed' | 'cancelled'\n duration: number\n error?: string\n setupHookExecutions: LiveHookPayload[]\n stepResults: LiveStepResultPayload[]\n teardownHookExecutions: LiveHookPayload[]\n}\n\nexport type ClientMessage =\n | { type: 'execute-step'; stepInstruction: string; stepIndex?: number; draft?: LiveDraftMetadata }\n | { type: 'execute-hook'; phase: 'setup' | 'teardown'; hookId: string }\n | {\n type: 'execute-test'\n testExecutionId: string\n testId: string\n path: string\n testIndex?: number\n draft?: LiveSuiteDraft\n }\n | { type: 'cancel-step' }\n | { type: 'terminate-session' }\n | { type: 'get-state' }\n | { type: 'navigate'; url: string }\n | { type: 'refresh-page' }\n | { type: 'go-back' }\n | { type: 'go-forward' }\n | { type: 'get-aria-tree' }\n\nexport type ServerMessage =\n | { type: 'session-ready'; sessionId: string; platform: string; interactive: boolean; error?: string | null }\n | { type: 'hook-start'; hook: LiveHookPayload }\n | { type: 'hook-complete'; hook: LiveHookPayload }\n | { type: 'step-phase'; phase: string; data?: unknown }\n | { type: 'step-complete'; result: LiveStepResultPayload }\n | { type: 'step-cancelled' }\n | { type: 'step-error'; error: string }\n | { type: 'test-start'; test: LiveTestExecutionPayload }\n | { type: 'test-step-start'; step: LiveTestStepPayload }\n | { type: 'test-step-phase'; step: LiveTestStepPayload; phase: string; data?: unknown }\n | { type: 'test-step-complete'; step: LiveTestStepPayload; result: LiveStepResultPayload }\n | { type: 'test-step-cancelled'; step: LiveTestStepPayload }\n | { type: 'test-step-error'; step: LiveTestStepPayload; error: string }\n | { type: 'test-complete'; test: LiveTestExecutionPayload; result: LiveTestResultPayload }\n | { type: 'test-error'; test: LiveTestExecutionPayload; error: string }\n | { type: 'session-state'; state: SessionState }\n | { type: 'session-terminated' }\n | { type: 'browser-disconnected' }\n | { type: 'error'; message: string }\n | { type: 'step-busy'; currentStep: string }\n | { type: 'navigate-complete'; url: string | null }\n | { type: 'device-logs'; entries: Array<{ level: string; message: string; timestamp: number }> }\n | { type: 'aria-tree'; tree: string }\n\nexport interface SessionState {\n sessionId: string\n platform: 'web' | 'android' | 'ios'\n targetName?: string | null\n status: 'idle' | 'executing' | 'disconnected'\n currentStep: string | null\n currentUrl: string | null\n stepsExecuted: number\n createdAt: number\n interactive: boolean\n terminalError: string | null\n}\n\n/**\n * What the create door found the current config declares about the session's target (432 D-18).\n *\n * It can only add a refusal: `initialize` refuses any name here unless the config it reads itself\n * opts in. There is deliberately no opt-in field, so nothing a caller passes can allow production.\n */\nexport interface LiveProductionFinding {\n readonly productionTargetNames: readonly string[]\n}\n\nexport interface LiveSessionConfig {\n platform: 'web' | 'android' | 'ios'\n targetName?: string\n production?: LiveProductionFinding\n /** 436 D-03: resolved at the create door from the project config and the edited entity. */\n plannerLimits?: PlannerLimits\n /** 436 D-03: per executed test, project then suite then the test's own `use`. */\n plannerLimitsForTest?: (testId: string) => Promise<PlannerLimits>\n llmConfig: LiveSessionLLMConfig\n authFetch?: typeof globalThis.fetch\n envVars?: Record<string, string>\n secretStore?: SecretStore\n secretRedactor?: SecretRedactor\n setupHooks?: string[]\n teardownHooks?: string[]\n resolvedHooks?: Map<string, HookDefinition>\n hookRegistryError?: string\n url?: string\n headless?: boolean\n useDeviceName?: string\n appState?: 'preserve' | 'reset'\n bundleId?: string\n appPackage?: string\n appActivity?: string\n device?: {\n name: string\n platformVersion?: string\n appPath?: string\n browserName?: string\n appPackage?: string\n appActivity?: string\n bundleId?: string\n udid?: string\n avd?: string\n appiumUrl?: string\n }\n}\n\n/**\n * The close code the control socket uses for a session this process does not hold (428 P5), so the\n * page can say the session ended instead of \"Disconnected\". The dashboard UI spells the same number;\n * Plan 23 pins the two equal.\n */\nexport const LIVE_EDITOR_UNKNOWN_SESSION_CLOSE_CODE = 4404\n\n/**\n * The close code for a control socket a newer one has replaced (428 WR-01). The session is still\n * held; this socket no longer drives it, so the page must not reconnect and take it back. The\n * dashboard UI spells the same number.\n */\nexport const LIVE_EDITOR_SUPERSEDED_CLOSE_CODE = 4409\n","// The LIVE-VIEW WIRE PROTOCOL (403 D-06, ratified 2026-08-25).\n//\n// THIS IS A PUBLISHED CONTRACT, not an internal shape. Phase 408's MCP App embed and M6's mobile\n// transport consume the served page and this socket UNCHANGED, so what a `liveUrl` resolves to is\n// one-way after they ship. The vocabulary is therefore written down once, here, and both ends of\n// the socket are typed against it.\n//\n// THE PATH CONSTANTS ARE SPELLED AGAIN IN THIS PACKAGE, deliberately: `dashboard-server` does not\n// import `agent` (the run-service routes' no-agent-import rule), so the embed prefix cannot be\n// imported from the function layer. `live-view-tracer.test.ts` pins the two spellings EQUAL from\n// the CLI, which may import both — the drift is measured rather than assumed away.\n\nimport { LIVE_URL_REFUSAL_REASONS } from '@vostride/agent-qa-schema'\nimport type {\n LiveStreamDeclaration,\n LiveStreamKind,\n LiveUrlRefusalReason,\n} from '@vostride/agent-qa-schema'\n\n/** The frame socket. A query carries the run id ONLY — never the token (D-04). */\nexport const LIVE_VIEW_WS_PATH = '/api/live-view/ws'\n\n/** The served embed page's prefix. Bare, so a host's `/api/` allowlist is not involved. */\nexport const LIVE_EMBED_PATH_PREFIX = '/live/'\n\n/** The largest first message this socket will read. A hello is a few hundred bytes. */\nexport const LIVE_VIEW_HELLO_MAX_BYTES = 4096\n\n/** Above this much buffered, a frame is DROPPED and acked — a slow viewer must not stall CDP. */\nexport const LIVE_VIEW_SLOW_VIEWER_BYTES = 2 * 1024 * 1024\n\n/** Keepalive cadence. */\nexport const LIVE_VIEW_PING_MS = 15_000\n\n/** The close code every refusal uses. In the 4000-4999 application range. */\nexport const LIVE_VIEW_REFUSAL_CLOSE_CODE = 4400\n\n/**\n * Every reason this socket can refuse a viewer, BY NAME.\n *\n * The four token verdicts plus the three this layer alone can answer: a run this process never\n * started, a handle that run does not have, and an editor session this process does not hold\n * (428 D-07). Extending the token's list rather than restating it is what stops the two\n * vocabularies from drifting.\n */\nexport type LiveViewRefusalReason =\n | LiveUrlRefusalReason\n | 'unknown_run'\n | 'unknown_handle'\n | 'unknown_session'\n// prettier-ignore\nexport const LIVE_VIEW_REFUSAL_REASONS = [\n ...LIVE_URL_REFUSAL_REASONS,\n 'unknown_run',\n 'unknown_handle',\n 'unknown_session',\n] as const satisfies readonly LiveViewRefusalReason[]\n\n/**\n * Every reason an `ended` message can carry, each naming a different fact (403 CR-03, 428 D-07/D-09).\n * `runFinished`: the run is over. `handleFinished`: this member's stream is over while its run\n * continues. `sessionEnded`: an editor session is over.\n */\nexport type LiveViewEndReason = 'runFinished' | 'handleFinished' | 'sessionEnded'\n// prettier-ignore\nexport const LIVE_VIEW_END_REASONS = [\n 'runFinished',\n 'handleFinished',\n 'sessionEnded',\n] as const satisfies readonly LiveViewEndReason[]\n\n/** What the PAGE sends. `hello` must be first; `ack` and `renew` are valid only after `ready`. */\nexport type LiveViewClientMessage =\n | { type: 'hello'; token: string }\n | { type: 'ack'; id: number }\n | { type: 'renew'; token: string }\n\n/**\n * What the SERVER sends.\n *\n * A `frame` is a TEXT header immediately followed by ONE BINARY message carrying the JPEG bytes.\n * Two messages rather than a length-prefixed binary frame so a consumer needs no custom header\n * parser — `JSON.parse` and a `Blob` are all an embed page has to know.\n */\nexport type LiveViewServerMessage =\n | { type: 'ready'; runId: string; handle: number; stream: LiveStreamDeclaration; expiresAt: number }\n | { type: 'refused'; reason: LiveViewRefusalReason }\n // 428 D-15: `ts` is the frame's capture time in epoch ms and `kind` the producing capability's\n // kind. Both are ADDITIVE and optional: a frame that carries neither sends the pre-428 header.\n | { type: 'frame'; id: number; width: number; height: number; ts?: number; kind?: LiveStreamKind }\n | { type: 'renewed'; expiresAt: number }\n // EVERY END BY ITS OWN NAME (403 CR-03). `handleFinished` says THIS member's stream is over\n // while the run continues; `runFinished` says the run is over; `sessionEnded` says an editor\n // session is over (428 D-07/D-09). Each is additive to the published contract: a consumer that\n // knows only the older names still reads every message it used to.\n | { type: 'ended'; reason: LiveViewEndReason }\n","// The SERVED EMBED PAGE (403 D-06/D-08, ratified 2026-08-25; changed once by 428 D-10).\n//\n// THIS DOCUMENT IS THE PRODUCT'S PUBLISHED SURFACE for a live view. A `liveUrl` resolves to it, an\n// iframe in the dashboard shows it, and 408's MCP App embed will show the same bytes — so what it\n// renders in every state is a contract, not a detail.\n//\n// SELF-CONTAINED, NONCE'D, AND `default-src 'none'`. One inline script, no imports, no fetches\n// except the socket. The run id is inserted through `textContent` in that script rather than\n// interpolated into markup, so a run id can never become markup (T-403-09).\n//\n// EVERY ABSENCE IS NAMED. There is no state in which this page shows a blank rectangle: an expired\n// link says `link expired`, a target that cannot stream says so, an unknown stream kind says so.\n// A live preview that fails silently is indistinguishable from a run that is not running, which is\n// the one thing a person watching must be able to tell.\n//\n// IT TELLS ITS HOST WHAT IT SEES, AND NOTHING ELSE (428 D-10/D-15, RESEARCH Q-BRIDGE). The page\n// posts closed-set facts to `window.parent` with target `'*'`, because a sandboxed page cannot name\n// its host's origin: `ready`, `frame` (throttled, always the newest), `ended`, `refused`, `lost`.\n// A payload is event words, stream kinds, end or refusal reasons and numbers — never the token, the\n// run id or the location, since whatever page frames this one reads every report. A host that does\n// not listen (the MCP App wrapper) loses nothing.\n//\n// ONE MESSAGE PER STATE. A host that draws its own status chrome says so with the `host` query\n// parameter; the page then hides its centred text, so no state is said twice on one screen. The\n// hint is read from the query, never the fragment, and carries no credential.\n\nimport { LIVE_VIEW_WS_PATH } from './protocol.js'\n\n/** Every value `[data-embed-state]` can take. */\nexport type LiveEmbedState =\n | 'connecting'\n | 'live'\n | 'no-stream'\n | 'expired'\n | 'refused'\n | 'stream-ended'\n | 'session-ended'\n | 'ended'\n | 'lost'\n\n/** Every value `[data-embed-state]` can take. The 403-02 DOM cells range this list. */\n// prettier-ignore\nexport const LIVE_EMBED_STATES = [\n 'connecting',\n 'live',\n 'no-stream',\n 'expired',\n 'refused',\n // THIS MEMBER'S STREAM ENDED WHILE THE RUN CONTINUES (403 CR-03). Separate the whole run's end,\n // because a person watching one member of a suite needs to know which of the two happened — and\n // neither may be shown as `live` over whichever frame happened to be last.\n 'stream-ended',\n // AN EDITOR SESSION ENDED (428 D-07/D-09). An editor subject has no run to end.\n 'session-ended',\n 'ended',\n 'lost',\n] as const satisfies readonly LiveEmbedState[]\n\n/** Every fact the page reports to its host (428 D-15). */\nexport type LiveEmbedReportEvent = 'ready' | 'frame' | 'ended' | 'refused' | 'lost'\n// prettier-ignore\nexport const LIVE_EMBED_REPORT_EVENTS = [\n 'ready',\n 'frame',\n 'ended',\n 'refused',\n 'lost',\n] as const satisfies readonly LiveEmbedReportEvent[]\n\n/**\n * The query parameter a host sets when it draws its own status chrome (`/live/<id>?host=dashboard`).\n * Any non-empty value lands on `main[data-embed-host]` and hides the page's centred text.\n */\nexport const LIVE_EMBED_HOST_PARAM = 'host'\n\n/** At most one `frame` report per this many milliseconds; the report carries the newest frame. */\nexport const LIVE_EMBED_REPORT_INTERVAL_MS = 500\n\n/**\n * What an EXPIRED link says, exactly (D-02).\n *\n * Exported so the tracer cell and 403-02's DOM cells assert the SAME string the page renders — a\n * literal spelled twice is a literal that can drift, and this one is the difference between a\n * person seeing \"your link timed out\" and a person seeing nothing at all.\n */\nexport const LIVE_EMBED_EXPIRED_MESSAGE = 'link expired'\n\n/**\n * What a target that declared NO live stream says, exactly (D-08).\n *\n * This document owns no step list, and its host — the dashboard iframe today, the 408 MCP App\n * later — is invisible to it, so the sentence claims nothing about where or whether steps are\n * shown. Exported so the served bytes are pinned against the constant (frame-proxy cell 25).\n */\nexport const LIVE_EMBED_NO_STREAM_MESSAGE = 'no live preview for this target'\n\n/** What an ended editor session says, exactly (428 D-07/D-09; frame-proxy cell 34). */\nexport const LIVE_EMBED_SESSION_ENDED_MESSAGE = 'session ended'\n\nconst STYLE = `\n :root { color-scheme: dark light }\n html, body { margin: 0; height: 100%; background: #0b0d10; }\n main { display: grid; place-items: center; height: 100%; font: 14px/1.5 ui-sans-serif, system-ui, sans-serif; color: #c9d1d9; }\n canvas { max-width: 100%; max-height: 100%; display: none; pointer-events: none; }\n main[data-embed-state=\"live\"] canvas { display: block; }\n main[data-embed-state=\"live\"] p { display: none; }\n main[data-embed-host] p { display: none; }\n`\n\n/**\n * Render the page for one run.\n *\n * `nonce` is minted per response by the caller and appears in both the CSP header and the two\n * inline elements; a page served twice never reuses one.\n */\nexport function renderLiveEmbedPage(input: { runId: string; nonce: string }): string {\n // JSON.stringify is the escape: the value lands inside a script as a STRING LITERAL, and the\n // `<` guard closes the one hole that leaves (a `</script` sequence inside it). One helper for\n // every value that enters the script, so the guard cannot be forgotten for a new one.\n const scriptLiteral = (value: string) => JSON.stringify(value).replaceAll('<', '\\\\u003c')\n const runIdLiteral = scriptLiteral(input.runId)\n const wsPathLiteral = scriptLiteral(LIVE_VIEW_WS_PATH)\n const expiredLiteral = scriptLiteral(LIVE_EMBED_EXPIRED_MESSAGE)\n const noStreamLiteral = scriptLiteral(LIVE_EMBED_NO_STREAM_MESSAGE)\n const sessionEndedLiteral = scriptLiteral(LIVE_EMBED_SESSION_ENDED_MESSAGE)\n const hostParamLiteral = scriptLiteral(LIVE_EMBED_HOST_PARAM)\n const reportIntervalLiteral = String(LIVE_EMBED_REPORT_INTERVAL_MS)\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>agent-qa live view</title>\n<style nonce=\"${input.nonce}\">${STYLE}</style>\n</head>\n<body>\n<main data-embed-state=\"connecting\" data-embed-frames=\"0\">\n<canvas data-embed-canvas width=\"0\" height=\"0\"></canvas>\n<p data-embed-message>connecting…</p>\n</main>\n<script nonce=\"${input.nonce}\">\n(function () {\n var runId = ${runIdLiteral};\n var root = document.querySelector('[data-embed-state]');\n var canvas = document.querySelector('[data-embed-canvas]');\n var message = document.querySelector('[data-embed-message]');\n var ctx = canvas.getContext('2d');\n var frames = 0;\n\n // A HOST THAT SPEAKS FOR THIS PAGE says so in the query. The value only ever becomes an\n // attribute value, so it can hide text and nothing more.\n var hostHint = new URLSearchParams(location.search).get(${hostParamLiteral});\n if (hostHint) root.setAttribute('data-embed-host', hostHint);\n\n function setState(state, text) {\n root.setAttribute('data-embed-state', state);\n message.textContent = text;\n }\n\n // Facts for whichever page frames this one. Built only from closed-set words and numbers.\n function report(payload) {\n if (window.parent === window) return;\n try { window.parent.postMessage(payload, '*'); } catch (e) { /* a host that cannot receive changes nothing here */ }\n }\n\n var reportInterval = ${reportIntervalLiteral};\n var lastFrameReportAt = 0;\n var frameReportTimer = null;\n var newestFrame = null;\n\n function flushFrameReport() {\n frameReportTimer = null;\n if (newestFrame === null) return;\n var fact = newestFrame;\n newestFrame = null;\n lastFrameReportAt = Date.now();\n report({ event: 'frame', ts: fact.ts, kind: fact.kind, width: fact.width, height: fact.height });\n }\n\n // At most one frame report per interval, and always the newest: a trailing timer flushes it.\n function reportFrame(fact) {\n newestFrame = fact;\n if (frameReportTimer !== null) return;\n var wait = lastFrameReportAt + reportInterval - Date.now();\n if (wait <= 0) flushFrameReport();\n else frameReportTimer = setTimeout(flushFrameReport, wait);\n }\n\n function stopFrameReports() {\n newestFrame = null;\n if (frameReportTimer !== null) clearTimeout(frameReportTimer);\n frameReportTimer = null;\n }\n\n // THE TOKEN IS READ FROM THE FRAGMENT AND NEVER PUT BACK ANYWHERE. It is not written to the\n // document, not added to the socket URL, not reported to the host, and not stored — it goes\n // into one message and stays in this closure.\n var token = location.hash.slice(1);\n if (token === '') {\n setState('refused', 'missing token');\n return;\n }\n\n var scheme = location.protocol === 'https:' ? 'wss://' : 'ws://';\n var socket = new WebSocket(scheme + location.host + ${wsPathLiteral} + '?runId=' + encodeURIComponent(runId));\n socket.binaryType = 'arraybuffer';\n\n var pending = null;\n var ended = false;\n\n socket.addEventListener('open', function () {\n socket.send(JSON.stringify({ type: 'hello', token: token }));\n });\n\n socket.addEventListener('message', function (event) {\n if (typeof event.data !== 'string') {\n // The binary half of a frame pair. Paint it, count it, then ack — the ack is what asks the\n // producer for the next one, so it goes AFTER the paint is scheduled.\n if (pending === null) return;\n var header = pending;\n pending = null;\n // NO MIME TYPE: the decoder sniffs the bytes, so a JPEG screencast frame and a PNG snapshot\n // both paint in every host, not only in Chromium (428 RESEARCH A2).\n var blob = new Blob([event.data]);\n createImageBitmap(blob).then(function (bitmap) {\n if (canvas.width !== header.width || canvas.height !== header.height) {\n canvas.width = header.width;\n canvas.height = header.height;\n }\n ctx.drawImage(bitmap, 0, 0, header.width, header.height);\n bitmap.close();\n frames += 1;\n root.setAttribute('data-embed-frames', String(frames));\n if (!ended) setState('live', 'live');\n socket.send(JSON.stringify({ type: 'ack', id: header.id }));\n if (!ended) reportFrame(header);\n }).catch(function () {\n socket.send(JSON.stringify({ type: 'ack', id: header.id }));\n });\n return;\n }\n\n var msg;\n try { msg = JSON.parse(event.data); } catch (e) { return; }\n\n if (msg.type === 'ready') {\n // THE PAINTER IS CHOSEN BY THE DECLARED KIND — never by a browser name, an adapter class or\n // a transport guess (LIVE-04's prohibition). A snapshot paints on the same canvas (428 D-11).\n var kind = msg.stream ? msg.stream.kind : undefined;\n if (kind === 'cdp-screencast' || kind === 'snapshot') {\n setState('connecting', 'waiting for the first frame…');\n } else if (kind === 'none') {\n setState('no-stream', ${noStreamLiteral});\n } else {\n setState('no-stream', 'unsupported stream kind');\n }\n report({ event: 'ready', kind: kind });\n return;\n }\n if (msg.type === 'frame') {\n pending = { id: msg.id, width: msg.width, height: msg.height, ts: msg.ts, kind: msg.kind };\n return;\n }\n if (msg.type === 'refused') {\n ended = true;\n stopFrameReports();\n if (msg.reason === 'expired') setState('expired', ${expiredLiteral});\n else setState('refused', String(msg.reason));\n report({ event: 'refused', reason: msg.reason });\n return;\n }\n if (msg.type === 'ended') {\n // EVERY ABSENCE IS NAMED, AND THESE ARE DIFFERENT ABSENCES. Painting stops either way -- the\n // canvas is hidden outside the live state -- so no end can leave a frozen frame on screen\n // labelled as though it were still arriving.\n ended = true;\n stopFrameReports();\n if (msg.reason === 'handleFinished') setState('stream-ended', 'this target finished — the run is still going');\n else if (msg.reason === 'sessionEnded') setState('session-ended', ${sessionEndedLiteral});\n else setState('ended', 'run ended');\n report({ event: 'ended', reason: msg.reason });\n return;\n }\n });\n\n socket.addEventListener('close', function () {\n if (ended) return;\n if (root.getAttribute('data-embed-state') === 'expired') return;\n if (root.getAttribute('data-embed-state') === 'refused') return;\n stopFrameReports();\n setState('lost', 'connection lost');\n report({ event: 'lost' });\n });\n\n // A HOST THAT RE-MINTS replaces the fragment; the socket renews in place rather than reloading,\n // so a renewal never costs the viewer the stream it is watching (D-02).\n window.addEventListener('hashchange', function () {\n var next = location.hash.slice(1);\n if (next === '' || socket.readyState !== 1) return;\n token = next;\n socket.send(JSON.stringify({ type: 'renew', token: next }));\n });\n}());\n</script>\n</body>\n</html>\n`\n}\n","// The FRAME PROXY (403 D-04/D-06/D-16) — the server end of one viewer's socket.\n//\n// WHAT IT HOLDS AND WHAT IT DOES NOT. It holds a validator it was HANDED, a run lookup it was\n// HANDED and, when it serves editor sessions, an editor lookup it was HANDED. It parses no token,\n// mints nothing, and reads no token off a URL: the first text message is the only carriage, and\n// `deps.validate` is the function layer's own `validateLiveUrlToken` bound to the same signer that\n// minted (LIVE-02's third prohibition made structural).\n//\n// TWO SUBJECTS, ONE SOCKET (428 D-07). The path id names a run or an editor session, and the\n// token's SIGNED subject kind decides which lookup is asked. A run token only ever reaches the run\n// lookup and an editor token only ever reaches the editor lookup, even when both hold the same id.\n// Validation always comes before either lookup, so `unknown_run` and `unknown_session` are only\n// reachable with a valid token for that exact id.\n//\n// D-16: a detach NEVER touches the run. Closing a viewer's socket unsubscribes it from the frame\n// hub and clears this socket's timers, and that is the whole of it — nothing that ends a run,\n// nothing that tears one down, no effect a person would not expect from closing a window.\n//\n// THAT CLAIM IS PINNED BY A SOURCE SCAN, which is why the run-ending verb does not appear anywhere\n// in this file, not even in prose: `live-view.frame-proxy.test.ts` cell (21) asserts the token is\n// absent from these bytes, so an implementation that grew the call — or a comment that talked\n// itself into one — is a named RED rather than a review someone has to notice (T-403-07).\n\nimport type WebSocket from 'ws'\n\nimport type {\n LiveFrame,\n LiveFrameEndReason,\n LiveFrameSubscription,\n LiveUrlVerdict,\n LiveViewSubjectKind,\n LiveViewSubjectRef,\n RunSession,\n} from '@vostride/agent-qa-schema'\n\nimport {\n LIVE_VIEW_HELLO_MAX_BYTES,\n LIVE_VIEW_PING_MS,\n LIVE_VIEW_REFUSAL_CLOSE_CODE,\n LIVE_VIEW_SLOW_VIEWER_BYTES,\n} from './protocol.js'\nimport type { LiveViewRefusalReason, LiveViewServerMessage } from './protocol.js'\nimport type { LiveEditorAttachment } from './editor-subjects.js'\n\nexport interface FrameProxyDeps {\n validate(token: string, expect: { subject: LiveViewSubjectRef; now: number }): LiveUrlVerdict\n attach(runId: string): RunSession | undefined\n /** 428 D-07: the editor-subject lookup. Absent means no editor subject is served on this socket. */\n attachEditor?(sessionId: string): LiveEditorAttachment | undefined\n now?: () => number\n}\n\n/** What the socket reads frames from: a run session, or an editor session's attachment. */\ntype FrameSource = Pick<RunSession, 'streamCapabilityOf' | 'subscribeFrames'>\n\n/** Guarded send — the `live-editor/ws-handler.ts` idiom, so a closed socket is never written to. */\nfunction send(ws: WebSocket, message: LiveViewServerMessage): void {\n if (ws.readyState === ws.OPEN) ws.send(JSON.stringify(message))\n}\n\nexport function createFrameProxy(deps: FrameProxyDeps): (ws: WebSocket, runId: string) => void {\n const now = deps.now ?? ((): number => Date.now())\n\n // `runId` is the path id. For an editor subject it is the session id; the published name stays.\n return (ws: WebSocket, runId: string): void => {\n let subscription: LiveFrameSubscription | undefined\n /** The subject kind the greet resolved. A renew is validated against this kind only. */\n let subjectKind: LiveViewSubjectKind | undefined\n /** The handle the greet opened, and the expiry the deadline is armed for (428 WR-07). */\n let greetedHandle: number | undefined\n let deadlineAt: number | undefined\n let deadline: ReturnType<typeof setTimeout> | undefined\n let ping: ReturnType<typeof setInterval> | undefined\n let greeted = false\n\n const clearTimers = (): void => {\n if (deadline !== undefined) clearTimeout(deadline)\n if (ping !== undefined) clearInterval(ping)\n deadline = undefined\n ping = undefined\n }\n\n const refuse = (reason: LiveViewRefusalReason): void => {\n send(ws, { type: 'refused', reason })\n clearTimers()\n subscription?.unsubscribe()\n subscription = undefined\n ws.close(LIVE_VIEW_REFUSAL_CLOSE_CODE, reason)\n }\n\n /** Arm (or re-arm) the expiry deadline. An unrenewed socket is refused BY NAME, not dropped. */\n const armDeadline = (expiresAt: number): void => {\n if (deadline !== undefined) clearTimeout(deadline)\n deadlineAt = expiresAt\n const remaining = Math.max(0, expiresAt - now())\n deadline = setTimeout(() => { refuse('expired') }, remaining)\n deadline.unref?.()\n }\n\n const onFrame = (frame: LiveFrame): void => {\n if (ws.readyState !== ws.OPEN) return\n // SLOW VIEWER: drop the pixels, ack anyway. CDP will not produce frame N+1 until N is acked,\n // so a viewer that cannot keep up must cost itself frames and never cost the producer its\n // stream. A live view that falls behind should skip, not stall.\n if (ws.bufferedAmount > LIVE_VIEW_SLOW_VIEWER_BYTES) {\n subscription?.ack(frame.id)\n return\n }\n // 428 D-15: the capture time and kind the frame CARRIES, forwarded when present. The proxy\n // keeps no clock of its own for this: a time taken here measures socket delivery, not capture.\n send(ws, {\n type: 'frame',\n id: frame.id,\n width: frame.metadata.width,\n height: frame.metadata.height,\n ...(frame.metadata.timestamp !== undefined ? { ts: frame.metadata.timestamp } : {}),\n ...(frame.kind !== undefined ? { kind: frame.kind } : {}),\n })\n // THE BINARY HALF IS GUARDED TOO (403 WR-06). The check at the top of this callback is not\n // enough: a socket can close between it and here, and `ws.send` then THROWS — straight up\n // into the hub's delivery walk, which detaches the viewer and reports the fault. The header\n // above already goes through the guarded writer; this one used to be bare.\n if (ws.readyState !== ws.OPEN) {\n // The viewer is gone. It owes an ack it can never give, and CDP will not produce the next\n // frame until somebody does — so ack on its behalf rather than stalling the producer.\n subscription?.ack(frame.id)\n return\n }\n try {\n ws.send(frame.bytes, (error?: Error) => {\n // An async write failure costs this viewer the frame and nothing else.\n if (error !== undefined) subscription?.ack(frame.id)\n })\n } catch {\n subscription?.ack(frame.id)\n }\n }\n\n /**\n * THIS HANDLE'S STREAM ENDED UNDER THE VIEWER, AND THE HUB SAYS WHY (403 CR-03, 428 RESEARCH P9).\n *\n * `withdrawn`: a multi-member run settles one member at a time, and the member's browser goes\n * down with it. Without a word the viewer kept a frozen last frame under\n * `data-embed-state=\"live\"` until the whole run ended — a stale picture claiming to be live,\n * which is exactly what the embed page's own law forbids. The socket is NOT closed:\n * `runFinished` is a different fact, it is still coming, and a viewer who is told one end is\n * not thereby told the other.\n *\n * `closed`: the hub itself went down because the whole subject is over. That is not a finished\n * member, so nothing is said here; the subject's own end message follows.\n */\n const onStreamEnd = (reason: LiveFrameEndReason): void => {\n subscription = undefined\n if (reason === 'withdrawn') send(ws, { type: 'ended', reason: 'handleFinished' })\n }\n\n const validateAs = (token: string, kind: LiveViewSubjectKind): LiveUrlVerdict =>\n deps.validate(token, { subject: { kind, id: runId }, now: now() })\n\n /**\n * RESOLVE THE SUBJECT BY THE TOKEN'S SIGNED KIND (428 D-07). A run first; only a\n * `scope_mismatch` there, on a socket that serves editor sessions, is worth asking again as an\n * editor. Every other refusal is the answer as it stands.\n */\n const resolve = (token: string): LiveUrlVerdict => {\n const asRun = validateAs(token, 'run')\n if (asRun.kind === 'refused' && asRun.reason === 'scope_mismatch' && deps.attachEditor) {\n return validateAs(token, 'editor')\n }\n return asRun\n }\n\n /** Subscribe, then say ready, then wait for the subject's own end. */\n const open = (\n source: FrameSource,\n handle: number,\n expiresAt: number,\n end: { ended: Promise<unknown>; reason: 'runFinished' | 'sessionEnded' },\n ): void => {\n greetedHandle = handle\n const stream = source.streamCapabilityOf(handle)\n // SUBSCRIBE FIRST, THEN READY (428 D-14, #274). `ready` tells the page a first frame is\n // coming, so it may only be said once a subscription exists. A declared stream whose\n // subscription comes back undefined settled between the two reads, and the viewer is told\n // so by name instead of waiting for a frame that will never arrive.\n // `{ kind: 'none' }` is an HONEST answer, not a failure: the socket stays open so the page\n // can still receive `ended`, and no painter is ever started.\n if (stream.kind !== 'none') {\n subscription = source.subscribeFrames(handle, onFrame, onStreamEnd)\n if (subscription === undefined) {\n refuse('unknown_handle')\n return\n }\n }\n // D-10: an editor subject reuses the published fields as they are. `runId` is the path id\n // and `handle` is 0; no subject field is added.\n send(ws, { type: 'ready', runId, handle, stream, expiresAt })\n armDeadline(expiresAt)\n ping = setInterval(() => {\n if (ws.readyState === ws.OPEN) ws.ping()\n }, LIVE_VIEW_PING_MS)\n ping.unref?.()\n\n const finish = (): void => {\n send(ws, { type: 'ended', reason: end.reason })\n clearTimers()\n ws.close(1000, end.reason)\n }\n end.ended.then(finish, finish)\n }\n\n const greet = (token: string): void => {\n const verdict = resolve(token)\n if (verdict.kind !== 'ok') {\n refuse(verdict.reason)\n return\n }\n const subject = verdict.claims.subject\n subjectKind = subject.kind\n if (subject.kind === 'run') {\n const session = deps.attach(runId)\n if (session === undefined) {\n refuse('unknown_run')\n return\n }\n open(session, subject.handle, verdict.claims.exp, {\n ended: session.done,\n reason: 'runFinished',\n })\n return\n }\n const attachment = deps.attachEditor?.(runId)\n if (attachment === undefined) {\n refuse('unknown_session')\n return\n }\n open(attachment, 0, verdict.claims.exp, { ended: attachment.ended, reason: 'sessionEnded' })\n }\n\n ws.on('message', (data: unknown, isBinary?: boolean) => {\n // A BINARY first message is malformed by definition — the hello is text.\n if (isBinary === true) {\n refuse('malformed')\n return\n }\n const raw = String(data)\n // THE CAP IS A BYTE CAP, AND THE DIFFERENCE IS NOT PEDANTRY. `String#length` counts UTF-16\n // code units, so a hello padded with multi-byte characters sits under a 4096-CHARACTER cap\n // while being several kilobytes of actual traffic — and bytes are what the socket buffered,\n // what the process allocated, and what T-403-11 is about. Measured off the received frame\n // where there is one, so the number is the wire's own rather than a re-encoding of it.\n const bytes = Buffer.isBuffer(data) ? data.byteLength : Buffer.byteLength(raw)\n if (bytes > LIVE_VIEW_HELLO_MAX_BYTES) {\n refuse('malformed')\n return\n }\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n refuse('malformed')\n return\n }\n if (typeof parsed !== 'object' || parsed === null) {\n refuse('malformed')\n return\n }\n const message = parsed as { type?: unknown; token?: unknown; id?: unknown }\n\n if (!greeted) {\n if (message.type !== 'hello' || typeof message.token !== 'string') {\n refuse('malformed')\n return\n }\n greeted = true\n greet(message.token)\n return\n }\n\n if (message.type === 'ack' && typeof message.id === 'number') {\n subscription?.ack(message.id)\n return\n }\n if (message.type === 'renew' && typeof message.token === 'string') {\n // D-02's silent re-mint, INSIDE the socket: a fresh token extends this viewer's deadline\n // without re-opening anything. It is re-validated in full — a renew is not a lesser check.\n if (subjectKind === undefined) {\n refuse('malformed')\n return\n }\n const verdict = validateAs(message.token, subjectKind)\n if (verdict.kind !== 'ok') {\n refuse(verdict.reason)\n return\n }\n // 428 WR-07: a token is view-scoped to one handle, so a renew must name the handle this\n // socket greeted with; and an older token, replayed or reordered, never shortens the\n // deadline a newer one set.\n const renewed = verdict.claims.subject\n if (renewed.kind === 'run' && renewed.handle !== greetedHandle) {\n refuse('scope_mismatch')\n return\n }\n if (deadlineAt === undefined || verdict.claims.exp > deadlineAt) armDeadline(verdict.claims.exp)\n send(ws, { type: 'renewed', expiresAt: deadlineAt ?? verdict.claims.exp })\n return\n }\n refuse('malformed')\n })\n\n ws.on('close', () => {\n // D-16, AND NOTHING ELSE. Detach releases this viewer's hold and this socket's timers. The\n // run is not consulted, not ended, and not told.\n subscription?.unsubscribe()\n subscription = undefined\n clearTimers()\n })\n\n ws.on('error', () => {\n subscription?.unsubscribe()\n subscription = undefined\n clearTimers()\n })\n }\n}\n"],"mappings":"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","names":["import_node_http","import_node_crypto","import_promises","import_node_path","import_node_os","osHostname","probe","import_node_crypto","import_promises","import_node_path","import_promises","import_node_path","import_node_crypto","import_node_fs","parseYaml","parseTestFile","import_node_crypto","import_promises","import_node_fs","import_node_path","import_node_util","import_yaml","import_agent_qa_core","isMissingFile","import_node_crypto","import_promises","import_node_path","import_agent_qa_core","import_agent_qa_ids","import_yaml","import_promises","import_node_path","import_agent_qa_core","import_yaml","parseYaml","parseYaml","resolve","import_node_crypto","import_node_path","import_agent_qa_core","import_agent_qa_model","import_agent_qa_schema","import_yaml","import_promises","import_node_path","import_yaml","import_agent_qa_core","parseYaml","parseYaml","refuse","resolve","completed","resolvePath","result","import_agent_qa_core","import_agent_qa_schema","import_agent_qa_schema","import_agent_qa_schema","import_agent_qa_schema","respondJson","import_agent_qa_schema","errorNameOf","errorMessageOf","refusalFor","respondJson","import_agent_qa_schema","import_agent_qa_schema","import_agent_qa_schema","import_agent_qa_core","import_agent_qa_model","import_agent_qa_schema","refuse","request","import_agent_qa_core","import_agent_qa_runner","import_agent_qa_runner_local","import_agent_qa_model","import_yaml","parseYaml","getConfiguredAuthStateDir","getConfiguredAuthStateDir","parseYaml","llmConfig","import_node_os","import_promises","import_node_path","import_agent_qa_ids","import_yaml","import_agent_qa_core","parseYaml","import_node_child_process","import_agent_qa_core","pc","resolve","treeKill","import_node_crypto","import_agent_qa_core","toStepResultPayload","import_agent_qa_schema","send","refuse","resolve","import_agent_qa_core","request","resolve"]}
|