import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; import { lastMetaForRole } from "../../lib/meta-helpers.js"; import { runTestCommand } from "../../lib/run-test-command.js"; import type { ImplementerMeta } from "../implementer/index.js"; import type { PlannerMeta } from "../planner/index.js"; export type TestCommandResult = { command: string; ok: boolean; stdoutPreview: string; stderrPreview: string; }; export type TesterMeta = { passed: boolean; attempt: number; failureReason: string | null; testCommandResults: TestCommandResult[] | null; }; export type BuildTesterDeps = { nerveRoot: string; }; export function buildTesterRole({ nerveRoot }: BuildTesterDeps): Role { return async (_start: StartStep, messages: WorkflowMessage[]): Promise> => { const plannerMeta = lastMetaForRole(messages, "planner"); const implementerMeta = lastMetaForRole(messages, "implementer"); const attempt = messages.filter((message) => message.role === "tester").length + 1; if (implementerMeta === null || !implementerMeta.implementationOk || implementerMeta.branchName === null) { return { content: "tester cannot continue: no successful implementer output", meta: { passed: false, attempt, failureReason: "no successful implementer output", testCommandResults: null, }, }; } const commands = plannerMeta?.testCommands !== null && plannerMeta?.testCommands !== undefined && plannerMeta.testCommands.length > 0 ? plannerMeta.testCommands : ["pnpm test"]; const testCommandResults: TestCommandResult[] = []; for (const command of commands) { const run = await runTestCommand(nerveRoot, command); testCommandResults.push({ command, ok: run.ok, stdoutPreview: run.stdoutPreview, stderrPreview: run.stderrPreview, }); if (!run.ok) { return { content: `test failed: ${command}\n${run.reason ?? "unknown error"}`, meta: { passed: false, attempt, failureReason: `command failed: ${command} (${run.reason ?? "unknown error"})`, testCommandResults, }, }; } } return { content: `all tests passed on branch ${implementerMeta.branchName}`, meta: { passed: true, attempt, failureReason: null, testCommandResults, }, }; }; }