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,11 +1,12 @@
1
1
  import { runTraceChecks, createRunStatusRule, createToolUsageRule, createRunDurationRule, createLlmUsageRule, createObservedOutcomeRule } from './chunk-QT6CQ2XA.mjs';
2
2
  export { MAX_TERMINAL_DEPTH, MAX_TERMINAL_NAME_LENGTH, TERMINAL_INDENT, TraceDirectory, createInspector, createInspectorRuntime, formatTerminalName, getCurrentContext, getCurrentCorrelationMetadata, getCurrentDepth, getCurrentRunId, getCurrentRunName, getCurrentStepId, getIndent, getParentStepId, getTraceDirFromContext, getTraceSafetyFromContext, hasActiveContext, isAgentInspectEnabled, isSilentContext, maybeInspectRun, printError, printFailedAt, printRunComplete, printRunStart, printStepComplete, printStepStart, renderErrorLine, renderRunSummary, renderStepLine, resolveTraceDir, runWithContext, runWithStepContext } from './chunk-ZWA5RWMV.mjs';
3
- import { filterTraces, extractMetadata, buildRunSummary } from './chunk-KDDU2R5P.mjs';
4
- export { buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildTraceStats, extractMetadata, filterTraces, renderRunWhat, renderTimeline, renderTraceStats } from './chunk-KDDU2R5P.mjs';
5
- import { parseObservationFilter, extractOutcomesFromTraceEvents, extractOutcomesFromPersistedEvents } from './chunk-VFO76UH3.mjs';
3
+ import { buildRunTimeline, filterTraces, extractMetadata, buildRunSummary } from './chunk-LFWZEO2L.mjs';
4
+ export { buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildTraceStats, extractMetadata, filterTraces, renderRunWhat, renderTimeline, renderTraceStats } from './chunk-LFWZEO2L.mjs';
5
+ import { extractOutcomesFromTraceEvents, parseObservationFilter, summarizeObservedOutcomes, extractOutcomesFromPersistedEvents, renderObservedOutcomesHtml } from './chunk-VFO76UH3.mjs';
6
6
  export { extractOutcomesFromPersistedEvents, extractOutcomesFromTraceEvents } from './chunk-VFO76UH3.mjs';
7
+ import { diffTraceEvents, renderRunDiff } from './chunk-F7STQ5JF.mjs';
7
8
  import './chunk-BT7CATSD.mjs';
8
- import { escapeHtml } from './chunk-CAWPF22J.mjs';
9
+ import { escapeHtml, flattenTree } from './chunk-CAWPF22J.mjs';
9
10
  import { resolveRedactionProfile, readTraceEventsFromFile } from './chunk-ULCGIRTC.mjs';
10
11
  export { DEFAULT_MAX_EVENT_BYTES, DEFAULT_MAX_METADATA_VALUE_LENGTH, DEFAULT_MAX_PREVIEW_LENGTH, getRunIdFromTraceFileName, initializeTraceFile, listTraceFiles, prepareMetadataForDisk, prepareTraceEventForDisk, readTraceEvents, readTraceFile, resolveRedactionProfile, resolveTraceSafetyOptions, serializeEvent, validateEvent, writeTraceEvent } from './chunk-ULCGIRTC.mjs';
11
12
  import { Redactor } from './chunk-VU6O5QAH.mjs';
@@ -15,14 +16,157 @@ import './chunk-S4YWKV4G.mjs';
15
16
  import './chunk-T5MASTIW.mjs';
16
17
  import { parseDuration, isTraceEvent, getTraceFilePath } from './chunk-WRE4CNPF.mjs';
17
18
  export { DEFAULT_TRACE_DIR_NAME, FALLBACK_TRACE_DIR, MAX_NAME_LENGTH, RUNS_DIR_NAME, createRunId, createStepId, ensureTraceDir, formatDuration, formatError, formatTimestamp, getDefaultTraceDir, getTraceFilePath, isStepStatus, isStepType, isTraceEvent, parseDuration, parseTraceJsonl, truncateName, unknownTraceFormatMessage, warn } from './chunk-WRE4CNPF.mjs';
18
- import './chunk-P366CCL2.mjs';
19
+ import { persistedInspectEventsToTraceEvents } from './chunk-P366CCL2.mjs';
19
20
  import './chunk-7TGZLWEE.mjs';
20
21
  import { createReadStream } from 'fs';
21
22
  import { createInterface } from 'readline';
22
23
  import path from 'path';
23
- import { access, readFile } from 'fs/promises';
24
+ import { createHash } from 'crypto';
25
+ import { stat, readFile, access, readdir } from 'fs/promises';
24
26
  import { pathToFileURL } from 'url';
25
27
 
28
+ // packages/core/src/causal-failure.ts
29
+ function runIdFromEvents(events) {
30
+ for (const event of events) {
31
+ if ("runId" in event && typeof event.runId === "string") return event.runId;
32
+ }
33
+ return void 0;
34
+ }
35
+ function noneResult(runId, rationale) {
36
+ return {
37
+ kind: "none",
38
+ evidenceIds: [],
39
+ rationale,
40
+ orderIndex: 0,
41
+ runId,
42
+ engine: "conservative-causal-v1"
43
+ };
44
+ }
45
+ function findFirstCausalFailure(events, options = {}) {
46
+ const runId = runIdFromEvents(events);
47
+ const timeline = buildRunTimeline(events);
48
+ const firstError = timeline.entries.find((entry) => entry.isError);
49
+ if (firstError) {
50
+ return {
51
+ kind: "explicit_error_event",
52
+ evidenceIds: [firstError.stepId],
53
+ rationale: "First timeline step with status error (explicit failure; no timing-only inference).",
54
+ orderIndex: 1,
55
+ runId: timeline.runId || runId,
56
+ primary: {
57
+ stepId: firstError.stepId,
58
+ name: firstError.name
59
+ },
60
+ relationship: { role: "self", relatedIds: [] },
61
+ engine: "conservative-causal-v1"
62
+ };
63
+ }
64
+ const runCompletedError = events.find(
65
+ (event) => event.event === "run_completed" && event.status === "error"
66
+ );
67
+ if (runCompletedError) {
68
+ return {
69
+ kind: "explicit_error_event",
70
+ evidenceIds: [runCompletedError.runId],
71
+ rationale: "Run completed with status error and no earlier errored step.",
72
+ orderIndex: 1,
73
+ runId: runCompletedError.runId,
74
+ primary: { name: "run", stepId: runCompletedError.runId },
75
+ relationship: { role: "self", relatedIds: [] },
76
+ engine: "conservative-causal-v1"
77
+ };
78
+ }
79
+ const outcomes = extractOutcomesFromTraceEvents(events);
80
+ const failedOutcome = outcomes.find((outcome) => outcome.status === "failed");
81
+ if (failedOutcome) {
82
+ const evidenceIds = [failedOutcome.outcomeId];
83
+ if (failedOutcome.parentId) evidenceIds.push(failedOutcome.parentId);
84
+ return {
85
+ kind: "failed_observed_outcome",
86
+ evidenceIds,
87
+ rationale: "First observed outcome with status failed.",
88
+ orderIndex: 2,
89
+ runId: failedOutcome.runId || runId,
90
+ primary: {
91
+ outcomeId: failedOutcome.outcomeId,
92
+ stepId: failedOutcome.parentId,
93
+ name: failedOutcome.name
94
+ },
95
+ relationship: failedOutcome.parentId ? { role: "child", relatedIds: [failedOutcome.parentId] } : { role: "self", relatedIds: [] },
96
+ engine: "conservative-causal-v1"
97
+ };
98
+ }
99
+ const contractFail = (options.contractFindings ?? []).find(
100
+ (finding) => finding.status === "fail" && (finding.evidenceIds?.length ?? 0) > 0
101
+ );
102
+ if (contractFail) {
103
+ const evidenceIds = [...contractFail.evidenceIds ?? []];
104
+ return {
105
+ kind: "contract_failure",
106
+ evidenceIds,
107
+ rationale: contractFail.message ?? `Contract rule ${contractFail.ruleId} failed with linked evidence ids.`,
108
+ orderIndex: 3,
109
+ runId,
110
+ primary: {
111
+ ruleId: contractFail.ruleId,
112
+ stepId: evidenceIds[0],
113
+ name: contractFail.ruleId
114
+ },
115
+ relationship: { role: "self", relatedIds: [] },
116
+ engine: "conservative-causal-v1"
117
+ };
118
+ }
119
+ const completed = events.filter(
120
+ (event) => event.event === "step_completed"
121
+ );
122
+ const started = events.filter(
123
+ (event) => event.event === "step_started"
124
+ );
125
+ const parentByStep = /* @__PURE__ */ new Map();
126
+ for (const start of started) {
127
+ parentByStep.set(start.stepId, start.parentId);
128
+ }
129
+ const errorSteps = completed.filter((event) => event.status === "error");
130
+ if (errorSteps.length > 0) {
131
+ const sorted = [...errorSteps].sort((a, b) => {
132
+ const depth = (id) => {
133
+ let d = 0;
134
+ let cur = id;
135
+ const seen = /* @__PURE__ */ new Set();
136
+ while (cur && parentByStep.has(cur) && !seen.has(cur)) {
137
+ seen.add(cur);
138
+ const parent = parentByStep.get(cur);
139
+ if (!parent) break;
140
+ d += 1;
141
+ cur = parent;
142
+ }
143
+ return d;
144
+ };
145
+ return depth(b.stepId) - depth(a.stepId);
146
+ });
147
+ const tip = sorted[0];
148
+ const parentId = parentByStep.get(tip.stepId);
149
+ const relatedIds = parentId ? [parentId] : [];
150
+ return {
151
+ kind: "failed_ancestor_or_child",
152
+ evidenceIds: [tip.stepId, ...relatedIds],
153
+ rationale: parentId ? "Deepest explicit error step with parent link (nearest ancestor relationship)." : "Explicit error step used as structural tip (no parent id).",
154
+ orderIndex: 4,
155
+ runId: tip.runId || runId,
156
+ primary: { stepId: tip.stepId, name: started.find((s) => s.stepId === tip.stepId)?.name },
157
+ relationship: {
158
+ role: parentId ? "child" : "self",
159
+ relatedIds
160
+ },
161
+ engine: "conservative-causal-v1"
162
+ };
163
+ }
164
+ return noneResult(
165
+ runId,
166
+ "No explicit error event, failed outcome, or linked contract failure; refusing timing-only inference."
167
+ );
168
+ }
169
+
26
170
  // packages/core/src/explain.ts
