agent-inspect 6.9.0 → 6.11.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 (35) hide show
  1. package/CHANGELOG.md +12 -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 +22 -2
  6. package/package.json +1 -1
  7. package/packages/cli/dist/{chunk-WQ5XMFH2.mjs → chunk-XTAA733P.mjs} +1756 -149
  8. package/packages/cli/dist/chunk-XTAA733P.mjs.map +1 -0
  9. package/packages/cli/dist/index.cjs +10634 -8880
  10. package/packages/cli/dist/index.cjs.map +1 -1
  11. package/packages/cli/dist/index.mjs +729 -708
  12. package/packages/cli/dist/index.mjs.map +1 -1
  13. package/packages/cli/dist/{src-C4EUHTER.mjs → src-G7PM24W2.mjs} +3 -3
  14. package/packages/cli/dist/{src-C4EUHTER.mjs.map → src-G7PM24W2.mjs.map} +1 -1
  15. package/packages/core/dist/advanced.cjs +1846 -12
  16. package/packages/core/dist/advanced.cjs.map +1 -1
  17. package/packages/core/dist/advanced.d.cts +373 -4
  18. package/packages/core/dist/advanced.d.ts +373 -4
  19. package/packages/core/dist/advanced.mjs +1307 -12
  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/{chunk-KDDU2R5P.mjs → chunk-LFWZEO2L.mjs} +2 -2
  24. package/packages/core/dist/{chunk-KDDU2R5P.mjs.map → chunk-LFWZEO2L.mjs.map} +1 -1
  25. package/packages/core/dist/diff.mjs +3 -477
  26. package/packages/core/dist/diff.mjs.map +1 -1
  27. package/packages/core/dist/exporters.cjs.map +1 -1
  28. package/packages/core/dist/exporters.mjs +1 -1
  29. package/packages/core/dist/reporters.cjs +25 -0
  30. package/packages/core/dist/reporters.cjs.map +1 -1
  31. package/packages/core/dist/reporters.d.cts +16 -2
  32. package/packages/core/dist/reporters.d.ts +16 -2
  33. package/packages/core/dist/reporters.mjs +24 -1
  34. package/packages/core/dist/reporters.mjs.map +1 -1
  35. 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-XTAA733P.mjs';
3
3
  import { realpathSync, constants as constants$1, existsSync, readFileSync } from 'fs';
