"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/evaluation/validation/index.ts
var validation_exports = {};
__export(validation_exports, {
  detectFileType: () => detectFileType,
  getExpectedSchema: () => getExpectedSchema,
  isValidSchema: () => isValidSchema,
  validateConfigFile: () => validateConfigFile,
  validateEvalFile: () => validateEvalFile,
  validateFileReferences: () => validateFileReferences,
  validateTargetsFile: () => validateTargetsFile
});
module.exports = __toCommonJS(validation_exports);

// src/evaluation/validation/file-type.ts
var import_promises = require("fs/promises");
var import_node_path = __toESM(require("path"), 1);
var import_yaml = require("yaml");
var SCHEMA_EVAL_V2 = "agentv-eval-v2";
var SCHEMA_TARGETS_V2 = "agentv-targets-v2.2";
var SCHEMA_CONFIG_V2 = "agentv-config-v2";
async function detectFileType(filePath) {
  try {
    const content = await (0, import_promises.readFile)(filePath, "utf8");
    const parsed = (0, import_yaml.parse)(content);
    if (typeof parsed !== "object" || parsed === null) {
      return inferFileTypeFromPath(filePath);
    }
    const record = parsed;
    const schema = record.$schema;
    if (typeof schema !== "string") {
      return inferFileTypeFromPath(filePath);
    }
    switch (schema) {
      case SCHEMA_EVAL_V2:
        return "eval";
      case SCHEMA_TARGETS_V2:
        return "targets";
      case SCHEMA_CONFIG_V2:
        return "config";
      default:
        return inferFileTypeFromPath(filePath);
    }
  } catch {
    return inferFileTypeFromPath(filePath);
  }
}
function inferFileTypeFromPath(filePath) {
  const normalized = import_node_path.default.normalize(filePath).replace(/\\/g, "/");
  const basename = import_node_path.default.basename(filePath);
  if (normalized.includes("/.agentv/")) {
    if (basename === "config.yaml" || basename === "config.yml") {
      return "config";
    }
    if (basename === "targets.yaml" || basename === "targets.yml") {
      return "targets";
    }
  }
  return "eval";
}
function isValidSchema(schema) {
  return schema === SCHEMA_EVAL_V2 || schema === SCHEMA_TARGETS_V2 || schema === SCHEMA_CONFIG_V2;
}
function getExpectedSchema(fileType) {
  switch (fileType) {
    case "eval":
      return SCHEMA_EVAL_V2;
    case "targets":
      return SCHEMA_TARGETS_V2;
    case "config":
      return SCHEMA_CONFIG_V2;
    default:
      return void 0;
  }
}

// src/evaluation/validation/eval-validator.ts
var import_promises3 = require("fs/promises");
var import_node_path3 = __toESM(require("path"), 1);
var import_yaml3 = require("yaml");

// src/evaluation/interpolation.ts
var ENV_VAR_PATTERN = /\$\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g;
function interpolateEnv(value, env) {
  if (typeof value === "string") {
    return value.replace(ENV_VAR_PATTERN, (_, varName) => env[varName] ?? "");
  }
  if (Array.isArray(value)) {
    return value.map((item) => interpolateEnv(item, env));
  }
  if (value !== null && typeof value === "object") {
    const result = {};
    for (const [key, val] of Object.entries(value)) {
      result[key] = interpolateEnv(val, env);
    }
    return result;
  }
  return value;
}

// src/evaluation/loaders/case-file-loader.ts
var import_promises2 = require("fs/promises");
var import_node_path2 = __toESM(require("path"), 1);
var import_fast_glob = __toESM(require("fast-glob"), 1);
var import_yaml2 = require("yaml");

// src/evaluation/types.ts
var TEST_MESSAGE_ROLE_VALUES = ["system", "user", "assistant", "tool"];
var TEST_MESSAGE_ROLE_SET = new Set(TEST_MESSAGE_ROLE_VALUES);
function isJsonObject(value) {
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
    return false;
  }
  return Object.values(value).every(isJsonValue);
}
function isJsonValue(value) {
  if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
    return true;
  }
  if (Array.isArray(value)) {
    return value.every(isJsonValue);
  }
  if (typeof value === "object") {
    return isJsonObject(value);
  }
  return false;
}
var EVALUATOR_KIND_VALUES = [
  "code-grader",
  "llm-grader",
  "rubric",
  "composite",
  "tool-trajectory",
  "field-accuracy",
  "latency",
  "cost",
  "token-usage",
  "execution-metrics",
  "skill-trigger",
  "contains",
  "contains-any",
  "contains-all",
  "icontains",
  "icontains-any",
  "icontains-all",
  "starts-with",
  "ends-with",
  "regex",
  "is-json",
  "equals",
  "rubrics",
  "inline-assert"
];
var EVALUATOR_KIND_SET = new Set(EVALUATOR_KIND_VALUES);
function isEvaluatorKind(value) {
  return typeof value === "string" && EVALUATOR_KIND_SET.has(value);
}

// src/evaluation/loaders/case-file-loader.ts
var ANSI_YELLOW = "\x1B[33m";
var ANSI_RESET = "\x1B[0m";
function parseYamlCases(content, filePath) {
  const raw = (0, import_yaml2.parse)(content);
  const parsed = interpolateEnv(raw, process.env);
  if (!Array.isArray(parsed)) {
    throw new Error(
      `External test file must contain a YAML array, got ${typeof parsed}: ${filePath}`
    );
  }
  const results = [];
  for (const item of parsed) {
    if (!isJsonObject(item)) {
      throw new Error(`External test file contains non-object entry: ${filePath}`);
    }
    results.push(item);
  }
  return results;
}
function parseJsonlCases(content, filePath) {
  const lines = content.split("\n");
  const results = [];
  for (let i = 0; i < lines.length; i++) {
    const line = lines[i].trim();
    if (line === "") continue;
    try {
      const raw = JSON.parse(line);
      const parsed = interpolateEnv(raw, process.env);
      if (!isJsonObject(parsed)) {
        throw new Error("Expected JSON object");
      }
      results.push(parsed);
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      throw new Error(`Malformed JSONL at line ${i + 1}: ${message}
  File: ${filePath}`);
    }
  }
  return results;
}
async function loadCasesFromFile(filePath) {
  const ext = import_node_path2.default.extname(filePath).toLowerCase();
  let content;
  try {
    content = await (0, import_promises2.readFile)(filePath, "utf8");
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    throw new Error(`Cannot read external test file: ${filePath}
  ${message}`);
  }
  if (content.trim() === "") {
    console.warn(
      `${ANSI_YELLOW}Warning: External test file is empty, skipping: ${filePath}${ANSI_RESET}`
    );
    return [];
  }
  if (ext === ".yaml" || ext === ".yml") {
    return parseYamlCases(content, filePath);
  }
  if (ext === ".jsonl") {
    return parseJsonlCases(content, filePath);
  }
  throw new Error(
    `Unsupported external test file format '${ext}': ${filePath}. Supported: .yaml, .yml, .jsonl`
  );
}

