agent-inspect 6.17.8 → 6.19.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/docs/ADAPTERS.md +34 -4
  4. package/docs/AI-SDK-ADOPTION.md +25 -0
  5. package/docs/API.md +13 -10
  6. package/docs/CLI.md +6 -0
  7. package/docs/COMPARE.md +6 -0
  8. package/docs/FIRST-TRACE-IN-5-MINUTES.md +3 -1
  9. package/docs/LIMITATIONS.md +1 -0
  10. package/docs/OPENAI-AGENTS-LOCAL.md +1 -0
  11. package/docs/SAFE-TRACE-SHARING.md +2 -2
  12. package/docs/SUPPORT-LEVELS.md +1 -0
  13. package/docs/USE-CASES.md +1 -1
  14. package/docs/VSCODE.md +8 -0
  15. package/package.json +2 -2
  16. package/packages/cli/dist/{chunk-25LUDS4T.mjs → chunk-R7Y5SGH5.mjs} +348 -27
  17. package/packages/cli/dist/chunk-R7Y5SGH5.mjs.map +1 -0
  18. package/packages/cli/dist/index.cjs +1622 -900
  19. package/packages/cli/dist/index.cjs.map +1 -1
  20. package/packages/cli/dist/index.mjs +1235 -850
  21. package/packages/cli/dist/index.mjs.map +1 -1
  22. package/packages/cli/dist/{src-2FS6BLR7.mjs → src-T4EZERCX.mjs} +3 -3
  23. package/packages/cli/dist/{src-2FS6BLR7.mjs.map → src-T4EZERCX.mjs.map} +1 -1
  24. package/packages/core/dist/advanced.cjs +180 -0
  25. package/packages/core/dist/advanced.cjs.map +1 -1
  26. package/packages/core/dist/advanced.d.cts +94 -4
  27. package/packages/core/dist/advanced.d.ts +94 -4
  28. package/packages/core/dist/advanced.mjs +177 -2
  29. package/packages/core/dist/advanced.mjs.map +1 -1
  30. package/packages/core/dist/checks.cjs +334 -5
  31. package/packages/core/dist/checks.cjs.map +1 -1
  32. package/packages/core/dist/checks.d.cts +81 -4
  33. package/packages/core/dist/checks.d.ts +81 -4
  34. package/packages/core/dist/checks.mjs +1 -1
  35. package/packages/core/dist/{chunk-LQC7IED3.mjs → chunk-NABMW5DX.mjs} +336 -8
  36. package/packages/core/dist/chunk-NABMW5DX.mjs.map +1 -0
  37. package/packages/core/dist/{index-B9ZGvUVL.d.ts → index-AMAGuO_i.d.ts} +1 -1
  38. package/packages/core/dist/{index-DWu54Y28.d.cts → index-DCR816Yt.d.cts} +2 -2
  39. package/packages/core/dist/{index-DlwbVqEs.d.ts → index-DKwuGSe-.d.ts} +2 -2
  40. package/packages/core/dist/{index-B259NKkH.d.cts → index-vqr-g6ev.d.cts} +1 -1
  41. package/packages/core/dist/readers.d.cts +1 -1
  42. package/packages/core/dist/readers.d.ts +1 -1
  43. package/packages/cli/dist/chunk-25LUDS4T.mjs.map +0 -1
  44. package/packages/core/dist/chunk-LQC7IED3.mjs.map +0 -1
@@ -4,7 +4,7 @@
4
4
  var crypto = require('crypto');
5
5
  var promises = require('fs/promises');
6
6
  var os = require('os');
7
- var path32 = require('path');
7
+ var path33 = require('path');
8
8
  var async_hooks = require('async_hooks');
9
9
  var process3 = require('process');
10
10
  var tty = require('tty');
@@ -22,7 +22,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
22
22
 
23
23
  var crypto__default = /*#__PURE__*/_interopDefault(crypto);
24
24
  var os__default = /*#__PURE__*/_interopDefault(os);
25
- var path32__default = /*#__PURE__*/_interopDefault(path32);
25
+ var path33__default = /*#__PURE__*/_interopDefault(path33);
26
26
  var process3__default = /*#__PURE__*/_interopDefault(process3);
27
27
  var tty__default = /*#__PURE__*/_interopDefault(tty);
28
28
 
@@ -866,7 +866,7 @@ function getDefaultTraceDir() {
866
866
  if (typeof home !== "string" || home.trim() === "") {
867
867
  return FALLBACK_TRACE_DIR;
868
868
  }
869
- return path32__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
869
+ return path33__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
870
870
  } catch {
871
871
  return FALLBACK_TRACE_DIR;
872
872
  }
