import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; export const reviewerMetaSchema = z.object({ approved: z.boolean().describe("true if the diff is clean and ready for tester validation"), }); export type ReviewerMeta = z.infer; export function reviewerPrompt({ threadId, nerveRoot }: { threadId: string; nerveRoot: string }): string { return `You are a **code reviewer** for Nerve workflow changes. You run after the coder and before the tester. **IMPORTANT: The Nerve workspace is at \`${nerveRoot}\`. Always \`cd ${nerveRoot}\` first.** Read the workflow thread for context: \`nerve thread ${threadId}\` Read project conventions: \`cat ${nerveRoot}/CONVENTIONS.md\` ## Your job — static analysis of the git diff Run these commands and analyze the output: 1. **\`cd ${nerveRoot} && git diff --stat\`** — see what files changed 2. **\`cd ${nerveRoot} && git diff\`** — read the actual diff 3. **\`cd ${nerveRoot} && git status --short\`** — check for untracked files ## Checklist Review the diff against CONVENTIONS.md. Key things to catch: ### 🔴 Reject (approved: false) — tell coder exactly what to fix - **Garbage files**: anything listed under "What NOT to commit" in CONVENTIONS.md - **Secrets/credentials**: API keys, tokens, passwords hardcoded in the diff - **Unrelated changes**: files modified outside the scope of the task - **Convention violations**: patterns that contradict CONVENTIONS.md (e.g. \`interface\` instead of \`type\`, \`class\`, dynamic \`import()\`, optional properties with \`?:\`) ### ✅ Approve (approved: true) — no comment needed - Diff is clean, focused, follows conventions End with: \`\`\`json { "approved": true } \`\`\` or \`\`\`json { "approved": false } \`\`\``; } export function createReviewerRole( adapter: AgentFn, extract: LlmExtractorConfig, nerveRoot: string, ): Role { return createRole( adapter, async (start: StartStep) => reviewerPrompt({ threadId: start.meta.threadId, nerveRoot }), reviewerMetaSchema, extract, ); }