// src/evaluation/validation/eval-validator.ts
var ASSERTION_TYPES_WITH_STRING_VALUE = /* @__PURE__ */ new Set([
  "contains",
  "icontains",
  "starts-with",
  "ends-with",
  "equals",
  "regex"
]);
var ASSERTION_TYPES_WITH_ARRAY_VALUE = /* @__PURE__ */ new Set([
  "contains-any",
  "contains-all",
  "icontains-any",
  "icontains-all"
]);
var VALID_TEST_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".yaml", ".yml", ".jsonl"]);
var NAME_PATTERN = /^[a-z0-9-]+$/;
function isObject(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
async function validateEvalFile(filePath) {
  const errors = [];
  const absolutePath = import_node_path3.default.resolve(filePath);
  let parsed;
  try {
    const content = await (0, import_promises3.readFile)(absolutePath, "utf8");
    parsed = interpolateEnv((0, import_yaml3.parse)(content), process.env);
  } catch (error) {
    errors.push({
      severity: "error",
      filePath: absolutePath,
      message: `Failed to parse YAML: ${error.message}`
    });
    return {
      valid: false,
      filePath: absolutePath,
      fileType: "eval",
      errors
    };
  }
  if (!isObject(parsed)) {
    errors.push({
      severity: "error",
      filePath: absolutePath,
      message: "File must contain a YAML object"
    });
    return {
      valid: false,
      filePath: absolutePath,
      fileType: "eval",
      errors
    };
  }
  validateMetadata(parsed, absolutePath, errors);
  const suiteInput = parsed.input;
  if (suiteInput !== void 0) {
    if (typeof suiteInput === "string") {
    } else if (Array.isArray(suiteInput)) {
      validateMessages(suiteInput, "input", absolutePath, errors);
    } else {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location: "input",
        message: "Invalid suite-level 'input' field (must be a string or array of messages)"
      });
    }
  }
  const cases = parsed.tests;
  if (typeof cases === "string") {
    validateTestsStringPath(cases, absolutePath, errors);
    await validateWorkspaceConfig(parsed.workspace, absolutePath, errors, "workspace");
    const ext = import_node_path3.default.extname(cases).toLowerCase();
    if (VALID_TEST_FILE_EXTENSIONS.has(ext)) {
      const externalCasesPath = import_node_path3.default.resolve(import_node_path3.default.dirname(absolutePath), cases);
      try {
        const externalCases = await loadCasesFromFile(externalCasesPath);
        for (let i = 0; i < externalCases.length; i++) {
          const externalCase = externalCases[i];
          await validateWorkspaceConfig(
            externalCase.workspace,
            absolutePath,
            errors,
            `tests[${i}].workspace`
          );
        }
      } catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        errors.push({
          severity: "error",
          filePath: absolutePath,
          location: "tests",
          message
        });
      }
    }
    return {
      valid: errors.filter((e) => e.severity === "error").length === 0,
      filePath: absolutePath,
      fileType: "eval",
      errors
    };
  }
  if (!Array.isArray(cases)) {
    errors.push({
      severity: "error",
      filePath: absolutePath,
      location: "tests",
      message: "Missing or invalid 'tests' field (must be an array or a file path string)"
    });
    return {
      valid: errors.length === 0,
      filePath: absolutePath,
      fileType: "eval",
      errors
    };
  }
  for (let i = 0; i < cases.length; i++) {
    const evalCase = cases[i];
    const location = `tests[${i}]`;
    if (typeof evalCase === "string") {
      if (evalCase.startsWith("file://")) {
        validateTestsStringPath(evalCase, absolutePath, errors);
      } else {
        errors.push({
          severity: "error",
          filePath: absolutePath,
          location,
          message: "Test case string must be a file reference (file://...)"
        });
      }
      continue;
    }
    if (!isObject(evalCase)) {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location,
        message: "Eval case must be an object"
      });
      continue;
    }
    const id = evalCase.id;
    if (typeof id !== "string" || id.trim().length === 0) {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location: `${location}.id`,
        message: "Missing or invalid 'id' field (must be a non-empty string)"
      });
    }
    let criteria = evalCase.criteria;
    if (criteria === void 0 && "expected_outcome" in evalCase) {
      criteria = evalCase.expected_outcome;
      errors.push({
        severity: "warning",
        filePath: absolutePath,
        location: `${location}.expected_outcome`,
        message: "'expected_outcome' is deprecated. Use 'criteria' instead."
      });
    }
    if (criteria !== void 0 && (typeof criteria !== "string" || criteria.trim().length === 0)) {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location: `${location}.criteria`,
        message: "Invalid 'criteria' field (must be a non-empty string if provided)"
      });
    }
    const inputField = evalCase.input;
    if (inputField !== void 0) {
      if (typeof inputField === "string") {
      } else if (Array.isArray(inputField)) {
        validateMessages(inputField, `${location}.input`, absolutePath, errors);
      } else {
        errors.push({
          severity: "error",
          filePath: absolutePath,
          location: `${location}.input`,
          message: "Invalid 'input' field (must be a string or array of messages)"
        });
      }
    } else {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location: `${location}.input`,
        message: "Missing 'input' field (must be a string or array of messages)"
      });
    }
    const expectedOutputField = evalCase.expected_output;
    if (expectedOutputField !== void 0) {
      if (typeof expectedOutputField === "string") {
      } else if (Array.isArray(expectedOutputField)) {
        if (expectedOutputField.length > 0 && isObject(expectedOutputField[0]) && "role" in expectedOutputField[0]) {
          validateMessages(
            expectedOutputField,
            `${location}.expected_output`,
            absolutePath,
            errors
          );
        }
      } else if (isObject(expectedOutputField)) {
      } else {
        errors.push({
          severity: "error",
          filePath: absolutePath,
          location: `${location}.expected_output`,
          message: "Invalid 'expected_output' field (must be a string, object, or array)"
        });
      }
    }
    const assertField = evalCase.assertions ?? evalCase.assert;
    if (assertField !== void 0) {
      validateAssertArray(assertField, location, absolutePath, errors);
    }
    await validateWorkspaceConfig(
      evalCase.workspace,
      absolutePath,
      errors,
      `${location}.workspace`
    );
  }
  await validateWorkspaceConfig(parsed.workspace, absolutePath, errors, "workspace");
  return {
    valid: errors.filter((e) => e.severity === "error").length === 0,
    filePath: absolutePath,
    fileType: "eval",
    errors
  };
}
async function validateWorkspaceConfig(workspace, evalFilePath, errors, location) {
  if (workspace === void 0) {
    return;
  }
  if (isObject(workspace)) {
    validateWorkspaceRepoConfig(workspace, evalFilePath, errors);
    return;
  }
  if (typeof workspace !== "string") {
    return;
  }
  const workspacePath = import_node_path3.default.resolve(import_node_path3.default.dirname(evalFilePath), workspace);
  try {
    const workspaceContent = await (0, import_promises3.readFile)(workspacePath, "utf8");
    const parsedWorkspace = interpolateEnv((0, import_yaml3.parse)(workspaceContent), process.env);
    if (!isObject(parsedWorkspace)) {
      errors.push({
        severity: "error",
        filePath: evalFilePath,
        location,
        message: `External workspace file must contain a YAML object: ${workspace}`
      });
      return;
    }
    validateWorkspaceRepoConfig(parsedWorkspace, workspacePath, errors);
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    errors.push({
      severity: "error",
      filePath: evalFilePath,
      location,
      message: `Failed to load external workspace file '${workspace}': ${message}`
    });
  }
}
function validateWorkspaceRepoConfig(workspace, filePath, errors) {
  const repos = workspace.repos;
  const hooks = workspace.hooks;
  const afterEachHook = isObject(hooks) ? hooks.after_each : void 0;
  const isolation = workspace.isolation;
  if (Array.isArray(repos)) {
    for (const repo of repos) {
      if (!isObject(repo)) continue;
      const source = repo.source;
      const checkout = repo.checkout;
      const clone = repo.clone;
      if (isObject(source) && isObject(checkout)) {
        const sourceType = source.type;
        const resolve = checkout.resolve;
        if (sourceType === "local" && typeof resolve === "string") {
          errors.push({
            severity: "warning",
            filePath,
            location: `workspace.repos[path=${repo.path}]`,
            message: "checkout.resolve has no effect for a local source. Use source.type to choose where the repo comes from; keep checkout.ref or checkout.ancestor only when pinning a local source."
          });
        }
      }
      if (isObject(checkout) && isObject(clone)) {
        const ancestor = checkout.ancestor;
        const depth = clone.depth;
        if (typeof ancestor === "number" && typeof depth === "number" && depth < ancestor + 1) {
          errors.push({
            severity: "warning",
            filePath,
            location: `workspace.repos[path=${repo.path}]`,
            message: `clone.depth (${depth}) may be insufficient for checkout.ancestor (${ancestor}). Recommend depth >= ${ancestor + 1}.`
          });
        }
      }
    }
  }
  if (isObject(afterEachHook) && afterEachHook.reset && afterEachHook.reset !== "none") {
    if (!Array.isArray(repos) || repos.length === 0) {
      errors.push({
        severity: "warning",
        filePath,
        location: "workspace.hooks.after_each",
        message: `hooks.after_each.reset '${afterEachHook.reset}' has no effect without repos.`
      });
    }
  }
  if (isObject(afterEachHook) && afterEachHook.reset && isolation === "per_test") {
    errors.push({
      severity: "warning",
      filePath,
      location: "workspace.hooks.after_each",
      message: "hooks.after_each.reset is redundant with isolation: per_test (each test gets a fresh workspace)."
    });
  }
}
function validateMessages(messages, location, filePath, errors) {
  for (let i = 0; i < messages.length; i++) {
    const message = messages[i];
    const msgLocation = `${location}[${i}]`;
    if (!isObject(message)) {
      errors.push({
        severity: "error",
        filePath,
        location: msgLocation,
        message: "Message must be an object"
      });
      continue;
    }
    const role = message.role;
    const validRoles = ["system", "user", "assistant"];
    if (!validRoles.includes(role)) {
      errors.push({
        severity: "error",
        filePath,
        location: `${msgLocation}.role`,
        message: `Invalid role '${role}'. Must be one of: ${validRoles.join(", ")}`
      });
    }
    const content = message.content;
    const hasToolCalls = "tool_calls" in message;
    if (content === void 0 && hasToolCalls) {
    } else if (typeof content === "string") {
      validateContentForRoleMarkers(content, `${msgLocation}.content`, filePath, errors);
    } else if (Array.isArray(content)) {
      for (let j = 0; j < content.length; j++) {
        const contentItem = content[j];
        const contentLocation = `${msgLocation}.content[${j}]`;
        if (typeof contentItem === "string") {
          validateContentForRoleMarkers(contentItem, contentLocation, filePath, errors);
        } else if (isObject(contentItem)) {
          const type = contentItem.type;
          if (typeof type !== "string") {
            errors.push({
              severity: "error",
              filePath,
              location: `${contentLocation}.type`,
              message: "Content object must have a 'type' field"
            });
          }
          if (type === "text") {
            const value = contentItem.value;
            if (typeof value !== "string") {
              errors.push({
                severity: "error",
                filePath,
                location: `${contentLocation}.value`,
                message: "Content with type 'text' must have a 'value' field"
              });
            } else {
              validateContentForRoleMarkers(value, `${contentLocation}.value`, filePath, errors);
            }
          }
        } else {
          errors.push({
            severity: "error",
            filePath,
            location: contentLocation,
            message: "Content array items must be strings or objects"
          });
        }
      }
    } else if (isObject(content)) {
    } else {
      errors.push({
        severity: "error",
        filePath,
        location: `${msgLocation}.content`,
        message: "Missing or invalid 'content' field (must be a string, array, or object)"
      });
    }
  }
}
function validateMetadata(parsed, filePath, errors) {
  const name = parsed.name;
  if (name !== void 0) {
    if (typeof name === "string") {
      if (!NAME_PATTERN.test(name)) {
        errors.push({
          severity: "warning",
          filePath,
          location: "name",
          message: `Invalid 'name' format '${name}'. Must match pattern /^[a-z0-9-]+$/ (lowercase alphanumeric with hyphens).`
        });
      }
    }
    if (!("description" in parsed) || parsed.description === void 0) {
      errors.push({
        severity: "warning",
        filePath,
        location: "name",
        message: "When 'name' is present, 'description' should also be provided."
      });
    }
  }
}
function validateTestsStringPath(testsPath, filePath, errors) {
  const ext = import_node_path3.default.extname(testsPath);
  if (!VALID_TEST_FILE_EXTENSIONS.has(ext)) {
    errors.push({
      severity: "warning",
      filePath,
      location: "tests",
      message: `Unsupported file extension '${ext}' for tests path '${testsPath}'. Supported extensions: ${[...VALID_TEST_FILE_EXTENSIONS].join(", ")}`
    });
  }
}
function validateAssertArray(assertField, parentLocation, filePath, errors) {
  if (!Array.isArray(assertField)) {
    errors.push({
      severity: "warning",
      filePath,
      location: `${parentLocation}.assertions`,
      message: "'assertions' must be an array of assertion objects."
    });
    return;
  }
  const objectItems = [];
  for (let i = 0; i < assertField.length; i++) {
    const item = assertField[i];
    if (typeof item === "string") {
      if (item.trim().length === 0) {
        errors.push({
          severity: "warning",
          filePath,
          location: `${parentLocation}.assertions[${i}]`,
          message: "Empty string assertion item will be ignored."
        });
      }
      continue;
    }
    if (!isObject(item)) {
      errors.push({
        severity: "warning",
        filePath,
        location: `${parentLocation}.assertions[${i}]`,
        message: "Assertion item must be a string or an object with a type field."
      });
      continue;
    }
    objectItems.push({ item, index: i });
  }
  for (const { item, index } of objectItems) {
    const location = `${parentLocation}.assertions[${index}]`;
    const rawTypeValue = item.type;
    if (rawTypeValue === void 0 || typeof rawTypeValue !== "string") {
      errors.push({
        severity: "warning",
        filePath,
        location: `${location}.type`,
        message: "Assertion item is missing a 'type' field."
      });
      continue;
    }
    const typeValue = rawTypeValue.replace(/_/g, "-");
    if (!isEvaluatorKind(typeValue)) {
      errors.push({
        severity: "warning",
        filePath,
        location: `${location}.type`,
        message: `Unknown assertion type '${rawTypeValue}'.`
      });
      continue;
    }
    if (ASSERTION_TYPES_WITH_STRING_VALUE.has(typeValue)) {
      const value = item.value;
      if (value === void 0 || typeof value !== "string") {
        errors.push({
          severity: "warning",
          filePath,
          location: `${location}.value`,
          message: `Assertion type '${typeValue}' requires a 'value' field (string).`
        });
        continue;
      }
      if (typeValue === "regex") {
        try {
          new RegExp(value);
        } catch {
          errors.push({
            severity: "warning",
            filePath,
            location: `${location}.value`,
            message: `Invalid regex pattern '${value}': not a valid regular expression.`
          });
        }
      }
    }
    if (ASSERTION_TYPES_WITH_ARRAY_VALUE.has(typeValue)) {
      const value = item.value;
      if (!Array.isArray(value) || value.length === 0) {
        errors.push({
          severity: "warning",
          filePath,
          location: `${location}.value`,
          message: `Assertion type '${typeValue}' requires a 'value' field (non-empty string array).`
        });
        continue;
      }
    }
    const required = item.required;
    if (required !== void 0) {
      validateRequiredField(required, location, filePath, errors);
    }
  }
}
function validateRequiredField(required, parentLocation, filePath, errors) {
  if (typeof required === "boolean") {
    return;
  }
  if (typeof required === "number") {
    if (required <= 0 || required > 1) {
      errors.push({
        severity: "warning",
        filePath,
        location: `${parentLocation}.required`,
        message: `Invalid 'required' value ${required}. When a number, it must be between 0 (exclusive) and 1 (inclusive).`
      });
    }
    return;
  }
  errors.push({
    severity: "warning",
    filePath,
    location: `${parentLocation}.required`,
    message: `Invalid 'required' value. Must be a boolean or a number between 0 (exclusive) and 1 (inclusive).`
  });
}
function validateContentForRoleMarkers(content, location, filePath, errors) {
  const markers = ["@[System]:", "@[User]:", "@[Assistant]:", "@[Tool]:"];
  for (const marker of markers) {
    if (content.toLowerCase().includes(marker.toLowerCase())) {
      errors.push({
        severity: "warning",
        filePath,
        location,
        message: `Content contains potential role marker '${marker}'. This may confuse agentic providers or cause prompt injection.`
      });
    }
  }
}

