import { CommandExecutionError, runCommand } from "./core/sys_exec.ts"; import { globToRegExp } from "https://deno.land/std@0.224.0/path/mod.ts"; import { parseArgs } from "https://deno.land/std@0.224.0/cli/parse_args.ts"; import { analyzeRequirements } from "./agents/gatekeeper.ts"; import { runAdversaryAnalysis } from "./agents/adversary.ts"; import { updateDocumentation } from "./agents/translator.ts"; import { evaluatePipeline } from "./agents/evaluator.ts"; import { gatherHistoricalContext } from "./agents/historian.ts"; import { runArchitectureAnalysis } from "./agents/analyst.ts"; import { getDiff, getStagedDiff, readBranchFile, } from "./core/git_inspector.ts"; import { readNote } from "./core/git_storage.ts"; async function getTransitions() { try { const content = await readBranchFile("meta-state", "transitions.json"); if (content) return JSON.parse(content); } catch {} try { return JSON.parse( await Deno.readTextFile(".forum/src/core/transitions.json"), ); } catch { try { return JSON.parse(await Deno.readTextFile("src/core/transitions.json")); } catch (e) { console.error("❌ No transitions.json:", e); Deno.exit(1); } } } async function getChangedFiles(flags: { all?: boolean; push?: boolean }) { if (flags.all) { try { const trackedCmd = await runCommand("git", [ "ls-files", "src/", "server/", "docs/", ]); if (trackedCmd.stdout) { return trackedCmd.stdout.split("\n").map((f) => f.trim()).filter( Boolean, ); } } catch {} } try { const staged = await getStagedDiff(); if (staged.length > 0) return staged.map((d) => d.filepath); const working = await getDiff(); // un-staged modifications in working tree if (working.length > 0) return working.map((d) => d.filepath); } catch {} try { const upstream = await getDiff("@{u}", "HEAD"); if (upstream.length > 0) return upstream.map((d) => d.filepath); } catch {} try { const last = await getDiff("HEAD~1", "HEAD"); if (last.length > 0) return last.map((d) => d.filepath); } catch {} return []; } // Maps rule names to agent runners const RULE_AGENT_RUNNERS: Record = { "Gatekeeper_Approval": () => analyzeRequirements(), "Translator_Check": () => updateDocumentation(), "Adversary_Pass": async (targets?: string[], fullMutation?: boolean) => { const cliArgs = ["--run"]; if (targets && targets.length > 0) { cliArgs.push("--targets", targets.join(",")); } if (fullMutation) cliArgs.push("--full-mutation"); await runAdversaryAnalysis(cliArgs); }, "Historian_Context": () => gatherHistoricalContext(), "Analyst_Optimize": () => runArchitectureAnalysis(), "Historian": () => gatherHistoricalContext(), "Analyst": () => runArchitectureAnalysis(), }; const runAgt = async (n: string, fn: any, tf?: string[], fm?: boolean) => { console.log(`\n========================================\nRunning ${n}...`); try { await fn(tf, fm); return { success: true, status: "Passed", noteRef: "-" }; } catch (e) { console.error(`❌ ${n} error:`, e); return { success: false, status: "Blocked", noteRef: "-" }; } }; export async function main(cliArgs: string[] = Deno.args) { console.log("=== Agent Forum Pipeline Runner ==="); const args = parseArgs(cliArgs, { boolean: [ "all", "full", "push", "adversary", "mutation", "full-mutation", "full-adversary", "force", ], }); if (args.push && !args.force) { try { const state = await readNote("evaluator_state", "HEAD"); if (state && state.pipelineState === "Valid") { console.log( "\n⚡ Commit HEAD has already been evaluated... Skipping duplicate compute.", ); Deno.exit(0); } } catch {} } const transitions = await getTransitions(); const changedFiles = await getChangedFiles({ all: args.all || args.full, push: args.push, }); const { evaluateRequiredRules } = await import("./run_utils.ts"); if (changedFiles.length > 0) { console.log(`\nChanged files (${changedFiles.length}):`); changedFiles.forEach((f) => console.log(` - ${f}`)); } else { console.log("\nNo files changed. Falling back to default Coder requires."); } const requiredRules = evaluateRequiredRules( changedFiles, transitions, args.adversary || args.mutation || args["full-mutation"] || args["full-adversary"], ); if (changedFiles.length > 0 && transitions.scopes) { for (const [scope, def] of Object.entries(transitions.scopes)) { const p = (def as any).patterns || []; const m = changedFiles.filter((f) => p.some((pat: string) => globToRegExp(pat).test(f)) ); if (m.length > 0) { console.log(`\nMatched scope: ${scope} (${m.length} files)`); } } } console.log( `\nEnforcing Rules: ${Array.from(requiredRules.keys()).join(", ")}`, ); const execSumm: { agent: string; status: string; noteRef: string }[] = []; const fullMut = args["full-mutation"] || args["full-adversary"]; const rulePromises = new Map>(); const execRule = async (rule: string): Promise => { if (rulePromises.has(rule)) return rulePromises.get(rule)!; const p = (async () => { const deps = transitions[rule.split("_")[0]]?.requires || []; const waitDeps = deps.filter((d: string) => requiredRules.has(d)); if (waitDeps.length > 0) await Promise.all(waitDeps.map(execRule)); const run = RULE_AGENT_RUNNERS[rule]; if (run) { const res = await runAgt( rule, run, Array.from(requiredRules.get(rule)!), fullMut, ); execSumm.push({ agent: rule, status: res.status, noteRef: res.noteRef, }); if (!res.success) throw new Error(`Pipeline halted: ${rule} failed.`); } else console.warn(`⚠️ No runner for: ${rule}`); })(); rulePromises.set(rule, p); return p; }; try { await Promise.all(Array.from(requiredRules.keys()).map(execRule)); } catch (err) { console.error("DAG failed:", err); Deno.exit(1); } // Always run Evaluator at the end to check transitions.json state and DAGs const evaluatorResult = await runAgt("Evaluator", evaluatePipeline); execSumm.push({ agent: "Evaluator", status: evaluatorResult.status, noteRef: evaluatorResult.noteRef, }); if (!evaluatorResult.success) { console.error(`\n❌ Pipeline halted: Evaluator found invalid state.`); Deno.exit(1); } console.log(`\n========================================`); console.log(`📋 Execution Summary`); console.log(`========================================`); console.table(execSumm); console.log(`========================================\n`); console.log(`✅ Pipeline completed SUCCESSFULLY.`); }