4
- import path14 from 'path';
4
+ import path16 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.11.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 ? path16.resolve(resolvedOutput) : void 0;
2975
2975
  if (outPath !== void 0) {
2976
- await mkdir(path14.dirname(outPath), { recursive: true });
2976
+ await mkdir(path16.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: path16.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-G7PM24W2.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 ? path16.resolve(resolvedOutput) : void 0;
4261
3799
  if (outPath !== void 0) {
4262
- await mkdir(path14.dirname(outPath), { recursive: true });
3800
+ await mkdir(path16.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(path27) {
3927
+ const normalized = path27.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(path27, key) {
4577
4115
  if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
4578
- return path25 ? `${path25}.${key}` : key;
4116
+ return path27 ? `${path27}.${key}` : key;
4579
4117
  }
4580
- return `${path25 || "$"}[${JSON.stringify(key)}]`;
4118
+ return `${path27 || "$"}[${JSON.stringify(key)}]`;
4581
4119
  }
4582
- function indexPath(path25, index) {
4583
- return `${path25 || "$"}[${index}]`;
4120
+ function indexPath(path27, index) {
4121
+ return `${path27 || "$"}[${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(path27, detector, action, matchKind, severity = "warning", preview) {
4124
+ return preview === void 0 ? { path: path27, detector, action, severity, matchKind } : { path: path27, 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, path27, 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(path27, "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(path27, `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: path27, 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
+ path27,
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(path27, 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(path27 === "$" ? "" : path27, 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 = path16.relative(parent, child);
4710
+ return relative === "" || !relative.startsWith("..") && !path16.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 = path16.resolve(inputPath);
4715
+ const outputAbs = path16.resolve(output2.trim());
4716
+ const inputDir = path16.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 = path16.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(path16.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, path27, 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: path27, 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: path27, 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: `${path27}.${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 = path16.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 = path16.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 path27 = 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}${path27 ? ` (${path27})` : ""}`);
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 = path16.join(path16.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 = path16.resolve(cwd);
6173
+ const workspaceDir = path16.join(projectRoot, WORKSPACE_DIR_NAME);
6636
6174
  return {
6637
6175
  projectRoot,
6638
6176
  workspaceDir,
6639
- manifestPath: path14.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
6177
+ manifestPath: path16.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 = path16.resolve(workspaceDir);
6182
+ const resolved = path16.resolve(base, relative);
6183
+ const rel = path16.relative(base, resolved);
6184
+ if (rel === "" || rel === "." || !rel.startsWith("..") && !path16.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() || path16.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(path16.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(path16.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 = path16.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: path16.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: path16.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
+ path16.join(location.workspaceDir, manifestRead.manifest.bundlesDir),
6488
+ path16.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: path16.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: path16.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: path16.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, path27) {
7069
+ return [{ runId: run.runId, ...path27 !== void 0 ? { path: path27 } : {} }];
7532
7070
  }
7533
- function evidenceForEvent(event, path25) {
7071
+ function evidenceForEvent(event, path27) {
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
+ ...path27 !== void 0 ? { path: path27 } : {}
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, path27) {
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, path27) : 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 path27 = finding.evidence[0]?.path;
7617
+ lines.push(`- ${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}`);
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 = path16.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 = path16.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 path27 = finding.evidence[0]?.path;
7811
+ console.log(`- ${finding.ruleId}: ${finding.message}${path27 ? ` (${path27})` : ""}`);
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 path27 = 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=${path27}; 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 path27 = 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}${path27 ? ` (${path27})` : ""}${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 = path16.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 (path16.isAbsolute(rawPath) || path16.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 = path16.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 = path16.resolve(outputDir, normalized);
8271
+ const relFromOutput = path16.relative(outputDir, absolutePath);
8272
+ if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path16.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 : path16.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 path27 = finding.evidence[0]?.path ?? "(run)";
8388
+ lines.push(`- ${finding.ruleId}: ${finding.message} (${path27})`);
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 = path16.join(outputDir, relativePath);
8467
+ await mkdir(path16.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() !== "" ? path16.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(path16.dirname(path16.resolve(summaryTarget)), { recursive: true });
8625
+ await appendFile(path16.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: path16.resolve(summaryTarget) } : {},
8947
8645
  note: NOTE
8948
8646
  };
8949
- await writeFile(path14.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
8647
+ await writeFile(path16.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 = path16.relative(location.workspaceDir, normalized);
8706
+ if (!rel.startsWith("..") && !path16.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
+ path16.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 = path16.dirname(outputDir);
9128
+ } else {
9129
+ await mkdir(outputDir, { recursive: true });
9130
+ htmlPath = path16.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(path16.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 = path16.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(path16.dirname(outPath), { recursive: true });
9156
+ await writeFile(outPath, content, "utf-8");
9157
+ }
9158
+ await writeFile(path16.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,179 @@ ${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 };
9199
+ function writeJson5(value) {
9200
+ return `${JSON.stringify(value, null, 2)}
9201
+ `;
9202
+ }
9203
+ async function bundleVerifyCommand(targetPath, options = {}) {
9204
+ const root = path16.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
+ }
9321
9232
  }
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 };
9233
+ if (!result.ok) {
9234
+ process.exitCode = 1;
9330
9235
  }
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 };
9236
+ }
9237
+ var CLIENTS = [
9238
+ "cursor",
9239
+ "claude-code",
9240
+ "codex",
9241
+ "gemini"
9242
+ ];
9243
+ function isMcpConfigureClient(value) {
9244
+ return CLIENTS.includes(value);
9245
+ }
9246
+ function buildServerBlock(traceDir) {
9247
+ return {
9248
+ command: "npx",
9249
+ args: ["-y", "@agent-inspect/mcp-server", "--dir", traceDir],
9250
+ env: {
9251
+ AGENT_INSPECT_TRACE_DIR: traceDir,
9252
+ AGENT_INSPECT_MCP_REDACTION_PROFILE: "share"
9253
+ }
9254
+ };
9255
+ }
9256
+ function buildMcpClientConfig(client, traceDir) {
9257
+ const server = buildServerBlock(traceDir);
9258
+ switch (client) {
9259
+ case "cursor":
9260
+ return {
9261
+ mcpServers: {
9262
+ "agent-inspect": server
9263
+ }
9264
+ };
9265
+ case "claude-code":
9266
+ return {
9267
+ mcpServers: {
9268
+ "agent-inspect": server
9269
+ }
9270
+ };
9271
+ case "codex":
9272
+ return {
9273
+ mcp_servers: {
9274
+ "agent-inspect": {
9275
+ command: server.command,
9276
+ args: server.args,
9277
+ env: server.env
9278
+ }
9279
+ }
9280
+ };
9281
+ case "gemini":
9282
+ return {
9283
+ mcpServers: {
9284
+ "agent-inspect": server
9285
+ }
9286
+ };
9287
+ default: {
9288
+ const _exhaustive = client;
9289
+ return _exhaustive;
9290
+ }
9339
9291
  }
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 };
9292
+ }
9293
+ function resolveTargetPath(client, projectLocal) {
9294
+ if (projectLocal) {
9295
+ switch (client) {
9296
+ case "cursor":
9297
+ return path16.join(".cursor", "mcp.json");
9298
+ case "claude-code":
9299
+ return path16.join(".mcp.json");
9300
+ case "codex":
9301
+ return path16.join(".codex", "config.toml.json");
9302
+ case "gemini":
9303
+ return path16.join(".gemini", "settings.json");
9304
+ }
9350
9305
  }
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 };
9306
+ switch (client) {
9307
+ case "cursor":
9308
+ return path16.join("~", ".cursor", "mcp.json");
9309
+ case "claude-code":
9310
+ return path16.join("~", ".claude.json");
9311
+ case "codex":
9312
+ return path16.join("~", ".codex", "config.toml");
9313
+ case "gemini":
9314
+ return path16.join("~", ".gemini", "settings.json");
9361
9315
  }
9362
- return {
9363
- ok: true,
9364
- outputDir,
9365
- relativePath: normalized,
9366
- absolutePath,
9367
- diagnostics
9316
+ }
9317
+ async function mcpConfigureCommand(options) {
9318
+ if (!isMcpConfigureClient(options.client)) {
9319
+ throw new Error(
9320
+ `Unsupported client "${String(options.client)}". Use: ${CLIENTS.join(", ")}`
9321
+ );
9322
+ }
9323
+ const traceDir = options.dir?.trim() || ".agent-inspect";
9324
+ const projectLocal = Boolean(options.projectLocal);
9325
+ const write = Boolean(options.write);
9326
+ const yes = Boolean(options.yes);
9327
+ const dryRun = !(write && yes && projectLocal);
9328
+ const config = buildMcpClientConfig(options.client, traceDir);
9329
+ const targetPath = resolveTargetPath(options.client, projectLocal);
9330
+ const notes = [
9331
+ "Read-only MCP server; no network upload; share redaction by default.",
9332
+ "Dry-run by default. Pass --project-local --write --yes to write a project file.",
9333
+ "User-level paths are never auto-written by this command.",
9334
+ "Remove the agent-inspect server block to uninstall."
9335
+ ];
9336
+ let wrote = false;
9337
+ if (!dryRun && projectLocal) {
9338
+ const abs = path16.resolve(targetPath);
9339
+ await mkdir(path16.dirname(abs), { recursive: true });
9340
+ await writeFile(abs, `${JSON.stringify(config, null, 2)}
9341
+ `, "utf8");
9342
+ wrote = true;
9343
+ }
9344
+ const result = {
9345
+ client: options.client,
9346
+ dryRun,
9347
+ wrote,
9348
+ targetPath,
9349
+ config,
9350
+ notes
9368
9351
  };
9352
+ if (options.json) {
9353
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
9354
+ `);
9355
+ } else {
9356
+ process.stdout.write(
9357
+ [
9358
+ `Client: ${result.client}`,
9359
+ `Mode: ${result.dryRun ? "dry-run" : "write"}`,
9360
+ `Target: ${result.targetPath}`,
9361
+ `Wrote: ${result.wrote}`,
9362
+ "",
9363
+ JSON.stringify(result.config, null, 2),
9364
+ "",
9365
+ ...result.notes.map((note) => `- ${note}`),
9366
+ ""
9367
+ ].join("\n")
9368
+ );
9369
+ }
9370
+ return result;
9369
9371
  }
9370
-
9371
- // packages/cli/src/ci-summary.ts
9372
9372
  var NOTE2 = "Generated locally by AgentInspect from reporter artifact manifests. Trace contents are not embedded.";
9373
9373
  var MAX_TEXT = 180;
9374
9374
  var FRAMEWORKS = /* @__PURE__ */ new Set(["vitest", "jest", "manual"]);
@@ -9384,7 +9384,7 @@ function stable7(value) {
9384
9384
  Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable7(record[key])])
9385
9385
  );
9386
9386
  }
9387
- function writeJson5(value) {
9387
+ function writeJson6(value) {
9388
9388
  return `${JSON.stringify(stable7(value), null, 2)}
9389
9389
  `;
9390
9390
  }
@@ -9496,23 +9496,23 @@ function readManifestDocument(value) {
9496
9496
  };
9497
9497
  }
9498
9498
  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);
9499
+ const relative = path16.relative(process.cwd(), path16.resolve(filePath)).replace(/\\/g, "/");
9500
+ if (relative === "" || relative.startsWith("../") || path16.isAbsolute(relative)) {
9501
+ return path16.basename(filePath);
9502
9502
  }
9503
9503
  return relative;
9504
9504
  }
9505
9505
  async function readReporterManifest(filePath) {
9506
- const absolute = path14.resolve(filePath);
9506
+ const absolute = path16.resolve(filePath);
9507
9507
  const raw = await readFile(absolute, "utf-8");
9508
9508
  const document = readManifestDocument(JSON.parse(raw));
9509
9509
  const manifest = document.manifest;
9510
9510
  const results = manifest.results.map((result) => ({
9511
9511
  testId: safeText(result.testId),
9512
9512
  name: safeText(result.name),
9513
- ...result.file === void 0 ? {} : { file: safeText(path14.basename(result.file)) },
9513
+ ...result.file === void 0 ? {} : { file: safeText(path16.basename(result.file)) },
9514
9514
  status: result.status,
9515
- ...result.tracePath === void 0 ? {} : { tracePath: safeText(path14.basename(result.tracePath)) },
9515
+ ...result.tracePath === void 0 ? {} : { tracePath: safeText(path16.basename(result.tracePath)) },
9516
9516
  artifacts: result.artifacts,
9517
9517
  diagnostics: result.diagnostics
9518
9518
  }));
@@ -9651,20 +9651,20 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
9651
9651
  return;
9652
9652
  }
9653
9653
  const markdown = renderMarkdown2(result);
9654
- const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path14.resolve(options.output.trim()) : void 0;
9654
+ const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path16.resolve(options.output.trim()) : void 0;
9655
9655
  if (outputPath !== void 0) {
9656
- await mkdir(path14.dirname(outputPath), { recursive: true });
9656
+ await mkdir(path16.dirname(outputPath), { recursive: true });
9657
9657
  await writeFile(outputPath, markdown, "utf-8");
9658
9658
  }
9659
9659
  const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
9660
9660
  if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
9661
- const summaryPath = path14.resolve(summaryTarget);
9662
- await mkdir(path14.dirname(summaryPath), { recursive: true });
9661
+ const summaryPath = path16.resolve(summaryTarget);
9662
+ await mkdir(path16.dirname(summaryPath), { recursive: true });
9663
9663
  await appendFile(summaryPath, `
9664
9664
  ${markdown}`, "utf-8");
9665
9665
  }
9666
9666
  if (options.json === true) {
9667
- console.log(writeJson5(result).trimEnd());
9667
+ console.log(writeJson6(result).trimEnd());
9668
9668
  } else if (outputPath !== void 0) {
9669
9669
  console.log(`Wrote AgentInspect CI summary to ${outputPath}`);
9670
9670
  console.log(`Status: ${result.status}`);
@@ -9807,7 +9807,7 @@ jobs:
9807
9807
  }
9808
9808
  async function planInit(options = {}) {
9809
9809
  const framework = normalizeFramework(options.framework);
9810
- const cwd = path14.resolve(options.cwd ?? process.cwd());
9810
+ const cwd = path16.resolve(options.cwd ?? process.cwd());
9811
9811
  const demoPath = framework === "custom" ? "examples/agent-inspect-demo.mjs" : `examples/agent-inspect-${framework}-demo.mjs`;
9812
9812
  const candidates = [
9813
9813
  { rel: CONFIG_FILE, content: configTemplate(framework) },
@@ -9822,7 +9822,7 @@ async function planInit(options = {}) {
9822
9822
  }
9823
9823
  const files = [];
9824
9824
  for (const candidate of candidates) {
9825
- const abs = path14.join(cwd, candidate.rel);
9825
+ const abs = path16.join(cwd, candidate.rel);
9826
9826
  try {
9827
9827
  await access(abs);
9828
9828
  files.push({
@@ -9843,12 +9843,12 @@ async function writePlannedFiles(plan, cwd, options) {
9843
9843
  if (entry.action === "skip") {
9844
9844
  continue;
9845
9845
  }
9846
- const abs = path14.join(cwd, entry.path);
9846
+ const abs = path16.join(cwd, entry.path);
9847
9847
  if (options.dryRun) {
9848
9848
  written.push(entry.path);
9849
9849
  continue;
9850
9850
  }
9851
- await mkdir(path14.dirname(abs), { recursive: true });
9851
+ await mkdir(path16.dirname(abs), { recursive: true });
9852
9852
  const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
9853
9853
  await writeFile(abs, content, "utf-8");
9854
9854
  written.push(entry.path);
@@ -9856,7 +9856,7 @@ async function writePlannedFiles(plan, cwd, options) {
9856
9856
  return written;
9857
9857
  }
9858
9858
  async function initCommand(options = {}) {
9859
- const cwd = path14.resolve(options.cwd ?? process.cwd());
9859
+ const cwd = path16.resolve(options.cwd ?? process.cwd());
9860
9860
  try {
9861
9861
  const plan = await planInit({ ...options, cwd });
9862
9862
  const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
@@ -9947,7 +9947,7 @@ function envCheck(name, optional = true) {
9947
9947
  };
9948
9948
  }
9949
9949
  async function traceDirWritable(traceDir) {
9950
- const resolved = path14.resolve(traceDir);
9950
+ const resolved = path16.resolve(traceDir);
9951
9951
  try {
9952
9952
  await mkdir(resolved, { recursive: true });
9953
9953
  await access(resolved, constants.W_OK);
@@ -9968,10 +9968,10 @@ async function traceDirWritable(traceDir) {
9968
9968
  }
9969
9969
  }
9970
9970
  function readPackageVersionNearEntry(entryPath, packageName) {
9971
- let dir = path14.dirname(path14.resolve(entryPath));
9972
- const { root } = path14.parse(dir);
9971
+ let dir = path16.dirname(path16.resolve(entryPath));
9972
+ const { root } = path16.parse(dir);
9973
9973
  while (true) {
9974
- const candidate = path14.join(dir, "package.json");
9974
+ const candidate = path16.join(dir, "package.json");
9975
9975
  if (existsSync(candidate)) {
9976
9976
  try {
9977
9977
  const pkg = JSON.parse(readFileSync(candidate, "utf8"));
@@ -9982,14 +9982,14 @@ function readPackageVersionNearEntry(entryPath, packageName) {
9982
9982
  }
9983
9983
  }
9984
9984
  if (dir === root) break;
9985
- const parent = path14.dirname(dir);
9985
+ const parent = path16.dirname(dir);
9986
9986
  if (parent === dir) break;
9987
9987
  dir = parent;
9988
9988
  }
9989
9989
  return void 0;
9990
9990
  }
9991
9991
  function resolveInstalledPackage(cwd, name) {
9992
- const require2 = createRequire(path14.join(cwd, "package.json"));
9992
+ const require2 = createRequire(path16.join(cwd, "package.json"));
9993
9993
  try {
9994
9994
  const entry = require2.resolve(name);
9995
9995
  let version2;
@@ -10087,7 +10087,7 @@ function versionMismatchCheck(cwd) {
10087
10087
  };
10088
10088
  }
10089
10089
  async function runDoctorChecks(options = {}) {
10090
- const cwd = path14.resolve(options.cwd ?? process2.cwd());
10090
+ const cwd = path16.resolve(options.cwd ?? process2.cwd());
10091
10091
  const traceDir = options.traceDir?.trim() || process2.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
10092
10092
  const checks2 = [
10093
10093
  nodeVersionCheck(),
@@ -10327,7 +10327,7 @@ function parsePluginManifest(input3) {
10327
10327
  };
10328
10328
  }
10329
10329
  async function readPluginManifestFile(packageDir) {
10330
- const manifestPath = path14.join(packageDir, PLUGIN_MANIFEST_FILENAME);
10330
+ const manifestPath = path16.join(packageDir, PLUGIN_MANIFEST_FILENAME);
10331
10331
  try {
10332
10332
  const raw = await readFile(manifestPath, "utf8");
10333
10333
  const parsed = parsePluginManifest(JSON.parse(raw));
@@ -10353,7 +10353,7 @@ async function indexIsStale(snapshot, traceDir) {
10353
10353
  const files = await td.list();
10354
10354
  for (const file of files) {
10355
10355
  const stats = await td.getFileStats(file);
10356
- if (stats.mtimeMs > builtMs) return true;
10356
+ if (Math.floor(stats.mtimeMs) > builtMs) return true;
10357
10357
  }
10358
10358
  return false;
10359
10359
  }
@@ -10401,7 +10401,7 @@ function createTraceDirectoryIndexer() {
10401
10401
  // packages/cli/src/plugins.ts
10402
10402
  async function readPackageName(packageDir) {
10403
10403
  try {
10404
- const raw = await readFile(path14.join(packageDir, "package.json"), "utf8");
10404
+ const raw = await readFile(path16.join(packageDir, "package.json"), "utf8");
10405
10405
  const parsed = JSON.parse(raw);
10406
10406
  return typeof parsed.name === "string" ? parsed.name : void 0;
10407
10407
  } catch {
@@ -10409,7 +10409,7 @@ async function readPackageName(packageDir) {
10409
10409
  }
10410
10410
  }
10411
10411
  async function discoverPlugins(cwd = process.cwd()) {
10412
- const nodeModules = path14.join(cwd, "node_modules");
10412
+ const nodeModules = path16.join(cwd, "node_modules");
10413
10413
  const found = [];
10414
10414
  let entries;
10415
10415
  try {
@@ -10420,7 +10420,7 @@ async function discoverPlugins(cwd = process.cwd()) {
10420
10420
  for (const entry of entries.sort()) {
10421
10421
  if (entry.startsWith("@")) continue;
10422
10422
  if (!isPluginPackageName(entry)) continue;
10423
- const packageDir = path14.join(nodeModules, entry);
10423
+ const packageDir = path16.join(nodeModules, entry);
10424
10424
  const manifestRead = await readPluginManifestFile(packageDir);
10425
10425
  found.push({
10426
10426
  packageName: entry,
@@ -10433,7 +10433,7 @@ async function discoverPlugins(cwd = process.cwd()) {
10433
10433
  return found;
10434
10434
  }
10435
10435
  async function validatePluginPackage(packageRef, cwd = process.cwd()) {
10436
- const packageDir = path14.isAbsolute(packageRef) ? packageRef : path14.join(cwd, "node_modules", packageRef);
10436
+ const packageDir = path16.isAbsolute(packageRef) ? packageRef : path16.join(cwd, "node_modules", packageRef);
10437
10437
  const packageName = await readPackageName(packageDir) ?? packageRef;
10438
10438
  const errors = [];
10439
10439
  const warnings = [];
@@ -10509,7 +10509,7 @@ async function pluginsValidateCommand(packageRef, cwd) {
10509
10509
  }
10510
10510
  var INDEX_FILENAME = ".agent-inspect-index.json";
10511
10511
  function traceIndexPath(traceDir) {
10512
- return path14.join(traceDir, INDEX_FILENAME);
10512
+ return path16.join(traceDir, INDEX_FILENAME);
10513
10513
  }
10514
10514
  function parseMaxEntries(raw) {
10515
10515
  if (raw === void 0 || raw.trim() === "") return void 0;
@@ -10622,7 +10622,7 @@ function isModuleNotFound4(e) {
10622
10622
  }
10623
10623
  async function loadIndexSqlite() {
10624
10624
  try {
10625
- return await import('./src-C4EUHTER.mjs');
10625
+ return await import('./src-G7PM24W2.mjs');
10626
10626
  } catch (e) {
10627
10627
  if (isModuleNotFound4(e)) {
10628
10628
  console.error(
@@ -10652,7 +10652,7 @@ async function newestTraceMtimeMs2(traceDir) {
10652
10652
  for (const file of files) {
10653
10653
  if (!file.endsWith(".jsonl")) continue;
10654
10654
  try {
10655
- const s = await stat(path14.join(traceDir, file));
10655
+ const s = await stat(path16.join(traceDir, file));
10656
10656
  if (s.mtimeMs > newest) newest = s.mtimeMs;
10657
10657
  } catch {
10658
10658
  }
@@ -10904,11 +10904,11 @@ function printJson5(value) {
10904
10904
  console.log(JSON.stringify(value, null, 2));
10905
10905
  }
10906
10906
  function resolveCwd(options) {
10907
- return path14.resolve(options.cwd ?? process.cwd());
10907
+ return path16.resolve(options.cwd ?? process.cwd());
10908
10908
  }
10909
10909
  async function suiteInitCommand(options = {}) {
10910
10910
  const cwd = resolveCwd(options);
10911
- const configPath = path14.join(cwd, DEFAULT_CONFIG_FILENAME);
10911
+ const configPath = path16.join(cwd, DEFAULT_CONFIG_FILENAME);
10912
10912
  const template = options.template?.trim();
10913
10913
  const suiteConfig = template !== void 0 && template !== "" ? resolveSuiteTemplate(template) : defaultSuiteConfigTemplate();
10914
10914
  if (options.dryRun) {
@@ -11027,13 +11027,13 @@ async function suiteListCommand(options = {}) {
11027
11027
  }
11028
11028
  async function writeSuiteArtifact(result, configOutputDir, options) {
11029
11029
  const cwd = resolveCwd(options);
11030
- const outputDir = path14.resolve(
11030
+ const outputDir = path16.resolve(
11031
11031
  cwd,
11032
11032
  options.output ?? configOutputDir ?? DEFAULT_SUITE_ARTIFACTS_DIR
11033
11033
  );
11034
11034
  await mkdir(outputDir, { recursive: true });
11035
11035
  const stamp = result.startedAt.replace(/[:.]/g, "-");
11036
- const filePath = path14.join(outputDir, `${result.suiteName}-${stamp}.json`);
11036
+ const filePath = path16.join(outputDir, `${result.suiteName}-${stamp}.json`);
11037
11037
  await writeFile(filePath, `${JSON.stringify(result, null, 2)}
11038
11038
  `, "utf-8");
11039
11039
  return filePath;
@@ -11091,7 +11091,7 @@ async function loadSuiteResultFromInput(options) {
11091
11091
  if (options.input === void 0 || options.input.trim() === "") {
11092
11092
  throw new Error("Pass --input <suite-run.json> from a prior suite run.");
11093
11093
  }
11094
- const inputPath = path14.resolve(cwd, options.input.trim());
11094
+ const inputPath = path16.resolve(cwd, options.input.trim());
11095
11095
  const raw = await readFile(inputPath, "utf-8");
11096
11096
  return JSON.parse(raw);
11097
11097
  }
@@ -11125,9 +11125,9 @@ function normalizeMetrics(raw) {
11125
11125
  }
11126
11126
  async function writeArtifacts(result, outputDir) {
11127
11127
  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");
11128
+ const jsonPath = path16.join(outputDir, "cohort-results.json");
11129
+ const markdownPath = path16.join(outputDir, "cohort-summary.md");
11130
+ const htmlPath = path16.join(outputDir, "cohort-report.html");
11131
11131
  await writeFile(jsonPath, `${renderCohortReport(result, { format: "json" })}
11132
11132
  `, "utf-8");
11133
11133
  await writeFile(
@@ -11155,7 +11155,7 @@ async function cohortCommand(options = {}) {
11155
11155
  const format = options.format ?? (options.json ? "json" : "markdown");
11156
11156
  let artifacts;
11157
11157
  if (options.output !== void 0 && options.output.trim() !== "") {
11158
- artifacts = await writeArtifacts(result, path14.resolve(options.output.trim()));
11158
+ artifacts = await writeArtifacts(result, path16.resolve(options.output.trim()));
11159
11159
  }
11160
11160
  if (options.json || format === "json") {
11161
11161
  console.log(
@@ -11225,11 +11225,11 @@ function parseDuration2(value) {
11225
11225
  async function writeArtifacts2(result, outputDir) {
11226
11226
  await mkdir(outputDir, { recursive: true });
11227
11227
  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")
11228
+ jsonPath: path16.join(outputDir, "gate-results.json"),
11229
+ markdownPath: path16.join(outputDir, "gate-summary.md"),
11230
+ htmlPath: path16.join(outputDir, "gate-report.html"),
11231
+ junitPath: path16.join(outputDir, "junit.xml"),
11232
+ githubPath: path16.join(outputDir, "github-step-summary.md")
11233
11233
  };
11234
11234
  await writeFile(
11235
11235
  paths.jsonPath,
@@ -11297,7 +11297,7 @@ async function gateCommand(options = {}) {
11297
11297
  const result = await runGate(runs, gateOptions);
11298
11298
  let artifacts;
11299
11299
  if (options.output !== void 0 && options.output.trim() !== "") {
11300
- artifacts = await writeArtifacts2(result, path14.resolve(options.output.trim()));
11300
+ artifacts = await writeArtifacts2(result, path16.resolve(options.output.trim()));
11301
11301
  }
11302
11302
  if (options.json || format === "json") {
11303
11303
  console.log(JSON.stringify({ ...result, artifacts: artifacts ?? null }, null, 2));
@@ -11552,19 +11552,26 @@ function createCliProgram() {
11552
11552
  "openinference-json",
11553
11553
  "otlp-json"
11554
11554
  ])
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) => {
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("--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
11556
  runCommand(() => artifactsCommand(target, opts));
11557
11557
  });
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(
11558
+ 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
11559
  new Option("--profile <profile>", "redaction profile for exported copies").choices(["local", "share", "strict"]).default("share")
11560
11560
  ).addOption(
11561
11561
  new Option(
11562
11562
  "--redaction-profile <profile>",
11563
11563
  "alias for --profile (canonical spelling)"
11564
11564
  ).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) => {
11565
+ ).option("--out <path>", "output directory, .html path, or .zip path").option("--output <path>", "alias for --out (canonical spelling)").addOption(
11566
+ new Option("--format <format>", "bundle output format").choices(["directory", "html", "zip"]).default("directory")
11567
+ ).option("--allow-unsafe", "write bundle even when verify-safe reports UNSAFE").option("--json", "print deterministic JSON manifest").action((runId, opts) => {
11566
11568
  runCommand(() => bundleCommand(runId, opts));
11567
11569
  });
11570
+ bundleCmd.command("verify").description("Verify Evidence v2 integrity (manifest, hashes, presence)").argument("<path>", "evidence/bundle directory containing evidence.json").addOption(
11571
+ new Option("--unexpected <mode>", "policy for files not listed in the manifest").choices(["fail", "warn", "ignore"]).default("fail")
11572
+ ).option("--json", "print deterministic JSON verify result").action((targetPath, opts) => {
11573
+ runCommand(() => bundleVerifyCommand(targetPath, opts));
11574
+ });
11568
11575
  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
11576
  runCommand(() => ciSummaryCommand(manifest, opts));
11570
11577
  });
@@ -11822,6 +11829,20 @@ function createCliProgram() {
11822
11829
  ).option("--format <format>", "markdown, json, or html", "markdown").option("-o, --output <dir>", "write cohort-results.json, cohort-summary.md, cohort-report.html").option("--json", "print deterministic JSON result").action((opts) => {
11823
11830
  runCommand(() => cohortCommand(opts));
11824
11831
  });
11832
+ const mcpCmd = program.command("mcp").description("Configure local coding-agent MCP clients (read-only; dry-run by default)");
11833
+ mcpCmd.command("configure").description("Print or write MCP client config for Cursor/Claude/Codex/Gemini").requiredOption(
11834
+ "--client <name>",
11835
+ "cursor | claude-code | codex | gemini"
11836
+ ).option("--dir <path>", "trace directory for the MCP server", ".agent-inspect").option("--project-local", "target a project-local config path").option("--write", "write config (requires --project-local --yes)").option("--yes", "confirm write").option("--json", "print deterministic JSON result").action((opts) => {
11837
+ runCommand(async () => {
11838
+ if (!isMcpConfigureClient(opts.client)) {
11839
+ throw new Error(
11840
+ `Unsupported --client "${opts.client}". Use: cursor, claude-code, codex, gemini`
11841
+ );
11842
+ }
11843
+ await mcpConfigureCommand({ ...opts, client: opts.client });
11844
+ });
11845
+ });
11825
11846
  program.command("gate").description("Run deterministic CI quality gates over traces or suites (v5.2+)").option("--dir <path>", "trace directory for threshold checks").option("--suite <path>", "suite config path").option("--max-error-rate <percent>", "maximum allowed error rate percentage").option("--max-p95-duration <ms>", "maximum allowed p95 run duration in ms").option("--forbid-tool <name>", "forbidden tool name (repeatable or comma-separated)").option(
11826
11847
  "--require-observation <name>",
11827
11848
  "required passed observation (repeatable or comma-separated)"
@@ -11838,9 +11859,9 @@ function isPrimaryModule() {
11838
11859
  if (!entry) return false;
11839
11860
  const selfPath = fileURLToPath(import.meta.url);
11840
11861
  try {
11841
- return realpathSync(path14.resolve(entry)) === realpathSync(path14.resolve(selfPath));
11862
+ return realpathSync(path16.resolve(entry)) === realpathSync(path16.resolve(selfPath));
11842
11863
  } catch {
11843
- return path14.resolve(entry) === path14.resolve(selfPath);
11864
+ return path16.resolve(entry) === path16.resolve(selfPath);
11844
11865
  }
11845
11866
  }
11846
11867
  if (isPrimaryModule()) {