27
171
  function toDisplayStatus(status) {
28
172
  if (status === "ok") return "success";
@@ -1111,12 +1255,12 @@ function buildCriticalPath(runs, handoffs) {
1111
1255
  handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
1112
1256
  );
1113
1257
  const ordered = [...runs].sort(compareRuns);
1114
- const path7 = [];
1258
+ const path9 = [];
1115
1259
  const visited = /* @__PURE__ */ new Set();
1116
1260
  const pushRun = (run, confidence, source) => {
1117
1261
  if (visited.has(run.runId)) return;
1118
1262
  visited.add(run.runId);
1119
- path7.push({
1263
+ path9.push({
1120
1264
  runId: run.runId,
1121
1265
  name: run.name,
1122
1266
  startedAt: run.startedAt,
@@ -1141,7 +1285,7 @@ function buildCriticalPath(runs, handoffs) {
1141
1285
  const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
1142
1286
  pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
1143
1287
  }
1144
- return path7;
1288
+ return path9;
1145
1289
  }
1146
1290
  function metaRunIdMatches(run, token, runById) {
1147
1291
  const meta = extractSessionWorkflowMetadata(run.metadata);
@@ -1451,13 +1595,13 @@ function assertBundlePathContained(outputDir, relativePath) {
1451
1595
  }
1452
1596
  return resolved;
1453
1597
  }
1454
- function normalizeBundleOutputPath(out) {
1598
+ function normalizeBundleOutputPath(out, options) {
1455
1599
  const trimmed = out.trim();
1456
1600
  if (trimmed === "") {
1457
1601
  throw new Error("--out requires a non-empty path.");
1458
1602
  }
1459
1603
  const resolved = path.resolve(trimmed);
1460
- if (resolved.toLowerCase().endsWith(".zip")) {
1604
+ if (options?.preserveZipExtension !== true && resolved.toLowerCase().endsWith(".zip")) {
1461
1605
  return resolved.slice(0, -4);
1462
1606
  }
1463
1607
  return resolved;
@@ -1468,6 +1612,1157 @@ function defaultBundleOutputPath(runIds) {
1468
1612
  return path.resolve(`agent-inspect-bundle-${label}-${stamp}`);
1469
1613
  }
1470
1614
 
1615
+ // packages/core/src/evidence/types.ts
1616
+ var EVIDENCE_FORMAT_VERSION = "1.0";
1617
+ var EVIDENCE_ASSESSMENT_NOTE = "Best-effort local safety verification only; not a compliance certification.";
1618
+ var EVIDENCE_MANIFEST_FILENAME = "evidence.json";
1619
+ var SHA256_RE = /^[a-f0-9]{64}$/i;
1620
+ function sha256Hex(data) {
1621
+ const hash = createHash("sha256");
1622
+ if (typeof data === "string") {
1623
+ hash.update(data, "utf8");
1624
+ } else {
1625
+ hash.update(data);
1626
+ }
1627
+ return hash.digest("hex");
1628
+ }
1629
+ function isSha256Hex(value) {
1630
+ return SHA256_RE.test(value);
1631
+ }
1632
+ function sha256Equals(expected, actual) {
1633
+ if (!isSha256Hex(expected) || !isSha256Hex(actual)) {
1634
+ return false;
1635
+ }
1636
+ const a = expected.toLowerCase();
1637
+ const b = actual.toLowerCase();
1638
+ if (a.length !== b.length) return false;
1639
+ let mismatch = 0;
1640
+ for (let i = 0; i < a.length; i += 1) {
1641
+ mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
1642
+ }
1643
+ return mismatch === 0;
1644
+ }
1645
+ function assertEvidenceRelativePath(relativePath) {
1646
+ if (typeof relativePath !== "string" || relativePath.trim() === "") {
1647
+ throw new Error("Evidence file path must be a non-empty relative path.");
1648
+ }
1649
+ const trimmed = relativePath.trim().replaceAll("\\", "/");
1650
+ if (path.isAbsolute(trimmed) || trimmed.startsWith("/")) {
1651
+ throw new Error(`Evidence file path must be relative: ${relativePath}`);
1652
+ }
1653
+ const parts = trimmed.split("/").filter((part) => part !== "");
1654
+ if (parts.length === 0) {
1655
+ throw new Error(`Evidence file path must be relative: ${relativePath}`);
1656
+ }
1657
+ for (const part of parts) {
1658
+ if (part === "." || part === "..") {
1659
+ throw new Error(`Evidence file path must not contain "." or "..": ${relativePath}`);
1660
+ }
1661
+ }
1662
+ return parts.join("/");
1663
+ }
1664
+
1665
+ // packages/core/src/evidence/manifest.ts
1666
+ function stable(value) {
1667
+ if (Array.isArray(value)) return value.map(stable);
1668
+ if (value === null || typeof value !== "object") return value;
1669
+ const record = value;
1670
+ return Object.fromEntries(
1671
+ Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable(record[key])])
1672
+ );
1673
+ }
1674
+ function serializeEvidenceManifest(manifest) {
1675
+ return `${JSON.stringify(stable(manifest), null, 2)}
1676
+ `;
1677
+ }
1678
+ function inferEvidenceFileRole(relativePath) {
1679
+ const normalized = assertEvidenceRelativePath(relativePath);
1680
+ const base = normalized.includes("/") ? normalized.slice(normalized.lastIndexOf("/") + 1) : normalized;
1681
+ if (base === "evidence.html" || base === "trace.html" || base.endsWith(".html")) {
1682
+ return "report";
1683
+ }
1684
+ if (base === "trace.jsonl" || base.endsWith(".jsonl")) {
1685
+ return "redacted-trace";
1686
+ }
1687
+ if (base === "check-results.json") {
1688
+ return "checks";
1689
+ }
1690
+ if (base === "redaction-report.json") {
1691
+ return "redaction-report";
1692
+ }
1693
+ if (base === "summary.md") {
1694
+ return "summary";
1695
+ }
1696
+ return "other";
1697
+ }
1698
+ function buildEvidenceFileEntries(files) {
1699
+ const byPath = /* @__PURE__ */ new Map();
1700
+ for (const file of files) {
1701
+ const relativePath = assertEvidenceRelativePath(file.path);
1702
+ if (relativePath === EVIDENCE_MANIFEST_FILENAME) {
1703
+ throw new Error(
1704
+ `Do not include ${EVIDENCE_MANIFEST_FILENAME} in packaged file hashes (self-hash is undefined).`
1705
+ );
1706
+ }
1707
+ if (byPath.has(relativePath)) {
1708
+ throw new Error(`Duplicate evidence file path: ${relativePath}`);
1709
+ }
1710
+ byPath.set(relativePath, {
1711
+ path: relativePath,
1712
+ sha256: sha256Hex(file.content),
1713
+ role: file.role ?? inferEvidenceFileRole(relativePath)
1714
+ });
1715
+ }
1716
+ return [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
1717
+ }
1718
+ function buildEvidenceManifest(parts) {
1719
+ const runIds = [...parts.runIds];
1720
+ if (runIds.length === 0) {
1721
+ throw new Error("Evidence manifest requires at least one run id.");
1722
+ }
1723
+ for (const item of parts.sourceHashes) {
1724
+ if (!runIds.includes(item.runId)) {
1725
+ throw new Error(`sourceHashes runId "${item.runId}" is not listed in source.runIds.`);
1726
+ }
1727
+ if (item.algorithm !== "sha256") {
1728
+ throw new Error(`Unsupported source hash algorithm: ${item.algorithm}`);
1729
+ }
1730
+ }
1731
+ const assessment = {
1732
+ status: parts.assessmentStatus,
1733
+ note: parts.note ?? EVIDENCE_ASSESSMENT_NOTE
1734
+ };
1735
+ if (parts.sourceStatus !== void 0) {
1736
+ assessment.sourceStatus = parts.sourceStatus;
1737
+ }
1738
+ return {
1739
+ evidenceFormatVersion: EVIDENCE_FORMAT_VERSION,
1740
+ generator: {
1741
+ name: parts.generatorName ?? "agent-inspect",
1742
+ version: parts.generatorVersion
1743
+ },
1744
+ createdAt: parts.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1745
+ source: {
1746
+ runIds,
1747
+ traceSchemaVersions: [...parts.traceSchemaVersions].sort((a, b) => a.localeCompare(b)),
1748
+ sourceHashes: [...parts.sourceHashes].sort((a, b) => a.runId.localeCompare(b.runId))
1749
+ },
1750
+ policy: {
1751
+ redactionProfile: parts.redactionProfile,
1752
+ verificationPolicy: parts.verificationPolicy ?? parts.redactionProfile
1753
+ },
1754
+ assessment,
1755
+ files: buildEvidenceFileEntries(parts.files)
1756
+ };
1757
+ }
1758
+ function validateEvidenceManifest(value) {
1759
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
1760
+ throw new Error("Evidence manifest must be a JSON object.");
1761
+ }
1762
+ const record = value;
1763
+ if (record.evidenceFormatVersion !== EVIDENCE_FORMAT_VERSION) {
1764
+ throw new Error(
1765
+ `Unsupported evidenceFormatVersion: ${String(record.evidenceFormatVersion)}`
1766
+ );
1767
+ }
1768
+ const generator = record.generator;
1769
+ if (generator === null || typeof generator !== "object" || Array.isArray(generator) || typeof generator.name !== "string" || typeof generator.version !== "string") {
1770
+ throw new Error("Evidence manifest requires generator.name and generator.version.");
1771
+ }
1772
+ const source = record.source;
1773
+ if (source === null || typeof source !== "object" || Array.isArray(source)) {
1774
+ throw new Error("Evidence manifest requires source.");
1775
+ }
1776
+ const sourceRecord = source;
1777
+ if (!Array.isArray(sourceRecord.runIds) || sourceRecord.runIds.length === 0) {
1778
+ throw new Error("Evidence manifest source.runIds must be a non-empty array.");
1779
+ }
1780
+ if (!Array.isArray(sourceRecord.traceSchemaVersions)) {
1781
+ throw new Error("Evidence manifest source.traceSchemaVersions must be an array.");
1782
+ }
1783
+ if (!Array.isArray(sourceRecord.sourceHashes)) {
1784
+ throw new Error("Evidence manifest source.sourceHashes must be an array.");
1785
+ }
1786
+ const policy = record.policy;
1787
+ if (policy === null || typeof policy !== "object" || Array.isArray(policy)) {
1788
+ throw new Error("Evidence manifest requires policy.");
1789
+ }
1790
+ const assessment = record.assessment;
1791
+ if (assessment === null || typeof assessment !== "object" || Array.isArray(assessment) || typeof assessment.status !== "string") {
1792
+ throw new Error("Evidence manifest requires assessment.status.");
1793
+ }
1794
+ if (!Array.isArray(record.files) || record.files.length === 0) {
1795
+ throw new Error("Evidence manifest files must be a non-empty array.");
1796
+ }
1797
+ for (const file of record.files) {
1798
+ if (file === null || typeof file !== "object" || Array.isArray(file)) {
1799
+ throw new Error("Evidence manifest file entries must be objects.");
1800
+ }
1801
+ const entry = file;
1802
+ if (typeof entry.path !== "string") {
1803
+ throw new Error("Evidence file entry requires path.");
1804
+ }
1805
+ assertEvidenceRelativePath(entry.path);
1806
+ if (typeof entry.sha256 !== "string" || !/^[a-f0-9]{64}$/i.test(entry.sha256)) {
1807
+ throw new Error(`Evidence file entry requires sha256 hex for ${entry.path}.`);
1808
+ }
1809
+ }
1810
+ return value;
1811
+ }
1812
+ function parseEvidenceManifestJson(text) {
1813
+ let parsed;
1814
+ try {
1815
+ parsed = JSON.parse(text);
1816
+ } catch (error) {
1817
+ const message = error instanceof Error ? error.message : String(error);
1818
+ throw new Error(`Evidence manifest is not valid JSON: ${message}`);
1819
+ }
1820
+ return validateEvidenceManifest(parsed);
1821
+ }
1822
+ function collectTraceSchemaVersions(jsonl) {
1823
+ const versions = /* @__PURE__ */ new Set();
1824
+ for (const line of jsonl.split(/\r?\n/)) {
1825
+ const trimmed = line.trim();
1826
+ if (trimmed === "") continue;
1827
+ try {
1828
+ const row = JSON.parse(trimmed);
1829
+ if (typeof row.schemaVersion === "string" && row.schemaVersion.trim() !== "") {
1830
+ versions.add(row.schemaVersion.trim());
1831
+ }
1832
+ } catch {
1833
+ }
1834
+ }
1835
+ return [...versions].sort((a, b) => a.localeCompare(b));
1836
+ }
1837
+
1838
+ // packages/core/src/evidence/views.ts
1839
+ function renderTreeHtml(nodes, ulClass = "tree") {
1840
+ if (nodes.length === 0) return "";
1841
+ const parts = [`<ul class="${ulClass}">`];
1842
+ for (const n of nodes) {
1843
+ const ev = n.event;
1844
+ const status = ev.status ?? "?";
1845
+ const dur = ev.durationMs !== void 0 && Number.isFinite(ev.durationMs) ? `${ev.durationMs}ms` : "-";
1846
+ const errClass = ev.status === "error" ? " is-error" : "";
1847
+ parts.push(`<li class="tree-node${errClass}">`);
1848
+ parts.push(
1849
+ `<span class="nm">${escapeHtml(ev.name)}</span> <span class="meta">[${escapeHtml(ev.kind)}] ${escapeHtml(status)} (${escapeHtml(dur)})</span>`
1850
+ );
1851
+ if (n.children.length > 0) {
1852
+ parts.push(renderTreeHtml(n.children, "tree nested"));
1853
+ }
1854
+ parts.push("</li>");
1855
+ }
1856
+ parts.push("</ul>");
1857
+ return parts.join("");
1858
+ }
1859
+ function buildEvidenceTreeViewHtml(trees) {
1860
+ if (trees.length === 0) {
1861
+ return `<p class="muted">No execution trees available.</p>`;
1862
+ }
1863
+ const parts = [];
1864
+ for (const tree of trees) {
1865
+ parts.push(`<article class="run-block">`);
1866
+ parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
1867
+ if (tree.name) {
1868
+ parts.push(`<p class="muted">Name: ${escapeHtml(tree.name)}</p>`);
1869
+ }
1870
+ parts.push(
1871
+ `<p>Status: <strong>${escapeHtml(String(tree.status ?? "unknown"))}</strong>${tree.durationMs !== void 0 ? ` \xB7 ${escapeHtml(String(tree.durationMs))}ms` : ""}</p>`
1872
+ );
1873
+ parts.push(
1874
+ tree.children.length > 0 ? renderTreeHtml(tree.children) : `<p class="muted">No steps recorded.</p>`
1875
+ );
1876
+ parts.push(`</article>`);
1877
+ }
1878
+ return parts.join("\n");
1879
+ }
1880
+ function timelineRows(tree) {
1881
+ const flat = flattenTree(tree);
1882
+ const origin = tree.startedAt ?? flat.reduce((min, n) => {
1883
+ const t = n.event.timestamp;
1884
+ if (!Number.isFinite(t)) return min;
1885
+ return min === void 0 ? t : Math.min(min, t);
1886
+ }, void 0) ?? 0;
1887
+ return flat.filter((n) => n.event.kind !== "RUN").map((n) => {
1888
+ const started = Number.isFinite(n.event.timestamp) ? n.event.timestamp : origin;
1889
+ const durationMs = n.event.durationMs !== void 0 && Number.isFinite(n.event.durationMs) ? Math.max(0, n.event.durationMs) : 0;
1890
+ return {
1891
+ name: n.event.name,
1892
+ kind: n.event.kind,
1893
+ status: n.event.status ?? "?",
1894
+ offsetMs: Math.max(0, started - origin),
1895
+ durationMs,
1896
+ isError: n.event.status === "error"
1897
+ };
1898
+ }).sort((a, b) => a.offsetMs - b.offsetMs || a.name.localeCompare(b.name));
1899
+ }
1900
+ function buildEvidenceTimelineViewHtml(trees) {
1901
+ if (trees.length === 0) {
1902
+ return `<p class="muted">No timeline data available.</p>`;
1903
+ }
1904
+ const parts = [];
1905
+ for (const tree of trees) {
1906
+ const rows = timelineRows(tree);
1907
+ const maxEnd = rows.reduce(
1908
+ (max, row) => Math.max(max, row.offsetMs + Math.max(row.durationMs, 1)),
1909
+ 1
1910
+ );
1911
+ parts.push(`<article class="run-block">`);
1912
+ parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
1913
+ if (rows.length === 0) {
1914
+ parts.push(`<p class="muted">No step timings recorded.</p>`);
1915
+ } else {
1916
+ parts.push(`<div class="waterfall" role="list">`);
1917
+ for (const row of rows) {
1918
+ const left = row.offsetMs / maxEnd * 100;
1919
+ const width = Math.max(0.8, Math.max(row.durationMs, 1) / maxEnd * 100);
1920
+ const err = row.isError ? " is-error" : "";
1921
+ parts.push(
1922
+ `<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>`
1923
+ );
1924
+ }
1925
+ parts.push(`</div>`);
1926
+ }
1927
+ parts.push(`</article>`);
1928
+ }
1929
+ return parts.join("\n");
1930
+ }
1931
+ function findNodeByEventId(nodes, eventId) {
1932
+ for (const node of nodes) {
1933
+ if (node.event.eventId === eventId) return node;
1934
+ const child = findNodeByEventId(node.children, eventId);
1935
+ if (child) return child;
1936
+ }
1937
+ return void 0;
1938
+ }
1939
+ function buildAncestorChain(tree, failure) {
1940
+ const chain = [failure];
1941
+ let parentId = failure.event.parentId;
1942
+ const guard = /* @__PURE__ */ new Set([failure.event.eventId]);
1943
+ while (parentId && !guard.has(parentId)) {
1944
+ guard.add(parentId);
1945
+ const parent = findNodeByEventId(tree.children, parentId);
1946
+ if (!parent) break;
1947
+ chain.unshift(parent);
1948
+ parentId = parent.event.parentId;
1949
+ }
1950
+ return chain;
1951
+ }
1952
+ function buildEvidenceCausalFailureViewHtml(trees) {
1953
+ if (trees.length === 0) {
1954
+ return `<p class="muted">No runs available for causal analysis.</p>`;
1955
+ }
1956
+ const parts = [];
1957
+ for (const tree of trees) {
1958
+ parts.push(`<article class="run-block">`);
1959
+ parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
1960
+ const errors = flattenTree(tree).filter((n) => n.event.status === "error" || n.event.kind === "ERROR").sort((a, b) => a.event.timestamp - b.event.timestamp);
1961
+ if (errors.length === 0) {
1962
+ parts.push(
1963
+ `<p class="muted">No error-status events found. Run status: <strong>${escapeHtml(String(tree.status ?? "unknown"))}</strong>.</p>`
1964
+ );
1965
+ parts.push(`</article>`);
1966
+ continue;
1967
+ }
1968
+ const first = errors[0];
1969
+ const chain = buildAncestorChain(tree, first);
1970
+ parts.push(`<p>First error by timestamp:</p>`);
1971
+ parts.push(`<ol class="causal-chain">`);
1972
+ for (const node of chain) {
1973
+ const isTip = node.event.eventId === first.event.eventId;
1974
+ const msg = typeof node.event.attributes?.message === "string" ? node.event.attributes.message : typeof node.event.attributes?.error === "string" ? node.event.attributes.error : void 0;
1975
+ parts.push(
1976
+ `<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>`
1977
+ );
1978
+ }
1979
+ parts.push(`</ol>`);
1980
+ if (errors.length > 1) {
1981
+ parts.push(
1982
+ `<p class="muted">${escapeHtml(String(errors.length - 1))} additional error event(s) not shown in the primary chain.</p>`
1983
+ );
1984
+ }
1985
+ parts.push(`</article>`);
1986
+ }
1987
+ return parts.join("\n");
1988
+ }
1989
+ var EVIDENCE_VIEW_CSS = `
1990
+ ul.tree{list-style:none;padding-left:1rem;margin:.5rem 0}
1991
+ ul.tree.nested{padding-left:1.25rem;border-left:1px solid var(--line);margin:.25rem 0}
1992
+ .tree-node.is-error .nm,.wf-row.is-error .nm,.causal-tip .nm{color:var(--unsafe)}
1993
+ .waterfall{display:flex;flex-direction:column;gap:.45rem;max-width:52rem}
1994
+ .wf-row{display:grid;grid-template-columns:minmax(10rem,18rem) 1fr;gap:.6rem;align-items:center}
1995
+ .wf-track{position:relative;height:.7rem;background:#e8e8e4;border-radius:.25rem;overflow:hidden}
1996
+ .wf-bar{position:absolute;top:0;bottom:0;background:var(--accent);border-radius:.25rem}
1997
+ .wf-row.is-error .wf-bar{background:var(--unsafe)}
1998
+ .causal-chain{max-width:44rem}
1999
+ .causal-msg{margin:.25rem 0 0;color:var(--muted);font-size:.92rem}
2000
+ .run-block{margin:0 0 1.25rem;padding-bottom:1rem;border-bottom:1px solid var(--line)}
2001
+ .run-block:last-child{border-bottom:0}
2002
+ @media (max-width:720px){
2003
+ .wf-row{grid-template-columns:1fr}
2004
+ }
2005
+ `.trim();
2006
+
2007
+ // packages/core/src/evidence/html-shell.ts
2008
+ var EVIDENCE_HTML_FILENAME = "evidence.html";
2009
+ var EVIDENCE_HTML_NOTE = "Generated locally by AgentInspect. Share-checked evidence for review \u2014 not a compliance or security certification.";
2010
+ var EVIDENCE_VIEW_IDS = [
2011
+ "summary",
2012
+ "tree",
2013
+ "timeline",
2014
+ "causal",
2015
+ "tools-llm",
2016
+ "outcomes",
2017
+ "contracts",
2018
+ "circuit",
2019
+ "diff",
2020
+ "safety",
2021
+ "provenance"
2022
+ ];
2023
+ function statusClass(status) {
2024
+ if (status === "SAFE") return "st-safe";
2025
+ if (status === "SAFE WITH WARNINGS") return "st-warn";
2026
+ if (status === "UNSAFE") return "st-unsafe";
2027
+ return "st-unknown";
2028
+ }
2029
+ function viewLabel(id) {
2030
+ switch (id) {
2031
+ case "summary":
2032
+ return "Summary";
2033
+ case "tree":
2034
+ return "Tree";
2035
+ case "timeline":
2036
+ return "Timeline";
2037
+ case "causal":
2038
+ return "Causal failure";
2039
+ case "tools-llm":
2040
+ return "Tools / LLM";
2041
+ case "outcomes":
2042
+ return "Outcomes";
2043
+ case "contracts":
2044
+ return "Contracts / checks";
2045
+ case "circuit":
2046
+ return "Circuit / guardrails";
2047
+ case "diff":
2048
+ return "Diff";
2049
+ case "safety":
2050
+ return "Safety / redaction";
2051
+ case "provenance":
2052
+ return "Provenance";
2053
+ default: {
2054
+ const _exhaustive = id;
2055
+ return _exhaustive;
2056
+ }
2057
+ }
2058
+ }
2059
+ function encodeEmbeddedEvidenceJson(value) {
2060
+ return JSON.stringify(value).replace(/</g, "\\u003c").replace(/>/g, "\\u003e");
2061
+ }
2062
+ function buildEmbeddedPayload(input) {
2063
+ return {
2064
+ evidenceFormatVersion: input.evidenceFormatVersion ?? "1.0",
2065
+ generator: {
2066
+ name: input.generatorName,
2067
+ version: input.generatorVersion
2068
+ },
2069
+ createdAt: input.createdAt,
2070
+ runIds: [...input.runIds],
2071
+ assessment: {
2072
+ status: input.assessmentStatus,
2073
+ ...input.sourceStatus !== void 0 ? { sourceStatus: input.sourceStatus } : {}
2074
+ },
2075
+ policy: {
2076
+ redactionProfile: input.redactionProfile,
2077
+ verificationPolicy: input.verificationPolicy
2078
+ },
2079
+ checkSummary: input.checkSummary
2080
+ };
2081
+ }
2082
+ function buildEvidenceHtmlShell(input) {
2083
+ if (input.runIds.length === 0) {
2084
+ throw new Error("Evidence HTML shell requires at least one run id.");
2085
+ }
2086
+ const maxChars = input.maxEmbeddedJsonChars ?? 64 * 1024;
2087
+ let embedded = encodeEmbeddedEvidenceJson(buildEmbeddedPayload(input));
2088
+ if (embedded.length > maxChars) {
2089
+ embedded = encodeEmbeddedEvidenceJson({
2090
+ truncated: true,
2091
+ evidenceFormatVersion: input.evidenceFormatVersion ?? "1.0",
2092
+ runIds: [...input.runIds],
2093
+ assessment: { status: input.assessmentStatus },
2094
+ note: "Embedded payload truncated to bound; open evidence.json / trace files for full detail."
2095
+ });
2096
+ }
2097
+ const title = escapeHtml(input.title ?? "AgentInspect evidence");
2098
+ const runList = input.runIds.map((id) => `<li><code>${escapeHtml(id)}</code></li>`).join("");
2099
+ 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>`;
2100
+ const checkRows = input.checkSummary?.runs.map(
2101
+ (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>`
2102
+ ).join("") ?? "";
2103
+ const nav = EVIDENCE_VIEW_IDS.map(
2104
+ (id) => `<a class="nav-link" href="#view-${id}" data-view="${id}">${escapeHtml(viewLabel(id))}</a>`
2105
+ ).join("\n");
2106
+ const stubPanels = EVIDENCE_VIEW_IDS.filter((id) => id !== "summary").map((id) => {
2107
+ const body = input.viewBodies?.[id];
2108
+ if (body !== void 0 && body.trim() !== "") {
2109
+ return ` <section id="view-${id}" class="panel" hidden>
2110
+ <h2>${escapeHtml(viewLabel(id))}</h2>
2111
+ ${body}
2112
+ </section>`;
2113
+ }
2114
+ return ` <section id="view-${id}" class="panel" hidden>
2115
+ <h2>${escapeHtml(viewLabel(id))}</h2>
2116
+ <p class="muted">This view will be filled in a later AgentInspect 6.10 release. The shell is offline-ready.</p>
2117
+ </section>`;
2118
+ }).join("\n");
2119
+ return `<!doctype html>
2120
+ <html lang="en">
2121
+ <head>
2122
+ <meta charset="utf-8"/>
2123
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
2124
+ <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'"/>
2125
+ <meta name="referrer" content="no-referrer"/>
2126
+ <title>${title}</title>
2127
+ <style>
2128
+ :root{--bg:#f7f7f5;--fg:#1a1a1a;--muted:#5c5c5c;--line:#d8d8d4;--accent:#0b5fff;--safe:#0a7a3e;--warn:#9a6700;--unsafe:#b42318;--unknown:#5c5c5c}
2129
+ *{box-sizing:border-box}
2130
+ 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}
2131
+ a{color:var(--accent)}
2132
+ header{padding:1.25rem 1.5rem;border-bottom:1px solid var(--line);background:#fff}
2133
+ header h1{margin:0 0 .35rem;font-size:1.35rem}
2134
+ .note{margin:0;color:var(--muted);font-size:.92rem;max-width:52rem}
2135
+ .layout{display:grid;grid-template-columns:14rem 1fr;min-height:70vh}
2136
+ nav{padding:1rem;border-right:1px solid var(--line);background:#fff}
2137
+ nav .nav-link{display:block;padding:.4rem .55rem;margin:0 0 .2rem;border-radius:.35rem;text-decoration:none;color:inherit}
2138
+ nav .nav-link:hover,nav .nav-link:focus{background:#eef3ff;outline:2px solid var(--accent);outline-offset:1px}
2139
+ main{padding:1.25rem 1.5rem}
2140
+ .panel[hidden]{display:none}
2141
+ .badge{display:inline-block;padding:.15rem .55rem;border-radius:.3rem;font-size:.85rem;font-weight:600}
2142
+ .st-safe{color:var(--safe)}.st-warn{color:var(--warn)}.st-unsafe{color:var(--unsafe)}.st-unknown{color:var(--unknown)}
2143
+ table{border-collapse:collapse;width:100%;max-width:48rem;background:#fff}
2144
+ th,td{border:1px solid var(--line);padding:.4rem .55rem;text-align:left;vertical-align:top}
2145
+ th{background:#f0f0ec}
2146
+ .summary-md,pre.data{white-space:pre-wrap;word-break:break-word;background:#fff;border:1px solid var(--line);padding:.75rem;max-width:52rem}
2147
+ .muted{color:var(--muted)}
2148
+ ul.runs{margin:.4rem 0 1rem;padding-left:1.2rem}
2149
+ @media print{
2150
+ nav{display:none}
2151
+ .layout{display:block}
2152
+ .panel[hidden]{display:block!important;page-break-before:always}
2153
+ header{border:0}
2154
+ }
2155
+ @media (max-width:720px){
2156
+ .layout{grid-template-columns:1fr}
2157
+ nav{border-right:0;border-bottom:1px solid var(--line);display:flex;flex-wrap:wrap;gap:.25rem}
2158
+ }
2159
+ ${EVIDENCE_VIEW_CSS}
2160
+ </style>
2161
+ </head>
2162
+ <body>
2163
+ <header>
2164
+ <h1>${title}</h1>
2165
+ <p class="note">${escapeHtml(EVIDENCE_HTML_NOTE)}</p>
2166
+ </header>
2167
+ <div class="layout">
2168
+ <nav aria-label="Evidence views">
2169
+ ${nav}
2170
+ </nav>
2171
+ <main id="main">
2172
+ <section id="view-summary" class="panel" tabindex="-1">
2173
+ <h2>Summary</h2>
2174
+ <p>Artifact status: <span class="badge ${statusClass(input.assessmentStatus)}">${escapeHtml(input.assessmentStatus)}</span>
2175
+ ${input.sourceStatus !== void 0 ? ` \xB7 Source status: <span class="badge ${statusClass(input.sourceStatus)}">${escapeHtml(input.sourceStatus)}</span>` : ""}</p>
2176
+ <p>Profile: <code>${escapeHtml(input.redactionProfile)}</code> \xB7 Verification: <code>${escapeHtml(input.verificationPolicy)}</code></p>
2177
+ <p>Generator: <code>${escapeHtml(input.generatorName)}@${escapeHtml(input.generatorVersion)}</code>
2178
+ ${input.createdAt ? ` \xB7 Created: <code>${escapeHtml(input.createdAt)}</code>` : ""}</p>
2179
+ <h3>Runs</h3>
2180
+ <ul class="runs">${runList}</ul>
2181
+ ${checkRows ? `<h3>Check summary</h3>
2182
+ <table>
2183
+ <thead><tr><th>runId</th><th>artifact</th><th>errors</th><th>warnings</th><th>findings</th></tr></thead>
2184
+ <tbody>${checkRows}</tbody>
2185
+ </table>` : ""}
2186
+ <h3>Text summary</h3>
2187
+ ${summaryBody}
2188
+ </section>
2189
+ ${stubPanels}
2190
+ </main>
2191
+ </div>
2192
+ <script type="application/json" id="ai-evidence-data">${embedded}</script>
2193
+ <script>
2194
+ (function(){
2195
+ var links=document.querySelectorAll("nav .nav-link");
2196
+ var panels=document.querySelectorAll("main .panel");
2197
+ function show(id){
2198
+ for(var i=0;i<panels.length;i++){
2199
+ var p=panels[i];
2200
+ var on=p.id==="view-"+id;
2201
+ if(on){p.removeAttribute("hidden");}else{p.setAttribute("hidden","");}
2202
+ }
2203
+ for(var j=0;j<links.length;j++){
2204
+ var a=links[j];
2205
+ if(a.getAttribute("data-view")===id){a.setAttribute("aria-current","page");}
2206
+ else{a.removeAttribute("aria-current");}
2207
+ }
2208
+ }
2209
+ for(var k=0;k<links.length;k++){
2210
+ links[k].addEventListener("click",function(ev){
2211
+ var id=ev.currentTarget.getAttribute("data-view");
2212
+ if(!id)return;
2213
+ ev.preventDefault();
2214
+ if(history.replaceState){history.replaceState(null,"","#view-"+id);}
2215
+ show(id);
2216
+ var panel=document.getElementById("view-"+id);
2217
+ if(panel)panel.focus();
2218
+ });
2219
+ }
2220
+ var hash=(location.hash||"").replace(/^#view-/,"");
2221
+ var initial="summary";
2222
+ for(var n=0;n<links.length;n++){
2223
+ if(links[n].getAttribute("data-view")===hash){initial=hash;break;}
2224
+ }
2225
+ show(initial);
2226
+ })();
2227
+ </script>
2228
+ </body>
2229
+ </html>
2230
+ `;
2231
+ }
2232
+ function buildEvidenceHtmlShellFromManifest(manifest, extras) {
2233
+ return buildEvidenceHtmlShell({
2234
+ title: extras?.title,
2235
+ runIds: manifest.source.runIds,
2236
+ assessmentStatus: manifest.assessment.status,
2237
+ sourceStatus: manifest.assessment.sourceStatus,
2238
+ redactionProfile: manifest.policy.redactionProfile,
2239
+ verificationPolicy: manifest.policy.verificationPolicy,
2240
+ generatorName: manifest.generator.name,
2241
+ generatorVersion: manifest.generator.version,
2242
+ createdAt: manifest.createdAt,
2243
+ evidenceFormatVersion: manifest.evidenceFormatVersion,
2244
+ summaryText: extras?.summaryText,
2245
+ checkSummary: extras?.checkSummary,
2246
+ viewBodies: extras?.viewBodies
2247
+ });
2248
+ }
2249
+
2250
+ // packages/core/src/evidence/views-contract.ts
2251
+ function boundMessage(message, max = 200) {
2252
+ const trimmed = message.trim();
2253
+ if (trimmed.length <= max) return trimmed;
2254
+ return `${trimmed.slice(0, max)}\u2026`;
2255
+ }
2256
+ function buildEvidenceContractsViewHtml(input) {
2257
+ const rows = input.runs.map(
2258
+ (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>`
2259
+ ).join("");
2260
+ const findings = input.findingSummaries ?? [];
2261
+ const findingRows = findings.length === 0 ? `<p class="muted">No structured check findings recorded for the redacted artifact.</p>` : `<table>
2262
+ <thead><tr><th>runId</th><th>severity</th><th>rule</th><th>category</th><th>detector</th><th>message</th></tr></thead>
2263
+ <tbody>${findings.map(
2264
+ (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>`
2265
+ ).join("")}</tbody>
2266
+ </table>`;
2267
+ return `<p>Aggregate artifact status: <strong>${escapeHtml(input.aggregateStatus)}</strong></p>
2268
+ <table>
2269
+ <thead><tr><th>runId</th><th>artifact</th><th>source</th><th>errors</th><th>warnings</th><th>findings</th></tr></thead>
2270
+ <tbody>${rows}</tbody>
2271
+ </table>
2272
+ <h3>Finding summaries</h3>
2273
+ ${findingRows}
2274
+ <p class="muted">TraceContract / check details are best-effort local results \u2014 not a compliance certification.</p>`;
2275
+ }
2276
+ function buildEvidenceOutcomesViewHtml(runs) {
2277
+ if (runs.length === 0) {
2278
+ return `<p class="muted">No runs available for outcome extraction.</p>`;
2279
+ }
2280
+ const parts = [];
2281
+ for (const run of runs) {
2282
+ const forRun = run.events.filter((event) => event.runId === run.runId);
2283
+ const summary = summarizeObservedOutcomes(extractOutcomesFromPersistedEvents(forRun));
2284
+ parts.push(`<article class="run-block">`);
2285
+ parts.push(`<h3><code>${escapeHtml(run.runId)}</code></h3>`);
2286
+ parts.push(renderObservedOutcomesHtml(summary));
2287
+ parts.push(`</article>`);
2288
+ }
2289
+ return parts.join("\n");
2290
+ }
2291
+ function buildEvidenceDiffViewHtml(parts) {
2292
+ if (parts === void 0 || parts.leftEvents.length === 0 || parts.rightEvents.length === 0) {
2293
+ 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>`;
2294
+ }
2295
+ try {
2296
+ const left = persistedInspectEventsToTraceEvents(
2297
+ parts.leftEvents.filter((e) => e.runId === parts.leftRunId)
2298
+ );
2299
+ const right = persistedInspectEventsToTraceEvents(
2300
+ parts.rightEvents.filter((e) => e.runId === parts.rightRunId)
2301
+ );
2302
+ if (left.length === 0 || right.length === 0) {
2303
+ return `<p class="muted">Could not normalize both runs for diff (missing v0.1-compatible events).</p>`;
2304
+ }
2305
+ const result = diffTraceEvents(left, right);
2306
+ const text = renderRunDiff(result, { color: false, verbose: false });
2307
+ return `<p>Comparing <code>${escapeHtml(parts.leftRunId)}</code> \u2192 <code>${escapeHtml(parts.rightRunId)}</code></p>
2308
+ <pre class="summary-md">${escapeHtml(text)}</pre>`;
2309
+ } catch (error) {
2310
+ const message = error instanceof Error ? error.message : String(error);
2311
+ return `<p class="muted">Diff unavailable: ${escapeHtml(message)}</p>`;
2312
+ }
2313
+ }
2314
+
2315
+ // packages/core/src/evidence/views-safety.ts
2316
+ function buildEvidenceSafetyViewHtml(input) {
2317
+ const findingRows = (input.findingSummaries ?? []).length === 0 ? `<p class="muted">No safety findings on the redacted artifact.</p>` : `<table>
2318
+ <thead><tr><th>runId</th><th>severity</th><th>category</th><th>detector</th><th>action</th><th>message</th></tr></thead>
2319
+ <tbody>${(input.findingSummaries ?? []).map((f) => {
2320
+ const msg = f.message.length > 160 ? `${f.message.slice(0, 160)}\u2026` : f.message;
2321
+ 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>`;
2322
+ }).join("")}</tbody>
2323
+ </table>`;
2324
+ const redactionBlock = input.redaction === void 0 ? `<p class="muted">No redaction report attached.</p>` : `<p>Total redaction findings: <strong>${input.redaction.totalFindings}</strong></p>
2325
+ <ul>${input.redaction.runs.map(
2326
+ (run) => `<li><code>${escapeHtml(run.runId)}</code>: ${run.findings} finding(s); detectors: ${escapeHtml(run.detectors.join(", ") || "none")}</li>`
2327
+ ).join("")}</ul>`;
2328
+ return `<p>Artifact status: <strong>${escapeHtml(String(input.artifactStatus))}</strong>
2329
+ ${input.sourceStatus !== void 0 ? ` \xB7 Source status: <strong>${escapeHtml(String(input.sourceStatus))}</strong>` : ""}</p>
2330
+ <p>Redaction profile: <code>${escapeHtml(input.redactionProfile)}</code> \xB7 Verification: <code>${escapeHtml(input.verificationPolicy)}</code></p>
2331
+ <h3>Redaction</h3>
2332
+ ${redactionBlock}
2333
+ <h3>Safety findings (artifact)</h3>
2334
+ ${findingRows}
2335
+ <p class="muted">Best-effort local verification only \u2014 not a compliance certification. Gate sharing on artifact status.</p>`;
2336
+ }
2337
+ function buildEvidenceProvenanceViewHtml(input) {
2338
+ const hashes = input.sourceHashes.length === 0 ? `<p class="muted">No source hashes recorded.</p>` : `<table>
2339
+ <thead><tr><th>runId</th><th>algorithm</th><th>hash</th></tr></thead>
2340
+ <tbody>${input.sourceHashes.map(
2341
+ (h) => `<tr><td><code>${escapeHtml(h.runId)}</code></td><td>${escapeHtml(h.algorithm)}</td><td><code>${escapeHtml(h.hash)}</code></td></tr>`
2342
+ ).join("")}</tbody>
2343
+ </table>`;
2344
+ const files = input.packagedFiles.length === 0 ? `<p class="muted">No packaged files listed.</p>` : `<ul>${input.packagedFiles.map(
2345
+ (f) => `<li><code>${escapeHtml(f.path)}</code>${f.role ? ` <span class="meta">(${escapeHtml(f.role)})</span>` : ""}</li>`
2346
+ ).join("")}</ul>`;
2347
+ return `<p>Generator: <code>${escapeHtml(input.generatorName)}@${escapeHtml(input.generatorVersion)}</code>
2348
+ \xB7 Evidence format: <code>${escapeHtml(input.evidenceFormatVersion)}</code>
2349
+ ${input.createdAt ? ` \xB7 Created: <code>${escapeHtml(input.createdAt)}</code>` : ""}</p>
2350
+ <p>Runs: ${input.runIds.map((id) => `<code>${escapeHtml(id)}</code>`).join(", ")}</p>
2351
+ <p>Trace schema versions: ${input.traceSchemaVersions.length > 0 ? input.traceSchemaVersions.map((v) => `<code>${escapeHtml(v)}</code>`).join(", ") : '<span class="muted">unknown</span>'}</p>
2352
+ <h3>Source hashes (pre-redaction input)</h3>
2353
+ ${hashes}
2354
+ <h3>Packaged files</h3>
2355
+ ${files}
2356
+ <p class="muted">${escapeHtml(input.note ?? "Reader/mapping losses are reported elsewhere when present; relationships are never invented without confidence policy.")}</p>`;
2357
+ }
2358
+ function buildEvidenceToolsLlmViewHtml(trees) {
2359
+ if (trees.length === 0) {
2360
+ return `<p class="muted">No runs available for tool/LLM metadata.</p>`;
2361
+ }
2362
+ const parts = [];
2363
+ for (const tree of trees) {
2364
+ const nodes = flattenTree(tree).filter(
2365
+ (n) => n.event.kind === "TOOL" || n.event.kind === "LLM" || n.event.kind === "AGENT"
2366
+ );
2367
+ parts.push(`<article class="run-block">`);
2368
+ parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
2369
+ if (nodes.length === 0) {
2370
+ parts.push(`<p class="muted">No TOOL/LLM/AGENT events in this run.</p>`);
2371
+ } else {
2372
+ parts.push(`<table>
2373
+ <thead><tr><th>name</th><th>kind</th><th>status</th><th>durationMs</th></tr></thead>
2374
+ <tbody>${nodes.map((n) => {
2375
+ const dur = n.event.durationMs !== void 0 && Number.isFinite(n.event.durationMs) ? String(n.event.durationMs) : "\u2014";
2376
+ 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>`;
2377
+ }).join("")}</tbody>
2378
+ </table>`);
2379
+ }
2380
+ parts.push(`</article>`);
2381
+ }
2382
+ return parts.join("\n");
2383
+ }
2384
+ function buildEvidenceCircuitViewHtml(parts) {
2385
+ const findings = parts?.findings ?? [];
2386
+ if (findings.length === 0) {
2387
+ return `<p class="muted">No circuit or guardrail findings were attached to this evidence bundle.</p>`;
2388
+ }
2389
+ return `<table>
2390
+ <thead><tr><th>runId</th><th>name</th><th>status</th><th>detail</th></tr></thead>
2391
+ <tbody>${findings.map(
2392
+ (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>`
2393
+ ).join("")}</tbody>
2394
+ </table>`;
2395
+ }
2396
+
2397
+ // packages/core/src/evidence/zip.ts
2398
+ var CRC_TABLE = (() => {
2399
+ const table = new Uint32Array(256);
2400
+ for (let n = 0; n < 256; n += 1) {
2401
+ let c = n;
2402
+ for (let k = 0; k < 8; k += 1) {
2403
+ c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
2404
+ }
2405
+ table[n] = c >>> 0;
2406
+ }
2407
+ return table;
2408
+ })();
2409
+ function crc32(data) {
2410
+ let crc = 4294967295;
2411
+ for (let i = 0; i < data.length; i += 1) {
2412
+ crc = CRC_TABLE[(crc ^ data[i]) & 255] ^ crc >>> 8;
2413
+ }
2414
+ return (crc ^ 4294967295) >>> 0;
2415
+ }
2416
+ function toBytes(content) {
2417
+ return typeof content === "string" ? Buffer.from(content, "utf8") : content;
2418
+ }
2419
+ function u16(value) {
2420
+ const buf = Buffer.alloc(2);
2421
+ buf.writeUInt16LE(value >>> 0, 0);
2422
+ return buf;
2423
+ }
2424
+ function u32(value) {
2425
+ const buf = Buffer.alloc(4);
2426
+ buf.writeUInt32LE(value >>> 0, 0);
2427
+ return buf;
2428
+ }
2429
+ function buildZipArchive(entries) {
2430
+ if (entries.length === 0) {
2431
+ throw new Error("ZIP archive requires at least one entry.");
2432
+ }
2433
+ const locals = [];
2434
+ const centrals = [];
2435
+ let offset = 0;
2436
+ const seen = /* @__PURE__ */ new Set();
2437
+ for (const entry of entries) {
2438
+ const name = assertEvidenceRelativePath(entry.path);
2439
+ if (seen.has(name)) {
2440
+ throw new Error(`Duplicate ZIP entry path: ${name}`);
2441
+ }
2442
+ seen.add(name);
2443
+ const nameBytes = Buffer.from(name, "utf8");
2444
+ const data = toBytes(entry.content);
2445
+ const checksum = crc32(data);
2446
+ const size = data.byteLength;
2447
+ const local = Buffer.concat([
2448
+ u32(67324752),
2449
+ u16(20),
2450
+ // version needed
2451
+ u16(0),
2452
+ // flags
2453
+ u16(0),
2454
+ // method STORE
2455
+ u16(0),
2456
+ // time
2457
+ u16(0),
2458
+ // date
2459
+ u32(checksum),
2460
+ u32(size),
2461
+ u32(size),
2462
+ u16(nameBytes.length),
2463
+ u16(0),
2464
+ // extra length
2465
+ nameBytes,
2466
+ Buffer.from(data)
2467
+ ]);
2468
+ const central = Buffer.concat([
2469
+ u32(33639248),
2470
+ u16(20),
2471
+ // version made by
2472
+ u16(20),
2473
+ // version needed
2474
+ u16(0),
2475
+ u16(0),
2476
+ u16(0),
2477
+ u16(0),
2478
+ u32(checksum),
2479
+ u32(size),
2480
+ u32(size),
2481
+ u16(nameBytes.length),
2482
+ u16(0),
2483
+ u16(0),
2484
+ u16(0),
2485
+ u16(0),
2486
+ u32(0),
2487
+ u32(offset),
2488
+ nameBytes
2489
+ ]);
2490
+ locals.push(local);
2491
+ centrals.push(central);
2492
+ offset += local.length;
2493
+ }
2494
+ const centralDir = Buffer.concat(centrals);
2495
+ const end = Buffer.concat([
2496
+ u32(101010256),
2497
+ u16(0),
2498
+ u16(0),
2499
+ u16(entries.length),
2500
+ u16(entries.length),
2501
+ u32(centralDir.length),
2502
+ u32(offset),
2503
+ u16(0)
2504
+ ]);
2505
+ return Buffer.concat([...locals, centralDir, end]);
2506
+ }
2507
+ async function listFilesRecursive(root) {
2508
+ const out = [];
2509
+ async function walk(dir) {
2510
+ const entries = await readdir(dir, { withFileTypes: true });
2511
+ for (const entry of entries) {
2512
+ const abs = path.join(dir, entry.name);
2513
+ if (entry.isDirectory()) {
2514
+ await walk(abs);
2515
+ } else if (entry.isFile()) {
2516
+ const rel = path.relative(root, abs).split(path.sep).join("/");
2517
+ out.push(rel);
2518
+ }
2519
+ }
2520
+ }
2521
+ await walk(root);
2522
+ return out.sort((a, b) => a.localeCompare(b));
2523
+ }
2524
+ async function verifyEvidenceDirectory(rootPath, options = {}) {
2525
+ const unexpectedMode = options.unexpectedFiles ?? "fail";
2526
+ const root = path.resolve(rootPath);
2527
+ const issues = [];
2528
+ let rootStat;
2529
+ try {
2530
+ rootStat = await stat(root);
2531
+ } catch (error) {
2532
+ const message = error instanceof Error ? error.message : String(error);
2533
+ return {
2534
+ ok: false,
2535
+ status: "fail",
2536
+ root,
2537
+ issues: [{ code: "io_error", severity: "error", message: `Cannot read path: ${message}` }],
2538
+ checkedFiles: 0
2539
+ };
2540
+ }
2541
+ if (!rootStat.isDirectory()) {
2542
+ return {
2543
+ ok: false,
2544
+ status: "fail",
2545
+ root,
2546
+ issues: [
2547
+ {
2548
+ code: "io_error",
2549
+ severity: "error",
2550
+ message: "Evidence verify expects a directory containing evidence.json (unpack ZIP first)."
2551
+ }
2552
+ ],
2553
+ checkedFiles: 0
2554
+ };
2555
+ }
2556
+ const manifestPath = path.join(root, EVIDENCE_MANIFEST_FILENAME);
2557
+ let manifestText;
2558
+ try {
2559
+ manifestText = await readFile(manifestPath, "utf-8");
2560
+ } catch {
2561
+ return {
2562
+ ok: false,
2563
+ status: "fail",
2564
+ root,
2565
+ issues: [
2566
+ {
2567
+ code: "manifest_missing",
2568
+ severity: "error",
2569
+ message: `Missing ${EVIDENCE_MANIFEST_FILENAME}`,
2570
+ path: EVIDENCE_MANIFEST_FILENAME
2571
+ }
2572
+ ],
2573
+ checkedFiles: 0
2574
+ };
2575
+ }
2576
+ let manifest;
2577
+ try {
2578
+ manifest = parseEvidenceManifestJson(manifestText);
2579
+ } catch (error) {
2580
+ const message = error instanceof Error ? error.message : String(error);
2581
+ return {
2582
+ ok: false,
2583
+ status: "fail",
2584
+ root,
2585
+ issues: [
2586
+ {
2587
+ code: "manifest_invalid",
2588
+ severity: "error",
2589
+ message,
2590
+ path: EVIDENCE_MANIFEST_FILENAME
2591
+ }
2592
+ ],
2593
+ checkedFiles: 0
2594
+ };
2595
+ }
2596
+ if (!manifest.assessment?.status) {
2597
+ issues.push({
2598
+ code: "assessment_missing",
2599
+ severity: "error",
2600
+ message: "Manifest assessment.status is required."
2601
+ });
2602
+ }
2603
+ if (!manifest.generator?.name || !manifest.generator?.version) {
2604
+ issues.push({
2605
+ code: "provenance_missing",
2606
+ severity: "error",
2607
+ message: "Manifest generator.name and generator.version are required."
2608
+ });
2609
+ }
2610
+ if (!manifest.source?.runIds?.length) {
2611
+ issues.push({
2612
+ code: "provenance_missing",
2613
+ severity: "error",
2614
+ message: "Manifest source.runIds must be non-empty."
2615
+ });
2616
+ }
2617
+ const listed = /* @__PURE__ */ new Set();
2618
+ for (const file of manifest.files) {
2619
+ let rel;
2620
+ try {
2621
+ rel = assertEvidenceRelativePath(file.path);
2622
+ } catch (error) {
2623
+ const message = error instanceof Error ? error.message : String(error);
2624
+ issues.push({
2625
+ code: "path_unsafe",
2626
+ severity: "error",
2627
+ message,
2628
+ path: file.path
2629
+ });
2630
+ continue;
2631
+ }
2632
+ if (rel === EVIDENCE_MANIFEST_FILENAME) {
2633
+ issues.push({
2634
+ code: "manifest_invalid",
2635
+ severity: "error",
2636
+ message: `${EVIDENCE_MANIFEST_FILENAME} must not list itself in files[].`,
2637
+ path: rel
2638
+ });
2639
+ continue;
2640
+ }
2641
+ listed.add(rel);
2642
+ const abs = path.join(root, ...rel.split("/"));
2643
+ let bytes;
2644
+ try {
2645
+ bytes = await readFile(abs);
2646
+ } catch {
2647
+ issues.push({
2648
+ code: "file_missing",
2649
+ severity: "error",
2650
+ message: `Listed file missing: ${rel}`,
2651
+ path: rel
2652
+ });
2653
+ continue;
2654
+ }
2655
+ const actual = sha256Hex(bytes);
2656
+ if (!sha256Equals(file.sha256, actual)) {
2657
+ issues.push({
2658
+ code: "hash_mismatch",
2659
+ severity: "error",
2660
+ message: `SHA-256 mismatch for ${rel}`,
2661
+ path: rel
2662
+ });
2663
+ }
2664
+ }
2665
+ let onDisk = [];
2666
+ try {
2667
+ onDisk = await listFilesRecursive(root);
2668
+ } catch (error) {
2669
+ const message = error instanceof Error ? error.message : String(error);
2670
+ issues.push({ code: "io_error", severity: "error", message });
2671
+ }
2672
+ for (const rel of onDisk) {
2673
+ if (rel === EVIDENCE_MANIFEST_FILENAME) continue;
2674
+ if (listed.has(rel)) continue;
2675
+ if (unexpectedMode === "ignore") continue;
2676
+ issues.push({
2677
+ code: "file_unexpected",
2678
+ severity: unexpectedMode === "warn" ? "warning" : "error",
2679
+ message: `Unexpected file not listed in manifest: ${rel}`,
2680
+ path: rel
2681
+ });
2682
+ }
2683
+ const hasError = issues.some((issue) => issue.severity === "error");
2684
+ return {
2685
+ ok: !hasError,
2686
+ status: hasError ? "fail" : "pass",
2687
+ root,
2688
+ manifest,
2689
+ issues,
2690
+ checkedFiles: listed.size
2691
+ };
2692
+ }
2693
+
2694
+ // packages/core/src/evidence/ci.ts
2695
+ function asMap(value) {
2696
+ if (value instanceof Map) return new Map(value);
2697
+ return new Map(Object.entries(value));
2698
+ }
2699
+ function buildEvidenceCiPackage(input) {
2700
+ const sources = asMap(input.sourceContents);
2701
+ const sourceHashes = input.runIds.map((runId) => ({
2702
+ runId,
2703
+ algorithm: "sha256",
2704
+ hash: sha256Hex(sources.get(runId) ?? "")
2705
+ }));
2706
+ const schemaVersions = /* @__PURE__ */ new Set();
2707
+ for (const content of sources.values()) {
2708
+ for (const version of collectTraceSchemaVersions(content)) {
2709
+ schemaVersions.add(version);
2710
+ }
2711
+ }
2712
+ for (const version of collectTraceSchemaVersions(input.redactedTraceJsonl)) {
2713
+ schemaVersions.add(version);
2714
+ }
2715
+ const createdAt = input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
2716
+ const evidenceHtml = buildEvidenceHtmlShell({
2717
+ title: "AgentInspect evidence",
2718
+ runIds: input.runIds,
2719
+ assessmentStatus: input.assessmentStatus,
2720
+ sourceStatus: input.sourceStatus,
2721
+ redactionProfile: input.redactionProfile,
2722
+ verificationPolicy: input.redactionProfile,
2723
+ generatorName: "agent-inspect",
2724
+ generatorVersion: input.generatorVersion,
2725
+ createdAt,
2726
+ summaryText: input.summaryText,
2727
+ checkSummary: {
2728
+ aggregateStatus: input.assessmentStatus,
2729
+ runs: input.runIds.map((runId) => ({
2730
+ runId,
2731
+ status: input.assessmentStatus,
2732
+ sourceStatus: input.sourceStatus,
2733
+ errors: input.assessmentStatus === "UNSAFE" || input.assessmentStatus === "UNKNOWN" ? 1 : 0,
2734
+ warnings: input.assessmentStatus === "SAFE WITH WARNINGS" ? 1 : 0,
2735
+ findings: 0
2736
+ }))
2737
+ }
2738
+ });
2739
+ const packaged = [
2740
+ { path: EVIDENCE_HTML_FILENAME, content: evidenceHtml },
2741
+ { path: "check-results.json", content: input.checkResultsJson },
2742
+ { path: "trace.jsonl", content: input.redactedTraceJsonl }
2743
+ ];
2744
+ const manifest = buildEvidenceManifest({
2745
+ generatorVersion: input.generatorVersion,
2746
+ runIds: input.runIds,
2747
+ traceSchemaVersions: [...schemaVersions].sort((a, b) => a.localeCompare(b)),
2748
+ sourceHashes,
2749
+ redactionProfile: input.redactionProfile,
2750
+ verificationPolicy: input.redactionProfile,
2751
+ assessmentStatus: input.assessmentStatus,
2752
+ sourceStatus: input.sourceStatus,
2753
+ files: packaged,
2754
+ createdAt,
2755
+ note: EVIDENCE_ASSESSMENT_NOTE
2756
+ });
2757
+ return {
2758
+ "evidence.html": evidenceHtml,
2759
+ "evidence.json": serializeEvidenceManifest(manifest),
2760
+ "check-results.json": input.checkResultsJson,
2761
+ "trace.jsonl": input.redactedTraceJsonl,
2762
+ manifest
2763
+ };
2764
+ }
2765
+
1471
2766
  // packages/core/src/suite/types.ts
1472
2767
  var DEFAULT_SUITE_CONFIG_NAMES = [
1473
2768
  "agent-inspect.suite.json",
@@ -3099,6 +4394,6 @@ function renderGateReport(result, options = {}) {
3099
4394
  return renderGateSummaryMarkdown(result);
3100
4395
  }
3101
4396
 
3102
- export { COHORT_METRIC_IDS, DEFAULT_SUITE_ARTIFACTS_DIR, DEFAULT_SUITE_CONFIG_NAMES, SESSION_WORKFLOW_KEYS, SUITE_TEMPLATE_IDS, aggregateBundleSafeStatus, aggregateSessionCheckResults, analyzeCohort, assertBundlePathContained, buildActivitySummary, buildBundleMetadata, buildBundleSummaryMarkdown, buildLocalExplanation, buildPlaceholderArtifact, buildSessionIndex, bundleFailsOnSafety, bundleRunAssetRelativePath, compareCohortAggregates, defaultBundleOutputPath, defaultSuiteConfigTemplate, deriveSessionStatus, enrichSessionRunRecord, enrichSessionSummary, extractSessionWorkflowMetadata, filterMetasBySessionScope, gateHasThresholds, getSuiteTemplate, groupSessionCohorts, isAgentInspectTrace, listSuiteTemplates, loadSessionRunRecords, loadSuiteConfig, loadTraceMetadataList, normalizeBundleOutputPath, normalizeSuiteConfig, parseCohortMetricList, parseDurationFilter, parseGateList, parseGateNumber, parseGroupBySpec, renderActivitySummaryHuman, renderCohortReport, renderCohortSummaryMarkdown, renderGateGithubStepSummary, renderGateJUnit, renderGateReport, renderGateSummaryMarkdown, renderSuiteReport, renderSuiteReportMarkdown, resolveBundleRunIds, resolveSuiteCaseTrace, resolveSuiteConfigPath, resolveSuiteTemplate, runGate, runSuite, sanitizeBundleRunId, searchTraces, sessionKeyForRun, toMetadataSafeStatus, traceMetasToSessionRunRecords, validateSuiteConfig };
4397
+ export { COHORT_METRIC_IDS, DEFAULT_SUITE_ARTIFACTS_DIR, DEFAULT_SUITE_CONFIG_NAMES, EVIDENCE_ASSESSMENT_NOTE, EVIDENCE_FORMAT_VERSION, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, EVIDENCE_VIEW_CSS, EVIDENCE_VIEW_IDS, SESSION_WORKFLOW_KEYS, SUITE_TEMPLATE_IDS, aggregateBundleSafeStatus, aggregateSessionCheckResults, analyzeCohort, assertBundlePathContained, assertEvidenceRelativePath, buildActivitySummary, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceCausalFailureViewHtml, buildEvidenceCiPackage, buildEvidenceCircuitViewHtml, buildEvidenceContractsViewHtml, buildEvidenceDiffViewHtml, buildEvidenceFileEntries, buildEvidenceHtmlShell, buildEvidenceHtmlShellFromManifest, buildEvidenceManifest, buildEvidenceOutcomesViewHtml, buildEvidenceProvenanceViewHtml, buildEvidenceSafetyViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceTreeViewHtml, buildLocalExplanation, buildPlaceholderArtifact, buildSessionIndex, buildZipArchive, bundleFailsOnSafety, bundleRunAssetRelativePath, collectTraceSchemaVersions, compareCohortAggregates, defaultBundleOutputPath, defaultSuiteConfigTemplate, deriveSessionStatus, encodeEmbeddedEvidenceJson, enrichSessionRunRecord, enrichSessionSummary, extractSessionWorkflowMetadata, filterMetasBySessionScope, findFirstCausalFailure, gateHasThresholds, getSuiteTemplate, groupSessionCohorts, inferEvidenceFileRole, isAgentInspectTrace, isSha256Hex, listSuiteTemplates, loadSessionRunRecords, loadSuiteConfig, loadTraceMetadataList, normalizeBundleOutputPath, normalizeSuiteConfig, parseCohortMetricList, parseDurationFilter, parseEvidenceManifestJson, parseGateList, parseGateNumber, parseGroupBySpec, renderActivitySummaryHuman, renderCohortReport, renderCohortSummaryMarkdown, renderGateGithubStepSummary, renderGateJUnit, renderGateReport, renderGateSummaryMarkdown, renderSuiteReport, renderSuiteReportMarkdown, resolveBundleRunIds, resolveSuiteCaseTrace, resolveSuiteConfigPath, resolveSuiteTemplate, runGate, runSuite, sanitizeBundleRunId, searchTraces, serializeEvidenceManifest, sessionKeyForRun, sha256Equals, sha256Hex, toMetadataSafeStatus, traceMetasToSessionRunRecords, validateEvidenceManifest, validateSuiteConfig, verifyEvidenceDirectory };
3103
4398
  //# sourceMappingURL=advanced.mjs.map
3104
4399
  //# sourceMappingURL=advanced.mjs.map