#!/usr/bin/env bun import { createVoiceGoldenCaseProgressLogger, runVoiceGoldenHarness, printVoiceGoldenHarnessReport, VOICE_GOLDEN_MODES } from "../src/voice/voiceGoldenHarness.ts"; import { writeJsonReport } from "./replay/core/output.ts";
type CliArgs = { mode: "simulated" | "live"; modes: string; iterations: number; actorProvider: string; actorModel: string; deciderProvider: string; deciderModel: string; judge: boolean; judgeProvider: string; judgeModel: string; allowMissingCredentials: boolean; maxCases: number; outJsonPath: string; };
const DEFAULT_ARGS: CliArgs = { mode: "simulated", modes: VOICE_GOLDEN_MODES.join(","), iterations: 1, actorProvider: "anthropic", actorModel: "claude-sonnet-4-5", deciderProvider: "anthropic", deciderModel: "claude-haiku-4-5", judge: true, judgeProvider: "anthropic", judgeModel: "claude-haiku-4-5", allowMissingCredentials: false, maxCases: 6, outJsonPath: "" };
function parseArgs(argv: string[]): CliArgs { const out = { ...DEFAULT_ARGS };
for (let index = 0; index < argv.length; index += 1) { const token = String(argv[index] || "").trim(); if (!token.startsWith("--")) continue; const name = token.slice(2); const next = String(argv[index + 1] || "").trim(); const hasValue = next && !next.startsWith("--"); if (hasValue) index += 1;
switch (name) {
case "mode":
out.mode = hasValue && next === "live" ? "live" : "simulated";
break;
case "modes":
if (hasValue) out.modes = next;
break;
case "iterations":
if (hasValue) out.iterations = Math.max(1, Math.floor(Number(next) || 1));
break;
case "actor-provider":
if (hasValue) out.actorProvider = next;
break;
case "actor-model":
if (hasValue) out.actorModel = next;
break;
case "decider-provider":
if (hasValue) out.deciderProvider = next;
break;
case "decider-model":
if (hasValue) out.deciderModel = next;
break;
case "judge":
out.judge = true;
break;
case "no-judge":
out.judge = false;
break;
case "judge-provider":
if (hasValue) out.judgeProvider = next;
break;
case "judge-model":
if (hasValue) out.judgeModel = next;
break;
case "allow-missing-credentials":
out.allowMissingCredentials = true;
break;
case "max-cases":
if (hasValue) out.maxCases = Math.max(1, Math.floor(Number(next) || 6));
break;
case "out-json":
if (hasValue) out.outJsonPath = next;
break;
default:
break;
}
}
return out; }
async function main() { const args = parseArgs(process.argv.slice(2)); const modes = args.modes .split(",") .map((value) => value.trim()) .filter(Boolean);
const report = await runVoiceGoldenHarness({ mode: args.mode, modes: modes as (typeof VOICE_GOLDEN_MODES)[number][], iterations: args.iterations, actorProvider: args.actorProvider, actorModel: args.actorModel, deciderProvider: args.deciderProvider, deciderModel: args.deciderModel, judge: { enabled: args.judge, provider: args.judgeProvider, model: args.judgeModel }, onCaseProgress: createVoiceGoldenCaseProgressLogger(), allowMissingCredentials: args.allowMissingCredentials, maxCases: args.maxCases });
printVoiceGoldenHarnessReport(report);
if (args.outJsonPath) { await writeJsonReport(args.outJsonPath, report); }
if (report.summary.failed > 0) { process.exitCode = 1; } }
main().catch((error) => { console.error("voice golden harness failed:", error); process.exit(1); });
