← back to Govarbitrage
src/agents/run.ts
81 lines
// CLI runner for the agent layer.
// npm run agents -- appraiser [N] re-appraise up to N listings via local AI (default 25)
// npm run agents -- skeptic [N] adversarial audit of the top N ranked (default 30)
// npm run agents -- scout hot deals closing within 48h
// npm run agents -- all skeptic → scout → appraiser (small batch)
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
import type { AgentRunResult } from "./framework";
// Minimal .env loader (same pattern as scripts/send-digest.ts — don't rely on
// Prisma's dotenv side-effect when invoked via tsx).
function loadEnv() {
const root = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
try {
const raw = readFileSync(join(root, ".env"), "utf8");
for (const line of raw.split("\n")) {
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/i);
if (!m) continue;
const key = m[1];
let val = m[2].trim();
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
val = val.slice(1, -1);
}
if (process.env[key] === undefined) process.env[key] = val;
}
} catch {
/* no .env — rely on ambient env */
}
}
loadEnv();
const { prisma } = await import("../lib/db");
const { runAppraiser } = await import("./appraiser");
const { runSkeptic } = await import("./skeptic");
const { runScout } = await import("./scout");
function report(r: AgentRunResult) {
console.log(
`[${r.agent}] ${r.status} — run ${r.runId} · ${r.itemsProcessed} items · ${r.findings} findings\n ${r.summary ?? ""}`,
);
}
async function main() {
const [agent, nArg] = process.argv.slice(2);
const n = nArg != null ? Number(nArg) : undefined;
if (nArg != null && (!Number.isFinite(n) || n! <= 0)) {
throw new Error(`Invalid count "${nArg}" — expected a positive number.`);
}
switch ((agent || "").toLowerCase()) {
case "appraiser":
report(await runAppraiser(n ?? 25));
break;
case "skeptic":
report(await runSkeptic(n ?? 30));
break;
case "scout":
report(await runScout());
break;
case "all":
report(await runSkeptic(n ?? 30));
report(await runScout());
report(await runAppraiser(n ?? 25));
break;
default:
console.log("Usage: npm run agents -- <appraiser [N] | skeptic [N] | scout | all>");
process.exitCode = 2;
}
}
main()
.catch((e) => {
console.error("[agents] ERROR:", e instanceof Error ? e.message : e);
process.exitCode = 1;
})
.finally(async () => {
await prisma.$disconnect();
});