agent-inspect 6.9.0 → 6.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/docs/BUNDLES.md +31 -9
  4. package/docs/CI-ARTIFACTS.md +10 -1
  5. package/docs/CLI.md +11 -2
  6. package/package.json +1 -1
  7. package/packages/cli/dist/{chunk-WQ5XMFH2.mjs → chunk-36IJ76LH.mjs} +1756 -149
  8. package/packages/cli/dist/chunk-36IJ76LH.mjs.map +1 -0
  9. package/packages/cli/dist/index.cjs +10370 -8774
  10. package/packages/cli/dist/index.cjs.map +1 -1
  11. package/packages/cli/dist/index.mjs +584 -712
  12. package/packages/cli/dist/index.mjs.map +1 -1
  13. package/packages/cli/dist/{src-C4EUHTER.mjs → src-YFN3Q3GP.mjs} +3 -3
  14. package/packages/cli/dist/{src-C4EUHTER.mjs.map → src-YFN3Q3GP.mjs.map} +1 -1
  15. package/packages/core/dist/advanced.cjs +1703 -12
  16. package/packages/core/dist/advanced.cjs.map +1 -1
  17. package/packages/core/dist/advanced.d.cts +334 -3
  18. package/packages/core/dist/advanced.d.ts +334 -3
  19. package/packages/core/dist/advanced.mjs +1163 -10
  20. package/packages/core/dist/advanced.mjs.map +1 -1
  21. package/packages/core/dist/chunk-F7STQ5JF.mjs +479 -0
  22. package/packages/core/dist/chunk-F7STQ5JF.mjs.map +1 -0
  23. package/packages/core/dist/diff.mjs +3 -477
  24. package/packages/core/dist/diff.mjs.map +1 -1
  25. package/packages/core/dist/reporters.cjs +25 -0
  26. package/packages/core/dist/reporters.cjs.map +1 -1
  27. package/packages/core/dist/reporters.d.cts +16 -2
  28. package/packages/core/dist/reporters.d.ts +16 -2
  29. package/packages/core/dist/reporters.mjs +24 -1
  30. package/packages/core/dist/reporters.mjs.map +1 -1
  31. package/packages/cli/dist/chunk-WQ5XMFH2.mjs.map +0 -1
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createSafetyOversizedAttributeRule, resolveTraceDir, parseDuration, buildSessionIndex, enrichSessionRunRecord, TraceDirectory, loadTraceMetadataList, loadSessionRunRecords, extractMetadata, filterTraces, truncateName, getTraceFilePath, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, openTrace, TraceReadError, filterMetasBySessionScope, runTraceChecks, aggregateSessionCheckResults, createBaselineRegressionRule, resolveBundleRunIds, aggregateBundleSafeStatus, bundleFailsOnSafety, bundleRunAssetRelativePath, buildPlaceholderArtifact, buildBundleMetadata, buildBundleSummaryMarkdown, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, buildActivitySummary, renderActivitySummaryHuman, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, resolveSuiteTemplate, defaultSuiteConfigTemplate, loadSuiteConfig, validateSuiteConfig, runSuite, renderSuiteReport, analyzeCohort, renderCohortReport, gateHasThresholds, runGate, renderGateReport, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, Redactor, TreeBuilder, zeroKinds, validateEvent, traceEventToPersistedInspectEvent, isPersistedInspectEvent, createRunStatusRule, createStructureOrphanRule, createStructureCycleRule, createRunDurationRule, createMaxStepDurationRule, createRequireCompletedRule, createStallDetectionRule, createObservedOutcomeRule, createRunDepthRule, createToolUsageRule, createLlmUsageRule, createStructureRelationshipRule, createStructureParallelWidthRule, normalizeBundleOutputPath, sanitizeBundleRunId, defaultBundleOutputPath, assertBundlePathContained, summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml, escapeMarkdown, escapeHtml, DEFAULT_SUITE_ARTIFACTS_DIR, parseCohortMetricList, COHORT_METRIC_IDS, parseGateList, nanoid, resolveRedactionProfile, applyProfileMetadataCaps, flattenTree, safeString, compactAttributes, stableJson, truncateStringForProfile } from './chunk-WQ5XMFH2.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, buildEvidenceCiPackage, verifyEvidenceDirectory, diffTraceEvents, renderRunDiff, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, 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-36IJ76LH.mjs';
3
3
  import { realpathSync, constants as constants$1, existsSync, readFileSync } from 'fs';
4
- import path14 from 'path';
4
+ import path15 from 'path';
5
5
  import { fileURLToPath, pathToFileURL } from 'url';
6
6
  import { Command, Option } from 'commander';
7
- import { unlink, stat, mkdir, writeFile, appendFile, readFile, rm, access, open, readdir, constants } from 'fs/promises';
7
+ import { readFile, stat, mkdir, writeFile, unlink, appendFile, rm, access, 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
11
  import { createRequire } from 'module';
12
12
 
13
13
  // package.json
14
- var version = "6.9.0";
14
+ var version = "6.10.0";
15
15
 
16
16
  // packages/cli/src/trace-dir-scale.ts
17
17
  var TRACE_COUNT_WARN = 1e3;
@@ -2971,9 +2971,9 @@ Trace directory: ${traceDir}`);
2971
2971
  process.exitCode = 1;
2972
2972
  }
2973
2973
  const resolvedOutput = resolveOutputOption(options);
2974
- const outPath = resolvedOutput !== void 0 ? path14.resolve(resolvedOutput) : void 0;
2974
+ const outPath = resolvedOutput !== void 0 ? path15.resolve(resolvedOutput) : void 0;
2975
2975
  if (outPath !== void 0) {
2976
- await mkdir(path14.dirname(outPath), { recursive: true });
2976
+ await mkdir(path15.dirname(outPath), { recursive: true });
2977
2977
  await writeFile(outPath, result.content, "utf-8");
2978
2978
  const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
2979
2979
  console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
@@ -3011,471 +3011,6 @@ Trace directory: ${traceDir}`);
3011
3011
  }
3012
3012
  }
3013
3013
 
