@agentv/core 4.9.0 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  resolveDelegatedTargetDefinition,
26
26
  resolveFileReference,
27
27
  resolveTargetDefinition
28
- } from "./chunk-VCVVKCC4.js";
28
+ } from "./chunk-BWHUWLGW.js";
29
29
  import {
30
30
  AgentvProvider
31
31
  } from "./chunk-PRNXHNLF.js";
@@ -152,8 +152,8 @@ function mergeExecutionMetrics(computed, metrics) {
152
152
  }
153
153
 
154
154
  // src/evaluation/yaml-parser.ts
155
- import { readFile as readFile6 } from "node:fs/promises";
156
- import path7 from "node:path";
155
+ import { readFile as readFile7 } from "node:fs/promises";
156
+ import path8 from "node:path";
157
157
  import micromatch2 from "micromatch";
158
158
  import { parse as parse2 } from "yaml";
159
159
 
@@ -684,10 +684,318 @@ function logWarning(message) {
684
684
  }
685
685
 
686
686
  // src/evaluation/loaders/evaluator-parser.ts
687
+ import path5 from "node:path";
688
+
689
+ // src/evaluation/content-preprocessor.ts
690
+ import { readFile as readFile3 } from "node:fs/promises";
687
691
  import path4 from "node:path";
692
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
693
+
694
+ // src/runtime/exec.ts
695
+ function shellEscapePath(value) {
696
+ if (process.platform === "win32") {
697
+ return `"${value.replaceAll('"', '""')}"`;
698
+ }
699
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
700
+ }
701
+ async function execFileWithStdin(argv, stdinPayload, options = {}) {
702
+ if (argv.length === 0) {
703
+ throw new Error("Executable argv must include at least one entry");
704
+ }
705
+ if (typeof Bun !== "undefined") {
706
+ return execFileWithStdinBun(argv, stdinPayload, options);
707
+ }
708
+ return execFileWithStdinNode(argv, stdinPayload, options);
709
+ }
710
+ async function execFileWithStdinBun(argv, stdinPayload, options) {
711
+ const command = [...argv];
712
+ const encoder = new TextEncoder();
713
+ const proc = Bun.spawn(command, {
714
+ cwd: options.cwd,
715
+ stdin: encoder.encode(stdinPayload),
716
+ stdout: "pipe",
717
+ stderr: "pipe",
718
+ // Merge additional env vars with process.env
719
+ env: options.env ? { ...process.env, ...options.env } : process.env
720
+ });
721
+ let timedOut = false;
722
+ const timeout = options.timeoutMs !== void 0 ? setTimeout(() => {
723
+ timedOut = true;
724
+ proc.kill("SIGKILL");
725
+ }, options.timeoutMs) : void 0;
726
+ try {
727
+ const stdoutPromise = proc.stdout ? new Response(proc.stdout).text() : Promise.resolve("");
728
+ const stderrPromise = proc.stderr ? new Response(proc.stderr).text() : Promise.resolve("");
729
+ const [stdout, stderr, exitCode] = await Promise.all([
730
+ stdoutPromise,
731
+ stderrPromise,
732
+ proc.exited
733
+ ]);
734
+ if (timedOut) {
735
+ throw new Error(`Process timed out after ${options.timeoutMs}ms`);
736
+ }
737
+ return {
738
+ stdout: stdout.replace(/\r\n/g, "\n"),
739
+ stderr: stderr.replace(/\r\n/g, "\n"),
740
+ exitCode
741
+ };
742
+ } finally {
743
+ if (timeout !== void 0) {
744
+ clearTimeout(timeout);
745
+ }
746
+ }
747
+ }
748
+ async function execFileWithStdinNode(argv, stdinPayload, options) {
749
+ const { spawn: spawn5 } = await import("node:child_process");
750
+ return new Promise((resolve, reject) => {
751
+ const [cmd, ...args] = argv;
752
+ const child = spawn5(cmd, args, {
753
+ cwd: options.cwd,
754
+ stdio: ["pipe", "pipe", "pipe"],
755
+ // Merge additional env vars with process.env
756
+ env: options.env ? { ...process.env, ...options.env } : process.env
757
+ });
758
+ const stdoutChunks = [];
759
+ const stderrChunks = [];
760
+ child.stdout?.on("data", (chunk) => stdoutChunks.push(chunk));
761
+ child.stderr?.on("data", (chunk) => stderrChunks.push(chunk));
762
+ let timedOut = false;
763
+ const timeout = options.timeoutMs !== void 0 ? setTimeout(() => {
764
+ timedOut = true;
765
+ child.kill("SIGKILL");
766
+ }, options.timeoutMs) : void 0;
767
+ child.on("error", (error) => {
768
+ if (timeout !== void 0) clearTimeout(timeout);
769
+ reject(error);
770
+ });
771
+ child.on("close", (code) => {
772
+ if (timeout !== void 0) clearTimeout(timeout);
773
+ if (timedOut) {
774
+ reject(new Error(`Process timed out after ${options.timeoutMs}ms`));
775
+ return;
776
+ }
777
+ const stdout = Buffer.concat(stdoutChunks).toString("utf8").replace(/\r\n/g, "\n");
778
+ const stderr = Buffer.concat(stderrChunks).toString("utf8").replace(/\r\n/g, "\n");
779
+ resolve({
780
+ stdout,
781
+ stderr,
782
+ exitCode: code ?? 0
783
+ });
784
+ });
785
+ if (child.stdin) {
786
+ child.stdin.write(stdinPayload);
787
+ child.stdin.end();
788
+ }
789
+ });
790
+ }
791
+ async function execShellWithStdin(command, stdinPayload, options = {}) {
792
+ const { mkdir: mkdir16, readFile: readFile17, rm: rm6, writeFile: writeFile9 } = await import("node:fs/promises");
793
+ const { tmpdir: tmpdir3 } = await import("node:os");
794
+ const path52 = await import("node:path");
795
+ const { randomUUID: randomUUID10 } = await import("node:crypto");
796
+ const dir = path52.join(tmpdir3(), `agentv-exec-${randomUUID10()}`);
797
+ await mkdir16(dir, { recursive: true });
798
+ const stdinPath = path52.join(dir, "stdin.txt");
799
+ const stdoutPath = path52.join(dir, "stdout.txt");
800
+ const stderrPath = path52.join(dir, "stderr.txt");
801
+ await writeFile9(stdinPath, stdinPayload, "utf8");
802
+ const wrappedCommand = process.platform === "win32" ? `(${command}) < ${shellEscapePath(stdinPath)} > ${shellEscapePath(stdoutPath)} 2> ${shellEscapePath(stderrPath)}` : `(${command}) < ${shellEscapePath(stdinPath)} > ${shellEscapePath(stdoutPath)} 2> ${shellEscapePath(stderrPath)}`;
803
+ const { spawn: spawn5 } = await import("node:child_process");
804
+ try {
805
+ const exitCode = await new Promise((resolve, reject) => {
806
+ const child = spawn5(wrappedCommand, {
807
+ shell: true,
808
+ cwd: options.cwd,
809
+ stdio: ["ignore", "ignore", "ignore"],
810
+ // Merge additional env vars with process.env
811
+ env: options.env ? { ...process.env, ...options.env } : process.env
812
+ });
813
+ const timeout = options.timeoutMs ? setTimeout(() => {
814
+ child.kill();
815
+ reject(new Error(`Process timed out after ${options.timeoutMs}ms`));
816
+ }, options.timeoutMs) : void 0;
817
+ child.on("error", (error) => {
818
+ if (timeout !== void 0) {
819
+ clearTimeout(timeout);
820
+ }
821
+ reject(error);
822
+ });
823
+ child.on("exit", (code) => {
824
+ if (timeout !== void 0) {
825
+ clearTimeout(timeout);
826
+ }
827
+ resolve(code ?? 0);
828
+ });
829
+ });
830
+ const stdout = (await readFile17(stdoutPath, "utf8")).replace(/\r\n/g, "\n");
831
+ const stderr = (await readFile17(stderrPath, "utf8")).replace(/\r\n/g, "\n");
832
+ return { stdout, stderr, exitCode };
833
+ } finally {
834
+ await rm6(dir, { recursive: true, force: true });
835
+ }
836
+ }
837
+
838
+ // src/evaluation/content-preprocessor.ts
839
+ var MIME_TYPE_ALIASES = {
840
+ csv: "text/csv",
841
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
842
+ htm: "text/html",
843
+ html: "text/html",
844
+ json: "application/json",
845
+ markdown: "text/markdown",
846
+ md: "text/markdown",
847
+ pdf: "application/pdf",
848
+ sql: "application/sql",
849
+ txt: "text/plain",
850
+ xhtml: "application/xhtml+xml",
851
+ xls: "application/vnd.ms-excel",
852
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
853
+ xml: "application/xml",
854
+ yaml: "application/yaml",
855
+ yml: "application/yaml"
856
+ };
857
+ var REPLACEMENT_CHAR = "\uFFFD";
858
+ async function extractTextWithPreprocessors(content, preprocessors, options = {}) {
859
+ if (typeof content === "string") {
860
+ return { text: content, warnings: [] };
861
+ }
862
+ if (!content || content.length === 0) {
863
+ return { text: "", warnings: [] };
864
+ }
865
+ const parts = [];
866
+ const warnings = [];
867
+ for (const block of content) {
868
+ if (block.type === "text") {
869
+ parts.push(block.text);
870
+ continue;
871
+ }
872
+ if (block.type !== "file") {
873
+ continue;
874
+ }
875
+ const result = await preprocessContentFile(block, preprocessors, options.basePath);
876
+ if (result.text) {
877
+ parts.push(result.text);
878
+ }
879
+ warnings.push(...result.warnings);
880
+ }
881
+ return { text: parts.join("\n"), warnings };
882
+ }
883
+ async function preprocessContentFile(block, preprocessors, basePath) {
884
+ const mediaType = normalizePreprocessorType(block.media_type);
885
+ const resolvedPath = resolveLocalFilePath(block.path, basePath);
886
+ if (!resolvedPath) {
887
+ return {
888
+ text: "",
889
+ warnings: [
890
+ {
891
+ file: block.path,
892
+ mediaType: block.media_type,
893
+ reason: "remote file paths are not supported for preprocessing"
894
+ }
895
+ ]
896
+ };
897
+ }
898
+ const preprocessor = preprocessors?.find(
899
+ (entry) => normalizePreprocessorType(entry.type) === mediaType
900
+ );
901
+ if (preprocessor) {
902
+ return runContentPreprocessor(block, resolvedPath, preprocessor);
903
+ }
904
+ try {
905
+ const buffer = await readFile3(resolvedPath);
906
+ const text = buffer.toString("utf8").replace(/\r\n/g, "\n");
907
+ if (buffer.includes(0) || text.includes(REPLACEMENT_CHAR)) {
908
+ return {
909
+ text: "",
910
+ warnings: [
911
+ {
912
+ file: block.path,
913
+ mediaType: block.media_type,
914
+ reason: "default UTF-8 read produced binary or invalid text; configure a preprocessor"
915
+ }
916
+ ]
917
+ };
918
+ }
919
+ return { text: formatFileText(block.path, text), warnings: [] };
920
+ } catch (error) {
921
+ return {
922
+ text: "",
923
+ warnings: [
924
+ {
925
+ file: block.path,
926
+ mediaType: block.media_type,
927
+ reason: error instanceof Error ? error.message : String(error)
928
+ }
929
+ ]
930
+ };
931
+ }
932
+ }
933
+ async function runContentPreprocessor(block, resolvedPath, preprocessor) {
934
+ try {
935
+ const argv = preprocessor.resolvedCommand ?? preprocessor.command;
936
+ const { stdout, stderr, exitCode } = await execFileWithStdin(
937
+ argv,
938
+ JSON.stringify({
939
+ path: resolvedPath,
940
+ original_path: block.path,
941
+ media_type: block.media_type
942
+ })
943
+ );
944
+ if (exitCode !== 0) {
945
+ return {
946
+ text: "",
947
+ warnings: [
948
+ {
949
+ file: block.path,
950
+ mediaType: block.media_type,
951
+ reason: stderr.trim() || `preprocessor exited with code ${exitCode}`
952
+ }
953
+ ]
954
+ };
955
+ }
956
+ return { text: formatFileText(block.path, stdout.trim()), warnings: [] };
957
+ } catch (error) {
958
+ return {
959
+ text: "",
960
+ warnings: [
961
+ {
962
+ file: block.path,
963
+ mediaType: block.media_type,
964
+ reason: error instanceof Error ? error.message : String(error)
965
+ }
966
+ ]
967
+ };
968
+ }
969
+ }
970
+ function appendPreprocessingWarnings(text, warnings) {
971
+ if (warnings.length === 0) {
972
+ return text;
973
+ }
974
+ const notes = warnings.map(
975
+ (warning) => `[file preprocessing warning] ${warning.file} (${warning.mediaType}): ${warning.reason}`
976
+ );
977
+ return [text, ...notes].filter((part) => part.length > 0).join("\n");
978
+ }
979
+ function normalizePreprocessorType(value) {
980
+ const normalized = value.trim().toLowerCase();
981
+ return MIME_TYPE_ALIASES[normalized] ?? normalized;
982
+ }
983
+ function resolveLocalFilePath(value, basePath) {
984
+ if (value.startsWith("file://")) {
985
+ return fileURLToPath2(value);
986
+ }
987
+ if (/^[a-z]+:\/\//i.test(value)) {
988
+ return void 0;
989
+ }
990
+ return basePath ? path4.resolve(basePath, value) : path4.resolve(value);
991
+ }
992
+ function formatFileText(filePath, text) {
993
+ return `[[ file: ${filePath} ]]
994
+ ${text}`;
995
+ }
688
996
 
689
997
  // src/evaluation/validation/prompt-validator.ts
690
- import { readFile as readFile3 } from "node:fs/promises";
998
+ import { readFile as readFile4 } from "node:fs/promises";
691
999
 
692
1000
  // src/evaluation/template-variables.ts
