agent-inspect 2.1.0 → 2.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.
@@ -2,7 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  var fs = require('fs');
5
- var path11 = require('path');
5
+ var path13 = require('path');
6
6
  var url = require('url');
7
7
  var commander = require('commander');
8
8
  var async_hooks = require('async_hooks');
@@ -16,14 +16,14 @@ var readline = require('readline');
16
16
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
17
17
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
18
18
 
19
- var path11__default = /*#__PURE__*/_interopDefault(path11);
19
+ var path13__default = /*#__PURE__*/_interopDefault(path13);
20
20
  var crypto__default = /*#__PURE__*/_interopDefault(crypto);
21
21
  var os__default = /*#__PURE__*/_interopDefault(os);
22
22
  var process2__default = /*#__PURE__*/_interopDefault(process2);
23
23
  var tty__default = /*#__PURE__*/_interopDefault(tty);
24
24
 
25
25
  // package.json
26
- var version = "2.1.0";
26
+ var version = "2.2.0";
27
27
 
28
28
  // packages/core/src/correlation-metadata.ts
29
29
  var TRACE_CORRELATION_KEYS = [
@@ -755,7 +755,7 @@ function formatDuration(ms) {
755
755
  // packages/core/src/utils.ts
756
756
  var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
757
757
  var RUNS_DIR_NAME = "runs";
758
- var FALLBACK_TRACE_DIR = path11__default.default.join(
758
+ var FALLBACK_TRACE_DIR = path13__default.default.join(
759
759
  os__default.default.tmpdir(),
760
760
  "agent-inspect",
761
761
  RUNS_DIR_NAME
@@ -790,7 +790,7 @@ function getDefaultTraceDir() {
790
790
  if (typeof home !== "string" || home.trim() === "") {
791
791
  return FALLBACK_TRACE_DIR;
792
792
  }
793
- return path11__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
793
+ return path13__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
794
794
  } catch {
795
795
  return FALLBACK_TRACE_DIR;
796
796
  }
@@ -798,11 +798,11 @@ function getDefaultTraceDir() {
798
798
  function getTraceFilePath(runId, traceDir) {
799
799
  const baseDir = traceDir ?? getDefaultTraceDir();
800
800
  let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
801
- safeId = path11__default.default.basename(safeId);
801
+ safeId = path13__default.default.basename(safeId);
802
802
  if (safeId === "" || safeId === "." || safeId === "..") {
803
803
  safeId = "run_unknown";
804
804
  }
805
- return path11__default.default.join(baseDir, `${safeId}.jsonl`);
805
+ return path13__default.default.join(baseDir, `${safeId}.jsonl`);
806
806
  }
807
807
  function formatError(error) {
808
808
  if (error instanceof Error) {
@@ -1564,7 +1564,7 @@ var TraceDirectory = class {
1564
1564
  this.#dir = resolveTraceDir(options);
1565
1565
  }
1566
1566
  getPath(filename) {
1567
- return filename ? path11__default.default.join(this.#dir, filename) : this.#dir;
1567
+ return filename ? path13__default.default.join(this.#dir, filename) : this.#dir;
1568
1568
  }
1569
1569
  async list() {
1570
1570
  try {
@@ -1591,7 +1591,7 @@ function parseIsoToMs2(value) {
1591
1591
  }
1592
1592
  async function extractMetadata(filePath, _quickScan) {
1593
1593
  const stats = await promises.stat(filePath);
1594
- let runIdFromFile = path11__default.default.basename(filePath);
1594
+ let runIdFromFile = path13__default.default.basename(filePath);
1595
1595
  if (runIdFromFile.endsWith(".jsonl")) {
1596
1596
  runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
1597
1597
  }
@@ -3562,7 +3562,7 @@ function findReaderByFormat(format, readers) {
3562
3562
  }
3563
3563
  async function jsonlFilesInDirectory(dirPath) {
3564
3564
  const entries = await promises.readdir(dirPath, { withFileTypes: true });
3565
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path11__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
3565
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path13__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
3566
3566
  }
3567
3567
  async function resolveInput(input3) {
3568
3568
  const cached = resolvedInputCache.get(input3);
@@ -7688,9 +7688,9 @@ Trace directory: ${traceDir}`);
7688
7688
  if (validation !== void 0 && !validation.ok) {
7689
7689
  process.exitCode = 1;
7690
7690
  }
7691
- const outPath = options.output !== void 0 && options.output.trim() !== "" ? path11__default.default.resolve(options.output.trim()) : void 0;
7691
+ const outPath = options.output !== void 0 && options.output.trim() !== "" ? path13__default.default.resolve(options.output.trim()) : void 0;
7692
7692
  if (outPath !== void 0) {
7693
- await promises.mkdir(path11__default.default.dirname(outPath), { recursive: true });
7693
+ await promises.mkdir(path13__default.default.dirname(outPath), { recursive: true });
7694
7694
  await promises.writeFile(outPath, result.content, "utf-8");
7695
7695
  const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
7696
7696
  console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
@@ -7867,13 +7867,13 @@ function pairSteps(left, right) {
7867
7867
  return pairs;
7868
7868
  }
7869
7869
  function compareLeafSteps(L, R, segments, opts, out) {
7870
- const path13 = buildPath(segments);
7870
+ const path15 = buildPath(segments);
7871
7871
  if (L.name !== R.name) {
7872
7872
  out.push({
7873
7873
  kind: "structure",
7874
7874
  severity: "warning",
7875
7875
  message: "Step name differs",
7876
- path: path13,
7876
+ path: path15,
7877
7877
  left: L.name,
7878
7878
  right: R.name
7879
7879
  });
@@ -7883,7 +7883,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7883
7883
  kind: "step-type",
7884
7884
  severity: "warning",
7885
7885
  message: "Step type differs",
7886
- path: path13,
7886
+ path: path15,
7887
7887
  left: L.type,
7888
7888
  right: R.type
7889
7889
  });
@@ -7893,7 +7893,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7893
7893
  kind: "step-status",
7894
7894
  severity: "warning",
7895
7895
  message: "Step status differs",
7896
- path: path13,
7896
+ path: path15,
7897
7897
  left: L.status,
7898
7898
  right: R.status
7899
7899
  });
@@ -7905,7 +7905,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7905
7905
  kind: "error",
7906
7906
  severity: "error",
7907
7907
  message: "Step error message differs",
7908
- path: path13,
7908
+ path: path15,
7909
7909
  left: le || void 0,
7910
7910
  right: re || void 0
7911
7911
  });
@@ -7923,7 +7923,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7923
7923
  kind: "duration",
7924
7924
  severity: "info",
7925
7925
  message: "Step duration differs",
7926
- path: path13,
7926
+ path: path15,
7927
7927
  left: ld,
7928
7928
  right: rd
7929
7929
  });
@@ -7936,7 +7936,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7936
7936
  kind: "metadata",
7937
7937
  severity: "info",
7938
7938
  message: "Step metadata differs",
7939
- path: path13,
7939
+ path: path15,
7940
7940
  left: L.metadata,
7941
7941
  right: R.metadata
7942
7942
  });
@@ -7948,7 +7948,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
7948
7948
  kind: "output",
7949
7949
  severity: "info",
7950
7950
  message: "Output preview differs",
7951
- path: path13,
7951
+ path: path15,
7952
7952
  left: L.outputPreview,
7953
7953
  right: R.outputPreview
7954
7954
  });
@@ -8108,11 +8108,11 @@ function diffRuns(left, right, options) {
8108
8108
  }
8109
8109
 
8110
8110
  // packages/core/src/diff/renderer.ts
8111
- function formatPath(path13) {
8112
- if (path13 === void 0 || path13.path.length === 0) {
8111
+ function formatPath(path15) {
8112
+ if (path15 === void 0 || path15.path.length === 0) {
8113
8113
  return "(run)";
8114
8114
  }
8115
- return path13.path.map((s) => s.name).join(" > ");
8115
+ return path15.path.map((s) => s.name).join(" > ");
8116
8116
  }
8117
8117
  function formatValue(v, verbose) {
8118
8118
  if (v === void 0) return "(undefined)";
@@ -8543,9 +8543,9 @@ async function reportCommand(runId, options = {}) {
8543
8543
  redactionProfile,
8544
8544
  correlation: !options.noCorrelation
8545
8545
  });
8546
- const outPath = options.output !== void 0 && options.output.trim() !== "" ? path11__default.default.resolve(options.output.trim()) : void 0;
8546
+ const outPath = options.output !== void 0 && options.output.trim() !== "" ? path13__default.default.resolve(options.output.trim()) : void 0;
8547
8547
  if (outPath !== void 0) {
8548
- await promises.mkdir(path11__default.default.dirname(outPath), { recursive: true });
8548
+ await promises.mkdir(path13__default.default.dirname(outPath), { recursive: true });
8549
8549
  await promises.writeFile(outPath, result.content, "utf-8");
8550
8550
  console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
8551
8551
  }
@@ -8792,17 +8792,17 @@ function applyRule(rule, value, replacement) {
8792
8792
  }
8793
8793
  return value;
8794
8794
  }
8795
- function childPath(path13, key) {
8795
+ function childPath(path15, key) {
8796
8796
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
8797
- return path13 ? `${path13}.${key}` : key;
8797
+ return path15 ? `${path15}.${key}` : key;
8798
8798
  }
8799
- return `${path13 || "$"}[${JSON.stringify(key)}]`;
8799
+ return `${path15 || "$"}[${JSON.stringify(key)}]`;
8800
8800
  }
8801
- function indexPath(path13, index) {
8802
- return `${path13 || "$"}[${index}]`;
8801
+ function indexPath(path15, index) {
8802
+ return `${path15 || "$"}[${index}]`;
8803
8803
  }
8804
- function makeFinding(path13, detector, action, matchKind, severity = "warning", preview) {
8805
- return preview === void 0 ? { path: path13, detector, action, severity, matchKind } : { path: path13, detector, action, severity, matchKind, preview };
8804
+ function makeFinding(path15, detector, action, matchKind, severity = "warning", preview) {
8805
+ return preview === void 0 ? { path: path15, detector, action, severity, matchKind } : { path: path15, detector, action, severity, matchKind, preview };
8806
8806
  }
8807
8807
  function createRedactionProfile(profile = "local") {
8808
8808
  switch (profile) {
@@ -8871,11 +8871,11 @@ var Redactor2 = class {
8871
8871
  #recordFinding(state, finding) {
8872
8872
  if (this.#collectFindings) state.findings.push(finding);
8873
8873
  }
8874
- #redactValue(value, key, path13, depth, state) {
8874
+ #redactValue(value, key, path15, depth, state) {
8875
8875
  if (depth > this.#maxDepth) {
8876
8876
  this.#recordFinding(
8877
8877
  state,
8878
- makeFinding(path13, "structure.maxDepth", "truncate", "value", "warning")
8878
+ makeFinding(path15, "structure.maxDepth", "truncate", "value", "warning")
8879
8879
  );
8880
8880
  return "[Truncated]";
8881
8881
  }
@@ -8884,19 +8884,19 @@ var Redactor2 = class {
8884
8884
  if (rule) {
8885
8885
  this.#recordFinding(
8886
8886
  state,
8887
- makeFinding(path13, `key.${rule.key}`, actionForRule(rule), "key", "warning")
8887
+ makeFinding(path15, `key.${rule.key}`, actionForRule(rule), "key", "warning")
8888
8888
  );
8889
8889
  return applyRule(rule, value, this.#replacement);
8890
8890
  }
8891
8891
  }
8892
8892
  for (const detector of this.#detectors) {
8893
- const detections = detector.detect({ path: path13, key, value });
8893
+ const detections = detector.detect({ path: path15, key, value });
8894
8894
  for (const detection of detections) {
8895
8895
  const action = detection.action ?? "replace";
8896
8896
  this.#recordFinding(
8897
8897
  state,
8898
8898
  makeFinding(
8899
- path13,
8899
+ path15,
8900
8900
  detector.id,
8901
8901
  action,
8902
8902
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -8914,7 +8914,7 @@ var Redactor2 = class {
8914
8914
  const out = [];
8915
8915
  state.seen.set(value, out);
8916
8916
  value.forEach((item, index) => {
8917
- out[index] = this.#redactValue(item, void 0, indexPath(path13, index), depth + 1, state);
8917
+ out[index] = this.#redactValue(item, void 0, indexPath(path15, index), depth + 1, state);
8918
8918
  });
8919
8919
  return out;
8920
8920
  }
@@ -8926,7 +8926,7 @@ var Redactor2 = class {
8926
8926
  out[entryKey] = this.#redactValue(
8927
8927
  entryValue,
8928
8928
  entryKey,
8929
- childPath(path13 === "$" ? "" : path13, entryKey),
8929
+ childPath(path15 === "$" ? "" : path15, entryKey),
8930
8930
  depth + 1,
8931
8931
  state
8932
8932
  );
@@ -9373,14 +9373,14 @@ function uniqueSorted(values) {
9373
9373
  return [...new Set(values)].sort();
9374
9374
  }
9375
9375
  function isWithinDirectory(child, parent) {
9376
- const relative = path11__default.default.relative(parent, child);
9377
- return relative === "" || !relative.startsWith("..") && !path11__default.default.isAbsolute(relative);
9376
+ const relative = path13__default.default.relative(parent, child);
9377
+ return relative === "" || !relative.startsWith("..") && !path13__default.default.isAbsolute(relative);
9378
9378
  }
9379
9379
  async function resolveOutputPath(inputPath, output2, force) {
9380
9380
  if (output2 === void 0 || output2.trim() === "") return void 0;
9381
- const inputAbs = path11__default.default.resolve(inputPath);
9382
- const outputAbs = path11__default.default.resolve(output2.trim());
9383
- const inputDir = path11__default.default.dirname(inputAbs);
9381
+ const inputAbs = path13__default.default.resolve(inputPath);
9382
+ const outputAbs = path13__default.default.resolve(output2.trim());
9383
+ const inputDir = path13__default.default.dirname(inputAbs);
9384
9384
  if (!isWithinDirectory(outputAbs, inputDir)) {
9385
9385
  throw new Error("Refusing to write migrated output outside the input directory.");
9386
9386
  }
@@ -9501,7 +9501,7 @@ async function migrateCommand(input3, options = {}) {
9501
9501
  process.exitCode = 1;
9502
9502
  return;
9503
9503
  }
9504
- const inputPath = path11__default.default.resolve(input3.trim());
9504
+ const inputPath = path13__default.default.resolve(input3.trim());
9505
9505
  const dryRun = options.dryRun === true;
9506
9506
  if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
9507
9507
  console.error("migrate requires --dry-run or --output <path>.");
@@ -9520,7 +9520,7 @@ async function migrateCommand(input3, options = {}) {
9520
9520
  );
9521
9521
  const result = await buildMigration(inputPath, outputPath);
9522
9522
  if (!dryRun && outputPath !== void 0) {
9523
- await promises.mkdir(path11__default.default.dirname(outputPath), { recursive: true });
9523
+ await promises.mkdir(path13__default.default.dirname(outputPath), { recursive: true });
9524
9524
  await promises.writeFile(outputPath, result.content, "utf-8");
9525
9525
  }
9526
9526
  printSummary2(result, dryRun);
@@ -9798,7 +9798,7 @@ function stripPrefix(name, prefixes) {
9798
9798
  }
9799
9799
  return name;
9800
9800
  }
9801
- function eventEvidence(event, path13) {
9801
+ function eventEvidence(event, path15) {
9802
9802
  return {
9803
9803
  runId: event.runId,
9804
9804
  eventId: event.eventId,
@@ -9808,7 +9808,7 @@ function eventEvidence(event, path13) {
9808
9808
  kind: event.kind,
9809
9809
  name: event.name,
9810
9810
  status: event.status,
9811
- ...path13 ? { path: path13 } : {}
9811
+ ...path15 ? { path: path15 } : {}
9812
9812
  };
9813
9813
  }
9814
9814
  function runEvidence(run) {
@@ -9871,9 +9871,9 @@ function eventEndMs(event) {
9871
9871
  function normalizedKey(value) {
9872
9872
  return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
9873
9873
  }
9874
- function lastPathSegment(path13) {
9875
- const parts = path13.split(".");
9876
- return parts[parts.length - 1] ?? path13;
9874
+ function lastPathSegment(path15) {
9875
+ const parts = path15.split(".");
9876
+ return parts[parts.length - 1] ?? path15;
9877
9877
  }
9878
9878
  function valueType(value) {
9879
9879
  if (Array.isArray(value)) return "array";
@@ -9887,12 +9887,12 @@ function serializedByteLength(value) {
9887
9887
  return void 0;
9888
9888
  }
9889
9889
  }
9890
- function pushValueEntries(entries, event, value, path13, key, depth = 0) {
9891
- entries.push({ event, path: path13, key, value });
9890
+ function pushValueEntries(entries, event, value, path15, key, depth = 0) {
9891
+ entries.push({ event, path: path15, key, value });
9892
9892
  if (depth >= 8) return;
9893
9893
  if (Array.isArray(value)) {
9894
9894
  for (const [index, item] of value.entries()) {
9895
- pushValueEntries(entries, event, item, `${path13}.${index}`, String(index), depth + 1);
9895
+ pushValueEntries(entries, event, item, `${path15}.${index}`, String(index), depth + 1);
9896
9896
  }
9897
9897
  return;
9898
9898
  }
@@ -9902,7 +9902,7 @@ function pushValueEntries(entries, event, value, path13, key, depth = 0) {
9902
9902
  entries,
9903
9903
  event,
9904
9904
  value[nestedKey],
9905
- `${path13}.${nestedKey}`,
9905
+ `${path15}.${nestedKey}`,
9906
9906
  nestedKey,
9907
9907
  depth + 1
9908
9908
  );
@@ -9983,9 +9983,9 @@ function eventDurationMs(event) {
9983
9983
  }
9984
9984
  function treeShape(nodes) {
9985
9985
  const lines = [];
9986
- const visit = (node, path13) => {
9987
- lines.push(`${path13}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
9988
- node.children.forEach((child, index) => visit(child, `${path13}.${index}`));
9986
+ const visit = (node, path15) => {
9987
+ lines.push(`${path15}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
9988
+ node.children.forEach((child, index) => visit(child, `${path15}.${index}`));
9989
9989
  };
9990
9990
  nodes.forEach((node, index) => visit(node, String(index)));
9991
9991
  return lines;
@@ -10034,9 +10034,9 @@ function retrievalShape(context) {
10034
10034
  function guardrailShape(context) {
10035
10035
  return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
10036
10036
  }
10037
- function firstEvidenceForKind(context, kind, path13) {
10037
+ function firstEvidenceForKind(context, kind, path15) {
10038
10038
  const event = context.events.find((candidate) => candidate.kind === kind);
10039
- return event ? [eventEvidence(event, path13)] : runEvidence(context.selectedRun);
10039
+ return event ? [eventEvidence(event, path15)] : runEvidence(context.selectedRun);
10040
10040
  }
10041
10041
  function baselineDiffFinding(message, evidence, expected, actual) {
10042
10042
  return failFinding("baseline.regression", message, evidence, expected, actual);
@@ -10284,13 +10284,13 @@ function createStructureCycleRule() {
10284
10284
  const seenCycles = /* @__PURE__ */ new Set();
10285
10285
  const findings = [];
10286
10286
  for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
10287
- const path13 = [];
10287
+ const path15 = [];
10288
10288
  const seenAt = /* @__PURE__ */ new Map();
10289
10289
  let current = event;
10290
10290
  while (current) {
10291
10291
  const existing = seenAt.get(current.eventId);
10292
10292
  if (existing !== void 0) {
10293
- const cycle = path13.slice(existing);
10293
+ const cycle = path15.slice(existing);
10294
10294
  const key = cycle.map((item) => item.eventId).sort().join("\0");
10295
10295
  if (!seenCycles.has(key)) {
10296
10296
  seenCycles.add(key);
@@ -10306,8 +10306,8 @@ function createStructureCycleRule() {
10306
10306
  }
10307
10307
  break;
10308
10308
  }
10309
- seenAt.set(current.eventId, path13.length);
10310
- path13.push(current);
10309
+ seenAt.set(current.eventId, path15.length);
10310
+ path15.push(current);
10311
10311
  current = current.parentId ? byId.get(current.parentId) : void 0;
10312
10312
  }
10313
10313
  }
@@ -10832,7 +10832,7 @@ function asConfig(value) {
10832
10832
  }
10833
10833
  async function loadConfig(configPath) {
10834
10834
  if (configPath === void 0) return {};
10835
- const extension = path11__default.default.extname(configPath);
10835
+ const extension = path13__default.default.extname(configPath);
10836
10836
  if (TS_CONFIG_EXTENSIONS.has(extension)) {
10837
10837
  throw new Error(
10838
10838
  "TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -10841,7 +10841,7 @@ async function loadConfig(configPath) {
10841
10841
  if (!CONFIG_EXTENSIONS.has(extension)) {
10842
10842
  throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
10843
10843
  }
10844
- const absolute = path11__default.default.resolve(configPath);
10844
+ const absolute = path13__default.default.resolve(configPath);
10845
10845
  if (extension === ".json") {
10846
10846
  const raw = await promises.readFile(absolute, "utf-8");
10847
10847
  return asConfig(JSON.parse(raw));
@@ -10963,8 +10963,8 @@ function printHuman(result) {
10963
10963
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
10964
10964
  }
10965
10965
  for (const finding of result.findings) {
10966
- const path13 = finding.evidence[0]?.path;
10967
- console.log(`- ${finding.ruleId}: ${finding.message}${path13 ? ` (${path13})` : ""}`);
10966
+ const path15 = finding.evidence[0]?.path;
10967
+ console.log(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
10968
10968
  }
10969
10969
  }
10970
10970
  function readErrorResult(error) {
@@ -11186,10 +11186,10 @@ async function evalRun(input3, options = {}) {
11186
11186
  diagnostics: []
11187
11187
  };
11188
11188
  }
11189
- function evidenceForRun(run, path13) {
11190
- return [{ runId: run.runId, ...path13 !== void 0 ? { path: path13 } : {} }];
11189
+ function evidenceForRun(run, path15) {
11190
+ return [{ runId: run.runId, ...path15 !== void 0 ? { path: path15 } : {} }];
11191
11191
  }
11192
- function evidenceForEvent(event, path13) {
11192
+ function evidenceForEvent(event, path15) {
11193
11193
  return [
11194
11194
  {
11195
11195
  runId: event.runId,
@@ -11197,7 +11197,7 @@ function evidenceForEvent(event, path13) {
11197
11197
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
11198
11198
  kind: event.kind,
11199
11199
  name: event.name,
11200
- ...path13 !== void 0 ? { path: path13 } : {}
11200
+ ...path15 !== void 0 ? { path: path15 } : {}
11201
11201
  }
11202
11202
  ];
11203
11203
  }
@@ -11355,9 +11355,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
11355
11355
  function tokenize(text) {
11356
11356
  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));
11357
11357
  }
11358
- function firstEvidence(fields, run, path13) {
11358
+ function firstEvidence(fields, run, path15) {
11359
11359
  const first = fields[0];
11360
- return first === void 0 ? evidenceForRun(run, path13) : evidenceForEvent(first.node.event, first.path);
11360
+ return first === void 0 ? evidenceForRun(run, path15) : evidenceForEvent(first.node.event, first.path);
11361
11361
  }
11362
11362
  function collectSourceIds(nodes, keys) {
11363
11363
  const wanted = keySet(keys);
@@ -11734,8 +11734,8 @@ function renderEvalMarkdown(result) {
11734
11734
  if (result.findings.length > 0) {
11735
11735
  lines.push("", "## Findings");
11736
11736
  for (const finding of result.findings) {
11737
- const path13 = finding.evidence[0]?.path;
11738
- lines.push(`- ${finding.ruleId}: ${finding.message}${path13 ? ` (${path13})` : ""}`);
11737
+ const path15 = finding.evidence[0]?.path;
11738
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
11739
11739
  }
11740
11740
  }
11741
11741
  return `${lines.join("\n")}
@@ -11782,7 +11782,7 @@ function asConfig2(value) {
11782
11782
  }
11783
11783
  async function loadConfig2(configPath) {
11784
11784
  if (configPath === void 0) return {};
11785
- const extension = path11__default.default.extname(configPath);
11785
+ const extension = path13__default.default.extname(configPath);
11786
11786
  if (TS_CONFIG_EXTENSIONS2.has(extension)) {
11787
11787
  throw new Error(
11788
11788
  "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -11791,7 +11791,7 @@ async function loadConfig2(configPath) {
11791
11791
  if (!CONFIG_EXTENSIONS2.has(extension)) {
11792
11792
  throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
11793
11793
  }
11794
- const absolute = path11__default.default.resolve(configPath);
11794
+ const absolute = path13__default.default.resolve(configPath);
11795
11795
  if (extension === ".json") {
11796
11796
  const raw = await promises.readFile(absolute, "utf-8");
11797
11797
  return asConfig2(JSON.parse(raw));
@@ -11928,8 +11928,8 @@ function printHuman2(result) {
11928
11928
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
11929
11929
  }
11930
11930
  for (const finding of result.findings) {
11931
- const path13 = finding.evidence[0]?.path;
11932
- console.log(`- ${finding.ruleId}: ${finding.message}${path13 ? ` (${path13})` : ""}`);
11931
+ const path15 = finding.evidence[0]?.path;
11932
+ console.log(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
11933
11933
  }
11934
11934
  }
11935
11935
  function readErrorResult2(error) {
@@ -12167,8 +12167,8 @@ function printHuman3(result) {
12167
12167
  console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
12168
12168
  }
12169
12169
  for (const finding of result.findings) {
12170
- const path13 = finding.evidence[0]?.path;
12171
- console.log(`- ${finding.ruleId}: ${finding.message}${path13 ? ` (${path13})` : ""}`);
12170
+ const path15 = finding.evidence[0]?.path;
12171
+ console.log(`- ${finding.ruleId}: ${finding.message}${path15 ? ` (${path15})` : ""}`);
12172
12172
  }
12173
12173
  console.log(`Note: ${result.note}`);
12174
12174
  }
@@ -12287,8 +12287,8 @@ function renderCheckSection(result) {
12287
12287
  `Diagnostics: ${result.diagnostics.length}`
12288
12288
  ];
12289
12289
  for (const finding of result.findings.slice(0, 10)) {
12290
- const path13 = finding.evidence[0]?.path ?? "(run)";
12291
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path13})`);
12290
+ const path15 = finding.evidence[0]?.path ?? "(run)";
12291
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path15})`);
12292
12292
  }
12293
12293
  for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
12294
12294
  lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
@@ -12366,8 +12366,8 @@ function renderHtml(trace, check, diff) {
12366
12366
  `;
12367
12367
  }
12368
12368
  async function writeArtifact(outputDir, relativePath, content, files) {
12369
- const outPath = path11__default.default.join(outputDir, relativePath);
12370
- await promises.mkdir(path11__default.default.dirname(outPath), { recursive: true });
12369
+ const outPath = path13__default.default.join(outputDir, relativePath);
12370
+ await promises.mkdir(path13__default.default.dirname(outPath), { recursive: true });
12371
12371
  await promises.writeFile(outPath, content, "utf-8");
12372
12372
  files.push(relativePath);
12373
12373
  }
@@ -12383,7 +12383,7 @@ function manifestStatus(check, diff) {
12383
12383
  return "ok";
12384
12384
  }
12385
12385
  async function artifactsCommand(target, options = {}, stdin = process.stdin) {
12386
- const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path11__default.default.resolve(options.outputDir.trim()) : "";
12386
+ const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path13__default.default.resolve(options.outputDir.trim()) : "";
12387
12387
  if (outputDir === "") {
12388
12388
  console.error("--output-dir is required.");
12389
12389
  process.exitCode = 1;
@@ -12449,8 +12449,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
12449
12449
  await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
12450
12450
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
12451
12451
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
12452
- await promises.mkdir(path11__default.default.dirname(path11__default.default.resolve(summaryTarget)), { recursive: true });
12453
- await promises.appendFile(path11__default.default.resolve(summaryTarget), `
12452
+ await promises.mkdir(path13__default.default.dirname(path13__default.default.resolve(summaryTarget)), { recursive: true });
12453
+ await promises.appendFile(path13__default.default.resolve(summaryTarget), `
12454
12454
  ${renderMarkdown(trace, check, diff)}`, "utf-8");
12455
12455
  }
12456
12456
  const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
@@ -12469,10 +12469,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
12469
12469
  findings: diff?.findings.length ?? 0,
12470
12470
  diagnostics: diff?.diagnostics.length ?? 0
12471
12471
  },
12472
- ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path11__default.default.resolve(summaryTarget) } : {},
12472
+ ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path13__default.default.resolve(summaryTarget) } : {},
12473
12473
  note: NOTE
12474
12474
  };
12475
- await promises.writeFile(path11__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
12475
+ await promises.writeFile(path13__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
12476
12476
  if (options.json === true) {
12477
12477
  console.log(writeJson3(manifest).trimEnd());
12478
12478
  } else {
@@ -12483,6 +12483,371 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
12483
12483
  }
12484
12484
  }
12485
12485
  }
12486
+ function validateReporterArtifactPath(options) {
12487
+ const outputDir = path13__default.default.resolve(options.outputDir);
12488
+ const diagnostics = [];
12489
+ const rawPath = options.relativePath;
12490
+ if (rawPath.length === 0) {
12491
+ diagnostics.push({
12492
+ code: "artifact_path_empty",
12493
+ severity: "error",
12494
+ message: "Reporter artifact path must not be empty."
12495
+ });
12496
+ return { ok: false, outputDir, diagnostics };
12497
+ }
12498
+ if (rawPath.includes("\0")) {
12499
+ diagnostics.push({
12500
+ code: "invalid_artifact_path",
12501
+ severity: "error",
12502
+ message: "Reporter artifact path must not contain null bytes.",
12503
+ target: rawPath
12504
+ });
12505
+ return { ok: false, outputDir, diagnostics };
12506
+ }
12507
+ if (path13__default.default.isAbsolute(rawPath) || path13__default.default.win32.isAbsolute(rawPath)) {
12508
+ diagnostics.push({
12509
+ code: "artifact_path_absolute",
12510
+ severity: "error",
12511
+ message: "Reporter artifact path must be relative.",
12512
+ target: rawPath
12513
+ });
12514
+ return { ok: false, outputDir, diagnostics };
12515
+ }
12516
+ const normalized = path13__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
12517
+ const segments = normalized.split("/");
12518
+ if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
12519
+ diagnostics.push({
12520
+ code: "artifact_path_escape",
12521
+ severity: "error",
12522
+ message: "Reporter artifact path must stay under the output directory.",
12523
+ target: rawPath
12524
+ });
12525
+ return { ok: false, outputDir, diagnostics };
12526
+ }
12527
+ const absolutePath = path13__default.default.resolve(outputDir, normalized);
12528
+ const relFromOutput = path13__default.default.relative(outputDir, absolutePath);
12529
+ if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path13__default.default.isAbsolute(relFromOutput)) {
12530
+ diagnostics.push({
12531
+ code: "artifact_path_escape",
12532
+ severity: "error",
12533
+ message: "Reporter artifact path resolved outside the output directory.",
12534
+ target: rawPath
12535
+ });
12536
+ return { ok: false, outputDir, diagnostics };
12537
+ }
12538
+ return {
12539
+ ok: true,
12540
+ outputDir,
12541
+ relativePath: normalized,
12542
+ absolutePath,
12543
+ diagnostics
12544
+ };
12545
+ }
12546
+
12547
+ // packages/cli/src/ci-summary.ts
12548
+ var NOTE2 = "Generated locally by AgentInspect from reporter artifact manifests. Trace contents are not embedded.";
12549
+ var MAX_TEXT = 180;
12550
+ var FRAMEWORKS = /* @__PURE__ */ new Set(["vitest", "jest", "manual"]);
12551
+ var STATUSES = /* @__PURE__ */ new Set(["passed", "failed", "skipped", "todo"]);
12552
+ var ARTIFACT_KINDS = /* @__PURE__ */ new Set(["trace", "report", "eval", "redaction", "summary"]);
12553
+ var ARTIFACT_FORMATS = /* @__PURE__ */ new Set(["json", "jsonl", "md", "html"]);
12554
+ var REDACTION_PROFILES = /* @__PURE__ */ new Set(["local", "share", "strict"]);
12555
+ function stable6(value) {
12556
+ if (Array.isArray(value)) return value.map(stable6);
12557
+ if (value === null || typeof value !== "object") return value;
12558
+ const record = value;
12559
+ return Object.fromEntries(
12560
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable6(record[key])])
12561
+ );
12562
+ }
12563
+ function writeJson4(value) {
12564
+ return `${JSON.stringify(stable6(value), null, 2)}
12565
+ `;
12566
+ }
12567
+ function isObject(value) {
12568
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12569
+ }
12570
+ function readString(value, label) {
12571
+ if (typeof value !== "string" || value.trim() === "") {
12572
+ throw new Error(`${label} must be a non-empty string.`);
12573
+ }
12574
+ return safeText(value);
12575
+ }
12576
+ function readOptionalString(value) {
12577
+ return typeof value === "string" && value.trim() !== "" ? safeText(value) : void 0;
12578
+ }
12579
+ function readFramework(value) {
12580
+ const framework = readString(value, "manifest.framework");
12581
+ if (!FRAMEWORKS.has(framework)) {
12582
+ throw new Error(`Unsupported reporter framework: ${framework}.`);
12583
+ }
12584
+ return framework;
12585
+ }
12586
+ function readStatus(value) {
12587
+ const status = readString(value, "result.status");
12588
+ if (!STATUSES.has(status)) {
12589
+ throw new Error(`Unsupported reporter test status: ${status}.`);
12590
+ }
12591
+ return status;
12592
+ }
12593
+ function readArtifact(value, index) {
12594
+ if (!isObject(value)) throw new Error(`manifest.artifacts[${index}] must be an object.`);
12595
+ const kind = readString(value.kind, `manifest.artifacts[${index}].kind`);
12596
+ const format = readString(value.format, `manifest.artifacts[${index}].format`);
12597
+ const redactionProfile = readString(
12598
+ value.redactionProfile,
12599
+ `manifest.artifacts[${index}].redactionProfile`
12600
+ );
12601
+ if (!ARTIFACT_KINDS.has(kind)) throw new Error(`Unsupported artifact kind: ${kind}.`);
12602
+ if (!ARTIFACT_FORMATS.has(format)) throw new Error(`Unsupported artifact format: ${format}.`);
12603
+ if (!REDACTION_PROFILES.has(redactionProfile)) {
12604
+ throw new Error(`Unsupported artifact redaction profile: ${redactionProfile}.`);
12605
+ }
12606
+ const artifactPath = readString(value.path, `manifest.artifacts[${index}].path`);
12607
+ const pathCheck = validateReporterArtifactPath({
12608
+ outputDir: process.cwd(),
12609
+ relativePath: artifactPath
12610
+ });
12611
+ if (!pathCheck.ok || pathCheck.relativePath === void 0) {
12612
+ throw new Error(`Unsafe reporter artifact path: ${artifactPath}.`);
12613
+ }
12614
+ return {
12615
+ kind,
12616
+ path: pathCheck.relativePath,
12617
+ format,
12618
+ redactionProfile
12619
+ };
12620
+ }
12621
+ function readArtifacts(value, label) {
12622
+ if (value === void 0) return [];
12623
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
12624
+ return value.map((item, index) => readArtifact(item, index));
12625
+ }
12626
+ function readDiagnosticsCount(value, label) {
12627
+ if (value === void 0) return 0;
12628
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array.`);
12629
+ return value.length;
12630
+ }
12631
+ function readResult(value, index) {
12632
+ if (!isObject(value)) throw new Error(`manifest.results[${index}] must be an object.`);
12633
+ const file = readOptionalString(value.file);
12634
+ const tracePath = readOptionalString(value.tracePath);
12635
+ return {
12636
+ testId: readString(value.testId, `manifest.results[${index}].testId`),
12637
+ name: readString(value.name, `manifest.results[${index}].name`),
12638
+ ...file === void 0 ? {} : { file },
12639
+ status: readStatus(value.status),
12640
+ ...tracePath === void 0 ? {} : { tracePath },
12641
+ artifacts: readArtifacts(value.artifacts, `manifest.results[${index}].artifacts`),
12642
+ diagnostics: readDiagnosticsCount(
12643
+ value.diagnostics,
12644
+ `manifest.results[${index}].diagnostics`
12645
+ )
12646
+ };
12647
+ }
12648
+ function readManifestDocument(value) {
12649
+ if (!isObject(value)) throw new Error("Reporter manifest file must contain a JSON object.");
12650
+ const candidate = isObject(value.manifest) ? value.manifest : value;
12651
+ if (!isObject(candidate)) throw new Error("Reporter manifest must be a JSON object.");
12652
+ const schemaVersion = readString(candidate.schemaVersion, "manifest.schemaVersion");
12653
+ if (schemaVersion !== "0.1") {
12654
+ throw new Error(`Unsupported reporter manifest schemaVersion: ${schemaVersion}.`);
12655
+ }
12656
+ if (!Array.isArray(candidate.results)) {
12657
+ throw new Error("manifest.results must be an array.");
12658
+ }
12659
+ const artifacts = readArtifacts(candidate.artifacts, "manifest.artifacts");
12660
+ const results = candidate.results.map((item, index) => readResult(item, index));
12661
+ const diagnostics = readDiagnosticsCount(candidate.diagnostics, "manifest.diagnostics");
12662
+ const manifest = {
12663
+ framework: readFramework(candidate.framework),
12664
+ generatedAt: readString(candidate.generatedAt, "manifest.generatedAt"),
12665
+ results,
12666
+ artifacts
12667
+ };
12668
+ return {
12669
+ packageName: readOptionalString(value.package),
12670
+ manifest,
12671
+ diagnostics
12672
+ };
12673
+ }
12674
+ function cwdRelative(filePath) {
12675
+ const relative = path13__default.default.relative(process.cwd(), path13__default.default.resolve(filePath)).replace(/\\/g, "/");
12676
+ if (relative === "" || relative.startsWith("../") || path13__default.default.isAbsolute(relative)) {
12677
+ return path13__default.default.basename(filePath);
12678
+ }
12679
+ return relative;
12680
+ }
12681
+ async function readReporterManifest(filePath) {
12682
+ const absolute = path13__default.default.resolve(filePath);
12683
+ const raw = await promises.readFile(absolute, "utf-8");
12684
+ const document = readManifestDocument(JSON.parse(raw));
12685
+ const manifest = document.manifest;
12686
+ const results = manifest.results.map((result) => ({
12687
+ testId: safeText(result.testId),
12688
+ name: safeText(result.name),
12689
+ ...result.file === void 0 ? {} : { file: safeText(path13__default.default.basename(result.file)) },
12690
+ status: result.status,
12691
+ ...result.tracePath === void 0 ? {} : { tracePath: safeText(path13__default.default.basename(result.tracePath)) },
12692
+ artifacts: result.artifacts,
12693
+ diagnostics: result.diagnostics
12694
+ }));
12695
+ return {
12696
+ ...document.packageName === void 0 ? {} : { packageName: document.packageName },
12697
+ manifestFile: cwdRelative(absolute),
12698
+ framework: manifest.framework,
12699
+ generatedAt: manifest.generatedAt,
12700
+ results,
12701
+ artifacts: manifest.artifacts,
12702
+ diagnostics: document.diagnostics
12703
+ };
12704
+ }
12705
+ function summarize3(manifests) {
12706
+ const summary = {
12707
+ manifests: manifests.length,
12708
+ tests: 0,
12709
+ failed: 0,
12710
+ passed: 0,
12711
+ skipped: 0,
12712
+ todo: 0,
12713
+ artifacts: 0,
12714
+ diagnostics: 0
12715
+ };
12716
+ for (const manifest of manifests) {
12717
+ summary.artifacts += manifest.artifacts.length;
12718
+ summary.diagnostics += manifest.diagnostics;
12719
+ for (const result of manifest.results) {
12720
+ summary.tests += 1;
12721
+ if (result.status === "failed") summary.failed += 1;
12722
+ else if (result.status === "passed") summary.passed += 1;
12723
+ else if (result.status === "skipped") summary.skipped += 1;
12724
+ else summary.todo += 1;
12725
+ summary.artifacts += result.artifacts.length;
12726
+ summary.diagnostics += result.diagnostics;
12727
+ }
12728
+ }
12729
+ return {
12730
+ status: summary.failed > 0 ? "failed" : summary.diagnostics > 0 ? "warning" : "ok",
12731
+ manifests,
12732
+ summary,
12733
+ note: NOTE2
12734
+ };
12735
+ }
12736
+ function markdownCell(value) {
12737
+ return safeText(String(value ?? "unknown")).replaceAll("|", "\\|").replace(/\r?\n/g, " ");
12738
+ }
12739
+ function renderMarkdown2(result) {
12740
+ const lines = [
12741
+ "# AgentInspect CI Summary",
12742
+ "",
12743
+ NOTE2,
12744
+ "",
12745
+ "| Field | Value |",
12746
+ "| --- | --- |",
12747
+ `| Status | ${result.status} |`,
12748
+ `| Manifests | ${result.summary.manifests} |`,
12749
+ `| Tests | ${result.summary.tests} |`,
12750
+ `| Failed | ${result.summary.failed} |`,
12751
+ `| Passed | ${result.summary.passed} |`,
12752
+ `| Skipped | ${result.summary.skipped} |`,
12753
+ `| Todo | ${result.summary.todo} |`,
12754
+ `| Artifacts | ${result.summary.artifacts} |`,
12755
+ `| Diagnostics | ${result.summary.diagnostics} |`,
12756
+ "",
12757
+ "## Tests",
12758
+ "",
12759
+ "| Framework | Status | Test | File | Trace | Artifacts |",
12760
+ "| --- | --- | --- | --- | --- | --- |"
12761
+ ];
12762
+ const rows = result.manifests.flatMap(
12763
+ (manifest) => manifest.results.map((test) => ({
12764
+ framework: manifest.framework,
12765
+ test
12766
+ }))
12767
+ );
12768
+ if (rows.length === 0) {
12769
+ lines.push("| unknown | unknown | No tests found | unknown | unknown | 0 |");
12770
+ } else {
12771
+ for (const row of rows) {
12772
+ lines.push(
12773
+ `| ${markdownCell(row.framework)} | ${markdownCell(row.test.status)} | ${markdownCell(row.test.name)} | ${markdownCell(row.test.file)} | ${markdownCell(row.test.tracePath)} | ${row.test.artifacts.length} |`
12774
+ );
12775
+ }
12776
+ }
12777
+ lines.push("", "## Manifests", "", "| Framework | File | Generated | Artifacts |", "| --- | --- | --- | --- |");
12778
+ for (const manifest of result.manifests) {
12779
+ lines.push(
12780
+ `| ${markdownCell(manifest.framework)} | ${markdownCell(manifest.manifestFile)} | ${markdownCell(manifest.generatedAt)} | ${manifest.artifacts.length} |`
12781
+ );
12782
+ }
12783
+ lines.push("", "## Artifacts", "", "| Framework | Kind | Path | Format | Profile |", "| --- | --- | --- | --- | --- |");
12784
+ const artifacts = result.manifests.flatMap(
12785
+ (manifest) => manifest.artifacts.map((artifact) => ({ framework: manifest.framework, artifact }))
12786
+ );
12787
+ if (artifacts.length === 0) {
12788
+ lines.push("| unknown | unknown | No artifacts found | unknown | unknown |");
12789
+ } else {
12790
+ for (const row of artifacts) {
12791
+ lines.push(
12792
+ `| ${markdownCell(row.framework)} | ${markdownCell(row.artifact.kind)} | ${markdownCell(row.artifact.path)} | ${markdownCell(row.artifact.format)} | ${markdownCell(row.artifact.redactionProfile)} |`
12793
+ );
12794
+ }
12795
+ }
12796
+ lines.push("");
12797
+ return `${lines.join("\n")}
12798
+ `;
12799
+ }
12800
+ function safeText(value) {
12801
+ const compact = value.replace(/\s+/g, " ").trim();
12802
+ const redacted = compact.replace(/\bsk-[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(
12803
+ /\b(?:api[_-]?key|authorization|token|secret|password)\s*[:=]\s*[^,\s]+/gi,
12804
+ "$1=[REDACTED]"
12805
+ );
12806
+ if (redacted.length <= MAX_TEXT) return redacted;
12807
+ return `${redacted.slice(0, MAX_TEXT - 12)}...[truncated]`;
12808
+ }
12809
+ async function ciSummaryCommand(manifestPaths, options = {}) {
12810
+ if (manifestPaths.length === 0) {
12811
+ console.error("At least one reporter manifest path is required.");
12812
+ process.exitCode = 1;
12813
+ return;
12814
+ }
12815
+ let result;
12816
+ try {
12817
+ const manifests = [];
12818
+ for (const manifestPath of manifestPaths) {
12819
+ manifests.push(await readReporterManifest(manifestPath));
12820
+ }
12821
+ manifests.sort((a, b) => a.manifestFile.localeCompare(b.manifestFile));
12822
+ result = summarize3(manifests);
12823
+ } catch (error) {
12824
+ const message = error instanceof Error ? error.message : String(error);
12825
+ console.error(`[AgentInspect] ci-summary failed: ${message}`);
12826
+ process.exitCode = 1;
12827
+ return;
12828
+ }
12829
+ const markdown = renderMarkdown2(result);
12830
+ const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path13__default.default.resolve(options.output.trim()) : void 0;
12831
+ if (outputPath !== void 0) {
12832
+ await promises.mkdir(path13__default.default.dirname(outputPath), { recursive: true });
12833
+ await promises.writeFile(outputPath, markdown, "utf-8");
12834
+ }
12835
+ const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
12836
+ if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
12837
+ const summaryPath = path13__default.default.resolve(summaryTarget);
12838
+ await promises.mkdir(path13__default.default.dirname(summaryPath), { recursive: true });
12839
+ await promises.appendFile(summaryPath, `
12840
+ ${markdown}`, "utf-8");
12841
+ }
12842
+ if (options.json === true) {
12843
+ console.log(writeJson4(result).trimEnd());
12844
+ } else if (outputPath !== void 0) {
12845
+ console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
12846
+ console.log(`Status: ${result.status}`);
12847
+ } else {
12848
+ console.log(markdown.trimEnd());
12849
+ }
12850
+ }
12486
12851
 
12487
12852
  // packages/cli/src/index.ts
12488
12853
  function runCommand(action) {
@@ -12668,6 +13033,9 @@ function createCliProgram() {
12668
13033
  ).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) => {
12669
13034
  runCommand(() => artifactsCommand(target, opts));
12670
13035
  });
13036
+ 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) => {
13037
+ runCommand(() => ciSummaryCommand(manifest, opts));
13038
+ });
12671
13039
  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(
12672
13040
  "--duration-threshold <duration>",
12673
13041
  "ignore duration deltas at or below this (e.g. 500ms, 2s, 1m)"
@@ -12760,9 +13128,9 @@ function isPrimaryModule() {
12760
13128
  if (!entry) return false;
12761
13129
  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)));
12762
13130
  try {
12763
- return fs.realpathSync(path11__default.default.resolve(entry)) === fs.realpathSync(path11__default.default.resolve(selfPath));
13131
+ return fs.realpathSync(path13__default.default.resolve(entry)) === fs.realpathSync(path13__default.default.resolve(selfPath));
12764
13132
  } catch {
12765
- return path11__default.default.resolve(entry) === path11__default.default.resolve(selfPath);
13133
+ return path13__default.default.resolve(entry) === path13__default.default.resolve(selfPath);
12766
13134
  }
12767
13135
  }
12768
13136
  if (isPrimaryModule()) {