agent-inspect 6.17.4 → 6.17.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/docs/ADAPTERS.md +3 -3
  4. package/docs/API.md +13 -7
  5. package/docs/CLI.md +2 -0
  6. package/docs/LIMITATIONS.md +1 -0
  7. package/docs/TRACE-CONTRACTS.md +90 -0
  8. package/package.json +5 -2
  9. package/packages/cli/dist/{chunk-YX6RFLV5.mjs → chunk-GOHYSE7W.mjs} +86 -17
  10. package/packages/cli/dist/chunk-GOHYSE7W.mjs.map +1 -0
  11. package/packages/cli/dist/index.cjs +480 -80
  12. package/packages/cli/dist/index.cjs.map +1 -1
  13. package/packages/cli/dist/index.mjs +399 -68
  14. package/packages/cli/dist/index.mjs.map +1 -1
  15. package/packages/cli/dist/{src-X6SLMBNH.mjs → src-OYGG7QAZ.mjs} +3 -3
  16. package/packages/cli/dist/{src-X6SLMBNH.mjs.map → src-OYGG7QAZ.mjs.map} +1 -1
  17. package/packages/core/dist/advanced.cjs +85 -16
  18. package/packages/core/dist/advanced.cjs.map +1 -1
  19. package/packages/core/dist/advanced.d.cts +1 -1
  20. package/packages/core/dist/advanced.d.ts +1 -1
  21. package/packages/core/dist/advanced.mjs +15 -5
  22. package/packages/core/dist/advanced.mjs.map +1 -1
  23. package/packages/core/dist/checks.cjs +119 -26
  24. package/packages/core/dist/checks.cjs.map +1 -1
  25. package/packages/core/dist/checks.d.cts +28 -2
  26. package/packages/core/dist/checks.d.ts +28 -2
  27. package/packages/core/dist/checks.mjs +1 -1
  28. package/packages/core/dist/{chunk-HN377P23.mjs → chunk-DIZPIPY2.mjs} +121 -28
  29. package/packages/core/dist/chunk-DIZPIPY2.mjs.map +1 -0
  30. package/packages/core/dist/{index-Xk9X-yjY.d.cts → index-DWu54Y28.d.cts} +107 -122
  31. package/packages/core/dist/{index-BsCcOKxy.d.ts → index-DlwbVqEs.d.ts} +107 -122
  32. package/packages/cli/dist/chunk-YX6RFLV5.mjs.map +0 -1
  33. package/packages/core/dist/chunk-HN377P23.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, resolveBundleRunIds, getTraceFilePath, openTrace, sha256Hex, collectTraceSchemaVersions, aggregateBundleSafeStatus, bundleFailsOnSafety, bundleRunAssetRelativePath, buildPlaceholderArtifact, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceHtmlShell, buildEvidenceProvenanceViewHtml, EVIDENCE_FORMAT_VERSION, inferEvidenceFileRole, buildEvidenceSafetyViewHtml, buildEvidenceDiffViewHtml, buildEvidenceCircuitViewHtml, buildEvidenceOutcomesViewHtml, buildEvidenceContractsViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceCausalFailureViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceTreeViewHtml, buildEvidenceManifest, serializeEvidenceManifest, buildZipArchive, assertBundlePathContained, enrichSessionRunRecord, normalizeBundleOutputPath, sanitizeBundleRunId, defaultBundleOutputPath, runTraceChecks, assertEvidenceRelativePath, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, TraceReadError, resolveRedactionProfile, applyProfileMetadataCaps, Redactor, flattenTree, escapeHtml, safeString, compactAttributes, stableJson, escapeMarkdown, truncateStringForProfile, extractMetadata, filterTraces, truncateName, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, filterMetasBySessionScope, aggregateSessionCheckResults, createBaselineRegressionRule, summarizeSemanticParity, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, formatStepLabel, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, resolveSuiteTemplate, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, diffRuns, manualTraceEventsToComparableRun } from './chunk-YX6RFLV5.mjs';
2
+ import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, resolveBundleRunIds, getTraceFilePath, openTrace, sha256Hex, collectTraceSchemaVersions, aggregateBundleSafeStatus, bundleFailsOnSafety, bundleRunAssetRelativePath, buildPlaceholderArtifact, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceHtmlShell, buildEvidenceProvenanceViewHtml, EVIDENCE_FORMAT_VERSION, inferEvidenceFileRole, buildEvidenceSafetyViewHtml, buildEvidenceDiffViewHtml, buildEvidenceCircuitViewHtml, buildEvidenceOutcomesViewHtml, buildEvidenceContractsViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceCausalFailureViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceTreeViewHtml, buildEvidenceManifest, serializeEvidenceManifest, buildZipArchive, assertBundlePathContained, enrichSessionRunRecord, normalizeBundleOutputPath, sanitizeBundleRunId, defaultBundleOutputPath, runTraceChecks, assertEvidenceRelativePath, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, TraceReadError, resolveRedactionProfile, applyProfileMetadataCaps, Redactor, flattenTree, escapeHtml, safeString, compactAttributes, stableJson, escapeMarkdown, truncateStringForProfile, extractMetadata, filterTraces, truncateName, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, filterMetasBySessionScope, aggregateSessionCheckResults, createBaselineRegressionRule, summarizeSemanticParity, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, formatStepLabel, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, resolveSuiteTemplate, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, diffRuns, manualTraceEventsToComparableRun } from './chunk-GOHYSE7W.mjs';
3
3
  import { realpathSync, constants as constants$1, existsSync, readFileSync } from 'fs';