// src/evaluation/validation/targets-validator.ts
var import_promises4 = require("fs/promises");
var import_node_path5 = __toESM(require("path"), 1);
var import_yaml4 = require("yaml");

// src/evaluation/providers/targets.ts
var import_node_path4 = __toESM(require("path"), 1);
var import_zod = require("zod");
var CliHealthcheckHttpInputSchema = import_zod.z.object({
  url: import_zod.z.string().min(1, "healthcheck URL is required"),
  timeout_seconds: import_zod.z.number().positive().optional(),
  timeoutSeconds: import_zod.z.number().positive().optional()
});
var CliHealthcheckCommandInputSchema = import_zod.z.object({
  command: import_zod.z.string().min(1, "healthcheck command is required"),
  cwd: import_zod.z.string().optional(),
  timeout_seconds: import_zod.z.number().positive().optional(),
  timeoutSeconds: import_zod.z.number().positive().optional()
});
var CliHealthcheckInputSchema = import_zod.z.union([
  CliHealthcheckHttpInputSchema,
  CliHealthcheckCommandInputSchema
]);
var CliTargetInputSchema = import_zod.z.object({
  name: import_zod.z.string().min(1, "target name is required"),
  provider: import_zod.z.string().refine((p) => p.toLowerCase() === "cli", { message: "provider must be 'cli'" }),
  // Command - required
  command: import_zod.z.string(),
  // Files format - optional
  files_format: import_zod.z.string().optional(),
  filesFormat: import_zod.z.string().optional(),
  attachments_format: import_zod.z.string().optional(),
  attachmentsFormat: import_zod.z.string().optional(),
  // Working directory - optional
  cwd: import_zod.z.string().optional(),
  // Workspace template directory - optional (mutually exclusive with cwd)
  workspace_template: import_zod.z.string().optional(),
  workspaceTemplate: import_zod.z.string().optional(),
  // Timeout in seconds - optional
  timeout_seconds: import_zod.z.number().positive().optional(),
  timeoutSeconds: import_zod.z.number().positive().optional(),
  // Healthcheck configuration - optional
  healthcheck: CliHealthcheckInputSchema.optional(),
  // Verbose mode - optional
  verbose: import_zod.z.boolean().optional(),
  cli_verbose: import_zod.z.boolean().optional(),
  cliVerbose: import_zod.z.boolean().optional(),
  // Keep temp files - optional
  keep_temp_files: import_zod.z.boolean().optional(),
  keepTempFiles: import_zod.z.boolean().optional(),
  keep_output_files: import_zod.z.boolean().optional(),
  keepOutputFiles: import_zod.z.boolean().optional(),
  // Common target fields
  grader_target: import_zod.z.string().optional(),
  judge_target: import_zod.z.string().optional(),
  // backward compat
  workers: import_zod.z.number().int().min(1).optional(),
  provider_batching: import_zod.z.boolean().optional(),
  providerBatching: import_zod.z.boolean().optional()
});
var CliHealthcheckHttpSchema = import_zod.z.object({
  url: import_zod.z.string().min(1),
  timeoutMs: import_zod.z.number().positive().optional()
}).strict();
var CliHealthcheckCommandSchema = import_zod.z.object({
  command: import_zod.z.string().min(1),
  cwd: import_zod.z.string().optional(),
  timeoutMs: import_zod.z.number().positive().optional()
}).strict();
var CliHealthcheckSchema = import_zod.z.union([
  CliHealthcheckHttpSchema,
  CliHealthcheckCommandSchema
]);
var CliTargetConfigSchema = import_zod.z.object({
  command: import_zod.z.string().min(1),
  filesFormat: import_zod.z.string().optional(),
  cwd: import_zod.z.string().optional(),
  workspaceTemplate: import_zod.z.string().optional(),
  timeoutMs: import_zod.z.number().positive().optional(),
  healthcheck: CliHealthcheckSchema.optional(),
  verbose: import_zod.z.boolean().optional(),
  keepTempFiles: import_zod.z.boolean().optional()
}).strict();
var CLI_PLACEHOLDERS = /* @__PURE__ */ new Set([
  "PROMPT",
  "PROMPT_FILE",
  "EVAL_ID",
  "ATTEMPT",
  "FILES",
  "OUTPUT_FILE"
]);
var COMMON_TARGET_SETTINGS = [
  "provider_batching",
  "providerBatching",
  "subagent_mode_allowed",
  "subagentModeAllowed"
];
var BASE_TARGET_SCHEMA = import_zod.z.object({
  name: import_zod.z.string().min(1, "target name is required"),
  provider: import_zod.z.string().min(1, "provider is required"),
  grader_target: import_zod.z.string().optional(),
  judge_target: import_zod.z.string().optional(),
  // backward compat
  workers: import_zod.z.number().int().min(1).optional(),
  workspace_template: import_zod.z.string().optional(),
  workspaceTemplate: import_zod.z.string().optional(),
  subagent_mode_allowed: import_zod.z.boolean().optional()
}).passthrough();