3014
- // packages/core/src/diff/comparable.ts
3015
- function extractOutputPreview(meta) {
3016
- if (meta === void 0) return void 0;
3017
- if ("outputPreview" in meta) return meta.outputPreview;
3018
- if ("resultPreview" in meta) return meta.resultPreview;
3019
- return void 0;
3020
- }
3021
- function mapStepStatus2(s) {
3022
- if (s === void 0) return "running";
3023
- return s;
3024
- }
3025
- function manualTraceEventsToComparableRun(events) {
3026
- const started = events.find((e) => e.event === "run_started");
3027
- if (!started || started.event !== "run_started") {
3028
- throw new Error("Invalid trace: missing run_started");
3029
- }
3030
- const rs = started;
3031
- const runId = rs.runId;
3032
- const completedAll = events.filter((e) => e.event === "run_completed");
3033
- const lastCompleted = completedAll[completedAll.length - 1];
3034
- let runStatus;
3035
- if (lastCompleted === void 0) runStatus = "running";
3036
- else runStatus = lastCompleted.status;
3037
- const durationMs2 = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
3038
- const steps = /* @__PURE__ */ new Map();
3039
- let order = 0;
3040
- for (const e of events) {
3041
- if (e.event !== "step_started") continue;
3042
- const s = e;
3043
- const meta = s.metadata ? { ...s.metadata } : void 0;
3044
- steps.set(s.stepId, {
3045
- id: s.stepId,
3046
- parentId: s.parentId,
3047
- name: s.name,
3048
- type: s.type,
3049
- order: order++,
3050
- timestamp: s.timestamp,
3051
- metadata: meta
3052
- });
3053
- }
3054
- for (const e of events) {
3055
- if (e.event !== "step_completed") continue;
3056
- const acc = steps.get(e.stepId);
3057
- if (!acc) continue;
3058
- acc.status = e.status;
3059
- acc.durationMs = e.durationMs;
3060
- if (e.error?.message) acc.errorMsg = e.error.message;
3061
- const extra = e;
3062
- if (extra.metadata !== void 0 && typeof extra.metadata === "object") {
3063
- acc.metadata = { ...acc.metadata ?? {}, ...extra.metadata };
3064
- }
3065
- }
3066
- const nodes = /* @__PURE__ */ new Map();
3067
- for (const acc of steps.values()) {
3068
- let meta = acc.metadata ? { ...acc.metadata } : void 0;
3069
- if (acc.parentId !== void 0 && !steps.has(acc.parentId)) {
3070
- meta = { ...meta ?? {}, agent_inspect_diff_parent_missing: true };
3071
- }
3072
- const outputPreview = extractOutputPreview(meta);
3073
- if (meta !== void 0 && ("outputPreview" in meta || "resultPreview" in meta)) {
3074
- delete meta.outputPreview;
3075
- delete meta.resultPreview;
3076
- }
3077
- const sc = {
3078
- id: acc.id,
3079
- name: acc.name,
3080
- type: acc.type,
3081
- status: mapStepStatus2(acc.status),
3082
- durationMs: acc.durationMs,
3083
- error: acc.errorMsg,
3084
- metadata: meta && Object.keys(meta).length > 0 ? meta : void 0,
3085
- outputPreview,
3086
- children: []
3087
- };
3088
- nodes.set(acc.id, sc);
3089
- }
3090
- const roots = [];
3091
- const sortByOrder = (a, b) => {
3092
- const oa = steps.get(a.id)?.order ?? 0;
3093
- const ob = steps.get(b.id)?.order ?? 0;
3094
- return oa - ob;
3095
- };
3096
- for (const acc of steps.values()) {
3097
- const node = nodes.get(acc.id);
3098
- if (acc.parentId !== void 0 && nodes.has(acc.parentId)) {
3099
- nodes.get(acc.parentId).children.push(node);
3100
- } else {
3101
- roots.push(node);
3102
- }
3103
- }
3104
- roots.sort(sortByOrder);
3105
- for (const n of nodes.values()) {
3106
- n.children.sort(sortByOrder);
3107
- }
3108
- return {
3109
- runId,
3110
- name: rs.name,
3111
- status: runStatus,
3112
- durationMs: durationMs2,
3113
- steps: roots
3114
- };
3115
- }
3116
-
3117
- // packages/core/src/diff/engine.ts
3118
- var DEFAULT_THRESHOLD_MS = 0;
3119
- function pathSeg(step, index) {
3120
- return { index, name: step.name, stepId: step.id };
3121
- }
3122
- function buildPath(segments) {
3123
- return { path: [...segments] };
3124
- }
3125
- function pairSteps(left, right) {
3126
- const usedRight = /* @__PURE__ */ new Set();
3127
- const pairs = [];
3128
- for (let i = 0; i < left.length; i++) {
3129
- const L = left[i];
3130
- let R = right.find((r) => !usedRight.has(r.id) && r.id === L.id);
3131
- if (R === void 0 && i < right.length && !usedRight.has(right[i].id)) {
3132
- const cand = right[i];
3133
- if (cand.name === L.name && (cand.type ?? "") === (L.type ?? "")) {
3134
- R = cand;
3135
- }
3136
- }
3137
- if (R === void 0) {
3138
- R = right.find(
3139
- (r) => !usedRight.has(r.id) && r.name === L.name && (r.type ?? "") === (L.type ?? "")
3140
- );
3141
- }
3142
- if (R !== void 0) {
3143
- usedRight.add(R.id);
3144
- pairs.push([L, R]);
3145
- } else {
3146
- pairs.push([L, void 0]);
3147
- }
3148
- }
3149
- for (const R of right) {
3150
- if (!usedRight.has(R.id)) {
3151
- pairs.push([void 0, R]);
3152
- }
3153
- }
3154
- return pairs;
3155
- }
3156
- function compareLeafSteps(L, R, segments, opts, out) {
3157
- const path25 = buildPath(segments);
3158
- if (L.name !== R.name) {
3159
- out.push({
3160
- kind: "structure",
3161
- severity: "warning",
3162
- message: "Step name differs",
3163
- path: path25,
3164
- left: L.name,
3165
- right: R.name
3166
- });
3167
- }
3168
- if ((L.type ?? "") !== (R.type ?? "")) {
3169
- out.push({
3170
- kind: "step-type",
3171
- severity: "warning",
3172
- message: "Step type differs",
3173
- path: path25,
3174
- left: L.type,
3175
- right: R.type
3176
- });
3177
- }
3178
- if ((L.status ?? "") !== (R.status ?? "")) {
3179
- out.push({
3180
- kind: "step-status",
3181
- severity: "warning",
3182
- message: "Step status differs",
3183
- path: path25,
3184
- left: L.status,
3185
- right: R.status
3186
- });
3187
- }
3188
- const le = L.error ?? "";
3189
- const re = R.error ?? "";
3190
- if (le !== re) {
3191
- out.push({
3192
- kind: "error",
3193
- severity: "error",
3194
- message: "Step error message differs",
3195
- path: path25,
3196
- left: le || void 0,
3197
- right: re || void 0
3198
- });
3199
- }
3200
- if (!opts.ignoreDuration) {
3201
- const ld = L.durationMs;
3202
- const rd = R.durationMs;
3203
- const th = opts.durationThresholdMs;
3204
- let differs = false;
3205
- if (ld === void 0 && rd === void 0) differs = false;
3206
- else if (ld === void 0 || rd === void 0) differs = true;
3207
- else differs = Math.abs(ld - rd) > th;
3208
- if (differs) {
3209
- out.push({
3210
- kind: "duration",
3211
- severity: "info",
3212
- message: "Step duration differs",
3213
- path: path25,
3214
- left: ld,
3215
- right: rd
3216
- });
3217
- }
3218
- }
3219
- const lm = stableJson(L.metadata ?? {});
3220
- const rm3 = stableJson(R.metadata ?? {});
3221
- if (lm !== rm3) {
3222
- out.push({
3223
- kind: "metadata",
3224
- severity: "info",
3225
- message: "Step metadata differs",
3226
- path: path25,
3227
- left: L.metadata,
3228
- right: R.metadata
3229
- });
3230
- }
3231
- const lo = stableJson(L.outputPreview ?? null);
3232
- const ro = stableJson(R.outputPreview ?? null);
3233
- if (lo !== ro) {
3234
- out.push({
3235
- kind: "output",
3236
- severity: "info",
3237
- message: "Output preview differs",
3238
- path: path25,
3239
- left: L.outputPreview,
3240
- right: R.outputPreview
3241
- });
3242
- }
3243
- }
3244
- function compareRecursive(L, R, segments, opts, out) {
3245
- compareLeafSteps(L, R, segments, opts, out);
3246
- const pairs = pairSteps(L.children, R.children);
3247
- let ci = 0;
3248
- for (const [lch, rch] of pairs) {
3249
- if (lch !== void 0 && rch !== void 0) {
3250
- compareRecursive(lch, rch, [...segments, pathSeg(lch, ci)], opts, out);
3251
- } else if (lch !== void 0) {
3252
- out.push({
3253
- kind: "step-removed",
3254
- severity: "warning",
3255
- message: `Step only in left run: ${lch.name}`,
3256
- path: buildPath([...segments, pathSeg(lch, ci)]),
3257
- left: lch.id,
3258
- right: void 0
3259
- });
3260
- } else if (rch !== void 0) {
3261
- out.push({
3262
- kind: "step-added",
3263
- severity: "warning",
3264
- message: `Step only in right run: ${rch.name}`,
3265
- path: buildPath([...segments, pathSeg(rch, ci)]),
3266
- left: void 0,
3267
- right: rch.id
3268
- });
3269
- }
3270
- ci += 1;
3271
- }
3272
- }
3273
- function mergeDiffDefaults(options) {
3274
- return {
3275
- ignoreDuration: options?.ignoreDuration ?? false,
3276
- durationThresholdMs: options?.durationThresholdMs !== void 0 ? options.durationThresholdMs : DEFAULT_THRESHOLD_MS,
3277
- focus: options?.focus ?? "all",
3278
- check: options?.check ?? "all"
3279
- };
3280
- }
3281
- function kindMatchesFilter(kind, merged) {
3282
- const { focus, check } = merged;
3283
- if (check !== "all") {
3284
- if (check === "structure") {
3285
- if (!["step-added", "step-removed", "structure", "step-type"].includes(kind)) return false;
3286
- } else if (check === "outputs") {
3287
- if (!["metadata", "output"].includes(kind)) return false;
3288
- } else if (check === "errors") {
3289
- if (!["run-status", "step-status", "error"].includes(kind)) return false;
3290
- } else if (check === "timing") {
3291
- if (kind !== "duration") return false;
3292
- }
3293
- }
3294
- if (focus !== "all") {
3295
- if (focus === "errors") {
3296
- if (!["run-status", "step-status", "error"].includes(kind)) return false;
3297
- } else if (focus === "structure") {
3298
- if (!["step-added", "step-removed", "structure", "step-type"].includes(kind)) return false;
3299
- } else if (focus === "outputs") {
3300
- if (!["metadata", "output"].includes(kind)) return false;
3301
- }
3302
- }
3303
- return true;
3304
- }
3305
- function diffRuns(left, right, options) {
3306
- const merged = mergeDiffDefaults(options);
3307
- const opts = {
3308
- ignoreDuration: merged.ignoreDuration,
3309
- durationThresholdMs: merged.durationThresholdMs
3310
- };
3311
- const raw = [];
3312
- if ((left.status ?? "") !== (right.status ?? "")) {
3313
- raw.push({
3314
- kind: "run-status",
3315
- severity: "warning",
3316
- message: "Run completion status differs",
3317
- left: left.status,
3318
- right: right.status
3319
- });
3320
- }
3321
- if (!merged.ignoreDuration) {
3322
- const ld = left.durationMs;
3323
- const rd = right.durationMs;
3324
- const th = merged.durationThresholdMs;
3325
- let differs = false;
3326
- if (ld === void 0 && rd === void 0) differs = false;
3327
- else if (ld === void 0 || rd === void 0) differs = true;
3328
- else differs = Math.abs(ld - rd) > th;
3329
- if (differs) {
3330
- raw.push({
3331
- kind: "duration",
3332
- severity: "info",
3333
- message: "Run duration differs",
3334
- left: ld,
3335
- right: rd
3336
- });
3337
- }
3338
- }
3339
- const pairs = pairSteps(left.steps, right.steps);
3340
- let idx = 0;
3341
- for (const [ls, rs] of pairs) {
3342
- if (ls !== void 0 && rs !== void 0) {
3343
- compareRecursive(ls, rs, [pathSeg(ls, idx)], opts, raw);
3344
- idx += 1;
3345
- } else if (ls !== void 0) {
3346
- raw.push({
3347
- kind: "step-removed",
3348
- severity: "warning",
3349
- message: `Step only in left run: ${ls.name}`,
3350
- path: buildPath([pathSeg(ls, idx)]),
3351
- left: ls.id,
3352
- right: void 0
3353
- });
3354
- idx += 1;
3355
- } else if (rs !== void 0) {
3356
- raw.push({
3357
- kind: "step-added",
3358
- severity: "warning",
3359
- message: `Step only in right run: ${rs.name}`,
3360
- path: buildPath([pathSeg(rs, idx)]),
3361
- left: void 0,
3362
- right: rs.id
3363
- });
3364
- idx += 1;
3365
- }
3366
- }
3367
- const differences = raw.filter((d) => kindMatchesFilter(d.kind, merged));
3368
- let errors = 0;
3369
- let warnings = 0;
3370
- let info = 0;
3371
- for (const d of differences) {
3372
- if (d.severity === "error") errors += 1;
3373
- else if (d.severity === "warning") warnings += 1;
3374
- else info += 1;
3375
- }
3376
- const firstVisible = differences[0];
3377
- const firstDivergence = firstVisible !== void 0 ? {
3378
- kind: "first-divergence",
3379
- severity: firstVisible.severity,
3380
- message: `First divergence: ${firstVisible.message}`,
3381
- path: firstVisible.path,
3382
- left: firstVisible.left,
3383
- right: firstVisible.right
3384
- } : void 0;
3385
- const summary = {
3386
- leftRunId: left.runId,
3387
- rightRunId: right.runId,
3388
- totalDifferences: differences.length,
3389
- errors,
3390
- warnings,
3391
- info,
3392
- firstDivergence
3393
- };
3394
- return { summary, differences };
3395
- }
3396
-
3397
- // packages/core/src/diff/renderer.ts
3398
- function formatPath(path25) {
3399
- if (path25 === void 0 || path25.path.length === 0) {
3400
- return "(run)";
3401
- }
3402
- return path25.path.map((s) => s.name).join(" > ");
3403
- }
3404
- function formatValue(v, verbose) {
3405
- if (v === void 0) return "(undefined)";
3406
- if (typeof v === "string") return v;
3407
- if (typeof v === "number" || typeof v === "boolean") return String(v);
3408
- const s = JSON.stringify(v);
3409
- if (verbose || s.length <= 120) return s;
3410
- return `${s.slice(0, 117)}...`;
3411
- }
3412
- function renderRunDiff(result, options) {
3413
- const verbose = options?.verbose === true;
3414
- const sev = (s, level) => {
3415
- return s;
3416
- };
3417
- const lines = [];
3418
- const { summary } = result;
3419
- lines.push("Run diff");
3420
- lines.push(`Left: ${summary.leftRunId}`);
3421
- lines.push(`Right: ${summary.rightRunId}`);
3422
- lines.push("");
3423
- lines.push("Summary:");
3424
- lines.push(` Differences: ${summary.totalDifferences}`);
3425
- lines.push(` Errors: ${summary.errors}`);
3426
- lines.push(` Warnings: ${summary.warnings}`);
3427
- lines.push(` Info: ${summary.info}`);
3428
- lines.push("");
3429
- const fd = summary.firstDivergence;
3430
- const firstKind = result.differences[0]?.kind;
3431
- if (fd !== void 0) {
3432
- lines.push("First divergence:");
3433
- const where = formatPath(fd.path);
3434
- const displayKind = firstKind ?? fd.kind;
3435
- lines.push(` ${displayKind} at ${where}`);
3436
- if (fd.left !== void 0 || fd.right !== void 0) {
3437
- lines.push(` left: ${formatValue(fd.left, verbose)}`);
3438
- lines.push(` right: ${formatValue(fd.right, verbose)}`);
3439
- }
3440
- lines.push("");
3441
- }
3442
- lines.push("Differences:");
3443
- if (result.differences.length === 0) {
3444
- lines.push(" (none)");
3445
- return lines.join("\n");
3446
- }
3447
- const showSides = (kind) => verbose || [
3448
- "run-status",
3449
- "step-status",
3450
- "error",
3451
- "duration",
3452
- "step-type",
3453
- "structure",
3454
- "step-added",
3455
- "step-removed"
3456
- ].includes(kind);
3457
- for (const d of result.differences) {
3458
- const tag = sev(`[${d.severity}]`, d.severity);
3459
- const pathStr = d.path !== void 0 ? ` ${formatPath(d.path)}` : "";
3460
- lines.push(` ${tag} ${d.kind}${pathStr}`);
3461
- lines.push(` ${d.message}`);
3462
- if (d.left !== void 0 || d.right !== void 0) {
3463
- if (showSides(d.kind)) {
3464
- lines.push(` left: ${formatValue(d.left, verbose)}`);
3465
- lines.push(` right: ${formatValue(d.right, verbose)}`);
3466
- }
3467
- }
3468
- }
3469
- return lines.join("\n");
3470
- }
3471
-
3472
- // packages/core/src/diff/index.ts
3473
- function diffTraceEvents(leftEvents, rightEvents, options) {
3474
- const left = manualTraceEventsToComparableRun(leftEvents);
3475
- const right = manualTraceEventsToComparableRun(rightEvents);
3476
- return diffRuns(left, right, options);
3477
- }
3478
-
3479
3014
  // packages/cli/src/diff.ts
