agent-inspect 6.16.2 → 6.17.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,17 +1,18 @@
1
1
  #!/usr/bin/env node
2
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-LFSBMUCD.mjs';
3
3
  import { realpathSync, constants as constants$1, existsSync, readFileSync } from 'fs';
4
- import path16 from 'path';
4
+ import path18 from 'path';
5
5
  import { fileURLToPath, pathToFileURL } from 'url';
6
6
  import { Command, Option } from 'commander';
7
- import { readFile, stat, mkdir, writeFile, unlink, appendFile, rm, access, open, readdir, constants } from 'fs/promises';
7
+ import { readFile, stat, mkdir, writeFile, unlink, appendFile, access, rm, open, readdir, constants } from 'fs/promises';
8
8
  import process2, { stdin, stdout } from 'process';
9
9
  import crypto, { createHash } from 'crypto';
10
10
  import { createServer } from 'http';
11
+ import { spawn } from 'child_process';
11
12
  import { createRequire } from 'module';
12
13
 
13
14
  // package.json
14
- var version = "6.16.2";
15
+ var version = "6.17.0";
15
16
 
16
17
  // packages/cli/src/trace-dir-scale.ts
17
18
  var TRACE_COUNT_WARN = 1e3;
@@ -2971,9 +2972,9 @@ Trace directory: ${traceDir}`);
2971
2972
  process.exitCode = 1;
2972
2973
  }
2973
2974
  const resolvedOutput = resolveOutputOption(options);
2974
- const outPath = resolvedOutput !== void 0 ? path16.resolve(resolvedOutput) : void 0;
2975
+ const outPath = resolvedOutput !== void 0 ? path18.resolve(resolvedOutput) : void 0;
2975
2976
  if (outPath !== void 0) {
2976
- await mkdir(path16.dirname(outPath), { recursive: true });
2977
+ await mkdir(path18.dirname(outPath), { recursive: true });
2977
2978
  await writeFile(outPath, result.content, "utf-8");
2978
2979
  const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
2979
2980
  console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
@@ -3317,7 +3318,7 @@ function indexedToMetadata(row, traceDir) {
3317
3318
  endedAt: row.endedAt ?? void 0,
3318
3319
  durationMs: row.durationMs ?? void 0,
3319
3320
  eventCount: 0,
3320
- filePath: path16.join(traceDir, row.file),
3321
+ filePath: path18.join(traceDir, row.file),
3321
3322
  fileSize: 0,
3322
3323
  createdAt: new Date(row.mtimeMs)
3323
3324
  };
@@ -3795,9 +3796,9 @@ async function reportCommand(runId, options = {}) {
3795
3796
  ...options.section ? { section: options.section } : {}
3796
3797
  });
3797
3798
  const resolvedOutput = resolveOutputOption(options);
3798
- const outPath = resolvedOutput !== void 0 ? path16.resolve(resolvedOutput) : void 0;
3799
+ const outPath = resolvedOutput !== void 0 ? path18.resolve(resolvedOutput) : void 0;
3799
3800
  if (outPath !== void 0) {
3800
- await mkdir(path16.dirname(outPath), { recursive: true });
3801
+ await mkdir(path18.dirname(outPath), { recursive: true });
3801
3802
  await writeFile(outPath, result.content, "utf-8");
3802
3803
  console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
3803
3804
  }
@@ -3976,8 +3977,8 @@ function passesLuhn(value) {
3976
3977
  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;
3977
3978
  var EPOCH_MS_RE = /^1[0-9]{12}$/;
3978
3979
  var EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
3979
- function pathSuggestsNonCard(path27) {
3980
- const normalized = path27.toLowerCase().replace(/[^a-z0-9._]/g, "");
3980
+ function pathSuggestsNonCard(path29) {
3981
+ const normalized = path29.toLowerCase().replace(/[^a-z0-9._]/g, "");
3981
3982
  return /(^|\.)(tokenusage|usage)(\.|$)/.test(normalized) || /(startedat|endedat|durationms|timestamp|createdat|updatedat)(\.|$)/.test(normalized) || /(^|\.)(runid|traceid|spanid|eventid|sessionid|userid|parentid|requestid|correlationid)(\.|$)/.test(
3982
3983
  normalized
3983
3984
  ) || /(^|\.)ts(\.|$)/.test(normalized);
@@ -4164,17 +4165,17 @@ function applyRule(rule, value, replacement) {
4164
4165
  }
4165
4166
  return value;
4166
4167
  }
4167
- function childPath(path27, key) {
4168
+ function childPath(path29, key) {
4168
4169
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
4169
- return path27 ? `${path27}.${key}` : key;
4170
+ return path29 ? `${path29}.${key}` : key;
4170
4171
  }
4171
- return `${path27 || "$"}[${JSON.stringify(key)}]`;
4172
+ return `${path29 || "$"}[${JSON.stringify(key)}]`;
4172
4173
  }
4173
- function indexPath(path27, index) {
4174
- return `${path27 || "$"}[${index}]`;
4174
+ function indexPath(path29, index) {
4175
+ return `${path29 || "$"}[${index}]`;
4175
4176
  }
4176
- function makeFinding(path27, detector, action, matchKind, severity = "warning", preview) {
4177
- return preview === void 0 ? { path: path27, detector, action, severity, matchKind } : { path: path27, detector, action, severity, matchKind, preview };
4177
+ function makeFinding(path29, detector, action, matchKind, severity = "warning", preview) {
4178
+ return preview === void 0 ? { path: path29, detector, action, severity, matchKind } : { path: path29, detector, action, severity, matchKind, preview };
4178
4179
  }
4179
4180
  function createRedactionProfile(profile = "local") {
4180
4181
  switch (profile) {
@@ -4243,11 +4244,11 @@ var Redactor2 = class {
4243
4244
  #recordFinding(state, finding) {
4244
4245
  if (this.#collectFindings) state.findings.push(finding);
4245
4246
  }
4246
- #redactValue(value, key, path27, depth, state) {
4247
+ #redactValue(value, key, path29, depth, state) {
4247
4248
  if (depth > this.#maxDepth) {
4248
4249
  this.#recordFinding(
4249
4250
  state,
4250
- makeFinding(path27, "structure.maxDepth", "truncate", "value", "warning")
4251
+ makeFinding(path29, "structure.maxDepth", "truncate", "value", "warning")
4251
4252
  );
4252
4253
  return "[Truncated]";
4253
4254
  }
@@ -4256,19 +4257,19 @@ var Redactor2 = class {
4256
4257
  if (rule) {
4257
4258
  this.#recordFinding(
4258
4259
  state,
4259
- makeFinding(path27, `key.${rule.key}`, actionForRule(rule), "key", "warning")
4260
+ makeFinding(path29, `key.${rule.key}`, actionForRule(rule), "key", "warning")
4260
4261
  );
4261
4262
  return applyRule(rule, value, this.#replacement);
4262
4263
  }
4263
4264
  }
4264
4265
  for (const detector of this.#detectors) {
4265
- const detections = detector.detect({ path: path27, key, value });
4266
+ const detections = detector.detect({ path: path29, key, value });
4266
4267
  for (const detection of detections) {
4267
4268
  const action = detection.action ?? "replace";
4268
4269
  this.#recordFinding(
4269
4270
  state,
4270
4271
  makeFinding(
4271
- path27,
4272
+ path29,
4272
4273
  detector.id,
4273
4274
  action,
4274
4275
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -4286,7 +4287,7 @@ var Redactor2 = class {
4286
4287
  const out = [];
4287
4288
  state.seen.set(value, out);
4288
4289
  value.forEach((item, index) => {
4289
- out[index] = this.#redactValue(item, void 0, indexPath(path27, index), depth + 1, state);
4290
+ out[index] = this.#redactValue(item, void 0, indexPath(path29, index), depth + 1, state);
4290
4291
  });
4291
4292
  return out;
4292
4293
  }
@@ -4298,7 +4299,7 @@ var Redactor2 = class {
4298
4299
  out[entryKey] = this.#redactValue(
4299
4300
  entryValue,
4300
4301
  entryKey,
4301
- childPath(path27 === "$" ? "" : path27, entryKey),
4302
+ childPath(path29 === "$" ? "" : path29, entryKey),
4302
4303
  depth + 1,
4303
4304
  state
4304
4305
  );
@@ -4759,14 +4760,14 @@ function uniqueSorted(values) {
4759
4760
  return [...new Set(values)].sort();
4760
4761
  }
4761
4762
  function isWithinDirectory(child, parent) {
4762
- const relative = path16.relative(parent, child);
4763
- return relative === "" || !relative.startsWith("..") && !path16.isAbsolute(relative);
4763
+ const relative = path18.relative(parent, child);
4764
+ return relative === "" || !relative.startsWith("..") && !path18.isAbsolute(relative);
4764
4765
  }
4765
4766
  async function resolveOutputPath(inputPath, output2, force) {
4766
4767
  if (output2 === void 0 || output2.trim() === "") return void 0;
4767
- const inputAbs = path16.resolve(inputPath);
4768
- const outputAbs = path16.resolve(output2.trim());
4769
- const inputDir = path16.dirname(inputAbs);
4768
+ const inputAbs = path18.resolve(inputPath);
4769
+ const outputAbs = path18.resolve(output2.trim());
4770
+ const inputDir = path18.dirname(inputAbs);
4770
4771
  if (!isWithinDirectory(outputAbs, inputDir)) {
4771
4772
  throw new Error("Refusing to write migrated output outside the input directory.");
4772
4773
  }
@@ -4887,7 +4888,7 @@ async function migrateCommand(input3, options = {}) {
4887
4888
  process.exitCode = 1;
4888
4889
  return;
4889
4890
  }
4890
- const inputPath = path16.resolve(input3.trim());
4891
+ const inputPath = path18.resolve(input3.trim());
4891
4892
  const dryRun = options.dryRun === true;
4892
4893
  if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
4893
4894
  console.error("migrate requires --dry-run or --output <path>.");
@@ -4906,7 +4907,7 @@ async function migrateCommand(input3, options = {}) {
4906
4907
  );
4907
4908
  const result = await buildMigration(inputPath, outputPath);
4908
4909
  if (!dryRun && outputPath !== void 0) {
4909
- await mkdir(path16.dirname(outputPath), { recursive: true });
4910
+ await mkdir(path18.dirname(outputPath), { recursive: true });
4910
4911
  await writeFile(outputPath, result.content, "utf-8");
4911
4912
  }
4912
4913
  printSummary2(result, dryRun);
@@ -4916,6 +4917,243 @@ async function migrateCommand(input3, options = {}) {
4916
4917
  process.exitCode = 1;
4917
4918
  }
4918
4919
  }
4920
+ function validateReporterArtifactPath(options) {
4921
+ const outputDir = path18.resolve(options.outputDir);
4922
+ const diagnostics = [];
4923
+ const rawPath = options.relativePath;
4924
+ if (rawPath.length === 0) {
4925
+ diagnostics.push({
4926
+ code: "artifact_path_empty",
4927
+ severity: "error",
4928
+ message: "Reporter artifact path must not be empty."
4929
+ });
4930
+ return { ok: false, outputDir, diagnostics };
4931
+ }
4932
+ if (rawPath.includes("\0")) {
4933
+ diagnostics.push({
4934
+ code: "invalid_artifact_path",
4935
+ severity: "error",
4936
+ message: "Reporter artifact path must not contain null bytes.",
4937
+ target: rawPath
4938
+ });
4939
+ return { ok: false, outputDir, diagnostics };
4940
+ }
4941
+ if (path18.isAbsolute(rawPath) || path18.win32.isAbsolute(rawPath)) {
4942
+ diagnostics.push({
4943
+ code: "artifact_path_absolute",
4944
+ severity: "error",
4945
+ message: "Reporter artifact path must be relative.",
4946
+ target: rawPath
4947
+ });
4948
+ return { ok: false, outputDir, diagnostics };
4949
+ }
4950
+ const normalized = path18.posix.normalize(rawPath.replace(/\\/g, "/"));
4951
+ const segments = normalized.split("/");
4952
+ if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
4953
+ diagnostics.push({
4954
+ code: "artifact_path_escape",
4955
+ severity: "error",
4956
+ message: "Reporter artifact path must stay under the output directory.",
4957
+ target: rawPath
4958
+ });
4959
+ return { ok: false, outputDir, diagnostics };
4960
+ }
4961
+ const absolutePath = path18.resolve(outputDir, normalized);
4962
+ const relFromOutput = path18.relative(outputDir, absolutePath);
4963
+ if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path18.isAbsolute(relFromOutput)) {
4964
+ diagnostics.push({
4965
+ code: "artifact_path_escape",
4966
+ severity: "error",
4967
+ message: "Reporter artifact path resolved outside the output directory.",
4968
+ target: rawPath
4969
+ });
4970
+ return { ok: false, outputDir, diagnostics };
4971
+ }
4972
+ return {
4973
+ ok: true,
4974
+ outputDir,
4975
+ relativePath: normalized,
4976
+ absolutePath,
4977
+ diagnostics
4978
+ };
4979
+ }
4980
+ var EVIDENCE_CI_ARTIFACT_FILES = [
4981
+ "evidence.html",
4982
+ "evidence.json",
4983
+ "check-results.json",
4984
+ "trace.jsonl"
4985
+ ];
4986
+ function createEvidenceCiArtifacts(options) {
4987
+ const profile = options.redactionProfile ?? "share";
4988
+ const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
4989
+ const join = (name) => prefix === "" ? name : path18.posix.join(prefix, name);
4990
+ const formatFor = (name) => {
4991
+ if (name.endsWith(".html")) return "html";
4992
+ if (name.endsWith(".jsonl")) return "jsonl";
4993
+ return "json";
4994
+ };
4995
+ return EVIDENCE_CI_ARTIFACT_FILES.map((name) => ({
4996
+ kind: "evidence",
4997
+ path: join(name),
4998
+ format: formatFor(name),
4999
+ redactionProfile: profile,
5000
+ title: `Evidence v2 ${name}`
5001
+ }));
5002
+ }
5003
+
5004
+ // packages/cli/src/evidence-on.ts
5005
+ function shouldEmitEvidence(mode, failed) {
5006
+ if (mode === void 0 || mode === "never") return false;
5007
+ if (mode === "always") return true;
5008
+ return failed;
5009
+ }
5010
+ function parseEvidenceProfile(value) {
5011
+ const profile = (value ?? "share").trim().toLowerCase();
5012
+ if (profile === "local" || profile === "share" || profile === "strict") {
5013
+ return profile;
5014
+ }
5015
+ throw new Error(
5016
+ `Unsupported --evidence-profile "${value}". Use local, share, or strict.`
5017
+ );
5018
+ }
5019
+ function parseEvidenceFormat(value) {
5020
+ const format = (value ?? "directory").trim().toLowerCase();
5021
+ if (format === "directory" || format === "html" || format === "zip") {
5022
+ return format;
5023
+ }
5024
+ throw new Error(
5025
+ `Unsupported --evidence-format "${value}". Use directory, html, or zip.`
5026
+ );
5027
+ }
5028
+ function toAssessmentStatus(failed) {
5029
+ return failed ? "UNSAFE" : "SAFE";
5030
+ }
5031
+ function stableJson2(value) {
5032
+ return `${JSON.stringify(value, null, 2)}
5033
+ `;
5034
+ }
5035
+ async function writeLocalEvidence(input3) {
5036
+ const profile = input3.redactionProfile ?? "share";
5037
+ const format = input3.format ?? "directory";
5038
+ const baseDir = path18.resolve(input3.outputDir);
5039
+ await mkdir(
5040
+ format === "zip" && baseDir.toLowerCase().endsWith(".zip") ? path18.dirname(baseDir) : baseDir,
5041
+ { recursive: true }
5042
+ );
5043
+ const sourceContents = /* @__PURE__ */ new Map();
5044
+ if (input3.sourceContents instanceof Map) {
5045
+ for (const [runId, content] of input3.sourceContents) {
5046
+ sourceContents.set(runId, content);
5047
+ }
5048
+ } else if (input3.sourceContents !== void 0) {
5049
+ for (const [runId, content] of Object.entries(input3.sourceContents)) {
5050
+ sourceContents.set(runId, content);
5051
+ }
5052
+ }
5053
+ const traceDir = resolveTraceDir({ dir: input3.dir });
5054
+ let combined = "";
5055
+ for (const runId of input3.runIds) {
5056
+ let raw = sourceContents.get(runId) ?? "";
5057
+ if (raw === "") {
5058
+ try {
5059
+ raw = await readFile(getTraceFilePath(runId, traceDir), "utf-8");
5060
+ } catch {
5061
+ raw = "";
5062
+ }
5063
+ sourceContents.set(runId, raw);
5064
+ }
5065
+ const redacted = redactTraceContent(raw, profile);
5066
+ combined += redacted.content.endsWith("\n") ? redacted.content : `${redacted.content}
5067
+ `;
5068
+ }
5069
+ const assessmentStatus = toAssessmentStatus(input3.failed);
5070
+ const evidencePackage = buildEvidenceCiPackage({
5071
+ generatorVersion: version,
5072
+ runIds: input3.runIds,
5073
+ sourceContents,
5074
+ redactedTraceJsonl: combined,
5075
+ redactionProfile: profile,
5076
+ assessmentStatus,
5077
+ checkResultsJson: input3.checkResultsJson,
5078
+ ...input3.summaryText !== void 0 ? { summaryText: input3.summaryText } : {}
5079
+ });
5080
+ const files = [
5081
+ ["evidence.html", evidencePackage["evidence.html"]],
5082
+ ["evidence.json", evidencePackage["evidence.json"]],
5083
+ ["check-results.json", evidencePackage["check-results.json"]],
5084
+ ["trace.jsonl", evidencePackage["trace.jsonl"]]
5085
+ ];
5086
+ const expected = createEvidenceCiArtifacts({
5087
+ redactionProfile: profile
5088
+ }).map((a) => a.path);
5089
+ for (const name of expected) {
5090
+ if (!files.some(([fileName]) => fileName === name)) {
5091
+ throw new Error(`Evidence CI package missing expected file: ${name}`);
5092
+ }
5093
+ }
5094
+ if (format === "zip") {
5095
+ const zipPath = baseDir.toLowerCase().endsWith(".zip") ? baseDir : `${baseDir}.zip`;
5096
+ await mkdir(path18.dirname(zipPath), { recursive: true });
5097
+ const archive = buildZipArchive(
5098
+ files.map(([relativePath, content]) => ({
5099
+ path: relativePath,
5100
+ content
5101
+ }))
5102
+ );
5103
+ await writeFile(zipPath, archive);
5104
+ return zipPath;
5105
+ }
5106
+ if (format === "html") {
5107
+ let htmlPath = baseDir;
5108
+ let sidecarDir = baseDir;
5109
+ if (baseDir.toLowerCase().endsWith(".html")) {
5110
+ htmlPath = baseDir;
5111
+ sidecarDir = path18.dirname(baseDir);
5112
+ } else {
5113
+ await mkdir(baseDir, { recursive: true });
5114
+ htmlPath = path18.join(baseDir, "evidence.html");
5115
+ sidecarDir = baseDir;
5116
+ }
5117
+ await mkdir(sidecarDir, { recursive: true });
5118
+ await writeFile(htmlPath, evidencePackage["evidence.html"], "utf-8");
5119
+ await writeFile(
5120
+ path18.join(sidecarDir, "evidence.json"),
5121
+ evidencePackage["evidence.json"],
5122
+ "utf-8"
5123
+ );
5124
+ return htmlPath;
5125
+ }
5126
+ await mkdir(baseDir, { recursive: true });
5127
+ for (const [name, content] of files) {
5128
+ await writeFile(path18.join(baseDir, name), content, "utf-8");
5129
+ }
5130
+ return baseDir;
5131
+ }
5132
+ function checkResultToEvidenceJson(result, runIds) {
5133
+ const status = result.status === "pass" ? "SAFE" : result.status === "fail" ? "UNSAFE" : "UNKNOWN";
5134
+ return stableJson2({
5135
+ aggregateStatus: status,
5136
+ runs: runIds.map((runId) => ({
5137
+ runId,
5138
+ status,
5139
+ errors: result.summary.errors,
5140
+ warnings: result.summary.warnings,
5141
+ findings: result.findings.length
5142
+ })),
5143
+ findings: result.findings,
5144
+ diagnostics: result.diagnostics
5145
+ });
5146
+ }
5147
+ function defaultEvidenceDir(label) {
5148
+ const safe = label.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 80) || "evidence";
5149
+ return path18.join(".agent-inspect", "evidence", safe);
5150
+ }
5151
+ function resolveEvidenceOutputDir(evidenceDir, label) {
5152
+ if (evidenceDir !== void 0 && evidenceDir.trim() !== "") {
5153
+ return path18.resolve(evidenceDir.trim());
5154
+ }
5155
+ return defaultEvidenceDir(label);
5156
+ }
4919
5157
  var ALL_RULES = [
4920
5158
  "circuit.same-tool-repetition",
4921
5159
  "circuit.same-args-repetition",
@@ -5236,23 +5474,23 @@ function evaluatePromptInjection(text, options = {}) {
5236
5474
  }
5237
5475
  return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
5238
5476
  }
5239
- function validateSchemaField(value, field, path27, evidence) {
5477
+ function validateSchemaField(value, field, path29, evidence) {
5240
5478
  const ruleId = "guardrail.structured-output";
5241
5479
  if (field.type) {
5242
5480
  const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
5243
5481
  if (actual !== field.type) {
5244
- evidence.push({ ruleId, path: path27, preview: `expected ${field.type}, got ${actual}` });
5482
+ evidence.push({ ruleId, path: path29, preview: `expected ${field.type}, got ${actual}` });
5245
5483
  return;
5246
5484
  }
5247
5485
  }
5248
5486
  if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
5249
- evidence.push({ ruleId, path: path27, preview: "value not in enum" });
5487
+ evidence.push({ ruleId, path: path29, preview: "value not in enum" });
5250
5488
  }
5251
5489
  if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
5252
5490
  const record = value;
5253
5491
  for (const key of field.required) {
5254
5492
  if (!(key in record)) {
5255
- evidence.push({ ruleId, path: `${path27}.${key}`, preview: "missing required key" });
5493
+ evidence.push({ ruleId, path: `${path29}.${key}`, preview: "missing required key" });
5256
5494
  }
5257
5495
  }
5258
5496
  }
@@ -5533,6 +5771,54 @@ function mergeSafetyExtensions(result, read, options) {
5533
5771
  }
5534
5772
 
5535
5773
  // packages/cli/src/check.ts
5774
+ function resolvePreset(preset, context = {}) {
5775
+ if (preset === void 0 || preset.trim() === "") return void 0;
5776
+ const name = preset.trim().toLowerCase();
5777
+ if (name !== "trajectory" && name !== "safety" && name !== "comprehensive") {
5778
+ throw new Error(
5779
+ `Unknown --preset "${preset}". Use trajectory, safety, or comprehensive.`
5780
+ );
5781
+ }
5782
+ const trajectorySelect = [
5783
+ "run.status",
5784
+ "run.requireCompleted",
5785
+ "structure.orphan",
5786
+ "structure.cycle",
5787
+ "structure.relationship"
5788
+ ];
5789
+ if (context.hasToolRules === true) {
5790
+ trajectorySelect.push("tool.usage");
5791
+ }
5792
+ const safetySelect = [
5793
+ "run.status",
5794
+ "safety.rawPrompt",
5795
+ "safety.secretPattern",
5796
+ "safety.redaction"
5797
+ ];
5798
+ if (name === "trajectory") {
5799
+ return {
5800
+ requireCompleted: true,
5801
+ enableSafetyRedaction: false,
5802
+ enableStructureRelationshipDefaults: true,
5803
+ select: trajectorySelect
5804
+ };
5805
+ }
5806
+ if (name === "safety") {
5807
+ return {
5808
+ requireCompleted: false,
5809
+ enableSafetyRedaction: true,
5810
+ enableStructureRelationshipDefaults: false,
5811
+ select: safetySelect
5812
+ };
5813
+ }
5814
+ const select = [.../* @__PURE__ */ new Set([...trajectorySelect, ...safetySelect])];
5815
+ return {
5816
+ requireCompleted: true,
5817
+ enableSafetyRedaction: true,
5818
+ enableStructureRelationshipDefaults: true,
5819
+ select
5820
+ };
5821
+ }
5536
5822
  var DEFAULT_SELECT = ["run.status"];
5537
5823
  var CONFIG_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
5538
5824
  var TS_CONFIG_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".mts", ".cts"]);
@@ -5579,7 +5865,7 @@ function asConfig(value) {
5579
5865
  }
5580
5866
  async function loadConfig(configPath) {
5581
5867
  if (configPath === void 0) return {};
5582
- const extension = path16.extname(configPath);
5868
+ const extension = path18.extname(configPath);
5583
5869
  if (TS_CONFIG_EXTENSIONS.has(extension)) {
5584
5870
  throw new Error(
5585
5871
  "TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -5588,7 +5874,7 @@ async function loadConfig(configPath) {
5588
5874
  if (!CONFIG_EXTENSIONS.has(extension)) {
5589
5875
  throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
5590
5876
  }
5591
- const absolute = path16.resolve(configPath);
5877
+ const absolute = path18.resolve(configPath);
5592
5878
  if (extension === ".json") {
5593
5879
  const raw = await readFile(absolute, "utf-8");
5594
5880
  return asConfig(JSON.parse(raw));
@@ -5603,6 +5889,33 @@ function normalizeConfig(config) {
5603
5889
  }
5604
5890
  return config.checks;
5605
5891
  }
5892
+ function hasToolRulesConfigured(config, options) {
5893
+ const tool = normalizeConfig(config).tool ?? {};
5894
+ return Boolean(
5895
+ (tool.required?.length ?? 0) > 0 || (tool.forbidden?.length ?? 0) > 0 || (tool.allowed?.length ?? 0) > 0 || tool.minCount !== void 0 || tool.maxCount !== void 0 || (options.requiredTool?.length ?? 0) > 0 || (options.forbiddenTool?.length ?? 0) > 0
5896
+ );
5897
+ }
5898
+ function applyResolvedPreset(config, options, resolved) {
5899
+ const checks2 = { ...normalizeConfig(config) };
5900
+ if (resolved.enableSafetyRedaction) {
5901
+ checks2.safety = { ...checks2.safety, redaction: true };
5902
+ }
5903
+ if (resolved.enableStructureRelationshipDefaults) {
5904
+ const structure = checks2.structure ?? {};
5905
+ const needed = structure.minConfidence === void 0 && structure.requireParentBeforeChild === void 0 && structure.requireTraceParentSpan === void 0;
5906
+ if (needed) {
5907
+ checks2.structure = { ...structure, requireParentBeforeChild: true };
5908
+ }
5909
+ }
5910
+ return {
5911
+ config: { checks: checks2 },
5912
+ options: {
5913
+ ...options,
5914
+ ...resolved.requireCompleted ? { requireCompleted: true } : {},
5915
+ rule: [...resolved.select, ...options.rule ?? []]
5916
+ }
5917
+ };
5918
+ }
5606
5919
  function buildRules(config, options) {
5607
5920
  const diagnostics = [];
5608
5921
  const checks2 = normalizeConfig(config);
@@ -5746,7 +6059,42 @@ function stable2(value) {
5746
6059
  function printJson(result) {
5747
6060
  console.log(JSON.stringify(stable2(result), null, 2));
5748
6061
  }
5749
- function printHuman(result) {
6062
+ function isSafetyFinding(ruleId) {
6063
+ return ruleId.startsWith("safety.") || ruleId.startsWith("guardrail.") || ruleId.includes("pii") || ruleId.includes("secret");
6064
+ }
6065
+ function printPresetClassSummary(result, preset) {
6066
+ const name = preset?.trim().toLowerCase();
6067
+ if (name !== "trajectory" && name !== "safety" && name !== "comprehensive") {
6068
+ return;
6069
+ }
6070
+ const hasSafetyFindings = result.findings.some(
6071
+ (finding) => isSafetyFinding(finding.ruleId)
6072
+ );
6073
+ const hasTrajectoryFindings = result.findings.some(
6074
+ (finding) => !isSafetyFinding(finding.ruleId)
6075
+ );
6076
+ if (name === "trajectory") {
6077
+ console.log(
6078
+ `Trajectory: ${result.status === "pass" && !hasTrajectoryFindings ? "PASS" : result.status === "pass" ? "PASS" : "FAIL"}`
6079
+ );
6080
+ console.log("Share safety: not evaluated");
6081
+ console.log("Run verify-safe before sharing.");
6082
+ return;
6083
+ }
6084
+ if (name === "safety") {
6085
+ console.log(
6086
+ `Share safety: ${result.status === "pass" && !hasSafetyFindings ? "PASS" : result.status === "pass" ? "PASS" : "FAIL"}`
6087
+ );
6088
+ return;
6089
+ }
6090
+ console.log(
6091
+ `Trajectory: ${hasTrajectoryFindings || result.status === "error" ? "FAIL" : "PASS"}`
6092
+ );
6093
+ console.log(
6094
+ `Share safety: ${hasSafetyFindings || result.status === "fail" ? "FAIL" : result.status === "pass" ? "PASS" : "FAIL"}`
6095
+ );
6096
+ }
6097
+ function printHuman(result, options = {}) {
5750
6098
  const scoped = result;
5751
6099
  if (scoped.scopeLabel) {
5752
6100
  console.log(`Scope: ${scoped.scopeKind} ${scoped.scopeLabel}`);
@@ -5755,6 +6103,7 @@ function printHuman(result) {
5755
6103
  }
5756
6104
  }
5757
6105
  console.log(`Check status: ${result.status}`);
6106
+ printPresetClassSummary(result, options.preset);
5758
6107
  console.log(`Format: ${result.format}`);
5759
6108
  if (result.runId !== void 0) console.log(`Run: ${result.runId}`);
5760
6109
  console.log(
@@ -5764,10 +6113,10 @@ function printHuman(result) {
5764
6113
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
5765
6114
  }
5766
6115
  for (const finding of result.findings) {
5767
- const path27 = finding.evidence[0]?.path;
6116
+ const path29 = finding.evidence[0]?.path;
5768
6117
  const run = finding.evidence[0]?.runId;
5769
6118
  const runPrefix = run ? `[${run}] ` : "";
5770
- console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}`);
6119
+ console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path29 ? ` (${path29})` : ""}`);
5771
6120
  }
5772
6121
  }
5773
6122
  function readErrorResult(error) {
@@ -5783,12 +6132,24 @@ function readErrorResult(error) {
5783
6132
  async function checkCommand(target, options = {}, stdin = process.stdin) {
5784
6133
  let result;
5785
6134
  let phase = "config";
6135
+ let evidenceRead;
6136
+ let evidenceRunIds = [];
6137
+ let evidenceSourceContents;
5786
6138
  const sessionId = options.session?.trim();
5787
6139
  const groupId = options.group?.trim();
5788
6140
  const useSessionScope = Boolean(sessionId || groupId);
5789
6141
  try {
5790
- const config = await loadConfig(options.config);
5791
- const built = buildRules(config, options);
6142
+ let config = await loadConfig(options.config);
6143
+ let effectiveOptions = options;
6144
+ const resolved = resolvePreset(options.preset, {
6145
+ hasToolRules: hasToolRulesConfigured(config, options)
6146
+ });
6147
+ if (resolved !== void 0) {
6148
+ const applied = applyResolvedPreset(config, options, resolved);
6149
+ config = applied.config;
6150
+ effectiveOptions = applied.options;
6151
+ }
6152
+ const built = buildRules(config, effectiveOptions);
5792
6153
  if (built.diagnostics.some((item) => item.severity === "error")) {
5793
6154
  result = errorResult("AI_CHECK_INVALID_CONFIG", "Invalid check configuration.");
5794
6155
  result.diagnostics = [...built.diagnostics];
@@ -5809,6 +6170,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
5809
6170
  correlateByGroupId: options.correlateGroup === true
5810
6171
  });
5811
6172
  const perRun = [];
6173
+ const sourceContents = /* @__PURE__ */ new Map();
5812
6174
  for (const meta of scoped.metas) {
5813
6175
  const read = await openTrace(
5814
6176
  { type: "file", path: meta.filePath },
@@ -5816,6 +6178,15 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
5816
6178
  ...options.format !== void 0 ? { format: options.format } : {}
5817
6179
  }
5818
6180
  );
6181
+ try {
6182
+ sourceContents.set(meta.runId, await readFile(meta.filePath, "utf-8"));
6183
+ } catch {
6184
+ sourceContents.set(
6185
+ meta.runId,
6186
+ `${read.events.map((event) => JSON.stringify(event)).join("\n")}
6187
+ `
6188
+ );
6189
+ }
5819
6190
  perRun.push(
5820
6191
  mergeSafetyExtensions(
5821
6192
  runTraceChecks(
@@ -5834,6 +6205,8 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
5834
6205
  )
5835
6206
  );
5836
6207
  }
6208
+ evidenceRunIds = scoped.runIds;
6209
+ evidenceSourceContents = sourceContents;
5837
6210
  result = aggregateSessionCheckResults(perRun, {
5838
6211
  scopeKind: scoped.scopeKind,
5839
6212
  scopeLabel: scoped.scopeLabel,
@@ -5848,6 +6221,26 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
5848
6221
  const read = await openTrace(input3, {
5849
6222
  ...options.format !== void 0 ? { format: options.format } : {}
5850
6223
  });
6224
+ evidenceRead = read;
6225
+ evidenceRunIds = options.run !== void 0 ? [options.run] : read.runs.length === 1 ? [read.runs[0].runId] : read.runs.map((run) => run.runId);
6226
+ if (input3.type === "file") {
6227
+ try {
6228
+ const raw = await readFile(input3.path, "utf-8");
6229
+ evidenceSourceContents = new Map(
6230
+ evidenceRunIds.map((runId) => [runId, raw])
6231
+ );
6232
+ } catch {
6233
+ evidenceSourceContents = void 0;
6234
+ }
6235
+ } else {
6236
+ evidenceSourceContents = new Map(
6237
+ evidenceRunIds.map((runId) => [
6238
+ runId,
6239
+ `${read.events.filter((event) => event.runId === runId).map((event) => JSON.stringify(event)).join("\n")}
6240
+ `
6241
+ ])
6242
+ );
6243
+ }
5851
6244
  result = mergeSafetyExtensions(
5852
6245
  runTraceChecks(
5853
6246
  { read },
@@ -5867,7 +6260,7 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
5867
6260
  } catch (error) {
5868
6261
  if (phase === "config") {
5869
6262
  const message = error instanceof Error ? error.message : String(error);
5870
- const code = message.startsWith("--") ? "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";
6263
+ 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";
5871
6264
  result = errorResult(
5872
6265
  code,
5873
6266
  message
@@ -5877,8 +6270,47 @@ async function checkCommand(target, options = {}, stdin = process.stdin) {
5877
6270
  }
5878
6271
  }
5879
6272
  process.exitCode = exitCodeFor(result);
6273
+ const failed = result.status !== "pass";
6274
+ if (shouldEmitEvidence(options.evidenceOn, failed)) {
6275
+ try {
6276
+ const runIds = evidenceRunIds.length > 0 ? evidenceRunIds : result.runId !== void 0 ? [result.runId] : ["check"];
6277
+ if (evidenceSourceContents === void 0 && evidenceRead !== void 0) {
6278
+ evidenceSourceContents = new Map(
6279
+ runIds.map((runId) => [
6280
+ runId,
6281
+ `${evidenceRead.events.filter((event) => event.runId === runId).map((event) => JSON.stringify(event)).join("\n")}
6282
+ `
6283
+ ])
6284
+ );
6285
+ }
6286
+ let redactionProfile = parseEvidenceProfile(options.evidenceProfile);
6287
+ let evidenceFormat = parseEvidenceFormat(options.evidenceFormat);
6288
+ const outputDir = resolveEvidenceOutputDir(
6289
+ options.evidenceDir,
6290
+ runIds[0] ?? "check"
6291
+ );
6292
+ const written = await writeLocalEvidence({
6293
+ outputDir,
6294
+ runIds,
6295
+ ...evidenceSourceContents !== void 0 ? { sourceContents: evidenceSourceContents } : {},
6296
+ ...options.dir !== void 0 ? { dir: options.dir } : {},
6297
+ failed,
6298
+ checkResultsJson: checkResultToEvidenceJson(result, runIds),
6299
+ summaryText: `Check status: ${result.status}`,
6300
+ redactionProfile,
6301
+ format: evidenceFormat
6302
+ });
6303
+ if (!options.json) {
6304
+ console.log(`Evidence: ${written}`);
6305
+ }
6306
+ } catch (error) {
6307
+ console.error(
6308
+ `[AgentInspect] evidence package skipped: ${error instanceof Error ? error.message : String(error)}`
6309
+ );
6310
+ }
6311
+ }
5880
6312
  if (options.json) printJson(result);
5881
- else printHuman(result);
6313
+ else printHuman(result, options);
5882
6314
  }
5883
6315
 
5884
6316
  // packages/viewer/src/html.ts
@@ -6029,7 +6461,7 @@ async function loadSuiteViewerData(options) {
6029
6461
  for (const suiteCase of result.cases) {
6030
6462
  cases.push(await enrichCase(suiteCase, baselinePath));
6031
6463
  }
6032
- const artifactsDir = path16.join(path16.dirname(result.configPath), ".agent-inspect/suite-runs");
6464
+ const artifactsDir = path18.join(path18.dirname(result.configPath), ".agent-inspect/suite-runs");
6033
6465
  return {
6034
6466
  suiteName: result.suiteName,
6035
6467
  configPath: result.configPath,
@@ -6222,19 +6654,19 @@ function serializeWorkspaceManifest(manifest) {
6222
6654
  }
6223
6655
  var INDEX_DIR_NAME = "index";
6224
6656
  function resolveWorkspaceLocation(cwd = process.cwd()) {
6225
- const projectRoot = path16.resolve(cwd);
6226
- const workspaceDir = path16.join(projectRoot, WORKSPACE_DIR_NAME);
6657
+ const projectRoot = path18.resolve(cwd);
6658
+ const workspaceDir = path18.join(projectRoot, WORKSPACE_DIR_NAME);
6227
6659
  return {
6228
6660
  projectRoot,
6229
6661
  workspaceDir,
6230
- manifestPath: path16.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
6662
+ manifestPath: path18.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
6231
6663
  };
6232
6664
  }
6233
6665
  function resolveInsideWorkspace(workspaceDir, relative) {
6234
- const base = path16.resolve(workspaceDir);
6235
- const resolved = path16.resolve(base, relative);
6236
- const rel = path16.relative(base, resolved);
6237
- if (rel === "" || rel === "." || !rel.startsWith("..") && !path16.isAbsolute(rel)) {
6666
+ const base = path18.resolve(workspaceDir);
6667
+ const resolved = path18.resolve(base, relative);
6668
+ const rel = path18.relative(base, resolved);
6669
+ if (rel === "" || rel === "." || !rel.startsWith("..") && !path18.isAbsolute(rel)) {
6238
6670
  return resolved;
6239
6671
  }
6240
6672
  throw new Error(
@@ -6303,7 +6735,7 @@ async function createWorkspace(options = {}) {
6303
6735
  created = false;
6304
6736
  adopted = true;
6305
6737
  } else {
6306
- const project = options.project?.trim() || path16.basename(location.projectRoot) || "workspace";
6738
+ const project = options.project?.trim() || path18.basename(location.projectRoot) || "workspace";
6307
6739
  const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
6308
6740
  manifest = createDefaultWorkspaceManifest({
6309
6741
  project,
@@ -6442,7 +6874,7 @@ async function doctorWorkspace(location) {
6442
6874
  const abs = resolveInsideWorkspace(location.workspaceDir, rel);
6443
6875
  for (const file of await listJsonl(abs)) {
6444
6876
  try {
6445
- const s = await stat(path16.join(abs, file));
6877
+ const s = await stat(path18.join(abs, file));
6446
6878
  newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
6447
6879
  } catch {
6448
6880
  checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
@@ -6490,7 +6922,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
6490
6922
  const relPath = `${rel}/${entry}`;
6491
6923
  removed.push(relPath);
6492
6924
  if (!dryRun) {
6493
- await rm(path16.join(abs, entry), { recursive: true, force: true });
6925
+ await rm(path18.join(abs, entry), { recursive: true, force: true });
6494
6926
  }
6495
6927
  }
6496
6928
  }
@@ -6499,7 +6931,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
6499
6931
 
6500
6932
  // packages/viewer/src/workspace-data.ts
6501
6933
  async function loadWorkspaceViewerData(options) {
6502
- const cwd = path16.resolve(options.cwd ?? process.cwd());
6934
+ const cwd = path18.resolve(options.cwd ?? process.cwd());
6503
6935
  const location = resolveWorkspaceLocation(cwd);
6504
6936
  const manifestRead = await readWorkspaceManifestFile(location);
6505
6937
  if (!manifestRead.ok || manifestRead.manifest === void 0) {
@@ -6512,7 +6944,7 @@ async function loadWorkspaceViewerData(options) {
6512
6944
  const runs = [];
6513
6945
  for (const rel of manifestRead.manifest.traceDirs) {
6514
6946
  const traceDir = resolveTraceDir({
6515
- dir: path16.join(location.workspaceDir, rel)
6947
+ dir: path18.join(location.workspaceDir, rel)
6516
6948
  });
6517
6949
  const td = new TraceDirectory({ dir: traceDir });
6518
6950
  const files = await td.list();
@@ -6526,7 +6958,7 @@ async function loadWorkspaceViewerData(options) {
6526
6958
  runId: meta.runId,
6527
6959
  ...meta.name !== void 0 ? { name: meta.name } : {},
6528
6960
  status: meta.status,
6529
- file: path16.basename(meta.filePath)
6961
+ file: path18.basename(meta.filePath)
6530
6962
  });
6531
6963
  }
6532
6964
  }
@@ -6537,8 +6969,8 @@ async function loadWorkspaceViewerData(options) {
6537
6969
  doctor,
6538
6970
  runs,
6539
6971
  bundleDirs: [
6540
- path16.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
6541
- path16.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
6972
+ path18.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
6973
+ path18.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
6542
6974
  ]
6543
6975
  };
6544
6976
  }
@@ -6601,7 +7033,7 @@ function createViewerServer(options = {}) {
6601
7033
  ok: true,
6602
7034
  readOnly: true,
6603
7035
  mode,
6604
- traceDir: path16.resolve(traceDir)
7036
+ traceDir: path18.resolve(traceDir)
6605
7037
  });
6606
7038
  }
6607
7039
  if (pathname === "/api/suite" && mode === "suite") {
@@ -6630,7 +7062,7 @@ function createViewerServer(options = {}) {
6630
7062
  runId: meta.runId,
6631
7063
  name: meta.name,
6632
7064
  status: meta.status,
6633
- file: path16.basename(meta.filePath),
7065
+ file: path18.basename(meta.filePath),
6634
7066
  startedAt: meta.startedAt,
6635
7067
  durationMs: meta.durationMs
6636
7068
  }))
@@ -6747,7 +7179,7 @@ function startViewerServer(options = {}) {
6747
7179
  resolve({
6748
7180
  host,
6749
7181
  port: resolvedPort,
6750
- traceDir: path16.resolve(traceDir),
7182
+ traceDir: path18.resolve(traceDir),
6751
7183
  url: `http://${host}:${resolvedPort}/${modeQuery}`,