4
4
  import path18 from 'path';
5
5
  import { fileURLToPath, pathToFileURL } from 'url';
@@ -12,7 +12,7 @@ import { spawn } from 'child_process';
12
12
  import { createRequire } from 'module';
13
13
 
14
14
  // package.json
15
- var version = "6.17.4";
15
+ var version = "6.17.5";
16
16
 
17
17
  // packages/cli/src/trace-dir-scale.ts
18
18
  var TRACE_COUNT_WARN = 1e3;
@@ -1540,6 +1540,11 @@ async function followFile(filePath, options, onLine, shouldStop) {
1540
1540
  const msg = e instanceof Error ? e.message : String(e);
1541
1541
  throw new Error(`Failed to stat file: ${filePath} (${msg})`);
1542
1542
  }
1543
+ if (next.size < pos) {
1544
+ pos = 0;
1545
+ carry = "";
1546
+ lineNumber = 0;
1547
+ }
1543
1548
  if (next.size > pos) {
1544
1549
  const fh = await open(filePath, "r");
1545
1550
  try {
@@ -3347,7 +3352,7 @@ async function newestTraceMtimeMs(traceDir) {
3347
3352
  }
3348
3353
  async function loadSessionRuns(traceDir) {
3349
3354
  try {
3350
- const mod = await import('./src-X6SLMBNH.mjs');
3355
+ const mod = await import('./src-OYGG7QAZ.mjs');
3351
3356
  const dbPath = mod.resolveIndexDbPath(traceDir);
3352
3357
  const status = mod.indexStatus(dbPath);
3353
3358
  if (!status.healthy) {
@@ -5143,8 +5148,11 @@ function checkResultToEvidenceJson(result, runIds) {
5143
5148
  status,
5144
5149
  errors: result.summary.errors,
5145
5150
  warnings: result.summary.warnings,
5146
- findings: result.findings.length
5151
+ findings: result.findings.length,
5152
+ rulesEvaluated: result.summary.rulesEvaluated ?? 0
5147
5153
  })),
5154
+ rulesEvaluated: result.summary.rulesEvaluated ?? 0,
5155
+ evaluatedRuleIds: (result.ruleExecutions ?? []).map((item) => item.ruleId),
5148
5156
  findings: result.findings,
5149
5157
  diagnostics: result.diagnostics
5150
5158
  });
@@ -5769,9 +5777,11 @@ function mergeSafetyExtensions(result, read, options) {
5769
5777
  passed,
5770
5778
  failed,
5771
5779
  warnings,
5772
- errors: result.summary.errors
5780
+ errors: result.summary.errors,
5781
+ rulesEvaluated: result.summary.rulesEvaluated ?? 0
5773
5782
  },
5774
- findings
5783
+ findings,
5784
+ ruleExecutions: result.ruleExecutions ?? []
5775
5785
  };
5776
5786
  }
5777
5787
 
@@ -5891,10 +5901,12 @@ function errorResult(code, message, format = "unknown") {
5891
5901
  passed: 0,
5892
5902
  failed: 0,
5893
5903
  warnings: 0,
5894
- errors: 1
5904
+ errors: 1,
5905
+ rulesEvaluated: 0
5895
5906
  },
5896
5907
  findings: [],
5897
- diagnostics
5908
+ diagnostics,
5909
+ ruleExecutions: []
5898
5910
  };
5899
5911
  }
5900
5912
  function parseNumber(value, label) {
@@ -5912,36 +5924,329 @@ function asStringArray(value) {
5912
5924
  }
5913
5925
  return value;
5914
5926
  }
