agent-inspect 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@
4
4
  var crypto = require('crypto');
5
5
  var promises = require('fs/promises');
6
6
  var os = require('os');
7
- var path23 = require('path');
7
+ var path24 = require('path');
8
8
  var async_hooks = require('async_hooks');
9
9
  var process3 = require('process');
10
10
  var tty = require('tty');
@@ -20,7 +20,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
20
20
 
21
21
  var crypto__default = /*#__PURE__*/_interopDefault(crypto);
22
22
  var os__default = /*#__PURE__*/_interopDefault(os);
23
- var path23__default = /*#__PURE__*/_interopDefault(path23);
23
+ var path24__default = /*#__PURE__*/_interopDefault(path24);
24
24
  var process3__default = /*#__PURE__*/_interopDefault(process3);
25
25
  var tty__default = /*#__PURE__*/_interopDefault(tty);
26
26
 
@@ -893,7 +893,7 @@ function getDefaultTraceDir() {
893
893
  if (typeof home !== "string" || home.trim() === "") {
894
894
  return FALLBACK_TRACE_DIR;
895
895
  }
896
- return path23__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
896
+ return path24__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
897
897
  } catch {
898
898
  return FALLBACK_TRACE_DIR;
899
899
  }
@@ -901,11 +901,11 @@ function getDefaultTraceDir() {
901
901
  function getTraceFilePath(runId, traceDir) {
902
902
  const baseDir = traceDir ?? getDefaultTraceDir();
903
903
  let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
904
- safeId = path23__default.default.basename(safeId);
904
+ safeId = path24__default.default.basename(safeId);
905
905
  if (safeId === "" || safeId === "." || safeId === "..") {
906
906
  safeId = "run_unknown";
907
907
  }
908
- return path23__default.default.join(baseDir, `${safeId}.jsonl`);
908
+ return path24__default.default.join(baseDir, `${safeId}.jsonl`);
909
909
  }
910
910
  function formatError(error) {
911
911
  if (error instanceof Error) {
@@ -962,7 +962,7 @@ var init_utils = __esm({
962
962
  init_duration();
963
963
  DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
964
964
  RUNS_DIR_NAME = "runs";
965
- FALLBACK_TRACE_DIR = path23__default.default.join(
965
+ FALLBACK_TRACE_DIR = path24__default.default.join(
966
966
  os__default.default.tmpdir(),
967
967
  "agent-inspect",
968
968
  RUNS_DIR_NAME
@@ -1928,7 +1928,7 @@ var init_trace_directory = __esm({
1928
1928
  this.#dir = resolveTraceDir(options);
1929
1929
  }
1930
1930
  getPath(filename) {
1931
- return filename ? path23__default.default.join(this.#dir, filename) : this.#dir;
1931
+ return filename ? path24__default.default.join(this.#dir, filename) : this.#dir;
1932
1932
  }
1933
1933
  async list() {
1934
1934
  try {
@@ -1957,7 +1957,7 @@ function parseIsoToMs2(value) {
1957
1957
  }
1958
1958
  async function extractMetadata(filePath, _quickScan) {
1959
1959
  const stats = await promises.stat(filePath);
1960
- let runIdFromFile = path23__default.default.basename(filePath);
1960
+ let runIdFromFile = path24__default.default.basename(filePath);
1961
1961
  if (runIdFromFile.endsWith(".jsonl")) {
1962
1962
  runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
1963
1963
  }
@@ -2942,9 +2942,9 @@ async function searchTraces(metas, options) {
2942
2942
  }
2943
2943
  const limit = options.limit ?? 50;
2944
2944
  const sessionId = options.session?.trim();
2945
- const observationStatus = parseObservationFilter(options.observation);
2945
+ const observationStatus2 = parseObservationFilter(options.observation);
2946
2946
  const hasContentFilter = Boolean(
2947
- options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter || observationStatus
2947
+ options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter || observationStatus2
2948
2948
  );
2949
2949
  const results = [];
2950
2950
  const sessionLabel = sessionId && sessionId !== "" ? sessionId : void 0;
@@ -2989,9 +2989,9 @@ async function searchTraces(metas, options) {
2989
2989
  statusFilter: options.status
2990
2990
  });
2991
2991
  results.push(...stepMatches);
2992
- if (observationStatus) {
2992
+ if (observationStatus2) {
2993
2993
  const outcomes = extractOutcomesFromTraceEvents(events);
2994
- const matched = outcomes.filter((outcome) => outcome.status === observationStatus);
2994
+ const matched = outcomes.filter((outcome) => outcome.status === observationStatus2);
2995
2995
  for (const outcome of matched) {
2996
2996
  results.push({
2997
2997
  runId: m.runId,
@@ -3786,12 +3786,12 @@ function buildCriticalPath(runs, handoffs) {
3786
3786
  handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
3787
3787
  );
3788
3788
  const ordered = [...runs].sort(compareRuns);
3789
- const path31 = [];
3789
+ const path33 = [];
3790
3790
  const visited = /* @__PURE__ */ new Set();
3791
3791
  const pushRun = (run, confidence, source) => {
3792
3792
  if (visited.has(run.runId)) return;
3793
3793
  visited.add(run.runId);
3794
- path31.push({
3794
+ path33.push({
3795
3795
  runId: run.runId,
3796
3796
  name: run.name,
3797
3797
  startedAt: run.startedAt,
@@ -3816,7 +3816,7 @@ function buildCriticalPath(runs, handoffs) {
3816
3816
  const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
3817
3817
  pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
3818
3818
  }
3819
- return path31;
3819
+ return path33;
3820
3820
  }
3821
3821
  function metaRunIdMatches(run, token, runById) {
3822
3822
  const meta2 = extractSessionWorkflowMetadata(run.metadata);
@@ -4147,7 +4147,7 @@ function normalizeBundleOutputPath(out) {
4147
4147
  if (trimmed === "") {
4148
4148
  throw new Error("--out requires a non-empty path.");
4149
4149
  }
4150
- const resolved = path23__default.default.resolve(trimmed);
4150
+ const resolved = path24__default.default.resolve(trimmed);
4151
4151
  if (resolved.toLowerCase().endsWith(".zip")) {
4152
4152
  return resolved.slice(0, -4);
4153
4153
  }
@@ -4156,7 +4156,7 @@ function normalizeBundleOutputPath(out) {
4156
4156
  function defaultBundleOutputPath(runIds) {
4157
4157
  const label = runIds.length === 1 ? runIds[0] : `multi-${runIds.length}`;
4158
4158
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4159
- return path23__default.default.resolve(`agent-inspect-bundle-${label}-${stamp}`);
4159
+ return path24__default.default.resolve(`agent-inspect-bundle-${label}-${stamp}`);
4160
4160
  }
4161
4161
  var init_paths = __esm({
4162
4162
  "packages/core/src/bundle/paths.ts"() {
@@ -4330,7 +4330,7 @@ function normalizeSuiteConfig(value) {
4330
4330
  }
4331
4331
  async function validateSuiteConfig(config, options) {
4332
4332
  const diagnostics = [];
4333
- const tracesDir = path23__default.default.resolve(options.configDir, config.traces);
4333
+ const tracesDir = path24__default.default.resolve(options.configDir, config.traces);
4334
4334
  try {
4335
4335
  await promises.access(tracesDir);
4336
4336
  } catch {
@@ -4340,7 +4340,7 @@ async function validateSuiteConfig(config, options) {
4340
4340
  }
4341
4341
  for (const suiteCase of config.cases) {
4342
4342
  if (suiteCase.input !== void 0) {
4343
- const inputPath = path23__default.default.resolve(options.configDir, suiteCase.input);
4343
+ const inputPath = path24__default.default.resolve(options.configDir, suiteCase.input);
4344
4344
  try {
4345
4345
  await promises.access(inputPath);
4346
4346
  } catch {
@@ -4373,12 +4373,12 @@ async function fileExists(filePath) {
4373
4373
  }
4374
4374
  }
4375
4375
  async function resolveSuiteConfigPath(options = {}) {
4376
- const cwd = path23__default.default.resolve(options.cwd ?? process.cwd());
4376
+ const cwd = path24__default.default.resolve(options.cwd ?? process.cwd());
4377
4377
  if (options.configPath !== void 0 && options.configPath.trim() !== "") {
4378
- return path23__default.default.resolve(cwd, options.configPath.trim());
4378
+ return path24__default.default.resolve(cwd, options.configPath.trim());
4379
4379
  }
4380
4380
  for (const name of DEFAULT_SUITE_CONFIG_NAMES) {
4381
- const candidate = path23__default.default.join(cwd, name);
4381
+ const candidate = path24__default.default.join(cwd, name);
4382
4382
  if (await fileExists(candidate)) return candidate;
4383
4383
  }
4384
4384
  throw new Error(
@@ -4395,7 +4395,7 @@ async function loadSuiteConfig(options = {}) {
4395
4395
  diagnostics: [diagnostic2("AI_SUITE_CONFIG_LOAD_FAILED", message)]
4396
4396
  });
4397
4397
  }
4398
- const extension = path23__default.default.extname(configPath);
4398
+ const extension = path24__default.default.extname(configPath);
4399
4399
  if (TS_CONFIG_EXTENSIONS.has(extension)) {
4400
4400
  const message = "TypeScript suite configs require an explicit precompiled JavaScript config or future --config-loader support.";
4401
4401
  throw Object.assign(new Error(message), {
@@ -4420,7 +4420,7 @@ async function loadSuiteConfig(options = {}) {
4420
4420
  return {
4421
4421
  config,
4422
4422
  configPath,
4423
- configDir: path23__default.default.dirname(configPath)
4423
+ configDir: path24__default.default.dirname(configPath)
4424
4424
  };
4425
4425
  } catch (error) {
4426
4426
  const message = error instanceof Error ? error.message : String(error);
@@ -4470,7 +4470,7 @@ async function exists(filePath) {
4470
4470
  }
4471
4471
  async function resolveSuiteCaseTrace(suiteCase, options) {
4472
4472
  if (suiteCase.trace !== void 0) {
4473
- const tracePath = path23__default.default.resolve(options.configDir, suiteCase.trace);
4473
+ const tracePath = path24__default.default.resolve(options.configDir, suiteCase.trace);
4474
4474
  if (await exists(tracePath)) {
4475
4475
  return { caseId: suiteCase.id, tracePath, missing: false };
4476
4476
  }
@@ -4486,7 +4486,7 @@ async function resolveSuiteCaseTrace(suiteCase, options) {
4486
4486
  if (await exists(directPath)) {
4487
4487
  return { caseId: suiteCase.id, tracePath: directPath, runId: runKey, missing: false };
4488
4488
  }
4489
- const nestedPath = path23__default.default.join(options.tracesDir, `${path23__default.default.basename(runKey)}.jsonl`);
4489
+ const nestedPath = path24__default.default.join(options.tracesDir, `${path24__default.default.basename(runKey)}.jsonl`);
4490
4490
  if (await exists(nestedPath)) {
4491
4491
  return { caseId: suiteCase.id, tracePath: nestedPath, runId: runKey, missing: false };
4492
4492
  }
@@ -4716,7 +4716,7 @@ function stripPrefix(name, prefixes) {
4716
4716
  }
4717
4717
  return name;
4718
4718
  }
4719
- function eventEvidence(event, path31) {
4719
+ function eventEvidence(event, path33) {
4720
4720
  return {
4721
4721
  runId: event.runId,
4722
4722
  eventId: event.eventId,
@@ -4726,7 +4726,7 @@ function eventEvidence(event, path31) {
4726
4726
  kind: event.kind,
4727
4727
  name: event.name,
4728
4728
  status: event.status,
4729
- ...path31 ? { path: path31 } : {}
4729
+ ...path33 ? { path: path33 } : {}
4730
4730
  };
4731
4731
  }
4732
4732
  function runEvidence(run) {
@@ -4789,9 +4789,9 @@ function eventEndMs(event) {
4789
4789
  function normalizedKey(value) {
4790
4790
  return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
4791
4791
  }
4792
- function lastPathSegment(path31) {
4793
- const parts = path31.split(".");
4794
- return parts[parts.length - 1] ?? path31;
4792
+ function lastPathSegment(path33) {
4793
+ const parts = path33.split(".");
4794
+ return parts[parts.length - 1] ?? path33;
4795
4795
  }
4796
4796
  function valueType(value) {
4797
4797
  if (Array.isArray(value)) return "array";
@@ -4805,12 +4805,12 @@ function serializedByteLength(value) {
4805
4805
  return void 0;
4806
4806
  }
4807
4807
  }
4808
- function pushValueEntries(entries, event, value, path31, key, depth = 0) {
4809
- entries.push({ event, path: path31, key, value });
4808
+ function pushValueEntries(entries, event, value, path33, key, depth = 0) {
4809
+ entries.push({ event, path: path33, key, value });
4810
4810
  if (depth >= 8) return;
4811
4811
  if (Array.isArray(value)) {
4812
4812
  for (const [index, item] of value.entries()) {
4813
- pushValueEntries(entries, event, item, `${path31}.${index}`, String(index), depth + 1);
4813
+ pushValueEntries(entries, event, item, `${path33}.${index}`, String(index), depth + 1);
4814
4814
  }
4815
4815
  return;
4816
4816
  }
@@ -4820,7 +4820,7 @@ function pushValueEntries(entries, event, value, path31, key, depth = 0) {
4820
4820
  entries,
4821
4821
  event,
4822
4822
  value[nestedKey],
4823
- `${path31}.${nestedKey}`,
4823
+ `${path33}.${nestedKey}`,
4824
4824
  nestedKey,
4825
4825
  depth + 1
4826
4826
  );
@@ -4901,9 +4901,9 @@ function eventDurationMs(event) {
4901
4901
  }
4902
4902
  function treeShape(nodes) {
4903
4903
  const lines = [];
4904
- const visit = (node, path31) => {
4905
- lines.push(`${path31}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
4906
- node.children.forEach((child, index) => visit(child, `${path31}.${index}`));
4904
+ const visit = (node, path33) => {
4905
+ lines.push(`${path33}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
4906
+ node.children.forEach((child, index) => visit(child, `${path33}.${index}`));
4907
4907
  };
4908
4908
  nodes.forEach((node, index) => visit(node, String(index)));
4909
4909
  return lines;
@@ -4952,9 +4952,9 @@ function retrievalShape(context) {
4952
4952
  function guardrailShape(context) {
4953
4953
  return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
4954
4954
  }
4955
- function firstEvidenceForKind(context, kind, path31) {
4955
+ function firstEvidenceForKind(context, kind, path33) {
4956
4956
  const event = context.events.find((candidate) => candidate.kind === kind);
4957
- return event ? [eventEvidence(event, path31)] : runEvidence(context.selectedRun);
4957
+ return event ? [eventEvidence(event, path33)] : runEvidence(context.selectedRun);
4958
4958
  }
4959
4959
  function baselineDiffFinding(message, evidence, expected, actual) {
4960
4960
  return failFinding("baseline.regression", message, evidence, expected, actual);
@@ -5304,13 +5304,13 @@ function createStructureCycleRule() {
5304
5304
  const seenCycles = /* @__PURE__ */ new Set();
5305
5305
  const findings = [];
5306
5306
  for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
5307
- const path31 = [];
5307
+ const path33 = [];
5308
5308
  const seenAt = /* @__PURE__ */ new Map();
5309
5309
  let current = event;
5310
5310
  while (current) {
5311
5311
  const existing = seenAt.get(current.eventId);
5312
5312
  if (existing !== void 0) {
5313
- const cycle = path31.slice(existing);
5313
+ const cycle = path33.slice(existing);
5314
5314
  const key = cycle.map((item) => item.eventId).sort().join("\0");
5315
5315
  if (!seenCycles.has(key)) {
5316
5316
  seenCycles.add(key);
@@ -5326,8 +5326,8 @@ function createStructureCycleRule() {
5326
5326
  }
5327
5327
  break;
5328
5328
  }
5329
- seenAt.set(current.eventId, path31.length);
5330
- path31.push(current);
5329
+ seenAt.set(current.eventId, path33.length);
5330
+ path33.push(current);
5331
5331
  current = current.parentId ? byId.get(current.parentId) : void 0;
5332
5332
  }
5333
5333
  }
@@ -6468,7 +6468,7 @@ function findReaderByFormat(format, readers) {
6468
6468
  }
6469
6469
  async function jsonlFilesInDirectory(dirPath) {
6470
6470
  const entries = await promises.readdir(dirPath, { withFileTypes: true });
6471
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path23__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
6471
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path24__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
6472
6472
  }
6473
6473
  async function resolveInput(input3) {
6474
6474
  const cached = resolvedInputCache.get(input3);
@@ -8167,7 +8167,7 @@ async function runSuiteCase(suiteCase, config, options) {
8167
8167
  async function runSuite(options = {}) {
8168
8168
  const startedAt = new Date(options.nowMs ?? Date.now()).toISOString();
8169
8169
  const { config, configPath, configDir } = await loadSuiteConfig(options);
8170
- const tracesDir = path23__default.default.resolve(configDir, config.traces);
8170
+ const tracesDir = path24__default.default.resolve(configDir, config.traces);
8171
8171
  const cases = [];
8172
8172
  const diagnostics = [];
8173
8173
  for (const suiteCase of config.cases) {
@@ -8951,6 +8951,426 @@ var init_cohort2 = __esm({
8951
8951
  }
8952
8952
  });
8953
8953
 
8954
+ // packages/core/src/gate/parse.ts
8955
+ function parseGateList(value) {
8956
+ if (value === void 0 || value.trim() === "") return [];
8957
+ return value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
8958
+ }
8959
+ var init_parse = __esm({
8960
+ "packages/core/src/gate/parse.ts"() {
8961
+ }
8962
+ });
8963
+
8964
+ // packages/core/src/gate/evaluate.ts
8965
+ function percentile3(values, p) {
8966
+ if (values.length === 0) return void 0;
8967
+ const sorted = [...values].sort((a, b) => a - b);
8968
+ const idx = Math.min(
8969
+ sorted.length - 1,
8970
+ Math.max(0, Math.ceil(p / 100 * sorted.length) - 1)
8971
+ );
8972
+ return sorted[idx];
8973
+ }
8974
+ function hasThresholds(options) {
8975
+ return options.maxErrorRate !== void 0 || options.maxP95DurationMs !== void 0 || (options.forbidTools?.length ?? 0) > 0 || (options.requireObservations?.length ?? 0) > 0;
8976
+ }
8977
+ function gateHasThresholds(options) {
8978
+ return hasThresholds(options);
8979
+ }
8980
+ async function loadRunMetrics(runs) {
8981
+ const metrics = [];
8982
+ for (const run of runs) {
8983
+ if (run.filePath === void 0) continue;
8984
+ metrics.push(
8985
+ await computeCohortRunMetrics({
8986
+ runId: run.runId,
8987
+ filePath: run.filePath,
8988
+ metadata: run.metadata,
8989
+ status: run.status,
8990
+ durationMs: run.durationMs,
8991
+ groupKey: "all"
8992
+ })
8993
+ );
8994
+ }
8995
+ return metrics;
8996
+ }
8997
+ async function observationStatus(filePath, name) {
8998
+ const events = await readTraceEventsFromFile(filePath);
8999
+ const outcomes = extractOutcomesFromTraceEvents(events);
9000
+ const match = outcomes.find((item) => item.name === name);
9001
+ if (!match) return "missing";
9002
+ return match.status === "passed" ? "passed" : "failed";
9003
+ }
9004
+ async function evaluateGateThresholds(runs, options) {
9005
+ const checks2 = [];
9006
+ const readErrors = [];
9007
+ if (!hasThresholds(options)) {
9008
+ return { checks: checks2, readErrors };
9009
+ }
9010
+ if (runs.length === 0) {
9011
+ readErrors.push("No trace runs found in the gate directory.");
9012
+ return { checks: checks2, readErrors };
9013
+ }
9014
+ let runMetrics;
9015
+ try {
9016
+ runMetrics = await loadRunMetrics(runs);
9017
+ } catch (error) {
9018
+ const message = error instanceof Error ? error.message : String(error);
9019
+ readErrors.push(message);
9020
+ return { checks: checks2, readErrors };
9021
+ }
9022
+ if (options.maxErrorRate !== void 0) {
9023
+ const errors = runMetrics.filter((run) => run.error).length;
9024
+ const actual = runMetrics.length > 0 ? errors / runMetrics.length * 100 : 0;
9025
+ const ok = actual <= options.maxErrorRate;
9026
+ checks2.push({
9027
+ id: "maxErrorRate",
9028
+ name: "Max error rate",
9029
+ ok,
9030
+ expected: options.maxErrorRate,
9031
+ actual: Math.round(actual * 10) / 10,
9032
+ message: ok ? `Error rate ${actual.toFixed(1)}% within limit ${options.maxErrorRate}%` : `Error rate ${actual.toFixed(1)}% exceeds limit ${options.maxErrorRate}%`
9033
+ });
9034
+ }
9035
+ if (options.maxP95DurationMs !== void 0) {
9036
+ const durations = runMetrics.map((run) => run.durationMs).filter((value) => typeof value === "number");
9037
+ const actual = percentile3(durations, 95);
9038
+ const ok = actual !== void 0 && actual <= options.maxP95DurationMs;
9039
+ checks2.push({
9040
+ id: "maxP95Duration",
9041
+ name: "Max p95 duration (ms)",
9042
+ ok,
9043
+ expected: options.maxP95DurationMs,
9044
+ actual: actual ?? "n/a",
9045
+ message: actual === void 0 ? "No duration samples available for p95 check." : ok ? `P95 duration ${Math.round(actual)} ms within limit ${options.maxP95DurationMs} ms` : `P95 duration ${Math.round(actual)} ms exceeds limit ${options.maxP95DurationMs} ms`
9046
+ });
9047
+ }
9048
+ for (const tool of options.forbidTools ?? []) {
9049
+ let violated = false;
9050
+ for (const run of runMetrics) {
9051
+ const used = run.toolChoices.includes(tool) || run.toolOrdering.includes(tool);
9052
+ if (used) {
9053
+ violated = true;
9054
+ checks2.push({
9055
+ id: "forbidTool",
9056
+ name: `Forbid tool: ${tool}`,
9057
+ ok: false,
9058
+ expected: `not used`,
9059
+ actual: "used",
9060
+ runId: run.runId,
9061
+ message: `Forbidden tool "${tool}" used in run ${run.runId}`
9062
+ });
9063
+ }
9064
+ }
9065
+ if (!violated) {
9066
+ checks2.push({
9067
+ id: "forbidTool",
9068
+ name: `Forbid tool: ${tool}`,
9069
+ ok: true,
9070
+ message: `Forbidden tool "${tool}" not used`
9071
+ });
9072
+ }
9073
+ }
9074
+ for (const observation of options.requireObservations ?? []) {
9075
+ for (const run of runs) {
9076
+ if (run.filePath === void 0) continue;
9077
+ try {
9078
+ const status = await observationStatus(run.filePath, observation);
9079
+ const ok = status === "passed";
9080
+ checks2.push({
9081
+ id: "requireObservation",
9082
+ name: `Require observation: ${observation}`,
9083
+ ok,
9084
+ expected: "passed",
9085
+ actual: status,
9086
+ runId: run.runId,
9087
+ message: ok ? `Observation "${observation}" passed in run ${run.runId}` : status === "missing" ? `Observation "${observation}" missing in run ${run.runId}` : `Observation "${observation}" failed in run ${run.runId}`
9088
+ });
9089
+ } catch (error) {
9090
+ const message = error instanceof Error ? error.message : String(error);
9091
+ readErrors.push(`Run ${run.runId}: ${message}`);
9092
+ }
9093
+ }
9094
+ }
9095
+ return { checks: checks2, readErrors };
9096
+ }
9097
+ function checksFromSuiteResult(suiteResult) {
9098
+ const checks2 = [
9099
+ {
9100
+ id: "suite",
9101
+ name: `Suite: ${suiteResult.suiteName}`,
9102
+ ok: suiteResult.ok,
9103
+ message: suiteResult.ok ? `Suite passed (${suiteResult.summary.passed} cases)` : `Suite failed (${suiteResult.summary.failed} failed, ${suiteResult.summary.errors} errors)`
9104
+ }
9105
+ ];
9106
+ for (const suiteCase of suiteResult.cases) {
9107
+ if (suiteCase.status === "pass") continue;
9108
+ checks2.push({
9109
+ id: "suite",
9110
+ name: `Case: ${suiteCase.id}`,
9111
+ ok: false,
9112
+ message: suiteCase.message ?? `Case status: ${suiteCase.status}`
9113
+ });
9114
+ }
9115
+ return checks2;
9116
+ }
9117
+ var init_evaluate = __esm({
9118
+ "packages/core/src/gate/evaluate.ts"() {
9119
+ init_extract();
9120
+ init_storage();
9121
+ init_metrics();
9122
+ }
9123
+ });
9124
+ function resolveExitCode(input3) {
9125
+ if (input3.configError) return 2;
9126
+ if (input3.readError) return 3;
9127
+ if (!input3.ok) return 1;
9128
+ return 0;
9129
+ }
9130
+ function validateOptions(options) {
9131
+ const errors = [];
9132
+ const hasSuite = options.suitePath !== void 0 && options.suitePath.trim() !== "";
9133
+ const hasThresholds2 = gateHasThresholds(options);
9134
+ if (!hasSuite && !hasThresholds2) {
9135
+ errors.push(
9136
+ "No gate rules specified. Pass --suite or at least one threshold flag."
9137
+ );
9138
+ }
9139
+ if (hasThresholds2 && (options.traceDir === void 0 || options.traceDir.trim() === "")) {
9140
+ if (!hasSuite) {
9141
+ errors.push("Threshold flags require --dir <trace-directory>.");
9142
+ }
9143
+ }
9144
+ if (options.maxErrorRate !== void 0 && options.maxErrorRate < 0) {
9145
+ errors.push("--max-error-rate must be a non-negative percentage.");
9146
+ }
9147
+ if (options.maxP95DurationMs !== void 0 && options.maxP95DurationMs < 0) {
9148
+ errors.push("--max-p95-duration must be a non-negative millisecond value.");
9149
+ }
9150
+ return errors;
9151
+ }
9152
+ function isConfigLoadError(error) {
9153
+ if (!(error instanceof Error)) return false;
9154
+ const ext = path24__default.default.extname(error.message);
9155
+ if (error.message.includes("Unsupported suite config extension")) return true;
9156
+ if (error.message.includes("TypeScript suite configs require")) return true;
9157
+ if (error.message.includes("No suite config found")) return true;
9158
+ if (error.message.includes("AI_SUITE_CONFIG")) return true;
9159
+ if (ext === ".ts" || ext === ".mts" || ext === ".cts") return true;
9160
+ return "diagnostics" in error;
9161
+ }
9162
+ async function runGate(runs, options) {
9163
+ const diagnostics = [];
9164
+ const checks2 = [];
9165
+ const validationErrors = validateOptions(options);
9166
+ if (validationErrors.length > 0) {
9167
+ return {
9168
+ ok: false,
9169
+ exitCode: 2,
9170
+ runCount: 0,
9171
+ checks: checks2,
9172
+ diagnostics: validationErrors
9173
+ };
9174
+ }
9175
+ let traceDir = options.traceDir?.trim();
9176
+ let suiteResult;
9177
+ if (options.suitePath !== void 0 && options.suitePath.trim() !== "") {
9178
+ try {
9179
+ suiteResult = await runSuite({
9180
+ configPath: options.suitePath,
9181
+ cwd: options.cwd
9182
+ });
9183
+ traceDir = traceDir ?? suiteResult.tracesDir;
9184
+ checks2.push(...checksFromSuiteResult(suiteResult));
9185
+ } catch (error) {
9186
+ const message = error instanceof Error ? error.message : String(error);
9187
+ diagnostics.push(message);
9188
+ return {
9189
+ ok: false,
9190
+ exitCode: isConfigLoadError(error) ? 2 : 3,
9191
+ traceDir,
9192
+ suitePath: options.suitePath,
9193
+ runCount: 0,
9194
+ checks: checks2,
9195
+ diagnostics
9196
+ };
9197
+ }
9198
+ }
9199
+ if (gateHasThresholds(options)) {
9200
+ const thresholdDir = traceDir;
9201
+ if (thresholdDir === void 0 || thresholdDir.trim() === "") {
9202
+ return {
9203
+ ok: false,
9204
+ exitCode: 2,
9205
+ traceDir,
9206
+ suitePath: options.suitePath,
9207
+ runCount: runs.length,
9208
+ checks: checks2,
9209
+ diagnostics: ["Threshold evaluation requires a trace directory."],
9210
+ ...suiteResult !== void 0 ? { suiteResult } : {}
9211
+ };
9212
+ }
9213
+ const thresholdRuns = runs.length > 0 ? runs : [];
9214
+ const { checks: thresholdChecks, readErrors } = await evaluateGateThresholds(
9215
+ thresholdRuns,
9216
+ options
9217
+ );
9218
+ checks2.push(...thresholdChecks);
9219
+ diagnostics.push(...readErrors);
9220
+ if (readErrors.length > 0) {
9221
+ const ok2 = checks2.length > 0 && checks2.every((item) => item.ok);
9222
+ return {
9223
+ ok: ok2,
9224
+ exitCode: resolveExitCode({
9225
+ ok: ok2,
9226
+ configError: false,
9227
+ readError: true
9228
+ }),
9229
+ traceDir: thresholdDir,
9230
+ suitePath: options.suitePath,
9231
+ runCount: thresholdRuns.length,
9232
+ checks: checks2,
9233
+ diagnostics,
9234
+ ...suiteResult !== void 0 ? { suiteResult } : {}
9235
+ };
9236
+ }
9237
+ }
9238
+ const ok = checks2.length > 0 && checks2.every((item) => item.ok);
9239
+ return {
9240
+ ok,
9241
+ exitCode: resolveExitCode({ ok, configError: false, readError: false }),
9242
+ traceDir,
9243
+ suitePath: options.suitePath,
9244
+ runCount: runs.length,
9245
+ checks: checks2,
9246
+ diagnostics,
9247
+ ...suiteResult !== void 0 ? { suiteResult } : {}
9248
+ };
9249
+ }
9250
+ var init_run2 = __esm({
9251
+ "packages/core/src/gate/run.ts"() {
9252
+ init_run();
9253
+ init_evaluate();
9254
+ }
9255
+ });
9256
+
9257
+ // packages/core/src/gate/render.ts
9258
+ function escapeXml(value) {
9259
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
9260
+ }
9261
+ function renderGateSummaryMarkdown(result) {
9262
+ const lines = [];
9263
+ lines.push("# AgentInspect gate");
9264
+ lines.push("");
9265
+ lines.push(`Status: **${result.ok ? "PASS" : "FAIL"}** (exit ${result.exitCode})`);
9266
+ if (result.traceDir !== void 0) {
9267
+ lines.push(`Trace directory: \`${result.traceDir}\``);
9268
+ }
9269
+ if (result.suitePath !== void 0) {
9270
+ lines.push(`Suite config: \`${result.suitePath}\``);
9271
+ }
9272
+ lines.push(`Runs evaluated: ${result.runCount}`);
9273
+ lines.push("");
9274
+ if (result.diagnostics.length > 0) {
9275
+ lines.push("## Diagnostics");
9276
+ for (const item of result.diagnostics) lines.push(`- ${item}`);
9277
+ lines.push("");
9278
+ }
9279
+ lines.push("## Checks");
9280
+ for (const check of result.checks) {
9281
+ const flag = check.ok ? "PASS" : "FAIL";
9282
+ lines.push(`- [${flag}] ${check.name}: ${check.message}`);
9283
+ }
9284
+ lines.push("");
9285
+ return lines.join("\n").trimEnd();
9286
+ }
9287
+ function renderGateGithubStepSummary(result) {
9288
+ const lines = [];
9289
+ lines.push(`## AgentInspect gate: ${result.ok ? "PASS" : "FAIL"}`);
9290
+ lines.push("");
9291
+ lines.push("| Check | Status | Details |");
9292
+ lines.push("| --- | --- | --- |");
9293
+ for (const check of result.checks) {
9294
+ lines.push(
9295
+ `| ${check.name} | ${check.ok ? "pass" : "fail"} | ${check.message.replace(/\|/g, "/")} |`
9296
+ );
9297
+ }
9298
+ if (result.diagnostics.length > 0) {
9299
+ lines.push("");
9300
+ lines.push("**Diagnostics**");
9301
+ for (const item of result.diagnostics) lines.push(`- ${item}`);
9302
+ }
9303
+ return lines.join("\n").trimEnd();
9304
+ }
9305
+ function renderGateReportHtml(result) {
9306
+ const rows = result.checks.map(
9307
+ (check) => `<tr><td>${escapeHtml(check.name)}</td><td>${check.ok ? "PASS" : "FAIL"}</td><td>${escapeHtml(check.message)}</td></tr>`
9308
+ ).join("");
9309
+ return `<!DOCTYPE html>
9310
+ <html lang="en">
9311
+ <head>
9312
+ <meta charset="utf-8" />
9313
+ <title>Gate report</title>
9314
+ <style>
9315
+ body { font-family: system-ui, sans-serif; margin: 2rem; }
9316
+ table { border-collapse: collapse; width: 100%; }
9317
+ th, td { border: 1px solid #ddd; padding: 0.5rem; text-align: left; }
9318
+ th { background: #f6f6f6; }
9319
+ </style>
9320
+ </head>
9321
+ <body>
9322
+ <h1>AgentInspect gate</h1>
9323
+ <p>Status: <strong>${result.ok ? "PASS" : "FAIL"}</strong> (exit ${result.exitCode})</p>
9324
+ <h2>Checks</h2>
9325
+ <table>
9326
+ <thead><tr><th>Check</th><th>Status</th><th>Details</th></tr></thead>
9327
+ <tbody>${rows}</tbody>
9328
+ </table>
9329
+ </body>
9330
+ </html>`;
9331
+ }
9332
+ function renderGateJUnit(result) {
9333
+ const failures = result.checks.filter((check) => !check.ok).length;
9334
+ const tests = result.checks.length;
9335
+ const cases = result.checks.map((check) => {
9336
+ if (check.ok) {
9337
+ return ` <testcase name="${escapeXml(check.name)}" classname="gate" />`;
9338
+ }
9339
+ return ` <testcase name="${escapeXml(check.name)}" classname="gate">
9340
+ <failure message="${escapeXml(check.message)}">${escapeXml(check.message)}</failure>
9341
+ </testcase>`;
9342
+ }).join("\n");
9343
+ return `<?xml version="1.0" encoding="UTF-8"?>
9344
+ <testsuites tests="${tests}" failures="${failures}" errors="0" time="0">
9345
+ <testsuite name="agent-inspect-gate" tests="${tests}" failures="${failures}" errors="0" time="0">
9346
+ ${cases}
9347
+ </testsuite>
9348
+ </testsuites>`;
9349
+ }
9350
+ function renderGateReport(result, options = {}) {
9351
+ const format = options.format ?? "markdown";
9352
+ if (format === "json") return JSON.stringify(result, null, 2);
9353
+ if (format === "html") return renderGateReportHtml(result);
9354
+ if (format === "junit") return renderGateJUnit(result);
9355
+ if (format === "github") return renderGateGithubStepSummary(result);
9356
+ return renderGateSummaryMarkdown(result);
9357
+ }
9358
+ var init_render3 = __esm({
9359
+ "packages/core/src/gate/render.ts"() {
9360
+ init_helpers();
9361
+ }
9362
+ });
9363
+
9364
+ // packages/core/src/gate/index.ts
9365
+ var init_gate = __esm({
9366
+ "packages/core/src/gate/index.ts"() {
9367
+ init_parse();
9368
+ init_evaluate();
9369
+ init_run2();
9370
+ init_render3();
9371
+ }
9372
+ });
9373
+
8954
9374
  // packages/core/src/inspect-run.ts
8955
9375
  var init_inspect_run = __esm({
8956
9376
  "packages/core/src/inspect-run.ts"() {
@@ -8997,6 +9417,7 @@ var init_advanced = __esm({
8997
9417
  init_bundle();
8998
9418
  init_suite();
8999
9419
  init_cohort2();
9420
+ init_gate();
9000
9421
  init_maybe_inspect_run();
9001
9422
  }
9002
9423
  });
@@ -9061,19 +9482,19 @@ var require_file_uri_to_path = __commonJS({
9061
9482
  var rest = decodeURI(uri.substring(7));
9062
9483
  var firstSlash = rest.indexOf("/");
9063
9484
  var host = rest.substring(0, firstSlash);
9064
- var path31 = rest.substring(firstSlash + 1);
9485
+ var path33 = rest.substring(firstSlash + 1);
9065
9486
  if ("localhost" == host) host = "";
9066
9487
  if (host) {
9067
9488
  host = sep + sep + host;
9068
9489
  }
9069
- path31 = path31.replace(/^(.+)\|/, "$1:");
9490
+ path33 = path33.replace(/^(.+)\|/, "$1:");
9070
9491
  if (sep == "\\") {
9071
- path31 = path31.replace(/\//g, "\\");
9492
+ path33 = path33.replace(/\//g, "\\");
9072
9493
  }
9073
- if (/^.+\:/.test(path31)) ; else {
9074
- path31 = sep + path31;
9494
+ if (/^.+\:/.test(path33)) ; else {
9495
+ path33 = sep + path33;
9075
9496
  }
9076
- return host + path31;
9497
+ return host + path33;
9077
9498
  }
9078
9499
  }
9079
9500
  });
@@ -9082,18 +9503,18 @@ var require_file_uri_to_path = __commonJS({
9082
9503
  var require_bindings = __commonJS({
9083
9504
  "node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js"(exports$1, module) {
9084
9505
  var fs = __require("fs");
9085
- var path31 = __require("path");
9506
+ var path33 = __require("path");
9086
9507
  var fileURLToPath2 = require_file_uri_to_path();
9087
- var join = path31.join;
9088
- var dirname = path31.dirname;
9089
- var exists2 = fs.accessSync && function(path32) {
9508
+ var join = path33.join;
9509
+ var dirname = path33.dirname;
9510
+ var exists2 = fs.accessSync && function(path34) {
9090
9511
  try {
9091
- fs.accessSync(path32);
9512
+ fs.accessSync(path34);
9092
9513
  } catch (e) {
9093
9514
  return false;
9094
9515
  }
9095
9516
  return true;
9096
- } || fs.existsSync || path31.existsSync;
9517
+ } || fs.existsSync || path33.existsSync;
9097
9518
  var defaults = {
9098
9519
  arrow: process.env.NODE_BINDINGS_ARROW || " \u2192 ",
9099
9520
  compiled: process.env.NODE_BINDINGS_COMPILED_DIR || "compiled",
@@ -9138,7 +9559,7 @@ var require_bindings = __commonJS({
9138
9559
  if (!opts.module_root) {
9139
9560
  opts.module_root = exports$1.getRoot(exports$1.getFileName());
9140
9561
  }
9141
- if (path31.extname(opts.bindings) != ".node") {
9562
+ if (path33.extname(opts.bindings) != ".node") {
9142
9563
  opts.bindings += ".node";
9143
9564
  }
9144
9565
  var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
@@ -9373,7 +9794,7 @@ var require_pragma = __commonJS({
9373
9794
  var require_backup = __commonJS({
9374
9795
  "node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/backup.js"(exports$1, module) {
9375
9796
  var fs = __require("fs");
9376
- var path31 = __require("path");
9797
+ var path33 = __require("path");
9377
9798
  var { promisify } = __require("util");
9378
9799
  var { cppdb } = require_util();
9379
9800
  var fsAccess = promisify(fs.access);
@@ -9389,7 +9810,7 @@ var require_backup = __commonJS({
9389
9810
  if (typeof attachedName !== "string") throw new TypeError('Expected the "attached" option to be a string');
9390
9811
  if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
9391
9812
  if (handler != null && typeof handler !== "function") throw new TypeError('Expected the "progress" option to be a function');
9392
- await fsAccess(path31.dirname(filename)).catch(() => {
9813
+ await fsAccess(path33.dirname(filename)).catch(() => {
9393
9814
  throw new TypeError("Cannot save backup because the directory does not exist");
9394
9815
  });
9395
9816
  const isNewFile = await fsAccess(filename).then(() => false, () => true);
@@ -9689,7 +10110,7 @@ var require_inspect = __commonJS({
9689
10110
  var require_database = __commonJS({
9690
10111
  "node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/database.js"(exports$1, module) {
9691
10112
  var fs = __require("fs");
9692
- var path31 = __require("path");
10113
+ var path33 = __require("path");
9693
10114
  var util = require_util();
9694
10115
  var SqliteError = require_sqlite_error();
9695
10116
  var DEFAULT_ADDON;
@@ -9725,7 +10146,7 @@ var require_database = __commonJS({
9725
10146
  addon = DEFAULT_ADDON || (DEFAULT_ADDON = require_bindings()("better_sqlite3.node"));
9726
10147
  } else if (typeof nativeBinding === "string") {
9727
10148
  const requireFunc = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : __require;
9728
- addon = requireFunc(path31.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
10149
+ addon = requireFunc(path33.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
9729
10150
  } else {
9730
10151
  addon = nativeBinding;
9731
10152
  }
@@ -9733,7 +10154,7 @@ var require_database = __commonJS({
9733
10154
  addon.setErrorConstructor(SqliteError);
9734
10155
  addon.isInitialized = true;
9735
10156
  }
9736
- if (!anonymous && !fs.existsSync(path31.dirname(filename))) {
10157
+ if (!anonymous && !fs.existsSync(path33.dirname(filename))) {
9737
10158
  throw new TypeError("Cannot open database because the directory does not exist");
9738
10159
  }
9739
10160
  Object.defineProperties(this, {
@@ -9860,8 +10281,8 @@ GROUP BY session_id;
9860
10281
  }
9861
10282
  });
9862
10283
  function resolveIndexDbPath(traceDir, dbPath) {
9863
- if (dbPath && dbPath.trim() !== "") return path23__default.default.resolve(dbPath);
9864
- return path23__default.default.join(path23__default.default.resolve(traceDir), INDEX_DB_FILENAME);
10284
+ if (dbPath && dbPath.trim() !== "") return path24__default.default.resolve(dbPath);
10285
+ return path24__default.default.join(path24__default.default.resolve(traceDir), INDEX_DB_FILENAME);
9865
10286
  }
9866
10287
  function str(value) {
9867
10288
  return typeof value === "string" && value !== "" ? value : null;
@@ -9953,7 +10374,7 @@ async function buildIndex(options = {}) {
9953
10374
  warnings.push(`index.unreadable: ${file}`);
9954
10375
  }
9955
10376
  }
9956
- await promises.mkdir(path23__default.default.dirname(dbPath), { recursive: true });
10377
+ await promises.mkdir(path24__default.default.dirname(dbPath), { recursive: true });
9957
10378
  await promises.rm(dbPath, { force: true });
9958
10379
  const db = new import_better_sqlite3.default(dbPath);
9959
10380
  let runCount = 0;
@@ -10191,7 +10612,7 @@ var init_src = __esm({
10191
10612
  });
10192
10613
 
10193
10614
  // package.json
10194
- var version = "5.1.0";
10615
+ var version = "5.2.0";
10195
10616
 
10196
10617
  // packages/cli/src/list.ts
10197
10618
  init_advanced();
@@ -13192,9 +13613,9 @@ Trace directory: ${traceDir}`);
13192
13613
  if (validation !== void 0 && !validation.ok) {
13193
13614
  process.exitCode = 1;
13194
13615
  }
13195
- const outPath = options.output !== void 0 && options.output.trim() !== "" ? path23__default.default.resolve(options.output.trim()) : void 0;
13616
+ const outPath = options.output !== void 0 && options.output.trim() !== "" ? path24__default.default.resolve(options.output.trim()) : void 0;
13196
13617
  if (outPath !== void 0) {
13197
- await promises.mkdir(path23__default.default.dirname(outPath), { recursive: true });
13618
+ await promises.mkdir(path24__default.default.dirname(outPath), { recursive: true });
13198
13619
  await promises.writeFile(outPath, result.content, "utf-8");
13199
13620
  const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
13200
13621
  console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
@@ -13375,13 +13796,13 @@ function pairSteps(left, right) {
13375
13796
  return pairs;
13376
13797
  }
13377
13798
  function compareLeafSteps(L, R, segments, opts, out) {
13378
- const path31 = buildPath(segments);
13799
+ const path33 = buildPath(segments);
13379
13800
  if (L.name !== R.name) {
13380
13801
  out.push({
13381
13802
  kind: "structure",
13382
13803
  severity: "warning",
13383
13804
  message: "Step name differs",
13384
- path: path31,
13805
+ path: path33,
13385
13806
  left: L.name,
13386
13807
  right: R.name
13387
13808
  });
@@ -13391,7 +13812,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
13391
13812
  kind: "step-type",
13392
13813
  severity: "warning",
13393
13814
  message: "Step type differs",
13394
- path: path31,
13815
+ path: path33,
13395
13816
  left: L.type,
13396
13817
  right: R.type
13397
13818
  });
@@ -13401,7 +13822,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
13401
13822
  kind: "step-status",
13402
13823
  severity: "warning",
13403
13824
  message: "Step status differs",
13404
- path: path31,
13825
+ path: path33,
13405
13826
  left: L.status,
13406
13827
  right: R.status
13407
13828
  });
@@ -13413,7 +13834,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
13413
13834
  kind: "error",
13414
13835
  severity: "error",
13415
13836
  message: "Step error message differs",
13416
- path: path31,
13837
+ path: path33,
13417
13838
  left: le || void 0,
13418
13839
  right: re || void 0
13419
13840
  });
@@ -13431,7 +13852,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
13431
13852
  kind: "duration",
13432
13853
  severity: "info",
13433
13854
  message: "Step duration differs",
13434
- path: path31,
13855
+ path: path33,
13435
13856
  left: ld,
13436
13857
  right: rd
13437
13858
  });
@@ -13444,7 +13865,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
13444
13865
  kind: "metadata",
13445
13866
  severity: "info",
13446
13867
  message: "Step metadata differs",
13447
- path: path31,
13868
+ path: path33,
13448
13869
  left: L.metadata,
13449
13870
  right: R.metadata
13450
13871
  });
@@ -13456,7 +13877,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
13456
13877
  kind: "output",
13457
13878
  severity: "info",
13458
13879
  message: "Output preview differs",
13459
- path: path31,
13880
+ path: path33,
13460
13881
  left: L.outputPreview,
13461
13882
  right: R.outputPreview
13462
13883
  });
@@ -13617,11 +14038,11 @@ function diffRuns(left, right, options) {
13617
14038
 
13618
14039
  // packages/core/src/diff/renderer.ts
13619
14040
  init_source();
13620
- function formatPath(path31) {
13621
- if (path31 === void 0 || path31.path.length === 0) {
14041
+ function formatPath(path33) {
14042
+ if (path33 === void 0 || path33.path.length === 0) {
13622
14043
  return "(run)";
13623
14044
  }
13624
- return path31.path.map((s) => s.name).join(" > ");
14045
+ return path33.path.map((s) => s.name).join(" > ");
13625
14046
  }
13626
14047
  function formatValue(v, verbose) {
13627
14048
  if (v === void 0) return "(undefined)";
@@ -14009,7 +14430,7 @@ function indexedToMetadata(row, traceDir) {
14009
14430
  endedAt: row.endedAt ?? void 0,
14010
14431
  durationMs: row.durationMs ?? void 0,
14011
14432
  eventCount: 0,
14012
- filePath: path23__default.default.join(traceDir, row.file),
14433
+ filePath: path24__default.default.join(traceDir, row.file),
14013
14434
  fileSize: 0,
14014
14435
  createdAt: new Date(row.mtimeMs)
14015
14436
  };
@@ -14490,9 +14911,9 @@ async function reportCommand(runId, options = {}) {
14490
14911
  correlation: !options.noCorrelation,
14491
14912
  ...options.section ? { section: options.section } : {}
14492
14913
  });
14493
- const outPath = options.output !== void 0 && options.output.trim() !== "" ? path23__default.default.resolve(options.output.trim()) : void 0;
14914
+ const outPath = options.output !== void 0 && options.output.trim() !== "" ? path24__default.default.resolve(options.output.trim()) : void 0;
14494
14915
  if (outPath !== void 0) {
14495
- await promises.mkdir(path23__default.default.dirname(outPath), { recursive: true });
14916
+ await promises.mkdir(path24__default.default.dirname(outPath), { recursive: true });
14496
14917
  await promises.writeFile(outPath, result.content, "utf-8");
14497
14918
  console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
14498
14919
  }
@@ -14742,17 +15163,17 @@ function applyRule(rule, value, replacement) {
14742
15163
  }
14743
15164
  return value;
14744
15165
  }
14745
- function childPath(path31, key) {
15166
+ function childPath(path33, key) {
14746
15167
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
14747
- return path31 ? `${path31}.${key}` : key;
15168
+ return path33 ? `${path33}.${key}` : key;
14748
15169
  }
14749
- return `${path31 || "$"}[${JSON.stringify(key)}]`;
15170
+ return `${path33 || "$"}[${JSON.stringify(key)}]`;
14750
15171
  }
14751
- function indexPath(path31, index) {
14752
- return `${path31 || "$"}[${index}]`;
15172
+ function indexPath(path33, index) {
15173
+ return `${path33 || "$"}[${index}]`;
14753
15174
  }
14754
- function makeFinding(path31, detector, action, matchKind, severity = "warning", preview) {
14755
- return preview === void 0 ? { path: path31, detector, action, severity, matchKind } : { path: path31, detector, action, severity, matchKind, preview };
15175
+ function makeFinding(path33, detector, action, matchKind, severity = "warning", preview) {
15176
+ return preview === void 0 ? { path: path33, detector, action, severity, matchKind } : { path: path33, detector, action, severity, matchKind, preview };
14756
15177
  }
14757
15178
  function createRedactionProfile(profile = "local") {
14758
15179
  switch (profile) {
@@ -14821,11 +15242,11 @@ var Redactor2 = class {
14821
15242
  #recordFinding(state, finding) {
14822
15243
  if (this.#collectFindings) state.findings.push(finding);
14823
15244
  }
14824
- #redactValue(value, key, path31, depth, state) {
15245
+ #redactValue(value, key, path33, depth, state) {
14825
15246
  if (depth > this.#maxDepth) {
14826
15247
  this.#recordFinding(
14827
15248
  state,
14828
- makeFinding(path31, "structure.maxDepth", "truncate", "value", "warning")
15249
+ makeFinding(path33, "structure.maxDepth", "truncate", "value", "warning")
14829
15250
  );
14830
15251
  return "[Truncated]";
14831
15252
  }
@@ -14834,19 +15255,19 @@ var Redactor2 = class {
14834
15255
  if (rule) {
14835
15256
  this.#recordFinding(
14836
15257
  state,
14837
- makeFinding(path31, `key.${rule.key}`, actionForRule(rule), "key", "warning")
15258
+ makeFinding(path33, `key.${rule.key}`, actionForRule(rule), "key", "warning")
14838
15259
  );
14839
15260
  return applyRule(rule, value, this.#replacement);
14840
15261
  }
14841
15262
  }
14842
15263
  for (const detector of this.#detectors) {
14843
- const detections = detector.detect({ path: path31, key, value });
15264
+ const detections = detector.detect({ path: path33, key, value });
14844
15265
  for (const detection of detections) {
14845
15266
  const action = detection.action ?? "replace";
14846
15267
  this.#recordFinding(
14847
15268
  state,
14848
15269
  makeFinding(
14849
- path31,
15270
+ path33,
14850
15271
  detector.id,
14851
15272
  action,
14852
15273
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -14864,7 +15285,7 @@ var Redactor2 = class {
14864
15285
  const out = [];
14865
15286
  state.seen.set(value, out);
14866
15287
  value.forEach((item, index) => {
14867
- out[index] = this.#redactValue(item, void 0, indexPath(path31, index), depth + 1, state);
15288
+ out[index] = this.#redactValue(item, void 0, indexPath(path33, index), depth + 1, state);
14868
15289
  });
14869
15290
  return out;
14870
15291
  }
@@ -14876,7 +15297,7 @@ var Redactor2 = class {
14876
15297
  out[entryKey] = this.#redactValue(
14877
15298
  entryValue,
14878
15299
  entryKey,
14879
- childPath(path31 === "$" ? "" : path31, entryKey),
15300
+ childPath(path33 === "$" ? "" : path33, entryKey),
14880
15301
  depth + 1,
14881
15302
  state
14882
15303
  );
@@ -15336,14 +15757,14 @@ function uniqueSorted(values) {
15336
15757
  return [...new Set(values)].sort();
15337
15758
  }
15338
15759
  function isWithinDirectory(child, parent) {
15339
- const relative = path23__default.default.relative(parent, child);
15340
- return relative === "" || !relative.startsWith("..") && !path23__default.default.isAbsolute(relative);
15760
+ const relative = path24__default.default.relative(parent, child);
15761
+ return relative === "" || !relative.startsWith("..") && !path24__default.default.isAbsolute(relative);
15341
15762
  }
15342
15763
  async function resolveOutputPath(inputPath, output2, force) {
15343
15764
  if (output2 === void 0 || output2.trim() === "") return void 0;
15344
- const inputAbs = path23__default.default.resolve(inputPath);
15345
- const outputAbs = path23__default.default.resolve(output2.trim());
15346
- const inputDir = path23__default.default.dirname(inputAbs);
15765
+ const inputAbs = path24__default.default.resolve(inputPath);
15766
+ const outputAbs = path24__default.default.resolve(output2.trim());
15767
+ const inputDir = path24__default.default.dirname(inputAbs);
15347
15768
  if (!isWithinDirectory(outputAbs, inputDir)) {
15348
15769
  throw new Error("Refusing to write migrated output outside the input directory.");
15349
15770
  }
@@ -15464,7 +15885,7 @@ async function migrateCommand(input3, options = {}) {
15464
15885
  process.exitCode = 1;
15465
15886
  return;
15466
15887
  }
15467
- const inputPath = path23__default.default.resolve(input3.trim());
15888
+ const inputPath = path24__default.default.resolve(input3.trim());
15468
15889
  const dryRun = options.dryRun === true;
15469
15890
  if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
15470
15891
  console.error("migrate requires --dry-run or --output <path>.");
@@ -15483,7 +15904,7 @@ async function migrateCommand(input3, options = {}) {
15483
15904
  );
15484
15905
  const result = await buildMigration(inputPath, outputPath);
15485
15906
  if (!dryRun && outputPath !== void 0) {
15486
- await promises.mkdir(path23__default.default.dirname(outputPath), { recursive: true });
15907
+ await promises.mkdir(path24__default.default.dirname(outputPath), { recursive: true });
15487
15908
  await promises.writeFile(outputPath, result.content, "utf-8");
15488
15909
  }
15489
15910
  printSummary2(result, dryRun);
@@ -15817,23 +16238,23 @@ function evaluatePromptInjection(text, options = {}) {
15817
16238
  }
15818
16239
  return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
15819
16240
  }
15820
- function validateSchemaField(value, field, path31, evidence) {
16241
+ function validateSchemaField(value, field, path33, evidence) {
15821
16242
  const ruleId = "guardrail.structured-output";
15822
16243
  if (field.type) {
15823
16244
  const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
15824
16245
  if (actual !== field.type) {
15825
- evidence.push({ ruleId, path: path31, preview: `expected ${field.type}, got ${actual}` });
16246
+ evidence.push({ ruleId, path: path33, preview: `expected ${field.type}, got ${actual}` });
15826
16247
  return;
15827
16248
  }
15828
16249
  }
15829
16250
  if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
15830
- evidence.push({ ruleId, path: path31, preview: "value not in enum" });
16251
+ evidence.push({ ruleId, path: path33, preview: "value not in enum" });
15831
16252
  }
15832
16253
  if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
15833
16254
  const record = value;
15834
16255
  for (const key of field.required) {
15835
16256
  if (!(key in record)) {
15836
- evidence.push({ ruleId, path: `${path31}.${key}`, preview: "missing required key" });
16257
+ evidence.push({ ruleId, path: `${path33}.${key}`, preview: "missing required key" });
15837
16258
  }
15838
16259
  }
15839
16260
  }
@@ -16160,7 +16581,7 @@ function asConfig(value) {
16160
16581
  }
16161
16582
  async function loadConfig(configPath) {
16162
16583
  if (configPath === void 0) return {};
16163
- const extension = path23__default.default.extname(configPath);
16584
+ const extension = path24__default.default.extname(configPath);
16164
16585
  if (TS_CONFIG_EXTENSIONS2.has(extension)) {
16165
16586
  throw new Error(
16166
16587
  "TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -16169,7 +16590,7 @@ async function loadConfig(configPath) {
16169
16590
  if (!CONFIG_EXTENSIONS2.has(extension)) {
16170
16591
  throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
16171
16592
  }
16172
- const absolute = path23__default.default.resolve(configPath);
16593
+ const absolute = path24__default.default.resolve(configPath);
16173
16594
  if (extension === ".json") {
16174
16595
  const raw = await promises.readFile(absolute, "utf-8");
16175
16596
  return asConfig(JSON.parse(raw));
@@ -16334,10 +16755,10 @@ function printHuman(result) {
16334
16755
  console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
16335
16756
  }
16336
16757
  for (const finding of result.findings) {
16337
- const path31 = finding.evidence[0]?.path;
16758
+ const path33 = finding.evidence[0]?.path;
16338
16759
  const run = finding.evidence[0]?.runId;
16339
16760
  const runPrefix = run ? `[${run}] ` : "";
16340
- console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path31 ? ` (${path31})` : ""}`);
16761
+ console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path33 ? ` (${path33})` : ""}`);
16341
16762
  }
16342
16763
  }
16343
16764
  function readErrorResult(error) {
@@ -16540,7 +16961,7 @@ function createViewerServer(options = {}) {
16540
16961
  return sendJson(res, 200, {
16541
16962
  ok: true,
16542
16963
  readOnly: true,
16543
- traceDir: path23__default.default.resolve(traceDir)
16964
+ traceDir: path24__default.default.resolve(traceDir)
16544
16965
  });
16545
16966
  }
16546
16967
  const td = new TraceDirectory({ dir: traceDir });
@@ -16558,7 +16979,7 @@ function createViewerServer(options = {}) {
16558
16979
  runId: meta2.runId,
16559
16980
  name: meta2.name,
16560
16981
  status: meta2.status,
16561
- file: path23__default.default.basename(meta2.filePath),
16982
+ file: path24__default.default.basename(meta2.filePath),
16562
16983
  startedAt: meta2.startedAt,
16563
16984
  durationMs: meta2.durationMs
16564
16985
  }))
@@ -16673,7 +17094,7 @@ function startViewerServer(options = {}) {
16673
17094
  resolve({
16674
17095
  host,
16675
17096
  port: resolvedPort,
16676
- traceDir: path23__default.default.resolve(traceDir),
17097
+ traceDir: path24__default.default.resolve(traceDir),
16677
17098
  url: `http://${host}:${resolvedPort}`
16678
17099
  });
16679
17100
  });
@@ -16878,10 +17299,10 @@ async function evalRun(input3, options = {}) {
16878
17299
  diagnostics: []
16879
17300
  };
16880
17301
  }
16881
- function evidenceForRun(run, path31) {
16882
- return [{ runId: run.runId, ...path31 !== void 0 ? { path: path31 } : {} }];
17302
+ function evidenceForRun(run, path33) {
17303
+ return [{ runId: run.runId, ...path33 !== void 0 ? { path: path33 } : {} }];
16883
17304
  }
16884
- function evidenceForEvent(event, path31) {
17305
+ function evidenceForEvent(event, path33) {
16885
17306
  return [
16886
17307
  {
16887
17308
  runId: event.runId,
@@ -16889,7 +17310,7 @@ function evidenceForEvent(event, path31) {
16889
17310
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
16890
17311
  kind: event.kind,
16891
17312
  name: event.name,
16892
- ...path31 !== void 0 ? { path: path31 } : {}
17313
+ ...path33 !== void 0 ? { path: path33 } : {}
16893
17314
  }
16894
17315
  ];
16895
17316
  }
@@ -17047,9 +17468,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
17047
17468
  function tokenize(text) {
17048
17469
  return [...text.toLowerCase().matchAll(/[a-z0-9][a-z0-9'-]{2,}/g)].map((match) => match[0].replace(/^['-]+|['-]+$/g, "")).filter((token) => token.length > 2 && !STOP_WORDS.has(token));
17049
17470
  }
17050
- function firstEvidence(fields, run, path31) {
17471
+ function firstEvidence(fields, run, path33) {
17051
17472
  const first = fields[0];
17052
- return first === void 0 ? evidenceForRun(run, path31) : evidenceForEvent(first.node.event, first.path);
17473
+ return first === void 0 ? evidenceForRun(run, path33) : evidenceForEvent(first.node.event, first.path);
17053
17474
  }
17054
17475
  function collectSourceIds(nodes, keys) {
17055
17476
  const wanted = keySet(keys);
@@ -17426,8 +17847,8 @@ function renderEvalMarkdown(result) {
17426
17847
  if (result.findings.length > 0) {
17427
17848
  lines.push("", "## Findings");
17428
17849
  for (const finding of result.findings) {
17429
- const path31 = finding.evidence[0]?.path;
17430
- lines.push(`- ${finding.ruleId}: ${finding.message}${path31 ? ` (${path31})` : ""}`);
17850
+ const path33 = finding.evidence[0]?.path;
17851
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path33 ? ` (${path33})` : ""}`);
17431
17852
  }
17432
17853
  }
17433
17854
  return `${lines.join("\n")}
@@ -17474,7 +17895,7 @@ function asConfig2(value) {
17474
17895
  }
17475
17896
  async function loadConfig2(configPath) {
17476
17897
  if (configPath === void 0) return {};
17477
- const extension = path23__default.default.extname(configPath);
17898
+ const extension = path24__default.default.extname(configPath);
17478
17899
  if (TS_CONFIG_EXTENSIONS3.has(extension)) {
17479
17900
  throw new Error(
17480
17901
  "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -17483,7 +17904,7 @@ async function loadConfig2(configPath) {
17483
17904
  if (!CONFIG_EXTENSIONS3.has(extension)) {
17484
17905
  throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
17485
17906
  }
17486
- const absolute = path23__default.default.resolve(configPath);
17907
+ const absolute = path24__default.default.resolve(configPath);
17487
17908
  if (extension === ".json") {
17488
17909
  const raw = await promises.readFile(absolute, "utf-8");
17489
17910
  return asConfig2(JSON.parse(raw));
@@ -17620,8 +18041,8 @@ function printHuman2(result) {
17620
18041
  console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
17621
18042
  }
17622
18043
  for (const finding of result.findings) {
17623
- const path31 = finding.evidence[0]?.path;
17624
- console.log(`- ${finding.ruleId}: ${finding.message}${path31 ? ` (${path31})` : ""}`);
18044
+ const path33 = finding.evidence[0]?.path;
18045
+ console.log(`- ${finding.ruleId}: ${finding.message}${path33 ? ` (${path33})` : ""}`);
17625
18046
  }
17626
18047
  }
17627
18048
  function readErrorResult2(error) {
@@ -17859,8 +18280,8 @@ function printHuman3(result) {
17859
18280
  console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
17860
18281
  }
17861
18282
  for (const finding of result.findings) {
17862
- const path31 = finding.evidence[0]?.path;
17863
- console.log(`- ${finding.ruleId}: ${finding.message}${path31 ? ` (${path31})` : ""}`);
18283
+ const path33 = finding.evidence[0]?.path;
18284
+ console.log(`- ${finding.ruleId}: ${finding.message}${path33 ? ` (${path33})` : ""}`);
17864
18285
  }
17865
18286
  console.log(`Note: ${result.note}`);
17866
18287
  }
@@ -18011,8 +18432,8 @@ function renderCheckSection(result) {
18011
18432
  `Diagnostics: ${result.diagnostics.length}`
18012
18433
  ];
18013
18434
  for (const finding of result.findings.slice(0, 10)) {
18014
- const path31 = finding.evidence[0]?.path ?? "(run)";
18015
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path31})`);
18435
+ const path33 = finding.evidence[0]?.path ?? "(run)";
18436
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path33})`);
18016
18437
  }
18017
18438
  for (const diagnostic7 of result.diagnostics.slice(0, 10)) {
18018
18439
  lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
@@ -18090,8 +18511,8 @@ function renderHtml(trace, check, diff) {
18090
18511
  `;
18091
18512
  }
18092
18513
  async function writeArtifact(outputDir, relativePath, content, files) {
18093
- const outPath = path23__default.default.join(outputDir, relativePath);
18094
- await promises.mkdir(path23__default.default.dirname(outPath), { recursive: true });
18514
+ const outPath = path24__default.default.join(outputDir, relativePath);
18515
+ await promises.mkdir(path24__default.default.dirname(outPath), { recursive: true });
18095
18516
  await promises.writeFile(outPath, content, "utf-8");
18096
18517
  files.push(relativePath);
18097
18518
  }
@@ -18107,7 +18528,7 @@ function manifestStatus(check, diff) {
18107
18528
  return "ok";
18108
18529
  }
18109
18530
  async function artifactsCommand(target, options = {}, stdin = process.stdin) {
18110
- const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path23__default.default.resolve(options.outputDir.trim()) : "";
18531
+ const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path24__default.default.resolve(options.outputDir.trim()) : "";
18111
18532
  if (outputDir === "") {
18112
18533
  console.error("--output-dir is required.");
18113
18534
  process.exitCode = 1;
@@ -18173,8 +18594,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
18173
18594
  await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
18174
18595
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
18175
18596
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
18176
- await promises.mkdir(path23__default.default.dirname(path23__default.default.resolve(summaryTarget)), { recursive: true });
18177
- await promises.appendFile(path23__default.default.resolve(summaryTarget), `
18597
+ await promises.mkdir(path24__default.default.dirname(path24__default.default.resolve(summaryTarget)), { recursive: true });
18598
+ await promises.appendFile(path24__default.default.resolve(summaryTarget), `
18178
18599
  ${renderMarkdown(trace, check, diff)}`, "utf-8");
18179
18600
  }
18180
18601
  const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
@@ -18193,10 +18614,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
18193
18614
  findings: diff?.findings.length ?? 0,
18194
18615
  diagnostics: diff?.diagnostics.length ?? 0
18195
18616
  },
18196
- ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path23__default.default.resolve(summaryTarget) } : {},
18617
+ ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path24__default.default.resolve(summaryTarget) } : {},
18197
18618
  note: NOTE
18198
18619
  };
18199
- await promises.writeFile(path23__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
18620
+ await promises.writeFile(path24__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
18200
18621
  if (options.json === true) {
18201
18622
  console.log(writeJson3(manifest).trimEnd());
18202
18623
  } else {
@@ -18390,19 +18811,19 @@ function serializeWorkspaceManifest(manifest) {
18390
18811
  }
18391
18812
  var INDEX_DIR_NAME = "index";
18392
18813
  function resolveWorkspaceLocation(cwd = process.cwd()) {
18393
- const projectRoot = path23__default.default.resolve(cwd);
18394
- const workspaceDir = path23__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
18814
+ const projectRoot = path24__default.default.resolve(cwd);
18815
+ const workspaceDir = path24__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
18395
18816
  return {
18396
18817
  projectRoot,
18397
18818
  workspaceDir,
18398
- manifestPath: path23__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
18819
+ manifestPath: path24__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
18399
18820
  };
18400
18821
  }
18401
18822
  function resolveInsideWorkspace(workspaceDir, relative) {
18402
- const base = path23__default.default.resolve(workspaceDir);
18403
- const resolved = path23__default.default.resolve(base, relative);
18404
- const rel = path23__default.default.relative(base, resolved);
18405
- if (rel === "" || rel === "." || !rel.startsWith("..") && !path23__default.default.isAbsolute(rel)) {
18823
+ const base = path24__default.default.resolve(workspaceDir);
18824
+ const resolved = path24__default.default.resolve(base, relative);
18825
+ const rel = path24__default.default.relative(base, resolved);
18826
+ if (rel === "" || rel === "." || !rel.startsWith("..") && !path24__default.default.isAbsolute(rel)) {
18406
18827
  return resolved;
18407
18828
  }
18408
18829
  throw new Error(
@@ -18471,7 +18892,7 @@ async function createWorkspace(options = {}) {
18471
18892
  created = false;
18472
18893
  adopted = true;
18473
18894
  } else {
18474
- const project = options.project?.trim() || path23__default.default.basename(location.projectRoot) || "workspace";
18895
+ const project = options.project?.trim() || path24__default.default.basename(location.projectRoot) || "workspace";
18475
18896
  const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
18476
18897
  manifest = createDefaultWorkspaceManifest({
18477
18898
  project,
@@ -18610,7 +19031,7 @@ async function doctorWorkspace(location) {
18610
19031
  const abs = resolveInsideWorkspace(location.workspaceDir, rel);
18611
19032
  for (const file of await listJsonl(abs)) {
18612
19033
  try {
18613
- const s = await promises.stat(path23__default.default.join(abs, file));
19034
+ const s = await promises.stat(path24__default.default.join(abs, file));
18614
19035
  newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
18615
19036
  } catch {
18616
19037
  checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
@@ -18658,7 +19079,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
18658
19079
  const relPath = `${rel}/${entry}`;
18659
19080
  removed.push(relPath);
18660
19081
  if (!dryRun) {
18661
- await promises.rm(path23__default.default.join(abs, entry), { recursive: true, force: true });
19082
+ await promises.rm(path24__default.default.join(abs, entry), { recursive: true, force: true });
18662
19083
  }
18663
19084
  }
18664
19085
  }
@@ -18704,8 +19125,8 @@ async function resolveOutputDir(options, runIds, cwd) {
18704
19125
  const location = resolveWorkspaceLocation(cwd);
18705
19126
  const manifest = await readWorkspaceManifestFile(location);
18706
19127
  if (manifest.ok && manifest.manifest) {
18707
- const rel = path23__default.default.relative(location.workspaceDir, normalized);
18708
- if (!rel.startsWith("..") && !path23__default.default.isAbsolute(rel)) {
19128
+ const rel = path24__default.default.relative(location.workspaceDir, normalized);
19129
+ if (!rel.startsWith("..") && !path24__default.default.isAbsolute(rel)) {
18709
19130
  return resolveInsideWorkspace(location.workspaceDir, rel);
18710
19131
  }
18711
19132
  }
@@ -18721,7 +19142,7 @@ async function resolveOutputDir(options, runIds, cwd) {
18721
19142
  const label = runIds.length === 1 ? runIds[0] : `multi-${runIds.length}`;
18722
19143
  return resolveInsideWorkspace(
18723
19144
  location.workspaceDir,
18724
- path23__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
19145
+ path24__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
18725
19146
  );
18726
19147
  }
18727
19148
  } catch {
@@ -18729,8 +19150,8 @@ async function resolveOutputDir(options, runIds, cwd) {
18729
19150
  return defaultBundleOutputPath(runIds);
18730
19151
  }
18731
19152
  async function writeBundleFile(outputDir, relativePath, content, files) {
18732
- const outPath = path23__default.default.join(outputDir, relativePath);
18733
- await promises.mkdir(path23__default.default.dirname(outPath), { recursive: true });
19153
+ const outPath = path24__default.default.join(outputDir, relativePath);
19154
+ await promises.mkdir(path24__default.default.dirname(outPath), { recursive: true });
18734
19155
  await promises.writeFile(outPath, content, "utf-8");
18735
19156
  files.push(relativePath);
18736
19157
  }
@@ -18956,7 +19377,7 @@ async function bundleCommand(runIdArg, options = {}) {
18956
19377
  files
18957
19378
  );
18958
19379
  metadata.files = [...files].sort((a, b) => a.localeCompare(b));
18959
- await promises.writeFile(path23__default.default.join(outputDir, "metadata.json"), writeJson4(metadata), "utf-8");
19380
+ await promises.writeFile(path24__default.default.join(outputDir, "metadata.json"), writeJson4(metadata), "utf-8");
18960
19381
  if (options.json) {
18961
19382
  console.log(
18962
19383
  writeJson4({
@@ -18990,7 +19411,7 @@ ${body}
18990
19411
  `;
18991
19412
  }
18992
19413
  function validateReporterArtifactPath(options) {
18993
- const outputDir = path23__default.default.resolve(options.outputDir);
19414
+ const outputDir = path24__default.default.resolve(options.outputDir);
18994
19415
  const diagnostics = [];
18995
19416
  const rawPath = options.relativePath;
18996
19417
  if (rawPath.length === 0) {
@@ -19010,7 +19431,7 @@ function validateReporterArtifactPath(options) {
19010
19431
  });
19011
19432
  return { ok: false, outputDir, diagnostics };
19012
19433
  }
19013
- if (path23__default.default.isAbsolute(rawPath) || path23__default.default.win32.isAbsolute(rawPath)) {
19434
+ if (path24__default.default.isAbsolute(rawPath) || path24__default.default.win32.isAbsolute(rawPath)) {
19014
19435
  diagnostics.push({
19015
19436
  code: "artifact_path_absolute",
19016
19437
  severity: "error",
@@ -19019,7 +19440,7 @@ function validateReporterArtifactPath(options) {
19019
19440
  });
19020
19441
  return { ok: false, outputDir, diagnostics };
19021
19442
  }
19022
- const normalized = path23__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
19443
+ const normalized = path24__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
19023
19444
  const segments = normalized.split("/");
19024
19445
  if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
19025
19446
  diagnostics.push({
@@ -19030,9 +19451,9 @@ function validateReporterArtifactPath(options) {
19030
19451
  });
19031
19452
  return { ok: false, outputDir, diagnostics };
19032
19453
  }
19033
- const absolutePath = path23__default.default.resolve(outputDir, normalized);
19034
- const relFromOutput = path23__default.default.relative(outputDir, absolutePath);
19035
- if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path23__default.default.isAbsolute(relFromOutput)) {
19454
+ const absolutePath = path24__default.default.resolve(outputDir, normalized);
19455
+ const relFromOutput = path24__default.default.relative(outputDir, absolutePath);
19456
+ if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path24__default.default.isAbsolute(relFromOutput)) {
19036
19457
  diagnostics.push({
19037
19458
  code: "artifact_path_escape",
19038
19459
  severity: "error",
@@ -19178,23 +19599,23 @@ function readManifestDocument(value) {
19178
19599
  };
19179
19600
  }
19180
19601
  function cwdRelative(filePath) {
19181
- const relative = path23__default.default.relative(process.cwd(), path23__default.default.resolve(filePath)).replace(/\\/g, "/");
19182
- if (relative === "" || relative.startsWith("../") || path23__default.default.isAbsolute(relative)) {
19183
- return path23__default.default.basename(filePath);
19602
+ const relative = path24__default.default.relative(process.cwd(), path24__default.default.resolve(filePath)).replace(/\\/g, "/");
19603
+ if (relative === "" || relative.startsWith("../") || path24__default.default.isAbsolute(relative)) {
19604
+ return path24__default.default.basename(filePath);
19184
19605
  }
19185
19606
  return relative;
19186
19607
  }
19187
19608
  async function readReporterManifest(filePath) {
19188
- const absolute = path23__default.default.resolve(filePath);
19609
+ const absolute = path24__default.default.resolve(filePath);
19189
19610
  const raw = await promises.readFile(absolute, "utf-8");
19190
19611
  const document = readManifestDocument(JSON.parse(raw));
19191
19612
  const manifest = document.manifest;
19192
19613
  const results = manifest.results.map((result) => ({
19193
19614
  testId: safeText(result.testId),
19194
19615
  name: safeText(result.name),
19195
- ...result.file === void 0 ? {} : { file: safeText(path23__default.default.basename(result.file)) },
19616
+ ...result.file === void 0 ? {} : { file: safeText(path24__default.default.basename(result.file)) },
19196
19617
  status: result.status,
19197
- ...result.tracePath === void 0 ? {} : { tracePath: safeText(path23__default.default.basename(result.tracePath)) },
19618
+ ...result.tracePath === void 0 ? {} : { tracePath: safeText(path24__default.default.basename(result.tracePath)) },
19198
19619
  artifacts: result.artifacts,
19199
19620
  diagnostics: result.diagnostics
19200
19621
  }));
@@ -19333,15 +19754,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
19333
19754
  return;
19334
19755
  }
19335
19756
  const markdown = renderMarkdown2(result);
19336
- const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path23__default.default.resolve(options.output.trim()) : void 0;
19757
+ const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path24__default.default.resolve(options.output.trim()) : void 0;
19337
19758
  if (outputPath !== void 0) {
19338
- await promises.mkdir(path23__default.default.dirname(outputPath), { recursive: true });
19759
+ await promises.mkdir(path24__default.default.dirname(outputPath), { recursive: true });
19339
19760
  await promises.writeFile(outputPath, markdown, "utf-8");
19340
19761
  }
19341
19762
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
19342
19763
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
19343
- const summaryPath = path23__default.default.resolve(summaryTarget);
19344
- await promises.mkdir(path23__default.default.dirname(summaryPath), { recursive: true });
19764
+ const summaryPath = path24__default.default.resolve(summaryTarget);
19765
+ await promises.mkdir(path24__default.default.dirname(summaryPath), { recursive: true });
19345
19766
  await promises.appendFile(summaryPath, `
19346
19767
  ${markdown}`, "utf-8");
19347
19768
  }
@@ -19489,8 +19910,8 @@ jobs:
19489
19910
  }
19490
19911
  async function planInit(options = {}) {
19491
19912
  const framework = normalizeFramework(options.framework);
19492
- const cwd = path23__default.default.resolve(options.cwd ?? process.cwd());
19493
- const demoPath = framework === "custom" ? path23__default.default.join("examples", "agent-inspect-demo.mjs") : path23__default.default.join("examples", `agent-inspect-${framework}-demo.mjs`);
19913
+ const cwd = path24__default.default.resolve(options.cwd ?? process.cwd());
19914
+ const demoPath = framework === "custom" ? path24__default.default.join("examples", "agent-inspect-demo.mjs") : path24__default.default.join("examples", `agent-inspect-${framework}-demo.mjs`);
19494
19915
  const candidates = [
19495
19916
  { rel: CONFIG_FILE, content: configTemplate(framework) },
19496
19917
  { rel: GITKEEP, content: "" },
@@ -19504,7 +19925,7 @@ async function planInit(options = {}) {
19504
19925
  }
19505
19926
  const files = [];
19506
19927
  for (const candidate of candidates) {
19507
- const abs = path23__default.default.join(cwd, candidate.rel);
19928
+ const abs = path24__default.default.join(cwd, candidate.rel);
19508
19929
  try {
19509
19930
  await promises.access(abs);
19510
19931
  files.push({
@@ -19525,12 +19946,12 @@ async function writePlannedFiles(plan, cwd, options) {
19525
19946
  if (entry.action === "skip") {
19526
19947
  continue;
19527
19948
  }
19528
- const abs = path23__default.default.join(cwd, entry.path);
19949
+ const abs = path24__default.default.join(cwd, entry.path);
19529
19950
  if (options.dryRun) {
19530
19951
  written.push(entry.path);
19531
19952
  continue;
19532
19953
  }
19533
- await promises.mkdir(path23__default.default.dirname(abs), { recursive: true });
19954
+ await promises.mkdir(path24__default.default.dirname(abs), { recursive: true });
19534
19955
  const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
19535
19956
  await promises.writeFile(abs, content, "utf-8");
19536
19957
  written.push(entry.path);
@@ -19538,7 +19959,7 @@ async function writePlannedFiles(plan, cwd, options) {
19538
19959
  return written;
19539
19960
  }
19540
19961
  async function initCommand(options = {}) {
19541
- const cwd = path23__default.default.resolve(options.cwd ?? process.cwd());
19962
+ const cwd = path24__default.default.resolve(options.cwd ?? process.cwd());
19542
19963
  try {
19543
19964
  const plan = await planInit({ ...options, cwd });
19544
19965
  const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
@@ -19629,7 +20050,7 @@ function envCheck(name, optional = true) {
19629
20050
  };
19630
20051
  }
19631
20052
  async function traceDirWritable(traceDir) {
19632
- const resolved = path23__default.default.resolve(traceDir);
20053
+ const resolved = path24__default.default.resolve(traceDir);
19633
20054
  try {
19634
20055
  await promises.mkdir(resolved, { recursive: true });
19635
20056
  await promises.access(resolved, promises.constants.W_OK);
@@ -19650,7 +20071,7 @@ async function traceDirWritable(traceDir) {
19650
20071
  }
19651
20072
  }
19652
20073
  function resolvePackage(cwd, name) {
19653
- const require2 = module$1.createRequire(path23__default.default.join(cwd, "package.json"));
20074
+ const require2 = module$1.createRequire(path24__default.default.join(cwd, "package.json"));
19654
20075
  try {
19655
20076
  const pkgPath = require2.resolve(`${name}/package.json`);
19656
20077
  const pkg = require2(pkgPath);
@@ -19661,7 +20082,7 @@ function resolvePackage(cwd, name) {
19661
20082
  }
19662
20083
  function importSmoke(cwd) {
19663
20084
  const results = [];
19664
- const require2 = module$1.createRequire(path23__default.default.join(cwd, "package.json"));
20085
+ const require2 = module$1.createRequire(path24__default.default.join(cwd, "package.json"));
19665
20086
  try {
19666
20087
  require2.resolve("agent-inspect");
19667
20088
  results.push({
@@ -19744,7 +20165,7 @@ function versionMismatchCheck(cwd) {
19744
20165
  };
19745
20166
  }
19746
20167
  async function runDoctorChecks(options = {}) {
19747
- const cwd = path23__default.default.resolve(options.cwd ?? process3__default.default.cwd());
20168
+ const cwd = path24__default.default.resolve(options.cwd ?? process3__default.default.cwd());
19748
20169
  const traceDir = options.traceDir?.trim() || process3__default.default.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
19749
20170
  const checks2 = [
19750
20171
  nodeVersionCheck(),
@@ -19858,7 +20279,7 @@ function createTraceDirectoryIndexer() {
19858
20279
  init_advanced();
19859
20280
  var INDEX_FILENAME = ".agent-inspect-index.json";
19860
20281
  function traceIndexPath(traceDir) {
19861
- return path23__default.default.join(traceDir, INDEX_FILENAME);
20282
+ return path24__default.default.join(traceDir, INDEX_FILENAME);
19862
20283
  }
19863
20284
  function parseMaxEntries(raw) {
19864
20285
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -20004,7 +20425,7 @@ async function newestTraceMtimeMs2(traceDir) {
20004
20425
  for (const file of files) {
20005
20426
  if (!file.endsWith(".jsonl")) continue;
20006
20427
  try {
20007
- const s = await promises.stat(path23__default.default.join(traceDir, file));
20428
+ const s = await promises.stat(path24__default.default.join(traceDir, file));
20008
20429
  if (s.mtimeMs > newest) newest = s.mtimeMs;
20009
20430
  } catch {
20010
20431
  }
@@ -20259,11 +20680,11 @@ function printJson5(value) {
20259
20680
  console.log(JSON.stringify(value, null, 2));
20260
20681
  }
20261
20682
  function resolveCwd(options) {
20262
- return path23__default.default.resolve(options.cwd ?? process.cwd());
20683
+ return path24__default.default.resolve(options.cwd ?? process.cwd());
20263
20684
  }
20264
20685
  async function suiteInitCommand(options = {}) {
20265
20686
  const cwd = resolveCwd(options);
20266
- const configPath = path23__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
20687
+ const configPath = path24__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
20267
20688
  const template = defaultSuiteConfigTemplate();
20268
20689
  if (options.dryRun) {
20269
20690
  if (options.json) {
@@ -20373,13 +20794,13 @@ async function suiteListCommand(options = {}) {
20373
20794
  }
20374
20795
  async function writeSuiteArtifact(result, configOutputDir, options) {
20375
20796
  const cwd = resolveCwd(options);
20376
- const outputDir = path23__default.default.resolve(
20797
+ const outputDir = path24__default.default.resolve(
20377
20798
  cwd,
20378
20799
  options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
20379
20800
  );
20380
20801
  await promises.mkdir(outputDir, { recursive: true });
20381
20802
  const stamp = result.startedAt.replace(/[:.]/g, "-");
20382
- const filePath = path23__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
20803
+ const filePath = path24__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
20383
20804
  await promises.writeFile(filePath, `${JSON.stringify(result, null, 2)}
20384
20805
  `, "utf-8");
20385
20806
  return filePath;
@@ -20437,7 +20858,7 @@ async function loadSuiteResultFromInput(options) {
20437
20858
  if (options.input === void 0 || options.input.trim() === "") {
20438
20859
  throw new Error("Pass --input <suite-run.json> from a prior suite run.");
20439
20860
  }
20440
- const inputPath = path23__default.default.resolve(cwd, options.input.trim());
20861
+ const inputPath = path24__default.default.resolve(cwd, options.input.trim());
20441
20862
  const raw = await promises.readFile(inputPath, "utf-8");
20442
20863
  return JSON.parse(raw);
20443
20864
  }
@@ -20474,9 +20895,9 @@ function normalizeMetrics2(raw) {
20474
20895
  }
20475
20896
  async function writeArtifacts(result, outputDir) {
20476
20897
  await promises.mkdir(outputDir, { recursive: true });
20477
- const jsonPath = path23__default.default.join(outputDir, "cohort-results.json");
20478
- const markdownPath = path23__default.default.join(outputDir, "cohort-summary.md");
20479
- const htmlPath = path23__default.default.join(outputDir, "cohort-report.html");
20898
+ const jsonPath = path24__default.default.join(outputDir, "cohort-results.json");
20899
+ const markdownPath = path24__default.default.join(outputDir, "cohort-summary.md");
20900
+ const htmlPath = path24__default.default.join(outputDir, "cohort-report.html");
20480
20901
  await promises.writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
20481
20902
  `, "utf-8");
20482
20903
  await promises.writeFile(
@@ -20504,7 +20925,7 @@ async function cohortCommand(options = {}) {
20504
20925
  const format = options.format ?? (options.json ? "json" : "markdown");
20505
20926
  let artifacts;
20506
20927
  if (options.output !== void 0 && options.output.trim() !== "") {
20507
- artifacts = await writeArtifacts(result, path23__default.default.resolve(options.output.trim()));
20928
+ artifacts = await writeArtifacts(result, path24__default.default.resolve(options.output.trim()));
20508
20929
  }
20509
20930
  if (options.json || format === "json") {
20510
20931
  console.log(
@@ -20544,6 +20965,135 @@ async function cohortCommand(options = {}) {
20544
20965
  }
20545
20966
  }
20546
20967
 
20968
+ // packages/cli/src/gate.ts
20969
+ init_advanced();
20970
+ var SUPPORTED_FORMATS = /* @__PURE__ */ new Set(["markdown", "json", "html", "junit", "github"]);
20971
+ function collectList(value) {
20972
+ if (value === void 0) return [];
20973
+ const items = Array.isArray(value) ? value : [value];
20974
+ return items.flatMap((item) => parseGateList(item));
20975
+ }
20976
+ function parseRate(value) {
20977
+ if (value === void 0 || value.trim() === "") return void 0;
20978
+ const parsed = Number(value);
20979
+ if (!Number.isFinite(parsed)) {
20980
+ throw new Error(`Invalid --max-error-rate: ${value}`);
20981
+ }
20982
+ return parsed;
20983
+ }
20984
+ function parseDuration2(value) {
20985
+ if (value === void 0 || value.trim() === "") return void 0;
20986
+ const parsed = Number(value);
20987
+ if (!Number.isFinite(parsed)) {
20988
+ throw new Error(`Invalid --max-p95-duration: ${value}`);
20989
+ }
20990
+ return parsed;
20991
+ }
20992
+ async function writeArtifacts2(result, outputDir) {
20993
+ await promises.mkdir(outputDir, { recursive: true });
20994
+ const paths = {
20995
+ jsonPath: path24__default.default.join(outputDir, "gate-results.json"),
20996
+ markdownPath: path24__default.default.join(outputDir, "gate-summary.md"),
20997
+ htmlPath: path24__default.default.join(outputDir, "gate-report.html"),
20998
+ junitPath: path24__default.default.join(outputDir, "junit.xml"),
20999
+ githubPath: path24__default.default.join(outputDir, "github-step-summary.md")
21000
+ };
21001
+ await promises.writeFile(
21002
+ paths.jsonPath,
21003
+ `${renderGateReport(result, { format: "json" })}
21004
+ `,
21005
+ "utf-8"
21006
+ );
21007
+ await promises.writeFile(
21008
+ paths.markdownPath,
21009
+ `${renderGateReport(result, { format: "markdown" })}
21010
+ `,
21011
+ "utf-8"
21012
+ );
21013
+ await promises.writeFile(
21014
+ paths.htmlPath,
21015
+ `${renderGateReport(result, { format: "html" })}
21016
+ `,
21017
+ "utf-8"
21018
+ );
21019
+ await promises.writeFile(
21020
+ paths.junitPath,
21021
+ `${renderGateReport(result, { format: "junit" })}
21022
+ `,
21023
+ "utf-8"
21024
+ );
21025
+ await promises.writeFile(
21026
+ paths.githubPath,
21027
+ `${renderGateReport(result, { format: "github" })}
21028
+ `,
21029
+ "utf-8"
21030
+ );
21031
+ return paths;
21032
+ }
21033
+ async function gateCommand(options = {}) {
21034
+ try {
21035
+ const format = options.format ?? (options.json ? "json" : "markdown");
21036
+ if (!SUPPORTED_FORMATS.has(format)) {
21037
+ if (options.json) {
21038
+ console.log(
21039
+ JSON.stringify({ ok: false, exitCode: 4, error: `Unsupported format: ${format}` }, null, 2)
21040
+ );
21041
+ } else {
21042
+ console.error(`[AgentInspect] Unsupported format: ${format}`);
21043
+ }
21044
+ process.exitCode = 4;
21045
+ return;
21046
+ }
21047
+ const gateOptions = {
21048
+ ...options.dir !== void 0 ? { traceDir: resolveTraceDir({ dir: options.dir }) } : {},
21049
+ ...options.suite !== void 0 ? { suitePath: options.suite } : {},
21050
+ ...options.cwd !== void 0 ? { cwd: options.cwd } : {},
21051
+ ...parseRate(options.maxErrorRate) !== void 0 ? { maxErrorRate: parseRate(options.maxErrorRate) } : {},
21052
+ ...parseDuration2(options.maxP95Duration) !== void 0 ? { maxP95DurationMs: parseDuration2(options.maxP95Duration) } : {},
21053
+ forbidTools: collectList(options.forbidTool),
21054
+ requireObservations: collectList(options.requireObservation)
21055
+ };
21056
+ let runs = [];
21057
+ const needsRuns = gateHasThresholds(gateOptions) || gateOptions.traceDir !== void 0 && gateOptions.suitePath === void 0;
21058
+ if (needsRuns) {
21059
+ const traceDir = gateOptions.traceDir ?? resolveTraceDir({ dir: options.dir });
21060
+ const loaded = await loadSessionRuns(traceDir);
21061
+ runs = loaded.runs;
21062
+ gateOptions.traceDir = traceDir;
21063
+ }
21064
+ const result = await runGate(runs, gateOptions);
21065
+ let artifacts;
21066
+ if (options.output !== void 0 && options.output.trim() !== "") {
21067
+ artifacts = await writeArtifacts2(result, path24__default.default.resolve(options.output.trim()));
21068
+ }
21069
+ if (options.json || format === "json") {
21070
+ console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
21071
+ } else if (format === "html") {
21072
+ console.log(renderGateReport(result, { format: "html" }));
21073
+ } else if (format === "junit") {
21074
+ console.log(renderGateReport(result, { format: "junit" }));
21075
+ } else if (format === "github") {
21076
+ console.log(renderGateReport(result, { format: "github" }));
21077
+ } else {
21078
+ console.log(renderGateReport(result, { format: "markdown" }));
21079
+ if (artifacts !== void 0) {
21080
+ console.log("");
21081
+ console.log("Artifacts:");
21082
+ for (const value of Object.values(artifacts)) console.log(`- ${value}`);
21083
+ }
21084
+ }
21085
+ process.exitCode = result.exitCode;
21086
+ } catch (error) {
21087
+ const message = error instanceof Error ? error.message : String(error);
21088
+ if (options.json) {
21089
+ console.log(JSON.stringify({ ok: false, exitCode: 2, error: message }, null, 2));
21090
+ } else {
21091
+ console.error(`[AgentInspect] gate failed: ${message}`);
21092
+ }
21093
+ process.exitCode = 2;
21094
+ }
21095
+ }
21096
+
20547
21097
  // packages/cli/src/index.ts
20548
21098
  function runCommand(action) {
20549
21099
  void action().catch((error) => {
@@ -20983,6 +21533,15 @@ function createCliProgram() {
20983
21533
  ).option("--format <format>", "markdown, json, or html", "markdown").option("-o, --output <dir>", "write cohort-results.json, cohort-summary.md, cohort-report.html").option("--json", "print deterministic JSON result").action((opts) => {
20984
21534
  runCommand(() => cohortCommand(opts));
20985
21535
  });
21536
+ program.command("gate").description("Run deterministic CI quality gates over traces or suites (v5.2+)").option("--dir <path>", "trace directory for threshold checks").option("--suite <path>", "suite config path").option("--max-error-rate <percent>", "maximum allowed error rate percentage").option("--max-p95-duration <ms>", "maximum allowed p95 run duration in ms").option("--forbid-tool <name>", "forbidden tool name (repeatable or comma-separated)").option(
21537
+ "--require-observation <name>",
21538
+ "required passed observation (repeatable or comma-separated)"
21539
+ ).option("--format <format>", "markdown, json, html, junit, or github", "markdown").option(
21540
+ "-o, --output <dir>",
21541
+ "write gate-results.json, gate-summary.md, gate-report.html, junit.xml, github-step-summary.md"
21542
+ ).option("--json", "print deterministic JSON result").action((opts) => {
21543
+ runCommand(() => gateCommand(opts));
21544
+ });
20986
21545
  return program;
20987
21546
  }
20988
21547
  function isPrimaryModule() {
@@ -20990,9 +21549,9 @@ function isPrimaryModule() {
20990
21549
  if (!entry) return false;
20991
21550
  const selfPath = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
20992
21551
  try {
20993
- return fs.realpathSync(path23__default.default.resolve(entry)) === fs.realpathSync(path23__default.default.resolve(selfPath));
21552
+ return fs.realpathSync(path24__default.default.resolve(entry)) === fs.realpathSync(path24__default.default.resolve(selfPath));
20994
21553
  } catch {
20995
- return path23__default.default.resolve(entry) === path23__default.default.resolve(selfPath);
21554
+ return path24__default.default.resolve(entry) === path24__default.default.resolve(selfPath);
20996
21555
  }
20997
21556
  }
20998
21557
  if (isPrimaryModule()) {