agentv 5.3.0-next.1 → 5.3.1-next.1

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.
Files changed (43) hide show
  1. package/README.md +22 -20
  2. package/dist/{artifact-writer-JFNIPMKW.js → artifact-writer-7NBCOAYC.js} +4 -4
  3. package/dist/{chunk-T32NL3E6.js → chunk-ASIGJIOJ.js} +50 -30
  4. package/dist/chunk-ASIGJIOJ.js.map +1 -0
  5. package/dist/{chunk-6ZZCDZPD.js → chunk-ELCJ23K4.js} +12766 -12478
  6. package/dist/chunk-ELCJ23K4.js.map +1 -0
  7. package/dist/{chunk-FVR4RQFK.js → chunk-LKGARI3W.js} +333 -24
  8. package/dist/chunk-LKGARI3W.js.map +1 -0
  9. package/dist/{chunk-V52ATPTT.js → chunk-LXBI3SPX.js} +142 -14
  10. package/dist/chunk-LXBI3SPX.js.map +1 -0
  11. package/dist/{chunk-BHKQHG26.js → chunk-RKE7SSET.js} +2 -2
  12. package/dist/cli.js +5 -5
  13. package/dist/dashboard/assets/{index-DNgf3qJ2.js → index-CbEMiJSb.js} +1 -1
  14. package/dist/dashboard/assets/{index-r_jSJmlw.js → index-DTA6-l7q.js} +3 -3
  15. package/dist/dashboard/index.html +1 -1
  16. package/dist/{dist-6Z7U473R.js → dist-NMXMI5SK.js} +17 -5
  17. package/dist/index.js +5 -5
  18. package/dist/{interactive-RUY3OCBI.js → interactive-BN527UV3.js} +5 -5
  19. package/dist/skills/agentv-bench/SKILL.md +14 -13
  20. package/dist/skills/agentv-bench/agents/analyzer.md +1 -1
  21. package/dist/skills/agentv-bench/agents/executor.md +1 -1
  22. package/dist/skills/agentv-bench/references/autoresearch.md +9 -9
  23. package/dist/skills/agentv-bench/references/environment-adaptation.md +4 -4
  24. package/dist/skills/agentv-bench/references/eval-yaml-spec.md +30 -47
  25. package/dist/skills/agentv-bench/references/schemas.md +44 -60
  26. package/dist/skills/agentv-bench/references/subagent-pipeline.md +20 -18
  27. package/dist/skills/agentv-eval-migrations/SKILL.md +13 -0
  28. package/dist/skills/agentv-eval-migrations/references/breaking-changes.md +39 -21
  29. package/dist/skills/agentv-eval-writer/SKILL.md +75 -46
  30. package/dist/skills/agentv-eval-writer/references/custom-evaluators.md +10 -5
  31. package/dist/skills/agentv-eval-writer/references/eval.schema.json +749 -2158
  32. package/dist/skills/agentv-eval-writer/references/rubric-evaluator.md +1 -1
  33. package/dist/{ts-eval-loader-DQDYRULE-V3377FOL.js → ts-eval-loader-2RFVZHCT-7CZ3DCDD.js} +8 -4
  34. package/package.json +1 -1
  35. package/dist/chunk-6ZZCDZPD.js.map +0 -1
  36. package/dist/chunk-FVR4RQFK.js.map +0 -1
  37. package/dist/chunk-T32NL3E6.js.map +0 -1
  38. package/dist/chunk-V52ATPTT.js.map +0 -1
  39. /package/dist/{artifact-writer-JFNIPMKW.js.map → artifact-writer-7NBCOAYC.js.map} +0 -0
  40. /package/dist/{chunk-BHKQHG26.js.map → chunk-RKE7SSET.js.map} +0 -0
  41. /package/dist/{dist-6Z7U473R.js.map → dist-NMXMI5SK.js.map} +0 -0
  42. /package/dist/{interactive-RUY3OCBI.js.map → interactive-BN527UV3.js.map} +0 -0
  43. /package/dist/{ts-eval-loader-DQDYRULE-V3377FOL.js.map → ts-eval-loader-2RFVZHCT-7CZ3DCDD.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
2
  import {
3
3
  writeArtifactsFromResults
4
- } from "./chunk-BHKQHG26.js";
4
+ } from "./chunk-RKE7SSET.js";
5
5
  import {
6
6
  RunBudgetTracker,
7
7
  buildWipBranchName,
@@ -18,7 +18,7 @@ import {
18
18
  resolveResultsRepoRunsDir,
19
19
  setupWipWorktree,
20
20
  syncResultsRepoForProject
21
- } from "./chunk-V52ATPTT.js";
21
+ } from "./chunk-LXBI3SPX.js";
22
22
  import {
23
23
  AGENTV_LOCAL_CONFIG_FILE_NAME,
24
24
  AGENTV_LOCAL_CONFIG_YML_FILE_NAME,
@@ -51,6 +51,7 @@ import {
51
51
  interpolateEnv,
52
52
  isAgentVConfigFileName,
53
53
  isGraderKind,
54
+ isTypeScriptEvalConfigFileName,
54
55
  listTargetNames,
55
56
  loadCasesFromDirectory,
56
57
  loadCasesFromFile,
@@ -83,8 +84,9 @@ import {
83
84
  toSnakeCaseDeep,
84
85
  traceEnvelopeToTraceSummary,
85
86
  traceEnvelopeToTranscriptMessages,
87
+ typeScriptEvalConfigGlob,
86
88
  writeInitialRunSummaryArtifact
87
- } from "./chunk-6ZZCDZPD.js";
89
+ } from "./chunk-ELCJ23K4.js";
88
90
 
89
91
  // src/commands/eval/shared.ts
90
92
  import { constants } from "node:fs";
@@ -215,7 +217,7 @@ function agentSkillsToAgentVYamlObject(suite) {
215
217
 
216
218
  // src/commands/eval/shared.ts
217
219
  function isNativeEvalFile(filePath) {
218
- return /\.(ya?ml|jsonl|[cm]?ts)$/i.test(filePath);
220
+ return /\.(ya?ml|jsonl)$/i.test(filePath) || isTypeScriptEvalConfigFileName(filePath);
219
221
  }
220
222
  function shouldInspectJsonPath(filePath) {
221
223
  const base = path.basename(filePath).toLowerCase();
@@ -265,7 +267,7 @@ async function resolveEvalPaths(evalPaths, cwd, options = {}) {
265
267
  continue;
266
268
  }
267
269
  if (candidateStats.isDirectory()) {
268
- const filePattern = options.allowReadAdapters ? "{suite.yaml,suite.yml,*.eval.yaml,*.eval.yml,eval.yaml,eval.yml,*.eval.ts,*.eval.mts,evals.json,*.evals.json}" : "{suite.yaml,suite.yml,*.eval.yaml,*.eval.yml,eval.yaml,eval.yml,*.eval.ts,*.eval.mts}";
270
+ const filePattern = options.allowReadAdapters ? `{suite.yaml,suite.yml,*.eval.yaml,*.eval.yml,eval.yaml,eval.yml,${typeScriptEvalConfigGlob()},evals.json,*.evals.json}` : `{suite.yaml,suite.yml,*.eval.yaml,*.eval.yml,eval.yaml,eval.yml,${typeScriptEvalConfigGlob()}}`;
269
271
  const dirGlob = path.posix.join(candidatePath.replace(/\\/g, "/"), `**/${filePattern}`);
270
272
  const dirMatches = await fg(dirGlob, {
271
273
  absolute: true,
@@ -347,7 +349,7 @@ async function findRepoRoot(start) {
347
349
  // package.json
348
350
  var package_default = {
349
351
  name: "agentv",
350
- version: "5.3.0-next.1",
352
+ version: "5.3.1-next.1",
351
353
  description: "CLI entry point for AgentV",
352
354
  type: "module",
353
355
  repository: {
@@ -3032,6 +3034,14 @@ var REMOVED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Map([
3032
3034
  "providers",
3033
3035
  "Top-level 'providers' is not a runtime alias in AgentV eval YAML. Use 'targets' for systems under test; provider names backend kind inside each target."
3034
3036
  ],
3037
+ [
3038
+ "eval_cases",
3039
+ "Top-level 'eval_cases' has been removed from authored eval YAML. Use 'tests' instead."
3040
+ ],
3041
+ [
3042
+ "evalcases",
3043
+ "Top-level 'evalcases' has been removed from authored eval YAML. Use 'tests' instead."
3044
+ ],
3035
3045
  ["repeat", "Top-level 'repeat' has been removed. Use evaluate_options.repeat instead."],
3036
3046
  ["runs", "Top-level 'runs' has been removed. Use evaluate_options.repeat.count instead."],
3037
3047
  [
@@ -3046,11 +3056,11 @@ var REMOVED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Map([
3046
3056
  [
3047
3057
  "preprocessors",
3048
3058
  "Top-level 'preprocessors' has been removed from authored eval YAML. Use default_test.options.transform or assertion-level transform instead."
3049
- ]
3059
+ ],
3060
+ ["providerPromptMap", "Top-level 'providerPromptMap' is not supported. Use 'targets'."],
3061
+ ["provider_prompt_map", "Top-level 'provider_prompt_map' is not supported. Use 'targets'."]
3050
3062
  ]);
3051
3063
  var DEPRECATED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Map([
3052
- ["eval_cases", "'eval_cases' is deprecated. Use 'tests' instead."],
3053
- ["evalcases", "'evalcases' is deprecated. Use 'tests' instead."],
3054
3064
  ["evaluator", "'evaluator' is deprecated. Use 'assert' instead."]
3055
3065
  ]);
3056
3066
  var KNOWN_TEST_FIELDS = /* @__PURE__ */ new Set([
@@ -3083,6 +3093,7 @@ var KNOWN_TEST_FIELDS = /* @__PURE__ */ new Set([
3083
3093
  "on_turn_failure",
3084
3094
  "window_size"
3085
3095
  ]);
3096
+ var KNOWN_SCENARIO_FIELDS = /* @__PURE__ */ new Set(["description", "config", "tests"]);
3086
3097
  var SUPPORTED_WORKSPACE_REPO_FIELDS = /* @__PURE__ */ new Set(["path", "repo", "commit", "ancestor", "sparse"]);
3087
3098
  var KNOWN_REMOVED_WORKSPACE_FIELDS = /* @__PURE__ */ new Set([
3088
3099
  "template",
@@ -3100,6 +3111,22 @@ REMOVED_TEST_FIELDS.set(
3100
3111
  "input",
3101
3112
  "tests[].input has been removed from authored eval YAML. Put prompt text or chat/system/user messages in top-level 'prompts' and put row-specific data in tests[].vars."
3102
3113
  );
3114
+ REMOVED_TEST_FIELDS.set(
3115
+ "preprocessors",
3116
+ "tests[].preprocessors has been removed from authored eval YAML. Use tests[].options.transform or assertion-level transform instead."
3117
+ );
3118
+ REMOVED_TEST_FIELDS.set(
3119
+ "postprocess",
3120
+ "tests[].postprocess has been removed from authored eval YAML. Use tests[].options.transform instead."
3121
+ );
3122
+ REMOVED_TEST_FIELDS.set(
3123
+ "eval_cases",
3124
+ "tests[].eval_cases has been removed from authored eval YAML. Use 'tests' rows directly."
3125
+ );
3126
+ REMOVED_TEST_FIELDS.set(
3127
+ "evalcases",
3128
+ "tests[].evalcases has been removed from authored eval YAML. Use 'tests' rows directly."
3129
+ );
3103
3130
  var DEPRECATED_TEST_FIELDS = /* @__PURE__ */ new Map([
3104
3131
  ["evaluator", "'evaluator' is deprecated. Use 'assert' instead."],
3105
3132
  ["expected_outcome", "'expected_outcome' is deprecated. Use 'assert' instead."]
@@ -3233,6 +3260,7 @@ async function validateEvalFile(filePath) {
3233
3260
  validateEvaluateOptions(parsed.evaluate_options, "evaluate_options", absolutePath, errors);
3234
3261
  validateAssertArray(parsed.assert, "assert", absolutePath, errors, customAssertionTypes);
3235
3262
  validateDefaultTest(parsed.default_test, absolutePath, errors, customAssertionTypes);
3263
+ await validateScenarios(parsed.scenarios, parsed, absolutePath, errors, customAssertionTypes);
3236
3264
  const cases = parsed.tests;
3237
3265
  const hasImports = collectImportEntries(parsed).length > 0;
3238
3266
  const hasScenarios = Array.isArray(parsed.scenarios);
@@ -3405,6 +3433,32 @@ async function validateEvalFile(filePath) {
3405
3433
  errors
3406
3434
  };
3407
3435
  }
3436
+ async function validateTypeScriptEvalConfigFile(filePath) {
3437
+ const absolutePath = path22.resolve(filePath);
3438
+ try {
3439
+ const { loadTsEvalSuite } = await import("./ts-eval-loader-2RFVZHCT-7CZ3DCDD.js");
3440
+ await loadTsEvalSuite(absolutePath, process.cwd());
3441
+ return {
3442
+ valid: true,
3443
+ filePath: absolutePath,
3444
+ fileType: "eval",
3445
+ errors: []
3446
+ };
3447
+ } catch (error) {
3448
+ return {
3449
+ valid: false,
3450
+ filePath: absolutePath,
3451
+ fileType: "eval",
3452
+ errors: [
3453
+ {
3454
+ severity: "error",
3455
+ filePath: absolutePath,
3456
+ message: error.message
3457
+ }
3458
+ ]
3459
+ };
3460
+ }
3461
+ }
3408
3462
  async function validateSuiteWorkspaceConfigs(parsed, absolutePath, errors) {
3409
3463
  await validateWorkspaceConfig(parsed.workspace, absolutePath, errors, "workspace");
3410
3464
  if (isObject(parsed.execution)) {
@@ -3891,6 +3945,182 @@ function validateDefaultTest(defaultTest, filePath, errors, customAssertionTypes
3891
3945
  });
3892
3946
  }
3893
3947
  }
3948
+ async function validateScenarios(scenarios, parsed, filePath, errors, customAssertionTypes) {
3949
+ if (scenarios === void 0) {
3950
+ return;
3951
+ }
3952
+ if (!Array.isArray(scenarios)) {
3953
+ errors.push({
3954
+ severity: "error",
3955
+ filePath,
3956
+ location: "scenarios",
3957
+ message: "Invalid 'scenarios' field (must be an array)"
3958
+ });
3959
+ return;
3960
+ }
3961
+ for (let scenarioIndex = 0; scenarioIndex < scenarios.length; scenarioIndex++) {
3962
+ const scenario = scenarios[scenarioIndex];
3963
+ const scenarioLocation = `scenarios[${scenarioIndex}]`;
3964
+ if (!isObject(scenario)) {
3965
+ errors.push({
3966
+ severity: "error",
3967
+ filePath,
3968
+ location: scenarioLocation,
3969
+ message: "Scenario must be an object"
3970
+ });
3971
+ continue;
3972
+ }
3973
+ for (const key of Object.keys(scenario)) {
3974
+ if (!KNOWN_SCENARIO_FIELDS.has(key)) {
3975
+ errors.push({
3976
+ severity: "error",
3977
+ filePath,
3978
+ location: `${scenarioLocation}.${key}`,
3979
+ message: `Unknown scenario field '${key}'.`
3980
+ });
3981
+ }
3982
+ }
3983
+ if (!Array.isArray(scenario.config)) {
3984
+ errors.push({
3985
+ severity: "error",
3986
+ filePath,
3987
+ location: `${scenarioLocation}.config`,
3988
+ message: "Invalid 'config' field (must be an array)"
3989
+ });
3990
+ } else {
3991
+ for (let configIndex = 0; configIndex < scenario.config.length; configIndex++) {
3992
+ await validateScenarioTestLikeRow(
3993
+ scenario.config[configIndex],
3994
+ `${scenarioLocation}.config[${configIndex}]`,
3995
+ filePath,
3996
+ errors,
3997
+ customAssertionTypes,
3998
+ { requireInput: false }
3999
+ );
4000
+ }
4001
+ }
4002
+ const scenarioConfigs = Array.isArray(scenario.config) ? scenario.config : [];
4003
+ if (!Array.isArray(scenario.tests)) {
4004
+ errors.push({
4005
+ severity: "error",
4006
+ filePath,
4007
+ location: `${scenarioLocation}.tests`,
4008
+ message: "Invalid 'tests' field (must be an array)"
4009
+ });
4010
+ continue;
4011
+ }
4012
+ for (let testIndex = 0; testIndex < scenario.tests.length; testIndex++) {
4013
+ const test = scenario.tests[testIndex];
4014
+ const everyConfigProvidesInput = scenarioConfigs.length > 0 && scenarioConfigs.every(
4015
+ (config) => isObject(config) && (config.prompts !== void 0 || config.provider_output !== void 0)
4016
+ );
4017
+ const requireInput = isObject(test) && parsed.prompts === void 0 && test.prompts === void 0 && test.provider_output === void 0 && !everyConfigProvidesInput;
4018
+ await validateScenarioTestLikeRow(
4019
+ test,
4020
+ `${scenarioLocation}.tests[${testIndex}]`,
4021
+ filePath,
4022
+ errors,
4023
+ customAssertionTypes,
4024
+ { requireInput }
4025
+ );
4026
+ }
4027
+ }
4028
+ }
4029
+ async function validateScenarioTestLikeRow(row, location, filePath, errors, customAssertionTypes, options) {
4030
+ if (!isObject(row)) {
4031
+ errors.push({
4032
+ severity: "error",
4033
+ filePath,
4034
+ location,
4035
+ message: "Scenario row must be an object"
4036
+ });
4037
+ return;
4038
+ }
4039
+ for (const key of Object.keys(row)) {
4040
+ const removedMessage = REMOVED_TEST_FIELDS.get(key);
4041
+ if (removedMessage) {
4042
+ errors.push({
4043
+ severity: "error",
4044
+ filePath,
4045
+ location: `${location}.${key}`,
4046
+ message: removedMessage.replaceAll("tests[]", location)
4047
+ });
4048
+ continue;
4049
+ }
4050
+ const deprecationMessage = DEPRECATED_TEST_FIELDS.get(key);
4051
+ if (deprecationMessage) {
4052
+ errors.push({
4053
+ severity: "warning",
4054
+ filePath,
4055
+ location: `${location}.${key}`,
4056
+ message: deprecationMessage
4057
+ });
4058
+ } else if (!KNOWN_TEST_FIELDS.has(key)) {
4059
+ errors.push({
4060
+ severity: "error",
4061
+ filePath,
4062
+ location: `${location}.${key}`,
4063
+ message: `Unknown test field '${key}'.`
4064
+ });
4065
+ }
4066
+ }
4067
+ const id = row.id;
4068
+ if (id !== void 0 && (typeof id !== "string" || id.trim().length === 0)) {
4069
+ errors.push({
4070
+ severity: "error",
4071
+ filePath,
4072
+ location: `${location}.id`,
4073
+ message: "Invalid 'id' field (must be a non-empty string when provided)"
4074
+ });
4075
+ }
4076
+ const criteria = row.criteria;
4077
+ if (criteria !== void 0 && (typeof criteria !== "string" || criteria.trim().length === 0)) {
4078
+ errors.push({
4079
+ severity: "error",
4080
+ filePath,
4081
+ location: `${location}.criteria`,
4082
+ message: "Invalid 'criteria' field (must be a non-empty string if provided)"
4083
+ });
4084
+ } else if (criteria !== void 0 && row.assert !== void 0) {
4085
+ errors.push({
4086
+ severity: "error",
4087
+ filePath,
4088
+ location: `${location}.criteria`,
4089
+ message: "Do not combine test-level 'criteria' with 'assert'. Put human-readable case descriptions in tests[].description, or express grading text as an explicit assertion such as { type: 'llm-rubric', value: ... }."
4090
+ });
4091
+ }
4092
+ validateInputField(row.input, `${location}.input`, filePath, errors, {
4093
+ required: options.requireInput
4094
+ });
4095
+ if (row.expected_output !== void 0) {
4096
+ errors.push({
4097
+ severity: "error",
4098
+ filePath,
4099
+ location: `${location}.expected_output`,
4100
+ message: "tests[].expected_output has been removed from authored eval YAML. Put the reference answer in tests[].vars.expected_output and consume it with an explicit assertion, for example { type: 'llm-rubric', value: 'Matches the reference answer: {{ expected_output }}' }."
4101
+ });
4102
+ }
4103
+ validateAssertArray(row.assert, `${location}.assert`, filePath, errors, customAssertionTypes);
4104
+ validateRunOverride(row.run, `${location}.run`, filePath, errors);
4105
+ validateTestOptions(row.options, `${location}.options`, filePath, errors);
4106
+ await validateEnvironmentConfig(row.environment, filePath, errors, `${location}.environment`);
4107
+ validateConversationMode(row, location, filePath, errors);
4108
+ await validateWorkspaceConfig(row.workspace, filePath, errors, `${location}.workspace`);
4109
+ const caseExecution = isObject(row.execution) ? row.execution : void 0;
4110
+ if (caseExecution) {
4111
+ validateTestExecutionFields(caseExecution, filePath, errors, location);
4112
+ rejectRuntimeWorkspaceConfig(
4113
+ caseExecution.workspace,
4114
+ filePath,
4115
+ errors,
4116
+ `${location}.execution.workspace`
4117
+ );
4118
+ }
4119
+ const targets = row.providers !== void 0 ? row.providers : row.provider;
4120
+ if (targets !== void 0) {
4121
+ validateTargetTestbedFields(targets, `${location}.providers`, filePath, errors);
4122
+ }
4123
+ }
3894
4124
  function validateEvaluateOptions(evaluateOptions, location, filePath, errors) {
3895
4125
  if (evaluateOptions === void 0) {
3896
4126
  return;
@@ -5212,6 +5442,7 @@ function validateUnknownSettings(target, provider, absolutePath, location, error
5212
5442
  "env",
5213
5443
  "grader_target",
5214
5444
  "judge_target",
5445
+ "use_target",
5215
5446
  "workers",
5216
5447
  "$schema",
5217
5448
  "targets"
@@ -5494,15 +5725,22 @@ async function validateTargetsFile(filePath) {
5494
5725
  const provider = effectiveTarget.provider;
5495
5726
  const rawTarget = rawTargets[i];
5496
5727
  const rawUseTarget = isObject3(rawTarget) ? rawTarget.use_target : void 0;
5497
- const hasUseTarget = isNonEmptyString(effectiveTarget.use_target) || isNonEmptyString(rawUseTarget);
5728
+ if (effectiveTarget.use_target !== void 0 || rawUseTarget !== void 0) {
5729
+ errors.push({
5730
+ severity: "error",
5731
+ filePath: absolutePath,
5732
+ location: `${location}.use_target`,
5733
+ message: "The 'use_target' field has been removed from authored targets.yaml target definitions. Define a concrete target with 'provider' instead."
5734
+ });
5735
+ }
5498
5736
  const providerValue = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
5499
5737
  const isTemplated = isEnvTemplated(provider);
5500
- if (!hasUseTarget && (typeof provider !== "string" || provider.trim().length === 0)) {
5738
+ if (typeof provider !== "string" || provider.trim().length === 0) {
5501
5739
  errors.push({
5502
5740
  severity: "error",
5503
5741
  filePath: absolutePath,
5504
5742
  location: `${location}.provider`,
5505
- message: "Missing or invalid 'provider' field (must be a non-empty string, or use use_target for delegation)"
5743
+ message: "Missing or invalid 'provider' field (must be a non-empty string)"
5506
5744
  });
5507
5745
  } else if (!isTemplated && (providerValue === "claude" || providerValue === "copilot")) {
5508
5746
  errors.push({
@@ -5637,6 +5875,9 @@ async function validateConfigFile(filePath, options = {}) {
5637
5875
  validateRefsConfig(errors, filePath, config.refs);
5638
5876
  validateComposableGraph(errors, filePath, config);
5639
5877
  validateDashboardConfig(errors, filePath, config.dashboard);
5878
+ validateHooksConfig(errors, filePath, config.hooks);
5879
+ validateEnvPathConfig(errors, filePath, config.env_path);
5880
+ validateEnvFromConfig(errors, filePath, config.env_from);
5640
5881
  const projects = config.projects;
5641
5882
  if (projects !== void 0) {
5642
5883
  if (scope === "project") {
@@ -5671,7 +5912,10 @@ async function validateConfigFile(filePath, options = {}) {
5671
5912
  "defaults",
5672
5913
  "projects",
5673
5914
  "dashboard",
5674
- "studio"
5915
+ "studio",
5916
+ "hooks",
5917
+ "env_path",
5918
+ "env_from"
5675
5919
  ]);
5676
5920
  const unexpectedFields = Object.keys(config).filter((key) => !allowedFields.has(key));
5677
5921
  if (unexpectedFields.length > 0) {
@@ -5720,6 +5964,76 @@ function validateDashboardConfig(errors, filePath, rawDashboard) {
5720
5964
  );
5721
5965
  }
5722
5966
  }
5967
+ var ENV_FROM_FORMATS = /* @__PURE__ */ new Set(["shell_exports", "json"]);
5968
+ function validateHooksConfig(errors, filePath, rawHooks) {
5969
+ if (rawHooks === void 0 || rawHooks === null) {
5970
+ return;
5971
+ }
5972
+ if (!isPlainObject(rawHooks)) {
5973
+ addError(errors, filePath, "hooks", "Field 'hooks' must be an object");
5974
+ return;
5975
+ }
5976
+ if (rawHooks.before_session !== void 0) {
5977
+ validateOptionalString(errors, filePath, rawHooks.before_session, "hooks.before_session");
5978
+ errors.push({
5979
+ severity: "warning",
5980
+ filePath,
5981
+ location: "hooks.before_session",
5982
+ message: "'hooks.before_session' is deprecated; use 'env_path' and/or 'env_from' to load environment variables before validation and eval."
5983
+ });
5984
+ }
5985
+ }
5986
+ function validateEnvPathConfig(errors, filePath, rawEnvPath) {
5987
+ if (rawEnvPath === void 0 || rawEnvPath === null) {
5988
+ return;
5989
+ }
5990
+ const isList = Array.isArray(rawEnvPath);
5991
+ const entries = isList ? rawEnvPath : [rawEnvPath];
5992
+ entries.forEach((entry, index) => {
5993
+ const location = isList ? `env_path[${index}]` : "env_path";
5994
+ if (typeof entry !== "string" || entry.trim().length === 0) {
5995
+ addError(errors, filePath, location, `Field '${location}' must be a non-empty string`);
5996
+ }
5997
+ });
5998
+ }
5999
+ function validateEnvFromConfig(errors, filePath, rawEnvFrom) {
6000
+ if (rawEnvFrom === void 0 || rawEnvFrom === null) {
6001
+ return;
6002
+ }
6003
+ const isList = Array.isArray(rawEnvFrom);
6004
+ const entries = isList ? rawEnvFrom : [rawEnvFrom];
6005
+ entries.forEach((entry, index) => {
6006
+ const location = isList ? `env_from[${index}]` : "env_from";
6007
+ if (!isPlainObject(entry)) {
6008
+ addError(errors, filePath, location, `Field '${location}' must be an object`);
6009
+ return;
6010
+ }
6011
+ const command = entry.command;
6012
+ if (typeof command === "string") {
6013
+ addError(
6014
+ errors,
6015
+ filePath,
6016
+ `${location}.command`,
6017
+ `Field '${location}.command' must be an argv array of strings, not a shell command string. Use e.g. ["bun", "scripts/load-secrets.ts"].`
6018
+ );
6019
+ } else if (!Array.isArray(command) || command.length === 0 || !command.every((part) => typeof part === "string" && part.length > 0)) {
6020
+ addError(
6021
+ errors,
6022
+ filePath,
6023
+ `${location}.command`,
6024
+ `Field '${location}.command' must be a non-empty array of strings`
6025
+ );
6026
+ }
6027
+ if (entry.format !== void 0 && !ENV_FROM_FORMATS.has(entry.format)) {
6028
+ addError(
6029
+ errors,
6030
+ filePath,
6031
+ `${location}.format`,
6032
+ `Field '${location}.format' must be "shell_exports" or "json"`
6033
+ );
6034
+ }
6035
+ });
6036
+ }
5723
6037
  function validateRefsConfig(errors, filePath, rawRefs) {
5724
6038
  if (rawRefs === void 0) {
5725
6039
  return;
@@ -5932,13 +6246,7 @@ async function validateFileReferences(evalFilePath) {
5932
6246
  if (!isObject4(parsed)) {
5933
6247
  return errors;
5934
6248
  }
5935
- let cases = parsed.tests;
5936
- if (cases === void 0 && "eval_cases" in parsed) {
5937
- cases = parsed.eval_cases;
5938
- }
5939
- if (cases === void 0 && "evalcases" in parsed) {
5940
- cases = parsed.evalcases;
5941
- }
6249
+ const cases = parsed.tests;
5942
6250
  if (!Array.isArray(cases)) {
5943
6251
  return errors;
5944
6252
  }
@@ -7585,7 +7893,7 @@ async function runEvalCommand(input) {
7585
7893
  const resolvedExperiment = resolveExperimentForRun(options.experiment);
7586
7894
  const evalPathInputs = input.testFiles.length > 0 ? [...input.testFiles] : [];
7587
7895
  if (evalPathInputs.length === 0 && process.stdin.isTTY) {
7588
- const { launchInteractiveWizard } = await import("./interactive-RUY3OCBI.js");
7896
+ const { launchInteractiveWizard } = await import("./interactive-BN527UV3.js");
7589
7897
  await launchInteractiveWizard();
7590
7898
  return void 0;
7591
7899
  }
@@ -7925,7 +8233,7 @@ async function runEvalCommand(input) {
7925
8233
  });
7926
8234
  let transcriptProviderFactory;
7927
8235
  if (options.transcript) {
7928
- const { TranscriptProvider } = await import("./dist-6Z7U473R.js");
8236
+ const { TranscriptProvider } = await import("./dist-NMXMI5SK.js");
7929
8237
  const transcriptProvider = await TranscriptProvider.fromFile(options.transcript);
7930
8238
  const totalTests = [...fileMetadata.values()].reduce(
7931
8239
  (sum, meta) => sum + meta.testCases.length,
@@ -8191,7 +8499,7 @@ ${formatRequiredVersionFailureNote(requiredVersionCheck)}`);
8191
8499
  const sourceTests = activeSourceTests;
8192
8500
  const taskBundleTargets = buildTaskBundleTargetSelections(activeTestFiles, fileMetadata);
8193
8501
  if (isResumeAppend) {
8194
- const { writePerTestArtifacts } = await import("./artifact-writer-JFNIPMKW.js");
8502
+ const { writePerTestArtifacts } = await import("./artifact-writer-7NBCOAYC.js");
8195
8503
  await writePerTestArtifacts(allResults, runDir, {
8196
8504
  experiment: normalizeExperimentName(options.experiment),
8197
8505
  runId: path12.basename(runDir),
@@ -8371,6 +8679,7 @@ export {
8371
8679
  loadEnvFromHierarchy,
8372
8680
  detectFileType,
8373
8681
  validateEvalFile,
8682
+ validateTypeScriptEvalConfigFile,
8374
8683
  validateCasesFile,
8375
8684
  validateTargetsFile,
8376
8685
  validateConfigFile,
@@ -8409,4 +8718,4 @@ export {
8409
8718
  filterByCategory,
8410
8719
  runEvalCommand
8411
8720
  };
8412
- //# sourceMappingURL=chunk-FVR4RQFK.js.map
8721
+ //# sourceMappingURL=chunk-LKGARI3W.js.map