5915
- function asConfig(value) {
5927
+ var CHECKS_KEYS = /* @__PURE__ */ new Set(["select", "run", "tool", "llm", "structure", "safety"]);
5928
+ var RUN_KEYS = /* @__PURE__ */ new Set(["expected", "allowIncomplete", "maxDurationMs", "maxDepth"]);
5929
+ var TOOL_KEYS = /* @__PURE__ */ new Set(["required", "forbidden", "allowed", "minCount", "maxCount"]);
5930
+ var LLM_KEYS = /* @__PURE__ */ new Set([
5931
+ "allowedModels",
5932
+ "allowedProviders",
5933
+ "finishReasons",
5934
+ "maxCalls",
5935
+ "maxTotalTokens",
5936
+ "maxInputTokens",
5937
+ "maxOutputTokens",
5938
+ "maxCachedTokens"
5939
+ ]);
5940
+ var STRUCTURE_KEYS = /* @__PURE__ */ new Set([
5941
+ "minConfidence",
5942
+ "requireParentBeforeChild",
5943
+ "requireTraceParentSpan",
5944
+ "orphan",
5945
+ "cycle",
5946
+ "maxChildren",
5947
+ "maxConcurrent"
5948
+ ]);
5949
+ var SAFETY_KEYS = /* @__PURE__ */ new Set([
5950
+ "redaction",
5951
+ "rawContent",
5952
+ "secretPattern",
5953
+ "maxStringLength",
5954
+ "maxArrayLength",
5955
+ "maxObjectKeys",
5956
+ "maxSerializedBytes",
5957
+ "maxFindings"
5958
+ ]);
5959
+ var RUN_EXPECTED = /* @__PURE__ */ new Set(["ok", "error", "running"]);
5960
+ var CONFIDENCE_VALUES = /* @__PURE__ */ new Set(["exact", "high", "medium", "low", "inferred"]);
5961
+ var CheckConfigError = class extends Error {
5962
+ code;
5963
+ constructor(code, message) {
5964
+ super(message);
5965
+ this.name = "CheckConfigError";
5966
+ this.code = code;
5967
+ }
5968
+ };
5969
+ function closestKey(unknown, known) {
5970
+ const lower = unknown.toLowerCase();
5971
+ let best;
5972
+ let bestDistance = Number.POSITIVE_INFINITY;
5973
+ for (const candidate of known) {
5974
+ if (candidate.toLowerCase() === lower) return candidate;
5975
+ let distance = Math.abs(candidate.length - unknown.length);
5976
+ const max = Math.max(candidate.length, unknown.length);
5977
+ for (let i = 0; i < Math.min(candidate.length, unknown.length); i += 1) {
5978
+ if (candidate[i].toLowerCase() !== unknown[i].toLowerCase()) distance += 1;
5979
+ }
5980
+ if (distance < bestDistance && distance <= Math.max(2, Math.floor(max / 3))) {
5981
+ bestDistance = distance;
5982
+ best = candidate;
5983
+ }
5984
+ }
5985
+ return best;
5986
+ }
5987
+ function rejectUnknownKeys(record, allowed, pathPrefix) {
5988
+ for (const key of Object.keys(record)) {
5989
+ if (allowed.has(key)) continue;
5990
+ const suggestion = closestKey(key, [...allowed]);
5991
+ const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
5992
+ throw new CheckConfigError(
5993
+ "AI_CHECK_CONFIG_UNKNOWN_KEY",
5994
+ `Unknown check config key "${pathPrefix}.${key}".${hint}`
5995
+ );
5996
+ }
5997
+ }
5998
+ function requireObject(value, pathPrefix) {
5999
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
6000
+ throw new CheckConfigError(
6001
+ "AI_CHECK_CONFIG_INVALID_VALUE",
6002
+ `${pathPrefix} must be an object.`
6003
+ );
6004
+ }
6005
+ return value;
6006
+ }
6007
+ function requireStringArray(value, pathPrefix) {
6008
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item.trim() === "")) {
6009
+ throw new CheckConfigError(
6010
+ "AI_CHECK_CONFIG_INVALID_VALUE",
6011
+ `${pathPrefix} must be an array of non-empty strings.`
6012
+ );
6013
+ }
6014
+ return value;
6015
+ }
6016
+ function requireNonNegativeNumber(value, pathPrefix) {
6017
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
6018
+ throw new CheckConfigError(
6019
+ "AI_CHECK_CONFIG_INVALID_VALUE",
6020
+ `${pathPrefix} must be a finite non-negative number.`
6021
+ );
6022
+ }
6023
+ return value;
6024
+ }
6025
+ function requireBoolean(value, pathPrefix) {
6026
+ if (typeof value !== "boolean") {
6027
+ throw new CheckConfigError(
6028
+ "AI_CHECK_CONFIG_INVALID_VALUE",
6029
+ `${pathPrefix} must be a boolean.`
6030
+ );
6031
+ }
6032
+ return value;
6033
+ }
6034
+ function parseRunSection(value) {
6035
+ const record = requireObject(value, "checks.run");
6036
+ rejectUnknownKeys(record, RUN_KEYS, "checks.run");
6037
+ const out = {};
6038
+ if (record.expected !== void 0) {
6039
+ if (typeof record.expected !== "string" || !RUN_EXPECTED.has(record.expected)) {
6040
+ throw new CheckConfigError(
6041
+ "AI_CHECK_CONFIG_INVALID_VALUE",
6042
+ `checks.run.expected must be one of: ok, error, running.`
6043
+ );
6044
+ }
6045
+ out.expected = record.expected;
6046
+ }
6047
+ if (record.allowIncomplete !== void 0) {
6048
+ out.allowIncomplete = requireBoolean(record.allowIncomplete, "checks.run.allowIncomplete");
6049
+ }
6050
+ if (record.maxDurationMs !== void 0) {
6051
+ out.maxDurationMs = requireNonNegativeNumber(record.maxDurationMs, "checks.run.maxDurationMs");
6052
+ }
6053
+ if (record.maxDepth !== void 0) {
6054
+ out.maxDepth = requireNonNegativeNumber(record.maxDepth, "checks.run.maxDepth");
6055
+ }
6056
+ return out;
6057
+ }
6058
+ function parseToolSection(value) {
6059
+ const record = requireObject(value, "checks.tool");
6060
+ rejectUnknownKeys(record, TOOL_KEYS, "checks.tool");
6061
+ const out = {};
6062
+ if (record.required !== void 0) out.required = requireStringArray(record.required, "checks.tool.required");
6063
+ if (record.forbidden !== void 0) out.forbidden = requireStringArray(record.forbidden, "checks.tool.forbidden");
6064
+ if (record.allowed !== void 0) out.allowed = requireStringArray(record.allowed, "checks.tool.allowed");
6065
+ if (record.minCount !== void 0) out.minCount = requireNonNegativeNumber(record.minCount, "checks.tool.minCount");
6066
+ if (record.maxCount !== void 0) out.maxCount = requireNonNegativeNumber(record.maxCount, "checks.tool.maxCount");
6067
+ return out;
6068
+ }
6069
+ function parseLlmSection(value) {
6070
+ const record = requireObject(value, "checks.llm");
6071
+ rejectUnknownKeys(record, LLM_KEYS, "checks.llm");
6072
+ const out = {};
6073
+ if (record.allowedModels !== void 0) {
6074
+ out.allowedModels = requireStringArray(record.allowedModels, "checks.llm.allowedModels");
6075
+ }
6076
+ if (record.allowedProviders !== void 0) {
6077
+ out.allowedProviders = requireStringArray(record.allowedProviders, "checks.llm.allowedProviders");
6078
+ }
6079
+ if (record.finishReasons !== void 0) {
6080
+ out.finishReasons = requireStringArray(record.finishReasons, "checks.llm.finishReasons");
6081
+ }
6082
+ if (record.maxCalls !== void 0) out.maxCalls = requireNonNegativeNumber(record.maxCalls, "checks.llm.maxCalls");
6083
+ if (record.maxTotalTokens !== void 0) {
6084
+ out.maxTotalTokens = requireNonNegativeNumber(record.maxTotalTokens, "checks.llm.maxTotalTokens");
6085
+ }
6086
+ if (record.maxInputTokens !== void 0) {
6087
+ out.maxInputTokens = requireNonNegativeNumber(record.maxInputTokens, "checks.llm.maxInputTokens");
6088
+ }
6089
+ if (record.maxOutputTokens !== void 0) {
6090
+ out.maxOutputTokens = requireNonNegativeNumber(record.maxOutputTokens, "checks.llm.maxOutputTokens");
6091
+ }
6092
+ if (record.maxCachedTokens !== void 0) {
6093
+ out.maxCachedTokens = requireNonNegativeNumber(record.maxCachedTokens, "checks.llm.maxCachedTokens");
6094
+ }
6095
+ return out;
6096
+ }
6097
+ function parseStructureSection(value) {
6098
+ const record = requireObject(value, "checks.structure");
6099
+ rejectUnknownKeys(record, STRUCTURE_KEYS, "checks.structure");
6100
+ const out = {};
6101
+ if (record.minConfidence !== void 0) {
6102
+ if (typeof record.minConfidence !== "string" || !CONFIDENCE_VALUES.has(record.minConfidence)) {
6103
+ throw new CheckConfigError(
6104
+ "AI_CHECK_CONFIG_INVALID_VALUE",
6105
+ `checks.structure.minConfidence must be one of: exact, high, medium, low, inferred.`
6106
+ );
6107
+ }
6108
+ out.minConfidence = record.minConfidence;
6109
+ }
6110
+ if (record.requireParentBeforeChild !== void 0) {
6111
+ out.requireParentBeforeChild = requireBoolean(
6112
+ record.requireParentBeforeChild,
6113
+ "checks.structure.requireParentBeforeChild"
6114
+ );
6115
+ }
6116
+ if (record.requireTraceParentSpan !== void 0) {
6117
+ out.requireTraceParentSpan = requireBoolean(
6118
+ record.requireTraceParentSpan,
6119
+ "checks.structure.requireTraceParentSpan"
6120
+ );
6121
+ }
6122
+ if (record.orphan !== void 0) out.orphan = requireBoolean(record.orphan, "checks.structure.orphan");
6123
+ if (record.cycle !== void 0) out.cycle = requireBoolean(record.cycle, "checks.structure.cycle");
6124
+ if (record.maxChildren !== void 0) {
6125
+ out.maxChildren = requireNonNegativeNumber(record.maxChildren, "checks.structure.maxChildren");
6126
+ }
6127
+ if (record.maxConcurrent !== void 0) {
6128
+ out.maxConcurrent = requireNonNegativeNumber(record.maxConcurrent, "checks.structure.maxConcurrent");
6129
+ }
6130
+ return out;
6131
+ }
6132
+ function parseSafetySection(value) {
6133
+ const record = requireObject(value, "checks.safety");
6134
+ rejectUnknownKeys(record, SAFETY_KEYS, "checks.safety");
6135
+ const out = {};
6136
+ if (record.redaction !== void 0) out.redaction = requireBoolean(record.redaction, "checks.safety.redaction");
6137
+ if (record.rawContent !== void 0) out.rawContent = requireBoolean(record.rawContent, "checks.safety.rawContent");
6138
+ if (record.secretPattern !== void 0) {
6139
+ out.secretPattern = requireBoolean(record.secretPattern, "checks.safety.secretPattern");
6140
+ }
6141
+ if (record.maxStringLength !== void 0) {
6142
+ out.maxStringLength = requireNonNegativeNumber(record.maxStringLength, "checks.safety.maxStringLength");
6143
+ }
6144
+ if (record.maxArrayLength !== void 0) {
6145
+ out.maxArrayLength = requireNonNegativeNumber(record.maxArrayLength, "checks.safety.maxArrayLength");
6146
+ }
6147
+ if (record.maxObjectKeys !== void 0) {
6148
+ out.maxObjectKeys = requireNonNegativeNumber(record.maxObjectKeys, "checks.safety.maxObjectKeys");
6149
+ }
6150
+ if (record.maxSerializedBytes !== void 0) {
6151
+ out.maxSerializedBytes = requireNonNegativeNumber(
6152
+ record.maxSerializedBytes,
6153
+ "checks.safety.maxSerializedBytes"
6154
+ );
6155
+ }
6156
+ if (record.maxFindings !== void 0) {
6157
+ out.maxFindings = requireNonNegativeNumber(record.maxFindings, "checks.safety.maxFindings");
6158
+ }
6159
+ return out;
6160
+ }
6161
+ function sectionHasEffect(section) {
6162
+ if (section === void 0) return false;
6163
+ return Object.keys(section).length > 0;
6164
+ }
6165
+ function checkConfigHasEffect(config) {
6166
+ const checks2 = config.checks;
6167
+ if (checks2 === void 0) return false;
6168
+ if ((checks2.select?.length ?? 0) > 0) return true;
6169
+ if (sectionHasEffect(checks2.run)) return true;
6170
+ if (sectionHasEffect(checks2.tool)) return true;
6171
+ if (sectionHasEffect(checks2.llm)) return true;
6172
+ if (sectionHasEffect(checks2.structure)) return true;
6173
+ if (sectionHasEffect(checks2.safety)) return true;
6174
+ return false;
6175
+ }
6176
+ function parseCheckConfig(value) {
5916
6177
  if (value === void 0 || value === null) return {};
5917
6178
  if (typeof value !== "object" || Array.isArray(value)) {
5918
- throw new Error("Config must export an object.");
6179
+ throw new CheckConfigError("AI_CHECK_CONFIG_INVALID_VALUE", "Config must export an object.");
5919
6180
  }
5920
- return value;
6181
+ const root = value;
6182
+ if ("contract" in root) {
6183
+ throw new CheckConfigError(
6184
+ "AI_CHECK_CONFIG_UNKNOWN_KEY",
6185
+ 'Top-level "contract" is not supported by `agent-inspect check --config`. Use the TraceContract TypeScript API (`defineTraceContract` / `evaluateTraceContract` from `agent-inspect/checks`), or express tool/run/llm rules under `checks`.'
6186
+ );
6187
+ }
6188
+ const rootKeys = Object.keys(root);
6189
+ for (const key of rootKeys) {
6190
+ if (key === "checks") continue;
6191
+ const suggestion = closestKey(key, ["checks"]);
6192
+ const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
6193
+ throw new CheckConfigError(
6194
+ "AI_CHECK_CONFIG_UNKNOWN_KEY",
6195
+ `Unknown top-level check config key "${key}". Allowed: checks.${hint}`
6196
+ );
6197
+ }
6198
+ if (!("checks" in root)) return {};
6199
+ const checksRecord = requireObject(root.checks, "checks");
6200
+ rejectUnknownKeys(checksRecord, CHECKS_KEYS, "checks");
6201
+ const checks2 = {};
6202
+ if (checksRecord.select !== void 0) {
6203
+ checks2.select = requireStringArray(checksRecord.select, "checks.select");
6204
+ }
6205
+ if (checksRecord.run !== void 0) checks2.run = parseRunSection(checksRecord.run);
6206
+ if (checksRecord.tool !== void 0) checks2.tool = parseToolSection(checksRecord.tool);
6207
+ if (checksRecord.llm !== void 0) checks2.llm = parseLlmSection(checksRecord.llm);
6208
+ if (checksRecord.structure !== void 0) {
6209
+ checks2.structure = parseStructureSection(checksRecord.structure);
6210
+ }
6211
+ if (checksRecord.safety !== void 0) checks2.safety = parseSafetySection(checksRecord.safety);
6212
+ return { checks: checks2 };
5921
6213
  }
