agent-inspect 6.17.7 → 6.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@
4
4
  var crypto = require('crypto');
5
5
  var promises = require('fs/promises');
6
6
  var os = require('os');
7
- var 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
  }
@@ -7106,7 +7114,7 @@ function stripPrefix(name, prefixes) {
7106
7114
  }
7107
7115
  return name;
7108
7116
  }
7109
- function eventEvidence(event, path43) {
7117
+ function eventEvidence(event, path44) {
7110
7118
  return {
7111
7119
  runId: event.runId,
7112
7120
  eventId: event.eventId,
@@ -7116,7 +7124,7 @@ function eventEvidence(event, path43) {
7116
7124
  kind: event.kind,
7117
7125
  name: event.name,
7118
7126
  status: event.status,
7119
- ...path43 ? { path: path43 } : {}
7127
+ ...path44 ? { path: path44 } : {}
7120
7128
  };
7121
7129
  }
7122
7130
  function runEvidence(run) {
@@ -7192,9 +7200,9 @@ function eventEndMs(event) {
7192
7200
  function normalizedKey(value) {
7193
7201
  return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
7194
7202
  }
7195
- function lastPathSegment(path43) {
7196
- const parts = path43.split(".");
7197
- return parts[parts.length - 1] ?? path43;
7203
+ function lastPathSegment(path44) {
7204
+ const parts = path44.split(".");
7205
+ return parts[parts.length - 1] ?? path44;
7198
7206
  }
7199
7207
  function valueType(value) {
7200
7208
  if (Array.isArray(value)) return "array";
@@ -7208,12 +7216,12 @@ function serializedByteLength(value) {
7208
7216
  return void 0;
7209
7217
  }
7210
7218
  }
7211
- function pushValueEntries(entries, event, value, path43, key, depth = 0) {
7212
- entries.push({ event, path: path43, key, value });
7219
+ function pushValueEntries(entries, event, value, path44, key, depth = 0) {
7220
+ entries.push({ event, path: path44, key, value });
7213
7221
  if (depth >= 8) return;
7214
7222
  if (Array.isArray(value)) {
7215
7223
  for (const [index, item] of value.entries()) {
7216
- pushValueEntries(entries, event, item, `${path43}.${index}`, String(index), depth + 1);
7224
+ pushValueEntries(entries, event, item, `${path44}.${index}`, String(index), depth + 1);
7217
7225
  }
7218
7226
  return;
7219
7227
  }
@@ -7223,7 +7231,7 @@ function pushValueEntries(entries, event, value, path43, key, depth = 0) {
7223
7231
  entries,
7224
7232
  event,
7225
7233
  value[nestedKey],
7226
- `${path43}.${nestedKey}`,
7234
+ `${path44}.${nestedKey}`,
7227
7235
  nestedKey,
7228
7236
  depth + 1
7229
7237
  );
@@ -7262,18 +7270,18 @@ function isRawContentKey(key, forbiddenKeys) {
7262
7270
  const normalized = normalizedKey(key);
7263
7271
  return forbiddenKeys.some((forbidden) => normalized === normalizedKey(forbidden));
7264
7272
  }
7265
- function isSafeRawContentMetricPath(path43, key, safePathPrefixes) {
7266
- const leaf = normalizedKey(key ?? lastPathSegment(path43));
7273
+ function isSafeRawContentMetricPath(path44, key, safePathPrefixes) {
7274
+ const leaf = normalizedKey(key ?? lastPathSegment(path44));
7267
7275
  if (!SAFE_USAGE_LEAF_KEYS.has(leaf)) return false;
7268
- const parts = path43.split(".").filter(Boolean);
7276
+ const parts = path44.split(".").filter(Boolean);
7269
7277
  if (parts.length < 2) return false;
7270
7278
  const parent = parts[parts.length - 2] ?? "";
7271
7279
  const parentNorm = normalizedKey(parent);
7272
7280
  return safePathPrefixes.some((prefix) => parentNorm === normalizedKey(prefix));
7273
7281
  }
7274
- function isRawContentPath(path43, key, forbiddenKeys, safePathPrefixes) {
7275
- if (isSafeRawContentMetricPath(path43, key, safePathPrefixes)) return false;
7276
- return isRawContentKey(key ?? lastPathSegment(path43), forbiddenKeys);
7282
+ function isRawContentPath(path44, key, forbiddenKeys, safePathPrefixes) {
7283
+ if (isSafeRawContentMetricPath(path44, key, safePathPrefixes)) return false;
7284
+ return isRawContentKey(key ?? lastPathSegment(path44), forbiddenKeys);
7277
7285
  }
7278
7286
  function parentMarkedUnresolved(event) {
7279
7287
  if (booleanAttr(event, [
@@ -7312,9 +7320,9 @@ function eventDurationMs(event) {
7312
7320
  }
7313
7321
  function treeShape(nodes) {
7314
7322
  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}`));
7323
+ const visit = (node, path44) => {
7324
+ lines.push(`${path44}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
7325
+ node.children.forEach((child, index) => visit(child, `${path44}.${index}`));
7318
7326
  };
7319
7327
  nodes.forEach((node, index) => visit(node, String(index)));
7320
7328
  return lines;
@@ -7363,9 +7371,9 @@ function retrievalShape(context) {
7363
7371
  function guardrailShape(context) {
7364
7372
  return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
7365
7373
  }
7366
- function firstEvidenceForKind(context, kind, path43) {
7374
+ function firstEvidenceForKind(context, kind, path44) {
7367
7375
  const event = semanticEvents(context).find((candidate) => candidate.kind === kind);
7368
- return event ? [eventEvidence(event, path43)] : runEvidence(context.selectedRun);
7376
+ return event ? [eventEvidence(event, path44)] : runEvidence(context.selectedRun);
7369
7377
  }
7370
7378
  function baselineDiffFinding(message, evidence, expected, actual) {
7371
7379
  return failFinding("baseline.regression", message, evidence, expected, actual);
@@ -7715,13 +7723,13 @@ function createStructureCycleRule() {
7715
7723
  const seenCycles = /* @__PURE__ */ new Set();
7716
7724
  const findings = [];
7717
7725
  for (const event of [...semanticEvents(context)].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
7718
- const path43 = [];
7726
+ const path44 = [];
7719
7727
  const seenAt = /* @__PURE__ */ new Map();
7720
7728
  let current = event;
7721
7729
  while (current) {
7722
7730
  const existing = seenAt.get(current.eventId);
7723
7731
  if (existing !== void 0) {
7724
- const cycle = path43.slice(existing);
7732
+ const cycle = path44.slice(existing);
7725
7733
  const key = cycle.map((item) => item.eventId).sort().join("\0");
7726
7734
  if (!seenCycles.has(key)) {
7727
7735
  seenCycles.add(key);
@@ -7737,8 +7745,8 @@ function createStructureCycleRule() {
7737
7745
  }
7738
7746
  break;
7739
7747
  }
7740
- seenAt.set(current.eventId, path43.length);
7741
- path43.push(current);
7748
+ seenAt.set(current.eventId, path44.length);
7749
+ path44.push(current);
7742
7750
  current = current.parentId ? byId.get(current.parentId) : void 0;
7743
7751
  }
7744
7752
  }
@@ -9117,7 +9125,7 @@ function findReaderByFormat(format, readers) {
9117
9125
  }
9118
9126
  async function jsonlFilesInDirectory(dirPath) {
9119
9127
  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));
9128
+ 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
9129
  }
9122
9130
  async function resolveInput(input3) {
9123
9131
  const cached2 = resolvedInputCache.get(input3);
@@ -10824,7 +10832,7 @@ async function runSuiteCase(suiteCase, config, options) {
10824
10832
  async function runSuite(options = {}) {
10825
10833
  const startedAt = new Date(options.nowMs ?? Date.now()).toISOString();
10826
10834
  const { config, configPath, configDir } = await loadSuiteConfig(options);
10827
- const tracesDir = path32__default.default.resolve(configDir, config.traces);
10835
+ const tracesDir = path33__default.default.resolve(configDir, config.traces);
10828
10836
  const cases = [];
10829
10837
  const diagnostics = [];
10830
10838
  for (const suiteCase of config.cases) {
@@ -11851,7 +11859,7 @@ function validateOptions(options) {
11851
11859
  }
11852
11860
  function isConfigLoadError(error) {
11853
11861
  if (!(error instanceof Error)) return false;
11854
- const ext = path32__default.default.extname(error.message);
11862
+ const ext = path33__default.default.extname(error.message);
11855
11863
  if (error.message.includes("Unsupported suite config extension")) return true;
11856
11864
  if (error.message.includes("TypeScript suite configs require")) return true;
11857
11865
  if (error.message.includes("No suite config found")) return true;
@@ -12098,6 +12106,7 @@ var init_advanced = __esm({
12098
12106
  init_inspector();
12099
12107
  init_inspector_runtime();
12100
12108
  init_trace_event_safety();
12109
+ init_preview_capture();
12101
12110
  init_terminal();
12102
12111
  init_utils();
12103
12112
  init_types();
@@ -12245,8 +12254,8 @@ var init_load_sqlite = __esm({
12245
12254
  }
12246
12255
  });
12247
12256
  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);
12257
+ if (dbPath && dbPath.trim() !== "") return path33__default.default.resolve(dbPath);
12258
+ return path33__default.default.join(path33__default.default.resolve(traceDir), INDEX_DB_FILENAME);
12250
12259
  }
12251
12260
  function str(value) {
12252
12261
  return typeof value === "string" && value !== "" ? value : null;
@@ -12338,7 +12347,7 @@ async function buildIndex(options = {}) {
12338
12347
  warnings.push(`index.unreadable: ${file}`);
12339
12348
  }
12340
12349
  }
12341
- await promises.mkdir(path32__default.default.dirname(dbPath), { recursive: true });
12350
+ await promises.mkdir(path33__default.default.dirname(dbPath), { recursive: true });
12342
12351
  await promises.rm(dbPath, { force: true });
12343
12352
  const Sqlite = loadBetterSqlite3();
12344
12353
  const db = new Sqlite(dbPath);
@@ -12586,7 +12595,7 @@ var init_src = __esm({
12586
12595
  });
12587
12596
 
12588
12597
  // package.json
12589
- var version = "6.17.7";
12598
+ var version = "6.18.0";
12590
12599
 
12591
12600
  // packages/cli/src/list.ts
12592
12601
  init_advanced();
@@ -12741,13 +12750,14 @@ async function list(options = {}) {
12741
12750
 
12742
12751
  // packages/cli/src/clean.ts
12743
12752
  init_advanced();
12753
+ var DECIMAL_INTEGER_PATTERN = /^\d+$/;
12744
12754
  function parseKeep(raw) {
12745
12755
  const trimmed = typeof raw === "string" ? raw.trim() : "";
12746
- if (trimmed === "") {
12756
+ if (!DECIMAL_INTEGER_PATTERN.test(trimmed)) {
12747
12757
  throw new Error(`Invalid --keep value: ${raw}. Provide a positive integer.`);
12748
12758
  }
12749
- const n = Number.parseInt(trimmed, 10);
12750
- if (!Number.isFinite(n) || n <= 0) {
12759
+ const n = Number(trimmed);
12760
+ if (!Number.isSafeInteger(n) || n <= 0) {
12751
12761
  throw new Error(`Invalid --keep value: ${raw}. Provide a positive integer.`);
12752
12762
  }
12753
12763
  return n;
@@ -13083,6 +13093,16 @@ function filterErrorEvents(events) {
13083
13093
  return false;
13084
13094
  });
13085
13095
  }
13096
+ function pruneErrorTree(nodes) {
13097
+ const pruned = [];
13098
+ for (const node of nodes) {
13099
+ const children = pruneErrorTree(node.children);
13100
+ if (node.status === "error" || children.length > 0) {
13101
+ pruned.push({ ...node, children });
13102
+ }
13103
+ }
13104
+ return pruned;
13105
+ }
13086
13106
  async function view(runId, options = {}) {
13087
13107
  try {
13088
13108
  const id = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "";
@@ -13155,11 +13175,44 @@ async function view(runId, options = {}) {
13155
13175
  const errEvents = filterErrorEvents(events);
13156
13176
  if (options.json) {
13157
13177
  console.log(JSON.stringify(errEvents, null, 2));
13158
- } else if (errEvents.length === 0) {
13178
+ return;
13179
+ }
13180
+ if (errEvents.length === 0) {
13159
13181
  console.log("No errors found in trace");
13182
+ return;
13183
+ }
13184
+ const started2 = events.find(
13185
+ (e) => e.event === "run_started"
13186
+ );
13187
+ const completed2 = events.filter(
13188
+ (e) => e.event === "run_completed"
13189
+ );
13190
+ const last2 = completed2[completed2.length - 1];
13191
+ const status2 = last2 ? last2.status : "running";
13192
+ const durationLine2 = last2 !== void 0 && Number.isFinite(last2.durationMs) ? formatDuration2(last2.durationMs) : "-";
13193
+ const startedTs2 = started2 !== void 0 && Number.isFinite(started2.startTime) ? started2.startTime : started2?.timestamp;
13194
+ const startedLabel2 = startedTs2 !== void 0 ? formatTimestamp(startedTs2) : "-";
13195
+ console.log(`AgentInspect Run: ${started2?.name ?? id}`);
13196
+ console.log(`ID: ${id}`);
13197
+ console.log(`Status: ${status2}`);
13198
+ console.log(`Duration: ${durationLine2}`);
13199
+ console.log(`Started: ${startedLabel2}`);
13200
+ console.log("");
13201
+ console.log("Error Tree:");
13202
+ const pruned = pruneErrorTree(buildStepTree(events));
13203
+ if (pruned.length === 0) {
13204
+ if (last2?.status === "error") {
13205
+ console.log(
13206
+ renderErrorLine(
13207
+ last2.error ?? { message: "Run completed with error status" },
13208
+ 0
13209
+ )
13210
+ );
13211
+ } else {
13212
+ console.log("No error steps recorded");
13213
+ }
13160
13214
  } else {
13161
- console.log("Error events");
13162
- console.log(JSON.stringify(errEvents, null, 2));
13215
+ printStepTree(pruned, 0, options.verbose === true);
13163
13216
  }
13164
13217
  return;
13165
13218
  }
@@ -15614,9 +15667,9 @@ Trace directory: ${traceDir}`);
15614
15667
  process.exitCode = 1;
15615
15668
  }
15616
15669
  const resolvedOutput = resolveOutputOption(options);
15617
- const outPath = resolvedOutput !== void 0 ? path32__default.default.resolve(resolvedOutput) : void 0;
15670
+ const outPath = resolvedOutput !== void 0 ? path33__default.default.resolve(resolvedOutput) : void 0;
15618
15671
  if (outPath !== void 0) {
15619
- await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
15672
+ await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
15620
15673
  await promises.writeFile(outPath, result.content, "utf-8");
15621
15674
  const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
15622
15675
  console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
@@ -15975,7 +16028,7 @@ function indexedToMetadata(row, traceDir) {
15975
16028
  endedAt: row.endedAt ?? void 0,
15976
16029
  durationMs: row.durationMs ?? void 0,
15977
16030
  eventCount: 0,
15978
- filePath: path32__default.default.join(traceDir, row.file),
16031
+ filePath: path33__default.default.join(traceDir, row.file),
15979
16032
  fileSize: 0,
15980
16033
  createdAt: new Date(row.mtimeMs)
15981
16034
  };
@@ -16457,9 +16510,9 @@ async function reportCommand(runId, options = {}) {
16457
16510
  ...options.section ? { section: options.section } : {}
16458
16511
  });
16459
16512
  const resolvedOutput = resolveOutputOption(options);
16460
- const outPath = resolvedOutput !== void 0 ? path32__default.default.resolve(resolvedOutput) : void 0;
16513
+ const outPath = resolvedOutput !== void 0 ? path33__default.default.resolve(resolvedOutput) : void 0;
16461
16514
  if (outPath !== void 0) {
16462
- await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
16515
+ await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
16463
16516
  await promises.writeFile(outPath, result.content, "utf-8");
16464
16517
  console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
16465
16518
  }
@@ -16657,8 +16710,8 @@ function passesLuhn(value) {
16657
16710
  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;
16658
16711
  var EPOCH_MS_RE = /^1[0-9]{12}$/;
16659
16712
  var EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
16660
- function pathSuggestsNonCard(path43) {
16661
- const normalized = path43.toLowerCase().replace(/[^a-z0-9._]/g, "");
16713
+ function pathSuggestsNonCard(path44) {
16714
+ const normalized = path44.toLowerCase().replace(/[^a-z0-9._]/g, "");
16662
16715
  return /(^|\.)(tokenusage|usage)(\.|$)/.test(normalized) || /(startedat|endedat|durationms|timestamp|createdat|updatedat)(\.|$)/.test(normalized) || /(^|\.)(runid|traceid|spanid|eventid|sessionid|userid|parentid|requestid|correlationid)(\.|$)/.test(
16663
16716
  normalized
16664
16717
  ) || /(^|\.)ts(\.|$)/.test(normalized);
@@ -16854,17 +16907,17 @@ function applyRule(rule, value, replacement) {
16854
16907
  }
16855
16908
  return value;
16856
16909
  }
16857
- function childPath(path43, key) {
16910
+ function childPath(path44, key) {
16858
16911
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
16859
- return path43 ? `${path43}.${key}` : key;
16912
+ return path44 ? `${path44}.${key}` : key;
16860
16913
  }
16861
- return `${path43 || "$"}[${JSON.stringify(key)}]`;
16914
+ return `${path44 || "$"}[${JSON.stringify(key)}]`;
16862
16915
  }
16863
- function indexPath(path43, index) {
16864
- return `${path43 || "$"}[${index}]`;
16916
+ function indexPath(path44, index) {
16917
+ return `${path44 || "$"}[${index}]`;
16865
16918
  }
16866
- function makeFinding(path43, detector, action, matchKind, severity = "warning", preview) {
16867
- return preview === void 0 ? { path: path43, detector, action, severity, matchKind } : { path: path43, detector, action, severity, matchKind, preview };
16919
+ function makeFinding(path44, detector, action, matchKind, severity = "warning", preview) {
16920
+ return preview === void 0 ? { path: path44, detector, action, severity, matchKind } : { path: path44, detector, action, severity, matchKind, preview };
16868
16921
  }
16869
16922
  function createRedactionProfile(profile = "local") {
16870
16923
  switch (profile) {
@@ -16933,11 +16986,11 @@ var Redactor2 = class {
16933
16986
  #recordFinding(state, finding) {
16934
16987
  if (this.#collectFindings) state.findings.push(finding);
16935
16988
  }
16936
- #redactValue(value, key, path43, depth, state) {
16989
+ #redactValue(value, key, path44, depth, state) {
16937
16990
  if (depth > this.#maxDepth) {
16938
16991
  this.#recordFinding(
16939
16992
  state,
16940
- makeFinding(path43, "structure.maxDepth", "truncate", "value", "warning")
16993
+ makeFinding(path44, "structure.maxDepth", "truncate", "value", "warning")
16941
16994
  );
16942
16995
  return "[Truncated]";
16943
16996
  }
@@ -16946,19 +16999,19 @@ var Redactor2 = class {
16946
16999
  if (rule) {
16947
17000
  this.#recordFinding(
16948
17001
  state,
16949
- makeFinding(path43, `key.${rule.key}`, actionForRule(rule), "key", "warning")
17002
+ makeFinding(path44, `key.${rule.key}`, actionForRule(rule), "key", "warning")
16950
17003
  );
16951
17004
  return applyRule(rule, value, this.#replacement);
16952
17005
  }
16953
17006
  }
16954
17007
  for (const detector of this.#detectors) {
16955
- const detections = detector.detect({ path: path43, key, value });
17008
+ const detections = detector.detect({ path: path44, key, value });
16956
17009
  for (const detection of detections) {
16957
17010
  const action = detection.action ?? "replace";
16958
17011
  this.#recordFinding(
16959
17012
  state,
16960
17013
  makeFinding(
16961
- path43,
17014
+ path44,
16962
17015
  detector.id,
16963
17016
  action,
16964
17017
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -16976,7 +17029,7 @@ var Redactor2 = class {
16976
17029
  const out = [];
16977
17030
  state.seen.set(value, out);
16978
17031
  value.forEach((item, index) => {
16979
- out[index] = this.#redactValue(item, void 0, indexPath(path43, index), depth + 1, state);
17032
+ out[index] = this.#redactValue(item, void 0, indexPath(path44, index), depth + 1, state);
16980
17033
  });
16981
17034
  return out;
16982
17035
  }
@@ -16988,7 +17041,7 @@ var Redactor2 = class {
16988
17041
  out[entryKey] = this.#redactValue(
16989
17042
  entryValue,
16990
17043
  entryKey,
16991
- childPath(path43 === "$" ? "" : path43, entryKey),
17044
+ childPath(path44 === "$" ? "" : path44, entryKey),
16992
17045
  depth + 1,
16993
17046
  state
16994
17047
  );
@@ -17004,6 +17057,233 @@ function createRedactor(options) {
17004
17057
  function redact(value, options) {
17005
17058
  return createRedactor(options).redact(value);
17006
17059
  }
17060
+ var REDACTION_POLICY_LIMITS = {
17061
+ maxExtraKeys: 64,
17062
+ maxKeyLength: 64,
17063
+ maxPatterns: 32,
17064
+ maxPatternLength: 128,
17065
+ maxPatternIdLength: 64,
17066
+ maxTypedQuantifier: 64
17067
+ };
17068
+ var SAFE_TYPED_PATTERN = /^[A-Za-z0-9_@./:=<>\-[\]()|+*?{},\\\s^$]+$/;
17069
+ function isRecord16(value) {
17070
+ return value !== null && typeof value === "object" && !Array.isArray(value);
17071
+ }
17072
+ function escapeRegExp(value) {
17073
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17074
+ }
17075
+ function rejectRemotePolicyPath(policyPath) {
17076
+ const trimmed = policyPath.trim();
17077
+ if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) {
17078
+ throw new Error(
17079
+ `--policy must be a local JSON file path (got a URL-like value). Remote policy fetch is not supported.`
17080
+ );
17081
+ }
17082
+ }
17083
+ function parseSeverity(value, label) {
17084
+ if (value === void 0) return "error";
17085
+ if (value === "info" || value === "warning" || value === "error") return value;
17086
+ throw new Error(`${label} severity must be info, warning, or error.`);
17087
+ }
17088
+ function validateExtraKey(key, index) {
17089
+ const label = `extraKeys[${index}]`;
17090
+ if (key.length === 0) throw new Error(`${label} must be a non-empty string.`);
17091
+ if (key.length > REDACTION_POLICY_LIMITS.maxKeyLength) {
17092
+ throw new Error(
17093
+ `${label} exceeds max length ${REDACTION_POLICY_LIMITS.maxKeyLength}.`
17094
+ );
17095
+ }
17096
+ if (!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(key)) {
17097
+ throw new Error(
17098
+ `${label} must be an identifier-like key (letters, digits, _, ., -).`
17099
+ );
17100
+ }
17101
+ return key;
17102
+ }
17103
+ function assertBoundedTypedPattern(pattern, label) {
17104
+ if (pattern.length === 0) throw new Error(`${label} must be non-empty.`);
17105
+ if (pattern.length > REDACTION_POLICY_LIMITS.maxPatternLength) {
17106
+ throw new Error(
17107
+ `${label} exceeds max length ${REDACTION_POLICY_LIMITS.maxPatternLength}.`
17108
+ );
17109
+ }
17110
+ if (!SAFE_TYPED_PATTERN.test(pattern)) {
17111
+ throw new Error(
17112
+ `${label} contains unsupported characters for bounded typed patterns.`
17113
+ );
17114
+ }
17115
+ if (/\(\?/.test(pattern) || /\\[1-9]/.test(pattern)) {
17116
+ throw new Error(
17117
+ `${label} rejects lookaround, backreferences, and nested quantifiers.`
17118
+ );
17119
+ }
17120
+ if (/\([^)]*[+*{][^)]*\)[+*{]/.test(pattern) || /\[[^\]]*[+*{][^\]]*\][+*{]/.test(pattern)) {
17121
+ throw new Error(`${label} rejects nested quantifiers.`);
17122
+ }
17123
+ if (/\.[*+]/.test(pattern) || /[*+]\{/.test(pattern)) {
17124
+ throw new Error(`${label} rejects unbounded .* / .+ style quantifiers.`);
17125
+ }
17126
+ for (const match of pattern.matchAll(/\{(\d+)(?:,(\d*))?\}/g)) {
17127
+ const min = Number(match[1]);
17128
+ const maxRaw = match[2];
17129
+ const max = maxRaw === void 0 || maxRaw === "" ? min : Number(maxRaw);
17130
+ if (!Number.isFinite(min) || !Number.isFinite(max) || min > REDACTION_POLICY_LIMITS.maxTypedQuantifier || max > REDACTION_POLICY_LIMITS.maxTypedQuantifier) {
17131
+ throw new Error(
17132
+ `${label} quantifiers must be <= ${REDACTION_POLICY_LIMITS.maxTypedQuantifier}.`
17133
+ );
17134
+ }
17135
+ }
17136
+ }
17137
+ function compilePatternDetector(input3, index) {
17138
+ const label = `patterns[${index}]`;
17139
+ if (!isRecord16(input3)) throw new Error(`${label} must be an object.`);
17140
+ const idRaw = input3.id;
17141
+ if (typeof idRaw !== "string" || idRaw.trim() === "") {
17142
+ throw new Error(`${label}.id must be a non-empty string.`);
17143
+ }
17144
+ const id = idRaw.trim();
17145
+ if (id.length > REDACTION_POLICY_LIMITS.maxPatternIdLength) {
17146
+ throw new Error(
17147
+ `${label}.id exceeds max length ${REDACTION_POLICY_LIMITS.maxPatternIdLength}.`
17148
+ );
17149
+ }
17150
+ if (!/^[A-Za-z][A-Za-z0-9._-]*$/.test(id)) {
17151
+ throw new Error(`${label}.id must be an identifier-like detector id.`);
17152
+ }
17153
+ const type = input3.type;
17154
+ if (type !== "literal" && type !== "prefix" && type !== "typed") {
17155
+ throw new Error(`${label}.type must be literal, prefix, or typed.`);
17156
+ }
17157
+ const severity = parseSeverity(input3.severity, label);
17158
+ let source;
17159
+ if (type === "typed") {
17160
+ if (typeof input3.pattern !== "string") {
17161
+ throw new Error(`${label}.pattern must be a string for typed patterns.`);
17162
+ }
17163
+ assertBoundedTypedPattern(input3.pattern, `${label}.pattern`);
17164
+ source = input3.pattern;
17165
+ } else {
17166
+ if (typeof input3.value !== "string") {
17167
+ throw new Error(`${label}.value must be a string for ${type} patterns.`);
17168
+ }
17169
+ if (input3.value.length === 0) {
17170
+ throw new Error(`${label}.value must be non-empty.`);
17171
+ }
17172
+ if (input3.value.length > REDACTION_POLICY_LIMITS.maxPatternLength) {
17173
+ throw new Error(
17174
+ `${label}.value exceeds max length ${REDACTION_POLICY_LIMITS.maxPatternLength}.`
17175
+ );
17176
+ }
17177
+ const escaped = escapeRegExp(input3.value);
17178
+ source = type === "prefix" ? `^${escaped}` : escaped;
17179
+ }
17180
+ let regex;
17181
+ try {
17182
+ regex = new RegExp(source);
17183
+ } catch (error) {
17184
+ throw new Error(
17185
+ `${label} failed to compile: ${error instanceof Error ? error.message : String(error)}`
17186
+ );
17187
+ }
17188
+ return {
17189
+ id: `policy.${id}`,
17190
+ severity,
17191
+ matchKind: "custom",
17192
+ detect({ value }) {
17193
+ if (typeof value !== "string") return [];
17194
+ regex.lastIndex = 0;
17195
+ return regex.test(value) ? [{ action: "replace", severity, matchKind: "custom" }] : [];
17196
+ }
17197
+ };
17198
+ }
17199
+ function compileRedactionPolicy(raw, policyPath) {
17200
+ if (!isRecord16(raw)) {
17201
+ throw new Error(`Redaction policy must be a JSON object (${policyPath}).`);
17202
+ }
17203
+ const diagnostics = [];
17204
+ if (raw.version !== void 0 && raw.version !== 1) {
17205
+ throw new Error(`Unsupported redaction policy version (supported: 1).`);
17206
+ }
17207
+ const extraKeysRaw = raw.extraKeys;
17208
+ const extraKeys = [];
17209
+ if (extraKeysRaw !== void 0) {
17210
+ if (!Array.isArray(extraKeysRaw)) {
17211
+ throw new Error(`extraKeys must be an array of strings.`);
17212
+ }
17213
+ if (extraKeysRaw.length > REDACTION_POLICY_LIMITS.maxExtraKeys) {
17214
+ throw new Error(
17215
+ `extraKeys exceeds max count ${REDACTION_POLICY_LIMITS.maxExtraKeys}.`
17216
+ );
17217
+ }
17218
+ for (let i = 0; i < extraKeysRaw.length; i += 1) {
17219
+ const key = extraKeysRaw[i];
17220
+ if (typeof key !== "string") {
17221
+ throw new Error(`extraKeys[${i}] must be a string.`);
17222
+ }
17223
+ extraKeys.push(validateExtraKey(key, i));
17224
+ }
17225
+ }
17226
+ const patternsRaw = raw.patterns;
17227
+ const detectors = [];
17228
+ if (patternsRaw !== void 0) {
17229
+ if (!Array.isArray(patternsRaw)) {
17230
+ throw new Error(`patterns must be an array.`);
17231
+ }
17232
+ if (patternsRaw.length > REDACTION_POLICY_LIMITS.maxPatterns) {
17233
+ throw new Error(
17234
+ `patterns exceeds max count ${REDACTION_POLICY_LIMITS.maxPatterns}.`
17235
+ );
17236
+ }
17237
+ const seenIds = /* @__PURE__ */ new Set();
17238
+ for (let i = 0; i < patternsRaw.length; i += 1) {
17239
+ const detector = compilePatternDetector(
17240
+ patternsRaw[i],
17241
+ i
17242
+ );
17243
+ if (seenIds.has(detector.id)) {
17244
+ throw new Error(`Duplicate pattern id "${detector.id}".`);
17245
+ }
17246
+ seenIds.add(detector.id);
17247
+ detectors.push(detector);
17248
+ }
17249
+ }
17250
+ if (extraKeys.length === 0 && detectors.length === 0) {
17251
+ diagnostics.push({
17252
+ code: "AI_POLICY_EMPTY",
17253
+ message: "Redaction policy contained no extraKeys or patterns."
17254
+ });
17255
+ }
17256
+ return {
17257
+ path: policyPath,
17258
+ extraKeys,
17259
+ detectors,
17260
+ diagnostics
17261
+ };
17262
+ }
17263
+ async function loadRedactionPolicy(policyPath) {
17264
+ rejectRemotePolicyPath(policyPath);
17265
+ const resolved = path33__default.default.resolve(policyPath);
17266
+ let text;
17267
+ try {
17268
+ text = await promises.readFile(resolved, "utf-8");
17269
+ } catch (error) {
17270
+ throw new Error(
17271
+ `Failed to read --policy file "${resolved}": ${error instanceof Error ? error.message : String(error)}`
17272
+ );
17273
+ }
17274
+ let parsed;
17275
+ try {
17276
+ parsed = JSON.parse(text);
17277
+ } catch (error) {
17278
+ throw new Error(
17279
+ `Invalid JSON in --policy file "${resolved}": ${error instanceof Error ? error.message : String(error)}`
17280
+ );
17281
+ }
17282
+ return compileRedactionPolicy(parsed, resolved);
17283
+ }
17284
+
17285
+ // packages/core/src/entries/checks.ts
17286
+ init_checks2();
17007
17287
 
17008
17288
  // packages/cli/src/trace-input.ts
17009
17289
  init_advanced();
@@ -17035,12 +17315,19 @@ async function inputFromTarget(target, options, stdin) {
17035
17315
  return { type: "file", path: runPath };
17036
17316
  }
17037
17317
 
17038
- // packages/cli/src/redact.ts
17039
- function parseRedactionProfile3(value) {
17040
- if (value === void 0 || value === "local" || value === "share" || value === "strict") {
17041
- return value ?? "share";
17318
+ // packages/cli/src/safety.ts
17319
+ var BEST_EFFORT_NOTE = "Best-effort local safety verification only; not a compliance, privacy, security, or regulatory certification.";
17320
+ var DEFAULT_MAX_STRING_LENGTH = 16384;
17321
+ var DEFAULT_MAX_ARRAY_LENGTH = 1e3;
17322
+ var DEFAULT_MAX_OBJECT_KEYS = 200;
17323
+ var DEFAULT_MAX_SERIALIZED_BYTES = 128 * 1024;
17324
+ function parseLimit3(value, label) {
17325
+ if (value === void 0) return void 0;
17326
+ const parsed = Number(value);
17327
+ if (!Number.isFinite(parsed) || parsed < 0) {
17328
+ throw new Error(`${label} must be a non-negative number.`);
17042
17329
  }
17043
- throw new Error(`Unsupported --profile "${value}". Use local, share, or strict.`);
17330
+ return parsed;
17044
17331
  }
17045
17332
  function stable2(value) {
17046
17333
  if (Array.isArray(value)) return value.map(stable2);
@@ -17050,103 +17337,585 @@ function stable2(value) {
17050
17337
  Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable2(record[key])])
17051
17338
  );
17052
17339
  }
17053
- function isMissingFileError3(error) {
17054
- return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
17340
+ function safetyDiagnostic(code, message, severity = "error") {
17341
+ return { code, message, severity };
17055
17342
  }
17056
- async function contentFromTarget(target, options, stdin) {
17057
- if (target === "-") {
17058
- return { content: await readStdin(stdin), source: "stdin" };
17059
- }
17060
- try {
17061
- const stats2 = await promises.stat(target);
17062
- if (stats2.isDirectory()) {
17063
- throw new Error("redact requires a trace file, JSON file, stdin, or run id.");
17064
- }
17065
- return { content: await promises.readFile(target, "utf-8"), source: target };
17066
- } catch (error) {
17067
- if (!isMissingFileError3(error)) throw error;
17068
- }
17069
- const runPath = getTraceFilePath(target, resolveTraceDir({ dir: options.dir }));
17070
- const stats = await promises.stat(runPath);
17071
- if (stats.isDirectory()) {
17072
- throw new Error("redact requires a trace file, JSON file, stdin, or run id.");
17073
- }
17074
- return { content: await promises.readFile(runPath, "utf-8"), source: runPath };
17343
+ function warningDiagnostics(warnings, unsupportedFields) {
17344
+ return [
17345
+ ...warnings.map(
17346
+ (warning) => safetyDiagnostic(
17347
+ warning.code,
17348
+ warning.message,
17349
+ warning.severity === "error" ? "error" : "warning"
17350
+ )
17351
+ ),
17352
+ ...unsupportedFields.map(
17353
+ (field) => safetyDiagnostic(
17354
+ "unsupported_field",
17355
+ `Reader reported unsupported field: ${field}`,
17356
+ "warning"
17357
+ )
17358
+ )
17359
+ ];
17075
17360
  }
17076
- function redactJsonText(content, profile) {
17077
- const parsed = JSON.parse(content);
17078
- const result = redact(parsed, { profile });
17361
+ function diagnosticFromCheck(item) {
17362
+ return safetyDiagnostic(item.code, item.message, item.severity);
17363
+ }
17364
+ function statusFrom(findings, diagnostics) {
17365
+ if (diagnostics.some((item) => item.severity === "error")) return "UNKNOWN";
17366
+ if (findings.some((item) => item.severity === "error")) return "UNSAFE";
17367
+ if (diagnostics.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
17368
+ if (findings.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
17369
+ return "SAFE";
17370
+ }
17371
+ function resultFromParts(parts) {
17372
+ const findings = [...parts.findings ?? []];
17373
+ const diagnostics = [...parts.diagnostics ?? []];
17374
+ const warnings = [...parts.warnings ?? []];
17375
+ const unsupportedFields = [...parts.unsupportedFields ?? []];
17376
+ const status = parts.status ?? statusFrom(findings, diagnostics);
17079
17377
  return {
17080
- content: `${JSON.stringify(result.value, null, 2)}
17081
- `,
17082
- findings: result.findings
17378
+ ok: status === "SAFE" || status === "SAFE WITH WARNINGS",
17379
+ command: parts.command,
17380
+ status,
17381
+ format: parts.format,
17382
+ ...parts.runId !== void 0 ? { runId: parts.runId } : {},
17383
+ summary: {
17384
+ findings: findings.length,
17385
+ warnings: diagnostics.filter((item) => item.severity === "warning").length + findings.filter((item) => item.severity === "warning").length,
17386
+ errors: diagnostics.filter((item) => item.severity === "error").length + findings.filter((item) => item.severity === "error").length
17387
+ },
17388
+ findings,
17389
+ diagnostics,
17390
+ warnings,
17391
+ unsupportedFields,
17392
+ note: BEST_EFFORT_NOTE,
17393
+ ...parts.sourceAssessment !== void 0 ? { sourceAssessment: parts.sourceAssessment } : {},
17394
+ ...parts.artifactAssessment !== void 0 ? { artifactAssessment: parts.artifactAssessment } : {},
17395
+ ...parts.redactionSummary !== void 0 ? { redactionSummary: parts.redactionSummary } : {}
17083
17396
  };
17084
17397
  }
17085
- function redactJsonlText(content, profile) {
17086
- const lines = content.split(/\r?\n/);
17087
- const out = [];
17088
- const findings = [];
17089
- for (let index = 0; index < lines.length; index += 1) {
17090
- const line = lines[index] ?? "";
17091
- if (line.trim() === "") continue;
17092
- let parsed;
17093
- try {
17094
- parsed = JSON.parse(line);
17095
- } catch {
17096
- throw new Error(`Input is not valid JSON or JSONL at line ${index + 1}.`);
17097
- }
17098
- const result = redact(parsed, { profile });
17099
- out.push(JSON.stringify(result.value));
17100
- findings.push(
17101
- ...result.findings.map((finding) => ({
17102
- ...finding,
17103
- path: `line:${index + 1}:${finding.path}`
17104
- }))
17105
- );
17106
- }
17398
+ function layerFromResult(result) {
17107
17399
  return {
17108
- content: out.length === 0 ? "" : `${out.join("\n")}
17109
- `,
17110
- findings
17400
+ status: result.status,
17401
+ summary: result.summary,
17402
+ findings: result.findings
17111
17403
  };
17112
17404
  }
17113
- function redactDocument(content, profile) {
17114
- const trimmed = content.trim();
17115
- if (trimmed.startsWith("{")) {
17116
- try {
17117
- const parsed = JSON.parse(trimmed);
17118
- if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && ("schemaVersion" in parsed || "eventId" in parsed || "runId" in parsed)) {
17119
- return redactJsonlText(content, profile);
17120
- }
17121
- } catch {
17122
- }
17123
- }
17124
- try {
17125
- return redactJsonText(content, profile);
17126
- } catch {
17127
- return redactJsonlText(content, profile);
17128
- }
17129
- }
17130
- function redactTraceContent(content, profile) {
17131
- return redactDocument(content, profile);
17132
- }
17405
+ function readErrorResult(command, error) {
17406
+ if (error instanceof TraceReadError) {
17407
+ const code = error.code === "unsupported_format" ? "AI_SAFETY_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_SAFETY_AMBIGUOUS_FORMAT" : "AI_SAFETY_TRACE_UNREADABLE";
17408
+ return resultFromParts({
17409
+ command,
17410
+ format: "unknown",
17411
+ diagnostics: [safetyDiagnostic(code, error.message)],
17412
+ warnings: error.warnings
17413
+ });
17414
+ }
17415
+ return resultFromParts({
17416
+ command,
17417
+ format: "unknown",
17418
+ diagnostics: [
17419
+ safetyDiagnostic(
17420
+ "AI_SAFETY_TRACE_UNREADABLE",
17421
+ error instanceof Error ? error.message : String(error)
17422
+ )
17423
+ ]
17424
+ });
17425
+ }
17426
+ function invalidArgumentResult(command, error) {
17427
+ return resultFromParts({
17428
+ command,
17429
+ format: "unknown",
17430
+ diagnostics: [
17431
+ safetyDiagnostic(
17432
+ "AI_SAFETY_INVALID_ARGUMENTS",
17433
+ error instanceof Error ? error.message : String(error)
17434
+ )
17435
+ ]
17436
+ });
17437
+ }
17438
+ function buildSafetyRules(options) {
17439
+ const maxStringLength2 = parseLimit3(options.maxStringLength, "--max-string-length") ?? DEFAULT_MAX_STRING_LENGTH;
17440
+ const maxArrayLength = parseLimit3(options.maxArrayLength, "--max-array-length") ?? DEFAULT_MAX_ARRAY_LENGTH;
17441
+ const maxObjectKeys = parseLimit3(options.maxObjectKeys, "--max-object-keys") ?? DEFAULT_MAX_OBJECT_KEYS;
17442
+ const maxSerializedBytes = parseLimit3(options.maxSerializedBytes, "--max-serialized-bytes") ?? DEFAULT_MAX_SERIALIZED_BYTES;
17443
+ return [
17444
+ createSafetyRawContentRule(),
17445
+ createSafetyRedactionRule(),
17446
+ createSafetySecretPatternRule(),
17447
+ createSafetyOversizedAttributeRule({
17448
+ maxStringLength: maxStringLength2,
17449
+ maxArrayLength,
17450
+ maxObjectKeys,
17451
+ maxSerializedBytes
17452
+ })
17453
+ ];
17454
+ }
17455
+ function flattenNodes2(nodes) {
17456
+ return nodes.flatMap((node) => [
17457
+ node,
17458
+ ...flattenNodes2(
17459
+ node.children
17460
+ )
17461
+ ]);
17462
+ }
17463
+ function detectorSeverity(finding) {
17464
+ return finding.severity;
17465
+ }
17466
+ function classifyRedactionDetector(detector) {
17467
+ if (detector === "value.creditCard" || detector === "value.email" || detector === "value.phone") {
17468
+ return { category: "personal-data", confidence: "high" };
17469
+ }
17470
+ if (detector === "value.ipv4" || detector === "value.ipv6") {
17471
+ return { category: "identifier", confidence: "medium" };
17472
+ }
17473
+ 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"))) {
17474
+ return { category: "credential", confidence: "high" };
17475
+ }
17476
+ if (detector.startsWith("key.")) {
17477
+ return { category: "credential", confidence: "medium" };
17478
+ }
17479
+ return { category: "credential", confidence: "medium" };
17480
+ }
17481
+ function redactionOptionsFromPolicy(policy) {
17482
+ if (policy === void 0) return {};
17483
+ return {
17484
+ ...policy.extraKeys.length > 0 ? { extraKeys: [...policy.extraKeys] } : {},
17485
+ ...policy.detectors.length > 0 ? { detectors: [...policy.detectors] } : {}
17486
+ };
17487
+ }
17488
+ function redactionDetectorFindings(read, runId, policy) {
17489
+ const runs = runId === void 0 ? read.runs : read.runs.filter((run) => run.runId === runId);
17490
+ const out = [];
17491
+ const policyOptions = redactionOptionsFromPolicy(policy);
17492
+ for (const run of runs) {
17493
+ for (const node of flattenNodes2(run.children)) {
17494
+ const attrs = node.event.attributes;
17495
+ if (attrs === void 0) continue;
17496
+ const result = createRedactor({
17497
+ profile: "share",
17498
+ ...policyOptions
17499
+ }).redact(attrs);
17500
+ for (const finding of result.findings) {
17501
+ if (finding.action === "keep") continue;
17502
+ const taxonomy = classifyRedactionDetector(finding.detector);
17503
+ out.push({
17504
+ ruleId: "safety.redactDetector",
17505
+ severity: detectorSeverity(finding),
17506
+ status: finding.severity === "error" ? "fail" : "warning",
17507
+ message: `Redaction detector ${finding.detector} matched ${finding.matchKind} at ${finding.path}.`,
17508
+ expected: "redacted trace content",
17509
+ actual: finding.detector,
17510
+ evidence: [
17511
+ {
17512
+ runId: node.event.runId,
17513
+ eventId: node.event.eventId,
17514
+ ...node.event.parentId !== void 0 ? { parentId: node.event.parentId } : {},
17515
+ kind: node.event.kind,
17516
+ name: node.event.name,
17517
+ ...node.event.status !== void 0 ? { status: node.event.status } : {},
17518
+ path: `attributes.${finding.path.replace(/^\$\.?/, "")}`
17519
+ }
17520
+ ],
17521
+ category: taxonomy.category,
17522
+ confidence: taxonomy.confidence,
17523
+ detector: finding.detector,
17524
+ action: finding.action
17525
+ });
17526
+ }
17527
+ }
17528
+ }
17529
+ return out.sort((a, b) => {
17530
+ const aEvidence = a.evidence[0];
17531
+ const bEvidence = b.evidence[0];
17532
+ return (aEvidence?.runId ?? "").localeCompare(bEvidence?.runId ?? "") || (aEvidence?.eventId ?? "").localeCompare(bEvidence?.eventId ?? "") || (aEvidence?.path ?? "").localeCompare(bEvidence?.path ?? "") || a.message.localeCompare(b.message);
17533
+ });
17534
+ }
17535
+ function exitCodeFor(result) {
17536
+ if (result.status === "SAFE" || result.status === "SAFE WITH WARNINGS") return 0;
17537
+ if (result.status === "UNSAFE") return 1;
17538
+ return 2;
17539
+ }
17540
+ function toResidualStatus(status) {
17541
+ if (status === "SAFE WITH WARNINGS") return "SAFE_WITH_WARNINGS";
17542
+ return status;
17543
+ }
17544
+ function toResidualSafetyAssessment(result) {
17545
+ const codes = [
17546
+ .../* @__PURE__ */ new Set([
17547
+ ...result.diagnostics.map((item) => item.code),
17548
+ ...result.findings.map((item) => item.ruleId)
17549
+ ])
17550
+ ].sort((a, b) => a.localeCompare(b));
17551
+ return {
17552
+ status: toResidualStatus(result.status),
17553
+ findings: result.summary.findings,
17554
+ warnings: result.summary.warnings,
17555
+ errors: result.summary.errors,
17556
+ codes,
17557
+ note: BEST_EFFORT_NOTE
17558
+ };
17559
+ }
17560
+ async function assessResidualFromContent(content, options = {}) {
17561
+ try {
17562
+ const policy = options.compiledPolicy ?? (options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0);
17563
+ const read = await openTrace(
17564
+ { type: "string", content },
17565
+ { format: options.format ?? "agent-inspect-jsonl" }
17566
+ );
17567
+ const result = assessOpenedTrace(read, {
17568
+ ...options,
17569
+ ...policy !== void 0 ? { compiledPolicy: policy } : {}
17570
+ });
17571
+ return toResidualSafetyAssessment(result);
17572
+ } catch (error) {
17573
+ if (error instanceof TraceReadError) {
17574
+ return toResidualSafetyAssessment(readErrorResult("verify-safe", error));
17575
+ }
17576
+ const message = error instanceof Error ? error.message : String(error);
17577
+ return {
17578
+ status: "UNKNOWN",
17579
+ findings: 0,
17580
+ warnings: 0,
17581
+ errors: 1,
17582
+ codes: ["AI_SAFETY_TRACE_UNREADABLE"],
17583
+ note: `${BEST_EFFORT_NOTE} Residual assessment requires a supported AgentInspect trace; ${message}`
17584
+ };
17585
+ }
17586
+ }
17587
+ function explainFinding(finding, blocksBundle) {
17588
+ const path44 = finding.evidence[0]?.path ?? "(unknown path)";
17589
+ const category = finding.category ?? "structure";
17590
+ const confidence = finding.confidence ?? "medium";
17591
+ const detector = finding.detector ?? finding.ruleId;
17592
+ const action = finding.action ?? "review";
17593
+ 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.";
17594
+ return [
17595
+ ` Matched: detector=${detector}; path=${path44}; category=${category}`,
17596
+ ` Why: ${finding.message}`,
17597
+ ` Confidence: ${confidence}`,
17598
+ ` Redaction: ${redactionHint}`,
17599
+ ` Override: configure a custom redaction/detector rule locally (see docs/SAFETY-POLICY.md); do not weaken defaults globally.`,
17600
+ ` Bundle gate: ${blocksBundle ? "blocks share-safe bundle unless --allow-unsafe" : "does not block by itself (warning/info)"}`
17601
+ ];
17602
+ }
17603
+ function findingExplanation(finding) {
17604
+ const blocks = finding.severity === "error" || finding.status === "fail";
17605
+ return {
17606
+ ruleId: finding.ruleId,
17607
+ detector: finding.detector ?? finding.ruleId,
17608
+ path: finding.evidence[0]?.path,
17609
+ category: finding.category,
17610
+ confidence: finding.confidence,
17611
+ action: finding.action,
17612
+ blocksBundle: blocks,
17613
+ // Never include matched secret/PII values.
17614
+ message: finding.message
17615
+ };
17616
+ }
17617
+ function printHuman(result, explain = false) {
17618
+ console.log(`Safety status: ${result.status}`);
17619
+ console.log(`Format: ${result.format}`);
17620
+ if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
17621
+ if (result.sourceAssessment !== void 0 && result.artifactAssessment !== void 0) {
17622
+ console.log(`Source assessment: ${result.sourceAssessment.status}`);
17623
+ console.log(`Artifact assessment: ${result.artifactAssessment.status}`);
17624
+ if (result.redactionSummary !== void 0) {
17625
+ console.log(
17626
+ `Redaction: profile=${result.redactionSummary.profile}, findings=${result.redactionSummary.findings}`
17627
+ );
17628
+ }
17629
+ }
17630
+ console.log(
17631
+ `Summary: ${result.summary.findings} finding(s), ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
17632
+ );
17633
+ for (const diagnostic7 of result.diagnostics) {
17634
+ console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
17635
+ }
17636
+ for (const finding of result.findings) {
17637
+ const path44 = finding.evidence[0]?.path;
17638
+ const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
17639
+ console.log(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}${taxonomy}`);
17640
+ if (explain) {
17641
+ const blocks = finding.severity === "error" || finding.status === "fail";
17642
+ for (const line of explainFinding(finding, blocks)) {
17643
+ console.log(line);
17644
+ }
17645
+ }
17646
+ }
17647
+ console.log(`Note: ${result.note}`);
17648
+ }
17649
+ function printJson(result, explain = false) {
17650
+ const payload = explain === true ? { ...result, explanations: result.findings.map(findingExplanation) } : result;
17651
+ console.log(JSON.stringify(stable2(payload), null, 2));
17652
+ }
17653
+ async function safetyCommand(command, target, options, stdin) {
17654
+ let result;
17655
+ try {
17656
+ const policy = options.compiledPolicy ?? (options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0);
17657
+ const optionsWithPolicy = {
17658
+ ...options,
17659
+ ...policy !== void 0 ? { compiledPolicy: policy } : {}
17660
+ };
17661
+ const input3 = await inputFromTarget(target, optionsWithPolicy, stdin);
17662
+ const read = await openTrace(input3, {
17663
+ ...options.format !== void 0 ? { format: options.format } : {}
17664
+ });
17665
+ const source = assessOpenedTrace(read, {
17666
+ ...optionsWithPolicy,
17667
+ ...options.run !== void 0 ? { runId: options.run } : {}
17668
+ });
17669
+ if (command === "scan") {
17670
+ result = { ...source, command: "scan" };
17671
+ } else {
17672
+ const profile = options.redactionProfile ?? "share";
17673
+ const rawContent = input3.type === "string" ? input3.content : input3.type === "file" ? await promises.readFile(input3.path, "utf-8") : void 0;
17674
+ if (rawContent === void 0) {
17675
+ result = {
17676
+ ...source,
17677
+ command: "verify-safe",
17678
+ sourceAssessment: layerFromResult(source)
17679
+ };
17680
+ } else {
17681
+ const redacted = redactTraceContent(rawContent, profile, policy);
17682
+ const artifactRead = await openTrace(
17683
+ { type: "string", content: redacted.content },
17684
+ { format: options.format ?? "agent-inspect-jsonl" }
17685
+ );
17686
+ const artifact = assessOpenedTrace(artifactRead, {
17687
+ ...optionsWithPolicy,
17688
+ ...options.run !== void 0 ? { runId: options.run } : {}
17689
+ });
17690
+ const detectors = [
17691
+ ...new Set(redacted.findings.map((finding) => finding.detector))
17692
+ ].sort((a, b) => a.localeCompare(b));
17693
+ result = resultFromParts({
17694
+ command: "verify-safe",
17695
+ format: artifact.format,
17696
+ runId: artifact.runId ?? source.runId,
17697
+ findings: artifact.findings,
17698
+ diagnostics: artifact.diagnostics,
17699
+ warnings: artifact.warnings,
17700
+ unsupportedFields: artifact.unsupportedFields,
17701
+ status: artifact.status,
17702
+ sourceAssessment: layerFromResult(source),
17703
+ artifactAssessment: layerFromResult(artifact),
17704
+ redactionSummary: {
17705
+ profile,
17706
+ findings: redacted.findings.length,
17707
+ detectors
17708
+ }
17709
+ });
17710
+ }
17711
+ }
17712
+ } catch (error) {
17713
+ const message = error instanceof Error ? error.message : String(error);
17714
+ result = message.startsWith("--") || message.includes("--policy") ? invalidArgumentResult(command, error) : readErrorResult(command, error);
17715
+ }
17716
+ process.exitCode = exitCodeFor(result);
17717
+ if (options.json) printJson(result, options.explain === true);
17718
+ else printHuman(result, options.explain === true);
17719
+ }
17720
+ function scanCommand(target, options = {}, stdin = process.stdin) {
17721
+ return safetyCommand("scan", target, options, stdin);
17722
+ }
17723
+ function verifySafeCommand(target, options = {}, stdin = process.stdin) {
17724
+ return safetyCommand("verify-safe", target, options, stdin);
17725
+ }
17726
+ function assessOpenedTrace(read, options = {}) {
17727
+ try {
17728
+ const rules = buildSafetyRules(options);
17729
+ const checkResult = runTraceChecks(
17730
+ { read },
17731
+ {
17732
+ rules,
17733
+ ...options.runId !== void 0 ? { runId: options.runId } : {},
17734
+ ...options.run !== void 0 ? { runId: options.run } : {}
17735
+ }
17736
+ );
17737
+ const detectorFindings = checkResult.diagnostics.length === 0 ? redactionDetectorFindings(read, checkResult.runId, options.compiledPolicy) : [];
17738
+ return resultFromParts({
17739
+ command: "verify-safe",
17740
+ format: checkResult.format,
17741
+ runId: checkResult.runId,
17742
+ findings: [...checkResult.findings, ...detectorFindings],
17743
+ diagnostics: [
17744
+ ...checkResult.diagnostics.map(diagnosticFromCheck),
17745
+ ...warningDiagnostics(read.warnings, read.unsupportedFields)
17746
+ ],
17747
+ warnings: read.warnings,
17748
+ unsupportedFields: read.unsupportedFields
17749
+ });
17750
+ } catch (error) {
17751
+ return messageStartsWithDash(error) ? invalidArgumentResult("verify-safe", error) : readErrorResult("verify-safe", error);
17752
+ }
17753
+ }
17754
+ function messageStartsWithDash(error) {
17755
+ const message = error instanceof Error ? error.message : String(error);
17756
+ return message.startsWith("--");
17757
+ }
17758
+
17759
+ // packages/cli/src/redact.ts
17760
+ function parseRedactionProfile3(value) {
17761
+ if (value === void 0 || value === "local" || value === "share" || value === "strict") {
17762
+ return value ?? "share";
17763
+ }
17764
+ throw new Error(`Unsupported --profile "${value}". Use local, share, or strict.`);
17765
+ }
17766
+ function stable3(value) {
17767
+ if (Array.isArray(value)) return value.map(stable3);
17768
+ if (value === null || typeof value !== "object") return value;
17769
+ const record = value;
17770
+ return Object.fromEntries(
17771
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable3(record[key])])
17772
+ );
17773
+ }
17774
+ function isMissingFileError3(error) {
17775
+ return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
17776
+ }
17777
+ async function contentFromTarget(target, options, stdin) {
17778
+ if (target === "-") {
17779
+ return { content: await readStdin(stdin), source: "stdin" };
17780
+ }
17781
+ try {
17782
+ const stats2 = await promises.stat(target);
17783
+ if (stats2.isDirectory()) {
17784
+ throw new Error("redact requires a trace file, JSON file, stdin, or run id.");
17785
+ }
17786
+ return { content: await promises.readFile(target, "utf-8"), source: target };
17787
+ } catch (error) {
17788
+ if (!isMissingFileError3(error)) throw error;
17789
+ }
17790
+ const runPath = getTraceFilePath(target, resolveTraceDir({ dir: options.dir }));
17791
+ const stats = await promises.stat(runPath);
17792
+ if (stats.isDirectory()) {
17793
+ throw new Error("redact requires a trace file, JSON file, stdin, or run id.");
17794
+ }
17795
+ return { content: await promises.readFile(runPath, "utf-8"), source: runPath };
17796
+ }
17797
+ function applyRedact(value, profile, policy) {
17798
+ const result = createRedactor({
17799
+ profile,
17800
+ ...policy?.extraKeys.length ? { extraKeys: [...policy.extraKeys] } : {},
17801
+ ...policy?.detectors.length ? { detectors: [...policy.detectors] } : {}
17802
+ }).redact(value);
17803
+ return { value: result.value, findings: result.findings };
17804
+ }
17805
+ function redactJsonText(content, profile, policy) {
17806
+ const parsed = JSON.parse(content);
17807
+ const result = applyRedact(parsed, profile, policy);
17808
+ return {
17809
+ content: `${JSON.stringify(result.value, null, 2)}
17810
+ `,
17811
+ findings: result.findings
17812
+ };
17813
+ }
17814
+ function redactJsonlText(content, profile, policy) {
17815
+ const lines = content.split(/\r?\n/);
17816
+ const out = [];
17817
+ const findings = [];
17818
+ for (let index = 0; index < lines.length; index += 1) {
17819
+ const line = lines[index] ?? "";
17820
+ if (line.trim() === "") continue;
17821
+ let parsed;
17822
+ try {
17823
+ parsed = JSON.parse(line);
17824
+ } catch {
17825
+ throw new Error(`Input is not valid JSON or JSONL at line ${index + 1}.`);
17826
+ }
17827
+ const result = applyRedact(parsed, profile, policy);
17828
+ out.push(JSON.stringify(result.value));
17829
+ findings.push(
17830
+ ...result.findings.map((finding) => ({
17831
+ ...finding,
17832
+ path: `line:${index + 1}:${finding.path}`
17833
+ }))
17834
+ );
17835
+ }
17836
+ return {
17837
+ content: out.length === 0 ? "" : `${out.join("\n")}
17838
+ `,
17839
+ findings
17840
+ };
17841
+ }
17842
+ function redactDocument(content, profile, policy) {
17843
+ const trimmed = content.trim();
17844
+ if (trimmed.startsWith("{")) {
17845
+ try {
17846
+ const parsed = JSON.parse(trimmed);
17847
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && ("schemaVersion" in parsed || "eventId" in parsed || "runId" in parsed)) {
17848
+ return redactJsonlText(content, profile, policy);
17849
+ }
17850
+ } catch {
17851
+ }
17852
+ }
17853
+ try {
17854
+ return redactJsonText(content, profile, policy);
17855
+ } catch {
17856
+ return redactJsonlText(content, profile, policy);
17857
+ }
17858
+ }
17859
+ function redactTraceContent(content, profile, policy) {
17860
+ return redactDocument(content, profile, policy);
17861
+ }
17862
+ function looksLikeAgentInspectTrace(content) {
17863
+ const trimmed = content.trim();
17864
+ if (!trimmed.startsWith("{")) return false;
17865
+ try {
17866
+ const firstLine = trimmed.split(/\r?\n/).find((line) => line.trim() !== "") ?? trimmed;
17867
+ const parsed = JSON.parse(firstLine);
17868
+ return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && ("schemaVersion" in parsed || "eventId" in parsed || "runId" in parsed);
17869
+ } catch {
17870
+ return false;
17871
+ }
17872
+ }
17873
+ function printResidualWarning(assessment, sourceLooksLikeTrace) {
17874
+ if (assessment.status === "SAFE") return;
17875
+ if (assessment.status === "UNKNOWN" && !sourceLooksLikeTrace) return;
17876
+ const codes = assessment.codes.length > 0 ? ` codes=${assessment.codes.join(",")}` : "";
17877
+ console.error(
17878
+ `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.`
17879
+ );
17880
+ }
17881
+ function residualExitCode(assessment) {
17882
+ if (assessment.status === "UNSAFE") return 1;
17883
+ if (assessment.status === "UNKNOWN") return 2;
17884
+ return 0;
17885
+ }
17133
17886
  async function redactCommand(target, options = {}, stdin = process.stdin) {
17134
17887
  const profile = parseRedactionProfile3(resolveRedactionProfileOption(options));
17888
+ const policy = options.policy !== void 0 ? await loadRedactionPolicy(options.policy) : void 0;
17135
17889
  const source = await contentFromTarget(target, options, stdin);
17136
- const redacted = redactDocument(source.content, profile);
17890
+ const redacted = redactDocument(source.content, profile, policy);
17137
17891
  const outputPath = resolveOutputOption(options);
17892
+ const residualAssessment = await assessResidualFromContent(redacted.content, {
17893
+ compiledPolicy: policy
17894
+ });
17138
17895
  if (outputPath !== void 0) {
17139
17896
  await promises.writeFile(outputPath, redacted.content, "utf-8");
17140
17897
  }
17898
+ if (options.failOnResidual === true) {
17899
+ process.exitCode = residualExitCode(residualAssessment);
17900
+ }
17141
17901
  if (options.json) {
17142
17902
  console.log(
17143
17903
  JSON.stringify(
17144
- stable2({
17904
+ stable3({
17145
17905
  ok: true,
17146
17906
  profile,
17147
17907
  source: source.source,
17148
17908
  output: outputPath,
17149
17909
  findings: redacted.findings,
17910
+ residualAssessment,
17911
+ ...policy !== void 0 ? {
17912
+ policy: {
17913
+ path: policy.path,
17914
+ extraKeys: policy.extraKeys.length,
17915
+ patterns: policy.detectors.length,
17916
+ diagnostics: policy.diagnostics
17917
+ }
17918
+ } : {},
17150
17919
  content: outputPath === void 0 ? redacted.content : void 0
17151
17920
  }),
17152
17921
  null,
@@ -17155,6 +17924,7 @@ async function redactCommand(target, options = {}, stdin = process.stdin) {
17155
17924
  );
17156
17925
  return;
17157
17926
  }
17927
+ printResidualWarning(residualAssessment, looksLikeAgentInspectTrace(redacted.content));
17158
17928
  if (outputPath === void 0) {
17159
17929
  process.stdout.write(redacted.content);
17160
17930
  }
@@ -17437,7 +18207,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
17437
18207
 
17438
18208
  // packages/cli/src/migrate.ts
17439
18209
  init_advanced();
17440
- function isRecord16(value) {
18210
+ function isRecord17(value) {
17441
18211
  return typeof value === "object" && value !== null && !Array.isArray(value);
17442
18212
  }
17443
18213
  function parseTarget(value) {
@@ -17446,7 +18216,7 @@ function parseTarget(value) {
17446
18216
  throw new Error('Unsupported migration target. Use "--to 1.0".');
17447
18217
  }
17448
18218
  function formatOf(value) {
17449
- if (!isRecord16(value)) return "unknown";
18219
+ if (!isRecord17(value)) return "unknown";
17450
18220
  if (value.schemaVersion === "0.1") return "0.1";
17451
18221
  if (value.schemaVersion === "0.2") return "0.2";
17452
18222
  if (value.schemaVersion === "1.0") return "1.0";
@@ -17459,14 +18229,14 @@ function uniqueSorted(values) {
17459
18229
  return [...new Set(values)].sort();
17460
18230
  }
17461
18231
  function isWithinDirectory(child, parent) {
17462
- const relative = path32__default.default.relative(parent, child);
17463
- return relative === "" || !relative.startsWith("..") && !path32__default.default.isAbsolute(relative);
18232
+ const relative = path33__default.default.relative(parent, child);
18233
+ return relative === "" || !relative.startsWith("..") && !path33__default.default.isAbsolute(relative);
17464
18234
  }
17465
18235
  async function resolveOutputPath(inputPath, output2, force) {
17466
18236
  if (output2 === void 0 || output2.trim() === "") return void 0;
17467
- const inputAbs = path32__default.default.resolve(inputPath);
17468
- const outputAbs = path32__default.default.resolve(output2.trim());
17469
- const inputDir = path32__default.default.dirname(inputAbs);
18237
+ const inputAbs = path33__default.default.resolve(inputPath);
18238
+ const outputAbs = path33__default.default.resolve(output2.trim());
18239
+ const inputDir = path33__default.default.dirname(inputAbs);
17470
18240
  if (!isWithinDirectory(outputAbs, inputDir)) {
17471
18241
  throw new Error("Refusing to write migrated output outside the input directory.");
17472
18242
  }
@@ -17587,7 +18357,7 @@ async function migrateCommand(input3, options = {}) {
17587
18357
  process.exitCode = 1;
17588
18358
  return;
17589
18359
  }
17590
- const inputPath = path32__default.default.resolve(input3.trim());
18360
+ const inputPath = path33__default.default.resolve(input3.trim());
17591
18361
  const dryRun = options.dryRun === true;
17592
18362
  if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
17593
18363
  console.error("migrate requires --dry-run or --output <path>.");
@@ -17606,7 +18376,7 @@ async function migrateCommand(input3, options = {}) {
17606
18376
  );
17607
18377
  const result = await buildMigration(inputPath, outputPath);
17608
18378
  if (!dryRun && outputPath !== void 0) {
17609
- await promises.mkdir(path32__default.default.dirname(outputPath), { recursive: true });
18379
+ await promises.mkdir(path33__default.default.dirname(outputPath), { recursive: true });
17610
18380
  await promises.writeFile(outputPath, result.content, "utf-8");
17611
18381
  }
17612
18382
  printSummary2(result, dryRun);
@@ -17615,16 +18385,13 @@ async function migrateCommand(input3, options = {}) {
17615
18385
  console.error(`[AgentInspect] migrate failed: ${msg}`);
17616
18386
  process.exitCode = 1;
17617
18387
  }
17618
- }
17619
- init_advanced();
17620
-
17621
- // packages/core/src/entries/checks.ts
17622
- init_checks2();
18388
+ }
18389
+ init_advanced();
17623
18390
 
17624
18391
  // packages/cli/src/evidence-on.ts
17625
18392
  init_advanced();
17626
18393
  function validateReporterArtifactPath(options) {
17627
- const outputDir = path32__default.default.resolve(options.outputDir);
18394
+ const outputDir = path33__default.default.resolve(options.outputDir);
17628
18395
  const diagnostics = [];
17629
18396
  const rawPath = options.relativePath;
17630
18397
  if (rawPath.length === 0) {
@@ -17644,7 +18411,7 @@ function validateReporterArtifactPath(options) {
17644
18411
  });
17645
18412
  return { ok: false, outputDir, diagnostics };
17646
18413
  }
17647
- if (path32__default.default.isAbsolute(rawPath) || path32__default.default.win32.isAbsolute(rawPath)) {
18414
+ if (path33__default.default.isAbsolute(rawPath) || path33__default.default.win32.isAbsolute(rawPath)) {
17648
18415
  diagnostics.push({
17649
18416
  code: "artifact_path_absolute",
17650
18417
  severity: "error",
@@ -17653,7 +18420,7 @@ function validateReporterArtifactPath(options) {
17653
18420
  });
17654
18421
  return { ok: false, outputDir, diagnostics };
17655
18422
  }
17656
- const normalized = path32__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
18423
+ const normalized = path33__default.default.posix.normalize(rawPath.replace(/\\/g, "/"));
17657
18424
  const segments = normalized.split("/");
17658
18425
  if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
17659
18426
  diagnostics.push({
@@ -17664,9 +18431,9 @@ function validateReporterArtifactPath(options) {
17664
18431
  });
17665
18432
  return { ok: false, outputDir, diagnostics };
17666
18433
  }
17667
- const absolutePath = path32__default.default.resolve(outputDir, normalized);
17668
- const relFromOutput = path32__default.default.relative(outputDir, absolutePath);
17669
- if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path32__default.default.isAbsolute(relFromOutput)) {
18434
+ const absolutePath = path33__default.default.resolve(outputDir, normalized);
18435
+ const relFromOutput = path33__default.default.relative(outputDir, absolutePath);
18436
+ if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path33__default.default.isAbsolute(relFromOutput)) {
17670
18437
  diagnostics.push({
17671
18438
  code: "artifact_path_escape",
17672
18439
  severity: "error",
@@ -17692,7 +18459,7 @@ var EVIDENCE_CI_ARTIFACT_FILES = [
17692
18459
  function createEvidenceCiArtifacts(options) {
17693
18460
  const profile = options.redactionProfile ?? "share";
17694
18461
  const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
17695
- const join = (name) => prefix === "" ? name : path32__default.default.posix.join(prefix, name);
18462
+ const join = (name) => prefix === "" ? name : path33__default.default.posix.join(prefix, name);
17696
18463
  const formatFor = (name) => {
17697
18464
  if (name.endsWith(".html")) return "html";
17698
18465
  if (name.endsWith(".jsonl")) return "jsonl";
@@ -17741,9 +18508,9 @@ function stableJson2(value) {
17741
18508
  async function writeLocalEvidence(input3) {
17742
18509
  const profile = input3.redactionProfile ?? "share";
17743
18510
  const format = input3.format ?? "directory";
17744
- const baseDir = path32__default.default.resolve(input3.outputDir);
18511
+ const baseDir = path33__default.default.resolve(input3.outputDir);
17745
18512
  await promises.mkdir(
17746
- format === "zip" && baseDir.toLowerCase().endsWith(".zip") ? path32__default.default.dirname(baseDir) : baseDir,
18513
+ format === "zip" && baseDir.toLowerCase().endsWith(".zip") ? path33__default.default.dirname(baseDir) : baseDir,
17747
18514
  { recursive: true }
17748
18515
  );
17749
18516
  const sourceContents = /* @__PURE__ */ new Map();
@@ -17799,7 +18566,7 @@ async function writeLocalEvidence(input3) {
17799
18566
  }
17800
18567
  if (format === "zip") {
17801
18568
  const zipPath = baseDir.toLowerCase().endsWith(".zip") ? baseDir : `${baseDir}.zip`;
17802
- await promises.mkdir(path32__default.default.dirname(zipPath), { recursive: true });
18569
+ await promises.mkdir(path33__default.default.dirname(zipPath), { recursive: true });
17803
18570
  const archive = buildZipArchive(
17804
18571
  files.map(([relativePath, content]) => ({
17805
18572
  path: relativePath,
@@ -17814,16 +18581,16 @@ async function writeLocalEvidence(input3) {
17814
18581
  let sidecarDir = baseDir;
17815
18582
  if (baseDir.toLowerCase().endsWith(".html")) {
17816
18583
  htmlPath = baseDir;
17817
- sidecarDir = path32__default.default.dirname(baseDir);
18584
+ sidecarDir = path33__default.default.dirname(baseDir);
17818
18585
  } else {
17819
18586
  await promises.mkdir(baseDir, { recursive: true });
17820
- htmlPath = path32__default.default.join(baseDir, "evidence.html");
18587
+ htmlPath = path33__default.default.join(baseDir, "evidence.html");
17821
18588
  sidecarDir = baseDir;
17822
18589
  }
17823
18590
  await promises.mkdir(sidecarDir, { recursive: true });
17824
18591
  await promises.writeFile(htmlPath, evidencePackage["evidence.html"], "utf-8");
17825
18592
  await promises.writeFile(
17826
- path32__default.default.join(sidecarDir, "evidence.json"),
18593
+ path33__default.default.join(sidecarDir, "evidence.json"),
17827
18594
  evidencePackage["evidence.json"],
17828
18595
  "utf-8"
17829
18596
  );
@@ -17831,7 +18598,7 @@ async function writeLocalEvidence(input3) {
17831
18598
  }
17832
18599
  await promises.mkdir(baseDir, { recursive: true });
17833
18600
  for (const [name, content] of files) {
17834
- await promises.writeFile(path32__default.default.join(baseDir, name), content, "utf-8");
18601
+ await promises.writeFile(path33__default.default.join(baseDir, name), content, "utf-8");
17835
18602
  }
17836
18603
  return baseDir;
17837
18604
  }
@@ -17855,11 +18622,11 @@ function checkResultToEvidenceJson(result, runIds) {
17855
18622
  }
17856
18623
  function defaultEvidenceDir(label) {
17857
18624
  const safe = label.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 80) || "evidence";
17858
- return path32__default.default.join(".agent-inspect", "evidence", safe);
18625
+ return path33__default.default.join(".agent-inspect", "evidence", safe);
17859
18626
  }
17860
18627
  function resolveEvidenceOutputDir(evidenceDir, label) {
17861
18628
  if (evidenceDir !== void 0 && evidenceDir.trim() !== "") {
17862
- return path32__default.default.resolve(evidenceDir.trim());
18629
+ return path33__default.default.resolve(evidenceDir.trim());
17863
18630
  }
17864
18631
  return defaultEvidenceDir(label);
17865
18632
  }
@@ -18183,23 +18950,23 @@ function evaluatePromptInjection(text, options = {}) {
18183
18950
  }
18184
18951
  return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
18185
18952
  }
18186
- function validateSchemaField(value, field, path43, evidence) {
18953
+ function validateSchemaField(value, field, path44, evidence) {
18187
18954
  const ruleId = "guardrail.structured-output";
18188
18955
  if (field.type) {
18189
18956
  const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
18190
18957
  if (actual !== field.type) {
18191
- evidence.push({ ruleId, path: path43, preview: `expected ${field.type}, got ${actual}` });
18958
+ evidence.push({ ruleId, path: path44, preview: `expected ${field.type}, got ${actual}` });
18192
18959
  return;
18193
18960
  }
18194
18961
  }
18195
18962
  if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
18196
- evidence.push({ ruleId, path: path43, preview: "value not in enum" });
18963
+ evidence.push({ ruleId, path: path44, preview: "value not in enum" });
18197
18964
  }
18198
18965
  if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
18199
18966
  const record = value;
18200
18967
  for (const key of field.required) {
18201
18968
  if (!(key in record)) {
18202
- evidence.push({ ruleId, path: `${path43}.${key}`, preview: "missing required key" });
18969
+ evidence.push({ ruleId, path: `${path44}.${key}`, preview: "missing required key" });
18203
18970
  }
18204
18971
  }
18205
18972
  }
@@ -18928,7 +19695,7 @@ function parseCheckConfig(value) {
18928
19695
  }
18929
19696
  async function loadConfig(configPath) {
18930
19697
  if (configPath === void 0) return {};
18931
- const extension = path32__default.default.extname(configPath);
19698
+ const extension = path33__default.default.extname(configPath);
18932
19699
  if (TS_CONFIG_EXTENSIONS2.has(extension)) {
18933
19700
  throw new CheckConfigError(
18934
19701
  "AI_CHECK_CONFIG_LOAD_FAILED",
@@ -18941,7 +19708,7 @@ async function loadConfig(configPath) {
18941
19708
  "Unsupported check config extension. Use .json, .js, .mjs, or .cjs."
18942
19709
  );
18943
19710
  }
18944
- const absolute = path32__default.default.resolve(configPath);
19711
+ const absolute = path33__default.default.resolve(configPath);
18945
19712
  try {
18946
19713
  if (extension === ".json") {
18947
19714
  const raw = await promises.readFile(absolute, "utf-8");
@@ -19135,7 +19902,7 @@ function buildRules(config, options, presetSelect = []) {
19135
19902
  diagnostics
19136
19903
  };
19137
19904
  }
19138
- function exitCodeFor(result) {
19905
+ function exitCodeFor2(result) {
19139
19906
  if (result.status === "pass") return 0;
19140
19907
  if (result.status === "fail") return 1;
19141
19908
  const codes = result.diagnostics.map((item) => item.code);
@@ -19156,16 +19923,16 @@ function exitCodeFor(result) {
19156
19923
  }
19157
19924
  return 1;
19158
19925
  }
19159
- function stable3(value) {
19160
- if (Array.isArray(value)) return value.map(stable3);
19926
+ function stable4(value) {
19927
+ if (Array.isArray(value)) return value.map(stable4);
19161
19928
  if (value === null || typeof value !== "object") return value;
19162
19929
  const record = value;
19163
19930
  return Object.fromEntries(
19164
- Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable3(record[key])])
19931
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable4(record[key])])
19165
19932
  );
19166
19933
  }
19167
- function printJson(result) {
19168
- console.log(JSON.stringify(stable3(result), null, 2));
19934
+ function printJson2(result) {
19935
+ console.log(JSON.stringify(stable4(result), null, 2));
19169
19936
  }
19170
19937
  function isSafetyFinding(ruleId) {
19171
19938
  return ruleId.startsWith("safety.") || ruleId.startsWith("guardrail.") || ruleId.includes("pii") || ruleId.includes("secret");
@@ -19202,7 +19969,7 @@ function printPresetClassSummary(result, preset) {
19202
19969
  `Share safety: ${hasSafetyFindings || result.status === "fail" ? "FAIL" : result.status === "pass" ? "PASS" : "FAIL"}`
19203
19970
  );
19204
19971
  }
19205
- function printHuman(result, options = {}) {
19972
+ function printHuman2(result, options = {}) {
19206
19973
  const scoped = result;
19207
19974
  if (scoped.scopeLabel) {
19208
19975
  console.log(`Scope: ${scoped.scopeKind} ${scoped.scopeLabel}`);
@@ -19222,13 +19989,13 @@ function printHuman(result, options = {}) {
19222
19989
  console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
19223
19990
  }
19224
19991
  for (const finding of result.findings) {
19225
- const path43 = finding.evidence[0]?.path;
19992
+ const path44 = finding.evidence[0]?.path;
19226
19993
  const run = finding.evidence[0]?.runId;
19227
19994
  const runPrefix = run ? `[${run}] ` : "";
19228
- console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
19995
+ console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
19229
19996
  }
19230
19997
  }
19231
- function readErrorResult(error) {
19998
+ function readErrorResult2(error) {
19232
19999
  if (error instanceof TraceReadError) {
19233
20000
  const code = error.code === "unsupported_format" ? "AI_CHECK_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_CHECK_AMBIGUOUS_FORMAT" : "AI_CHECK_TRACE_UNREADABLE";
19234
20001
  return errorResult2(code, error.message);
@@ -19255,9 +20022,9 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
19255
20022
  "AI_CHECK_CONFIG_NO_EFFECTIVE_RULES",
19256
20023
  "Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, or checks.safety."
19257
20024
  );
19258
- if (options.json) printJson(result);
19259
- else printHuman(result, options);
19260
- process.exitCode = exitCodeFor(result);
20025
+ if (options.json) printJson2(result);
20026
+ else printHuman2(result, options);
20027
+ process.exitCode = exitCodeFor2(result);
19261
20028
  return;
19262
20029
  }
19263
20030
  let effectiveOptions = options;
@@ -19387,10 +20154,10 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
19387
20154
  result = errorResult2(code, message);
19388
20155
  }
19389
20156
  } else {
19390
- result = readErrorResult(error);
20157
+ result = readErrorResult2(error);
19391
20158
  }
19392
20159
  }
19393
- process.exitCode = exitCodeFor(result);
20160
+ process.exitCode = exitCodeFor2(result);
19394
20161
  const failed = result.status !== "pass";
19395
20162
  if (shouldEmitEvidence(options.evidenceOn, failed)) {
19396
20163
  try {
@@ -19430,8 +20197,8 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
19430
20197
  );
19431
20198
  }
19432
20199
  }
19433
- if (options.json) printJson(result);
19434
- else printHuman(result, options);
20200
+ if (options.json) printJson2(result);
20201
+ else printHuman2(result, options);
19435
20202
  }
19436
20203
 
19437
20204
  // packages/viewer/src/server.ts
@@ -19588,7 +20355,7 @@ async function loadSuiteViewerData(options) {
19588
20355
  for (const suiteCase of result.cases) {
19589
20356
  cases.push(await enrichCase(suiteCase, baselinePath));
19590
20357
  }
19591
- const artifactsDir = path32__default.default.join(path32__default.default.dirname(result.configPath), ".agent-inspect/suite-runs");
20358
+ const artifactsDir = path33__default.default.join(path33__default.default.dirname(result.configPath), ".agent-inspect/suite-runs");
19592
20359
  return {
19593
20360
  suiteName: result.suiteName,
19594
20361
  configPath: result.configPath,
@@ -19784,19 +20551,19 @@ function serializeWorkspaceManifest(manifest) {
19784
20551
  }
19785
20552
  var INDEX_DIR_NAME = "index";
19786
20553
  function resolveWorkspaceLocation(cwd = process.cwd()) {
19787
- const projectRoot = path32__default.default.resolve(cwd);
19788
- const workspaceDir = path32__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
20554
+ const projectRoot = path33__default.default.resolve(cwd);
20555
+ const workspaceDir = path33__default.default.join(projectRoot, WORKSPACE_DIR_NAME);
19789
20556
  return {
19790
20557
  projectRoot,
19791
20558
  workspaceDir,
19792
- manifestPath: path32__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
20559
+ manifestPath: path33__default.default.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
19793
20560
  };
19794
20561
  }
19795
20562
  function resolveInsideWorkspace(workspaceDir, relative) {
19796
- const base = path32__default.default.resolve(workspaceDir);
19797
- const resolved = path32__default.default.resolve(base, relative);
19798
- const rel = path32__default.default.relative(base, resolved);
19799
- if (rel === "" || rel === "." || !rel.startsWith("..") && !path32__default.default.isAbsolute(rel)) {
20563
+ const base = path33__default.default.resolve(workspaceDir);
20564
+ const resolved = path33__default.default.resolve(base, relative);
20565
+ const rel = path33__default.default.relative(base, resolved);
20566
+ if (rel === "" || rel === "." || !rel.startsWith("..") && !path33__default.default.isAbsolute(rel)) {
19800
20567
  return resolved;
19801
20568
  }
19802
20569
  throw new Error(
@@ -19865,7 +20632,7 @@ async function createWorkspace(options = {}) {
19865
20632
  created = false;
19866
20633
  adopted = true;
19867
20634
  } else {
19868
- const project = options.project?.trim() || path32__default.default.basename(location.projectRoot) || "workspace";
20635
+ const project = options.project?.trim() || path33__default.default.basename(location.projectRoot) || "workspace";
19869
20636
  const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
19870
20637
  manifest = createDefaultWorkspaceManifest({
19871
20638
  project,
@@ -20004,7 +20771,7 @@ async function doctorWorkspace(location) {
20004
20771
  const abs = resolveInsideWorkspace(location.workspaceDir, rel);
20005
20772
  for (const file of await listJsonl(abs)) {
20006
20773
  try {
20007
- const s = await promises.stat(path32__default.default.join(abs, file));
20774
+ const s = await promises.stat(path33__default.default.join(abs, file));
20008
20775
  newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
20009
20776
  } catch {
20010
20777
  checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
@@ -20052,7 +20819,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
20052
20819
  const relPath = `${rel}/${entry}`;
20053
20820
  removed.push(relPath);
20054
20821
  if (!dryRun) {
20055
- await promises.rm(path32__default.default.join(abs, entry), { recursive: true, force: true });
20822
+ await promises.rm(path33__default.default.join(abs, entry), { recursive: true, force: true });
20056
20823
  }
20057
20824
  }
20058
20825
  }
@@ -20061,7 +20828,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
20061
20828
 
20062
20829
  // packages/viewer/src/workspace-data.ts
20063
20830
  async function loadWorkspaceViewerData(options) {
20064
- const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
20831
+ const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
20065
20832
  const location = resolveWorkspaceLocation(cwd);
20066
20833
  const manifestRead = await readWorkspaceManifestFile(location);
20067
20834
  if (!manifestRead.ok || manifestRead.manifest === void 0) {
@@ -20074,7 +20841,7 @@ async function loadWorkspaceViewerData(options) {
20074
20841
  const runs = [];
20075
20842
  for (const rel of manifestRead.manifest.traceDirs) {
20076
20843
  const traceDir = resolveTraceDir({
20077
- dir: path32__default.default.join(location.workspaceDir, rel)
20844
+ dir: path33__default.default.join(location.workspaceDir, rel)
20078
20845
  });
20079
20846
  const td = new TraceDirectory({ dir: traceDir });
20080
20847
  const files = await td.list();
@@ -20088,7 +20855,7 @@ async function loadWorkspaceViewerData(options) {
20088
20855
  runId: meta2.runId,
20089
20856
  ...meta2.name !== void 0 ? { name: meta2.name } : {},
20090
20857
  status: meta2.status,
20091
- file: path32__default.default.basename(meta2.filePath)
20858
+ file: path33__default.default.basename(meta2.filePath)
20092
20859
  });
20093
20860
  }
20094
20861
  }
@@ -20099,8 +20866,8 @@ async function loadWorkspaceViewerData(options) {
20099
20866
  doctor,
20100
20867
  runs,
20101
20868
  bundleDirs: [
20102
- path32__default.default.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
20103
- path32__default.default.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
20869
+ path33__default.default.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
20870
+ path33__default.default.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
20104
20871
  ]
20105
20872
  };
20106
20873
  }
@@ -20163,7 +20930,7 @@ function createViewerServer(options = {}) {
20163
20930
  ok: true,
20164
20931
  readOnly: true,
20165
20932
  mode,
20166
- traceDir: path32__default.default.resolve(traceDir)
20933
+ traceDir: path33__default.default.resolve(traceDir)
20167
20934
  });
20168
20935
  }
20169
20936
  if (pathname === "/api/suite" && mode === "suite") {
@@ -20192,7 +20959,7 @@ function createViewerServer(options = {}) {
20192
20959
  runId: meta2.runId,
20193
20960
  name: meta2.name,
20194
20961
  status: meta2.status,
20195
- file: path32__default.default.basename(meta2.filePath),
20962
+ file: path33__default.default.basename(meta2.filePath),
20196
20963
  startedAt: meta2.startedAt,
20197
20964
  durationMs: meta2.durationMs
20198
20965
  }))
@@ -20309,7 +21076,7 @@ function startViewerServer(options = {}) {
20309
21076
  resolve({
20310
21077
  host,
20311
21078
  port: resolvedPort,
20312
- traceDir: path32__default.default.resolve(traceDir),
21079
+ traceDir: path33__default.default.resolve(traceDir),
20313
21080
  url: `http://${host}:${resolvedPort}/${modeQuery}`,
20314
21081
  mode
20315
21082
  });
@@ -20720,10 +21487,10 @@ async function evalRun(input3, options = {}) {
20720
21487
  diagnostics: []
20721
21488
  };
20722
21489
  }
20723
- function evidenceForRun(run, path43) {
20724
- return [{ runId: run.runId, ...path43 !== void 0 ? { path: path43 } : {} }];
21490
+ function evidenceForRun(run, path44) {
21491
+ return [{ runId: run.runId, ...path44 !== void 0 ? { path: path44 } : {} }];
20725
21492
  }
20726
- function evidenceForEvent(event, path43) {
21493
+ function evidenceForEvent(event, path44) {
20727
21494
  return [
20728
21495
  {
20729
21496
  runId: event.runId,
@@ -20731,7 +21498,7 @@ function evidenceForEvent(event, path43) {
20731
21498
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
20732
21499
  kind: event.kind,
20733
21500
  name: event.name,
20734
- ...path43 !== void 0 ? { path: path43 } : {}
21501
+ ...path44 !== void 0 ? { path: path44 } : {}
20735
21502
  }
20736
21503
  ];
20737
21504
  }
@@ -20889,9 +21656,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
20889
21656
  function tokenize(text) {
20890
21657
  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));
20891
21658
  }
20892
- function firstEvidence(fields, run, path43) {
21659
+ function firstEvidence(fields, run, path44) {
20893
21660
  const first = fields[0];
20894
- return first === void 0 ? evidenceForRun(run, path43) : evidenceForEvent(first.node.event, first.path);
21661
+ return first === void 0 ? evidenceForRun(run, path44) : evidenceForEvent(first.node.event, first.path);
20895
21662
  }
20896
21663
  function collectSourceIds(nodes, keys) {
20897
21664
  const wanted = keySet(keys);
@@ -21244,273 +22011,55 @@ var checks = {
21244
22011
  "Answer contained banned unsupported-answer phrasing.",
21245
22012
  firstEvidence(answers, context.run, "attributes.answer"),
21246
22013
  { bannedPhraseCount: banned.length },
21247
- { matchedPhraseCount: matches.length }
21248
- )
21249
- ] : [];
21250
- });
21251
- }
21252
- };
21253
- function renderEvalMarkdown(result) {
21254
- const lines = [
21255
- `# AgentInspect Eval`,
21256
- "",
21257
- `Status: ${result.status}`,
21258
- `Format: ${result.format}`,
21259
- ...result.runId !== void 0 ? [`Run: ${result.runId}`] : [],
21260
- `Summary: ${result.summary.passed} passed, ${result.summary.failed} failed, ${result.summary.warnings} warnings, ${result.summary.errors} errors`
21261
- ];
21262
- if (result.diagnostics.length > 0) {
21263
- lines.push("", "## Diagnostics");
21264
- for (const diagnostic7 of result.diagnostics) {
21265
- lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
21266
- }
21267
- }
21268
- if (result.findings.length > 0) {
21269
- lines.push("", "## Findings");
21270
- for (const finding of result.findings) {
21271
- const path43 = finding.evidence[0]?.path;
21272
- lines.push(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
21273
- }
21274
- }
21275
- return `${lines.join("\n")}
21276
- `;
21277
- }
21278
-
21279
- // packages/cli/src/eval.ts
21280
- var CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
21281
- var TS_CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
21282
- function diagnostic6(code, message, severity = "error") {
21283
- return { code, message, severity };
21284
- }
21285
- function errorResult4(code, message, format = "unknown") {
21286
- return {
21287
- ok: false,
21288
- status: "error",
21289
- format,
21290
- summary: { passed: 0, failed: 0, warnings: 0, errors: 1 },
21291
- findings: [],
21292
- diagnostics: [diagnostic6(code, message)]
21293
- };
21294
- }
21295
- function parseNumber2(value, label) {
21296
- if (value === void 0) return void 0;
21297
- const parsed = Number(value);
21298
- if (!Number.isFinite(parsed) || parsed < 0) {
21299
- throw new Error(`${label} must be a non-negative number.`);
21300
- }
21301
- return parsed;
21302
- }
21303
- function asStringArray3(value, label) {
21304
- if (value === void 0) return void 0;
21305
- if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
21306
- throw new Error(`${label} must be an array of strings.`);
21307
- }
21308
- return value;
21309
- }
21310
- function asConfig(value) {
21311
- if (value === void 0 || value === null) return {};
21312
- if (typeof value !== "object" || Array.isArray(value)) {
21313
- throw new Error("Config must export an object.");
21314
- }
21315
- return value;
21316
- }
21317
- async function loadConfig2(configPath) {
21318
- if (configPath === void 0) return {};
21319
- const extension = path32__default.default.extname(configPath);
21320
- if (TS_CONFIG_EXTENSIONS3.has(extension)) {
21321
- throw new Error(
21322
- "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
21323
- );
21324
- }
21325
- if (!CONFIG_EXTENSIONS3.has(extension)) {
21326
- throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
21327
- }
21328
- const absolute = path32__default.default.resolve(configPath);
21329
- if (extension === ".json") {
21330
- const raw = await promises.readFile(absolute, "utf-8");
21331
- return asConfig(JSON.parse(raw));
21332
- }
21333
- const mod = await import(url.pathToFileURL(absolute).href);
21334
- return asConfig("default" in mod ? mod.default : mod);
21335
- }
21336
- function normalizeConfig2(config) {
21337
- if (config.eval === void 0) return {};
21338
- if (typeof config.eval !== "object" || Array.isArray(config.eval)) {
21339
- throw new Error("eval config must be an object.");
21340
- }
21341
- return config.eval;
21342
- }
21343
- function maybeAdd(rules, value, makeRule) {
21344
- if (value !== void 0) rules.push(makeRule(value));
21345
- }
21346
- function optionObject(value) {
21347
- if (value === void 0 || value === false) return void 0;
21348
- if (value === true) return {};
21349
- if (typeof value !== "object" || Array.isArray(value)) {
21350
- throw new Error("Eval heuristic config must be a boolean or object.");
21351
- }
21352
- return value;
21353
- }
21354
- function sourceIdsFromConfig(value) {
21355
- if (value === void 0) return void 0;
21356
- if (Array.isArray(value)) return { ids: asStringArray3(value, "eval.requiredSourceIds") ?? [] };
21357
- if (typeof value !== "object" || Array.isArray(value)) {
21358
- throw new Error("eval.requiredSourceIds must be an array or object.");
21359
- }
21360
- const ids = asStringArray3(value.ids, "eval.requiredSourceIds.ids") ?? [];
21361
- return { ids, options: { sourceIdKeys: value.sourceIdKeys } };
21362
- }
21363
- function buildRules2(config, options) {
21364
- const evalConfig = normalizeConfig2(config);
21365
- const rules = [];
21366
- if (evalConfig.requireSuccess || options.requireSuccess) rules.push(checks.requireSuccess());
21367
- const requiredTools = [
21368
- ...asStringArray3(evalConfig.requiredTools, "eval.requiredTools") ?? [],
21369
- ...options.requiredTool ?? []
21370
- ];
21371
- if (requiredTools.length > 0) rules.push(checks.requiredTools(requiredTools));
21372
- const forbiddenTools = [
21373
- ...asStringArray3(evalConfig.forbiddenTools, "eval.forbiddenTools") ?? [],
21374
- ...options.forbidTool ?? [],
21375
- ...options.forbiddenTool ?? []
21376
- ];
21377
- if (forbiddenTools.length > 0) rules.push(checks.forbiddenTools(forbiddenTools));
21378
- const maxDurationMs = parseNumber2(options.maxDurationMs, "--max-duration-ms") ?? evalConfig.maxDurationMs;
21379
- maybeAdd(rules, maxDurationMs, checks.maxDurationMs);
21380
- const maxDepth = parseNumber2(options.maxDepth, "--max-depth") ?? evalConfig.maxDepth;
21381
- maybeAdd(rules, maxDepth, checks.maxDepth);
21382
- const maxRetries = parseNumber2(options.maxRetries, "--max-retries") ?? evalConfig.maxRetries;
21383
- maybeAdd(rules, maxRetries, checks.maxRetries);
21384
- const maxTotalTokens = parseNumber2(options.maxTotalTokens, "--max-total-tokens") ?? evalConfig.maxTotalTokens;
21385
- maybeAdd(rules, maxTotalTokens, checks.maxTotalTokens);
21386
- if (evalConfig.requiredRetrievalBeforeGeneration || options.requireRetrievalBeforeGeneration) {
21387
- rules.push(checks.requiredRetrievalBeforeGeneration());
21388
- }
21389
- const requiredDecisionMetadata = [
21390
- ...asStringArray3(
21391
- evalConfig.requiredDecisionMetadata,
21392
- "eval.requiredDecisionMetadata"
21393
- ) ?? [],
21394
- ...options.requiredDecisionMetadata ?? []
21395
- ];
21396
- if (requiredDecisionMetadata.length > 0) {
21397
- rules.push(checks.requiredDecisionMetadata(requiredDecisionMetadata));
21398
- }
21399
- const contextOverlap = optionObject(evalConfig.contextOverlap);
21400
- const minOverlap = parseNumber2(options.minContextOverlap, "--min-context-overlap");
21401
- const minSharedTerms = parseNumber2(options.minSharedTerms, "--min-shared-terms");
21402
- if (contextOverlap !== void 0 || options.contextOverlap || minOverlap !== void 0 || minSharedTerms !== void 0) {
21403
- rules.push(checks.contextOverlap({ ...contextOverlap, minOverlap, minSharedTerms }));
21404
- }
21405
- const quoteOverlap = optionObject(evalConfig.quoteOverlap);
21406
- if (quoteOverlap !== void 0 || options.quoteOverlap) {
21407
- rules.push(checks.quoteOverlap(quoteOverlap));
21408
- }
21409
- const citationPresence = optionObject(evalConfig.citationPresence);
21410
- if (citationPresence !== void 0 || options.citationPresence) {
21411
- rules.push(checks.citationPresence(citationPresence));
21412
- }
21413
- const sourceIds = sourceIdsFromConfig(evalConfig.requiredSourceIds);
21414
- const requiredSourceIds = [...sourceIds?.ids ?? [], ...options.requiredSourceId ?? []];
21415
- if (requiredSourceIds.length > 0) {
21416
- rules.push(checks.requiredSourceIds(requiredSourceIds, sourceIds?.options));
21417
- }
21418
- const cliAnswerLength = {
21419
- minCharacters: parseNumber2(options.minAnswerCharacters, "--min-answer-characters"),
21420
- maxCharacters: parseNumber2(options.maxAnswerCharacters, "--max-answer-characters"),
21421
- minWords: parseNumber2(options.minAnswerWords, "--min-answer-words"),
21422
- maxWords: parseNumber2(options.maxAnswerWords, "--max-answer-words")
21423
- };
21424
- const hasCliAnswerLength = Object.values(cliAnswerLength).some((value) => value !== void 0);
21425
- if (evalConfig.answerLengthBounds !== void 0 || hasCliAnswerLength) {
21426
- rules.push(checks.answerLengthBounds({ ...evalConfig.answerLengthBounds, ...cliAnswerLength }));
21427
- }
21428
- const bannedPhrases = [
21429
- ...asStringArray3(
21430
- evalConfig.bannedUnsupportedPhrases,
21431
- "eval.bannedUnsupportedPhrases"
21432
- ) ?? [],
21433
- ...options.bannedPhrase ?? []
21434
- ];
21435
- if (bannedPhrases.length > 0) rules.push(checks.bannedUnsupportedPhrases(bannedPhrases));
21436
- return rules.length > 0 ? rules : void 0;
21437
- }
21438
- function exitCodeFor2(result) {
21439
- if (result.status === "pass") return 0;
21440
- if (result.status === "fail") return 1;
21441
- return 2;
21442
- }
21443
- function stable4(value) {
21444
- if (Array.isArray(value)) return value.map(stable4);
21445
- if (value === null || typeof value !== "object") return value;
21446
- const record = value;
21447
- return Object.fromEntries(
21448
- Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable4(record[key])])
21449
- );
21450
- }
21451
- function printJson2(result) {
21452
- console.log(JSON.stringify(stable4(result), null, 2));
21453
- }
21454
- function printHuman2(result) {
21455
- console.log(`Eval status: ${result.status}`);
21456
- console.log(`Format: ${result.format}`);
21457
- if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
21458
- console.log(
21459
- `Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
21460
- );
21461
- for (const diagnostic7 of result.diagnostics) {
21462
- console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
21463
- }
21464
- for (const finding of result.findings) {
21465
- const path43 = finding.evidence[0]?.path;
21466
- console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}`);
21467
- }
21468
- }
21469
- function readErrorResult2(error) {
21470
- if (error instanceof TraceReadError) {
21471
- const code = error.code === "unsupported_format" ? "AI_EVAL_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_EVAL_AMBIGUOUS_FORMAT" : "AI_EVAL_TRACE_UNREADABLE";
21472
- return errorResult4(code, error.message);
21473
- }
21474
- return errorResult4(
21475
- "AI_EVAL_TRACE_UNREADABLE",
21476
- error instanceof Error ? error.message : String(error)
21477
- );
21478
- }
21479
- async function evalCommand(target, options = {}, stdin = process.stdin) {
21480
- let result;
21481
- let phase = "config";
21482
- try {
21483
- const config = await loadConfig2(options.config);
21484
- const rules = buildRules2(config, options);
21485
- phase = "read";
21486
- const input3 = await inputFromTarget(target, options, stdin);
21487
- const read = await openTrace(input3, {
21488
- ...options.format !== void 0 ? { format: options.format } : {}
21489
- });
21490
- result = await evalRun(read, {
21491
- ...rules !== void 0 ? { checks: rules } : {},
21492
- ...options.run !== void 0 ? { runId: options.run } : {}
22014
+ { matchedPhraseCount: matches.length }
22015
+ )
22016
+ ] : [];
21493
22017
  });
21494
- } catch (error) {
21495
- if (phase === "config") {
21496
- const message = error instanceof Error ? error.message : String(error);
21497
- 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";
21498
- result = errorResult4(code, message);
21499
- } else {
21500
- result = readErrorResult2(error);
22018
+ }
22019
+ };
22020
+ function renderEvalMarkdown(result) {
22021
+ const lines = [
22022
+ `# AgentInspect Eval`,
22023
+ "",
22024
+ `Status: ${result.status}`,
22025
+ `Format: ${result.format}`,
22026
+ ...result.runId !== void 0 ? [`Run: ${result.runId}`] : [],
22027
+ `Summary: ${result.summary.passed} passed, ${result.summary.failed} failed, ${result.summary.warnings} warnings, ${result.summary.errors} errors`
22028
+ ];
22029
+ if (result.diagnostics.length > 0) {
22030
+ lines.push("", "## Diagnostics");
22031
+ for (const diagnostic7 of result.diagnostics) {
22032
+ lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
21501
22033
  }
21502
22034
  }
21503
- process.exitCode = exitCodeFor2(result);
21504
- if (options.json) printJson2(result);
21505
- else if (options.markdown) console.log(renderEvalMarkdown(result).trimEnd());
21506
- else printHuman2(result);
22035
+ if (result.findings.length > 0) {
22036
+ lines.push("", "## Findings");
22037
+ for (const finding of result.findings) {
22038
+ const path44 = finding.evidence[0]?.path;
22039
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
22040
+ }
22041
+ }
22042
+ return `${lines.join("\n")}
22043
+ `;
21507
22044
  }
21508
- var BEST_EFFORT_NOTE = "Best-effort local safety verification only; not a compliance, privacy, security, or regulatory certification.";
21509
- var DEFAULT_MAX_STRING_LENGTH = 16384;
21510
- var DEFAULT_MAX_ARRAY_LENGTH = 1e3;
21511
- var DEFAULT_MAX_OBJECT_KEYS = 200;
21512
- var DEFAULT_MAX_SERIALIZED_BYTES = 128 * 1024;
21513
- function parseLimit3(value, label) {
22045
+
22046
+ // packages/cli/src/eval.ts
22047
+ var CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
22048
+ var TS_CONFIG_EXTENSIONS3 = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
22049
+ function diagnostic6(code, message, severity = "error") {
22050
+ return { code, message, severity };
22051
+ }
22052
+ function errorResult4(code, message, format = "unknown") {
22053
+ return {
22054
+ ok: false,
22055
+ status: "error",
22056
+ format,
22057
+ summary: { passed: 0, failed: 0, warnings: 0, errors: 1 },
22058
+ findings: [],
22059
+ diagnostics: [diagnostic6(code, message)]
22060
+ };
22061
+ }
22062
+ function parseNumber2(value, label) {
21514
22063
  if (value === void 0) return void 0;
21515
22064
  const parsed = Number(value);
21516
22065
  if (!Number.isFinite(parsed) || parsed < 0) {
@@ -21518,368 +22067,210 @@ function parseLimit3(value, label) {
21518
22067
  }
21519
22068
  return parsed;
21520
22069
  }
21521
- function stable5(value) {
21522
- if (Array.isArray(value)) return value.map(stable5);
21523
- if (value === null || typeof value !== "object") return value;
21524
- const record = value;
21525
- return Object.fromEntries(
21526
- Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable5(record[key])])
21527
- );
21528
- }
21529
- function safetyDiagnostic(code, message, severity = "error") {
21530
- return { code, message, severity };
21531
- }
21532
- function warningDiagnostics(warnings, unsupportedFields) {
21533
- return [
21534
- ...warnings.map(
21535
- (warning) => safetyDiagnostic(
21536
- warning.code,
21537
- warning.message,
21538
- warning.severity === "error" ? "error" : "warning"
21539
- )
21540
- ),
21541
- ...unsupportedFields.map(
21542
- (field) => safetyDiagnostic(
21543
- "unsupported_field",
21544
- `Reader reported unsupported field: ${field}`,
21545
- "warning"
21546
- )
21547
- )
21548
- ];
22070
+ function asStringArray3(value, label) {
22071
+ if (value === void 0) return void 0;
22072
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
22073
+ throw new Error(`${label} must be an array of strings.`);
22074
+ }
22075
+ return value;
21549
22076
  }
21550
- function diagnosticFromCheck(item) {
21551
- return safetyDiagnostic(item.code, item.message, item.severity);
22077
+ function asConfig(value) {
22078
+ if (value === void 0 || value === null) return {};
22079
+ if (typeof value !== "object" || Array.isArray(value)) {
22080
+ throw new Error("Config must export an object.");
22081
+ }
22082
+ return value;
21552
22083
  }
21553
- function statusFrom(findings, diagnostics) {
21554
- if (diagnostics.some((item) => item.severity === "error")) return "UNKNOWN";
21555
- if (findings.some((item) => item.severity === "error")) return "UNSAFE";
21556
- if (diagnostics.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
21557
- if (findings.some((item) => item.severity === "warning")) return "SAFE WITH WARNINGS";
21558
- return "SAFE";
22084
+ async function loadConfig2(configPath) {
22085
+ if (configPath === void 0) return {};
22086
+ const extension = path33__default.default.extname(configPath);
22087
+ if (TS_CONFIG_EXTENSIONS3.has(extension)) {
22088
+ throw new Error(
22089
+ "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
22090
+ );
22091
+ }
22092
+ if (!CONFIG_EXTENSIONS3.has(extension)) {
22093
+ throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
22094
+ }
22095
+ const absolute = path33__default.default.resolve(configPath);
22096
+ if (extension === ".json") {
22097
+ const raw = await promises.readFile(absolute, "utf-8");
22098
+ return asConfig(JSON.parse(raw));
22099
+ }
22100
+ const mod = await import(url.pathToFileURL(absolute).href);
22101
+ return asConfig("default" in mod ? mod.default : mod);
21559
22102
  }
21560
- function resultFromParts(parts) {
21561
- const findings = [...parts.findings ?? []];
21562
- const diagnostics = [...parts.diagnostics ?? []];
21563
- const warnings = [...parts.warnings ?? []];
21564
- const unsupportedFields = [...parts.unsupportedFields ?? []];
21565
- const status = parts.status ?? statusFrom(findings, diagnostics);
21566
- return {
21567
- ok: status === "SAFE" || status === "SAFE WITH WARNINGS",
21568
- command: parts.command,
21569
- status,
21570
- format: parts.format,
21571
- ...parts.runId !== void 0 ? { runId: parts.runId } : {},
21572
- summary: {
21573
- findings: findings.length,
21574
- warnings: diagnostics.filter((item) => item.severity === "warning").length + findings.filter((item) => item.severity === "warning").length,
21575
- errors: diagnostics.filter((item) => item.severity === "error").length + findings.filter((item) => item.severity === "error").length
21576
- },
21577
- findings,
21578
- diagnostics,
21579
- warnings,
21580
- unsupportedFields,
21581
- note: BEST_EFFORT_NOTE,
21582
- ...parts.sourceAssessment !== void 0 ? { sourceAssessment: parts.sourceAssessment } : {},
21583
- ...parts.artifactAssessment !== void 0 ? { artifactAssessment: parts.artifactAssessment } : {},
21584
- ...parts.redactionSummary !== void 0 ? { redactionSummary: parts.redactionSummary } : {}
21585
- };
22103
+ function normalizeConfig2(config) {
22104
+ if (config.eval === void 0) return {};
22105
+ if (typeof config.eval !== "object" || Array.isArray(config.eval)) {
22106
+ throw new Error("eval config must be an object.");
22107
+ }
22108
+ return config.eval;
21586
22109
  }
21587
- function layerFromResult(result) {
21588
- return {
21589
- status: result.status,
21590
- summary: result.summary,
21591
- findings: result.findings
21592
- };
22110
+ function maybeAdd(rules, value, makeRule) {
22111
+ if (value !== void 0) rules.push(makeRule(value));
21593
22112
  }
21594
- function readErrorResult3(command, error) {
21595
- if (error instanceof TraceReadError) {
21596
- const code = error.code === "unsupported_format" ? "AI_SAFETY_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_SAFETY_AMBIGUOUS_FORMAT" : "AI_SAFETY_TRACE_UNREADABLE";
21597
- return resultFromParts({
21598
- command,
21599
- format: "unknown",
21600
- diagnostics: [safetyDiagnostic(code, error.message)],
21601
- warnings: error.warnings
21602
- });
22113
+ function optionObject(value) {
22114
+ if (value === void 0 || value === false) return void 0;
22115
+ if (value === true) return {};
22116
+ if (typeof value !== "object" || Array.isArray(value)) {
22117
+ throw new Error("Eval heuristic config must be a boolean or object.");
21603
22118
  }
21604
- return resultFromParts({
21605
- command,
21606
- format: "unknown",
21607
- diagnostics: [
21608
- safetyDiagnostic(
21609
- "AI_SAFETY_TRACE_UNREADABLE",
21610
- error instanceof Error ? error.message : String(error)
21611
- )
21612
- ]
21613
- });
22119
+ return value;
21614
22120
  }
21615
- function invalidArgumentResult(command, error) {
21616
- return resultFromParts({
21617
- command,
21618
- format: "unknown",
21619
- diagnostics: [
21620
- safetyDiagnostic(
21621
- "AI_SAFETY_INVALID_ARGUMENTS",
21622
- error instanceof Error ? error.message : String(error)
21623
- )
21624
- ]
21625
- });
22121
+ function sourceIdsFromConfig(value) {
22122
+ if (value === void 0) return void 0;
22123
+ if (Array.isArray(value)) return { ids: asStringArray3(value, "eval.requiredSourceIds") ?? [] };
22124
+ if (typeof value !== "object" || Array.isArray(value)) {
22125
+ throw new Error("eval.requiredSourceIds must be an array or object.");
22126
+ }
22127
+ const ids = asStringArray3(value.ids, "eval.requiredSourceIds.ids") ?? [];
22128
+ return { ids, options: { sourceIdKeys: value.sourceIdKeys } };
21626
22129
  }
21627
- function buildSafetyRules(options) {
21628
- const maxStringLength2 = parseLimit3(options.maxStringLength, "--max-string-length") ?? DEFAULT_MAX_STRING_LENGTH;
21629
- const maxArrayLength = parseLimit3(options.maxArrayLength, "--max-array-length") ?? DEFAULT_MAX_ARRAY_LENGTH;
21630
- const maxObjectKeys = parseLimit3(options.maxObjectKeys, "--max-object-keys") ?? DEFAULT_MAX_OBJECT_KEYS;
21631
- const maxSerializedBytes = parseLimit3(options.maxSerializedBytes, "--max-serialized-bytes") ?? DEFAULT_MAX_SERIALIZED_BYTES;
21632
- return [
21633
- createSafetyRawContentRule(),
21634
- createSafetyRedactionRule(),
21635
- createSafetySecretPatternRule(),
21636
- createSafetyOversizedAttributeRule({
21637
- maxStringLength: maxStringLength2,
21638
- maxArrayLength,
21639
- maxObjectKeys,
21640
- maxSerializedBytes
21641
- })
22130
+ function buildRules2(config, options) {
22131
+ const evalConfig = normalizeConfig2(config);
22132
+ const rules = [];
22133
+ if (evalConfig.requireSuccess || options.requireSuccess) rules.push(checks.requireSuccess());
22134
+ const requiredTools = [
22135
+ ...asStringArray3(evalConfig.requiredTools, "eval.requiredTools") ?? [],
22136
+ ...options.requiredTool ?? []
21642
22137
  ];
21643
- }
21644
- function flattenNodes2(nodes) {
21645
- return nodes.flatMap((node) => [
21646
- node,
21647
- ...flattenNodes2(
21648
- node.children
21649
- )
21650
- ]);
21651
- }
21652
- function detectorSeverity(finding) {
21653
- return finding.severity;
21654
- }
21655
- function classifyRedactionDetector(detector) {
21656
- if (detector === "value.creditCard" || detector === "value.email" || detector === "value.phone") {
21657
- return { category: "personal-data", confidence: "high" };
22138
+ if (requiredTools.length > 0) rules.push(checks.requiredTools(requiredTools));
22139
+ const forbiddenTools = [
22140
+ ...asStringArray3(evalConfig.forbiddenTools, "eval.forbiddenTools") ?? [],
22141
+ ...options.forbidTool ?? [],
22142
+ ...options.forbiddenTool ?? []
22143
+ ];
22144
+ if (forbiddenTools.length > 0) rules.push(checks.forbiddenTools(forbiddenTools));
22145
+ const maxDurationMs = parseNumber2(options.maxDurationMs, "--max-duration-ms") ?? evalConfig.maxDurationMs;
22146
+ maybeAdd(rules, maxDurationMs, checks.maxDurationMs);
22147
+ const maxDepth = parseNumber2(options.maxDepth, "--max-depth") ?? evalConfig.maxDepth;
22148
+ maybeAdd(rules, maxDepth, checks.maxDepth);
22149
+ const maxRetries = parseNumber2(options.maxRetries, "--max-retries") ?? evalConfig.maxRetries;
22150
+ maybeAdd(rules, maxRetries, checks.maxRetries);
22151
+ const maxTotalTokens = parseNumber2(options.maxTotalTokens, "--max-total-tokens") ?? evalConfig.maxTotalTokens;
22152
+ maybeAdd(rules, maxTotalTokens, checks.maxTotalTokens);
22153
+ if (evalConfig.requiredRetrievalBeforeGeneration || options.requireRetrievalBeforeGeneration) {
22154
+ rules.push(checks.requiredRetrievalBeforeGeneration());
21658
22155
  }
21659
- if (detector === "value.ipv4" || detector === "value.ipv6") {
21660
- return { category: "identifier", confidence: "medium" };
22156
+ const requiredDecisionMetadata = [
22157
+ ...asStringArray3(
22158
+ evalConfig.requiredDecisionMetadata,
22159
+ "eval.requiredDecisionMetadata"
22160
+ ) ?? [],
22161
+ ...options.requiredDecisionMetadata ?? []
22162
+ ];
22163
+ if (requiredDecisionMetadata.length > 0) {
22164
+ rules.push(checks.requiredDecisionMetadata(requiredDecisionMetadata));
21661
22165
  }
21662
- 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"))) {
21663
- return { category: "credential", confidence: "high" };
22166
+ const contextOverlap = optionObject(evalConfig.contextOverlap);
22167
+ const minOverlap = parseNumber2(options.minContextOverlap, "--min-context-overlap");
22168
+ const minSharedTerms = parseNumber2(options.minSharedTerms, "--min-shared-terms");
22169
+ if (contextOverlap !== void 0 || options.contextOverlap || minOverlap !== void 0 || minSharedTerms !== void 0) {
22170
+ rules.push(checks.contextOverlap({ ...contextOverlap, minOverlap, minSharedTerms }));
21664
22171
  }
21665
- if (detector.startsWith("key.")) {
21666
- return { category: "credential", confidence: "medium" };
22172
+ const quoteOverlap = optionObject(evalConfig.quoteOverlap);
22173
+ if (quoteOverlap !== void 0 || options.quoteOverlap) {
22174
+ rules.push(checks.quoteOverlap(quoteOverlap));
21667
22175
  }
21668
- return { category: "credential", confidence: "medium" };
21669
- }
21670
- function redactionDetectorFindings(read, runId) {
21671
- const runs = runId === void 0 ? read.runs : read.runs.filter((run) => run.runId === runId);
21672
- const out = [];
21673
- for (const run of runs) {
21674
- for (const node of flattenNodes2(run.children)) {
21675
- const attrs = node.event.attributes;
21676
- if (attrs === void 0) continue;
21677
- const result = redact(attrs, { profile: "share" });
21678
- for (const finding of result.findings) {
21679
- if (finding.action === "keep") continue;
21680
- const taxonomy = classifyRedactionDetector(finding.detector);
21681
- out.push({
21682
- ruleId: "safety.redactDetector",
21683
- severity: detectorSeverity(finding),
21684
- status: finding.severity === "error" ? "fail" : "warning",
21685
- message: `Redaction detector ${finding.detector} matched ${finding.matchKind} at ${finding.path}.`,
21686
- expected: "redacted trace content",
21687
- actual: finding.detector,
21688
- evidence: [
21689
- {
21690
- runId: node.event.runId,
21691
- eventId: node.event.eventId,
21692
- ...node.event.parentId !== void 0 ? { parentId: node.event.parentId } : {},
21693
- kind: node.event.kind,
21694
- name: node.event.name,
21695
- ...node.event.status !== void 0 ? { status: node.event.status } : {},
21696
- path: `attributes.${finding.path.replace(/^\$\.?/, "")}`
21697
- }
21698
- ],
21699
- category: taxonomy.category,
21700
- confidence: taxonomy.confidence,
21701
- detector: finding.detector,
21702
- action: finding.action
21703
- });
21704
- }
21705
- }
22176
+ const citationPresence = optionObject(evalConfig.citationPresence);
22177
+ if (citationPresence !== void 0 || options.citationPresence) {
22178
+ rules.push(checks.citationPresence(citationPresence));
21706
22179
  }
21707
- return out.sort((a, b) => {
21708
- const aEvidence = a.evidence[0];
21709
- const bEvidence = b.evidence[0];
21710
- return (aEvidence?.runId ?? "").localeCompare(bEvidence?.runId ?? "") || (aEvidence?.eventId ?? "").localeCompare(bEvidence?.eventId ?? "") || (aEvidence?.path ?? "").localeCompare(bEvidence?.path ?? "") || a.message.localeCompare(b.message);
21711
- });
22180
+ const sourceIds = sourceIdsFromConfig(evalConfig.requiredSourceIds);
22181
+ const requiredSourceIds = [...sourceIds?.ids ?? [], ...options.requiredSourceId ?? []];
22182
+ if (requiredSourceIds.length > 0) {
22183
+ rules.push(checks.requiredSourceIds(requiredSourceIds, sourceIds?.options));
22184
+ }
22185
+ const cliAnswerLength = {
22186
+ minCharacters: parseNumber2(options.minAnswerCharacters, "--min-answer-characters"),
22187
+ maxCharacters: parseNumber2(options.maxAnswerCharacters, "--max-answer-characters"),
22188
+ minWords: parseNumber2(options.minAnswerWords, "--min-answer-words"),
22189
+ maxWords: parseNumber2(options.maxAnswerWords, "--max-answer-words")
22190
+ };
22191
+ const hasCliAnswerLength = Object.values(cliAnswerLength).some((value) => value !== void 0);
22192
+ if (evalConfig.answerLengthBounds !== void 0 || hasCliAnswerLength) {
22193
+ rules.push(checks.answerLengthBounds({ ...evalConfig.answerLengthBounds, ...cliAnswerLength }));
22194
+ }
22195
+ const bannedPhrases = [
22196
+ ...asStringArray3(
22197
+ evalConfig.bannedUnsupportedPhrases,
22198
+ "eval.bannedUnsupportedPhrases"
22199
+ ) ?? [],
22200
+ ...options.bannedPhrase ?? []
22201
+ ];
22202
+ if (bannedPhrases.length > 0) rules.push(checks.bannedUnsupportedPhrases(bannedPhrases));
22203
+ return rules.length > 0 ? rules : void 0;
21712
22204
  }
21713
22205
  function exitCodeFor3(result) {
21714
- if (result.status === "SAFE" || result.status === "SAFE WITH WARNINGS") return 0;
21715
- if (result.status === "UNSAFE") return 1;
22206
+ if (result.status === "pass") return 0;
22207
+ if (result.status === "fail") return 1;
21716
22208
  return 2;
21717
22209
  }
21718
- function explainFinding(finding, blocksBundle) {
21719
- const path43 = finding.evidence[0]?.path ?? "(unknown path)";
21720
- const category = finding.category ?? "structure";
21721
- const confidence = finding.confidence ?? "medium";
21722
- const detector = finding.detector ?? finding.ruleId;
21723
- const action = finding.action ?? "review";
21724
- 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.";
21725
- return [
21726
- ` Matched: detector=${detector}; path=${path43}; category=${category}`,
21727
- ` Why: ${finding.message}`,
21728
- ` Confidence: ${confidence}`,
21729
- ` Redaction: ${redactionHint}`,
21730
- ` Override: configure a custom redaction/detector rule locally (see docs/SAFETY-POLICY.md); do not weaken defaults globally.`,
21731
- ` Bundle gate: ${blocksBundle ? "blocks share-safe bundle unless --allow-unsafe" : "does not block by itself (warning/info)"}`
21732
- ];
22210
+ function stable5(value) {
22211
+ if (Array.isArray(value)) return value.map(stable5);
22212
+ if (value === null || typeof value !== "object") return value;
22213
+ const record = value;
22214
+ return Object.fromEntries(
22215
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable5(record[key])])
22216
+ );
21733
22217
  }
21734
- function findingExplanation(finding) {
21735
- const blocks = finding.severity === "error" || finding.status === "fail";
21736
- return {
21737
- ruleId: finding.ruleId,
21738
- detector: finding.detector ?? finding.ruleId,
21739
- path: finding.evidence[0]?.path,
21740
- category: finding.category,
21741
- confidence: finding.confidence,
21742
- action: finding.action,
21743
- blocksBundle: blocks,
21744
- // Never include matched secret/PII values.
21745
- message: finding.message
21746
- };
22218
+ function printJson3(result) {
22219
+ console.log(JSON.stringify(stable5(result), null, 2));
21747
22220
  }
21748
- function printHuman3(result, explain = false) {
21749
- console.log(`Safety status: ${result.status}`);
22221
+ function printHuman3(result) {
22222
+ console.log(`Eval status: ${result.status}`);
21750
22223
  console.log(`Format: ${result.format}`);
21751
22224
  if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
21752
- if (result.sourceAssessment !== void 0 && result.artifactAssessment !== void 0) {
21753
- console.log(`Source assessment: ${result.sourceAssessment.status}`);
21754
- console.log(`Artifact assessment: ${result.artifactAssessment.status}`);
21755
- if (result.redactionSummary !== void 0) {
21756
- console.log(
21757
- `Redaction: profile=${result.redactionSummary.profile}, findings=${result.redactionSummary.findings}`
21758
- );
21759
- }
21760
- }
21761
22225
  console.log(
21762
- `Summary: ${result.summary.findings} finding(s), ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
22226
+ `Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
21763
22227
  );
21764
22228
  for (const diagnostic7 of result.diagnostics) {
21765
22229
  console.log(`- ${diagnostic7.code}: ${diagnostic7.message}`);
21766
22230
  }
21767
22231
  for (const finding of result.findings) {
21768
- const path43 = finding.evidence[0]?.path;
21769
- const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
21770
- console.log(`- ${finding.ruleId}: ${finding.message}${path43 ? ` (${path43})` : ""}${taxonomy}`);
21771
- if (explain) {
21772
- const blocks = finding.severity === "error" || finding.status === "fail";
21773
- for (const line of explainFinding(finding, blocks)) {
21774
- console.log(line);
21775
- }
21776
- }
22232
+ const path44 = finding.evidence[0]?.path;
22233
+ console.log(`- ${finding.ruleId}: ${finding.message}${path44 ? ` (${path44})` : ""}`);
21777
22234
  }
21778
- console.log(`Note: ${result.note}`);
21779
22235
  }
21780
- function printJson3(result, explain = false) {
21781
- const payload = explain === true ? { ...result, explanations: result.findings.map(findingExplanation) } : result;
21782
- console.log(JSON.stringify(stable5(payload), null, 2));
22236
+ function readErrorResult3(error) {
22237
+ if (error instanceof TraceReadError) {
22238
+ const code = error.code === "unsupported_format" ? "AI_EVAL_UNSUPPORTED_FORMAT" : error.code === "ambiguous_format" ? "AI_EVAL_AMBIGUOUS_FORMAT" : "AI_EVAL_TRACE_UNREADABLE";
22239
+ return errorResult4(code, error.message);
22240
+ }
22241
+ return errorResult4(
22242
+ "AI_EVAL_TRACE_UNREADABLE",
22243
+ error instanceof Error ? error.message : String(error)
22244
+ );
21783
22245
  }
21784
- async function safetyCommand(command, target, options, stdin) {
22246
+ async function evalCommand(target, options = {}, stdin = process.stdin) {
21785
22247
  let result;
22248
+ let phase = "config";
21786
22249
  try {
22250
+ const config = await loadConfig2(options.config);
22251
+ const rules = buildRules2(config, options);
22252
+ phase = "read";
21787
22253
  const input3 = await inputFromTarget(target, options, stdin);
21788
22254
  const read = await openTrace(input3, {
21789
22255
  ...options.format !== void 0 ? { format: options.format } : {}
21790
22256
  });
21791
- const source = assessOpenedTrace(read, {
21792
- ...options,
22257
+ result = await evalRun(read, {
22258
+ ...rules !== void 0 ? { checks: rules } : {},
21793
22259
  ...options.run !== void 0 ? { runId: options.run } : {}
21794
22260
  });
21795
- if (command === "scan") {
21796
- result = { ...source, command: "scan" };
22261
+ } catch (error) {
22262
+ if (phase === "config") {
22263
+ const message = error instanceof Error ? error.message : String(error);
22264
+ 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";
22265
+ result = errorResult4(code, message);
21797
22266
  } else {
21798
- const profile = options.redactionProfile ?? "share";
21799
- const rawContent = input3.type === "string" ? input3.content : input3.type === "file" ? await promises.readFile(input3.path, "utf-8") : void 0;
21800
- if (rawContent === void 0) {
21801
- result = {
21802
- ...source,
21803
- command: "verify-safe",
21804
- sourceAssessment: layerFromResult(source)
21805
- };
21806
- } else {
21807
- const redacted = redactTraceContent(rawContent, profile);
21808
- const artifactRead = await openTrace(
21809
- { type: "string", content: redacted.content },
21810
- { format: options.format ?? "agent-inspect-jsonl" }
21811
- );
21812
- const artifact = assessOpenedTrace(artifactRead, {
21813
- ...options,
21814
- ...options.run !== void 0 ? { runId: options.run } : {}
21815
- });
21816
- const detectors = [
21817
- ...new Set(redacted.findings.map((finding) => finding.detector))
21818
- ].sort((a, b) => a.localeCompare(b));
21819
- result = resultFromParts({
21820
- command: "verify-safe",
21821
- format: artifact.format,
21822
- runId: artifact.runId ?? source.runId,
21823
- findings: artifact.findings,
21824
- diagnostics: artifact.diagnostics,
21825
- warnings: artifact.warnings,
21826
- unsupportedFields: artifact.unsupportedFields,
21827
- status: artifact.status,
21828
- sourceAssessment: layerFromResult(source),
21829
- artifactAssessment: layerFromResult(artifact),
21830
- redactionSummary: {
21831
- profile,
21832
- findings: redacted.findings.length,
21833
- detectors
21834
- }
21835
- });
21836
- }
22267
+ result = readErrorResult3(error);
21837
22268
  }
21838
- } catch (error) {
21839
- const message = error instanceof Error ? error.message : String(error);
21840
- result = message.startsWith("--") ? invalidArgumentResult(command, error) : readErrorResult3(command, error);
21841
22269
  }
21842
22270
  process.exitCode = exitCodeFor3(result);
21843
- if (options.json) printJson3(result, options.explain === true);
21844
- else printHuman3(result, options.explain === true);
21845
- }
21846
- function scanCommand(target, options = {}, stdin = process.stdin) {
21847
- return safetyCommand("scan", target, options, stdin);
21848
- }
21849
- function verifySafeCommand(target, options = {}, stdin = process.stdin) {
21850
- return safetyCommand("verify-safe", target, options, stdin);
21851
- }
21852
- function assessOpenedTrace(read, options = {}) {
21853
- try {
21854
- const rules = buildSafetyRules(options);
21855
- const checkResult = runTraceChecks(
21856
- { read },
21857
- {
21858
- rules,
21859
- ...options.runId !== void 0 ? { runId: options.runId } : {},
21860
- ...options.run !== void 0 ? { runId: options.run } : {}
21861
- }
21862
- );
21863
- const detectorFindings = checkResult.diagnostics.length === 0 ? redactionDetectorFindings(read, checkResult.runId) : [];
21864
- return resultFromParts({
21865
- command: "verify-safe",
21866
- format: checkResult.format,
21867
- runId: checkResult.runId,
21868
- findings: [...checkResult.findings, ...detectorFindings],
21869
- diagnostics: [
21870
- ...checkResult.diagnostics.map(diagnosticFromCheck),
21871
- ...warningDiagnostics(read.warnings, read.unsupportedFields)
21872
- ],
21873
- warnings: read.warnings,
21874
- unsupportedFields: read.unsupportedFields
21875
- });
21876
- } catch (error) {
21877
- return messageStartsWithDash(error) ? invalidArgumentResult("verify-safe", error) : readErrorResult3("verify-safe", error);
21878
- }
21879
- }
21880
- function messageStartsWithDash(error) {
21881
- const message = error instanceof Error ? error.message : String(error);
21882
- return message.startsWith("--");
22271
+ if (options.json) printJson3(result);
22272
+ else if (options.markdown) console.log(renderEvalMarkdown(result).trimEnd());
22273
+ else printHuman3(result);
21883
22274
  }
21884
22275
  init_advanced();
21885
22276
  var NOTE = "Generated locally by AgentInspect. Artifacts are best-effort summaries, not compliance or security certification.";
@@ -21955,8 +22346,8 @@ function renderCheckSection(result) {
21955
22346
  `Diagnostics: ${result.diagnostics.length}`
21956
22347
  ];
21957
22348
  for (const finding of result.findings.slice(0, 10)) {
21958
- const path43 = finding.evidence[0]?.path ?? "(run)";
21959
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path43})`);
22349
+ const path44 = finding.evidence[0]?.path ?? "(run)";
22350
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path44})`);
21960
22351
  }
21961
22352
  for (const diagnostic7 of result.diagnostics.slice(0, 10)) {
21962
22353
  lines.push(`- ${diagnostic7.code}: ${diagnostic7.message}`);
@@ -22034,8 +22425,8 @@ function renderHtml(trace, check, diff) {
22034
22425
  `;
22035
22426
  }
22036
22427
  async function writeArtifact(outputDir, relativePath, content, files) {
22037
- const outPath = path32__default.default.join(outputDir, relativePath);
22038
- await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
22428
+ const outPath = path33__default.default.join(outputDir, relativePath);
22429
+ await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
22039
22430
  await promises.writeFile(outPath, content, "utf-8");
22040
22431
  files.push(relativePath);
22041
22432
  }
@@ -22064,7 +22455,7 @@ function shouldWriteEvidence(options, status) {
22064
22455
  return status === "unsafe" || status === "regression" || status === "unknown" || status === "warning";
22065
22456
  }
22066
22457
  async function artifactsCommand(target, options = {}, stdin = process.stdin) {
22067
- const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path32__default.default.resolve(options.outputDir.trim()) : "";
22458
+ const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path33__default.default.resolve(options.outputDir.trim()) : "";
22068
22459
  if (outputDir === "") {
22069
22460
  console.error("--output-dir is required.");
22070
22461
  process.exitCode = 1;
@@ -22204,8 +22595,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
22204
22595
  }
22205
22596
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
22206
22597
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
22207
- await promises.mkdir(path32__default.default.dirname(path32__default.default.resolve(summaryTarget)), { recursive: true });
22208
- await promises.appendFile(path32__default.default.resolve(summaryTarget), `
22598
+ await promises.mkdir(path33__default.default.dirname(path33__default.default.resolve(summaryTarget)), { recursive: true });
22599
+ await promises.appendFile(path33__default.default.resolve(summaryTarget), `
22209
22600
  ${renderMarkdown(trace, check, diff)}`, "utf-8");
22210
22601
  }
22211
22602
  const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
@@ -22224,10 +22615,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
22224
22615
  findings: diff?.findings.length ?? 0,
22225
22616
  diagnostics: diff?.diagnostics.length ?? 0
22226
22617
  },
22227
- ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path32__default.default.resolve(summaryTarget) } : {},
22618
+ ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path33__default.default.resolve(summaryTarget) } : {},
22228
22619
  note: NOTE
22229
22620
  };
22230
- await promises.writeFile(path32__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
22621
+ await promises.writeFile(path33__default.default.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
22231
22622
  if (options.json === true) {
22232
22623
  console.log(writeJson3(manifest).trimEnd());
22233
22624
  } else {
@@ -22288,8 +22679,8 @@ async function resolveOutputDir(options, runIds, cwd, format) {
22288
22679
  const location = resolveWorkspaceLocation(cwd);
22289
22680
  const manifest = await readWorkspaceManifestFile(location);
22290
22681
  if (manifest.ok && manifest.manifest) {
22291
- const rel = path32__default.default.relative(location.workspaceDir, normalized);
22292
- if (!rel.startsWith("..") && !path32__default.default.isAbsolute(rel)) {
22682
+ const rel = path33__default.default.relative(location.workspaceDir, normalized);
22683
+ if (!rel.startsWith("..") && !path33__default.default.isAbsolute(rel)) {
22293
22684
  return resolveInsideWorkspace(location.workspaceDir, rel);
22294
22685
  }
22295
22686
  }
@@ -22305,7 +22696,7 @@ async function resolveOutputDir(options, runIds, cwd, format) {
22305
22696
  const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
22306
22697
  const base2 = resolveInsideWorkspace(
22307
22698
  location.workspaceDir,
22308
- path32__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
22699
+ path33__default.default.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
22309
22700
  );
22310
22701
  return format === "zip" ? `${base2}.zip` : base2;
22311
22702
  }
@@ -22710,19 +23101,19 @@ async function bundleCommand(runIdArg, options = {}) {
22710
23101
  let sidecarDir = outputDir;
22711
23102
  if (outputDir.toLowerCase().endsWith(".html")) {
22712
23103
  htmlPath = outputDir;
22713
- sidecarDir = path32__default.default.dirname(outputDir);
23104
+ sidecarDir = path33__default.default.dirname(outputDir);
22714
23105
  } else {
22715
23106
  await promises.mkdir(outputDir, { recursive: true });
22716
- htmlPath = path32__default.default.join(outputDir, EVIDENCE_HTML_FILENAME);
23107
+ htmlPath = path33__default.default.join(outputDir, EVIDENCE_HTML_FILENAME);
22717
23108
  sidecarDir = outputDir;
22718
23109
  }
22719
23110
  await promises.mkdir(sidecarDir, { recursive: true });
22720
23111
  await promises.writeFile(htmlPath, htmlContent, "utf-8");
22721
- await promises.writeFile(path32__default.default.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
23112
+ await promises.writeFile(path33__default.default.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
22722
23113
  outputPath = htmlPath;
22723
23114
  } else if (format === "zip") {
22724
23115
  const zipPath = outputDir.toLowerCase().endsWith(".zip") ? outputDir : `${outputDir}.zip`;
22725
- const zipParent = path32__default.default.dirname(zipPath);
23116
+ const zipParent = path33__default.default.dirname(zipPath);
22726
23117
  await promises.mkdir(zipParent, { recursive: true });
22727
23118
  const entries = [
22728
23119
  ...[...packaged.entries()].map(([relativePath, content]) => ({
@@ -22738,10 +23129,10 @@ async function bundleCommand(runIdArg, options = {}) {
22738
23129
  await promises.mkdir(outputDir, { recursive: true });
22739
23130
  for (const [relativePath, content] of packaged.entries()) {
22740
23131
  const outPath = assertBundlePathContained(outputDir, relativePath);
22741
- await promises.mkdir(path32__default.default.dirname(outPath), { recursive: true });
23132
+ await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
22742
23133
  await promises.writeFile(outPath, content, "utf-8");
22743
23134
  }
22744
- await promises.writeFile(path32__default.default.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
23135
+ await promises.writeFile(path33__default.default.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
22745
23136
  if (!files.includes(EVIDENCE_MANIFEST_FILENAME)) {
22746
23137
  files.push(EVIDENCE_MANIFEST_FILENAME);
22747
23138
  }
@@ -22790,7 +23181,7 @@ function writeJson5(value) {
22790
23181
  `;
22791
23182
  }
22792
23183
  async function bundleVerifyCommand(targetPath, options = {}) {
22793
- const root = path32__default.default.resolve(targetPath.trim() || ".");
23184
+ const root = path33__default.default.resolve(targetPath.trim() || ".");
22794
23185
  const result = await verifyEvidenceDirectory(root, {
22795
23186
  unexpectedFiles: options.unexpected ?? "fail"
22796
23187
  });
@@ -22832,7 +23223,7 @@ function writeJson6(value) {
22832
23223
  }
22833
23224
  async function resolveHtmlPath(root) {
22834
23225
  const candidates = [
22835
- path32__default.default.join(root, "evidence.html"),
23226
+ path33__default.default.join(root, "evidence.html"),
22836
23227
  root.toLowerCase().endsWith(".html") ? root : ""
22837
23228
  ].filter(Boolean);
22838
23229
  for (const candidate of candidates) {
@@ -22847,7 +23238,7 @@ async function resolveHtmlPath(root) {
22847
23238
  );
22848
23239
  }
22849
23240
  async function bundleOpenCommand(targetPath, options = {}) {
22850
- const root = path32__default.default.resolve(targetPath.trim() || ".");
23241
+ const root = path33__default.default.resolve(targetPath.trim() || ".");
22851
23242
  try {
22852
23243
  await promises.access(root);
22853
23244
  } catch {
@@ -22864,7 +23255,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
22864
23255
  try {
22865
23256
  const info = await promises.stat(root);
22866
23257
  if (info.isFile() && root.toLowerCase().endsWith(".html")) {
22867
- verifyRoot = path32__default.default.dirname(root);
23258
+ verifyRoot = path33__default.default.dirname(root);
22868
23259
  }
22869
23260
  } catch {
22870
23261
  }
@@ -22896,7 +23287,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
22896
23287
  let htmlPath;
22897
23288
  try {
22898
23289
  htmlPath = await resolveHtmlPath(
22899
- root.toLowerCase().endsWith(".html") ? path32__default.default.dirname(root) : root
23290
+ root.toLowerCase().endsWith(".html") ? path33__default.default.dirname(root) : root
22900
23291
  );
22901
23292
  if (root.toLowerCase().endsWith(".html")) {
22902
23293
  htmlPath = root;
@@ -22912,7 +23303,7 @@ async function bundleOpenCommand(targetPath, options = {}) {
22912
23303
  return;
22913
23304
  }
22914
23305
  try {
22915
- await promises.readFile(path32__default.default.join(path32__default.default.dirname(htmlPath), "evidence.json"), "utf-8");
23306
+ await promises.readFile(path33__default.default.join(path33__default.default.dirname(htmlPath), "evidence.json"), "utf-8");
22916
23307
  } catch {
22917
23308
  }
22918
23309
  const fileUrl = url.pathToFileURL(htmlPath).href;
@@ -22998,24 +23389,24 @@ function resolveTargetPath(client, projectLocal) {
22998
23389
  if (projectLocal) {
22999
23390
  switch (client) {
23000
23391
  case "cursor":
23001
- return path32__default.default.join(".cursor", "mcp.json");
23392
+ return path33__default.default.join(".cursor", "mcp.json");
23002
23393
  case "claude-code":
23003
- return path32__default.default.join(".mcp.json");
23394
+ return path33__default.default.join(".mcp.json");
23004
23395
  case "codex":
23005
- return path32__default.default.join(".codex", "config.toml.json");
23396
+ return path33__default.default.join(".codex", "config.toml.json");
23006
23397
  case "gemini":
23007
- return path32__default.default.join(".gemini", "settings.json");
23398
+ return path33__default.default.join(".gemini", "settings.json");
23008
23399
  }
23009
23400
  }
23010
23401
  switch (client) {
23011
23402
  case "cursor":
23012
- return path32__default.default.join("~", ".cursor", "mcp.json");
23403
+ return path33__default.default.join("~", ".cursor", "mcp.json");
23013
23404
  case "claude-code":
23014
- return path32__default.default.join("~", ".claude.json");
23405
+ return path33__default.default.join("~", ".claude.json");
23015
23406
  case "codex":
23016
- return path32__default.default.join("~", ".codex", "config.toml");
23407
+ return path33__default.default.join("~", ".codex", "config.toml");
23017
23408
  case "gemini":
23018
- return path32__default.default.join("~", ".gemini", "settings.json");
23409
+ return path33__default.default.join("~", ".gemini", "settings.json");
23019
23410
  }
23020
23411
  }
23021
23412
  async function mcpConfigureCommand(options) {
@@ -23039,8 +23430,8 @@ async function mcpConfigureCommand(options) {
23039
23430
  ];
23040
23431
  let wrote = false;
23041
23432
  if (!dryRun && projectLocal) {
23042
- const abs = path32__default.default.resolve(targetPath);
23043
- await promises.mkdir(path32__default.default.dirname(abs), { recursive: true });
23433
+ const abs = path33__default.default.resolve(targetPath);
23434
+ await promises.mkdir(path33__default.default.dirname(abs), { recursive: true });
23044
23435
  await promises.writeFile(abs, `${JSON.stringify(config, null, 2)}
23045
23436
  `, "utf8");
23046
23437
  wrote = true;
@@ -23200,23 +23591,23 @@ function readManifestDocument(value) {
23200
23591
  };
23201
23592
  }
23202
23593
  function cwdRelative(filePath) {
23203
- const relative = path32__default.default.relative(process.cwd(), path32__default.default.resolve(filePath)).replace(/\\/g, "/");
23204
- if (relative === "" || relative.startsWith("../") || path32__default.default.isAbsolute(relative)) {
23205
- return path32__default.default.basename(filePath);
23594
+ const relative = path33__default.default.relative(process.cwd(), path33__default.default.resolve(filePath)).replace(/\\/g, "/");
23595
+ if (relative === "" || relative.startsWith("../") || path33__default.default.isAbsolute(relative)) {
23596
+ return path33__default.default.basename(filePath);
23206
23597
  }
23207
23598
  return relative;
23208
23599
  }
23209
23600
  async function readReporterManifest(filePath) {
23210
- const absolute = path32__default.default.resolve(filePath);
23601
+ const absolute = path33__default.default.resolve(filePath);
23211
23602
  const raw = await promises.readFile(absolute, "utf-8");
23212
23603
  const document = readManifestDocument(JSON.parse(raw));
23213
23604
  const manifest = document.manifest;
23214
23605
  const results = manifest.results.map((result) => ({
23215
23606
  testId: safeText(result.testId),
23216
23607
  name: safeText(result.name),
23217
- ...result.file === void 0 ? {} : { file: safeText(path32__default.default.basename(result.file)) },
23608
+ ...result.file === void 0 ? {} : { file: safeText(path33__default.default.basename(result.file)) },
23218
23609
  status: result.status,
23219
- ...result.tracePath === void 0 ? {} : { tracePath: safeText(path32__default.default.basename(result.tracePath)) },
23610
+ ...result.tracePath === void 0 ? {} : { tracePath: safeText(path33__default.default.basename(result.tracePath)) },
23220
23611
  artifacts: result.artifacts,
23221
23612
  diagnostics: result.diagnostics
23222
23613
  }));
@@ -23355,15 +23746,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
23355
23746
  return;
23356
23747
  }
23357
23748
  const markdown = renderMarkdown2(result);
23358
- const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path32__default.default.resolve(options.output.trim()) : void 0;
23749
+ const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path33__default.default.resolve(options.output.trim()) : void 0;
23359
23750
  if (outputPath !== void 0) {
23360
- await promises.mkdir(path32__default.default.dirname(outputPath), { recursive: true });
23751
+ await promises.mkdir(path33__default.default.dirname(outputPath), { recursive: true });
23361
23752
  await promises.writeFile(outputPath, markdown, "utf-8");
23362
23753
  }
23363
23754
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
23364
23755
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
23365
- const summaryPath = path32__default.default.resolve(summaryTarget);
23366
- await promises.mkdir(path32__default.default.dirname(summaryPath), { recursive: true });
23756
+ const summaryPath = path33__default.default.resolve(summaryTarget);
23757
+ await promises.mkdir(path33__default.default.dirname(summaryPath), { recursive: true });
23367
23758
  await promises.appendFile(summaryPath, `
23368
23759
  ${markdown}`, "utf-8");
23369
23760
  }
@@ -23548,7 +23939,7 @@ jobs:
23548
23939
  }
23549
23940
  async function planInit(options = {}) {
23550
23941
  const framework = normalizeFramework(options.framework);
23551
- const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
23942
+ const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
23552
23943
  const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
23553
23944
  const candidates = [
23554
23945
  { rel: CONFIG_FILE, content: configTemplate(framework) },
@@ -23563,7 +23954,7 @@ async function planInit(options = {}) {
23563
23954
  }
23564
23955
  const files = [];
23565
23956
  for (const candidate of candidates) {
23566
- const abs = path32__default.default.join(cwd, candidate.rel);
23957
+ const abs = path33__default.default.join(cwd, candidate.rel);
23567
23958
  try {
23568
23959
  await promises.access(abs);
23569
23960
  files.push({
@@ -23584,12 +23975,12 @@ async function writePlannedFiles(plan, cwd, options) {
23584
23975
  if (entry.action === "skip") {
23585
23976
  continue;
23586
23977
  }
23587
- const abs = path32__default.default.join(cwd, entry.path);
23978
+ const abs = path33__default.default.join(cwd, entry.path);
23588
23979
  if (options.dryRun) {
23589
23980
  written.push(entry.path);
23590
23981
  continue;
23591
23982
  }
23592
- await promises.mkdir(path32__default.default.dirname(abs), { recursive: true });
23983
+ await promises.mkdir(path33__default.default.dirname(abs), { recursive: true });
23593
23984
  const demoPath = plan.framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${plan.framework}-demo.mjs`;
23594
23985
  const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate(demoPath) : demoTemplate(plan.framework);
23595
23986
  await promises.writeFile(abs, content, "utf-8");
@@ -23598,7 +23989,7 @@ async function writePlannedFiles(plan, cwd, options) {
23598
23989
  return written;
23599
23990
  }
23600
23991
  async function initCommand(options = {}) {
23601
- const cwd = path32__default.default.resolve(options.cwd ?? process.cwd());
23992
+ const cwd = path33__default.default.resolve(options.cwd ?? process.cwd());
23602
23993
  try {
23603
23994
  const plan = await planInit({ ...options, cwd });
23604
23995
  const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
@@ -23647,6 +24038,9 @@ async function initCommand(options = {}) {
23647
24038
  process.exitCode = 1;
23648
24039
  }
23649
24040
  }
24041
+ var DOCS_BASE = "https://github.com/rajudandigam/agent-inspect/blob/main/docs";
24042
+ var AGENT_INSPECT_NOT_RESOLVABLE_MESSAGE = "agent-inspect does not resolve from this project. A global CLI install is not enough \u2014 the package must be a dependency here.";
24043
+ var AGENT_INSPECT_NOT_RESOLVABLE_REMEDIATION = `Install it in this project: npm install agent-inspect (or pnpm add agent-inspect). See ${DOCS_BASE}/FIRST-TRACE-IN-5-MINUTES.md`;
23650
24044
  var OPTIONAL_PACKAGES = {
23651
24045
  custom: [],
23652
24046
  "ai-sdk": ["@agent-inspect/ai-sdk"],
@@ -23661,7 +24055,7 @@ function nodeVersionCheck() {
23661
24055
  id: "node-version",
23662
24056
  status: "fail",
23663
24057
  message: `Node ${process3__default.default.versions.node} is below the supported minimum (20).`,
23664
- remediation: "Upgrade to Node 20 LTS or newer.",
24058
+ remediation: `Upgrade to Node 20 LTS or newer, then reinstall. See ${DOCS_BASE}/GETTING-STARTED.md`,
23665
24059
  evidence: process3__default.default.versions.node
23666
24060
  };
23667
24061
  }
@@ -23690,7 +24084,7 @@ function envCheck(name, optional = true) {
23690
24084
  };
23691
24085
  }
23692
24086
  async function traceDirWritable(traceDir) {
23693
- const resolved = path32__default.default.resolve(traceDir);
24087
+ const resolved = path33__default.default.resolve(traceDir);
23694
24088
  try {
23695
24089
  await promises.mkdir(resolved, { recursive: true });
23696
24090
  await promises.access(resolved, promises.constants.W_OK);
@@ -23705,16 +24099,16 @@ async function traceDirWritable(traceDir) {
23705
24099
  id: "trace-dir-writable",
23706
24100
  status: "fail",
23707
24101
  message: `Trace directory is not writable: ${resolved}`,
23708
- remediation: "Create the directory or set AGENT_INSPECT_TRACE_DIR to a writable path.",
24102
+ remediation: `Create the directory or set AGENT_INSPECT_TRACE_DIR to a writable path. See ${DOCS_BASE}/GETTING-STARTED.md`,
23709
24103
  evidence: error instanceof Error ? error.message : String(error)
23710
24104
  };
23711
24105
  }
23712
24106
  }
23713
24107
  function readPackageVersionNearEntry(entryPath, packageName) {
23714
- let dir = path32__default.default.dirname(path32__default.default.resolve(entryPath));
23715
- const { root } = path32__default.default.parse(dir);
24108
+ let dir = path33__default.default.dirname(path33__default.default.resolve(entryPath));
24109
+ const { root } = path33__default.default.parse(dir);
23716
24110
  while (true) {
23717
- const candidate = path32__default.default.join(dir, "package.json");
24111
+ const candidate = path33__default.default.join(dir, "package.json");
23718
24112
  if (fs.existsSync(candidate)) {
23719
24113
  try {
23720
24114
  const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
@@ -23725,14 +24119,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
23725
24119
  }
23726
24120
  }
23727
24121
  if (dir === root) break;
23728
- const parent = path32__default.default.dirname(dir);
24122
+ const parent = path33__default.default.dirname(dir);
23729
24123
  if (parent === dir) break;
23730
24124
  dir = parent;
23731
24125
  }
23732
24126
  return void 0;
23733
24127
  }
23734
24128
  function resolveInstalledPackage(cwd, name) {
23735
- const require2 = module$1.createRequire(path32__default.default.join(cwd, "package.json"));
24129
+ const require2 = module$1.createRequire(path33__default.default.join(cwd, "package.json"));
23736
24130
  try {
23737
24131
  const entry = require2.resolve(name);
23738
24132
  let version2;
@@ -23768,8 +24162,8 @@ function importSmoke(cwd) {
23768
24162
  results.push({
23769
24163
  id: "import-agent-inspect",
23770
24164
  status: "warn",
23771
- message: "agent-inspect is not installed in the current project.",
23772
- remediation: "Run npm install agent-inspect (or pnpm add agent-inspect)."
24165
+ message: AGENT_INSPECT_NOT_RESOLVABLE_MESSAGE,
24166
+ remediation: AGENT_INSPECT_NOT_RESOLVABLE_REMEDIATION
23773
24167
  });
23774
24168
  results.push({
23775
24169
  id: "import-agent-inspect-cjs",
@@ -23818,8 +24212,8 @@ function versionMismatchCheck(cwd) {
23818
24212
  return {
23819
24213
  id: "version-alignment",
23820
24214
  status: "warn",
23821
- message: `CLI version ${version} differs from local agent-inspect@${root.version}.`,
23822
- remediation: "Align versions with npm install agent-inspect@latest",
24215
+ message: `CLI version ${version} differs from local agent-inspect@${root.version}. A packed consumer can hit this when npx uses a cached global CLI.`,
24216
+ remediation: `Align versions with npm install agent-inspect@${version}, or run via the local binary. See ${DOCS_BASE}/KNOWN-ISSUES.md`,
23823
24217
  evidence: `cli=${version};local=${root.version}`
23824
24218
  };
23825
24219
  }
@@ -23830,7 +24224,7 @@ function versionMismatchCheck(cwd) {
23830
24224
  };
23831
24225
  }
23832
24226
  async function runDoctorChecks(options = {}) {
23833
- const cwd = path32__default.default.resolve(options.cwd ?? process3__default.default.cwd());
24227
+ const cwd = path33__default.default.resolve(options.cwd ?? process3__default.default.cwd());
23834
24228
  const traceDir = options.traceDir?.trim() || process3__default.default.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
23835
24229
  const checks2 = [
23836
24230
  nodeVersionCheck(),
@@ -24070,7 +24464,7 @@ function parsePluginManifest(input3) {
24070
24464
  };
24071
24465
  }
24072
24466
  async function readPluginManifestFile(packageDir) {
24073
- const manifestPath = path32__default.default.join(packageDir, PLUGIN_MANIFEST_FILENAME);
24467
+ const manifestPath = path33__default.default.join(packageDir, PLUGIN_MANIFEST_FILENAME);
24074
24468
  try {
24075
24469
  const raw = await promises.readFile(manifestPath, "utf8");
24076
24470
  const parsed = parsePluginManifest(JSON.parse(raw));
@@ -24145,7 +24539,7 @@ function createTraceDirectoryIndexer() {
24145
24539
  // packages/cli/src/plugins.ts
24146
24540
  async function readPackageName(packageDir) {
24147
24541
  try {
24148
- const raw = await promises.readFile(path32__default.default.join(packageDir, "package.json"), "utf8");
24542
+ const raw = await promises.readFile(path33__default.default.join(packageDir, "package.json"), "utf8");
24149
24543
  const parsed = JSON.parse(raw);
24150
24544
  return typeof parsed.name === "string" ? parsed.name : void 0;
24151
24545
  } catch {
@@ -24153,7 +24547,7 @@ async function readPackageName(packageDir) {
24153
24547
  }
24154
24548
  }
24155
24549
  async function discoverPlugins(cwd = process.cwd()) {
24156
- const nodeModules = path32__default.default.join(cwd, "node_modules");
24550
+ const nodeModules = path33__default.default.join(cwd, "node_modules");
24157
24551
  const found = [];
24158
24552
  let entries;
24159
24553
  try {
@@ -24164,7 +24558,7 @@ async function discoverPlugins(cwd = process.cwd()) {
24164
24558
  for (const entry of entries.sort()) {
24165
24559
  if (entry.startsWith("@")) continue;
24166
24560
  if (!isPluginPackageName(entry)) continue;
24167
- const packageDir = path32__default.default.join(nodeModules, entry);
24561
+ const packageDir = path33__default.default.join(nodeModules, entry);
24168
24562
  const manifestRead = await readPluginManifestFile(packageDir);
24169
24563
  found.push({
24170
24564
  packageName: entry,
@@ -24177,7 +24571,7 @@ async function discoverPlugins(cwd = process.cwd()) {
24177
24571
  return found;
24178
24572
  }
24179
24573
  async function validatePluginPackage(packageRef, cwd = process.cwd()) {
24180
- const packageDir = path32__default.default.isAbsolute(packageRef) ? packageRef : path32__default.default.join(cwd, "node_modules", packageRef);
24574
+ const packageDir = path33__default.default.isAbsolute(packageRef) ? packageRef : path33__default.default.join(cwd, "node_modules", packageRef);
24181
24575
  const packageName = await readPackageName(packageDir) ?? packageRef;
24182
24576
  const errors = [];
24183
24577
  const warnings = [];
@@ -24254,7 +24648,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
24254
24648
  init_advanced();
24255
24649
  var INDEX_FILENAME = ".agent-inspect-index.json";
24256
24650
  function traceIndexPath(traceDir) {
24257
- return path32__default.default.join(traceDir, INDEX_FILENAME);
24651
+ return path33__default.default.join(traceDir, INDEX_FILENAME);
24258
24652
  }
24259
24653
  function parseMaxEntries(raw) {
24260
24654
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -24400,7 +24794,7 @@ async function newestTraceMtimeMs2(traceDir) {
24400
24794
  for (const file of files) {
24401
24795
  if (!file.endsWith(".jsonl")) continue;
24402
24796
  try {
24403
- const s = await promises.stat(path32__default.default.join(traceDir, file));
24797
+ const s = await promises.stat(path33__default.default.join(traceDir, file));
24404
24798
  if (s.mtimeMs > newest) newest = s.mtimeMs;
24405
24799
  } catch {
24406
24800
  }
@@ -24655,11 +25049,11 @@ function printJson5(value) {
24655
25049
  console.log(JSON.stringify(value, null, 2));
24656
25050
  }
24657
25051
  function resolveCwd(options) {
24658
- return path32__default.default.resolve(options.cwd ?? process.cwd());
25052
+ return path33__default.default.resolve(options.cwd ?? process.cwd());
24659
25053
  }
24660
25054
  async function suiteInitCommand(options = {}) {
24661
25055
  const cwd = resolveCwd(options);
24662
- const configPath = path32__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
25056
+ const configPath = path33__default.default.join(cwd, DEFAULT_CONFIG_FILENAME);
24663
25057
  const template = options.template?.trim();
24664
25058
  const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
24665
25059
  if (options.dryRun) {
@@ -24778,13 +25172,13 @@ async function suiteListCommand(options = {}) {
24778
25172
  }
24779
25173
  async function writeSuiteArtifact(result, configOutputDir, options) {
24780
25174
  const cwd = resolveCwd(options);
24781
- const outputDir = path32__default.default.resolve(
25175
+ const outputDir = path33__default.default.resolve(
24782
25176
  cwd,
24783
25177
  options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
24784
25178
  );
24785
25179
  await promises.mkdir(outputDir, { recursive: true });
24786
25180
  const stamp = result.startedAt.replace(/[:.]/g, "-");
24787
- const filePath = path32__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
25181
+ const filePath = path33__default.default.join(outputDir, `${result.suiteName}-${stamp}.json`);
24788
25182
  await promises.writeFile(filePath, `${JSON.stringify(result, null, 2)}
24789
25183
  `, "utf-8");
24790
25184
  return filePath;
@@ -24842,7 +25236,7 @@ async function loadSuiteResultFromInput(options) {
24842
25236
  if (options.input === void 0 || options.input.trim() === "") {
24843
25237
  throw new Error("Pass --input <suite-run.json> from a prior suite run.");
24844
25238
  }
24845
- const inputPath = path32__default.default.resolve(cwd, options.input.trim());
25239
+ const inputPath = path33__default.default.resolve(cwd, options.input.trim());
24846
25240
  const raw = await promises.readFile(inputPath, "utf-8");
24847
25241
  return JSON.parse(raw);
24848
25242
  }
@@ -24885,9 +25279,9 @@ function normalizeMetrics2(raw) {
24885
25279
  }
24886
25280
  async function writeArtifacts(result, outputDir) {
24887
25281
  await promises.mkdir(outputDir, { recursive: true });
24888
- const jsonPath = path32__default.default.join(outputDir, "cohort-results.json");
24889
- const markdownPath = path32__default.default.join(outputDir, "cohort-summary.md");
24890
- const htmlPath = path32__default.default.join(outputDir, "cohort-report.html");
25282
+ const jsonPath = path33__default.default.join(outputDir, "cohort-results.json");
25283
+ const markdownPath = path33__default.default.join(outputDir, "cohort-summary.md");
25284
+ const htmlPath = path33__default.default.join(outputDir, "cohort-report.html");
24891
25285
  await promises.writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
24892
25286
  `, "utf-8");
24893
25287
  await promises.writeFile(
@@ -24916,7 +25310,7 @@ async function cohortCommand(options = {}) {
24916
25310
  const format = options.format ?? (options.json ? "json" : "markdown");
24917
25311
  let artifacts;
24918
25312
  if (options.output !== void 0 && options.output.trim() !== "") {
24919
- artifacts = await writeArtifacts(result, path32__default.default.resolve(options.output.trim()));
25313
+ artifacts = await writeArtifacts(result, path33__default.default.resolve(options.output.trim()));
24920
25314
  }
24921
25315
  if (options.json || format === "json") {
24922
25316
  console.log(
@@ -24989,11 +25383,11 @@ function parseDuration2(value) {
24989
25383
  async function writeArtifacts2(result, outputDir) {
24990
25384
  await promises.mkdir(outputDir, { recursive: true });
24991
25385
  const paths = {
24992
- jsonPath: path32__default.default.join(outputDir, "gate-results.json"),
24993
- markdownPath: path32__default.default.join(outputDir, "gate-summary.md"),
24994
- htmlPath: path32__default.default.join(outputDir, "gate-report.html"),
24995
- junitPath: path32__default.default.join(outputDir, "junit.xml"),
24996
- githubPath: path32__default.default.join(outputDir, "github-step-summary.md")
25386
+ jsonPath: path33__default.default.join(outputDir, "gate-results.json"),
25387
+ markdownPath: path33__default.default.join(outputDir, "gate-summary.md"),
25388
+ htmlPath: path33__default.default.join(outputDir, "gate-report.html"),
25389
+ junitPath: path33__default.default.join(outputDir, "junit.xml"),
25390
+ githubPath: path33__default.default.join(outputDir, "github-step-summary.md")
24997
25391
  };
24998
25392
  await promises.writeFile(
24999
25393
  paths.jsonPath,
@@ -25061,7 +25455,7 @@ async function gateCommand(options = {}) {
25061
25455
  const result = await runGate(runs, gateOptions);
25062
25456
  let artifacts;
25063
25457
  if (options.output !== void 0 && options.output.trim() !== "") {
25064
- artifacts = await writeArtifacts2(result, path32__default.default.resolve(options.output.trim()));
25458
+ artifacts = await writeArtifacts2(result, path33__default.default.resolve(options.output.trim()));
25065
25459
  }
25066
25460
  const failed = !result.ok;
25067
25461
  if (shouldEmitEvidence(options.evidenceOn, failed)) {
@@ -25368,7 +25762,7 @@ function createCliProgram() {
25368
25762
  "openinference-json",
25369
25763
  "otlp-json"
25370
25764
  ])
25371
- ).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) => {
25765
+ ).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) => {
25372
25766
  runCommand(() => scanCommand(target, opts));
25373
25767
  });
25374
25768
  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(
@@ -25377,7 +25771,7 @@ function createCliProgram() {
25377
25771
  "openinference-json",
25378
25772
  "otlp-json"
25379
25773
  ])
25380
- ).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) => {
25774
+ ).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) => {
25381
25775
  runCommand(() => verifySafeCommand(target, opts));
25382
25776
  });
25383
25777
  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(
@@ -25537,7 +25931,10 @@ function createCliProgram() {
25537
25931
  "--redaction-profile <profile>",
25538
25932
  "alias for --profile (canonical spelling)"
25539
25933
  ).choices(["local", "share", "strict"])
25540
- ).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) => {
25934
+ ).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(
25935
+ "--fail-on-residual",
25936
+ "exit non-zero when residual safety is UNSAFE or UNKNOWN (opt-in)"
25937
+ ).action((target, opts) => {
25541
25938
  runCommand(() => redactCommand(target, opts));
25542
25939
  });
25543
25940
  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(
@@ -25719,9 +26116,9 @@ function isPrimaryModule() {
25719
26116
  if (!entry) return false;
25720
26117
  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)));
25721
26118
  try {
25722
- return fs.realpathSync(path32__default.default.resolve(entry)) === fs.realpathSync(path32__default.default.resolve(selfPath));
26119
+ return fs.realpathSync(path33__default.default.resolve(entry)) === fs.realpathSync(path33__default.default.resolve(selfPath));
25723
26120
  } catch {
25724
- return path32__default.default.resolve(entry) === path32__default.default.resolve(selfPath);
26121
+ return path33__default.default.resolve(entry) === path33__default.default.resolve(selfPath);
25725
26122
  }
25726
26123
  }
25727
26124
  if (isPrimaryModule()) {