@alis-build/harness-eval 0.1.0 → 0.1.2

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 (33) hide show
  1. package/README.md +17 -4
  2. package/dist/adapters/claude-code/index.d.ts +1 -1
  3. package/dist/adapters/claude-code/index.js +1 -1
  4. package/dist/{claude-code-ycT0JQZF.js → claude-code-DZ4Vkgp6.js} +35 -6
  5. package/dist/{claude-code-ycT0JQZF.js.map → claude-code-DZ4Vkgp6.js.map} +1 -1
  6. package/dist/cli/bin.js +109 -12
  7. package/dist/cli/bin.js.map +1 -1
  8. package/dist/config/loader.d.ts +1 -1
  9. package/dist/config/loader.js +1 -1
  10. package/dist/{index-6Z17eKZx.d.ts → index-V22PrR0p.d.ts} +2 -1
  11. package/dist/index.d.ts +270 -152
  12. package/dist/index.js +124 -5
  13. package/dist/index.js.map +1 -0
  14. package/dist/{loader-DTvoVfN0.d.ts → loader-C9yQHUPC.d.ts} +19 -2
  15. package/dist/{loader-BCnFJ8rm.js → loader-DcI0KfRX.js} +291 -4
  16. package/dist/loader-DcI0KfRX.js.map +1 -0
  17. package/dist/{build-DsVJ_UeU.js → projections-BcX7w-f6.js} +486 -243
  18. package/dist/projections-BcX7w-f6.js.map +1 -0
  19. package/dist/runner/suite.d.ts +1 -1
  20. package/dist/runner/suite.js +1 -1
  21. package/dist/{suite-BoOvK_lq.d.ts → suite-DPJMIEbu.d.ts} +7 -2
  22. package/dist/{suite-chj0j22j.js → suite-Dlzl-HI0.js} +58 -4
  23. package/dist/suite-Dlzl-HI0.js.map +1 -0
  24. package/dist/{types-BQol062t.d.ts → types-CD3TwOtZ.d.ts} +151 -10
  25. package/package.json +4 -2
  26. package/schemas/eval-interchange-instances.schema.json +196 -0
  27. package/schemas/eval-interchange.schema.json +65 -52
  28. package/schemas/eval-run-envelope.schema.json +182 -425
  29. package/dist/build-DsVJ_UeU.js.map +0 -1
  30. package/dist/loader-BCnFJ8rm.js.map +0 -1
  31. package/dist/suite-chj0j22j.js.map +0 -1
  32. package/schemas/eval-interchange-agent-trace.schema.json +0 -322
  33. package/schemas/eval-interchange-proto-instance.schema.json +0 -106
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-DcI0KfRX.js","names":["parseYaml","formatZodError","parseYaml"],"sources":["../src/config/paths.ts","../src/config/schema.ts","../src/config/transform.ts","../src/config/grading-schema.ts","../src/config/grading-loader.ts","../src/config/loader.ts"],"sourcesContent":["/**\n * Resolve relative paths in suite config against the suite file directory.\n *\n * YAML authors write paths relative to the suite file; this module absolutizes\n * them at load time so the runner and adapters receive filesystem-ready values.\n * Tilde-prefixed paths and inline JSON blobs (settings starting with `{`) are\n * left unchanged.\n */\n\nimport { isAbsolute, join } from \"node:path\";\n\nimport type { SuiteConfig } from \"../adapters/types\";\n\n/** Resolve a single path relative to `suiteDir` unless already absolute or `~/`. */\nfunction resolvePath(value: string, suiteDir: string): string {\n if (isAbsolute(value) || value.startsWith(\"~/\")) {\n return value;\n }\n return join(suiteDir, value);\n}\n\n/** Resolve Claude Code-specific path fields within a config block. */\nfunction resolveClaudeCodePaths(\n block: Record<string, unknown>,\n suiteDir: string,\n): Record<string, unknown> {\n const resolved = { ...block };\n if (typeof resolved.mcpConfig === \"string\") {\n resolved.mcpConfig = resolvePath(resolved.mcpConfig, suiteDir);\n }\n if (Array.isArray(resolved.pluginDirs)) {\n resolved.pluginDirs = resolved.pluginDirs.map((p) =>\n typeof p === \"string\" ? resolvePath(p, suiteDir) : p,\n );\n }\n if (Array.isArray(resolved.addDirs)) {\n resolved.addDirs = resolved.addDirs.map((p) =>\n typeof p === \"string\" ? resolvePath(p, suiteDir) : p,\n );\n }\n const filePathFields = [\n \"systemPromptFile\",\n \"appendSystemPromptFile\",\n \"debugFile\",\n ] as const;\n for (const field of filePathFields) {\n const value = resolved[field];\n // Inline JSON settings blobs start with `{` and are not filesystem paths.\n if (typeof value === \"string\" && !value.trim().startsWith(\"{\")) {\n resolved[field] = resolvePath(value, suiteDir);\n }\n }\n if (typeof resolved.settings === \"string\" && !resolved.settings.trim().startsWith(\"{\")) {\n resolved.settings = resolvePath(resolved.settings, suiteDir);\n }\n return resolved;\n}\n\n/** Resolve relative paths in a config layer relative to `suiteDir`. */\nexport function resolveConfigPaths(\n config: SuiteConfig | undefined,\n suiteDir: string,\n): SuiteConfig | undefined {\n if (!config) return undefined;\n\n const resolved: SuiteConfig = { ...config };\n if (typeof resolved.cwd === \"string\") {\n resolved.cwd = resolvePath(resolved.cwd, suiteDir);\n }\n if (\n resolved.claudeCode &&\n typeof resolved.claudeCode === \"object\" &&\n !Array.isArray(resolved.claudeCode)\n ) {\n resolved.claudeCode = resolveClaudeCodePaths(\n resolved.claudeCode as Record<string, unknown>,\n suiteDir,\n );\n }\n return resolved;\n}\n\n/** Resolve paths on an entire suite after load. */\nexport function resolveSuitePaths(\n suite: {\n defaultConfig?: SuiteConfig;\n matrix: Array<{ config: SuiteConfig }>;\n cases: Array<{ config?: SuiteConfig }>;\n },\n suiteFilePath: string,\n): void {\n const suiteDir = configFileDir(suiteFilePath);\n\n suite.defaultConfig = resolveConfigPaths(suite.defaultConfig, suiteDir);\n for (const cell of suite.matrix) {\n cell.config = resolveConfigPaths(cell.config, suiteDir) ?? cell.config;\n }\n for (const testCase of suite.cases) {\n testCase.config = resolveConfigPaths(testCase.config, suiteDir);\n }\n}\n\n/** Parent directory of a suite or grading config file path. */\nfunction configFileDir(filePath: string): string {\n return filePath.includes(\"/\") || filePath.includes(\"\\\\\")\n ? filePath.replace(/[/\\\\][^/\\\\]+$/, \"\")\n : \".\";\n}\n\n/**\n * Heuristically resolve env var values that look like relative file paths.\n *\n * Used for grading config where credential or config paths may be expressed\n * relative to the grading YAML location.\n */\nfunction resolveEnvPaths(\n env: Record<string, string>,\n baseDir: string,\n): Record<string, string> {\n const resolved: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (\n value.startsWith(\"./\") ||\n value.startsWith(\"../\") ||\n (value.includes(\"/\") && !value.startsWith(\"http\"))\n ) {\n resolved[key] = resolvePath(value, baseDir);\n } else {\n resolved[key] = value;\n }\n }\n return resolved;\n}\n\n/** Resolve relative paths in a standalone grading config file. */\nexport function resolveGradingConfigPaths(\n config: { judge: SuiteConfig & { maxConcurrent?: number; adapter?: string } },\n configFilePath: string,\n): void {\n const baseDir = configFileDir(configFilePath);\n const { adapter, maxConcurrent, ...rest } = config.judge;\n const resolved = resolveConfigPaths(rest, baseDir) ?? rest;\n config.judge = {\n ...resolved,\n adapter,\n maxConcurrent,\n };\n if (config.judge.env) {\n config.judge.env = resolveEnvPaths(config.judge.env, baseDir);\n }\n}\n","/**\n * zod schemas for the YAML on-disk shape.\n *\n * Config uses a nested layout: generic harness fields at the top level,\n * adapter-specific options under a named key (e.g. `claudeCode`). Validated\n * raw shapes are transformed into runtime types by `src/config/transform.ts`.\n */\n\nimport { z } from \"zod\";\n\n/** Claude Code adapter-specific options (nested under `claudeCode`). */\nexport const ClaudeCodeConfigSchema = z\n .object({\n binary: z.string(),\n pluginDirs: z.array(z.string()),\n mcpConfig: z.string(),\n permissionMode: z.enum([\n \"default\",\n \"acceptEdits\",\n \"plan\",\n \"auto\",\n \"dontAsk\",\n \"bypassPermissions\",\n ]),\n effort: z.enum([\"low\", \"medium\", \"high\", \"xhigh\", \"max\"]),\n pluginUrls: z.array(z.string()),\n addDirs: z.array(z.string()),\n strictMcpConfig: z.boolean(),\n agent: z.string(),\n fallbackModel: z.string(),\n tools: z.string(),\n maxBudgetUsd: z.number().positive(),\n settings: z.string(),\n settingSources: z.string(),\n systemPrompt: z.string(),\n systemPromptFile: z.string(),\n appendSystemPrompt: z.string(),\n appendSystemPromptFile: z.string(),\n debug: z.union([z.string(), z.boolean()]),\n debugFile: z.string(),\n includeHookEvents: z.boolean(),\n noSessionPersistence: z.boolean(),\n disableSlashCommands: z.boolean(),\n bare: z.boolean(),\n safeMode: z.boolean(),\n allowDangerouslySkipPermissions: z.boolean(),\n dangerouslySkipPermissions: z.boolean(),\n allowedTools: z.array(z.string()),\n disallowedTools: z.array(z.string()),\n maxTurns: z.number().int().positive(),\n isolateConfig: z.boolean(),\n })\n .partial();\n\n/** Generic + nested adapter config for one layer (defaultConfig, case, cell). */\nexport const ConfigPartialSchema = z\n .object({\n model: z.string(),\n cwd: z.string(),\n timeoutMs: z.number().int().positive(),\n env: z.record(z.string(), z.string()),\n claudeCode: ClaudeCodeConfigSchema,\n })\n .partial();\n\n/** A matrix cell — one point in the configuration matrix. */\nexport const MatrixCellSchema = z.object({\n label: z.string().min(1),\n config: ConfigPartialSchema,\n axes: z.record(z.string(), z.string()).optional(),\n});\n\n/** Reference tool call in suite YAML. */\nexport const ReferenceToolCallSchema = z.object({\n tool_name: z.string().min(1),\n tool_input: z.unknown(),\n});\n\n/** Reference trajectory in suite YAML — array of steps or object with mode + steps. */\nexport const ReferenceTrajectorySchema = z.union([\n z.array(ReferenceToolCallSchema),\n z.object({\n tool_name_mode: z.enum([\"harness\", \"bare\"]).optional(),\n steps: z.array(ReferenceToolCallSchema).min(1),\n }),\n]);\n\n/** A test case. */\nexport const TestCaseSchema = z.object({\n id: z.string().min(1),\n prompt: z.string().min(1),\n category: z.string().optional(),\n notes: z.string().optional(),\n expectations: z.array(z.string().min(1)).optional(),\n reference_trajectory: ReferenceTrajectorySchema.optional(),\n human_ratings: z.record(z.string(), z.number()).optional(),\n assertions: z.array(z.unknown()).min(1),\n repetitions: z.number().int().positive().optional(),\n config: ConfigPartialSchema.optional(),\n});\n\n/** Top-level suite shape. */\nexport const TestSuiteSchema = z.object({\n adapter: z.string().optional(),\n defaultConfig: ConfigPartialSchema.optional(),\n matrix: z.array(MatrixCellSchema).min(1),\n cases: z.array(TestCaseSchema).min(1),\n});\n\n/** Directory suite root (suite.yaml) — cases may live under cases/ as separate YAML files. */\nexport const SuiteDirectorySchema = z.object({\n adapter: z.string().optional(),\n defaultConfig: ConfigPartialSchema.optional(),\n matrix: z.array(MatrixCellSchema).min(1),\n cases: z.array(TestCaseSchema).optional(),\n});\n\nexport type RawTestSuite = z.infer<typeof TestSuiteSchema>;\n/** Raw shape of a directory suite root (`suite.yaml` with optional inline cases). */\nexport type RawSuiteDirectory = z.infer<typeof SuiteDirectorySchema>;\n/** Raw shape of one test case before assertion transformation. */\nexport type RawTestCase = z.infer<typeof TestCaseSchema>;\n/** Raw shape of one matrix cell before path resolution. */\nexport type RawMatrixCell = z.infer<typeof MatrixCellSchema>;\n","/**\n * Transform YAML-shape assertions into runtime tagged-union assertions.\n *\n * Why a hand-written transformer rather than zod? The YAML shape is single-key objects (`called: \"foo\"`) and the runtime\n * shape is a tagged union (`{ type: \"called\", tool: \"foo\" }`). zod CAN\n * express this via `z.union` with one member per assertion type, but the\n * error messages devolve into \"expected one of 19 alternatives, none\n * matched\" with no indication of which one the user was trying to write.\n * Hand-written transformers per-assertion give targeted errors like\n * `at cases[2].assertions[1].called: 'tool' field missing`.\n *\n * Shortcut policy: for ergonomics, four assertions accept a bare scalar in place of an\n * object: `called`, `not_called`, `response_contains`, and\n * `responded_without_tool_calls`. Everything else requires the verbose\n * object form. This keeps the transformer small without giving up the\n * 90% of YAML readability.\n */\n\nimport type {\n Assertion,\n Predicate,\n ThresholdedAssertion,\n ToolPattern,\n} from \"../types/assertions\";\nimport { parseCardinality } from \"../assertions/cardinality\";\nimport type { MatrixCell, TestCase, TestSuite } from \"../runner/types\";\nimport type { ReferenceTrajectoryConfig } from \"../types/eval-interchange\";\nimport type { RawMatrixCell, RawTestCase, RawTestSuite, RawSuiteDirectory } from \"./schema\";\n\n// error type\n\n/**\n * Thrown when a YAML suite fails to validate or transform. Carries a JSON-path-\n * like trail so users can find the offending node in their config quickly.\n */\nexport class ConfigError extends Error {\n constructor(\n message: string,\n public readonly path?: string,\n ) {\n super(path ? `[${path}] ${message}` : message);\n this.name = \"ConfigError\";\n }\n}\n\n// suite-level transformer\n\n/** Transform a zod-validated raw suite into the runtime `TestSuite` shape. */\nexport function transformSuite(raw: RawTestSuite): TestSuite {\n return transformSuiteParts(raw);\n}\n\n/** Transform a directory `suite.yaml` (cases optional) into runtime shape. */\nexport function transformSuiteDirectory(raw: RawSuiteDirectory): TestSuite {\n return transformSuiteParts({\n ...raw,\n cases: raw.cases ?? [],\n });\n}\n\n/** Transform parsed case files into runtime test cases. */\nexport function transformTestCases(\n raw: RawTestCase[],\n pathPrefix: string,\n): TestCase[] {\n return raw.map((c, i) => transformTestCase(c, `${pathPrefix}[${i}]`));\n}\n\n/** Merge suite-level parts shared by single-file and directory transforms. */\nfunction transformSuiteParts(raw: RawTestSuite): TestSuite {\n return {\n adapter: raw.adapter,\n defaultConfig: raw.defaultConfig,\n matrix: raw.matrix.map(transformMatrixCell),\n cases: raw.cases.map((c, i) => transformTestCase(c, `cases[${i}]`)),\n };\n}\n\n/**\n * Normalize reference trajectory YAML into {@link ReferenceTrajectoryConfig}.\n *\n * Accepts a bare step array or `{ tool_name_mode?, steps }` object form.\n */\nfunction normalizeReferenceTrajectory(\n raw: RawTestCase[\"reference_trajectory\"],\n path: string,\n): ReferenceTrajectoryConfig | undefined {\n if (raw === undefined) return undefined;\n\n if (Array.isArray(raw)) {\n return { steps: raw };\n }\n\n if (!isPlainObject(raw) || !Array.isArray(raw.steps)) {\n throw new ConfigError(\n \"reference_trajectory must be an array of tool calls or { tool_name_mode?, steps: [...] }\",\n path,\n );\n }\n\n return {\n tool_name_mode: raw.tool_name_mode,\n steps: raw.steps,\n };\n}\n\n/** Map raw matrix cell YAML to runtime {@link MatrixCell}. */\nfunction transformMatrixCell(raw: RawMatrixCell): MatrixCell {\n return {\n label: raw.label,\n config: raw.config,\n axes: raw.axes,\n };\n}\n\n/** Map one raw test case to runtime {@link TestCase}, transforming assertions. */\nfunction transformTestCase(raw: RawTestCase, path: string): TestCase {\n return {\n id: raw.id,\n prompt: raw.prompt,\n category: raw.category,\n notes: raw.notes,\n expectations: raw.expectations,\n reference_trajectory: normalizeReferenceTrajectory(\n raw.reference_trajectory,\n `${path}.reference_trajectory`,\n ),\n human_ratings: raw.human_ratings,\n repetitions: raw.repetitions,\n config: raw.config,\n assertions: raw.assertions.map((a, i) =>\n transformThresholdedAssertion(a, `${path}.assertions[${i}]`),\n ),\n };\n}\n\n// thresholded assertion\n\n/** Keys that may appear alongside an assertion-type key. Not assertion types themselves. */\nconst SIBLING_KEYS = new Set([\"threshold\"]);\n\n/**\n * Parse optional `threshold` sibling and delegate the assertion body to\n * {@link transformAssertion}.\n *\n * @throws {ConfigError} When the wrapper is not an object, threshold is out of\n * `[0, 1]`, or the nested assertion fails validation.\n *\n * @example\n * transformThresholdedAssertion({ called: \"Read\", threshold: 0.9 }, \"path\")\n * // → { assertion: { type: \"called\", tool: \"Read\" }, threshold: 0.9 }\n */\nfunction transformThresholdedAssertion(\n raw: unknown,\n path: string,\n): ThresholdedAssertion {\n if (!isPlainObject(raw)) {\n throw new ConfigError(`expected object, got ${typeOf(raw)}`, path);\n }\n\n const threshold = raw.threshold;\n if (threshold !== undefined) {\n if (typeof threshold !== \"number\" || threshold < 0 || threshold > 1) {\n throw new ConfigError(\n `threshold must be a number in [0, 1], got ${JSON.stringify(threshold)}`,\n `${path}.threshold`,\n );\n }\n }\n\n return {\n assertion: transformAssertion(raw, path),\n threshold: typeof threshold === \"number\" ? threshold : undefined,\n };\n}\n\n// assertion transformer (the bulk)\n\n/**\n * Transform one assertion from YAML shape to runtime shape.\n *\n * Finds the single non-sibling key, dispatches to the per-type transformer.\n * Per-type transformers handle both verbose-object and shortcut-scalar input\n * shapes where applicable.\n *\n * @param raw - Single assertion object from parsed YAML (may include `threshold` sibling).\n * @param path - JSON-path-like location for error messages (e.g. `cases[0].assertions[1]`).\n * @returns Runtime {@link Assertion} tagged union.\n * @throws {ConfigError} When the object has no assertion key, multiple type keys, or an unknown type.\n *\n * @example\n * transformAssertion({ called: \"Read\" }, \"cases[0].assertions[0]\")\n * // → { type: \"called\", tool: \"Read\" }\n *\n * @example\n * transformAssertion({ called: { tool: \"Read\", times: \">= 2\" } }, \"path\")\n * // → { type: \"called\", tool: \"Read\", times: \">= 2\" }\n */\nexport function transformAssertion(raw: unknown, path: string): Assertion {\n if (!isPlainObject(raw)) {\n throw new ConfigError(`expected object, got ${typeOf(raw)}`, path);\n }\n\n const typeKeys = Object.keys(raw).filter((k) => !SIBLING_KEYS.has(k));\n if (typeKeys.length === 0) {\n throw new ConfigError(\n `no assertion type key found (got only sibling keys: ${Object.keys(raw).join(\", \")})`,\n path,\n );\n }\n if (typeKeys.length > 1) {\n throw new ConfigError(\n `multiple assertion type keys; pick one: ${typeKeys.join(\", \")}`,\n path,\n );\n }\n\n const typeKey = typeKeys[0];\n const value = raw[typeKey];\n const valuePath = `${path}.${typeKey}`;\n\n switch (typeKey) {\n case \"called\":\n return transformCalled(value, valuePath);\n case \"not_called\":\n return transformNotCalled(value, valuePath);\n case \"called_any_of\":\n return transformCalledAnyOf(value, valuePath);\n case \"called_all_of\":\n return transformCalledAllOf(value, valuePath);\n\n case \"called_before\":\n return transformCalledBefore(value, valuePath);\n case \"sequence\":\n return transformSequence(value, valuePath);\n\n case \"called_with\":\n return transformCalledWith(value, valuePath);\n\n case \"responded_without_tool_calls\":\n return transformRespondedWithoutToolCalls(value, valuePath);\n case \"iterations_within\":\n return transformScalarMax(value, valuePath, \"iterations_within\");\n case \"cost_within_usd\":\n return transformScalarMax(value, valuePath, \"cost_within_usd\");\n case \"duration_within_ms\":\n return transformScalarMax(value, valuePath, \"duration_within_ms\");\n case \"finished_with\":\n return transformFinishedWith(value, valuePath);\n\n case \"response_contains\":\n return transformResponseText(value, valuePath, \"response_contains\");\n case \"response_not_contains\":\n return transformResponseText(value, valuePath, \"response_not_contains\");\n case \"response_matches\":\n return transformResponseMatches(value, valuePath);\n\n case \"all_of\":\n return transformAllOf(value, valuePath);\n case \"any_of\":\n return transformAnyOf(value, valuePath);\n case \"not\":\n return transformNot(value, valuePath);\n\n default:\n throw new ConfigError(`unknown assertion type: ${typeKey}`, path);\n }\n}\n\n// per-assertion transformers — YAML single-key shape → runtime tagged union\n\n/**\n * Transform `called` YAML (scalar or `{tool, times?}`) to runtime assertion.\n *\n * @throws {ConfigError} When value is neither string nor object, tool is invalid,\n * or `times` is not a valid cardinality string.\n *\n * @example\n * // Scalar shortcut\n * transformCalled(\"mcp__api__search_skills\", \"path\")\n * // → { type: \"called\", tool: \"mcp__api__search_skills\" }\n *\n * @example\n * // Verbose form with cardinality\n * transformCalled({ tool: \"Read\", times: \">= 1\" }, \"path\")\n * // → { type: \"called\", tool: \"Read\", times: \">= 1\" }\n */\nfunction transformCalled(value: unknown, path: string): Assertion {\n // Scalar shortcut: bare string is the tool name.\n if (typeof value === \"string\") {\n return { type: \"called\", tool: value };\n }\n if (!isPlainObject(value)) {\n throw new ConfigError(\n `expected string or object, got ${typeOf(value)}`,\n path,\n );\n }\n const tool = requireToolPattern(value.tool, `${path}.tool`);\n let times: string | undefined;\n if (value.times !== undefined) {\n times = requireString(value.times, `${path}.times`);\n try {\n parseCardinality(times);\n } catch (err) {\n throw new ConfigError(\n err instanceof Error ? err.message : `invalid cardinality: ${times}`,\n `${path}.times`,\n );\n }\n }\n return { type: \"called\", tool, times };\n}\n\n/**\n * Transform `not_called` YAML (scalar or `{tool}`).\n *\n * @throws {ConfigError} When value is neither string nor object with a valid `tool`.\n *\n * @example\n * transformNotCalled(\"Bash\", \"path\") // → { type: \"not_called\", tool: \"Bash\" }\n */\nfunction transformNotCalled(value: unknown, path: string): Assertion {\n if (typeof value === \"string\") {\n return { type: \"not_called\", tool: value };\n }\n if (!isPlainObject(value)) {\n throw new ConfigError(\n `expected string or object, got ${typeOf(value)}`,\n path,\n );\n }\n return {\n type: \"not_called\",\n tool: requireToolPattern(value.tool, `${path}.tool`),\n };\n}\n\n/**\n * Transform `called_any_of` — bare tool list or `{tools: [...]}`.\n *\n * @throws {ConfigError} When the value is not an array or `{tools: [...]}` object.\n *\n * @example\n * transformCalledAnyOf([\"Read\", \"Glob\"], \"path\")\n * // → { type: \"called_any_of\", tools: [\"Read\", \"Glob\"] }\n */\nfunction transformCalledAnyOf(value: unknown, path: string): Assertion {\n const tools = requireToolPatternList(value, path);\n return { type: \"called_any_of\", tools };\n}\n\n/**\n * Transform `called_all_of` — bare tool list or `{tools: [...]}`.\n *\n * @throws {ConfigError} When the value is not an array or `{tools: [...]}` object.\n *\n * @example\n * transformCalledAllOf({ tools: [\"Read\", \"Grep\"] }, \"path\")\n * // → { type: \"called_all_of\", tools: [\"Read\", \"Grep\"] }\n */\nfunction transformCalledAllOf(value: unknown, path: string): Assertion {\n const tools = requireToolPatternList(value, path);\n return { type: \"called_all_of\", tools };\n}\n\n/**\n * Transform `called_before: {first, then}` ordering assertion.\n *\n * @throws {ConfigError} When value is not an object or `first`/`then` are invalid patterns.\n *\n * @example\n * transformCalledBefore({ first: \"SearchSkills\", then: \"LoadSkill\" }, \"path\")\n * // → { type: \"called_before\", first: \"SearchSkills\", then: \"LoadSkill\" }\n */\nfunction transformCalledBefore(value: unknown, path: string): Assertion {\n if (!isPlainObject(value)) {\n throw new ConfigError(\n `expected object with {first, then}, got ${typeOf(value)}`,\n path,\n );\n }\n const first = requireToolPattern(value.first, `${path}.first`);\n const then = requireToolPattern(value.then, `${path}.then`);\n return { type: \"called_before\", first, then };\n}\n\n/**\n * Transform `sequence` — tool list with optional `strict` flag.\n *\n * @throws {ConfigError} When value is neither a pattern array nor `{tools, strict?}` object.\n *\n * @example\n * // Bare array (non-strict by default)\n * transformSequence([\"Read\", \"Edit\"], \"path\")\n *\n * @example\n * // Explicit strict ordering\n * transformSequence({ tools: [\"Read\", \"Edit\"], strict: true }, \"path\")\n */\nfunction transformSequence(value: unknown, path: string): Assertion {\n // Two forms: bare list of patterns, or {tools: [...], strict?: bool}.\n if (Array.isArray(value)) {\n return {\n type: \"sequence\",\n tools: value.map((v, i) => requireToolPattern(v, `${path}[${i}]`)),\n };\n }\n if (!isPlainObject(value)) {\n throw new ConfigError(\n `expected array or object, got ${typeOf(value)}`,\n path,\n );\n }\n const tools = requireToolPatternList(value.tools, `${path}.tools`);\n const strict =\n value.strict === undefined\n ? undefined\n : requireBool(value.strict, `${path}.strict`);\n return { type: \"sequence\", tools, strict };\n}\n\n/**\n * Transform `called_with: {tool, args}` with predicate validation on args.\n *\n * @throws {ConfigError} When `tool` or `args` is missing/invalid, or `args` fails\n * {@link validatePredicate}.\n *\n * @example\n * transformCalledWith(\n * { tool: \"Read\", args: { path: { contains: \"README\" } } },\n * \"path\",\n * )\n * // → { type: \"called_with\", tool: \"Read\", args: { path: { contains: \"README\" } } }\n */\nfunction transformCalledWith(value: unknown, path: string): Assertion {\n if (!isPlainObject(value)) {\n throw new ConfigError(\n `expected object with {tool, args}, got ${typeOf(value)}`,\n path,\n );\n }\n const tool = requireToolPattern(value.tool, `${path}.tool`);\n if (value.args === undefined) {\n throw new ConfigError(`missing required field 'args'`, `${path}.args`);\n }\n validatePredicate(value.args, `${path}.args`);\n return { type: \"called_with\", tool, args: value.args as Predicate };\n}\n\n/**\n * Transform `responded_without_tool_calls` — accepts true or empty object.\n *\n * @throws {ConfigError} When value is neither `true`, null, nor an empty object.\n *\n * @example\n * transformRespondedWithoutToolCalls(true, \"path\")\n * // → { type: \"responded_without_tool_calls\" }\n */\nfunction transformRespondedWithoutToolCalls(\n value: unknown,\n path: string,\n): Assertion {\n // Accepts `true`, `{}`, or omitted (since the key being present is enough).\n if (\n value === true ||\n value === null ||\n (isPlainObject(value) && Object.keys(value).length === 0)\n ) {\n return { type: \"responded_without_tool_calls\" };\n }\n throw new ConfigError(\n `expected true or empty object, got ${JSON.stringify(value)}`,\n path,\n );\n}\n\n/**\n * Transform budget assertions (`iterations_within`, `cost_within_usd`, `duration_within_ms`).\n *\n * @throws {ConfigError} When `max` is missing, non-positive, or not a number.\n *\n * @example\n * transformScalarMax(5, \"path\", \"iterations_within\")\n * // → { type: \"iterations_within\", max: 5 }\n *\n * @example\n * transformScalarMax({ max: 2.5 }, \"path\", \"cost_within_usd\")\n * // → { type: \"cost_within_usd\", max: 2.5 }\n */\nfunction transformScalarMax(\n value: unknown,\n path: string,\n type: \"iterations_within\" | \"cost_within_usd\" | \"duration_within_ms\",\n): Assertion {\n let max: number | undefined;\n if (typeof value === \"number\") {\n max = value;\n } else if (isPlainObject(value) && typeof value.max === \"number\") {\n max = value.max;\n } else {\n throw new ConfigError(\n `expected number or {max: number}, got ${JSON.stringify(value)}`,\n path,\n );\n }\n if (max <= 0) {\n throw new ConfigError(`max must be positive, got ${max}`, path);\n }\n return { type, max };\n}\n\n/**\n * Transform `finished_with` — stop reason string, list, or `{reasons}`.\n *\n * @throws {ConfigError} When value is not a string, string array, or `{reasons}` object.\n *\n * @example\n * transformFinishedWith(\"end_turn\", \"path\")\n * // → { type: \"finished_with\", reasons: \"end_turn\" }\n */\nfunction transformFinishedWith(value: unknown, path: string): Assertion {\n // Three forms: bare string, bare array of strings, or {reasons: string | string[]}.\n if (typeof value === \"string\") {\n return { type: \"finished_with\", reasons: value };\n }\n if (Array.isArray(value)) {\n return {\n type: \"finished_with\",\n reasons: value.map((v, i) => requireString(v, `${path}[${i}]`)),\n };\n }\n if (isPlainObject(value)) {\n const reasons = value.reasons;\n if (typeof reasons === \"string\") return { type: \"finished_with\", reasons };\n if (Array.isArray(reasons)) {\n return {\n type: \"finished_with\",\n reasons: reasons.map((v, i) =>\n requireString(v, `${path}.reasons[${i}]`),\n ),\n };\n }\n }\n throw new ConfigError(\n `expected string, string[], or {reasons: ...}, got ${JSON.stringify(value)}`,\n path,\n );\n}\n\n/**\n * Transform `response_contains` / `response_not_contains` scalar or `{text}`.\n *\n * @throws {ConfigError} When value is neither a string nor `{text: string}`.\n *\n * @example\n * transformResponseText(\"done\", \"path\", \"response_contains\")\n * // → { type: \"response_contains\", text: \"done\" }\n */\nfunction transformResponseText(\n value: unknown,\n path: string,\n type: \"response_contains\" | \"response_not_contains\",\n): Assertion {\n if (typeof value === \"string\") {\n return { type, text: value };\n }\n if (isPlainObject(value) && typeof value.text === \"string\") {\n return { type, text: value.text };\n }\n throw new ConfigError(\n `expected string or {text: string}, got ${JSON.stringify(value)}`,\n path,\n );\n}\n\n/**\n * Transform `response_matches: {pattern, flags?}`.\n *\n * @throws {ConfigError} When `pattern` is missing or not a string.\n *\n * @example\n * transformResponseMatches({ pattern: \"error\\\\d+\", flags: \"i\" }, \"path\")\n * // → { type: \"response_matches\", pattern: \"error\\\\d+\", flags: \"i\" }\n */\nfunction transformResponseMatches(value: unknown, path: string): Assertion {\n if (!isPlainObject(value)) {\n throw new ConfigError(\n `expected object with {pattern, flags?}, got ${typeOf(value)}`,\n path,\n );\n }\n const pattern = requireString(value.pattern, `${path}.pattern`);\n const flags =\n value.flags === undefined\n ? undefined\n : requireString(value.flags, `${path}.flags`);\n return { type: \"response_matches\", pattern, flags };\n}\n\n/**\n * Transform compound `all_of` assertion list.\n *\n * @throws {ConfigError} When value is not an array or `{assertions: [...]}`.\n *\n * @example\n * transformAllOf([{ called: \"Read\" }, { not_called: \"Bash\" }], \"path\")\n */\nfunction transformAllOf(value: unknown, path: string): Assertion {\n return { type: \"all_of\", assertions: transformCompoundList(value, path) };\n}\n\n/**\n * Transform compound `any_of` assertion list.\n *\n * @throws {ConfigError} When value is not an array or `{assertions: [...]}`.\n *\n * @example\n * transformAnyOf({ assertions: [{ called: \"Read\" }, { called: \"Glob\" }] }, \"path\")\n */\nfunction transformAnyOf(value: unknown, path: string): Assertion {\n return { type: \"any_of\", assertions: transformCompoundList(value, path) };\n}\n\n/**\n * Transform compound `not` — single nested assertion, no threshold.\n *\n * The inner assertion uses the same single-key YAML shape as top-level\n * assertions; thresholds apply only at the outer {@link transformThresholdedAssertion} level.\n *\n * @throws {ConfigError} Propagates from nested {@link transformAssertion}.\n *\n * @example\n * transformNot({ called: \"Bash\" }, \"path\")\n * // → { type: \"not\", assertion: { type: \"called\", tool: \"Bash\" } }\n */\nfunction transformNot(value: unknown, path: string): Assertion {\n // `not` takes a single assertion as its value (not a list). The inner\n // assertion uses the same single-key shape as top-level assertions, so\n // we recurse via the main transformer. We don't pass thresholds for\n // inner assertions — those only apply at the top level.\n return { type: \"not\", assertion: transformAssertion(value, path) };\n}\n\n/**\n * Parse compound assertion list from array or `{assertions: [...]}`.\n *\n * @throws {ConfigError} When value is neither form.\n */\nfunction transformCompoundList(value: unknown, path: string): Assertion[] {\n // Two forms: bare array of assertions, or {assertions: [...]}.\n const list = Array.isArray(value)\n ? value\n : isPlainObject(value) && Array.isArray(value.assertions)\n ? value.assertions\n : null;\n\n if (list === null) {\n throw new ConfigError(\n `expected array or {assertions: [...]}, got ${JSON.stringify(value)}`,\n path,\n );\n }\n\n return list.map((a, i) => transformAssertion(a, `${path}[${i}]`));\n}\n\n// predicate validation\n\nconst LEAF_OPS = new Set([\n \"equals\",\n \"contains\",\n \"not_contains\",\n \"regex\",\n \"gte\",\n \"lte\",\n \"gt\",\n \"lt\",\n \"one_of\",\n]);\nconst COMPOUND_OPS = new Set([\"any_of\", \"all_of\", \"not\"]);\n\n/**\n * Validate that a predicate is well-formed. The runtime engine is tolerant\n * (returns false on bad shapes), but the loader is strict — invalid\n * predicates are far more often user typos than intentional patterns.\n *\n * Permitted shapes:\n * - scalar (treated as `{equals: scalar}` at runtime)\n * - single-key object whose key is a leaf op (e.g. `{contains: \"x\"}`)\n * - single-key compound (`{any_of: [...]}`, `{all_of: [...]}`, `{not: ...}`)\n * - multi-key object (descend into fields; each value is a sub-predicate)\n *\n * @throws {ConfigError} When a compound op has a non-array value or a leaf op\n * has the wrong value type (e.g. non-string `contains`).\n */\nfunction validatePredicate(raw: unknown, path: string): void {\n // Scalars are valid (interpreted as equals at runtime).\n if (!isPlainObject(raw)) return;\n\n const keys = Object.keys(raw);\n if (keys.length === 1) {\n const key = keys[0];\n\n if (LEAF_OPS.has(key)) {\n validateLeafOperator(key, raw[key], `${path}.${key}`);\n return;\n }\n\n if (COMPOUND_OPS.has(key)) {\n if (key === \"not\") {\n validatePredicate(raw[key], `${path}.not`);\n } else {\n const arr = raw[key];\n if (!Array.isArray(arr)) {\n throw new ConfigError(\n `${key} must be an array, got ${typeOf(arr)}`,\n `${path}.${key}`,\n );\n }\n arr.forEach((sub, i) => validatePredicate(sub, `${path}.${key}[${i}]`));\n }\n return;\n }\n\n // Single key but not a known op — falls through to object predicate.\n }\n\n // Multi-key object: each field is a sub-predicate.\n for (const [field, sub] of Object.entries(raw)) {\n validatePredicate(sub, `${path}.${field}`);\n }\n}\n\n/**\n * Validate a leaf predicate operator's value shape at config load time.\n *\n * @throws {ConfigError} When the operator's value has the wrong type or `regex`\n * is not a valid JavaScript regular expression.\n */\nfunction validateLeafOperator(op: string, value: unknown, path: string): void {\n switch (op) {\n case \"equals\":\n return;\n case \"contains\":\n case \"not_contains\":\n if (typeof value !== \"string\") {\n throw new ConfigError(`${op} requires a string`, path);\n }\n return;\n case \"regex\":\n if (typeof value !== \"string\") {\n throw new ConfigError(\"regex requires a string\", path);\n }\n try {\n new RegExp(value);\n } catch {\n throw new ConfigError(`invalid regex: ${value}`, path);\n }\n return;\n case \"gte\":\n case \"lte\":\n case \"gt\":\n case \"lt\":\n if (typeof value !== \"number\") {\n throw new ConfigError(`${op} requires a number`, path);\n }\n return;\n case \"one_of\":\n if (!Array.isArray(value)) {\n throw new ConfigError(\"one_of requires an array\", path);\n }\n return;\n default:\n return;\n }\n}\n\n// small validation helpers\n\n/** Require a tool pattern string or `{ pattern }` object. */\nfunction requireToolPattern(value: unknown, path: string): ToolPattern {\n if (typeof value === \"string\") return value;\n if (isPlainObject(value) && typeof value.pattern === \"string\") {\n return { pattern: value.pattern };\n }\n throw new ConfigError(\n `expected string or {pattern: string}, got ${JSON.stringify(value)}`,\n path,\n );\n}\n\n/** Require a bare tool pattern array or `{ tools: [...] }` wrapper. */\nfunction requireToolPatternList(value: unknown, path: string): ToolPattern[] {\n // Two forms: bare array, or {tools: [...]}.\n const list = Array.isArray(value)\n ? value\n : isPlainObject(value) && Array.isArray(value.tools)\n ? value.tools\n : null;\n\n if (list === null) {\n throw new ConfigError(\n `expected array of tool patterns or {tools: [...]}, got ${JSON.stringify(value)}`,\n path,\n );\n }\n\n return list.map((v, i) => requireToolPattern(v, `${path}[${i}]`));\n}\n\n/** Require a string value at `path` or throw {@link ConfigError}. */\nfunction requireString(value: unknown, path: string): string {\n if (typeof value === \"string\") return value;\n throw new ConfigError(`expected string, got ${typeOf(value)}`, path);\n}\n\n/** Require a boolean value at `path` or throw {@link ConfigError}. */\nfunction requireBool(value: unknown, path: string): boolean {\n if (typeof value === \"boolean\") return value;\n throw new ConfigError(`expected boolean, got ${typeOf(value)}`, path);\n}\n\n/** True for non-null, non-array objects (YAML mapping nodes). */\nfunction isPlainObject(x: unknown): x is Record<string, unknown> {\n return typeof x === \"object\" && x !== null && !Array.isArray(x);\n}\n\n/** Human-readable type name for config error messages. */\nfunction typeOf(x: unknown): string {\n if (x === null) return \"null\";\n if (Array.isArray(x)) return \"array\";\n return typeof x;\n}\n","/**\n * Zod schema for standalone grading YAML (`grading.yaml`).\n *\n * The top-level `judge` block reuses {@link ConfigPartialSchema} fields plus\n * grader-specific concurrency and system-instruction overrides.\n */\n\nimport { z } from \"zod\";\n\nimport { ConfigPartialSchema } from \"./schema\";\n\n/** Top-level `judge` block — mirrors harness config fields plus grader concurrency. */\nexport const JudgeConfigSchema = ConfigPartialSchema.extend({\n adapter: z.string().optional(),\n maxConcurrent: z.number().int().positive().optional(),\n /** Optional judge prompt prefix (maps to upstream system_instruction). */\n system_instruction: z.string().optional(),\n});\n\nexport const GradingConfigSchema = z.object({\n judge: JudgeConfigSchema,\n});\n\nexport type RawGradingConfig = z.infer<typeof GradingConfigSchema>;\n/** Raw shape of the nested `judge` block before path resolution. */\nexport type RawJudgeConfig = z.infer<typeof JudgeConfigSchema>;\n","/**\n * Load standalone grading YAML for `harness-eval grade`.\n *\n * Grading config defines the judge subprocess (model, concurrency, Claude Code\n * flags) separately from the suite under test.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { z } from \"zod\";\n\nimport type { SuiteConfig } from \"../adapters/types\";\nimport { resolveGradingConfigPaths } from \"./paths\";\nimport { GradingConfigSchema, type RawGradingConfig } from \"./grading-schema\";\nimport { ConfigError } from \"./transform\";\n\n/** Runtime shape of a parsed grading config file. */\nexport interface GradingConfig {\n judge: SuiteConfig & {\n adapter?: string;\n maxConcurrent?: number;\n system_instruction?: string;\n };\n}\n\n/** Load grading YAML from disk and resolve relative paths. */\nexport async function loadGradingConfig(filePath: string): Promise<GradingConfig> {\n const absolutePath = resolve(filePath);\n let content: string;\n try {\n content = await readFile(absolutePath, \"utf8\");\n } catch (err) {\n throw new ConfigError(\n `failed to read grading config: ${err instanceof Error ? err.message : String(err)}`,\n filePath,\n );\n }\n return parseGradingConfig(content, absolutePath);\n}\n\n/**\n * Parse grading YAML from a string.\n *\n * @param sourcePath Optional path for error messages and path resolution.\n */\nexport function parseGradingConfig(\n yamlContent: string,\n sourcePath?: string,\n): GradingConfig {\n let raw: unknown;\n try {\n raw = parseYaml(yamlContent);\n } catch (err) {\n throw new ConfigError(\n `YAML parse error: ${err instanceof Error ? err.message : String(err)}`,\n sourcePath,\n );\n }\n\n const validated = GradingConfigSchema.safeParse(raw);\n if (!validated.success) {\n throw new ConfigError(\n `validation failed:\\n${formatZodError(validated.error, sourcePath)}`,\n sourcePath,\n );\n }\n\n const config: GradingConfig = {\n judge: { ...validated.data.judge },\n };\n\n if (sourcePath) {\n resolveGradingConfigPaths(config, sourcePath);\n }\n\n return config;\n}\n\n/** Format a zod validation error with optional source file prefix. */\nfunction formatZodError(err: z.ZodError, sourcePath?: string): string {\n return err.issues\n .map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join(\".\") : \"(root)\";\n const prefix = sourcePath ? `${sourcePath} → ${path}` : path;\n return ` ${prefix}: ${issue.message}`;\n })\n .join(\"\\n\");\n}\n","/**\n * Load a `TestSuite` from a YAML file, directory, or string.\n *\n * Supports two on-disk layouts:\n * - Single file: `suite.yaml` with inline `cases`.\n * - Directory: `suite.yaml` plus optional `cases/*.yaml` fragments merged\n * in lexicographic path order.\n *\n * Relative paths in config (MCP config, plugin dirs, etc.) are resolved\n * against the suite file directory after load.\n */\n\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport { join, relative, resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { z } from \"zod\";\n\nimport type { TestCase, TestSuite } from \"../runner/types\";\nimport { resolveSuitePaths } from \"./paths\";\nimport {\n SuiteDirectorySchema,\n TestCaseSchema,\n TestSuiteSchema,\n type RawTestCase,\n} from \"./schema\";\nimport {\n ConfigError,\n transformSuite,\n transformSuiteDirectory,\n transformTestCases,\n} from \"./transform\";\n\nexport { ConfigError } from \"./transform\";\nexport {\n loadGradingConfig,\n parseGradingConfig,\n type GradingConfig,\n} from \"./grading-loader\";\n\n/**\n * Load a suite from a file path or directory path.\n *\n * @throws {@link ConfigError} when the path is unreadable or validation fails.\n */\nexport async function loadSuite(filePath: string): Promise<TestSuite> {\n const absolutePath = resolve(filePath);\n let info;\n try {\n info = await stat(absolutePath);\n } catch (err) {\n throw new ConfigError(\n `failed to read suite path: ${err instanceof Error ? err.message : String(err)}`,\n filePath,\n );\n }\n\n if (info.isDirectory()) {\n return loadSuiteDirectory(absolutePath);\n }\n return loadSuiteFile(absolutePath);\n}\n\n/** Load and parse a single-file suite (not a directory layout). */\nasync function loadSuiteFile(absolutePath: string): Promise<TestSuite> {\n let content: string;\n try {\n content = await readFile(absolutePath, \"utf8\");\n } catch (err) {\n throw new ConfigError(\n `failed to read suite file: ${err instanceof Error ? err.message : String(err)}`,\n absolutePath,\n );\n }\n\n return parseSuite(content, absolutePath);\n}\n\n/**\n * Load a directory suite: `suite.yaml` plus optional `cases/` YAML files.\n *\n * Cases from `suite.yaml` sort before external case files; within each file,\n * array order is preserved.\n */\nasync function loadSuiteDirectory(dir: string): Promise<TestSuite> {\n const suiteYamlPath = join(dir, \"suite.yaml\");\n let content: string;\n try {\n content = await readFile(suiteYamlPath, \"utf8\");\n } catch (err) {\n throw new ConfigError(\n `missing suite.yaml in suite directory: ${err instanceof Error ? err.message : String(err)}`,\n dir,\n );\n }\n\n const base = parseSuiteDirectory(content, suiteYamlPath);\n const casesDir = join(dir, \"cases\");\n const caseFiles = await collectCaseYamlFiles(casesDir);\n\n type TaggedCase = { relPath: string; index: number; testCase: TestCase };\n const tagged: TaggedCase[] = base.cases.map((testCase, index) => ({\n relPath: \"suite.yaml\",\n index,\n testCase,\n }));\n\n for (const filePath of caseFiles) {\n const fileContent = await readFile(filePath, \"utf8\");\n const cases = parseCasesFile(fileContent, filePath);\n const relPath = relative(casesDir, filePath);\n for (const [index, testCase] of cases.entries()) {\n tagged.push({ relPath, index, testCase });\n }\n }\n\n tagged.sort((a, b) => {\n const pathCmp = a.relPath.localeCompare(b.relPath);\n if (pathCmp !== 0) return pathCmp;\n return a.index - b.index;\n });\n\n const cases = tagged.map((entry) => entry.testCase);\n if (cases.length === 0) {\n throw new ConfigError(\"suite directory has no test cases\", dir);\n }\n\n const suite: TestSuite = { ...base, cases };\n resolveSuitePaths(suite, suiteYamlPath);\n return suite;\n}\n\n/**\n * Parse suite YAML from a string (single-file layout with inline cases).\n *\n * @param sourcePath Optional path for error messages and relative path resolution.\n */\nexport function parseSuite(\n yamlContent: string,\n sourcePath?: string,\n): TestSuite {\n let raw: unknown;\n try {\n raw = parseYaml(yamlContent);\n } catch (err) {\n throw new ConfigError(\n `YAML parse error: ${err instanceof Error ? err.message : String(err)}`,\n sourcePath,\n );\n }\n\n const validated = TestSuiteSchema.safeParse(raw);\n if (!validated.success) {\n throw new ConfigError(\n `validation failed:\\n${formatZodError(validated.error, sourcePath)}`,\n sourcePath,\n );\n }\n\n const suite = transformSuite(validated.data);\n if (sourcePath) {\n resolveSuitePaths(suite, resolve(sourcePath));\n }\n return suite;\n}\n\n/** Parse `suite.yaml` for directory layout (cases may be omitted). */\nfunction parseSuiteDirectory(\n yamlContent: string,\n sourcePath: string,\n): TestSuite {\n let raw: unknown;\n try {\n raw = parseYaml(yamlContent);\n } catch (err) {\n throw new ConfigError(\n `YAML parse error: ${err instanceof Error ? err.message : String(err)}`,\n sourcePath,\n );\n }\n\n const validated = SuiteDirectorySchema.safeParse(raw);\n if (!validated.success) {\n throw new ConfigError(\n `validation failed:\\n${formatZodError(validated.error, sourcePath)}`,\n sourcePath,\n );\n }\n\n return transformSuiteDirectory(validated.data);\n}\n\n/** Parse one case file: single case, array, or `{ cases: [...] }`. */\nexport function parseCasesFile(\n yamlContent: string,\n sourcePath?: string,\n): TestCase[] {\n let raw: unknown;\n try {\n raw = parseYaml(yamlContent);\n } catch (err) {\n throw new ConfigError(\n `YAML parse error: ${err instanceof Error ? err.message : String(err)}`,\n sourcePath,\n );\n }\n\n const rawCases = extractRawCases(raw, sourcePath);\n return transformTestCases(rawCases, sourcePath ?? \"cases\");\n}\n\n/**\n * Normalize raw YAML into a list of {@link RawTestCase} objects.\n *\n * Accepts a single case, an array, or `{ cases: [...] }`.\n */\nfunction extractRawCases(raw: unknown, sourcePath?: string): RawTestCase[] {\n if (Array.isArray(raw)) {\n return raw.map((item, index) => validateRawCase(item, sourcePath, index));\n }\n\n if (raw && typeof raw === \"object\") {\n const obj = raw as Record<string, unknown>;\n if (Array.isArray(obj.cases)) {\n return obj.cases.map((item, index) =>\n validateRawCase(item, sourcePath, index),\n );\n }\n if (\"id\" in obj && \"prompt\" in obj && \"assertions\" in obj) {\n return [validateRawCase(raw, sourcePath, 0)];\n }\n }\n\n throw new ConfigError(\n \"expected a case object, array of cases, or { cases: [...] }\",\n sourcePath,\n );\n}\n\n/** Validate one raw case object against {@link TestCaseSchema}. */\nfunction validateRawCase(\n raw: unknown,\n sourcePath: string | undefined,\n index: number,\n): RawTestCase {\n const validated = TestCaseSchema.safeParse(raw);\n if (!validated.success) {\n throw new ConfigError(\n `validation failed:\\n${formatZodError(validated.error, sourcePath)}`,\n sourcePath,\n );\n }\n\n return validated.data;\n}\n\n/**\n * Recursively collect `.yaml` / `.yml` files under `casesDir`.\n *\n * Returns an empty list when the directory does not exist — external cases\n * are optional in directory layout.\n */\nasync function collectCaseYamlFiles(casesDir: string): Promise<string[]> {\n const files: string[] = [];\n\n async function walk(dir: string): Promise<void> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (err) {\n if (\n err instanceof Error &&\n \"code\" in err &&\n (err as NodeJS.ErrnoException).code === \"ENOENT\"\n ) {\n return;\n }\n throw err;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(fullPath);\n } else if (\n entry.isFile() &&\n (entry.name.endsWith(\".yaml\") || entry.name.endsWith(\".yml\"))\n ) {\n files.push(fullPath);\n }\n }\n }\n\n await walk(casesDir);\n return files.sort();\n}\n\n/** Format a zod validation error with optional source file prefix. */\nfunction formatZodError(err: z.ZodError, sourcePath?: string): string {\n return err.issues\n .map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join(\".\") : \"(root)\";\n const prefix = sourcePath ? `${sourcePath} → ${path}` : path;\n return ` ${prefix}: ${issue.message}`;\n })\n .join(\"\\n\");\n}\n"],"mappings":"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"}