import { Ct as buildEvalKey, Nt as getEvalRegistry, St as resolveLlmCallsConfig, bt as runSummarySchema, c as resolveArtifactPath, ct as applyDerivedCallAttributes, dt as getEvalDisplayStatus, f as resolveEvalDefaultConfig, ft as deriveScopedSummaryFromCases, gt as matchesTagsFilter, h as normalizeScoreDef, m as buildDeclaredColumnDefs, o as stripTerminalControlCodes, p as loadConfig, s as resolveTracePresentation, ut as getEvalTitle, v as createFsCacheStore, wt as getCaseRowCaseKey, xt as resolveApiCallsConfig } from "./runExecution-6lrtj48K.mjs";
import { C as validateCharts, S as parseEvalDiscovery, _ as runTouchesEval, a as validateTagsFilters, b as deriveEvalFreshness, c as getLatestRunInfos, d as nextShortIdFromSnapshots, f as persistCaseDetail, g as recomputePersistedCaseStatus, h as recomputeEvalStatusesInRuns, i as resolveEvalTags, l as loadPersistedRunSnapshot, m as persistRunState, n as getTargetEvalKeys, o as generateRunId, p as deleteTemporaryRuns, s as getLastRunStatuses, u as loadPersistedRunSnapshots, v as buildManualInputDescriptor, x as loadIsolatedEvalRegistry, y as parseManualInputValues } from "./runOrchestration-BYaN2mzS.mjs";
import { copyFile, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
import { createHash, randomUUID } from "node:crypto";
import { watch } from "chokidar";
import { glob } from "glob";
import { existsSync } from "node:fs";
import { resultify } from "t-result";
import { fileURLToPath } from "node:url";
import { spawn, spawnSync } from "node:child_process";
//#region ../runner/src/caseDetailLookup.ts
function getCaseLookupIds(caseId) {
	const decodedResult = resultify(() => decodeURIComponent(caseId));
	const decodedCaseId = decodedResult.error ? caseId : decodedResult.value;
	const lookupIds = new Set([caseId, decodedCaseId]);
	for (const lookupId of [...lookupIds]) {
		const segments = lookupId.split("#");
		if (segments.length < 3) continue;
		lookupIds.add(segments.map((segment) => encodeURIComponent(segment)).join("#"));
	}
	return [...lookupIds];
}
function resolveCaseDetailLookup(run, caseId) {
	const lookupIds = new Set(getCaseLookupIds(caseId));
	for (const lookupId of lookupIds) {
		const caseDetail = run.caseDetails.get(lookupId);
		if (caseDetail) return caseDetail;
	}
	const matchingCaseRow = run.cases.find((caseRow) => lookupIds.has(getCaseRowCaseKey(caseRow)) || lookupIds.has(caseRow.caseId));
	if (matchingCaseRow === void 0) return void 0;
	return run.caseDetails.get(getCaseRowCaseKey(matchingCaseRow));
}
//#endregion
//#region ../runner/src/configReload.ts
/** Coordinates idle-only reloads for `agent-evals.config.ts` in app mode. */
function createConfigReloadController({ getActiveRunCount, closeRunnerWatchers, loadRunnerState, emitToDiscoveryListeners }) {
	let watcher;
	let reloadTimer;
	let reloadPromise;
	let state = {
		status: "idle",
		activeRunCount: 0,
		lastChangedAt: null,
		lastReloadedAt: null
	};
	function currentState() {
		return {
			...state,
			activeRunCount: getActiveRunCount()
		};
	}
	function emitReloadEvent() {
		emitToDiscoveryListeners({
			type: "config.reload",
			timestamp: (/* @__PURE__ */ new Date()).toISOString(),
			payload: currentState()
		});
	}
	function setState(patch) {
		state = {
			...state,
			...patch,
			activeRunCount: getActiveRunCount()
		};
		emitReloadEvent();
	}
	async function close() {
		if (reloadTimer !== void 0) {
			clearTimeout(reloadTimer);
			reloadTimer = void 0;
		}
		const watcherToClose = watcher;
		watcher = void 0;
		if (watcherToClose !== void 0) await watcherToClose.close();
	}
	async function reloadConfigNow(changedAt) {
		setState({
			status: "reloading",
			lastChangedAt: changedAt
		});
		await close();
		await closeRunnerWatchers();
		await loadRunnerState();
		setState({
			status: "idle",
			lastChangedAt: changedAt,
			lastReloadedAt: (/* @__PURE__ */ new Date()).toISOString()
		});
	}
	async function reloadConfig(changedAt) {
		if (reloadPromise !== void 0) {
			setState({
				status: "pending",
				lastChangedAt: changedAt
			});
			await reloadPromise;
			await reloadIfPendingAndIdle();
			return;
		}
		reloadPromise = reloadConfigNow(changedAt);
		try {
			await reloadPromise;
		} finally {
			reloadPromise = void 0;
		}
	}
	async function handleConfigChanged() {
		const changedAt = (/* @__PURE__ */ new Date()).toISOString();
		if (getActiveRunCount() > 0) {
			setState({
				status: "pending",
				lastChangedAt: changedAt
			});
			return;
		}
		await reloadConfig(changedAt);
	}
	async function reloadIfPendingAndIdle() {
		if (state.status !== "pending") return;
		if (getActiveRunCount() > 0) {
			state = currentState();
			return;
		}
		await reloadConfig(state.lastChangedAt ?? (/* @__PURE__ */ new Date()).toISOString());
	}
	async function setupWatcher() {
		const nextWatcher = watch(resolve(process.cwd(), "agent-evals.config.ts"), {
			awaitWriteFinish: {
				stabilityThreshold: 100,
				pollInterval: 20
			},
			ignoreInitial: true,
			persistent: true
		});
		watcher = nextWatcher;
		const scheduleReload = () => {
			if (reloadTimer !== void 0) clearTimeout(reloadTimer);
			reloadTimer = setTimeout(() => {
				reloadTimer = void 0;
				handleConfigChanged();
			}, 50);
		};
		nextWatcher.on("change", scheduleReload);
		nextWatcher.on("add", scheduleReload);
		nextWatcher.on("unlink", scheduleReload);
		await new Promise((ready) => {
			nextWatcher.once("ready", ready);
		});
	}
	return {
		close,
		currentState,
		reloadIfPendingAndIdle,
		setupWatcher
	};
}
//#endregion
//#region ../runner/src/evalSummaries.ts
/** Build the API/UI summary payload for one discovered eval. */
function buildEvalSummary(params) {
	const { meta, config, gitState, latestRun, lastRunStatus } = params;
	const { sourceFingerprint, manualInputDescriptor, requiresManualInput, ...summaryMeta } = meta;
	const freshness = deriveEvalFreshness({
		latestRun,
		gitState,
		currentEvalSourceFingerprint: sourceFingerprint,
		staleAfterDays: config.staleAfterDays ?? 14
	});
	const summary = {
		...summaryMeta,
		stale: freshness.stale,
		outdated: freshness.outdated,
		freshnessStatus: freshness.freshnessStatus,
		latestRunAt: latestRun?.startedAt ?? null,
		latestRunCommitSha: latestRun?.commitSha ?? null,
		currentCommitSha: gitState.commitSha,
		lastRunStatus
	};
	if (manualInputDescriptor && requiresManualInput) summary.manualInput = manualInputDescriptor;
	return summary;
}
/** Write one latest-run snapshot to each targeted eval id. */
function setLatestRunInfoMap(params) {
	const { latestRunInfoMap, evalIds, info } = params;
	for (const evalId of evalIds) latestRunInfoMap.set(evalId, info);
}
//#endregion
//#region ../runner/src/gitState.ts
function runGitCommand(workspaceRoot, args) {
	const result = spawnSync("git", args, {
		cwd: workspaceRoot,
		encoding: "utf8",
		stdio: [
			"ignore",
			"pipe",
			"ignore"
		]
	});
	return {
		status: result.status,
		stdout: result.stdout.trim()
	};
}
/** Read the current git commit for the workspace, if available. */
function readGitWorktreeState(workspaceRoot) {
	const insideWorktree = runGitCommand(workspaceRoot, ["rev-parse", "--is-inside-work-tree"]);
	if (insideWorktree.status !== 0 || insideWorktree.stdout !== "true") return { commitSha: null };
	const commitResult = runGitCommand(workspaceRoot, ["rev-parse", "HEAD"]);
	return { commitSha: commitResult.status === 0 ? commitResult.stdout : null };
}
//#endregion
//#region ../runner/src/manualInput/discovery.ts
/**
* Inspect an eval's `manualInput` config during discovery. Rejects evals that
* declare both `cases` and `manualInput` and evals whose schema cannot be
* walked into a wire descriptor.
*/
function resolveManualInputDiscovery(params) {
	const { evalDef, evalId, relativeFilePath } = params;
	if (!evalDef.manualInput) return { kind: "none" };
	if (evalDef.cases !== void 0) return {
		kind: "issue",
		issue: {
			type: "manual-input-with-cases",
			severity: "error",
			filePath: relativeFilePath,
			evalId,
			message: `Eval "${evalId}" in ${relativeFilePath} declares both "cases" and "manualInput". Remove one of them.`
		}
	};
	const descriptorResult = buildManualInputDescriptor(evalDef.manualInput);
	if (descriptorResult.error) return {
		kind: "issue",
		issue: {
			type: "manual-input-with-cases",
			severity: "error",
			filePath: relativeFilePath,
			evalId,
			message: `Eval "${evalId}" in ${relativeFilePath} has an unsupported manualInput schema: ${descriptorResult.error.message}`
		}
	};
	return {
		kind: "ok",
		requiresManualInput: true,
		descriptor: descriptorResult.value,
		config: evalDef.manualInput
	};
}
//#endregion
//#region ../runner/src/manualInput/files.ts
const stagedUploadDir = ".agent-evals/manual-input-uploads";
const mimeTypeByExtension = {
	".gif": "image/gif",
	".jpeg": "image/jpeg",
	".jpg": "image/jpeg",
	".json": "application/json",
	".md": "text/markdown",
	".pdf": "application/pdf",
	".png": "image/png",
	".svg": "image/svg+xml",
	".txt": "text/plain",
	".webp": "image/webp"
};
function toWorkspaceRelativePath(params) {
	return relative(params.workspaceRoot, params.filePath).replaceAll("\\", "/");
}
function isInsideWorkspace(params) {
	const rel = relative(params.workspaceRoot, params.filePath);
	return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
}
function sanitizeSegment(value) {
	const normalized = value.trim().replaceAll(/[^A-Za-z0-9._-]+/g, "-");
	return normalized.length > 0 ? normalized : "file";
}
function sanitizeFileName(value) {
	const normalized = sanitizeSegment(value);
	const extension = extname(normalized);
	if (extension.length === 0) return normalized;
	return `${normalized.slice(0, -extension.length).replaceAll(".", "-")}${extension}`;
}
function inferMimeType(params) {
	const normalized = params.mimeType?.trim();
	if (normalized && normalized.length > 0) return normalized;
	return mimeTypeByExtension[extname(params.name).toLowerCase()] ?? "";
}
function hashBytes(bytes) {
	return createHash("sha256").update(bytes).digest("hex");
}
function isRecord$1(value) {
	return typeof value === "object" && value !== null && !Array.isArray(value);
}
function isManualInputFileValue(value) {
	if (!isRecord$1(value)) return false;
	return typeof value.name === "string" && typeof value.mimeType === "string" && typeof value.sizeBytes === "number" && typeof value.sha256 === "string" && typeof value.path === "string";
}
function isStagedManualInputPath(path) {
	return path === stagedUploadDir || path.startsWith(`${stagedUploadDir}/`) || path.startsWith(stagedUploadDir + sep);
}
/**
* Persist uploaded manual-input bytes in the workspace staging area and return
* the JSON-safe metadata used by manual-input schemas.
*/
async function stageManualInputFile({ workspaceRoot, bytes, name, mimeType }) {
	const fileName = sanitizeFileName(name || "uploaded-file");
	const sha256 = hashBytes(bytes);
	const dir = resolve(workspaceRoot, stagedUploadDir);
	await mkdir(dir, { recursive: true });
	const targetPath = join(dir, `${Date.now().toString(36)}-${randomUUID()}__${sha256.slice(0, 12)}__${fileName}`);
	await writeFile(targetPath, bytes);
	return {
		name: name || fileName,
		mimeType: inferMimeType({
			mimeType,
			name: fileName
		}),
		sizeBytes: bytes.byteLength,
		sha256,
		path: toWorkspaceRelativePath({
			workspaceRoot,
			filePath: targetPath
		})
	};
}
/**
* Read a file path supplied by the CLI and stage it as a manual-input file.
*/
async function stageManualInputFileFromPath({ workspaceRoot, path, name, mimeType }) {
	const sourcePath = isAbsolute(path) ? resolve(path) : resolve(workspaceRoot, path);
	return await stageManualInputFile({
		workspaceRoot,
		bytes: new Uint8Array(await readFile(sourcePath)),
		name: name ?? basename(sourcePath),
		mimeType: inferMimeType({
			mimeType,
			name: name ?? basename(sourcePath)
		})
	});
}
async function materializeOneManualInputFile(params) {
	const sourcePath = resolve(params.workspaceRoot, params.value.path);
	if (!isInsideWorkspace({
		workspaceRoot: params.workspaceRoot,
		filePath: sourcePath
	})) throw new Error(`Manual input file path escapes workspace: ${params.value.path}`);
	const bytes = new Uint8Array(await readFile(sourcePath));
	const sha256 = hashBytes(bytes);
	const fileName = sanitizeFileName(params.value.name || basename(sourcePath));
	const artifactId = [
		sanitizeSegment(params.runId),
		"manual-input",
		sha256.slice(0, 12),
		fileName
	].join("__");
	const targetPath = join(params.runDir, "artifacts", artifactId);
	await mkdir(join(params.runDir, "artifacts"), { recursive: true });
	if (sourcePath !== targetPath) await copyFile(sourcePath, targetPath);
	if (isStagedManualInputPath(params.value.path)) await resultify(() => rm(sourcePath, { force: true }));
	return {
		name: params.value.name,
		mimeType: inferMimeType({
			mimeType: params.value.mimeType,
			name: params.value.name || fileName
		}),
		sizeBytes: bytes.byteLength,
		sha256,
		path: toWorkspaceRelativePath({
			workspaceRoot: params.workspaceRoot,
			filePath: targetPath
		})
	};
}
async function materializeUnknownValue(params) {
	if (isManualInputFileValue(params.value)) return await materializeOneManualInputFile({
		workspaceRoot: params.workspaceRoot,
		runId: params.runId,
		runDir: params.runDir,
		value: params.value
	});
	if (Array.isArray(params.value)) return await Promise.all(params.value.map(async (entry) => await materializeUnknownValue({
		workspaceRoot: params.workspaceRoot,
		runId: params.runId,
		runDir: params.runDir,
		value: entry
	})));
	if (isRecord$1(params.value)) {
		const entries = await Promise.all(Object.entries(params.value).map(async ([key, child]) => {
			return [key, await materializeUnknownValue({
				workspaceRoot: params.workspaceRoot,
				runId: params.runId,
				runDir: params.runDir,
				value: child
			})];
		}));
		return Object.fromEntries(entries);
	}
	return params.value;
}
/**
* Copy all manual-input file references inside a run request into the run's
* artifact directory and return a request-safe value with artifact paths.
*/
async function materializeManualInputFiles({ workspaceRoot, runId, runDir, value }) {
	const result = await resultify(() => materializeUnknownValue({
		workspaceRoot,
		runId,
		runDir,
		value
	}));
	if (result.error) return {
		error: result.error.message,
		value: null
	};
	return {
		error: null,
		value: result.value
	};
}
/** Remove stale staged manual-input uploads from previous abandoned runs. */
async function cleanupStagedManualInputFiles(workspaceRoot) {
	await resultify(() => rm(resolve(workspaceRoot, stagedUploadDir), {
		force: true,
		recursive: true
	}));
}
//#endregion
//#region ../runner/src/manualInput/validation.ts
function evalIsTargeted(evalMeta, target) {
	if (target.evalKeys && target.evalKeys.length > 0) {
		if (!target.evalKeys.includes(evalMeta.key)) return false;
	}
	if (target.evalIds && target.evalIds.length > 0) {
		if (!target.evalIds.includes(evalMeta.id)) return false;
	}
	if (target.tagsFilter && target.tagsFilter.length > 0 && !matchesTagsFilter({
		tags: evalMeta.tags,
		filters: target.tagsFilter
	})) return false;
	return true;
}
/**
* Validate the `manualInputs` map carried by a `CreateRunRequest` against the
* authored Zod schemas of every targeted eval that requires manual input.
*
* Pure: takes captured discovery state (eval metas + schema configs) and the
* request, returns a structured result the server/CLI can format directly.
*/
function validateManualInputsForRequest(params) {
	const { evalMetas, manualInputConfigs, request } = params;
	const failures = [];
	const parsed = {};
	for (const evalMeta of evalMetas) {
		if (!evalMeta.requiresManualInput) continue;
		if (!evalIsTargeted(evalMeta, request.target)) continue;
		const rawValue = request.manualInputs?.[evalMeta.key];
		if (rawValue === void 0) {
			failures.push({
				evalKey: evalMeta.key,
				evalId: evalMeta.id,
				reason: "missing",
				issues: [{
					path: "",
					message: `manualInputs is missing an entry for "${evalMeta.key}"`
				}]
			});
			continue;
		}
		const config = manualInputConfigs.get(evalMeta.key);
		if (!config) {
			failures.push({
				evalKey: evalMeta.key,
				evalId: evalMeta.id,
				reason: "invalid",
				issues: [{
					path: "",
					message: "manualInput schema is unavailable; reload the workspace and try again"
				}]
			});
			continue;
		}
		const result = parseManualInputValues(config, rawValue);
		if (result.error) {
			failures.push({
				evalKey: evalMeta.key,
				evalId: evalMeta.id,
				reason: "invalid",
				issues: result.error.issues
			});
			continue;
		}
		parsed[evalMeta.key] = result.value;
	}
	if (failures.length > 0) return {
		ok: false,
		failures
	};
	return {
		ok: true,
		parsed
	};
}
//#endregion
//#region ../runner/src/objectUtils.ts
function isRecord(value) {
	return typeof value === "object" && value !== null && !Array.isArray(value);
}
//#endregion
//#region ../runner/src/recalculateDerivedAttributes.ts
function getCaseArtifactFileIdForExistingRun(runState, caseRow) {
	const caseKey = getCaseRowCaseKey(caseRow);
	return runState.cases.some((existing) => existing.caseId === caseRow.caseId && getCaseRowCaseKey(existing) !== caseKey) ? caseKey : caseRow.caseId;
}
async function recalculateDerivedAttributesForCase(params) {
	const { run, caseId } = params;
	if (run.manifest.status === "running") return {
		updated: false,
		reason: "Run is still running"
	};
	const caseRow = run.cases.find((row) => getCaseRowCaseKey(row) === caseId || row.caseId === caseId);
	if (!caseRow) return {
		updated: false,
		reason: "Case not found"
	};
	const caseKey = getCaseRowCaseKey(caseRow);
	const caseDetail = run.caseDetails.get(caseKey);
	if (!caseDetail) return {
		updated: false,
		reason: "Case detail not found"
	};
	const spansWithDerivedAttributes = applyDerivedCallAttributes({
		spans: caseDetail.trace,
		llmCallsConfig: params.llmCallsConfig,
		apiCallsConfig: params.apiCallsConfig
	});
	let nextTrace = spansWithDerivedAttributes;
	let nextTraceDisplay = caseDetail.traceDisplay;
	const evalMeta = caseRow.evalKey === void 0 ? void 0 : params.evals.get(caseRow.evalKey);
	const entry = evalMeta === void 0 ? void 0 : getEvalRegistry().get(evalMeta.id);
	if (entry !== void 0) entry.use((evalDef) => {
		const resolved = resolveTracePresentation(spansWithDerivedAttributes, params.traceDisplayConfig, evalDef.traceDisplay);
		nextTrace = resolved.trace;
		nextTraceDisplay = resolved.traceDisplay;
	});
	const nextCaseDetail = {
		...caseDetail,
		trace: nextTrace,
		traceDisplay: nextTraceDisplay
	};
	run.caseDetails.set(caseKey, nextCaseDetail);
	const artifactFileId = getCaseArtifactFileIdForExistingRun(run, caseRow);
	await writeFile(join(run.runDir, "traces", `${encodeURIComponent(artifactFileId)}.json`), JSON.stringify(nextCaseDetail.trace, null, 2));
	await params.persistCaseDetail(run.runDir, nextCaseDetail, artifactFileId);
	return {
		updated: true,
		caseDetail: nextCaseDetail
	};
}
//#endregion
//#region ../runner/src/runChildProtocol.ts
function isRunChildMessage(value) {
	if (typeof value !== "object" || value === null) return false;
	if (!("type" in value) || typeof value.type !== "string") return false;
	if (value.type === "event") return "event" in value;
	if (value.type === "case.finished") return "caseDetail" in value && "caseRow" in value;
	return value.type === "done" && "evals" in value;
}
//#endregion
//#region ../runner/src/runChildManager.ts
const runChildInspectArgEnv = "AGENT_EVALS_RUN_CHILD_INSPECT_ARG";
const moduleMocksFlag = "--experimental-test-module-mocks";
const inspectFlagPrefix = "--inspect";
const inspectBrkFlagPrefix = "--inspect-brk";
const childOutputTailMaxLength = 12e3;
const outputHeadlineMaxLength = 240;
function startRunChild(params) {
	const child = spawn(process.execPath, [
		...getRunChildExecArgv(),
		resolveRunChildEntrypoint(),
		params.contextPath
	], {
		cwd: params.managerContext.workspaceRoot,
		env: process.env,
		stdio: [
			"ignore",
			"pipe",
			"pipe",
			"ipc"
		]
	});
	const outputTail = createRunChildOutputTail(child);
	params.runState.childProcess = child;
	child.once("error", (error) => {
		if (params.runState.childProcess === child) params.runState.childProcess = void 0;
		if (params.runState.manifest.status !== "running" || params.runState.childTerminalReceived) return;
		markRunErrored(params.runState, `Failed to start run child: ${error.message}`, params.managerContext);
	});
	child.on("message", (message) => {
		if (!isRunChildMessage(message)) return;
		handleRunChildMessage({
			runState: params.runState,
			message,
			managerContext: params.managerContext
		});
	});
	child.once("close", (code, signal) => {
		if (params.runState.childProcess === child) params.runState.childProcess = void 0;
		if (params.runState.manifest.status !== "running" || params.runState.childTerminalReceived) return;
		const reason = formatChildExitReason(code, signal);
		markRunErrored(params.runState, formatUnexpectedRunChildExit(reason, outputTail), params.managerContext);
	});
}
function createRunChildOutputTail(child) {
	const tail = {
		stdout: "",
		stderr: "",
		stdoutTruncated: false,
		stderrTruncated: false
	};
	child.stdout?.on("data", (chunk) => {
		process.stdout.write(chunk);
		const nextTail = appendOutputTail(tail.stdout, chunkToText(chunk));
		tail.stdout = nextTail.text;
		tail.stdoutTruncated = tail.stdoutTruncated || nextTail.truncated;
	});
	child.stderr?.on("data", (chunk) => {
		process.stderr.write(chunk);
		const nextTail = appendOutputTail(tail.stderr, chunkToText(chunk));
		tail.stderr = nextTail.text;
		tail.stderrTruncated = tail.stderrTruncated || nextTail.truncated;
	});
	return tail;
}
function chunkToText(chunk) {
	return typeof chunk === "string" ? chunk : chunk.toString("utf-8");
}
function appendOutputTail(current, next) {
	const combined = current + next;
	if (combined.length <= childOutputTailMaxLength) return {
		text: combined,
		truncated: false
	};
	return {
		text: combined.slice(combined.length - childOutputTailMaxLength),
		truncated: true
	};
}
function formatUnexpectedRunChildExit(reason, outputTail) {
	const stderr = stripTerminalControlCodes(outputTail.stderr).trim();
	const stdout = stripTerminalControlCodes(outputTail.stdout).trim();
	const headline = getChildStderrHeadline(stderr);
	const sections = [headline === null ? `${reason} before sending a structured run error.` : `Run child exited before sending a structured run error: ${headline}`, reason];
	if (stderr.length > 0) sections.push(formatOutputSection("stderr", stderr, outputTail.stderrTruncated));
	if (stdout.length > 0) sections.push(formatOutputSection("stdout", stdout, outputTail.stdoutTruncated));
	return sections.join("\n\n");
}
function formatChildExitReason(code, signal) {
	if (signal !== null) return `Run child exited with signal ${signal}`;
	return `Run child exited with code ${String(code)}`;
}
function getChildStderrHeadline(stderr) {
	const line = stderr.split("\n").map((entry) => entry.trim()).find((entry) => entry.length > 0);
	if (line === void 0) return null;
	if (line.length <= outputHeadlineMaxLength) return line;
	return `${line.slice(0, outputHeadlineMaxLength)}...`;
}
function formatOutputSection(streamName, output, truncated) {
	return `${truncated ? `Child ${streamName} (last ${String(output.length)} chars)` : `Child ${streamName}`}:\n${output}`;
}
function getRunChildExecArgv() {
	const execArgv = [moduleMocksFlag];
	let skipNext = false;
	for (const arg of process.execArgv) {
		if (skipNext) {
			skipNext = false;
			continue;
		}
		if (arg === "--eval" || arg === "-e" || arg === "--print" || arg === "-p") {
			skipNext = true;
			continue;
		}
		if (arg.startsWith("--eval=") || arg.startsWith("--print=")) continue;
		if (arg === "--input-type" || arg.startsWith("--input-type=")) {
			if (arg === "--input-type") skipNext = true;
			continue;
		}
		if (arg === moduleMocksFlag) continue;
		if (isInspectArg(arg)) continue;
		execArgv.push(arg);
	}
	const inspectArg = process.env[runChildInspectArgEnv];
	if (inspectArg !== void 0 && isInspectArg(inspectArg)) execArgv.push(inspectArg);
	return execArgv;
}
function isInspectArg(arg) {
	return arg === inspectFlagPrefix || arg.startsWith(`${inspectFlagPrefix}=`) || arg === inspectBrkFlagPrefix || arg.startsWith(`${inspectBrkFlagPrefix}=`);
}
function killRunChild(runState) {
	const child = runState.childProcess;
	runState.childProcess = void 0;
	if (child === void 0 || child.killed) return;
	if (!child.kill("SIGKILL")) child.kill();
}
function resolveRunChildEntrypoint() {
	const currentDir = dirname(fileURLToPath(import.meta.url));
	for (const fileName of [
		"runChild.ts",
		"runChild.mjs",
		"runChild.js"
	]) {
		const candidate = join(currentDir, fileName);
		if (existsSync(candidate)) return candidate;
	}
	throw new Error("Unable to locate the Agent Evals run child entrypoint.");
}
function handleRunChildMessage(params) {
	const { runState, message, managerContext } = params;
	if (message.type === "case.finished") {
		if (runState.manifest.status !== "running") return;
		upsertFinishedCase(runState, message.caseDetail, message.caseRow);
		managerContext.emitEvent(runState, {
			type: "case.finished",
			runId: runState.manifest.id,
			timestamp: (/* @__PURE__ */ new Date()).toISOString(),
			payload: message.caseRow
		});
		return;
	}
	if (message.type === "done") {
		applyChildEvalMetas(managerContext.evals, message.evals);
		managerContext.emitDiscoveryEvent();
		return;
	}
	handleRunChildEvent(runState, message.event, managerContext);
}
function upsertFinishedCase(runState, caseDetail, caseRow) {
	const existingIndex = runState.cases.findIndex((row) => getCaseRowCaseKey(row) === getCaseRowCaseKey(caseRow) && row.trial === caseRow.trial);
	if (existingIndex === -1) runState.cases.push(caseRow);
	else runState.cases[existingIndex] = caseRow;
	runState.caseDetails.set(caseDetail.caseKey ?? caseDetail.caseId, caseDetail);
}
function applyChildEvalMetas(evals, childMetas) {
	for (const childMeta of childMetas) {
		const evalMeta = evals.get(childMeta.key);
		if (evalMeta === void 0) {
			evals.set(childMeta.key, childMeta);
			continue;
		}
		evalMeta.columnDefs = childMeta.columnDefs;
		evalMeta.tags = childMeta.tags;
		evalMeta.caseCount = childMeta.caseCount;
		evalMeta.caseIds = childMeta.caseIds;
		evalMeta.stats = childMeta.stats;
		evalMeta.defaultStatAggregate = childMeta.defaultStatAggregate;
		evalMeta.charts = childMeta.charts;
		evalMeta.sourceFingerprint = childMeta.sourceFingerprint;
	}
}
function handleRunChildEvent(runState, event, managerContext) {
	if (runState.manifest.status !== "running") return;
	if (event.type === "run.summary") {
		const parsed = runSummarySchema.safeParse(event.payload);
		if (parsed.success) runState.summary = parsed.data;
		managerContext.emitEvent(runState, event);
		return;
	}
	if (event.type === "run.finished") {
		runState.childTerminalReceived = true;
		runState.childProcess = void 0;
		markRunTerminalFromChild(runState, event, managerContext);
		return;
	}
	if (event.type === "run.error") {
		runState.childTerminalReceived = true;
		runState.childProcess = void 0;
		markRunTerminalFromChild(runState, event, managerContext);
		return;
	}
	managerContext.emitEvent(runState, event);
}
function getRunErrorMessage(payload) {
	if (typeof payload === "object" && payload !== null && "message" in payload && typeof payload.message === "string") return payload.message;
	return "Run child ended with an error";
}
async function markRunErrored(runState, message, managerContext) {
	runState.manifest.status = "error";
	runState.manifest.endedAt = (/* @__PURE__ */ new Date()).toISOString();
	runState.summary.status = "error";
	runState.summary.errorMessage = message;
	await persistRunState(runState);
	managerContext.emitEvent(runState, {
		type: "run.error",
		runId: runState.manifest.id,
		timestamp: (/* @__PURE__ */ new Date()).toISOString(),
		payload: { message }
	});
	managerContext.emitDiscoveryEvent();
	managerContext.onRunTerminal();
}
async function markRunTerminalFromChild(runState, event, managerContext) {
	const snapshot = await loadPersistedRunSnapshot(runState.runDir);
	if (snapshot !== null) {
		runState.manifest = snapshot.manifest;
		runState.summary = snapshot.summary;
		runState.cases = snapshot.cases;
		runState.caseDetails = snapshot.caseDetails;
	} else if (event.type === "run.finished") {
		runState.manifest.status = "completed";
		runState.manifest.endedAt = (/* @__PURE__ */ new Date()).toISOString();
		const parsed = runSummarySchema.safeParse(event.payload);
		if (parsed.success) runState.summary = parsed.data;
	} else {
		runState.manifest.status = "error";
		runState.manifest.endedAt = (/* @__PURE__ */ new Date()).toISOString();
		runState.summary.status = "error";
		runState.summary.errorMessage = getRunErrorMessage(event.payload);
	}
	managerContext.emitEvent(runState, event);
	managerContext.emitDiscoveryEvent();
	managerContext.onRunTerminal();
}
//#endregion
//#region ../runner/src/runnerStateHydration.ts
/** Rehydrate a persisted run while preserving live listeners/process handles. */
function toRunnerRunState(snapshot, existing) {
	return {
		...snapshot,
		listeners: existing?.listeners ?? /* @__PURE__ */ new Set(),
		childProcess: existing?.childProcess,
		childTerminalReceived: existing?.childTerminalReceived ?? false
	};
}
//#endregion
//#region ../runner/src/runTargetPersistence.ts
/** Build the exact-key run target persisted in run history. */
function buildPersistedRunTarget(params) {
	const { target, evalKeys } = params;
	if (target.mode === "all") return { mode: "all" };
	const persistEvalKeys = (target.evalKeys?.length ?? 0) > 0 || (target.evalIds?.length ?? 0) > 0 || (target.files?.length ?? 0) > 0;
	const keyedTarget = {
		mode: target.mode,
		evalKeys: persistEvalKeys && evalKeys.length > 0 ? evalKeys : void 0,
		files: target.files,
		tagsFilter: target.tagsFilter
	};
	if (target.mode === "caseIds") return {
		...keyedTarget,
		caseIds: target.caseIds
	};
	return keyedTarget;
}
//#endregion
//#region ../runner/src/watchRoots.ts
const globMagicCharacters = new Set([
	"*",
	"?",
	"[",
	"]",
	"{",
	"}",
	"(",
	")",
	"!",
	"+",
	"@"
]);
function hasGlobMagic(value) {
	for (const char of value) if (globMagicCharacters.has(char)) return true;
	return false;
}
function getWatchRootForIncludePattern(params) {
	const segments = params.pattern.replaceAll("\\", "/").split("/").filter((part) => part !== "");
	const firstGlobSegmentIndex = segments.findIndex(hasGlobMagic);
	if (firstGlobSegmentIndex === -1) return dirname(resolve(params.workspaceRoot, params.pattern));
	if (firstGlobSegmentIndex === 0) return params.workspaceRoot;
	return resolve(params.workspaceRoot, segments.slice(0, firstGlobSegmentIndex).join("/"));
}
function getWatchRootsForIncludePatterns(params) {
	const roots = /* @__PURE__ */ new Set();
	for (const pattern of params.patterns) roots.add(getWatchRootForIncludePattern({
		pattern,
		workspaceRoot: params.workspaceRoot
	}));
	if (roots.size === 0) return [params.workspaceRoot];
	return [...roots];
}
//#endregion
//#region ../runner/src/runner.ts
const defaultCachePruneIdleDelayMs = 5e3;
/** Create an in-memory eval runner bound to the current workspace config. */
function createRunner({ watchForChanges = true } = {}) {
	let config;
	let workspaceRoot;
	let localStateDir;
	let cacheStore;
	let llmCallsConfig = resolveLlmCallsConfig(void 0);
	let apiCallsConfig = resolveApiCallsConfig(void 0);
	const evals = /* @__PURE__ */ new Map();
	const manualInputConfigs = /* @__PURE__ */ new Map();
	let discoveryIssues = [];
	const runs = /* @__PURE__ */ new Map();
	const lastRunStatusMap = /* @__PURE__ */ new Map();
	const latestRunInfoMap = /* @__PURE__ */ new Map();
	const discoveryListeners = /* @__PURE__ */ new Set();
	let nextShortIdNum = 0;
	let discoveryWatcher;
	let runHistoryWatcher;
	let discoveryRefreshTimer;
	let runHistoryRefreshTimer;
	let cachePruneIdleTimer;
	let registryLoadCounter = 0;
	const configReload = createConfigReloadController({
		getActiveRunCount,
		closeRunnerWatchers: closeWatchers,
		loadRunnerState,
		emitToDiscoveryListeners
	});
	function toWorkspaceRelativePath(filePath) {
		return relative(workspaceRoot, filePath).replaceAll("\\", "/");
	}
	function getSortedEvalMetas() {
		return [...evals.values()].toSorted((a, b) => a.filePath.localeCompare(b.filePath) || a.id.localeCompare(b.id));
	}
	function resolveEvalMeta(evalRef) {
		const exactMatch = evals.get(evalRef);
		if (exactMatch !== void 0) return exactMatch;
		const matches = getSortedEvalMetas().filter((ev) => ev.id === evalRef);
		return matches.length === 1 ? matches[0] : void 0;
	}
	function getSourceFingerprint(source) {
		return createHash("sha256").update(source).digest("hex");
	}
	function nextRegistryLoadIsolationKey(prefix, filePath) {
		registryLoadCounter++;
		return `${prefix}:${String(registryLoadCounter)}:${filePath}`;
	}
	const runner = {
		async init() {
			await loadRunnerState();
		},
		async listCache() {
			return cacheStore.list();
		},
		async getCacheEntry(namespace, key) {
			return cacheStore.lookupWithDebug(namespace, key);
		},
		async clearCache(filter) {
			await cacheStore.clear(filter);
		},
		async repairCache() {
			return cacheStore.repair();
		},
		async recomputeStatusesForEval(evalKey) {
			const evalMeta = resolveEvalMeta(evalKey);
			if (!evalMeta) return { updatedRuns: 0 };
			const entry = (await loadIsolatedEvalRegistry({
				evalFilePath: evalMeta.sourceFilePath,
				sourceFingerprint: evalMeta.sourceFingerprint ?? void 0,
				moduleIsolation: {
					key: nextRegistryLoadIsolationKey("recompute-status", evalMeta.sourceFilePath),
					workspaceRoot
				},
				runtimeScope: "env"
			})).get(evalMeta.id);
			if (!entry) return { updatedRuns: 0 };
			const scoreThresholds = /* @__PURE__ */ new Map();
			entry.use((evalDef) => {
				for (const [key, def] of Object.entries(evalDef.scores ?? {})) {
					const threshold = normalizeScoreDef(def).passThreshold;
					if (threshold !== void 0) scoreThresholds.set(key, threshold);
				}
				for (const [key, def] of Object.entries(evalDef.manualScores ?? {})) if (def.passThreshold !== void 0) scoreThresholds.set(key, def.passThreshold);
			});
			const updatedRuns = await recomputeEvalStatusesInRuns({
				runs: runs.values(),
				evalKey: evalMeta.key,
				evalExists: evals.has(evalMeta.key),
				scoreThresholds,
				persistCaseDetail
			});
			emitDiscoveryEvent();
			return { updatedRuns };
		},
		async recalculateDerivedAttributesForCase({ runId, caseId }) {
			const run = runs.get(runId);
			if (!run) return {
				updated: false,
				reason: "Run not found"
			};
			return recalculateDerivedAttributesForCase({
				run,
				caseId,
				llmCallsConfig,
				apiCallsConfig,
				traceDisplayConfig: config.traceDisplay,
				evals,
				persistCaseDetail
			});
		},
		async cleanRunsForEval(evalKey) {
			const evalMeta = resolveEvalMeta(evalKey);
			let deletedRuns = 0;
			for (const [runId, run] of [...runs]) {
				if (!runTouchesEval({
					target: run.manifest.target,
					caseRows: run.cases,
					evalKey: evalMeta?.key ?? evalKey,
					evalExists: evalMeta !== void 0
				})) continue;
				if (run.manifest.status === "running") continue;
				runs.delete(runId);
				await rm(run.runDir, {
					recursive: true,
					force: true
				});
				deletedRuns += 1;
			}
			emitDiscoveryEvent();
			return { deletedRuns };
		},
		async updateManualScore({ runId, caseId, scoreKey, value }) {
			const run = runs.get(runId);
			if (!run) return {
				updated: false,
				reason: "Run not found"
			};
			if (run.manifest.status === "running") return {
				updated: false,
				reason: "Run is still running"
			};
			const caseRow = run.cases.find((row) => getCaseRowCaseKey(row) === caseId || row.caseId === caseId);
			if (!caseRow) return {
				updated: false,
				reason: "Case not found"
			};
			const evalMeta = caseRow.evalKey === void 0 ? void 0 : evals.get(caseRow.evalKey);
			if (!evalMeta) return {
				updated: false,
				reason: "Eval not found"
			};
			if (evalMeta.columnDefs.find((def) => def.key === scoreKey)?.isManualScore !== true) return {
				updated: false,
				reason: "Manual score not found"
			};
			const caseDetail = run.caseDetails.get(getCaseRowCaseKey(caseRow));
			if (!caseDetail) return {
				updated: false,
				reason: "Case detail not found"
			};
			caseRow.columns[scoreKey] = value;
			caseDetail.columns[scoreKey] = value;
			const scoreThresholds = /* @__PURE__ */ new Map();
			for (const def of evalMeta.columnDefs) {
				if (def.isScore !== true || def.passThreshold === void 0) continue;
				scoreThresholds.set(def.key, def.passThreshold);
			}
			const nextStatus = recomputePersistedCaseStatus(caseRow, caseDetail, scoreThresholds);
			caseRow.status = nextStatus;
			caseDetail.status = nextStatus;
			const derivedSummary = deriveScopedSummaryFromCases({ caseRows: run.cases });
			run.summary.totalCases = derivedSummary.totalCases;
			run.summary.passedCases = derivedSummary.passedCases;
			run.summary.failedCases = derivedSummary.failedCases;
			run.summary.errorCases = derivedSummary.errorCases;
			run.summary.cancelledCases = derivedSummary.cancelledCases;
			run.summary.totalDurationMs = derivedSummary.totalDurationMs;
			await persistCaseDetail(run.runDir, caseDetail);
			await persistRunState(run);
			emitDiscoveryEvent();
			return {
				updated: true,
				run: {
					manifest: run.manifest,
					summary: run.summary,
					cases: run.cases
				},
				caseDetail
			};
		},
		async deleteRun(runId) {
			const run = runs.get(runId);
			if (!run) return { deleted: false };
			if (run.manifest.status === "running") return { deleted: false };
			runs.delete(runId);
			await rm(run.runDir, {
				recursive: true,
				force: true
			});
			emitDiscoveryEvent();
			return { deleted: true };
		},
		async promoteRun(runId) {
			const run = runs.get(runId);
			if (!run) return { promoted: false };
			const wasTemporary = run.manifest.temporary === true;
			if (wasTemporary) {
				run.manifest.temporary = false;
				await persistRunState(run);
				emitDiscoveryEvent();
			}
			return {
				promoted: wasTemporary,
				run: {
					manifest: run.manifest,
					summary: run.summary,
					cases: run.cases
				}
			};
		},
		validateManualInputs(request) {
			return validateManualInputsForRequest({
				evalMetas: getSortedEvalMetas(),
				manualInputConfigs,
				request
			});
		},
		getEvals() {
			const gitState = readGitWorktreeState(workspaceRoot);
			const result = [];
			for (const meta of getSortedEvalMetas()) result.push(buildEvalSummary({
				meta,
				config,
				gitState,
				latestRun: latestRunInfoMap.get(meta.key),
				lastRunStatus: lastRunStatusMap.get(meta.key) ?? null
			}));
			return result;
		},
		getEval(id) {
			const meta = resolveEvalMeta(id);
			if (!meta) return void 0;
			return buildEvalSummary({
				meta,
				config,
				gitState: readGitWorktreeState(workspaceRoot),
				latestRun: latestRunInfoMap.get(meta.key),
				lastRunStatus: lastRunStatusMap.get(meta.key) ?? null
			});
		},
		getDiscoveryIssues() {
			return discoveryIssues;
		},
		getConfigReloadState() {
			return configReload.currentState();
		},
		async refreshDiscovery() {
			const patterns = config.include;
			const discovered = [];
			for (const pattern of patterns) {
				const files = await glob(pattern, {
					cwd: workspaceRoot,
					absolute: true
				});
				discovered.push(...files);
			}
			evals.clear();
			manualInputConfigs.clear();
			discoveryIssues = [];
			for (const filePath of discovered) try {
				const content = await readFile(filePath, "utf-8");
				const discovery = parseEvalDiscovery(filePath, content);
				const discoveredMetas = discovery.metas;
				discoveryIssues.push(...discovery.issues.map((issue) => ({
					...issue,
					filePath: toWorkspaceRelativePath(issue.filePath),
					message: `Duplicate eval id "${issue.evalId}" in ${toWorkspaceRelativePath(issue.filePath)}. Eval ids must be unique within one file.`
				})));
				const sourceFingerprint = getSourceFingerprint(content);
				let loadedRegistry;
				try {
					loadedRegistry = await loadIsolatedEvalRegistry({
						evalFilePath: filePath,
						sourceFingerprint,
						moduleIsolation: {
							key: nextRegistryLoadIsolationKey("discovery", filePath),
							workspaceRoot
						},
						runtimeScope: "env"
					});
				} catch {}
				for (const meta of discoveredMetas) {
					const discoveredEntry = loadedRegistry?.get(meta.id);
					const title = meta.title;
					let columnDefs = buildDeclaredColumnDefs(void 0, void 0, void 0);
					let stats;
					let defaultStatAggregate;
					let charts;
					let tags = [];
					let manualInputDescriptor;
					let requiresManualInput = false;
					const relativeFilePath = toWorkspaceRelativePath(meta.filePath);
					discoveredEntry?.use((evalDef) => {
						const tagResult = resolveEvalTags({
							configTags: config.tags,
							evalDef,
							evalId: meta.id,
							filePath: relativeFilePath
						});
						tags = tagResult.tags;
						discoveryIssues.push(...tagResult.issues);
						const defaultConfig = resolveEvalDefaultConfig({
							evalDef,
							globalColumns: config.columns,
							globalStats: config.stats,
							globalDefaultStatAggregate: config.defaultStatAggregate,
							globalRemove: config.removeDefaultConfig
						});
						columnDefs = buildDeclaredColumnDefs(defaultConfig.columns, evalDef.scores, evalDef.manualScores);
						stats = defaultConfig.stats;
						defaultStatAggregate = defaultConfig.defaultStatAggregate;
						const validated = validateCharts({
							charts: defaultConfig.charts,
							columnDefs,
							evalId: meta.id
						});
						for (const warning of validated.warnings) console.warn(warning);
						charts = validated.charts;
						const manualInputResult = resolveManualInputDiscovery({
							evalDef,
							evalId: meta.id,
							relativeFilePath
						});
						if (manualInputResult.kind === "issue") {
							discoveryIssues.push(manualInputResult.issue);
							requiresManualInput = true;
							return;
						}
						if (manualInputResult.kind === "ok") {
							requiresManualInput = manualInputResult.requiresManualInput;
							manualInputDescriptor = manualInputResult.descriptor;
							manualInputConfigs.set(buildEvalKey({
								filePath: relativeFilePath,
								evalId: meta.id
							}), manualInputResult.config);
						}
					});
					const key = buildEvalKey({
						filePath: relativeFilePath,
						evalId: meta.id
					});
					evals.set(key, {
						key,
						id: meta.id,
						title,
						filePath: relativeFilePath,
						tags,
						sourceFilePath: meta.filePath,
						sourceFingerprint,
						columnDefs,
						caseCount: null,
						caseIds: void 0,
						stats,
						defaultStatAggregate,
						charts,
						manualInputDescriptor,
						requiresManualInput
					});
				}
			} catch {}
			emitDiscoveryEvent();
		},
		async startRun(request) {
			cancelCacheRetentionPrune();
			const tagsFilterError = validateTagsFilters(request.target.tagsFilter);
			if (tagsFilterError !== null) throw new Error(tagsFilterError);
			const deletedTemporaryRuns = await deleteTemporaryRuns({
				runs,
				cancelRunningRun: killRunChild
			});
			const runId = generateRunId();
			const shortId = `r${String(nextShortIdNum++)}`;
			const now = (/* @__PURE__ */ new Date()).toISOString();
			const cacheMode = request.cache?.mode ?? "use";
			const runDir = join(localStateDir, "runs", runId);
			const gitState = readGitWorktreeState(workspaceRoot);
			const targetEvalKeys = getTargetEvalKeys({
				request,
				sortedEvals: getSortedEvalMetas()
			});
			const manifest = {
				id: runId,
				shortId,
				status: "running",
				temporary: request.temporary === true,
				startedAt: now,
				endedAt: null,
				commitSha: gitState.commitSha,
				evalSourceFingerprints: {},
				target: buildPersistedRunTarget({
					target: request.target,
					evalKeys: targetEvalKeys
				}),
				trials: request.trials,
				trialSelection: config.trialSelection ?? "lowestScore",
				cacheMode
			};
			const summary = {
				runId,
				status: "running",
				totalCases: 0,
				passedCases: 0,
				failedCases: 0,
				errorCases: 0,
				cancelledCases: 0,
				totalDurationMs: null,
				errorMessage: null
			};
			const runState = {
				runDir,
				manifest,
				summary,
				cases: [],
				caseDetails: /* @__PURE__ */ new Map(),
				listeners: /* @__PURE__ */ new Set(),
				childProcess: void 0,
				childTerminalReceived: false
			};
			await mkdir(runDir, { recursive: true });
			await mkdir(join(runDir, "traces"), { recursive: true });
			await mkdir(join(runDir, "artifacts"), { recursive: true });
			await mkdir(join(runDir, "case-details"), { recursive: true });
			const materializedRequest = { ...request };
			if (request.manualInputs !== void 0) {
				const materialized = await materializeManualInputFiles({
					workspaceRoot,
					runId,
					runDir,
					value: request.manualInputs
				});
				if (materialized.error !== null) throw new Error(materialized.error);
				if (!isRecord(materialized.value)) throw new Error("Materialized manual inputs must be an object");
				materializedRequest.manualInputs = materialized.value;
			}
			runs.set(runId, runState);
			setLatestRunInfoMap({
				latestRunInfoMap,
				evalIds: targetEvalKeys,
				info: {
					status: "running",
					startedAt: now,
					commitSha: manifest.commitSha ?? null,
					evalSourceFingerprint: null
				}
			});
			await writeFile(join(runDir, "run.json"), JSON.stringify(manifest, null, 2));
			const childContext = {
				request: materializedRequest,
				workspaceRoot,
				runDir,
				manifest,
				summary
			};
			await writeFile(join(runDir, "run-child-context.json"), JSON.stringify(childContext, null, 2));
			startRunChild({
				runState,
				contextPath: join(runDir, "run-child-context.json"),
				managerContext: {
					workspaceRoot,
					evals,
					emitEvent,
					emitDiscoveryEvent,
					onRunTerminal: scheduleCacheRetentionPrune
				}
			});
			if (deletedTemporaryRuns > 0) emitDiscoveryEvent();
			return {
				manifest,
				summary,
				cases: []
			};
		},
		getRuns() {
			return [...runs.values()].map((r) => r.manifest);
		},
		getRun(id) {
			const run = runs.get(id);
			if (!run) return void 0;
			return {
				manifest: run.manifest,
				summary: run.summary,
				cases: run.cases
			};
		},
		async cancelRun(id) {
			const run = runs.get(id);
			if (!run) return;
			if (run.manifest.status !== "running") return;
			const endedAt = /* @__PURE__ */ new Date();
			run.manifest.status = "cancelled";
			run.manifest.endedAt = endedAt.toISOString();
			run.summary.status = "cancelled";
			const derivedSummary = deriveScopedSummaryFromCases({
				caseRows: run.cases,
				lifecycleStatus: "cancelled"
			});
			run.summary.totalCases = derivedSummary.totalCases;
			run.summary.passedCases = derivedSummary.passedCases;
			run.summary.failedCases = derivedSummary.failedCases;
			run.summary.errorCases = derivedSummary.errorCases;
			run.summary.cancelledCases = derivedSummary.cancelledCases;
			run.summary.totalDurationMs = endedAt.getTime() - new Date(run.manifest.startedAt).getTime();
			killRunChild(run);
			await persistRunState(run);
			emitEvent(run, {
				type: "run.cancelled",
				runId: id,
				timestamp: (/* @__PURE__ */ new Date()).toISOString(),
				payload: run.summary
			});
			emitDiscoveryEvent();
			scheduleCacheRetentionPrune();
		},
		getCaseDetail(runId, caseId) {
			const run = runs.get(runId);
			if (!run) return void 0;
			return resolveCaseDetailLookup(run, caseId);
		},
		subscribe(runId, listener) {
			const run = runs.get(runId);
			if (!run) return () => {};
			run.listeners.add(listener);
			return () => {
				run.listeners.delete(listener);
			};
		},
		subscribeDiscovery(listener) {
			discoveryListeners.add(listener);
			return () => {
				discoveryListeners.delete(listener);
			};
		},
		async close() {
			cancelCacheRetentionPrune();
			await Promise.all([closeWatchers(), configReload.close()]);
		},
		getWorkspaceRoot() {
			return workspaceRoot;
		},
		getAllowCliRunAll() {
			return config.allowCliRunAll === true;
		},
		getLlmCallsConfig() {
			return llmCallsConfig;
		},
		getApiCallsConfig() {
			return apiCallsConfig;
		},
		getArtifactPath(artifactId_) {
			return resolveArtifactPath(join(localStateDir, "runs"), artifactId_);
		}
	};
	async function loadRunnerState() {
		config = await loadConfig();
		workspaceRoot = config.workspaceRoot ?? process.cwd();
		localStateDir = resolve(workspaceRoot, ".agent-evals");
		llmCallsConfig = resolveLlmCallsConfig(config.llmCalls);
		apiCallsConfig = resolveApiCallsConfig(config.apiCalls);
		await mkdir(localStateDir, { recursive: true });
		await mkdir(join(localStateDir, "runs"), { recursive: true });
		await cleanupStagedManualInputFiles(workspaceRoot);
		cacheStore = createFsCacheStore({
			workspaceRoot,
			dir: config.cache?.dir,
			maxEntriesPerNamespace: config.cache?.maxEntriesPerNamespace ?? config.cache?.maxEntriesPerEval,
			maxEntriesByNamespace: config.cache?.maxEntriesByNamespace
		});
		await loadPersistedRuns();
		await runner.refreshDiscovery();
		if (watchForChanges) await setupWatcher();
	}
	async function closeWatchers() {
		if (discoveryRefreshTimer !== void 0) {
			clearTimeout(discoveryRefreshTimer);
			discoveryRefreshTimer = void 0;
		}
		if (runHistoryRefreshTimer !== void 0) {
			clearTimeout(runHistoryRefreshTimer);
			runHistoryRefreshTimer = void 0;
		}
		const watchers = [discoveryWatcher, runHistoryWatcher].filter((watcher) => watcher !== void 0);
		discoveryWatcher = void 0;
		runHistoryWatcher = void 0;
		await Promise.all(watchers.map((watcher) => watcher.close()));
	}
	async function setupWatcher() {
		const watcher = watch(getWatchRootsForIncludePatterns({
			patterns: config.include,
			workspaceRoot
		}), {
			ignoreInitial: true,
			persistent: true
		});
		const watcherReady = new Promise((ready) => {
			watcher.once("ready", ready);
		});
		discoveryWatcher = watcher;
		const scheduleRefresh = () => {
			if (discoveryRefreshTimer !== void 0) clearTimeout(discoveryRefreshTimer);
			discoveryRefreshTimer = setTimeout(() => {
				discoveryRefreshTimer = void 0;
				runner.refreshDiscovery();
			}, 50);
		};
		watcher.on("change", scheduleRefresh);
		watcher.on("add", scheduleRefresh);
		watcher.on("unlink", scheduleRefresh);
		watcher.on("addDir", scheduleRefresh);
		watcher.on("unlinkDir", scheduleRefresh);
		await Promise.all([setupRunHistoryWatcher(), configReload.setupWatcher()]);
		await watcherReady;
	}
	async function setupRunHistoryWatcher() {
		const watcher = watch(join(localStateDir, "runs"), {
			ignoreInitial: true,
			persistent: true
		});
		runHistoryWatcher = watcher;
		const scheduleRefresh = () => {
			if (runHistoryRefreshTimer !== void 0) clearTimeout(runHistoryRefreshTimer);
			runHistoryRefreshTimer = setTimeout(() => {
				runHistoryRefreshTimer = void 0;
				refreshPersistedRunsFromDisk();
			}, 50);
		};
		watcher.on("change", scheduleRefresh);
		watcher.on("add", scheduleRefresh);
		watcher.on("unlink", scheduleRefresh);
		watcher.on("addDir", scheduleRefresh);
		watcher.on("unlinkDir", scheduleRefresh);
		await new Promise((ready) => {
			watcher.once("ready", ready);
		});
	}
	function getActiveRunCount() {
		return [...runs.values()].filter((run) => run.manifest.status === "running").length;
	}
	function getCachePruneIdleDelayMs() {
		const configured = config.cache?.pruneIdleDelayMs;
		if (configured === void 0 || !Number.isFinite(configured) || configured <= 0) return defaultCachePruneIdleDelayMs;
		return Math.floor(configured);
	}
	function cancelCacheRetentionPrune() {
		if (cachePruneIdleTimer === void 0) return;
		clearTimeout(cachePruneIdleTimer);
		cachePruneIdleTimer = void 0;
	}
	function scheduleCacheRetentionPrune() {
		cancelCacheRetentionPrune();
		cachePruneIdleTimer = setTimeout(() => {
			cachePruneIdleTimer = void 0;
			pruneCacheRetentionIfIdle();
		}, getCachePruneIdleDelayMs());
		cachePruneIdleTimer.unref();
	}
	async function pruneCacheRetentionIfIdle() {
		if (getActiveRunCount() > 0) return;
		await cacheStore.pruneRetention();
	}
	function emitDiscoveryEvent() {
		const lastRunStatuses = getLastRunStatuses({
			runs: runs.values(),
			knownEvals: evals.values()
		});
		const latestRunInfos = getLatestRunInfos({
			runs: runs.values(),
			knownEvals: evals.values()
		});
		lastRunStatusMap.clear();
		for (const [evalId, status] of lastRunStatuses) lastRunStatusMap.set(evalId, status);
		latestRunInfoMap.clear();
		for (const [evalId, info] of latestRunInfos) latestRunInfoMap.set(evalId, info);
		const event = {
			type: "discovery.updated",
			timestamp: (/* @__PURE__ */ new Date()).toISOString(),
			payload: runner.getEvals()
		};
		for (const listener of discoveryListeners) listener(event);
		configReload.reloadIfPendingAndIdle();
	}
	function emitToDiscoveryListeners(event) {
		for (const listener of discoveryListeners) listener(event);
	}
	function emitEvent(runState, event) {
		for (const listener of runState.listeners) try {
			listener(event);
		} catch {}
	}
	async function loadPersistedRuns() {
		runs.clear();
		const persistedRuns = await loadPersistedRunSnapshots(localStateDir);
		nextShortIdNum = nextShortIdFromSnapshots(persistedRuns);
		for (const persistedRun of persistedRuns) runs.set(persistedRun.manifest.id, toRunnerRunState(persistedRun));
	}
	async function refreshPersistedRunsFromDisk() {
		const persistedRuns = await loadPersistedRunSnapshots(localStateDir);
		const persistedRunIds = new Set(persistedRuns.map((snapshot) => snapshot.manifest.id));
		let changed = false;
		for (const persistedRun of persistedRuns) {
			const existing = runs.get(persistedRun.manifest.id);
			if (existing?.manifest.status === "running" && existing.childProcess) continue;
			runs.set(persistedRun.manifest.id, toRunnerRunState(persistedRun, existing));
			changed = true;
		}
		for (const [runId, existing] of [...runs]) {
			if (persistedRunIds.has(runId)) continue;
			if (existing.manifest.status === "running") continue;
			runs.delete(runId);
			changed = true;
		}
		nextShortIdNum = Math.max(nextShortIdNum, nextShortIdFromSnapshots(persistedRuns));
		if (changed) emitDiscoveryEvent();
	}
	return runner;
}
//#endregion
//#region src/cliHelp.ts
/** Render the help block for a given CLI topic to stdout via `console.info`. */
function printHelp(topic = "global") {
	if (topic === "app") {
		console.info(`
agent-evals app - Start server with UI

Usage:
  agent-evals app [flags]

Flags:
  --port <n>                 Server port (default: 4100)
  --no-env                   Disable automatic .env loading
  --help, -h                 Show this help
  `);
		return;
	}
	if (topic === "list") {
		console.info(`
agent-evals list - List discovered evals

Usage:
  agent-evals list [flags]

Flags:
  --no-env                   Disable automatic .env loading
  --help, -h                 Show this help
  `);
		return;
	}
	if (topic === "run") {
		console.info(`
agent-evals run - Run evals

Usage:
  agent-evals run [flags]

Flags:
  --eval <id>                Run specific eval(s) (comma-separated)
  --file <path|glob>         Run eval files matching path/glob (comma-separated)
  --case <id>                Run case(s); combine with --file/--eval if ambiguous
  --tags-filter <expr>       Run cases matching a tag expression
  --trials <n>               Number of trials per case
  --inspect[=host:port]      Run with the Node.js inspector enabled
  --inspect-brk[=host:port]  Enable inspector and pause before startup
  --json                     Output run summary as JSON
  --cache <use|bypass|refresh>  Cache mode for this run (default: use)
  --no-cache                 Shortcut for --cache bypass
  --refresh-cache            Shortcut for --cache refresh
  --clear-cache              Clear the cache before starting the run
  --temporary                Persist until the next run starts, then delete
  --input <json>             Manual input value for a single targeted eval
                             that declares manualInput
  --input-file <path>        JSON object keyed by eval key (or eval id) with
                             manual input values for one or more targeted evals
  --no-env                   Disable automatic .env loading
  --help, -h                 Show this help
  `);
		return;
	}
	if (topic === "show-runs") {
		console.info(`
agent-evals show-runs - Show saved run artifact file paths

Usage:
  agent-evals show-runs [<run-id>|latest] [--json]

Prints the run directory and stable artifact paths for run.json, summary.json,
cases.jsonl, case detail JSON, and trace JSON files. Run ids can be full
timestamp ids, short ids such as r0, or latest.

Flags:
  --json                     Output the file index as JSON
  --no-env                   Disable automatic .env loading
  --help, -h                 Show this help
  `);
		return;
	}
	if (topic === "cache" || topic === "cache list" || topic === "cache clear" || topic === "cache repair") {
		console.info(`
agent-evals cache - Manage cached namespace/key entries

Usage:
  agent-evals cache list [flags]
  agent-evals cache clear --eval <id>
  agent-evals cache clear --all
  agent-evals cache repair [flags]

Flags:
  --eval <id>                Clear entries for specific eval(s) (comma-separated)
  --all                      Confirm clearing every cached entry
  --json                     Output cache listing or repair summary as JSON
  --no-env                   Disable automatic .env loading
  --help, -h                 Show this help
  `);
		return;
	}
	console.info(`
agent-evals - LLM/Agent eval runner

Commands:
  app                        Start server with UI
  list                       List discovered evals
  run                        Run evals
  show-runs [id|latest]      Show saved run artifact file paths
  cache list                 List cached namespace/key entries
  cache clear --eval <id>    Clear cache entries for one eval
  cache clear --all          Clear every cached entry
  cache repair               Remove unindexed/orphaned cache files
  help                       Show this help

Options:
  --eval <id>                Run specific eval(s) (comma-separated)
  --case <id>                Run specific case(s) (comma-separated)
  --tags-filter <expr>       Run cases matching a tag expression
  --trials <n>               Number of trials per case
  --inspect[=host:port]      Run with the Node.js inspector enabled
  --inspect-brk[=host:port]  Enable inspector and pause before startup
  --json                     Output results as JSON
  --port <n>                 Server port (default: 4100)
  --cache <use|bypass|refresh>  Cache mode for this run (default: use)
  --no-cache                 Shortcut for --cache bypass
  --refresh-cache            Shortcut for --cache refresh
  --clear-cache              Clear the cache before starting the run
  --temporary                Persist until the next run starts, then delete
  --no-env                   Disable automatic .env loading
  --help, -h                 Show help
  `);
}
//#endregion
//#region src/manualInputArgs.ts
function isPlainObject(value) {
	return typeof value === "object" && value !== null && !Array.isArray(value);
}
function isPathInputObject(value) {
	if (!isPlainObject(value)) return false;
	return typeof value.path === "string" && (value.name === void 0 || typeof value.name === "string") && (value.mimeType === void 0 || typeof value.mimeType === "string");
}
function escapeRegex$1(value) {
	return value.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
}
function globToRegex$1(pattern) {
	const normalized = pattern.replaceAll("\\", "/");
	let regex = "^";
	for (let i = 0; i < normalized.length; i++) {
		const char = normalized[i];
		const next = normalized[i + 1];
		if (char === "*" && next === "*") {
			regex += ".*";
			i++;
		} else if (char === "*") regex += "[^/]*";
		else if (char === "?") regex += "[^/]";
		else regex += escapeRegex$1(char ?? "");
	}
	regex += "$";
	return new RegExp(regex);
}
function fileMatches$1(pattern, filePath) {
	const normalizedPattern = pattern.replaceAll("\\", "/");
	if (normalizedPattern === filePath) return true;
	return globToRegex$1(normalizedPattern).test(filePath);
}
function isManualInputEvalTargeted(params) {
	const { evalSummary, args } = params;
	const hasEvalIds = args.evalIds.length > 0;
	const hasFiles = args.files.length > 0;
	const hasCaseIds = args.caseIds.length > 0;
	if (hasEvalIds && !args.evalIds.includes(evalSummary.id)) return false;
	if (hasFiles) {
		if (!args.files.some((file) => fileMatches$1(file, evalSummary.filePath))) return false;
	}
	if (!hasEvalIds && !hasFiles) {
		if (hasCaseIds) return false;
	}
	return matchesTagsFilter({
		tags: evalSummary.tags ?? [],
		filters: args.tagsFilter
	});
}
async function readInputFileMap(inputFilePath) {
	const readResult = await resultify(() => readFile(inputFilePath, "utf-8"));
	if (readResult.error) return {
		error: `Failed to read --input-file at ${inputFilePath}: ${readResult.error.message}`,
		value: null
	};
	const parseResult = resultify(() => JSON.parse(readResult.value));
	if (parseResult.error) return {
		error: `Failed to parse --input-file at ${inputFilePath} as JSON: ${parseResult.error.message}`,
		value: null
	};
	return {
		error: null,
		value: parseResult.value
	};
}
async function normalizeManualInputFileValue(params) {
	if (isManualInputFileValue(params.value)) return {
		error: null,
		value: params.value
	};
	if (!isPathInputObject(params.value)) return {
		error: null,
		value: params.value
	};
	const pathInput = params.value;
	const staged = await resultify(() => stageManualInputFileFromPath({
		workspaceRoot: params.workspaceRoot,
		path: pathInput.path,
		name: pathInput.name,
		mimeType: pathInput.mimeType
	}));
	if (staged.error) return {
		error: `Failed to stage file input "${params.fieldKey}" for eval "${params.evalId}": ${staged.error.message}`,
		value: null
	};
	return {
		error: null,
		value: staged.value
	};
}
async function normalizeManualInputValue(params) {
	const descriptor = params.evalSummary.manualInput;
	if (!descriptor || !isPlainObject(params.value)) return {
		error: null,
		value: params.value
	};
	const next = { ...params.value };
	for (const field of descriptor.fields) {
		if (field.kind !== "file") continue;
		const normalized = await normalizeManualInputFileValue({
			workspaceRoot: params.workspaceRoot,
			evalId: params.evalSummary.id,
			fieldKey: field.key,
			value: next[field.key]
		});
		if (normalized.error !== null) return {
			error: normalized.error,
			value: null
		};
		next[field.key] = normalized.value;
	}
	return {
		error: null,
		value: next
	};
}
/**
* Resolve the `manualInputs` payload to send with `runner.startRun`.
*
* Inspects every discovered eval that declares `manualInput`, filters them to
* the run target, and either returns the typed map (single eval via `--input`,
* multiple via `--input-file`) or a structured error to display and exit on.
*/
async function collectManualInputs(params) {
	const { runner, args } = params;
	const workspaceRoot = runner.getWorkspaceRoot();
	const targetedManualInputEvals = runner.getEvals().filter((evalSummary) => evalSummary.manualInput !== void 0).filter((evalSummary) => isManualInputEvalTargeted({
		evalSummary,
		args
	}));
	if (targetedManualInputEvals.length === 0) {
		if (args.inputJson !== void 0 || args.inputFilePath !== void 0) return {
			error: "--input/--input-file was provided but no targeted eval requires manual input.",
			value: null
		};
		return {
			error: null,
			value: void 0
		};
	}
	if (args.inputJson !== void 0 && args.inputFilePath !== void 0) return {
		error: "Cannot use --input and --input-file together; choose one.",
		value: null
	};
	if (args.inputJson !== void 0) {
		if (targetedManualInputEvals.length > 1) {
			const ids = targetedManualInputEvals.map((evalSummary) => evalSummary.id).join(", ");
			return {
				error: `--input only works for one targeted manual-input eval at a time; got ${String(targetedManualInputEvals.length)} (${ids}). Use --input-file with a JSON object keyed by eval key.`,
				value: null
			};
		}
		const parsedResult = resultify(() => JSON.parse(args.inputJson ?? ""));
		if (parsedResult.error) return {
			error: `Failed to parse --input as JSON: ${parsedResult.error.message}`,
			value: null
		};
		const [onlyEval] = targetedManualInputEvals;
		if (onlyEval === void 0) return {
			error: null,
			value: void 0
		};
		const normalized = await normalizeManualInputValue({
			workspaceRoot,
			evalSummary: onlyEval,
			value: parsedResult.value
		});
		if (normalized.error !== null) return {
			error: normalized.error,
			value: null
		};
		return {
			error: null,
			value: { [onlyEval.key]: normalized.value }
		};
	}
	if (args.inputFilePath !== void 0) {
		const fileResult = await readInputFileMap(args.inputFilePath);
		if (fileResult.error !== null) return {
			error: fileResult.error,
			value: null
		};
		if (!isPlainObject(fileResult.value)) return {
			error: `--input-file must contain a JSON object keyed by eval key (got ${typeof fileResult.value}).`,
			value: null
		};
		const map = {};
		for (const evalSummary of targetedManualInputEvals) {
			const byKey = fileResult.value[evalSummary.key];
			const byId = fileResult.value[evalSummary.id];
			const value = byKey !== void 0 ? byKey : byId;
			if (value === void 0) return {
				error: `--input-file is missing manual input for eval "${evalSummary.id}" (key "${evalSummary.key}").`,
				value: null
			};
			const normalized = await normalizeManualInputValue({
				workspaceRoot,
				evalSummary,
				value
			});
			if (normalized.error !== null) return {
				error: normalized.error,
				value: null
			};
			map[evalSummary.key] = normalized.value;
		}
		return {
			error: null,
			value: map
		};
	}
	return {
		error: `Eval(s) require manual input but no --input/--input-file was provided: ${targetedManualInputEvals.map((evalSummary) => evalSummary.id).join(", ")}`,
		value: null
	};
}
//#endregion
//#region src/cli.ts
function parseArgs(argv) {
	const normalizedArgv = argv.filter((arg) => arg !== "--no-env");
	const args = {
		command: "help",
		subcommand: void 0,
		positionals: [],
		showHelp: false,
		helpTopic: "global",
		unknownHelpTarget: void 0,
		evalIds: [],
		files: [],
		caseIds: [],
		tagsFilter: [],
		trials: 1,
		json: false,
		port: 4100,
		cacheMode: "use",
		clearCache: false,
		temporary: false,
		all: false,
		loadEnv: normalizedArgv.length === argv.length,
		inputJson: void 0,
		inputFilePath: void 0
	};
	const command = normalizedArgv[0];
	if (command === "--help" || command === "-h") {
		args.showHelp = true;
		return args;
	}
	if (isCliCommand(command)) {
		args.command = command;
		args.helpTopic = command === "help" ? "global" : command;
	} else if (command !== void 0 && !command.startsWith("-")) args.unknownHelpTarget = command;
	let cursor = 1;
	if (args.command === "cache") {
		const sub = normalizedArgv[cursor];
		if (sub === "list" || sub === "clear" || sub === "repair") {
			args.subcommand = sub;
			args.helpTopic = `cache ${sub}`;
			cursor++;
		} else if (sub !== void 0 && !sub.startsWith("-")) args.unknownHelpTarget = `cache ${sub}`;
	}
	for (let i = cursor; i < normalizedArgv.length; i++) {
		const arg = normalizedArgv[i];
		if (arg === void 0) continue;
		const next = normalizedArgv[i + 1];
		if (arg === "--help" || arg === "-h") args.showHelp = true;
		else if (arg === "--eval" && next) {
			args.evalIds.push(...next.split(","));
			i++;
		} else if (arg === "--file" && next) {
			args.files.push(...next.split(","));
			i++;
		} else if (arg === "--case" && next) {
			args.caseIds.push(...next.split(","));
			i++;
		} else if (arg === "--tags-filter" && next) {
			args.tagsFilter.push(...next.split(","));
			i++;
		} else if (arg === "--trials" && next) {
			args.trials = Number(next);
			i++;
		} else if (arg === "--json") args.json = true;
		else if (arg === "--port" && next) {
			args.port = Number(next);
			i++;
		} else if (arg === "--cache" && next) {
			if (next === "use" || next === "bypass" || next === "refresh") args.cacheMode = next;
			i++;
		} else if (arg === "--no-cache") args.cacheMode = "bypass";
		else if (arg === "--refresh-cache") args.cacheMode = "refresh";
		else if (arg === "--clear-cache") args.clearCache = true;
		else if (arg === "--temporary") args.temporary = true;
		else if (arg === "--input" && next !== void 0) {
			args.inputJson = next;
			i++;
		} else if (arg === "--input-file" && next !== void 0) {
			args.inputFilePath = next;
			i++;
		} else if (arg === "--all") args.all = true;
		else if (!arg.startsWith("-")) args.positionals.push(arg);
	}
	return args;
}
/**
* Run the Agent Evals CLI against the current workspace.
*
* @param argv Raw command-line arguments excluding the executable name.
*/
async function runCli(argv) {
	const args = parseArgs(argv);
	if (args.loadEnv && !loadWorkspaceEnv()) process.exit(1);
	if (args.showHelp) {
		if (args.unknownHelpTarget !== void 0) {
			console.error(`No help found for "${args.unknownHelpTarget}".`);
			process.exit(1);
		}
		printHelp(args.helpTopic);
		return;
	}
	switch (args.command) {
		case "app":
			await commandApp(args);
			break;
		case "list":
			await commandList(args);
			break;
		case "run":
			await commandRun(args);
			break;
		case "show-runs":
			await commandShowRuns(args);
			break;
		case "cache":
			await commandCache(args);
			break;
		default:
			printHelp(args.helpTopic);
			break;
	}
}
function isCliCommand(command) {
	return command === "app" || command === "list" || command === "run" || command === "show-runs" || command === "cache" || command === "help";
}
function escapeRegex(value) {
	return value.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
}
function globToRegex(pattern) {
	const normalized = pattern.replaceAll("\\", "/");
	let regex = "^";
	for (let i = 0; i < normalized.length; i++) {
		const char = normalized[i];
		const next = normalized[i + 1];
		if (char === "*" && next === "*") {
			regex += ".*";
			i++;
		} else if (char === "*") regex += "[^/]*";
		else if (char === "?") regex += "[^/]";
		else regex += escapeRegex(char ?? "");
	}
	return new RegExp(`${regex}$`);
}
function fileMatches(pattern, filePath) {
	const normalized = pattern.replaceAll("\\", "/");
	return normalized === filePath || globToRegex(normalized).test(filePath);
}
function loadWorkspaceEnv() {
	const envPath = resolve(process.cwd(), ".env");
	if (!existsSync(envPath)) return true;
	const loadResult = resultify(() => {
		process.loadEnvFile(envPath);
	});
	if (loadResult.error) {
		console.error(`Failed to load .env at ${envPath}: ${loadResult.error.message}`);
		return false;
	}
	return true;
}
function formatUnknownErrorDetails(error) {
	if (error instanceof Error) return error.stack ?? error.message;
	if (typeof error === "string") return error;
	return String(error);
}
const currentDir = dirname(fileURLToPath(import.meta.url));
const repoRoot = resolve(currentDir, "../../..");
const pnpmCommand = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
function hasRepoWebWorkspace() {
	return existsSync(resolve(repoRoot, "apps/web/package.json"));
}
async function ensureWebUiIsBuilt() {
	if (!hasRepoWebWorkspace()) return;
	console.info("Preparing web UI...");
	await new Promise((resolvePromise, rejectPromise) => {
		const child = spawn(pnpmCommand, [
			"--filter",
			"@agent-evals/web",
			"build"
		], {
			cwd: repoRoot,
			stdio: "inherit"
		});
		child.once("error", (error) => {
			rejectPromise(error);
		});
		child.once("exit", (code, signal) => {
			if (signal) {
				rejectPromise(/* @__PURE__ */ new Error(`Web UI build stopped with signal ${signal}.`));
				return;
			}
			if (code !== 0) {
				rejectPromise(/* @__PURE__ */ new Error(`Web UI build failed with exit code ${String(code)}.`));
				return;
			}
			resolvePromise();
		});
	});
}
function isHonoAppModule(mod) {
	if (typeof mod !== "object" || mod === null || !("app" in mod)) return false;
	const { app } = mod;
	return typeof app === "object" && app !== null && "fetch" in app && typeof app.fetch === "function";
}
function isServerRunnerModule(mod) {
	if (typeof mod !== "object" || mod === null || !("initRunner" in mod)) return false;
	return typeof mod.initRunner === "function";
}
async function commandApp(args) {
	await ensureWebUiIsBuilt();
	const { serve } = await import("@hono/node-server");
	const bundledWebDist = resolve(currentDir, "apps/web/dist");
	if (existsSync(bundledWebDist)) process.env.AGENT_EVALS_WEB_DIST = bundledWebDist;
	const appModule = await import("./app-Bpe6Monh.mjs");
	const runnerModule = await import("./runner-C3CiS2o7.mjs");
	if (!isHonoAppModule(appModule)) throw new Error("Server app module is invalid");
	if (!isServerRunnerModule(runnerModule)) throw new Error("Server runner module is invalid");
	await runnerModule.initRunner();
	console.info(`Agent Evals app: http://localhost:${String(args.port)}`);
	serve({
		fetch: appModule.app.fetch,
		port: args.port
	});
}
async function commandList(args_) {
	const runner = createRunner({ watchForChanges: false });
	await runner.init();
	const discoveryIssues = runner.getDiscoveryIssues();
	if (discoveryIssues.length > 0) {
		console.error("Discovery errors:\n");
		for (const issue of discoveryIssues) console.error(`  ${issue.message}`);
		console.error("");
	}
	const evals = runner.getEvals();
	if (evals.length === 0) {
		console.info("No eval files found.");
		if (discoveryIssues.length > 0) process.exit(1);
		return;
	}
	console.info("Discovered evals:\n");
	for (const ev of evals) {
		const displayStatus = getEvalDisplayStatus({
			freshnessStatus: ev.freshnessStatus,
			stale: ev.stale,
			outdated: ev.outdated,
			lastRunStatus: ev.lastRunStatus
		});
		const title = getEvalTitle(ev);
		console.info(`  ${title}`);
		console.info(`    id: ${ev.id}`);
		console.info(`    file: ${ev.filePath}`);
		if (displayStatus !== "pending") console.info(`    status: ${displayStatus}`);
		if (ev.caseCount !== null) console.info(`    cases: ${String(ev.caseCount)}`);
		console.info("");
	}
	if (discoveryIssues.length > 0) process.exit(1);
}
async function commandRun(args) {
	const runner = createRunner({ watchForChanges: false });
	await runner.init();
	if (args.evalIds.length === 0 && args.caseIds.length === 0 && args.files.length === 0 && args.tagsFilter.length === 0 && !runner.getAllowCliRunAll()) {
		console.error("This workspace disables running all evals from the CLI. Pass --eval <id>, --file <path|glob>, --case <id>, or --tags-filter <expr> to run a targeted subset.");
		process.exit(1);
	}
	if (args.clearCache) {
		await runner.clearCache();
		if (!args.json) {
			console.info("Cleared cache before run.");
			console.info("");
		}
	}
	const target = args.caseIds.length > 0 ? {
		mode: "caseIds",
		caseIds: args.caseIds,
		evalIds: args.evalIds.length > 0 ? args.evalIds : void 0,
		files: args.files.length > 0 ? args.files : void 0,
		tagsFilter: args.tagsFilter.length > 0 ? args.tagsFilter : void 0
	} : args.evalIds.length > 0 ? {
		mode: "evalIds",
		evalIds: args.evalIds,
		files: args.files.length > 0 ? args.files : void 0,
		tagsFilter: args.tagsFilter.length > 0 ? args.tagsFilter : void 0
	} : args.files.length > 0 ? {
		mode: "evalIds",
		files: args.files,
		tagsFilter: args.tagsFilter.length > 0 ? args.tagsFilter : void 0
	} : args.tagsFilter.length > 0 ? {
		mode: "evalIds",
		tagsFilter: args.tagsFilter
	} : { mode: "all" };
	const manualInputsResult = await collectManualInputs({
		runner,
		args: {
			evalIds: args.evalIds,
			files: args.files,
			caseIds: args.caseIds,
			tagsFilter: args.tagsFilter,
			inputJson: args.inputJson,
			inputFilePath: args.inputFilePath
		}
	});
	if (manualInputsResult.error !== null) {
		console.error(manualInputsResult.error);
		process.exit(1);
	}
	const runResult = await resultify(() => runner.startRun({
		target,
		trials: args.trials,
		temporary: args.temporary,
		cache: { mode: args.cacheMode },
		manualInputs: manualInputsResult.value
	}));
	if (runResult.error) {
		console.error("Failed to start run:");
		console.error(formatUnknownErrorDetails(runResult.error));
		process.exit(1);
	}
	const run = runResult.value;
	if (!args.json) {
		console.info(`Run started: ${run.manifest.id}`);
		console.info(`Trials: ${String(args.trials)}`);
		if (args.cacheMode !== "use") console.info(`Cache mode: ${args.cacheMode}`);
		if (args.temporary) console.info("Temporary: yes");
		console.info("");
	}
	await waitForRunCompletion(runner, run.manifest.id);
	const finalRun = runner.getRun(run.manifest.id);
	if (!finalRun) process.exit(1);
	const { summary } = finalRun;
	if (args.json) console.info(JSON.stringify(summary, null, 2));
	else {
		console.info("--- Run Summary ---");
		console.info(`Status: ${summary.status}`);
		console.info(`Total: ${String(summary.totalCases)}`);
		console.info(`Passed: ${String(summary.passedCases)}`);
		console.info(`Failed: ${String(summary.failedCases)}`);
		console.info(`Errors: ${String(summary.errorCases)}`);
		if (summary.totalCases > 0) console.info(`Pass Rate: ${String(summary.passedCases)}/${String(summary.totalCases)}`);
		if (summary.totalDurationMs !== null) console.info(`Duration: ${(summary.totalDurationMs / 1e3).toFixed(1)}s`);
		if (summary.errorMessage !== null) {
			console.info("");
			console.info(summary.errorMessage);
		}
	}
	if (summary.status === "error" || summary.failedCases > 0 || summary.errorCases > 0) process.exit(1);
}
async function commandShowRuns(args) {
	const runner = createRunner({ watchForChanges: false });
	await runner.init();
	const runRef = args.positionals[0];
	if (runRef !== void 0) {
		const run = resolveRunSnapshot(runner, runRef);
		if (!run) {
			printMissingRun(runRef);
			process.exit(1);
		}
		const index = buildRunFileIndex(runner.getWorkspaceRoot(), run);
		if (args.json) {
			printJson(index);
			return;
		}
		printRunFileIndex(index);
		return;
	}
	const indexes = getSortedRunSnapshots(runner).map((run) => buildRunFileIndex(runner.getWorkspaceRoot(), run));
	if (args.json) {
		printJson(indexes);
		return;
	}
	printRunFileIndexes(indexes);
}
async function commandCache(args) {
	const runner = createRunner({ watchForChanges: false });
	await runner.init();
	if (args.subcommand === "list" || args.subcommand === void 0) {
		const entries = await runner.listCache();
		if (args.json) {
			console.info(JSON.stringify(entries, null, 2));
			return;
		}
		if (entries.length === 0) {
			console.info("No cache entries.");
			return;
		}
		console.info(`Cache entries (${String(entries.length)}):\n`);
		for (const entry of entries) {
			console.info(`  ${entry.namespace}`);
			console.info(`    key: ${entry.key}`);
			console.info(`    stored: ${entry.storedAt}`);
			console.info(`    last accessed: ${entry.lastAccessedAt}`);
			console.info("");
		}
		return;
	}
	if (args.subcommand === "clear") {
		if (args.evalIds.length > 0 || args.files.length > 0) {
			const evalIds = runner.getEvals().filter((ev) => (args.evalIds.length === 0 || args.evalIds.includes(ev.id)) && (args.files.length === 0 || args.files.some((file) => fileMatches(file, ev.filePath)))).map((ev) => ev.id);
			for (const evalId of evalIds) {
				const entries = await runner.listCache();
				const prefix = `${evalId}.`;
				const matching = entries.filter((entry) => entry.namespace.startsWith(prefix));
				for (const entry of matching) await runner.clearCache({
					namespace: entry.namespace,
					key: entry.key
				});
			}
			console.info(`Cleared cache entries for: ${evalIds.join(", ")}`);
			return;
		}
		if (args.all) {
			await runner.clearCache();
			console.info("Cleared all cache entries.");
			return;
		}
		console.info("Refusing to clear cache without --eval <id> or --all. Use one of these flags to confirm.");
		process.exit(1);
	}
	if (args.subcommand === "repair") {
		const summary = await runner.repairCache();
		if (args.json) {
			console.info(JSON.stringify(summary, null, 2));
			return;
		}
		console.info("Cache repair complete.");
		console.info(`Removed cache files: ${String(summary.removedCacheFiles)}`);
		console.info(`Removed debug files: ${String(summary.removedDebugFiles)}`);
		console.info(`Removed blob files: ${String(summary.removedBlobFiles)}`);
		console.info(`Removed index rows: ${String(summary.removedIndexRows)}`);
		console.info(`Rewritten indexes: ${String(summary.rewrittenIndexes)}`);
		return;
	}
	printHelp(args.helpTopic);
}
function getSortedRunSnapshots(runner) {
	return runner.getRuns().toSorted((a, b) => getRunStartTime(a) - getRunStartTime(b)).map((manifest) => runner.getRun(manifest.id)).filter((run) => run !== void 0);
}
function buildRunFileIndex(workspaceRoot, run) {
	const runDir = join(workspaceRoot, ".agent-evals", "runs", run.manifest.id);
	const caseIdCounts = /* @__PURE__ */ new Map();
	for (const caseRow of run.cases) caseIdCounts.set(caseRow.caseId, (caseIdCounts.get(caseRow.caseId) ?? 0) + 1);
	const seenCaseIds = /* @__PURE__ */ new Set();
	return {
		id: run.manifest.id,
		shortId: run.manifest.shortId,
		status: run.manifest.status,
		temporary: run.manifest.temporary,
		startedAt: run.manifest.startedAt,
		endedAt: run.manifest.endedAt,
		target: run.manifest.target,
		summary: run.summary,
		files: {
			dir: runDir,
			run: join(runDir, "run.json"),
			summary: join(runDir, "summary.json"),
			cases: join(runDir, "cases.jsonl"),
			caseDetailsDir: join(runDir, "case-details"),
			tracesDir: join(runDir, "traces")
		},
		cases: run.cases.map((caseRow) => {
			const duplicateCaseIdCount = caseIdCounts.get(caseRow.caseId) ?? 0;
			const hasPreviousCaseWithId = seenCaseIds.has(caseRow.caseId);
			const fileId = duplicateCaseIdCount > 1 && hasPreviousCaseWithId ? caseRow.caseKey ?? caseRow.caseId : caseRow.caseId;
			seenCaseIds.add(caseRow.caseId);
			const fileName = `${encodeURIComponent(fileId)}.json`;
			return {
				caseId: caseRow.caseId,
				caseKey: caseRow.caseKey,
				evalId: caseRow.evalId,
				evalKey: caseRow.evalKey,
				status: caseRow.status,
				files: {
					caseDetail: join(runDir, "case-details", fileName),
					trace: join(runDir, "traces", fileName)
				}
			};
		})
	};
}
function resolveRunSnapshot(runner, runRef) {
	const runs = getSortedRunSnapshots(runner);
	if (runs.length === 0) return void 0;
	if (runRef === void 0 || runRef === "latest") return runs[runs.length - 1];
	return runs.find((run) => run.manifest.id === runRef || run.manifest.shortId === runRef);
}
function printMissingRun(runRef) {
	console.error(runRef === void 0 ? "No saved runs found." : `No saved run found for "${runRef}".`);
}
function getRunStartTime(manifest) {
	const parsed = new Date(manifest.startedAt).getTime();
	return Number.isFinite(parsed) ? parsed : 0;
}
function printJson(value) {
	console.info(JSON.stringify(value, null, 2));
}
function printRunFileIndexes(indexes) {
	if (indexes.length === 0) {
		console.info("No saved runs.");
		return;
	}
	console.info(`Saved runs (${String(indexes.length)}):\n`);
	for (const index of indexes) {
		printRunFileIndex(index);
		console.info("");
	}
}
function printRunFileIndex(index) {
	console.info(`${index.shortId} (${index.id})  ${index.status}${index.temporary ? "  temporary" : ""}  ${formatCaseCounts(index.summary)}`);
	console.info(`  dir: ${index.files.dir}`);
	console.info(`  run: ${index.files.run}`);
	console.info(`  summary: ${index.files.summary}`);
	console.info(`  cases: ${index.files.cases}`);
	console.info(`  case details: ${index.files.caseDetailsDir}`);
	console.info(`  traces: ${index.files.tracesDir}`);
	if (index.cases.length === 0) return;
	console.info("  case files:");
	for (const caseEntry of index.cases) {
		console.info(`    ${caseEntry.caseId} [${caseEntry.evalId}] ${caseEntry.status}`);
		console.info(`      detail: ${caseEntry.files.caseDetail}`);
		console.info(`      trace: ${caseEntry.files.trace}`);
	}
}
function formatCaseCounts(summary) {
	return [
		`${String(summary.totalCases)} total`,
		`${String(summary.passedCases)} passed`,
		`${String(summary.failedCases)} failed`,
		`${String(summary.errorCases)} errors`,
		`${String(summary.cancelledCases)} cancelled`
	].join(", ");
}
async function waitForRunCompletion(runner, runId) {
	return new Promise((resolvePromise) => {
		const check = () => {
			const run = runner.getRun(runId);
			if (!run || run.manifest.status === "completed" || run.manifest.status === "cancelled" || run.manifest.status === "error") {
				resolvePromise();
				return;
			}
			setTimeout(check, 200);
		};
		check();
	});
}
//#endregion
export { materializeManualInputFiles as a, isManualInputFileValue as i, createRunner as n, stageManualInputFile as o, cleanupStagedManualInputFiles as r, stageManualInputFileFromPath as s, runCli as t };