3480
3015
  function parseFocus(s) {
3481
3016
  const v = (s ?? "all").trim().toLowerCase();
@@ -3576,7 +3111,10 @@ Trace directory: ${traceDir}`
3576
3111
  }
3577
3112
  console.log(
3578
3113
  renderRunDiff(result, {
3579
- verbose: options.verbose === true})
3114
+ verbose: options.verbose === true,
3115
+ color: false,
3116
+ json: false
3117
+ })
3580
3118
  );
3581
3119
  }
3582
3120
 
@@ -3779,7 +3317,7 @@ function indexedToMetadata(row, traceDir) {
3779
3317
  endedAt: row.endedAt ?? void 0,
3780
3318
  durationMs: row.durationMs ?? void 0,
3781
3319
  eventCount: 0,
3782
- filePath: path14.join(traceDir, row.file),
3320
+ filePath: path15.join(traceDir, row.file),
3783
3321
  fileSize: 0,
3784
3322
  createdAt: new Date(row.mtimeMs)
3785
3323
  };
@@ -3808,7 +3346,7 @@ async function newestTraceMtimeMs(traceDir) {
3808
3346
  }
3809
3347
  async function loadSessionRuns(traceDir) {
3810
3348
  try {
3811
- const mod = await import('./src-C4EUHTER.mjs');
3349
+ const mod = await import('./src-YFN3Q3GP.mjs');
3812
3350
  const dbPath = mod.resolveIndexDbPath(traceDir);
3813
3351
  const status = mod.indexStatus(dbPath);
3814
3352
  if (!status.healthy) {
@@ -4257,9 +3795,9 @@ async function reportCommand(runId, options = {}) {
4257
3795
  ...options.section ? { section: options.section } : {}
4258
3796
  });
4259
3797
  const resolvedOutput = resolveOutputOption(options);
4260
- const outPath = resolvedOutput !== void 0 ? path14.resolve(resolvedOutput) : void 0;
3798
+ const outPath = resolvedOutput !== void 0 ? path15.resolve(resolvedOutput) : void 0;
4261
3799
  if (outPath !== void 0) {
4262
- await mkdir(path14.dirname(outPath), { recursive: true });
3800
+ await mkdir(path15.dirname(outPath), { recursive: true });
4263
3801
  await writeFile(outPath, result.content, "utf-8");
4264
3802
  console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
4265
3803
  }
@@ -4385,8 +3923,8 @@ function passesLuhn(value) {
4385
3923
  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;
4386
3924
  var EPOCH_MS_RE = /^1[0-9]{12}$/;
4387
3925
  var EMAIL_RE = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
4388
- function pathSuggestsNonCard(path25) {
4389
- const normalized = path25.toLowerCase().replace(/[^a-z0-9._]/g, "");
3926
+ function pathSuggestsNonCard(path26) {
3927
+ const normalized = path26.toLowerCase().replace(/[^a-z0-9._]/g, "");
4390
3928
  return /(^|\.)(tokenusage|usage)(\.|$)/.test(normalized) || /(startedat|endedat|durationms|timestamp|createdat|updatedat)(\.|$)/.test(normalized) || /(^|\.)(runid|traceid|spanid|eventid|sessionid|userid|parentid|requestid|correlationid)(\.|$)/.test(
4391
3929
  normalized
4392
3930
  ) || /(^|\.)ts(\.|$)/.test(normalized);
@@ -4573,17 +4111,17 @@ function applyRule(rule, value, replacement) {
4573
4111
  }
4574
4112
  return value;
4575
4113
  }
4576
- function childPath(path25, key) {
4114
+ function childPath(path26, key) {
4577
4115
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
4578
- return path25 ? `${path25}.${key}` : key;
4116
+ return path26 ? `${path26}.${key}` : key;
4579
4117
  }
4580
- return `${path25 || "$"}[${JSON.stringify(key)}]`;
4118
+ return `${path26 || "$"}[${JSON.stringify(key)}]`;
4581
4119
  }
4582
- function indexPath(path25, index) {
4583
- return `${path25 || "$"}[${index}]`;
4120
+ function indexPath(path26, index) {
4121
+ return `${path26 || "$"}[${index}]`;
4584
4122
  }
4585
- function makeFinding(path25, detector, action, matchKind, severity = "warning", preview) {
4586
- return preview === void 0 ? { path: path25, detector, action, severity, matchKind } : { path: path25, detector, action, severity, matchKind, preview };
4123
+ function makeFinding(path26, detector, action, matchKind, severity = "warning", preview) {
4124
+ return preview === void 0 ? { path: path26, detector, action, severity, matchKind } : { path: path26, detector, action, severity, matchKind, preview };
4587
4125
  }
4588
4126
  function createRedactionProfile(profile = "local") {
4589
4127
  switch (profile) {
@@ -4652,11 +4190,11 @@ var Redactor2 = class {
4652
4190
  #recordFinding(state, finding) {
4653
4191
  if (this.#collectFindings) state.findings.push(finding);
4654
4192
  }
4655
- #redactValue(value, key, path25, depth, state) {
4193
+ #redactValue(value, key, path26, depth, state) {
4656
4194
  if (depth > this.#maxDepth) {
4657
4195
  this.#recordFinding(
4658
4196
  state,
4659
- makeFinding(path25, "structure.maxDepth", "truncate", "value", "warning")
4197
+ makeFinding(path26, "structure.maxDepth", "truncate", "value", "warning")
4660
4198
  );
4661
4199
  return "[Truncated]";
4662
4200
  }
@@ -4665,19 +4203,19 @@ var Redactor2 = class {
4665
4203
  if (rule) {
4666
4204
  this.#recordFinding(
4667
4205
  state,
4668
- makeFinding(path25, `key.${rule.key}`, actionForRule(rule), "key", "warning")
4206
+ makeFinding(path26, `key.${rule.key}`, actionForRule(rule), "key", "warning")
4669
4207
  );
4670
4208
  return applyRule(rule, value, this.#replacement);
4671
4209
  }
4672
4210
  }
4673
4211
  for (const detector of this.#detectors) {
4674
- const detections = detector.detect({ path: path25, key, value });
4212
+ const detections = detector.detect({ path: path26, key, value });
4675
4213
  for (const detection of detections) {
4676
4214
  const action = detection.action ?? "replace";
4677
4215
  this.#recordFinding(
4678
4216
  state,
4679
4217
  makeFinding(
4680
- path25,
4218
+ path26,
4681
4219
  detector.id,
4682
4220
  action,
4683
4221
  detection.matchKind ?? detector.matchKind ?? "custom",
@@ -4695,7 +4233,7 @@ var Redactor2 = class {
4695
4233
  const out = [];
4696
4234
  state.seen.set(value, out);
4697
4235
  value.forEach((item, index) => {
4698
- out[index] = this.#redactValue(item, void 0, indexPath(path25, index), depth + 1, state);
4236
+ out[index] = this.#redactValue(item, void 0, indexPath(path26, index), depth + 1, state);
4699
4237
  });
4700
4238
  return out;
4701
4239
  }
@@ -4707,7 +4245,7 @@ var Redactor2 = class {
4707
4245
  out[entryKey] = this.#redactValue(
4708
4246
  entryValue,
4709
4247
  entryKey,
4710
- childPath(path25 === "$" ? "" : path25, entryKey),
4248
+ childPath(path26 === "$" ? "" : path26, entryKey),
4711
4249
  depth + 1,
4712
4250
  state
4713
4251
  );
@@ -5168,14 +4706,14 @@ function uniqueSorted(values) {
5168
4706
  return [...new Set(values)].sort();
5169
4707
  }
5170
4708
  function isWithinDirectory(child, parent) {
5171
- const relative = path14.relative(parent, child);
5172
- return relative === "" || !relative.startsWith("..") && !path14.isAbsolute(relative);
4709
+ const relative = path15.relative(parent, child);
4710
+ return relative === "" || !relative.startsWith("..") && !path15.isAbsolute(relative);
5173
4711
  }
5174
4712
  async function resolveOutputPath(inputPath, output2, force) {
5175
4713
  if (output2 === void 0 || output2.trim() === "") return void 0;
5176
- const inputAbs = path14.resolve(inputPath);
5177
- const outputAbs = path14.resolve(output2.trim());
5178
- const inputDir = path14.dirname(inputAbs);
4714
+ const inputAbs = path15.resolve(inputPath);
4715
+ const outputAbs = path15.resolve(output2.trim());
4716
+ const inputDir = path15.dirname(inputAbs);
5179
4717
  if (!isWithinDirectory(outputAbs, inputDir)) {
5180
4718
  throw new Error("Refusing to write migrated output outside the input directory.");
5181
4719
  }
@@ -5296,7 +4834,7 @@ async function migrateCommand(input3, options = {}) {
5296
4834
  process.exitCode = 1;
5297
4835
  return;
5298
4836
  }
5299
- const inputPath = path14.resolve(input3.trim());
4837
+ const inputPath = path15.resolve(input3.trim());
5300
4838
  const dryRun = options.dryRun === true;
5301
4839
  if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
5302
4840
  console.error("migrate requires --dry-run or --output <path>.");
@@ -5315,7 +4853,7 @@ async function migrateCommand(input3, options = {}) {
5315
4853
  );
5316
4854
  const result = await buildMigration(inputPath, outputPath);
5317
4855
  if (!dryRun && outputPath !== void 0) {
5318
- await mkdir(path14.dirname(outputPath), { recursive: true });
4856
+ await mkdir(path15.dirname(outputPath), { recursive: true });
5319
4857
  await writeFile(outputPath, result.content, "utf-8");
5320
4858
  }
5321
4859
  printSummary2(result, dryRun);
@@ -5645,23 +5183,23 @@ function evaluatePromptInjection(text, options = {}) {
5645
5183
  }
5646
5184
  return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
5647
5185
  }
5648
- function validateSchemaField(value, field, path25, evidence) {
5186
+ function validateSchemaField(value, field, path26, evidence) {
5649
5187
  const ruleId = "guardrail.structured-output";
5650
5188
  if (field.type) {
5651
5189
  const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
5652
5190
  if (actual !== field.type) {
5653
- evidence.push({ ruleId, path: path25, preview: `expected ${field.type}, got ${actual}` });
5191
+ evidence.push({ ruleId, path: path26, preview: `expected ${field.type}, got ${actual}` });
5654
5192
  return;
5655
5193
  }
5656
5194
  }
5657
5195
  if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
5658
- evidence.push({ ruleId, path: path25, preview: "value not in enum" });
5196
+ evidence.push({ ruleId, path: path26, preview: "value not in enum" });
5659
5197
  }
5660
5198
  if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
5661
5199
  const record = value;
5662
5200
  for (const key of field.required) {
5663
5201
  if (!(key in record)) {
5664
- evidence.push({ ruleId, path: `${path25}.${key}`, preview: "missing required key" });
5202
+ evidence.push({ ruleId, path: `${path26}.${key}`, preview: "missing required key" });
5665
5203
  }
5666
5204
  }
5667
5205
  }
@@ -5988,7 +5526,7 @@ function asConfig(value) {
5988
5526
  }
5989
5527
  async function loadConfig(configPath) {
5990
5528
  if (configPath === void 0) return {};
5991
- const extension = path14.extname(configPath);
5529
+ const extension = path15.extname(configPath);
5992
5530
  if (TS_CONFIG_EXTENSIONS.has(extension)) {
5993
5531
  throw new Error(
5994
5532
  "TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -5997,7 +5535,7 @@ async function loadConfig(configPath) {
5997
5535
  if (!CONFIG_EXTENSIONS.has(extension)) {
5998
5536
  throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
5999
5537
  }
6000
- const absolute = path14.resolve(configPath);
5538
+ const absolute = path15.resolve(configPath);
6001
5539
  if (extension === ".json") {
6002
5540
  const raw = await readFile(absolute, "utf-8");
6003
5541
  return asConfig(JSON.parse(raw));
@@ -6173,10 +5711,10 @@ function printHuman(result) {
6173
5711
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
6174
5712
  }
6175
5713
  for (const finding of result.findings) {
6176
- const path25 = finding.evidence[0]?.path;
5714
+ const path26 = finding.evidence[0]?.path;
6177
5715
  const run = finding.evidence[0]?.runId;
6178
5716
  const runPrefix = run ? `[${run}] ` : "";
6179
- console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path25 ? ` (${path25})` : ""}`);
5717
+ console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path26 ? ` (${path26})` : ""}`);
6180
5718
  }
6181
5719
  }
6182
5720
  function readErrorResult(error) {
@@ -6438,7 +5976,7 @@ async function loadSuiteViewerData(options) {
6438
5976
  for (const suiteCase of result.cases) {
6439
5977
  cases.push(await enrichCase(suiteCase, baselinePath));
6440
5978
  }
6441
- const artifactsDir = path14.join(path14.dirname(result.configPath), ".agent-inspect/suite-runs");
5979
+ const artifactsDir = path15.join(path15.dirname(result.configPath), ".agent-inspect/suite-runs");
6442
5980
  return {
6443
5981
  suiteName: result.suiteName,
6444
5982
  configPath: result.configPath,
@@ -6631,19 +6169,19 @@ function serializeWorkspaceManifest(manifest) {
6631
6169
  }
6632
6170
  var INDEX_DIR_NAME = "index";
6633
6171
  function resolveWorkspaceLocation(cwd = process.cwd()) {
6634
- const projectRoot = path14.resolve(cwd);
6635
- const workspaceDir = path14.join(projectRoot, WORKSPACE_DIR_NAME);
6172
+ const projectRoot = path15.resolve(cwd);
6173
+ const workspaceDir = path15.join(projectRoot, WORKSPACE_DIR_NAME);
6636
6174
  return {
6637
6175
  projectRoot,
6638
6176
  workspaceDir,
6639
- manifestPath: path14.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
6177
+ manifestPath: path15.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
6640
6178
  };
6641
6179
  }
6642
6180
  function resolveInsideWorkspace(workspaceDir, relative) {
6643
- const base = path14.resolve(workspaceDir);
6644
- const resolved = path14.resolve(base, relative);
6645
- const rel = path14.relative(base, resolved);
6646
- if (rel === "" || rel === "." || !rel.startsWith("..") && !path14.isAbsolute(rel)) {
6181
+ const base = path15.resolve(workspaceDir);
6182
+ const resolved = path15.resolve(base, relative);
6183
+ const rel = path15.relative(base, resolved);
6184
+ if (rel === "" || rel === "." || !rel.startsWith("..") && !path15.isAbsolute(rel)) {
6647
6185
  return resolved;
6648
6186
  }
6649
6187
  throw new Error(
@@ -6712,7 +6250,7 @@ async function createWorkspace(options = {}) {
6712
6250
  created = false;
6713
6251
  adopted = true;
6714
6252
  } else {
6715
- const project = options.project?.trim() || path14.basename(location.projectRoot) || "workspace";
6253
+ const project = options.project?.trim() || path15.basename(location.projectRoot) || "workspace";
6716
6254
  const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
6717
6255
  manifest = createDefaultWorkspaceManifest({
6718
6256
  project,
@@ -6851,7 +6389,7 @@ async function doctorWorkspace(location) {
6851
6389
  const abs = resolveInsideWorkspace(location.workspaceDir, rel);
6852
6390
  for (const file of await listJsonl(abs)) {
6853
6391
  try {
6854
- const s = await stat(path14.join(abs, file));
6392
+ const s = await stat(path15.join(abs, file));
6855
6393
  newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
6856
6394
  } catch {
6857
6395
  checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
@@ -6899,7 +6437,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
6899
6437
  const relPath = `${rel}/${entry}`;
6900
6438
  removed.push(relPath);
6901
6439
  if (!dryRun) {
6902
- await rm(path14.join(abs, entry), { recursive: true, force: true });
6440
+ await rm(path15.join(abs, entry), { recursive: true, force: true });
6903
6441
  }
6904
6442
  }
6905
6443
  }
@@ -6908,7 +6446,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
6908
6446
 
6909
6447
  // packages/viewer/src/workspace-data.ts
6910
6448
  async function loadWorkspaceViewerData(options) {
6911
- const cwd = path14.resolve(options.cwd ?? process.cwd());
6449
+ const cwd = path15.resolve(options.cwd ?? process.cwd());
6912
6450
  const location = resolveWorkspaceLocation(cwd);
6913
6451
  const manifestRead = await readWorkspaceManifestFile(location);
6914
6452
  if (!manifestRead.ok || manifestRead.manifest === void 0) {
@@ -6921,7 +6459,7 @@ async function loadWorkspaceViewerData(options) {
6921
6459
  const runs = [];
6922
6460
  for (const rel of manifestRead.manifest.traceDirs) {
6923
6461
  const traceDir = resolveTraceDir({
6924
- dir: path14.join(location.workspaceDir, rel)
6462
+ dir: path15.join(location.workspaceDir, rel)
6925
6463
  });
6926
6464
  const td = new TraceDirectory({ dir: traceDir });
6927
6465
  const files = await td.list();
@@ -6935,7 +6473,7 @@ async function loadWorkspaceViewerData(options) {
6935
6473
  runId: meta.runId,
6936
6474
  ...meta.name !== void 0 ? { name: meta.name } : {},
6937
6475
  status: meta.status,
6938
- file: path14.basename(meta.filePath)
6476
+ file: path15.basename(meta.filePath)
6939
6477
  });
6940
6478
  }
6941
6479
  }
@@ -6946,8 +6484,8 @@ async function loadWorkspaceViewerData(options) {
6946
6484
  doctor,
6947
6485
  runs,
6948
6486
  bundleDirs: [
6949
- path14.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
6950
- path14.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
6487
+ path15.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
6488
+ path15.join(location.workspaceDir, manifestRead.manifest.artifactsDir)
6951
6489
  ]
6952
6490
  };
6953
6491
  }
@@ -7010,7 +6548,7 @@ function createViewerServer(options = {}) {
7010
6548
  ok: true,
7011
6549
  readOnly: true,
7012
6550
  mode,
7013
- traceDir: path14.resolve(traceDir)
6551
+ traceDir: path15.resolve(traceDir)
7014
6552
  });
7015
6553
  }
7016
6554
  if (pathname === "/api/suite" && mode === "suite") {
@@ -7039,7 +6577,7 @@ function createViewerServer(options = {}) {
7039
6577
  runId: meta.runId,
7040
6578
  name: meta.name,
7041
6579
  status: meta.status,
7042
- file: path14.basename(meta.filePath),
6580
+ file: path15.basename(meta.filePath),
7043
6581
  startedAt: meta.startedAt,
7044
6582
  durationMs: meta.durationMs
7045
6583
  }))
@@ -7156,7 +6694,7 @@ function startViewerServer(options = {}) {
7156
6694
  resolve({
7157
6695
  host,
7158
6696
  port: resolvedPort,
7159
- traceDir: path14.resolve(traceDir),
6697
+ traceDir: path15.resolve(traceDir),
7160
6698
  url: `http://${host}:${resolvedPort}/${modeQuery}`,
