{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/core/benchmark/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,uBAAuB,GAAG,SAAS,CA2CtF;AAED,MAAM,WAAW,uBAAuB;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAqBzC;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAwG7E","sourcesContent":["/**\n * CLI handler for \"jensen benchmark\" commands.\n */\n\nimport chalk from \"chalk\";\nimport { readFileSync, writeFileSync } from \"fs\";\nimport { resolve } from \"path\";\nimport { handleLongHorizonCommand } from \"../long-horizon/cli.js\";\nimport { evaluate } from \"./evaluator.js\";\nimport { generateJsonReport, generateTextReport } from \"./report.js\";\nimport type { LongHorizonBenchmarkManifest, LongHorizonRunReport } from \"./types.js\";\n\nconst MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB\n\nexport function parseBenchmarkArgs(args: string[]): BenchmarkCommandOptions | undefined {\n\tif (args[0] !== \"benchmark\") return undefined;\n\n\tconst options: BenchmarkCommandOptions = {};\n\tlet i = 1;\n\n\twhile (i < args.length) {\n\t\tconst arg = args[i];\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\toptions.help = true;\n\t\t\ti++;\n\t\t} else if (arg === \"--manifest\" && i + 1 < args.length) {\n\t\t\toptions.manifest = args[++i];\n\t\t\ti++;\n\t\t} else if (arg === \"--run-report\" && i + 1 < args.length) {\n\t\t\toptions.runReport = args[++i];\n\t\t\ti++;\n\t\t} else if (arg === \"--format\" && i + 1 < args.length) {\n\t\t\tconst fmt = args[++i];\n\t\t\tif (fmt === \"text\" || fmt === \"json\") {\n\t\t\t\toptions.format = fmt;\n\t\t\t} else {\n\t\t\t\tconsole.error(chalk.red(`Unknown format: ${fmt}. Valid: text, json`));\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t}\n\t\t\ti++;\n\t\t} else if (arg === \"--output\" && i + 1 < args.length) {\n\t\t\toptions.output = args[++i];\n\t\t\ti++;\n\t\t} else if (arg === \"long-horizon\" || arg === \"evaluate\") {\n\t\t\t// Positional subcommands - skip\n\t\t\ti++;\n\t\t} else if (!arg.startsWith(\"-\")) {\n\t\t\t// Unknown positional arg - ignore (for future commands)\n\t\t\ti++;\n\t\t} else {\n\t\t\tconsole.error(chalk.red(`Unknown option: ${arg}`));\n\t\t\toptions.help = true;\n\t\t\ti++;\n\t\t}\n\t}\n\n\treturn options;\n}\n\nexport interface BenchmarkCommandOptions {\n\thelp?: boolean;\n\tmanifest?: string;\n\trunReport?: string;\n\tformat?: \"text\" | \"json\";\n\toutput?: string;\n}\n\nexport function printBenchmarkHelp(): void {\n\tconsole.log(`${chalk.bold(\"Usage:\")} jensen benchmark long-horizon evaluate [options]\n\n${chalk.bold(\"Evaluate a long-horizon benchmark run report against a task manifest.\")}\n\n${chalk.bold(\"Options:\")}\n  --manifest <path>        Path to benchmark task manifest JSON\n  --run-report <path>      Path to run report JSON\n  --format <text|json>     Output format (default: text)\n  --output <path>          Write output to file instead of stdout\n  --help, -h               Show this help\n\n${chalk.bold(\"Examples:\")}\n  jensen benchmark long-horizon evaluate --manifest manifest.json --run-report run.json\n  jensen benchmark long-horizon evaluate --manifest manifest.json --run-report run.json --format json\n  jensen benchmark long-horizon evaluate --manifest manifest.json --run-report run.json --output result.txt\n\n${chalk.bold(\"Exit Codes:\")}\n  0   Evaluation completed (benchmark pass/fail in output)\n  1   Invalid input or evaluation error\n`);\n}\n\nexport async function handleBenchmarkCommand(args: string[]): Promise<boolean> {\n\t// Try long-horizon mission/ledger commands first\n\tconst lhResult = await handleLongHorizonCommand(args);\n\tif (lhResult) return true;\n\n\tconst options = parseBenchmarkArgs(args);\n\tif (!options) return false;\n\n\tif (options.help) {\n\t\tprintBenchmarkHelp();\n\t\treturn true;\n\t}\n\n\t// Validate required args\n\tif (!options.manifest) {\n\t\tconsole.error(chalk.red(\"Error: --manifest is required\"));\n\t\tprintBenchmarkHelp();\n\t\tprocess.exitCode = 1;\n\t\treturn true;\n\t}\n\tif (!options.runReport) {\n\t\tconsole.error(chalk.red(\"Error: --run-report is required\"));\n\t\tprintBenchmarkHelp();\n\t\tprocess.exitCode = 1;\n\t\treturn true;\n\t}\n\n\tconst format = options.format ?? \"text\";\n\n\t// Read and parse manifest\n\tlet manifest: LongHorizonBenchmarkManifest;\n\ttry {\n\t\tconst raw = readFileSync(options.manifest, \"utf-8\");\n\t\tif (Buffer.byteLength(raw, \"utf-8\") > MAX_FILE_SIZE) {\n\t\t\tconsole.error(chalk.red(\"Error: manifest file exceeds 10MB limit\"));\n\t\t\tprocess.exitCode = 1;\n\t\t\treturn true;\n\t\t}\n\t\tmanifest = JSON.parse(raw);\n\t} catch (err: unknown) {\n\t\tconst message = err instanceof Error ? err.message : \"Unknown error\";\n\t\tconsole.error(chalk.red(`Error reading manifest: ${message}`));\n\t\tprocess.exitCode = 1;\n\t\treturn true;\n\t}\n\n\t// Read and parse run report\n\tlet runReport: LongHorizonRunReport;\n\ttry {\n\t\tconst raw = readFileSync(options.runReport, \"utf-8\");\n\t\tif (Buffer.byteLength(raw, \"utf-8\") > MAX_FILE_SIZE) {\n\t\t\tconsole.error(chalk.red(\"Error: run report file exceeds 10MB limit\"));\n\t\t\tprocess.exitCode = 1;\n\t\t\treturn true;\n\t\t}\n\t\trunReport = JSON.parse(raw);\n\t} catch (err: unknown) {\n\t\tconst message = err instanceof Error ? err.message : \"Unknown error\";\n\t\tconsole.error(chalk.red(`Error reading run report: ${message}`));\n\t\tprocess.exitCode = 1;\n\t\treturn true;\n\t}\n\n\t// Evaluate\n\tconst result = evaluate(manifest, runReport);\n\n\t// Schema validation failure: evaluation could not validly execute.\n\t// The structured report is still emitted, but the process must exit 1.\n\tif (!result.schemaValidation.valid) {\n\t\tprocess.exitCode = 1;\n\t}\n\n\t// Generate output\n\tlet output: string;\n\tif (format === \"json\") {\n\t\toutput = generateJsonReport(result);\n\t} else {\n\t\toutput = generateTextReport(result);\n\t}\n\n\t// Write output\n\tif (options.output) {\n\t\tconst outputPath = resolve(options.output);\n\t\t// Path traversal check\n\t\tif (outputPath.includes(\"..\")) {\n\t\t\tconsole.error(chalk.red(\"Error: --output path must not contain '..'\"));\n\t\t\tprocess.exitCode = 1;\n\t\t\treturn true;\n\t\t}\n\t\ttry {\n\t\t\twriteFileSync(outputPath, output, \"utf-8\");\n\t\t} catch (err: unknown) {\n\t\t\tconst message = err instanceof Error ? err.message : \"Unknown error\";\n\t\t\tconsole.error(chalk.red(`Error writing output: ${message}`));\n\t\t\tprocess.exitCode = 1;\n\t\t\treturn true;\n\t\t}\n\t} else {\n\t\tconsole.log(output);\n\t}\n\n\t// Exit code: 0 for successful evaluation (pass or fail), 1 for errors\n\t// Benchmark pass/fail is in the output text\n\treturn true;\n}\n"]}