agent-inspect 5.0.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, enrichSessionRunRecord, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, extractMetadata, filterTraces, truncateName, getTraceFilePath, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, openTrace, TraceReadError, filterMetasBySessionScope, runTraceChecks, aggregateSessionCheckResults, createBaselineRegressionRule, resolveBundleRunIds, aggregateBundleSafeStatus, bundleFailsOnSafety, buildPlaceholderArtifact, buildBundleMetadata, buildBundleSummaryMarkdown, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, Redactor, TreeBuilder, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, normalizeBundleOutputPath, defaultBundleOutputPath, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, DEFAULT_SUITE_ARTIFACTS_DIR, nanoid, resolveRedactionProfile, applyProfileMetadataCaps, truncateStringForProfile } from './chunk-TB45H3QT.mjs';
2
+ import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, enrichSessionRunRecord, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, extractMetadata, filterTraces, truncateName, getTraceFilePath, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, openTrace, TraceReadError, filterMetasBySessionScope, runTraceChecks, aggregateSessionCheckResults, createBaselineRegressionRule, resolveBundleRunIds, aggregateBundleSafeStatus, bundleFailsOnSafety, buildPlaceholderArtifact, buildBundleMetadata, buildBundleSummaryMarkdown, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, Redactor, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, normalizeBundleOutputPath, defaultBundleOutputPath, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, escapeMarkdown, escapeHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, resolveRedactionProfile, applyProfileMetadataCaps, flattenTree, safeString, compactAttributes, stableJson, truncateStringForProfile } from './chunk-SJ5R2XBE.mjs';
3
3
  import { realpathSync, constants as constants$1 } from 'fs';
4
4
  import path12 from 'path';
5
5
  import { fileURLToPath, pathToFileURL } from 'url';
@@ -11,7 +11,7 @@ import { createServer } from 'http';
11
11
  import { createRequire } from 'module';
12
12
 
13
13
  // package.json
14
- var version = "5.0.0";
14
+ var version = "5.2.0";
15
15
 
16
16
  // packages/cli/src/trace-dir-scale.ts
17
17
  var TRACE_COUNT_WARN = 1e3;