7161
6699
  mode
7162
6700
  });
@@ -7527,10 +7065,10 @@ async function evalRun(input3, options = {}) {
7527
7065
  diagnostics: []
7528
7066
  };
7529
7067
  }
7530
- function evidenceForRun(run, path25) {
7531
- return [{ runId: run.runId, ...path25 !== void 0 ? { path: path25 } : {} }];
7068
+ function evidenceForRun(run, path26) {
7069
+ return [{ runId: run.runId, ...path26 !== void 0 ? { path: path26 } : {} }];
7532
7070
  }
7533
- function evidenceForEvent(event, path25) {
7071
+ function evidenceForEvent(event, path26) {
7534
7072
  return [
7535
7073
  {
7536
7074
  runId: event.runId,
@@ -7538,7 +7076,7 @@ function evidenceForEvent(event, path25) {
7538
7076
  ...event.parentId !== void 0 ? { parentId: event.parentId } : {},
7539
7077
  kind: event.kind,
7540
7078
  name: event.name,
7541
- ...path25 !== void 0 ? { path: path25 } : {}
7079
+ ...path26 !== void 0 ? { path: path26 } : {}
7542
7080
  }
7543
7081
  ];
7544
7082
  }
@@ -7696,9 +7234,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
7696
7234
  function tokenize(text) {
7697
7235
  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));
7698
7236
  }
7699
- function firstEvidence(fields, run, path25) {
7237
+ function firstEvidence(fields, run, path26) {
7700
7238
  const first = fields[0];
7701
- return first === void 0 ? evidenceForRun(run, path25) : evidenceForEvent(first.node.event, first.path);
7239
+ return first === void 0 ? evidenceForRun(run, path26) : evidenceForEvent(first.node.event, first.path);
7702
7240
  }
7703
7241
  function collectSourceIds(nodes, keys) {
7704
7242
  const wanted = keySet(keys);
@@ -8075,8 +7613,8 @@ function renderEvalMarkdown(result) {
8075
7613
  if (result.findings.length > 0) {
8076
7614
  lines.push("", "## Findings");
8077
7615
  for (const finding of result.findings) {
8078
- const path25 = finding.evidence[0]?.path;
8079
- lines.push(`- ${finding.ruleId}: ${finding.message}${path25 ? ` (${path25})` : ""}`);
7616
+ const path26 = finding.evidence[0]?.path;
7617
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path26 ? ` (${path26})` : ""}`);
8080
7618
  }
8081
7619
  }
8082
7620
  return `${lines.join("\n")}
@@ -8123,7 +7661,7 @@ function asConfig2(value) {
8123
7661
  }
8124
7662
  async function loadConfig2(configPath) {
8125
7663
  if (configPath === void 0) return {};
8126
- const extension = path14.extname(configPath);
7664
+ const extension = path15.extname(configPath);
8127
7665
  if (TS_CONFIG_EXTENSIONS2.has(extension)) {
8128
7666
  throw new Error(
8129
7667
  "TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
@@ -8132,7 +7670,7 @@ async function loadConfig2(configPath) {
8132
7670
  if (!CONFIG_EXTENSIONS2.has(extension)) {
8133
7671
  throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
8134
7672
  }
8135
- const absolute = path14.resolve(configPath);
7673
+ const absolute = path15.resolve(configPath);
8136
7674
  if (extension === ".json") {
8137
7675
  const raw = await readFile(absolute, "utf-8");
8138
7676
  return asConfig2(JSON.parse(raw));
@@ -8269,8 +7807,8 @@ function printHuman2(result) {
8269
7807
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
8270
7808
  }
8271
7809
  for (const finding of result.findings) {
8272
- const path25 = finding.evidence[0]?.path;
8273
- console.log(`- ${finding.ruleId}: ${finding.message}${path25 ? ` (${path25})` : ""}`);
7810
+ const path26 = finding.evidence[0]?.path;
7811
+ console.log(`- ${finding.ruleId}: ${finding.message}${path26 ? ` (${path26})` : ""}`);
8274
7812
  }
8275
7813
  }
8276
7814
  function readErrorResult2(error) {
@@ -8523,14 +8061,14 @@ function exitCodeFor3(result) {
8523
8061
  return 2;
8524
8062
  }
8525
8063
  function explainFinding(finding, blocksBundle) {
8526
- const path25 = finding.evidence[0]?.path ?? "(unknown path)";
8064
+ const path26 = finding.evidence[0]?.path ?? "(unknown path)";
8527
8065
  const category = finding.category ?? "structure";
8528
8066
  const confidence = finding.confidence ?? "medium";
8529
8067
  const detector = finding.detector ?? finding.ruleId;
8530
8068
  const action = finding.action ?? "review";
8531
8069
  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.";
8532
8070
  return [
8533
- ` Matched: detector=${detector}; path=${path25}; category=${category}`,
8071
+ ` Matched: detector=${detector}; path=${path26}; category=${category}`,
8534
8072
  ` Why: ${finding.message}`,
8535
8073
  ` Confidence: ${confidence}`,
8536
8074
  ` Redaction: ${redactionHint}`,
@@ -8572,9 +8110,9 @@ function printHuman3(result, explain = false) {
8572
8110
  console.log(`- ${diagnostic3.code}: ${diagnostic3.message}`);
8573
8111
  }
8574
8112
  for (const finding of result.findings) {
8575
- const path25 = finding.evidence[0]?.path;
8113
+ const path26 = finding.evidence[0]?.path;
8576
8114
  const taxonomy = finding.category !== void 0 || finding.confidence !== void 0 ? ` [${[finding.category, finding.confidence].filter(Boolean).join("/")}]` : "";
8577
- console.log(`- ${finding.ruleId}: ${finding.message}${path25 ? ` (${path25})` : ""}${taxonomy}`);
8115
+ console.log(`- ${finding.ruleId}: ${finding.message}${path26 ? ` (${path26})` : ""}${taxonomy}`);
8578
8116
  if (explain) {
8579
8117
  const blocks = finding.severity === "error" || finding.status === "fail";
8580
8118
  for (const line of explainFinding(finding, blocks)) {
@@ -8688,6 +8226,91 @@ function messageStartsWithDash(error) {
8688
8226
  const message = error instanceof Error ? error.message : String(error);
8689
8227
  return message.startsWith("--");
8690
8228
  }
8229
+ function validateReporterArtifactPath(options) {
8230
+ const outputDir = path15.resolve(options.outputDir);
8231
+ const diagnostics = [];
8232
+ const rawPath = options.relativePath;
8233
+ if (rawPath.length === 0) {
8234
+ diagnostics.push({
8235
+ code: "artifact_path_empty",
8236
+ severity: "error",
8237
+ message: "Reporter artifact path must not be empty."
8238
+ });
8239
+ return { ok: false, outputDir, diagnostics };
8240
+ }
8241
+ if (rawPath.includes("\0")) {
8242
+ diagnostics.push({
8243
+ code: "invalid_artifact_path",
8244
+ severity: "error",
8245
+ message: "Reporter artifact path must not contain null bytes.",
8246
+ target: rawPath
8247
+ });
8248
+ return { ok: false, outputDir, diagnostics };
8249
+ }
8250
+ if (path15.isAbsolute(rawPath) || path15.win32.isAbsolute(rawPath)) {
8251
+ diagnostics.push({
8252
+ code: "artifact_path_absolute",
8253
+ severity: "error",
8254
+ message: "Reporter artifact path must be relative.",
8255
+ target: rawPath
8256
+ });
8257
+ return { ok: false, outputDir, diagnostics };
8258
+ }
8259
+ const normalized = path15.posix.normalize(rawPath.replace(/\\/g, "/"));
8260
+ const segments = normalized.split("/");
8261
+ if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
8262
+ diagnostics.push({
8263
+ code: "artifact_path_escape",
8264
+ severity: "error",
8265
+ message: "Reporter artifact path must stay under the output directory.",
8266
+ target: rawPath
8267
+ });
8268
+ return { ok: false, outputDir, diagnostics };
8269
+ }
8270
+ const absolutePath = path15.resolve(outputDir, normalized);
8271
+ const relFromOutput = path15.relative(outputDir, absolutePath);
8272
+ if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path15.isAbsolute(relFromOutput)) {
8273
+ diagnostics.push({
8274
+ code: "artifact_path_escape",
8275
+ severity: "error",
8276
+ message: "Reporter artifact path resolved outside the output directory.",
8277
+ target: rawPath
8278
+ });
8279
+ return { ok: false, outputDir, diagnostics };
8280
+ }
8281
+ return {
8282
+ ok: true,
8283
+ outputDir,
8284
+ relativePath: normalized,
8285
+ absolutePath,
8286
+ diagnostics
8287
+ };
8288
+ }
8289
+ var EVIDENCE_CI_ARTIFACT_FILES = [
8290
+ "evidence.html",
8291
+ "evidence.json",
8292
+ "check-results.json",
8293
+ "trace.jsonl"
8294
+ ];
8295
+ function createEvidenceCiArtifacts(options) {
8296
+ const profile = options.redactionProfile;
8297
+ const prefix = options.relativeDir !== void 0 && options.relativeDir.trim() !== "" ? options.relativeDir.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "") : "";
8298
+ const join = (name) => prefix === "" ? name : path15.posix.join(prefix, name);
8299
+ const formatFor = (name) => {
8300
+ if (name.endsWith(".html")) return "html";
8301
+ if (name.endsWith(".jsonl")) return "jsonl";
8302
+ return "json";
8303
+ };
8304
+ return EVIDENCE_CI_ARTIFACT_FILES.map((name) => ({
8305
+ kind: "evidence",
8306
+ path: join(name),
8307
+ format: formatFor(name),
8308
+ redactionProfile: profile,
8309
+ title: `Evidence v2 ${name}`
8310
+ }));
8311
+ }
8312
+
8313
+ // packages/cli/src/artifacts.ts
8691
8314
  var NOTE = "Generated locally by AgentInspect. Artifacts are best-effort summaries, not compliance or security certification.";
8692
8315
  var SAFETY_RULES = [
8693
8316
  createSafetyRawContentRule(),
@@ -8761,8 +8384,8 @@ function renderCheckSection(result) {
8761
8384
  `Diagnostics: ${result.diagnostics.length}`
8762
8385
  ];
8763
8386
  for (const finding of result.findings.slice(0, 10)) {
8764
- const path25 = finding.evidence[0]?.path ?? "(run)";
8765
- lines.push(`- ${finding.ruleId}: ${finding.message} (${path25})`);
8387
+ const path26 = finding.evidence[0]?.path ?? "(run)";
8388
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path26})`);
8766
8389
  }
8767
8390
  for (const diagnostic3 of result.diagnostics.slice(0, 10)) {
8768
8391
  lines.push(`- ${diagnostic3.code}: ${diagnostic3.message}`);
@@ -8840,8 +8463,8 @@ function renderHtml(trace, check, diff) {
8840
8463
  `;
8841
8464
  }
8842
8465
  async function writeArtifact(outputDir, relativePath, content, files) {
8843
- const outPath = path14.join(outputDir, relativePath);
8844
- await mkdir(path14.dirname(outPath), { recursive: true });
8466
+ const outPath = path15.join(outputDir, relativePath);
8467
+ await mkdir(path15.dirname(outPath), { recursive: true });
8845
8468
  await writeFile(outPath, content, "utf-8");
8846
8469
  files.push(relativePath);
8847
8470
  }
@@ -8856,8 +8479,21 @@ function manifestStatus(check, diff) {
8856
8479
  if (check.summary.warnings > 0 || (diff?.summary.warnings ?? 0) > 0) return "warning";
8857
8480
  return "ok";
8858
8481
  }
8482
+ function toEvidenceStatus(status) {
8483
+ if (status === "ok") return "SAFE";
8484
+ if (status === "warning") return "SAFE WITH WARNINGS";
8485
+ if (status === "unsafe" || status === "regression") return "UNSAFE";
8486
+ return "UNKNOWN";
8487
+ }
8488
+ function shouldWriteEvidence(options, status) {
8489
+ if (options.alwaysEvidence === true) return true;
8490
+ if (options.evidence === false) return false;
8491
+ const onFailureOnly = options.onFailureOnly !== false;
8492
+ if (!onFailureOnly) return true;
8493
+ return status === "unsafe" || status === "regression" || status === "unknown" || status === "warning";
8494
+ }
8859
8495
  async function artifactsCommand(target, options = {}, stdin = process.stdin) {
8860
- const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path14.resolve(options.outputDir.trim()) : "";
8496
+ const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path15.resolve(options.outputDir.trim()) : "";
8861
8497
  if (outputDir === "") {
8862
8498
  console.error("--output-dir is required.");
8863
8499
  process.exitCode = 1;
@@ -8921,15 +8557,77 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
8921
8557
  );
8922
8558
  await writeArtifact(outputDir, "summary.md", renderMarkdown(trace, check, diff), files);
8923
8559
  await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
8560
+ const status = manifestStatus(check, diff);
8561
+ if (shouldWriteEvidence(options, status)) {
8562
+ try {
8563
+ const runIds = selectedRun !== void 0 ? [selectedRun.runId] : read.runs.map((run) => run.runId);
8564
+ const traceDir = resolveTraceDir({ dir: options.dir });
8565
+ const sourceContents = /* @__PURE__ */ new Map();
8566
+ let combined = "";
8567
+ for (const runId of runIds) {
8568
+ const tracePath = getTraceFilePath(runId, traceDir);
8569
+ let raw = "";
8570
+ try {
8571
+ raw = await readFile(tracePath, "utf-8");
8572
+ } catch {
8573
+ raw = `${read.events.filter((event) => event.runId === runId).map((event) => JSON.stringify(event)).join("\n")}
8574
+ `;
8575
+ }
8576
+ sourceContents.set(runId, raw);
8577
+ const redacted = redactTraceContent(raw, "strict");
8578
+ combined += redacted.content.endsWith("\n") ? redacted.content : `${redacted.content}
8579
+ `;
8580
+ }
8581
+ const checkResultsJson = writeJson3({
8582
+ aggregateStatus: toEvidenceStatus(status),
8583
+ runs: runIds.map((runId) => ({
8584
+ runId,
8585
+ status: toEvidenceStatus(status),
8586
+ errors: check.summary.errors,
8587
+ warnings: check.summary.warnings,
8588
+ findings: check.findings.length
8589
+ }))
8590
+ });
8591
+ const evidencePackage = buildEvidenceCiPackage({
8592
+ generatorVersion: version,
8593
+ runIds,
8594
+ sourceContents,
8595
+ redactedTraceJsonl: combined,
8596
+ redactionProfile: "strict",
8597
+ assessmentStatus: toEvidenceStatus(status),
8598
+ checkResultsJson,
8599
+ summaryText: renderMarkdown(trace, check, diff)
8600
+ });
8601
+ await writeArtifact(outputDir, "evidence.html", evidencePackage["evidence.html"], files);
8602
+ await writeArtifact(outputDir, "evidence.json", evidencePackage["evidence.json"], files);
8603
+ await writeArtifact(
8604
+ outputDir,
8605
+ "check-results.json",
8606
+ evidencePackage["check-results.json"],
8607
+ files
8608
+ );
8609
+ await writeArtifact(outputDir, "trace.jsonl", evidencePackage["trace.jsonl"], files);
8610
+ const expected = createEvidenceCiArtifacts({ redactionProfile: "strict" }).map((a) => a.path);
8611
+ for (const name of expected) {
8612
+ if (!files.includes(name)) {
8613
+ throw new Error(`Evidence CI package missing expected file: ${name}`);
8614
+ }
8615
+ }
8616
+ } catch (error) {
8617
+ console.error(
8618
+ `[AgentInspect] evidence package skipped: ${error instanceof Error ? error.message : String(error)}`
8619
+ );
8620
+ }
8621
+ }
8924
8622
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
8925
8623
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
8926
- await mkdir(path14.dirname(path14.resolve(summaryTarget)), { recursive: true });
8927
- await appendFile(path14.resolve(summaryTarget), `
8624
+ await mkdir(path15.dirname(path15.resolve(summaryTarget)), { recursive: true });
8625
+ await appendFile(path15.resolve(summaryTarget), `
8928
8626
  ${renderMarkdown(trace, check, diff)}`, "utf-8");
8929
8627
  }
8930
8628
  const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
8931
8629
  const manifest = {
8932
- status: manifestStatus(check, diff),
8630
+ status,
8933
8631
  outputDir,
8934
8632
  files: manifestFiles,
8935
8633
  trace,
@@ -8943,10 +8641,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
8943
8641
  findings: diff?.findings.length ?? 0,
8944
8642
  diagnostics: diff?.diagnostics.length ?? 0
8945
8643
  },
8946
- ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path14.resolve(summaryTarget) } : {},
8644
+ ...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path15.resolve(summaryTarget) } : {},
8947
8645
  note: NOTE
8948
8646
  };
8949
- await writeFile(path14.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
8647
+ await writeFile(path15.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
8950
8648
  if (options.json === true) {
8951
8649
  console.log(writeJson3(manifest).trimEnd());
8952
8650
  } else {
@@ -8988,16 +8686,24 @@ function safetyStatusFromAssess(status) {
8988
8686
  }
8989
8687
  return "UNKNOWN";
8990
8688
  }
8991
- async function resolveOutputDir(options, runIds, cwd) {
8689
+ function parseBundleFormat(value) {
8690
+ if (value === void 0 || value === "directory" || value === "html" || value === "zip") {
8691
+ return value ?? "directory";
8692
+ }
8693
+ throw new Error(`Unsupported --format "${value}". Use directory, html, or zip.`);
8694
+ }
8695
+ async function resolveOutputDir(options, runIds, cwd, format) {
8992
8696
  const out = resolveOutputOption(options);
8993
8697
  if (out !== void 0) {
8994
- const normalized = normalizeBundleOutputPath(out);
8698
+ const normalized = normalizeBundleOutputPath(out, {
8699
+ preserveZipExtension: format === "zip"
8700
+ });
8995
8701
  try {
8996
8702
  const location = resolveWorkspaceLocation(cwd);
8997
8703
  const manifest = await readWorkspaceManifestFile(location);
8998
8704
  if (manifest.ok && manifest.manifest) {
8999
- const rel = path14.relative(location.workspaceDir, normalized);
9000
- if (!rel.startsWith("..") && !path14.isAbsolute(rel)) {
8705
+ const rel = path15.relative(location.workspaceDir, normalized);
8706
+ if (!rel.startsWith("..") && !path15.isAbsolute(rel)) {
9001
8707
  return resolveInsideWorkspace(location.workspaceDir, rel);
9002
8708
  }
9003
8709
  }
@@ -9011,20 +8717,21 @@ async function resolveOutputDir(options, runIds, cwd) {
9011
8717
  if (manifest.ok && manifest.manifest) {
9012
8718
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
9013
8719
  const label = runIds.length === 1 ? sanitizeBundleRunId(runIds[0]) : `multi-${runIds.length}`;
9014
- return resolveInsideWorkspace(
8720
+ const base2 = resolveInsideWorkspace(
9015
8721
  location.workspaceDir,
9016
- path14.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
8722
+ path15.join(manifest.manifest.bundlesDir, `bundle-${label}-${stamp}`)
9017
8723
  );
8724
+ return format === "zip" ? `${base2}.zip` : base2;
9018
8725
  }
9019
8726
  } catch {
9020
8727
  }
9021
- return defaultBundleOutputPath(runIds);
8728
+ const base = defaultBundleOutputPath(runIds);
8729
+ return format === "zip" ? `${base}.zip` : base;
9022
8730
  }
9023
- async function writeBundleFile(outputDir, relativePath, content, files) {
9024
- const outPath = assertBundlePathContained(outputDir, relativePath);
9025
- await mkdir(path14.dirname(outPath), { recursive: true });
9026
- await writeFile(outPath, content, "utf-8");
9027
- files.push(relativePath);
8731
+ function stageBundleFile(relativePath, content, files, packaged) {
8732
+ const safe = assertEvidenceRelativePath(relativePath);
8733
+ if (!files.includes(safe)) files.push(safe);
8734
+ packaged.set(safe, content);
9028
8735
  }
9029
8736
  function renderBundleIndexHtml(parts) {
9030
8737
  const links = parts.runIds.map(
@@ -9062,6 +8769,7 @@ function extractHtmlBody(content) {
9062
8769
  }
9063
8770
  async function bundleCommand(runIdArg, options = {}) {
9064
8771
  const profile = parseBundleProfile(resolveRedactionProfileOption(options));
8772
+ const format = parseBundleFormat(options.format);
9065
8773
  const traceDir = resolveTraceDir({ dir: options.dir });
9066
8774
  const cwd = process.cwd();
9067
8775
  let resolveResult;
@@ -9087,12 +8795,18 @@ async function bundleCommand(runIdArg, options = {}) {
9087
8795
  process.exitCode = 1;
9088
8796
  return;
9089
8797
  }
9090
- const outputDir = await resolveOutputDir(options, resolveResult.runIds, cwd);
8798
+ const outputDir = await resolveOutputDir(options, resolveResult.runIds, cwd, format);
9091
8799
  const files = [];
8800
+ const packaged = /* @__PURE__ */ new Map();
9092
8801
  const checkRuns = [];
9093
8802
  const redactionRuns = [];
9094
8803
  const htmlByRun = /* @__PURE__ */ new Map();
9095
8804
  const redactedJsonlByRun = /* @__PURE__ */ new Map();
8805
+ const artifactTrees = [];
8806
+ const artifactEventsByRun = /* @__PURE__ */ new Map();
8807
+ const findingSummaries = [];
8808
+ const sourceHashes = [];
8809
+ const schemaVersions = /* @__PURE__ */ new Set();
9096
8810
  let combinedJsonl = "";
9097
8811
  for (const runId of resolveResult.runIds) {
9098
8812
  const tracePath = getTraceFilePath(runId, traceDir);
@@ -9129,6 +8843,14 @@ async function bundleCommand(runIdArg, options = {}) {
9129
8843
  }
9130
8844
  const sourceSafety = assessOpenedTrace(read, { run: runId });
9131
8845
  const sourceStatus = safetyStatusFromAssess(sourceSafety.status);
8846
+ sourceHashes.push({
8847
+ runId,
8848
+ algorithm: "sha256",
8849
+ hash: sha256Hex(rawContent)
8850
+ });
8851
+ for (const version2 of collectTraceSchemaVersions(rawContent)) {
8852
+ schemaVersions.add(version2);
8853
+ }
9132
8854
  const redacted = redactTraceContent(rawContent, toReportProfile(profile));
9133
8855
  redactedJsonlByRun.set(runId, redacted.content);
9134
8856
  combinedJsonl += redacted.content.endsWith("\n") ? redacted.content : `${redacted.content}
@@ -9142,12 +8864,18 @@ async function bundleCommand(runIdArg, options = {}) {
9142
8864
  detectors
9143
8865
  });
9144
8866
  let artifactSafety = sourceSafety;
8867
+ let artifactTree;
9145
8868
  try {
9146
8869
  const artifactRead = await openTrace(
9147
8870
  { type: "string", content: redacted.content },
9148
8871
  { format: "agent-inspect-jsonl" }
9149
8872
  );
9150
8873
  artifactSafety = assessOpenedTrace(artifactRead, { run: runId });
8874
+ artifactTree = artifactRead.runs.find((run) => run.runId === runId) ?? artifactRead.runs[0];
8875
+ artifactEventsByRun.set(
8876
+ runId,
8877
+ artifactRead.events.filter((event) => event.runId === runId)
8878
+ );
9151
8879
  } catch {
9152
8880
  artifactSafety = {
9153
8881
  ...sourceSafety,
@@ -9160,6 +8888,24 @@ async function bundleCommand(runIdArg, options = {}) {
9160
8888
  }
9161
8889
  };
9162
8890
  }
8891
+ for (const finding of artifactSafety.findings) {
8892
+ findingSummaries.push({
8893
+ runId,
8894
+ ruleId: finding.ruleId,
8895
+ severity: finding.severity,
8896
+ message: finding.message,
8897
+ ...finding.category !== void 0 ? { category: finding.category } : {},
8898
+ ...finding.detector !== void 0 ? { detector: finding.detector } : {},
8899
+ ...finding.confidence !== void 0 ? { confidence: finding.confidence } : {},
8900
+ ...finding.action !== void 0 ? { action: finding.action } : {}
8901
+ });
8902
+ }
8903
+ if (artifactTree) {
8904
+ artifactTrees.push(artifactTree);
8905
+ } else {
8906
+ const selected2 = read.runs.find((run) => run.runId === runId);
8907
+ if (selected2) artifactTrees.push(selected2);
8908
+ }
9163
8909
  const status = safetyStatusFromAssess(artifactSafety.status);
9164
8910
  checkRuns.push({
9165
8911
  runId,
@@ -9214,80 +8960,223 @@ async function bundleCommand(runIdArg, options = {}) {
9214
8960
  totalFindings: redactionRuns.reduce((sum, run) => sum + run.findings, 0),
9215
8961
  runs: redactionRuns
9216
8962
  };
9217
- await mkdir(outputDir, { recursive: true });
9218
8963
  for (const runId of resolveResult.runIds) {
9219
8964
  const jsonl = redactedJsonlByRun.get(runId) ?? "";
9220
- await writeBundleFile(
9221
- outputDir,
8965
+ stageBundleFile(
9222
8966
  bundleRunAssetRelativePath(runId, ".jsonl"),
9223
8967
  jsonl,
9224
- files
8968
+ files,
8969
+ packaged
9225
8970
  );
9226
8971
  const html = htmlByRun.get(runId) ?? "";
9227
- await writeBundleFile(
9228
- outputDir,
8972
+ stageBundleFile(
9229
8973
  bundleRunAssetRelativePath(runId, ".html"),
9230
8974
  runReportWrap(html, runId),
9231
- files
8975
+ files,
8976
+ packaged
9232
8977
  );
9233
8978
  }
9234
8979
  const primaryRunId = resolveResult.runIds[0];
9235
8980
  const traceHtml = resolveResult.runIds.length === 1 ? runReportWrap(htmlByRun.get(primaryRunId) ?? "", primaryRunId) : renderBundleIndexHtml({ runIds: resolveResult.runIds, reports: htmlByRun });
9236
- await writeBundleFile(outputDir, "trace.jsonl", combinedJsonl, files);
9237
- await writeBundleFile(outputDir, "trace.html", traceHtml, files);
9238
- await writeBundleFile(
9239
- outputDir,
9240
- "check-results.json",
9241
- writeJson4(checks2),
9242
- files
9243
- );
9244
- await writeBundleFile(
9245
- outputDir,
8981
+ stageBundleFile("trace.jsonl", combinedJsonl, files, packaged);
8982
+ stageBundleFile("trace.html", traceHtml, files, packaged);
8983
+ stageBundleFile("check-results.json", writeJson4(checks2), files, packaged);
8984
+ stageBundleFile(
9246
8985
  "eval-results.json",
9247
8986
  writeJson4(buildPlaceholderArtifact()),
9248
- files
8987
+ files,
8988
+ packaged
9249
8989
  );
9250
- await writeBundleFile(
9251
- outputDir,
8990
+ stageBundleFile(
9252
8991
  "redaction-report.json",
9253
8992
  writeJson4(redactionReport),
9254
- files
8993
+ files,
8994
+ packaged
9255
8995
  );
9256
- await writeBundleFile(
9257
- outputDir,
8996
+ stageBundleFile(
9258
8997
  "performance-summary.json",
9259
8998
  writeJson4(buildPlaceholderArtifact()),
9260
- files
8999
+ files,
9000
+ packaged
9001
+ );
9002
+ const summaryPath = "summary.md";
9003
+ const metadataPath = "metadata.json";
9004
+ const aggregateSourceStatus = aggregateBundleSafeStatus(
9005
+ checkRuns.map((run) => run.sourceStatus ?? run.status)
9261
9006
  );
9007
+ const metadataFileList = [
9008
+ ...files,
9009
+ summaryPath,
9010
+ EVIDENCE_HTML_FILENAME,
9011
+ metadataPath,
9012
+ EVIDENCE_MANIFEST_FILENAME
9013
+ ].filter((name, index, all) => all.indexOf(name) === index).sort((a, b) => a.localeCompare(b));
9262
9014
  const metadata = buildBundleMetadata({
9263
9015
  agentInspectVersion: version,
9264
9016
  profile,
9265
9017
  resolve: resolveResult,
9266
9018
  checks: checks2,
9267
- files: [...files]
9019
+ files: metadataFileList
9268
9020
  });
9269
- await writeBundleFile(outputDir, "metadata.json", writeJson4(metadata), files);
9270
- await writeBundleFile(
9271
- outputDir,
9272
- "summary.md",
9273
- buildBundleSummaryMarkdown({ metadata, checks: checks2, redaction: redactionReport }),
9274
- files
9021
+ const summaryMd = buildBundleSummaryMarkdown({
9022
+ metadata,
9023
+ checks: checks2,
9024
+ redaction: redactionReport
9025
+ });
9026
+ const evidenceHtml = buildEvidenceHtmlShell({
9027
+ title: "AgentInspect evidence",
9028
+ runIds: resolveResult.runIds,
9029
+ assessmentStatus: checks2.aggregateStatus,
9030
+ sourceStatus: aggregateSourceStatus,
9031
+ redactionProfile: profile,
9032
+ verificationPolicy: profile,
9033
+ generatorName: "agent-inspect",
9034
+ generatorVersion: version,
9035
+ createdAt: metadata.createdAt,
9036
+ summaryText: summaryMd,
9037
+ checkSummary: {
9038
+ aggregateStatus: checks2.aggregateStatus,
9039
+ runs: checkRuns
9040
+ },
9041
+ viewBodies: {
9042
+ tree: buildEvidenceTreeViewHtml(artifactTrees),
9043
+ timeline: buildEvidenceTimelineViewHtml(artifactTrees),
9044
+ causal: buildEvidenceCausalFailureViewHtml(artifactTrees),
9045
+ "tools-llm": buildEvidenceToolsLlmViewHtml(artifactTrees),
9046
+ contracts: buildEvidenceContractsViewHtml({
9047
+ aggregateStatus: checks2.aggregateStatus,
9048
+ runs: checkRuns,
9049
+ findingSummaries
9050
+ }),
9051
+ outcomes: buildEvidenceOutcomesViewHtml(
9052
+ resolveResult.runIds.map((id) => ({
9053
+ runId: id,
9054
+ events: artifactEventsByRun.get(id) ?? []
9055
+ }))
9056
+ ),
9057
+ circuit: buildEvidenceCircuitViewHtml(),
9058
+ diff: resolveResult.runIds.length >= 2 ? buildEvidenceDiffViewHtml({
9059
+ leftRunId: resolveResult.runIds[0],
9060
+ rightRunId: resolveResult.runIds[1],
9061
+ leftEvents: artifactEventsByRun.get(resolveResult.runIds[0]) ?? [],
9062
+ rightEvents: artifactEventsByRun.get(resolveResult.runIds[1]) ?? []
9063
+ }) : buildEvidenceDiffViewHtml(),
9064
+ safety: buildEvidenceSafetyViewHtml({
9065
+ artifactStatus: checks2.aggregateStatus,
9066
+ sourceStatus: aggregateSourceStatus,
9067
+ redactionProfile: profile,
9068
+ verificationPolicy: profile,
9069
+ redaction: redactionReport,
9070
+ findingSummaries
9071
+ }),
9072
+ provenance: buildEvidenceProvenanceViewHtml({
9073
+ generatorName: "agent-inspect",
9074
+ generatorVersion: version,
9075
+ evidenceFormatVersion: EVIDENCE_FORMAT_VERSION,
9076
+ createdAt: metadata.createdAt,
9077
+ runIds: resolveResult.runIds,
9078
+ traceSchemaVersions: [...schemaVersions].sort((a, b) => a.localeCompare(b)),
9079
+ sourceHashes,
9080
+ packagedFiles: metadataFileList.filter((name) => name !== EVIDENCE_MANIFEST_FILENAME).map((name) => ({ path: name, role: inferEvidenceFileRole(name) }))
9081
+ })
9082
+ }
9083
+ });
9084
+ stageBundleFile(EVIDENCE_HTML_FILENAME, evidenceHtml, files, packaged);
9085
+ stageBundleFile(summaryPath, summaryMd, files, packaged);
9086
+ const metadataJson = writeJson4(metadata);
9087
+ packaged.set(metadataPath, metadataJson);
9088
+ if (!files.includes(metadataPath)) {
9089
+ files.push(metadataPath);
9090
+ }
9091
+ const evidenceFiles = [...packaged.entries()].map(
9092
+ ([relativePath, content]) => ({ path: relativePath, content })
9275
9093
  );
9276
- metadata.files = [...files].sort((a, b) => a.localeCompare(b));
9277
- await writeFile(path14.join(outputDir, "metadata.json"), writeJson4(metadata), "utf-8");
9094
+ const evidence = buildEvidenceManifest({
9095
+ generatorVersion: version,
9096
+ runIds: resolveResult.runIds,
9097
+ traceSchemaVersions: [...schemaVersions].sort((a, b) => a.localeCompare(b)),
9098
+ sourceHashes,
9099
+ redactionProfile: profile,
9100
+ verificationPolicy: profile,
9101
+ assessmentStatus: checks2.aggregateStatus,
9102
+ sourceStatus: aggregateSourceStatus,
9103
+ files: evidenceFiles,
9104
+ createdAt: metadata.createdAt
9105
+ });
9106
+ let evidenceJson = serializeEvidenceManifest(evidence);
9107
+ let outputPath = outputDir;
9108
+ if (format === "html") {
9109
+ const htmlContent = packaged.get(EVIDENCE_HTML_FILENAME) ?? evidenceHtml;
9110
+ const htmlEvidence = buildEvidenceManifest({
9111
+ generatorVersion: version,
9112
+ runIds: resolveResult.runIds,
9113
+ traceSchemaVersions: [...schemaVersions].sort((a, b) => a.localeCompare(b)),
9114
+ sourceHashes,
9115
+ redactionProfile: profile,
9116
+ verificationPolicy: profile,
9117
+ assessmentStatus: checks2.aggregateStatus,
9118
+ sourceStatus: aggregateSourceStatus,
9119
+ files: [{ path: EVIDENCE_HTML_FILENAME, content: htmlContent }],
9120
+ createdAt: metadata.createdAt
9121
+ });
9122
+ evidenceJson = serializeEvidenceManifest(htmlEvidence);
9123
+ let htmlPath = outputDir;
9124
+ let sidecarDir = outputDir;
9125
+ if (outputDir.toLowerCase().endsWith(".html")) {
9126
+ htmlPath = outputDir;
9127
+ sidecarDir = path15.dirname(outputDir);
9128
+ } else {
9129
+ await mkdir(outputDir, { recursive: true });
9130
+ htmlPath = path15.join(outputDir, EVIDENCE_HTML_FILENAME);
9131
+ sidecarDir = outputDir;
9132
+ }
9133
+ await mkdir(sidecarDir, { recursive: true });
9134
+ await writeFile(htmlPath, htmlContent, "utf-8");
9135
+ await writeFile(path15.join(sidecarDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
9136
+ outputPath = htmlPath;
9137
+ } else if (format === "zip") {
9138
+ const zipPath = outputDir.toLowerCase().endsWith(".zip") ? outputDir : `${outputDir}.zip`;
9139
+ const zipParent = path15.dirname(zipPath);
9140
+ await mkdir(zipParent, { recursive: true });
9141
+ const entries = [
9142
+ ...[...packaged.entries()].map(([relativePath, content]) => ({
9143
+ path: relativePath,
9144
+ content
9145
+ })),
9146
+ { path: EVIDENCE_MANIFEST_FILENAME, content: evidenceJson }
9147
+ ];
9148
+ const archive = buildZipArchive(entries);
9149
+ await writeFile(zipPath, archive);
9150
+ outputPath = zipPath;
9151
+ } else {
9152
+ await mkdir(outputDir, { recursive: true });
9153
+ for (const [relativePath, content] of packaged.entries()) {
9154
+ const outPath = assertBundlePathContained(outputDir, relativePath);
9155
+ await mkdir(path15.dirname(outPath), { recursive: true });
9156
+ await writeFile(outPath, content, "utf-8");
9157
+ }
9158
+ await writeFile(path15.join(outputDir, EVIDENCE_MANIFEST_FILENAME), evidenceJson, "utf-8");
9159
+ if (!files.includes(EVIDENCE_MANIFEST_FILENAME)) {
9160
+ files.push(EVIDENCE_MANIFEST_FILENAME);
9161
+ }
9162
+ outputPath = outputDir;
9163
+ }
9278
9164
  if (options.json) {
9279
9165
  console.log(
9280
9166
  writeJson4({
9281
9167
  ok: true,
9282
- outputDir,
9168
+ format,
9169
+ outputDir: outputPath,
9283
9170
  metadata,
9171
+ evidence: format === "html" ? JSON.parse(evidenceJson) : evidence,
9284
9172
  checks: checks2,
9285
9173
  redaction: redactionReport
9286
9174
  }).trimEnd()
9287
9175
  );
9288
9176
  return;
9289
9177
  }
9290
- console.log(`Bundle written to ${outputDir}`);
9178
+ console.log(`Bundle written to ${outputPath}`);
9179
+ console.log(`Format: ${format}`);
9291
9180
  console.log(`Safe status: ${metadata.safeStatus}`);
9292
9181
  console.log(`Runs: ${resolveResult.runIds.join(", ")}`);
9293
9182
  console.log(`Files: ${metadata.files.length}`);
@@ -9307,68 +9196,44 @@ ${body}
9307
9196
  </html>
9308
9197
  `;
9309
9198
  }
9310
- function validateReporterArtifactPath(options) {
9311
- const outputDir = path14.resolve(options.outputDir);
9312
- const diagnostics = [];
9313
- const rawPath = options.relativePath;
9314
- if (rawPath.length === 0) {
9315
- diagnostics.push({
9316
- code: "artifact_path_empty",
9317
- severity: "error",
9318
- message: "Reporter artifact path must not be empty."
9319
- });
9320
- return { ok: false, outputDir, diagnostics };
9321
- }
9322
- if (rawPath.includes("\0")) {
9323
- diagnostics.push({
9324
- code: "invalid_artifact_path",
9325
- severity: "error",
9326
- message: "Reporter artifact path must not contain null bytes.",
9327
- target: rawPath
9328
- });
9329
- return { ok: false, outputDir, diagnostics };
9330
- }
9331
- if (path14.isAbsolute(rawPath) || path14.win32.isAbsolute(rawPath)) {
9332
- diagnostics.push({
9333
- code: "artifact_path_absolute",
9334
- severity: "error",
9335
- message: "Reporter artifact path must be relative.",
9336
- target: rawPath
9337
- });
9338
- return { ok: false, outputDir, diagnostics };
9339
- }
9340
- const normalized = path14.posix.normalize(rawPath.replace(/\\/g, "/"));
9341
- const segments = normalized.split("/");
9342
- if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
9343
- diagnostics.push({
9344
- code: "artifact_path_escape",
9345
- severity: "error",
9346
- message: "Reporter artifact path must stay under the output directory.",
9347
- target: rawPath
9348
- });
9349
- return { ok: false, outputDir, diagnostics };
9199
+ function writeJson5(value) {
9200
+ return `${JSON.stringify(value, null, 2)}
9201
+ `;
9202
+ }
9203
+ async function bundleVerifyCommand(targetPath, options = {}) {
9204
+ const root = path15.resolve(targetPath.trim() || ".");
9205
+ const result = await verifyEvidenceDirectory(root, {
9206
+ unexpectedFiles: options.unexpected ?? "fail"
9207
+ });
9208
+ if (options.json) {
9209
+ console.log(
9210
+ writeJson5({
9211
+ ok: result.ok,
9212
+ status: result.status,
9213
+ root: result.root,
9214
+ checkedFiles: result.checkedFiles,
9215
+ issues: result.issues,
9216
+ assessment: result.manifest?.assessment,
9217
+ generator: result.manifest?.generator
9218
+ }).trimEnd()
9219
+ );
9220
+ } else if (result.ok) {
9221
+ console.log(`Evidence verify: pass (${result.checkedFiles} file(s) checked)`);
9222
+ console.log(`Root: ${result.root}`);
9223
+ if (result.manifest?.assessment?.status) {
9224
+ console.log(`Assessment: ${result.manifest.assessment.status}`);
9225
+ }
9226
+ } else {
9227
+ console.error(`Evidence verify: fail (${result.issues.length} issue(s))`);
9228
+ console.error(`Root: ${result.root}`);
9229
+ for (const issue of result.issues) {
9230
+ console.error(`- [${issue.severity}] ${issue.code}: ${issue.message}`);
9231
+ }
9350
9232
  }
9351
- const absolutePath = path14.resolve(outputDir, normalized);
9352
- const relFromOutput = path14.relative(outputDir, absolutePath);
9353
- if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path14.isAbsolute(relFromOutput)) {
9354
- diagnostics.push({
9355
- code: "artifact_path_escape",
9356
- severity: "error",
9357
- message: "Reporter artifact path resolved outside the output directory.",
9358
- target: rawPath
9359
- });
9360
- return { ok: false, outputDir, diagnostics };
9233
+ if (!result.ok) {
9234
+ process.exitCode = 1;
9361
9235
  }
9362
- return {
9363
- ok: true,
9364
- outputDir,
9365
- relativePath: normalized,
9366
- absolutePath,
9367
- diagnostics
9368
- };
9369
9236
  }
9370
-
9371
- // packages/cli/src/ci-summary.ts
9372
9237
  var NOTE2 = "Generated locally by AgentInspect from reporter artifact manifests. Trace contents are not embedded.";
9373
9238
  var MAX_TEXT = 180;
9374
9239
  var FRAMEWORKS = /* @__PURE__ */ new Set(["vitest", "jest", "manual"]);
@@ -9384,7 +9249,7 @@ function stable7(value) {
9384
9249
  Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable7(record[key])])
9385
9250
  );
9386
9251
  }
9387
- function writeJson5(value) {
9252
+ function writeJson6(value) {
9388
9253
  return `${JSON.stringify(stable7(value), null, 2)}
9389
9254
  `;
9390
9255
  }
@@ -9496,23 +9361,23 @@ function readManifestDocument(value) {
9496
9361
  };
9497
9362
  }
9498
9363
  function cwdRelative(filePath) {
9499
- const relative = path14.relative(process.cwd(), path14.resolve(filePath)).replace(/\\/g, "/");
9500
- if (relative === "" || relative.startsWith("../") || path14.isAbsolute(relative)) {
9501
- return path14.basename(filePath);
9364
+ const relative = path15.relative(process.cwd(), path15.resolve(filePath)).replace(/\\/g, "/");
9365
+ if (relative === "" || relative.startsWith("../") || path15.isAbsolute(relative)) {
9366
+ return path15.basename(filePath);
9502
9367
  }
9503
9368
  return relative;
9504
9369
  }
9505
9370
  async function readReporterManifest(filePath) {
9506
- const absolute = path14.resolve(filePath);
9371
+ const absolute = path15.resolve(filePath);
9507
9372
  const raw = await readFile(absolute, "utf-8");
9508
9373
  const document = readManifestDocument(JSON.parse(raw));
9509
9374
  const manifest = document.manifest;
9510
9375
  const results = manifest.results.map((result) => ({
9511
9376
  testId: safeText(result.testId),
9512
9377
  name: safeText(result.name),
9513
- ...result.file === void 0 ? {} : { file: safeText(path14.basename(result.file)) },
9378
+ ...result.file === void 0 ? {} : { file: safeText(path15.basename(result.file)) },
9514
9379
  status: result.status,
9515
- ...result.tracePath === void 0 ? {} : { tracePath: safeText(path14.basename(result.tracePath)) },
9380
+ ...result.tracePath === void 0 ? {} : { tracePath: safeText(path15.basename(result.tracePath)) },
9516
9381
  artifacts: result.artifacts,
9517
9382
  diagnostics: result.diagnostics
9518
9383
  }));
@@ -9651,20 +9516,20 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
9651
9516
  return;
9652
9517
  }
9653
9518
  const markdown = renderMarkdown2(result);
9654
- const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path14.resolve(options.output.trim()) : void 0;
9519
+ const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path15.resolve(options.output.trim()) : void 0;
9655
9520
  if (outputPath !== void 0) {
9656
- await mkdir(path14.dirname(outputPath), { recursive: true });
9521
+ await mkdir(path15.dirname(outputPath), { recursive: true });
9657
9522
  await writeFile(outputPath, markdown, "utf-8");
9658
9523
  }
9659
9524
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
9660
9525
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
9661
- const summaryPath = path14.resolve(summaryTarget);
9662
- await mkdir(path14.dirname(summaryPath), { recursive: true });
9526
+ const summaryPath = path15.resolve(summaryTarget);
9527
+ await mkdir(path15.dirname(summaryPath), { recursive: true });
9663
9528
  await appendFile(summaryPath, `
9664
9529
  ${markdown}`, "utf-8");
9665
9530
  }
9666
9531
  if (options.json === true) {
9667
- console.log(writeJson5(result).trimEnd());
9532
+ console.log(writeJson6(result).trimEnd());
9668
9533
  } else if (outputPath !== void 0) {
9669
9534
  console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
9670
9535
  console.log(`Status: ${result.status}`);
@@ -9807,7 +9672,7 @@ jobs:
9807
9672
  }
9808
9673
  async function planInit(options = {}) {
9809
9674
  const framework = normalizeFramework(options.framework);
9810
- const cwd = path14.resolve(options.cwd ?? process.cwd());
9675
+ const cwd = path15.resolve(options.cwd ?? process.cwd());
9811
9676
  const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
9812
9677
  const candidates = [
9813
9678
  { rel: CONFIG_FILE, content: configTemplate(framework) },
@@ -9822,7 +9687,7 @@ async function planInit(options = {}) {
9822
9687
  }
9823
9688
  const files = [];
9824
9689
  for (const candidate of candidates) {
9825
- const abs = path14.join(cwd, candidate.rel);
9690
+ const abs = path15.join(cwd, candidate.rel);
9826
9691
  try {
9827
9692
  await access(abs);
9828
9693
  files.push({
@@ -9843,12 +9708,12 @@ async function writePlannedFiles(plan, cwd, options) {
9843
9708
  if (entry.action === "skip") {
9844
9709
  continue;
9845
9710
  }
9846
- const abs = path14.join(cwd, entry.path);
9711
+ const abs = path15.join(cwd, entry.path);
9847
9712
  if (options.dryRun) {
9848
9713
  written.push(entry.path);
9849
9714
  continue;
9850
9715
  }
9851
- await mkdir(path14.dirname(abs), { recursive: true });
9716
+ await mkdir(path15.dirname(abs), { recursive: true });
9852
9717
  const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
9853
9718
  await writeFile(abs, content, "utf-8");
9854
9719
  written.push(entry.path);
@@ -9856,7 +9721,7 @@ async function writePlannedFiles(plan, cwd, options) {
9856
9721
  return written;
9857
9722
  }
9858
9723
  async function initCommand(options = {}) {
9859
- const cwd = path14.resolve(options.cwd ?? process.cwd());
9724
+ const cwd = path15.resolve(options.cwd ?? process.cwd());
9860
9725
  try {
9861
9726
  const plan = await planInit({ ...options, cwd });
9862
9727
  const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
@@ -9947,7 +9812,7 @@ function envCheck(name, optional = true) {
9947
9812
  };
9948
9813
  }
9949
9814
  async function traceDirWritable(traceDir) {
9950
- const resolved = path14.resolve(traceDir);
9815
+ const resolved = path15.resolve(traceDir);
9951
9816
  try {
9952
9817
  await mkdir(resolved, { recursive: true });
9953
9818
  await access(resolved, constants.W_OK);
@@ -9968,10 +9833,10 @@ async function traceDirWritable(traceDir) {
9968
9833
  }
9969
9834
  }
9970
9835
  function readPackageVersionNearEntry(entryPath, packageName) {
9971
- let dir = path14.dirname(path14.resolve(entryPath));
9972
- const { root } = path14.parse(dir);
9836
+ let dir = path15.dirname(path15.resolve(entryPath));
9837
+ const { root } = path15.parse(dir);
9973
9838
  while (true) {
9974
- const candidate = path14.join(dir, "package.json");
9839
+ const candidate = path15.join(dir, "package.json");
9975
9840
  if (existsSync(candidate)) {
9976
9841
  try {
9977
9842
  const pkg = JSON.parse(readFileSync(candidate, "utf8"));
@@ -9982,14 +9847,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
9982
9847
  }
9983
9848
  }
9984
9849
  if (dir === root) break;
9985
- const parent = path14.dirname(dir);
9850
+ const parent = path15.dirname(dir);
9986
9851
  if (parent === dir) break;
9987
9852
  dir = parent;
9988
9853
  }
9989
9854
  return void 0;
9990
9855
  }
9991
9856
  function resolveInstalledPackage(cwd, name) {
9992
- const require2 = createRequire(path14.join(cwd, "package.json"));
9857
+ const require2 = createRequire(path15.join(cwd, "package.json"));
9993
9858
  try {
9994
9859
  const entry = require2.resolve(name);
9995
9860
  let version2;
@@ -10087,7 +9952,7 @@ function versionMismatchCheck(cwd) {
10087
9952
  };
10088
9953
  }
10089
9954
  async function runDoctorChecks(options = {}) {
10090
- const cwd = path14.resolve(options.cwd ?? process2.cwd());
9955
+ const cwd = path15.resolve(options.cwd ?? process2.cwd());
10091
9956
  const traceDir = options.traceDir?.trim() || process2.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
10092
9957
  const checks2 = [
10093
9958
  nodeVersionCheck(),
@@ -10327,7 +10192,7 @@ function parsePluginManifest(input3) {
10327
10192
  };
10328
10193
  }
10329
10194
  async function readPluginManifestFile(packageDir) {
10330
- const manifestPath = path14.join(packageDir, PLUGIN_MANIFEST_FILENAME);
10195
+ const manifestPath = path15.join(packageDir, PLUGIN_MANIFEST_FILENAME);
10331
10196
  try {
10332
10197
  const raw = await readFile(manifestPath, "utf8");
10333
10198
  const parsed = parsePluginManifest(JSON.parse(raw));
@@ -10353,7 +10218,7 @@ async function indexIsStale(snapshot, traceDir) {
10353
10218
  const files = await td.list();
10354
10219
  for (const file of files) {
10355
10220
  const stats = await td.getFileStats(file);
10356
- if (stats.mtimeMs > builtMs) return true;
10221
+ if (Math.floor(stats.mtimeMs) > builtMs) return true;
10357
10222
  }
10358
10223
  return false;
10359
10224
  }
@@ -10401,7 +10266,7 @@ function createTraceDirectoryIndexer() {
10401
10266
  // packages/cli/src/plugins.ts
10402
10267
  async function readPackageName(packageDir) {
10403
10268
  try {
10404
- const raw = await readFile(path14.join(packageDir, "package.json"), "utf8");
10269
+ const raw = await readFile(path15.join(packageDir, "package.json"), "utf8");
10405
10270
  const parsed = JSON.parse(raw);
10406
10271
  return typeof parsed.name === "string" ? parsed.name : void 0;
10407
10272
  } catch {
@@ -10409,7 +10274,7 @@ async function readPackageName(packageDir) {
10409
10274
  }
10410
10275
  }
10411
10276
  async function discoverPlugins(cwd = process.cwd()) {
10412
- const nodeModules = path14.join(cwd, "node_modules");
10277
+ const nodeModules = path15.join(cwd, "node_modules");
10413
10278
  const found = [];
10414
10279
  let entries;
10415
10280
  try {
@@ -10420,7 +10285,7 @@ async function discoverPlugins(cwd = process.cwd()) {
10420
10285
  for (const entry of entries.sort()) {
10421
10286
  if (entry.startsWith("@")) continue;
10422
10287
  if (!isPluginPackageName(entry)) continue;
10423
- const packageDir = path14.join(nodeModules, entry);
10288
+ const packageDir = path15.join(nodeModules, entry);
10424
10289
  const manifestRead = await readPluginManifestFile(packageDir);
10425
10290
  found.push({
10426
10291
  packageName: entry,
@@ -10433,7 +10298,7 @@ async function discoverPlugins(cwd = process.cwd()) {
10433
10298
  return found;
10434
10299
  }
10435
10300
  async function validatePluginPackage(packageRef, cwd = process.cwd()) {
10436
- const packageDir = path14.isAbsolute(packageRef) ? packageRef : path14.join(cwd, "node_modules", packageRef);
10301
+ const packageDir = path15.isAbsolute(packageRef) ? packageRef : path15.join(cwd, "node_modules", packageRef);
10437
10302
  const packageName = await readPackageName(packageDir) ?? packageRef;
10438
10303
  const errors = [];
10439
10304
  const warnings = [];
@@ -10509,7 +10374,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
10509
10374
  }
10510
10375
  var INDEX_FILENAME = ".agent-inspect-index.json";
10511
10376
  function traceIndexPath(traceDir) {
10512
- return path14.join(traceDir, INDEX_FILENAME);
10377
+ return path15.join(traceDir, INDEX_FILENAME);
10513
10378
  }
10514
10379
  function parseMaxEntries(raw) {
10515
10380
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -10622,7 +10487,7 @@ function isModuleNotFound4(e) {
10622
10487
  }
10623
10488
  async function loadIndexSqlite() {
10624
10489
  try {
10625
- return await import('./src-C4EUHTER.mjs');
10490
+ return await import('./src-YFN3Q3GP.mjs');
10626
10491
  } catch (e) {
10627
10492
  if (isModuleNotFound4(e)) {
10628
10493
  console.error(
@@ -10652,7 +10517,7 @@ async function newestTraceMtimeMs2(traceDir) {
10652
10517
  for (const file of files) {
10653
10518
  if (!file.endsWith(".jsonl")) continue;
10654
10519
  try {
10655
- const s = await stat(path14.join(traceDir, file));
10520
+ const s = await stat(path15.join(traceDir, file));
10656
10521
  if (s.mtimeMs > newest) newest = s.mtimeMs;
10657
10522
  } catch {
10658
10523
  }
@@ -10904,11 +10769,11 @@ function printJson5(value) {
10904
10769
  console.log(JSON.stringify(value, null, 2));
10905
10770
  }
10906
10771
  function resolveCwd(options) {
10907
- return path14.resolve(options.cwd ?? process.cwd());
10772
+ return path15.resolve(options.cwd ?? process.cwd());
10908
10773
  }
10909
10774
  async function suiteInitCommand(options = {}) {
10910
10775
  const cwd = resolveCwd(options);
10911
- const configPath = path14.join(cwd, DEFAULT_CONFIG_FILENAME);
10776
+ const configPath = path15.join(cwd, DEFAULT_CONFIG_FILENAME);
10912
10777
  const template = options.template?.trim();
10913
10778
  const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
10914
10779
  if (options.dryRun) {
@@ -11027,13 +10892,13 @@ async function suiteListCommand(options = {}) {
11027
10892
  }
11028
10893
  async function writeSuiteArtifact(result, configOutputDir, options) {
11029
10894
  const cwd = resolveCwd(options);
11030
- const outputDir = path14.resolve(
10895
+ const outputDir = path15.resolve(
11031
10896
  cwd,
11032
10897
  options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
11033
10898
  );
11034
10899
  await mkdir(outputDir, { recursive: true });
11035
10900
  const stamp = result.startedAt.replace(/[:.]/g, "-");
11036
- const filePath = path14.join(outputDir, `${result.suiteName}-${stamp}.json`);
10901
+ const filePath = path15.join(outputDir, `${result.suiteName}-${stamp}.json`);
11037
10902
  await writeFile(filePath, `${JSON.stringify(result, null, 2)}
11038
10903
  `, "utf-8");
11039
10904
  return filePath;
@@ -11091,7 +10956,7 @@ async function loadSuiteResultFromInput(options) {
11091
10956
  if (options.input === void 0 || options.input.trim() === "") {
11092
10957
  throw new Error("Pass --input <suite-run.json> from a prior suite run.");
11093
10958
  }
11094
- const inputPath = path14.resolve(cwd, options.input.trim());
10959
+ const inputPath = path15.resolve(cwd, options.input.trim());
11095
10960
  const raw = await readFile(inputPath, "utf-8");
11096
10961
  return JSON.parse(raw);
11097
10962
  }
@@ -11125,9 +10990,9 @@ function normalizeMetrics(raw) {
11125
10990
  }
11126
10991
  async function writeArtifacts(result, outputDir) {
11127
10992
  await mkdir(outputDir, { recursive: true });
11128
- const jsonPath = path14.join(outputDir, "cohort-results.json");
11129
- const markdownPath = path14.join(outputDir, "cohort-summary.md");
11130
- const htmlPath = path14.join(outputDir, "cohort-report.html");
10993
+ const jsonPath = path15.join(outputDir, "cohort-results.json");
10994
+ const markdownPath = path15.join(outputDir, "cohort-summary.md");
10995
+ const htmlPath = path15.join(outputDir, "cohort-report.html");
11131
10996
  await writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
11132
10997
  `, "utf-8");
11133
10998
  await writeFile(
@@ -11155,7 +11020,7 @@ async function cohortCommand(options = {}) {
11155
11020
  const format = options.format ?? (options.json ? "json" : "markdown");
11156
11021
  let artifacts;
11157
11022
  if (options.output !== void 0 && options.output.trim() !== "") {
11158
- artifacts = await writeArtifacts(result, path14.resolve(options.output.trim()));
11023
+ artifacts = await writeArtifacts(result, path15.resolve(options.output.trim()));
11159
11024
  }
11160
11025
  if (options.json || format === "json") {
11161
11026
  console.log(
@@ -11225,11 +11090,11 @@ function parseDuration2(value) {
11225
11090
  async function writeArtifacts2(result, outputDir) {
11226
11091
  await mkdir(outputDir, { recursive: true });
11227
11092
  const paths = {
11228
- jsonPath: path14.join(outputDir, "gate-results.json"),
11229
- markdownPath: path14.join(outputDir, "gate-summary.md"),
11230
- htmlPath: path14.join(outputDir, "gate-report.html"),
11231
- junitPath: path14.join(outputDir, "junit.xml"),
11232
- githubPath: path14.join(outputDir, "github-step-summary.md")
11093
+ jsonPath: path15.join(outputDir, "gate-results.json"),
11094
+ markdownPath: path15.join(outputDir, "gate-summary.md"),
11095
+ htmlPath: path15.join(outputDir, "gate-report.html"),
11096
+ junitPath: path15.join(outputDir, "junit.xml"),
11097
+ githubPath: path15.join(outputDir, "github-step-summary.md")
11233
11098
  };
11234
11099
  await writeFile(
11235
11100
  paths.jsonPath,
@@ -11297,7 +11162,7 @@ async function gateCommand(options = {}) {
11297
11162
  const result = await runGate(runs, gateOptions);
11298
11163
  let artifacts;
11299
11164
  if (options.output !== void 0 && options.output.trim() !== "") {
11300
- artifacts = await writeArtifacts2(result, path14.resolve(options.output.trim()));
11165
+ artifacts = await writeArtifacts2(result, path15.resolve(options.output.trim()));
11301
11166
  }
11302
11167
  if (options.json || format === "json") {
11303
11168
  console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
@@ -11552,19 +11417,26 @@ function createCliProgram() {
11552
11417
  "openinference-json",
11553
11418
  "otlp-json"
11554
11419
  ])
11555
- ).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--baseline <trace-path-or-run-id>", "optional baseline trace for diff artifacts").option("--baseline-run <run-id>", "select a run from the baseline trace").option("--github-summary <path>", "append a safe summary to this file, e.g. GITHUB_STEP_SUMMARY").option("--json", "print deterministic JSON manifest").action((target, opts) => {
11420
+ ).option("--run <run-id>", "select a run when the trace contains multiple runs").option("--baseline <trace-path-or-run-id>", "optional baseline trace for diff artifacts").option("--baseline-run <run-id>", "select a run from the baseline trace").option("--github-summary <path>", "append a safe summary to this file, e.g. GITHUB_STEP_SUMMARY").option("--evidence", "write Evidence v2 package on failure (default behavior when omitted)").option("--no-evidence", "skip Evidence v2 package").option("--always-evidence", "write Evidence v2 package even when checks pass").option("--json", "print deterministic JSON manifest").action((target, opts) => {
11556
11421
  runCommand(() => artifactsCommand(target, opts));
11557
11422
  });
11558
- program.command("bundle").description("Create a share-safe offline trace bundle (local folder)").argument("[run-id]", "run id to bundle (optional with --session or --since)").option("--dir <path>", "trace directory for run/session lookup").option("--session <session-id>", "bundle all runs in a session").option("--since <duration>", "bundle runs with activity since a duration (e.g. 24h)").addOption(
11423
+ const bundleCmd = program.command("bundle").description("Create or verify share-safe offline evidence bundles").argument("[run-id]", "run id to bundle (optional with --session or --since)").option("--dir <path>", "trace directory for run/session lookup").option("--session <session-id>", "bundle all runs in a session").option("--since <duration>", "bundle runs with activity since a duration (e.g. 24h)").addOption(
11559
11424
  new Option("--profile <profile>", "redaction profile for exported copies").choices(["local", "share", "strict"]).default("share")
11560
11425
  ).addOption(
11561
11426
  new Option(
11562
11427
  "--redaction-profile <profile>",
11563
11428
  "alias for --profile (canonical spelling)"
11564
11429
  ).choices(["local", "share", "strict"])
11565
- ).option("--out <path>", "output directory (folder; .zip suffix is stripped)").option("--output <path>", "alias for --out (canonical spelling)").option("--allow-unsafe", "write bundle even when verify-safe reports UNSAFE").option("--json", "print deterministic JSON manifest").action((runId, opts) => {
11430
+ ).option("--out <path>", "output directory, .html path, or .zip path").option("--output <path>", "alias for --out (canonical spelling)").addOption(
11431
+ new Option("--format <format>", "bundle output format").choices(["directory", "html", "zip"]).default("directory")
11432
+ ).option("--allow-unsafe", "write bundle even when verify-safe reports UNSAFE").option("--json", "print deterministic JSON manifest").action((runId, opts) => {
11566
11433
  runCommand(() => bundleCommand(runId, opts));
11567
11434
  });
11435
+ bundleCmd.command("verify").description("Verify Evidence v2 integrity (manifest, hashes, presence)").argument("<path>", "evidence/bundle directory containing evidence.json").addOption(
11436
+ new Option("--unexpected <mode>", "policy for files not listed in the manifest").choices(["fail", "warn", "ignore"]).default("fail")
11437
+ ).option("--json", "print deterministic JSON verify result").action((targetPath, opts) => {
11438
+ runCommand(() => bundleVerifyCommand(targetPath, opts));
11439
+ });
11568
11440
  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) => {
11569
11441
  runCommand(() => ciSummaryCommand(manifest, opts));
11570
11442
  });
@@ -11838,9 +11710,9 @@ function isPrimaryModule() {
11838
11710
  if (!entry) return false;
11839
11711
  const selfPath = fileURLToPath(import.meta.url);
11840
11712
  try {
11841
- return realpathSync(path14.resolve(entry)) === realpathSync(path14.resolve(selfPath));
11713
+ return realpathSync(path15.resolve(entry)) === realpathSync(path15.resolve(selfPath));
11842
11714
  } catch {
11843
- return path14.resolve(entry) === path14.resolve(selfPath);
11715
+ return path15.resolve(entry) === path15.resolve(selfPath);
11844
11716
  }
11845
11717
  }
11846
11718
  if (isPrimaryModule()) {