// src/evaluation/providers/types.ts
var KNOWN_PROVIDERS = [
  "openai",
  "openrouter",
  "azure",
  "anthropic",
  "gemini",
  "codex",
  "copilot-sdk",
  "copilot-cli",
  "copilot-log",
  "pi-coding-agent",
  "pi-cli",
  "claude",
  "claude-cli",
  "claude-sdk",
  "cli",
  "mock",
  "vscode",
  "vscode-insiders",
  "agentv"
];
var PROVIDER_ALIASES = [
  "azure-openai",
  // alias for "azure"
  "google",
  // alias for "gemini"
  "google-gemini",
  // alias for "gemini"
  "codex-cli",
  // alias for "codex"
  "copilot",
  // alias for "copilot-cli" (default copilot experience)
  "copilot_sdk",
  // alias for "copilot-sdk" (underscore variant)
  "pi",
  // alias for "pi-coding-agent"
  "claude-code",
  // alias for "claude" (legacy)
  "bedrock",
  // legacy/future support
  "vertex"
  // legacy/future support
];

// src/evaluation/validation/targets-validator.ts
function isObject2(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
var COMMON_SETTINGS = new Set(COMMON_TARGET_SETTINGS);
var RETRY_SETTINGS = /* @__PURE__ */ new Set([
  "max_retries",
  "maxRetries",
  "retry_initial_delay_ms",
  "retryInitialDelayMs",
  "retry_max_delay_ms",
  "retryMaxDelayMs",
  "retry_backoff_factor",
  "retryBackoffFactor",
  "retry_status_codes",
  "retryStatusCodes"
]);
var AZURE_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  ...RETRY_SETTINGS,
  "endpoint",
  "resource",
  "resourceName",
  "api_key",
  "apiKey",
  "deployment",
  "deploymentName",
  "model",
  "version",
  "api_version",
  "temperature",
  "max_output_tokens",
  "maxTokens"
]);
var OPENAI_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  ...RETRY_SETTINGS,
  "endpoint",
  "base_url",
  "baseUrl",
  "api_key",
  "apiKey",
  "model",
  "deployment",
  "variant",
  "temperature",
  "max_output_tokens",
  "maxTokens"
]);
var OPENROUTER_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  ...RETRY_SETTINGS,
  "api_key",
  "apiKey",
  "model",
  "deployment",
  "variant",
  "temperature",
  "max_output_tokens",
  "maxTokens"
]);
var ANTHROPIC_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  ...RETRY_SETTINGS,
  "api_key",
  "apiKey",
  "model",
  "deployment",
  "variant",
  "temperature",
  "max_output_tokens",
  "maxTokens",
  "thinking_budget",
  "thinkingBudget"
]);
var GEMINI_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  ...RETRY_SETTINGS,
  "api_key",
  "apiKey",
  "model",
  "deployment",
  "variant",
  "temperature",
  "max_output_tokens",
  "maxTokens"
]);
var CODEX_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  "model",
  "executable",
  "command",
  "binary",
  "args",
  "arguments",
  "cwd",
  "timeout_seconds",
  "timeoutSeconds",
  "log_dir",
  "logDir",
  "log_directory",
  "logDirectory",
  "log_format",
  "logFormat",
  "log_output_format",
  "logOutputFormat",
  "system_prompt",
  "systemPrompt",
  "workspace_template",
  "workspaceTemplate"
]);
var COPILOT_SDK_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  "cli_url",
  "cliUrl",
  "cli_path",
  "cliPath",
  "github_token",
  "githubToken",
  "model",
  "cwd",
  "timeout_seconds",
  "timeoutSeconds",
  "log_dir",
  "logDir",
  "log_format",
  "logFormat",
  "system_prompt",
  "systemPrompt",
  "workspace_template",
  "workspaceTemplate"
]);
var COPILOT_CLI_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  "executable",
  "command",
  "binary",
  "args",
  "arguments",
  "model",
  "cwd",
  "timeout_seconds",
  "timeoutSeconds",
  "log_dir",
  "logDir",
  "log_format",
  "logFormat",
  "system_prompt",
  "systemPrompt",
  "workspace_template",
  "workspaceTemplate"
]);
var VSCODE_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  "executable",
  "workspace_template",
  "workspaceTemplate",
  "wait",
  "dry_run",
  "dryRun",
  "subagent_root",
  "subagentRoot",
  "timeout_seconds",
  "timeoutSeconds"
]);
var MOCK_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  "response",
  "delayMs",
  "delayMinMs",
  "delayMaxMs",
  "trace"
  // For testing tool-trajectory evaluator
]);
var CLAUDE_SETTINGS = /* @__PURE__ */ new Set([
  ...COMMON_SETTINGS,
  "model",
  "cwd",
  "timeout_seconds",
  "timeoutSeconds",
  "log_dir",
  "logDir",
  "log_directory",
  "logDirectory",
  "log_format",
  "logFormat",
  "log_output_format",
  "logOutputFormat",
  "system_prompt",
  "systemPrompt",
  "workspace_template",
  "workspaceTemplate",
  "max_turns",
  "maxTurns",
  "max_budget_usd",
  "maxBudgetUsd"
]);
function getKnownSettings(provider) {
  const normalizedProvider = provider.toLowerCase();
  switch (normalizedProvider) {
    case "openai":
      return OPENAI_SETTINGS;
    case "openrouter":
      return OPENROUTER_SETTINGS;
    case "azure":
    case "azure-openai":
      return AZURE_SETTINGS;
    case "anthropic":
      return ANTHROPIC_SETTINGS;
    case "gemini":
    case "google":
    case "google-gemini":
      return GEMINI_SETTINGS;
    case "codex":
    case "codex-cli":
      return CODEX_SETTINGS;
    case "copilot-sdk":
    case "copilot_sdk":
      return COPILOT_SDK_SETTINGS;
    case "copilot":
    case "copilot-cli":
      return COPILOT_CLI_SETTINGS;
    case "claude":
    case "claude-code":
    case "claude-cli":
    case "claude-sdk":
      return CLAUDE_SETTINGS;
    case "vscode":
    case "vscode-insiders":
      return VSCODE_SETTINGS;
    case "mock":
      return MOCK_SETTINGS;
    case "cli":
      return null;
    default:
      return null;
  }
}
function validateUnknownSettings(target, provider, absolutePath, location, errors) {
  const removedTargetFields = /* @__PURE__ */ new Set(["workspace_template", "workspaceTemplate"]);
  const knownSettings = getKnownSettings(provider);
  if (!knownSettings) {
    return;
  }
  const baseFields = /* @__PURE__ */ new Set([
    "name",
    "provider",
    "grader_target",
    "judge_target",
    "workers",
    "$schema",
    "targets"
  ]);
  for (const key of Object.keys(target)) {
    if (removedTargetFields.has(key)) {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location: `${location}.${key}`,
        message: "target-level workspace_template has been removed. Use eval-level workspace.template."
      });
      continue;
    }
    if (!baseFields.has(key) && !knownSettings.has(key)) {
      errors.push({
        severity: "warning",
        filePath: absolutePath,
        location: `${location}.${key}`,
        message: `Unknown setting '${key}' for ${provider} provider. This property will be ignored.`
      });
    }
  }
}
async function validateTargetsFile(filePath) {
  const errors = [];
  const absolutePath = import_node_path5.default.resolve(filePath);
  let parsed;
  try {
    const content = await (0, import_promises4.readFile)(absolutePath, "utf8");
    parsed = (0, import_yaml4.parse)(content);
  } catch (error) {
    errors.push({
      severity: "error",
      filePath: absolutePath,
      message: `Failed to parse YAML: ${error.message}`
    });
    return {
      valid: false,
      filePath: absolutePath,
      fileType: "targets",
      errors
    };
  }
  function validateCliSettings(target, absolutePath2, location, errors2) {
    const command = target.command;
    if (typeof command !== "string" || command.trim().length === 0) {
      errors2.push({
        severity: "error",
        filePath: absolutePath2,
        location: `${location}.command`,
        message: "CLI provider requires 'command' as a non-empty string"
      });
    } else {
      recordUnknownPlaceholders(command, absolutePath2, `${location}.command`, errors2);
    }
    const healthcheck = target.healthcheck;
    if (healthcheck !== void 0) {
      validateCliHealthcheck(healthcheck, absolutePath2, `${location}.healthcheck`, errors2);
    }
  }
  function validateCliHealthcheck(healthcheck, absolutePath2, location, errors2) {
    if (!isObject2(healthcheck)) {
      errors2.push({
        severity: "error",
        filePath: absolutePath2,
        location,
        message: "'healthcheck' must be an object when provided"
      });
      return;
    }
    const timeoutSeconds = healthcheck.timeout_seconds ?? healthcheck.timeoutSeconds;
    if (timeoutSeconds !== void 0) {
      const numericTimeout = Number(timeoutSeconds);
      if (!Number.isFinite(numericTimeout) || numericTimeout <= 0) {
        errors2.push({
          severity: "error",
          filePath: absolutePath2,
          location: `${location}.timeoutSeconds`,
          message: "healthcheck.timeoutSeconds must be a positive number when provided"
        });
      }
    }
    const hasUrl = typeof healthcheck.url === "string" && healthcheck.url.trim().length > 0;
    const hasCommand = typeof healthcheck.command === "string" && healthcheck.command.trim().length > 0;
    if (!hasUrl && !hasCommand) {
      errors2.push({
        severity: "error",
        filePath: absolutePath2,
        location,
        message: "healthcheck must have either 'url' (HTTP) or 'command' (command)"
      });
      return;
    }
    if (hasUrl) {
      return;
    }
    recordUnknownPlaceholders(
      healthcheck.command,
      absolutePath2,
      `${location}.command`,
      errors2
    );
    const cwd = healthcheck.cwd;
    if (cwd !== void 0 && typeof cwd !== "string") {
      errors2.push({
        severity: "error",
        filePath: absolutePath2,
        location: `${location}.cwd`,
        message: "healthcheck.cwd must be a string when provided"
      });
    }
  }
  function recordUnknownPlaceholders(template, absolutePath2, location, errors2) {
    const placeholders = extractPlaceholders(template);
    for (const placeholder of placeholders) {
      if (!CLI_PLACEHOLDERS.has(placeholder)) {
        errors2.push({
          severity: "error",
          filePath: absolutePath2,
          location,
          message: `Unknown CLI placeholder '{${placeholder}}'. Supported placeholders: ${Array.from(CLI_PLACEHOLDERS).join(", ")}`
        });
      }
    }
  }
  function extractPlaceholders(template) {
    const matches = template.matchAll(/\{([A-Z_]+)\}/g);
    const result = [];
    for (const match of matches) {
      const placeholder = match[1];
      if (placeholder) {
        result.push(placeholder);
      }
    }
    return result;
  }
  if (!isObject2(parsed)) {
    errors.push({
      severity: "error",
      filePath: absolutePath,
      message: "File must contain a YAML object"
    });
    return {
      valid: false,
      filePath: absolutePath,
      fileType: "targets",
      errors
    };
  }
  const targets = parsed.targets;
  if (!Array.isArray(targets)) {
    errors.push({
      severity: "error",
      filePath: absolutePath,
      location: "targets",
      message: "Missing or invalid 'targets' field (must be an array)"
    });
    return {
      valid: errors.length === 0,
      filePath: absolutePath,
      fileType: "targets",
      errors
    };
  }
  const knownProviders = [...KNOWN_PROVIDERS, ...PROVIDER_ALIASES];
  for (let i = 0; i < targets.length; i++) {
    const target = targets[i];
    const location = `targets[${i}]`;
    if (!isObject2(target)) {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location,
        message: "Target must be an object"
      });
      continue;
    }
    const name = target.name;
    if (typeof name !== "string" || name.trim().length === 0) {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location: `${location}.name`,
        message: "Missing or invalid 'name' field (must be a non-empty string)"
      });
    }
    const provider = target.provider;
    const providerValue = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
    const isTemplated = typeof provider === "string" && /^\$\{\{.+\}\}$/.test(provider.trim());
    if (typeof provider !== "string" || provider.trim().length === 0) {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location: `${location}.provider`,
        message: "Missing or invalid 'provider' field (must be a non-empty string)"
      });
    } else if (!isTemplated && !knownProviders.includes(provider)) {
      errors.push({
        severity: "warning",
        filePath: absolutePath,
        location: `${location}.provider`,
        message: `Unknown provider '${provider}'. Known providers: ${knownProviders.join(", ")}`
      });
    }
    if (providerValue === "cli") {
      validateCliSettings(target, absolutePath, location, errors);
    }
    if (typeof provider === "string" && !isTemplated) {
      validateUnknownSettings(target, provider, absolutePath, location, errors);
    }
    const graderTarget = target.grader_target ?? target.judge_target;
    if (graderTarget !== void 0 && typeof graderTarget !== "string") {
      errors.push({
        severity: "error",
        filePath: absolutePath,
        location: `${location}.grader_target`,
        message: "Invalid 'grader_target' field (must be a string)"
      });
    }
  }
  return {
    valid: errors.filter((e) => e.severity === "error").length === 0,
    filePath: absolutePath,
    fileType: "targets",
    errors
  };
}