@@ -923,7 +923,7 @@ function matchMapping(eventName, mappings) {
923
923
  function isFiniteNumber(v) {
924
924
  return typeof v === "number" && Number.isFinite(v);
925
925
  }
926
- function safeString(v) {
926
+ function safeString2(v) {
927
927
  if (typeof v !== "string") return void 0;
928
928
  const t = v.trim();
929
929
  return t === "" ? void 0 : t;
@@ -973,7 +973,7 @@ var EventNormalizer = class {
973
973
  let runId;
974
974
  for (const k of cfg.runIdKeys) {
975
975
  const v = raw[k];
976
- const s = safeString(v);
976
+ const s = safeString2(v);
977
977
  if (s) {
978
978
  runId = s;
979
979
  break;
@@ -989,7 +989,7 @@ var EventNormalizer = class {
989
989
  }
990
990
  };
991
991
  }
992
- const eventName = safeString(raw[cfg.eventKey]);
992
+ const eventName = safeString2(raw[cfg.eventKey]);
993
993
  if (!eventName) {
994
994
  return {
995
995
  warning: {
@@ -1007,7 +1007,7 @@ var EventNormalizer = class {
1007
1007
  const timestamp = parsedTs ?? Date.now();
1008
1008
  const timestampMissing = parsedTs === void 0;
1009
1009
  const parentIdKey = cfg.parentIdKey;
1010
- const parentId = parentIdKey ? safeString(raw[parentIdKey]) : void 0;
1010
+ const parentId = parentIdKey ? safeString2(raw[parentIdKey]) : void 0;
1011
1011
  let durationMs2;
1012
1012
  const durationKey = cfg.durationKey;
1013
1013
  if (durationKey) {
@@ -1018,7 +1018,7 @@ var EventNormalizer = class {
1018
1018
  }
1019
1019
  let status;
1020
1020
  const statusKey = cfg.statusKey;
1021
- const statusRaw = statusKey ? safeString(raw[statusKey]) : void 0;
1021
+ const statusRaw = statusKey ? safeString2(raw[statusKey]) : void 0;
1022
1022
  if (statusRaw === "running" || statusRaw === "ok" || statusRaw === "error") {
1023
1023
  status = statusRaw;
1024
1024
  } else if (mapping?.status) {
@@ -1950,114 +1950,6 @@ function redactRunTreeForExport(tree, options) {
1950
1950
  return clone;
1951
1951
  }
1952
1952
 
1953
- // packages/core/src/exporters/helpers.ts
1954
- var REDACT_SUBSTRINGS = [
1955
- "authorization",
1956
- "cookie",
1957
- "token",
1958
- "apikey",
1959
- "password",
1960
- "secret",
1961
- "email"
1962
- ];
1963
- function shouldRedactKey(key) {
1964
- const k = key.toLowerCase();
1965
- for (const s of REDACT_SUBSTRINGS) {
1966
- if (k.includes(s)) return true;
1967
- }
1968
- return false;
1969
- }
1970
- function safeString2(value, maxLength) {
1971
- if (value === null || value === void 0) return "";
1972
- let s;
1973
- if (typeof value === "string") s = value;
1974
- else if (typeof value === "number" || typeof value === "boolean") s = String(value);
1975
- else s = stableJson(value, false);
1976
- if (maxLength !== void 0 && maxLength >= 0 && s.length > maxLength) {
1977
- return `${s.slice(0, maxLength)}\u2026`;
1978
- }
1979
- return s;
1980
- }
1981
- function escapeMarkdown(value) {
1982
- return value.replace(/\|/g, "\\|").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n/g, " ");
1983
- }
1984
- function escapeHtml(value) {
1985
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1986
- }
1987
- function sortKeysDeep(input3) {
1988
- if (input3 === null || typeof input3 !== "object") return input3;
1989
- if (Array.isArray(input3)) return input3.map(sortKeysDeep);
1990
- const o = input3;
1991
- const out = {};
1992
- for (const k of Object.keys(o).sort()) {
1993
- out[k] = sortKeysDeep(o[k]);
1994
- }
1995
- return out;
1996
- }
1997
- function stableJson(value, pretty) {
1998
- const sorted = sortKeysDeep(value);
1999
- return pretty === true ? JSON.stringify(sorted, null, 2) : JSON.stringify(sorted);
2000
- }
2001
- function compactAttributes(attrs, options) {
2002
- if (attrs === void 0) return {};
2003
- const maxLen = options?.maxLength ?? 500;
2004
- const redacted = options?.redacted ?? true;
2005
- const out = {};
2006
- for (const key of Object.keys(attrs).sort()) {
2007
- if (redacted && shouldRedactKey(key)) {
2008
- out[key] = "[REDACTED]";
2009
- continue;
2010
- }
2011
- const v = attrs[key];
2012
- out[key] = compactValue(v, maxLen, redacted);
2013
- }
2014
- return out;
2015
- }
2016
- function compactValue(value, maxLen, redacted) {
2017
- if (value === null || typeof value !== "object") {
2018
- return typeof value === "string" ? safeString2(value, maxLen) : value;
2019
- }
2020
- if (Array.isArray(value)) {
2021
- const arr = value.slice(0, 20).map((x) => compactValue(x, maxLen, redacted));
2022
- if (value.length > 20) arr.push(`\u2026(+${value.length - 20} more)`);
2023
- return arr;
2024
- }
2025
- const o = value;
2026
- const inner = {};
2027
- for (const k of Object.keys(o)) {
2028
- if (redacted && shouldRedactKey(k)) inner[k] = "[REDACTED]";
2029
- else inner[k] = compactValue(o[k], maxLen, redacted);
2030
- }
2031
- return inner;
2032
- }
2033
- function flattenTree(tree) {
2034
- const out = [];
2035
- function walk(nodes) {
2036
- for (const n of nodes) {
2037
- out.push(n);
2038
- if (n.children.length > 0) walk(n.children);
2039
- }
2040
- }
2041
- walk(tree.children);
2042
- return out;
2043
- }
2044
- function zeroKinds() {
2045
- return {
2046
- RUN: 0,
2047
- AGENT: 0,
2048
- LLM: 0,
2049
- TOOL: 0,
2050
- CHAIN: 0,
2051
- RETRIEVER: 0,
2052
- DECISION: 0,
2053
- RESULT: 0,
2054
- ERROR: 0,
2055
- LOGIC: 0,
2056
- LOG: 0,
2057
- OUTCOME: 0
2058
- };
2059
- }
2060
-
2061
1953
  // packages/core/src/exporters/html-exporter.ts
2062
1954
  function renderTreeHtml(nodes, ulClass = "tree") {
2063
1955
  if (nodes.length === 0) return "";
@@ -2131,7 +2023,7 @@ function exportHtml(tree, options) {
2131
2023
  if (includeErrors && errors.length > 0) {
2132
2024
  errorsHtml += "<h2>Errors</h2><ul>";
2133
2025
  for (const n of errors) {
2134
- const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString2(
2026
+ const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString(
2135
2027
  n.event.attributes.error.message,
2136
2028
  maxLen
2137
2029
  ) : "";
@@ -2280,7 +2172,7 @@ function exportMarkdown(tree, options) {
2280
2172
  lines.push("## Errors");
2281
2173
  lines.push("");
2282
2174
  for (const n of errors) {
2283
- const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString2(
2175
+ const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString(
2284
2176
  n.event.attributes.error.message,
2285
2177
  maxLen
2286
2178
  ) : "";
@@ -3237,13 +3129,13 @@ function pairSteps(left, right) {
3237
3129
  return pairs;
3238
3130
  }
3239
3131
  function compareLeafSteps(L, R, segments, opts, out) {
3240
- const path19 = buildPath(segments);
3132
+ const path21 = buildPath(segments);
3241
3133
  if (L.name !== R.name) {
3242
3134
  out.push({
3243
3135
  kind: "structure",
3244
3136
  severity: "warning",
3245
3137
  message: "Step name differs",
3246
- path: path19,
3138
+ path: path21,
3247
3139
  left: L.name,
3248
3140
  right: R.name
3249
3141
  });
@@ -3253,7 +3145,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
3253
3145
  kind: "step-type",
3254
3146
  severity: "warning",
3255
3147
  message: "Step type differs",
3256
- path: path19,
3148
+ path: path21,
3257
3149
  left: L.type,
3258
3150
  right: R.type
3259
3151
  });
@@ -3263,7 +3155,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
3263
3155
  kind: "step-status",
3264
3156
  severity: "warning",
3265
3157
  message: "Step status differs",
3266
- path: path19,
3158
+ path: path21,
3267
3159
  left: L.status,
3268
3160
  right: R.status
3269
3161
  });
@@ -3275,7 +3167,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
3275
3167
  kind: "error",
3276
3168
  severity: "error",
3277
3169
  message: "Step error message differs",
3278
- path: path19,
3170
+ path: path21,
3279
3171
  left: le || void 0,
3280
3172
  right: re || void 0
3281
3173
  });
@@ -3293,7 +3185,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
3293
3185
  kind: "duration",
3294
3186
  severity: "info",
3295
3187
  message: "Step duration differs",
3296
- path: path19,
3188
+ path: path21,
3297
3189
  left: ld,
3298
3190
  right: rd
3299
3191
  });
@@ -3306,7 +3198,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
3306
3198
  kind: "metadata",
3307
3199
  severity: "info",
3308
3200
  message: "Step metadata differs",
3309
- path: path19,
3201
+ path: path21,
3310
3202
  left: L.metadata,
3311
3203
  right: R.metadata
3312
3204
  });
@@ -3318,7 +3210,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
3318
3210
  kind: "output",
3319
3211
  severity: "info",
3320
3212
  message: "Output preview differs",
3321
- path: path19,
3213
+ path: path21,
3322
3214
  left: L.outputPreview,
3323
3215
  right: R.outputPreview
3324
3216
  });
@@ -3478,11 +3370,11 @@ function diffRuns(left, right, options) {
3478
3370
  }
3479
3371
 
3480
3372
  // packages/core/src/diff/renderer.ts
3481
- function formatPath(path19) {
3482
- if (path19 === void 0 || path19.path.length === 0) {
3373
+ function formatPath(path21) {
3374
+ if (path21 === void 0 || path21.path.length === 0) {
3483
3375
  return "(run)";
3484
3376
  }
3485
- return path19.path.map((s) => s.name).join(" > ");
3377
+ return path21.path.map((s) => s.name).join(" > ");
3486
3378
  }
3487
3379
  function formatValue(v, verbose) {
3488
3380
  if (v === void 0) return "(undefined)";
@@ -3890,7 +3782,7 @@ async function newestTraceMtimeMs(traceDir) {
3890
3782
  }
3891
3783
  async function loadSessionRuns(traceDir) {
3892
3784
  try {
3893
- const mod = await import('./src-ZRFSYML6.mjs');
3785
+ const mod = await import('./src-PK22BBMH.mjs');
3894
3786
  const dbPath = mod.resolveIndexDbPath(traceDir);
3895
3787
  const status = mod.indexStatus(dbPath);
3896
3788
  if (!status.healthy) {
@@ -4587,17 +4479,17 @@ function applyRule(rule, value, replacement) {
4587
4479
  }
4588
4480
  return value;
4589
4481
  }
4590
- function childPath(path19, key) {
4482
+ function childPath(path21, key) {
4591
4483
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
4592
- return path19 ? `${path19}.${key}` : key;
4484
+ return path21 ? `${path21}.${key}` : key;
4593
4485
  }
4594
- return `${path19 || "$"}[${JSON.stringify(key)}]`;
4486
+ return `${path21 || "$"}[${JSON.stringify(key)}]`;
4595
4487
  }
4596
- function indexPath(path19, index) {
4597
- return `${path19 || "$"}[${index}]`;
4488
+ function indexPath(path21, index) {
4489
+ return `${path21 || "$"}[${index}]`;
4598
4490
  }
4599
- function makeFinding(path19, detector, action, matchKind, severity = "warning", preview) {
4600
- return preview === void 0 ? { path: path19, detector, action, severity, matchKind } : { path: path19, detector, action, severity, matchKind, preview };
4491
+ function makeFinding(path21, detector, action, matchKind, severity = "warning", preview) {
4492
+ return preview === void 0 ? { path: path21, detector, action, severity, matchKind } : { path: path21, detector, action, severity, matchKind, preview };
4601
4493
  }
4602
4494
  function createRedactionProfile(profile = "local") {
4603
4495
  switch (profile) {
@@ -4666,11 +4558,11 @@ var Redactor2 = class {
4666
4558
  #recordFinding(state, finding) {
4667
4559
  if (this.#collectFindings) state.findings.push(finding);
4668
4560
  }
4669
- #redactValue(value, key, path19, depth, state) {
4561
+ #redactValue(value, key, path21, depth, state) {
4670
4562
  if (depth > this.#maxDepth) {
4671
4563
  this.#recordFinding(
4672
4564
  state,
4673
- makeFinding(path19, "structure.maxDepth", "truncate", "value", "warning")
4565
+ makeFinding(path21, "structure.maxDepth", "truncate", "value", "warning")
4674
4566
  );
4675
4567
  return "[Truncated]";
4676
4568
  }
@@ -4679,19 +4571,19 @@ var Redactor2 = class {
4679
4571
  if (rule) {
4680
4572
  this.#recordFinding(
4681
4573
  state,
4682
- makeFinding(path19, `key.${rule.key}`, actionForRule(rule), "key", "warning")
4574
+ makeFinding(path21, `key.${rule.key}`, actionForRule(rule), "key", "warning")
4683
4575
  );
4684
4576
  return applyRule(rule, value, this.#replacement);
4685
4577
  }
4686
4578
  }
4687
4579
  for (const detector of this.#detectors) {
4688
- const detections = detector.detect({ path: path19, key, value });
4580
+ const detections = detector.detect({ path: path21, key, value });
4689
4581
  for (const detection of detections) {
4690
4582
  const action = detection.action ?? "replace";
4691
4583
  this.#recordFinding(
4692
4584
  state,
4693
4585
  makeFinding(
4694
- path19,
4586
+ path21,
4695
4587
  detector.id,
4696
4588
  action,
4697
4589
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -4709,7 +4601,7 @@ var Redactor2 = class {
4709
4601
  const out = [];
4710
4602
  state.seen.set(value, out);
4711
4603
  value.forEach((item, index) => {
4712
- out[index] = this.#redactValue(item, void 0, indexPath(path19, index), depth + 1, state);
4604
+ out[index] = this.#redactValue(item, void 0, indexPath(path21, index), depth + 1, state);
4713
4605
  });
4714
4606
  return out;
4715
4607
  }
@@ -4721,7 +4613,7 @@ var Redactor2 = class {
4721
4613
  out[entryKey] = this.#redactValue(
4722
4614
  entryValue,
4723
4615
  entryKey,
4724
- childPath(path19 === "$" ? "" : path19, entryKey),
4616
+ childPath(path21 === "$" ? "" : path21, entryKey),
4725
4617
  depth + 1,
4726
4618
  state
4727
4619
  );
@@ -5648,23 +5540,23 @@ function evaluatePromptInjection(text, options = {}) {
5648
5540
  }
5649
5541
  return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
5650
5542
  }
5651
- function validateSchemaField(value, field, path19, evidence) {
5543
+ function validateSchemaField(value, field, path21, evidence) {
5652
5544
  const ruleId = "guardrail.structured-output";
5653
5545
  if (field.type) {
5654
5546
  const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
5655
5547
  if (actual !== field.type) {
5656
- evidence.push({ ruleId, path: path19, preview: `expected ${field.type}, got ${actual}` });
5548
+ evidence.push({ ruleId, path: path21, preview: `expected ${field.type}, got ${actual}` });
5657
5549
  return;
5658
5550
  }
5659
5551
  }
5660
5552
  if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
5661
- evidence.push({ ruleId, path: path19, preview: "value not in enum" });
5553
+ evidence.push({ ruleId, path: path21, preview: "value not in enum" });
5662
5554
  }
5663
5555
  if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
5664
5556
  const record = value;
5665
5557
  for (const key of field.required) {
5666
5558
  if (!(key in record)) {
5667
- evidence.push({ ruleId, path: `${path19}.${key}`, preview: "missing required key" });
5559
+ evidence.push({ ruleId, path: `${path21}.${key}`, preview: "missing required key" });
5668
5560
  }
5669
5561
  }
5670
5562
  }
@@ -6165,10 +6057,10 @@ function printHuman(result) {
6165
6057
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
6166
6058
  }
6167
6059
  for (const finding of result.findings) {
6168
- const path19 = finding.evidence[0]?.path;
6060
+ const path21 = finding.evidence[0]?.path;
6169
6061
  const run = finding.evidence[0]?.runId;
6170
6062
  const runPrefix = run ? `[${run}] ` : "";
6171
- console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path19 ? ` (${path19})` : ""}`);
6063
+ console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path21 ? ` (${path21})` : ""}`);
6172
6064
  }
6173
6065
  }
6174
6066
  function readErrorResult(error) {
@@ -6706,10 +6598,10 @@ async function evalRun(input3, options = {}) {
6706
6598
  diagnostics: []
6707
6599
  };
6708
6600
  }
6709
- function evidenceForRun(run, path19) {
6710
- return [{ runId: run.runId, ...path19 !== void 0 ? { path: path19 } : {} }];
6601
+ function evidenceForRun(run, path21) {
6602
+ return [{ runId: run.runId, ...path21 !== void 0 ? { path: path21 } : {} }];
6711
6603
  }
6712
- function evidenceForEvent(event, path19) {
6604
+ function evidenceForEvent(event, path21) {
6713
6605
  return [
6714
6606
  {
6715
6607
  runId: event.runId,
@@ -6717,7 +6609,7 @@ function evidenceForEvent(event, path19) {
6717
6609
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
6718
6610
  kind: event.kind,
6719
6611
  name: event.name,
6720
- ...path19 !== void 0 ? { path: path19 } : {}
6612
+ ...path21 !== void 0 ? { path: path21 } : {}
6721
6613
  }
6722
6614
  ];
6723
6615
  }
@@ -6875,9 +6767,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
6875
6767
  function tokenize(text) {
6876
6768
  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));
6877
6769
  }
6878
- function firstEvidence(fields, run, path19) {
6770
+ function firstEvidence(fields, run, path21) {
6879
6771
  const first = fields[0];
6880
- return first === void 0 ? evidenceForRun(run, path19) : evidenceForEvent(first.node.event, first.path);
6772
+ return first === void 0 ? evidenceForRun(run, path21) : evidenceForEvent(first.node.event, first.path);
6881
6773
  }
6882
6774
  function collectSourceIds(nodes, keys) {
6883
6775
  const wanted = keySet(keys);
@@ -7254,8 +7146,8 @@ function renderEvalMarkdown(result) {
7254
7146
  if (result.findings.length > 0) {
7255
7147
  lines.push("", "## Findings");
7256
7148
  for (const finding of result.findings) {
7257
- const path19 = finding.evidence[0]?.path;
7258
- lines.push(`- ${finding.ruleId}: ${finding.message}${path19 ? ` (${path19})` : ""}`);
7149
+ const path21 = finding.evidence[0]?.path;
7150
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path21 ? ` (${path21})` : ""}`);
7259
7151
  }
7260
7152
  }
7261
7153
  return `${lines.join("\n")}
@@ -7448,8 +7340,8 @@ function printHuman2(result) {
7448
7340
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
7449
7341
  }
7450
7342
  for (const finding of result.findings) {
7451
- const path19 = finding.evidence[0]?.path;
7452
- console.log(`- ${finding.ruleId}: ${finding.message}${path19 ? ` (${path19})` : ""}`);
7343
+ const path21 = finding.evidence[0]?.path;
7344
+ console.log(`- ${finding.ruleId}: ${finding.message}${path21 ? ` (${path21})` : ""}`);
7453
7345
  }
7454
7346
  }
7455
7347
  function readErrorResult2(error) {
@@ -7687,8 +7579,8 @@ function printHuman3(result) {
7687
7579
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
7688
7580
  }
7689
7581
  for (const finding of result.findings) {
7690
- const path19 = finding.evidence[0]?.path;
7691
- console.log(`- ${finding.ruleId}: ${finding.message}${path19 ? ` (${path19})` : ""}`);
7582
+ const path21 = finding.evidence[0]?.path;
7583
+ console.log(`- ${finding.ruleId}: ${finding.message}${path21 ? ` (${path21})` : ""}`);
7692
7584
  }
7693
7585
  console.log(`Note: ${result.note}`);
7694
7586
  }
@@ -7839,8 +7731,8 @@ function renderCheckSection(result) {
7839
7731
  `Diagnostics: ${result.diagnostics.length}`
7840
7732
  ];
7841
7733
  for (const finding of result.findings.slice(0, 10)) {
7842
- const path19 = finding.evidence[0]?.path ?? "(run)";
7843
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path19})`);
7734
+ const path21 = finding.evidence[0]?.path ?? "(run)";
7735
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path21})`);
7844
7736
  }
7845
7737
  for (const diagnostic3 of result.diagnostics.slice(0, 10)) {
7846
7738
  lines.push(`- ${diagnostic3.code}: ${diagnostic3.message}`);
@@ -9794,7 +9686,7 @@ function isModuleNotFound3(e) {
9794
9686
  }
9795
9687
  async function loadIndexSqlite() {
9796
9688
  try {
9797
- return await import('./src-ZRFSYML6.mjs');
9689
+ return await import('./src-PK22BBMH.mjs');
9798
9690
  } catch (e) {
9799
9691
  if (isModuleNotFound3(e)) {
9800
9692
  console.error(
@@ -10278,6 +10170,211 @@ async function suiteReportCommand(options = {}) {
10278
10170
  process.exitCode = 1;
10279
10171
  }
10280
10172
  }
10173
+ function normalizeMetrics(raw) {
10174
+ const parsed = parseCohortMetricList(raw);
10175
+ if (parsed.length === 0) return void 0;
10176
+ const allowed = new Set(COHORT_METRIC_IDS);
10177
+ return parsed.filter(
10178
+ (item) => allowed.has(item)
10179
+ );
10180
+ }
10181
+ async function writeArtifacts(result, outputDir) {
10182
+ await mkdir(outputDir, { recursive: true });
10183
+ const jsonPath = path12.join(outputDir, "cohort-results.json");
10184
+ const markdownPath = path12.join(outputDir, "cohort-summary.md");
10185
+ const htmlPath = path12.join(outputDir, "cohort-report.html");
10186
+ await writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
10187
+ `, "utf-8");
10188
+ await writeFile(
10189
+ markdownPath,
10190
+ `${renderCohortReport(result, { format: "markdown" })}
10191
+ `,
10192
+ "utf-8"
10193
+ );
10194
+ await writeFile(htmlPath, `${renderCohortReport(result, { format: "html" })}
10195
+ `, "utf-8");
10196
+ return { jsonPath, markdownPath, htmlPath };
10197
+ }
10198
+ async function cohortCommand(options = {}) {
10199
+ try {
10200
+ const traceDir = resolveTraceDir({ dir: options.dir });
10201
+ const { runs } = await loadSessionRuns(traceDir);
10202
+ const result = await analyzeCohort(runs, {
10203
+ traceDir,
10204
+ baseline: options.baseline,
10205
+ candidate: options.candidate,
10206
+ cohortKey: options.cohortKey,
10207
+ groupBy: options.groupBy,
10208
+ metrics: normalizeMetrics(options.metric)
10209
+ });
10210
+ const format = options.format ?? (options.json ? "json" : "markdown");
10211
+ let artifacts;
10212
+ if (options.output !== void 0 && options.output.trim() !== "") {
10213
+ artifacts = await writeArtifacts(result, path12.resolve(options.output.trim()));
10214
+ }
10215
+ if (options.json || format === "json") {
10216
+ console.log(
10217
+ JSON.stringify(
10218
+ {
10219
+ ...result,
10220
+ artifacts: artifacts ?? null
10221
+ },
10222
+ null,
10223
+ 2
10224
+ )
10225
+ );
10226
+ } else if (format === "html") {
10227
+ console.log(renderCohortReport(result, { format: "html" }));
10228
+ if (artifacts !== void 0) {
10229
+ console.error(`Artifacts written to ${options.output}`);
10230
+ }
10231
+ } else {
10232
+ console.log(renderCohortReport(result, { format: "markdown" }));
10233
+ if (artifacts !== void 0) {
10234
+ console.log("");
10235
+ console.log(`Artifacts:`);
10236
+ console.log(`- ${artifacts.jsonPath}`);
10237
+ console.log(`- ${artifacts.markdownPath}`);
10238
+ console.log(`- ${artifacts.htmlPath}`);
10239
+ }
10240
+ }
10241
+ if (!result.ok) process.exitCode = 1;
10242
+ } catch (error) {
10243
+ const message = error instanceof Error ? error.message : String(error);
10244
+ if (options.json) {
10245
+ console.log(JSON.stringify({ ok: false, error: message }, null, 2));
10246
+ } else {
10247
+ console.error(`[AgentInspect] cohort failed: ${message}`);
10248
+ }
10249
+ process.exitCode = 1;
10250
+ }
10251
+ }
10252
+ var SUPPORTED_FORMATS = /* @__PURE__ */ new Set(["markdown", "json", "html", "junit", "github"]);
10253
+ function collectList(value) {
10254
+ if (value === void 0) return [];
10255
+ const items = Array.isArray(value) ? value : [value];
10256
+ return items.flatMap((item) => parseGateList(item));
10257
+ }
10258
+ function parseRate(value) {
10259
+ if (value === void 0 || value.trim() === "") return void 0;
10260
+ const parsed = Number(value);
10261
+ if (!Number.isFinite(parsed)) {
10262
+ throw new Error(`Invalid --max-error-rate: ${value}`);
10263
+ }
10264
+ return parsed;
10265
+ }
10266
+ function parseDuration2(value) {
10267
+ if (value === void 0 || value.trim() === "") return void 0;
10268
+ const parsed = Number(value);
10269
+ if (!Number.isFinite(parsed)) {
10270
+ throw new Error(`Invalid --max-p95-duration: ${value}`);
10271
+ }
10272
+ return parsed;
10273
+ }
10274
+ async function writeArtifacts2(result, outputDir) {
10275
+ await mkdir(outputDir, { recursive: true });
10276
+ const paths = {
10277
+ jsonPath: path12.join(outputDir, "gate-results.json"),
10278
+ markdownPath: path12.join(outputDir, "gate-summary.md"),
10279
+ htmlPath: path12.join(outputDir, "gate-report.html"),
10280
+ junitPath: path12.join(outputDir, "junit.xml"),
10281
+ githubPath: path12.join(outputDir, "github-step-summary.md")
10282
+ };
10283
+ await writeFile(
10284
+ paths.jsonPath,
10285
+ `${renderGateReport(result, { format: "json" })}
10286
+ `,
10287
+ "utf-8"
10288
+ );
10289
+ await writeFile(
10290
+ paths.markdownPath,
10291
+ `${renderGateReport(result, { format: "markdown" })}
10292
+ `,
10293
+ "utf-8"
10294
+ );
10295
+ await writeFile(
10296
+ paths.htmlPath,
10297
+ `${renderGateReport(result, { format: "html" })}
10298
+ `,
10299
+ "utf-8"
10300
+ );
10301
+ await writeFile(
10302
+ paths.junitPath,
10303
+ `${renderGateReport(result, { format: "junit" })}
10304
+ `,
10305
+ "utf-8"
10306
+ );
10307
+ await writeFile(
10308
+ paths.githubPath,
10309
+ `${renderGateReport(result, { format: "github" })}
10310
+ `,
10311
+ "utf-8"
10312
+ );
10313
+ return paths;
10314
+ }
10315
+ async function gateCommand(options = {}) {
10316
+ try {
10317
+ const format = options.format ?? (options.json ? "json" : "markdown");
10318
+ if (!SUPPORTED_FORMATS.has(format)) {
10319
+ if (options.json) {
10320
+ console.log(
10321
+ JSON.stringify({ ok: false, exitCode: 4, error: `Unsupported format: ${format}` }, null, 2)
10322
+ );
10323
+ } else {
10324
+ console.error(`[AgentInspect] Unsupported format: ${format}`);
10325
+ }
10326
+ process.exitCode = 4;
10327
+ return;
10328
+ }
10329
+ const gateOptions = {
10330
+ ...options.dir !== void 0 ? { traceDir: resolveTraceDir({ dir: options.dir }) } : {},
10331
+ ...options.suite !== void 0 ? { suitePath: options.suite } : {},
10332
+ ...options.cwd !== void 0 ? { cwd: options.cwd } : {},
10333
+ ...parseRate(options.maxErrorRate) !== void 0 ? { maxErrorRate: parseRate(options.maxErrorRate) } : {},
10334
+ ...parseDuration2(options.maxP95Duration) !== void 0 ? { maxP95DurationMs: parseDuration2(options.maxP95Duration) } : {},
10335
+ forbidTools: collectList(options.forbidTool),
10336
+ requireObservations: collectList(options.requireObservation)
10337
+ };
10338
+ let runs = [];
10339
+ const needsRuns = gateHasThresholds(gateOptions) || gateOptions.traceDir !== void 0 && gateOptions.suitePath === void 0;
10340
+ if (needsRuns) {
10341
+ const traceDir = gateOptions.traceDir ?? resolveTraceDir({ dir: options.dir });
10342
+ const loaded = await loadSessionRuns(traceDir);
10343
+ runs = loaded.runs;
10344
+ gateOptions.traceDir = traceDir;
10345
+ }
10346
+ const result = await runGate(runs, gateOptions);
10347
+ let artifacts;
10348
+ if (options.output !== void 0 && options.output.trim() !== "") {
10349
+ artifacts = await writeArtifacts2(result, path12.resolve(options.output.trim()));
10350
+ }
10351
+ if (options.json || format === "json") {
10352
+ console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
10353
+ } else if (format === "html") {
10354
+ console.log(renderGateReport(result, { format: "html" }));
10355
+ } else if (format === "junit") {
10356
+ console.log(renderGateReport(result, { format: "junit" }));
10357
+ } else if (format === "github") {
10358
+ console.log(renderGateReport(result, { format: "github" }));
10359
+ } else {
10360
+ console.log(renderGateReport(result, { format: "markdown" }));
10361
+ if (artifacts !== void 0) {
10362
+ console.log("");
10363
+ console.log("Artifacts:");
10364
+ for (const value of Object.values(artifacts)) console.log(`- ${value}`);
10365
+ }
10366
+ }
10367
+ process.exitCode = result.exitCode;
10368
+ } catch (error) {
10369
+ const message = error instanceof Error ? error.message : String(error);
10370
+ if (options.json) {
10371
+ console.log(JSON.stringify({ ok: false, exitCode: 2, error: message }, null, 2));
10372
+ } else {
10373
+ console.error(`[AgentInspect] gate failed: ${message}`);
10374
+ }
10375
+ process.exitCode = 2;
10376
+ }
10377
+ }
10281
10378
 
10282
10379
  // packages/cli/src/index.ts
10283
10380
  function runCommand(action) {
@@ -10712,6 +10809,21 @@ function createCliProgram() {
10712
10809
  suiteCmd.command("report").description("Render a report from a prior suite run artifact").option("--input <path>", "suite run JSON artifact").option("--format <format>", "markdown or json", "markdown").option("--json", "print JSON wrapper").action((opts) => {
10713
10810
  runCommand(() => suiteReportCommand(opts));
10714
10811
  });
10812
+ program.command("cohort").description("Compare baseline/candidate trace cohorts for regressions (v5.1+)").option("--dir <path>", "trace directory").option("--baseline <label>", "baseline cohort label (metadata key)").option("--candidate <label>", "candidate cohort label (metadata key)").option("--cohort-key <key>", "metadata key for cohort labels", "cohort").option("--group-by <spec>", "model | session | group | metadata.<key>", "model").option(
10813
+ "--metric <list>",
10814
+ "comma-separated metrics (errorRate,duration,toolChoice,...)"
10815
+ ).option("--format <format>", "markdown, json, or html", "markdown").option("-o, --output <dir>", "write cohort-results.json, cohort-summary.md, cohort-report.html").option("--json", "print deterministic JSON result").action((opts) => {
10816
+ runCommand(() => cohortCommand(opts));
10817
+ });
10818
+ program.command("gate").description("Run deterministic CI quality gates over traces or suites (v5.2+)").option("--dir <path>", "trace directory for threshold checks").option("--suite <path>", "suite config path").option("--max-error-rate <percent>", "maximum allowed error rate percentage").option("--max-p95-duration <ms>", "maximum allowed p95 run duration in ms").option("--forbid-tool <name>", "forbidden tool name (repeatable or comma-separated)").option(
10819
+ "--require-observation <name>",
10820
+ "required passed observation (repeatable or comma-separated)"
10821
+ ).option("--format <format>", "markdown, json, html, junit, or github", "markdown").option(
10822
+ "-o, --output <dir>",
10823
+ "write gate-results.json, gate-summary.md, gate-report.html, junit.xml, github-step-summary.md"
10824
+ ).option("--json", "print deterministic JSON result").action((opts) => {
10825
+ runCommand(() => gateCommand(opts));
10826
+ });
10715
10827
  return program;
10716
10828
  }
10717
10829
  function isPrimaryModule() {