5922
6214
  async function loadConfig(configPath) {
5923
6215
  if (configPath === void 0) return {};
5924
6216
  const extension = path18.extname(configPath);
5925
6217
  if (TS_CONFIG_EXTENSIONS.has(extension)) {
5926
- throw new Error(
6218
+ throw new CheckConfigError(
6219
+ "AI_CHECK_CONFIG_LOAD_FAILED",
5927
6220
  "TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
5928
6221
  );
5929
6222
  }
5930
6223
  if (!CONFIG_EXTENSIONS.has(extension)) {
5931
- throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
6224
+ throw new CheckConfigError(
6225
+ "AI_CHECK_CONFIG_LOAD_FAILED",
6226
+ "Unsupported check config extension. Use .json, .js, .mjs, or .cjs."
6227
+ );
5932
6228
  }
5933
6229
  const absolute = path18.resolve(configPath);
5934
- if (extension === ".json") {
5935
- const raw = await readFile(absolute, "utf-8");
5936
- return asConfig(JSON.parse(raw));
6230
+ try {
6231
+ if (extension === ".json") {
6232
+ const raw = await readFile(absolute, "utf-8");
6233
+ return parseCheckConfig(JSON.parse(raw));
6234
+ }
6235
+ const mod = await import(pathToFileURL(absolute).href);
6236
+ return parseCheckConfig("default" in mod ? mod.default : mod);
6237
+ } catch (error) {
6238
+ if (error instanceof CheckConfigError) throw error;
6239
+ const message = error instanceof Error ? error.message : String(error);
6240
+ throw new CheckConfigError(
6241
+ "AI_CHECK_CONFIG_LOAD_FAILED",
6242
+ `Failed to load check config: ${message}`
6243
+ );
5937
6244
  }
5938
- const mod = await import(pathToFileURL(absolute).href);
5939
- return asConfig("default" in mod ? mod.default : mod);
5940
6245
  }
5941
6246
  function normalizeConfig(config) {
5942
6247
  if (config.checks === void 0) return {};
5943
6248
  if (typeof config.checks !== "object" || Array.isArray(config.checks)) {
5944
- throw new Error("checks config must be an object.");
6249
+ throw new CheckConfigError("AI_CHECK_CONFIG_INVALID_VALUE", "checks config must be an object.");
5945
6250
  }
5946
6251
  return config.checks;
5947
6252
  }
@@ -6019,7 +6324,7 @@ function buildRules(config, options, presetSelect = []) {
6019
6324
  }
6020
6325
  throw new Error(`unsupported status "${value}"`);
6021
6326
  });