// src/evaluation/validation/config-validator.ts
var import_promises5 = require("fs/promises");
var import_yaml5 = require("yaml");
async function validateConfigFile(filePath) {
  const errors = [];
  try {
    const content = await (0, import_promises5.readFile)(filePath, "utf8");
    const parsed = (0, import_yaml5.parse)(content);
    if (typeof parsed !== "object" || parsed === null) {
      errors.push({
        severity: "error",
        filePath,
        message: "Config file must contain a valid YAML object"
      });
      return { valid: false, filePath, fileType: "config", errors };
    }
    const config = parsed;
    const evalPatterns = config.eval_patterns;
    if (evalPatterns !== void 0) {
      if (!Array.isArray(evalPatterns)) {
        errors.push({
          severity: "error",
          filePath,
          location: "eval_patterns",
          message: "Field 'eval_patterns' must be an array"
        });
      } else if (!evalPatterns.every((p) => typeof p === "string")) {
        errors.push({
          severity: "error",
          filePath,
          location: "eval_patterns",
          message: "All entries in 'eval_patterns' must be strings"
        });
      } else if (evalPatterns.length === 0) {
        errors.push({
          severity: "warning",
          filePath,
          location: "eval_patterns",
          message: "Field 'eval_patterns' is empty. Consider removing it or adding patterns."
        });
      }
    }
    const requiredVersion = config.required_version;
    if (requiredVersion !== void 0) {
      if (typeof requiredVersion !== "string" || requiredVersion.trim().length === 0) {
        errors.push({
          severity: "error",
          filePath,
          location: "required_version",
          message: `Field 'required_version' must be a non-empty string (e.g. ">=3.1.0")`
        });
      }
    }
    const allowedFields = /* @__PURE__ */ new Set(["$schema", "eval_patterns", "required_version", "execution"]);
    const unexpectedFields = Object.keys(config).filter((key) => !allowedFields.has(key));
    if (unexpectedFields.length > 0) {
      errors.push({
        severity: "warning",
        filePath,
        message: `Unexpected fields: ${unexpectedFields.join(", ")}`
      });
    }
    return {
      valid: errors.filter((e) => e.severity === "error").length === 0,
      filePath,
      fileType: "config",
      errors
    };
  } catch (error) {
    errors.push({
      severity: "error",
      filePath,
      message: `Failed to parse config file: ${error.message}`
    });
    return { valid: false, filePath, fileType: "config", errors };
  }
}