6752
7184
  mode
6753
7185
  });
@@ -7118,10 +7550,10 @@ async function evalRun(input3, options = {}) {
7118
7550
  diagnostics: []
7119
7551
  };
7120
7552
  }
7121
- function evidenceForRun(run, path27) {
7122
- return [{ runId: run.runId, ...path27 !== void 0 ? { path: path27 } : {} }];
7553
+ function evidenceForRun(run, path29) {
7554
+ return [{ runId: run.runId, ...path29 !== void 0 ? { path: path29 } : {} }];
7123
7555
  }
7124
- function evidenceForEvent(event, path27) {
7556
+ function evidenceForEvent(event, path29) {
7125
7557
  return [
7126
7558
  {
7127
7559
  runId: event.runId,
@@ -7129,7 +7561,7 @@ function evidenceForEvent(event, path27) {
7129
7561
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
7130
7562
  kind: event.kind,
7131
7563
  name: event.name,
7132
- ...path27 !== void 0 ? { path: path27 } : {}
7564
+ ...path29 !== void 0 ? { path: path29 } : {}
7133
7565
  }
7134
7566
  ];
7135
7567
  }
@@ -7287,9 +7719,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
7287
7719
  function tokenize(text) {
7288
7720
  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));
7289
7721
  }
7290
- function firstEvidence(fields, run, path27) {
7722
+ function firstEvidence(fields, run, path29) {
7291
7723
  const first = fields[0];
7292
- return first === void 0 ? evidenceForRun(run, path27) : evidenceForEvent(first.node.event, first.path);
7724
+ return first === void 0 ? evidenceForRun(run, path29) : evidenceForEvent(first.node.event, first.path);
7293
7725
  }
7294
7726
  function collectSourceIds(nodes, keys) {
7295
7727
  const wanted = keySet(keys);
@@ -7666,8 +8098,8 @@ function renderEvalMarkdown(result) {
7666
8098
  if (result.findings.length > 0) {
7667
8099
  lines.push("", "## Findings");
7668
8100
  for (const finding of result.findings) {
7669
- const path27 = finding.evidence[0]?.path;
7670
- lines.push(`- ${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}`);
8101
+ const path29 = finding.evidence[0]?.path;
8102
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path29 ? ` (${path29})` : ""}`);
7671
8103
  }
7672
8104
  }
7673
8105
  return `${lines.join("\n")}
@@ -7714,7 +8146,7 @@ function asConfig2(value) {
7714
8146
  }
7715
8147
  async function loadConfig2(configPath) {
7716
8148
  if (configPath === void 0) return {};
7717
- const extension = path16.extname(configPath);
8149
+ const extension = path18.extname(configPath);
7718
8150
  if (TS_CONFIG_EXTENSIONS2.has(extension)) {
7719
8151
  throw new Error(
7720
8152
  "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -7723,7 +8155,7 @@ async function loadConfig2(configPath) {
7723
8155
  if (!CONFIG_EXTENSIONS2.has(extension)) {
7724
8156
  throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
7725
8157
  }
7726
- const absolute = path16.resolve(configPath);
8158
+ const absolute = path18.resolve(configPath);
7727
8159
  if (extension === ".json") {
7728
8160
  const raw = await readFile(absolute, "utf-8");
7729
8161
  return asConfig2(JSON.parse(raw));
@@ -7860,8 +8292,8 @@ function printHuman2(result) {
7860
8292
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
7861
8293
  }
7862
8294
  for (const finding of result.findings) {
7863
- const path27 = finding.evidence[0]?.path;
7864
- console.log(`- ${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}`);
8295
+ const path29 = finding.evidence[0]?.path;
8296
+ console.log(`- ${finding.ruleId}: ${finding.message}${path29 ? ` (${path29})` : ""}`);
7865
8297
  }
7866
8298
  }
7867
8299
  function readErrorResult2(error) {
@@ -8114,14 +8546,14 @@ function exitCodeFor3(result) {
8114
8546
  return 2;
8115
8547
  }
8116
8548
  function explainFinding(finding, blocksBundle) {
8117
- const path27 = finding.evidence[0]?.path ?? "(unknown path)";
8549
+ const path29 = finding.evidence[0]?.path ?? "(unknown path)";
8118
8550
  const category = finding.category ?? "structure";
8119
8551
  const confidence = finding.confidence ?? "medium";
8120
8552
  const detector = finding.detector ?? finding.ruleId;
8121
8553
  const action = finding.action ?? "review";
8122
8554
  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.";
8123
8555
  return [
8124
- ` Matched: detector=${detector}; path=${path27}; category=${category}`,
8556
+ ` Matched: detector=${detector}; path=${path29}; category=${category}`,
8125
8557
  ` Why: ${finding.message}`,
8126
8558
  ` Confidence: ${confidence}`,
8127
8559
  ` Redaction: ${redactionHint}`,
@@ -8163,9 +8595,9 @@ function printHuman3(result, explain = false) {
8163
8595
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
8164
8596
  }
8165
8597
  for (const finding of result.findings) {
8166
- const path27 = finding.evidence[0]?.path;
8598
+ const path29 = finding.evidence[0]?.path;
8167
8599
  const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
8168
- console.log(`- ${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}${taxonomy}`);
8600
+ console.log(`- ${finding.ruleId}: ${finding.message}${path29 ? ` (${path29})` : ""}${taxonomy}`);
8169
8601
  if (explain) {
8170
8602
  const blocks = finding.severity === "error" || finding.status === "fail";
8171
8603
  for (const line of explainFinding(finding, blocks)) {
@@ -8279,91 +8711,6 @@ function messageStartsWithDash(error) {
8279
8711
  const message = error instanceof Error ? error.message : String(error);
8280
8712
  return message.startsWith("--");
8281
8713
  }
8282
- function validateReporterArtifactPath(options) {
8283
- const outputDir = path16.resolve(options.outputDir);
8284
- const diagnostics = [];
8285
- const rawPath = options.relativePath;
8286
- if (rawPath.length === 0) {
8287
- diagnostics.push({
8288
- code: "artifact_path_empty",
8289
- severity: "error",
8290
- message: "Reporter artifact path must not be empty."
8291
- });
8292
- return { ok: false, outputDir, diagnostics };
8293
- }
8294
- if (rawPath.includes("\0")) {
8295
- diagnostics.push({
8296
- code: "invalid_artifact_path",
8297
- severity: "error",
8298
- message: "Reporter artifact path must not contain null bytes.",
8299
- target: rawPath
8300
- });
8301
- return { ok: false, outputDir, diagnostics };
8302
- }
8303
- if (path16.isAbsolute(rawPath) || path16.win32.isAbsolute(rawPath)) {
8304
- diagnostics.push({
8305
- code: "artifact_path_absolute",
8306
- severity: "error",
8307
- message: "Reporter artifact path must be relative.",
8308
- target: rawPath
8309
- });
8310
- return { ok: false, outputDir, diagnostics };
8311
- }
8312
- const normalized = path16.posix.normalize(rawPath.replace(/\\/g, "/"));
8313
- const segments = normalized.split("/");
8314
- if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
8315
- diagnostics.push({
8316
- code: "artifact_path_escape",
8317
- severity: "error",
8318
- message: "Reporter artifact path must stay under the output directory.",
8319
- target: rawPath
8320
- });
8321
- return { ok: false, outputDir, diagnostics };
8322
- }
8323
- const absolutePath = path16.resolve(outputDir, normalized);
8324
- const relFromOutput = path16.relative(outputDir, absolutePath);
8325
- if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path16.isAbsolute(relFromOutput)) {
8326
- diagnostics.push({
8327
- code: "artifact_path_escape",
8328
- severity: "error",
8329
- message: "Reporter artifact path resolved outside the output directory.",
8330
- target: rawPath
8331
- });
8332
- return { ok: false, outputDir, diagnostics };
8333
- }
8334
- return {
8335
- ok: true,
8336
- outputDir,
8337
- relativePath: normalized,
8338
- absolutePath,
8339
- diagnostics
8340
- };
8341
- }
8342
- var EVIDENCE_CI_ARTIFACT_FILES = [
8343
- "evidence.html",
8344
- "evidence.json",
8345
- "check-results.json",
8346
- "trace.jsonl"
8347
- ];
8348
- function createEvidenceCiArtifacts(options) {
8349
- const profile = options.redactionProfile;
8350
- const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
8351
- const join = (name) => prefix === "" ? name : path16.posix.join(prefix, name);
8352
- const formatFor = (name) => {
8353
- if (name.endsWith(".html")) return "html";
8354
- if (name.endsWith(".jsonl")) return "jsonl";
8355
- return "json";
8356
- };
8357
- return EVIDENCE_CI_ARTIFACT_FILES.map((name) => ({
8358
- kind: "evidence",
8359
- path: join(name),
8360
- format: formatFor(name),
8361
- redactionProfile: profile,
8362
- title: `Evidence v2 ${name}`
8363
- }));
8364
- }
8365
-
8366
- // packages/cli/src/artifacts.ts
8367
8714
  var NOTE = "Generated locally by AgentInspect. Artifacts are best-effort summaries, not compliance or security certification.";
8368
8715
  var SAFETY_RULES = [
8369
8716
  createSafetyRawContentRule(),
@@ -8437,8 +8784,8 @@ function renderCheckSection(result) {
8437
8784
  `Diagnostics: ${result.diagnostics.length}`
8438
8785
  ];
8439
8786
  for (const finding of result.findings.slice(0, 10)) {
8440
- const path27 = finding.evidence[0]?.path ?? "(run)";
8441
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path27})`);
8787
+ const path29 = finding.evidence[0]?.path ?? "(run)";
8788
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path29})`);
8442
8789
  }
8443
8790
  for (const diagnostic3 of result.diagnostics.slice(0, 10)) {
8444
8791
  lines.push(`- ${diagnostic3.code}: ${diagnostic3.message}`);
@@ -8516,8 +8863,8 @@ function renderHtml(trace, check, diff) {
8516
8863
  `;
8517
8864
  }
8518
8865
  async function writeArtifact(outputDir, relativePath, content, files) {
8519
- const outPath = path16.join(outputDir, relativePath);
8520
- await mkdir(path16.dirname(outPath), { recursive: true });
8866
+ const outPath = path18.join(outputDir, relativePath);
8867
+ await mkdir(path18.dirname(outPath), { recursive: true });
8521
8868
  await writeFile(outPath, content, "utf-8");
8522
8869
  files.push(relativePath);
8523
8870
  }
@@ -8546,7 +8893,7 @@ function shouldWriteEvidence(options, status) {
8546
8893
  return status === "unsafe" || status === "regression" || status === "unknown" || status === "warning";
8547
8894
  }
8548
8895
  async function artifactsCommand(target, options = {}, stdin = process.stdin) {
8549
- const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path16.resolve(options.outputDir.trim()) : "";
8896
+ const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path18.resolve(options.outputDir.trim()) : "";
8550
8897
  if (outputDir === "") {
8551
8898
  console.error("--output-dir is required.");
8552
8899
  process.exitCode = 1;
@@ -8686,8 +9033,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
8686
9033
  }
8687
9034
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
8688
9035
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
8689
- await mkdir(path16.dirname(path16.resolve(summaryTarget)), { recursive: true });
8690
- await appendFile(path16.resolve(summaryTarget), `
9036
+ await mkdir(path18.dirname(path18.resolve(summaryTarget)), { recursive: true });
9037
+ await appendFile(path18.resolve(summaryTarget), `
8691
9038
  ${renderMarkdown(trace, check, diff)}`, "utf-8");
8692
9039
  }
8693
9040
  const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
@@ -8706,10 +9053,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
8706
9053
  findings: diff?.findings.length ?? 0,
8707
9054
  diagnostics: diff?.diagnostics.length ?? 0
8708
9055
  },
8709
- ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path16.resolve(summaryTarget) } : {},
9056
+ ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path18.resolve(summaryTarget) } : {},
8710
9057
  note: NOTE
8711
9058
  };
8712
- await writeFile(path16.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
9059
+ await writeFile(path18.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
8713
9060
  if (options.json === true) {
8714
9061
  console.log(writeJson3(manifest).trimEnd());
8715
9062
  } else {
@@ -8767,8 +9114,8 @@ async function resolveOutputDir(options, runIds, cwd, format) {
8767
9114
  const location = resolveWorkspaceLocation(cwd);
8768
9115
  const manifest = await readWorkspaceManifestFile(location);
8769
9116
  if (manifest.ok && manifest.manifest) {
8770
- const rel = path16.relative(location.workspaceDir, normalized);
8771
- if (!rel.startsWith("..") && !path16.isAbsolute(rel)) {
9117
+ const rel = path18.relative(location.workspaceDir, normalized);
9118
+ if (!rel.startsWith("..") && !path18.isAbsolute(rel)) {
8772
9119
  return resolveInsideWorkspace(location.workspaceDir, rel);
8773
9120
  }
8774
9121
  }
@@ -8784,7 +9131,7 @@ async function resolveOutputDir(options, runIds, cwd, format) {
8784
9131
  const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
8785
9132
  const base2 = resolveInsideWorkspace(
8786
9133
  location.workspaceDir,
8787
- path16.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
9134
+ path18.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
8788
9135
  );
8789
9136
  return format === "zip" ? `${base2}.zip` : base2;
8790
9137
  }
@@ -9189,19 +9536,19 @@ async function bundleCommand(runIdArg, options = {}) {
9189
9536
  let sidecarDir = outputDir;
9190
9537
  if (outputDir.toLowerCase().endsWith(".html")) {
9191
9538
  htmlPath = outputDir;
9192
- sidecarDir = path16.dirname(outputDir);
9539
+ sidecarDir = path18.dirname(outputDir);
9193
9540
  } else {
9194
9541
  await mkdir(outputDir, { recursive: true });
9195
- htmlPath = path16.join(outputDir, EVIDENCE_HTML_FILENAME);
9542
+ htmlPath = path18.join(outputDir, EVIDENCE_HTML_FILENAME);
9196
9543
  sidecarDir = outputDir;
9197
9544
  }
9198
9545
  await mkdir(sidecarDir, { recursive: true });
9199
9546
  await writeFile(htmlPath, htmlContent, "utf-8");
9200
- await writeFile(path16.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
9547
+ await writeFile(path18.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
9201
9548
  outputPath = htmlPath;
9202
9549
  } else if (format === "zip") {
9203
9550
  const zipPath = outputDir.toLowerCase().endsWith(".zip") ? outputDir : `${outputDir}.zip`;
9204
- const zipParent = path16.dirname(zipPath);
9551
+ const zipParent = path18.dirname(zipPath);
9205
9552
  await mkdir(zipParent, { recursive: true });
9206
9553
  const entries = [
9207
9554
  ...[...packaged.entries()].map(([relativePath, content]) => ({
@@ -9217,10 +9564,10 @@ async function bundleCommand(runIdArg, options = {}) {
9217
9564
  await mkdir(outputDir, { recursive: true });
9218
9565
  for (const [relativePath, content] of packaged.entries()) {
9219
9566
  const outPath = assertBundlePathContained(outputDir, relativePath);
9220
- await mkdir(path16.dirname(outPath), { recursive: true });
9567
+ await mkdir(path18.dirname(outPath), { recursive: true });
9221
9568
  await writeFile(outPath, content, "utf-8");
9222
9569
  }
9223
- await writeFile(path16.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
9570
+ await writeFile(path18.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
9224
9571
  if (!files.includes(EVIDENCE_MANIFEST_FILENAME)) {
9225
9572
  files.push(EVIDENCE_MANIFEST_FILENAME);
9226
9573
  }
@@ -9266,7 +9613,7 @@ function writeJson5(value) {
9266
9613
  `;
9267
9614
  }
9268
9615
  async function bundleVerifyCommand(targetPath, options = {}) {
9269
- const root = path16.resolve(targetPath.trim() || ".");
9616
+ const root = path18.resolve(targetPath.trim() || ".");
9270
9617
  const result = await verifyEvidenceDirectory(root, {
9271
9618
  unexpectedFiles: options.unexpected ?? "fail"
9272
9619
  });
@@ -9299,6 +9646,144 @@ async function bundleVerifyCommand(targetPath, options = {}) {
9299
9646
  process.exitCode = 1;
9300
9647
  }
9301
9648
  }
9649
+ function writeJson6(value) {
9650
+ return `${JSON.stringify(value, null, 2)}
9651
+ `;
9652
+ }
9653
+ async function resolveHtmlPath(root) {
9654
+ const candidates = [
9655
+ path18.join(root, "evidence.html"),
9656
+ root.toLowerCase().endsWith(".html") ? root : ""
9657
+ ].filter(Boolean);
9658
+ for (const candidate of candidates) {
9659
+ try {
9660
+ const info = await stat(candidate);
9661
+ if (info.isFile()) return candidate;
9662
+ } catch {
9663
+ }
9664
+ }
9665
+ throw new Error(
9666
+ `No evidence.html found under ${root}. Pass a bundle directory or .html path.`
9667
+ );
9668
+ }
9669
+ function openLocalFile(filePath) {
9670
+ const fileUrl = pathToFileURL(filePath).href;
9671
+ const platform = process.platform;
9672
+ const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
9673
+ const args = platform === "darwin" ? [filePath] : platform === "win32" ? ["/c", "start", "", filePath] : [filePath];
9674
+ return new Promise((resolve) => {
9675
+ try {
9676
+ const child = spawn(command, args, {
9677
+ detached: true,
9678
+ stdio: "ignore"
9679
+ });
9680
+ child.on("error", (error) => {
9681
+ resolve({
9682
+ ok: false,
9683
+ detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
9684
+ });
9685
+ });
9686
+ child.unref();
9687
+ resolve({ ok: true, detail: fileUrl });
9688
+ } catch (error) {
9689
+ resolve({
9690
+ ok: false,
9691
+ detail: `${error instanceof Error ? error.message : String(error)}; open manually: ${fileUrl}`
9692
+ });
9693
+ }
9694
+ });
9695
+ }
9696
+ async function bundleOpenCommand(targetPath, options = {}) {
9697
+ const root = path18.resolve(targetPath.trim() || ".");
9698
+ try {
9699
+ await access(root);
9700
+ } catch {
9701
+ const message = `Evidence path not found: ${root}`;
9702
+ if (options.json) {
9703
+ console.log(writeJson6({ ok: false, error: message }).trimEnd());
9704
+ } else {
9705
+ console.error(`[AgentInspect] ${message}`);
9706
+ }
9707
+ process.exitCode = 1;
9708
+ return;
9709
+ }
9710
+ let verifyRoot = root;
9711
+ try {
9712
+ const info = await stat(root);
9713
+ if (info.isFile() && root.toLowerCase().endsWith(".html")) {
9714
+ verifyRoot = path18.dirname(root);
9715
+ }
9716
+ } catch {
9717
+ }
9718
+ if (options.skipVerify !== true) {
9719
+ const result = await verifyEvidenceDirectory(verifyRoot, {
9720
+ unexpectedFiles: "fail"
9721
+ });
9722
+ if (!result.ok) {
9723
+ if (options.json) {
9724
+ console.log(
9725
+ writeJson6({
9726
+ ok: false,
9727
+ error: "Evidence verify failed",
9728
+ root: result.root,
9729
+ issues: result.issues
9730
+ }).trimEnd()
9731
+ );
9732
+ } else {
9733
+ console.error(`Evidence verify: fail (${result.issues.length} issue(s))`);
9734
+ for (const issue of result.issues) {
9735
+ console.error(`- [${issue.severity}] ${issue.code}: ${issue.message}`);
9736
+ }
9737
+ console.error("Fix integrity issues or pass --skip-verify (not recommended).");
9738
+ }
9739
+ process.exitCode = 1;
9740
+ return;
9741
+ }
9742
+ }
9743
+ let htmlPath;
9744
+ try {
9745
+ htmlPath = await resolveHtmlPath(
9746
+ root.toLowerCase().endsWith(".html") ? path18.dirname(root) : root
9747
+ );
9748
+ if (root.toLowerCase().endsWith(".html")) {
9749
+ htmlPath = root;
9750
+ }
9751
+ } catch (error) {
9752
+ const message = error instanceof Error ? error.message : String(error);
9753
+ if (options.json) {
9754
+ console.log(writeJson6({ ok: false, error: message }).trimEnd());
9755
+ } else {
9756
+ console.error(`[AgentInspect] ${message}`);
9757
+ }
9758
+ process.exitCode = 1;
9759
+ return;
9760
+ }
9761
+ try {
9762
+ await readFile(path18.join(path18.dirname(htmlPath), "evidence.json"), "utf-8");
9763
+ } catch {
9764
+ }
9765
+ const opened = await openLocalFile(htmlPath);
9766
+ if (options.json) {
9767
+ console.log(
9768
+ writeJson6({
9769
+ ok: opened.ok,
9770
+ path: htmlPath,
9771
+ opened: opened.ok,
9772
+ detail: opened.detail
9773
+ }).trimEnd()
9774
+ );
9775
+ } else if (opened.ok) {
9776
+ console.log(`Opened local Evidence: ${htmlPath}`);
9777
+ console.log(`URL: ${opened.detail}`);
9778
+ } else {
9779
+ console.error(`[AgentInspect] Could not open browser automatically.`);
9780
+ console.error(`Open this file locally: ${htmlPath}`);
9781
+ console.error(opened.detail);
9782
+ }
9783
+ if (!opened.ok) {
9784
+ process.exitCode = 0;
9785
+ }
9786
+ }
9302
9787
  var CLIENTS = [
9303
9788
  "cursor",
9304
9789
  "claude-code",
@@ -9359,24 +9844,24 @@ function resolveTargetPath(client, projectLocal) {
9359
9844
  if (projectLocal) {
9360
9845
  switch (client) {
9361
9846
  case "cursor":
9362
- return path16.join(".cursor", "mcp.json");
9847
+ return path18.join(".cursor", "mcp.json");
9363
9848
  case "claude-code":
9364
- return path16.join(".mcp.json");
9849
+ return path18.join(".mcp.json");
9365
9850
  case "codex":
9366
- return path16.join(".codex", "config.toml.json");
9851
+ return path18.join(".codex", "config.toml.json");
9367
9852
  case "gemini":
9368
- return path16.join(".gemini", "settings.json");
9853
+ return path18.join(".gemini", "settings.json");
9369
9854
  }
9370
9855
  }
9371
9856
  switch (client) {
9372
9857
  case "cursor":
9373
- return path16.join("~", ".cursor", "mcp.json");
9858
+ return path18.join("~", ".cursor", "mcp.json");
9374
9859
  case "claude-code":
9375
- return path16.join("~", ".claude.json");
9860
+ return path18.join("~", ".claude.json");
9376
9861
  case "codex":
9377
- return path16.join("~", ".codex", "config.toml");
9862
+ return path18.join("~", ".codex", "config.toml");
9378
9863
  case "gemini":
9379
- return path16.join("~", ".gemini", "settings.json");
9864
+ return path18.join("~", ".gemini", "settings.json");
9380
9865
  }
9381
9866
  }
9382
9867
  async function mcpConfigureCommand(options) {
@@ -9400,8 +9885,8 @@ async function mcpConfigureCommand(options) {
9400
9885
  ];
9401
9886
  let wrote = false;
9402
9887
  if (!dryRun && projectLocal) {
9403
- const abs = path16.resolve(targetPath);
9404
- await mkdir(path16.dirname(abs), { recursive: true });
9888
+ const abs = path18.resolve(targetPath);
9889
+ await mkdir(path18.dirname(abs), { recursive: true });
9405
9890
  await writeFile(abs, `${JSON.stringify(config, null, 2)}
9406
9891
  `, "utf8");
9407
9892
  wrote = true;
@@ -9449,7 +9934,7 @@ function stable7(value) {
9449
9934
  Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable7(record[key])])
9450
9935
  );
9451
9936
  }
9452
- function writeJson6(value) {
9937
+ function writeJson7(value) {
9453
9938
  return `${JSON.stringify(stable7(value), null, 2)}
9454
9939
  `;
9455
9940
  }
@@ -9561,23 +10046,23 @@ function readManifestDocument(value) {
9561
10046
  };
9562
10047
  }
9563
10048
  function cwdRelative(filePath) {
9564
- const relative = path16.relative(process.cwd(), path16.resolve(filePath)).replace(/\\/g, "/");
9565
- if (relative === "" || relative.startsWith("../") || path16.isAbsolute(relative)) {
9566
- return path16.basename(filePath);
10049
+ const relative = path18.relative(process.cwd(), path18.resolve(filePath)).replace(/\\/g, "/");
10050
+ if (relative === "" || relative.startsWith("../") || path18.isAbsolute(relative)) {
10051
+ return path18.basename(filePath);
9567
10052
  }
9568
10053
  return relative;
9569
10054
  }
9570
10055
  async function readReporterManifest(filePath) {
9571
- const absolute = path16.resolve(filePath);
10056
+ const absolute = path18.resolve(filePath);
9572
10057
  const raw = await readFile(absolute, "utf-8");
9573
10058
  const document = readManifestDocument(JSON.parse(raw));
9574
10059
  const manifest = document.manifest;
9575
10060
  const results = manifest.results.map((result) => ({
9576
10061
  testId: safeText(result.testId),
9577
10062
  name: safeText(result.name),
9578
- ...result.file === void 0 ? {} : { file: safeText(path16.basename(result.file)) },
10063
+ ...result.file === void 0 ? {} : { file: safeText(path18.basename(result.file)) },
9579
10064
  status: result.status,
9580
- ...result.tracePath === void 0 ? {} : { tracePath: safeText(path16.basename(result.tracePath)) },
10065
+ ...result.tracePath === void 0 ? {} : { tracePath: safeText(path18.basename(result.tracePath)) },
9581
10066
  artifacts: result.artifacts,
9582
10067
  diagnostics: result.diagnostics
9583
10068
  }));
@@ -9716,20 +10201,20 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
9716
10201
  return;
9717
10202
  }
9718
10203
  const markdown = renderMarkdown2(result);
9719
- const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path16.resolve(options.output.trim()) : void 0;
10204
+ const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path18.resolve(options.output.trim()) : void 0;
9720
10205
  if (outputPath !== void 0) {
9721
- await mkdir(path16.dirname(outputPath), { recursive: true });
10206
+ await mkdir(path18.dirname(outputPath), { recursive: true });
9722
10207
  await writeFile(outputPath, markdown, "utf-8");
9723
10208
  }
9724
10209
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
9725
10210
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
9726
- const summaryPath = path16.resolve(summaryTarget);
9727
- await mkdir(path16.dirname(summaryPath), { recursive: true });
10211
+ const summaryPath = path18.resolve(summaryTarget);
10212
+ await mkdir(path18.dirname(summaryPath), { recursive: true });
9728
10213
  await appendFile(summaryPath, `
9729
10214
  ${markdown}`, "utf-8");
9730
10215
  }
9731
10216
  if (options.json === true) {
9732
- console.log(writeJson6(result).trimEnd());
10217
+ console.log(writeJson7(result).trimEnd());
9733
10218
  } else if (outputPath !== void 0) {
9734
10219
  console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
9735
10220
  console.log(`Status: ${result.status}`);
@@ -9867,7 +10352,7 @@ console.log("Trace written to .agent-inspect/");
9867
10352
  `;
9868
10353
  }
9869
10354
  }
9870
- function githubWorkflowTemplate() {
10355
+ function githubWorkflowTemplate(demoPath) {
9871
10356
  return `name: AgentInspect artifacts
9872
10357
 
9873
10358
  on:
@@ -9884,19 +10369,32 @@ jobs:
9884
10369
  with:
9885
10370
  node-version: "22"
9886
10371
  - run: npm ci
9887
- - run: npm test
9888
- - name: Upload AgentInspect traces
10372
+ - name: Run deterministic agent fixture
10373
+ run: node ${demoPath}
10374
+ - name: Trajectory check with Evidence on failure
10375
+ run: >
10376
+ npx --yes agent-inspect check --dir .agent-inspect
10377
+ --preset trajectory
10378
+ --evidence-on fail
10379
+ --evidence-profile share
10380
+ --evidence-format directory
10381
+ - name: Verify share safety
10382
+ if: always()
10383
+ run: npx --yes agent-inspect verify-safe . --dir .agent-inspect
10384
+ - name: Upload AgentInspect traces and Evidence
9889
10385
  if: always()
9890
10386
  uses: actions/upload-artifact@v4
9891
10387
  with:
9892
10388
  name: agent-inspect-traces
9893
- path: .agent-inspect/**/*.jsonl
10389
+ path: |
10390
+ .agent-inspect/**/*.jsonl
10391
+ .agent-inspect/evidence/**
9894
10392
  if-no-files-found: ignore
9895
10393
  `;
9896
10394
  }
9897
10395
  async function planInit(options = {}) {
9898
10396
  const framework = normalizeFramework(options.framework);
9899
- const cwd = path16.resolve(options.cwd ?? process.cwd());
10397
+ const cwd = path18.resolve(options.cwd ?? process.cwd());
9900
10398
  const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
9901
10399
  const candidates = [
9902
10400
  { rel: CONFIG_FILE, content: configTemplate(framework) },
@@ -9906,12 +10404,12 @@ async function planInit(options = {}) {
9906
10404
  if (options.ci === "github") {
9907
10405
  candidates.push({
9908
10406
  rel: ".github/workflows/agent-inspect-artifacts.yml",
9909
- content: githubWorkflowTemplate()
10407
+ content: githubWorkflowTemplate(demoPath)
9910
10408
  });
9911
10409
  }
9912
10410
  const files = [];
9913
10411
  for (const candidate of candidates) {
9914
- const abs = path16.join(cwd, candidate.rel);
10412
+ const abs = path18.join(cwd, candidate.rel);
9915
10413
  try {
9916
10414
  await access(abs);
9917
10415
  files.push({
@@ -9932,20 +10430,21 @@ async function writePlannedFiles(plan, cwd, options) {
9932
10430
  if (entry.action === "skip") {
9933
10431
  continue;
9934
10432
  }
9935
- const abs = path16.join(cwd, entry.path);
10433
+ const abs = path18.join(cwd, entry.path);
9936
10434
  if (options.dryRun) {
9937
10435
  written.push(entry.path);
9938
10436
  continue;
9939
10437
  }
9940
- await mkdir(path16.dirname(abs), { recursive: true });
9941
- const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
10438
+ await mkdir(path18.dirname(abs), { recursive: true });
10439
+ const demoPath = plan.framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${plan.framework}-demo.mjs`;
10440
+ const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate(demoPath) : demoTemplate(plan.framework);
9942
10441
  await writeFile(abs, content, "utf-8");
9943
10442
  written.push(entry.path);
9944
10443
  }
9945
10444
  return written;
9946
10445
  }
9947
10446
  async function initCommand(options = {}) {
9948
- const cwd = path16.resolve(options.cwd ?? process.cwd());
10447
+ const cwd = path18.resolve(options.cwd ?? process.cwd());
9949
10448
  try {
9950
10449
  const plan = await planInit({ ...options, cwd });
9951
10450
  const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
@@ -10037,7 +10536,7 @@ function envCheck(name, optional = true) {
10037
10536
  };
10038
10537
  }
10039
10538
  async function traceDirWritable(traceDir) {
10040
- const resolved = path16.resolve(traceDir);
10539
+ const resolved = path18.resolve(traceDir);
10041
10540
  try {
10042
10541
  await mkdir(resolved, { recursive: true });
10043
10542
  await access(resolved, constants.W_OK);
@@ -10058,10 +10557,10 @@ async function traceDirWritable(traceDir) {
10058
10557
  }
10059
10558
  }
10060
10559
  function readPackageVersionNearEntry(entryPath, packageName) {
10061
- let dir = path16.dirname(path16.resolve(entryPath));
10062
- const { root } = path16.parse(dir);
10560
+ let dir = path18.dirname(path18.resolve(entryPath));
10561
+ const { root } = path18.parse(dir);
10063
10562
  while (true) {
10064
- const candidate = path16.join(dir, "package.json");
10563
+ const candidate = path18.join(dir, "package.json");
10065
10564
  if (existsSync(candidate)) {
10066
10565
  try {
10067
10566
  const pkg = JSON.parse(readFileSync(candidate, "utf8"));
@@ -10072,14 +10571,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
10072
10571
  }
10073
10572
  }
10074
10573
  if (dir === root) break;
10075
- const parent = path16.dirname(dir);
10574
+ const parent = path18.dirname(dir);
10076
10575
  if (parent === dir) break;
10077
10576
  dir = parent;
10078
10577
  }
10079
10578
  return void 0;
10080
10579
  }
10081
10580
  function resolveInstalledPackage(cwd, name) {
10082
- const require2 = createRequire(path16.join(cwd, "package.json"));
10581
+ const require2 = createRequire(path18.join(cwd, "package.json"));
10083
10582
  try {
10084
10583
  const entry = require2.resolve(name);
10085
10584
  let version2;
@@ -10177,7 +10676,7 @@ function versionMismatchCheck(cwd) {
10177
10676
  };
10178
10677
  }
10179
10678
  async function runDoctorChecks(options = {}) {
10180
- const cwd = path16.resolve(options.cwd ?? process2.cwd());
10679
+ const cwd = path18.resolve(options.cwd ?? process2.cwd());
10181
10680
  const traceDir = options.traceDir?.trim() || process2.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
10182
10681
  const checks2 = [
10183
10682
  nodeVersionCheck(),
@@ -10417,7 +10916,7 @@ function parsePluginManifest(input3) {
10417
10916
  };
10418
10917
  }
10419
10918
  async function readPluginManifestFile(packageDir) {
10420
- const manifestPath = path16.join(packageDir, PLUGIN_MANIFEST_FILENAME);
10919
+ const manifestPath = path18.join(packageDir, PLUGIN_MANIFEST_FILENAME);
10421
10920
  try {
10422
10921
  const raw = await readFile(manifestPath, "utf8");
10423
10922
  const parsed = parsePluginManifest(JSON.parse(raw));
@@ -10491,7 +10990,7 @@ function createTraceDirectoryIndexer() {
10491
10990
  // packages/cli/src/plugins.ts
10492
10991
  async function readPackageName(packageDir) {
10493
10992
  try {
10494
- const raw = await readFile(path16.join(packageDir, "package.json"), "utf8");
10993
+ const raw = await readFile(path18.join(packageDir, "package.json"), "utf8");
10495
10994
  const parsed = JSON.parse(raw);
10496
10995
  return typeof parsed.name === "string" ? parsed.name : void 0;
10497
10996
  } catch {
@@ -10499,7 +10998,7 @@ async function readPackageName(packageDir) {
10499
10998
  }
10500
10999
  }
10501
11000
  async function discoverPlugins(cwd = process.cwd()) {
10502
- const nodeModules = path16.join(cwd, "node_modules");
11001
+ const nodeModules = path18.join(cwd, "node_modules");
10503
11002
  const found = [];
10504
11003
  let entries;
10505
11004
  try {
@@ -10510,7 +11009,7 @@ async function discoverPlugins(cwd = process.cwd()) {
10510
11009
  for (const entry of entries.sort()) {
10511
11010
  if (entry.startsWith("@")) continue;
10512
11011
  if (!isPluginPackageName(entry)) continue;
10513
- const packageDir = path16.join(nodeModules, entry);
11012
+ const packageDir = path18.join(nodeModules, entry);
10514
11013
  const manifestRead = await readPluginManifestFile(packageDir);
10515
11014
  found.push({
10516
11015
  packageName: entry,
@@ -10523,7 +11022,7 @@ async function discoverPlugins(cwd = process.cwd()) {
10523
11022
  return found;
10524
11023
  }
10525
11024
  async function validatePluginPackage(packageRef, cwd = process.cwd()) {
10526
- const packageDir = path16.isAbsolute(packageRef) ? packageRef : path16.join(cwd, "node_modules", packageRef);
11025
+ const packageDir = path18.isAbsolute(packageRef) ? packageRef : path18.join(cwd, "node_modules", packageRef);
10527
11026
  const packageName = await readPackageName(packageDir) ?? packageRef;
10528
11027
  const errors = [];
10529
11028
  const warnings = [];
@@ -10599,7 +11098,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
10599
11098
  }
10600
11099
  var INDEX_FILENAME = ".agent-inspect-index.json";
10601
11100
  function traceIndexPath(traceDir) {
10602
- return path16.join(traceDir, INDEX_FILENAME);
11101
+ return path18.join(traceDir, INDEX_FILENAME);
10603
11102
  }
10604
11103
  function parseMaxEntries(raw) {
10605
11104
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -10742,7 +11241,7 @@ async function newestTraceMtimeMs2(traceDir) {
10742
11241
  for (const file of files) {
10743
11242
  if (!file.endsWith(".jsonl")) continue;
10744
11243
  try {
10745
- const s = await stat(path16.join(traceDir, file));
11244
+ const s = await stat(path18.join(traceDir, file));
10746
11245
  if (s.mtimeMs > newest) newest = s.mtimeMs;
10747
11246
  } catch {
10748
11247
  }
@@ -10994,11 +11493,11 @@ function printJson5(value) {
10994
11493
  console.log(JSON.stringify(value, null, 2));
10995
11494
  }
10996
11495
  function resolveCwd(options) {
10997
- return path16.resolve(options.cwd ?? process.cwd());
11496
+ return path18.resolve(options.cwd ?? process.cwd());
10998
11497
  }
10999
11498
  async function suiteInitCommand(options = {}) {
11000
11499
  const cwd = resolveCwd(options);
11001
- const configPath = path16.join(cwd, DEFAULT_CONFIG_FILENAME);
11500
+ const configPath = path18.join(cwd, DEFAULT_CONFIG_FILENAME);
11002
11501
  const template = options.template?.trim();
11003
11502
  const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
11004
11503
  if (options.dryRun) {
@@ -11117,13 +11616,13 @@ async function suiteListCommand(options = {}) {
11117
11616
  }
11118
11617
  async function writeSuiteArtifact(result, configOutputDir, options) {
11119
11618
  const cwd = resolveCwd(options);
11120
- const outputDir = path16.resolve(
11619
+ const outputDir = path18.resolve(
11121
11620
  cwd,
11122
11621
  options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
11123
11622
  );
11124
11623
  await mkdir(outputDir, { recursive: true });
11125
11624
  const stamp = result.startedAt.replace(/[:.]/g, "-");
11126
- const filePath = path16.join(outputDir, `${result.suiteName}-${stamp}.json`);
11625
+ const filePath = path18.join(outputDir, `${result.suiteName}-${stamp}.json`);
11127
11626
  await writeFile(filePath, `${JSON.stringify(result, null, 2)}
11128
11627
  `, "utf-8");
11129
11628
  return filePath;
@@ -11181,7 +11680,7 @@ async function loadSuiteResultFromInput(options) {
11181
11680
  if (options.input === void 0 || options.input.trim() === "") {
11182
11681
  throw new Error("Pass --input <suite-run.json> from a prior suite run.");
11183
11682
  }
11184
- const inputPath = path16.resolve(cwd, options.input.trim());
11683
+ const inputPath = path18.resolve(cwd, options.input.trim());
11185
11684
  const raw = await readFile(inputPath, "utf-8");
11186
11685
  return JSON.parse(raw);
11187
11686
  }
@@ -11215,9 +11714,9 @@ function normalizeMetrics(raw) {
11215
11714
  }
11216
11715
  async function writeArtifacts(result, outputDir) {
11217
11716
  await mkdir(outputDir, { recursive: true });
11218
- const jsonPath = path16.join(outputDir, "cohort-results.json");
11219
- const markdownPath = path16.join(outputDir, "cohort-summary.md");
11220
- const htmlPath = path16.join(outputDir, "cohort-report.html");
11717
+ const jsonPath = path18.join(outputDir, "cohort-results.json");
11718
+ const markdownPath = path18.join(outputDir, "cohort-summary.md");
11719
+ const htmlPath = path18.join(outputDir, "cohort-report.html");
11221
11720
  await writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
11222
11721
  `, "utf-8");
11223
11722
  await writeFile(
@@ -11245,7 +11744,7 @@ async function cohortCommand(options = {}) {
11245
11744
  const format = options.format ?? (options.json ? "json" : "markdown");
11246
11745
  let artifacts;
11247
11746
  if (options.output !== void 0 && options.output.trim() !== "") {
11248
- artifacts = await writeArtifacts(result, path16.resolve(options.output.trim()));
11747
+ artifacts = await writeArtifacts(result, path18.resolve(options.output.trim()));
11249
11748
  }
11250
11749
  if (options.json || format === "json") {
11251
11750
  console.log(
@@ -11315,11 +11814,11 @@ function parseDuration2(value) {
11315
11814
  async function writeArtifacts2(result, outputDir) {
11316
11815
  await mkdir(outputDir, { recursive: true });
11317
11816
  const paths = {
11318
- jsonPath: path16.join(outputDir, "gate-results.json"),
11319
- markdownPath: path16.join(outputDir, "gate-summary.md"),
11320
- htmlPath: path16.join(outputDir, "gate-report.html"),
11321
- junitPath: path16.join(outputDir, "junit.xml"),
11322
- githubPath: path16.join(outputDir, "github-step-summary.md")
11817
+ jsonPath: path18.join(outputDir, "gate-results.json"),
11818
+ markdownPath: path18.join(outputDir, "gate-summary.md"),
11819
+ htmlPath: path18.join(outputDir, "gate-report.html"),
11820
+ junitPath: path18.join(outputDir, "junit.xml"),
11821
+ githubPath: path18.join(outputDir, "github-step-summary.md")
11323
11822
  };
11324
11823
  await writeFile(
11325
11824
  paths.jsonPath,
@@ -11387,7 +11886,57 @@ async function gateCommand(options = {}) {
11387
11886
  const result = await runGate(runs, gateOptions);
11388
11887
  let artifacts;
11389
11888
  if (options.output !== void 0 && options.output.trim() !== "") {
11390
- artifacts = await writeArtifacts2(result, path16.resolve(options.output.trim()));
11889
+ artifacts = await writeArtifacts2(result, path18.resolve(options.output.trim()));
11890
+ }
11891
+ const failed = !result.ok;
11892
+ if (shouldEmitEvidence(options.evidenceOn, failed)) {
11893
+ try {
11894
+ const runIds = runs.length > 0 ? runs.map((run) => run.runId) : result.suiteResult?.cases.map((item) => item.runId).filter((id) => typeof id === "string" && id.length > 0) ?? ["gate"];
11895
+ const sourceContents = /* @__PURE__ */ new Map();
11896
+ for (const run of runs) {
11897
+ if (run.filePath) {
11898
+ try {
11899
+ sourceContents.set(run.runId, await readFile(run.filePath, "utf-8"));
11900
+ } catch {
11901
+ sourceContents.set(run.runId, "");
11902
+ }
11903
+ }
11904
+ }
11905
+ const label = runIds[0] ?? "gate";
11906
+ const outputDir = resolveEvidenceOutputDir(
11907
+ options.evidenceDir,
11908
+ `gate-${label}`
11909
+ );
11910
+ const written = await writeLocalEvidence({
11911
+ outputDir,
11912
+ runIds: runIds.length > 0 ? runIds : ["gate"],
11913
+ sourceContents,
11914
+ ...gateOptions.traceDir !== void 0 ? { dir: gateOptions.traceDir } : {},
11915
+ failed,
11916
+ checkResultsJson: `${JSON.stringify(
11917
+ {
11918
+ aggregateStatus: failed ? "UNSAFE" : "SAFE",
11919
+ gate: result
11920
+ },
11921
+ null,
11922
+ 2
11923
+ )}
11924
+ `,
11925
+ summaryText: renderGateReport(result, { format: "markdown" }),
11926
+ redactionProfile: parseEvidenceProfile(options.evidenceProfile),
11927
+ format: parseEvidenceFormat(options.evidenceFormat)
11928
+ });
11929
+ if (!options.json && format !== "json") {
11930
+ console.log(`Evidence: ${written}`);
11931
+ }
11932
+ if (artifacts !== void 0) {
11933
+ artifacts = { ...artifacts, evidence: written };
11934
+ }
11935
+ } catch (error) {
11936
+ console.error(
11937
+ `[AgentInspect] evidence package skipped: ${error instanceof Error ? error.message : String(error)}`
11938
+ );
11939
+ }
11391
11940
  }
11392
11941
  if (options.json || format === "json") {
11393
11942
  console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
@@ -11564,6 +12113,23 @@ function createCliProgram() {
11564
12113
  "--circuit <rule>",
11565
12114
  "run optional circuit rules (repeatable): same-tool-repetition, max-retries, ...",
11566
12115
  (value, previous = []) => [...previous, value]
12116
+ ).addOption(
12117
+ new Option("--preset <name>", "additive check preset").choices(["trajectory", "safety", "comprehensive"])
12118
+ ).addOption(
12119
+ new Option(
12120
+ "--evidence-on <mode>",
12121
+ "write local Evidence v2 (fail=on failure, always, never; no upload)"
12122
+ ).choices(["fail", "always", "never"])
12123
+ ).option("--evidence-dir <path>", "local Evidence output directory or base path").addOption(
12124
+ new Option(
12125
+ "--evidence-profile <profile>",
12126
+ "Evidence redaction profile (default share)"
12127
+ ).choices(["local", "share", "strict"])
12128
+ ).addOption(
12129
+ new Option(
12130
+ "--evidence-format <format>",
12131
+ "Evidence output format (default directory)"
12132
+ ).choices(["directory", "html", "zip"])
11567
12133
  ).action((target, opts) => {
11568
12134
  runCommand(() => checkCommand(target, opts));
11569
12135
  });
@@ -11662,6 +12228,9 @@ function createCliProgram() {
11662
12228
  ).option("--json", "print deterministic JSON verify result").action((targetPath, opts) => {
11663
12229
  runCommand(() => bundleVerifyCommand(targetPath, opts));
11664
12230
  });
12231
+ bundleCmd.command("open").description("Verify then open local Evidence HTML in the platform browser (no network)").argument("<path>", "evidence/bundle directory or evidence.html path").option("--skip-verify", "skip integrity verify before open (not recommended)").option("--json", "print deterministic JSON open result").action((targetPath, opts) => {
12232
+ runCommand(() => bundleOpenCommand(targetPath, opts));
12233
+ });
11665
12234
  program.command("ci-summary").description("Summarize local reporter artifact manifests for CI").argument("<manifest...>", "reporter artifact manifest JSON files").option("-o, --output <path>", "write Markdown summary to a local file").option("--github-summary <path>", "append Markdown summary to this local file, e.g. GITHUB_STEP_SUMMARY").option("--json", "print deterministic JSON summary").action((manifest, opts) => {
11666
12235
  runCommand(() => ciSummaryCommand(manifest, opts));
11667
12236
  });
@@ -11941,7 +12510,22 @@ function createCliProgram() {
11941
12510
  ).option("--format <format>", "markdown, json, html, junit, or github", "markdown").option(
11942
12511
  "-o, --output <dir>",
11943
12512
  "write gate-results.json, gate-summary.md, gate-report.html, junit.xml, github-step-summary.md"
11944
- ).option("--json", "print deterministic JSON result").action((opts) => {
12513
+ ).option("--json", "print deterministic JSON result").addOption(
12514
+ new Option(
12515
+ "--evidence-on <mode>",
12516
+ "write local Evidence v2 (fail=on failure, always, never; no upload)"
12517
+ ).choices(["fail", "always", "never"])
12518
+ ).option("--evidence-dir <path>", "local Evidence output directory or base path").addOption(
12519
+ new Option(
12520
+ "--evidence-profile <profile>",
12521
+ "Evidence redaction profile (default share)"
12522
+ ).choices(["local", "share", "strict"])
12523
+ ).addOption(
12524
+ new Option(
12525
+ "--evidence-format <format>",
12526
+ "Evidence output format (default directory)"
12527
+ ).choices(["directory", "html", "zip"])
12528
+ ).action((opts) => {
11945
12529
  runCommand(() => gateCommand(opts));
11946
12530
  });
11947
12531
  return program;
@@ -11951,9 +12535,9 @@ function isPrimaryModule() {
11951
12535
  if (!entry) return false;
11952
12536
  const selfPath = fileURLToPath(import.meta.url);
11953
12537
  try {
11954
- return realpathSync(path16.resolve(entry)) === realpathSync(path16.resolve(selfPath));
12538
+ return realpathSync(path18.resolve(entry)) === realpathSync(path18.resolve(selfPath));
11955
12539
  } catch {
11956
- return path16.resolve(entry) === path16.resolve(selfPath);
12540
+ return path18.resolve(entry) === path18.resolve(selfPath);
11957
12541
  }
11958
12542
  }
11959
12543
  if (isPrimaryModule()) {