agent-inspect 2.1.0 → 2.3.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.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { realpathSync, createReadStream } from 'fs';
3
- import path11 from 'path';
3
+ import path13 from 'path';
4
4
  import { fileURLToPath, pathToFileURL } from 'url';
5
5
  import { Command, Option } from 'commander';
6
6
  import { AsyncLocalStorage } from 'async_hooks';
@@ -12,7 +12,7 @@ import tty from 'tty';
12
12
  import { createInterface } from 'readline';
13
13
 
14
14
  // package.json
15
- var version = "2.1.0";
15
+ var version = "2.3.0";
16
16
 
17
17
  // packages/core/src/correlation-metadata.ts
18
18
  var TRACE_CORRELATION_KEYS = [
@@ -744,7 +744,7 @@ function formatDuration(ms) {
744
744
  // packages/core/src/utils.ts
745
745
  var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
746
746
  var RUNS_DIR_NAME = "runs";
747
- var FALLBACK_TRACE_DIR = path11.join(
747
+ var FALLBACK_TRACE_DIR = path13.join(
748
748
  os.tmpdir(),
749
749
  "agent-inspect",
750
750
  RUNS_DIR_NAME
@@ -779,7 +779,7 @@ function getDefaultTraceDir() {
779
779
  if (typeof home !== "string" || home.trim() === "") {
780
780
  return FALLBACK_TRACE_DIR;
781
781
  }
782
- return path11.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
782
+ return path13.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
783
783
  } catch {
784
784
  return FALLBACK_TRACE_DIR;
785
785
  }
@@ -787,11 +787,11 @@ function getDefaultTraceDir() {
787
787
  function getTraceFilePath(runId, traceDir) {
788
788
  const baseDir = traceDir ?? getDefaultTraceDir();
789
789
  let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
790
- safeId = path11.basename(safeId);
790
+ safeId = path13.basename(safeId);
791
791
  if (safeId === "" || safeId === "." || safeId === "..") {
792
792
  safeId = "run_unknown";
793
793
  }
794
- return path11.join(baseDir, `${safeId}.jsonl`);
794
+ return path13.join(baseDir, `${safeId}.jsonl`);
795
795
  }
796
796
  function formatError(error) {
797
797
  if (error instanceof Error) {
@@ -1553,7 +1553,7 @@ var TraceDirectory = class {
1553
1553
  this.#dir = resolveTraceDir(options);
1554
1554
  }
1555
1555
  getPath(filename) {
1556
- return filename ? path11.join(this.#dir, filename) : this.#dir;
1556
+ return filename ? path13.join(this.#dir, filename) : this.#dir;
1557
1557
  }
1558
1558
  async list() {
1559
1559
  try {
@@ -1580,7 +1580,7 @@ function parseIsoToMs2(value) {
1580
1580
  }
1581
1581
  async function extractMetadata(filePath, _quickScan) {
1582
1582
  const stats = await stat(filePath);
1583
- let runIdFromFile = path11.basename(filePath);
1583
+ let runIdFromFile = path13.basename(filePath);
1584
1584
  if (runIdFromFile.endsWith(".jsonl")) {
1585
1585
  runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
1586
1586
  }
@@ -3551,7 +3551,7 @@ function findReaderByFormat(format, readers) {
3551
3551
  }
3552
3552
  async function jsonlFilesInDirectory(dirPath) {
3553
3553
  const entries = await readdir(dirPath, { withFileTypes: true });
3554
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path11.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
3554
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path13.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
3555
3555
  }
3556
3556
  async function resolveInput(input3) {
3557
3557
  const cached = resolvedInputCache.get(input3);
@@ -7677,9 +7677,9 @@ Trace directory: ${traceDir}`);
7677
7677
  if (validation !== void 0 && !validation.ok) {
7678
7678
  process.exitCode = 1;
7679
7679
  }
7680
- const outPath = options.output !== void 0 && options.output.trim() !== "" ? path11.resolve(options.output.trim()) : void 0;
7680
+ const outPath = options.output !== void 0 && options.output.trim() !== "" ? path13.resolve(options.output.trim()) : void 0;
7681
7681
  if (outPath !== void 0) {
7682
- await mkdir(path11.dirname(outPath), { recursive: true });
7682
+ await mkdir(path13.dirname(outPath), { recursive: true });
7683
7683
  await writeFile(outPath, result.content, "utf-8");
7684
7684
  const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
7685
7685
  console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
@@ -7856,13 +7856,13 @@ function pairSteps(left, right) {
7856
7856
  return pairs;
7857
7857
  }
7858
7858
  function compareLeafSteps(L, R, segments, opts, out) {
7859
- const path13 = buildPath(segments);
7859
+ const path15 = buildPath(segments);
7860
7860
  if (L.name !== R.name) {
7861
7861
  out.push({
7862
7862
  kind: "structure",
7863
7863
  severity: "warning",
7864
7864
  message: "Step name differs",
7865
- path: path13,
7865
+ path: path15,
7866
7866
  left: L.name,
7867
7867
  right: R.name
7868
7868
  });
@@ -7872,7 +7872,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7872
7872
  kind: "step-type",
7873
7873
  severity: "warning",
7874
7874
  message: "Step type differs",
7875
- path: path13,
7875
+ path: path15,
7876
7876
  left: L.type,
7877
7877
  right: R.type
7878
7878
  });
@@ -7882,7 +7882,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7882
7882
  kind: "step-status",
7883
7883
  severity: "warning",
7884
7884
  message: "Step status differs",
7885
- path: path13,
7885
+ path: path15,
7886
7886
  left: L.status,
7887
7887
  right: R.status
7888
7888
  });
@@ -7894,7 +7894,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7894
7894
  kind: "error",
7895
7895
  severity: "error",
7896
7896
  message: "Step error message differs",
7897
- path: path13,
7897
+ path: path15,
7898
7898
  left: le || void 0,
7899
7899
  right: re || void 0
7900
7900
  });
@@ -7912,7 +7912,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7912
7912
  kind: "duration",
7913
7913
  severity: "info",
7914
7914
  message: "Step duration differs",
7915
- path: path13,
7915
+ path: path15,
7916
7916
  left: ld,
7917
7917
  right: rd
7918
7918
  });
@@ -7925,7 +7925,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7925
7925
  kind: "metadata",
7926
7926
  severity: "info",
7927
7927
  message: "Step metadata differs",
7928
- path: path13,
7928
+ path: path15,
7929
7929
  left: L.metadata,
7930
7930
  right: R.metadata
7931
7931
  });
@@ -7937,7 +7937,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7937
7937
  kind: "output",
7938
7938
  severity: "info",
7939
7939
  message: "Output preview differs",
7940
- path: path13,
7940
+ path: path15,
7941
7941
  left: L.outputPreview,
7942
7942
  right: R.outputPreview
7943
7943
  });
@@ -8097,11 +8097,11 @@ function diffRuns(left, right, options) {
8097
8097
  }
8098
8098
 
8099
8099
  // packages/core/src/diff/renderer.ts
8100
- function formatPath(path13) {
8101
- if (path13 === void 0 || path13.path.length === 0) {
8100
+ function formatPath(path15) {
8101
+ if (path15 === void 0 || path15.path.length === 0) {
8102
8102
  return "(run)";
8103
8103
  }
8104
- return path13.path.map((s) => s.name).join(" > ");
8104
+ return path15.path.map((s) => s.name).join(" > ");
8105
8105
  }
8106
8106
  function formatValue(v, verbose) {
8107
8107
  if (v === void 0) return "(undefined)";
@@ -8532,9 +8532,9 @@ async function reportCommand(runId, options = {}) {
8532
8532
  redactionProfile,
8533
8533
  correlation: !options.noCorrelation
8534
8534
  });
8535
- const outPath = options.output !== void 0 && options.output.trim() !== "" ? path11.resolve(options.output.trim()) : void 0;
8535
+ const outPath = options.output !== void 0 && options.output.trim() !== "" ? path13.resolve(options.output.trim()) : void 0;
8536
8536
  if (outPath !== void 0) {
8537
- await mkdir(path11.dirname(outPath), { recursive: true });
8537
+ await mkdir(path13.dirname(outPath), { recursive: true });
8538
8538
  await writeFile(outPath, result.content, "utf-8");
8539
8539
  console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
8540
8540
  }
@@ -8781,17 +8781,17 @@ function applyRule(rule, value, replacement) {
8781
8781
  }
8782
8782
  return value;
8783
8783
  }
8784
- function childPath(path13, key) {
8784
+ function childPath(path15, key) {
8785
8785
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
8786
- return path13 ? `${path13}.${key}` : key;
8786
+ return path15 ? `${path15}.${key}` : key;
8787
8787
  }
8788
- return `${path13 || "$"}[${JSON.stringify(key)}]`;
8788
+ return `${path15 || "$"}[${JSON.stringify(key)}]`;
8789
8789
  }
8790
- function indexPath(path13, index) {
8791
- return `${path13 || "$"}[${index}]`;
8790
+ function indexPath(path15, index) {
8791
+ return `${path15 || "$"}[${index}]`;
8792
8792
  }
8793
- function makeFinding(path13, detector, action, matchKind, severity = "warning", preview) {
8794
- return preview === void 0 ? { path: path13, detector, action, severity, matchKind } : { path: path13, detector, action, severity, matchKind, preview };
8793
+ function makeFinding(path15, detector, action, matchKind, severity = "warning", preview) {
8794
+ return preview === void 0 ? { path: path15, detector, action, severity, matchKind } : { path: path15, detector, action, severity, matchKind, preview };
8795
8795
  }
8796
8796
  function createRedactionProfile(profile = "local") {
8797
8797
  switch (profile) {
@@ -8860,11 +8860,11 @@ var Redactor2 = class {
8860
8860
  #recordFinding(state, finding) {
8861
8861
  if (this.#collectFindings) state.findings.push(finding);
8862
8862
  }
8863
- #redactValue(value, key, path13, depth, state) {
8863
+ #redactValue(value, key, path15, depth, state) {
8864
8864
  if (depth > this.#maxDepth) {
8865
8865
  this.#recordFinding(
8866
8866
  state,
8867
- makeFinding(path13, "structure.maxDepth", "truncate", "value", "warning")
8867
+ makeFinding(path15, "structure.maxDepth", "truncate", "value", "warning")
8868
8868
  );
8869
8869
  return "[Truncated]";
8870
8870
  }
@@ -8873,19 +8873,19 @@ var Redactor2 = class {
8873
8873
  if (rule) {
8874
8874
  this.#recordFinding(
8875
8875
  state,
8876
- makeFinding(path13, `key.${rule.key}`, actionForRule(rule), "key", "warning")
8876
+ makeFinding(path15, `key.${rule.key}`, actionForRule(rule), "key", "warning")
8877
8877
  );
8878
8878
  return applyRule(rule, value, this.#replacement);
8879
8879
  }
8880
8880
  }
8881
8881
  for (const detector of this.#detectors) {
8882
- const detections = detector.detect({ path: path13, key, value });
8882
+ const detections = detector.detect({ path: path15, key, value });
8883
8883
  for (const detection of detections) {
8884
8884
  const action = detection.action ?? "replace";
8885
8885
  this.#recordFinding(
8886
8886
  state,
8887
8887
  makeFinding(
8888
- path13,
8888
+ path15,
8889
8889
  detector.id,
8890
8890
  action,
8891
8891
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -8903,7 +8903,7 @@ var Redactor2 = class {
8903
8903
  const out = [];
8904
8904
  state.seen.set(value, out);
8905
8905
  value.forEach((item, index) => {
8906
- out[index] = this.#redactValue(item, void 0, indexPath(path13, index), depth + 1, state);
8906
+ out[index] = this.#redactValue(item, void 0, indexPath(path15, index), depth + 1, state);
8907
8907
  });
8908
8908
  return out;
8909
8909
  }
@@ -8915,7 +8915,7 @@ var Redactor2 = class {
8915
8915
  out[entryKey] = this.#redactValue(
8916
8916
  entryValue,
8917
8917
  entryKey,
8918
- childPath(path13 === "$" ? "" : path13, entryKey),
8918
+ childPath(path15 === "$" ? "" : path15, entryKey),
8919
8919
  depth + 1,
8920
8920
  state
8921
8921
  );
@@ -9362,14 +9362,14 @@ function uniqueSorted(values) {
9362
9362
  return [...new Set(values)].sort();
9363
9363
  }
9364
9364
  function isWithinDirectory(child, parent) {
9365
- const relative = path11.relative(parent, child);
9366
- return relative === "" || !relative.startsWith("..") && !path11.isAbsolute(relative);
9365
+ const relative = path13.relative(parent, child);
9366
+ return relative === "" || !relative.startsWith("..") && !path13.isAbsolute(relative);
9367
9367
  }
9368
9368
  async function resolveOutputPath(inputPath, output2, force) {
9369
9369
  if (output2 === void 0 || output2.trim() === "") return void 0;
9370
- const inputAbs = path11.resolve(inputPath);
9371
- const outputAbs = path11.resolve(output2.trim());
9372
- const inputDir = path11.dirname(inputAbs);
9370
+ const inputAbs = path13.resolve(inputPath);
9371
+ const outputAbs = path13.resolve(output2.trim());
9372
+ const inputDir = path13.dirname(inputAbs);
9373
9373
  if (!isWithinDirectory(outputAbs, inputDir)) {
9374
9374
  throw new Error("Refusing to write migrated output outside the input directory.");
9375
9375
  }
@@ -9490,7 +9490,7 @@ async function migrateCommand(input3, options = {}) {
9490
9490
  process.exitCode = 1;
9491
9491
  return;
9492
9492
  }
9493
- const inputPath = path11.resolve(input3.trim());
9493
+ const inputPath = path13.resolve(input3.trim());
9494
9494
  const dryRun = options.dryRun === true;
9495
9495
  if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
9496
9496
  console.error("migrate requires --dry-run or --output <path>.");
@@ -9509,7 +9509,7 @@ async function migrateCommand(input3, options = {}) {
9509
9509
  );
9510
9510
  const result = await buildMigration(inputPath, outputPath);
9511
9511
  if (!dryRun && outputPath !== void 0) {
9512
- await mkdir(path11.dirname(outputPath), { recursive: true });
9512
+ await mkdir(path13.dirname(outputPath), { recursive: true });
9513
9513
  await writeFile(outputPath, result.content, "utf-8");
9514
9514
  }
9515
9515
  printSummary2(result, dryRun);
@@ -9787,7 +9787,7 @@ function stripPrefix(name, prefixes) {
9787
9787
  }
9788
9788
  return name;
9789
9789
  }
9790
- function eventEvidence(event, path13) {
9790
+ function eventEvidence(event, path15) {
9791
9791
  return {
9792
9792
  runId: event.runId,
9793
9793
  eventId: event.eventId,
@@ -9797,7 +9797,7 @@ function eventEvidence(event, path13) {
9797
9797
  kind: event.kind,
9798
9798
  name: event.name,
9799
9799
  status: event.status,
9800
- ...path13 ? { path: path13 } : {}
9800
+ ...path15 ? { path: path15 } : {}
9801
9801
  };
9802
9802
  }
9803
9803
  function runEvidence(run) {
@@ -9860,9 +9860,9 @@ function eventEndMs(event) {
9860
9860
  function normalizedKey(value) {
9861
9861
  return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
9862
9862
  }
9863
- function lastPathSegment(path13) {
9864
- const parts = path13.split(".");
9865
- return parts[parts.length - 1] ?? path13;
9863
+ function lastPathSegment(path15) {
9864
+ const parts = path15.split(".");
9865
+ return parts[parts.length - 1] ?? path15;
9866
9866
  }
9867
9867
  function valueType(value) {
9868
9868
  if (Array.isArray(value)) return "array";
@@ -9876,12 +9876,12 @@ function serializedByteLength(value) {
9876
9876
  return void 0;
9877
9877
  }
9878
9878
  }
9879
- function pushValueEntries(entries, event, value, path13, key, depth = 0) {
9880
- entries.push({ event, path: path13, key, value });
9879
+ function pushValueEntries(entries, event, value, path15, key, depth = 0) {
9880
+ entries.push({ event, path: path15, key, value });
9881
9881
  if (depth >= 8) return;
9882
9882
  if (Array.isArray(value)) {
9883
9883
  for (const [index, item] of value.entries()) {
9884
- pushValueEntries(entries, event, item, `${path13}.${index}`, String(index), depth + 1);
9884
+ pushValueEntries(entries, event, item, `${path15}.${index}`, String(index), depth + 1);
9885
9885
  }
9886
9886
  return;
9887
9887
  }
@@ -9891,7 +9891,7 @@ function pushValueEntries(entries, event, value, path13, key, depth = 0) {
9891
9891
  entries,
9892
9892
  event,
9893
9893
  value[nestedKey],
9894
- `${path13}.${nestedKey}`,
9894
+ `${path15}.${nestedKey}`,
9895
9895
  nestedKey,
9896
9896
  depth + 1
9897
9897
  );
@@ -9972,9 +9972,9 @@ function eventDurationMs(event) {
9972
9972
  }
9973
9973
  function treeShape(nodes) {
9974
9974
  const lines = [];
9975
- const visit = (node, path13) => {
9976
- lines.push(`${path13}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
9977
- node.children.forEach((child, index) => visit(child, `${path13}.${index}`));
9975
+ const visit = (node, path15) => {
9976
+ lines.push(`${path15}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
9977
+ node.children.forEach((child, index) => visit(child, `${path15}.${index}`));
9978
9978
  };
9979
9979
  nodes.forEach((node, index) => visit(node, String(index)));
9980
9980
  return lines;
@@ -10023,9 +10023,9 @@ function retrievalShape(context) {
10023
10023
  function guardrailShape(context) {
10024
10024
  return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
10025
10025
  }
10026
- function firstEvidenceForKind(context, kind, path13) {
10026
+ function firstEvidenceForKind(context, kind, path15) {
10027
10027
  const event = context.events.find((candidate) => candidate.kind === kind);
10028
- return event ? [eventEvidence(event, path13)] : runEvidence(context.selectedRun);
10028
+ return event ? [eventEvidence(event, path15)] : runEvidence(context.selectedRun);
10029
10029
  }
10030
10030
  function baselineDiffFinding(message, evidence, expected, actual) {
10031
10031
  return failFinding("baseline.regression", message, evidence, expected, actual);
@@ -10273,13 +10273,13 @@ function createStructureCycleRule() {
10273
10273
  const seenCycles = /* @__PURE__ */ new Set();
10274
10274
  const findings = [];
10275
10275
  for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
10276
- const path13 = [];
10276
+ const path15 = [];
10277
10277
  const seenAt = /* @__PURE__ */ new Map();
10278
10278
  let current = event;
10279
10279
  while (current) {
10280
10280
  const existing = seenAt.get(current.eventId);
10281
10281
  if (existing !== void 0) {
10282
- const cycle = path13.slice(existing);
10282
+ const cycle = path15.slice(existing);
10283
10283
  const key = cycle.map((item) => item.eventId).sort().join("\0");
10284
10284
  if (!seenCycles.has(key)) {
10285
10285
  seenCycles.add(key);
@@ -10295,8 +10295,8 @@ function createStructureCycleRule() {
10295
10295
  }
10296
10296
  break;
10297
10297
  }
10298
- seenAt.set(current.eventId, path13.length);
10299
- path13.push(current);
10298
+ seenAt.set(current.eventId, path15.length);
10299
+ path15.push(current);
10300
10300
  current = current.parentId ? byId.get(current.parentId) : void 0;
10301
10301
  }
10302
10302
  }
@@ -10821,7 +10821,7 @@ function asConfig(value) {
10821
10821
  }
10822
10822
  async function loadConfig(configPath) {
10823
10823
  if (configPath === void 0) return {};
10824
- const extension = path11.extname(configPath);
10824
+ const extension = path13.extname(configPath);
10825
10825
  if (TS_CONFIG_EXTENSIONS.has(extension)) {
10826
10826
  throw new Error(
10827
10827
  "TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -10830,7 +10830,7 @@ async function loadConfig(configPath) {
10830
10830
  if (!CONFIG_EXTENSIONS.has(extension)) {
10831
10831
  throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
10832
10832
  }
10833
- const absolute = path11.resolve(configPath);
10833
+ const absolute = path13.resolve(configPath);
10834
10834
  if (extension === ".json") {
10835
10835
  const raw = await readFile(absolute, "utf-8");
10836
10836
  return asConfig(JSON.parse(raw));
@@ -10952,8 +10952,8 @@ function printHuman(result) {
10952
10952
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
10953
10953
  }
10954
10954
  for (const finding of result.findings) {
10955
- const path13 = finding.evidence[0]?.path;
10956
- console.log(`- ${finding.ruleId}: ${finding.message}${path13 ? ` (${path13})` : ""}`);
10955
+ const path15 = finding.evidence[0]?.path;
10956
+ console.log(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
10957
10957
  }
10958
10958
  }
10959
10959
  function readErrorResult(error) {
@@ -11175,10 +11175,10 @@ async function evalRun(input3, options = {}) {
11175
11175
  diagnostics: []
11176
11176
  };
11177
11177
  }
11178
- function evidenceForRun(run, path13) {
11179
- return [{ runId: run.runId, ...path13 !== void 0 ? { path: path13 } : {} }];
11178
+ function evidenceForRun(run, path15) {
11179
+ return [{ runId: run.runId, ...path15 !== void 0 ? { path: path15 } : {} }];
11180
11180
  }
11181
- function evidenceForEvent(event, path13) {
11181
+ function evidenceForEvent(event, path15) {
11182
11182
  return [
11183
11183
  {
11184
11184
  runId: event.runId,
@@ -11186,7 +11186,7 @@ function evidenceForEvent(event, path13) {
11186
11186
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
11187
11187
  kind: event.kind,
11188
11188
  name: event.name,
11189
- ...path13 !== void 0 ? { path: path13 } : {}
11189
+ ...path15 !== void 0 ? { path: path15 } : {}
11190
11190
  }
11191
11191
  ];
11192
11192
  }
@@ -11344,9 +11344,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
11344
11344
  function tokenize(text) {
11345
11345
  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));
11346
11346
  }
11347
- function firstEvidence(fields, run, path13) {
11347
+ function firstEvidence(fields, run, path15) {
11348
11348
  const first = fields[0];
11349
- return first === void 0 ? evidenceForRun(run, path13) : evidenceForEvent(first.node.event, first.path);
11349
+ return first === void 0 ? evidenceForRun(run, path15) : evidenceForEvent(first.node.event, first.path);
11350
11350
  }
11351
11351
  function collectSourceIds(nodes, keys) {
11352
11352
  const wanted = keySet(keys);
@@ -11723,8 +11723,8 @@ function renderEvalMarkdown(result) {
11723
11723
  if (result.findings.length > 0) {
11724
11724
  lines.push("", "## Findings");
11725
11725
  for (const finding of result.findings) {
11726
- const path13 = finding.evidence[0]?.path;
11727
- lines.push(`- ${finding.ruleId}: ${finding.message}${path13 ? ` (${path13})` : ""}`);
11726
+ const path15 = finding.evidence[0]?.path;
11727
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
11728
11728
  }
11729
11729
  }
11730
11730
  return `${lines.join("\n")}
@@ -11771,7 +11771,7 @@ function asConfig2(value) {
11771
11771
  }
11772
11772
  async function loadConfig2(configPath) {
11773
11773
  if (configPath === void 0) return {};
11774
- const extension = path11.extname(configPath);
11774
+ const extension = path13.extname(configPath);
11775
11775
  if (TS_CONFIG_EXTENSIONS2.has(extension)) {
11776
11776
  throw new Error(
11777
11777
  "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -11780,7 +11780,7 @@ async function loadConfig2(configPath) {
11780
11780
  if (!CONFIG_EXTENSIONS2.has(extension)) {
11781
11781
  throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
11782
11782
  }
11783
- const absolute = path11.resolve(configPath);
11783
+ const absolute = path13.resolve(configPath);
11784
11784
  if (extension === ".json") {
11785
11785
  const raw = await readFile(absolute, "utf-8");
11786
11786
  return asConfig2(JSON.parse(raw));
@@ -11917,8 +11917,8 @@ function printHuman2(result) {
11917
11917
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
11918
11918
  }
11919
11919
  for (const finding of result.findings) {
11920
- const path13 = finding.evidence[0]?.path;
11921
- console.log(`- ${finding.ruleId}: ${finding.message}${path13 ? ` (${path13})` : ""}`);
11920
+ const path15 = finding.evidence[0]?.path;
11921
+ console.log(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
11922
11922
  }
11923
11923
  }
11924
11924
  function readErrorResult2(error) {
@@ -12156,8 +12156,8 @@ function printHuman3(result) {
12156
12156
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
12157
12157
  }
12158
12158
  for (const finding of result.findings) {
12159
- const path13 = finding.evidence[0]?.path;
12160
- console.log(`- ${finding.ruleId}: ${finding.message}${path13 ? ` (${path13})` : ""}`);
12159
+ const path15 = finding.evidence[0]?.path;
12160
+ console.log(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
12161
12161
  }
12162
12162
  console.log(`Note: ${result.note}`);
12163
12163
  }
@@ -12276,8 +12276,8 @@ function renderCheckSection(result) {
12276
12276
  `Diagnostics: ${result.diagnostics.length}`
12277
12277
  ];
12278
12278
  for (const finding of result.findings.slice(0, 10)) {
12279
- const path13 = finding.evidence[0]?.path ?? "(run)";
12280
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path13})`);
12279
+ const path15 = finding.evidence[0]?.path ?? "(run)";
12280
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path15})`);
12281
12281
  }
12282
12282
  for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
12283
12283
  lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
@@ -12355,8 +12355,8 @@ function renderHtml(trace, check, diff) {
12355
12355
  `;
12356
12356
  }
12357
12357
  async function writeArtifact(outputDir, relativePath, content, files) {
12358
- const outPath = path11.join(outputDir, relativePath);
12359
- await mkdir(path11.dirname(outPath), { recursive: true });
12358
+ const outPath = path13.join(outputDir, relativePath);
12359
+ await mkdir(path13.dirname(outPath), { recursive: true });
12360
12360
  await writeFile(outPath, content, "utf-8");
12361
12361
  files.push(relativePath);
12362
12362
  }
@@ -12372,7 +12372,7 @@ function manifestStatus(check, diff) {
12372
12372
  return "ok";
12373
12373
  }
12374
12374
  async function artifactsCommand(target, options = {}, stdin = process.stdin) {
12375
- const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path11.resolve(options.outputDir.trim()) : "";
12375
+ const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path13.resolve(options.outputDir.trim()) : "";
12376
12376
  if (outputDir === "") {
12377
12377
  console.error("--output-dir is required.");
12378
12378
  process.exitCode = 1;
@@ -12438,8 +12438,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
12438
12438
  await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
12439
12439
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
12440
12440
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
12441
- await mkdir(path11.dirname(path11.resolve(summaryTarget)), { recursive: true });
12442
- await appendFile(path11.resolve(summaryTarget), `
12441
+ await mkdir(path13.dirname(path13.resolve(summaryTarget)), { recursive: true });
12442
+ await appendFile(path13.resolve(summaryTarget), `
12443
12443
  ${renderMarkdown(trace, check, diff)}`, "utf-8");
12444
12444
  }
12445
12445
  const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
@@ -12458,10 +12458,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
12458
12458
  findings: diff?.findings.length ?? 0,
12459
12459
  diagnostics: diff?.diagnostics.length ?? 0
12460
12460
  },
12461
- ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path11.resolve(summaryTarget) } : {},
12461
+ ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path13.resolve(summaryTarget) } : {},
12462
12462
  note: NOTE
12463
12463
  };
12464
- await writeFile(path11.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
12464
+ await writeFile(path13.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
12465
12465
  if (options.json === true) {
12466
12466
  console.log(writeJson3(manifest).trimEnd());
12467
12467
  } else {
@@ -12472,6 +12472,371 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
12472
12472
  }
12473
12473
  }
12474
12474
  }
12475
+ function validateReporterArtifactPath(options) {
12476
+ const outputDir = path13.resolve(options.outputDir);
12477
+ const diagnostics = [];
12478
+ const rawPath = options.relativePath;
12479
+ if (rawPath.length === 0) {
12480
+ diagnostics.push({
12481
+ code: "artifact_path_empty",
12482
+ severity: "error",
12483
+ message: "Reporter artifact path must not be empty."
12484
+ });
12485
+ return { ok: false, outputDir, diagnostics };
12486
+ }
12487
+ if (rawPath.includes("\0")) {
12488
+ diagnostics.push({
12489
+ code: "invalid_artifact_path",
12490
+ severity: "error",
12491
+ message: "Reporter artifact path must not contain null bytes.",
12492
+ target: rawPath
12493
+ });
12494
+ return { ok: false, outputDir, diagnostics };
12495
+ }
12496
+ if (path13.isAbsolute(rawPath) || path13.win32.isAbsolute(rawPath)) {
12497
+ diagnostics.push({
12498
+ code: "artifact_path_absolute",
12499
+ severity: "error",
12500
+ message: "Reporter artifact path must be relative.",
12501
+ target: rawPath
12502
+ });
12503
+ return { ok: false, outputDir, diagnostics };
12504
+ }
12505
+ const normalized = path13.posix.normalize(rawPath.replace(/\\/g, "/"));
12506
+ const segments = normalized.split("/");
12507
+ if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
12508
+ diagnostics.push({
12509
+ code: "artifact_path_escape",
12510
+ severity: "error",
12511
+ message: "Reporter artifact path must stay under the output directory.",
12512
+ target: rawPath
12513
+ });
12514
+ return { ok: false, outputDir, diagnostics };
12515
+ }
12516
+ const absolutePath = path13.resolve(outputDir, normalized);
12517
+ const relFromOutput = path13.relative(outputDir, absolutePath);
12518
+ if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path13.isAbsolute(relFromOutput)) {
12519
+ diagnostics.push({
12520
+ code: "artifact_path_escape",
12521
+ severity: "error",
12522
+ message: "Reporter artifact path resolved outside the output directory.",
12523
+ target: rawPath
12524
+ });
12525
+ return { ok: false, outputDir, diagnostics };
12526
+ }
12527
+ return {
12528
+ ok: true,
12529
+ outputDir,
12530
+ relativePath: normalized,
12531
+ absolutePath,
12532
+ diagnostics
12533
+ };
12534
+ }
12535
+
12536
+ // packages/cli/src/ci-summary.ts
12537
+ var NOTE2 = "Generated locally by AgentInspect from reporter artifact manifests. Trace contents are not embedded.";
12538
+ var MAX_TEXT = 180;
12539
+ var FRAMEWORKS = /* @__PURE__ */ new Set(["vitest", "jest", "manual"]);
12540
+ var STATUSES = /* @__PURE__ */ new Set(["passed", "failed", "skipped", "todo"]);
12541
+ var ARTIFACT_KINDS = /* @__PURE__ */ new Set(["trace", "report", "eval", "redaction", "summary"]);
12542
+ var ARTIFACT_FORMATS = /* @__PURE__ */ new Set(["json", "jsonl", "md", "html"]);
12543
+ var REDACTION_PROFILES = /* @__PURE__ */ new Set(["local", "share", "strict"]);
12544
+ function stable6(value) {
12545
+ if (Array.isArray(value)) return value.map(stable6);
12546
+ if (value === null || typeof value !== "object") return value;
12547
+ const record = value;
12548
+ return Object.fromEntries(
12549
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable6(record[key])])
12550
+ );
12551
+ }
12552
+ function writeJson4(value) {
12553
+ return `${JSON.stringify(stable6(value), null, 2)}
12554
+ `;
12555
+ }
12556
+ function isObject(value) {
12557
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12558
+ }
12559
+ function readString(value, label) {
12560
+ if (typeof value !== "string" || value.trim() === "") {
12561
+ throw new Error(`${label} must be a non-empty string.`);
12562
+ }
12563
+ return safeText(value);
12564
+ }
12565
+ function readOptionalString(value) {
12566
+ return typeof value === "string" && value.trim() !== "" ? safeText(value) : void 0;
12567
+ }
12568
+ function readFramework(value) {
12569
+ const framework = readString(value, "manifest.framework");
12570
+ if (!FRAMEWORKS.has(framework)) {
12571
+ throw new Error(`Unsupported reporter framework: ${framework}.`);
12572
+ }
12573
+ return framework;
12574
+ }
12575
+ function readStatus(value) {
12576
+ const status = readString(value, "result.status");
12577
+ if (!STATUSES.has(status)) {
12578
+ throw new Error(`Unsupported reporter test status: ${status}.`);
12579
+ }
12580
+ return status;
12581
+ }
12582
+ function readArtifact(value, index) {
12583
+ if (!isObject(value)) throw new Error(`manifest.artifacts[${index}] must be an object.`);
12584
+ const kind = readString(value.kind, `manifest.artifacts[${index}].kind`);
12585
+ const format = readString(value.format, `manifest.artifacts[${index}].format`);
12586
+ const redactionProfile = readString(
12587
+ value.redactionProfile,
12588
+ `manifest.artifacts[${index}].redactionProfile`
12589
+ );
12590
+ if (!ARTIFACT_KINDS.has(kind)) throw new Error(`Unsupported artifact kind: ${kind}.`);
12591
+ if (!ARTIFACT_FORMATS.has(format)) throw new Error(`Unsupported artifact format: ${format}.`);
12592
+ if (!REDACTION_PROFILES.has(redactionProfile)) {
12593
+ throw new Error(`Unsupported artifact redaction profile: ${redactionProfile}.`);
12594
+ }
12595
+ const artifactPath = readString(value.path, `manifest.artifacts[${index}].path`);
12596
+ const pathCheck = validateReporterArtifactPath({
12597
+ outputDir: process.cwd(),
12598
+ relativePath: artifactPath
12599
+ });
12600
+ if (!pathCheck.ok || pathCheck.relativePath === void 0) {
12601
+ throw new Error(`Unsafe reporter artifact path: ${artifactPath}.`);
12602
+ }
12603
+ return {
12604
+ kind,
12605
+ path: pathCheck.relativePath,
12606
+ format,
12607
+ redactionProfile
12608
+ };
12609
+ }
12610
+ function readArtifacts(value, label) {
12611
+ if (value === void 0) return [];
12612
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
12613
+ return value.map((item, index) => readArtifact(item, index));
12614
+ }
12615
+ function readDiagnosticsCount(value, label) {
12616
+ if (value === void 0) return 0;
12617
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
12618
+ return value.length;
12619
+ }
12620
+ function readResult(value, index) {
12621
+ if (!isObject(value)) throw new Error(`manifest.results[${index}] must be an object.`);
12622
+ const file = readOptionalString(value.file);
12623
+ const tracePath = readOptionalString(value.tracePath);
12624
+ return {
12625
+ testId: readString(value.testId, `manifest.results[${index}].testId`),
12626
+ name: readString(value.name, `manifest.results[${index}].name`),
12627
+ ...file === void 0 ? {} : { file },
12628
+ status: readStatus(value.status),
12629
+ ...tracePath === void 0 ? {} : { tracePath },
12630
+ artifacts: readArtifacts(value.artifacts, `manifest.results[${index}].artifacts`),
12631
+ diagnostics: readDiagnosticsCount(
12632
+ value.diagnostics,
12633
+ `manifest.results[${index}].diagnostics`
12634
+ )
12635
+ };
12636
+ }
12637
+ function readManifestDocument(value) {
12638
+ if (!isObject(value)) throw new Error("Reporter manifest file must contain a JSON object.");
12639
+ const candidate = isObject(value.manifest) ? value.manifest : value;
12640
+ if (!isObject(candidate)) throw new Error("Reporter manifest must be a JSON object.");
12641
+ const schemaVersion = readString(candidate.schemaVersion, "manifest.schemaVersion");
12642
+ if (schemaVersion !== "0.1") {
12643
+ throw new Error(`Unsupported reporter manifest schemaVersion: ${schemaVersion}.`);
12644
+ }
12645
+ if (!Array.isArray(candidate.results)) {
12646
+ throw new Error("manifest.results must be an array.");
12647
+ }
12648
+ const artifacts = readArtifacts(candidate.artifacts, "manifest.artifacts");
12649
+ const results = candidate.results.map((item, index) => readResult(item, index));
12650
+ const diagnostics = readDiagnosticsCount(candidate.diagnostics, "manifest.diagnostics");
12651
+ const manifest = {
12652
+ framework: readFramework(candidate.framework),
12653
+ generatedAt: readString(candidate.generatedAt, "manifest.generatedAt"),
12654
+ results,
12655
+ artifacts
12656
+ };
12657
+ return {
12658
+ packageName: readOptionalString(value.package),
12659
+ manifest,
12660
+ diagnostics
12661
+ };
12662
+ }
12663
+ function cwdRelative(filePath) {
12664
+ const relative = path13.relative(process.cwd(), path13.resolve(filePath)).replace(/\\/g, "/");
12665
+ if (relative === "" || relative.startsWith("../") || path13.isAbsolute(relative)) {
12666
+ return path13.basename(filePath);
12667
+ }
12668
+ return relative;
12669
+ }
12670
+ async function readReporterManifest(filePath) {
12671
+ const absolute = path13.resolve(filePath);
12672
+ const raw = await readFile(absolute, "utf-8");
12673
+ const document = readManifestDocument(JSON.parse(raw));
12674
+ const manifest = document.manifest;
12675
+ const results = manifest.results.map((result) => ({
12676
+ testId: safeText(result.testId),
12677
+ name: safeText(result.name),
12678
+ ...result.file === void 0 ? {} : { file: safeText(path13.basename(result.file)) },
12679
+ status: result.status,
12680
+ ...result.tracePath === void 0 ? {} : { tracePath: safeText(path13.basename(result.tracePath)) },
12681
+ artifacts: result.artifacts,
12682
+ diagnostics: result.diagnostics
12683
+ }));
12684
+ return {
12685
+ ...document.packageName === void 0 ? {} : { packageName: document.packageName },
12686
+ manifestFile: cwdRelative(absolute),
12687
+ framework: manifest.framework,
12688
+ generatedAt: manifest.generatedAt,
12689
+ results,
12690
+ artifacts: manifest.artifacts,
12691
+ diagnostics: document.diagnostics
12692
+ };
12693
+ }
12694
+ function summarize3(manifests) {
12695
+ const summary = {
12696
+ manifests: manifests.length,
12697
+ tests: 0,
12698
+ failed: 0,
12699
+ passed: 0,
12700
+ skipped: 0,
12701
+ todo: 0,
12702
+ artifacts: 0,
12703
+ diagnostics: 0
12704
+ };
12705
+ for (const manifest of manifests) {
12706
+ summary.artifacts += manifest.artifacts.length;
12707
+ summary.diagnostics += manifest.diagnostics;
12708
+ for (const result of manifest.results) {
12709
+ summary.tests += 1;
12710
+ if (result.status === "failed") summary.failed += 1;
12711
+ else if (result.status === "passed") summary.passed += 1;
12712
+ else if (result.status === "skipped") summary.skipped += 1;
12713
+ else summary.todo += 1;
12714
+ summary.artifacts += result.artifacts.length;
12715
+ summary.diagnostics += result.diagnostics;
12716
+ }
12717
+ }
12718
+ return {
12719
+ status: summary.failed > 0 ? "failed" : summary.diagnostics > 0 ? "warning" : "ok",
12720
+ manifests,
12721
+ summary,
12722
+ note: NOTE2
12723
+ };
12724
+ }
12725
+ function markdownCell(value) {
12726
+ return safeText(String(value ?? "unknown")).replaceAll("|", "\\|").replace(/\r?\n/g, " ");
12727
+ }
12728
+ function renderMarkdown2(result) {
12729
+ const lines = [
12730
+ "# AgentInspect CI Summary",
12731
+ "",
12732
+ NOTE2,
12733
+ "",
12734
+ "| Field | Value |",
12735
+ "| --- | --- |",
12736
+ `| Status | ${result.status} |`,
12737
+ `| Manifests | ${result.summary.manifests} |`,
12738
+ `| Tests | ${result.summary.tests} |`,
12739
+ `| Failed | ${result.summary.failed} |`,
12740
+ `| Passed | ${result.summary.passed} |`,
12741
+ `| Skipped | ${result.summary.skipped} |`,
12742
+ `| Todo | ${result.summary.todo} |`,
12743
+ `| Artifacts | ${result.summary.artifacts} |`,
12744
+ `| Diagnostics | ${result.summary.diagnostics} |`,
12745
+ "",
12746
+ "## Tests",
12747
+ "",
12748
+ "| Framework | Status | Test | File | Trace | Artifacts |",
12749
+ "| --- | --- | --- | --- | --- | --- |"
12750
+ ];
12751
+ const rows = result.manifests.flatMap(
12752
+ (manifest) => manifest.results.map((test) => ({
12753
+ framework: manifest.framework,
12754
+ test
12755
+ }))
12756
+ );
12757
+ if (rows.length === 0) {
12758
+ lines.push("| unknown | unknown | No tests found | unknown | unknown | 0 |");
12759
+ } else {
12760
+ for (const row of rows) {
12761
+ lines.push(
12762
+ `| ${markdownCell(row.framework)} | ${markdownCell(row.test.status)} | ${markdownCell(row.test.name)} | ${markdownCell(row.test.file)} | ${markdownCell(row.test.tracePath)} | ${row.test.artifacts.length} |`
12763
+ );
12764
+ }
12765
+ }
12766
+ lines.push("", "## Manifests", "", "| Framework | File | Generated | Artifacts |", "| --- | --- | --- | --- |");
12767
+ for (const manifest of result.manifests) {
12768
+ lines.push(
12769
+ `| ${markdownCell(manifest.framework)} | ${markdownCell(manifest.manifestFile)} | ${markdownCell(manifest.generatedAt)} | ${manifest.artifacts.length} |`
12770
+ );
12771
+ }
12772
+ lines.push("", "## Artifacts", "", "| Framework | Kind | Path | Format | Profile |", "| --- | --- | --- | --- | --- |");
12773
+ const artifacts = result.manifests.flatMap(
12774
+ (manifest) => manifest.artifacts.map((artifact) => ({ framework: manifest.framework, artifact }))
12775
+ );
12776
+ if (artifacts.length === 0) {
12777
+ lines.push("| unknown | unknown | No artifacts found | unknown | unknown |");
12778
+ } else {
12779
+ for (const row of artifacts) {
12780
+ lines.push(
12781
+ `| ${markdownCell(row.framework)} | ${markdownCell(row.artifact.kind)} | ${markdownCell(row.artifact.path)} | ${markdownCell(row.artifact.format)} | ${markdownCell(row.artifact.redactionProfile)} |`
12782
+ );
12783
+ }
12784
+ }
12785
+ lines.push("");
12786
+ return `${lines.join("\n")}
12787
+ `;
12788
+ }
12789
+ function safeText(value) {
12790
+ const compact = value.replace(/\s+/g, " ").trim();
12791
+ const redacted = compact.replace(/\bsk-[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(
12792
+ /\b(?:api[_-]?key|authorization|token|secret|password)\s*[:=]\s*[^,\s]+/gi,
12793
+ "$1=[REDACTED]"
12794
+ );
12795
+ if (redacted.length <= MAX_TEXT) return redacted;
12796
+ return `${redacted.slice(0, MAX_TEXT - 12)}...[truncated]`;
12797
+ }
12798
+ async function ciSummaryCommand(manifestPaths, options = {}) {
12799
+ if (manifestPaths.length === 0) {
12800
+ console.error("At least one reporter manifest path is required.");
12801
+ process.exitCode = 1;
12802
+ return;
12803
+ }
12804
+ let result;
12805
+ try {
12806
+ const manifests = [];
12807
+ for (const manifestPath of manifestPaths) {
12808
+ manifests.push(await readReporterManifest(manifestPath));
12809
+ }
12810
+ manifests.sort((a, b) => a.manifestFile.localeCompare(b.manifestFile));
12811
+ result = summarize3(manifests);
12812
+ } catch (error) {
12813
+ const message = error instanceof Error ? error.message : String(error);
12814
+ console.error(`[AgentInspect] ci-summary failed: ${message}`);
12815
+ process.exitCode = 1;
12816
+ return;
12817
+ }
12818
+ const markdown = renderMarkdown2(result);
12819
+ const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path13.resolve(options.output.trim()) : void 0;
12820
+ if (outputPath !== void 0) {
12821
+ await mkdir(path13.dirname(outputPath), { recursive: true });
12822
+ await writeFile(outputPath, markdown, "utf-8");
12823
+ }
12824
+ const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
12825
+ if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
12826
+ const summaryPath = path13.resolve(summaryTarget);
12827
+ await mkdir(path13.dirname(summaryPath), { recursive: true });
12828
+ await appendFile(summaryPath, `
12829
+ ${markdown}`, "utf-8");
12830
+ }
12831
+ if (options.json === true) {
12832
+ console.log(writeJson4(result).trimEnd());
12833
+ } else if (outputPath !== void 0) {
12834
+ console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
12835
+ console.log(`Status: ${result.status}`);
12836
+ } else {
12837
+ console.log(markdown.trimEnd());
12838
+ }
12839
+ }
12475
12840
 
12476
12841
  // packages/cli/src/index.ts
12477
12842
  function runCommand(action) {
@@ -12657,6 +13022,9 @@ function createCliProgram() {
12657
13022
  ).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--baseline <trace-path-or-run-id>", "optional baseline trace for diff artifacts").option("--baseline-run <run-id>", "select a run from the baseline trace").option("--github-summary <path>", "append a safe summary to this file, e.g. GITHUB_STEP_SUMMARY").option("--json", "print deterministic JSON manifest").action((target, opts) => {
12658
13023
  runCommand(() => artifactsCommand(target, opts));
12659
13024
  });
13025
+ program.command("ci-summary").description("Summarize local reporter artifact manifests for CI").argument("<manifest...>", "reporter artifact manifest JSON files").option("-o, --output <path>", "write Markdown summary to a local file").option("--github-summary <path>", "append Markdown summary to this local file, e.g. GITHUB_STEP_SUMMARY").option("--json", "print deterministic JSON summary").action((manifest, opts) => {
13026
+ runCommand(() => ciSummaryCommand(manifest, opts));
13027
+ });
12660
13028
  program.command("diff").description("Compare two local AgentInspect JSONL traces (read-only)").argument("<left-run-id>", "first run id").argument("<right-run-id>", "second run id").option("--dir <path>", "trace directory").option("--json", "print diff result as JSON").option("--ignore-duration", "omit duration comparisons").option(
12661
13029
  "--duration-threshold <duration>",
12662
13030
  "ignore duration deltas at or below this (e.g. 500ms, 2s, 1m)"
@@ -12749,9 +13117,9 @@ function isPrimaryModule() {
12749
13117
  if (!entry) return false;
12750
13118
  const selfPath = fileURLToPath(import.meta.url);
12751
13119
  try {
12752
- return realpathSync(path11.resolve(entry)) === realpathSync(path11.resolve(selfPath));
13120
+ return realpathSync(path13.resolve(entry)) === realpathSync(path13.resolve(selfPath));
12753
13121
  } catch {
12754
- return path11.resolve(entry) === path11.resolve(selfPath);
13122
+ return path13.resolve(entry) === path13.resolve(selfPath);
12755
13123
  }
12756
13124
  }
12757
13125
  if (isPrimaryModule()) {