// src/evaluation/validation/file-reference-validator.ts
var import_promises7 = require("fs/promises");
var import_node_path7 = __toESM(require("path"), 1);
var import_yaml6 = require("yaml");

// src/evaluation/file-utils.ts
var import_node_fs = require("fs");
var import_promises6 = require("fs/promises");
var import_node_path6 = __toESM(require("path"), 1);
async function fileExists(filePath) {
  try {
    await (0, import_promises6.access)(filePath, import_node_fs.constants.F_OK);
    return true;
  } catch {
    return false;
  }
}
async function findGitRoot(startPath) {
  let currentDir = import_node_path6.default.dirname(import_node_path6.default.resolve(startPath));
  const root = import_node_path6.default.parse(currentDir).root;
  while (currentDir !== root) {
    const gitPath = import_node_path6.default.join(currentDir, ".git");
    if (await fileExists(gitPath)) {
      return currentDir;
    }
    const parentDir = import_node_path6.default.dirname(currentDir);
    if (parentDir === currentDir) {
      break;
    }
    currentDir = parentDir;
  }
  return null;
}
function buildSearchRoots(evalPath, repoRoot) {
  const uniqueRoots = [];
  const addRoot = (root) => {
    const normalized = import_node_path6.default.resolve(root);
    if (!uniqueRoots.includes(normalized)) {
      uniqueRoots.push(normalized);
    }
  };
  let currentDir = import_node_path6.default.dirname(evalPath);
  let reachedBoundary = false;
  while (!reachedBoundary) {
    addRoot(currentDir);
    const parentDir = import_node_path6.default.dirname(currentDir);
    if (currentDir === repoRoot || parentDir === currentDir) {
      reachedBoundary = true;
    } else {
      currentDir = parentDir;
    }
  }
  addRoot(repoRoot);
  addRoot(process.cwd());
  return uniqueRoots;
}
function trimLeadingSeparators(value) {
  const trimmed = value.replace(/^[/\\]+/, "");
  return trimmed.length > 0 ? trimmed : value;
}
async function resolveFileReference(rawValue, searchRoots) {
  const displayPath = trimLeadingSeparators(rawValue);
  const potentialPaths = [];
  if (import_node_path6.default.isAbsolute(rawValue)) {
    potentialPaths.push(import_node_path6.default.normalize(rawValue));
  }
  for (const base of searchRoots) {
    potentialPaths.push(import_node_path6.default.resolve(base, displayPath));
  }
  const attempted = [];
  const seen = /* @__PURE__ */ new Set();
  for (const candidate of potentialPaths) {
    const absoluteCandidate = import_node_path6.default.resolve(candidate);
    if (seen.has(absoluteCandidate)) {
      continue;
    }
    seen.add(absoluteCandidate);
    attempted.push(absoluteCandidate);
    if (await fileExists(absoluteCandidate)) {
      return { displayPath, resolvedPath: absoluteCandidate, attempted };
    }
  }
  return { displayPath, attempted };
}