@@ -874,11 +874,11 @@ function getDefaultTraceDir() {
874
874
  function getTraceFilePath(runId, traceDir) {
875
875
  const baseDir = traceDir ?? getDefaultTraceDir();
876
876
  let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
877
- safeId = path32__default.default.basename(safeId);
877
+ safeId = path33__default.default.basename(safeId);
878
878
  if (safeId === "" || safeId === "." || safeId === "..") {
879
879
  safeId = "run_unknown";
880
880
  }
881
- return path32__default.default.join(baseDir, `${safeId}.jsonl`);
881
+ return path33__default.default.join(baseDir, `${safeId}.jsonl`);
882
882
  }
883
883
  function formatError(error) {
884
884
  if (error instanceof Error) {
@@ -935,7 +935,7 @@ var init_utils = __esm({
935
935
  init_duration();
936
936
  DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
937
937
  RUNS_DIR_NAME = "runs";
938
- FALLBACK_TRACE_DIR = path32__default.default.join(
938
+ FALLBACK_TRACE_DIR = path33__default.default.join(
939
939
  os__default.default.tmpdir(),
940
940
  "agent-inspect",
941
941
  RUNS_DIR_NAME
@@ -1306,6 +1306,14 @@ var init_inspector = __esm({
1306
1306
  }
1307
1307
  });
1308
1308
 
1309
+ // packages/core/src/adapters/preview-capture.ts
1310
+ var init_preview_capture = __esm({
1311
+ "packages/core/src/adapters/preview-capture.ts"() {
1312
+ init_redactor();
1313
+ init_redaction_profiles();
1314
+ }
1315
+ });
1316
+
1309
1317
  // node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
1310
1318
  function assembleStyles() {
1311
1319
  const codes = /* @__PURE__ */ new Map();
@@ -1901,7 +1909,7 @@ var init_trace_directory = __esm({
1901
1909
  this.#dir = resolveTraceDir(options);
1902
1910
  }
1903
1911
  getPath(filename) {
1904
- return filename ? path32__default.default.join(this.#dir, filename) : this.#dir;
1912
+ return filename ? path33__default.default.join(this.#dir, filename) : this.#dir;
1905
1913
  }
1906
1914
  async list() {
1907
1915
  try {
@@ -1930,7 +1938,7 @@ function parseIsoToMs2(value) {
1930
1938
  }
1931
1939
  async function extractMetadata(filePath, _quickScan) {
1932
1940
  const stats = await promises.stat(filePath);
1933
- let runIdFromFile = path32__default.default.basename(filePath);
1941
+ let runIdFromFile = path33__default.default.basename(filePath);
1934
1942
  if (runIdFromFile.endsWith(".jsonl")) {
1935
1943
  runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
1936
1944
  }
@@ -3800,12 +3808,12 @@ function buildCriticalPath(runs, handoffs) {
3800
3808
  handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
3801
3809
  );
3802
3810
  const ordered = [...runs].sort(compareRuns);
3803
- const path43 = [];
3811
+ const path44 = [];
3804
3812
  const visited = /* @__PURE__ */ new Set();
3805
3813
  const pushRun = (run, confidence, source) => {
3806
3814
  if (visited.has(run.runId)) return;
3807
3815
  visited.add(run.runId);
3808
- path43.push({
3816
+ path44.push({
3809
3817
  runId: run.runId,
3810
3818
  name: run.name,
3811
3819
  startedAt: run.startedAt,
@@ -3830,7 +3838,7 @@ function buildCriticalPath(runs, handoffs) {
3830
3838
  const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
3831
3839
  pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
3832
3840
  }
3833
- return path43;
3841
+ return path44;
3834
3842
  }
3835
3843
  function metaRunIdMatches(run, token, runById) {
3836
3844
  const meta2 = extractSessionWorkflowMetadata(run.metadata);
@@ -4159,7 +4167,7 @@ var init_summary = __esm({
4159
4167
  });
4160
4168
  function sanitizeBundleRunId(runId) {
4161
4169
  let safe = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
4162
- safe = path32__default.default.basename(safe);
4170
+ safe = path33__default.default.basename(safe);
4163
4171
  safe = safe.replace(/[^a-zA-Z0-9._-]+/g, "_");
4164
4172
  if (safe === "" || safe === "." || safe === "..") {
4165
4173
  safe = "run_unknown";
@@ -4169,12 +4177,12 @@ function sanitizeBundleRunId(runId) {
4169
4177
  function bundleRunAssetRelativePath(runId, extension) {
4170
4178
  const safe = sanitizeBundleRunId(runId);
4171
4179
  const ext = extension.startsWith(".") ? extension : `.${extension}`;
4172
- return path32__default.default.posix.join("assets", "runs", `${safe}${ext}`);
4180
+ return path33__default.default.posix.join("assets", "runs", `${safe}${ext}`);
4173
4181
  }
4174
4182
  function assertBundlePathContained(outputDir, relativePath) {
4175
- const base = path32__default.default.resolve(outputDir);
4176
- const resolved = path32__default.default.resolve(base, relativePath);
4177
- if (resolved !== base && !resolved.startsWith(base + path32__default.default.sep)) {
4183
+ const base = path33__default.default.resolve(outputDir);
4184
+ const resolved = path33__default.default.resolve(base, relativePath);
4185
+ if (resolved !== base && !resolved.startsWith(base + path33__default.default.sep)) {
4178
4186
  throw new Error(`Bundle path escapes output directory: ${relativePath}`);
4179
4187
  }
4180
4188
  return resolved;
@@ -4184,7 +4192,7 @@ function normalizeBundleOutputPath(out, options) {
4184
4192
  if (trimmed === "") {
4185
4193
  throw new Error("--out requires a non-empty path.");
4186
4194
  }
4187
- const resolved = path32__default.default.resolve(trimmed);
4195
+ const resolved = path33__default.default.resolve(trimmed);
4188
4196
  if (options?.preserveZipExtension !== true && resolved.toLowerCase().endsWith(".zip")) {
4189
4197
  return resolved.slice(0, -4);
4190
4198
  }
@@ -4193,7 +4201,7 @@ function normalizeBundleOutputPath(out, options) {
4193
4201
  function defaultBundleOutputPath(runIds) {
4194
4202
  const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
4195
4203
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4196
- return path32__default.default.resolve(`agent-inspect-bundle-${label}-${stamp}`);
4204
+ return path33__default.default.resolve(`agent-inspect-bundle-${label}-${stamp}`);
4197
4205
  }
4198
4206
  var init_paths = __esm({
4199
4207
  "packages/core/src/bundle/paths.ts"() {
@@ -4256,7 +4264,7 @@ function assertEvidenceRelativePath(relativePath) {
4256
4264
  throw new Error("Evidence file path must be a non-empty relative path.");
4257
4265
  }
4258
4266
  const trimmed = relativePath.trim().replaceAll("\\", "/");
4259
- if (path32__default.default.isAbsolute(trimmed) || trimmed.startsWith("/")) {
4267
+ if (path33__default.default.isAbsolute(trimmed) || trimmed.startsWith("/")) {
4260
4268
  throw new Error(`Evidence file path must be relative: ${relativePath}`);
4261
4269
  }
4262
4270
  const parts = trimmed.split("/").filter((part) => part !== "");
@@ -5123,13 +5131,13 @@ function pairSteps(left, right) {
5123
5131
  return pairs;
5124
5132
  }
5125
5133
  function compareLeafSteps(L, R, segments, opts, out) {
5126
- const path43 = buildPath(segments);
5134
+ const path44 = buildPath(segments);
5127
5135
  if (L.name !== R.name) {
5128
5136
  out.push({
5129
5137
  kind: "structure",
5130
5138
  severity: "warning",
5131
5139
  message: "Step name differs",
5132
- path: path43,
5140
+ path: path44,
5133
5141
  left: L.name,
5134
5142
  right: R.name
5135
5143
  });
@@ -5139,7 +5147,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5139
5147
  kind: "step-type",
5140
5148
  severity: "warning",
5141
5149
  message: "Step type differs",
5142
- path: path43,
5150
+ path: path44,
5143
5151
  left: L.type,
5144
5152
  right: R.type
5145
5153
  });
@@ -5149,7 +5157,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5149
5157
  kind: "step-status",
5150
5158
  severity: "warning",
5151
5159
  message: "Step status differs",
5152
- path: path43,
5160
+ path: path44,
5153
5161
  left: L.status,
5154
5162
  right: R.status
5155
5163
  });
@@ -5161,7 +5169,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5161
5169
  kind: "error",
5162
5170
  severity: "error",
5163
5171
  message: "Step error message differs",
5164
- path: path43,
5172
+ path: path44,
5165
5173
  left: le || void 0,
5166
5174
  right: re || void 0
5167
5175
  });
@@ -5179,7 +5187,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5179
5187
  kind: "duration",
5180
5188
  severity: "info",
5181
5189
  message: "Step duration differs",
5182
- path: path43,
5190
+ path: path44,
5183
5191
  left: ld,
5184
5192
  right: rd
5185
5193
  });
@@ -5192,7 +5200,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5192
5200
  kind: "metadata",
5193
5201
  severity: "info",
5194
5202
  message: "Step metadata differs",
5195
- path: path43,
5203
+ path: path44,
5196
5204
  left: L.metadata,
5197
5205
  right: R.metadata
5198
5206
  });
@@ -5204,7 +5212,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
5204
5212
  kind: "output",
5205
5213
  severity: "info",
5206
5214
  message: "Output preview differs",
5207
- path: path43,
5215
+ path: path44,
5208
5216
  left: L.outputPreview,
5209
5217
  right: R.outputPreview
5210
5218
  });
@@ -5371,11 +5379,11 @@ var init_engine = __esm({
5371
5379
  });
5372
5380
 
5373
5381
  // packages/core/src/diff/renderer.ts
5374
- function formatPath(path43) {
5375
- if (path43 === void 0 || path43.path.length === 0) {
5382
+ function formatPath(path44) {
5383
+ if (path44 === void 0 || path44.path.length === 0) {
5376
5384
  return "(run)";
5377
5385
  }
5378
- return path43.path.map((s) => s.name).join(" > ");
5386
+ return path44.path.map((s) => s.name).join(" > ");
5379
5387
  }
5380
5388
  function formatValue(v, verbose) {
5381
5389
  if (v === void 0) return "(undefined)";
@@ -5755,11 +5763,11 @@ async function listFilesRecursive(root) {
5755
5763
  async function walk(dir) {
5756
5764
  const entries = await promises.readdir(dir, { withFileTypes: true });
5757
5765
  for (const entry of entries) {
5758
- const abs = path32__default.default.join(dir, entry.name);
5766
+ const abs = path33__default.default.join(dir, entry.name);
5759
5767
  if (entry.isDirectory()) {
5760
5768
  await walk(abs);
5761
5769
  } else if (entry.isFile()) {
5762
- const rel = path32__default.default.relative(root, abs).split(path32__default.default.sep).join("/");
5770
+ const rel = path33__default.default.relative(root, abs).split(path33__default.default.sep).join("/");
5763
5771
  out.push(rel);
5764
5772
  }
5765
5773
  }
@@ -5769,7 +5777,7 @@ async function listFilesRecursive(root) {
5769
5777
  }
5770
5778
  async function verifyEvidenceDirectory(rootPath, options = {}) {
5771
5779
  const unexpectedMode = options.unexpectedFiles ?? "fail";
5772
- const root = path32__default.default.resolve(rootPath);
5780
+ const root = path33__default.default.resolve(rootPath);
5773
5781
  const issues = [];
5774
5782
  let rootStat;
5775
5783
  try {
@@ -5799,7 +5807,7 @@ async function verifyEvidenceDirectory(rootPath, options = {}) {
5799
5807
  checkedFiles: 0
5800
5808
  };
5801
5809
  }
5802
- const manifestPath = path32__default.default.join(root, EVIDENCE_MANIFEST_FILENAME);
5810
+ const manifestPath = path33__default.default.join(root, EVIDENCE_MANIFEST_FILENAME);
5803
5811
  let manifestText;
5804
5812
  try {
5805
5813
  manifestText = await promises.readFile(manifestPath, "utf-8");
@@ -5885,7 +5893,7 @@ async function verifyEvidenceDirectory(rootPath, options = {}) {
5885
5893
  continue;
5886
5894
  }
5887
5895
  listed.add(rel);
5888
- const abs = path32__default.default.join(root, ...rel.split("/"));
5896
+ const abs = path33__default.default.join(root, ...rel.split("/"));
5889
5897
  let bytes;
5890
5898
  try {
5891
5899
  bytes = await promises.readFile(abs);
@@ -6200,7 +6208,7 @@ function normalizeSuiteConfig(value) {
6200
6208
  }
6201
6209
  async function validateSuiteConfig(config, options) {
6202
6210
  const diagnostics = [];
6203
- const tracesDir = path32__default.default.resolve(options.configDir, config.traces);
6211
+ const tracesDir = path33__default.default.resolve(options.configDir, config.traces);
6204
6212
  try {
6205
6213
  await promises.access(tracesDir);
6206
6214
  } catch {
@@ -6210,7 +6218,7 @@ async function validateSuiteConfig(config, options) {
6210
6218
  }
6211
6219
  for (const suiteCase of config.cases) {
6212
6220
  if (suiteCase.input !== void 0) {
6213
- const inputPath = path32__default.default.resolve(options.configDir, suiteCase.input);
6221
+ const inputPath = path33__default.default.resolve(options.configDir, suiteCase.input);
6214
6222
  try {
6215
6223
  await promises.access(inputPath);
6216
6224
  } catch {
@@ -6243,12 +6251,12 @@ async function fileExists(filePath) {
6243
6251
  }
6244
6252
  }
6245
6253
  async function resolveSuiteConfigPath(options = {}) {
6246
- const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
6254
+ const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
6247
6255
  if (options.configPath !== void 0 && options.configPath.trim() !== "") {
6248
- return path32__default.default.resolve(cwd, options.configPath.trim());
6256
+ return path33__default.default.resolve(cwd, options.configPath.trim());
6249
6257
  }
6250
6258
  for (const name of DEFAULT_SUITE_CONFIG_NAMES) {
6251
- const candidate = path32__default.default.join(cwd, name);
6259
+ const candidate = path33__default.default.join(cwd, name);
6252
6260
  if (await fileExists(candidate)) return candidate;
6253
6261
  }
6254
6262
  throw new Error(
@@ -6265,7 +6273,7 @@ async function loadSuiteConfig(options = {}) {
6265
6273
  diagnostics: [diagnostic2("AI_SUITE_CONFIG_LOAD_FAILED", message)]
6266
6274
  });
6267
6275
  }
6268
- const extension = path32__default.default.extname(configPath);
6276
+ const extension = path33__default.default.extname(configPath);
6269
6277
  if (TS_CONFIG_EXTENSIONS.has(extension)) {
6270
6278
  const message = "TypeScript suite configs require an explicit precompiled JavaScript config or future --config-loader support.";
6271
6279
  throw Object.assign(new Error(message), {
@@ -6290,7 +6298,7 @@ async function loadSuiteConfig(options = {}) {
6290
6298
  return {
6291
6299
  config,
6292
6300
  configPath,
6293
- configDir: path32__default.default.dirname(configPath)
6301
+ configDir: path33__default.default.dirname(configPath)
6294
6302
  };
6295
6303
  } catch (error) {
6296
6304
  const message = error instanceof Error ? error.message : String(error);
@@ -6340,7 +6348,7 @@ async function exists(filePath) {
6340
6348
  }
6341
6349
  async function resolveSuiteCaseTrace(suiteCase, options) {
6342
6350
  if (suiteCase.trace !== void 0) {
6343
- const tracePath = path32__default.default.resolve(options.configDir, suiteCase.trace);
6351
+ const tracePath = path33__default.default.resolve(options.configDir, suiteCase.trace);
6344
6352
  if (await exists(tracePath)) {
6345
6353
  return { caseId: suiteCase.id, tracePath, missing: false };
6346
6354
  }
@@ -6356,7 +6364,7 @@ async function resolveSuiteCaseTrace(suiteCase, options) {
6356
6364
  if (await exists(directPath)) {
6357
6365
  return { caseId: suiteCase.id, tracePath: directPath, runId: runKey, missing: false };
6358
6366
  }
6359
- const nestedPath = path32__default.default.join(options.tracesDir, `${path32__default.default.basename(runKey)}.jsonl`);
6367
+ const nestedPath = path33__default.default.join(options.tracesDir, `${path33__default.default.basename(runKey)}.jsonl`);
6360
6368
  if (await exists(nestedPath)) {
6361
6369
  return { caseId: suiteCase.id, tracePath: nestedPath, runId: runKey, missing: false };
6362
6370
  }
@@ -6812,6 +6820,330 @@ var init_logical_events = __esm({
6812
6820
  }
6813
6821
  });
6814
6822
 
6823
+ // packages/core/src/checks/derived-failure.ts
6824
+ function isRecord8(value) {
6825
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6826
+ }
6827
+ function pickString2(record, keys) {
6828
+ if (!record) return void 0;
6829
+ for (const key of keys) {
6830
+ const value = record[key];
6831
+ if (typeof value === "string" && value.trim() !== "") return value;
6832
+ }
6833
+ return void 0;
6834
+ }
6835
+ function pickNumber(record, keys) {
6836
+ if (!record) return void 0;
6837
+ for (const key of keys) {
6838
+ const value = record[key];
6839
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
6840
+ return value;
6841
+ }
6842
+ }
6843
+ return void 0;
6844
+ }
6845
+ function eventMetadata(event) {
6846
+ const attrs = isRecord8(event.attributes) ? event.attributes : void 0;
6847
+ const nested = attrs !== void 0 && isRecord8(attrs.metadata) ? attrs.metadata : void 0;
6848
+ return {
6849
+ ...attrs ?? {},
6850
+ ...nested ?? {}
6851
+ };
6852
+ }
6853
+ function canonicalName(event) {
6854
+ if (event.kind === "TOOL") return resolveCanonicalToolName(event);
6855
+ return event.name;
6856
+ }
6857
+ function linkKeys(event) {
6858
+ const meta2 = eventMetadata(event);
6859
+ const keys = [];
6860
+ for (const key of ["linkedStepId", "toolCallId", "mcpToolCallId"]) {
6861
+ const value = pickString2(meta2, [key]);
6862
+ if (value !== void 0) keys.push(`${key}:${value}`);
6863
+ }
6864
+ const stepId = pickString2(meta2, ["stepId"]);
6865
+ if (stepId !== void 0) keys.push(`stepId:${stepId}`);
6866
+ return keys;
6867
+ }
6868
+ function buildRunContexts(logicalEvents) {
6869
+ const byRun = /* @__PURE__ */ new Map();
6870
+ for (const event of logicalEvents) {
6871
+ const existing = byRun.get(event.runId) ?? {
6872
+ runId: event.runId,
6873
+ name: event.name
6874
+ };
6875
+ const meta2 = eventMetadata(event);
6876
+ if (event.kind === "RUN" || existing.name === event.runId) {
6877
+ existing.name = event.name || existing.name;
6878
+ }
6879
+ if (event.kind === "RUN" && event.status !== void 0 && event.status !== "running") {
6880
+ existing.status = event.status;
6881
+ }
6882
+ existing.retryOf ??= pickString2(meta2, ["retryOf"]);
6883
+ existing.attempt ??= pickNumber(meta2, ["attempt", "retryAttempt", "retryCount"]);
6884
+ existing.sessionId ??= pickString2(meta2, ["sessionId", "conversationId"]);
6885
+ existing.groupId ??= pickString2(meta2, ["groupId"]);
6886
+ existing.parentGroupId ??= pickString2(meta2, ["parentGroupId"]);
6887
+ existing.fallbackOf ??= pickString2(meta2, ["fallbackOf", "fallbackFrom"]);
6888
+ byRun.set(event.runId, existing);
6889
+ }
6890
+ return byRun;
6891
+ }
6892
+ function sameCorrelationScope(a, b) {
6893
+ if (a.sessionId && b.sessionId && a.sessionId === b.sessionId) return true;
6894
+ if (a.groupId && b.groupId && a.groupId === b.groupId) return true;
6895
+ if (a.parentGroupId && b.parentGroupId && a.parentGroupId === b.parentGroupId) {
6896
+ return true;
6897
+ }
6898
+ return false;
6899
+ }
6900
+ function isSuccessful(event) {
6901
+ return event.status === "ok";
6902
+ }
6903
+ function isFailure(event) {
6904
+ return event.status === "error";
6905
+ }
6906
+ function compareEventOrder(a, b) {
6907
+ const byTime = a.timestamp.localeCompare(b.timestamp);
6908
+ if (byTime !== 0) return byTime;
6909
+ return a.eventId.localeCompare(b.eventId);
6910
+ }
6911
+ function collectCandidates(failure, logicalEvents, runs) {
6912
+ const failureRun = runs.get(failure.runId);
6913
+ const failureLinks = new Set(linkKeys(failure));
6914
+ const failureName = canonicalName(failure);
6915
+ const failureAttempt = pickNumber(eventMetadata(failure), ["attempt", "retryAttempt", "retryCount"]) ?? failureRun?.attempt;
6916
+ const candidates = [];
6917
+ for (const event of logicalEvents) {
6918
+ if (event.eventId === failure.eventId) continue;
6919
+ if (event.status === "running") continue;
6920
+ const eventRun = runs.get(event.runId);
6921
+ const eventMeta = eventMetadata(event);
6922
+ const sameRun = event.runId === failure.runId;
6923
+ if (eventRun?.retryOf === failure.runId) {
6924
+ candidates.push({
6925
+ event,
6926
+ basis: "retryOf",
6927
+ confidence: "explicit",
6928
+ viaRunId: event.runId
6929
+ });
6930
+ continue;
6931
+ }
6932
+ if (eventRun?.fallbackOf === failure.runId || pickString2(eventMeta, ["fallbackOf", "fallbackFrom"]) === failure.runId) {
6933
+ candidates.push({
6934
+ event,
6935
+ basis: "fallbackOf",
6936
+ confidence: "explicit",
6937
+ viaRunId: event.runId
6938
+ });
6939
+ continue;
6940
+ }
6941
+ if (sameRun && compareEventOrder(failure, event) >= 0) continue;
6942
+ const eventLinks = linkKeys(event);
6943
+ const sharedLink = eventLinks.find((key) => failureLinks.has(key));
6944
+ if (sharedLink !== void 0) {
6945
+ candidates.push({
6946
+ event,
6947
+ basis: sharedLink.split(":")[0] ?? "linkedId",
6948
+ confidence: "explicit"
6949
+ });
6950
+ continue;
6951
+ }
6952
+ const eventAttempt = pickNumber(eventMeta, ["attempt", "retryAttempt", "retryCount"]) ?? eventRun?.attempt;
6953
+ const sameParent = failure.parentId !== void 0 && event.parentId !== void 0 && failure.parentId === event.parentId;
6954
+ const differentParent = failure.parentId !== void 0 && event.parentId !== void 0 && failure.parentId !== event.parentId;
6955
+ const sessionScoped = failureRun !== void 0 && eventRun !== void 0 && sameCorrelationScope(failureRun, eventRun);
6956
+ if (canonicalName(event) === failureName && failureAttempt !== void 0 && eventAttempt !== void 0 && eventAttempt > failureAttempt && !differentParent && (sameParent || sessionScoped || sameRun)) {
6957
+ candidates.push({
6958
+ event,
6959
+ basis: "attempt-progression",
6960
+ confidence: "correlated",
6961
+ ...event.runId !== failure.runId ? { viaRunId: event.runId } : {}
6962
+ });
6963
+ }
6964
+ }
6965
+ const byId = /* @__PURE__ */ new Map();
6966
+ for (const candidate of candidates) {
6967
+ const prev = byId.get(candidate.event.eventId);
6968
+ if (!prev || prev.confidence !== "explicit" && candidate.confidence === "explicit") {
6969
+ byId.set(candidate.event.eventId, candidate);
6970
+ }
6971
+ }
6972
+ return [...byId.values()].sort((a, b) => compareEventOrder(a.event, b.event));
6973
+ }
6974
+ function classifyFailure(failure, candidates, runs, logicalEvents) {
6975
+ const successful = candidates.filter((c) => isSuccessful(c.event));
6976
+ const unsuccessful = candidates.filter((c) => !isSuccessful(c.event));
6977
+ const retryRunIds = Object.freeze(
6978
+ [...new Set(candidates.map((c) => c.viaRunId).filter((id) => id !== void 0))].sort(
6979
+ (a, b) => a.localeCompare(b)
6980
+ )
6981
+ );
6982
+ if (successful.length > 1) {
6983
+ const distinctRuns = new Set(successful.map((c) => c.event.runId));
6984
+ const distinctParents = new Set(
6985
+ successful.map((c) => c.event.parentId ?? "").filter((id) => id !== "")
6986
+ );
6987
+ if (distinctRuns.size > 1 || distinctParents.size > 1) {
6988
+ return {
6989
+ eventId: failure.eventId,
6990
+ runId: failure.runId,
6991
+ name: failure.name,
6992
+ kind: failure.kind,
6993
+ role: "unknown",
6994
+ confidence: "unknown",
6995
+ basis: Object.freeze(["ambiguous-recovery-candidates"]),
6996
+ recoveryEventIds: Object.freeze(
6997
+ successful.map((c) => c.event.eventId).sort((a, b) => a.localeCompare(b))
6998
+ ),
6999
+ retryRunIds
7000
+ };
7001
+ }
7002
+ }
7003
+ if (successful.length >= 1) {
7004
+ const best = successful[0];
7005
+ return {
7006
+ eventId: failure.eventId,
7007
+ runId: failure.runId,
7008
+ name: failure.name,
7009
+ kind: failure.kind,
7010
+ role: "recovered",
7011
+ confidence: best.confidence,
7012
+ basis: Object.freeze([best.basis]),
7013
+ recoveryEventIds: Object.freeze(
7014
+ successful.map((c) => c.event.eventId).sort((a, b) => a.localeCompare(b))
7015
+ ),
7016
+ retryRunIds
7017
+ };
7018
+ }
7019
+ if (candidates.length > 0) {
7020
+ const best = candidates[0];
7021
+ return {
7022
+ eventId: failure.eventId,
7023
+ runId: failure.runId,
7024
+ name: failure.name,
7025
+ kind: failure.kind,
7026
+ role: "transient",
7027
+ confidence: best.confidence,
7028
+ basis: Object.freeze([
7029
+ best.basis,
7030
+ unsuccessful.some((c) => c.event.status === void 0) ? "retry-incomplete" : "retry-without-success"
7031
+ ]),
7032
+ recoveryEventIds: Object.freeze([]),
7033
+ retryRunIds
7034
+ };
7035
+ }
7036
+ const failureMeta = eventMetadata(failure);
7037
+ const declaredSuccessor = pickString2(failureMeta, [
7038
+ "retriedBy",
7039
+ "nextRetryRunId",
7040
+ "retryRunId"
7041
+ ]);
7042
+ if (declaredSuccessor !== void 0 && !runs.has(declaredSuccessor)) {
7043
+ return {
7044
+ eventId: failure.eventId,
7045
+ runId: failure.runId,
7046
+ name: failure.name,
7047
+ kind: failure.kind,
7048
+ role: "transient",
7049
+ confidence: "explicit",
7050
+ basis: Object.freeze(["retry-declared", "retry-run-missing"]),
7051
+ recoveryEventIds: Object.freeze([]),
7052
+ retryRunIds: Object.freeze([declaredSuccessor])
7053
+ };
7054
+ }
7055
+ for (const run of runs.values()) {
7056
+ if (run.retryOf === failure.runId) {
7057
+ return {
7058
+ eventId: failure.eventId,
7059
+ runId: failure.runId,
7060
+ name: failure.name,
7061
+ kind: failure.kind,
7062
+ role: "transient",
7063
+ confidence: "explicit",
7064
+ basis: Object.freeze(["retryOf", "retry-run-missing-or-empty"]),
7065
+ recoveryEventIds: Object.freeze([]),
7066
+ retryRunIds: Object.freeze([run.runId])
7067
+ };
7068
+ }
7069
+ }
7070
+ const failureRun = runs.get(failure.runId);
7071
+ const hasSuccessorDeclared = [...runs.values()].some((run) => run.retryOf === failure.runId);
7072
+ const isFinalInChain = failureRun !== void 0 && !hasSuccessorDeclared && (failureRun.retryOf !== void 0 || failureRun.attempt !== void 0 && failureRun.attempt > 1 || pickNumber(eventMetadata(failure), ["attempt"]) !== void 0);
7073
+ if (isFinalInChain && failureRun?.status === "error" && !logicalEvents.some(
7074
+ (event) => event.runId === failure.runId && event.eventId !== failure.eventId && isSuccessful(event) && canonicalName(event) === canonicalName(failure)
7075
+ )) {
7076
+ return {
7077
+ eventId: failure.eventId,
7078
+ runId: failure.runId,
7079
+ name: failure.name,
7080
+ kind: failure.kind,
7081
+ role: "terminal",
7082
+ confidence: failureRun.retryOf !== void 0 ? "explicit" : "correlated",
7083
+ basis: Object.freeze(["final-retry-chain-member", "enclosing-run-error"]),
7084
+ recoveryEventIds: Object.freeze([]),
7085
+ retryRunIds: Object.freeze(
7086
+ failureRun.retryOf !== void 0 ? [failureRun.retryOf] : []
7087
+ )
7088
+ };
7089
+ }
7090
+ return {
7091
+ eventId: failure.eventId,
7092
+ runId: failure.runId,
7093
+ name: failure.name,
7094
+ kind: failure.kind,
7095
+ role: "unknown",
7096
+ confidence: "unknown",
7097
+ basis: Object.freeze(["no-explicit-or-correlated-recovery"]),
7098
+ recoveryEventIds: Object.freeze([]),
7099
+ retryRunIds: Object.freeze([])
7100
+ };
7101
+ }
7102
+ function deriveFailureFacts(logicalEvents) {
7103
+ const runs = buildRunContexts(logicalEvents);
7104
+ const failures = logicalEvents.filter((event) => isFailure(event)).sort(compareEventOrder);
7105
+ const failureFacts = failures.map(
7106
+ (failure) => classifyFailure(failure, collectCandidates(failure, logicalEvents, runs), runs, logicalEvents)
7107
+ );
7108
+ const byRole = /* @__PURE__ */ new Map([
7109
+ ["transient", []],
7110
+ ["recovered", []],
7111
+ ["terminal", []],
7112
+ ["unknown", []]
7113
+ ]);
7114
+ for (const fact2 of failureFacts) {
7115
+ byRole.get(fact2.role).push(fact2);
7116
+ }
7117
+ for (const [role, list2] of byRole) {
7118
+ byRole.set(
7119
+ role,
7120
+ Object.freeze(
7121
+ [...list2].sort((a, b) => {
7122
+ const byRun = a.runId.localeCompare(b.runId);
7123
+ if (byRun !== 0) return byRun;
7124
+ return a.eventId.localeCompare(b.eventId);
7125
+ })
7126
+ )
7127
+ );
7128
+ }
7129
+ const failureRoleCounts = {
7130
+ transient: byRole.get("transient").length,
7131
+ recovered: byRole.get("recovered").length,
7132
+ terminal: byRole.get("terminal").length,
7133
+ unknown: byRole.get("unknown").length
7134
+ };
7135
+ return {
7136
+ failureFacts: Object.freeze(failureFacts),
7137
+ failuresByRole: byRole,
7138
+ failureRoleCounts
7139
+ };
7140
+ }
7141
+ var init_derived_failure = __esm({
7142
+ "packages/core/src/checks/derived-failure.ts"() {
7143
+ init_logical_events();
7144
+ }
7145
+ });
7146
+
6815
7147
  // packages/core/src/checks/trace-facts.ts
6816
7148
  function summarizeSemanticParity(events) {
6817
7149
  const projection = projectLogicalEvents(events);
@@ -6822,6 +7154,7 @@ function summarizeSemanticParity(events) {
6822
7154
  const finishedToolNames = Object.freeze(
6823
7155
  finishedTools.map((event) => resolveCanonicalToolName(event)).sort((a, b) => a.localeCompare(b))
6824
7156
  );
7157
+ const derived = deriveFailureFacts(logical);
6825
7158
  return {
6826
7159
  rawEventCount: events.length,
6827
7160
  logicalEventCount: logical.length,
@@ -6832,13 +7165,16 @@ function summarizeSemanticParity(events) {
6832
7165
  parentRemapCount: projection.diagnostics.filter(
6833
7166
  (item) => item.code === "AI_LOGICAL_PARENT_REMAPPED"
6834
7167
  ).length,
6835
- diagnostics: projection.diagnostics
7168
+ diagnostics: projection.diagnostics,
7169
+ failureRoleCounts: derived.failureRoleCounts
6836
7170
  };
6837
7171
  }
6838
7172
  var init_trace_facts = __esm({
6839
7173
  "packages/core/src/checks/trace-facts.ts"() {
6840
7174
  init_programmatic();
7175
+ init_derived_failure();
6841
7176
  init_logical_events();
7177
+ init_derived_failure();
6842
7178
  formatProgrammaticDiagnostic(
6843
7179
  "AI_TRACE_FACTS_INPUT_NOT_NORMALIZED"
6844
7180
  );
@@ -7106,7 +7442,7 @@ function stripPrefix(name, prefixes) {
7106
7442
  }
7107
7443
  return name;
7108
7444
  }
7109
- function eventEvidence(event, path43) {
7445
+ function eventEvidence(event, path44) {
7110
7446
  return {
7111
7447
  runId: event.runId,
7112
7448
  eventId: event.eventId,
@@ -7116,7 +7452,7 @@ function eventEvidence(event, path43) {
7116
7452
  kind: event.kind,
7117
7453
  name: event.name,
7118
7454
  status: event.status,
7119
- ...path43 ? { path: path43 } : {}
7455
+ ...path44 ? { path: path44 } : {}
7120
7456
  };
7121
7457
  }
7122
7458
  function runEvidence(run) {
@@ -7166,7 +7502,7 @@ function finishedEvents(context, kind) {
7166
7502
  function toolInvocationEvents(context) {
7167
7503
  return semanticEvents(context).filter((event) => event.kind === "TOOL");
7168
7504
  }
7169
- function isRecord8(value) {
7505
+ function isRecord9(value) {
7170
7506
  return typeof value === "object" && value !== null && !Array.isArray(value);
7171
7507
  }
7172
7508
  function eventMap(events) {
@@ -7192,9 +7528,9 @@ function eventEndMs(event) {
7192
7528
  function normalizedKey(value) {
7193
7529
  return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
7194
7530
  }
7195
- function lastPathSegment(path43) {
7196
- const parts = path43.split(".");
7197
- return parts[parts.length - 1] ?? path43;
7531
+ function lastPathSegment(path44) {
7532
+ const parts = path44.split(".");
7533
+ return parts[parts.length - 1] ?? path44;
7198
7534
  }
7199
7535
  function valueType(value) {
7200
7536
  if (Array.isArray(value)) return "array";
@@ -7208,22 +7544,22 @@ function serializedByteLength(value) {
7208
7544
  return void 0;
7209
7545
  }
7210
7546
  }
7211
- function pushValueEntries(entries, event, value, path43, key, depth = 0) {
7212
- entries.push({ event, path: path43, key, value });
7547
+ function pushValueEntries(entries, event, value, path44, key, depth = 0) {
7548
+ entries.push({ event, path: path44, key, value });
7213
7549
  if (depth >= 8) return;
7214
7550
  if (Array.isArray(value)) {
7215
7551
  for (const [index, item] of value.entries()) {
7216
- pushValueEntries(entries, event, item, `${path43}.${index}`, String(index), depth + 1);
7552
+ pushValueEntries(entries, event, item, `${path44}.${index}`, String(index), depth + 1);
7217
7553
  }
7218
7554
  return;
7219
7555
  }
7220
- if (!isRecord8(value)) return;
7556
+ if (!isRecord9(value)) return;
7221
7557
  for (const nestedKey of Object.keys(value).sort((a, b) => a.localeCompare(b))) {
7222
7558
  pushValueEntries(
7223
7559
  entries,
7224
7560
  event,
7225
7561
  value[nestedKey],
7226
- `${path43}.${nestedKey}`,
7562
+ `${path44}.${nestedKey}`,
7227
7563
  nestedKey,
7228
7564
  depth + 1
7229
7565
  );
@@ -7262,18 +7598,18 @@ function isRawContentKey(key, forbiddenKeys) {
7262
7598
  const normalized = normalizedKey(key);
7263
7599
  return forbiddenKeys.some((forbidden) => normalized === normalizedKey(forbidden));
7264
7600
  }
7265
- function isSafeRawContentMetricPath(path43, key, safePathPrefixes) {
7266
- const leaf = normalizedKey(key ?? lastPathSegment(path43));
7601
+ function isSafeRawContentMetricPath(path44, key, safePathPrefixes) {
7602
+ const leaf = normalizedKey(key ?? lastPathSegment(path44));
7267
7603
  if (!SAFE_USAGE_LEAF_KEYS.has(leaf)) return false;
7268
- const parts = path43.split(".").filter(Boolean);
7604
+ const parts = path44.split(".").filter(Boolean);
7269
7605
  if (parts.length < 2) return false;
7270
7606
  const parent = parts[parts.length - 2] ?? "";
7271
7607
  const parentNorm = normalizedKey(parent);
7272
7608
  return safePathPrefixes.some((prefix) => parentNorm === normalizedKey(prefix));
7273
7609
  }
7274
- function isRawContentPath(path43, key, forbiddenKeys, safePathPrefixes) {
7275
- if (isSafeRawContentMetricPath(path43, key, safePathPrefixes)) return false;
7276
- return isRawContentKey(key ?? lastPathSegment(path43), forbiddenKeys);
7610
+ function isRawContentPath(path44, key, forbiddenKeys, safePathPrefixes) {
7611
+ if (isSafeRawContentMetricPath(path44, key, safePathPrefixes)) return false;
7612
+ return isRawContentKey(key ?? lastPathSegment(path44), forbiddenKeys);
7277
7613
  }
7278
7614
  function parentMarkedUnresolved(event) {
7279
7615
  if (booleanAttr(event, [
@@ -7312,9 +7648,9 @@ function eventDurationMs(event) {
7312
7648
  }
7313
7649
  function treeShape(nodes) {
7314
7650
  const lines = [];
7315
- const visit = (node, path43) => {
7316
- lines.push(`${path43}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
7317
- node.children.forEach((child, index) => visit(child, `${path43}.${index}`));
7651
+ const visit = (node, path44) => {
7652
+ lines.push(`${path44}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
7653
+ node.children.forEach((child, index) => visit(child, `${path44}.${index}`));
7318
7654
  };
7319
7655
  nodes.forEach((node, index) => visit(node, String(index)));
7320
7656
  return lines;
@@ -7363,9 +7699,9 @@ function retrievalShape(context) {
7363
7699
  function guardrailShape(context) {
7364
7700
  return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
7365
7701
  }
7366
- function firstEvidenceForKind(context, kind, path43) {
7702
+ function firstEvidenceForKind(context, kind, path44) {
7367
7703
  const event = semanticEvents(context).find((candidate) => candidate.kind === kind);
7368
- return event ? [eventEvidence(event, path43)] : runEvidence(context.selectedRun);
7704
+ return event ? [eventEvidence(event, path44)] : runEvidence(context.selectedRun);
7369
7705
  }
7370
7706
  function baselineDiffFinding(message, evidence, expected, actual) {
7371
7707
  return failFinding("baseline.regression", message, evidence, expected, actual);
@@ -7715,13 +8051,13 @@ function createStructureCycleRule() {
7715
8051
  const seenCycles = /* @__PURE__ */ new Set();
7716
8052
  const findings = [];
7717
8053
  for (const event of [...semanticEvents(context)].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
7718
- const path43 = [];
8054
+ const path44 = [];
7719
8055
  const seenAt = /* @__PURE__ */ new Map();
7720
8056
  let current = event;
7721
8057
  while (current) {
7722
8058
  const existing = seenAt.get(current.eventId);
7723
8059
  if (existing !== void 0) {
7724
- const cycle = path43.slice(existing);
8060
+ const cycle = path44.slice(existing);
7725
8061
  const key = cycle.map((item) => item.eventId).sort().join("\0");
7726
8062
  if (!seenCycles.has(key)) {
7727
8063
  seenCycles.add(key);
@@ -7737,8 +8073,8 @@ function createStructureCycleRule() {
7737
8073
  }
7738
8074
  break;
7739
8075
  }
7740
- seenAt.set(current.eventId, path43.length);
7741
- path43.push(current);
8076
+ seenAt.set(current.eventId, path44.length);
8077
+ path44.push(current);
7742
8078
  current = current.parentId ? byId.get(current.parentId) : void 0;
7743
8079
  }
7744
8080
  }
@@ -8043,7 +8379,7 @@ function createSafetyOversizedAttributeRule(options) {
8043
8379
  )
8044
8380
  );
8045
8381
  }
8046
- if (isRecord8(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
8382
+ if (isRecord9(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
8047
8383
  findings.push(
8048
8384
  failFinding(
8049
8385
  "safety.oversizedAttribute",
@@ -8429,14 +8765,14 @@ var init_checks2 = __esm({
8429
8765
  });
8430
8766
 
8431
8767
  // packages/core/src/persisted/token-usage.ts
8432
- function isRecord9(value) {
8768
+ function isRecord10(value) {
8433
8769
  return typeof value === "object" && value !== null && !Array.isArray(value);
8434
8770
  }
8435
8771
  function nonNegativeFinite(value) {
8436
8772
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
8437
8773
  }
8438
8774
  function normalizeTokenUsage(value) {
8439
- if (!isRecord9(value)) return void 0;
8775
+ if (!isRecord10(value)) return void 0;
8440
8776
  const input3 = nonNegativeFinite(value.input);
8441
8777
  const output2 = nonNegativeFinite(value.output);
8442
8778
  const suppliedTotal = nonNegativeFinite(value.total);
@@ -9117,7 +9453,7 @@ function findReaderByFormat(format, readers) {
9117
9453
  }
9118
9454
  async function jsonlFilesInDirectory(dirPath) {
9119
9455
  const entries = await promises.readdir(dirPath, { withFileTypes: true });
9120
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path32__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
9456
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path33__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
9121
9457
  }
9122
9458
  async function resolveInput(input3) {
9123
9459
  const cached2 = resolvedInputCache.get(input3);
@@ -9266,7 +9602,7 @@ function persistedEventsForParsedTrace(parsed) {
9266
9602
  sourceName: "agent-inspect-jsonl-reader"
9267
9603
  });
9268
9604
  }
9269
- function isRecord10(value) {
9605
+ function isRecord11(value) {
9270
9606
  return typeof value === "object" && value !== null && !Array.isArray(value);
9271
9607
  }
9272
9608
  function isNonEmptyString4(value) {
@@ -9281,13 +9617,13 @@ function readStringField(record, keys) {
9281
9617
  }
9282
9618
  function readRecordField(record, key) {
9283
9619
  const value = record[key];
9284
- return isRecord10(value) ? value : void 0;
9620
+ return isRecord11(value) ? value : void 0;
9285
9621
  }
9286
9622
  function parseJsonDocument(content) {
9287
9623
  return JSON.parse(content);
9288
9624
  }
9289
9625
  function looksLikeOpenInferenceSpan(value) {
9290
- if (!isRecord10(value)) return false;
9626
+ if (!isRecord11(value)) return false;
9291
9627
  const attributes = readRecordField(value, "attributes");
9292
9628
  return readStringField(value, ["trace_id", "traceId"]) !== void 0 && readStringField(value, ["span_id", "spanId"]) !== void 0 && (readStringField(value, ["name"]) !== void 0 || attributes?.["openinference.span.kind"] !== void 0);
9293
9629
  }
@@ -9312,7 +9648,7 @@ function extractOpenInferenceDocument(root) {
9312
9648
  unsupportedFields
9313
9649
  };
9314
9650
  }
9315
- if (!isRecord10(root)) return void 0;
9651
+ if (!isRecord11(root)) return void 0;
9316
9652
  const rootFormat = root.format;
9317
9653
  const rootCompatibility = root.compatibility;
9318
9654
  const version2 = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
@@ -9452,7 +9788,7 @@ function summarizeAttributeValue(value) {
9452
9788
  if (Array.isArray(value)) {
9453
9789
  return { type: "array", length: value.length };
9454
9790
  }
9455
- if (isRecord10(value)) {
9791
+ if (isRecord11(value)) {
9456
9792
  return { type: "object", keyCount: Object.keys(value).length };
9457
9793
  }
9458
9794
  if (value === null) {
@@ -9539,7 +9875,7 @@ function mapOpenInferenceKind(span, attributes, pathPrefix) {
9539
9875
  }
9540
9876
  }
9541
9877
  function mapOpenInferenceStatus(status) {
9542
- if (!isRecord10(status)) return void 0;
9878
+ if (!isRecord11(status)) return void 0;
9543
9879
  const rawCode = status.code;
9544
9880
  if (typeof rawCode !== "string") return void 0;
9545
9881
  switch (rawCode.toUpperCase()) {
@@ -9639,7 +9975,7 @@ function mapOpenInferenceSpan(span, index, version2) {
9639
9975
  warnings.push(...kindWarnings);
9640
9976
  const status = mapOpenInferenceStatus(span.status);
9641
9977
  const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
9642
- const errorMessage = isRecord10(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
9978
+ const errorMessage = isRecord11(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
9643
9979
  const event = {
9644
9980
  schemaVersion: "0.2",
9645
9981
  eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
@@ -9707,7 +10043,7 @@ function mapOpenInferenceEvents(document) {
9707
10043
  };
9708
10044
  }
9709
10045
  function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
9710
- if (!isRecord10(value)) {
10046
+ if (!isRecord11(value)) {
9711
10047
  unsupportedFields.push(field);
9712
10048
  warnings.push({
9713
10049
  code: "otlp_attribute_value_invalid",
@@ -9729,15 +10065,15 @@ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
9729
10065
  if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
9730
10066
  return value.doubleValue;
9731
10067
  }
9732
- if (isRecord10(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
10068
+ if (isRecord11(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
9733
10069
  return value.arrayValue.values.map(
9734
10070
  (item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
9735
10071
  );
9736
10072
  }
9737
- if (isRecord10(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
10073
+ if (isRecord11(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
9738
10074
  const out = {};
9739
10075
  for (const [index, item] of value.kvlistValue.values.entries()) {
9740
- if (!isRecord10(item) || typeof item.key !== "string") {
10076
+ if (!isRecord11(item) || typeof item.key !== "string") {
9741
10077
  unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
9742
10078
  continue;
9743
10079
  }
@@ -9788,7 +10124,7 @@ function parseOtlpAttributes(value, pathPrefix) {
9788
10124
  }
9789
10125
  for (const [index, item] of value.entries()) {
9790
10126
  const field = `${pathPrefix}[${index}]`;
9791
- if (!isRecord10(item) || typeof item.key !== "string") {
10127
+ if (!isRecord11(item) || typeof item.key !== "string") {
9792
10128
  unsupportedFields.push(field);
9793
10129
  warnings.push({
9794
10130
  code: "otlp_attribute_invalid",
@@ -9811,16 +10147,16 @@ function parseOtlpAttributes(value, pathPrefix) {
9811
10147
  return { attributes, warnings, unsupportedFields };
9812
10148
  }
9813
10149
  function looksLikeOtlpSpan(value) {
9814
- return isRecord10(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
10150
+ return isRecord11(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
9815
10151
  }
9816
10152
  function extractOtlpDocument(root) {
9817
- if (!isRecord10(root) || !Array.isArray(root.resourceSpans)) return void 0;
10153
+ if (!isRecord11(root) || !Array.isArray(root.resourceSpans)) return void 0;
9818
10154
  const spans = [];
9819
10155
  const warnings = [];
9820
10156
  const unsupportedFields = [];
9821
10157
  for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
9822
10158
  const resourcePath = `resourceSpans[${resourceIndex}]`;
9823
- if (!isRecord10(resourceSpan)) {
10159
+ if (!isRecord11(resourceSpan)) {
9824
10160
  unsupportedFields.push(resourcePath);
9825
10161
  continue;
9826
10162
  }
@@ -9843,7 +10179,7 @@ function extractOtlpDocument(root) {
9843
10179
  }
9844
10180
  for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
9845
10181
  const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
9846
- if (!isRecord10(scopeSpan)) {
10182
+ if (!isRecord11(scopeSpan)) {
9847
10183
  unsupportedFields.push(scopePath);
9848
10184
  continue;
9849
10185
  }
@@ -9910,7 +10246,7 @@ function extractOtlpDocument(root) {
9910
10246
  };
9911
10247
  }
9912
10248
  function mapOtlpStatus(status) {
9913
- if (!isRecord10(status)) return void 0;
10249
+ if (!isRecord11(status)) return void 0;
9914
10250
  const rawCode = status.code;
9915
10251
  if (typeof rawCode !== "string") return void 0;
9916
10252
  switch (rawCode.toUpperCase()) {
@@ -10010,7 +10346,7 @@ function mapOtlpEvents(value, pathPrefix) {
10010
10346
  const events = [];
10011
10347
  for (const [index, event] of value.entries()) {
10012
10348
  const eventPath = `${pathPrefix}[${index}]`;
10013
- if (!isRecord10(event)) {
10349
+ if (!isRecord11(event)) {
10014
10350
  unsupportedFields.push(eventPath);
10015
10351
  continue;
10016
10352
  }
@@ -10148,7 +10484,7 @@ function mapOtlpSpan(context) {
10148
10484
  warnings.push(...kindWarnings);
10149
10485
  const status = mapOtlpStatus(span.status);
10150
10486
  const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
10151
- const errorMessage = isRecord10(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
10487
+ const errorMessage = isRecord11(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
10152
10488
  const event = {
10153
10489
  schemaVersion: "0.2",
10154
10490
  eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
@@ -10824,7 +11160,7 @@ async function runSuiteCase(suiteCase, config, options) {
10824
11160
  async function runSuite(options = {}) {
10825
11161
  const startedAt = new Date(options.nowMs ?? Date.now()).toISOString();
10826
11162
  const { config, configPath, configDir } = await loadSuiteConfig(options);
10827
- const tracesDir = path32__default.default.resolve(configDir, config.traces);
11163
+ const tracesDir = path33__default.default.resolve(configDir, config.traces);
10828
11164
  const cases = [];
10829
11165
  const diagnostics = [];
10830
11166
  for (const suiteCase of config.cases) {
@@ -11851,7 +12187,7 @@ function validateOptions(options) {
11851
12187
  }
11852
12188
  function isConfigLoadError(error) {
11853
12189
  if (!(error instanceof Error)) return false;
11854
- const ext = path32__default.default.extname(error.message);
12190
+ const ext = path33__default.default.extname(error.message);
11855
12191
  if (error.message.includes("Unsupported suite config extension")) return true;
11856
12192
  if (error.message.includes("TypeScript suite configs require")) return true;
11857
12193
  if (error.message.includes("No suite config found")) return true;
@@ -12098,6 +12434,7 @@ var init_advanced = __esm({
12098
12434
  init_inspector();
12099
12435
  init_inspector_runtime();
12100
12436
  init_trace_event_safety();
12437
+ init_preview_capture();
12101
12438
  init_terminal();
12102
12439
  init_utils();
12103
12440
  init_types();
@@ -12245,8 +12582,8 @@ var init_load_sqlite = __esm({
12245
12582
  }
12246
12583
  });
12247
12584
  function resolveIndexDbPath(traceDir, dbPath) {
12248
- if (dbPath && dbPath.trim() !== "") return path32__default.default.resolve(dbPath);
12249
- return path32__default.default.join(path32__default.default.resolve(traceDir), INDEX_DB_FILENAME);
12585
+ if (dbPath && dbPath.trim() !== "") return path33__default.default.resolve(dbPath);
12586
+ return path33__default.default.join(path33__default.default.resolve(traceDir), INDEX_DB_FILENAME);
12250
12587
  }
12251
12588
  function str(value) {
12252
12589
  return typeof value === "string" && value !== "" ? value : null;
@@ -12338,7 +12675,7 @@ async function buildIndex(options = {}) {
12338
12675
  warnings.push(`index.unreadable: ${file}`);
12339
12676
  }
12340
12677
  }
12341
- await promises.mkdir(path32__default.default.dirname(dbPath), { recursive: true });
12678
+ await promises.mkdir(path33__default.default.dirname(dbPath), { recursive: true });
12342
12679
  await promises.rm(dbPath, { force: true });
12343
12680
  const Sqlite = loadBetterSqlite3();
12344
12681
  const db = new Sqlite(dbPath);
@@ -12586,7 +12923,7 @@ var init_src = __esm({
12586
12923
  });
12587
12924
 
12588
12925
  // package.json
12589
- var version = "6.17.8";
12926
+ var version = "6.19.0";
12590
12927
 
12591
12928
  // packages/cli/src/list.ts
12592
12929
  init_advanced();
@@ -13084,6 +13421,16 @@ function filterErrorEvents(events) {
13084
13421
  return false;
13085
13422
  });
13086
13423
  }
13424
+ function pruneErrorTree(nodes) {
13425
+ const pruned = [];
13426
+ for (const node of nodes) {
13427
+ const children = pruneErrorTree(node.children);
13428
+ if (node.status === "error" || children.length > 0) {
13429
+ pruned.push({ ...node, children });
13430
+ }
13431
+ }
13432
+ return pruned;
13433
+ }
13087
13434
  async function view(runId, options = {}) {
13088
13435
  try {
13089
13436
  const id = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "";
@@ -13156,11 +13503,44 @@ async function view(runId, options = {}) {
13156
13503
  const errEvents = filterErrorEvents(events);
13157
13504
  if (options.json) {
13158
13505
  console.log(JSON.stringify(errEvents, null, 2));
13159
- } else if (errEvents.length === 0) {
13506
+ return;
13507
+ }
13508
+ if (errEvents.length === 0) {
13160
13509
  console.log("No errors found in trace");
13510
+ return;
13511
+ }
13512
+ const started2 = events.find(
13513
+ (e) => e.event === "run_started"
13514
+ );
13515
+ const completed2 = events.filter(
13516
+ (e) => e.event === "run_completed"
13517
+ );
13518
+ const last2 = completed2[completed2.length - 1];
13519
+ const status2 = last2 ? last2.status : "running";
13520
+ const durationLine2 = last2 !== void 0 && Number.isFinite(last2.durationMs) ? formatDuration2(last2.durationMs) : "-";
13521
+ const startedTs2 = started2 !== void 0 && Number.isFinite(started2.startTime) ? started2.startTime : started2?.timestamp;
13522
+ const startedLabel2 = startedTs2 !== void 0 ? formatTimestamp(startedTs2) : "-";
13523
+ console.log(`AgentInspect Run: ${started2?.name ?? id}`);
13524
+ console.log(`ID: ${id}`);
13525
+ console.log(`Status: ${status2}`);
13526
+ console.log(`Duration: ${durationLine2}`);
13527
+ console.log(`Started: ${startedLabel2}`);
13528
+ console.log("");
13529
+ console.log("Error Tree:");
13530
+ const pruned = pruneErrorTree(buildStepTree(events));
13531
+ if (pruned.length === 0) {
13532
+ if (last2?.status === "error") {
13533
+ console.log(
13534
+ renderErrorLine(
13535
+ last2.error ?? { message: "Run completed with error status" },
13536
+ 0
13537
+ )
13538
+ );
13539
+ } else {
13540
+ console.log("No error steps recorded");
13541
+ }
13161
13542
  } else {
13162
- console.log("Error events");
13163
- console.log(JSON.stringify(errEvents, null, 2));
13543
+ printStepTree(pruned, 0, options.verbose === true);
13164
13544
  }
13165
13545
  return;
13166
13546
  }
@@ -13205,7 +13585,7 @@ async function view(runId, options = {}) {
13205
13585
  process.exitCode = 1;
13206
13586
  }
13207
13587
  }
13208
- function isRecord11(v) {
13588
+ function isRecord12(v) {
13209
13589
  return typeof v === "object" && v !== null && !Array.isArray(v);
13210
13590
  }
13211
13591
  function isNonEmptyStringArray(v) {
@@ -13217,7 +13597,7 @@ function validateRedact(redact2) {
13217
13597
  }
13218
13598
  for (const r of redact2) {
13219
13599
  if (typeof r === "string") continue;
13220
- if (!isRecord11(r)) {
13600
+ if (!isRecord12(r)) {
13221
13601
  throw new Error("Invalid config: redact entries must be strings or objects");
13222
13602
  }
13223
13603
  if (typeof r.key !== "string" || r.key.trim() === "") {
@@ -13236,7 +13616,7 @@ function validateRedact(redact2) {
13236
13616
  }
13237
13617
  }
13238
13618
  function validateMappings(mappings) {
13239
- if (!isRecord11(mappings)) {
13619
+ if (!isRecord12(mappings)) {
13240
13620
  throw new Error("Invalid config: mappings must be an object");
13241
13621
  }
13242
13622
  }
@@ -13286,7 +13666,7 @@ async function loadLogIngestConfig(configPath) {
13286
13666
  const msg = e instanceof Error ? e.message : String(e);
13287
13667
  throw new Error(`Invalid JSON in config file: ${configPath} (${msg})`);
13288
13668
  }
13289
- if (!isRecord11(parsed)) {
13669
+ if (!isRecord12(parsed)) {
13290
13670
  throw new Error("Invalid config: expected a JSON object at top-level");
13291
13671
  }
13292
13672
  const user = parsed;
@@ -13323,7 +13703,7 @@ async function loadLogIngestConfig(configPath) {
13323
13703
  }
13324
13704
  return mergeLogIngestConfig(DEFAULT_LOG_INGEST_CONFIG, user);
13325
13705
  }
13326
- function isRecord12(v) {
13706
+ function isRecord13(v) {
13327
13707
  return typeof v === "object" && v !== null && !Array.isArray(v);
13328
13708
  }
13329
13709
  var JsonLogParser = class {
@@ -13348,7 +13728,7 @@ var JsonLogParser = class {
13348
13728
  });
13349
13729
  continue;
13350
13730
  }
13351
- if (!isRecord12(parsed)) {
13731
+ if (!isRecord13(parsed)) {
13352
13732
  warnings.push({
13353
13733
  code: "MALFORMED_JSON",
13354
13734
  message: "JSON log line must be an object",
@@ -13379,7 +13759,7 @@ var JsonLogParser = class {
13379
13759
  return this.parseLines(lines, filePath);
13380
13760
  }
13381
13761
  };
13382
- function isRecord13(v) {
13762
+ function isRecord14(v) {
13383
13763
  return typeof v === "object" && v !== null && !Array.isArray(v);
13384
13764
  }
13385
13765
  function findLastJsonObjectSubstring(line) {
@@ -13455,7 +13835,7 @@ var Log4jsParser = class {
13455
13835
  });
13456
13836
  continue;
13457
13837
  }
13458
- if (!isRecord13(parsed)) {
13838
+ if (!isRecord14(parsed)) {
13459
13839
  warnings.push({
13460
13840
  code: "UNSUPPORTED_LOG4JS_PAYLOAD",
13461
13841
  message: "Embedded JSON payload must be an object",
@@ -14334,7 +14714,7 @@ var EXPORT_PAYLOAD_VERSION = "0.1.2";
14334
14714
  // packages/core/src/exporters/redact-export.ts
14335
14715
  init_redactor();
14336
14716
  init_redaction_profiles();
14337
- function isRecord14(value) {
14717
+ function isRecord15(value) {
14338
14718
  return typeof value === "object" && value !== null && !Array.isArray(value);
14339
14719
  }
14340
14720
  function deepClone(value) {
@@ -14408,7 +14788,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
14408
14788
  0
14409
14789
  );
14410
14790
  const err = bounded.error;
14411
- if (isRecord14(err) && typeof err.message === "string") {
14791
+ if (isRecord15(err) && typeof err.message === "string") {
14412
14792
  bounded.error = {
14413
14793
  ...err,
14414
14794
  message: truncateStringForProfile(
@@ -14438,7 +14818,7 @@ function redactErrorInfo(error, redactor, maxMetadataValueLength, maxPreviewLeng
14438
14818
  maxPreviewLength
14439
14819
  );
14440
14820
  const redacted = record?.error;
14441
- if (!isRecord14(redacted) || typeof redacted.message !== "string") {
14821
+ if (!isRecord15(redacted) || typeof redacted.message !== "string") {
14442
14822
  return void 0;
14443
14823
  }
14444
14824
  return {
@@ -14518,7 +14898,7 @@ function redactTraceEventsForReport(events, options) {
14518
14898
  ) : void 0;
14519
14899
  const redactedActual = actualAttrs !== void 0 && "value" in actualAttrs ? actualAttrs.value : void 0;
14520
14900
  const redactedEvidence = event.evidence !== void 0 ? redactEventAttributes(
14521
- isRecord14(event.evidence) ? event.evidence : { value: event.evidence },
14901
+ isRecord15(event.evidence) ? event.evidence : { value: event.evidence },
14522
14902
  redactor,
14523
14903
  maxMetadataValueLength,
14524
14904
  maxPreviewLength
@@ -15615,9 +15995,9 @@ Trace directory: ${traceDir}`);
15615
15995
  process.exitCode = 1;
15616
15996
  }
15617
15997
  const resolvedOutput = resolveOutputOption(options);
15618
- const outPath = resolvedOutput !== void 0 ? path32__default.default.resolve(resolvedOutput) : void 0;
15998
+ const outPath = resolvedOutput !== void 0 ? path33__default.default.resolve(resolvedOutput) : void 0;
15619
15999
  if (outPath !== void 0) {
15620
- await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
16000
+ await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
15621
16001
  await promises.writeFile(outPath, result.content, "utf-8");
15622
16002
  const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
15623
16003
  console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
@@ -15976,7 +16356,7 @@ function indexedToMetadata(row, traceDir) {
15976
16356
  endedAt: row.endedAt ?? void 0,
15977
16357
  durationMs: row.durationMs ?? void 0,
15978
16358
  eventCount: 0,
15979
- filePath: path32__default.default.join(traceDir, row.file),
16359
+ filePath: path33__default.default.join(traceDir, row.file),
15980
16360
  fileSize: 0,
15981
16361
  createdAt: new Date(row.mtimeMs)
15982
16362
  };
@@ -16458,9 +16838,9 @@ async function reportCommand(runId, options = {}) {
16458
16838
  ...options.section ? { section: options.section } : {}
16459
16839
  });
16460
16840
  const resolvedOutput = resolveOutputOption(options);
16461
- const outPath = resolvedOutput !== void 0 ? path32__default.default.resolve(resolvedOutput) : void 0;
16841
+ const outPath = resolvedOutput !== void 0 ? path33__default.default.resolve(resolvedOutput) : void 0;
16462
16842
  if (outPath !== void 0) {
16463
- await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
16843
+ await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
16464
16844
  await promises.writeFile(outPath, result.content, "utf-8");
16465
16845
  console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
16466
16846
  }
@@ -16601,7 +16981,7 @@ var STRICT_PROFILE_EXTRA_KEYS2 = [
16601
16981
  "retrieval",
16602
16982
  "query"
16603
16983
  ];
16604
- function isRecord15(value) {
16984
+ function isRecord16(value) {
16605
16985
  return typeof value === "object" && value !== null && !Array.isArray(value);
16606
16986
  }
16607
16987
  function toKey2(key) {
@@ -16658,8 +17038,8 @@ function passesLuhn(value) {
16658
17038
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
16659
17039
  var EPOCH_MS_RE = /^1[0-9]{12}$/;
16660
17040
  var EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
16661
- function pathSuggestsNonCard(path43) {
16662
- const normalized = path43.toLowerCase().replace(/[^a-z0-9._]/g, "");
17041
+ function pathSuggestsNonCard(path44) {
17042
+ const normalized = path44.toLowerCase().replace(/[^a-z0-9._]/g, "");
16663
17043
  return /(^|\.)(tokenusage|usage)(\.|$)/.test(normalized) || /(startedat|endedat|durationms|timestamp|createdat|updatedat)(\.|$)/.test(normalized) || /(^|\.)(runid|traceid|spanid|eventid|sessionid|userid|parentid|requestid|correlationid)(\.|$)/.test(
16664
17044
  normalized
16665
17045
  ) || /(^|\.)ts(\.|$)/.test(normalized);
@@ -16855,17 +17235,17 @@ function applyRule(rule, value, replacement) {
16855
17235
  }
16856
17236
  return value;
16857
17237
  }
16858
- function childPath(path43, key) {
17238
+ function childPath(path44, key) {
16859
17239
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
16860
- return path43 ? `${path43}.${key}` : key;
17240
+ return path44 ? `${path44}.${key}` : key;
16861
17241
  }
16862
- return `${path43 || "$"}[${JSON.stringify(key)}]`;
17242
+ return `${path44 || "$"}[${JSON.stringify(key)}]`;
16863
17243
  }
16864
- function indexPath(path43, index) {
16865
- return `${path43 || "$"}[${index}]`;
17244
+ function indexPath(path44, index) {
17245
+ return `${path44 || "$"}[${index}]`;
16866
17246
  }
16867
- function makeFinding(path43, detector, action, matchKind, severity = "warning", preview) {
16868
- return preview === void 0 ? { path: path43, detector, action, severity, matchKind } : { path: path43, detector, action, severity, matchKind, preview };
17247
+ function makeFinding(path44, detector, action, matchKind, severity = "warning", preview) {
17248
+ return preview === void 0 ? { path: path44, detector, action, severity, matchKind } : { path: path44, detector, action, severity, matchKind, preview };
16869
17249
  }
16870
17250
  function createRedactionProfile(profile = "local") {
16871
17251
  switch (profile) {
@@ -16934,11 +17314,11 @@ var Redactor2 = class {
16934
17314
  #recordFinding(state, finding) {
16935
17315
  if (this.#collectFindings) state.findings.push(finding);
16936
17316
  }
16937
- #redactValue(value, key, path43, depth, state) {
17317
+ #redactValue(value, key, path44, depth, state) {
16938
17318
  if (depth > this.#maxDepth) {
16939
17319
  this.#recordFinding(
16940
17320
  state,
16941
- makeFinding(path43, "structure.maxDepth", "truncate", "value", "warning")
17321
+ makeFinding(path44, "structure.maxDepth", "truncate", "value", "warning")
16942
17322
  );
16943
17323
  return "[Truncated]";
16944
17324
  }
@@ -16947,19 +17327,19 @@ var Redactor2 = class {
16947
17327
  if (rule) {
16948
17328
  this.#recordFinding(
16949
17329
  state,
16950
- makeFinding(path43, `key.${rule.key}`, actionForRule(rule), "key", "warning")
17330
+ makeFinding(path44, `key.${rule.key}`, actionForRule(rule), "key", "warning")
16951
17331
  );
16952
17332
  return applyRule(rule, value, this.#replacement);
16953
17333
  }
16954
17334
  }
16955
17335
  for (const detector of this.#detectors) {
16956
- const detections = detector.detect({ path: path43, key, value });
17336
+ const detections = detector.detect({ path: path44, key, value });
16957
17337
  for (const detection of detections) {
16958
17338
  const action = detection.action ?? "replace";
16959
17339
  this.#recordFinding(
16960
17340
  state,
16961
17341
  makeFinding(
16962
- path43,
17342
+ path44,
16963
17343
  detector.id,
16964
17344
  action,
16965
17345
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -16977,11 +17357,11 @@ var Redactor2 = class {
16977
17357
  const out = [];
16978
17358
  state.seen.set(value, out);
16979
17359
  value.forEach((item, index) => {
16980
- out[index] = this.#redactValue(item, void 0, indexPath(path43, index), depth + 1, state);
17360
+ out[index] = this.#redactValue(item, void 0, indexPath(path44, index), depth + 1, state);
16981
17361
  });
16982
17362
  return out;
16983
17363
  }
16984
- if (isRecord15(value)) {
17364
+ if (isRecord16(value)) {
16985
17365
  if (state.seen.has(value)) return state.seen.get(value);
16986
17366
  const out = {};
16987
17367
  state.seen.set(value, out);
@@ -16989,7 +17369,7 @@ var Redactor2 = class {
16989
17369
  out[entryKey] = this.#redactValue(
16990
17370
  entryValue,
16991
17371
  entryKey,
16992
- childPath(path43 === "$" ? "" : path43, entryKey),
17372
+ childPath(path44 === "$" ? "" : path44, entryKey),
16993
17373
  depth + 1,
16994
17374
  state
16995
17375
  );
@@ -17005,6 +17385,233 @@ function createRedactor(options) {
17005
17385
  function redact(value, options) {
17006
17386
  return createRedactor(options).redact(value);
17007
17387
  }
17388
+ var REDACTION_POLICY_LIMITS = {
17389
+ maxExtraKeys: 64,
17390
+ maxKeyLength: 64,
17391
+ maxPatterns: 32,
17392
+ maxPatternLength: 128,
17393
+ maxPatternIdLength: 64,
17394
+ maxTypedQuantifier: 64
17395
+ };
17396
+ var SAFE_TYPED_PATTERN = /^[A-Za-z0-9_@./:=<>\-[\]()|+*?{},\\\s^$]+$/;
17397
+ function isRecord17(value) {
17398
+ return value !== null && typeof value === "object" && !Array.isArray(value);
17399
+ }
17400
+ function escapeRegExp(value) {
17401
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17402
+ }
17403
+ function rejectRemotePolicyPath(policyPath) {
17404
+ const trimmed = policyPath.trim();
17405
+ if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) {
17406
+ throw new Error(
17407
+ `--policy must be a local JSON file path (got a URL-like value). Remote policy fetch is not supported.`
17408
+ );
17409
+ }
17410
+ }
17411
+ function parseSeverity(value, label) {
17412
+ if (value === void 0) return "error";
17413
+ if (value === "info" || value === "warning" || value === "error") return value;
17414
+ throw new Error(`${label} severity must be info, warning, or error.`);
17415
+ }
17416
+ function validateExtraKey(key, index) {
17417
+ const label = `extraKeys[${index}]`;
17418
+ if (key.length === 0) throw new Error(`${label} must be a non-empty string.`);
17419
+ if (key.length > REDACTION_POLICY_LIMITS.maxKeyLength) {
17420
+ throw new Error(
17421
+ `${label} exceeds max length ${REDACTION_POLICY_LIMITS.maxKeyLength}.`
17422
+ );
17423
+ }
17424
+ if (!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(key)) {
17425
+ throw new Error(
17426
+ `${label} must be an identifier-like key (letters, digits, _, ., -).`
17427
+ );
17428
+ }
17429
+ return key;
17430
+ }
17431
+ function assertBoundedTypedPattern(pattern, label) {
17432
+ if (pattern.length === 0) throw new Error(`${label} must be non-empty.`);
17433
+ if (pattern.length > REDACTION_POLICY_LIMITS.maxPatternLength) {
17434
+ throw new Error(
17435
+ `${label} exceeds max length ${REDACTION_POLICY_LIMITS.maxPatternLength}.`
17436
+ );
17437
+ }
17438
+ if (!SAFE_TYPED_PATTERN.test(pattern)) {
17439
+ throw new Error(
17440
+ `${label} contains unsupported characters for bounded typed patterns.`
17441
+ );
17442
+ }
17443
+ if (/\(\?/.test(pattern) || /\\[1-9]/.test(pattern)) {
17444
+ throw new Error(
17445
+ `${label} rejects lookaround, backreferences, and nested quantifiers.`
17446
+ );
17447
+ }
17448
+ if (/\([^)]*[+*{][^)]*\)[+*{]/.test(pattern) || /\[[^\]]*[+*{][^\]]*\][+*{]/.test(pattern)) {
17449
+ throw new Error(`${label} rejects nested quantifiers.`);
17450
+ }
17451
+ if (/\.[*+]/.test(pattern) || /[*+]\{/.test(pattern)) {
17452
+ throw new Error(`${label} rejects unbounded .* / .+ style quantifiers.`);
17453
+ }
17454
+ for (const match of pattern.matchAll(/\{(\d+)(?:,(\d*))?\}/g)) {
17455
+ const min = Number(match[1]);
17456
+ const maxRaw = match[2];
17457
+ const max = maxRaw === void 0 || maxRaw === "" ? min : Number(maxRaw);
17458
+ if (!Number.isFinite(min) || !Number.isFinite(max) || min > REDACTION_POLICY_LIMITS.maxTypedQuantifier || max > REDACTION_POLICY_LIMITS.maxTypedQuantifier) {
17459
+ throw new Error(
17460
+ `${label} quantifiers must be <= ${REDACTION_POLICY_LIMITS.maxTypedQuantifier}.`
17461
+ );
17462
+ }
17463
+ }
17464
+ }
17465
+ function compilePatternDetector(input3, index) {
17466
+ const label = `patterns[${index}]`;
17467
+ if (!isRecord17(input3)) throw new Error(`${label} must be an object.`);
17468
+ const idRaw = input3.id;
17469
+ if (typeof idRaw !== "string" || idRaw.trim() === "") {
17470
+ throw new Error(`${label}.id must be a non-empty string.`);
17471
+ }
17472
+ const id = idRaw.trim();
17473
+ if (id.length > REDACTION_POLICY_LIMITS.maxPatternIdLength) {
17474
+ throw new Error(
17475
+ `${label}.id exceeds max length ${REDACTION_POLICY_LIMITS.maxPatternIdLength}.`
17476
+ );
17477
+ }
17478
+ if (!/^[A-Za-z][A-Za-z0-9._-]*$/.test(id)) {
17479
+ throw new Error(`${label}.id must be an identifier-like detector id.`);
17480
+ }
17481
+ const type = input3.type;
17482
+ if (type !== "literal" && type !== "prefix" && type !== "typed") {
17483
+ throw new Error(`${label}.type must be literal, prefix, or typed.`);
17484
+ }
17485
+ const severity = parseSeverity(input3.severity, label);
17486
+ let source;
17487
+ if (type === "typed") {
17488
+ if (typeof input3.pattern !== "string") {
17489
+ throw new Error(`${label}.pattern must be a string for typed patterns.`);
17490
+ }
17491
+ assertBoundedTypedPattern(input3.pattern, `${label}.pattern`);
17492
+ source = input3.pattern;
17493
+ } else {
17494
+ if (typeof input3.value !== "string") {
17495
+ throw new Error(`${label}.value must be a string for ${type} patterns.`);
17496
+ }
17497
+ if (input3.value.length === 0) {
17498
+ throw new Error(`${label}.value must be non-empty.`);
17499
+ }
17500
+ if (input3.value.length > REDACTION_POLICY_LIMITS.maxPatternLength) {
17501
+ throw new Error(
17502
+ `${label}.value exceeds max length ${REDACTION_POLICY_LIMITS.maxPatternLength}.`
17503
+ );
17504
+ }
17505
+ const escaped = escapeRegExp(input3.value);
17506
+ source = type === "prefix" ? `^${escaped}` : escaped;
17507
+ }
17508
+ let regex;
17509
+ try {
17510
+ regex = new RegExp(source);
17511
+ } catch (error) {
17512
+ throw new Error(
17513
+ `${label} failed to compile: ${error instanceof Error ? error.message : String(error)}`
17514
+ );
17515
+ }
17516
+ return {
17517
+ id: `policy.${id}`,
17518
+ severity,
17519
+ matchKind: "custom",
17520
+ detect({ value }) {
17521
+ if (typeof value !== "string") return [];
17522
+ regex.lastIndex = 0;
17523
+ return regex.test(value) ? [{ action: "replace", severity, matchKind: "custom" }] : [];
17524
+ }
17525
+ };
17526
+ }
17527
+ function compileRedactionPolicy(raw, policyPath) {
17528
+ if (!isRecord17(raw)) {
17529
+ throw new Error(`Redaction policy must be a JSON object (${policyPath}).`);
17530
+ }
17531
+ const diagnostics = [];
17532
+ if (raw.version !== void 0 && raw.version !== 1) {
17533
+ throw new Error(`Unsupported redaction policy version (supported: 1).`);
17534
+ }
17535
+ const extraKeysRaw = raw.extraKeys;
17536
+ const extraKeys = [];
17537
+ if (extraKeysRaw !== void 0) {
17538
+ if (!Array.isArray(extraKeysRaw)) {
17539
+ throw new Error(`extraKeys must be an array of strings.`);
17540
+ }
17541
+ if (extraKeysRaw.length > REDACTION_POLICY_LIMITS.maxExtraKeys) {
17542
+ throw new Error(
17543
+ `extraKeys exceeds max count ${REDACTION_POLICY_LIMITS.maxExtraKeys}.`
17544
+ );
17545
+ }
17546
+ for (let i = 0; i < extraKeysRaw.length; i += 1) {
17547
+ const key = extraKeysRaw[i];
17548
+ if (typeof key !== "string") {
17549
+ throw new Error(`extraKeys[${i}] must be a string.`);
17550
+ }
17551
+ extraKeys.push(validateExtraKey(key, i));
17552
+ }
17553
+ }
17554
+ const patternsRaw = raw.patterns;
17555
+ const detectors = [];
17556
+ if (patternsRaw !== void 0) {
17557
+ if (!Array.isArray(patternsRaw)) {
17558
+ throw new Error(`patterns must be an array.`);
17559
+ }
17560
+ if (patternsRaw.length > REDACTION_POLICY_LIMITS.maxPatterns) {
17561
+ throw new Error(
17562
+ `patterns exceeds max count ${REDACTION_POLICY_LIMITS.maxPatterns}.`
17563
+ );
17564
+ }
17565
+ const seenIds = /* @__PURE__ */ new Set();
17566
+ for (let i = 0; i < patternsRaw.length; i += 1) {
17567
+ const detector = compilePatternDetector(
17568
+ patternsRaw[i],
17569
+ i
17570
+ );
17571
+ if (seenIds.has(detector.id)) {
17572
+ throw new Error(`Duplicate pattern id "${detector.id}".`);
17573
+ }
17574
+ seenIds.add(detector.id);
17575
+ detectors.push(detector);
17576
+ }
17577
+ }
17578
+ if (extraKeys.length === 0 && detectors.length === 0) {
17579
+ diagnostics.push({
17580
+ code: "AI_POLICY_EMPTY",
17581
+ message: "Redaction policy contained no extraKeys or patterns."
17582
+ });
17583
+ }
17584
+ return {
17585
+ path: policyPath,
17586
+ extraKeys,
17587
+ detectors,
17588
+ diagnostics
17589
+ };
17590
+ }
17591
+ async function loadRedactionPolicy(policyPath) {
17592
+ rejectRemotePolicyPath(policyPath);
17593
+ const resolved = path33__default.default.resolve(policyPath);
17594
+ let text;
17595
+ try {
17596
+ text = await promises.readFile(resolved, "utf-8");
17597
+ } catch (error) {
17598
+ throw new Error(
17599
+ `Failed to read --policy file "${resolved}": ${error instanceof Error ? error.message : String(error)}`
17600
+ );
17601
+ }
17602
+ let parsed;
17603
+ try {
17604
+ parsed = JSON.parse(text);
17605
+ } catch (error) {
17606
+ throw new Error(
17607
+ `Invalid JSON in --policy file "${resolved}": ${error instanceof Error ? error.message : String(error)}`
17608
+ );
17609
+ }
17610
+ return compileRedactionPolicy(parsed, resolved);
17611
+ }
17612
+
17613
+ // packages/core/src/entries/checks.ts
17614
+ init_checks2();
17008
17615
 
17009
17616
  // packages/cli/src/trace-input.ts
17010
17617
  init_advanced();
@@ -17036,12 +17643,19 @@ async function inputFromTarget(target, options, stdin) {
17036
17643
  return { type: "file", path: runPath };
17037
17644
  }
17038
17645
 
17039
- // packages/cli/src/redact.ts
17040
- function parseRedactionProfile3(value) {
17041
- if (value === void 0 || value === "local" || value === "share" || value === "strict") {
17042
- return value ?? "share";
17646
+ // packages/cli/src/safety.ts
17647
+ var BEST_EFFORT_NOTE = "Best-effort local safety verification only; not a compliance, privacy, security, or regulatory certification.";
17648
+ var DEFAULT_MAX_STRING_LENGTH = 16384;
17649
+ var DEFAULT_MAX_ARRAY_LENGTH = 1e3;
17650
+ var DEFAULT_MAX_OBJECT_KEYS = 200;
17651
+ var DEFAULT_MAX_SERIALIZED_BYTES = 128 * 1024;
17652
+ function parseLimit3(value, label) {
17653
+ if (value === void 0) return void 0;
17654
+ const parsed = Number(value);
17655
+ if (!Number.isFinite(parsed) || parsed < 0) {
17656
+ throw new Error(`${label} must be a non-negative number.`);
17043
17657
  }
17044
- throw new Error(`Unsupported --profile "${value}". Use local, share, or strict.`);
17658
+ return parsed;
17045
17659
  }
17046
17660
  function stable2(value) {
17047
17661
  if (Array.isArray(value)) return value.map(stable2);
@@ -17051,7 +17665,441 @@ function stable2(value) {
17051
17665
  Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable2(record[key])])
17052
17666
  );
17053
17667
  }
17054
- function isMissingFileError3(error) {
17668
+ function safetyDiagnostic(code, message, severity = "error") {
17669
+ return { code, message, severity };
17670
+ }
17671
+ function warningDiagnostics(warnings, unsupportedFields) {
17672
+ return [
17673
+ ...warnings.map(
17674
+ (warning) => safetyDiagnostic(
17675
+ warning.code,
17676
+ warning.message,
17677
+ warning.severity === "error" ? "error" : "warning"
17678
+ )
17679
+ ),
17680
+ ...unsupportedFields.map(
17681
+ (field) => safetyDiagnostic(
17682
+ "unsupported_field",
17683
+ `Reader reported unsupported field: ${field}`,
17684
+ "warning"
17685
+ )
17686
+ )
17687
+ ];
17688
+ }
17689
+ function diagnosticFromCheck(item) {
17690
+ return safetyDiagnostic(item.code, item.message, item.severity);
17691
+ }
17692
+ function statusFrom(findings, diagnostics) {
17693
+ if (diagnostics.some((item) => item.severity === "error")) return "UNKNOWN";
17694
+ if (findings.some((item) => item.severity === "error")) return "UNSAFE";
17695
+ if (diagnostics.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
17696
+ if (findings.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
17697
+ return "SAFE";
17698
+ }
17699
+ function resultFromParts(parts) {
17700
+ const findings = [...parts.findings ?? []];
17701
+ const diagnostics = [...parts.diagnostics ?? []];
17702
+ const warnings = [...parts.warnings ?? []];
17703
+ const unsupportedFields = [...parts.unsupportedFields ?? []];
17704
+ const status = parts.status ?? statusFrom(findings, diagnostics);
17705
+ return {
17706
+ ok: status === "SAFE" || status === "SAFE WITH WARNINGS",
17707
+ command: parts.command,
17708
+ status,
17709
+ format: parts.format,
17710
+ ...parts.runId !== void 0 ? { runId: parts.runId } : {},
17711
+ summary: {
17712
+ findings: findings.length,
17713
+ warnings: diagnostics.filter((item) => item.severity === "warning").length + findings.filter((item) => item.severity === "warning").length,
17714
+ errors: diagnostics.filter((item) => item.severity === "error").length + findings.filter((item) => item.severity === "error").length
17715
+ },
17716
+ findings,
17717
+ diagnostics,
17718
+ warnings,
17719
+ unsupportedFields,
17720
+ note: BEST_EFFORT_NOTE,
17721
+ ...parts.sourceAssessment !== void 0 ? { sourceAssessment: parts.sourceAssessment } : {},
17722
+ ...parts.artifactAssessment !== void 0 ? { artifactAssessment: parts.artifactAssessment } : {},
17723
+ ...parts.redactionSummary !== void 0 ? { redactionSummary: parts.redactionSummary } : {}
17724
+ };
17725
+ }
17726
+ function layerFromResult(result) {
17727
+ return {
17728
+ status: result.status,
17729
+ summary: result.summary,
17730
+ findings: result.findings
17731
+ };
17732
+ }
17733
+ function readErrorResult(command, error) {
17734
+ if (error instanceof TraceReadError) {
17735
+ const code = error.code === "unsupported_format" ? "AI_SAFETY_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_SAFETY_AMBIGUOUS_FORMAT" : "AI_SAFETY_TRACE_UNREADABLE";
17736
+ return resultFromParts({
17737
+ command,
17738
+ format: "unknown",
17739
+ diagnostics: [safetyDiagnostic(code, error.message)],
17740
+ warnings: error.warnings
17741
+ });
17742
+ }
17743
+ return resultFromParts({
17744
+ command,
17745
+ format: "unknown",
17746
+ diagnostics: [
17747
+ safetyDiagnostic(
17748
+ "AI_SAFETY_TRACE_UNREADABLE",
17749
+ error instanceof Error ? error.message : String(error)
17750
+ )
17751
+ ]
17752
+ });
17753
+ }
17754
+ function invalidArgumentResult(command, error) {
17755
+ return resultFromParts({
17756
+ command,
17757
+ format: "unknown",
17758
+ diagnostics: [
17759
+ safetyDiagnostic(
17760
+ "AI_SAFETY_INVALID_ARGUMENTS",
17761
+ error instanceof Error ? error.message : String(error)
17762
+ )
17763
+ ]
17764
+ });
17765
+ }
17766
+ function buildSafetyRules(options) {
17767
+ const maxStringLength2 = parseLimit3(options.maxStringLength, "--max-string-length") ?? DEFAULT_MAX_STRING_LENGTH;
17768
+ const maxArrayLength = parseLimit3(options.maxArrayLength, "--max-array-length") ?? DEFAULT_MAX_ARRAY_LENGTH;
17769
+ const maxObjectKeys = parseLimit3(options.maxObjectKeys, "--max-object-keys") ?? DEFAULT_MAX_OBJECT_KEYS;
17770
+ const maxSerializedBytes = parseLimit3(options.maxSerializedBytes, "--max-serialized-bytes") ?? DEFAULT_MAX_SERIALIZED_BYTES;
17771
+ return [
17772
+ createSafetyRawContentRule(),
17773
+ createSafetyRedactionRule(),
17774
+ createSafetySecretPatternRule(),
17775
+ createSafetyOversizedAttributeRule({
17776
+ maxStringLength: maxStringLength2,
17777
+ maxArrayLength,
17778
+ maxObjectKeys,
17779
+ maxSerializedBytes
17780
+ })
17781
+ ];
17782
+ }
17783
+ function flattenNodes2(nodes) {
17784
+ return nodes.flatMap((node) => [
17785
+ node,
17786
+ ...flattenNodes2(
17787
+ node.children
17788
+ )
17789
+ ]);
17790
+ }
17791
+ function detectorSeverity(finding) {
17792
+ return finding.severity;
17793
+ }
17794
+ function classifyRedactionDetector(detector) {
17795
+ if (detector === "value.creditCard" || detector === "value.email" || detector === "value.phone") {
17796
+ return { category: "personal-data", confidence: "high" };
17797
+ }
17798
+ if (detector === "value.ipv4" || detector === "value.ipv6") {
17799
+ return { category: "identifier", confidence: "medium" };
17800
+ }
17801
+ if (detector.startsWith("value.") && (detector.includes("Token") || detector.includes("Key") || detector.includes("jwt") || detector.includes("authorization") || detector.includes("bearer") || detector.includes("cookie") || detector.includes("privateKey") || detector.includes("github") || detector.includes("aws") || detector.includes("provider"))) {
17802
+ return { category: "credential", confidence: "high" };
17803
+ }
17804
+ if (detector.startsWith("key.")) {
17805
+ return { category: "credential", confidence: "medium" };
17806
+ }
17807
+ return { category: "credential", confidence: "medium" };
17808
+ }
17809
+ function redactionOptionsFromPolicy(policy) {
17810
+ if (policy === void 0) return {};
17811
+ return {
17812
+ ...policy.extraKeys.length > 0 ? { extraKeys: [...policy.extraKeys] } : {},
17813
+ ...policy.detectors.length > 0 ? { detectors: [...policy.detectors] } : {}
17814
+ };
17815
+ }
17816
+ function redactionDetectorFindings(read, runId, policy) {
17817
+ const runs = runId === void 0 ? read.runs : read.runs.filter((run) => run.runId === runId);
17818
+ const out = [];
17819
+ const policyOptions = redactionOptionsFromPolicy(policy);
17820
+ for (const run of runs) {
17821
+ for (const node of flattenNodes2(run.children)) {
17822
+ const attrs = node.event.attributes;
17823
+ if (attrs === void 0) continue;
17824
+ const result = createRedactor({
17825
+ profile: "share",
17826
+ ...policyOptions
17827
+ }).redact(attrs);
17828
+ for (const finding of result.findings) {
17829
+ if (finding.action === "keep") continue;
17830
+ const taxonomy = classifyRedactionDetector(finding.detector);
17831
+ out.push({
17832
+ ruleId: "safety.redactDetector",
17833
+ severity: detectorSeverity(finding),
17834
+ status: finding.severity === "error" ? "fail" : "warning",
17835
+ message: `Redaction detector ${finding.detector} matched ${finding.matchKind} at ${finding.path}.`,
17836
+ expected: "redacted trace content",
17837
+ actual: finding.detector,
17838
+ evidence: [
17839
+ {
17840
+ runId: node.event.runId,
17841
+ eventId: node.event.eventId,
17842
+ ...node.event.parentId !== void 0 ? { parentId: node.event.parentId } : {},
17843
+ kind: node.event.kind,
17844
+ name: node.event.name,
17845
+ ...node.event.status !== void 0 ? { status: node.event.status } : {},
17846
+ path: `attributes.${finding.path.replace(/^\$\.?/, "")}`
17847
+ }
17848
+ ],
17849
+ category: taxonomy.category,
17850
+ confidence: taxonomy.confidence,
17851
+ detector: finding.detector,
17852
+ action: finding.action
17853
+ });
17854
+ }
17855
+ }
17856
+ }
17857
+ return out.sort((a, b) => {
17858
+ const aEvidence = a.evidence[0];
17859
+ const bEvidence = b.evidence[0];
17860
+ return (aEvidence?.runId ?? "").localeCompare(bEvidence?.runId ?? "") || (aEvidence?.eventId ?? "").localeCompare(bEvidence?.eventId ?? "") || (aEvidence?.path ?? "").localeCompare(bEvidence?.path ?? "") || a.message.localeCompare(b.message);
17861
+ });
17862
+ }
17863
+ function exitCodeFor(result) {
17864
+ if (result.status === "SAFE" || result.status === "SAFE WITH WARNINGS") return 0;
17865
+ if (result.status === "UNSAFE") return 1;
17866
+ return 2;
17867
+ }
17868
+ function toResidualStatus(status) {
17869
+ if (status === "SAFE WITH WARNINGS") return "SAFE_WITH_WARNINGS";
17870
+ return status;
17871
+ }
17872
+ function toResidualSafetyAssessment(result) {
17873
+ const codes = [
17874
+ .../* @__PURE__ */ new Set([
17875
+ ...result.diagnostics.map((item) => item.code),
17876
+ ...result.findings.map((item) => item.ruleId)
17877
+ ])
17878
+ ].sort((a, b) => a.localeCompare(b));
17879
+ return {
17880
+ status: toResidualStatus(result.status),
17881
+ findings: result.summary.findings,
17882
+ warnings: result.summary.warnings,
17883
+ errors: result.summary.errors,
17884
+ codes,
17885
+ note: BEST_EFFORT_NOTE
17886
+ };
17887
+ }
17888
+ async function assessResidualFromContent(content, options = {}) {
17889
+ try {
17890
+ const policy = options.compiledPolicy ?? (options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0);
17891
+ const read = await openTrace(
17892
+ { type: "string", content },
17893
+ { format: options.format ?? "agent-inspect-jsonl" }
17894
+ );
17895
+ const result = assessOpenedTrace(read, {
17896
+ ...options,
17897
+ ...policy !== void 0 ? { compiledPolicy: policy } : {}
17898
+ });
17899
+ return toResidualSafetyAssessment(result);
17900
+ } catch (error) {
17901
+ if (error instanceof TraceReadError) {
17902
+ return toResidualSafetyAssessment(readErrorResult("verify-safe", error));
17903
+ }
17904
+ const message = error instanceof Error ? error.message : String(error);
17905
+ return {
17906
+ status: "UNKNOWN",
17907
+ findings: 0,
17908
+ warnings: 0,
17909
+ errors: 1,
17910
+ codes: ["AI_SAFETY_TRACE_UNREADABLE"],
17911
+ note: `${BEST_EFFORT_NOTE} Residual assessment requires a supported AgentInspect trace; ${message}`
17912
+ };
17913
+ }
17914
+ }
17915
+ function explainFinding(finding, blocksBundle) {
17916
+ const path44 = finding.evidence[0]?.path ?? "(unknown path)";
17917
+ const category = finding.category ?? "structure";
17918
+ const confidence = finding.confidence ?? "medium";
17919
+ const detector = finding.detector ?? finding.ruleId;
17920
+ const action = finding.action ?? "review";
17921
+ const redactionHint = category === "credential" || category === "personal-data" || category === "raw-content" || action.includes("redact") ? "Usually removable by share/strict redaction before bundling." : "May require omitting the field, lowering limits, or an explicit local override.";
17922
+ return [
17923
+ ` Matched: detector=${detector}; path=${path44}; category=${category}`,
17924
+ ` Why: ${finding.message}`,
17925
+ ` Confidence: ${confidence}`,
17926
+ ` Redaction: ${redactionHint}`,
17927
+ ` Override: configure a custom redaction/detector rule locally (see docs/SAFETY-POLICY.md); do not weaken defaults globally.`,
17928
+ ` Bundle gate: ${blocksBundle ? "blocks share-safe bundle unless --allow-unsafe" : "does not block by itself (warning/info)"}`
17929
+ ];
17930
+ }
17931
+ function findingExplanation(finding) {
17932
+ const blocks = finding.severity === "error" || finding.status === "fail";
17933
+ return {
17934
+ ruleId: finding.ruleId,
17935
+ detector: finding.detector ?? finding.ruleId,
17936
+ path: finding.evidence[0]?.path,
17937
+ category: finding.category,
17938
+ confidence: finding.confidence,
17939
+ action: finding.action,
17940
+ blocksBundle: blocks,
17941
+ // Never include matched secret/PII values.
17942
+ message: finding.message
17943
+ };
17944
+ }
17945
+ function printHuman(result, explain = false) {
17946
+ console.log(`Safety status: ${result.status}`);
17947
+ console.log(`Format: ${result.format}`);
17948
+ if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
17949
+ if (result.sourceAssessment !== void 0 && result.artifactAssessment !== void 0) {
17950
+ console.log(`Source assessment: ${result.sourceAssessment.status}`);
17951
+ console.log(`Artifact assessment: ${result.artifactAssessment.status}`);
17952
+ if (result.redactionSummary !== void 0) {
17953
+ console.log(
17954
+ `Redaction: profile=${result.redactionSummary.profile}, findings=${result.redactionSummary.findings}`
17955
+ );
17956
+ }
17957
+ }
17958
+ console.log(
17959
+ `Summary: ${result.summary.findings} finding(s), ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
17960
+ );
17961
+ for (const diagnostic7 of result.diagnostics) {
17962
+ console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
17963
+ }
17964
+ for (const finding of result.findings) {
17965
+ const path44 = finding.evidence[0]?.path;
17966
+ const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
17967
+ console.log(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}${taxonomy}`);
17968
+ if (explain) {
17969
+ const blocks = finding.severity === "error" || finding.status === "fail";
17970
+ for (const line of explainFinding(finding, blocks)) {
17971
+ console.log(line);
17972
+ }
17973
+ }
17974
+ }
17975
+ console.log(`Note: ${result.note}`);
17976
+ }
17977
+ function printJson(result, explain = false) {
17978
+ const payload = explain === true ? { ...result, explanations: result.findings.map(findingExplanation) } : result;
17979
+ console.log(JSON.stringify(stable2(payload), null, 2));
17980
+ }
17981
+ async function safetyCommand(command, target, options, stdin) {
17982
+ let result;
17983
+ try {
17984
+ const policy = options.compiledPolicy ?? (options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0);
17985
+ const optionsWithPolicy = {
17986
+ ...options,
17987
+ ...policy !== void 0 ? { compiledPolicy: policy } : {}
17988
+ };
17989
+ const input3 = await inputFromTarget(target, optionsWithPolicy, stdin);
17990
+ const read = await openTrace(input3, {
17991
+ ...options.format !== void 0 ? { format: options.format } : {}
17992
+ });
17993
+ const source = assessOpenedTrace(read, {
17994
+ ...optionsWithPolicy,
17995
+ ...options.run !== void 0 ? { runId: options.run } : {}
17996
+ });
17997
+ if (command === "scan") {
17998
+ result = { ...source, command: "scan" };
17999
+ } else {
18000
+ const profile = options.redactionProfile ?? "share";
18001
+ const rawContent = input3.type === "string" ? input3.content : input3.type === "file" ? await promises.readFile(input3.path, "utf-8") : void 0;
18002
+ if (rawContent === void 0) {
18003
+ result = {
18004
+ ...source,
18005
+ command: "verify-safe",
18006
+ sourceAssessment: layerFromResult(source)
18007
+ };
18008
+ } else {
18009
+ const redacted = redactTraceContent(rawContent, profile, policy);
18010
+ const artifactRead = await openTrace(
18011
+ { type: "string", content: redacted.content },
18012
+ { format: options.format ?? "agent-inspect-jsonl" }
18013
+ );
18014
+ const artifact = assessOpenedTrace(artifactRead, {
18015
+ ...optionsWithPolicy,
18016
+ ...options.run !== void 0 ? { runId: options.run } : {}
18017
+ });
18018
+ const detectors = [
18019
+ ...new Set(redacted.findings.map((finding) => finding.detector))
18020
+ ].sort((a, b) => a.localeCompare(b));
18021
+ result = resultFromParts({
18022
+ command: "verify-safe",
18023
+ format: artifact.format,
18024
+ runId: artifact.runId ?? source.runId,
18025
+ findings: artifact.findings,
18026
+ diagnostics: artifact.diagnostics,
18027
+ warnings: artifact.warnings,
18028
+ unsupportedFields: artifact.unsupportedFields,
18029
+ status: artifact.status,
18030
+ sourceAssessment: layerFromResult(source),
18031
+ artifactAssessment: layerFromResult(artifact),
18032
+ redactionSummary: {
18033
+ profile,
18034
+ findings: redacted.findings.length,
18035
+ detectors
18036
+ }
18037
+ });
18038
+ }
18039
+ }
18040
+ } catch (error) {
18041
+ const message = error instanceof Error ? error.message : String(error);
18042
+ result = message.startsWith("--") || message.includes("--policy") ? invalidArgumentResult(command, error) : readErrorResult(command, error);
18043
+ }
18044
+ process.exitCode = exitCodeFor(result);
18045
+ if (options.json) printJson(result, options.explain === true);
18046
+ else printHuman(result, options.explain === true);
18047
+ }
18048
+ function scanCommand(target, options = {}, stdin = process.stdin) {
18049
+ return safetyCommand("scan", target, options, stdin);
18050
+ }
18051
+ function verifySafeCommand(target, options = {}, stdin = process.stdin) {
18052
+ return safetyCommand("verify-safe", target, options, stdin);
18053
+ }
18054
+ function assessOpenedTrace(read, options = {}) {
18055
+ try {
18056
+ const rules = buildSafetyRules(options);
18057
+ const checkResult = runTraceChecks(
18058
+ { read },
18059
+ {
18060
+ rules,
18061
+ ...options.runId !== void 0 ? { runId: options.runId } : {},
18062
+ ...options.run !== void 0 ? { runId: options.run } : {}
18063
+ }
18064
+ );
18065
+ const detectorFindings = checkResult.diagnostics.length === 0 ? redactionDetectorFindings(read, checkResult.runId, options.compiledPolicy) : [];
18066
+ return resultFromParts({
18067
+ command: "verify-safe",
18068
+ format: checkResult.format,
18069
+ runId: checkResult.runId,
18070
+ findings: [...checkResult.findings, ...detectorFindings],
18071
+ diagnostics: [
18072
+ ...checkResult.diagnostics.map(diagnosticFromCheck),
18073
+ ...warningDiagnostics(read.warnings, read.unsupportedFields)
18074
+ ],
18075
+ warnings: read.warnings,
18076
+ unsupportedFields: read.unsupportedFields
18077
+ });
18078
+ } catch (error) {
18079
+ return messageStartsWithDash(error) ? invalidArgumentResult("verify-safe", error) : readErrorResult("verify-safe", error);
18080
+ }
18081
+ }
18082
+ function messageStartsWithDash(error) {
18083
+ const message = error instanceof Error ? error.message : String(error);
18084
+ return message.startsWith("--");
18085
+ }
18086
+
18087
+ // packages/cli/src/redact.ts
18088
+ function parseRedactionProfile3(value) {
18089
+ if (value === void 0 || value === "local" || value === "share" || value === "strict") {
18090
+ return value ?? "share";
18091
+ }
18092
+ throw new Error(`Unsupported --profile "${value}". Use local, share, or strict.`);
18093
+ }
18094
+ function stable3(value) {
18095
+ if (Array.isArray(value)) return value.map(stable3);
18096
+ if (value === null || typeof value !== "object") return value;
18097
+ const record = value;
18098
+ return Object.fromEntries(
18099
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable3(record[key])])
18100
+ );
18101
+ }
18102
+ function isMissingFileError3(error) {
17055
18103
  return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
17056
18104
  }
17057
18105
  async function contentFromTarget(target, options, stdin) {
@@ -17074,16 +18122,24 @@ async function contentFromTarget(target, options, stdin) {
17074
18122
  }
17075
18123
  return { content: await promises.readFile(runPath, "utf-8"), source: runPath };
17076
18124
  }
17077
- function redactJsonText(content, profile) {
18125
+ function applyRedact(value, profile, policy) {
18126
+ const result = createRedactor({
18127
+ profile,
18128
+ ...policy?.extraKeys.length ? { extraKeys: [...policy.extraKeys] } : {},
18129
+ ...policy?.detectors.length ? { detectors: [...policy.detectors] } : {}
18130
+ }).redact(value);
18131
+ return { value: result.value, findings: result.findings };
18132
+ }
18133
+ function redactJsonText(content, profile, policy) {
17078
18134
  const parsed = JSON.parse(content);
17079
- const result = redact(parsed, { profile });
18135
+ const result = applyRedact(parsed, profile, policy);
17080
18136
  return {
17081
18137
  content: `${JSON.stringify(result.value, null, 2)}
17082
18138
  `,
17083
18139
  findings: result.findings
17084
18140
  };
17085
18141
  }
17086
- function redactJsonlText(content, profile) {
18142
+ function redactJsonlText(content, profile, policy) {
17087
18143
  const lines = content.split(/\r?\n/);
17088
18144
  const out = [];
17089
18145
  const findings = [];
@@ -17096,7 +18152,7 @@ function redactJsonlText(content, profile) {
17096
18152
  } catch {
17097
18153
  throw new Error(`Input is not valid JSON or JSONL at line ${index + 1}.`);
17098
18154
  }
17099
- const result = redact(parsed, { profile });
18155
+ const result = applyRedact(parsed, profile, policy);
17100
18156
  out.push(JSON.stringify(result.value));
17101
18157
  findings.push(
17102
18158
  ...result.findings.map((finding) => ({
@@ -17111,43 +18167,83 @@ function redactJsonlText(content, profile) {
17111
18167
  findings
17112
18168
  };
17113
18169
  }
17114
- function redactDocument(content, profile) {
18170
+ function redactDocument(content, profile, policy) {
17115
18171
  const trimmed = content.trim();
17116
18172
  if (trimmed.startsWith("{")) {
17117
18173
  try {
17118
18174
  const parsed = JSON.parse(trimmed);
17119
18175
  if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && ("schemaVersion" in parsed || "eventId" in parsed || "runId" in parsed)) {
17120
- return redactJsonlText(content, profile);
18176
+ return redactJsonlText(content, profile, policy);
17121
18177
  }
17122
18178
  } catch {
17123
18179
  }
17124
18180
  }
17125
18181
  try {
17126
- return redactJsonText(content, profile);
18182
+ return redactJsonText(content, profile, policy);
17127
18183
  } catch {
17128
- return redactJsonlText(content, profile);
18184
+ return redactJsonlText(content, profile, policy);
17129
18185
  }
17130
18186
  }
17131
- function redactTraceContent(content, profile) {
17132
- return redactDocument(content, profile);
18187
+ function redactTraceContent(content, profile, policy) {
18188
+ return redactDocument(content, profile, policy);
18189
+ }
18190
+ function looksLikeAgentInspectTrace(content) {
18191
+ const trimmed = content.trim();
18192
+ if (!trimmed.startsWith("{")) return false;
18193
+ try {
18194
+ const firstLine = trimmed.split(/\r?\n/).find((line) => line.trim() !== "") ?? trimmed;
18195
+ const parsed = JSON.parse(firstLine);
18196
+ return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && ("schemaVersion" in parsed || "eventId" in parsed || "runId" in parsed);
18197
+ } catch {
18198
+ return false;
18199
+ }
18200
+ }
18201
+ function printResidualWarning(assessment, sourceLooksLikeTrace) {
18202
+ if (assessment.status === "SAFE") return;
18203
+ if (assessment.status === "UNKNOWN" && !sourceLooksLikeTrace) return;
18204
+ const codes = assessment.codes.length > 0 ? ` codes=${assessment.codes.join(",")}` : "";
18205
+ console.error(
18206
+ `Residual safety: ${assessment.status} (findings=${assessment.findings}, warnings=${assessment.warnings}, errors=${assessment.errors})${codes}. Redact does not certify safe sharing; run verify-safe before publishing.`
18207
+ );
18208
+ }
18209
+ function residualExitCode(assessment) {
18210
+ if (assessment.status === "UNSAFE") return 1;
18211
+ if (assessment.status === "UNKNOWN") return 2;
18212
+ return 0;
17133
18213
  }
17134
18214
  async function redactCommand(target, options = {}, stdin = process.stdin) {
17135
18215
  const profile = parseRedactionProfile3(resolveRedactionProfileOption(options));
18216
+ const policy = options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0;
17136
18217
  const source = await contentFromTarget(target, options, stdin);
17137
- const redacted = redactDocument(source.content, profile);
18218
+ const redacted = redactDocument(source.content, profile, policy);
17138
18219
  const outputPath = resolveOutputOption(options);
18220
+ const residualAssessment = await assessResidualFromContent(redacted.content, {
18221
+ compiledPolicy: policy
18222
+ });
17139
18223
  if (outputPath !== void 0) {
17140
18224
  await promises.writeFile(outputPath, redacted.content, "utf-8");
17141
18225
  }
18226
+ if (options.failOnResidual === true) {
18227
+ process.exitCode = residualExitCode(residualAssessment);
18228
+ }
17142
18229
  if (options.json) {
17143
18230
  console.log(
17144
18231
  JSON.stringify(
17145
- stable2({
18232
+ stable3({
17146
18233
  ok: true,
17147
18234
  profile,
17148
18235
  source: source.source,
17149
18236
  output: outputPath,
17150
18237
  findings: redacted.findings,
18238
+ residualAssessment,
18239
+ ...policy !== void 0 ? {
18240
+ policy: {
18241
+ path: policy.path,
18242
+ extraKeys: policy.extraKeys.length,
18243
+ patterns: policy.detectors.length,
18244
+ diagnostics: policy.diagnostics
18245
+ }
18246
+ } : {},
17151
18247
  content: outputPath === void 0 ? redacted.content : void 0
17152
18248
  }),
17153
18249
  null,
@@ -17156,6 +18252,7 @@ async function redactCommand(target, options = {}, stdin = process.stdin) {
17156
18252
  );
17157
18253
  return;
17158
18254
  }
18255
+ printResidualWarning(residualAssessment, looksLikeAgentInspectTrace(redacted.content));
17159
18256
  if (outputPath === void 0) {
17160
18257
  process.stdout.write(redacted.content);
17161
18258
  }
@@ -17438,7 +18535,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
17438
18535
 
17439
18536
  // packages/cli/src/migrate.ts
17440
18537
  init_advanced();
17441
- function isRecord16(value) {
18538
+ function isRecord18(value) {
17442
18539
  return typeof value === "object" && value !== null && !Array.isArray(value);
17443
18540
  }
17444
18541
  function parseTarget(value) {
@@ -17447,7 +18544,7 @@ function parseTarget(value) {
17447
18544
  throw new Error('Unsupported migration target. Use "--to 1.0".');
17448
18545
  }
17449
18546
  function formatOf(value) {
17450
- if (!isRecord16(value)) return "unknown";
18547
+ if (!isRecord18(value)) return "unknown";
17451
18548
  if (value.schemaVersion === "0.1") return "0.1";
17452
18549
  if (value.schemaVersion === "0.2") return "0.2";
17453
18550
  if (value.schemaVersion === "1.0") return "1.0";
@@ -17460,14 +18557,14 @@ function uniqueSorted(values) {
17460
18557
  return [...new Set(values)].sort();
17461
18558
  }
17462
18559
  function isWithinDirectory(child, parent) {
17463
- const relative = path32__default.default.relative(parent, child);
17464
- return relative === "" || !relative.startsWith("..") && !path32__default.default.isAbsolute(relative);
18560
+ const relative = path33__default.default.relative(parent, child);
18561
+ return relative === "" || !relative.startsWith("..") && !path33__default.default.isAbsolute(relative);
17465
18562
  }
17466
18563
  async function resolveOutputPath(inputPath, output2, force) {
17467
18564
  if (output2 === void 0 || output2.trim() === "") return void 0;
17468
- const inputAbs = path32__default.default.resolve(inputPath);
17469
- const outputAbs = path32__default.default.resolve(output2.trim());
17470
- const inputDir = path32__default.default.dirname(inputAbs);
18565
+ const inputAbs = path33__default.default.resolve(inputPath);
18566
+ const outputAbs = path33__default.default.resolve(output2.trim());
18567
+ const inputDir = path33__default.default.dirname(inputAbs);
17471
18568
  if (!isWithinDirectory(outputAbs, inputDir)) {
17472
18569
  throw new Error("Refusing to write migrated output outside the input directory.");
17473
18570
  }
@@ -17588,7 +18685,7 @@ async function migrateCommand(input3, options = {}) {
17588
18685
  process.exitCode = 1;
17589
18686
  return;
17590
18687
  }
17591
- const inputPath = path32__default.default.resolve(input3.trim());
18688
+ const inputPath = path33__default.default.resolve(input3.trim());
17592
18689
  const dryRun = options.dryRun === true;
17593
18690
  if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
17594
18691
  console.error("migrate requires --dry-run or --output <path>.");
@@ -17607,7 +18704,7 @@ async function migrateCommand(input3, options = {}) {
17607
18704
  );
17608
18705
  const result = await buildMigration(inputPath, outputPath);
17609
18706
  if (!dryRun && outputPath !== void 0) {
17610
- await promises.mkdir(path32__default.default.dirname(outputPath), { recursive: true });
18707
+ await promises.mkdir(path33__default.default.dirname(outputPath), { recursive: true });
17611
18708
  await promises.writeFile(outputPath, result.content, "utf-8");
17612
18709
  }
17613
18710
  printSummary2(result, dryRun);
@@ -17616,16 +18713,13 @@ async function migrateCommand(input3, options = {}) {
17616
18713
  console.error(`[AgentInspect] migrate failed: ${msg}`);
17617
18714
  process.exitCode = 1;
17618
18715
  }
17619
- }
17620
- init_advanced();
17621
-
17622
- // packages/core/src/entries/checks.ts
17623
- init_checks2();
18716
+ }
18717
+ init_advanced();
17624
18718
 
17625
18719
  // packages/cli/src/evidence-on.ts
17626
18720
  init_advanced();
17627
18721
  function validateReporterArtifactPath(options) {
17628
- const outputDir = path32__default.default.resolve(options.outputDir);
18722
+ const outputDir = path33__default.default.resolve(options.outputDir);
17629
18723
  const diagnostics = [];
17630
18724
  const rawPath = options.relativePath;
17631
18725
  if (rawPath.length === 0) {
@@ -17645,7 +18739,7 @@ function validateReporterArtifactPath(options) {
17645
18739
  });
17646
18740
  return { ok: false, outputDir, diagnostics };
17647
18741
  }
17648
- if (path32__default.default.isAbsolute(rawPath) || path32__default.default.win32.isAbsolute(rawPath)) {
18742
+ if (path33__default.default.isAbsolute(rawPath) || path33__default.default.win32.isAbsolute(rawPath)) {
17649
18743
  diagnostics.push({
17650
18744
  code: "artifact_path_absolute",
17651
18745
  severity: "error",
@@ -17654,7 +18748,7 @@ function validateReporterArtifactPath(options) {
17654
18748
  });
17655
18749
  return { ok: false, outputDir, diagnostics };
17656
18750
  }
17657
- const normalized = path32__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
18751
+ const normalized = path33__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
17658
18752
  const segments = normalized.split("/");
17659
18753
  if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
17660
18754
  diagnostics.push({
@@ -17665,9 +18759,9 @@ function validateReporterArtifactPath(options) {
17665
18759
  });
17666
18760
  return { ok: false, outputDir, diagnostics };
17667
18761
  }
17668
- const absolutePath = path32__default.default.resolve(outputDir, normalized);
17669
- const relFromOutput = path32__default.default.relative(outputDir, absolutePath);
17670
- if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path32__default.default.isAbsolute(relFromOutput)) {
18762
+ const absolutePath = path33__default.default.resolve(outputDir, normalized);
18763
+ const relFromOutput = path33__default.default.relative(outputDir, absolutePath);
18764
+ if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path33__default.default.isAbsolute(relFromOutput)) {
17671
18765
  diagnostics.push({
17672
18766
  code: "artifact_path_escape",
17673
18767
  severity: "error",
@@ -17693,7 +18787,7 @@ var EVIDENCE_CI_ARTIFACT_FILES = [
17693
18787
  function createEvidenceCiArtifacts(options) {
17694
18788
  const profile = options.redactionProfile ?? "share";
17695
18789
  const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
17696
- const join = (name) => prefix === "" ? name : path32__default.default.posix.join(prefix, name);
18790
+ const join = (name) => prefix === "" ? name : path33__default.default.posix.join(prefix, name);
17697
18791
  const formatFor = (name) => {
17698
18792
  if (name.endsWith(".html")) return "html";
17699
18793
  if (name.endsWith(".jsonl")) return "jsonl";
@@ -17742,9 +18836,9 @@ function stableJson2(value) {
17742
18836
  async function writeLocalEvidence(input3) {
17743
18837
  const profile = input3.redactionProfile ?? "share";
17744
18838
  const format = input3.format ?? "directory";
17745
- const baseDir = path32__default.default.resolve(input3.outputDir);
18839
+ const baseDir = path33__default.default.resolve(input3.outputDir);
17746
18840
  await promises.mkdir(
17747
- format === "zip" && baseDir.toLowerCase().endsWith(".zip") ? path32__default.default.dirname(baseDir) : baseDir,
18841
+ format === "zip" && baseDir.toLowerCase().endsWith(".zip") ? path33__default.default.dirname(baseDir) : baseDir,
17748
18842
  { recursive: true }
17749
18843
  );
17750
18844
  const sourceContents = /* @__PURE__ */ new Map();
@@ -17800,7 +18894,7 @@ async function writeLocalEvidence(input3) {
17800
18894
  }
17801
18895
  if (format === "zip") {
17802
18896
  const zipPath = baseDir.toLowerCase().endsWith(".zip") ? baseDir : `${baseDir}.zip`;
17803
- await promises.mkdir(path32__default.default.dirname(zipPath), { recursive: true });
18897
+ await promises.mkdir(path33__default.default.dirname(zipPath), { recursive: true });
17804
18898
  const archive = buildZipArchive(
17805
18899
  files.map(([relativePath, content]) => ({
17806
18900
  path: relativePath,
@@ -17815,16 +18909,16 @@ async function writeLocalEvidence(input3) {
17815
18909
  let sidecarDir = baseDir;
17816
18910
  if (baseDir.toLowerCase().endsWith(".html")) {
17817
18911
  htmlPath = baseDir;
17818
- sidecarDir = path32__default.default.dirname(baseDir);
18912
+ sidecarDir = path33__default.default.dirname(baseDir);
17819
18913
  } else {
17820
18914
  await promises.mkdir(baseDir, { recursive: true });
17821
- htmlPath = path32__default.default.join(baseDir, "evidence.html");
18915
+ htmlPath = path33__default.default.join(baseDir, "evidence.html");
17822
18916
  sidecarDir = baseDir;
17823
18917
  }
17824
18918
  await promises.mkdir(sidecarDir, { recursive: true });
17825
18919
  await promises.writeFile(htmlPath, evidencePackage["evidence.html"], "utf-8");
17826
18920
  await promises.writeFile(
17827
- path32__default.default.join(sidecarDir, "evidence.json"),
18921
+ path33__default.default.join(sidecarDir, "evidence.json"),
17828
18922
  evidencePackage["evidence.json"],
17829
18923
  "utf-8"
17830
18924
  );
@@ -17832,7 +18926,7 @@ async function writeLocalEvidence(input3) {
17832
18926
  }
17833
18927
  await promises.mkdir(baseDir, { recursive: true });
17834
18928
  for (const [name, content] of files) {
17835
- await promises.writeFile(path32__default.default.join(baseDir, name), content, "utf-8");
18929
+ await promises.writeFile(path33__default.default.join(baseDir, name), content, "utf-8");
17836
18930
  }
17837
18931
  return baseDir;
17838
18932
  }
@@ -17856,11 +18950,11 @@ function checkResultToEvidenceJson(result, runIds) {
17856
18950
  }
17857
18951
  function defaultEvidenceDir(label) {
17858
18952
  const safe = label.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 80) || "evidence";
17859
- return path32__default.default.join(".agent-inspect", "evidence", safe);
18953
+ return path33__default.default.join(".agent-inspect", "evidence", safe);
17860
18954
  }
17861
18955
  function resolveEvidenceOutputDir(evidenceDir, label) {
17862
18956
  if (evidenceDir !== void 0 && evidenceDir.trim() !== "") {
17863
- return path32__default.default.resolve(evidenceDir.trim());
18957
+ return path33__default.default.resolve(evidenceDir.trim());
17864
18958
  }
17865
18959
  return defaultEvidenceDir(label);
17866
18960
  }
@@ -18184,23 +19278,23 @@ function evaluatePromptInjection(text, options = {}) {
18184
19278
  }
18185
19279
  return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
18186
19280
  }
18187
- function validateSchemaField(value, field, path43, evidence) {
19281
+ function validateSchemaField(value, field, path44, evidence) {
18188
19282
  const ruleId = "guardrail.structured-output";
18189
19283
  if (field.type) {
18190
19284
  const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
18191
19285
  if (actual !== field.type) {
18192
- evidence.push({ ruleId, path: path43, preview: `expected ${field.type}, got ${actual}` });
19286
+ evidence.push({ ruleId, path: path44, preview: `expected ${field.type}, got ${actual}` });
18193
19287
  return;
18194
19288
  }
18195
19289
  }
18196
19290
  if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
18197
- evidence.push({ ruleId, path: path43, preview: "value not in enum" });
19291
+ evidence.push({ ruleId, path: path44, preview: "value not in enum" });
18198
19292
  }
18199
19293
  if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
18200
19294
  const record = value;
18201
19295
  for (const key of field.required) {
18202
19296
  if (!(key in record)) {
18203
- evidence.push({ ruleId, path: `${path43}.${key}`, preview: "missing required key" });
19297
+ evidence.push({ ruleId, path: `${path44}.${key}`, preview: "missing required key" });
18204
19298
  }
18205
19299
  }
18206
19300
  }
@@ -18929,7 +20023,7 @@ function parseCheckConfig(value) {
18929
20023
  }
18930
20024
  async function loadConfig(configPath) {
18931
20025
  if (configPath === void 0) return {};
18932
- const extension = path32__default.default.extname(configPath);
20026
+ const extension = path33__default.default.extname(configPath);
18933
20027
  if (TS_CONFIG_EXTENSIONS2.has(extension)) {
18934
20028
  throw new CheckConfigError(
18935
20029
  "AI_CHECK_CONFIG_LOAD_FAILED",
@@ -18942,7 +20036,7 @@ async function loadConfig(configPath) {
18942
20036
  "Unsupported check config extension. Use .json, .js, .mjs, or .cjs."
18943
20037
  );
18944
20038
  }
18945
- const absolute = path32__default.default.resolve(configPath);
20039
+ const absolute = path33__default.default.resolve(configPath);
18946
20040
  try {
18947
20041
  if (extension === ".json") {
18948
20042
  const raw = await promises.readFile(absolute, "utf-8");
@@ -19136,7 +20230,7 @@ function buildRules(config, options, presetSelect = []) {
19136
20230
  diagnostics
19137
20231
  };
19138
20232
  }
19139
- function exitCodeFor(result) {
20233
+ function exitCodeFor2(result) {
19140
20234
  if (result.status === "pass") return 0;
19141
20235
  if (result.status === "fail") return 1;
19142
20236
  const codes = result.diagnostics.map((item) => item.code);
@@ -19157,16 +20251,16 @@ function exitCodeFor(result) {
19157
20251
  }
19158
20252
  return 1;
19159
20253
  }
19160
- function stable3(value) {
19161
- if (Array.isArray(value)) return value.map(stable3);
20254
+ function stable4(value) {
20255
+ if (Array.isArray(value)) return value.map(stable4);
19162
20256
  if (value === null || typeof value !== "object") return value;
19163
20257
  const record = value;
19164
20258
  return Object.fromEntries(
19165
- Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable3(record[key])])
20259
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable4(record[key])])
19166
20260
  );
19167
20261
  }
19168
- function printJson(result) {
19169
- console.log(JSON.stringify(stable3(result), null, 2));
20262
+ function printJson2(result) {
20263
+ console.log(JSON.stringify(stable4(result), null, 2));
19170
20264
  }
19171
20265
  function isSafetyFinding(ruleId) {
19172
20266
  return ruleId.startsWith("safety.") || ruleId.startsWith("guardrail.") || ruleId.includes("pii") || ruleId.includes("secret");
@@ -19203,7 +20297,7 @@ function printPresetClassSummary(result, preset) {
19203
20297
  `Share safety: ${hasSafetyFindings || result.status === "fail" ? "FAIL" : result.status === "pass" ? "PASS" : "FAIL"}`
19204
20298
  );
19205
20299
  }
19206
- function printHuman(result, options = {}) {
20300
+ function printHuman2(result, options = {}) {
19207
20301
  const scoped = result;
19208
20302
  if (scoped.scopeLabel) {
19209
20303
  console.log(`Scope: ${scoped.scopeKind} ${scoped.scopeLabel}`);
@@ -19223,13 +20317,13 @@ function printHuman(result, options = {}) {
19223
20317
  console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
19224
20318
  }
19225
20319
  for (const finding of result.findings) {
19226
- const path43 = finding.evidence[0]?.path;
20320
+ const path44 = finding.evidence[0]?.path;
19227
20321
  const run = finding.evidence[0]?.runId;
19228
20322
  const runPrefix = run ? `[${run}] ` : "";
19229
- console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
20323
+ console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
19230
20324
  }
19231
20325
  }
19232
- function readErrorResult(error) {
20326
+ function readErrorResult2(error) {
19233
20327
  if (error instanceof TraceReadError) {
19234
20328
  const code = error.code === "unsupported_format" ? "AI_CHECK_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_CHECK_AMBIGUOUS_FORMAT" : "AI_CHECK_TRACE_UNREADABLE";
19235
20329
  return errorResult2(code, error.message);
@@ -19256,9 +20350,9 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
19256
20350
  "AI_CHECK_CONFIG_NO_EFFECTIVE_RULES",
19257
20351
  "Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, or checks.safety."
19258
20352
  );
19259
- if (options.json) printJson(result);
19260
- else printHuman(result, options);
19261
- process.exitCode = exitCodeFor(result);
20353
+ if (options.json) printJson2(result);
20354
+ else printHuman2(result, options);
20355
+ process.exitCode = exitCodeFor2(result);
19262
20356
  return;
19263
20357
  }
19264
20358
  let effectiveOptions = options;
@@ -19388,10 +20482,10 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
19388
20482
  result = errorResult2(code, message);
19389
20483
  }
19390
20484
  } else {
19391
- result = readErrorResult(error);
20485
+ result = readErrorResult2(error);
19392
20486
  }
19393
20487
  }
19394
- process.exitCode = exitCodeFor(result);
20488
+ process.exitCode = exitCodeFor2(result);
19395
20489
  const failed = result.status !== "pass";
19396
20490
  if (shouldEmitEvidence(options.evidenceOn, failed)) {
19397
20491
  try {
@@ -19431,8 +20525,8 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
19431
20525
  );
19432
20526
  }
19433
20527
  }
19434
- if (options.json) printJson(result);
19435
- else printHuman(result, options);
20528
+ if (options.json) printJson2(result);
20529
+ else printHuman2(result, options);
19436
20530
  }
19437
20531
 
19438
20532
  // packages/viewer/src/server.ts
@@ -19589,7 +20683,7 @@ async function loadSuiteViewerData(options) {
19589
20683
  for (const suiteCase of result.cases) {
19590
20684
  cases.push(await enrichCase(suiteCase, baselinePath));
19591
20685
  }
19592
- const artifactsDir = path32__default.default.join(path32__default.default.dirname(result.configPath), ".agent-inspect/suite-runs");
20686
+ const artifactsDir = path33__default.default.join(path33__default.default.dirname(result.configPath), ".agent-inspect/suite-runs");
19593
20687
  return {
19594
20688
  suiteName: result.suiteName,
19595
20689
  configPath: result.configPath,
@@ -19785,19 +20879,19 @@ function serializeWorkspaceManifest(manifest) {
19785
20879
  }
19786
20880
  var INDEX_DIR_NAME = "index";
19787
20881
  function resolveWorkspaceLocation(cwd = process.cwd()) {
19788
- const projectRoot = path32__default.default.resolve(cwd);
19789
- const workspaceDir = path32__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
20882
+ const projectRoot = path33__default.default.resolve(cwd);
20883
+ const workspaceDir = path33__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
19790
20884
  return {
19791
20885
  projectRoot,
19792
20886
  workspaceDir,
19793
- manifestPath: path32__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
20887
+ manifestPath: path33__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
19794
20888
  };
19795
20889
  }
19796
20890
  function resolveInsideWorkspace(workspaceDir, relative) {
19797
- const base = path32__default.default.resolve(workspaceDir);
19798
- const resolved = path32__default.default.resolve(base, relative);
19799
- const rel = path32__default.default.relative(base, resolved);
19800
- if (rel === "" || rel === "." || !rel.startsWith("..") && !path32__default.default.isAbsolute(rel)) {
20891
+ const base = path33__default.default.resolve(workspaceDir);
20892
+ const resolved = path33__default.default.resolve(base, relative);
20893
+ const rel = path33__default.default.relative(base, resolved);
20894
+ if (rel === "" || rel === "." || !rel.startsWith("..") && !path33__default.default.isAbsolute(rel)) {
19801
20895
  return resolved;
19802
20896
  }
19803
20897
  throw new Error(
@@ -19866,7 +20960,7 @@ async function createWorkspace(options = {}) {
19866
20960
  created = false;
19867
20961
  adopted = true;
19868
20962
  } else {
19869
- const project = options.project?.trim() || path32__default.default.basename(location.projectRoot) || "workspace";
20963
+ const project = options.project?.trim() || path33__default.default.basename(location.projectRoot) || "workspace";
19870
20964
  const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
19871
20965
  manifest = createDefaultWorkspaceManifest({
19872
20966
  project,
@@ -20005,7 +21099,7 @@ async function doctorWorkspace(location) {
20005
21099
  const abs = resolveInsideWorkspace(location.workspaceDir, rel);
20006
21100
  for (const file of await listJsonl(abs)) {
20007
21101
  try {
20008
- const s = await promises.stat(path32__default.default.join(abs, file));
21102
+ const s = await promises.stat(path33__default.default.join(abs, file));
20009
21103
  newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
20010
21104
  } catch {
20011
21105
  checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
@@ -20053,7 +21147,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
20053
21147
  const relPath = `${rel}/${entry}`;
20054
21148
  removed.push(relPath);
20055
21149
  if (!dryRun) {
20056
- await promises.rm(path32__default.default.join(abs, entry), { recursive: true, force: true });
21150
+ await promises.rm(path33__default.default.join(abs, entry), { recursive: true, force: true });
20057
21151
  }
20058
21152
  }
20059
21153
  }
@@ -20062,7 +21156,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
20062
21156
 
20063
21157
  // packages/viewer/src/workspace-data.ts
20064
21158
  async function loadWorkspaceViewerData(options) {
20065
- const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
21159
+ const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
20066
21160
  const location = resolveWorkspaceLocation(cwd);
20067
21161
  const manifestRead = await readWorkspaceManifestFile(location);
20068
21162
  if (!manifestRead.ok || manifestRead.manifest === void 0) {
@@ -20075,7 +21169,7 @@ async function loadWorkspaceViewerData(options) {
20075
21169
  const runs = [];
20076
21170
  for (const rel of manifestRead.manifest.traceDirs) {
20077
21171
  const traceDir = resolveTraceDir({
20078
- dir: path32__default.default.join(location.workspaceDir, rel)
21172
+ dir: path33__default.default.join(location.workspaceDir, rel)
20079
21173
  });
20080
21174
  const td = new TraceDirectory({ dir: traceDir });
20081
21175
  const files = await td.list();
@@ -20089,7 +21183,7 @@ async function loadWorkspaceViewerData(options) {
20089
21183
  runId: meta2.runId,
20090
21184
  ...meta2.name !== void 0 ? { name: meta2.name } : {},
20091
21185
  status: meta2.status,
20092
- file: path32__default.default.basename(meta2.filePath)
21186
+ file: path33__default.default.basename(meta2.filePath)
20093
21187
  });
20094
21188
  }
20095
21189
  }
@@ -20100,8 +21194,8 @@ async function loadWorkspaceViewerData(options) {
20100
21194
  doctor,
20101
21195
  runs,
20102
21196
  bundleDirs: [
20103
- path32__default.default.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
20104
- path32__default.default.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
21197
+ path33__default.default.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
21198
+ path33__default.default.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
20105
21199
  ]
20106
21200
  };
20107
21201
  }
@@ -20164,7 +21258,7 @@ function createViewerServer(options = {}) {
20164
21258
  ok: true,
20165
21259
  readOnly: true,
20166
21260
  mode,
20167
- traceDir: path32__default.default.resolve(traceDir)
21261
+ traceDir: path33__default.default.resolve(traceDir)
20168
21262
  });
20169
21263
  }
20170
21264
  if (pathname === "/api/suite" && mode === "suite") {
@@ -20193,7 +21287,7 @@ function createViewerServer(options = {}) {
20193
21287
  runId: meta2.runId,
20194
21288
  name: meta2.name,
20195
21289
  status: meta2.status,
20196
- file: path32__default.default.basename(meta2.filePath),
21290
+ file: path33__default.default.basename(meta2.filePath),
20197
21291
  startedAt: meta2.startedAt,
20198
21292
  durationMs: meta2.durationMs
20199
21293
  }))
@@ -20310,7 +21404,7 @@ function startViewerServer(options = {}) {
20310
21404
  resolve({
20311
21405
  host,
20312
21406
  port: resolvedPort,
20313
- traceDir: path32__default.default.resolve(traceDir),
21407
+ traceDir: path33__default.default.resolve(traceDir),
20314
21408
  url: `http://${host}:${resolvedPort}/${modeQuery}`,
20315
21409
  mode
20316
21410
  });
@@ -20721,10 +21815,10 @@ async function evalRun(input3, options = {}) {
20721
21815
  diagnostics: []
20722
21816
  };
20723
21817
  }
20724
- function evidenceForRun(run, path43) {
20725
- return [{ runId: run.runId, ...path43 !== void 0 ? { path: path43 } : {} }];
21818
+ function evidenceForRun(run, path44) {
21819
+ return [{ runId: run.runId, ...path44 !== void 0 ? { path: path44 } : {} }];
20726
21820
  }
20727
- function evidenceForEvent(event, path43) {
21821
+ function evidenceForEvent(event, path44) {
20728
21822
  return [
20729
21823
  {
20730
21824
  runId: event.runId,
@@ -20732,7 +21826,7 @@ function evidenceForEvent(event, path43) {
20732
21826
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
20733
21827
  kind: event.kind,
20734
21828
  name: event.name,
20735
- ...path43 !== void 0 ? { path: path43 } : {}
21829
+ ...path44 !== void 0 ? { path: path44 } : {}
20736
21830
  }
20737
21831
  ];
20738
21832
  }
@@ -20890,9 +21984,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
20890
21984
  function tokenize(text) {
20891
21985
  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));
20892
21986
  }
20893
- function firstEvidence(fields, run, path43) {
21987
+ function firstEvidence(fields, run, path44) {
20894
21988
  const first = fields[0];
20895
- return first === void 0 ? evidenceForRun(run, path43) : evidenceForEvent(first.node.event, first.path);
21989
+ return first === void 0 ? evidenceForRun(run, path44) : evidenceForEvent(first.node.event, first.path);
20896
21990
  }
20897
21991
  function collectSourceIds(nodes, keys) {
20898
21992
  const wanted = keySet(keys);
@@ -21245,273 +22339,55 @@ var checks = {
21245
22339
  "Answer contained banned unsupported-answer phrasing.",
21246
22340
  firstEvidence(answers, context.run, "attributes.answer"),
21247
22341
  { bannedPhraseCount: banned.length },
21248
- { matchedPhraseCount: matches.length }
21249
- )
21250
- ] : [];
21251
- });
21252
- }
21253
- };
21254
- function renderEvalMarkdown(result) {
21255
- const lines = [
21256
- `# AgentInspect Eval`,
21257
- "",
21258
- `Status: ${result.status}`,
21259
- `Format: ${result.format}`,
21260
- ...result.runId !== void 0 ? [`Run: ${result.runId}`] : [],
21261
- `Summary: ${result.summary.passed} passed, ${result.summary.failed} failed, ${result.summary.warnings} warnings, ${result.summary.errors} errors`
21262
- ];
21263
- if (result.diagnostics.length > 0) {
21264
- lines.push("", "## Diagnostics");
21265
- for (const diagnostic7 of result.diagnostics) {
21266
- lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
21267
- }
21268
- }
21269
- if (result.findings.length > 0) {
21270
- lines.push("", "## Findings");
21271
- for (const finding of result.findings) {
21272
- const path43 = finding.evidence[0]?.path;
21273
- lines.push(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
21274
- }
21275
- }
21276
- return `${lines.join("\n")}
21277
- `;
21278
- }
21279
-
21280
- // packages/cli/src/eval.ts
21281
- var CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
21282
- var TS_CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
21283
- function diagnostic6(code, message, severity = "error") {
21284
- return { code, message, severity };
21285
- }
21286
- function errorResult4(code, message, format = "unknown") {
21287
- return {
21288
- ok: false,
21289
- status: "error",
21290
- format,
21291
- summary: { passed: 0, failed: 0, warnings: 0, errors: 1 },
21292
- findings: [],
21293
- diagnostics: [diagnostic6(code, message)]
21294
- };
21295
- }
21296
- function parseNumber2(value, label) {
21297
- if (value === void 0) return void 0;
21298
- const parsed = Number(value);
21299
- if (!Number.isFinite(parsed) || parsed < 0) {
21300
- throw new Error(`${label} must be a non-negative number.`);
21301
- }
21302
- return parsed;
21303
- }
21304
- function asStringArray3(value, label) {
21305
- if (value === void 0) return void 0;
21306
- if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
21307
- throw new Error(`${label} must be an array of strings.`);
21308
- }
21309
- return value;
21310
- }
21311
- function asConfig(value) {
21312
- if (value === void 0 || value === null) return {};
21313
- if (typeof value !== "object" || Array.isArray(value)) {
21314
- throw new Error("Config must export an object.");
21315
- }
21316
- return value;
21317
- }
21318
- async function loadConfig2(configPath) {
21319
- if (configPath === void 0) return {};
21320
- const extension = path32__default.default.extname(configPath);
21321
- if (TS_CONFIG_EXTENSIONS3.has(extension)) {
21322
- throw new Error(
21323
- "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
21324
- );
21325
- }
21326
- if (!CONFIG_EXTENSIONS3.has(extension)) {
21327
- throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
21328
- }
21329
- const absolute = path32__default.default.resolve(configPath);
21330
- if (extension === ".json") {
21331
- const raw = await promises.readFile(absolute, "utf-8");
21332
- return asConfig(JSON.parse(raw));
21333
- }
21334
- const mod = await import(url.pathToFileURL(absolute).href);
21335
- return asConfig("default" in mod ? mod.default : mod);
21336
- }
21337
- function normalizeConfig2(config) {
21338
- if (config.eval === void 0) return {};
21339
- if (typeof config.eval !== "object" || Array.isArray(config.eval)) {
21340
- throw new Error("eval config must be an object.");
21341
- }
21342
- return config.eval;
21343
- }
21344
- function maybeAdd(rules, value, makeRule) {
21345
- if (value !== void 0) rules.push(makeRule(value));
21346
- }
21347
- function optionObject(value) {
21348
- if (value === void 0 || value === false) return void 0;
21349
- if (value === true) return {};
21350
- if (typeof value !== "object" || Array.isArray(value)) {
21351
- throw new Error("Eval heuristic config must be a boolean or object.");
21352
- }
21353
- return value;
21354
- }
21355
- function sourceIdsFromConfig(value) {
21356
- if (value === void 0) return void 0;
21357
- if (Array.isArray(value)) return { ids: asStringArray3(value, "eval.requiredSourceIds") ?? [] };
21358
- if (typeof value !== "object" || Array.isArray(value)) {
21359
- throw new Error("eval.requiredSourceIds must be an array or object.");
21360
- }
21361
- const ids = asStringArray3(value.ids, "eval.requiredSourceIds.ids") ?? [];
21362
- return { ids, options: { sourceIdKeys: value.sourceIdKeys } };
21363
- }
21364
- function buildRules2(config, options) {
21365
- const evalConfig = normalizeConfig2(config);
21366
- const rules = [];
21367
- if (evalConfig.requireSuccess || options.requireSuccess) rules.push(checks.requireSuccess());
21368
- const requiredTools = [
21369
- ...asStringArray3(evalConfig.requiredTools, "eval.requiredTools") ?? [],
21370
- ...options.requiredTool ?? []
21371
- ];
21372
- if (requiredTools.length > 0) rules.push(checks.requiredTools(requiredTools));
21373
- const forbiddenTools = [
21374
- ...asStringArray3(evalConfig.forbiddenTools, "eval.forbiddenTools") ?? [],
21375
- ...options.forbidTool ?? [],
21376
- ...options.forbiddenTool ?? []
21377
- ];
21378
- if (forbiddenTools.length > 0) rules.push(checks.forbiddenTools(forbiddenTools));
21379
- const maxDurationMs = parseNumber2(options.maxDurationMs, "--max-duration-ms") ?? evalConfig.maxDurationMs;
21380
- maybeAdd(rules, maxDurationMs, checks.maxDurationMs);
21381
- const maxDepth = parseNumber2(options.maxDepth, "--max-depth") ?? evalConfig.maxDepth;
21382
- maybeAdd(rules, maxDepth, checks.maxDepth);
21383
- const maxRetries = parseNumber2(options.maxRetries, "--max-retries") ?? evalConfig.maxRetries;
21384
- maybeAdd(rules, maxRetries, checks.maxRetries);
21385
- const maxTotalTokens = parseNumber2(options.maxTotalTokens, "--max-total-tokens") ?? evalConfig.maxTotalTokens;
21386
- maybeAdd(rules, maxTotalTokens, checks.maxTotalTokens);
21387
- if (evalConfig.requiredRetrievalBeforeGeneration || options.requireRetrievalBeforeGeneration) {
21388
- rules.push(checks.requiredRetrievalBeforeGeneration());
21389
- }
21390
- const requiredDecisionMetadata = [
21391
- ...asStringArray3(
21392
- evalConfig.requiredDecisionMetadata,
21393
- "eval.requiredDecisionMetadata"
21394
- ) ?? [],
21395
- ...options.requiredDecisionMetadata ?? []
21396
- ];
21397
- if (requiredDecisionMetadata.length > 0) {
21398
- rules.push(checks.requiredDecisionMetadata(requiredDecisionMetadata));
21399
- }
21400
- const contextOverlap = optionObject(evalConfig.contextOverlap);
21401
- const minOverlap = parseNumber2(options.minContextOverlap, "--min-context-overlap");
21402
- const minSharedTerms = parseNumber2(options.minSharedTerms, "--min-shared-terms");
21403
- if (contextOverlap !== void 0 || options.contextOverlap || minOverlap !== void 0 || minSharedTerms !== void 0) {
21404
- rules.push(checks.contextOverlap({ ...contextOverlap, minOverlap, minSharedTerms }));
21405
- }
21406
- const quoteOverlap = optionObject(evalConfig.quoteOverlap);
21407
- if (quoteOverlap !== void 0 || options.quoteOverlap) {
21408
- rules.push(checks.quoteOverlap(quoteOverlap));
21409
- }
21410
- const citationPresence = optionObject(evalConfig.citationPresence);
21411
- if (citationPresence !== void 0 || options.citationPresence) {
21412
- rules.push(checks.citationPresence(citationPresence));
21413
- }
21414
- const sourceIds = sourceIdsFromConfig(evalConfig.requiredSourceIds);
21415
- const requiredSourceIds = [...sourceIds?.ids ?? [], ...options.requiredSourceId ?? []];
21416
- if (requiredSourceIds.length > 0) {
21417
- rules.push(checks.requiredSourceIds(requiredSourceIds, sourceIds?.options));
21418
- }
21419
- const cliAnswerLength = {
21420
- minCharacters: parseNumber2(options.minAnswerCharacters, "--min-answer-characters"),
21421
- maxCharacters: parseNumber2(options.maxAnswerCharacters, "--max-answer-characters"),
21422
- minWords: parseNumber2(options.minAnswerWords, "--min-answer-words"),
21423
- maxWords: parseNumber2(options.maxAnswerWords, "--max-answer-words")
21424
- };
21425
- const hasCliAnswerLength = Object.values(cliAnswerLength).some((value) => value !== void 0);
21426
- if (evalConfig.answerLengthBounds !== void 0 || hasCliAnswerLength) {
21427
- rules.push(checks.answerLengthBounds({ ...evalConfig.answerLengthBounds, ...cliAnswerLength }));
21428
- }
21429
- const bannedPhrases = [
21430
- ...asStringArray3(
21431
- evalConfig.bannedUnsupportedPhrases,
21432
- "eval.bannedUnsupportedPhrases"
21433
- ) ?? [],
21434
- ...options.bannedPhrase ?? []
21435
- ];
21436
- if (bannedPhrases.length > 0) rules.push(checks.bannedUnsupportedPhrases(bannedPhrases));
21437
- return rules.length > 0 ? rules : void 0;
21438
- }
21439
- function exitCodeFor2(result) {
21440
- if (result.status === "pass") return 0;
21441
- if (result.status === "fail") return 1;
21442
- return 2;
21443
- }
21444
- function stable4(value) {
21445
- if (Array.isArray(value)) return value.map(stable4);
21446
- if (value === null || typeof value !== "object") return value;
21447
- const record = value;
21448
- return Object.fromEntries(
21449
- Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable4(record[key])])
21450
- );
21451
- }
21452
- function printJson2(result) {
21453
- console.log(JSON.stringify(stable4(result), null, 2));
21454
- }
21455
- function printHuman2(result) {
21456
- console.log(`Eval status: ${result.status}`);
21457
- console.log(`Format: ${result.format}`);
21458
- if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
21459
- console.log(
21460
- `Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
21461
- );
21462
- for (const diagnostic7 of result.diagnostics) {
21463
- console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
21464
- }
21465
- for (const finding of result.findings) {
21466
- const path43 = finding.evidence[0]?.path;
21467
- console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
21468
- }
21469
- }
21470
- function readErrorResult2(error) {
21471
- if (error instanceof TraceReadError) {
21472
- const code = error.code === "unsupported_format" ? "AI_EVAL_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_EVAL_AMBIGUOUS_FORMAT" : "AI_EVAL_TRACE_UNREADABLE";
21473
- return errorResult4(code, error.message);
21474
- }
21475
- return errorResult4(
21476
- "AI_EVAL_TRACE_UNREADABLE",
21477
- error instanceof Error ? error.message : String(error)
21478
- );
21479
- }
21480
- async function evalCommand(target, options = {}, stdin = process.stdin) {
21481
- let result;
21482
- let phase = "config";
21483
- try {
21484
- const config = await loadConfig2(options.config);
21485
- const rules = buildRules2(config, options);
21486
- phase = "read";
21487
- const input3 = await inputFromTarget(target, options, stdin);
21488
- const read = await openTrace(input3, {
21489
- ...options.format !== void 0 ? { format: options.format } : {}
21490
- });
21491
- result = await evalRun(read, {
21492
- ...rules !== void 0 ? { checks: rules } : {},
21493
- ...options.run !== void 0 ? { runId: options.run } : {}
22342
+ { matchedPhraseCount: matches.length }
22343
+ )
22344
+ ] : [];
21494
22345
  });
21495
- } catch (error) {
21496
- if (phase === "config") {
21497
- const message = error instanceof Error ? error.message : String(error);
21498
- const code = message.startsWith("--") ? "AI_EVAL_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported eval config extension") || message.includes("TypeScript eval configs") || message.includes("Config must") || message.includes("eval config") || message.includes("must be an array") ? "AI_EVAL_INVALID_CONFIG" : "AI_EVAL_CONFIG_LOAD_FAILED";
21499
- result = errorResult4(code, message);
21500
- } else {
21501
- result = readErrorResult2(error);
22346
+ }
22347
+ };
22348
+ function renderEvalMarkdown(result) {
22349
+ const lines = [
22350
+ `# AgentInspect Eval`,
22351
+ "",
22352
+ `Status: ${result.status}`,
22353
+ `Format: ${result.format}`,
22354
+ ...result.runId !== void 0 ? [`Run: ${result.runId}`] : [],
22355
+ `Summary: ${result.summary.passed} passed, ${result.summary.failed} failed, ${result.summary.warnings} warnings, ${result.summary.errors} errors`
22356
+ ];
22357
+ if (result.diagnostics.length > 0) {
22358
+ lines.push("", "## Diagnostics");
22359
+ for (const diagnostic7 of result.diagnostics) {
22360
+ lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
21502
22361
  }
21503
22362
  }
21504
- process.exitCode = exitCodeFor2(result);
21505
- if (options.json) printJson2(result);
21506
- else if (options.markdown) console.log(renderEvalMarkdown(result).trimEnd());
21507
- else printHuman2(result);
22363
+ if (result.findings.length > 0) {
22364
+ lines.push("", "## Findings");
22365
+ for (const finding of result.findings) {
22366
+ const path44 = finding.evidence[0]?.path;
22367
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
22368
+ }
22369
+ }
22370
+ return `${lines.join("\n")}
22371
+ `;
21508
22372
  }
21509
- var BEST_EFFORT_NOTE = "Best-effort local safety verification only; not a compliance, privacy, security, or regulatory certification.";
21510
- var DEFAULT_MAX_STRING_LENGTH = 16384;
21511
- var DEFAULT_MAX_ARRAY_LENGTH = 1e3;
21512
- var DEFAULT_MAX_OBJECT_KEYS = 200;
21513
- var DEFAULT_MAX_SERIALIZED_BYTES = 128 * 1024;
21514
- function parseLimit3(value, label) {
22373
+
22374
+ // packages/cli/src/eval.ts
22375
+ var CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
22376
+ var TS_CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
22377
+ function diagnostic6(code, message, severity = "error") {
22378
+ return { code, message, severity };
22379
+ }
22380
+ function errorResult4(code, message, format = "unknown") {
22381
+ return {
22382
+ ok: false,
22383
+ status: "error",
22384
+ format,
22385
+ summary: { passed: 0, failed: 0, warnings: 0, errors: 1 },
22386
+ findings: [],
22387
+ diagnostics: [diagnostic6(code, message)]
22388
+ };
22389
+ }
22390
+ function parseNumber2(value, label) {
21515
22391
  if (value === void 0) return void 0;
21516
22392
  const parsed = Number(value);
21517
22393
  if (!Number.isFinite(parsed) || parsed < 0) {
@@ -21519,368 +22395,210 @@ function parseLimit3(value, label) {
21519
22395
  }
21520
22396
  return parsed;
21521
22397
  }
21522
- function stable5(value) {
21523
- if (Array.isArray(value)) return value.map(stable5);
21524
- if (value === null || typeof value !== "object") return value;
21525
- const record = value;
21526
- return Object.fromEntries(
21527
- Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable5(record[key])])
21528
- );
21529
- }
21530
- function safetyDiagnostic(code, message, severity = "error") {
21531
- return { code, message, severity };
21532
- }
21533
- function warningDiagnostics(warnings, unsupportedFields) {
21534
- return [
21535
- ...warnings.map(
21536
- (warning) => safetyDiagnostic(
21537
- warning.code,
21538
- warning.message,
21539
- warning.severity === "error" ? "error" : "warning"
21540
- )
21541
- ),
21542
- ...unsupportedFields.map(
21543
- (field) => safetyDiagnostic(
21544
- "unsupported_field",
21545
- `Reader reported unsupported field: ${field}`,
21546
- "warning"
21547
- )
21548
- )
21549
- ];
22398
+ function asStringArray3(value, label) {
22399
+ if (value === void 0) return void 0;
22400
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
22401
+ throw new Error(`${label} must be an array of strings.`);
22402
+ }
22403
+ return value;
21550
22404
  }
21551
- function diagnosticFromCheck(item) {
21552
- return safetyDiagnostic(item.code, item.message, item.severity);
22405
+ function asConfig(value) {
22406
+ if (value === void 0 || value === null) return {};
22407
+ if (typeof value !== "object" || Array.isArray(value)) {
22408
+ throw new Error("Config must export an object.");
22409
+ }
22410
+ return value;
21553
22411
  }
21554
- function statusFrom(findings, diagnostics) {
21555
- if (diagnostics.some((item) => item.severity === "error")) return "UNKNOWN";
21556
- if (findings.some((item) => item.severity === "error")) return "UNSAFE";
21557
- if (diagnostics.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
21558
- if (findings.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
21559
- return "SAFE";
22412
+ async function loadConfig2(configPath) {
22413
+ if (configPath === void 0) return {};
22414
+ const extension = path33__default.default.extname(configPath);
22415
+ if (TS_CONFIG_EXTENSIONS3.has(extension)) {
22416
+ throw new Error(
22417
+ "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
22418
+ );
22419
+ }
22420
+ if (!CONFIG_EXTENSIONS3.has(extension)) {
22421
+ throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
22422
+ }
22423
+ const absolute = path33__default.default.resolve(configPath);
22424
+ if (extension === ".json") {
22425
+ const raw = await promises.readFile(absolute, "utf-8");
22426
+ return asConfig(JSON.parse(raw));
22427
+ }
22428
+ const mod = await import(url.pathToFileURL(absolute).href);
22429
+ return asConfig("default" in mod ? mod.default : mod);
21560
22430
  }
21561
- function resultFromParts(parts) {
21562
- const findings = [...parts.findings ?? []];
21563
- const diagnostics = [...parts.diagnostics ?? []];
21564
- const warnings = [...parts.warnings ?? []];
21565
- const unsupportedFields = [...parts.unsupportedFields ?? []];
21566
- const status = parts.status ?? statusFrom(findings, diagnostics);
21567
- return {
21568
- ok: status === "SAFE" || status === "SAFE WITH WARNINGS",
21569
- command: parts.command,
21570
- status,
21571
- format: parts.format,
21572
- ...parts.runId !== void 0 ? { runId: parts.runId } : {},
21573
- summary: {
21574
- findings: findings.length,
21575
- warnings: diagnostics.filter((item) => item.severity === "warning").length + findings.filter((item) => item.severity === "warning").length,
21576
- errors: diagnostics.filter((item) => item.severity === "error").length + findings.filter((item) => item.severity === "error").length
21577
- },
21578
- findings,
21579
- diagnostics,
21580
- warnings,
21581
- unsupportedFields,
21582
- note: BEST_EFFORT_NOTE,
21583
- ...parts.sourceAssessment !== void 0 ? { sourceAssessment: parts.sourceAssessment } : {},
21584
- ...parts.artifactAssessment !== void 0 ? { artifactAssessment: parts.artifactAssessment } : {},
21585
- ...parts.redactionSummary !== void 0 ? { redactionSummary: parts.redactionSummary } : {}
21586
- };
22431
+ function normalizeConfig2(config) {
22432
+ if (config.eval === void 0) return {};
22433
+ if (typeof config.eval !== "object" || Array.isArray(config.eval)) {
22434
+ throw new Error("eval config must be an object.");
22435
+ }
22436
+ return config.eval;
21587
22437
  }
21588
- function layerFromResult(result) {
21589
- return {
21590
- status: result.status,
21591
- summary: result.summary,
21592
- findings: result.findings
21593
- };
22438
+ function maybeAdd(rules, value, makeRule) {
22439
+ if (value !== void 0) rules.push(makeRule(value));
21594
22440
  }
21595
- function readErrorResult3(command, error) {
21596
- if (error instanceof TraceReadError) {
21597
- const code = error.code === "unsupported_format" ? "AI_SAFETY_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_SAFETY_AMBIGUOUS_FORMAT" : "AI_SAFETY_TRACE_UNREADABLE";
21598
- return resultFromParts({
21599
- command,
21600
- format: "unknown",
21601
- diagnostics: [safetyDiagnostic(code, error.message)],
21602
- warnings: error.warnings
21603
- });
22441
+ function optionObject(value) {
22442
+ if (value === void 0 || value === false) return void 0;
22443
+ if (value === true) return {};
22444
+ if (typeof value !== "object" || Array.isArray(value)) {
22445
+ throw new Error("Eval heuristic config must be a boolean or object.");
21604
22446
  }
21605
- return resultFromParts({
21606
- command,
21607
- format: "unknown",
21608
- diagnostics: [
21609
- safetyDiagnostic(
21610
- "AI_SAFETY_TRACE_UNREADABLE",
21611
- error instanceof Error ? error.message : String(error)
21612
- )
21613
- ]
21614
- });
22447
+ return value;
21615
22448
  }
21616
- function invalidArgumentResult(command, error) {
21617
- return resultFromParts({
21618
- command,
21619
- format: "unknown",
21620
- diagnostics: [
21621
- safetyDiagnostic(
21622
- "AI_SAFETY_INVALID_ARGUMENTS",
21623
- error instanceof Error ? error.message : String(error)
21624
- )
21625
- ]
21626
- });
22449
+ function sourceIdsFromConfig(value) {
22450
+ if (value === void 0) return void 0;
22451
+ if (Array.isArray(value)) return { ids: asStringArray3(value, "eval.requiredSourceIds") ?? [] };
22452
+ if (typeof value !== "object" || Array.isArray(value)) {
22453
+ throw new Error("eval.requiredSourceIds must be an array or object.");
22454
+ }
22455
+ const ids = asStringArray3(value.ids, "eval.requiredSourceIds.ids") ?? [];
22456
+ return { ids, options: { sourceIdKeys: value.sourceIdKeys } };
21627
22457
  }
21628
- function buildSafetyRules(options) {
21629
- const maxStringLength2 = parseLimit3(options.maxStringLength, "--max-string-length") ?? DEFAULT_MAX_STRING_LENGTH;
21630
- const maxArrayLength = parseLimit3(options.maxArrayLength, "--max-array-length") ?? DEFAULT_MAX_ARRAY_LENGTH;
21631
- const maxObjectKeys = parseLimit3(options.maxObjectKeys, "--max-object-keys") ?? DEFAULT_MAX_OBJECT_KEYS;
21632
- const maxSerializedBytes = parseLimit3(options.maxSerializedBytes, "--max-serialized-bytes") ?? DEFAULT_MAX_SERIALIZED_BYTES;
21633
- return [
21634
- createSafetyRawContentRule(),
21635
- createSafetyRedactionRule(),
21636
- createSafetySecretPatternRule(),
21637
- createSafetyOversizedAttributeRule({
21638
- maxStringLength: maxStringLength2,
21639
- maxArrayLength,
21640
- maxObjectKeys,
21641
- maxSerializedBytes
21642
- })
22458
+ function buildRules2(config, options) {
22459
+ const evalConfig = normalizeConfig2(config);
22460
+ const rules = [];
22461
+ if (evalConfig.requireSuccess || options.requireSuccess) rules.push(checks.requireSuccess());
22462
+ const requiredTools = [
22463
+ ...asStringArray3(evalConfig.requiredTools, "eval.requiredTools") ?? [],
22464
+ ...options.requiredTool ?? []
21643
22465
  ];
21644
- }
21645
- function flattenNodes2(nodes) {
21646
- return nodes.flatMap((node) => [
21647
- node,
21648
- ...flattenNodes2(
21649
- node.children
21650
- )
21651
- ]);
21652
- }
21653
- function detectorSeverity(finding) {
21654
- return finding.severity;
21655
- }
21656
- function classifyRedactionDetector(detector) {
21657
- if (detector === "value.creditCard" || detector === "value.email" || detector === "value.phone") {
21658
- return { category: "personal-data", confidence: "high" };
22466
+ if (requiredTools.length > 0) rules.push(checks.requiredTools(requiredTools));
22467
+ const forbiddenTools = [
22468
+ ...asStringArray3(evalConfig.forbiddenTools, "eval.forbiddenTools") ?? [],
22469
+ ...options.forbidTool ?? [],
22470
+ ...options.forbiddenTool ?? []
22471
+ ];
22472
+ if (forbiddenTools.length > 0) rules.push(checks.forbiddenTools(forbiddenTools));
22473
+ const maxDurationMs = parseNumber2(options.maxDurationMs, "--max-duration-ms") ?? evalConfig.maxDurationMs;
22474
+ maybeAdd(rules, maxDurationMs, checks.maxDurationMs);
22475
+ const maxDepth = parseNumber2(options.maxDepth, "--max-depth") ?? evalConfig.maxDepth;
22476
+ maybeAdd(rules, maxDepth, checks.maxDepth);
22477
+ const maxRetries = parseNumber2(options.maxRetries, "--max-retries") ?? evalConfig.maxRetries;
22478
+ maybeAdd(rules, maxRetries, checks.maxRetries);
22479
+ const maxTotalTokens = parseNumber2(options.maxTotalTokens, "--max-total-tokens") ?? evalConfig.maxTotalTokens;
22480
+ maybeAdd(rules, maxTotalTokens, checks.maxTotalTokens);
22481
+ if (evalConfig.requiredRetrievalBeforeGeneration || options.requireRetrievalBeforeGeneration) {
22482
+ rules.push(checks.requiredRetrievalBeforeGeneration());
21659
22483
  }
21660
- if (detector === "value.ipv4" || detector === "value.ipv6") {
21661
- return { category: "identifier", confidence: "medium" };
22484
+ const requiredDecisionMetadata = [
22485
+ ...asStringArray3(
22486
+ evalConfig.requiredDecisionMetadata,
22487
+ "eval.requiredDecisionMetadata"
22488
+ ) ?? [],
22489
+ ...options.requiredDecisionMetadata ?? []
22490
+ ];
22491
+ if (requiredDecisionMetadata.length > 0) {
22492
+ rules.push(checks.requiredDecisionMetadata(requiredDecisionMetadata));
21662
22493
  }
21663
- if (detector.startsWith("value.") && (detector.includes("Token") || detector.includes("Key") || detector.includes("jwt") || detector.includes("authorization") || detector.includes("bearer") || detector.includes("cookie") || detector.includes("privateKey") || detector.includes("github") || detector.includes("aws") || detector.includes("provider"))) {
21664
- return { category: "credential", confidence: "high" };
22494
+ const contextOverlap = optionObject(evalConfig.contextOverlap);
22495
+ const minOverlap = parseNumber2(options.minContextOverlap, "--min-context-overlap");
22496
+ const minSharedTerms = parseNumber2(options.minSharedTerms, "--min-shared-terms");
22497
+ if (contextOverlap !== void 0 || options.contextOverlap || minOverlap !== void 0 || minSharedTerms !== void 0) {
22498
+ rules.push(checks.contextOverlap({ ...contextOverlap, minOverlap, minSharedTerms }));
21665
22499
  }
21666
- if (detector.startsWith("key.")) {
21667
- return { category: "credential", confidence: "medium" };
22500
+ const quoteOverlap = optionObject(evalConfig.quoteOverlap);
22501
+ if (quoteOverlap !== void 0 || options.quoteOverlap) {
22502
+ rules.push(checks.quoteOverlap(quoteOverlap));
21668
22503
  }
21669
- return { category: "credential", confidence: "medium" };
21670
- }
21671
- function redactionDetectorFindings(read, runId) {
21672
- const runs = runId === void 0 ? read.runs : read.runs.filter((run) => run.runId === runId);
21673
- const out = [];
21674
- for (const run of runs) {
21675
- for (const node of flattenNodes2(run.children)) {
21676
- const attrs = node.event.attributes;
21677
- if (attrs === void 0) continue;
21678
- const result = redact(attrs, { profile: "share" });
21679
- for (const finding of result.findings) {
21680
- if (finding.action === "keep") continue;
21681
- const taxonomy = classifyRedactionDetector(finding.detector);
21682
- out.push({
21683
- ruleId: "safety.redactDetector",
21684
- severity: detectorSeverity(finding),
21685
- status: finding.severity === "error" ? "fail" : "warning",
21686
- message: `Redaction detector ${finding.detector} matched ${finding.matchKind} at ${finding.path}.`,
21687
- expected: "redacted trace content",
21688
- actual: finding.detector,
21689
- evidence: [
21690
- {
21691
- runId: node.event.runId,
21692
- eventId: node.event.eventId,
21693
- ...node.event.parentId !== void 0 ? { parentId: node.event.parentId } : {},
21694
- kind: node.event.kind,
21695
- name: node.event.name,
21696
- ...node.event.status !== void 0 ? { status: node.event.status } : {},
21697
- path: `attributes.${finding.path.replace(/^\$\.?/, "")}`
21698
- }
21699
- ],
21700
- category: taxonomy.category,
21701
- confidence: taxonomy.confidence,
21702
- detector: finding.detector,
21703
- action: finding.action
21704
- });
21705
- }
21706
- }
22504
+ const citationPresence = optionObject(evalConfig.citationPresence);
22505
+ if (citationPresence !== void 0 || options.citationPresence) {
22506
+ rules.push(checks.citationPresence(citationPresence));
21707
22507
  }
21708
- return out.sort((a, b) => {
21709
- const aEvidence = a.evidence[0];
21710
- const bEvidence = b.evidence[0];
21711
- return (aEvidence?.runId ?? "").localeCompare(bEvidence?.runId ?? "") || (aEvidence?.eventId ?? "").localeCompare(bEvidence?.eventId ?? "") || (aEvidence?.path ?? "").localeCompare(bEvidence?.path ?? "") || a.message.localeCompare(b.message);
21712
- });
22508
+ const sourceIds = sourceIdsFromConfig(evalConfig.requiredSourceIds);
22509
+ const requiredSourceIds = [...sourceIds?.ids ?? [], ...options.requiredSourceId ?? []];
22510
+ if (requiredSourceIds.length > 0) {
22511
+ rules.push(checks.requiredSourceIds(requiredSourceIds, sourceIds?.options));
22512
+ }
22513
+ const cliAnswerLength = {
22514
+ minCharacters: parseNumber2(options.minAnswerCharacters, "--min-answer-characters"),
22515
+ maxCharacters: parseNumber2(options.maxAnswerCharacters, "--max-answer-characters"),
22516
+ minWords: parseNumber2(options.minAnswerWords, "--min-answer-words"),
22517
+ maxWords: parseNumber2(options.maxAnswerWords, "--max-answer-words")
22518
+ };
22519
+ const hasCliAnswerLength = Object.values(cliAnswerLength).some((value) => value !== void 0);
22520
+ if (evalConfig.answerLengthBounds !== void 0 || hasCliAnswerLength) {
22521
+ rules.push(checks.answerLengthBounds({ ...evalConfig.answerLengthBounds, ...cliAnswerLength }));
22522
+ }
22523
+ const bannedPhrases = [
22524
+ ...asStringArray3(
22525
+ evalConfig.bannedUnsupportedPhrases,
22526
+ "eval.bannedUnsupportedPhrases"
22527
+ ) ?? [],
22528
+ ...options.bannedPhrase ?? []
22529
+ ];
22530
+ if (bannedPhrases.length > 0) rules.push(checks.bannedUnsupportedPhrases(bannedPhrases));
22531
+ return rules.length > 0 ? rules : void 0;
21713
22532
  }
21714
22533
  function exitCodeFor3(result) {
21715
- if (result.status === "SAFE" || result.status === "SAFE WITH WARNINGS") return 0;
21716
- if (result.status === "UNSAFE") return 1;
22534
+ if (result.status === "pass") return 0;
22535
+ if (result.status === "fail") return 1;
21717
22536
  return 2;
21718
22537
  }
21719
- function explainFinding(finding, blocksBundle) {
21720
- const path43 = finding.evidence[0]?.path ?? "(unknown path)";
21721
- const category = finding.category ?? "structure";
21722
- const confidence = finding.confidence ?? "medium";
21723
- const detector = finding.detector ?? finding.ruleId;
21724
- const action = finding.action ?? "review";
21725
- const redactionHint = category === "credential" || category === "personal-data" || category === "raw-content" || action.includes("redact") ? "Usually removable by share/strict redaction before bundling." : "May require omitting the field, lowering limits, or an explicit local override.";
21726
- return [
21727
- ` Matched: detector=${detector}; path=${path43}; category=${category}`,
21728
- ` Why: ${finding.message}`,
21729
- ` Confidence: ${confidence}`,
21730
- ` Redaction: ${redactionHint}`,
21731
- ` Override: configure a custom redaction/detector rule locally (see docs/SAFETY-POLICY.md); do not weaken defaults globally.`,
21732
- ` Bundle gate: ${blocksBundle ? "blocks share-safe bundle unless --allow-unsafe" : "does not block by itself (warning/info)"}`
21733
- ];
22538
+ function stable5(value) {
22539
+ if (Array.isArray(value)) return value.map(stable5);
22540
+ if (value === null || typeof value !== "object") return value;
22541
+ const record = value;
22542
+ return Object.fromEntries(
22543
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable5(record[key])])
22544
+ );
21734
22545
  }
21735
- function findingExplanation(finding) {
21736
- const blocks = finding.severity === "error" || finding.status === "fail";
21737
- return {
21738
- ruleId: finding.ruleId,
21739
- detector: finding.detector ?? finding.ruleId,
21740
- path: finding.evidence[0]?.path,
21741
- category: finding.category,
21742
- confidence: finding.confidence,
21743
- action: finding.action,
21744
- blocksBundle: blocks,
21745
- // Never include matched secret/PII values.
21746
- message: finding.message
21747
- };
22546
+ function printJson3(result) {
22547
+ console.log(JSON.stringify(stable5(result), null, 2));
21748
22548
  }
21749
- function printHuman3(result, explain = false) {
21750
- console.log(`Safety status: ${result.status}`);
22549
+ function printHuman3(result) {
22550
+ console.log(`Eval status: ${result.status}`);
21751
22551
  console.log(`Format: ${result.format}`);
21752
22552
  if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
21753
- if (result.sourceAssessment !== void 0 && result.artifactAssessment !== void 0) {
21754
- console.log(`Source assessment: ${result.sourceAssessment.status}`);
21755
- console.log(`Artifact assessment: ${result.artifactAssessment.status}`);
21756
- if (result.redactionSummary !== void 0) {
21757
- console.log(
21758
- `Redaction: profile=${result.redactionSummary.profile}, findings=${result.redactionSummary.findings}`
21759
- );
21760
- }
21761
- }
21762
22553
  console.log(
21763
- `Summary: ${result.summary.findings} finding(s), ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
22554
+ `Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
21764
22555
  );
21765
22556
  for (const diagnostic7 of result.diagnostics) {
21766
22557
  console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
21767
22558
  }
21768
22559
  for (const finding of result.findings) {
21769
- const path43 = finding.evidence[0]?.path;
21770
- const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
21771
- console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}${taxonomy}`);
21772
- if (explain) {
21773
- const blocks = finding.severity === "error" || finding.status === "fail";
21774
- for (const line of explainFinding(finding, blocks)) {
21775
- console.log(line);
21776
- }
21777
- }
22560
+ const path44 = finding.evidence[0]?.path;
22561
+ console.log(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
21778
22562
  }
21779
- console.log(`Note: ${result.note}`);
21780
22563
  }
21781
- function printJson3(result, explain = false) {
21782
- const payload = explain === true ? { ...result, explanations: result.findings.map(findingExplanation) } : result;
21783
- console.log(JSON.stringify(stable5(payload), null, 2));
22564
+ function readErrorResult3(error) {
22565
+ if (error instanceof TraceReadError) {
22566
+ const code = error.code === "unsupported_format" ? "AI_EVAL_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_EVAL_AMBIGUOUS_FORMAT" : "AI_EVAL_TRACE_UNREADABLE";
22567
+ return errorResult4(code, error.message);
22568
+ }
22569
+ return errorResult4(
22570
+ "AI_EVAL_TRACE_UNREADABLE",
22571
+ error instanceof Error ? error.message : String(error)
22572
+ );
21784
22573
  }
21785
- async function safetyCommand(command, target, options, stdin) {
22574
+ async function evalCommand(target, options = {}, stdin = process.stdin) {
21786
22575
  let result;
22576
+ let phase = "config";
21787
22577
  try {
22578
+ const config = await loadConfig2(options.config);
22579
+ const rules = buildRules2(config, options);
22580
+ phase = "read";
21788
22581
  const input3 = await inputFromTarget(target, options, stdin);
21789
22582
  const read = await openTrace(input3, {
21790
22583
  ...options.format !== void 0 ? { format: options.format } : {}
21791
22584
  });
21792
- const source = assessOpenedTrace(read, {
21793
- ...options,
22585
+ result = await evalRun(read, {
22586
+ ...rules !== void 0 ? { checks: rules } : {},
21794
22587
  ...options.run !== void 0 ? { runId: options.run } : {}
21795
22588
  });
21796
- if (command === "scan") {
21797
- result = { ...source, command: "scan" };
22589
+ } catch (error) {
22590
+ if (phase === "config") {
22591
+ const message = error instanceof Error ? error.message : String(error);
22592
+ const code = message.startsWith("--") ? "AI_EVAL_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported eval config extension") || message.includes("TypeScript eval configs") || message.includes("Config must") || message.includes("eval config") || message.includes("must be an array") ? "AI_EVAL_INVALID_CONFIG" : "AI_EVAL_CONFIG_LOAD_FAILED";
22593
+ result = errorResult4(code, message);
21798
22594
  } else {
21799
- const profile = options.redactionProfile ?? "share";
21800
- const rawContent = input3.type === "string" ? input3.content : input3.type === "file" ? await promises.readFile(input3.path, "utf-8") : void 0;
21801
- if (rawContent === void 0) {
21802
- result = {
21803
- ...source,
21804
- command: "verify-safe",
21805
- sourceAssessment: layerFromResult(source)
21806
- };
21807
- } else {
21808
- const redacted = redactTraceContent(rawContent, profile);
21809
- const artifactRead = await openTrace(
21810
- { type: "string", content: redacted.content },
21811
- { format: options.format ?? "agent-inspect-jsonl" }
21812
- );
21813
- const artifact = assessOpenedTrace(artifactRead, {
21814
- ...options,
21815
- ...options.run !== void 0 ? { runId: options.run } : {}
21816
- });
21817
- const detectors = [
21818
- ...new Set(redacted.findings.map((finding) => finding.detector))
21819
- ].sort((a, b) => a.localeCompare(b));
21820
- result = resultFromParts({
21821
- command: "verify-safe",
21822
- format: artifact.format,
21823
- runId: artifact.runId ?? source.runId,
21824
- findings: artifact.findings,
21825
- diagnostics: artifact.diagnostics,
21826
- warnings: artifact.warnings,
21827
- unsupportedFields: artifact.unsupportedFields,
21828
- status: artifact.status,
21829
- sourceAssessment: layerFromResult(source),
21830
- artifactAssessment: layerFromResult(artifact),
21831
- redactionSummary: {
21832
- profile,
21833
- findings: redacted.findings.length,
21834
- detectors
21835
- }
21836
- });
21837
- }
22595
+ result = readErrorResult3(error);
21838
22596
  }
21839
- } catch (error) {
21840
- const message = error instanceof Error ? error.message : String(error);
21841
- result = message.startsWith("--") ? invalidArgumentResult(command, error) : readErrorResult3(command, error);
21842
22597
  }
21843
22598
  process.exitCode = exitCodeFor3(result);
21844
- if (options.json) printJson3(result, options.explain === true);
21845
- else printHuman3(result, options.explain === true);
21846
- }
21847
- function scanCommand(target, options = {}, stdin = process.stdin) {
21848
- return safetyCommand("scan", target, options, stdin);
21849
- }
21850
- function verifySafeCommand(target, options = {}, stdin = process.stdin) {
21851
- return safetyCommand("verify-safe", target, options, stdin);
21852
- }
21853
- function assessOpenedTrace(read, options = {}) {
21854
- try {
21855
- const rules = buildSafetyRules(options);
21856
- const checkResult = runTraceChecks(
21857
- { read },
21858
- {
21859
- rules,
21860
- ...options.runId !== void 0 ? { runId: options.runId } : {},
21861
- ...options.run !== void 0 ? { runId: options.run } : {}
21862
- }
21863
- );
21864
- const detectorFindings = checkResult.diagnostics.length === 0 ? redactionDetectorFindings(read, checkResult.runId) : [];
21865
- return resultFromParts({
21866
- command: "verify-safe",
21867
- format: checkResult.format,
21868
- runId: checkResult.runId,
21869
- findings: [...checkResult.findings, ...detectorFindings],
21870
- diagnostics: [
21871
- ...checkResult.diagnostics.map(diagnosticFromCheck),
21872
- ...warningDiagnostics(read.warnings, read.unsupportedFields)
21873
- ],
21874
- warnings: read.warnings,
21875
- unsupportedFields: read.unsupportedFields
21876
- });
21877
- } catch (error) {
21878
- return messageStartsWithDash(error) ? invalidArgumentResult("verify-safe", error) : readErrorResult3("verify-safe", error);
21879
- }
21880
- }
21881
- function messageStartsWithDash(error) {
21882
- const message = error instanceof Error ? error.message : String(error);
21883
- return message.startsWith("--");
22599
+ if (options.json) printJson3(result);
22600
+ else if (options.markdown) console.log(renderEvalMarkdown(result).trimEnd());
22601
+ else printHuman3(result);
21884
22602
  }
21885
22603
  init_advanced();
21886
22604
  var NOTE = "Generated locally by AgentInspect. Artifacts are best-effort summaries, not compliance or security certification.";
@@ -21956,8 +22674,8 @@ function renderCheckSection(result) {
21956
22674
  `Diagnostics: ${result.diagnostics.length}`
21957
22675
  ];
21958
22676
  for (const finding of result.findings.slice(0, 10)) {
21959
- const path43 = finding.evidence[0]?.path ?? "(run)";
21960
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path43})`);
22677
+ const path44 = finding.evidence[0]?.path ?? "(run)";
22678
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path44})`);
21961
22679
  }
21962
22680
  for (const diagnostic7 of result.diagnostics.slice(0, 10)) {
21963
22681
  lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
@@ -22035,8 +22753,8 @@ function renderHtml(trace, check, diff) {
22035
22753
  `;
22036
22754
  }
22037
22755
  async function writeArtifact(outputDir, relativePath, content, files) {
22038
- const outPath = path32__default.default.join(outputDir, relativePath);
22039
- await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
22756
+ const outPath = path33__default.default.join(outputDir, relativePath);
22757
+ await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
22040
22758
  await promises.writeFile(outPath, content, "utf-8");
22041
22759
  files.push(relativePath);
22042
22760
  }
@@ -22065,7 +22783,7 @@ function shouldWriteEvidence(options, status) {
22065
22783
  return status === "unsafe" || status === "regression" || status === "unknown" || status === "warning";
22066
22784
  }
22067
22785
  async function artifactsCommand(target, options = {}, stdin = process.stdin) {
22068
- const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path32__default.default.resolve(options.outputDir.trim()) : "";
22786
+ const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path33__default.default.resolve(options.outputDir.trim()) : "";
22069
22787
  if (outputDir === "") {
22070
22788
  console.error("--output-dir is required.");
22071
22789
  process.exitCode = 1;
@@ -22179,7 +22897,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
22179
22897
  finishedToolNames: [...parity.finishedToolNames],
22180
22898
  pairedCount: parity.pairedCount,
22181
22899
  parentRemapCount: parity.parentRemapCount,
22182
- contractStatus: check.status === "pass" ? "pass" : check.status === "fail" ? "fail" : "error"
22900
+ contractStatus: check.status === "pass" ? "pass" : check.status === "fail" ? "fail" : "error",
22901
+ ...parity.failureRoleCounts !== void 0 ? { failureRoleCounts: { ...parity.failureRoleCounts } } : {}
22183
22902
  }
22184
22903
  });
22185
22904
  await writeArtifact(outputDir, "evidence.html", evidencePackage["evidence.html"], files);
@@ -22205,8 +22924,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
22205
22924
  }
22206
22925
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
22207
22926
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
22208
- await promises.mkdir(path32__default.default.dirname(path32__default.default.resolve(summaryTarget)), { recursive: true });
22209
- await promises.appendFile(path32__default.default.resolve(summaryTarget), `
22927
+ await promises.mkdir(path33__default.default.dirname(path33__default.default.resolve(summaryTarget)), { recursive: true });
22928
+ await promises.appendFile(path33__default.default.resolve(summaryTarget), `
22210
22929
  ${renderMarkdown(trace, check, diff)}`, "utf-8");
22211
22930
  }
22212
22931
  const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
@@ -22225,10 +22944,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
22225
22944
  findings: diff?.findings.length ?? 0,
22226
22945
  diagnostics: diff?.diagnostics.length ?? 0
22227
22946
  },
22228
- ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path32__default.default.resolve(summaryTarget) } : {},
22947
+ ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path33__default.default.resolve(summaryTarget) } : {},
22229
22948
  note: NOTE
22230
22949
  };
22231
- await promises.writeFile(path32__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
22950
+ await promises.writeFile(path33__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
22232
22951
  if (options.json === true) {
22233
22952
  console.log(writeJson3(manifest).trimEnd());
22234
22953
  } else {
@@ -22289,8 +23008,8 @@ async function resolveOutputDir(options, runIds, cwd, format) {
22289
23008
  const location = resolveWorkspaceLocation(cwd);
22290
23009
  const manifest = await readWorkspaceManifestFile(location);
22291
23010
  if (manifest.ok && manifest.manifest) {
22292
- const rel = path32__default.default.relative(location.workspaceDir, normalized);
22293
- if (!rel.startsWith("..") && !path32__default.default.isAbsolute(rel)) {
23011
+ const rel = path33__default.default.relative(location.workspaceDir, normalized);
23012
+ if (!rel.startsWith("..") && !path33__default.default.isAbsolute(rel)) {
22294
23013
  return resolveInsideWorkspace(location.workspaceDir, rel);
22295
23014
  }
22296
23015
  }
@@ -22306,7 +23025,7 @@ async function resolveOutputDir(options, runIds, cwd, format) {
22306
23025
  const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
22307
23026
  const base2 = resolveInsideWorkspace(
22308
23027
  location.workspaceDir,
22309
- path32__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
23028
+ path33__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
22310
23029
  );
22311
23030
  return format === "zip" ? `${base2}.zip` : base2;
22312
23031
  }
@@ -22711,19 +23430,19 @@ async function bundleCommand(runIdArg, options = {}) {
22711
23430
  let sidecarDir = outputDir;
22712
23431
  if (outputDir.toLowerCase().endsWith(".html")) {
22713
23432
  htmlPath = outputDir;
22714
- sidecarDir = path32__default.default.dirname(outputDir);
23433
+ sidecarDir = path33__default.default.dirname(outputDir);
22715
23434
  } else {
22716
23435
  await promises.mkdir(outputDir, { recursive: true });
22717
- htmlPath = path32__default.default.join(outputDir, EVIDENCE_HTML_FILENAME);
23436
+ htmlPath = path33__default.default.join(outputDir, EVIDENCE_HTML_FILENAME);
22718
23437
  sidecarDir = outputDir;
22719
23438
  }
22720
23439
  await promises.mkdir(sidecarDir, { recursive: true });
22721
23440
  await promises.writeFile(htmlPath, htmlContent, "utf-8");
22722
- await promises.writeFile(path32__default.default.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
23441
+ await promises.writeFile(path33__default.default.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
22723
23442
  outputPath = htmlPath;
22724
23443
  } else if (format === "zip") {
22725
23444
  const zipPath = outputDir.toLowerCase().endsWith(".zip") ? outputDir : `${outputDir}.zip`;
22726
- const zipParent = path32__default.default.dirname(zipPath);
23445
+ const zipParent = path33__default.default.dirname(zipPath);
22727
23446
  await promises.mkdir(zipParent, { recursive: true });
22728
23447
  const entries = [
22729
23448
  ...[...packaged.entries()].map(([relativePath, content]) => ({
@@ -22739,10 +23458,10 @@ async function bundleCommand(runIdArg, options = {}) {
22739
23458
  await promises.mkdir(outputDir, { recursive: true });
22740
23459
  for (const [relativePath, content] of packaged.entries()) {
22741
23460
  const outPath = assertBundlePathContained(outputDir, relativePath);
22742
- await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
23461
+ await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
22743
23462
  await promises.writeFile(outPath, content, "utf-8");
22744
23463
  }
22745
- await promises.writeFile(path32__default.default.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
23464
+ await promises.writeFile(path33__default.default.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
22746
23465
  if (!files.includes(EVIDENCE_MANIFEST_FILENAME)) {
22747
23466
  files.push(EVIDENCE_MANIFEST_FILENAME);
22748
23467
  }
@@ -22791,7 +23510,7 @@ function writeJson5(value) {
22791
23510
  `;
22792
23511
  }
22793
23512
  async function bundleVerifyCommand(targetPath, options = {}) {
22794
- const root = path32__default.default.resolve(targetPath.trim() || ".");
23513
+ const root = path33__default.default.resolve(targetPath.trim() || ".");
22795
23514
  const result = await verifyEvidenceDirectory(root, {
22796
23515
  unexpectedFiles: options.unexpected ?? "fail"
22797
23516
  });
@@ -22833,7 +23552,7 @@ function writeJson6(value) {
22833
23552
  }
22834
23553
  async function resolveHtmlPath(root) {
22835
23554
  const candidates = [
22836
- path32__default.default.join(root, "evidence.html"),
23555
+ path33__default.default.join(root, "evidence.html"),
22837
23556
  root.toLowerCase().endsWith(".html") ? root : ""
22838
23557
  ].filter(Boolean);
22839
23558
  for (const candidate of candidates) {
@@ -22848,7 +23567,7 @@ async function resolveHtmlPath(root) {
22848
23567
  );
22849
23568
  }
22850
23569
  async function bundleOpenCommand(targetPath, options = {}) {
22851
- const root = path32__default.default.resolve(targetPath.trim() || ".");
23570
+ const root = path33__default.default.resolve(targetPath.trim() || ".");
22852
23571
  try {
22853
23572
  await promises.access(root);
22854
23573
  } catch {
@@ -22865,7 +23584,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
22865
23584
  try {
22866
23585
  const info = await promises.stat(root);
22867
23586
  if (info.isFile() && root.toLowerCase().endsWith(".html")) {
22868
- verifyRoot = path32__default.default.dirname(root);
23587
+ verifyRoot = path33__default.default.dirname(root);
22869
23588
  }
22870
23589
  } catch {
22871
23590
  }
@@ -22897,7 +23616,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
22897
23616
  let htmlPath;
22898
23617
  try {
22899
23618
  htmlPath = await resolveHtmlPath(
22900
- root.toLowerCase().endsWith(".html") ? path32__default.default.dirname(root) : root
23619
+ root.toLowerCase().endsWith(".html") ? path33__default.default.dirname(root) : root
22901
23620
  );
22902
23621
  if (root.toLowerCase().endsWith(".html")) {
22903
23622
  htmlPath = root;
@@ -22913,7 +23632,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
22913
23632
  return;
22914
23633
  }
22915
23634
  try {
22916
- await promises.readFile(path32__default.default.join(path32__default.default.dirname(htmlPath), "evidence.json"), "utf-8");
23635
+ await promises.readFile(path33__default.default.join(path33__default.default.dirname(htmlPath), "evidence.json"), "utf-8");
22917
23636
  } catch {
22918
23637
  }
22919
23638
  const fileUrl = url.pathToFileURL(htmlPath).href;
@@ -22999,24 +23718,24 @@ function resolveTargetPath(client, projectLocal) {
22999
23718
  if (projectLocal) {
23000
23719
  switch (client) {
23001
23720
  case "cursor":
23002
- return path32__default.default.join(".cursor", "mcp.json");
23721
+ return path33__default.default.join(".cursor", "mcp.json");
23003
23722
  case "claude-code":
23004
- return path32__default.default.join(".mcp.json");
23723
+ return path33__default.default.join(".mcp.json");
23005
23724
  case "codex":
23006
- return path32__default.default.join(".codex", "config.toml.json");
23725
+ return path33__default.default.join(".codex", "config.toml.json");
23007
23726
  case "gemini":
23008
- return path32__default.default.join(".gemini", "settings.json");
23727
+ return path33__default.default.join(".gemini", "settings.json");
23009
23728
  }
23010
23729
  }
23011
23730
  switch (client) {
23012
23731
  case "cursor":
23013
- return path32__default.default.join("~", ".cursor", "mcp.json");
23732
+ return path33__default.default.join("~", ".cursor", "mcp.json");
23014
23733
  case "claude-code":
23015
- return path32__default.default.join("~", ".claude.json");
23734
+ return path33__default.default.join("~", ".claude.json");
23016
23735
  case "codex":
23017
- return path32__default.default.join("~", ".codex", "config.toml");
23736
+ return path33__default.default.join("~", ".codex", "config.toml");
23018
23737
  case "gemini":
23019
- return path32__default.default.join("~", ".gemini", "settings.json");
23738
+ return path33__default.default.join("~", ".gemini", "settings.json");
23020
23739
  }
23021
23740
  }
23022
23741
  async function mcpConfigureCommand(options) {
@@ -23040,8 +23759,8 @@ async function mcpConfigureCommand(options) {
23040
23759
  ];
23041
23760
  let wrote = false;
23042
23761
  if (!dryRun && projectLocal) {
23043
- const abs = path32__default.default.resolve(targetPath);
23044
- await promises.mkdir(path32__default.default.dirname(abs), { recursive: true });
23762
+ const abs = path33__default.default.resolve(targetPath);
23763
+ await promises.mkdir(path33__default.default.dirname(abs), { recursive: true });
23045
23764
  await promises.writeFile(abs, `${JSON.stringify(config, null, 2)}
23046
23765
  `, "utf8");
23047
23766
  wrote = true;
@@ -23201,23 +23920,23 @@ function readManifestDocument(value) {
23201
23920
  };
23202
23921
  }
23203
23922
  function cwdRelative(filePath) {
23204
- const relative = path32__default.default.relative(process.cwd(), path32__default.default.resolve(filePath)).replace(/\\/g, "/");
23205
- if (relative === "" || relative.startsWith("../") || path32__default.default.isAbsolute(relative)) {
23206
- return path32__default.default.basename(filePath);
23923
+ const relative = path33__default.default.relative(process.cwd(), path33__default.default.resolve(filePath)).replace(/\\/g, "/");
23924
+ if (relative === "" || relative.startsWith("../") || path33__default.default.isAbsolute(relative)) {
23925
+ return path33__default.default.basename(filePath);
23207
23926
  }
23208
23927
  return relative;
23209
23928
  }
23210
23929
  async function readReporterManifest(filePath) {
23211
- const absolute = path32__default.default.resolve(filePath);
23930
+ const absolute = path33__default.default.resolve(filePath);
23212
23931
  const raw = await promises.readFile(absolute, "utf-8");
23213
23932
  const document = readManifestDocument(JSON.parse(raw));
23214
23933
  const manifest = document.manifest;
23215
23934
  const results = manifest.results.map((result) => ({
23216
23935
  testId: safeText(result.testId),
23217
23936
  name: safeText(result.name),
23218
- ...result.file === void 0 ? {} : { file: safeText(path32__default.default.basename(result.file)) },
23937
+ ...result.file === void 0 ? {} : { file: safeText(path33__default.default.basename(result.file)) },
23219
23938
  status: result.status,
23220
- ...result.tracePath === void 0 ? {} : { tracePath: safeText(path32__default.default.basename(result.tracePath)) },
23939
+ ...result.tracePath === void 0 ? {} : { tracePath: safeText(path33__default.default.basename(result.tracePath)) },
23221
23940
  artifacts: result.artifacts,
23222
23941
  diagnostics: result.diagnostics
23223
23942
  }));
@@ -23356,15 +24075,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
23356
24075
  return;
23357
24076
  }
23358
24077
  const markdown = renderMarkdown2(result);
23359
- const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path32__default.default.resolve(options.output.trim()) : void 0;
24078
+ const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path33__default.default.resolve(options.output.trim()) : void 0;
23360
24079
  if (outputPath !== void 0) {
23361
- await promises.mkdir(path32__default.default.dirname(outputPath), { recursive: true });
24080
+ await promises.mkdir(path33__default.default.dirname(outputPath), { recursive: true });
23362
24081
  await promises.writeFile(outputPath, markdown, "utf-8");
23363
24082
  }
23364
24083
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
23365
24084
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
23366
- const summaryPath = path32__default.default.resolve(summaryTarget);
23367
- await promises.mkdir(path32__default.default.dirname(summaryPath), { recursive: true });
24085
+ const summaryPath = path33__default.default.resolve(summaryTarget);
24086
+ await promises.mkdir(path33__default.default.dirname(summaryPath), { recursive: true });
23368
24087
  await promises.appendFile(summaryPath, `
23369
24088
  ${markdown}`, "utf-8");
23370
24089
  }
@@ -23549,7 +24268,7 @@ jobs:
23549
24268
  }
23550
24269
  async function planInit(options = {}) {
23551
24270
  const framework = normalizeFramework(options.framework);
23552
- const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
24271
+ const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
23553
24272
  const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
23554
24273
  const candidates = [
23555
24274
  { rel: CONFIG_FILE, content: configTemplate(framework) },
@@ -23564,7 +24283,7 @@ async function planInit(options = {}) {
23564
24283
  }
23565
24284
  const files = [];
23566
24285
  for (const candidate of candidates) {
23567
- const abs = path32__default.default.join(cwd, candidate.rel);
24286
+ const abs = path33__default.default.join(cwd, candidate.rel);
23568
24287
  try {
23569
24288
  await promises.access(abs);
23570
24289
  files.push({
@@ -23585,12 +24304,12 @@ async function writePlannedFiles(plan, cwd, options) {
23585
24304
  if (entry.action === "skip") {
23586
24305
  continue;
23587
24306
  }
23588
- const abs = path32__default.default.join(cwd, entry.path);
24307
+ const abs = path33__default.default.join(cwd, entry.path);
23589
24308
  if (options.dryRun) {
23590
24309
  written.push(entry.path);
23591
24310
  continue;
23592
24311
  }
23593
- await promises.mkdir(path32__default.default.dirname(abs), { recursive: true });
24312
+ await promises.mkdir(path33__default.default.dirname(abs), { recursive: true });
23594
24313
  const demoPath = plan.framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${plan.framework}-demo.mjs`;
23595
24314
  const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate(demoPath) : demoTemplate(plan.framework);
23596
24315
  await promises.writeFile(abs, content, "utf-8");
@@ -23599,7 +24318,7 @@ async function writePlannedFiles(plan, cwd, options) {
23599
24318
  return written;
23600
24319
  }
23601
24320
  async function initCommand(options = {}) {
23602
- const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
24321
+ const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
23603
24322
  try {
23604
24323
  const plan = await planInit({ ...options, cwd });
23605
24324
  const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
@@ -23694,7 +24413,7 @@ function envCheck(name, optional = true) {
23694
24413
  };
23695
24414
  }
23696
24415
  async function traceDirWritable(traceDir) {
23697
- const resolved = path32__default.default.resolve(traceDir);
24416
+ const resolved = path33__default.default.resolve(traceDir);
23698
24417
  try {
23699
24418
  await promises.mkdir(resolved, { recursive: true });
23700
24419
  await promises.access(resolved, promises.constants.W_OK);
@@ -23715,10 +24434,10 @@ async function traceDirWritable(traceDir) {
23715
24434
  }
23716
24435
  }
23717
24436
  function readPackageVersionNearEntry(entryPath, packageName) {
23718
- let dir = path32__default.default.dirname(path32__default.default.resolve(entryPath));
23719
- const { root } = path32__default.default.parse(dir);
24437
+ let dir = path33__default.default.dirname(path33__default.default.resolve(entryPath));
24438
+ const { root } = path33__default.default.parse(dir);
23720
24439
  while (true) {
23721
- const candidate = path32__default.default.join(dir, "package.json");
24440
+ const candidate = path33__default.default.join(dir, "package.json");
23722
24441
  if (fs.existsSync(candidate)) {
23723
24442
  try {
23724
24443
  const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
@@ -23729,14 +24448,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
23729
24448
  }
23730
24449
  }
23731
24450
  if (dir === root) break;
23732
- const parent = path32__default.default.dirname(dir);
24451
+ const parent = path33__default.default.dirname(dir);
23733
24452
  if (parent === dir) break;
23734
24453
  dir = parent;
23735
24454
  }
23736
24455
  return void 0;
23737
24456
  }
23738
24457
  function resolveInstalledPackage(cwd, name) {
23739
- const require2 = module$1.createRequire(path32__default.default.join(cwd, "package.json"));
24458
+ const require2 = module$1.createRequire(path33__default.default.join(cwd, "package.json"));
23740
24459
  try {
23741
24460
  const entry = require2.resolve(name);
23742
24461
  let version2;
@@ -23834,7 +24553,7 @@ function versionMismatchCheck(cwd) {
23834
24553
  };
23835
24554
  }
23836
24555
  async function runDoctorChecks(options = {}) {
23837
- const cwd = path32__default.default.resolve(options.cwd ?? process3__default.default.cwd());
24556
+ const cwd = path33__default.default.resolve(options.cwd ?? process3__default.default.cwd());
23838
24557
  const traceDir = options.traceDir?.trim() || process3__default.default.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
23839
24558
  const checks2 = [
23840
24559
  nodeVersionCheck(),
@@ -24074,7 +24793,7 @@ function parsePluginManifest(input3) {
24074
24793
  };
24075
24794
  }
24076
24795
  async function readPluginManifestFile(packageDir) {
24077
- const manifestPath = path32__default.default.join(packageDir, PLUGIN_MANIFEST_FILENAME);
24796
+ const manifestPath = path33__default.default.join(packageDir, PLUGIN_MANIFEST_FILENAME);
24078
24797
  try {
24079
24798
  const raw = await promises.readFile(manifestPath, "utf8");
24080
24799
  const parsed = parsePluginManifest(JSON.parse(raw));
@@ -24149,7 +24868,7 @@ function createTraceDirectoryIndexer() {
24149
24868
  // packages/cli/src/plugins.ts
24150
24869
  async function readPackageName(packageDir) {
24151
24870
  try {
24152
- const raw = await promises.readFile(path32__default.default.join(packageDir, "package.json"), "utf8");
24871
+ const raw = await promises.readFile(path33__default.default.join(packageDir, "package.json"), "utf8");
24153
24872
  const parsed = JSON.parse(raw);
24154
24873
  return typeof parsed.name === "string" ? parsed.name : void 0;
24155
24874
  } catch {
@@ -24157,7 +24876,7 @@ async function readPackageName(packageDir) {
24157
24876
  }
24158
24877
  }
24159
24878
  async function discoverPlugins(cwd = process.cwd()) {
24160
- const nodeModules = path32__default.default.join(cwd, "node_modules");
24879
+ const nodeModules = path33__default.default.join(cwd, "node_modules");
24161
24880
  const found = [];
24162
24881
  let entries;
24163
24882
  try {
@@ -24168,7 +24887,7 @@ async function discoverPlugins(cwd = process.cwd()) {
24168
24887
  for (const entry of entries.sort()) {
24169
24888
  if (entry.startsWith("@")) continue;
24170
24889
  if (!isPluginPackageName(entry)) continue;
24171
- const packageDir = path32__default.default.join(nodeModules, entry);
24890
+ const packageDir = path33__default.default.join(nodeModules, entry);
24172
24891
  const manifestRead = await readPluginManifestFile(packageDir);
24173
24892
  found.push({
24174
24893
  packageName: entry,
@@ -24181,7 +24900,7 @@ async function discoverPlugins(cwd = process.cwd()) {
24181
24900
  return found;
24182
24901
  }
24183
24902
  async function validatePluginPackage(packageRef, cwd = process.cwd()) {
24184
- const packageDir = path32__default.default.isAbsolute(packageRef) ? packageRef : path32__default.default.join(cwd, "node_modules", packageRef);
24903
+ const packageDir = path33__default.default.isAbsolute(packageRef) ? packageRef : path33__default.default.join(cwd, "node_modules", packageRef);
24185
24904
  const packageName = await readPackageName(packageDir) ?? packageRef;
24186
24905
  const errors = [];
24187
24906
  const warnings = [];
@@ -24258,7 +24977,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
24258
24977
  init_advanced();
24259
24978
  var INDEX_FILENAME = ".agent-inspect-index.json";
24260
24979
  function traceIndexPath(traceDir) {
24261
- return path32__default.default.join(traceDir, INDEX_FILENAME);
24980
+ return path33__default.default.join(traceDir, INDEX_FILENAME);
24262
24981
  }
24263
24982
  function parseMaxEntries(raw) {
24264
24983
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -24404,7 +25123,7 @@ async function newestTraceMtimeMs2(traceDir) {
24404
25123
  for (const file of files) {
24405
25124
  if (!file.endsWith(".jsonl")) continue;
24406
25125
  try {
24407
- const s = await promises.stat(path32__default.default.join(traceDir, file));
25126
+ const s = await promises.stat(path33__default.default.join(traceDir, file));
24408
25127
  if (s.mtimeMs > newest) newest = s.mtimeMs;
24409
25128
  } catch {
24410
25129
  }
@@ -24659,11 +25378,11 @@ function printJson5(value) {
24659
25378
  console.log(JSON.stringify(value, null, 2));
24660
25379
  }
24661
25380
  function resolveCwd(options) {
24662
- return path32__default.default.resolve(options.cwd ?? process.cwd());
25381
+ return path33__default.default.resolve(options.cwd ?? process.cwd());
24663
25382
  }
24664
25383
  async function suiteInitCommand(options = {}) {
24665
25384
  const cwd = resolveCwd(options);
24666
- const configPath = path32__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
25385
+ const configPath = path33__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
24667
25386
  const template = options.template?.trim();
24668
25387
  const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
24669
25388
  if (options.dryRun) {
@@ -24782,13 +25501,13 @@ async function suiteListCommand(options = {}) {
24782
25501
  }
24783
25502
  async function writeSuiteArtifact(result, configOutputDir, options) {
24784
25503
  const cwd = resolveCwd(options);
24785
- const outputDir = path32__default.default.resolve(
25504
+ const outputDir = path33__default.default.resolve(
24786
25505
  cwd,
24787
25506
  options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
24788
25507
  );
24789
25508
  await promises.mkdir(outputDir, { recursive: true });
24790
25509
  const stamp = result.startedAt.replace(/[:.]/g, "-");
24791
- const filePath = path32__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
25510
+ const filePath = path33__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
24792
25511
  await promises.writeFile(filePath, `${JSON.stringify(result, null, 2)}
24793
25512
  `, "utf-8");
24794
25513
  return filePath;
@@ -24846,7 +25565,7 @@ async function loadSuiteResultFromInput(options) {
24846
25565
  if (options.input === void 0 || options.input.trim() === "") {
24847
25566
  throw new Error("Pass --input <suite-run.json> from a prior suite run.");
24848
25567
  }
24849
- const inputPath = path32__default.default.resolve(cwd, options.input.trim());
25568
+ const inputPath = path33__default.default.resolve(cwd, options.input.trim());
24850
25569
  const raw = await promises.readFile(inputPath, "utf-8");
24851
25570
  return JSON.parse(raw);
24852
25571
  }
@@ -24889,9 +25608,9 @@ function normalizeMetrics2(raw) {
24889
25608
  }
24890
25609
  async function writeArtifacts(result, outputDir) {
24891
25610
  await promises.mkdir(outputDir, { recursive: true });
24892
- const jsonPath = path32__default.default.join(outputDir, "cohort-results.json");
24893
- const markdownPath = path32__default.default.join(outputDir, "cohort-summary.md");
24894
- const htmlPath = path32__default.default.join(outputDir, "cohort-report.html");
25611
+ const jsonPath = path33__default.default.join(outputDir, "cohort-results.json");
25612
+ const markdownPath = path33__default.default.join(outputDir, "cohort-summary.md");
25613
+ const htmlPath = path33__default.default.join(outputDir, "cohort-report.html");
24895
25614
  await promises.writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
24896
25615
  `, "utf-8");
24897
25616
  await promises.writeFile(
@@ -24920,7 +25639,7 @@ async function cohortCommand(options = {}) {
24920
25639
  const format = options.format ?? (options.json ? "json" : "markdown");
24921
25640
  let artifacts;
24922
25641
  if (options.output !== void 0 && options.output.trim() !== "") {
24923
- artifacts = await writeArtifacts(result, path32__default.default.resolve(options.output.trim()));
25642
+ artifacts = await writeArtifacts(result, path33__default.default.resolve(options.output.trim()));
24924
25643
  }
24925
25644
  if (options.json || format === "json") {
24926
25645
  console.log(
@@ -24993,11 +25712,11 @@ function parseDuration2(value) {
24993
25712
  async function writeArtifacts2(result, outputDir) {
24994
25713
  await promises.mkdir(outputDir, { recursive: true });
24995
25714
  const paths = {
24996
- jsonPath: path32__default.default.join(outputDir, "gate-results.json"),
24997
- markdownPath: path32__default.default.join(outputDir, "gate-summary.md"),
24998
- htmlPath: path32__default.default.join(outputDir, "gate-report.html"),
24999
- junitPath: path32__default.default.join(outputDir, "junit.xml"),
25000
- githubPath: path32__default.default.join(outputDir, "github-step-summary.md")
25715
+ jsonPath: path33__default.default.join(outputDir, "gate-results.json"),
25716
+ markdownPath: path33__default.default.join(outputDir, "gate-summary.md"),
25717
+ htmlPath: path33__default.default.join(outputDir, "gate-report.html"),
25718
+ junitPath: path33__default.default.join(outputDir, "junit.xml"),
25719
+ githubPath: path33__default.default.join(outputDir, "github-step-summary.md")
25001
25720
  };
25002
25721
  await promises.writeFile(
25003
25722
  paths.jsonPath,
@@ -25065,7 +25784,7 @@ async function gateCommand(options = {}) {
25065
25784
  const result = await runGate(runs, gateOptions);
25066
25785
  let artifacts;
25067
25786
  if (options.output !== void 0 && options.output.trim() !== "") {
25068
- artifacts = await writeArtifacts2(result, path32__default.default.resolve(options.output.trim()));
25787
+ artifacts = await writeArtifacts2(result, path33__default.default.resolve(options.output.trim()));
25069
25788
  }
25070
25789
  const failed = !result.ok;
25071
25790
  if (shouldEmitEvidence(options.evidenceOn, failed)) {
@@ -25372,7 +26091,7 @@ function createCliProgram() {
25372
26091
  "openinference-json",
25373
26092
  "otlp-json"
25374
26093
  ])
25375
- ).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--json", "print deterministic JSON safety result").option("--explain", "explain each finding (path, confidence, redaction, override, bundle gate)").option("--max-string-length <number>", "unsafe threshold for string values").option("--max-array-length <number>", "unsafe threshold for array values").option("--max-object-keys <number>", "unsafe threshold for object key counts").option("--max-serialized-bytes <number>", "unsafe threshold for serialized values").action((target, opts) => {
26094
+ ).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--json", "print deterministic JSON safety result").option("--explain", "explain each finding (path, confidence, redaction, override, bundle gate)").option("--max-string-length <number>", "unsafe threshold for string values").option("--max-array-length <number>", "unsafe threshold for array values").option("--max-object-keys <number>", "unsafe threshold for object key counts").option("--max-serialized-bytes <number>", "unsafe threshold for serialized values").option("--policy <path>", "local JSON redaction policy (extraKeys + bounded patterns)").action((target, opts) => {
25376
26095
  runCommand(() => scanCommand(target, opts));
25377
26096
  });
25378
26097
  program.command("verify-safe").description("Best-effort local trace safety verification").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").option("--dir <path>", "trace directory for run-id lookup").addOption(
@@ -25381,7 +26100,7 @@ function createCliProgram() {
25381
26100
  "openinference-json",
25382
26101
  "otlp-json"
25383
26102
  ])
25384
- ).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--json", "print deterministic JSON safety result").option("--explain", "explain each finding (path, confidence, redaction, override, bundle gate)").option("--max-string-length <number>", "unsafe threshold for string values").option("--max-array-length <number>", "unsafe threshold for array values").option("--max-object-keys <number>", "unsafe threshold for object key counts").option("--max-serialized-bytes <number>", "unsafe threshold for serialized values").action((target, opts) => {
26103
+ ).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--json", "print deterministic JSON safety result").option("--explain", "explain each finding (path, confidence, redaction, override, bundle gate)").option("--max-string-length <number>", "unsafe threshold for string values").option("--max-array-length <number>", "unsafe threshold for array values").option("--max-object-keys <number>", "unsafe threshold for object key counts").option("--max-serialized-bytes <number>", "unsafe threshold for serialized values").option("--policy <path>", "local JSON redaction policy (extraKeys + bounded patterns)").action((target, opts) => {
25385
26104
  runCommand(() => verifySafeCommand(target, opts));
25386
26105
  });
25387
26106
  program.command("artifacts").description("Create safe local CI trace artifacts").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").requiredOption("--output-dir <path>", "directory for generated artifacts").option("--dir <path>", "trace directory for run-id lookup").addOption(
@@ -25541,7 +26260,10 @@ function createCliProgram() {
25541
26260
  "--redaction-profile <profile>",
25542
26261
  "alias for --profile (canonical spelling)"
25543
26262
  ).choices(["local", "share", "strict"])
25544
- ).option("-o, --output <path>", "write redacted content to a file").option("--out <path>", "alias for --output").option("--json", "print deterministic JSON wrapper with findings").action((target, opts) => {
26263
+ ).option("-o, --output <path>", "write redacted content to a file").option("--out <path>", "alias for --output").option("--json", "print deterministic JSON wrapper with findings").option("--policy <path>", "local JSON redaction policy (extraKeys + bounded patterns)").option(
26264
+ "--fail-on-residual",
26265
+ "exit non-zero when residual safety is UNSAFE or UNKNOWN (opt-in)"
26266
+ ).action((target, opts) => {
25545
26267
  runCommand(() => redactCommand(target, opts));
25546
26268
  });
25547
26269
  program.command("explain").description("Explain a local trace with deterministic facts (no provider calls)").argument("<trace-path-or-run-id>", "trace file, directory, stdin -, or run id").option("--dir <path>", "trace directory for run-id lookup").addOption(
@@ -25723,9 +26445,9 @@ function isPrimaryModule() {
25723
26445
  if (!entry) return false;
25724
26446
  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)));
25725
26447
  try {
25726
- return fs.realpathSync(path32__default.default.resolve(entry)) === fs.realpathSync(path32__default.default.resolve(selfPath));
26448
+ return fs.realpathSync(path33__default.default.resolve(entry)) === fs.realpathSync(path33__default.default.resolve(selfPath));
25727
26449
  } catch {
25728
- return path32__default.default.resolve(entry) === path32__default.default.resolve(selfPath);
26450
+ return path33__default.default.resolve(entry) === path33__default.default.resolve(selfPath);
25729
26451
  }
25730
26452
  }
25731
26453
  if (isPrimaryModule()) {