6022
- rules.push(createObservedOutcomeRule({ failOn: statuses }));
6327
+ rules.push(createObservedOutcomeRule({ failOn: statuses, requireAny: true }));
6023
6328
  } catch (error) {
6024
6329
  const message = error instanceof Error ? error.message : String(error);
6025
6330
  diagnostics.push(
@@ -6091,7 +6396,7 @@ function exitCodeFor(result) {
6091
6396
  return 3;
6092
6397
  }
6093
6398
  if (codes.some(
6094
- (code) => code === "AI_CHECK_INVALID_ARGUMENTS" || code === "AI_CHECK_INVALID_CONFIG" || code === "AI_CHECK_CONFIG_LOAD_FAILED" || code === "AI_CHECK_RUN_SELECTION_REQUIRED"
6399
+ (code) => code === "AI_CHECK_INVALID_ARGUMENTS" || code === "AI_CHECK_INVALID_CONFIG" || code === "AI_CHECK_CONFIG_LOAD_FAILED" || code === "AI_CHECK_CONFIG_UNKNOWN_KEY" || code === "AI_CHECK_CONFIG_INVALID_VALUE" || code === "AI_CHECK_CONFIG_NO_EFFECTIVE_RULES" || code === "AI_CHECK_NO_RULES_EVALUATED" || code === "AI_CHECK_RUN_SELECTION_REQUIRED"
6095
6400
  )) {
6096
6401
  return 2;
6097
6402
  }
@@ -6158,6 +6463,7 @@ function printHuman(result, options = {}) {
6158
6463
  console.log(
6159
6464
  `Summary: ${result.summary.failed} failed, ${result.summary.warnings} warning(s), ${result.summary.errors} error(s)`
6160
6465
  );
6466
+ console.log(`Rules evaluated: ${result.summary.rulesEvaluated ?? result.ruleExecutions?.length ?? 0}`);
6161
6467
  for (const diagnostic3 of result.diagnostics) {
6162
6468
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
6163
6469
  }
@@ -6189,6 +6495,16 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
6189
6495
  const useSessionScope = Boolean(sessionId || groupId);
6190
6496
  try {
6191
6497
  let config = await loadConfig(options.config);
6498
+ if (options.config !== void 0 && !checkConfigHasEffect(config)) {
6499
+ result = errorResult(
6500
+ "AI_CHECK_CONFIG_NO_EFFECTIVE_RULES",
6501
+ "Explicit --config has no effective check rules. Configure checks.select, checks.run, checks.tool, checks.llm, checks.structure, or checks.safety."
6502
+ );
6503
+ if (options.json) printJson(result);
6504
+ else printHuman(result, options);
6505
+ process.exitCode = exitCodeFor(result);
6506
+ return;
6507
+ }
6192
6508
  let effectiveOptions = options;
6193
6509
  const resolved = resolvePreset(options.preset, {
6194
6510
  hasToolRules: hasToolRulesConfigured(config, options)
@@ -6308,12 +6624,13 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
6308
6624
  }
6309
6625
  } catch (error) {
6310
6626
  if (phase === "config") {
6311
- const message = error instanceof Error ? error.message : String(error);
6312
- const code = message.startsWith("--") || message.includes("Unknown --preset") ? "AI_CHECK_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported check config extension") || message.includes("TypeScript check configs") || message.includes("Config must") || message.includes("checks config") || message.includes("Expected an array") ? "AI_CHECK_INVALID_CONFIG" : "AI_CHECK_CONFIG_LOAD_FAILED";
6313
- result = errorResult(
6314
- code,
6315
- message
6316
- );
6627
+ if (error instanceof CheckConfigError) {
6628
+ result = errorResult(error.code, error.message);
6629
+ } else {
6630
+ const message = error instanceof Error ? error.message : String(error);
6631
+ const code = message.startsWith("--") || message.includes("Unknown --preset") ? "AI_CHECK_INVALID_ARGUMENTS" : error instanceof SyntaxError || message.includes("Unsupported check config extension") || message.includes("TypeScript check configs") || message.includes("Config must") || message.includes("checks config") || message.includes("Expected an array") ? "AI_CHECK_INVALID_CONFIG" : "AI_CHECK_CONFIG_LOAD_FAILED";
6632
+ result = errorResult(code, message);
6633
+ }
6317
6634
  } else {
6318
6635
  result = readErrorResult(error);
6319
6636
  }
@@ -7235,6 +7552,42 @@ function startViewerServer(options = {}) {
7235
7552
  });
7236
7553
  });
7237
7554
  }