// src/evaluation/validation/file-reference-validator.ts
function isObject3(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
async function validateFileReferences(evalFilePath) {
  const errors = [];
  const absolutePath = import_node_path7.default.resolve(evalFilePath);
  const gitRoot = await findGitRoot(absolutePath);
  if (!gitRoot) {
    errors.push({
      severity: "error",
      filePath: absolutePath,
      message: "Cannot validate file references: git repository root not found"
    });
    return errors;
  }
  const searchRoots = buildSearchRoots(absolutePath, gitRoot);
  let parsed;
  try {
    const content = await (0, import_promises7.readFile)(absolutePath, "utf8");
    parsed = (0, import_yaml6.parse)(content);
  } catch {
    return errors;
  }
  if (!isObject3(parsed)) {
    return errors;
  }
  let cases = parsed.tests;
  if (cases === void 0 && "eval_cases" in parsed) {
    cases = parsed.eval_cases;
  }
  if (cases === void 0 && "evalcases" in parsed) {
    cases = parsed.evalcases;
  }
  if (!Array.isArray(cases)) {
    return errors;
  }
  for (let i = 0; i < cases.length; i++) {
    const evalCase = cases[i];
    if (!isObject3(evalCase)) {
      continue;
    }
    const inputField = evalCase.input;
    if (Array.isArray(inputField)) {
      await validateMessagesFileRefs(
        inputField,
        `tests[${i}].input`,
        searchRoots,
        absolutePath,
        errors
      );
    }
    const expectedOutputField = evalCase.expected_output;
    if (Array.isArray(expectedOutputField)) {
      await validateMessagesFileRefs(
        expectedOutputField,
        `tests[${i}].expected_output`,
        searchRoots,
        absolutePath,
        errors
      );
    }
  }
  return errors;
}
async function validateMessagesFileRefs(messages, location, searchRoots, filePath, errors) {
  for (let i = 0; i < messages.length; i++) {
    const message = messages[i];
    if (!isObject3(message)) {
      continue;
    }
    const content = message.content;
    if (typeof content === "string") {
      continue;
    }
    if (!Array.isArray(content)) {
      continue;
    }
    for (let j = 0; j < content.length; j++) {
      const contentItem = content[j];
      if (!isObject3(contentItem)) {
        continue;
      }
      const type = contentItem.type;
      if (type !== "file") {
        continue;
      }
      const value = contentItem.value;
      if (typeof value !== "string") {
        errors.push({
          severity: "error",
          filePath,
          location: `${location}[${i}].content[${j}].value`,
          message: "File reference must have a 'value' field with the file path"
        });
        continue;
      }
      const { resolvedPath } = await resolveFileReference(value, searchRoots);
      if (!resolvedPath) {
        errors.push({
          severity: "error",
          filePath,
          location: `${location}[${i}].content[${j}]`,
          message: `Referenced file not found: ${value}`
        });
      } else {
        try {
          const fileContent = await (0, import_promises7.readFile)(resolvedPath, "utf8");
          if (fileContent.trim().length === 0) {
            errors.push({
              severity: "warning",
              filePath,
              location: `${location}[${i}].content[${j}]`,
              message: `Referenced file is empty: ${value}`
            });
          }
        } catch (error) {
          errors.push({
            severity: "error",
            filePath,
            location: `${location}[${i}].content[${j}]`,
            message: `Cannot read referenced file: ${value} (${error.message})`
          });
        }
      }
    }
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  detectFileType,
  getExpectedSchema,
  isValidSchema,
  validateConfigFile,
  validateEvalFile,
  validateFileReferences,
  validateTargetsFile
});
//# sourceMappingURL=index.cjs.map