Something went wrong. Try again.
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576import { parseArgs } from "./args";import { diagnoseAddress, type DiagnoseOptions } from "./diagnose";import { readFileSync, existsSync, writeFileSync } from "node:fs";import { generateReportFile, type ReportIo } from "../report/generate";import { runScriptFile, type RunOptions, type RunOutcome } from "./run";import { serveVerdict, type VerdictOptions } from "./verdictCli";import { openProfile, realLauncherDeps, type ProfileOptions } from "./profileLauncher";import { realRunDeps } from "./run";import { authorOutcome, realAuthorDeps, type AuthorCliOptions } from "./authorCli";import { recordSession, realRecordDeps, type RecordOptions } from "./record";import { realScheduleDeps, scheduleOutcome, type ScheduleCliOptions } from "./scheduleCli";
export interface CliResult { exitCode: number; stdout: string; stderr: string;}
/** The `aite` command, minus process.argv, console and process.exit, so it can be tested. */const realReportIo: ReportIo = { readFile: (p) => readFileSync(p, "utf8"), readBinary: (p) => readFileSync(p), writeFile: (p, t) => writeFileSync(p, t), fileExists: (p) => existsSync(p) };/** Opens the profile for real; Ctrl-C (or a termination signal) closes Chrome and ends it. */export function openRealProfile(options: Omit<ProfileOptions, "signal">): Promise<RunOutcome> { const stop = new AbortController(); const onSignal = () => stop.abort(); process.once("SIGINT", onSignal); process.once("SIGTERM", onSignal); return openProfile({ ...options, signal: stop.signal }, realLauncherDeps(realRunDeps())).finally(() => { process.off("SIGINT", onSignal); process.off("SIGTERM", onSignal); });}
export const reportOutcome = (dir: string, io: ReportIo = realReportIo): RunOutcome => { try { return { exitCode: 0, output: `report: ${generateReportFile(dir.replace(/\/+$/, ""), io)}` }; } catch (err) { return { exitCode: 2, output: `cannot make a report from ${dir}: ${err instanceof Error ? err.message : String(err)}` }; }};
export async function runCli(argv: string[], deps: { run(options: RunOptions): Promise<RunOutcome>; diagnose?(options: DiagnoseOptions): Promise<RunOutcome>; report?(dir: string): RunOutcome; verdict?(options: VerdictOptions): Promise<RunOutcome>; profile?(options: Omit<ProfileOptions, "signal">): Promise<RunOutcome>; schedule?(options: ScheduleCliOptions): Promise<RunOutcome>; record?(options: RecordOptions): Promise<RunOutcome>; author?(options: AuthorCliOptions): Promise<RunOutcome> } = { run: (o) => runScriptFile(o), diagnose: (o) => diagnoseAddress(o), report: (d) => reportOutcome(d), verdict: (o) => serveVerdict(o), profile: (o) => openRealProfile(o), schedule: (o) => scheduleOutcome(o, realScheduleDeps()), record: (o) => recordSession(o, realRecordDeps()), author: (o) => authorOutcome(o, realAuthorDeps()) }): Promise<CliResult> { const parsed = parseArgs(argv); if (parsed.kind === "help") return { exitCode: 0, stdout: parsed.text, stderr: "" }; if (parsed.kind === "error") return { exitCode: 2, stdout: "", stderr: parsed.message }; try { if (parsed.kind === "profile") { const outcome = await (deps.profile ?? ((o) => openRealProfile(o)))(parsed.options); return outcome.exitCode >= 2 ? { exitCode: outcome.exitCode, stdout: "", stderr: outcome.output } : { exitCode: outcome.exitCode, stdout: outcome.output, stderr: "" }; } if (parsed.kind === "author") { const outcome = await (deps.author ?? ((o) => authorOutcome(o, realAuthorDeps())))(parsed.options); return outcome.exitCode >= 2 ? { exitCode: outcome.exitCode, stdout: "", stderr: outcome.output } : { exitCode: outcome.exitCode, stdout: outcome.output, stderr: "" }; } if (parsed.kind === "record") { const outcome = await (deps.record ?? ((o) => recordSession(o, realRecordDeps())))(parsed.options); return outcome.exitCode >= 2 ? { exitCode: outcome.exitCode, stdout: "", stderr: outcome.output } : { exitCode: outcome.exitCode, stdout: outcome.output, stderr: "" }; } if (parsed.kind === "schedule") { const outcome = await (deps.schedule ?? ((o) => scheduleOutcome(o, realScheduleDeps())))(parsed.options); return outcome.exitCode >= 2 ? { exitCode: outcome.exitCode, stdout: "", stderr: outcome.output } : { exitCode: outcome.exitCode, stdout: outcome.output, stderr: "" }; } if (parsed.kind === "verdict") { const outcome = await (deps.verdict ?? ((o) => serveVerdict(o)))(parsed.options); return outcome.exitCode >= 2 ? { exitCode: outcome.exitCode, stdout: "", stderr: outcome.output } : { exitCode: outcome.exitCode, stdout: outcome.output, stderr: "" }; } if (parsed.kind === "report") { const outcome = (deps.report ?? ((d) => reportOutcome(d)))(parsed.dir); return outcome.exitCode >= 2 ? { exitCode: outcome.exitCode, stdout: "", stderr: outcome.output } : { exitCode: 0, stdout: outcome.output, stderr: "" }; } const outcome = parsed.kind === "diagnose" ? await (deps.diagnose ?? ((o) => diagnoseAddress(o)))(parsed.options) : await deps.run(parsed.options); return outcome.exitCode >= 2 ? { exitCode: outcome.exitCode, stdout: "", stderr: outcome.output } : { exitCode: outcome.exitCode, stdout: outcome.output, stderr: "" }; } catch (err) { return { exitCode: 3, stdout: "", stderr: `aite crashed: ${err instanceof Error ? err.message : String(err)}` }; }}