7555
+ function openInDefaultBrowser(target) {
7556
+ const platform = process.platform;
7557
+ const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
7558
+ const args = platform === "win32" ? ["/c", "start", "", target] : [target];
7559
+ return new Promise((resolve) => {
7560
+ try {
7561
+ const child = spawn(command, args, {
7562
+ detached: true,
7563
+ stdio: "ignore",
7564
+ windowsHide: platform === "win32"
7565
+ });
7566
+ child.once("spawn", () => {
7567
+ try {
7568
+ child.unref();
7569
+ resolve({ ok: true });
7570
+ } catch (error) {
7571
+ resolve({
7572
+ ok: false,
7573
+ detail: error instanceof Error ? error.message : String(error)
7574
+ });
7575
+ }
7576
+ });
7577
+ child.once("error", (error) => {
7578
+ resolve({
7579
+ ok: false,
7580
+ detail: error instanceof Error ? error.message : String(error)
7581
+ });
7582
+ });
7583
+ } catch (error) {
7584
+ resolve({
7585
+ ok: false,
7586
+ detail: error instanceof Error ? error.message : String(error)
7587
+ });
7588
+ }
7589
+ });
7590
+ }
7238
7591
 
7239
7592
  // packages/cli/src/serve.ts
7240
7593
  function parsePort(value) {
@@ -7264,9 +7617,11 @@ async function serveCommand(options = {}) {
7264
7617
  if (options.open === true && host !== "127.0.0.1" && host !== "localhost") {
7265
7618
  console.warn("Skipping browser open for non-local host binding.");
7266
7619
  } else if (options.open === true) {
7267
- const openMod = await import('child_process');
7268
- openMod.exec(`open ${info.url}`, () => {
7269
- });
7620
+ const opened = await openInDefaultBrowser(info.url);
7621
+ if (!opened.ok) {
7622
+ console.warn("Viewer started, but the browser could not be opened automatically.");
7623
+ console.warn(`Open manually: ${info.url}`);
7624
+ }
7270
7625
  }
7271
7626
  await new Promise(() => {
7272
7627
  });
@@ -7425,9 +7780,11 @@ async function studioCommand(options = {}) {
7425
7780
  if (options.open === true && info.host !== "127.0.0.1" && info.host !== "localhost") {
7426
7781
  console.warn("Skipping browser open for non-local host binding.");
7427
7782
  } else if (options.open === true) {
7428
- const openMod = await import('child_process');
7429
- openMod.exec(`open ${info.url}`, () => {
7430
- });
7783
+ const opened = await openInDefaultBrowser(info.url);
7784
+ if (!opened.ok) {
7785
+ console.warn("Studio started, but the browser could not be opened automatically.");
7786
+ console.warn(`Open manually: ${info.url}`);
7787
+ }
7431
7788
  }
7432
7789
  await new Promise(() => {
7433
7790
  });
@@ -8186,7 +8543,7 @@ function asStringArray2(value, label) {
8186
8543
  }
8187
8544
  return value;
8188
8545
  }
8189
- function asConfig2(value) {
8546
+ function asConfig(value) {
8190
8547
  if (value === void 0 || value === null) return {};
8191
8548
  if (typeof value !== "object" || Array.isArray(value)) {
8192
8549
  throw new Error("Config must export an object.");
@@ -8207,10 +8564,10 @@ async function loadConfig2(configPath) {
8207
8564
  const absolute = path18.resolve(configPath);
8208
8565
  if (extension === ".json") {
8209
8566
  const raw = await readFile(absolute, "utf-8");
8210
- return asConfig2(JSON.parse(raw));
8567
+ return asConfig(JSON.parse(raw));
8211
8568
  }
8212
8569
  const mod = await import(pathToFileURL(absolute).href);
8213
- return asConfig2("default" in mod ? mod.default : mod);
8570
+ return asConfig("default" in mod ? mod.default : mod);
8214
8571
  }
8215
8572
  function normalizeConfig2(config) {
8216
8573
  if (config.eval === void 0) return {};
@@ -9715,33 +10072,6 @@ async function resolveHtmlPath(root) {
9715
10072
  `No evidence.html found under ${root}. Pass a bundle directory or .html path.`
9716
10073
  );
9717
10074
  }
9718
- function openLocalFile(filePath) {
9719
- const fileUrl = pathToFileURL(filePath).href;
9720
- const platform = process.platform;
9721
- const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
9722
- const args = platform === "darwin" ? [filePath] : platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
9723
- return new Promise((resolve) => {
9724
- try {
9725
- const child = spawn(command, args, {
9726
- detached: true,
9727
- stdio: "ignore"
9728
- });
9729
- child.on("error", (error) => {
9730
- resolve({
9731
- ok: false,
9732
- detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
9733
- });
9734
- });
9735
- child.unref();
9736
- resolve({ ok: true, detail: fileUrl });
9737
- } catch (error) {
9738
- resolve({
9739
- ok: false,
9740
- detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
9741
- });
9742
- }
9743
- });
9744
- }
9745
10075
  async function bundleOpenCommand(targetPath, options = {}) {
9746
10076
  const root = path18.resolve(targetPath.trim() || ".");
9747
10077
  try {
@@ -9811,23 +10141,24 @@ async function bundleOpenCommand(targetPath, options = {}) {
9811
10141
  await readFile(path18.join(path18.dirname(htmlPath), "evidence.json"), "utf-8");
9812
10142
  } catch {
9813
10143
  }
9814
- const opened = await openLocalFile(htmlPath);
10144
+ const fileUrl = pathToFileURL(htmlPath).href;
10145
+ const opened = await openInDefaultBrowser(fileUrl);
9815
10146
  if (options.json) {
9816
10147
  console.log(
9817
10148
  writeJson6({
9818
10149
  ok: opened.ok,
9819
10150
  path: htmlPath,
9820
10151
  opened: opened.ok,
9821
- detail: opened.detail
10152
+ detail: opened.ok ? fileUrl : `${opened.detail ?? "unknown error"}; open manually: ${fileUrl}`
9822
10153
  }).trimEnd()
9823
10154
  );
9824
10155
  } else if (opened.ok) {
9825
10156
  console.log(`Opened local Evidence: ${htmlPath}`);
9826
- console.log(`URL: ${opened.detail}`);
10157
+ console.log(`URL: ${fileUrl}`);
9827
10158
  } else {
9828
10159
  console.error(`[AgentInspect] Could not open browser automatically.`);
9829
10160
  console.error(`Open this file locally: ${htmlPath}`);
9830
- console.error(opened.detail);
10161
+ console.error(`${opened.detail ?? "unknown error"}; open manually: ${fileUrl}`);
9831
10162
  }
9832
10163
  if (!opened.ok) {
9833
10164
  process.exitCode = 0;
@@ -11260,7 +11591,7 @@ function isModuleNotFound4(e) {
11260
11591
  }
11261
11592
  async function loadIndexSqlite() {
11262
11593
  try {
11263
- return await import('./src-X6SLMBNH.mjs');
11594
+ return await import('./src-OYGG7QAZ.mjs');
11264
11595
  } catch (e) {
11265
11596
  if (isModuleNotFound4(e)) {
11266
11597
  console.error(