693
1001
  var TEMPLATE_VARIABLES = {
@@ -718,7 +1026,7 @@ var DEPRECATED_TEMPLATE_VARIABLES = /* @__PURE__ */ new Map([
718
1026
  var ANSI_YELLOW2 = "\x1B[33m";
719
1027
  var ANSI_RESET3 = "\x1B[0m";
720
1028
  async function validateCustomPromptContent(promptPath) {
721
- const content = await readFile3(promptPath, "utf8");
1029
+ const content = await readFile4(promptPath, "utf8");
722
1030
  validateTemplateVariables(content, promptPath);
723
1031
  }
724
1032
  function validateTemplateVariables(content, source) {
@@ -775,22 +1083,32 @@ function normalizeEvaluatorType(type) {
775
1083
  function isDeprecatedJudgeType(type) {
776
1084
  return type === "code-judge" || type === "llm-judge";
777
1085
  }
778
- async function parseEvaluators(rawEvalCase, globalExecution, searchRoots, evalId) {
1086
+ async function parseEvaluators(rawEvalCase, globalExecution, searchRoots, evalId, defaultPreprocessors) {
779
1087
  const execution = rawEvalCase.execution;
780
1088
  const executionObject = isJsonObject2(execution) ? execution : void 0;
781
1089
  const caseEvaluators = rawEvalCase.assertions ?? rawEvalCase.assert ?? (executionObject ? executionObject.evaluators : void 0) ?? // deprecated: use assertions
782
1090
  rawEvalCase.evaluators;
783
1091
  const skipDefaults = executionObject?.skip_defaults === true;
784
1092
  const rootEvaluators = skipDefaults ? void 0 : globalExecution?.assertions ?? globalExecution?.assert ?? globalExecution?.evaluators;
785
- const parsedCase = await parseEvaluatorList(caseEvaluators, searchRoots, evalId);
786
- const parsedRoot = await parseEvaluatorList(rootEvaluators, searchRoots, evalId);
1093
+ const parsedCase = await parseEvaluatorList(
1094
+ caseEvaluators,
1095
+ searchRoots,
1096
+ evalId,
1097
+ defaultPreprocessors
1098
+ );
1099
+ const parsedRoot = await parseEvaluatorList(
1100
+ rootEvaluators,
1101
+ searchRoots,
1102
+ evalId,
1103
+ defaultPreprocessors
1104
+ );
787
1105
  if (!parsedCase && !parsedRoot) {
788
1106
  return void 0;
789
1107
  }
790
1108
  const evaluators = [...parsedCase ?? [], ...parsedRoot ?? []];
791
1109
  return evaluators.length > 0 ? evaluators : void 0;
792
1110
  }
793
- async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
1111
+ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId, defaultPreprocessors) {
794
1112
  if (candidateEvaluators === void 0) {
795
1113
  return void 0;
796
1114
  }
@@ -855,6 +1173,13 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
855
1173
  continue;
856
1174
  }
857
1175
  const negate = rawEvaluator.negate === true ? true : void 0;
1176
+ const mergedPreprocessors = await parseMergedPreprocessors(
1177
+ rawEvaluator.preprocessors,
1178
+ defaultPreprocessors,
1179
+ searchRoots,
1180
+ name,
1181
+ evalId
1182
+ );
858
1183
  if (isCustomType) {
859
1184
  const weight2 = validateWeight(rawEvaluator.weight, name, evalId);
860
1185
  const { required: required2, min_score: min_score2 } = parseRequiredAndMinScore(
@@ -913,7 +1238,7 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
913
1238
  if (cwd) {
914
1239
  const resolved = await resolveFileReference2(cwd, searchRoots);
915
1240
  if (resolved.resolvedPath) {
916
- resolvedCwd = path4.resolve(resolved.resolvedPath);
1241
+ resolvedCwd = path5.resolve(resolved.resolvedPath);
917
1242
  } else {
918
1243
  logWarning2(
919
1244
  `Code-grader evaluator '${name}' in '${evalId}': cwd not found (${resolved.displayPath})`,
@@ -959,6 +1284,7 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
959
1284
  "cwd",
960
1285
  "weight",
961
1286
  "target",
1287
+ "preprocessors",
962
1288
  "required",
963
1289
  "negate"
964
1290
  ]);
@@ -979,6 +1305,7 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
979
1305
  ...min_score2 !== void 0 ? { min_score: min_score2 } : {},
980
1306
  ...negate !== void 0 ? { negate } : {},
981
1307
  ...Object.keys(config2).length > 0 ? { config: config2 } : {},
1308
+ ...mergedPreprocessors ? { preprocessors: mergedPreprocessors } : {},
982
1309
  ...targetConfig !== void 0 ? { target: targetConfig } : {}
983
1310
  });
984
1311
  continue;
@@ -1088,7 +1415,7 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
1088
1415
  aggregatorPrompt = fileRef;
1089
1416
  const resolved = await resolveFileReference2(fileRef, searchRoots);
1090
1417
  if (resolved.resolvedPath) {
1091
- promptPath2 = path4.resolve(resolved.resolvedPath);
1418
+ promptPath2 = path5.resolve(resolved.resolvedPath);
1092
1419
  } else {
1093
1420
  throw new Error(
1094
1421
  `Composite aggregator in '${evalId}': prompt file not found: ${resolved.displayPath}`
@@ -1742,7 +2069,8 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
1742
2069
  ...weight2 !== void 0 ? { weight: weight2 } : {},
1743
2070
  ...required2 !== void 0 ? { required: required2 } : {},
1744
2071
  ...min_score2 !== void 0 ? { min_score: min_score2 } : {},
1745
- ...negate !== void 0 ? { negate } : {}
2072
+ ...negate !== void 0 ? { negate } : {},
2073
+ ...mergedPreprocessors ? { preprocessors: mergedPreprocessors } : {}
1746
2074
  });
1747
2075
  continue;
1748
2076
  }
@@ -1767,7 +2095,7 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
1767
2095
  const commandPath = commandArray[commandArray.length - 1];
1768
2096
  const resolved = await resolveFileReference2(commandPath, searchRoots);
1769
2097
  if (resolved.resolvedPath) {
1770
- resolvedPromptScript = [...commandArray.slice(0, -1), path4.resolve(resolved.resolvedPath)];
2098
+ resolvedPromptScript = [...commandArray.slice(0, -1), path5.resolve(resolved.resolvedPath)];
1771
2099
  } else {
1772
2100
  throw new Error(
1773
2101
  `Evaluator '${name}' in '${evalId}': prompt command file not found: ${resolved.displayPath}`
@@ -1782,7 +2110,7 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
1782
2110
  prompt = fileRef;
1783
2111
  const resolved = await resolveFileReference2(fileRef, searchRoots);
1784
2112
  if (resolved.resolvedPath) {
1785
- promptPath = path4.resolve(resolved.resolvedPath);
2113
+ promptPath = path5.resolve(resolved.resolvedPath);
1786
2114
  try {
1787
2115
  await validateCustomPromptContent(promptPath);
1788
2116
  } catch (error) {
@@ -1825,7 +2153,8 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
1825
2153
  ...weight2 !== void 0 ? { weight: weight2 } : {},
1826
2154
  ...required2 !== void 0 ? { required: required2 } : {},
1827
2155
  ...min_score2 !== void 0 ? { min_score: min_score2 } : {},
1828
- ...negate !== void 0 ? { negate } : {}
2156
+ ...negate !== void 0 ? { negate } : {},
2157
+ ...mergedPreprocessors ? { preprocessors: mergedPreprocessors } : {}
1829
2158
  });
1830
2159
  continue;
1831
2160
  }
@@ -1850,7 +2179,8 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
1850
2179
  "negate",
1851
2180
  "max_steps",
1852
2181
  "maxSteps",
1853
- "temperature"
2182
+ "temperature",
2183
+ "preprocessors"
1854
2184
  ]);
1855
2185
  const config = {};
1856
2186
  for (const [key, value] of Object.entries(rawEvaluator)) {
@@ -1880,30 +2210,70 @@ async function parseEvaluatorList(candidateEvaluators, searchRoots, evalId) {
1880
2210
  ...negate !== void 0 ? { negate } : {},
1881
2211
  ...finalConfig ? { config: finalConfig } : {},
1882
2212
  ...llmMaxSteps !== void 0 ? { max_steps: llmMaxSteps } : {},
1883
- ...llmTemperature !== void 0 ? { temperature: llmTemperature } : {}
2213
+ ...llmTemperature !== void 0 ? { temperature: llmTemperature } : {},
2214
+ ...mergedPreprocessors ? { preprocessors: mergedPreprocessors } : {}
1884
2215
  });
1885
2216
  }
1886
2217
  return evaluators.length > 0 ? evaluators : void 0;
1887
2218
  }
1888
- var ASSERTION_TYPES = /* @__PURE__ */ new Set([
1889
- "skill-trigger",
1890
- "contains",
1891
- "contains-any",
1892
- "contains-all",
1893
- "icontains",
1894
- "icontains-any",
1895
- "icontains-all",
1896
- "starts-with",
1897
- "ends-with",
1898
- "regex",
1899
- "is-json",
1900
- "equals",
1901
- "rubrics"
1902
- ]);
1903
- function generateAssertionName(typeValue, rawEvaluator) {
1904
- if (!ASSERTION_TYPES.has(typeValue)) {
2219
+ async function parseMergedPreprocessors(rawValue, defaultPreprocessors, searchRoots, evaluatorName, evalId) {
2220
+ const parsedDefaults = defaultPreprocessors ?? [];
2221
+ const parsedOverrides = await parsePreprocessors(rawValue, searchRoots, evaluatorName, evalId);
2222
+ if (parsedDefaults.length === 0 && (!parsedOverrides || parsedOverrides.length === 0)) {
2223
+ return void 0;
2224
+ }
2225
+ const merged = /* @__PURE__ */ new Map();
2226
+ for (const entry of parsedDefaults) {
2227
+ merged.set(normalizePreprocessorType(entry.type), entry);
2228
+ }
2229
+ for (const entry of parsedOverrides ?? []) {
2230
+ merged.set(normalizePreprocessorType(entry.type), entry);
2231
+ }
2232
+ return [...merged.values()];
2233
+ }
2234
+ async function parsePreprocessors(rawValue, searchRoots, evaluatorName, evalId) {
2235
+ if (rawValue === void 0) {
1905
2236
  return void 0;
1906
2237
  }
2238
+ if (!Array.isArray(rawValue)) {
2239
+ throw new Error(`Evaluator '${evaluatorName}' in '${evalId}': preprocessors must be an array`);
2240
+ }
2241
+ const preprocessors = [];
2242
+ for (const rawEntry of rawValue) {
2243
+ if (!isJsonObject2(rawEntry)) {
2244
+ throw new Error(
2245
+ `Evaluator '${evaluatorName}' in '${evalId}': each preprocessor must be an object`
2246
+ );
2247
+ }
2248
+ const type = asString(rawEntry.type)?.trim();
2249
+ if (!type) {
2250
+ throw new Error(`Evaluator '${evaluatorName}' in '${evalId}': preprocessor.type is required`);
2251
+ }
2252
+ const command = asStringArray(
2253
+ rawEntry.command,
2254
+ `preprocessor command for evaluator '${evaluatorName}' in '${evalId}'`
2255
+ );
2256
+ if (!command || command.length === 0) {
2257
+ throw new Error(
2258
+ `Evaluator '${evaluatorName}' in '${evalId}': preprocessor '${type}' requires command`
2259
+ );
2260
+ }
2261
+ const commandPath = command[command.length - 1];
2262
+ const resolved = await resolveFileReference2(commandPath, searchRoots);
2263
+ if (!resolved.resolvedPath) {
2264
+ throw new Error(
2265
+ `Evaluator '${evaluatorName}' in '${evalId}': preprocessor command file not found: ${resolved.displayPath}`
2266
+ );
2267
+ }
2268
+ preprocessors.push({
2269
+ type,
2270
+ command,
2271
+ resolvedCommand: [...command.slice(0, -1), path5.resolve(resolved.resolvedPath)]
2272
+ });
2273
+ }
2274
+ return preprocessors;
2275
+ }
2276
+ function generateAssertionName(typeValue, rawEvaluator) {
1907
2277
  const value = asString(rawEvaluator.value);
1908
2278
  const arrayValue = Array.isArray(rawEvaluator.value) ? rawEvaluator.value : void 0;
1909
2279
  switch (typeValue) {
@@ -1936,7 +2306,7 @@ function generateAssertionName(typeValue, rawEvaluator) {
1936
2306
  case "rubrics":
1937
2307
  return "rubrics";
1938
2308
  default:
1939
- return void 0;
2309
+ return typeValue;
1940
2310
  }
1941
2311
  }
1942
2312
  function coerceEvaluator(candidate, contextId) {
@@ -2294,14 +2664,14 @@ function parseInlineRubrics(rawRubrics) {
2294
2664
  }
2295
2665
 
2296
2666
  // src/evaluation/loaders/jsonl-parser.ts
2297
- import { readFile as readFile5 } from "node:fs/promises";
2298
- import path6 from "node:path";
2667
+ import { readFile as readFile6 } from "node:fs/promises";
2668
+ import path7 from "node:path";
2299
2669
  import micromatch from "micromatch";
2300
2670
  import { parse as parseYaml } from "yaml";
2301
2671
 
2302
2672
  // src/evaluation/loaders/message-processor.ts
2303
- import { readFile as readFile4 } from "node:fs/promises";
2304
- import path5 from "node:path";
2673
+ import { readFile as readFile5 } from "node:fs/promises";
2674
+ import path6 from "node:path";
2305
2675
 
2306
2676
  // src/evaluation/formatting/segment-formatter.ts
2307
2677
  function formatFileContents(parts) {
@@ -2367,7 +2737,7 @@ var IMAGE_MEDIA_TYPES = {
2367
2737
  ".bmp": "image/bmp"
2368
2738
  };
2369
2739
  function detectImageMediaType(filePath) {
2370
- const ext = path5.extname(filePath).toLowerCase();
2740
+ const ext = path6.extname(filePath).toLowerCase();
2371
2741
  return IMAGE_MEDIA_TYPES[ext];
2372
2742
  }
2373
2743
  var ANSI_YELLOW4 = "\x1B[33m";
@@ -2417,12 +2787,12 @@ async function processMessages(options) {
2417
2787
  continue;
2418
2788
  }
2419
2789
  try {
2420
- const fileContent = (await readFile4(resolvedPath, "utf8")).replace(/\r\n/g, "\n");
2790
+ const fileContent = (await readFile5(resolvedPath, "utf8")).replace(/\r\n/g, "\n");
2421
2791
  processedContent.push({
2422
2792
  ...cloneJsonObject(rawSegment),
2423
2793
  path: displayPath,
2424
2794
  text: fileContent,
2425
- resolvedPath: path5.resolve(resolvedPath)
2795
+ resolvedPath: path6.resolve(resolvedPath)
2426
2796
  });
2427
2797
  if (verbose) {
2428
2798
  const label = messageType === "input" ? "[File]" : "[Expected Output File]";
@@ -2458,7 +2828,7 @@ async function processMessages(options) {
2458
2828
  continue;
2459
2829
  }
2460
2830
  try {
2461
- const imageBuffer = await readFile4(resolvedPath);
2831
+ const imageBuffer = await readFile5(resolvedPath);
2462
2832
  const base64 = imageBuffer.toString("base64");
2463
2833
  processedContent.push({
2464
2834
  type: "image",
@@ -2535,12 +2905,12 @@ async function processExpectedMessages(options) {
2535
2905
  continue;
2536
2906
  }
2537
2907
  try {
2538
- const fileContent = (await readFile4(resolvedPath, "utf8")).replace(/\r\n/g, "\n");
2908
+ const fileContent = (await readFile5(resolvedPath, "utf8")).replace(/\r\n/g, "\n");
2539
2909
  processedContent.push({
2540
2910
  type: "file",
2541
2911
  path: displayPath,
2542
2912
  text: fileContent,
2543
- resolvedPath: path5.resolve(resolvedPath)
2913
+ resolvedPath: path6.resolve(resolvedPath)
2544
2914
  });
2545
2915
  if (verbose) {
2546
2916
  console.log(` [Expected Output File] Found: ${displayPath}`);
@@ -2575,7 +2945,7 @@ async function processExpectedMessages(options) {
2575
2945
  continue;
2576
2946
  }
2577
2947
  try {
2578
- const imageBuffer = await readFile4(resolvedPath);
2948
+ const imageBuffer = await readFile5(resolvedPath);
2579
2949
  const base64 = imageBuffer.toString("base64");
2580
2950
  processedContent.push({
2581
2951
  type: "image",
@@ -2684,7 +3054,7 @@ function matchesFilter(id, filter) {
2684
3054
  return typeof filter === "string" ? micromatch.isMatch(id, filter) : filter.some((pattern) => micromatch.isMatch(id, pattern));
2685
3055
  }
2686
3056
  function detectFormat(filePath) {
2687
- const ext = path6.extname(filePath).toLowerCase();
3057
+ const ext = path7.extname(filePath).toLowerCase();
2688
3058
  if (ext === ".jsonl") return "jsonl";
2689
3059
  if (ext === ".yaml" || ext === ".yml") return "yaml";
2690
3060
  if (ext === ".json") return "agent-skills-json";
@@ -2693,9 +3063,9 @@ function detectFormat(filePath) {
2693
3063
  );
2694
3064
  }
2695
3065
  async function loadSidecarMetadata(jsonlPath, verbose) {
2696
- const dir = path6.dirname(jsonlPath);
2697
- const base = path6.basename(jsonlPath, ".jsonl");
2698
- const sidecarPath = path6.join(dir, `${base}.yaml`);
3066
+ const dir = path7.dirname(jsonlPath);
3067
+ const base = path7.basename(jsonlPath, ".jsonl");
3068
+ const sidecarPath = path7.join(dir, `${base}.yaml`);
2699
3069
  if (!await fileExists2(sidecarPath)) {
2700
3070
  if (verbose) {
2701
3071
  logWarning4(`Sidecar metadata file not found: ${sidecarPath} (using defaults)`);
@@ -2703,7 +3073,7 @@ async function loadSidecarMetadata(jsonlPath, verbose) {
2703
3073
  return {};
2704
3074
  }
2705
3075
  try {
2706
- const content = await readFile5(sidecarPath, "utf8");
3076
+ const content = await readFile6(sidecarPath, "utf8");
2707
3077
  const parsed = interpolateEnv(parseYaml(content), process.env);
2708
3078
  if (!isJsonObject(parsed)) {
2709
3079
  logWarning4(`Invalid sidecar metadata format in ${sidecarPath}`);
@@ -2744,13 +3114,13 @@ function parseJsonlContent(content, filePath) {
2744
3114
  async function loadTestsFromJsonl(evalFilePath, repoRoot, options) {
2745
3115
  const verbose = options?.verbose ?? false;
2746
3116
  const filterPattern = options?.filter;
2747
- const absoluteTestPath = path6.resolve(evalFilePath);
3117
+ const absoluteTestPath = path7.resolve(evalFilePath);
2748
3118
  const repoRootPath = resolveToAbsolutePath(repoRoot);
2749
3119
  const searchRoots = buildSearchRoots2(absoluteTestPath, repoRootPath);
2750
3120
  const sidecar = await loadSidecarMetadata(absoluteTestPath, verbose);
2751
- const rawFile = await readFile5(absoluteTestPath, "utf8");
3121
+ const rawFile = await readFile6(absoluteTestPath, "utf8");
2752
3122
  const rawCases = parseJsonlContent(rawFile, evalFilePath);
2753
- const fallbackSuiteName = path6.basename(absoluteTestPath, ".jsonl") || "eval";
3123
+ const fallbackSuiteName = path7.basename(absoluteTestPath, ".jsonl") || "eval";
2754
3124
  const suiteName = sidecar.name && sidecar.name.trim().length > 0 ? sidecar.name : fallbackSuiteName;
2755
3125
  const globalEvaluator = coerceEvaluator(sidecar.evaluator, "sidecar") ?? "llm-grader";
2756
3126
  const globalExecution = sidecar.execution;
@@ -3109,8 +3479,8 @@ function resolveTests(suite) {
3109
3479
  }
3110
3480
  async function readTestSuiteMetadata(testFilePath) {
3111
3481
  try {
3112
- const absolutePath = path7.resolve(testFilePath);
3113
- const content = await readFile6(absolutePath, "utf8");
3482
+ const absolutePath = path8.resolve(testFilePath);
3483
+ const content = await readFile7(absolutePath, "utf8");
3114
3484
  const parsed = interpolateEnv(parse2(content), process.env);
3115
3485
  if (!isJsonObject(parsed)) {
3116
3486
  return {};
@@ -3164,25 +3534,31 @@ var loadEvalCases = loadTests;
3164
3534
  async function loadTestsFromYaml(evalFilePath, repoRoot, options) {
3165
3535
  const verbose = options?.verbose ?? false;
3166
3536
  const filterPattern = options?.filter;
3167
- const absoluteTestPath = path7.resolve(evalFilePath);
3537
+ const absoluteTestPath = path8.resolve(evalFilePath);
3168
3538
  const repoRootPath = resolveToAbsolutePath(repoRoot);
3169
3539
  const searchRoots = buildSearchRoots2(absoluteTestPath, repoRootPath);
3170
3540
  const config = await loadConfig(absoluteTestPath, repoRootPath);
3171
- const rawFile = await readFile6(absoluteTestPath, "utf8");
3541
+ const rawFile = await readFile7(absoluteTestPath, "utf8");
3172
3542
  const interpolated = interpolateEnv(parse2(rawFile), process.env);
3173
3543
  if (!isJsonObject(interpolated)) {
3174
3544
  throw new Error(`Invalid test file format: ${evalFilePath}`);
3175
3545
  }
3176
3546
  const suite = interpolated;
3177
3547
  const suiteNameFromFile = asString5(suite.name)?.trim();
3178
- const fallbackSuiteName = path7.basename(absoluteTestPath).replace(/\.eval\.ya?ml$/i, "").replace(/\.ya?ml$/i, "") || "eval";
3548
+ const fallbackSuiteName = path8.basename(absoluteTestPath).replace(/\.eval\.ya?ml$/i, "").replace(/\.ya?ml$/i, "") || "eval";
3179
3549
  const suiteName = suiteNameFromFile && suiteNameFromFile.length > 0 ? suiteNameFromFile : fallbackSuiteName;
3180
3550
  const rawTestCases = resolveTests(suite);
3181
3551
  const globalEvaluator = coerceEvaluator(suite.evaluator, "global") ?? "llm-grader";
3182
- const evalFileDir = path7.dirname(absoluteTestPath);
3552
+ const suitePreprocessors = await parsePreprocessors(
3553
+ suite.preprocessors,
3554
+ searchRoots,
3555
+ "<suite>",
3556
+ absoluteTestPath
3557
+ );
3558
+ const evalFileDir = path8.dirname(absoluteTestPath);
3183
3559
  let expandedTestCases;
3184
3560
  if (typeof rawTestCases === "string") {
3185
- const externalPath = path7.resolve(evalFileDir, rawTestCases);
3561
+ const externalPath = path8.resolve(evalFileDir, rawTestCases);
3186
3562
  expandedTestCases = await loadCasesFromFile(externalPath);
3187
3563
  } else if (Array.isArray(rawTestCases)) {
3188
3564
  expandedTestCases = await expandFileReferences(rawTestCases, evalFileDir);
@@ -3280,7 +3656,8 @@ async function loadTestsFromYaml(evalFilePath, repoRoot, options) {
3280
3656
  testCaseConfig,
3281
3657
  globalExecution,
3282
3658
  searchRoots,
3283
- id ?? "unknown"
3659
+ id ?? "unknown",
3660
+ suitePreprocessors
3284
3661
  );
3285
3662
  } catch (error) {
3286
3663
  const message = error instanceof Error ? error.message : String(error);
@@ -3313,6 +3690,7 @@ async function loadTestsFromYaml(evalFilePath, repoRoot, options) {
3313
3690
  criteria: outcome ?? "",
3314
3691
  evaluator: testCaseEvaluatorKind,
3315
3692
  assertions: evaluators,
3693
+ ...suitePreprocessors ? { preprocessors: suitePreprocessors } : {},
3316
3694
  workspace: mergedWorkspace,
3317
3695
  metadata,
3318
3696
  targets: caseTargets,
@@ -3353,8 +3731,8 @@ function parseWorkspaceScriptConfig(raw, evalFileDir) {
3353
3731
  if (!command) return void 0;
3354
3732
  const timeoutMs = typeof obj.timeout_ms === "number" ? obj.timeout_ms : void 0;
3355
3733
  let cwd = typeof obj.cwd === "string" ? obj.cwd : void 0;
3356
- if (cwd && !path7.isAbsolute(cwd)) {
3357
- cwd = path7.resolve(evalFileDir, cwd);
3734
+ if (cwd && !path8.isAbsolute(cwd)) {
3735
+ cwd = path8.resolve(evalFileDir, cwd);
3358
3736
  }
3359
3737
  const config = { command };
3360
3738
  if (timeoutMs !== void 0) {
@@ -3392,10 +3770,10 @@ function parseWorkspaceHooksConfig(raw, evalFileDir) {
3392
3770
  }
3393
3771
  async function resolveWorkspaceConfig(raw, evalFileDir) {
3394
3772
  if (typeof raw === "string") {
3395
- const workspaceFilePath = path7.resolve(evalFileDir, raw);
3773
+ const workspaceFilePath = path8.resolve(evalFileDir, raw);
3396
3774
  let content;
3397
3775
  try {
3398
- content = await readFile6(workspaceFilePath, "utf8");
3776
+ content = await readFile7(workspaceFilePath, "utf8");
3399
3777
  } catch {
3400
3778
  throw new Error(`Workspace file not found: ${raw} (resolved to ${workspaceFilePath})`);
3401
3779
  }
@@ -3405,7 +3783,7 @@ async function resolveWorkspaceConfig(raw, evalFileDir) {
3405
3783
  `Invalid workspace file format: ${workspaceFilePath} (expected a YAML object)`
3406
3784
  );
3407
3785
  }
3408
- const workspaceFileDir = path7.dirname(workspaceFilePath);
3786
+ const workspaceFileDir = path8.dirname(workspaceFilePath);
3409
3787
  return parseWorkspaceConfig(parsed, workspaceFileDir);
3410
3788
  }
3411
3789
  return parseWorkspaceConfig(raw, evalFileDir);
@@ -3425,8 +3803,8 @@ function parseWorkspaceConfig(raw, evalFileDir) {
3425
3803
  throw new Error("workspace.static has been removed. Use workspace.mode='static'.");
3426
3804
  }
3427
3805
  let template = typeof obj.template === "string" ? obj.template : void 0;
3428
- if (template && !path7.isAbsolute(template)) {
3429
- template = path7.resolve(evalFileDir, template);
3806
+ if (template && !path8.isAbsolute(template)) {
3807
+ template = path8.resolve(evalFileDir, template);
3430
3808
  }
3431
3809
  const isolation = obj.isolation === "shared" || obj.isolation === "per_test" ? obj.isolation : void 0;
3432
3810
  const repos = Array.isArray(obj.repos) ? obj.repos.map(parseRepoConfig).filter(Boolean) : void 0;
@@ -3497,7 +3875,7 @@ ${detailBlock}${ANSI_RESET7}`);
3497
3875
 
3498
3876
  // src/evaluation/loaders/eval-yaml-transpiler.ts
3499
3877
  import { readFileSync } from "node:fs";
3500
- import path8 from "node:path";
3878
+ import path9 from "node:path";
3501
3879
  import { parse as parse3 } from "yaml";
3502
3880
  function codeGraderInstruction(graderName, description) {
3503
3881
  const desc = description ? ` This grader: ${description}.` : "";
@@ -3738,7 +4116,7 @@ function transpileEvalYaml(suite, source = "EVAL.yaml") {
3738
4116
  function transpileEvalYamlFile(evalYamlPath) {
3739
4117
  const content = readFileSync(evalYamlPath, "utf8");
3740
4118
  const parsed = parse3(content);
3741
- return transpileEvalYaml(parsed, path8.basename(evalYamlPath));
4119
+ return transpileEvalYaml(parsed, path9.basename(evalYamlPath));
3742
4120
  }
3743
4121
  function getOutputFilenames(result) {
3744
4122
  const names = /* @__PURE__ */ new Map();
@@ -4176,7 +4554,7 @@ import { spawn } from "node:child_process";
4176
4554
  import { randomUUID } from "node:crypto";
4177
4555
  import { createWriteStream } from "node:fs";
4178
4556
  import { mkdir } from "node:fs/promises";
4179
- import path10 from "node:path";
4557
+ import path11 from "node:path";
4180
4558
 
4181
4559
  // src/evaluation/providers/claude-content.ts
4182
4560
  function toContentArray(content) {
@@ -4275,7 +4653,7 @@ function subscribeToClaudeLogEntries(listener) {
4275
4653
  }
4276
4654
 
4277
4655
  // src/evaluation/providers/preread.ts
4278
- import path9 from "node:path";
4656
+ import path10 from "node:path";
4279
4657
  function buildPromptDocument(request, inputFiles) {
4280
4658
  const parts = [];
4281
4659
  const inputFilesList = collectInputFiles(inputFiles);
@@ -4292,7 +4670,7 @@ function normalizeInputFiles(inputFiles) {
4292
4670
  }
4293
4671
  const deduped = /* @__PURE__ */ new Map();
4294
4672
  for (const inputFile of inputFiles) {
4295
- const absolutePath = path9.resolve(inputFile);
4673
+ const absolutePath = path10.resolve(inputFile);
4296
4674
  if (!deduped.has(absolutePath)) {
4297
4675
  deduped.set(absolutePath, absolutePath);
4298
4676
  }
@@ -4305,7 +4683,7 @@ function collectInputFiles(inputFiles) {
4305
4683
  }
4306
4684
  const unique = /* @__PURE__ */ new Map();
4307
4685
  for (const inputFile of inputFiles) {
4308
- const absolutePath = path9.resolve(inputFile);
4686
+ const absolutePath = path10.resolve(inputFile);
4309
4687
  if (!unique.has(absolutePath)) {
4310
4688
  unique.set(absolutePath, absolutePath);
4311
4689
  }
@@ -4317,7 +4695,7 @@ function buildMandatoryPrereadBlock(inputFiles) {
4317
4695
  return "";
4318
4696
  }
4319
4697
  const buildList = (files) => files.map((absolutePath) => {
4320
- const fileName = path9.basename(absolutePath);
4698
+ const fileName = path10.basename(absolutePath);
4321
4699
  const fileUri = pathToFileUri(absolutePath);
4322
4700
  return `* [${fileName}](${fileUri})`;
4323
4701
  });
@@ -4333,7 +4711,7 @@ ${buildList(inputFiles).join("\n")}.`);
4333
4711
  return sections.join("\n");
4334
4712
  }
4335
4713
  function pathToFileUri(filePath) {
4336
- const absolutePath = path9.isAbsolute(filePath) ? filePath : path9.resolve(filePath);
4714
+ const absolutePath = path10.isAbsolute(filePath) ? filePath : path10.resolve(filePath);
4337
4715
  const normalizedPath = absolutePath.replace(/\\/g, "/");
4338
4716
  if (/^[a-zA-Z]:\//.test(normalizedPath)) {
4339
4717
  return `file:///${normalizedPath}`;
@@ -4481,10 +4859,10 @@ var ClaudeCliProvider = class {
4481
4859
  }
4482
4860
  resolveCwd(cwdOverride) {
4483
4861
  if (cwdOverride) {
4484
- return path10.resolve(cwdOverride);
4862
+ return path11.resolve(cwdOverride);
4485
4863
  }
4486
4864
  if (this.config.cwd) {
4487
- return path10.resolve(this.config.cwd);
4865
+ return path11.resolve(this.config.cwd);
4488
4866
  }
4489
4867
  return void 0;
4490
4868
  }
@@ -4494,9 +4872,9 @@ var ClaudeCliProvider = class {
4494
4872
  return void 0;
4495
4873
  }
4496
4874
  if (this.config.logDir) {
4497
- return path10.resolve(this.config.logDir);
4875
+ return path11.resolve(this.config.logDir);
4498
4876
  }
4499
- return path10.join(process.cwd(), ".agentv", "logs", "claude-cli");
4877
+ return path11.join(process.cwd(), ".agentv", "logs", "claude-cli");
4500
4878
  }
4501
4879
  async createStreamLogger(request) {
4502
4880
  const logDir = this.resolveLogDirectory();
@@ -4510,7 +4888,7 @@ var ClaudeCliProvider = class {
4510
4888
  console.warn(`Skipping Claude CLI stream logging (could not create ${logDir}): ${message}`);
4511
4889
  return void 0;
4512
4890
  }
4513
- const filePath = path10.join(logDir, buildLogFilename(request, this.targetName));
4891
+ const filePath = path11.join(logDir, buildLogFilename(request, this.targetName));
4514
4892
  try {
4515
4893
  const logger = await ClaudeCliStreamLogger.create({
4516
4894
  filePath,
@@ -4812,7 +5190,7 @@ function tryParseJson(line) {
4812
5190
  import { randomUUID as randomUUID2 } from "node:crypto";
4813
5191
  import { createWriteStream as createWriteStream2 } from "node:fs";
4814
5192
  import { mkdir as mkdir2 } from "node:fs/promises";
4815
- import path11 from "node:path";
5193
+ import path12 from "node:path";
4816
5194
  var claudeSdkModule = null;
4817
5195
  async function loadClaudeSdk() {
4818
5196
  if (!claudeSdkModule) {
@@ -4973,10 +5351,10 @@ var ClaudeSdkProvider = class {
4973
5351
  }
4974
5352
  resolveCwd(cwdOverride) {
4975
5353
  if (cwdOverride) {
4976
- return path11.resolve(cwdOverride);
5354
+ return path12.resolve(cwdOverride);
4977
5355
  }
4978
5356
  if (this.config.cwd) {
4979
- return path11.resolve(this.config.cwd);
5357
+ return path12.resolve(this.config.cwd);
4980
5358
  }
4981
5359
  return void 0;
4982
5360
  }
@@ -4986,9 +5364,9 @@ var ClaudeSdkProvider = class {
4986
5364
  return void 0;
4987
5365
  }
4988
5366
  if (this.config.logDir) {
4989
- return path11.resolve(this.config.logDir);
5367
+ return path12.resolve(this.config.logDir);
4990
5368
  }
4991
- return path11.join(process.cwd(), ".agentv", "logs", "claude");
5369
+ return path12.join(process.cwd(), ".agentv", "logs", "claude");
4992
5370
  }
4993
5371
  async createStreamLogger(request) {
4994
5372
  const logDir = this.resolveLogDirectory();
@@ -5002,7 +5380,7 @@ var ClaudeSdkProvider = class {
5002
5380
  console.warn(`Skipping Claude stream logging (could not create ${logDir}): ${message}`);
5003
5381
  return void 0;
5004
5382
  }
5005
- const filePath = path11.join(logDir, buildLogFilename2(request, this.targetName));
5383
+ const filePath = path12.join(logDir, buildLogFilename2(request, this.targetName));
5006
5384
  try {
5007
5385
  const logger = await ClaudeStreamLogger.create({
5008
5386
  filePath,
@@ -5190,7 +5568,7 @@ function formatElapsed2(startedAt) {
5190
5568
  import { exec as execWithCallback } from "node:child_process";
5191
5569
  import fs from "node:fs/promises";
5192
5570
  import os from "node:os";
5193
- import path12 from "node:path";
5571
+ import path13 from "node:path";
5194
5572
  import { promisify } from "node:util";
5195
5573
  import { z as z2 } from "zod";
5196
5574
  var ToolCallSchema = z2.object({
@@ -5693,7 +6071,7 @@ function normalizeInputFiles2(inputFiles) {
5693
6071
  }
5694
6072
  const unique = /* @__PURE__ */ new Map();
5695
6073
  for (const inputFile of inputFiles) {
5696
- const absolutePath = path12.resolve(inputFile);
6074
+ const absolutePath = path13.resolve(inputFile);
5697
6075
  if (!unique.has(absolutePath)) {
5698
6076
  unique.set(absolutePath, absolutePath);
5699
6077
  }
@@ -5707,7 +6085,7 @@ function formatFileList(files, template) {
5707
6085
  const formatter = template ?? "{path}";
5708
6086
  return files.map((filePath) => {
5709
6087
  const escapedPath = shellEscape(filePath);
5710
- const escapedName = shellEscape(path12.basename(filePath));
6088
+ const escapedName = shellEscape(path13.basename(filePath));
5711
6089
  return formatter.replaceAll("{path}", escapedPath).replaceAll("{basename}", escapedName);
5712
6090
  }).join(" ");
5713
6091
  }
@@ -5731,7 +6109,7 @@ function generateOutputFilePath(evalCaseId, extension = ".json") {
5731
6109
  const safeEvalId = evalCaseId || "unknown";
5732
6110
  const timestamp = Date.now();
5733
6111
  const random = Math.random().toString(36).substring(2, 9);
5734
- return path12.join(os.tmpdir(), `agentv-${safeEvalId}-${timestamp}-${random}${extension}`);
6112
+ return path13.join(os.tmpdir(), `agentv-${safeEvalId}-${timestamp}-${random}${extension}`);
5735
6113
  }
5736
6114
  function formatTimeoutSuffix2(timeoutMs) {
5737
6115
  if (!timeoutMs || timeoutMs <= 0) {
@@ -5745,7 +6123,7 @@ function formatTimeoutSuffix2(timeoutMs) {
5745
6123
  import { randomUUID as randomUUID3 } from "node:crypto";
5746
6124
  import { createWriteStream as createWriteStream3 } from "node:fs";
5747
6125
  import { mkdir as mkdir3 } from "node:fs/promises";
5748
- import path13 from "node:path";
6126
+ import path14 from "node:path";
5749
6127
 
5750
6128
  // src/evaluation/providers/codex-log-tracker.ts
5751
6129
  var GLOBAL_LOGS_KEY2 = Symbol.for("agentv.codexLogs");
@@ -5980,10 +6358,10 @@ ${basePrompt}` : basePrompt;
5980
6358
  }
5981
6359
  resolveCwd(cwdOverride) {
5982
6360
  if (cwdOverride) {
5983
- return path13.resolve(cwdOverride);
6361
+ return path14.resolve(cwdOverride);
5984
6362
  }
5985
6363
  if (this.config.cwd) {
5986
- return path13.resolve(this.config.cwd);
6364
+ return path14.resolve(this.config.cwd);
5987
6365
  }
5988
6366
  return void 0;
5989
6367
  }
@@ -5993,9 +6371,9 @@ ${basePrompt}` : basePrompt;
5993
6371
  return void 0;
5994
6372
  }
5995
6373
  if (this.config.logDir) {
5996
- return path13.resolve(this.config.logDir);
6374
+ return path14.resolve(this.config.logDir);
5997
6375
  }
5998
- return path13.join(process.cwd(), ".agentv", "logs", "codex");
6376
+ return path14.join(process.cwd(), ".agentv", "logs", "codex");
5999
6377
  }
6000
6378
  async createStreamLogger(request) {
6001
6379
  const logDir = this.resolveLogDirectory();
@@ -6009,7 +6387,7 @@ ${basePrompt}` : basePrompt;
6009
6387
  console.warn(`Skipping Codex SDK stream logging (could not create ${logDir}): ${message}`);
6010
6388
  return void 0;
6011
6389
  }
6012
- const filePath = path13.join(logDir, buildLogFilename3(request, this.targetName));
6390
+ const filePath = path14.join(logDir, buildLogFilename3(request, this.targetName));
6013
6391
  try {
6014
6392
  const logger = await CodexSdkStreamLogger.create({
6015
6393
  filePath,
@@ -6153,7 +6531,7 @@ function formatElapsed3(startedAt) {
6153
6531
  // src/evaluation/providers/copilot-cli.ts
6154
6532
  import { randomUUID as randomUUID5 } from "node:crypto";
6155
6533
  import { mkdir as mkdir4 } from "node:fs/promises";
6156
- import path15 from "node:path";
6534
+ import path16 from "node:path";
6157
6535
  import { Readable, Writable } from "node:stream";
6158
6536
  import { spawn as spawn2 } from "node:child_process";
6159
6537
  import * as acp from "@agentclientprotocol/sdk";
@@ -6215,8 +6593,8 @@ function subscribeToCopilotCliLogEntries(listener) {
6215
6593
  import { randomUUID as randomUUID4 } from "node:crypto";
6216
6594
  import { createWriteStream as createWriteStream4, existsSync, readdirSync } from "node:fs";
6217
6595
  import { arch, platform } from "node:os";
6218
- import path14 from "node:path";
6219
- import { fileURLToPath as fileURLToPath2 } from "node:url";
6596
+ import path15 from "node:path";
6597
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
6220
6598
  function resolvePlatformCliPath() {
6221
6599
  const os3 = platform();
6222
6600
  const cpu = arch();
@@ -6238,8 +6616,8 @@ function resolvePlatformCliPath() {
6238
6616
  const binaryName = os3 === "win32" ? "copilot.exe" : "copilot";
6239
6617
  try {
6240
6618
  const resolved = import.meta.resolve(`${packageName}/package.json`);
6241
- const packageJsonPath = resolved.startsWith("file:") ? fileURLToPath2(resolved) : resolved;
6242
- const binaryPath = path14.join(path14.dirname(packageJsonPath), binaryName);
6619
+ const packageJsonPath = resolved.startsWith("file:") ? fileURLToPath3(resolved) : resolved;
6620
+ const binaryPath = path15.join(path15.dirname(packageJsonPath), binaryName);
6243
6621
  if (existsSync(binaryPath)) {
6244
6622
  return binaryPath;
6245
6623
  }
@@ -6247,7 +6625,7 @@ function resolvePlatformCliPath() {
6247
6625
  }
6248
6626
  let searchDir = process.cwd();
6249
6627
  for (let i = 0; i < 10; i++) {
6250
- const standardPath = path14.join(
6628
+ const standardPath = path15.join(
6251
6629
  searchDir,
6252
6630
  "node_modules",
6253
6631
  ...packageName.split("/"),
@@ -6256,13 +6634,13 @@ function resolvePlatformCliPath() {
6256
6634
  if (existsSync(standardPath)) {
6257
6635
  return standardPath;
6258
6636
  }
6259
- const bunDir = path14.join(searchDir, "node_modules", ".bun");
6637
+ const bunDir = path15.join(searchDir, "node_modules", ".bun");
6260
6638
  const prefix = `@github+copilot-${osPart}-${archPart}@`;
6261
6639
  try {
6262
6640
  const entries = readdirSync(bunDir);
6263
6641
  for (const entry of entries) {
6264
6642
  if (entry.startsWith(prefix)) {
6265
- const candidate = path14.join(
6643
+ const candidate = path15.join(
6266
6644
  bunDir,
6267
6645
  entry,
6268
6646
  "node_modules",
@@ -6277,7 +6655,7 @@ function resolvePlatformCliPath() {
6277
6655
  }
6278
6656
  } catch {
6279
6657
  }
6280
- const parent = path14.dirname(searchDir);
6658
+ const parent = path15.dirname(searchDir);
6281
6659
  if (parent === searchDir) break;
6282
6660
  searchDir = parent;
6283
6661
  }
@@ -6621,10 +6999,10 @@ var CopilotCliProvider = class {
6621
6999
  }
6622
7000
  resolveCwd(cwdOverride) {
6623
7001
  if (cwdOverride) {
6624
- return path15.resolve(cwdOverride);
7002
+ return path16.resolve(cwdOverride);
6625
7003
  }
6626
7004
  if (this.config.cwd) {
6627
- return path15.resolve(this.config.cwd);
7005
+ return path16.resolve(this.config.cwd);
6628
7006
  }
6629
7007
  return void 0;
6630
7008
  }
@@ -6643,9 +7021,9 @@ var CopilotCliProvider = class {
6643
7021
  return void 0;
6644
7022
  }
6645
7023
  if (this.config.logDir) {
6646
- return path15.resolve(this.config.logDir);
7024
+ return path16.resolve(this.config.logDir);
6647
7025
  }
6648
- return path15.join(process.cwd(), ".agentv", "logs", "copilot-cli");
7026
+ return path16.join(process.cwd(), ".agentv", "logs", "copilot-cli");
6649
7027
  }
6650
7028
  async createStreamLogger(request) {
6651
7029
  const logDir = this.resolveLogDirectory();
@@ -6659,7 +7037,7 @@ var CopilotCliProvider = class {
6659
7037
  console.warn(`Skipping Copilot CLI stream logging (could not create ${logDir}): ${message}`);
6660
7038
  return void 0;
6661
7039
  }
6662
- const filePath = path15.join(logDir, buildLogFilename4(request, this.targetName, "copilot-cli"));
7040
+ const filePath = path16.join(logDir, buildLogFilename4(request, this.targetName, "copilot-cli"));
6663
7041
  try {
6664
7042
  const logger = await CopilotStreamLogger.create(
6665
7043
  {
@@ -6752,9 +7130,9 @@ function summarizeAcpEvent(eventType, data) {
6752
7130
  }
6753
7131
 
6754
7132
  // src/evaluation/providers/copilot-log.ts
6755
- import { readFile as readFile8 } from "node:fs/promises";
7133
+ import { readFile as readFile9 } from "node:fs/promises";
6756
7134
  import { homedir as homedir2 } from "node:os";
6757
- import path17 from "node:path";
7135
+ import path18 from "node:path";
6758
7136
 
6759
7137
  // src/evaluation/providers/copilot-log-parser.ts
6760
7138
  function parseCopilotEvents(eventsJsonl) {
@@ -6886,11 +7264,11 @@ function parseCopilotEvents(eventsJsonl) {
6886
7264
  }
6887
7265
 
6888
7266
  // src/evaluation/providers/copilot-session-discovery.ts
6889
- import { readFile as readFile7, readdir, stat } from "node:fs/promises";
7267
+ import { readFile as readFile8, readdir, stat } from "node:fs/promises";
6890
7268
  import { homedir } from "node:os";
6891
- import path16 from "node:path";
7269
+ import path17 from "node:path";
6892
7270
  import { parse as parseYaml2 } from "yaml";
6893
- var DEFAULT_SESSION_STATE_DIR = () => path16.join(homedir(), ".copilot", "session-state");
7271
+ var DEFAULT_SESSION_STATE_DIR = () => path17.join(homedir(), ".copilot", "session-state");
6894
7272
  async function discoverCopilotSessions(opts) {
6895
7273
  const sessionStateDir = opts?.sessionStateDir ?? DEFAULT_SESSION_STATE_DIR();
6896
7274
  const limit = opts?.limit ?? 10;
@@ -6902,11 +7280,11 @@ async function discoverCopilotSessions(opts) {
6902
7280
  }
6903
7281
  const sessions = [];
6904
7282
  for (const entry of entries) {
6905
- const sessionDir = path16.join(sessionStateDir, entry);
6906
- const workspacePath = path16.join(sessionDir, "workspace.yaml");
6907
- const eventsPath = path16.join(sessionDir, "events.jsonl");
7283
+ const sessionDir = path17.join(sessionStateDir, entry);
7284
+ const workspacePath = path17.join(sessionDir, "workspace.yaml");
7285
+ const eventsPath = path17.join(sessionDir, "events.jsonl");
6908
7286
  try {
6909
- const workspaceContent = await readFile7(workspacePath, "utf8");
7287
+ const workspaceContent = await readFile8(workspacePath, "utf8");
6910
7288
  const workspace = parseYaml2(workspaceContent) ?? {};
6911
7289
  const cwd = String(workspace.cwd ?? "");
6912
7290
  let updatedAt;
@@ -6965,10 +7343,10 @@ var CopilotLogProvider = class {
6965
7343
  }
6966
7344
  async invoke(_request) {
6967
7345
  const sessionDir = await this.resolveSessionDir();
6968
- const eventsPath = path17.join(sessionDir, "events.jsonl");
7346
+ const eventsPath = path18.join(sessionDir, "events.jsonl");
6969
7347
  let eventsContent;
6970
7348
  try {
6971
- eventsContent = await readFile8(eventsPath, "utf8");
7349
+ eventsContent = await readFile9(eventsPath, "utf8");
6972
7350
  } catch (err) {
6973
7351
  throw new Error(
6974
7352
  `Failed to read Copilot session transcript at ${eventsPath}: ${err instanceof Error ? err.message : String(err)}`
@@ -6987,8 +7365,8 @@ var CopilotLogProvider = class {
6987
7365
  return this.config.sessionDir;
6988
7366
  }
6989
7367
  if (this.config.sessionId) {
6990
- const stateDir = this.config.sessionStateDir ?? path17.join(homedir2(), ".copilot", "session-state");
6991
- return path17.join(stateDir, this.config.sessionId);
7368
+ const stateDir = this.config.sessionStateDir ?? path18.join(homedir2(), ".copilot", "session-state");
7369
+ return path18.join(stateDir, this.config.sessionId);
6992
7370
  }
6993
7371
  if (this.config.discover === "latest") {
6994
7372
  const sessions = await discoverCopilotSessions({
@@ -7013,7 +7391,7 @@ var CopilotLogProvider = class {
7013
7391
  import { randomUUID as randomUUID6 } from "node:crypto";
7014
7392
  import { existsSync as existsSync2 } from "node:fs";
7015
7393
  import { mkdir as mkdir5 } from "node:fs/promises";
7016
- import path18 from "node:path";
7394
+ import path19 from "node:path";
7017
7395
 
7018
7396
  // src/evaluation/providers/copilot-sdk-log-tracker.ts
7019
7397
  var GLOBAL_LOGS_KEY4 = Symbol.for("agentv.copilotSdkLogs");
@@ -7323,10 +7701,10 @@ var CopilotSdkProvider = class {
7323
7701
  }
7324
7702
  resolveCwd(cwdOverride) {
7325
7703
  if (cwdOverride) {
7326
- return path18.resolve(cwdOverride);
7704
+ return path19.resolve(cwdOverride);
7327
7705
  }
7328
7706
  if (this.config.cwd) {
7329
- return path18.resolve(this.config.cwd);
7707
+ return path19.resolve(this.config.cwd);
7330
7708
  }
7331
7709
  return void 0;
7332
7710
  }
@@ -7335,9 +7713,9 @@ var CopilotSdkProvider = class {
7335
7713
  return void 0;
7336
7714
  }
7337
7715
  if (this.config.logDir) {
7338
- return path18.resolve(this.config.logDir);
7716
+ return path19.resolve(this.config.logDir);
7339
7717
  }
7340
- return path18.join(process.cwd(), ".agentv", "logs", "copilot-sdk");
7718
+ return path19.join(process.cwd(), ".agentv", "logs", "copilot-sdk");
7341
7719
  }
7342
7720
  async createStreamLogger(request) {
7343
7721
  const logDir = this.resolveLogDirectory();
@@ -7351,7 +7729,7 @@ var CopilotSdkProvider = class {
7351
7729
  console.warn(`Skipping Copilot SDK stream logging (could not create ${logDir}): ${message}`);
7352
7730
  return void 0;
7353
7731
  }
7354
- const filePath = path18.join(logDir, buildLogFilename4(request, this.targetName, "copilot-sdk"));
7732
+ const filePath = path19.join(logDir, buildLogFilename4(request, this.targetName, "copilot-sdk"));
7355
7733
  try {
7356
7734
  const logger = await CopilotStreamLogger.create(
7357
7735
  {
@@ -7380,9 +7758,9 @@ var CopilotSdkProvider = class {
7380
7758
  };
7381
7759
  function resolveSkillDirectories(cwd) {
7382
7760
  const candidates = [
7383
- path18.join(cwd, ".claude", "skills"),
7384
- path18.join(cwd, ".agents", "skills"),
7385
- path18.join(cwd, ".codex", "skills")
7761
+ path19.join(cwd, ".claude", "skills"),
7762
+ path19.join(cwd, ".agents", "skills"),
7763
+ path19.join(cwd, ".codex", "skills")
7386
7764
  ];
7387
7765
  return candidates.filter((dir) => existsSync2(dir));
7388
7766
  }
@@ -7466,7 +7844,7 @@ import { randomUUID as randomUUID7 } from "node:crypto";
7466
7844
  import { accessSync, createWriteStream as createWriteStream5, readFileSync as readFileSync2 } from "node:fs";
7467
7845
  import { mkdir as mkdir6, mkdtemp, rm, writeFile } from "node:fs/promises";
7468
7846
  import { tmpdir } from "node:os";
7469
- import path19 from "node:path";
7847
+ import path20 from "node:path";
7470
7848
 
7471
7849
  // src/evaluation/providers/pi-log-tracker.ts
7472
7850
  var GLOBAL_LOGS_KEY5 = Symbol.for("agentv.piLogs");
@@ -7672,7 +8050,7 @@ var PiCliProvider = class {
7672
8050
  const cwd = this.resolveCwd(workspaceRoot, request.cwd);
7673
8051
  const logger = await this.createStreamLogger(request).catch(() => void 0);
7674
8052
  try {
7675
- const promptFile = path19.join(cwd, PROMPT_FILENAME);
8053
+ const promptFile = path20.join(cwd, PROMPT_FILENAME);
7676
8054
  await writeFile(promptFile, request.question, "utf8");
7677
8055
  const args = this.buildPiArgs(request.question, inputFiles);
7678
8056
  const result = await this.executePi(args, cwd, request.signal, logger);
@@ -7735,10 +8113,10 @@ var PiCliProvider = class {
7735
8113
  }
7736
8114
  resolveCwd(workspaceRoot, cwdOverride) {
7737
8115
  if (cwdOverride) {
7738
- return path19.resolve(cwdOverride);
8116
+ return path20.resolve(cwdOverride);
7739
8117
  }
7740
8118
  if (this.config.cwd) {
7741
- return path19.resolve(this.config.cwd);
8119
+ return path20.resolve(this.config.cwd);
7742
8120
  }
7743
8121
  if (workspaceRoot) {
7744
8122
  return workspaceRoot;
@@ -7844,7 +8222,7 @@ ${prompt}` : prompt;
7844
8222
  return env;
7845
8223
  }
7846
8224
  async createWorkspace() {
7847
- return await mkdtemp(path19.join(tmpdir(), WORKSPACE_PREFIX));
8225
+ return await mkdtemp(path20.join(tmpdir(), WORKSPACE_PREFIX));
7848
8226
  }
7849
8227
  async cleanupWorkspace(workspaceRoot) {
7850
8228
  try {
@@ -7854,9 +8232,9 @@ ${prompt}` : prompt;
7854
8232
  }
7855
8233
  resolveLogDirectory() {
7856
8234
  if (this.config.logDir) {
7857
- return path19.resolve(this.config.logDir);
8235
+ return path20.resolve(this.config.logDir);
7858
8236
  }
7859
- return path19.join(process.cwd(), ".agentv", "logs", "pi-cli");
8237
+ return path20.join(process.cwd(), ".agentv", "logs", "pi-cli");
7860
8238
  }
7861
8239
  async createStreamLogger(request) {
7862
8240
  const logDir = this.resolveLogDirectory();
@@ -7870,7 +8248,7 @@ ${prompt}` : prompt;
7870
8248
  console.warn(`Skipping Pi stream logging (could not create ${logDir}): ${message}`);
7871
8249
  return void 0;
7872
8250
  }
7873
- const filePath = path19.join(logDir, buildLogFilename5(request, this.targetName));
8251
+ const filePath = path20.join(logDir, buildLogFilename5(request, this.targetName));
7874
8252
  try {
7875
8253
  const logger = await PiStreamLogger.create({
7876
8254
  filePath,
@@ -8341,8 +8719,8 @@ function resolveWindowsCmd(executable) {
8341
8719
  const content = readFileSync2(cmdPath, "utf-8");
8342
8720
  const match = content.match(/"?%_prog%"?\s+"([^"]+\.js)"/);
8343
8721
  if (match) {
8344
- const dp0 = path19.dirname(path19.resolve(cmdPath));
8345
- const scriptPath = match[1].replace(/%dp0%[/\\]?/gi, `${dp0}${path19.sep}`);
8722
+ const dp0 = path20.dirname(path20.resolve(cmdPath));
8723
+ const scriptPath = match[1].replace(/%dp0%[/\\]?/gi, `${dp0}${path20.sep}`);
8346
8724
  try {
8347
8725
  accessSync(scriptPath);
8348
8726
  return ["node", [scriptPath]];
@@ -8421,13 +8799,13 @@ import { execSync as execSync2 } from "node:child_process";
8421
8799
  import { randomUUID as randomUUID8 } from "node:crypto";
8422
8800
  import { accessSync as accessSync2, createWriteStream as createWriteStream6, mkdirSync } from "node:fs";
8423
8801
  import { mkdir as mkdir7 } from "node:fs/promises";
8424
- import path21 from "node:path";
8802
+ import path22 from "node:path";
8425
8803
  import { createInterface } from "node:readline";
8426
- import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
8804
+ import { fileURLToPath as fileURLToPath4, pathToFileURL } from "node:url";
8427
8805
 
8428
8806
  // src/paths.ts
8429
8807
  import os2 from "node:os";
8430
- import path20 from "node:path";
8808
+ import path21 from "node:path";
8431
8809
  var logged = false;
8432
8810
  function getAgentvHome() {
8433
8811
  const envHome = process.env.AGENTV_HOME;
@@ -8438,19 +8816,19 @@ function getAgentvHome() {
8438
8816
  }
8439
8817
  return envHome;
8440
8818
  }
8441
- return path20.join(os2.homedir(), ".agentv");
8819
+ return path21.join(os2.homedir(), ".agentv");
8442
8820
  }
8443
8821
  function getWorkspacesRoot() {
8444
- return path20.join(getAgentvHome(), "workspaces");
8822
+ return path21.join(getAgentvHome(), "workspaces");
8445
8823
  }
8446
8824
  function getSubagentsRoot() {
8447
- return path20.join(getAgentvHome(), "subagents");
8825
+ return path21.join(getAgentvHome(), "subagents");
8448
8826
  }
8449
8827
  function getTraceStateRoot() {
8450
- return path20.join(getAgentvHome(), "trace-state");
8828
+ return path21.join(getAgentvHome(), "trace-state");
8451
8829
  }
8452
8830
  function getWorkspacePoolRoot() {
8453
- return path20.join(getAgentvHome(), "workspace-pool");
8831
+ return path21.join(getAgentvHome(), "workspace-pool");
8454
8832
  }
8455
8833
 
8456
8834
  // src/evaluation/providers/pi-coding-agent.ts
@@ -8472,7 +8850,7 @@ async function promptInstall() {
8472
8850
  }
8473
8851
  }
8474
8852
  function findManagedSdkInstallRoot() {
8475
- return path21.join(getAgentvHome(), "deps", "pi-sdk");
8853
+ return path22.join(getAgentvHome(), "deps", "pi-sdk");
8476
8854
  }
8477
8855
  function resolveGlobalNpmRoot() {
8478
8856
  try {
@@ -8486,7 +8864,7 @@ function resolveGlobalNpmRoot() {
8486
8864
  }
8487
8865
  }
8488
8866
  function buildGlobalModuleEntry(moduleName, globalNpmRoot) {
8489
- return path21.join(globalNpmRoot, ...moduleName.split("/"), "dist", "index.js");
8867
+ return path22.join(globalNpmRoot, ...moduleName.split("/"), "dist", "index.js");
8490
8868
  }
8491
8869
  function findAccessiblePath(paths) {
8492
8870
  for (const candidate of paths) {
@@ -8512,11 +8890,11 @@ async function tryImportLocalSdkModules() {
8512
8890
  async function tryImportManagedSdkModules() {
8513
8891
  const managedRoot = findManagedSdkInstallRoot();
8514
8892
  const piCodingAgentEntry = findAccessiblePath([
8515
- path21.join(managedRoot, "node_modules", "@mariozechner", "pi-coding-agent", "dist", "index.js")
8893
+ path22.join(managedRoot, "node_modules", "@mariozechner", "pi-coding-agent", "dist", "index.js")
8516
8894
  ]);
8517
8895
  const piAiEntry = findAccessiblePath([
8518
- path21.join(managedRoot, "node_modules", "@mariozechner", "pi-ai", "dist", "index.js"),
8519
- path21.join(
8896
+ path22.join(managedRoot, "node_modules", "@mariozechner", "pi-ai", "dist", "index.js"),
8897
+ path22.join(
8520
8898
  managedRoot,
8521
8899
  "node_modules",
8522
8900
  "@mariozechner",
@@ -8547,7 +8925,7 @@ async function tryImportGlobalSdkModules() {
8547
8925
  ]);
8548
8926
  const piAiEntry = findAccessiblePath([
8549
8927
  buildGlobalModuleEntry("@mariozechner/pi-ai", globalNpmRoot),
8550
- path21.join(
8928
+ path22.join(
8551
8929
  globalNpmRoot,
8552
8930
  "@mariozechner",
8553
8931
  "pi-coding-agent",
@@ -8848,10 +9226,10 @@ ${fileList}`;
8848
9226
  }
8849
9227
  resolveCwd(cwdOverride) {
8850
9228
  if (cwdOverride) {
8851
- return path21.resolve(cwdOverride);
9229
+ return path22.resolve(cwdOverride);
8852
9230
  }
8853
9231
  if (this.config.cwd) {
8854
- return path21.resolve(this.config.cwd);
9232
+ return path22.resolve(this.config.cwd);
8855
9233
  }
8856
9234
  return process.cwd();
8857
9235
  }
@@ -8870,9 +9248,9 @@ ${fileList}`;
8870
9248
  }
8871
9249
  resolveLogDirectory() {
8872
9250
  if (this.config.logDir) {
8873
- return path21.resolve(this.config.logDir);
9251
+ return path22.resolve(this.config.logDir);
8874
9252
  }
8875
- return path21.join(process.cwd(), ".agentv", "logs", "pi-coding-agent");
9253
+ return path22.join(process.cwd(), ".agentv", "logs", "pi-coding-agent");
8876
9254
  }
8877
9255
  async createStreamLogger(request) {
8878
9256
  const logDir = this.resolveLogDirectory();
@@ -8886,7 +9264,7 @@ ${fileList}`;
8886
9264
  console.warn(`Skipping Pi stream logging (could not create ${logDir}): ${message}`);
8887
9265
  return void 0;
8888
9266
  }
8889
- const filePath = path21.join(logDir, buildLogFilename6(request, this.targetName));
9267
+ const filePath = path22.join(logDir, buildLogFilename6(request, this.targetName));
8890
9268
  try {
8891
9269
  const logger = await PiStreamLogger2.create({
8892
9270
  filePath,
@@ -9101,17 +9479,17 @@ var ProviderRegistry = class {
9101
9479
  // src/evaluation/providers/vscode-provider.ts
9102
9480
  import { exec as exec2 } from "node:child_process";
9103
9481
  import { constants as constants3, access as access3, stat as stat5 } from "node:fs/promises";
9104
- import path32 from "node:path";
9482
+ import path33 from "node:path";
9105
9483
  import { promisify as promisify3 } from "node:util";
9106
9484
 
9107
9485
  // src/evaluation/providers/vscode/dispatch/agentDispatch.ts
9108
9486
  import { stat as stat4, writeFile as writeFile4 } from "node:fs/promises";
9109
- import path30 from "node:path";
9487
+ import path31 from "node:path";
9110
9488
 
9111
9489
  // src/evaluation/providers/vscode/utils/fs.ts
9112
9490
  import { constants as constants2 } from "node:fs";
9113
9491
  import { access as access2, mkdir as mkdir8, readdir as readdir2, rm as rm2, stat as stat2 } from "node:fs/promises";
9114
- import path22 from "node:path";
9492
+ import path23 from "node:path";
9115
9493
  async function pathExists(target) {
9116
9494
  try {
9117
9495
  await access2(target, constants2.F_OK);
@@ -9127,7 +9505,7 @@ async function readDirEntries(target) {
9127
9505
  const entries = await readdir2(target, { withFileTypes: true });
9128
9506
  return entries.map((entry) => ({
9129
9507
  name: entry.name,
9130
- absolutePath: path22.join(target, entry.name),
9508
+ absolutePath: path23.join(target, entry.name),
9131
9509
  isDirectory: entry.isDirectory()
9132
9510
  }));
9133
9511
  }
@@ -9142,9 +9520,9 @@ async function removeIfExists(target) {
9142
9520
  }
9143
9521
 
9144
9522
  // src/evaluation/providers/vscode/utils/path.ts
9145
- import path23 from "node:path";
9523
+ import path24 from "node:path";
9146
9524
  function pathToFileUri2(filePath) {
9147
- const absolutePath = path23.isAbsolute(filePath) ? filePath : path23.resolve(filePath);
9525
+ const absolutePath = path24.isAbsolute(filePath) ? filePath : path24.resolve(filePath);
9148
9526
  const normalizedPath = absolutePath.replace(/\\/g, "/");
9149
9527
  if (/^[a-zA-Z]:\//.test(normalizedPath)) {
9150
9528
  return `file:///${normalizedPath}`;
@@ -9153,7 +9531,7 @@ function pathToFileUri2(filePath) {
9153
9531
  }
9154
9532
 
9155
9533
  // src/evaluation/providers/vscode/dispatch/promptBuilder.ts
9156
- import path24 from "node:path";
9534
+ import path25 from "node:path";
9157
9535
 
9158
9536
  // src/evaluation/providers/vscode/utils/template.ts
9159
9537
  function renderTemplate2(content, variables) {
@@ -9245,8 +9623,8 @@ function createBatchRequestPrompt(userQuery, responseFileTmp, responseFileFinal,
9245
9623
  });
9246
9624
  }
9247
9625
  function createBatchOrchestratorPrompt(requestFiles, responseFiles, templateContent) {
9248
- const requestLines = requestFiles.map((file, index) => `${index + 1}. messages/${path24.basename(file)}`).join("\n");
9249
- const responseList = responseFiles.map((file) => `"${path24.basename(file)}"`).join(", ");
9626
+ const requestLines = requestFiles.map((file, index) => `${index + 1}. messages/${path25.basename(file)}`).join("\n");
9627
+ const responseList = responseFiles.map((file) => `"${path25.basename(file)}"`).join(", ");
9250
9628
  return renderTemplate2(templateContent, {
9251
9629
  requestFiles: requestLines,
9252
9630
  responseList
@@ -9254,8 +9632,8 @@ function createBatchOrchestratorPrompt(requestFiles, responseFiles, templateCont
9254
9632
  }
9255
9633
 
9256
9634
  // src/evaluation/providers/vscode/dispatch/responseWaiter.ts
9257
- import { readFile as readFile9 } from "node:fs/promises";
9258
- import path25 from "node:path";
9635
+ import { readFile as readFile10 } from "node:fs/promises";
9636
+ import path26 from "node:path";
9259
9637
 
9260
9638
  // src/evaluation/providers/vscode/utils/time.ts
9261
9639
  function sleep2(ms) {
@@ -9293,7 +9671,7 @@ async function waitForResponseOutput(responseFileFinal, pollInterval = 1e3, sile
9293
9671
  const maxAttempts = 10;
9294
9672
  while (attempts < maxAttempts) {
9295
9673
  try {
9296
- const content = await readFile9(responseFileFinal, { encoding: "utf8" });
9674
+ const content = await readFile10(responseFileFinal, { encoding: "utf8" });
9297
9675
  if (!silent) {
9298
9676
  process.stdout.write(`${content}
9299
9677
  `);
@@ -9314,7 +9692,7 @@ async function waitForResponseOutput(responseFileFinal, pollInterval = 1e3, sile
9314
9692
  }
9315
9693
  async function waitForBatchResponses(responseFilesFinal, pollInterval = 1e3, silent = false, timeoutMs = DEFAULT_TIMEOUT_MS) {
9316
9694
  if (!silent) {
9317
- const fileList = responseFilesFinal.map((file) => path25.basename(file)).join(", ");
9695
+ const fileList = responseFilesFinal.map((file) => path26.basename(file)).join(", ");
9318
9696
  console.error(`waiting for ${responseFilesFinal.length} batch response(s): ${fileList}`);
9319
9697
  }
9320
9698
  const deadline = Date.now() + timeoutMs;
@@ -9323,7 +9701,7 @@ async function waitForBatchResponses(responseFilesFinal, pollInterval = 1e3, sil
9323
9701
  while (pending.size > 0) {
9324
9702
  if (Date.now() >= deadline) {
9325
9703
  if (!silent) {
9326
- const remaining = [...pending].map((f) => path25.basename(f)).join(", ");
9704
+ const remaining = [...pending].map((f) => path26.basename(f)).join(", ");
9327
9705
  console.error(
9328
9706
  `error: timed out after ${Math.round(timeoutMs / 1e3)}s waiting for batch responses. Still pending: ${remaining}`
9329
9707
  );
@@ -9350,7 +9728,7 @@ async function waitForBatchResponses(responseFilesFinal, pollInterval = 1e3, sil
9350
9728
  const maxAttempts = 10;
9351
9729
  while (attempts < maxAttempts) {
9352
9730
  try {
9353
- const content = await readFile9(file, { encoding: "utf8" });
9731
+ const content = await readFile10(file, { encoding: "utf8" });
9354
9732
  if (!silent) {
9355
9733
  process.stdout.write(`${content}
9356
9734
  `);
@@ -9374,16 +9752,16 @@ async function waitForBatchResponses(responseFilesFinal, pollInterval = 1e3, sil
9374
9752
  // src/evaluation/providers/vscode/dispatch/vscodeProcess.ts
9375
9753
  import { exec, spawn as spawn4 } from "node:child_process";
9376
9754
  import { mkdir as mkdir9, writeFile as writeFile2 } from "node:fs/promises";
9377
- import path27 from "node:path";
9755
+ import path28 from "node:path";
9378
9756
  import { promisify as promisify2 } from "node:util";
9379
9757
 
9380
9758
  // src/evaluation/providers/vscode/dispatch/constants.ts
9381
- import path26 from "node:path";
9759
+ import path27 from "node:path";
9382
9760
  var DEFAULT_LOCK_NAME = "subagent.lock";
9383
9761
  var DEFAULT_ALIVE_FILENAME = ".alive";
9384
9762
  function getDefaultSubagentRoot(vscodeCmd = "code") {
9385
9763
  const folder = vscodeCmd === "code-insiders" ? "vscode-insiders-agents" : "vscode-agents";
9386
- return path26.join(getSubagentsRoot(), folder);
9764
+ return path27.join(getSubagentsRoot(), folder);
9387
9765
  }
9388
9766
  var DEFAULT_SUBAGENT_ROOT = getDefaultSubagentRoot();
9389
9767
 
@@ -9450,11 +9828,11 @@ async function ensureWorkspaceFocused(workspacePath, workspaceName, subagentDir,
9450
9828
  await raceSpawnError(child);
9451
9829
  return true;
9452
9830
  }
9453
- const aliveFile = path27.join(subagentDir, DEFAULT_ALIVE_FILENAME);
9831
+ const aliveFile = path28.join(subagentDir, DEFAULT_ALIVE_FILENAME);
9454
9832
  await removeIfExists(aliveFile);
9455
- const githubAgentsDir = path27.join(subagentDir, ".github", "agents");
9833
+ const githubAgentsDir = path28.join(subagentDir, ".github", "agents");
9456
9834
  await mkdir9(githubAgentsDir, { recursive: true });
9457
- const wakeupDst = path27.join(githubAgentsDir, "wakeup.md");
9835
+ const wakeupDst = path28.join(githubAgentsDir, "wakeup.md");
9458
9836
  await writeFile2(wakeupDst, DEFAULT_WAKEUP_CONTENT, "utf8");
9459
9837
  const workspaceChild = spawnVsCode(vscodeCmd, [workspacePath], {
9460
9838
  label: "open-workspace"
@@ -9467,7 +9845,7 @@ async function ensureWorkspaceFocused(workspacePath, workspaceName, subagentDir,
9467
9845
  "chat",
9468
9846
  "-m",
9469
9847
  wakeupChatId,
9470
- `create a file named .alive in the ${path27.basename(subagentDir)} folder`
9848
+ `create a file named .alive in the ${path28.basename(subagentDir)} folder`
9471
9849
  ];
9472
9850
  const wakeupChild = spawnVsCode(vscodeCmd, chatArgs, { label: "send-wakeup-chat" });
9473
9851
  await raceSpawnError(wakeupChild);
@@ -9482,10 +9860,10 @@ async function ensureWorkspaceFocused(workspacePath, workspaceName, subagentDir,
9482
9860
  return true;
9483
9861
  }
9484
9862
  async function launchVsCodeWithChat(subagentDir, chatId, attachmentPaths, requestInstructions, timestamp, vscodeCmd) {
9485
- const workspacePath = path27.join(subagentDir, `${path27.basename(subagentDir)}.code-workspace`);
9486
- const messagesDir = path27.join(subagentDir, "messages");
9863
+ const workspacePath = path28.join(subagentDir, `${path28.basename(subagentDir)}.code-workspace`);
9864
+ const messagesDir = path28.join(subagentDir, "messages");
9487
9865
  await mkdir9(messagesDir, { recursive: true });
9488
- const reqFile = path27.join(messagesDir, `${timestamp}_req.md`);
9866
+ const reqFile = path28.join(messagesDir, `${timestamp}_req.md`);
9489
9867
  await writeFile2(reqFile, requestInstructions, { encoding: "utf8" });
9490
9868
  const reqUri = pathToFileUri2(reqFile);
9491
9869
  const chatArgs = ["-r", "chat", "-m", chatId];
@@ -9493,16 +9871,16 @@ async function launchVsCodeWithChat(subagentDir, chatId, attachmentPaths, reques
9493
9871
  chatArgs.push("-a", attachment);
9494
9872
  }
9495
9873
  chatArgs.push("-a", reqFile);
9496
- chatArgs.push(`Follow instructions in [${path27.basename(reqFile)}](${reqUri})`);
9874
+ chatArgs.push(`Follow instructions in [${path28.basename(reqFile)}](${reqUri})`);
9497
9875
  const workspaceReady = await ensureWorkspaceFocused(
9498
9876
  workspacePath,
9499
- path27.basename(subagentDir),
9877
+ path28.basename(subagentDir),
9500
9878
  subagentDir,
9501
9879
  vscodeCmd
9502
9880
  );
9503
9881
  if (!workspaceReady) {
9504
9882
  throw new Error(
9505
- `VS Code workspace '${path27.basename(subagentDir)}' failed to become ready within the timeout. Check that '${vscodeCmd}' can open workspaces.`
9883
+ `VS Code workspace '${path28.basename(subagentDir)}' failed to become ready within the timeout. Check that '${vscodeCmd}' can open workspaces.`
9506
9884
  );
9507
9885
  }
9508
9886
  await sleep2(500);
@@ -9510,8 +9888,8 @@ async function launchVsCodeWithChat(subagentDir, chatId, attachmentPaths, reques
9510
9888
  await raceSpawnError(child);
9511
9889
  }
9512
9890
  async function launchVsCodeWithBatchChat(subagentDir, chatId, attachmentPaths, chatInstruction, vscodeCmd) {
9513
- const workspacePath = path27.join(subagentDir, `${path27.basename(subagentDir)}.code-workspace`);
9514
- const messagesDir = path27.join(subagentDir, "messages");
9891
+ const workspacePath = path28.join(subagentDir, `${path28.basename(subagentDir)}.code-workspace`);
9892
+ const messagesDir = path28.join(subagentDir, "messages");
9515
9893
  await mkdir9(messagesDir, { recursive: true });
9516
9894
  const chatArgs = ["-r", "chat", "-m", chatId];
9517
9895
  for (const attachment of attachmentPaths) {
@@ -9520,13 +9898,13 @@ async function launchVsCodeWithBatchChat(subagentDir, chatId, attachmentPaths, c
9520
9898
  chatArgs.push(chatInstruction);
9521
9899
  const workspaceReady = await ensureWorkspaceFocused(
9522
9900
  workspacePath,
9523
- path27.basename(subagentDir),
9901
+ path28.basename(subagentDir),
9524
9902
  subagentDir,
9525
9903
  vscodeCmd
9526
9904
  );
9527
9905
  if (!workspaceReady) {
9528
9906
  throw new Error(
9529
- `VS Code workspace '${path27.basename(subagentDir)}' failed to become ready within the timeout. Check that '${vscodeCmd}' can open workspaces.`
9907
+ `VS Code workspace '${path28.basename(subagentDir)}' failed to become ready within the timeout. Check that '${vscodeCmd}' can open workspaces.`
9530
9908
  );
9531
9909
  }
9532
9910
  await sleep2(500);
@@ -9535,11 +9913,11 @@ async function launchVsCodeWithBatchChat(subagentDir, chatId, attachmentPaths, c
9535
9913
  }
9536
9914
 
9537
9915
  // src/evaluation/providers/vscode/dispatch/workspaceManager.ts
9538
- import { copyFile, mkdir as mkdir10, readFile as readFile10, readdir as readdir3, stat as stat3, writeFile as writeFile3 } from "node:fs/promises";
9539
- import path29 from "node:path";
9916
+ import { copyFile, mkdir as mkdir10, readFile as readFile11, readdir as readdir3, stat as stat3, writeFile as writeFile3 } from "node:fs/promises";
9917
+ import path30 from "node:path";
9540
9918
 
9541
9919
  // src/evaluation/providers/vscode/utils/workspace.ts
9542
- import path28 from "node:path";
9920
+ import path29 from "node:path";
9543
9921
  import JSON5 from "json5";
9544
9922
  function transformWorkspacePaths(workspaceContent, templateDir) {
9545
9923
  let workspace;
@@ -9556,10 +9934,10 @@ function transformWorkspacePaths(workspaceContent, templateDir) {
9556
9934
  }
9557
9935
  const transformedFolders = workspace.folders.map((folder) => {
9558
9936
  const folderPath = folder.path;
9559
- if (path28.isAbsolute(folderPath)) {
9937
+ if (path29.isAbsolute(folderPath)) {
9560
9938
  return folder;
9561
9939
  }
9562
- const absolutePath = path28.resolve(templateDir, folderPath);
9940
+ const absolutePath = path29.resolve(templateDir, folderPath);
9563
9941
  return {
9564
9942
  ...folder,
9565
9943
  path: absolutePath
@@ -9581,19 +9959,19 @@ function transformWorkspacePaths(workspaceContent, templateDir) {
9581
9959
  if (locationMap && typeof locationMap === "object") {
9582
9960
  const transformedMap = {};
9583
9961
  for (const [locationPath, value] of Object.entries(locationMap)) {
9584
- const isAbsolute = path28.isAbsolute(locationPath);
9962
+ const isAbsolute = path29.isAbsolute(locationPath);
9585
9963
  if (isAbsolute) {
9586
9964
  transformedMap[locationPath] = value;
9587
9965
  } else {
9588
9966
  const firstGlobIndex = locationPath.search(/[*]/);
9589
9967
  if (firstGlobIndex === -1) {
9590
- const resolvedPath = path28.resolve(templateDir, locationPath).replace(/\\/g, "/");
9968
+ const resolvedPath = path29.resolve(templateDir, locationPath).replace(/\\/g, "/");
9591
9969
  transformedMap[resolvedPath] = value;
9592
9970
  } else {
9593
9971
  const basePathEnd = locationPath.lastIndexOf("/", firstGlobIndex);
9594
9972
  const basePath = basePathEnd !== -1 ? locationPath.substring(0, basePathEnd) : ".";
9595
9973
  const patternPath = locationPath.substring(basePathEnd !== -1 ? basePathEnd : 0);
9596
- const resolvedPath = (path28.resolve(templateDir, basePath) + patternPath).replace(
9974
+ const resolvedPath = (path29.resolve(templateDir, basePath) + patternPath).replace(
9597
9975
  /\\/g,
9598
9976
  "/"
9599
9977
  );
@@ -9634,7 +10012,7 @@ async function findUnlockedSubagent(subagentRoot) {
9634
10012
  number: Number.parseInt(entry.name.split("-")[1] ?? "", 10)
9635
10013
  })).filter((entry) => Number.isInteger(entry.number)).sort((a, b) => a.number - b.number);
9636
10014
  for (const subagent of subagents) {
9637
- const lockFile = path29.join(subagent.absolutePath, DEFAULT_LOCK_NAME);
10015
+ const lockFile = path30.join(subagent.absolutePath, DEFAULT_LOCK_NAME);
9638
10016
  if (!await pathExists(lockFile)) {
9639
10017
  return subagent.absolutePath;
9640
10018
  }
@@ -9644,7 +10022,7 @@ async function findUnlockedSubagent(subagentRoot) {
9644
10022
  async function copyAgentConfig(subagentDir, workspaceTemplate, cwd) {
9645
10023
  let workspaceContent;
9646
10024
  if (workspaceTemplate) {
9647
- const workspaceSrc = path29.resolve(workspaceTemplate);
10025
+ const workspaceSrc = path30.resolve(workspaceTemplate);
9648
10026
  if (!await pathExists(workspaceSrc)) {
9649
10027
  throw new Error(`workspace template not found: ${workspaceSrc}`);
9650
10028
  }
@@ -9652,18 +10030,18 @@ async function copyAgentConfig(subagentDir, workspaceTemplate, cwd) {
9652
10030
  if (!stats.isFile()) {
9653
10031
  throw new Error(`workspace template must be a file, not a directory: ${workspaceSrc}`);
9654
10032
  }
9655
- const templateText = await readFile10(workspaceSrc, "utf8");
10033
+ const templateText = await readFile11(workspaceSrc, "utf8");
9656
10034
  workspaceContent = JSON.parse(templateText);
9657
10035
  } else {
9658
10036
  workspaceContent = DEFAULT_WORKSPACE_TEMPLATE;
9659
10037
  }
9660
- const workspaceName = `${path29.basename(subagentDir)}.code-workspace`;
9661
- const workspaceDst = path29.join(subagentDir, workspaceName);
9662
- const templateDir = workspaceTemplate ? path29.dirname(path29.resolve(workspaceTemplate)) : subagentDir;
10038
+ const workspaceName = `${path30.basename(subagentDir)}.code-workspace`;
10039
+ const workspaceDst = path30.join(subagentDir, workspaceName);
10040
+ const templateDir = workspaceTemplate ? path30.dirname(path30.resolve(workspaceTemplate)) : subagentDir;
9663
10041
  const workspaceJson = JSON.stringify(workspaceContent, null, 2);
9664
10042
  let transformedContent = transformWorkspacePaths(workspaceJson, templateDir);
9665
10043
  if (cwd) {
9666
- const absCwd = path29.resolve(cwd);
10044
+ const absCwd = path30.resolve(cwd);
9667
10045
  const parsed = JSON.parse(transformedContent);
9668
10046
  const alreadyPresent = parsed.folders.some((f) => f.path === absCwd);
9669
10047
  if (!alreadyPresent) {
@@ -9672,35 +10050,35 @@ async function copyAgentConfig(subagentDir, workspaceTemplate, cwd) {
9672
10050
  }
9673
10051
  }
9674
10052
  await writeFile3(workspaceDst, transformedContent, "utf8");
9675
- const messagesDir = path29.join(subagentDir, "messages");
10053
+ const messagesDir = path30.join(subagentDir, "messages");
9676
10054
  await mkdir10(messagesDir, { recursive: true });
9677
10055
  return { workspace: workspaceDst, messagesDir };
9678
10056
  }
9679
10057
  async function createSubagentLock(subagentDir) {
9680
- const messagesDir = path29.join(subagentDir, "messages");
10058
+ const messagesDir = path30.join(subagentDir, "messages");
9681
10059
  if (await pathExists(messagesDir)) {
9682
10060
  const files = await readdir3(messagesDir);
9683
10061
  await Promise.all(
9684
10062
  files.map(async (file) => {
9685
- const target = path29.join(messagesDir, file);
10063
+ const target = path30.join(messagesDir, file);
9686
10064
  await removeIfExists(target);
9687
10065
  })
9688
10066
  );
9689
10067
  }
9690
- const githubAgentsDir = path29.join(subagentDir, ".github", "agents");
10068
+ const githubAgentsDir = path30.join(subagentDir, ".github", "agents");
9691
10069
  if (await pathExists(githubAgentsDir)) {
9692
10070
  const agentFiles = await readdir3(githubAgentsDir);
9693
10071
  const preservedFiles = /* @__PURE__ */ new Set(["wakeup.md", "subagent.md"]);
9694
10072
  await Promise.all(
9695
- agentFiles.filter((file) => file.endsWith(".md") && !preservedFiles.has(file)).map((file) => removeIfExists(path29.join(githubAgentsDir, file)))
10073
+ agentFiles.filter((file) => file.endsWith(".md") && !preservedFiles.has(file)).map((file) => removeIfExists(path30.join(githubAgentsDir, file)))
9696
10074
  );
9697
10075
  }
9698
- const lockFile = path29.join(subagentDir, DEFAULT_LOCK_NAME);
10076
+ const lockFile = path30.join(subagentDir, DEFAULT_LOCK_NAME);
9699
10077
  await writeFile3(lockFile, "", { encoding: "utf8" });
9700
10078
  return lockFile;
9701
10079
  }
9702
10080
  async function removeSubagentLock(subagentDir) {
9703
- const lockFile = path29.join(subagentDir, DEFAULT_LOCK_NAME);
10081
+ const lockFile = path30.join(subagentDir, DEFAULT_LOCK_NAME);
9704
10082
  await removeIfExists(lockFile);
9705
10083
  }
9706
10084
  async function prepareSubagentDirectory(subagentDir, promptFile, chatId, workspaceTemplate, dryRun, cwd) {
@@ -9720,9 +10098,9 @@ async function prepareSubagentDirectory(subagentDir, promptFile, chatId, workspa
9720
10098
  return 1;
9721
10099
  }
9722
10100
  if (promptFile) {
9723
- const githubAgentsDir = path29.join(subagentDir, ".github", "agents");
10101
+ const githubAgentsDir = path30.join(subagentDir, ".github", "agents");
9724
10102
  await mkdir10(githubAgentsDir, { recursive: true });
9725
- const agentFile = path29.join(githubAgentsDir, `${chatId}.md`);
10103
+ const agentFile = path30.join(githubAgentsDir, `${chatId}.md`);
9726
10104
  try {
9727
10105
  await copyFile(promptFile, agentFile);
9728
10106
  } catch (error) {
@@ -9741,7 +10119,7 @@ async function resolvePromptFile(promptFile) {
9741
10119
  if (!promptFile) {
9742
10120
  return void 0;
9743
10121
  }
9744
- const resolvedPrompt = path30.resolve(promptFile);
10122
+ const resolvedPrompt = path31.resolve(promptFile);
9745
10123
  if (!await pathExists(resolvedPrompt)) {
9746
10124
  throw new Error(`Prompt file not found: ${resolvedPrompt}`);
9747
10125
  }
@@ -9757,7 +10135,7 @@ async function resolveAttachments(extraAttachments) {
9757
10135
  }
9758
10136
  const resolved = [];
9759
10137
  for (const attachment of extraAttachments) {
9760
- const resolvedPath = path30.resolve(attachment);
10138
+ const resolvedPath = path31.resolve(attachment);
9761
10139
  if (!await pathExists(resolvedPath)) {
9762
10140
  throw new Error(`Attachment not found: ${resolvedPath}`);
9763
10141
  }
@@ -9799,7 +10177,7 @@ async function dispatchAgentSession(options) {
9799
10177
  error: "No unlocked subagents available. Provision additional subagents with: subagent code provision --subagents <desired_total>"
9800
10178
  };
9801
10179
  }
9802
- const subagentName = path30.basename(subagentDir);
10180
+ const subagentName = path31.basename(subagentDir);
9803
10181
  const chatId = Math.random().toString(16).slice(2, 10);
9804
10182
  const preparationResult = await prepareSubagentDirectory(
9805
10183
  subagentDir,
@@ -9827,9 +10205,9 @@ async function dispatchAgentSession(options) {
9827
10205
  };
9828
10206
  }
9829
10207
  const timestamp = generateTimestamp();
9830
- const messagesDir = path30.join(subagentDir, "messages");
9831
- const responseFileTmp = path30.join(messagesDir, `${timestamp}_res.tmp.md`);
9832
- const responseFileFinal = path30.join(messagesDir, `${timestamp}_res.md`);
10208
+ const messagesDir = path31.join(subagentDir, "messages");
10209
+ const responseFileTmp = path31.join(messagesDir, `${timestamp}_res.tmp.md`);
10210
+ const responseFileFinal = path31.join(messagesDir, `${timestamp}_res.md`);
9833
10211
  const requestInstructions = createRequestPrompt(
9834
10212
  userQuery,
9835
10213
  responseFileTmp,
@@ -9934,7 +10312,7 @@ async function dispatchBatchAgent(options) {
9934
10312
  error: "No unlocked subagents available. Provision additional subagents with: subagent code provision --subagents <desired_total>"
9935
10313
  };
9936
10314
  }
9937
- subagentName = path30.basename(subagentDir);
10315
+ subagentName = path31.basename(subagentDir);
9938
10316
  const chatId = Math.random().toString(16).slice(2, 10);
9939
10317
  const preparationResult = await prepareSubagentDirectory(
9940
10318
  subagentDir,
@@ -9965,17 +10343,17 @@ async function dispatchBatchAgent(options) {
9965
10343
  };
9966
10344
  }
9967
10345
  const timestamp = generateTimestamp();
9968
- const messagesDir = path30.join(subagentDir, "messages");
10346
+ const messagesDir = path31.join(subagentDir, "messages");
9969
10347
  requestFiles = userQueries.map(
9970
- (_, index) => path30.join(messagesDir, `${timestamp}_${index}_req.md`)
10348
+ (_, index) => path31.join(messagesDir, `${timestamp}_${index}_req.md`)
9971
10349
  );
9972
10350
  const responseTmpFiles = userQueries.map(
9973
- (_, index) => path30.join(messagesDir, `${timestamp}_${index}_res.tmp.md`)
10351
+ (_, index) => path31.join(messagesDir, `${timestamp}_${index}_res.tmp.md`)
9974
10352
  );
9975
10353
  responseFilesFinal = userQueries.map(
9976
- (_, index) => path30.join(messagesDir, `${timestamp}_${index}_res.md`)
10354
+ (_, index) => path31.join(messagesDir, `${timestamp}_${index}_res.md`)
9977
10355
  );
9978
- const orchestratorFile = path30.join(messagesDir, `${timestamp}_orchestrator.md`);
10356
+ const orchestratorFile = path31.join(messagesDir, `${timestamp}_orchestrator.md`);
9979
10357
  if (!dryRun) {
9980
10358
  await Promise.all(
9981
10359
  userQueries.map((query, index) => {
@@ -10061,7 +10439,7 @@ async function dispatchBatchAgent(options) {
10061
10439
 
10062
10440
  // src/evaluation/providers/vscode/dispatch/provision.ts
10063
10441
  import { writeFile as writeFile5 } from "node:fs/promises";
10064
- import path31 from "node:path";
10442
+ import path32 from "node:path";
10065
10443
  var DEFAULT_WORKSPACE_TEMPLATE2 = {
10066
10444
  folders: [
10067
10445
  {
@@ -10092,7 +10470,7 @@ async function provisionSubagents(options) {
10092
10470
  if (!Number.isInteger(subagents) || subagents < 1) {
10093
10471
  throw new Error("subagents must be a positive integer");
10094
10472
  }
10095
- const targetPath = path31.resolve(targetRoot);
10473
+ const targetPath = path32.resolve(targetRoot);
10096
10474
  if (!dryRun) {
10097
10475
  await ensureDir(targetPath);
10098
10476
  }
@@ -10112,7 +10490,7 @@ async function provisionSubagents(options) {
10112
10490
  continue;
10113
10491
  }
10114
10492
  highestNumber = Math.max(highestNumber, parsed);
10115
- const lockFile = path31.join(entry.absolutePath, lockName);
10493
+ const lockFile = path32.join(entry.absolutePath, lockName);
10116
10494
  const locked = await pathExists(lockFile);
10117
10495
  if (locked) {
10118
10496
  lockedSubagents.add(entry.absolutePath);
@@ -10129,10 +10507,10 @@ async function provisionSubagents(options) {
10129
10507
  break;
10130
10508
  }
10131
10509
  const subagentDir = subagent.absolutePath;
10132
- const githubAgentsDir = path31.join(subagentDir, ".github", "agents");
10133
- const lockFile = path31.join(subagentDir, lockName);
10134
- const workspaceDst = path31.join(subagentDir, `${path31.basename(subagentDir)}.code-workspace`);
10135
- const wakeupDst = path31.join(githubAgentsDir, "wakeup.md");
10510
+ const githubAgentsDir = path32.join(subagentDir, ".github", "agents");
10511
+ const lockFile = path32.join(subagentDir, lockName);
10512
+ const workspaceDst = path32.join(subagentDir, `${path32.basename(subagentDir)}.code-workspace`);
10513
+ const wakeupDst = path32.join(githubAgentsDir, "wakeup.md");
10136
10514
  const isLocked = await pathExists(lockFile);
10137
10515
  if (isLocked && !force) {
10138
10516
  continue;
@@ -10170,10 +10548,10 @@ async function provisionSubagents(options) {
10170
10548
  let nextIndex = highestNumber;
10171
10549
  while (subagentsProvisioned < subagents) {
10172
10550
  nextIndex += 1;
10173
- const subagentDir = path31.join(targetPath, `subagent-${nextIndex}`);
10174
- const githubAgentsDir = path31.join(subagentDir, ".github", "agents");
10175
- const workspaceDst = path31.join(subagentDir, `${path31.basename(subagentDir)}.code-workspace`);
10176
- const wakeupDst = path31.join(githubAgentsDir, "wakeup.md");
10551
+ const subagentDir = path32.join(targetPath, `subagent-${nextIndex}`);
10552
+ const githubAgentsDir = path32.join(subagentDir, ".github", "agents");
10553
+ const workspaceDst = path32.join(subagentDir, `${path32.basename(subagentDir)}.code-workspace`);
10554
+ const wakeupDst = path32.join(githubAgentsDir, "wakeup.md");
10177
10555
  if (!dryRun) {
10178
10556
  await ensureDir(subagentDir);
10179
10557
  await ensureDir(githubAgentsDir);
@@ -10363,7 +10741,7 @@ var VSCodeProvider = class {
10363
10741
  async function locateVSCodeExecutable(candidate) {
10364
10742
  const includesPathSeparator = candidate.includes("/") || candidate.includes("\\");
10365
10743
  if (includesPathSeparator) {
10366
- const resolved = path32.isAbsolute(candidate) ? candidate : path32.resolve(candidate);
10744
+ const resolved = path33.isAbsolute(candidate) ? candidate : path33.resolve(candidate);
10367
10745
  try {
10368
10746
  await access3(resolved, constants3.F_OK);
10369
10747
  return resolved;
@@ -10392,7 +10770,7 @@ async function resolveWorkspaceTemplateFile(template) {
10392
10770
  return void 0;
10393
10771
  }
10394
10772
  try {
10395
- const stats = await stat5(path32.resolve(template));
10773
+ const stats = await stat5(path33.resolve(template));
10396
10774
  return stats.isFile() ? template : void 0;
10397
10775
  } catch {
10398
10776
  return template;
@@ -10416,7 +10794,7 @@ function buildMandatoryPrereadBlock2(attachmentFiles) {
10416
10794
  return "";
10417
10795
  }
10418
10796
  const buildList = (files) => files.map((absolutePath) => {
10419
- const fileName = path32.basename(absolutePath);
10797
+ const fileName = path33.basename(absolutePath);
10420
10798
  const fileUri = pathToFileUri3(absolutePath);
10421
10799
  return `* [${fileName}](${fileUri})`;
10422
10800
  });
@@ -10437,7 +10815,7 @@ function collectAttachmentFiles(attachments) {
10437
10815
  }
10438
10816
  const unique = /* @__PURE__ */ new Map();
10439
10817
  for (const attachment of attachments) {
10440
- const absolutePath = path32.resolve(attachment);
10818
+ const absolutePath = path33.resolve(attachment);
10441
10819
  if (!unique.has(absolutePath)) {
10442
10820
  unique.set(absolutePath, absolutePath);
10443
10821
  }
@@ -10445,7 +10823,7 @@ function collectAttachmentFiles(attachments) {
10445
10823
  return Array.from(unique.values());
10446
10824
  }
10447
10825
  function pathToFileUri3(filePath) {
10448
- const absolutePath = path32.isAbsolute(filePath) ? filePath : path32.resolve(filePath);
10826
+ const absolutePath = path33.isAbsolute(filePath) ? filePath : path33.resolve(filePath);
10449
10827
  const normalizedPath = absolutePath.replace(/\\/g, "/");
10450
10828
  if (/^[a-zA-Z]:\//.test(normalizedPath)) {
10451
10829
  return `file:///${normalizedPath}`;
@@ -10458,7 +10836,7 @@ function normalizeAttachments(attachments) {
10458
10836
  }
10459
10837
  const deduped = /* @__PURE__ */ new Set();
10460
10838
  for (const attachment of attachments) {
10461
- deduped.add(path32.resolve(attachment));
10839
+ deduped.add(path33.resolve(attachment));
10462
10840
  }
10463
10841
  return Array.from(deduped);
10464
10842
  }
@@ -10467,7 +10845,7 @@ function mergeAttachments(all) {
10467
10845
  for (const list of all) {
10468
10846
  if (!list) continue;
10469
10847
  for (const inputFile of list) {
10470
- deduped.add(path32.resolve(inputFile));
10848
+ deduped.add(path33.resolve(inputFile));
10471
10849
  }
10472
10850
  }
10473
10851
  return deduped.size > 0 ? Array.from(deduped) : void 0;
@@ -10515,8 +10893,8 @@ total unlocked subagents available: ${result.created.length + result.skippedExis
10515
10893
 
10516
10894
  // src/evaluation/providers/targets-file.ts
10517
10895
  import { constants as constants4 } from "node:fs";
10518
- import { access as access4, readFile as readFile11 } from "node:fs/promises";
10519
- import path33 from "node:path";
10896
+ import { access as access4, readFile as readFile12 } from "node:fs/promises";
10897
+ import path34 from "node:path";
10520
10898
  import { parse as parse4 } from "yaml";
10521
10899
  function isRecord(value) {
10522
10900
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -10556,11 +10934,11 @@ async function fileExists3(filePath) {
10556
10934
  }
10557
10935
  }
10558
10936
  async function readTargetDefinitions(filePath) {
10559
- const absolutePath = path33.resolve(filePath);
10937
+ const absolutePath = path34.resolve(filePath);
10560
10938
  if (!await fileExists3(absolutePath)) {
10561
10939
  throw new Error(`targets.yaml not found at ${absolutePath}`);
10562
10940
  }
10563
- const raw = await readFile11(absolutePath, "utf8");
10941
+ const raw = await readFile12(absolutePath, "utf8");
10564
10942
  const parsed = parse4(raw);
10565
10943
  if (!isRecord(parsed)) {
10566
10944
  throw new Error(`targets.yaml at ${absolutePath} must be a YAML object with a 'targets' field`);
@@ -10576,16 +10954,16 @@ function listTargetNames(definitions) {
10576
10954
  }
10577
10955
 
10578
10956
  // src/evaluation/providers/provider-discovery.ts
10579
- import path34 from "node:path";
10957
+ import path35 from "node:path";
10580
10958
  import fg from "fast-glob";
10581
10959
  async function discoverProviders(registry, baseDir) {
10582
10960
  const patterns = ["*.ts", "*.js", "*.mts", "*.mjs"];
10583
10961
  const candidateDirs = [];
10584
- let dir = path34.resolve(baseDir);
10585
- const root = path34.parse(dir).root;
10962
+ let dir = path35.resolve(baseDir);
10963
+ const root = path35.parse(dir).root;
10586
10964
  while (dir !== root) {
10587
- candidateDirs.push(path34.join(dir, ".agentv", "providers"));
10588
- dir = path34.dirname(dir);
10965
+ candidateDirs.push(path35.join(dir, ".agentv", "providers"));
10966
+ dir = path35.dirname(dir);
10589
10967
  }
10590
10968
  let files = [];
10591
10969
  for (const providersDir of candidateDirs) {
@@ -10601,7 +10979,7 @@ async function discoverProviders(registry, baseDir) {
10601
10979
  }
10602
10980
  const discoveredKinds = [];
10603
10981
  for (const filePath of files) {
10604
- const basename = path34.basename(filePath);
10982
+ const basename = path35.basename(filePath);
10605
10983
  const kindName = basename.replace(/\.(ts|js|mts|mjs)$/, "");
10606
10984
  if (registry.has(kindName)) {
10607
10985
  continue;
@@ -10727,150 +11105,6 @@ import { mkdtemp as mkdtemp2, rm as rm3, writeFile as writeFile6 } from "node:fs
10727
11105
  import { tmpdir as tmpdir2 } from "node:os";
10728
11106
  import { dirname, join } from "node:path";
10729
11107
 
10730
- // src/runtime/exec.ts
10731
- function shellEscapePath(value) {
10732
- if (process.platform === "win32") {
10733
- return `"${value.replaceAll('"', '""')}"`;
10734
- }
10735
- return `'${value.replaceAll("'", `'"'"'`)}'`;
10736
- }
10737
- async function execFileWithStdin(argv, stdinPayload, options = {}) {
10738
- if (argv.length === 0) {
10739
- throw new Error("Executable argv must include at least one entry");
10740
- }
10741
- if (typeof Bun !== "undefined") {
10742
- return execFileWithStdinBun(argv, stdinPayload, options);
10743
- }
10744
- return execFileWithStdinNode(argv, stdinPayload, options);
10745
- }
10746
- async function execFileWithStdinBun(argv, stdinPayload, options) {
10747
- const command = [...argv];
10748
- const encoder = new TextEncoder();
10749
- const proc = Bun.spawn(command, {
10750
- cwd: options.cwd,
10751
- stdin: encoder.encode(stdinPayload),
10752
- stdout: "pipe",
10753
- stderr: "pipe",
10754
- // Merge additional env vars with process.env
10755
- env: options.env ? { ...process.env, ...options.env } : process.env
10756
- });
10757
- let timedOut = false;
10758
- const timeout = options.timeoutMs !== void 0 ? setTimeout(() => {
10759
- timedOut = true;
10760
- proc.kill("SIGKILL");
10761
- }, options.timeoutMs) : void 0;
10762
- try {
10763
- const stdoutPromise = proc.stdout ? new Response(proc.stdout).text() : Promise.resolve("");
10764
- const stderrPromise = proc.stderr ? new Response(proc.stderr).text() : Promise.resolve("");
10765
- const [stdout, stderr, exitCode] = await Promise.all([
10766
- stdoutPromise,
10767
- stderrPromise,
10768
- proc.exited
10769
- ]);
10770
- if (timedOut) {
10771
- throw new Error(`Process timed out after ${options.timeoutMs}ms`);
10772
- }
10773
- return {
10774
- stdout: stdout.replace(/\r\n/g, "\n"),
10775
- stderr: stderr.replace(/\r\n/g, "\n"),
10776
- exitCode
10777
- };
10778
- } finally {
10779
- if (timeout !== void 0) {
10780
- clearTimeout(timeout);
10781
- }
10782
- }
10783
- }
10784
- async function execFileWithStdinNode(argv, stdinPayload, options) {
10785
- const { spawn: spawn5 } = await import("node:child_process");
10786
- return new Promise((resolve, reject) => {
10787
- const [cmd, ...args] = argv;
10788
- const child = spawn5(cmd, args, {
10789
- cwd: options.cwd,
10790
- stdio: ["pipe", "pipe", "pipe"],
10791
- // Merge additional env vars with process.env
10792
- env: options.env ? { ...process.env, ...options.env } : process.env
10793
- });
10794
- const stdoutChunks = [];
10795
- const stderrChunks = [];
10796
- child.stdout?.on("data", (chunk) => stdoutChunks.push(chunk));
10797
- child.stderr?.on("data", (chunk) => stderrChunks.push(chunk));
10798
- let timedOut = false;
10799
- const timeout = options.timeoutMs !== void 0 ? setTimeout(() => {
10800
- timedOut = true;
10801
- child.kill("SIGKILL");
10802
- }, options.timeoutMs) : void 0;
10803
- child.on("error", (error) => {
10804
- if (timeout !== void 0) clearTimeout(timeout);
10805
- reject(error);
10806
- });
10807
- child.on("close", (code) => {
10808
- if (timeout !== void 0) clearTimeout(timeout);
10809
- if (timedOut) {
10810
- reject(new Error(`Process timed out after ${options.timeoutMs}ms`));
10811
- return;
10812
- }
10813
- const stdout = Buffer.concat(stdoutChunks).toString("utf8").replace(/\r\n/g, "\n");
10814
- const stderr = Buffer.concat(stderrChunks).toString("utf8").replace(/\r\n/g, "\n");
10815
- resolve({
10816
- stdout,
10817
- stderr,
10818
- exitCode: code ?? 0
10819
- });
10820
- });
10821
- if (child.stdin) {
10822
- child.stdin.write(stdinPayload);
10823
- child.stdin.end();
10824
- }
10825
- });
10826
- }
10827
- async function execShellWithStdin(command, stdinPayload, options = {}) {
10828
- const { mkdir: mkdir16, readFile: readFile16, rm: rm6, writeFile: writeFile9 } = await import("node:fs/promises");
10829
- const { tmpdir: tmpdir3 } = await import("node:os");
10830
- const path51 = await import("node:path");
10831
- const { randomUUID: randomUUID10 } = await import("node:crypto");
10832
- const dir = path51.join(tmpdir3(), `agentv-exec-${randomUUID10()}`);
10833
- await mkdir16(dir, { recursive: true });
10834
- const stdinPath = path51.join(dir, "stdin.txt");
10835
- const stdoutPath = path51.join(dir, "stdout.txt");
10836
- const stderrPath = path51.join(dir, "stderr.txt");
10837
- await writeFile9(stdinPath, stdinPayload, "utf8");
10838
- const wrappedCommand = process.platform === "win32" ? `(${command}) < ${shellEscapePath(stdinPath)} > ${shellEscapePath(stdoutPath)} 2> ${shellEscapePath(stderrPath)}` : `(${command}) < ${shellEscapePath(stdinPath)} > ${shellEscapePath(stdoutPath)} 2> ${shellEscapePath(stderrPath)}`;
10839
- const { spawn: spawn5 } = await import("node:child_process");
10840
- try {
10841
- const exitCode = await new Promise((resolve, reject) => {
10842
- const child = spawn5(wrappedCommand, {
10843
- shell: true,
10844
- cwd: options.cwd,
10845
- stdio: ["ignore", "ignore", "ignore"],
10846
- // Merge additional env vars with process.env
10847
- env: options.env ? { ...process.env, ...options.env } : process.env
10848
- });
10849
- const timeout = options.timeoutMs ? setTimeout(() => {
10850
- child.kill();
10851
- reject(new Error(`Process timed out after ${options.timeoutMs}ms`));
10852
- }, options.timeoutMs) : void 0;
10853
- child.on("error", (error) => {
10854
- if (timeout !== void 0) {
10855
- clearTimeout(timeout);
10856
- }
10857
- reject(error);
10858
- });
10859
- child.on("exit", (code) => {
10860
- if (timeout !== void 0) {
10861
- clearTimeout(timeout);
10862
- }
10863
- resolve(code ?? 0);
10864
- });
10865
- });
10866
- const stdout = (await readFile16(stdoutPath, "utf8")).replace(/\r\n/g, "\n");
10867
- const stderr = (await readFile16(stderrPath, "utf8")).replace(/\r\n/g, "\n");
10868
- return { stdout, stderr, exitCode };
10869
- } finally {
10870
- await rm6(dir, { recursive: true, force: true });
10871
- }
10872
- }
10873
-
10874
11108
  // src/runtime/target-proxy.ts
10875
11109
  import { randomBytes } from "node:crypto";
10876
11110
  import { createServer } from "node:http";
@@ -11380,7 +11614,7 @@ import { generateText as generateText3 } from "ai";
11380
11614
 
11381
11615
  // src/evaluation/evaluators/llm-grader.ts
11382
11616
  import fs2 from "node:fs/promises";
11383
- import path35 from "node:path";
11617
+ import path36 from "node:path";
11384
11618
  import { generateText as generateText2, stepCountIs, tool } from "ai";
11385
11619
  import { z as z3 } from "zod";
11386
11620
  var DEFAULT_MAX_STEPS = 10;
@@ -11464,6 +11698,15 @@ var scoreRangeEvaluationSchema = z3.object({
11464
11698
  checks: z3.array(scoreRangeCheckResultSchema).describe("Scores for each rubric criterion"),
11465
11699
  overall_reasoning: z3.string().describe("Overall assessment summary (1-2 sentences)").optional()
11466
11700
  });
11701
+ function resolveContentBasePath(context) {
11702
+ if (context.workspacePath) {
11703
+ return context.workspacePath;
11704
+ }
11705
+ if ("config" in context.target && context.target.config && typeof context.target.config === "object" && "cwd" in context.target.config && typeof context.target.config.cwd === "string") {
11706
+ return context.target.config.cwd;
11707
+ }
11708
+ return void 0;
11709
+ }
11467
11710
  var LlmGraderEvaluator = class {
11468
11711
  kind = "llm-grader";
11469
11712
  resolveGraderProvider;
@@ -11481,24 +11724,46 @@ var LlmGraderEvaluator = class {
11481
11724
  this.graderTargetProvider = options.graderTargetProvider ?? options.judgeTargetProvider;
11482
11725
  }
11483
11726
  async evaluate(context) {
11727
+ const preparedContext = await this.prepareContext(context);
11484
11728
  if (this.graderTargetProvider) {
11485
- return this.evaluateWithGraderTarget(context);
11729
+ return this.evaluateWithGraderTarget(preparedContext);
11486
11730
  }
11487
- const graderProvider = await this.resolveGraderProvider(context);
11731
+ const graderProvider = await this.resolveGraderProvider(preparedContext);
11488
11732
  if (!graderProvider) {
11489
11733
  throw new Error("No grader provider available for LLM grading");
11490
11734
  }
11491
11735
  if (graderProvider.kind === "agentv") {
11492
- return this.evaluateBuiltIn(context, graderProvider);
11736
+ return this.evaluateBuiltIn(preparedContext, graderProvider);
11493
11737
  }
11494
11738
  if (isAgentProvider(graderProvider)) {
11495
- return this.evaluateWithDelegatedAgent(context, graderProvider);
11739
+ return this.evaluateWithDelegatedAgent(preparedContext, graderProvider);
11496
11740
  }
11497
- const config = context.evaluator;
11741
+ const config = preparedContext.evaluator;
11498
11742
  if (config?.type === "llm-grader" && config.rubrics && config.rubrics.length > 0) {
11499
- return this.evaluateWithRubrics(context, graderProvider, config.rubrics);
11743
+ return this.evaluateWithRubrics(preparedContext, graderProvider, config.rubrics);
11744
+ }
11745
+ return this.evaluateFreeform(preparedContext, graderProvider);
11746
+ }
11747
+ async prepareContext(context) {
11748
+ const config = context.evaluator;
11749
+ if (config?.type !== "llm-grader" || !context.output) {
11750
+ return context;
11751
+ }
11752
+ const lastAssistant = [...context.output].reverse().find((message) => message.role === "assistant" && message.content !== void 0);
11753
+ if (!lastAssistant || typeof lastAssistant.content === "string") {
11754
+ return context;
11500
11755
  }
11501
- return this.evaluateFreeform(context, graderProvider);
11756
+ const extracted = await extractTextWithPreprocessors(
11757
+ lastAssistant.content,
11758
+ config.preprocessors,
11759
+ {
11760
+ basePath: resolveContentBasePath(context)
11761
+ }
11762
+ );
11763
+ return {
11764
+ ...context,
11765
+ candidate: appendPreprocessingWarnings(extracted.text, extracted.warnings)
11766
+ };
11502
11767
  }
11503
11768
  // ---------------------------------------------------------------------------
11504
11769
  // LLM mode (existing)
@@ -12383,8 +12648,8 @@ function toAiSdkImageParts(images) {
12383
12648
  }));
12384
12649
  }
12385
12650
  function resolveSandboxed(basePath, relativePath) {
12386
- const resolved = path35.resolve(basePath, relativePath);
12387
- if (!resolved.startsWith(basePath + path35.sep) && resolved !== basePath) {
12651
+ const resolved = path36.resolve(basePath, relativePath);
12652
+ if (!resolved.startsWith(basePath + path36.sep) && resolved !== basePath) {
12388
12653
  throw new Error(`Path '${relativePath}' is outside the workspace`);
12389
12654
  }
12390
12655
  return resolved;
@@ -12474,11 +12739,11 @@ async function searchDirectory(dirPath, workspacePath, regex, matches) {
12474
12739
  for (const entry of entries) {
12475
12740
  if (matches.length >= MAX_SEARCH_MATCHES) return;
12476
12741
  if (SEARCH_SKIP_DIRS.has(entry.name)) continue;
12477
- const fullPath = path35.join(dirPath, entry.name);
12742
+ const fullPath = path36.join(dirPath, entry.name);
12478
12743
  if (entry.isDirectory()) {
12479
12744
  await searchDirectory(fullPath, workspacePath, regex, matches);
12480
12745
  } else if (entry.isFile()) {
12481
- const ext = path35.extname(entry.name).toLowerCase();
12746
+ const ext = path36.extname(entry.name).toLowerCase();
12482
12747
  if (BINARY_EXTENSIONS.has(ext)) continue;
12483
12748
  try {
12484
12749
  const stat11 = await fs2.stat(fullPath);
@@ -12490,7 +12755,7 @@ async function searchDirectory(dirPath, workspacePath, regex, matches) {
12490
12755
  regex.lastIndex = 0;
12491
12756
  if (regex.test(lines[i])) {
12492
12757
  matches.push({
12493
- file: path35.relative(workspacePath, fullPath),
12758
+ file: path36.relative(workspacePath, fullPath),
12494
12759
  line: i + 1,
12495
12760
  text: lines[i].substring(0, 200)
12496
12761
  });
@@ -13123,115 +13388,115 @@ var FieldAccuracyEvaluator = class {
13123
13388
  * Evaluate a single field against the expected value.
13124
13389
  */
13125
13390
  evaluateField(fieldConfig, candidateData, expectedData) {
13126
- const { path: path51, match, required = true, weight = 1 } = fieldConfig;
13127
- const candidateValue = resolvePath(candidateData, path51);
13128
- const expectedValue = resolvePath(expectedData, path51);
13391
+ const { path: path52, match, required = true, weight = 1 } = fieldConfig;
13392
+ const candidateValue = resolvePath(candidateData, path52);
13393
+ const expectedValue = resolvePath(expectedData, path52);
13129
13394
  if (expectedValue === void 0) {
13130
13395
  return {
13131
- path: path51,
13396
+ path: path52,
13132
13397
  score: 1,
13133
13398
  // No expected value means no comparison needed
13134
13399
  weight,
13135
13400
  hit: true,
13136
- message: `${path51}: no expected value`
13401
+ message: `${path52}: no expected value`
13137
13402
  };
13138
13403
  }
13139
13404
  if (candidateValue === void 0) {
13140
13405
  if (required) {
13141
13406
  return {
13142
- path: path51,
13407
+ path: path52,
13143
13408
  score: 0,
13144
13409
  weight,
13145
13410
  hit: false,
13146
- message: `${path51} (required, missing)`
13411
+ message: `${path52} (required, missing)`
13147
13412
  };
13148
13413
  }
13149
13414
  return {
13150
- path: path51,
13415
+ path: path52,
13151
13416
  score: 1,
13152
13417
  // Don't penalize missing optional fields
13153
13418
  weight: 0,
13154
13419
  // Zero weight means it won't affect the score
13155
13420
  hit: true,
13156
- message: `${path51}: optional field missing`
13421
+ message: `${path52}: optional field missing`
13157
13422
  };
13158
13423
  }
13159
13424
  switch (match) {
13160
13425
  case "exact":
13161
- return this.compareExact(path51, candidateValue, expectedValue, weight);
13426
+ return this.compareExact(path52, candidateValue, expectedValue, weight);
13162
13427
  case "numeric_tolerance":
13163
13428
  return this.compareNumericTolerance(
13164
- path51,
13429
+ path52,
13165
13430
  candidateValue,
13166
13431
  expectedValue,
13167
13432
  fieldConfig,
13168
13433
  weight
13169
13434
  );
13170
13435
  case "date":
13171
- return this.compareDate(path51, candidateValue, expectedValue, fieldConfig, weight);
13436
+ return this.compareDate(path52, candidateValue, expectedValue, fieldConfig, weight);
13172
13437
  default:
13173
13438
  return {
13174
- path: path51,
13439
+ path: path52,
13175
13440
  score: 0,
13176
13441
  weight,
13177
13442
  hit: false,
13178
- message: `${path51}: unknown match type "${match}"`
13443
+ message: `${path52}: unknown match type "${match}"`
13179
13444
  };
13180
13445
  }
13181
13446
  }
13182
13447
  /**
13183
13448
  * Exact equality comparison.
13184
13449
  */
13185
- compareExact(path51, candidateValue, expectedValue, weight) {
13450
+ compareExact(path52, candidateValue, expectedValue, weight) {
13186
13451
  if (deepEqual(candidateValue, expectedValue)) {
13187
13452
  return {
13188
- path: path51,
13453
+ path: path52,
13189
13454
  score: 1,
13190
13455
  weight,
13191
13456
  hit: true,
13192
- message: path51
13457
+ message: path52
13193
13458
  };
13194
13459
  }
13195
13460
  if (typeof candidateValue !== typeof expectedValue) {
13196
13461
  return {
13197
- path: path51,
13462
+ path: path52,
13198
13463
  score: 0,
13199
13464
  weight,
13200
13465
  hit: false,
13201
- message: `${path51} (type mismatch: got ${typeof candidateValue}, expected ${typeof expectedValue})`
13466
+ message: `${path52} (type mismatch: got ${typeof candidateValue}, expected ${typeof expectedValue})`
13202
13467
  };
13203
13468
  }
13204
13469
  return {
13205
- path: path51,
13470
+ path: path52,
13206
13471
  score: 0,
13207
13472
  weight,
13208
13473
  hit: false,
13209
- message: `${path51} (value mismatch)`
13474
+ message: `${path52} (value mismatch)`
13210
13475
  };
13211
13476
  }
13212
13477
  /**
13213
13478
  * Numeric comparison with absolute or relative tolerance.
13214
13479
  */
13215
- compareNumericTolerance(path51, candidateValue, expectedValue, fieldConfig, weight) {
13480
+ compareNumericTolerance(path52, candidateValue, expectedValue, fieldConfig, weight) {
13216
13481
  const { tolerance = 0, relative = false } = fieldConfig;
13217
13482
  const candidateNum = toNumber(candidateValue);
13218
13483
  const expectedNum = toNumber(expectedValue);
13219
13484
  if (candidateNum === null || expectedNum === null) {
13220
13485
  return {
13221
- path: path51,
13486
+ path: path52,
13222
13487
  score: 0,
13223
13488
  weight,
13224
13489
  hit: false,
13225
- message: `${path51} (non-numeric value)`
13490
+ message: `${path52} (non-numeric value)`
13226
13491
  };
13227
13492
  }
13228
13493
  if (!Number.isFinite(candidateNum) || !Number.isFinite(expectedNum)) {
13229
13494
  return {
13230
- path: path51,
13495
+ path: path52,
13231
13496
  score: 0,
13232
13497
  weight,
13233
13498
  hit: false,
13234
- message: `${path51} (invalid numeric value)`
13499
+ message: `${path52} (invalid numeric value)`
13235
13500
  };
13236
13501
  }
13237
13502
  const diff = Math.abs(candidateNum - expectedNum);
@@ -13244,61 +13509,61 @@ var FieldAccuracyEvaluator = class {
13244
13509
  }
13245
13510
  if (withinTolerance) {
13246
13511
  return {
13247
- path: path51,
13512
+ path: path52,
13248
13513
  score: 1,
13249
13514
  weight,
13250
13515
  hit: true,
13251
- message: `${path51} (within tolerance: diff=${diff.toFixed(2)})`
13516
+ message: `${path52} (within tolerance: diff=${diff.toFixed(2)})`
13252
13517
  };
13253
13518
  }
13254
13519
  return {
13255
- path: path51,
13520
+ path: path52,
13256
13521
  score: 0,
13257
13522
  weight,
13258
13523
  hit: false,
13259
- message: `${path51} (outside tolerance: diff=${diff.toFixed(2)}, tolerance=${tolerance})`
13524
+ message: `${path52} (outside tolerance: diff=${diff.toFixed(2)}, tolerance=${tolerance})`
13260
13525
  };
13261
13526
  }
13262
13527
  /**
13263
13528
  * Date comparison with format normalization.
13264
13529
  */
13265
- compareDate(path51, candidateValue, expectedValue, fieldConfig, weight) {
13530
+ compareDate(path52, candidateValue, expectedValue, fieldConfig, weight) {
13266
13531
  const formats = fieldConfig.formats ?? DEFAULT_DATE_FORMATS;
13267
13532
  const candidateDate = parseDate(String(candidateValue), formats);
13268
13533
  const expectedDate = parseDate(String(expectedValue), formats);
13269
13534
  if (candidateDate === null) {
13270
13535
  return {
13271
- path: path51,
13536
+ path: path52,
13272
13537
  score: 0,
13273
13538
  weight,
13274
13539
  hit: false,
13275
- message: `${path51} (unparseable candidate date)`
13540
+ message: `${path52} (unparseable candidate date)`
13276
13541
  };
13277
13542
  }
13278
13543
  if (expectedDate === null) {
13279
13544
  return {
13280
- path: path51,
13545
+ path: path52,
13281
13546
  score: 0,
13282
13547
  weight,
13283
13548
  hit: false,
13284
- message: `${path51} (unparseable expected date)`
13549
+ message: `${path52} (unparseable expected date)`
13285
13550
  };
13286
13551
  }
13287
13552
  if (candidateDate.getFullYear() === expectedDate.getFullYear() && candidateDate.getMonth() === expectedDate.getMonth() && candidateDate.getDate() === expectedDate.getDate()) {
13288
13553
  return {
13289
- path: path51,
13554
+ path: path52,
13290
13555
  score: 1,
13291
13556
  weight,
13292
13557
  hit: true,
13293
- message: path51
13558
+ message: path52
13294
13559
  };
13295
13560
  }
13296
13561
  return {
13297
- path: path51,
13562
+ path: path52,
13298
13563
  score: 0,
13299
13564
  weight,
13300
13565
  hit: false,
13301
- message: `${path51} (date mismatch: got ${formatDateISO(candidateDate)}, expected ${formatDateISO(expectedDate)})`
13566
+ message: `${path52} (date mismatch: got ${formatDateISO(candidateDate)}, expected ${formatDateISO(expectedDate)})`
13302
13567
  };
13303
13568
  }
13304
13569
  /**
@@ -13331,11 +13596,11 @@ var FieldAccuracyEvaluator = class {
13331
13596
  };
13332
13597
  }
13333
13598
  };
13334
- function resolvePath(obj, path51) {
13335
- if (!path51 || !obj) {
13599
+ function resolvePath(obj, path52) {
13600
+ if (!path52 || !obj) {
13336
13601
  return void 0;
13337
13602
  }
13338
- const parts = path51.split(/\.|\[|\]/).filter((p) => p.length > 0);
13603
+ const parts = path52.split(/\.|\[|\]/).filter((p) => p.length > 0);
13339
13604
  let current = obj;
13340
13605
  for (const part of parts) {
13341
13606
  if (current === null || current === void 0) {
@@ -13827,8 +14092,8 @@ var TokenUsageEvaluator = class {
13827
14092
  };
13828
14093
 
13829
14094
  // src/evaluation/evaluators/tool-trajectory.ts
13830
- function getNestedValue(obj, path51) {
13831
- const parts = path51.split(".");
14095
+ function getNestedValue(obj, path52) {
14096
+ const parts = path52.split(".");
13832
14097
  let current = obj;
13833
14098
  for (const part of parts) {
13834
14099
  if (current === null || current === void 0 || typeof current !== "object") {
@@ -14449,8 +14714,9 @@ function runEqualsAssertion(output, value) {
14449
14714
 
14450
14715
  // src/evaluation/orchestrator.ts
14451
14716
  import { createHash as createHash2, randomUUID as randomUUID9 } from "node:crypto";
14717
+ import { existsSync as existsSync5 } from "node:fs";
14452
14718
  import { copyFile as copyFile2, mkdir as mkdir14, readdir as readdir7, stat as stat8 } from "node:fs/promises";
14453
- import path44 from "node:path";
14719
+ import path45 from "node:path";
14454
14720
  import micromatch3 from "micromatch";
14455
14721
 
14456
14722
  // ../../node_modules/.bun/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
@@ -14664,7 +14930,7 @@ var InlineAssertEvaluator = class {
14664
14930
  };
14665
14931
 
14666
14932
  // src/evaluation/evaluators/prompt-resolution.ts
14667
- import path36 from "node:path";
14933
+ import path37 from "node:path";
14668
14934
  async function resolveCustomPrompt(promptConfig, context, timeoutMs) {
14669
14935
  if (promptConfig.resolvedPromptScript && promptConfig.resolvedPromptScript.length > 0) {
14670
14936
  if (!context) {
@@ -14707,7 +14973,7 @@ async function executePromptTemplate(script, context, config, timeoutMs) {
14707
14973
  };
14708
14974
  const inputJson = JSON.stringify(toSnakeCaseDeep(payload), null, 2);
14709
14975
  const scriptPath = script[script.length - 1];
14710
- const cwd = path36.dirname(scriptPath);
14976
+ const cwd = path37.dirname(scriptPath);
14711
14977
  try {
14712
14978
  const stdout = await executeScript(script, inputJson, timeoutMs, cwd);
14713
14979
  const prompt = stdout.trim();
@@ -14979,16 +15245,16 @@ function createBuiltinRegistry() {
14979
15245
  }
14980
15246
 
14981
15247
  // src/evaluation/registry/assertion-discovery.ts
14982
- import path37 from "node:path";
15248
+ import path38 from "node:path";
14983
15249
  import fg2 from "fast-glob";
14984
15250
  async function discoverAssertions(registry, baseDir) {
14985
15251
  const patterns = ["*.ts", "*.js", "*.mts", "*.mjs"];
14986
15252
  const candidateDirs = [];
14987
- let dir = path37.resolve(baseDir);
14988
- const root = path37.parse(dir).root;
15253
+ let dir = path38.resolve(baseDir);
15254
+ const root = path38.parse(dir).root;
14989
15255
  while (dir !== root) {
14990
- candidateDirs.push(path37.join(dir, ".agentv", "assertions"));
14991
- dir = path37.dirname(dir);
15256
+ candidateDirs.push(path38.join(dir, ".agentv", "assertions"));
15257
+ dir = path38.dirname(dir);
14992
15258
  }
14993
15259
  let files = [];
14994
15260
  for (const assertionsDir of candidateDirs) {
@@ -15004,7 +15270,7 @@ async function discoverAssertions(registry, baseDir) {
15004
15270
  }
15005
15271
  const discoveredTypes = [];
15006
15272
  for (const filePath of files) {
15007
- const basename = path37.basename(filePath);
15273
+ const basename = path38.basename(filePath);
15008
15274
  const typeName = basename.replace(/\.(ts|js|mts|mjs)$/, "");
15009
15275
  if (registry.has(typeName)) {
15010
15276
  continue;
@@ -15022,17 +15288,17 @@ async function discoverAssertions(registry, baseDir) {
15022
15288
  }
15023
15289
 
15024
15290
  // src/evaluation/registry/grader-discovery.ts
15025
- import path38 from "node:path";
15291
+ import path39 from "node:path";
15026
15292
  import fg3 from "fast-glob";
15027
15293
  async function discoverGraders(registry, baseDir) {
15028
15294
  const patterns = ["*.ts", "*.js", "*.mts", "*.mjs"];
15029
15295
  const candidateDirs = [];
15030
- let dir = path38.resolve(baseDir);
15031
- const root = path38.parse(dir).root;
15296
+ let dir = path39.resolve(baseDir);
15297
+ const root = path39.parse(dir).root;
15032
15298
  while (dir !== root) {
15033
- candidateDirs.push(path38.join(dir, ".agentv", "graders"));
15034
- candidateDirs.push(path38.join(dir, ".agentv", "judges"));
15035
- dir = path38.dirname(dir);
15299
+ candidateDirs.push(path39.join(dir, ".agentv", "graders"));
15300
+ candidateDirs.push(path39.join(dir, ".agentv", "judges"));
15301
+ dir = path39.dirname(dir);
15036
15302
  }
15037
15303
  let files = [];
15038
15304
  for (const gradersDir of candidateDirs) {
@@ -15048,7 +15314,7 @@ async function discoverGraders(registry, baseDir) {
15048
15314
  }
15049
15315
  const discoveredTypes = [];
15050
15316
  for (const filePath of files) {
15051
- const basename = path38.basename(filePath);
15317
+ const basename = path39.basename(filePath);
15052
15318
  const typeName = basename.replace(/\.(ts|js|mts|mjs)$/, "");
15053
15319
  if (registry.has(typeName)) {
15054
15320
  continue;
@@ -15208,7 +15474,7 @@ function getTCritical(df) {
15208
15474
  // src/evaluation/workspace/file-changes.ts
15209
15475
  import { exec as execCallback } from "node:child_process";
15210
15476
  import { readdirSync as readdirSync2, statSync } from "node:fs";
15211
- import path39 from "node:path";
15477
+ import path40 from "node:path";
15212
15478
  import { promisify as promisify4 } from "node:util";
15213
15479
  var execAsync4 = promisify4(execCallback);
15214
15480
  function gitExecOpts(workspacePath) {
@@ -15242,10 +15508,10 @@ async function stageNestedRepoChanges(workspacePath) {
15242
15508
  }
15243
15509
  for (const entry of entries) {
15244
15510
  if (entry === ".git" || entry === "node_modules") continue;
15245
- const childPath = path39.join(workspacePath, entry);
15511
+ const childPath = path40.join(workspacePath, entry);
15246
15512
  try {
15247
15513
  if (!statSync(childPath).isDirectory()) continue;
15248
- if (!statSync(path39.join(childPath, ".git")).isDirectory()) continue;
15514
+ if (!statSync(path40.join(childPath, ".git")).isDirectory()) continue;
15249
15515
  } catch {
15250
15516
  continue;
15251
15517
  }
@@ -15256,7 +15522,7 @@ async function stageNestedRepoChanges(workspacePath) {
15256
15522
 
15257
15523
  // src/evaluation/workspace/manager.ts
15258
15524
  import { cp, mkdir as mkdir12, readdir as readdir4, rm as rm4, stat as stat6 } from "node:fs/promises";
15259
- import path40 from "node:path";
15525
+ import path41 from "node:path";
15260
15526
  var TemplateNotFoundError = class extends Error {
15261
15527
  constructor(templatePath) {
15262
15528
  super(`Workspace template not found: ${templatePath}`);
@@ -15286,14 +15552,14 @@ async function isDirectory(filePath) {
15286
15552
  }
15287
15553
  function getWorkspacePath(evalRunId, caseId, workspaceRoot) {
15288
15554
  const root = workspaceRoot ?? getWorkspacesRoot();
15289
- return path40.join(root, evalRunId, caseId);
15555
+ return path41.join(root, evalRunId, caseId);
15290
15556
  }
15291
15557
  async function copyDirectoryRecursive(src, dest) {
15292
15558
  await mkdir12(dest, { recursive: true });
15293
15559
  const entries = await readdir4(src, { withFileTypes: true });
15294
15560
  for (const entry of entries) {
15295
- const srcPath = path40.join(src, entry.name);
15296
- const destPath = path40.join(dest, entry.name);
15561
+ const srcPath = path41.join(src, entry.name);
15562
+ const destPath = path41.join(dest, entry.name);
15297
15563
  if (entry.name === ".git") {
15298
15564
  continue;
15299
15565
  }
@@ -15305,7 +15571,7 @@ async function copyDirectoryRecursive(src, dest) {
15305
15571
  }
15306
15572
  }
15307
15573
  async function createTempWorkspace(templatePath, evalRunId, caseId, workspaceRoot) {
15308
- const resolvedTemplatePath = path40.resolve(templatePath);
15574
+ const resolvedTemplatePath = path41.resolve(templatePath);
15309
15575
  if (!await fileExists(resolvedTemplatePath)) {
15310
15576
  throw new TemplateNotFoundError(resolvedTemplatePath);
15311
15577
  }
@@ -15354,7 +15620,7 @@ async function cleanupWorkspace(workspacePath) {
15354
15620
  }
15355
15621
  async function cleanupEvalWorkspaces(evalRunId, workspaceRoot) {
15356
15622
  const root = workspaceRoot ?? getWorkspacesRoot();
15357
- const evalDir = path40.join(root, evalRunId);
15623
+ const evalDir = path41.join(root, evalRunId);
15358
15624
  if (await fileExists(evalDir)) {
15359
15625
  await rm4(evalDir, { recursive: true, force: true });
15360
15626
  }
@@ -15364,8 +15630,8 @@ async function cleanupEvalWorkspaces(evalRunId, workspaceRoot) {
15364
15630
  import { execFile } from "node:child_process";
15365
15631
  import { createHash } from "node:crypto";
15366
15632
  import { existsSync as existsSync3 } from "node:fs";
15367
- import { cp as cp2, mkdir as mkdir13, readFile as readFile12, readdir as readdir5, rm as rm5, unlink, writeFile as writeFile7 } from "node:fs/promises";
15368
- import path41 from "node:path";
15633
+ import { cp as cp2, mkdir as mkdir13, readFile as readFile13, readdir as readdir5, rm as rm5, unlink, writeFile as writeFile7 } from "node:fs/promises";
15634
+ import path42 from "node:path";
15369
15635
  import { promisify as promisify5 } from "node:util";
15370
15636
  var execFileAsync = promisify5(execFile);
15371
15637
  function gitEnv() {
@@ -15419,8 +15685,8 @@ async function copyDirectoryRecursive2(src, dest, skipDirs) {
15419
15685
  await mkdir13(dest, { recursive: true });
15420
15686
  const entries = await readdir5(src, { withFileTypes: true });
15421
15687
  for (const entry of entries) {
15422
- const srcPath = path41.join(src, entry.name);
15423
- const destPath = path41.join(dest, entry.name);
15688
+ const srcPath = path42.join(src, entry.name);
15689
+ const destPath = path42.join(dest, entry.name);
15424
15690
  if (entry.name === ".git") {
15425
15691
  continue;
15426
15692
  }
@@ -15453,7 +15719,7 @@ var WorkspacePoolManager = class {
15453
15719
  async acquireWorkspace(options) {
15454
15720
  const { templatePath, repos, maxSlots, repoManager, poolReset } = options;
15455
15721
  const fingerprint = computeWorkspaceFingerprint(repos);
15456
- const poolDir = path41.join(this.poolRoot, fingerprint);
15722
+ const poolDir = path42.join(this.poolRoot, fingerprint);
15457
15723
  await mkdir13(poolDir, { recursive: true });
15458
15724
  const drifted = await this.checkDrift(poolDir, fingerprint);
15459
15725
  if (drifted) {
@@ -15463,7 +15729,7 @@ var WorkspacePoolManager = class {
15463
15729
  await this.removeAllSlots(poolDir);
15464
15730
  }
15465
15731
  for (let i = 0; i < maxSlots; i++) {
15466
- const slotPath = path41.join(poolDir, `slot-${i}`);
15732
+ const slotPath = path42.join(poolDir, `slot-${i}`);
15467
15733
  const lockPath = `${slotPath}.lock`;
15468
15734
  const locked = await this.tryLock(lockPath);
15469
15735
  if (!locked) {
@@ -15525,7 +15791,7 @@ var WorkspacePoolManager = class {
15525
15791
  throw err;
15526
15792
  }
15527
15793
  try {
15528
- const pidStr = await readFile12(lockPath, "utf-8");
15794
+ const pidStr = await readFile13(lockPath, "utf-8");
15529
15795
  const pid = Number.parseInt(pidStr.trim(), 10);
15530
15796
  if (!Number.isNaN(pid)) {
15531
15797
  try {
@@ -15550,9 +15816,9 @@ var WorkspacePoolManager = class {
15550
15816
  * Returns false (no drift) if metadata.json doesn't exist (first use).
15551
15817
  */
15552
15818
  async checkDrift(poolDir, fingerprint) {
15553
- const metadataPath = path41.join(poolDir, "metadata.json");
15819
+ const metadataPath = path42.join(poolDir, "metadata.json");
15554
15820
  try {
15555
- const raw = await readFile12(metadataPath, "utf-8");
15821
+ const raw = await readFile13(metadataPath, "utf-8");
15556
15822
  const metadata = JSON.parse(raw);
15557
15823
  return metadata.fingerprint !== fingerprint;
15558
15824
  } catch {
@@ -15567,17 +15833,17 @@ var WorkspacePoolManager = class {
15567
15833
  repos,
15568
15834
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
15569
15835
  };
15570
- await writeFile7(path41.join(poolDir, "metadata.json"), JSON.stringify(metadata, null, 2));
15836
+ await writeFile7(path42.join(poolDir, "metadata.json"), JSON.stringify(metadata, null, 2));
15571
15837
  }
15572
15838
  /** Remove all slot directories and their lock files from a pool directory. */
15573
15839
  async removeAllSlots(poolDir) {
15574
15840
  const entries = await readdir5(poolDir);
15575
15841
  for (const entry of entries) {
15576
15842
  if (entry.startsWith("slot-") && !entry.endsWith(".lock")) {
15577
- const lockPath = path41.join(poolDir, `${entry}.lock`);
15843
+ const lockPath = path42.join(poolDir, `${entry}.lock`);
15578
15844
  if (existsSync3(lockPath)) {
15579
15845
  try {
15580
- const pidStr = await readFile12(lockPath, "utf-8");
15846
+ const pidStr = await readFile13(lockPath, "utf-8");
15581
15847
  const pid = Number.parseInt(pidStr.trim(), 10);
15582
15848
  if (!Number.isNaN(pid)) {
15583
15849
  try {
@@ -15590,12 +15856,12 @@ var WorkspacePoolManager = class {
15590
15856
  } catch {
15591
15857
  }
15592
15858
  }
15593
- await rm5(path41.join(poolDir, entry), { recursive: true, force: true });
15859
+ await rm5(path42.join(poolDir, entry), { recursive: true, force: true });
15594
15860
  await rm5(lockPath, { force: true }).catch(() => {
15595
15861
  });
15596
15862
  }
15597
15863
  }
15598
- await rm5(path41.join(poolDir, "metadata.json"), { force: true }).catch(() => {
15864
+ await rm5(path42.join(poolDir, "metadata.json"), { force: true }).catch(() => {
15599
15865
  });
15600
15866
  }
15601
15867
  /**
@@ -15605,7 +15871,7 @@ var WorkspacePoolManager = class {
15605
15871
  */
15606
15872
  async resetSlot(slotPath, templatePath, repos, poolReset = "fast") {
15607
15873
  for (const repo of repos) {
15608
- const repoDir = path41.join(slotPath, repo.path);
15874
+ const repoDir = path42.join(slotPath, repo.path);
15609
15875
  if (!existsSync3(repoDir)) {
15610
15876
  continue;
15611
15877
  }
@@ -15642,7 +15908,7 @@ var WorkspacePoolManager = class {
15642
15908
  // src/evaluation/workspace/repo-manager.ts
15643
15909
  import { execFile as execFile2 } from "node:child_process";
15644
15910
  import { existsSync as existsSync4 } from "node:fs";
15645
- import path42 from "node:path";
15911
+ import path43 from "node:path";
15646
15912
  import { promisify as promisify6 } from "node:util";
15647
15913
  var execFileAsync2 = promisify6(execFile2);
15648
15914
  var DEFAULT_TIMEOUT_MS2 = 3e5;
@@ -15742,7 +16008,7 @@ ${lines.join("\n")}`;
15742
16008
  * Handles checkout, ref resolution, ancestor walking, shallow clone, sparse checkout.
15743
16009
  */
15744
16010
  async materialize(repo, workspacePath) {
15745
- const targetDir = path42.join(workspacePath, repo.path);
16011
+ const targetDir = path43.join(workspacePath, repo.path);
15746
16012
  const sourceUrl = getSourceUrl(repo.source);
15747
16013
  const startedAt = Date.now();
15748
16014
  if (this.verbose) {
@@ -15833,7 +16099,7 @@ ${lines.join("\n")}`;
15833
16099
  async reset(repos, workspacePath, reset) {
15834
16100
  const cleanFlag = reset === "strict" ? "-fdx" : "-fd";
15835
16101
  for (const repo of repos) {
15836
- const targetDir = path42.join(workspacePath, repo.path);
16102
+ const targetDir = path43.join(workspacePath, repo.path);
15837
16103
  await this.runGit(["reset", "--hard", "HEAD"], { cwd: targetDir });
15838
16104
  await this.runGit(["clean", cleanFlag], { cwd: targetDir });
15839
16105
  }
@@ -15842,16 +16108,16 @@ ${lines.join("\n")}`;
15842
16108
 
15843
16109
  // src/evaluation/workspace/resolve.ts
15844
16110
  import { readdir as readdir6, stat as stat7 } from "node:fs/promises";
15845
- import path43 from "node:path";
16111
+ import path44 from "node:path";
15846
16112
  async function resolveWorkspaceTemplate(templatePath) {
15847
16113
  if (!templatePath) {
15848
16114
  return void 0;
15849
16115
  }
15850
- const resolved = path43.resolve(templatePath);
16116
+ const resolved = path44.resolve(templatePath);
15851
16117
  const stats = await stat7(resolved);
15852
16118
  if (stats.isFile()) {
15853
16119
  return {
15854
- dir: path43.dirname(resolved),
16120
+ dir: path44.dirname(resolved),
15855
16121
  workspaceFile: resolved
15856
16122
  };
15857
16123
  }
@@ -15863,14 +16129,14 @@ async function resolveWorkspaceTemplate(templatePath) {
15863
16129
  if (workspaceFiles.length === 1) {
15864
16130
  return {
15865
16131
  dir: resolved,
15866
- workspaceFile: path43.join(resolved, workspaceFiles[0])
16132
+ workspaceFile: path44.join(resolved, workspaceFiles[0])
15867
16133
  };
15868
16134
  }
15869
16135
  if (workspaceFiles.length > 1) {
15870
16136
  const conventionFile = workspaceFiles.find((f) => f === "template.code-workspace");
15871
16137
  return {
15872
16138
  dir: resolved,
15873
- workspaceFile: conventionFile ? path43.join(resolved, conventionFile) : void 0
16139
+ workspaceFile: conventionFile ? path44.join(resolved, conventionFile) : void 0
15874
16140
  };
15875
16141
  }
15876
16142
  return { dir: resolved };
@@ -16089,7 +16355,7 @@ async function runEvaluation(options) {
16089
16355
  ];
16090
16356
  const evaluatorRegistry = buildEvaluatorRegistry(evaluators, resolveGraderProvider);
16091
16357
  const typeRegistry = createBuiltinRegistry();
16092
- const discoveryBaseDir = evalFilePath ? path44.dirname(path44.resolve(evalFilePath)) : process.cwd();
16358
+ const discoveryBaseDir = evalFilePath ? path45.dirname(path45.resolve(evalFilePath)) : process.cwd();
16093
16359
  const evalDir = discoveryBaseDir;
16094
16360
  await discoverAssertions(typeRegistry, discoveryBaseDir);
16095
16361
  await discoverGraders(typeRegistry, discoveryBaseDir);
@@ -16228,8 +16494,8 @@ async function runEvaluation(options) {
16228
16494
  const poolSlotBaselines = /* @__PURE__ */ new Map();
16229
16495
  const poolMaxSlots = Math.min(configPoolMaxSlots ?? 10, 50);
16230
16496
  let staticMaterialised = false;
16497
+ const isYamlConfiguredPath = !cliWorkspacePath && !!yamlWorkspacePath;
16231
16498
  if (useStaticWorkspace && configuredStaticPath) {
16232
- const isYamlConfiguredPath = !cliWorkspacePath && !!yamlWorkspacePath;
16233
16499
  const dirExists = await stat8(configuredStaticPath).then(
16234
16500
  (s) => s.isDirectory(),
16235
16501
  () => false
@@ -16287,21 +16553,35 @@ async function runEvaluation(options) {
16287
16553
  }
16288
16554
  try {
16289
16555
  if (suiteWorkspaceFile && sharedWorkspacePath) {
16290
- const copiedWorkspaceFile = path44.join(sharedWorkspacePath, path44.basename(suiteWorkspaceFile));
16556
+ const copiedWorkspaceFile = path45.join(sharedWorkspacePath, path45.basename(suiteWorkspaceFile));
16291
16557
  try {
16292
16558
  await stat8(copiedWorkspaceFile);
16293
16559
  suiteWorkspaceFile = copiedWorkspaceFile;
16294
16560
  } catch {
16295
16561
  }
16296
16562
  }
16297
- const needsRepoMaterialisation = !!suiteWorkspace?.repos?.length && !usePool && (!useStaticWorkspace || staticMaterialised);
16298
- const repoManager = needsRepoMaterialisation ? new RepoManager(verbose) : void 0;
16299
- if (repoManager && sharedWorkspacePath && suiteWorkspace?.repos && !isPerTestIsolation) {
16300
- setupLog(
16301
- `materializing ${suiteWorkspace.repos.length} shared repo(s) into ${sharedWorkspacePath}`
16302
- );
16563
+ const hasReposToMaterialize = !!suiteWorkspace?.repos?.length && !usePool && !isPerTestIsolation;
16564
+ const needsRepoMaterialisation = hasReposToMaterialize && (!useStaticWorkspace || staticMaterialised);
16565
+ const needsPerRepoCheck = hasReposToMaterialize && useStaticWorkspace && !staticMaterialised && isYamlConfiguredPath;
16566
+ const repoManager = needsRepoMaterialisation || needsPerRepoCheck ? new RepoManager(verbose) : void 0;
16567
+ if (repoManager && sharedWorkspacePath && suiteWorkspace?.repos) {
16303
16568
  try {
16304
- await repoManager.materializeAll(suiteWorkspace.repos, sharedWorkspacePath);
16569
+ if (needsPerRepoCheck) {
16570
+ for (const repo of suiteWorkspace.repos) {
16571
+ const targetDir = path45.join(sharedWorkspacePath, repo.path);
16572
+ if (existsSync5(targetDir)) {
16573
+ setupLog(`reusing existing repo at: ${targetDir}`);
16574
+ continue;
16575
+ }
16576
+ setupLog(`materializing missing repo: ${repo.path}`);
16577
+ await repoManager.materialize(repo, sharedWorkspacePath);
16578
+ }
16579
+ } else {
16580
+ setupLog(
16581
+ `materializing ${suiteWorkspace.repos.length} shared repo(s) into ${sharedWorkspacePath}`
16582
+ );
16583
+ await repoManager.materializeAll(suiteWorkspace.repos, sharedWorkspacePath);
16584
+ }
16305
16585
  setupLog("shared repo materialization complete");
16306
16586
  } catch (error) {
16307
16587
  const message = error instanceof Error ? error.message : String(error);
@@ -16875,7 +17155,7 @@ async function runEvalCase(options) {
16875
17155
  );
16876
17156
  }
16877
17157
  if (caseWorkspaceFile && workspacePath) {
16878
- const copiedFile = path44.join(workspacePath, path44.basename(caseWorkspaceFile));
17158
+ const copiedFile = path45.join(workspacePath, path45.basename(caseWorkspaceFile));
16879
17159
  try {
16880
17160
  await stat8(copiedFile);
16881
17161
  caseWorkspaceFile = copiedFile;
@@ -16937,10 +17217,10 @@ async function runEvalCase(options) {
16937
17217
  const files = evalCase.metadata.agent_skills_files;
16938
17218
  if (baseDir && files.length > 0) {
16939
17219
  for (const relPath of files) {
16940
- const srcPath = path44.resolve(baseDir, relPath);
16941
- const destPath = path44.resolve(workspacePath, relPath);
17220
+ const srcPath = path45.resolve(baseDir, relPath);
17221
+ const destPath = path45.resolve(workspacePath, relPath);
16942
17222
  try {
16943
- await mkdir14(path44.dirname(destPath), { recursive: true });
17223
+ await mkdir14(path45.dirname(destPath), { recursive: true });
16944
17224
  await copyFile2(srcPath, destPath);
16945
17225
  } catch (error) {
16946
17226
  const message = error instanceof Error ? error.message : String(error);
@@ -17536,6 +17816,7 @@ async function runEvaluatorsForCase(options) {
17536
17816
  if (!activeEvaluator) {
17537
17817
  throw new Error(`No evaluator registered for kind '${evaluatorKind}'`);
17538
17818
  }
17819
+ const implicitEvaluator = evaluatorKind === "llm-grader" && !evalCase.assertions ? buildImplicitLlmGraderConfig(evalCase) : void 0;
17539
17820
  const score = await activeEvaluator.evaluate({
17540
17821
  evalCase,
17541
17822
  candidate,
@@ -17555,10 +17836,21 @@ async function runEvaluatorsForCase(options) {
17555
17836
  targetResolver,
17556
17837
  availableTargets,
17557
17838
  fileChanges,
17558
- workspacePath
17839
+ workspacePath,
17840
+ ...implicitEvaluator ? { evaluator: implicitEvaluator } : {}
17559
17841
  });
17560
17842
  return { score };
17561
17843
  }
17844
+ function buildImplicitLlmGraderConfig(evalCase) {
17845
+ if (!evalCase.preprocessors || evalCase.preprocessors.length === 0) {
17846
+ return void 0;
17847
+ }
17848
+ return {
17849
+ name: "llm-grader",
17850
+ type: "llm-grader",
17851
+ preprocessors: evalCase.preprocessors
17852
+ };
17853
+ }
17562
17854
  async function runEvaluatorList(options) {
17563
17855
  const {
17564
17856
  evalCase,
@@ -17608,7 +17900,7 @@ async function runEvaluatorList(options) {
17608
17900
  fileChanges,
17609
17901
  workspacePath
17610
17902
  };
17611
- const evalFileDir = evalCase.file_paths[0] ? path44.dirname(evalCase.file_paths[0]) : process.cwd();
17903
+ const evalFileDir = evalCase.file_paths[0] ? path45.dirname(evalCase.file_paths[0]) : process.cwd();
17612
17904
  const dispatchContext = {
17613
17905
  graderProvider,
17614
17906
  targetResolver,
@@ -17975,8 +18267,8 @@ function computeWeightedMean(entries) {
17975
18267
  }
17976
18268
 
17977
18269
  // src/evaluation/evaluate.ts
17978
- import { existsSync as existsSync5 } from "node:fs";
17979
- import path45 from "node:path";
18270
+ import { existsSync as existsSync6 } from "node:fs";
18271
+ import path46 from "node:path";
17980
18272
 
17981
18273
  // src/evaluation/providers/function-provider.ts
17982
18274
  function createFunctionProvider(taskFn) {
@@ -18013,7 +18305,7 @@ async function evaluate(config) {
18013
18305
  }
18014
18306
  const gitRoot = await findGitRoot(process.cwd());
18015
18307
  const repoRoot = gitRoot ?? process.cwd();
18016
- const testFilePath = config.specFile ? path45.resolve(config.specFile) : path45.join(process.cwd(), "__programmatic__.yaml");
18308
+ const testFilePath = config.specFile ? path46.resolve(config.specFile) : path46.join(process.cwd(), "__programmatic__.yaml");
18017
18309
  await loadEnvHierarchy(repoRoot, testFilePath);
18018
18310
  let resolvedTarget;
18019
18311
  let taskProvider;
@@ -18128,11 +18420,11 @@ function computeSummary(results, durationMs, threshold = DEFAULT_THRESHOLD) {
18128
18420
  var TARGET_FILE_CANDIDATES = [".agentv/targets.yaml", ".agentv/targets.yml"];
18129
18421
  async function discoverDefaultTarget(repoRoot) {
18130
18422
  const cwd = process.cwd();
18131
- const chain = buildDirectoryChain(path45.join(cwd, "_placeholder"), repoRoot);
18423
+ const chain = buildDirectoryChain(path46.join(cwd, "_placeholder"), repoRoot);
18132
18424
  for (const dir of chain) {
18133
18425
  for (const candidate of TARGET_FILE_CANDIDATES) {
18134
- const targetsPath = path45.join(dir, candidate);
18135
- if (!existsSync5(targetsPath)) continue;
18426
+ const targetsPath = path46.join(dir, candidate);
18427
+ if (!existsSync6(targetsPath)) continue;
18136
18428
  try {
18137
18429
  const definitions = await readTargetDefinitions(targetsPath);
18138
18430
  const defaultTarget = definitions.find((d) => d.name === "default");
@@ -18148,8 +18440,8 @@ async function loadEnvHierarchy(repoRoot, startPath) {
18148
18440
  const chain = buildDirectoryChain(startPath, repoRoot);
18149
18441
  const envFiles = [];
18150
18442
  for (const dir of chain) {
18151
- const envPath = path45.join(dir, ".env");
18152
- if (existsSync5(envPath)) envFiles.push(envPath);
18443
+ const envPath = path46.join(dir, ".env");
18444
+ if (existsSync6(envPath)) envFiles.push(envPath);
18153
18445
  }
18154
18446
  for (let i = 0; i < envFiles.length; i++) {
18155
18447
  try {
@@ -18225,12 +18517,12 @@ var CONFIG_FILE_NAMES = [
18225
18517
  ".agentv/config.js"
18226
18518
  ];
18227
18519
  async function loadTsConfig(projectRoot) {
18228
- const { existsSync: existsSync7 } = await import("node:fs");
18520
+ const { existsSync: existsSync8 } = await import("node:fs");
18229
18521
  const { pathToFileURL: pathToFileURL2 } = await import("node:url");
18230
18522
  const { join: join2 } = await import("node:path");
18231
18523
  for (const fileName of CONFIG_FILE_NAMES) {
18232
18524
  const filePath = join2(projectRoot, fileName);
18233
- if (!existsSync7(filePath)) {
18525
+ if (!existsSync8(filePath)) {
18234
18526
  continue;
18235
18527
  }
18236
18528
  try {
@@ -18327,8 +18619,8 @@ function buildPrompt(criteria, question, referenceAnswer) {
18327
18619
  }
18328
18620
 
18329
18621
  // src/evaluation/workspace/deps-scanner.ts
18330
- import { readFile as readFile13 } from "node:fs/promises";
18331
- import path46 from "node:path";
18622
+ import { readFile as readFile14 } from "node:fs/promises";
18623
+ import path47 from "node:path";
18332
18624
  import { parse as parse5 } from "yaml";
18333
18625
  function normalizeGitUrl(url) {
18334
18626
  let normalized = url.replace(/\.git$/, "");
@@ -18375,11 +18667,11 @@ async function scanRepoDeps(evalFilePaths) {
18375
18667
  return { repos: [...seen.values()], errors };
18376
18668
  }
18377
18669
  async function extractReposFromEvalFile(filePath) {
18378
- const content = await readFile13(filePath, "utf8");
18670
+ const content = await readFile14(filePath, "utf8");
18379
18671
  const parsed = interpolateEnv(parse5(content), process.env);
18380
18672
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return [];
18381
18673
  const obj = parsed;
18382
- const evalFileDir = path46.dirname(path46.resolve(filePath));
18674
+ const evalFileDir = path47.dirname(path47.resolve(filePath));
18383
18675
  const repos = [];
18384
18676
  const suiteRepos = await extractReposFromWorkspaceRaw(obj.workspace, evalFileDir);
18385
18677
  repos.push(...suiteRepos);
@@ -18395,8 +18687,8 @@ async function extractReposFromEvalFile(filePath) {
18395
18687
  }
18396
18688
  async function extractReposFromWorkspaceRaw(raw, evalFileDir) {
18397
18689
  if (typeof raw === "string") {
18398
- const workspaceFilePath = path46.resolve(evalFileDir, raw);
18399
- const content = await readFile13(workspaceFilePath, "utf8");
18690
+ const workspaceFilePath = path47.resolve(evalFileDir, raw);
18691
+ const content = await readFile14(workspaceFilePath, "utf8");
18400
18692
  const parsed = interpolateEnv(parse5(content), process.env);
18401
18693
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return [];
18402
18694
  return extractReposFromObject(parsed);
@@ -18424,8 +18716,8 @@ function extractReposFromObject(obj) {
18424
18716
  }
18425
18717
 
18426
18718
  // src/evaluation/cache/response-cache.ts
18427
- import { mkdir as mkdir15, readFile as readFile14, writeFile as writeFile8 } from "node:fs/promises";
18428
- import path47 from "node:path";
18719
+ import { mkdir as mkdir15, readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
18720
+ import path48 from "node:path";
18429
18721
  var DEFAULT_CACHE_PATH = ".agentv/cache";
18430
18722
  var ResponseCache = class {
18431
18723
  cachePath;
@@ -18435,7 +18727,7 @@ var ResponseCache = class {
18435
18727
  async get(key) {
18436
18728
  const filePath = this.keyToPath(key);
18437
18729
  try {
18438
- const data = await readFile14(filePath, "utf8");
18730
+ const data = await readFile15(filePath, "utf8");
18439
18731
  return JSON.parse(data);
18440
18732
  } catch {
18441
18733
  return void 0;
@@ -18443,13 +18735,13 @@ var ResponseCache = class {
18443
18735
  }
18444
18736
  async set(key, value) {
18445
18737
  const filePath = this.keyToPath(key);
18446
- const dir = path47.dirname(filePath);
18738
+ const dir = path48.dirname(filePath);
18447
18739
  await mkdir15(dir, { recursive: true });
18448
18740
  await writeFile8(filePath, JSON.stringify(value, null, 2), "utf8");
18449
18741
  }
18450
18742
  keyToPath(key) {
18451
18743
  const prefix = key.slice(0, 2);
18452
- return path47.join(this.cachePath, prefix, `${key}.json`);
18744
+ return path48.join(this.cachePath, prefix, `${key}.json`);
18453
18745
  }
18454
18746
  };
18455
18747
  function shouldEnableCache(params) {
@@ -18465,15 +18757,15 @@ function shouldSkipCacheForTemperature(targetConfig) {
18465
18757
  }
18466
18758
 
18467
18759
  // src/projects.ts
18468
- import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync as readdirSync3, statSync as statSync2, writeFileSync } from "node:fs";
18469
- import path48 from "node:path";
18760
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync as readdirSync3, statSync as statSync2, writeFileSync } from "node:fs";
18761
+ import path49 from "node:path";
18470
18762
  import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
18471
18763
  function getProjectsRegistryPath() {
18472
- return path48.join(getAgentvHome(), "projects.yaml");
18764
+ return path49.join(getAgentvHome(), "projects.yaml");
18473
18765
  }
18474
18766
  function loadProjectRegistry() {
18475
18767
  const registryPath = getProjectsRegistryPath();
18476
- if (!existsSync6(registryPath)) {
18768
+ if (!existsSync7(registryPath)) {
18477
18769
  return { projects: [] };
18478
18770
  }
18479
18771
  try {
@@ -18489,14 +18781,14 @@ function loadProjectRegistry() {
18489
18781
  }
18490
18782
  function saveProjectRegistry(registry) {
18491
18783
  const registryPath = getProjectsRegistryPath();
18492
- const dir = path48.dirname(registryPath);
18493
- if (!existsSync6(dir)) {
18784
+ const dir = path49.dirname(registryPath);
18785
+ if (!existsSync7(dir)) {
18494
18786
  mkdirSync2(dir, { recursive: true });
18495
18787
  }
18496
18788
  writeFileSync(registryPath, stringifyYaml(registry), "utf-8");
18497
18789
  }
18498
18790
  function deriveProjectId(dirPath, existingIds) {
18499
- const base = path48.basename(dirPath).toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
18791
+ const base = path49.basename(dirPath).toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
18500
18792
  let candidate = base || "project";
18501
18793
  let suffix = 2;
18502
18794
  while (existingIds.includes(candidate)) {
@@ -18506,11 +18798,11 @@ function deriveProjectId(dirPath, existingIds) {
18506
18798
  return candidate;
18507
18799
  }
18508
18800
  function addProject(projectPath) {
18509
- const absPath = path48.resolve(projectPath);
18510
- if (!existsSync6(absPath)) {
18801
+ const absPath = path49.resolve(projectPath);
18802
+ if (!existsSync7(absPath)) {
18511
18803
  throw new Error(`Directory not found: ${absPath}`);
18512
18804
  }
18513
- if (!existsSync6(path48.join(absPath, ".agentv"))) {
18805
+ if (!existsSync7(path49.join(absPath, ".agentv"))) {
18514
18806
  throw new Error(`No .agentv/ directory found in ${absPath}. Run an evaluation first.`);
18515
18807
  }
18516
18808
  const registry = loadProjectRegistry();
@@ -18524,7 +18816,7 @@ function addProject(projectPath) {
18524
18816
  absPath,
18525
18817
  registry.projects.map((p) => p.id)
18526
18818
  ),
18527
- name: path48.basename(absPath),
18819
+ name: path49.basename(absPath),
18528
18820
  path: absPath,
18529
18821
  addedAt: now,
18530
18822
  lastOpenedAt: now
@@ -18553,14 +18845,14 @@ function touchProject(projectId) {
18553
18845
  }
18554
18846
  }
18555
18847
  function discoverProjects(rootDir, maxDepth = 2) {
18556
- const absRoot = path48.resolve(rootDir);
18557
- if (!existsSync6(absRoot) || !statSync2(absRoot).isDirectory()) {
18848
+ const absRoot = path49.resolve(rootDir);
18849
+ if (!existsSync7(absRoot) || !statSync2(absRoot).isDirectory()) {
18558
18850
  return [];
18559
18851
  }
18560
18852
  const results = [];
18561
18853
  function scan(dir, depth) {
18562
18854
  if (depth > maxDepth) return;
18563
- if (existsSync6(path48.join(dir, ".agentv"))) {
18855
+ if (existsSync7(path49.join(dir, ".agentv"))) {
18564
18856
  results.push(dir);
18565
18857
  return;
18566
18858
  }
@@ -18570,7 +18862,7 @@ function discoverProjects(rootDir, maxDepth = 2) {
18570
18862
  for (const entry of entries) {
18571
18863
  if (!entry.isDirectory()) continue;
18572
18864
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
18573
- scan(path48.join(dir, entry.name), depth + 1);
18865
+ scan(path49.join(dir, entry.name), depth + 1);
18574
18866
  }
18575
18867
  } catch {
18576
18868
  }
@@ -19483,8 +19775,8 @@ function extractResponseItemContent(content) {
19483
19775
  // src/import/codex-session-discovery.ts
19484
19776
  import { readdir as readdir8, stat as stat9 } from "node:fs/promises";
19485
19777
  import { homedir as homedir3 } from "node:os";
19486
- import path49 from "node:path";
19487
- var DEFAULT_SESSIONS_DIR = () => path49.join(homedir3(), ".codex", "sessions");
19778
+ import path50 from "node:path";
19779
+ var DEFAULT_SESSIONS_DIR = () => path50.join(homedir3(), ".codex", "sessions");
19488
19780
  async function discoverCodexSessions(opts) {
19489
19781
  const sessionsDir = opts?.sessionsDir ?? DEFAULT_SESSIONS_DIR();
19490
19782
  const limit = opts?.latest ? 1 : opts?.limit ?? 10;
@@ -19496,7 +19788,7 @@ async function discoverCodexSessions(opts) {
19496
19788
  return [];
19497
19789
  }
19498
19790
  for (const year of yearDirs) {
19499
- const yearPath = path49.join(sessionsDir, year);
19791
+ const yearPath = path50.join(sessionsDir, year);
19500
19792
  let monthDirs;
19501
19793
  try {
19502
19794
  monthDirs = await readdir8(yearPath);
@@ -19504,7 +19796,7 @@ async function discoverCodexSessions(opts) {
19504
19796
  continue;
19505
19797
  }
19506
19798
  for (const month of monthDirs) {
19507
- const monthPath = path49.join(yearPath, month);
19799
+ const monthPath = path50.join(yearPath, month);
19508
19800
  let dayDirs;
19509
19801
  try {
19510
19802
  dayDirs = await readdir8(monthPath);
@@ -19516,7 +19808,7 @@ async function discoverCodexSessions(opts) {
19516
19808
  const dirDate = `${year}-${month}-${day}`;
19517
19809
  if (dirDate !== opts.date) continue;
19518
19810
  }
19519
- const dayPath = path49.join(monthPath, day);
19811
+ const dayPath = path50.join(monthPath, day);
19520
19812
  let files;
19521
19813
  try {
19522
19814
  files = await readdir8(dayPath);
@@ -19525,7 +19817,7 @@ async function discoverCodexSessions(opts) {
19525
19817
  }
19526
19818
  for (const file of files) {
19527
19819
  if (!file.startsWith("rollout-") || !file.endsWith(".jsonl")) continue;
19528
- const filePath = path49.join(dayPath, file);
19820
+ const filePath = path50.join(dayPath, file);
19529
19821
  const nameWithoutExt = file.replace(/\.jsonl$/, "");
19530
19822
  const parts = nameWithoutExt.split("-");
19531
19823
  const sessionId = parts.length >= 6 ? parts.slice(-5).join("-") : nameWithoutExt;
@@ -19548,8 +19840,8 @@ async function discoverCodexSessions(opts) {
19548
19840
  // src/import/session-discovery.ts
19549
19841
  import { readdir as readdir9, stat as stat10 } from "node:fs/promises";
19550
19842
  import { homedir as homedir4 } from "node:os";
19551
- import path50 from "node:path";
19552
- var DEFAULT_PROJECTS_DIR = () => path50.join(homedir4(), ".claude", "projects");
19843
+ import path51 from "node:path";
19844
+ var DEFAULT_PROJECTS_DIR = () => path51.join(homedir4(), ".claude", "projects");
19553
19845
  function encodeProjectPath(projectPath) {
19554
19846
  return projectPath.replace(/\//g, "-");
19555
19847
  }
@@ -19568,7 +19860,7 @@ async function discoverClaudeSessions(opts) {
19568
19860
  }
19569
19861
  const sessions = [];
19570
19862
  for (const projectDir of projectDirs) {
19571
- const dirPath = path50.join(projectsDir, projectDir);
19863
+ const dirPath = path51.join(projectsDir, projectDir);
19572
19864
  let entries;
19573
19865
  try {
19574
19866
  entries = await readdir9(dirPath);
@@ -19579,7 +19871,7 @@ async function discoverClaudeSessions(opts) {
19579
19871
  if (!entry.endsWith(".jsonl")) continue;
19580
19872
  const sessionId = entry.replace(/\.jsonl$/, "");
19581
19873
  if (opts?.sessionId && sessionId !== opts.sessionId) continue;
19582
- const filePath = path50.join(dirPath, entry);
19874
+ const filePath = path51.join(dirPath, entry);
19583
19875
  let updatedAt;
19584
19876
  try {
19585
19877
  const fileStat = await stat10(filePath);
@@ -19600,7 +19892,7 @@ async function discoverClaudeSessions(opts) {
19600
19892
  }
19601
19893
 
19602
19894
  // src/import/types.ts
19603
- import { readFile as readFile15 } from "node:fs/promises";
19895
+ import { readFile as readFile16 } from "node:fs/promises";
19604
19896
  function toTranscriptJsonLine(entry) {
19605
19897
  const firstUserMessage = entry.messages.find((m) => m.role === "user");
19606
19898
  const input = typeof firstUserMessage?.content === "string" ? firstUserMessage.content : "";
@@ -19626,11 +19918,11 @@ function toTranscriptJsonLine(entry) {
19626
19918
  };
19627
19919
  }
19628
19920
  async function readTranscriptJsonl(filePath) {
19629
- const text = await readFile15(filePath, "utf8");
19921
+ const text = await readFile16(filePath, "utf8");
19630
19922
  return text.split("\n").filter((line) => line.trim().length > 0).map((line) => JSON.parse(line));
19631
19923
  }
19632
19924
  async function readTranscriptFile(filePath) {
19633
- return readFile15(filePath, "utf8");
19925
+ return readFile16(filePath, "utf8");
19634
19926
  }
19635
19927
 
19636
19928
  // src/import/transcript-provider.ts