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,7 +1,7 @@
1
1
  import { readdir, stat, readFile, access } from 'fs/promises';
2
2
  import os from 'os';
3
3
  import path5 from 'path';
4
- import crypto2, { webcrypto } from 'crypto';
4
+ import crypto2, { createHash, webcrypto } from 'crypto';
5
5
  import process2 from 'process';
6
6
  import tty from 'tty';
7
7
  import { AsyncLocalStorage } from 'async_hooks';
@@ -3443,12 +3443,12 @@ function buildCriticalPath(runs, handoffs) {
3443
3443
  handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
3444
3444
  );
3445
3445
  const ordered = [...runs].sort(compareRuns);
3446
- const path12 = [];
3446
+ const path14 = [];
3447
3447
  const visited = /* @__PURE__ */ new Set();
3448
3448
  const pushRun = (run, confidence, source) => {
3449
3449
  if (visited.has(run.runId)) return;
3450
3450
  visited.add(run.runId);
3451
- path12.push({
3451
+ path14.push({
3452
3452
  runId: run.runId,
3453
3453
  name: run.name,
3454
3454
  startedAt: run.startedAt,
@@ -3473,7 +3473,7 @@ function buildCriticalPath(runs, handoffs) {
3473
3473
  const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
3474
3474
  pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
3475
3475
  }
3476
- return path12;
3476
+ return path14;
3477
3477
  }
3478
3478
  function metaRunIdMatches(run, token, runById) {
3479
3479
  const meta = extractSessionWorkflowMetadata(run.metadata);
@@ -3847,13 +3847,13 @@ function assertBundlePathContained(outputDir, relativePath) {
3847
3847
  }
3848
3848
  return resolved;
3849
3849
  }
3850
- function normalizeBundleOutputPath(out) {
3850
+ function normalizeBundleOutputPath(out, options) {
3851
3851
  const trimmed = out.trim();
3852
3852
  if (trimmed === "") {
3853
3853
  throw new Error("--out requires a non-empty path.");
3854
3854
  }
3855
3855
  const resolved = path5.resolve(trimmed);
3856
- if (resolved.toLowerCase().endsWith(".zip")) {
3856
+ if (options?.preserveZipExtension !== true && resolved.toLowerCase().endsWith(".zip")) {
3857
3857
  return resolved.slice(0, -4);
3858
3858
  }
3859
3859
  return resolved;
@@ -3864,6 +3864,1721 @@ function defaultBundleOutputPath(runIds) {
3864
3864
  return path5.resolve(`agent-inspect-bundle-${label}-${stamp}`);
3865
3865
  }
3866
3866
 
3867
+ // packages/core/src/evidence/types.ts
3868
+ var EVIDENCE_FORMAT_VERSION = "1.0";
3869
+ var EVIDENCE_ASSESSMENT_NOTE = "Best-effort local safety verification only; not a compliance certification.";
3870
+ var EVIDENCE_MANIFEST_FILENAME = "evidence.json";
3871
+ var SHA256_RE = /^[a-f0-9]{64}$/i;
3872
+ function sha256Hex(data) {
3873
+ const hash = createHash("sha256");
3874
+ if (typeof data === "string") {
3875
+ hash.update(data, "utf8");
3876
+ } else {
3877
+ hash.update(data);
3878
+ }
3879
+ return hash.digest("hex");
3880
+ }
3881
+ function isSha256Hex(value) {
3882
+ return SHA256_RE.test(value);
3883
+ }
3884
+ function sha256Equals(expected, actual) {
3885
+ if (!isSha256Hex(expected) || !isSha256Hex(actual)) {
3886
+ return false;
3887
+ }
3888
+ const a = expected.toLowerCase();
3889
+ const b = actual.toLowerCase();
3890
+ if (a.length !== b.length) return false;
3891
+ let mismatch = 0;
3892
+ for (let i = 0; i < a.length; i += 1) {
3893
+ mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
3894
+ }
3895
+ return mismatch === 0;
3896
+ }
3897
+ function assertEvidenceRelativePath(relativePath) {
3898
+ if (typeof relativePath !== "string" || relativePath.trim() === "") {
3899
+ throw new Error("Evidence file path must be a non-empty relative path.");
3900
+ }
3901
+ const trimmed = relativePath.trim().replaceAll("\\", "/");
3902
+ if (path5.isAbsolute(trimmed) || trimmed.startsWith("/")) {
3903
+ throw new Error(`Evidence file path must be relative: ${relativePath}`);
3904
+ }
3905
+ const parts = trimmed.split("/").filter((part) => part !== "");
3906
+ if (parts.length === 0) {
3907
+ throw new Error(`Evidence file path must be relative: ${relativePath}`);
3908
+ }
3909
+ for (const part of parts) {
3910
+ if (part === "." || part === "..") {
3911
+ throw new Error(`Evidence file path must not contain "." or "..": ${relativePath}`);
3912
+ }
3913
+ }
3914
+ return parts.join("/");
3915
+ }
3916
+
3917
+ // packages/core/src/evidence/manifest.ts
3918
+ function stable(value) {
3919
+ if (Array.isArray(value)) return value.map(stable);
3920
+ if (value === null || typeof value !== "object") return value;
3921
+ const record = value;
3922
+ return Object.fromEntries(
3923
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable(record[key])])
3924
+ );
3925
+ }
3926
+ function serializeEvidenceManifest(manifest) {
3927
+ return `${JSON.stringify(stable(manifest), null, 2)}
3928
+ `;
3929
+ }
3930
+ function inferEvidenceFileRole(relativePath) {
3931
+ const normalized = assertEvidenceRelativePath(relativePath);
3932
+ const base = normalized.includes("/") ? normalized.slice(normalized.lastIndexOf("/") + 1) : normalized;
3933
+ if (base === "evidence.html" || base === "trace.html" || base.endsWith(".html")) {
3934
+ return "report";
3935
+ }
3936
+ if (base === "trace.jsonl" || base.endsWith(".jsonl")) {
3937
+ return "redacted-trace";
3938
+ }
3939
+ if (base === "check-results.json") {
3940
+ return "checks";
3941
+ }
3942
+ if (base === "redaction-report.json") {
3943
+ return "redaction-report";
3944
+ }
3945
+ if (base === "summary.md") {
3946
+ return "summary";
3947
+ }
3948
+ return "other";
3949
+ }
3950
+ function buildEvidenceFileEntries(files) {
3951
+ const byPath = /* @__PURE__ */ new Map();
3952
+ for (const file of files) {
3953
+ const relativePath = assertEvidenceRelativePath(file.path);
3954
+ if (relativePath === EVIDENCE_MANIFEST_FILENAME) {
3955
+ throw new Error(
3956
+ `Do not include ${EVIDENCE_MANIFEST_FILENAME} in packaged file hashes (self-hash is undefined).`
3957
+ );
3958
+ }
3959
+ if (byPath.has(relativePath)) {
3960
+ throw new Error(`Duplicate evidence file path: ${relativePath}`);
3961
+ }
3962
+ byPath.set(relativePath, {
3963
+ path: relativePath,
3964
+ sha256: sha256Hex(file.content),
3965
+ role: file.role ?? inferEvidenceFileRole(relativePath)
3966
+ });
3967
+ }
3968
+ return [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
3969
+ }
3970
+ function buildEvidenceManifest(parts) {
3971
+ const runIds = [...parts.runIds];
3972
+ if (runIds.length === 0) {
3973
+ throw new Error("Evidence manifest requires at least one run id.");
3974
+ }
3975
+ for (const item of parts.sourceHashes) {
3976
+ if (!runIds.includes(item.runId)) {
3977
+ throw new Error(`sourceHashes runId "${item.runId}" is not listed in source.runIds.`);
3978
+ }
3979
+ if (item.algorithm !== "sha256") {
3980
+ throw new Error(`Unsupported source hash algorithm: ${item.algorithm}`);
3981
+ }
3982
+ }
3983
+ const assessment = {
3984
+ status: parts.assessmentStatus,
3985
+ note: parts.note ?? EVIDENCE_ASSESSMENT_NOTE
3986
+ };
3987
+ if (parts.sourceStatus !== void 0) {
3988
+ assessment.sourceStatus = parts.sourceStatus;
3989
+ }
3990
+ return {
3991
+ evidenceFormatVersion: EVIDENCE_FORMAT_VERSION,
3992
+ generator: {
3993
+ name: parts.generatorName ?? "agent-inspect",
3994
+ version: parts.generatorVersion
3995
+ },
3996
+ createdAt: parts.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
3997
+ source: {
3998
+ runIds,
3999
+ traceSchemaVersions: [...parts.traceSchemaVersions].sort((a, b) => a.localeCompare(b)),
4000
+ sourceHashes: [...parts.sourceHashes].sort((a, b) => a.runId.localeCompare(b.runId))
4001
+ },
4002
+ policy: {
4003
+ redactionProfile: parts.redactionProfile,
4004
+ verificationPolicy: parts.verificationPolicy ?? parts.redactionProfile
4005
+ },
4006
+ assessment,
4007
+ files: buildEvidenceFileEntries(parts.files)
4008
+ };
4009
+ }
4010
+ function validateEvidenceManifest(value) {
4011
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
4012
+ throw new Error("Evidence manifest must be a JSON object.");
4013
+ }
4014
+ const record = value;
4015
+ if (record.evidenceFormatVersion !== EVIDENCE_FORMAT_VERSION) {
4016
+ throw new Error(
4017
+ `Unsupported evidenceFormatVersion: ${String(record.evidenceFormatVersion)}`
4018
+ );
4019
+ }
4020
+ const generator = record.generator;
4021
+ if (generator === null || typeof generator !== "object" || Array.isArray(generator) || typeof generator.name !== "string" || typeof generator.version !== "string") {
4022
+ throw new Error("Evidence manifest requires generator.name and generator.version.");
4023
+ }
4024
+ const source = record.source;
4025
+ if (source === null || typeof source !== "object" || Array.isArray(source)) {
4026
+ throw new Error("Evidence manifest requires source.");
4027
+ }
4028
+ const sourceRecord = source;
4029
+ if (!Array.isArray(sourceRecord.runIds) || sourceRecord.runIds.length === 0) {
4030
+ throw new Error("Evidence manifest source.runIds must be a non-empty array.");
4031
+ }
4032
+ if (!Array.isArray(sourceRecord.traceSchemaVersions)) {
4033
+ throw new Error("Evidence manifest source.traceSchemaVersions must be an array.");
4034
+ }
4035
+ if (!Array.isArray(sourceRecord.sourceHashes)) {
4036
+ throw new Error("Evidence manifest source.sourceHashes must be an array.");
4037
+ }
4038
+ const policy = record.policy;
4039
+ if (policy === null || typeof policy !== "object" || Array.isArray(policy)) {
4040
+ throw new Error("Evidence manifest requires policy.");
4041
+ }
4042
+ const assessment = record.assessment;
4043
+ if (assessment === null || typeof assessment !== "object" || Array.isArray(assessment) || typeof assessment.status !== "string") {
4044
+ throw new Error("Evidence manifest requires assessment.status.");
4045
+ }
4046
+ if (!Array.isArray(record.files) || record.files.length === 0) {
4047
+ throw new Error("Evidence manifest files must be a non-empty array.");
4048
+ }
4049
+ for (const file of record.files) {
4050
+ if (file === null || typeof file !== "object" || Array.isArray(file)) {
4051
+ throw new Error("Evidence manifest file entries must be objects.");
4052
+ }
4053
+ const entry = file;
4054
+ if (typeof entry.path !== "string") {
4055
+ throw new Error("Evidence file entry requires path.");
4056
+ }
4057
+ assertEvidenceRelativePath(entry.path);
4058
+ if (typeof entry.sha256 !== "string" || !/^[a-f0-9]{64}$/i.test(entry.sha256)) {
4059
+ throw new Error(`Evidence file entry requires sha256 hex for ${entry.path}.`);
4060
+ }
4061
+ }
4062
+ return value;
4063
+ }
4064
+ function parseEvidenceManifestJson(text) {
4065
+ let parsed;
4066
+ try {
4067
+ parsed = JSON.parse(text);
4068
+ } catch (error) {
4069
+ const message = error instanceof Error ? error.message : String(error);
4070
+ throw new Error(`Evidence manifest is not valid JSON: ${message}`);
4071
+ }
4072
+ return validateEvidenceManifest(parsed);
4073
+ }
4074
+ function collectTraceSchemaVersions(jsonl) {
4075
+ const versions = /* @__PURE__ */ new Set();
4076
+ for (const line of jsonl.split(/\r?\n/)) {
4077
+ const trimmed = line.trim();
4078
+ if (trimmed === "") continue;
4079
+ try {
4080
+ const row = JSON.parse(trimmed);
4081
+ if (typeof row.schemaVersion === "string" && row.schemaVersion.trim() !== "") {
4082
+ versions.add(row.schemaVersion.trim());
4083
+ }
4084
+ } catch {
4085
+ }
4086
+ }
4087
+ return [...versions].sort((a, b) => a.localeCompare(b));
4088
+ }
4089
+
4090
+ // packages/core/src/exporters/helpers.ts
4091
+ var REDACT_SUBSTRINGS = [
4092
+ "authorization",
4093
+ "cookie",
4094
+ "token",
4095
+ "apikey",
4096
+ "password",
4097
+ "secret",
4098
+ "email"
4099
+ ];
4100
+ function shouldRedactKey(key) {
4101
+ const k = key.toLowerCase();
4102
+ for (const s of REDACT_SUBSTRINGS) {
4103
+ if (k.includes(s)) return true;
4104
+ }
4105
+ return false;
4106
+ }
4107
+ function safeString(value, maxLength) {
4108
+ if (value === null || value === void 0) return "";
4109
+ let s;
4110
+ if (typeof value === "string") s = value;
4111
+ else if (typeof value === "number" || typeof value === "boolean") s = String(value);
4112
+ else s = stableJson(value, false);
4113
+ if (maxLength !== void 0 && maxLength >= 0 && s.length > maxLength) {
4114
+ return `${s.slice(0, maxLength)}\u2026`;
4115
+ }
4116
+ return s;
4117
+ }
4118
+ function escapeMarkdown(value) {
4119
+ return value.replace(/\|/g, "\\|").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n/g, " ");
4120
+ }
4121
+ function escapeHtml(value) {
4122
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
4123
+ }
4124
+ function sortKeysDeep(input) {
4125
+ if (input === null || typeof input !== "object") return input;
4126
+ if (Array.isArray(input)) return input.map(sortKeysDeep);
4127
+ const o = input;
4128
+ const out = {};
4129
+ for (const k of Object.keys(o).sort()) {
4130
+ out[k] = sortKeysDeep(o[k]);
4131
+ }
4132
+ return out;
4133
+ }
4134
+ function stableJson(value, pretty) {
4135
+ const sorted = sortKeysDeep(value);
4136
+ return pretty === true ? JSON.stringify(sorted, null, 2) : JSON.stringify(sorted);
4137
+ }
4138
+ function compactAttributes(attrs, options) {
4139
+ if (attrs === void 0) return {};
4140
+ const maxLen = options?.maxLength ?? 500;
4141
+ const redacted = options?.redacted ?? true;
4142
+ const out = {};
4143
+ for (const key of Object.keys(attrs).sort()) {
4144
+ if (redacted && shouldRedactKey(key)) {
4145
+ out[key] = "[REDACTED]";
4146
+ continue;
4147
+ }
4148
+ const v = attrs[key];
4149
+ out[key] = compactValue(v, maxLen, redacted);
4150
+ }
4151
+ return out;
4152
+ }
4153
+ function compactValue(value, maxLen, redacted) {
4154
+ if (value === null || typeof value !== "object") {
4155
+ return typeof value === "string" ? safeString(value, maxLen) : value;
4156
+ }
4157
+ if (Array.isArray(value)) {
4158
+ const arr = value.slice(0, 20).map((x) => compactValue(x, maxLen, redacted));
4159
+ if (value.length > 20) arr.push(`\u2026(+${value.length - 20} more)`);
4160
+ return arr;
4161
+ }
4162
+ const o = value;
4163
+ const inner = {};
4164
+ for (const k of Object.keys(o)) {
4165
+ if (redacted && shouldRedactKey(k)) inner[k] = "[REDACTED]";
4166
+ else inner[k] = compactValue(o[k], maxLen, redacted);
4167
+ }
4168
+ return inner;
4169
+ }
4170
+ function flattenTree(tree) {
4171
+ const out = [];
4172
+ function walk(nodes) {
4173
+ for (const n of nodes) {
4174
+ out.push(n);
4175
+ if (n.children.length > 0) walk(n.children);
4176
+ }
4177
+ }
4178
+ walk(tree.children);
4179
+ return out;
4180
+ }
4181
+ function zeroKinds() {
4182
+ return {
4183
+ RUN: 0,
4184
+ AGENT: 0,
4185
+ LLM: 0,
4186
+ TOOL: 0,
4187
+ CHAIN: 0,
4188
+ RETRIEVER: 0,
4189
+ DECISION: 0,
4190
+ RESULT: 0,
4191
+ ERROR: 0,
4192
+ LOGIC: 0,
4193
+ LOG: 0,
4194
+ OUTCOME: 0
4195
+ };
4196
+ }
4197
+
4198
+ // packages/core/src/evidence/views.ts
4199
+ function renderTreeHtml(nodes, ulClass = "tree") {
4200
+ if (nodes.length === 0) return "";
4201
+ const parts = [`<ul class="${ulClass}">`];
4202
+ for (const n of nodes) {
4203
+ const ev = n.event;
4204
+ const status = ev.status ?? "?";
4205
+ const dur = ev.durationMs !== void 0 && Number.isFinite(ev.durationMs) ? `${ev.durationMs}ms` : "-";
4206
+ const errClass = ev.status === "error" ? " is-error" : "";
4207
+ parts.push(`<li class="tree-node${errClass}">`);
4208
+ parts.push(
4209
+ `<span class="nm">${escapeHtml(ev.name)}</span> <span class="meta">[${escapeHtml(ev.kind)}] ${escapeHtml(status)} (${escapeHtml(dur)})</span>`
4210
+ );
4211
+ if (n.children.length > 0) {
4212
+ parts.push(renderTreeHtml(n.children, "tree nested"));
4213
+ }
4214
+ parts.push("</li>");
4215
+ }
4216
+ parts.push("</ul>");
4217
+ return parts.join("");
4218
+ }
4219
+ function buildEvidenceTreeViewHtml(trees) {
4220
+ if (trees.length === 0) {
4221
+ return `<p class="muted">No execution trees available.</p>`;
4222
+ }
4223
+ const parts = [];
4224
+ for (const tree of trees) {
4225
+ parts.push(`<article class="run-block">`);
4226
+ parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
4227
+ if (tree.name) {
4228
+ parts.push(`<p class="muted">Name: ${escapeHtml(tree.name)}</p>`);
4229
+ }
4230
+ parts.push(
4231
+ `<p>Status: <strong>${escapeHtml(String(tree.status ?? "unknown"))}</strong>${tree.durationMs !== void 0 ? ` \xB7 ${escapeHtml(String(tree.durationMs))}ms` : ""}</p>`
4232
+ );
4233
+ parts.push(
4234
+ tree.children.length > 0 ? renderTreeHtml(tree.children) : `<p class="muted">No steps recorded.</p>`
4235
+ );
4236
+ parts.push(`</article>`);
4237
+ }
4238
+ return parts.join("\n");
4239
+ }
4240
+ function timelineRows(tree) {
4241
+ const flat = flattenTree(tree);
4242
+ const origin = tree.startedAt ?? flat.reduce((min, n) => {
4243
+ const t = n.event.timestamp;
4244
+ if (!Number.isFinite(t)) return min;
4245
+ return min === void 0 ? t : Math.min(min, t);
4246
+ }, void 0) ?? 0;
4247
+ return flat.filter((n) => n.event.kind !== "RUN").map((n) => {
4248
+ const started = Number.isFinite(n.event.timestamp) ? n.event.timestamp : origin;
4249
+ const durationMs = n.event.durationMs !== void 0 && Number.isFinite(n.event.durationMs) ? Math.max(0, n.event.durationMs) : 0;
4250
+ return {
4251
+ name: n.event.name,
4252
+ kind: n.event.kind,
4253
+ status: n.event.status ?? "?",
4254
+ offsetMs: Math.max(0, started - origin),
4255
+ durationMs,
4256
+ isError: n.event.status === "error"
4257
+ };
4258
+ }).sort((a, b) => a.offsetMs - b.offsetMs || a.name.localeCompare(b.name));
4259
+ }
4260
+ function buildEvidenceTimelineViewHtml(trees) {
4261
+ if (trees.length === 0) {
4262
+ return `<p class="muted">No timeline data available.</p>`;
4263
+ }
4264
+ const parts = [];
4265
+ for (const tree of trees) {
4266
+ const rows = timelineRows(tree);
4267
+ const maxEnd = rows.reduce(
4268
+ (max, row) => Math.max(max, row.offsetMs + Math.max(row.durationMs, 1)),
4269
+ 1
4270
+ );
4271
+ parts.push(`<article class="run-block">`);
4272
+ parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
4273
+ if (rows.length === 0) {
4274
+ parts.push(`<p class="muted">No step timings recorded.</p>`);
4275
+ } else {
4276
+ parts.push(`<div class="waterfall" role="list">`);
4277
+ for (const row of rows) {
4278
+ const left = row.offsetMs / maxEnd * 100;
4279
+ const width = Math.max(0.8, Math.max(row.durationMs, 1) / maxEnd * 100);
4280
+ const err = row.isError ? " is-error" : "";
4281
+ parts.push(
4282
+ `<div class="wf-row${err}" role="listitem"><div class="wf-label"><span class="nm">${escapeHtml(row.name)}</span> <span class="meta">[${escapeHtml(row.kind)}] ${escapeHtml(row.status)} \xB7 ${escapeHtml(String(row.durationMs))}ms @+${escapeHtml(String(row.offsetMs))}ms</span></div><div class="wf-track"><span class="wf-bar" style="left:${left.toFixed(2)}%;width:${width.toFixed(2)}%"></span></div></div>`
4283
+ );
4284
+ }
4285
+ parts.push(`</div>`);
4286
+ }
4287
+ parts.push(`</article>`);
4288
+ }
4289
+ return parts.join("\n");
4290
+ }
4291
+ function findNodeByEventId(nodes, eventId) {
4292
+ for (const node of nodes) {
4293
+ if (node.event.eventId === eventId) return node;
4294
+ const child = findNodeByEventId(node.children, eventId);
4295
+ if (child) return child;
4296
+ }
4297
+ return void 0;
4298
+ }
4299
+ function buildAncestorChain(tree, failure) {
4300
+ const chain = [failure];
4301
+ let parentId = failure.event.parentId;
4302
+ const guard = /* @__PURE__ */ new Set([failure.event.eventId]);
4303
+ while (parentId && !guard.has(parentId)) {
4304
+ guard.add(parentId);
4305
+ const parent = findNodeByEventId(tree.children, parentId);
4306
+ if (!parent) break;
4307
+ chain.unshift(parent);
4308
+ parentId = parent.event.parentId;
4309
+ }
4310
+ return chain;
4311
+ }
4312
+ function buildEvidenceCausalFailureViewHtml(trees) {
4313
+ if (trees.length === 0) {
4314
+ return `<p class="muted">No runs available for causal analysis.</p>`;
4315
+ }
4316
+ const parts = [];
4317
+ for (const tree of trees) {
4318
+ parts.push(`<article class="run-block">`);
4319
+ parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
4320
+ const errors = flattenTree(tree).filter((n) => n.event.status === "error" || n.event.kind === "ERROR").sort((a, b) => a.event.timestamp - b.event.timestamp);
4321
+ if (errors.length === 0) {
4322
+ parts.push(
4323
+ `<p class="muted">No error-status events found. Run status: <strong>${escapeHtml(String(tree.status ?? "unknown"))}</strong>.</p>`
4324
+ );
4325
+ parts.push(`</article>`);
4326
+ continue;
4327
+ }
4328
+ const first = errors[0];
4329
+ const chain = buildAncestorChain(tree, first);
4330
+ parts.push(`<p>First error by timestamp:</p>`);
4331
+ parts.push(`<ol class="causal-chain">`);
4332
+ for (const node of chain) {
4333
+ const isTip = node.event.eventId === first.event.eventId;
4334
+ const msg = typeof node.event.attributes?.message === "string" ? node.event.attributes.message : typeof node.event.attributes?.error === "string" ? node.event.attributes.error : void 0;
4335
+ parts.push(
4336
+ `<li class="${isTip ? "causal-tip" : ""}"><span class="nm">${escapeHtml(node.event.name)}</span> <span class="meta">[${escapeHtml(node.event.kind)}] ${escapeHtml(node.event.status ?? "?")} \xB7 ${escapeHtml(node.event.eventId)}</span>${msg ? `<div class="causal-msg">${escapeHtml(msg.slice(0, 400))}</div>` : ""}</li>`
4337
+ );
4338
+ }
4339
+ parts.push(`</ol>`);
4340
+ if (errors.length > 1) {
4341
+ parts.push(
4342
+ `<p class="muted">${escapeHtml(String(errors.length - 1))} additional error event(s) not shown in the primary chain.</p>`
4343
+ );
4344
+ }
4345
+ parts.push(`</article>`);
4346
+ }
4347
+ return parts.join("\n");
4348
+ }
4349
+ var EVIDENCE_VIEW_CSS = `
4350
+ ul.tree{list-style:none;padding-left:1rem;margin:.5rem 0}
4351
+ ul.tree.nested{padding-left:1.25rem;border-left:1px solid var(--line);margin:.25rem 0}
4352
+ .tree-node.is-error .nm,.wf-row.is-error .nm,.causal-tip .nm{color:var(--unsafe)}
4353
+ .waterfall{display:flex;flex-direction:column;gap:.45rem;max-width:52rem}
4354
+ .wf-row{display:grid;grid-template-columns:minmax(10rem,18rem) 1fr;gap:.6rem;align-items:center}
4355
+ .wf-track{position:relative;height:.7rem;background:#e8e8e4;border-radius:.25rem;overflow:hidden}
4356
+ .wf-bar{position:absolute;top:0;bottom:0;background:var(--accent);border-radius:.25rem}
4357
+ .wf-row.is-error .wf-bar{background:var(--unsafe)}
4358
+ .causal-chain{max-width:44rem}
4359
+ .causal-msg{margin:.25rem 0 0;color:var(--muted);font-size:.92rem}
4360
+ .run-block{margin:0 0 1.25rem;padding-bottom:1rem;border-bottom:1px solid var(--line)}
4361
+ .run-block:last-child{border-bottom:0}
4362
+ @media (max-width:720px){
4363
+ .wf-row{grid-template-columns:1fr}
4364
+ }
4365
+ `.trim();
4366
+
4367
+ // packages/core/src/evidence/html-shell.ts
4368
+ var EVIDENCE_HTML_FILENAME = "evidence.html";
4369
+ var EVIDENCE_HTML_NOTE = "Generated locally by AgentInspect. Share-checked evidence for review \u2014 not a compliance or security certification.";
4370
+ var EVIDENCE_VIEW_IDS = [
4371
+ "summary",
4372
+ "tree",
4373
+ "timeline",
4374
+ "causal",
4375
+ "tools-llm",
4376
+ "outcomes",
4377
+ "contracts",
4378
+ "circuit",
4379
+ "diff",
4380
+ "safety",
4381
+ "provenance"
4382
+ ];
4383
+ function statusClass(status) {
4384
+ if (status === "SAFE") return "st-safe";
4385
+ if (status === "SAFE WITH WARNINGS") return "st-warn";
4386
+ if (status === "UNSAFE") return "st-unsafe";
4387
+ return "st-unknown";
4388
+ }
4389
+ function viewLabel(id) {
4390
+ switch (id) {
4391
+ case "summary":
4392
+ return "Summary";
4393
+ case "tree":
4394
+ return "Tree";
4395
+ case "timeline":
4396
+ return "Timeline";
4397
+ case "causal":
4398
+ return "Causal failure";
4399
+ case "tools-llm":
4400
+ return "Tools / LLM";
4401
+ case "outcomes":
4402
+ return "Outcomes";
4403
+ case "contracts":
4404
+ return "Contracts / checks";
4405
+ case "circuit":
4406
+ return "Circuit / guardrails";
4407
+ case "diff":
4408
+ return "Diff";
4409
+ case "safety":
4410
+ return "Safety / redaction";
4411
+ case "provenance":
4412
+ return "Provenance";
4413
+ default: {
4414
+ const _exhaustive = id;
4415
+ return _exhaustive;
4416
+ }
4417
+ }
4418
+ }
4419
+ function encodeEmbeddedEvidenceJson(value) {
4420
+ return JSON.stringify(value).replace(/</g, "\\u003c").replace(/>/g, "\\u003e");
4421
+ }
4422
+ function buildEmbeddedPayload(input) {
4423
+ return {
4424
+ evidenceFormatVersion: input.evidenceFormatVersion ?? "1.0",
4425
+ generator: {
4426
+ name: input.generatorName,
4427
+ version: input.generatorVersion
4428
+ },
4429
+ createdAt: input.createdAt,
4430
+ runIds: [...input.runIds],
4431
+ assessment: {
4432
+ status: input.assessmentStatus,
4433
+ ...input.sourceStatus !== void 0 ? { sourceStatus: input.sourceStatus } : {}
4434
+ },
4435
+ policy: {
4436
+ redactionProfile: input.redactionProfile,
4437
+ verificationPolicy: input.verificationPolicy
4438
+ },
4439
+ checkSummary: input.checkSummary
4440
+ };
4441
+ }
4442
+ function buildEvidenceHtmlShell(input) {
4443
+ if (input.runIds.length === 0) {
4444
+ throw new Error("Evidence HTML shell requires at least one run id.");
4445
+ }
4446
+ const maxChars = input.maxEmbeddedJsonChars ?? 64 * 1024;
4447
+ let embedded = encodeEmbeddedEvidenceJson(buildEmbeddedPayload(input));
4448
+ if (embedded.length > maxChars) {
4449
+ embedded = encodeEmbeddedEvidenceJson({
4450
+ truncated: true,
4451
+ evidenceFormatVersion: input.evidenceFormatVersion ?? "1.0",
4452
+ runIds: [...input.runIds],
4453
+ assessment: { status: input.assessmentStatus },
4454
+ note: "Embedded payload truncated to bound; open evidence.json / trace files for full detail."
4455
+ });
4456
+ }
4457
+ const title = escapeHtml(input.title ?? "AgentInspect evidence");
4458
+ const runList = input.runIds.map((id) => `<li><code>${escapeHtml(id)}</code></li>`).join("");
4459
+ const summaryBody = input.summaryText !== void 0 && input.summaryText.trim() !== "" ? `<pre class="summary-md">${escapeHtml(input.summaryText)}</pre>` : `<p class="muted">Open <code>summary.md</code> in this bundle for the full text summary.</p>`;
4460
+ const checkRows = input.checkSummary?.runs.map(
4461
+ (run) => `<tr><td><code>${escapeHtml(run.runId)}</code></td><td class="${statusClass(run.status)}">${escapeHtml(run.status)}</td><td>${run.errors}</td><td>${run.warnings}</td><td>${run.findings}</td></tr>`
4462
+ ).join("") ?? "";
4463
+ const nav = EVIDENCE_VIEW_IDS.map(
4464
+ (id) => `<a class="nav-link" href="#view-${id}" data-view="${id}">${escapeHtml(viewLabel(id))}</a>`
4465
+ ).join("\n");
4466
+ const stubPanels = EVIDENCE_VIEW_IDS.filter((id) => id !== "summary").map((id) => {
4467
+ const body = input.viewBodies?.[id];
4468
+ if (body !== void 0 && body.trim() !== "") {
4469
+ return ` <section id="view-${id}" class="panel" hidden>
4470
+ <h2>${escapeHtml(viewLabel(id))}</h2>
4471
+ ${body}
4472
+ </section>`;
4473
+ }
4474
+ return ` <section id="view-${id}" class="panel" hidden>
4475
+ <h2>${escapeHtml(viewLabel(id))}</h2>
4476
+ <p class="muted">This view will be filled in a later AgentInspect 6.10 release. The shell is offline-ready.</p>
4477
+ </section>`;
4478
+ }).join("\n");
4479
+ return `<!doctype html>
4480
+ <html lang="en">
4481
+ <head>
4482
+ <meta charset="utf-8"/>
4483
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
4484
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'; frame-ancestors 'none'"/>
4485
+ <meta name="referrer" content="no-referrer"/>
4486
+ <title>${title}</title>
4487
+ <style>
4488
+ :root{--bg:#f7f7f5;--fg:#1a1a1a;--muted:#5c5c5c;--line:#d8d8d4;--accent:#0b5fff;--safe:#0a7a3e;--warn:#9a6700;--unsafe:#b42318;--unknown:#5c5c5c}
4489
+ *{box-sizing:border-box}
4490
+ body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;background:var(--bg);color:var(--fg);line-height:1.5}
4491
+ a{color:var(--accent)}
4492
+ header{padding:1.25rem 1.5rem;border-bottom:1px solid var(--line);background:#fff}
4493
+ header h1{margin:0 0 .35rem;font-size:1.35rem}
4494
+ .note{margin:0;color:var(--muted);font-size:.92rem;max-width:52rem}
4495
+ .layout{display:grid;grid-template-columns:14rem 1fr;min-height:70vh}
4496
+ nav{padding:1rem;border-right:1px solid var(--line);background:#fff}
4497
+ nav .nav-link{display:block;padding:.4rem .55rem;margin:0 0 .2rem;border-radius:.35rem;text-decoration:none;color:inherit}
4498
+ nav .nav-link:hover,nav .nav-link:focus{background:#eef3ff;outline:2px solid var(--accent);outline-offset:1px}
4499
+ main{padding:1.25rem 1.5rem}
4500
+ .panel[hidden]{display:none}
4501
+ .badge{display:inline-block;padding:.15rem .55rem;border-radius:.3rem;font-size:.85rem;font-weight:600}
4502
+ .st-safe{color:var(--safe)}.st-warn{color:var(--warn)}.st-unsafe{color:var(--unsafe)}.st-unknown{color:var(--unknown)}
4503
+ table{border-collapse:collapse;width:100%;max-width:48rem;background:#fff}
4504
+ th,td{border:1px solid var(--line);padding:.4rem .55rem;text-align:left;vertical-align:top}
4505
+ th{background:#f0f0ec}
4506
+ .summary-md,pre.data{white-space:pre-wrap;word-break:break-word;background:#fff;border:1px solid var(--line);padding:.75rem;max-width:52rem}
4507
+ .muted{color:var(--muted)}
4508
+ ul.runs{margin:.4rem 0 1rem;padding-left:1.2rem}
4509
+ @media print{
4510
+ nav{display:none}
4511
+ .layout{display:block}
4512
+ .panel[hidden]{display:block!important;page-break-before:always}
4513
+ header{border:0}
4514
+ }
4515
+ @media (max-width:720px){
4516
+ .layout{grid-template-columns:1fr}
4517
+ nav{border-right:0;border-bottom:1px solid var(--line);display:flex;flex-wrap:wrap;gap:.25rem}
4518
+ }
4519
+ ${EVIDENCE_VIEW_CSS}
4520
+ </style>
4521
+ </head>
4522
+ <body>
4523
+ <header>
4524
+ <h1>${title}</h1>
4525
+ <p class="note">${escapeHtml(EVIDENCE_HTML_NOTE)}</p>
4526
+ </header>
4527
+ <div class="layout">
4528
+ <nav aria-label="Evidence views">
4529
+ ${nav}
4530
+ </nav>
4531
+ <main id="main">
4532
+ <section id="view-summary" class="panel" tabindex="-1">
4533
+ <h2>Summary</h2>
4534
+ <p>Artifact status: <span class="badge ${statusClass(input.assessmentStatus)}">${escapeHtml(input.assessmentStatus)}</span>
4535
+ ${input.sourceStatus !== void 0 ? ` \xB7 Source status: <span class="badge ${statusClass(input.sourceStatus)}">${escapeHtml(input.sourceStatus)}</span>` : ""}</p>
4536
+ <p>Profile: <code>${escapeHtml(input.redactionProfile)}</code> \xB7 Verification: <code>${escapeHtml(input.verificationPolicy)}</code></p>
4537
+ <p>Generator: <code>${escapeHtml(input.generatorName)}@${escapeHtml(input.generatorVersion)}</code>
4538
+ ${input.createdAt ? ` \xB7 Created: <code>${escapeHtml(input.createdAt)}</code>` : ""}</p>
4539
+ <h3>Runs</h3>
4540
+ <ul class="runs">${runList}</ul>
4541
+ ${checkRows ? `<h3>Check summary</h3>
4542
+ <table>
4543
+ <thead><tr><th>runId</th><th>artifact</th><th>errors</th><th>warnings</th><th>findings</th></tr></thead>
4544
+ <tbody>${checkRows}</tbody>
4545
+ </table>` : ""}
4546
+ <h3>Text summary</h3>
4547
+ ${summaryBody}
4548
+ </section>
4549
+ ${stubPanels}
4550
+ </main>
4551
+ </div>
4552
+ <script type="application/json" id="ai-evidence-data">${embedded}</script>
4553
+ <script>
4554
+ (function(){
4555
+ var links=document.querySelectorAll("nav .nav-link");
4556
+ var panels=document.querySelectorAll("main .panel");
4557
+ function show(id){
4558
+ for(var i=0;i<panels.length;i++){
4559
+ var p=panels[i];
4560
+ var on=p.id==="view-"+id;
4561
+ if(on){p.removeAttribute("hidden");}else{p.setAttribute("hidden","");}
4562
+ }
4563
+ for(var j=0;j<links.length;j++){
4564
+ var a=links[j];
4565
+ if(a.getAttribute("data-view")===id){a.setAttribute("aria-current","page");}
4566
+ else{a.removeAttribute("aria-current");}
4567
+ }
4568
+ }
4569
+ for(var k=0;k<links.length;k++){
4570
+ links[k].addEventListener("click",function(ev){
4571
+ var id=ev.currentTarget.getAttribute("data-view");
4572
+ if(!id)return;
4573
+ ev.preventDefault();
4574
+ if(history.replaceState){history.replaceState(null,"","#view-"+id);}
4575
+ show(id);
4576
+ var panel=document.getElementById("view-"+id);
4577
+ if(panel)panel.focus();
4578
+ });
4579
+ }
4580
+ var hash=(location.hash||"").replace(/^#view-/,"");
4581
+ var initial="summary";
4582
+ for(var n=0;n<links.length;n++){
4583
+ if(links[n].getAttribute("data-view")===hash){initial=hash;break;}
4584
+ }
4585
+ show(initial);
4586
+ })();
4587
+ </script>
4588
+ </body>
4589
+ </html>
4590
+ `;
4591
+ }
4592
+
4593
+ // packages/core/src/diff/renderer.ts
4594
+ function formatPath(path14) {
4595
+ if (path14 === void 0 || path14.path.length === 0) {
4596
+ return "(run)";
4597
+ }
4598
+ return path14.path.map((s) => s.name).join(" > ");
4599
+ }
4600
+ function formatValue(v, verbose) {
4601
+ if (v === void 0) return "(undefined)";
4602
+ if (typeof v === "string") return v;
4603
+ if (typeof v === "number" || typeof v === "boolean") return String(v);
4604
+ const s = JSON.stringify(v);
4605
+ if (verbose || s.length <= 120) return s;
4606
+ return `${s.slice(0, 117)}...`;
4607
+ }
4608
+ function renderRunDiff(result, options) {
4609
+ const json = options?.json === true;
4610
+ const verbose = options?.verbose === true;
4611
+ const color = options?.color === true;
4612
+ if (json) {
4613
+ return JSON.stringify(result, null, 2);
4614
+ }
4615
+ const sev = (s, level) => {
4616
+ if (!color) return s;
4617
+ if (level === "error") return source_default.red(s);
4618
+ if (level === "warning") return source_default.yellow(s);
4619
+ return source_default.gray(s);
4620
+ };
4621
+ const lines = [];
4622
+ const { summary } = result;
4623
+ lines.push("Run diff");
4624
+ lines.push(`Left: ${summary.leftRunId}`);
4625
+ lines.push(`Right: ${summary.rightRunId}`);
4626
+ lines.push("");
4627
+ lines.push("Summary:");
4628
+ lines.push(` Differences: ${summary.totalDifferences}`);
4629
+ lines.push(` Errors: ${summary.errors}`);
4630
+ lines.push(` Warnings: ${summary.warnings}`);
4631
+ lines.push(` Info: ${summary.info}`);
4632
+ lines.push("");
4633
+ const fd = summary.firstDivergence;
4634
+ const firstKind = result.differences[0]?.kind;
4635
+ if (fd !== void 0) {
4636
+ lines.push("First divergence:");
4637
+ const where = formatPath(fd.path);
4638
+ const displayKind = firstKind ?? fd.kind;
4639
+ lines.push(` ${displayKind} at ${where}`);
4640
+ if (fd.left !== void 0 || fd.right !== void 0) {
4641
+ lines.push(` left: ${formatValue(fd.left, verbose)}`);
4642
+ lines.push(` right: ${formatValue(fd.right, verbose)}`);
4643
+ }
4644
+ lines.push("");
4645
+ }
4646
+ lines.push("Differences:");
4647
+ if (result.differences.length === 0) {
4648
+ lines.push(" (none)");
4649
+ return lines.join("\n");
4650
+ }
4651
+ const showSides = (kind) => verbose || [
4652
+ "run-status",
4653
+ "step-status",
4654
+ "error",
4655
+ "duration",
4656
+ "step-type",
4657
+ "structure",
4658
+ "step-added",
4659
+ "step-removed"
4660
+ ].includes(kind);
4661
+ for (const d of result.differences) {
4662
+ const tag = sev(`[${d.severity}]`, d.severity);
4663
+ const pathStr = d.path !== void 0 ? ` ${formatPath(d.path)}` : "";
4664
+ lines.push(` ${tag} ${d.kind}${pathStr}`);
4665
+ lines.push(` ${d.message}`);
4666
+ if (d.left !== void 0 || d.right !== void 0) {
4667
+ if (showSides(d.kind)) {
4668
+ lines.push(` left: ${formatValue(d.left, verbose)}`);
4669
+ lines.push(` right: ${formatValue(d.right, verbose)}`);
4670
+ }
4671
+ }
4672
+ }
4673
+ return lines.join("\n");
4674
+ }
4675
+
4676
+ // packages/core/src/diff/comparable.ts
4677
+ function extractOutputPreview(meta) {
4678
+ if (meta === void 0) return void 0;
4679
+ if ("outputPreview" in meta) return meta.outputPreview;
4680
+ if ("resultPreview" in meta) return meta.resultPreview;
4681
+ return void 0;
4682
+ }
4683
+ function mapStepStatus(s) {
4684
+ if (s === void 0) return "running";
4685
+ return s;
4686
+ }
4687
+ function manualTraceEventsToComparableRun(events) {
4688
+ const started = events.find((e) => e.event === "run_started");
4689
+ if (!started || started.event !== "run_started") {
4690
+ throw new Error("Invalid trace: missing run_started");
4691
+ }
4692
+ const rs = started;
4693
+ const runId = rs.runId;
4694
+ const completedAll = events.filter((e) => e.event === "run_completed");
4695
+ const lastCompleted = completedAll[completedAll.length - 1];
4696
+ let runStatus;
4697
+ if (lastCompleted === void 0) runStatus = "running";
4698
+ else runStatus = lastCompleted.status;
4699
+ const durationMs = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
4700
+ const steps = /* @__PURE__ */ new Map();
4701
+ let order = 0;
4702
+ for (const e of events) {
4703
+ if (e.event !== "step_started") continue;
4704
+ const s = e;
4705
+ const meta = s.metadata ? { ...s.metadata } : void 0;
4706
+ steps.set(s.stepId, {
4707
+ id: s.stepId,
4708
+ parentId: s.parentId,
4709
+ name: s.name,
4710
+ type: s.type,
4711
+ order: order++,
4712
+ timestamp: s.timestamp,
4713
+ metadata: meta
4714
+ });
4715
+ }
4716
+ for (const e of events) {
4717
+ if (e.event !== "step_completed") continue;
4718
+ const acc = steps.get(e.stepId);
4719
+ if (!acc) continue;
4720
+ acc.status = e.status;
4721
+ acc.durationMs = e.durationMs;
4722
+ if (e.error?.message) acc.errorMsg = e.error.message;
4723
+ const extra = e;
4724
+ if (extra.metadata !== void 0 && typeof extra.metadata === "object") {
4725
+ acc.metadata = { ...acc.metadata ?? {}, ...extra.metadata };
4726
+ }
4727
+ }
4728
+ const nodes = /* @__PURE__ */ new Map();
4729
+ for (const acc of steps.values()) {
4730
+ let meta = acc.metadata ? { ...acc.metadata } : void 0;
4731
+ if (acc.parentId !== void 0 && !steps.has(acc.parentId)) {
4732
+ meta = { ...meta ?? {}, agent_inspect_diff_parent_missing: true };
4733
+ }
4734
+ const outputPreview = extractOutputPreview(meta);
4735
+ if (meta !== void 0 && ("outputPreview" in meta || "resultPreview" in meta)) {
4736
+ delete meta.outputPreview;
4737
+ delete meta.resultPreview;
4738
+ }
4739
+ const sc = {
4740
+ id: acc.id,
4741
+ name: acc.name,
4742
+ type: acc.type,
4743
+ status: mapStepStatus(acc.status),
4744
+ durationMs: acc.durationMs,
4745
+ error: acc.errorMsg,
4746
+ metadata: meta && Object.keys(meta).length > 0 ? meta : void 0,
4747
+ outputPreview,
4748
+ children: []
4749
+ };
4750
+ nodes.set(acc.id, sc);
4751
+ }
4752
+ const roots = [];
4753
+ const sortByOrder = (a, b) => {
4754
+ const oa = steps.get(a.id)?.order ?? 0;
4755
+ const ob = steps.get(b.id)?.order ?? 0;
4756
+ return oa - ob;
4757
+ };
4758
+ for (const acc of steps.values()) {
4759
+ const node = nodes.get(acc.id);
4760
+ if (acc.parentId !== void 0 && nodes.has(acc.parentId)) {
4761
+ nodes.get(acc.parentId).children.push(node);
4762
+ } else {
4763
+ roots.push(node);
4764
+ }
4765
+ }
4766
+ roots.sort(sortByOrder);
4767
+ for (const n of nodes.values()) {
4768
+ n.children.sort(sortByOrder);
4769
+ }
4770
+ return {
4771
+ runId,
4772
+ name: rs.name,
4773
+ status: runStatus,
4774
+ durationMs,
4775
+ steps: roots
4776
+ };
4777
+ }
4778
+
4779
+ // packages/core/src/diff/engine.ts
4780
+ var DEFAULT_THRESHOLD_MS = 0;
4781
+ function pathSeg(step, index) {
4782
+ return { index, name: step.name, stepId: step.id };
4783
+ }
4784
+ function buildPath(segments) {
4785
+ return { path: [...segments] };
4786
+ }
4787
+ function pairSteps(left, right) {
4788
+ const usedRight = /* @__PURE__ */ new Set();
4789
+ const pairs = [];
4790
+ for (let i = 0; i < left.length; i++) {
4791
+ const L = left[i];
4792
+ let R = right.find((r) => !usedRight.has(r.id) && r.id === L.id);
4793
+ if (R === void 0 && i < right.length && !usedRight.has(right[i].id)) {
4794
+ const cand = right[i];
4795
+ if (cand.name === L.name && (cand.type ?? "") === (L.type ?? "")) {
4796
+ R = cand;
4797
+ }
4798
+ }
4799
+ if (R === void 0) {
4800
+ R = right.find(
4801
+ (r) => !usedRight.has(r.id) && r.name === L.name && (r.type ?? "") === (L.type ?? "")
4802
+ );
4803
+ }
4804
+ if (R !== void 0) {
4805
+ usedRight.add(R.id);
4806
+ pairs.push([L, R]);
4807
+ } else {
4808
+ pairs.push([L, void 0]);
4809
+ }
4810
+ }
4811
+ for (const R of right) {
4812
+ if (!usedRight.has(R.id)) {
4813
+ pairs.push([void 0, R]);
4814
+ }
4815
+ }
4816
+ return pairs;
4817
+ }
4818
+ function compareLeafSteps(L, R, segments, opts, out) {
4819
+ const path14 = buildPath(segments);
4820
+ if (L.name !== R.name) {
4821
+ out.push({
4822
+ kind: "structure",
4823
+ severity: "warning",
4824
+ message: "Step name differs",
4825
+ path: path14,
4826
+ left: L.name,
4827
+ right: R.name
4828
+ });
4829
+ }
4830
+ if ((L.type ?? "") !== (R.type ?? "")) {
4831
+ out.push({
4832
+ kind: "step-type",
4833
+ severity: "warning",
4834
+ message: "Step type differs",
4835
+ path: path14,
4836
+ left: L.type,
4837
+ right: R.type
4838
+ });
4839
+ }
4840
+ if ((L.status ?? "") !== (R.status ?? "")) {
4841
+ out.push({
4842
+ kind: "step-status",
4843
+ severity: "warning",
4844
+ message: "Step status differs",
4845
+ path: path14,
4846
+ left: L.status,
4847
+ right: R.status
4848
+ });
4849
+ }
4850
+ const le = L.error ?? "";
4851
+ const re = R.error ?? "";
4852
+ if (le !== re) {
4853
+ out.push({
4854
+ kind: "error",
4855
+ severity: "error",
4856
+ message: "Step error message differs",
4857
+ path: path14,
4858
+ left: le || void 0,
4859
+ right: re || void 0
4860
+ });
4861
+ }
4862
+ if (!opts.ignoreDuration) {
4863
+ const ld = L.durationMs;
4864
+ const rd = R.durationMs;
4865
+ const th = opts.durationThresholdMs;
4866
+ let differs = false;
4867
+ if (ld === void 0 && rd === void 0) differs = false;
4868
+ else if (ld === void 0 || rd === void 0) differs = true;
4869
+ else differs = Math.abs(ld - rd) > th;
4870
+ if (differs) {
4871
+ out.push({
4872
+ kind: "duration",
4873
+ severity: "info",
4874
+ message: "Step duration differs",
4875
+ path: path14,
4876
+ left: ld,
4877
+ right: rd
4878
+ });
4879
+ }
4880
+ }
4881
+ const lm = stableJson(L.metadata ?? {});
4882
+ const rm = stableJson(R.metadata ?? {});
4883
+ if (lm !== rm) {
4884
+ out.push({
4885
+ kind: "metadata",
4886
+ severity: "info",
4887
+ message: "Step metadata differs",
4888
+ path: path14,
4889
+ left: L.metadata,
4890
+ right: R.metadata
4891
+ });
4892
+ }
4893
+ const lo = stableJson(L.outputPreview ?? null);
4894
+ const ro = stableJson(R.outputPreview ?? null);
4895
+ if (lo !== ro) {
4896
+ out.push({
4897
+ kind: "output",
4898
+ severity: "info",
4899
+ message: "Output preview differs",
4900
+ path: path14,
4901
+ left: L.outputPreview,
4902
+ right: R.outputPreview
4903
+ });
4904
+ }
4905
+ }
4906
+ function compareRecursive(L, R, segments, opts, out) {
4907
+ compareLeafSteps(L, R, segments, opts, out);
4908
+ const pairs = pairSteps(L.children, R.children);
4909
+ let ci = 0;
4910
+ for (const [lch, rch] of pairs) {
4911
+ if (lch !== void 0 && rch !== void 0) {
4912
+ compareRecursive(lch, rch, [...segments, pathSeg(lch, ci)], opts, out);
4913
+ } else if (lch !== void 0) {
4914
+ out.push({
4915
+ kind: "step-removed",
4916
+ severity: "warning",
4917
+ message: `Step only in left run: ${lch.name}`,
4918
+ path: buildPath([...segments, pathSeg(lch, ci)]),
4919
+ left: lch.id,
4920
+ right: void 0
4921
+ });
4922
+ } else if (rch !== void 0) {
4923
+ out.push({
4924
+ kind: "step-added",
4925
+ severity: "warning",
4926
+ message: `Step only in right run: ${rch.name}`,
4927
+ path: buildPath([...segments, pathSeg(rch, ci)]),
4928
+ left: void 0,
4929
+ right: rch.id
4930
+ });
4931
+ }
4932
+ ci += 1;
4933
+ }
4934
+ }
4935
+ function mergeDiffDefaults(options) {
4936
+ return {
4937
+ ignoreDuration: options?.ignoreDuration ?? false,
4938
+ durationThresholdMs: options?.durationThresholdMs !== void 0 ? options.durationThresholdMs : DEFAULT_THRESHOLD_MS,
4939
+ focus: options?.focus ?? "all",
4940
+ check: options?.check ?? "all"
4941
+ };
4942
+ }
4943
+ function kindMatchesFilter(kind, merged) {
4944
+ const { focus, check } = merged;
4945
+ if (check !== "all") {
4946
+ if (check === "structure") {
4947
+ if (!["step-added", "step-removed", "structure", "step-type"].includes(kind)) return false;
4948
+ } else if (check === "outputs") {
4949
+ if (!["metadata", "output"].includes(kind)) return false;
4950
+ } else if (check === "errors") {
4951
+ if (!["run-status", "step-status", "error"].includes(kind)) return false;
4952
+ } else if (check === "timing") {
4953
+ if (kind !== "duration") return false;
4954
+ }
4955
+ }
4956
+ if (focus !== "all") {
4957
+ if (focus === "errors") {
4958
+ if (!["run-status", "step-status", "error"].includes(kind)) return false;
4959
+ } else if (focus === "structure") {
4960
+ if (!["step-added", "step-removed", "structure", "step-type"].includes(kind)) return false;
4961
+ } else if (focus === "outputs") {
4962
+ if (!["metadata", "output"].includes(kind)) return false;
4963
+ }
4964
+ }
4965
+ return true;
4966
+ }
4967
+ function diffRuns(left, right, options) {
4968
+ const merged = mergeDiffDefaults(options);
4969
+ const opts = {
4970
+ ignoreDuration: merged.ignoreDuration,
4971
+ durationThresholdMs: merged.durationThresholdMs
4972
+ };
4973
+ const raw = [];
4974
+ if ((left.status ?? "") !== (right.status ?? "")) {
4975
+ raw.push({
4976
+ kind: "run-status",
4977
+ severity: "warning",
4978
+ message: "Run completion status differs",
4979
+ left: left.status,
4980
+ right: right.status
4981
+ });
4982
+ }
4983
+ if (!merged.ignoreDuration) {
4984
+ const ld = left.durationMs;
4985
+ const rd = right.durationMs;
4986
+ const th = merged.durationThresholdMs;
4987
+ let differs = false;
4988
+ if (ld === void 0 && rd === void 0) differs = false;
4989
+ else if (ld === void 0 || rd === void 0) differs = true;
4990
+ else differs = Math.abs(ld - rd) > th;
4991
+ if (differs) {
4992
+ raw.push({
4993
+ kind: "duration",
4994
+ severity: "info",
4995
+ message: "Run duration differs",
4996
+ left: ld,
4997
+ right: rd
4998
+ });
4999
+ }
5000
+ }
5001
+ const pairs = pairSteps(left.steps, right.steps);
5002
+ let idx = 0;
5003
+ for (const [ls, rs] of pairs) {
5004
+ if (ls !== void 0 && rs !== void 0) {
5005
+ compareRecursive(ls, rs, [pathSeg(ls, idx)], opts, raw);
5006
+ idx += 1;
5007
+ } else if (ls !== void 0) {
5008
+ raw.push({
5009
+ kind: "step-removed",
5010
+ severity: "warning",
5011
+ message: `Step only in left run: ${ls.name}`,
5012
+ path: buildPath([pathSeg(ls, idx)]),
5013
+ left: ls.id,
5014
+ right: void 0
5015
+ });
5016
+ idx += 1;
5017
+ } else if (rs !== void 0) {
5018
+ raw.push({
5019
+ kind: "step-added",
5020
+ severity: "warning",
5021
+ message: `Step only in right run: ${rs.name}`,
5022
+ path: buildPath([pathSeg(rs, idx)]),
5023
+ left: void 0,
5024
+ right: rs.id
5025
+ });
5026
+ idx += 1;
5027
+ }
5028
+ }
5029
+ const differences = raw.filter((d) => kindMatchesFilter(d.kind, merged));
5030
+ let errors = 0;
5031
+ let warnings = 0;
5032
+ let info = 0;
5033
+ for (const d of differences) {
5034
+ if (d.severity === "error") errors += 1;
5035
+ else if (d.severity === "warning") warnings += 1;
5036
+ else info += 1;
5037
+ }
5038
+ const firstVisible = differences[0];
5039
+ const firstDivergence = firstVisible !== void 0 ? {
5040
+ kind: "first-divergence",
5041
+ severity: firstVisible.severity,
5042
+ message: `First divergence: ${firstVisible.message}`,
5043
+ path: firstVisible.path,
5044
+ left: firstVisible.left,
5045
+ right: firstVisible.right
5046
+ } : void 0;
5047
+ const summary = {
5048
+ leftRunId: left.runId,
5049
+ rightRunId: right.runId,
5050
+ totalDifferences: differences.length,
5051
+ errors,
5052
+ warnings,
5053
+ info,
5054
+ firstDivergence
5055
+ };
5056
+ return { summary, differences };
5057
+ }
5058
+
5059
+ // packages/core/src/diff/index.ts
5060
+ function diffTraceEvents(leftEvents, rightEvents, options) {
5061
+ const left = manualTraceEventsToComparableRun(leftEvents);
5062
+ const right = manualTraceEventsToComparableRun(rightEvents);
5063
+ return diffRuns(left, right, options);
5064
+ }
5065
+
5066
+ // packages/core/src/evidence/views-contract.ts
5067
+ function boundMessage(message, max = 200) {
5068
+ const trimmed = message.trim();
5069
+ if (trimmed.length <= max) return trimmed;
5070
+ return `${trimmed.slice(0, max)}\u2026`;
5071
+ }
5072
+ function buildEvidenceContractsViewHtml(input) {
5073
+ const rows = input.runs.map(
5074
+ (run) => `<tr><td><code>${escapeHtml(run.runId)}</code></td><td>${escapeHtml(run.status)}</td><td>${escapeHtml(run.sourceStatus ?? "\u2014")}</td><td>${run.errors}</td><td>${run.warnings}</td><td>${run.findings}</td></tr>`
5075
+ ).join("");
5076
+ const findings = input.findingSummaries ?? [];
5077
+ const findingRows = findings.length === 0 ? `<p class="muted">No structured check findings recorded for the redacted artifact.</p>` : `<table>
5078
+ <thead><tr><th>runId</th><th>severity</th><th>rule</th><th>category</th><th>detector</th><th>message</th></tr></thead>
5079
+ <tbody>${findings.map(
5080
+ (f) => `<tr><td><code>${escapeHtml(f.runId)}</code></td><td>${escapeHtml(f.severity)}</td><td><code>${escapeHtml(f.ruleId)}</code></td><td>${escapeHtml(f.category ?? "\u2014")}</td><td>${escapeHtml(f.detector ?? "\u2014")}</td><td>${escapeHtml(boundMessage(f.message))}</td></tr>`
5081
+ ).join("")}</tbody>
5082
+ </table>`;
5083
+ return `<p>Aggregate artifact status: <strong>${escapeHtml(input.aggregateStatus)}</strong></p>
5084
+ <table>
5085
+ <thead><tr><th>runId</th><th>artifact</th><th>source</th><th>errors</th><th>warnings</th><th>findings</th></tr></thead>
5086
+ <tbody>${rows}</tbody>
5087
+ </table>
5088
+ <h3>Finding summaries</h3>
5089
+ ${findingRows}
5090
+ <p class="muted">TraceContract / check details are best-effort local results \u2014 not a compliance certification.</p>`;
5091
+ }
5092
+ function buildEvidenceOutcomesViewHtml(runs) {
5093
+ if (runs.length === 0) {
5094
+ return `<p class="muted">No runs available for outcome extraction.</p>`;
5095
+ }
5096
+ const parts = [];
5097
+ for (const run of runs) {
5098
+ const forRun = run.events.filter((event) => event.runId === run.runId);
5099
+ const summary = summarizeObservedOutcomes(extractOutcomesFromPersistedEvents(forRun));
5100
+ parts.push(`<article class="run-block">`);
5101
+ parts.push(`<h3><code>${escapeHtml(run.runId)}</code></h3>`);
5102
+ parts.push(renderObservedOutcomesHtml(summary));
5103
+ parts.push(`</article>`);
5104
+ }
5105
+ return parts.join("\n");
5106
+ }
5107
+ function buildEvidenceDiffViewHtml(parts) {
5108
+ if (parts === void 0 || parts.leftEvents.length === 0 || parts.rightEvents.length === 0) {
5109
+ return `<p class="muted">No baseline/candidate pair was supplied for this evidence bundle. Attach two runs (or a reporter baseline) to populate this view.</p>`;
5110
+ }
5111
+ try {
5112
+ const left = persistedInspectEventsToTraceEvents(
5113
+ parts.leftEvents.filter((e) => e.runId === parts.leftRunId)
5114
+ );
5115
+ const right = persistedInspectEventsToTraceEvents(
5116
+ parts.rightEvents.filter((e) => e.runId === parts.rightRunId)
5117
+ );
5118
+ if (left.length === 0 || right.length === 0) {
5119
+ return `<p class="muted">Could not normalize both runs for diff (missing v0.1-compatible events).</p>`;
5120
+ }
5121
+ const result = diffTraceEvents(left, right);
5122
+ const text = renderRunDiff(result, { color: false, verbose: false });
5123
+ return `<p>Comparing <code>${escapeHtml(parts.leftRunId)}</code> \u2192 <code>${escapeHtml(parts.rightRunId)}</code></p>
5124
+ <pre class="summary-md">${escapeHtml(text)}</pre>`;
5125
+ } catch (error) {
5126
+ const message = error instanceof Error ? error.message : String(error);
5127
+ return `<p class="muted">Diff unavailable: ${escapeHtml(message)}</p>`;
5128
+ }
5129
+ }
5130
+
5131
+ // packages/core/src/evidence/views-safety.ts
5132
+ function buildEvidenceSafetyViewHtml(input) {
5133
+ const findingRows = (input.findingSummaries ?? []).length === 0 ? `<p class="muted">No safety findings on the redacted artifact.</p>` : `<table>
5134
+ <thead><tr><th>runId</th><th>severity</th><th>category</th><th>detector</th><th>action</th><th>message</th></tr></thead>
5135
+ <tbody>${(input.findingSummaries ?? []).map((f) => {
5136
+ const msg = f.message.length > 160 ? `${f.message.slice(0, 160)}\u2026` : f.message;
5137
+ return `<tr><td><code>${escapeHtml(f.runId)}</code></td><td>${escapeHtml(f.severity)}</td><td>${escapeHtml(f.category ?? "\u2014")}</td><td>${escapeHtml(f.detector ?? "\u2014")}</td><td>${escapeHtml(f.action ?? "\u2014")}</td><td>${escapeHtml(msg)}</td></tr>`;
5138
+ }).join("")}</tbody>
5139
+ </table>`;
5140
+ const redactionBlock = input.redaction === void 0 ? `<p class="muted">No redaction report attached.</p>` : `<p>Total redaction findings: <strong>${input.redaction.totalFindings}</strong></p>
5141
+ <ul>${input.redaction.runs.map(
5142
+ (run) => `<li><code>${escapeHtml(run.runId)}</code>: ${run.findings} finding(s); detectors: ${escapeHtml(run.detectors.join(", ") || "none")}</li>`
5143
+ ).join("")}</ul>`;
5144
+ return `<p>Artifact status: <strong>${escapeHtml(String(input.artifactStatus))}</strong>
5145
+ ${input.sourceStatus !== void 0 ? ` \xB7 Source status: <strong>${escapeHtml(String(input.sourceStatus))}</strong>` : ""}</p>
5146
+ <p>Redaction profile: <code>${escapeHtml(input.redactionProfile)}</code> \xB7 Verification: <code>${escapeHtml(input.verificationPolicy)}</code></p>
5147
+ <h3>Redaction</h3>
5148
+ ${redactionBlock}
5149
+ <h3>Safety findings (artifact)</h3>
5150
+ ${findingRows}
5151
+ <p class="muted">Best-effort local verification only \u2014 not a compliance certification. Gate sharing on artifact status.</p>`;
5152
+ }
5153
+ function buildEvidenceProvenanceViewHtml(input) {
5154
+ const hashes = input.sourceHashes.length === 0 ? `<p class="muted">No source hashes recorded.</p>` : `<table>
5155
+ <thead><tr><th>runId</th><th>algorithm</th><th>hash</th></tr></thead>
5156
+ <tbody>${input.sourceHashes.map(
5157
+ (h) => `<tr><td><code>${escapeHtml(h.runId)}</code></td><td>${escapeHtml(h.algorithm)}</td><td><code>${escapeHtml(h.hash)}</code></td></tr>`
5158
+ ).join("")}</tbody>
5159
+ </table>`;
5160
+ const files = input.packagedFiles.length === 0 ? `<p class="muted">No packaged files listed.</p>` : `<ul>${input.packagedFiles.map(
5161
+ (f) => `<li><code>${escapeHtml(f.path)}</code>${f.role ? ` <span class="meta">(${escapeHtml(f.role)})</span>` : ""}</li>`
5162
+ ).join("")}</ul>`;
5163
+ return `<p>Generator: <code>${escapeHtml(input.generatorName)}@${escapeHtml(input.generatorVersion)}</code>
5164
+ \xB7 Evidence format: <code>${escapeHtml(input.evidenceFormatVersion)}</code>
5165
+ ${input.createdAt ? ` \xB7 Created: <code>${escapeHtml(input.createdAt)}</code>` : ""}</p>
5166
+ <p>Runs: ${input.runIds.map((id) => `<code>${escapeHtml(id)}</code>`).join(", ")}</p>
5167
+ <p>Trace schema versions: ${input.traceSchemaVersions.length > 0 ? input.traceSchemaVersions.map((v) => `<code>${escapeHtml(v)}</code>`).join(", ") : '<span class="muted">unknown</span>'}</p>
5168
+ <h3>Source hashes (pre-redaction input)</h3>
5169
+ ${hashes}
5170
+ <h3>Packaged files</h3>
5171
+ ${files}
5172
+ <p class="muted">${escapeHtml(input.note ?? "Reader/mapping losses are reported elsewhere when present; relationships are never invented without confidence policy.")}</p>`;
5173
+ }
5174
+ function buildEvidenceToolsLlmViewHtml(trees) {
5175
+ if (trees.length === 0) {
5176
+ return `<p class="muted">No runs available for tool/LLM metadata.</p>`;
5177
+ }
5178
+ const parts = [];
5179
+ for (const tree of trees) {
5180
+ const nodes = flattenTree(tree).filter(
5181
+ (n) => n.event.kind === "TOOL" || n.event.kind === "LLM" || n.event.kind === "AGENT"
5182
+ );
5183
+ parts.push(`<article class="run-block">`);
5184
+ parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
5185
+ if (nodes.length === 0) {
5186
+ parts.push(`<p class="muted">No TOOL/LLM/AGENT events in this run.</p>`);
5187
+ } else {
5188
+ parts.push(`<table>
5189
+ <thead><tr><th>name</th><th>kind</th><th>status</th><th>durationMs</th></tr></thead>
5190
+ <tbody>${nodes.map((n) => {
5191
+ const dur = n.event.durationMs !== void 0 && Number.isFinite(n.event.durationMs) ? String(n.event.durationMs) : "\u2014";
5192
+ return `<tr><td>${escapeHtml(n.event.name)}</td><td>${escapeHtml(n.event.kind)}</td><td>${escapeHtml(n.event.status ?? "?")}</td><td>${escapeHtml(dur)}</td></tr>`;
5193
+ }).join("")}</tbody>
5194
+ </table>`);
5195
+ }
5196
+ parts.push(`</article>`);
5197
+ }
5198
+ return parts.join("\n");
5199
+ }
5200
+ function buildEvidenceCircuitViewHtml(parts) {
5201
+ const findings = parts?.findings ?? [];
5202
+ if (findings.length === 0) {
5203
+ return `<p class="muted">No circuit or guardrail findings were attached to this evidence bundle.</p>`;
5204
+ }
5205
+ return `<table>
5206
+ <thead><tr><th>runId</th><th>name</th><th>status</th><th>detail</th></tr></thead>
5207
+ <tbody>${findings.map(
5208
+ (f) => `<tr><td><code>${escapeHtml(f.runId)}</code></td><td>${escapeHtml(f.name)}</td><td>${escapeHtml(f.status)}</td><td>${escapeHtml(f.detail ?? "\u2014")}</td></tr>`
5209
+ ).join("")}</tbody>
5210
+ </table>`;
5211
+ }
5212
+
5213
+ // packages/core/src/evidence/zip.ts
5214
+ var CRC_TABLE = (() => {
5215
+ const table = new Uint32Array(256);
5216
+ for (let n = 0; n < 256; n += 1) {
5217
+ let c = n;
5218
+ for (let k = 0; k < 8; k += 1) {
5219
+ c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
5220
+ }
5221
+ table[n] = c >>> 0;
5222
+ }
5223
+ return table;
5224
+ })();
5225
+ function crc32(data) {
5226
+ let crc = 4294967295;
5227
+ for (let i = 0; i < data.length; i += 1) {
5228
+ crc = CRC_TABLE[(crc ^ data[i]) & 255] ^ crc >>> 8;
5229
+ }
5230
+ return (crc ^ 4294967295) >>> 0;
5231
+ }
5232
+ function toBytes(content) {
5233
+ return typeof content === "string" ? Buffer.from(content, "utf8") : content;
5234
+ }
5235
+ function u16(value) {
5236
+ const buf = Buffer.alloc(2);
5237
+ buf.writeUInt16LE(value >>> 0, 0);
5238
+ return buf;
5239
+ }
5240
+ function u32(value) {
5241
+ const buf = Buffer.alloc(4);
5242
+ buf.writeUInt32LE(value >>> 0, 0);
5243
+ return buf;
5244
+ }
5245
+ function buildZipArchive(entries) {
5246
+ if (entries.length === 0) {
5247
+ throw new Error("ZIP archive requires at least one entry.");
5248
+ }
5249
+ const locals = [];
5250
+ const centrals = [];
5251
+ let offset = 0;
5252
+ const seen = /* @__PURE__ */ new Set();
5253
+ for (const entry of entries) {
5254
+ const name = assertEvidenceRelativePath(entry.path);
5255
+ if (seen.has(name)) {
5256
+ throw new Error(`Duplicate ZIP entry path: ${name}`);
5257
+ }
5258
+ seen.add(name);
5259
+ const nameBytes = Buffer.from(name, "utf8");
5260
+ const data = toBytes(entry.content);
5261
+ const checksum = crc32(data);
5262
+ const size = data.byteLength;
5263
+ const local = Buffer.concat([
5264
+ u32(67324752),
5265
+ u16(20),
5266
+ // version needed
5267
+ u16(0),
5268
+ // flags
5269
+ u16(0),
5270
+ // method STORE
5271
+ u16(0),
5272
+ // time
5273
+ u16(0),
5274
+ // date
5275
+ u32(checksum),
5276
+ u32(size),
5277
+ u32(size),
5278
+ u16(nameBytes.length),
5279
+ u16(0),
5280
+ // extra length
5281
+ nameBytes,
5282
+ Buffer.from(data)
5283
+ ]);
5284
+ const central = Buffer.concat([
5285
+ u32(33639248),
5286
+ u16(20),
5287
+ // version made by
5288
+ u16(20),
5289
+ // version needed
5290
+ u16(0),
5291
+ u16(0),
5292
+ u16(0),
5293
+ u16(0),
5294
+ u32(checksum),
5295
+ u32(size),
5296
+ u32(size),
5297
+ u16(nameBytes.length),
5298
+ u16(0),
5299
+ u16(0),
5300
+ u16(0),
5301
+ u16(0),
5302
+ u32(0),
5303
+ u32(offset),
5304
+ nameBytes
5305
+ ]);
5306
+ locals.push(local);
5307
+ centrals.push(central);
5308
+ offset += local.length;
5309
+ }
5310
+ const centralDir = Buffer.concat(centrals);
5311
+ const end = Buffer.concat([
5312
+ u32(101010256),
5313
+ u16(0),
5314
+ u16(0),
5315
+ u16(entries.length),
5316
+ u16(entries.length),
5317
+ u32(centralDir.length),
5318
+ u32(offset),
5319
+ u16(0)
5320
+ ]);
5321
+ return Buffer.concat([...locals, centralDir, end]);
5322
+ }
5323
+ async function listFilesRecursive(root) {
5324
+ const out = [];
5325
+ async function walk(dir) {
5326
+ const entries = await readdir(dir, { withFileTypes: true });
5327
+ for (const entry of entries) {
5328
+ const abs = path5.join(dir, entry.name);
5329
+ if (entry.isDirectory()) {
5330
+ await walk(abs);
5331
+ } else if (entry.isFile()) {
5332
+ const rel = path5.relative(root, abs).split(path5.sep).join("/");
5333
+ out.push(rel);
5334
+ }
5335
+ }
5336
+ }
5337
+ await walk(root);
5338
+ return out.sort((a, b) => a.localeCompare(b));
5339
+ }
5340
+ async function verifyEvidenceDirectory(rootPath, options = {}) {
5341
+ const unexpectedMode = options.unexpectedFiles ?? "fail";
5342
+ const root = path5.resolve(rootPath);
5343
+ const issues = [];
5344
+ let rootStat;
5345
+ try {
5346
+ rootStat = await stat(root);
5347
+ } catch (error) {
5348
+ const message = error instanceof Error ? error.message : String(error);
5349
+ return {
5350
+ ok: false,
5351
+ status: "fail",
5352
+ root,
5353
+ issues: [{ code: "io_error", severity: "error", message: `Cannot read path: ${message}` }],
5354
+ checkedFiles: 0
5355
+ };
5356
+ }
5357
+ if (!rootStat.isDirectory()) {
5358
+ return {
5359
+ ok: false,
5360
+ status: "fail",
5361
+ root,
5362
+ issues: [
5363
+ {
5364
+ code: "io_error",
5365
+ severity: "error",
5366
+ message: "Evidence verify expects a directory containing evidence.json (unpack ZIP first)."
5367
+ }
5368
+ ],
5369
+ checkedFiles: 0
5370
+ };
5371
+ }
5372
+ const manifestPath = path5.join(root, EVIDENCE_MANIFEST_FILENAME);
5373
+ let manifestText;
5374
+ try {
5375
+ manifestText = await readFile(manifestPath, "utf-8");
5376
+ } catch {
5377
+ return {
5378
+ ok: false,
5379
+ status: "fail",
5380
+ root,
5381
+ issues: [
5382
+ {
5383
+ code: "manifest_missing",
5384
+ severity: "error",
5385
+ message: `Missing ${EVIDENCE_MANIFEST_FILENAME}`,
5386
+ path: EVIDENCE_MANIFEST_FILENAME
5387
+ }
5388
+ ],
5389
+ checkedFiles: 0
5390
+ };
5391
+ }
5392
+ let manifest;
5393
+ try {
5394
+ manifest = parseEvidenceManifestJson(manifestText);
5395
+ } catch (error) {
5396
+ const message = error instanceof Error ? error.message : String(error);
5397
+ return {
5398
+ ok: false,
5399
+ status: "fail",
5400
+ root,
5401
+ issues: [
5402
+ {
5403
+ code: "manifest_invalid",
5404
+ severity: "error",
5405
+ message,
5406
+ path: EVIDENCE_MANIFEST_FILENAME
5407
+ }
5408
+ ],
5409
+ checkedFiles: 0
5410
+ };
5411
+ }
5412
+ if (!manifest.assessment?.status) {
5413
+ issues.push({
5414
+ code: "assessment_missing",
5415
+ severity: "error",
5416
+ message: "Manifest assessment.status is required."
5417
+ });
5418
+ }
5419
+ if (!manifest.generator?.name || !manifest.generator?.version) {
5420
+ issues.push({
5421
+ code: "provenance_missing",
5422
+ severity: "error",
5423
+ message: "Manifest generator.name and generator.version are required."
5424
+ });
5425
+ }
5426
+ if (!manifest.source?.runIds?.length) {
5427
+ issues.push({
5428
+ code: "provenance_missing",
5429
+ severity: "error",
5430
+ message: "Manifest source.runIds must be non-empty."
5431
+ });
5432
+ }
5433
+ const listed = /* @__PURE__ */ new Set();
5434
+ for (const file of manifest.files) {
5435
+ let rel;
5436
+ try {
5437
+ rel = assertEvidenceRelativePath(file.path);
5438
+ } catch (error) {
5439
+ const message = error instanceof Error ? error.message : String(error);
5440
+ issues.push({
5441
+ code: "path_unsafe",
5442
+ severity: "error",
5443
+ message,
5444
+ path: file.path
5445
+ });
5446
+ continue;
5447
+ }
5448
+ if (rel === EVIDENCE_MANIFEST_FILENAME) {
5449
+ issues.push({
5450
+ code: "manifest_invalid",
5451
+ severity: "error",
5452
+ message: `${EVIDENCE_MANIFEST_FILENAME} must not list itself in files[].`,
5453
+ path: rel
5454
+ });
5455
+ continue;
5456
+ }
5457
+ listed.add(rel);
5458
+ const abs = path5.join(root, ...rel.split("/"));
5459
+ let bytes;
5460
+ try {
5461
+ bytes = await readFile(abs);
5462
+ } catch {
5463
+ issues.push({
5464
+ code: "file_missing",
5465
+ severity: "error",
5466
+ message: `Listed file missing: ${rel}`,
5467
+ path: rel
5468
+ });
5469
+ continue;
5470
+ }
5471
+ const actual = sha256Hex(bytes);
5472
+ if (!sha256Equals(file.sha256, actual)) {
5473
+ issues.push({
5474
+ code: "hash_mismatch",
5475
+ severity: "error",
5476
+ message: `SHA-256 mismatch for ${rel}`,
5477
+ path: rel
5478
+ });
5479
+ }
5480
+ }
5481
+ let onDisk = [];
5482
+ try {
5483
+ onDisk = await listFilesRecursive(root);
5484
+ } catch (error) {
5485
+ const message = error instanceof Error ? error.message : String(error);
5486
+ issues.push({ code: "io_error", severity: "error", message });
5487
+ }
5488
+ for (const rel of onDisk) {
5489
+ if (rel === EVIDENCE_MANIFEST_FILENAME) continue;
5490
+ if (listed.has(rel)) continue;
5491
+ if (unexpectedMode === "ignore") continue;
5492
+ issues.push({
5493
+ code: "file_unexpected",
5494
+ severity: unexpectedMode === "warn" ? "warning" : "error",
5495
+ message: `Unexpected file not listed in manifest: ${rel}`,
5496
+ path: rel
5497
+ });
5498
+ }
5499
+ const hasError = issues.some((issue) => issue.severity === "error");
5500
+ return {
5501
+ ok: !hasError,
5502
+ status: hasError ? "fail" : "pass",
5503
+ root,
5504
+ manifest,
5505
+ issues,
5506
+ checkedFiles: listed.size
5507
+ };
5508
+ }
5509
+
5510
+ // packages/core/src/evidence/ci.ts
5511
+ function asMap(value) {
5512
+ if (value instanceof Map) return new Map(value);
5513
+ return new Map(Object.entries(value));
5514
+ }
5515
+ function buildEvidenceCiPackage(input) {
5516
+ const sources = asMap(input.sourceContents);
5517
+ const sourceHashes = input.runIds.map((runId) => ({
5518
+ runId,
5519
+ algorithm: "sha256",
5520
+ hash: sha256Hex(sources.get(runId) ?? "")
5521
+ }));
5522
+ const schemaVersions = /* @__PURE__ */ new Set();
5523
+ for (const content of sources.values()) {
5524
+ for (const version of collectTraceSchemaVersions(content)) {
5525
+ schemaVersions.add(version);
5526
+ }
5527
+ }
5528
+ for (const version of collectTraceSchemaVersions(input.redactedTraceJsonl)) {
5529
+ schemaVersions.add(version);
5530
+ }
5531
+ const createdAt = input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
5532
+ const evidenceHtml = buildEvidenceHtmlShell({
5533
+ title: "AgentInspect evidence",
5534
+ runIds: input.runIds,
5535
+ assessmentStatus: input.assessmentStatus,
5536
+ sourceStatus: input.sourceStatus,
5537
+ redactionProfile: input.redactionProfile,
5538
+ verificationPolicy: input.redactionProfile,
5539
+ generatorName: "agent-inspect",
5540
+ generatorVersion: input.generatorVersion,
5541
+ createdAt,
5542
+ summaryText: input.summaryText,
5543
+ checkSummary: {
5544
+ aggregateStatus: input.assessmentStatus,
5545
+ runs: input.runIds.map((runId) => ({
5546
+ runId,
5547
+ status: input.assessmentStatus,
5548
+ sourceStatus: input.sourceStatus,
5549
+ errors: input.assessmentStatus === "UNSAFE" || input.assessmentStatus === "UNKNOWN" ? 1 : 0,
5550
+ warnings: input.assessmentStatus === "SAFE WITH WARNINGS" ? 1 : 0,
5551
+ findings: 0
5552
+ }))
5553
+ }
5554
+ });
5555
+ const packaged = [
5556
+ { path: EVIDENCE_HTML_FILENAME, content: evidenceHtml },
5557
+ { path: "check-results.json", content: input.checkResultsJson },
5558
+ { path: "trace.jsonl", content: input.redactedTraceJsonl }
5559
+ ];
5560
+ const manifest = buildEvidenceManifest({
5561
+ generatorVersion: input.generatorVersion,
5562
+ runIds: input.runIds,
5563
+ traceSchemaVersions: [...schemaVersions].sort((a, b) => a.localeCompare(b)),
5564
+ sourceHashes,
5565
+ redactionProfile: input.redactionProfile,
5566
+ verificationPolicy: input.redactionProfile,
5567
+ assessmentStatus: input.assessmentStatus,
5568
+ sourceStatus: input.sourceStatus,
5569
+ files: packaged,
5570
+ createdAt,
5571
+ note: EVIDENCE_ASSESSMENT_NOTE
5572
+ });
5573
+ return {
5574
+ "evidence.html": evidenceHtml,
5575
+ "evidence.json": serializeEvidenceManifest(manifest),
5576
+ "check-results.json": input.checkResultsJson,
5577
+ "trace.jsonl": input.redactedTraceJsonl,
5578
+ manifest
5579
+ };
5580
+ }
5581
+
3867
5582
  // packages/core/src/suite/types.ts
3868
5583
  var DEFAULT_SUITE_CONFIG_NAMES = [
3869
5584
  "agent-inspect.suite.json",
@@ -4433,7 +6148,7 @@ function stripPrefix(name, prefixes) {
4433
6148
  }
4434
6149
  return name;
4435
6150
  }
4436
- function eventEvidence(event, path12) {
6151
+ function eventEvidence(event, path14) {
4437
6152
  return {
4438
6153
  runId: event.runId,
4439
6154
  eventId: event.eventId,
@@ -4443,7 +6158,7 @@ function eventEvidence(event, path12) {
4443
6158
  kind: event.kind,
4444
6159
  name: event.name,
4445
6160
  status: event.status,
4446
- ...path12 ? { path: path12 } : {}
6161
+ ...path14 ? { path: path14 } : {}
4447
6162
  };
4448
6163
  }
4449
6164
  function runEvidence(run) {
@@ -4510,9 +6225,9 @@ function eventEndMs(event) {
4510
6225
  function normalizedKey(value) {
4511
6226
  return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
4512
6227
  }
4513
- function lastPathSegment(path12) {
4514
- const parts = path12.split(".");
4515
- return parts[parts.length - 1] ?? path12;
6228
+ function lastPathSegment(path14) {
6229
+ const parts = path14.split(".");
6230
+ return parts[parts.length - 1] ?? path14;
4516
6231
  }
4517
6232
  function valueType(value) {
4518
6233
  if (Array.isArray(value)) return "array";
@@ -4526,12 +6241,12 @@ function serializedByteLength(value) {
4526
6241
  return void 0;
4527
6242
  }
4528
6243
  }
4529
- function pushValueEntries(entries, event, value, path12, key, depth = 0) {
4530
- entries.push({ event, path: path12, key, value });
6244
+ function pushValueEntries(entries, event, value, path14, key, depth = 0) {
6245
+ entries.push({ event, path: path14, key, value });
4531
6246
  if (depth >= 8) return;
4532
6247
  if (Array.isArray(value)) {
4533
6248
  for (const [index, item] of value.entries()) {
4534
- pushValueEntries(entries, event, item, `${path12}.${index}`, String(index), depth + 1);
6249
+ pushValueEntries(entries, event, item, `${path14}.${index}`, String(index), depth + 1);
4535
6250
  }
4536
6251
  return;
4537
6252
  }
@@ -4541,7 +6256,7 @@ function pushValueEntries(entries, event, value, path12, key, depth = 0) {
4541
6256
  entries,
4542
6257
  event,
4543
6258
  value[nestedKey],
4544
- `${path12}.${nestedKey}`,
6259
+ `${path14}.${nestedKey}`,
4545
6260
  nestedKey,
4546
6261
  depth + 1
4547
6262
  );
@@ -4582,18 +6297,18 @@ function isRawContentKey(key, forbiddenKeys) {
4582
6297
  const normalized = normalizedKey(key);
4583
6298
  return forbiddenKeys.some((forbidden) => normalized === normalizedKey(forbidden));
4584
6299
  }
4585
- function isSafeRawContentMetricPath(path12, key, safePathPrefixes) {
4586
- const leaf = normalizedKey(key ?? lastPathSegment(path12));
6300
+ function isSafeRawContentMetricPath(path14, key, safePathPrefixes) {
6301
+ const leaf = normalizedKey(key ?? lastPathSegment(path14));
4587
6302
  if (!SAFE_USAGE_LEAF_KEYS.has(leaf)) return false;
4588
- const parts = path12.split(".").filter(Boolean);
6303
+ const parts = path14.split(".").filter(Boolean);
4589
6304
  if (parts.length < 2) return false;
4590
6305
  const parent = parts[parts.length - 2] ?? "";
4591
6306
  const parentNorm = normalizedKey(parent);
4592
6307
  return safePathPrefixes.some((prefix) => parentNorm === normalizedKey(prefix));
4593
6308
  }
4594
- function isRawContentPath(path12, key, forbiddenKeys, safePathPrefixes) {
4595
- if (isSafeRawContentMetricPath(path12, key, safePathPrefixes)) return false;
4596
- return isRawContentKey(key ?? lastPathSegment(path12), forbiddenKeys);
6309
+ function isRawContentPath(path14, key, forbiddenKeys, safePathPrefixes) {
6310
+ if (isSafeRawContentMetricPath(path14, key, safePathPrefixes)) return false;
6311
+ return isRawContentKey(key ?? lastPathSegment(path14), forbiddenKeys);
4597
6312
  }
4598
6313
  function parentMarkedUnresolved(event) {
4599
6314
  if (booleanAttr(event, [
@@ -4635,9 +6350,9 @@ function eventDurationMs(event) {
4635
6350
  }
4636
6351
  function treeShape(nodes) {
4637
6352
  const lines = [];
4638
- const visit = (node, path12) => {
4639
- lines.push(`${path12}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
4640
- node.children.forEach((child, index) => visit(child, `${path12}.${index}`));
6353
+ const visit = (node, path14) => {
6354
+ lines.push(`${path14}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
6355
+ node.children.forEach((child, index) => visit(child, `${path14}.${index}`));
4641
6356
  };
4642
6357
  nodes.forEach((node, index) => visit(node, String(index)));
4643
6358
  return lines;
@@ -4686,9 +6401,9 @@ function retrievalShape(context) {
4686
6401
  function guardrailShape(context) {
4687
6402
  return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
4688
6403
  }
4689
- function firstEvidenceForKind(context, kind, path12) {
6404
+ function firstEvidenceForKind(context, kind, path14) {
4690
6405
  const event = context.events.find((candidate) => candidate.kind === kind);
4691
- return event ? [eventEvidence(event, path12)] : runEvidence(context.selectedRun);
6406
+ return event ? [eventEvidence(event, path14)] : runEvidence(context.selectedRun);
4692
6407
  }
4693
6408
  function baselineDiffFinding(message, evidence, expected, actual) {
4694
6409
  return failFinding("baseline.regression", message, evidence, expected, actual);
@@ -5038,13 +6753,13 @@ function createStructureCycleRule() {
5038
6753
  const seenCycles = /* @__PURE__ */ new Set();
5039
6754
  const findings = [];
5040
6755
  for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
5041
- const path12 = [];
6756
+ const path14 = [];
5042
6757
  const seenAt = /* @__PURE__ */ new Map();
5043
6758
  let current = event;
5044
6759
  while (current) {
5045
6760
  const existing = seenAt.get(current.eventId);
5046
6761
  if (existing !== void 0) {
5047
- const cycle = path12.slice(existing);
6762
+ const cycle = path14.slice(existing);
5048
6763
  const key = cycle.map((item) => item.eventId).sort().join("\0");
5049
6764
  if (!seenCycles.has(key)) {
5050
6765
  seenCycles.add(key);
@@ -5060,8 +6775,8 @@ function createStructureCycleRule() {
5060
6775
  }
5061
6776
  break;
5062
6777
  }
5063
- seenAt.set(current.eventId, path12.length);
5064
- path12.push(current);
6778
+ seenAt.set(current.eventId, path14.length);
6779
+ path14.push(current);
5065
6780
  current = current.parentId ? byId.get(current.parentId) : void 0;
5066
6781
  }
5067
6782
  }
@@ -5718,7 +7433,7 @@ function mapErrorInfo(error) {
5718
7433
  function mapTokenUsageFromMetadata(metadata) {
5719
7434
  return normalizeTokenUsage(metadata?.tokens);
5720
7435
  }
5721
- function compactAttributes(entries) {
7436
+ function compactAttributes2(entries) {
5722
7437
  const out = {};
5723
7438
  for (const [key, value] of Object.entries(entries)) {
5724
7439
  if (value !== void 0) {
@@ -5736,7 +7451,7 @@ function traceEventToPersistedInspectEvent(event, options) {
5736
7451
  case "run_started": {
5737
7452
  const tsStart = toIsoTimestamp(event.startTime);
5738
7453
  const correlation = extractCorrelationMetadata(event.metadata);
5739
- const attributes = compactAttributes({
7454
+ const attributes = compactAttributes2({
5740
7455
  legacyEvent: "run_started",
5741
7456
  metadata: event.metadata !== void 0 ? { ...event.metadata } : void 0,
5742
7457
  correlationId: correlation?.correlationId,
@@ -5762,7 +7477,7 @@ function traceEventToPersistedInspectEvent(event, options) {
5762
7477
  case "run_completed": {
5763
7478
  const tsEnd = toIsoTimestamp(event.endTime);
5764
7479
  const { persisted: error, errorStack } = mapErrorInfo(event.error);
5765
- const attributes = compactAttributes({
7480
+ const attributes = compactAttributes2({
5766
7481
  legacyEvent: "run_completed",
5767
7482
  errorStack,
5768
7483
  invalidTimestamp: tsMain.invalidTimestamp || tsEnd.invalidTimestamp ? true : void 0
@@ -5786,7 +7501,7 @@ function traceEventToPersistedInspectEvent(event, options) {
5786
7501
  case "step_started": {
5787
7502
  const tsStart = toIsoTimestamp(event.startTime);
5788
7503
  const tokenUsage = mapTokenUsageFromMetadata(event.metadata);
5789
- const attributes = compactAttributes({
7504
+ const attributes = compactAttributes2({
5790
7505
  legacyEvent: "step_started",
5791
7506
  stepId: event.stepId,
5792
7507
  stepType: event.type,
@@ -5817,7 +7532,7 @@ function traceEventToPersistedInspectEvent(event, options) {
5817
7532
  case "step_completed": {
5818
7533
  const tsEnd = toIsoTimestamp(event.endTime);
5819
7534
  const { persisted: error, errorStack } = mapErrorInfo(event.error);
5820
- const attributes = compactAttributes({
7535
+ const attributes = compactAttributes2({
5821
7536
  legacyEvent: "step_completed",
5822
7537
  stepId: event.stepId,
5823
7538
  errorStack,
@@ -5841,7 +7556,7 @@ function traceEventToPersistedInspectEvent(event, options) {
5841
7556
  }
5842
7557
  case "outcome_observed": {
5843
7558
  const tsObserved = toIsoTimestamp(event.observedAt);
5844
- const attributes = compactAttributes({
7559
+ const attributes = compactAttributes2({
5845
7560
  legacyEvent: "outcome_observed",
5846
7561
  outcomeId: event.outcomeId,
5847
7562
  outcomeStatus: event.status,
@@ -5976,7 +7691,7 @@ var TreeBuilder = class {
5976
7691
  };
5977
7692
 
5978
7693
  // packages/core/src/persisted/to-inspect-event.ts
5979
- function compactAttributes2(entries) {
7694
+ function compactAttributes3(entries) {
5980
7695
  const out = {};
5981
7696
  for (const [key, value] of Object.entries(entries)) {
5982
7697
  if (value !== void 0) {
@@ -6085,7 +7800,7 @@ function persistedInspectEventToInspectEvent(event) {
6085
7800
  timestamp: ts.ms,
6086
7801
  confidence: event.confidence,
6087
7802
  source: mapPersistedSourceToInspect(event),
6088
- attributes: compactAttributes2(attrs)
7803
+ attributes: compactAttributes3(attrs)
6089
7804
  };
6090
7805
  if (event.parentId !== void 0) {
6091
7806
  out.parentId = event.parentId;
@@ -8558,114 +10273,6 @@ async function analyzeCohort(runsInput, options) {
8558
10273
  };
8559
10274
  }
8560
10275
 
8561
- // packages/core/src/exporters/helpers.ts
8562
- var REDACT_SUBSTRINGS = [
8563
- "authorization",
8564
- "cookie",
8565
- "token",
8566
- "apikey",
8567
- "password",
8568
- "secret",
8569
- "email"
8570
- ];
8571
- function shouldRedactKey(key) {
8572
- const k = key.toLowerCase();
8573
- for (const s of REDACT_SUBSTRINGS) {
8574
- if (k.includes(s)) return true;
8575
- }
8576
- return false;
8577
- }
8578
- function safeString(value, maxLength) {
8579
- if (value === null || value === void 0) return "";
8580
- let s;
8581
- if (typeof value === "string") s = value;
8582
- else if (typeof value === "number" || typeof value === "boolean") s = String(value);
8583
- else s = stableJson(value, false);
8584
- if (maxLength !== void 0 && maxLength >= 0 && s.length > maxLength) {
8585
- return `${s.slice(0, maxLength)}\u2026`;
8586
- }
8587
- return s;
8588
- }
8589
- function escapeMarkdown(value) {
8590
- return value.replace(/\|/g, "\\|").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n/g, " ");
8591
- }
8592
- function escapeHtml(value) {
8593
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
8594
- }
8595
- function sortKeysDeep(input) {
8596
- if (input === null || typeof input !== "object") return input;
8597
- if (Array.isArray(input)) return input.map(sortKeysDeep);
8598
- const o = input;
8599
- const out = {};
8600
- for (const k of Object.keys(o).sort()) {
8601
- out[k] = sortKeysDeep(o[k]);
8602
- }
8603
- return out;
8604
- }
8605
- function stableJson(value, pretty) {
8606
- const sorted = sortKeysDeep(value);
8607
- return pretty === true ? JSON.stringify(sorted, null, 2) : JSON.stringify(sorted);
8608
- }
8609
- function compactAttributes3(attrs, options) {
8610
- if (attrs === void 0) return {};
8611
- const maxLen = options?.maxLength ?? 500;
8612
- const redacted = options?.redacted ?? true;
8613
- const out = {};
8614
- for (const key of Object.keys(attrs).sort()) {
8615
- if (redacted && shouldRedactKey(key)) {
8616
- out[key] = "[REDACTED]";
8617
- continue;
8618
- }
8619
- const v = attrs[key];
8620
- out[key] = compactValue(v, maxLen, redacted);
8621
- }
8622
- return out;
8623
- }
8624
- function compactValue(value, maxLen, redacted) {
8625
- if (value === null || typeof value !== "object") {
8626
- return typeof value === "string" ? safeString(value, maxLen) : value;
8627
- }
8628
- if (Array.isArray(value)) {
8629
- const arr = value.slice(0, 20).map((x) => compactValue(x, maxLen, redacted));
8630
- if (value.length > 20) arr.push(`\u2026(+${value.length - 20} more)`);
8631
- return arr;
8632
- }
8633
- const o = value;
8634
- const inner = {};
8635
- for (const k of Object.keys(o)) {
8636
- if (redacted && shouldRedactKey(k)) inner[k] = "[REDACTED]";
8637
- else inner[k] = compactValue(o[k], maxLen, redacted);
8638
- }
8639
- return inner;
8640
- }
8641
- function flattenTree(tree) {
8642
- const out = [];
8643
- function walk(nodes) {
8644
- for (const n of nodes) {
8645
- out.push(n);
8646
- if (n.children.length > 0) walk(n.children);
8647
- }
8648
- }
8649
- walk(tree.children);
8650
- return out;
8651
- }
8652
- function zeroKinds() {
8653
- return {
8654
- RUN: 0,
8655
- AGENT: 0,
8656
- LLM: 0,
8657
- TOOL: 0,
8658
- CHAIN: 0,
8659
- RETRIEVER: 0,
8660
- DECISION: 0,
8661
- RESULT: 0,
8662
- ERROR: 0,
8663
- LOGIC: 0,
8664
- LOG: 0,
8665
- OUTCOME: 0
8666
- };
8667
- }
8668
-
8669
10276
  // packages/core/src/cohort/render.ts
8670
10277
  function formatRate(value) {
8671
10278
  if (value === void 0) return "n/a";
@@ -9146,6 +10753,6 @@ function renderGateReport(result, options = {}) {
9146
10753
  return renderGateSummaryMarkdown(result);
9147
10754
  }
9148
10755
 
9149
- export { COHORT_METRIC_IDS, DEFAULT_SUITE_ARTIFACTS_DIR, Redactor, TraceDirectory, TraceReadError, TreeBuilder, aggregateBundleSafeStatus, aggregateSessionCheckResults, analyzeCohort, applyProfileMetadataCaps, assertBundlePathContained, buildActivitySummary, buildBundleMetadata, buildBundleSummaryMarkdown, buildLocalExplanation, buildPlaceholderArtifact, buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildSessionIndex, buildTraceStats, bundleFailsOnSafety, bundleRunAssetRelativePath, compactAttributes3 as compactAttributes, createBaselineRegressionRule, createLlmUsageRule, createMaxStepDurationRule, createObservedOutcomeRule, createRequireCompletedRule, createRunDepthRule, createRunDurationRule, createRunStatusRule, createSafetyOversizedAttributeRule, createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createStallDetectionRule, createStructureCycleRule, createStructureOrphanRule, createStructureParallelWidthRule, createStructureRelationshipRule, createToolUsageRule, defaultBundleOutputPath, defaultSuiteConfigTemplate, enrichSessionRunRecord, escapeHtml, escapeMarkdown, extractMetadata, extractOutcomesFromTraceEvents, filterMetasBySessionScope, filterTraces, flattenTree, formatDuration2 as formatDuration, formatTimestamp, gateHasThresholds, getIndent, getTraceFilePath, isAgentInspectTrace, isPersistedInspectEvent, loadSessionRunRecords, loadSuiteConfig, loadTraceMetadataList, nanoid, normalizeBundleOutputPath, openTrace, parseCohortMetricList, parseDuration, parseDurationFilter, parseGateList, parseTraceJsonl, persistedInspectEventsToTraceEvents, renderActivitySummaryHuman, renderCohortReport, renderErrorLine, renderGateReport, renderObservedOutcomesHtml, renderObservedOutcomesMarkdown, renderRunWhat, renderStepLine, renderSuiteReport, renderTimeline, renderTraceStats, resolveBundleRunIds, resolveRedactionProfile, resolveSuiteTemplate, resolveTraceDir, runGate, runSuite, runTraceChecks, safeString, sanitizeBundleRunId, searchTraces, source_default, stableJson, summarizeObservedOutcomes, traceEventToPersistedInspectEvent, truncateName, truncateStringForProfile, validateEvent, validateSuiteConfig, zeroKinds };
9150
- //# sourceMappingURL=chunk-WQ5XMFH2.mjs.map
9151
- //# sourceMappingURL=chunk-WQ5XMFH2.mjs.map
10756
+ export { COHORT_METRIC_IDS, DEFAULT_SUITE_ARTIFACTS_DIR, EVIDENCE_FORMAT_VERSION, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, Redactor, TraceDirectory, TraceReadError, TreeBuilder, aggregateBundleSafeStatus, aggregateSessionCheckResults, analyzeCohort, applyProfileMetadataCaps, assertBundlePathContained, assertEvidenceRelativePath, buildActivitySummary, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceCausalFailureViewHtml, buildEvidenceCiPackage, buildEvidenceCircuitViewHtml, buildEvidenceContractsViewHtml, buildEvidenceDiffViewHtml, buildEvidenceHtmlShell, buildEvidenceManifest, buildEvidenceOutcomesViewHtml, buildEvidenceProvenanceViewHtml, buildEvidenceSafetyViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceTreeViewHtml, buildLocalExplanation, buildPlaceholderArtifact, buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildSessionIndex, buildTraceStats, buildZipArchive, bundleFailsOnSafety, bundleRunAssetRelativePath, collectTraceSchemaVersions, compactAttributes, createBaselineRegressionRule, createLlmUsageRule, createMaxStepDurationRule, createObservedOutcomeRule, createRequireCompletedRule, createRunDepthRule, createRunDurationRule, createRunStatusRule, createSafetyOversizedAttributeRule, createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createStallDetectionRule, createStructureCycleRule, createStructureOrphanRule, createStructureParallelWidthRule, createStructureRelationshipRule, createToolUsageRule, defaultBundleOutputPath, defaultSuiteConfigTemplate, diffRuns, diffTraceEvents, enrichSessionRunRecord, escapeHtml, escapeMarkdown, extractMetadata, extractOutcomesFromTraceEvents, filterMetasBySessionScope, filterTraces, flattenTree, formatDuration2 as formatDuration, formatTimestamp, gateHasThresholds, getIndent, getTraceFilePath, inferEvidenceFileRole, isAgentInspectTrace, isPersistedInspectEvent, loadSessionRunRecords, loadSuiteConfig, loadTraceMetadataList, manualTraceEventsToComparableRun, nanoid, normalizeBundleOutputPath, openTrace, parseCohortMetricList, parseDuration, parseDurationFilter, parseGateList, parseTraceJsonl, persistedInspectEventsToTraceEvents, renderActivitySummaryHuman, renderCohortReport, renderErrorLine, renderGateReport, renderObservedOutcomesHtml, renderObservedOutcomesMarkdown, renderRunDiff, renderRunWhat, renderStepLine, renderSuiteReport, renderTimeline, renderTraceStats, resolveBundleRunIds, resolveRedactionProfile, resolveSuiteTemplate, resolveTraceDir, runGate, runSuite, runTraceChecks, safeString, sanitizeBundleRunId, searchTraces, serializeEvidenceManifest, sha256Hex, stableJson, summarizeObservedOutcomes, traceEventToPersistedInspectEvent, truncateName, truncateStringForProfile, validateEvent, validateSuiteConfig, verifyEvidenceDirectory, zeroKinds };
10757
+ //# sourceMappingURL=chunk-XTAA733P.mjs.map
10758
+ //# sourceMappingURL=chunk-XTAA733P.mjs.map