agent-inspect 6.8.0 → 6.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/docs/BUNDLES.md +31 -9
- package/docs/CI-ARTIFACTS.md +10 -1
- package/docs/CLI.md +20 -4
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-TO4VENHV.mjs → chunk-36IJ76LH.mjs} +1857 -158
- package/packages/cli/dist/chunk-36IJ76LH.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +10764 -8877
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +825 -754
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-Z5W27YCW.mjs → src-YFN3Q3GP.mjs} +3 -3
- package/packages/cli/dist/{src-Z5W27YCW.mjs.map → src-YFN3Q3GP.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +1718 -18
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +338 -4
- package/packages/core/dist/advanced.d.ts +338 -4
- package/packages/core/dist/advanced.mjs +1166 -12
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/checks.cjs +105 -14
- package/packages/core/dist/checks.cjs.map +1 -1
- package/packages/core/dist/checks.d.cts +2 -2
- package/packages/core/dist/checks.d.ts +2 -2
- package/packages/core/dist/checks.mjs +1 -1
- package/packages/core/dist/chunk-F7STQ5JF.mjs +479 -0
- package/packages/core/dist/chunk-F7STQ5JF.mjs.map +1 -0
- package/packages/core/dist/{chunk-EQVXDGGU.mjs → chunk-QT6CQ2XA.mjs} +107 -16
- package/packages/core/dist/chunk-QT6CQ2XA.mjs.map +1 -0
- package/packages/core/dist/diff.mjs +3 -477
- package/packages/core/dist/diff.mjs.map +1 -1
- package/packages/core/dist/{index-BblJEdYZ.d.ts → index-BO7l0iAe.d.ts} +44 -1
- package/packages/core/dist/{index-DyKk7iR9.d.cts → index-mdFcxSOR.d.cts} +44 -1
- package/packages/core/dist/reporters.cjs +25 -0
- package/packages/core/dist/reporters.cjs.map +1 -1
- package/packages/core/dist/reporters.d.cts +16 -2
- package/packages/core/dist/reporters.d.ts +16 -2
- package/packages/core/dist/reporters.mjs +24 -1
- package/packages/core/dist/reporters.mjs.map +1 -1
- package/packages/cli/dist/chunk-TO4VENHV.mjs.map +0 -1
- package/packages/core/dist/chunk-EQVXDGGU.mjs.map +0 -1
|
@@ -711,6 +711,15 @@ function persistedInspectEventToTraceEvents(event) {
|
|
|
711
711
|
}
|
|
712
712
|
return fromNativeStep(event);
|
|
713
713
|
}
|
|
714
|
+
function persistedInspectEventsToTraceEvents(events, options) {
|
|
715
|
+
const out = [];
|
|
716
|
+
events.forEach((event, index) => {
|
|
717
|
+
const rows = persistedInspectEventToTraceEvents(event);
|
|
718
|
+
if (rows.length === 0 && options?.eventIndex !== void 0) ;
|
|
719
|
+
out.push(...rows);
|
|
720
|
+
});
|
|
721
|
+
return out;
|
|
722
|
+
}
|
|
714
723
|
|
|
715
724
|
// node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/url-alphabet/index.js
|
|
716
725
|
var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
@@ -2131,6 +2140,20 @@ function extractOutcomesFromPersistedEvents(events) {
|
|
|
2131
2140
|
}
|
|
2132
2141
|
return out.sort((a, b) => a.observedAt - b.observedAt || a.name.localeCompare(b.name));
|
|
2133
2142
|
}
|
|
2143
|
+
function summarizeObservedOutcomes(outcomes) {
|
|
2144
|
+
const summary = {
|
|
2145
|
+
total: outcomes.length,
|
|
2146
|
+
passed: 0,
|
|
2147
|
+
failed: 0,
|
|
2148
|
+
unknown: 0,
|
|
2149
|
+
skipped: 0,
|
|
2150
|
+
outcomes: [...outcomes]
|
|
2151
|
+
};
|
|
2152
|
+
for (const outcome of outcomes) {
|
|
2153
|
+
summary[outcome.status] += 1;
|
|
2154
|
+
}
|
|
2155
|
+
return summary;
|
|
2156
|
+
}
|
|
2134
2157
|
function outcomesMatchingStatus(outcomes, statuses) {
|
|
2135
2158
|
const set = new Set(statuses);
|
|
2136
2159
|
return outcomes.filter((outcome) => set.has(outcome.status));
|
|
@@ -2140,6 +2163,18 @@ function parseObservationFilter(value) {
|
|
|
2140
2163
|
return parseObservedOutcomeStatus(value);
|
|
2141
2164
|
}
|
|
2142
2165
|
|
|
2166
|
+
// packages/core/src/outcomes/render.ts
|
|
2167
|
+
function renderObservedOutcomesHtml(summary) {
|
|
2168
|
+
if (summary.total === 0) {
|
|
2169
|
+
return "<p>No observed outcomes recorded for this run.</p>";
|
|
2170
|
+
}
|
|
2171
|
+
const rows = summary.outcomes.map((outcome) => {
|
|
2172
|
+
const esc = (v) => v.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
2173
|
+
return `<tr><td>${esc(outcome.name)}</td><td>${esc(outcome.status)}</td><td>${esc(outcome.expectation)}</td><td>${esc(outcome.method ?? "-")}</td></tr>`;
|
|
2174
|
+
}).join("");
|
|
2175
|
+
return `<p>Total: ${summary.total} (passed ${summary.passed}, failed ${summary.failed}, unknown ${summary.unknown}, skipped ${summary.skipped})</p><table><thead><tr><th>Name</th><th>Status</th><th>Expectation</th><th>Method</th></tr></thead><tbody>${rows}</tbody></table>`;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2143
2178
|
// packages/core/src/inspector.ts
|
|
2144
2179
|
var INSPECTOR_PERSISTED_SCHEMA_VERSION = "1.0";
|
|
2145
2180
|
function normalizeName2(name, fallback) {
|
|
@@ -4986,12 +5021,12 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
4986
5021
|
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
4987
5022
|
);
|
|
4988
5023
|
const ordered = [...runs].sort(compareRuns);
|
|
4989
|
-
const
|
|
5024
|
+
const path14 = [];
|
|
4990
5025
|
const visited = /* @__PURE__ */ new Set();
|
|
4991
5026
|
const pushRun = (run, confidence, source) => {
|
|
4992
5027
|
if (visited.has(run.runId)) return;
|
|
4993
5028
|
visited.add(run.runId);
|
|
4994
|
-
|
|
5029
|
+
path14.push({
|
|
4995
5030
|
runId: run.runId,
|
|
4996
5031
|
name: run.name,
|
|
4997
5032
|
startedAt: run.startedAt,
|
|
@@ -5016,7 +5051,7 @@ function buildCriticalPath(runs, handoffs) {
|
|
|
5016
5051
|
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
5017
5052
|
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
5018
5053
|
}
|
|
5019
|
-
return
|
|
5054
|
+
return path14;
|
|
5020
5055
|
}
|
|
5021
5056
|
function metaRunIdMatches(run, token, runById) {
|
|
5022
5057
|
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
@@ -5283,8 +5318,9 @@ function buildBundleSummaryMarkdown(parts) {
|
|
|
5283
5318
|
""
|
|
5284
5319
|
];
|
|
5285
5320
|
for (const run of checks.runs) {
|
|
5321
|
+
const source = run.sourceStatus !== void 0 && run.sourceStatus !== run.status ? `; source ${run.sourceStatus}` : "";
|
|
5286
5322
|
lines.push(
|
|
5287
|
-
`- \`${run.runId}\`: ${run.status} (${run.findings} finding(s), ${run.errors} error(s), ${run.warnings} warning(s))`
|
|
5323
|
+
`- \`${run.runId}\`: artifact ${run.status}${source} (${run.findings} finding(s), ${run.errors} error(s), ${run.warnings} warning(s))`
|
|
5288
5324
|
);
|
|
5289
5325
|
}
|
|
5290
5326
|
lines.push("", "## Redaction", "", `Total findings: ${redaction.totalFindings}`, "");
|
|
@@ -5325,13 +5361,13 @@ function assertBundlePathContained(outputDir, relativePath) {
|
|
|
5325
5361
|
}
|
|
5326
5362
|
return resolved;
|
|
5327
5363
|
}
|
|
5328
|
-
function normalizeBundleOutputPath(out) {
|
|
5364
|
+
function normalizeBundleOutputPath(out, options) {
|
|
5329
5365
|
const trimmed = out.trim();
|
|
5330
5366
|
if (trimmed === "") {
|
|
5331
5367
|
throw new Error("--out requires a non-empty path.");
|
|
5332
5368
|
}
|
|
5333
5369
|
const resolved = path5__default.default.resolve(trimmed);
|
|
5334
|
-
if (resolved.toLowerCase().endsWith(".zip")) {
|
|
5370
|
+
if (options?.preserveZipExtension !== true && resolved.toLowerCase().endsWith(".zip")) {
|
|
5335
5371
|
return resolved.slice(0, -4);
|
|
5336
5372
|
}
|
|
5337
5373
|
return resolved;
|
|
@@ -5342,6 +5378,1634 @@ function defaultBundleOutputPath(runIds) {
|
|
|
5342
5378
|
return path5__default.default.resolve(`agent-inspect-bundle-${label}-${stamp}`);
|
|
5343
5379
|
}
|
|
5344
5380
|
|
|
5381
|
+
// packages/core/src/evidence/types.ts
|
|
5382
|
+
var EVIDENCE_FORMAT_VERSION = "1.0";
|
|
5383
|
+
var EVIDENCE_ASSESSMENT_NOTE = "Best-effort local safety verification only; not a compliance certification.";
|
|
5384
|
+
var EVIDENCE_MANIFEST_FILENAME = "evidence.json";
|
|
5385
|
+
var SHA256_RE = /^[a-f0-9]{64}$/i;
|
|
5386
|
+
function sha256Hex(data) {
|
|
5387
|
+
const hash = crypto.createHash("sha256");
|
|
5388
|
+
if (typeof data === "string") {
|
|
5389
|
+
hash.update(data, "utf8");
|
|
5390
|
+
} else {
|
|
5391
|
+
hash.update(data);
|
|
5392
|
+
}
|
|
5393
|
+
return hash.digest("hex");
|
|
5394
|
+
}
|
|
5395
|
+
function isSha256Hex(value) {
|
|
5396
|
+
return SHA256_RE.test(value);
|
|
5397
|
+
}
|
|
5398
|
+
function sha256Equals(expected, actual) {
|
|
5399
|
+
if (!isSha256Hex(expected) || !isSha256Hex(actual)) {
|
|
5400
|
+
return false;
|
|
5401
|
+
}
|
|
5402
|
+
const a = expected.toLowerCase();
|
|
5403
|
+
const b = actual.toLowerCase();
|
|
5404
|
+
if (a.length !== b.length) return false;
|
|
5405
|
+
let mismatch = 0;
|
|
5406
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
5407
|
+
mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
5408
|
+
}
|
|
5409
|
+
return mismatch === 0;
|
|
5410
|
+
}
|
|
5411
|
+
function assertEvidenceRelativePath(relativePath) {
|
|
5412
|
+
if (typeof relativePath !== "string" || relativePath.trim() === "") {
|
|
5413
|
+
throw new Error("Evidence file path must be a non-empty relative path.");
|
|
5414
|
+
}
|
|
5415
|
+
const trimmed = relativePath.trim().replaceAll("\\", "/");
|
|
5416
|
+
if (path5__default.default.isAbsolute(trimmed) || trimmed.startsWith("/")) {
|
|
5417
|
+
throw new Error(`Evidence file path must be relative: ${relativePath}`);
|
|
5418
|
+
}
|
|
5419
|
+
const parts = trimmed.split("/").filter((part) => part !== "");
|
|
5420
|
+
if (parts.length === 0) {
|
|
5421
|
+
throw new Error(`Evidence file path must be relative: ${relativePath}`);
|
|
5422
|
+
}
|
|
5423
|
+
for (const part of parts) {
|
|
5424
|
+
if (part === "." || part === "..") {
|
|
5425
|
+
throw new Error(`Evidence file path must not contain "." or "..": ${relativePath}`);
|
|
5426
|
+
}
|
|
5427
|
+
}
|
|
5428
|
+
return parts.join("/");
|
|
5429
|
+
}
|
|
5430
|
+
|
|
5431
|
+
// packages/core/src/evidence/manifest.ts
|
|
5432
|
+
function stable(value) {
|
|
5433
|
+
if (Array.isArray(value)) return value.map(stable);
|
|
5434
|
+
if (value === null || typeof value !== "object") return value;
|
|
5435
|
+
const record = value;
|
|
5436
|
+
return Object.fromEntries(
|
|
5437
|
+
Object.keys(record).sort((a, b) => a.localeCompare(b)).map((key) => [key, stable(record[key])])
|
|
5438
|
+
);
|
|
5439
|
+
}
|
|
5440
|
+
function serializeEvidenceManifest(manifest) {
|
|
5441
|
+
return `${JSON.stringify(stable(manifest), null, 2)}
|
|
5442
|
+
`;
|
|
5443
|
+
}
|
|
5444
|
+
function inferEvidenceFileRole(relativePath) {
|
|
5445
|
+
const normalized = assertEvidenceRelativePath(relativePath);
|
|
5446
|
+
const base = normalized.includes("/") ? normalized.slice(normalized.lastIndexOf("/") + 1) : normalized;
|
|
5447
|
+
if (base === "evidence.html" || base === "trace.html" || base.endsWith(".html")) {
|
|
5448
|
+
return "report";
|
|
5449
|
+
}
|
|
5450
|
+
if (base === "trace.jsonl" || base.endsWith(".jsonl")) {
|
|
5451
|
+
return "redacted-trace";
|
|
5452
|
+
}
|
|
5453
|
+
if (base === "check-results.json") {
|
|
5454
|
+
return "checks";
|
|
5455
|
+
}
|
|
5456
|
+
if (base === "redaction-report.json") {
|
|
5457
|
+
return "redaction-report";
|
|
5458
|
+
}
|
|
5459
|
+
if (base === "summary.md") {
|
|
5460
|
+
return "summary";
|
|
5461
|
+
}
|
|
5462
|
+
return "other";
|
|
5463
|
+
}
|
|
5464
|
+
function buildEvidenceFileEntries(files) {
|
|
5465
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
5466
|
+
for (const file of files) {
|
|
5467
|
+
const relativePath = assertEvidenceRelativePath(file.path);
|
|
5468
|
+
if (relativePath === EVIDENCE_MANIFEST_FILENAME) {
|
|
5469
|
+
throw new Error(
|
|
5470
|
+
`Do not include ${EVIDENCE_MANIFEST_FILENAME} in packaged file hashes (self-hash is undefined).`
|
|
5471
|
+
);
|
|
5472
|
+
}
|
|
5473
|
+
if (byPath.has(relativePath)) {
|
|
5474
|
+
throw new Error(`Duplicate evidence file path: ${relativePath}`);
|
|
5475
|
+
}
|
|
5476
|
+
byPath.set(relativePath, {
|
|
5477
|
+
path: relativePath,
|
|
5478
|
+
sha256: sha256Hex(file.content),
|
|
5479
|
+
role: file.role ?? inferEvidenceFileRole(relativePath)
|
|
5480
|
+
});
|
|
5481
|
+
}
|
|
5482
|
+
return [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
|
|
5483
|
+
}
|
|
5484
|
+
function buildEvidenceManifest(parts) {
|
|
5485
|
+
const runIds = [...parts.runIds];
|
|
5486
|
+
if (runIds.length === 0) {
|
|
5487
|
+
throw new Error("Evidence manifest requires at least one run id.");
|
|
5488
|
+
}
|
|
5489
|
+
for (const item of parts.sourceHashes) {
|
|
5490
|
+
if (!runIds.includes(item.runId)) {
|
|
5491
|
+
throw new Error(`sourceHashes runId "${item.runId}" is not listed in source.runIds.`);
|
|
5492
|
+
}
|
|
5493
|
+
if (item.algorithm !== "sha256") {
|
|
5494
|
+
throw new Error(`Unsupported source hash algorithm: ${item.algorithm}`);
|
|
5495
|
+
}
|
|
5496
|
+
}
|
|
5497
|
+
const assessment = {
|
|
5498
|
+
status: parts.assessmentStatus,
|
|
5499
|
+
note: parts.note ?? EVIDENCE_ASSESSMENT_NOTE
|
|
5500
|
+
};
|
|
5501
|
+
if (parts.sourceStatus !== void 0) {
|
|
5502
|
+
assessment.sourceStatus = parts.sourceStatus;
|
|
5503
|
+
}
|
|
5504
|
+
return {
|
|
5505
|
+
evidenceFormatVersion: EVIDENCE_FORMAT_VERSION,
|
|
5506
|
+
generator: {
|
|
5507
|
+
name: parts.generatorName ?? "agent-inspect",
|
|
5508
|
+
version: parts.generatorVersion
|
|
5509
|
+
},
|
|
5510
|
+
createdAt: parts.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
5511
|
+
source: {
|
|
5512
|
+
runIds,
|
|
5513
|
+
traceSchemaVersions: [...parts.traceSchemaVersions].sort((a, b) => a.localeCompare(b)),
|
|
5514
|
+
sourceHashes: [...parts.sourceHashes].sort((a, b) => a.runId.localeCompare(b.runId))
|
|
5515
|
+
},
|
|
5516
|
+
policy: {
|
|
5517
|
+
redactionProfile: parts.redactionProfile,
|
|
5518
|
+
verificationPolicy: parts.verificationPolicy ?? parts.redactionProfile
|
|
5519
|
+
},
|
|
5520
|
+
assessment,
|
|
5521
|
+
files: buildEvidenceFileEntries(parts.files)
|
|
5522
|
+
};
|
|
5523
|
+
}
|
|
5524
|
+
function validateEvidenceManifest(value) {
|
|
5525
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
5526
|
+
throw new Error("Evidence manifest must be a JSON object.");
|
|
5527
|
+
}
|
|
5528
|
+
const record = value;
|
|
5529
|
+
if (record.evidenceFormatVersion !== EVIDENCE_FORMAT_VERSION) {
|
|
5530
|
+
throw new Error(
|
|
5531
|
+
`Unsupported evidenceFormatVersion: ${String(record.evidenceFormatVersion)}`
|
|
5532
|
+
);
|
|
5533
|
+
}
|
|
5534
|
+
const generator = record.generator;
|
|
5535
|
+
if (generator === null || typeof generator !== "object" || Array.isArray(generator) || typeof generator.name !== "string" || typeof generator.version !== "string") {
|
|
5536
|
+
throw new Error("Evidence manifest requires generator.name and generator.version.");
|
|
5537
|
+
}
|
|
5538
|
+
const source = record.source;
|
|
5539
|
+
if (source === null || typeof source !== "object" || Array.isArray(source)) {
|
|
5540
|
+
throw new Error("Evidence manifest requires source.");
|
|
5541
|
+
}
|
|
5542
|
+
const sourceRecord = source;
|
|
5543
|
+
if (!Array.isArray(sourceRecord.runIds) || sourceRecord.runIds.length === 0) {
|
|
5544
|
+
throw new Error("Evidence manifest source.runIds must be a non-empty array.");
|
|
5545
|
+
}
|
|
5546
|
+
if (!Array.isArray(sourceRecord.traceSchemaVersions)) {
|
|
5547
|
+
throw new Error("Evidence manifest source.traceSchemaVersions must be an array.");
|
|
5548
|
+
}
|
|
5549
|
+
if (!Array.isArray(sourceRecord.sourceHashes)) {
|
|
5550
|
+
throw new Error("Evidence manifest source.sourceHashes must be an array.");
|
|
5551
|
+
}
|
|
5552
|
+
const policy = record.policy;
|
|
5553
|
+
if (policy === null || typeof policy !== "object" || Array.isArray(policy)) {
|
|
5554
|
+
throw new Error("Evidence manifest requires policy.");
|
|
5555
|
+
}
|
|
5556
|
+
const assessment = record.assessment;
|
|
5557
|
+
if (assessment === null || typeof assessment !== "object" || Array.isArray(assessment) || typeof assessment.status !== "string") {
|
|
5558
|
+
throw new Error("Evidence manifest requires assessment.status.");
|
|
5559
|
+
}
|
|
5560
|
+
if (!Array.isArray(record.files) || record.files.length === 0) {
|
|
5561
|
+
throw new Error("Evidence manifest files must be a non-empty array.");
|
|
5562
|
+
}
|
|
5563
|
+
for (const file of record.files) {
|
|
5564
|
+
if (file === null || typeof file !== "object" || Array.isArray(file)) {
|
|
5565
|
+
throw new Error("Evidence manifest file entries must be objects.");
|
|
5566
|
+
}
|
|
5567
|
+
const entry = file;
|
|
5568
|
+
if (typeof entry.path !== "string") {
|
|
5569
|
+
throw new Error("Evidence file entry requires path.");
|
|
5570
|
+
}
|
|
5571
|
+
assertEvidenceRelativePath(entry.path);
|
|
5572
|
+
if (typeof entry.sha256 !== "string" || !/^[a-f0-9]{64}$/i.test(entry.sha256)) {
|
|
5573
|
+
throw new Error(`Evidence file entry requires sha256 hex for ${entry.path}.`);
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
return value;
|
|
5577
|
+
}
|
|
5578
|
+
function parseEvidenceManifestJson(text) {
|
|
5579
|
+
let parsed;
|
|
5580
|
+
try {
|
|
5581
|
+
parsed = JSON.parse(text);
|
|
5582
|
+
} catch (error) {
|
|
5583
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5584
|
+
throw new Error(`Evidence manifest is not valid JSON: ${message}`);
|
|
5585
|
+
}
|
|
5586
|
+
return validateEvidenceManifest(parsed);
|
|
5587
|
+
}
|
|
5588
|
+
function collectTraceSchemaVersions(jsonl) {
|
|
5589
|
+
const versions = /* @__PURE__ */ new Set();
|
|
5590
|
+
for (const line of jsonl.split(/\r?\n/)) {
|
|
5591
|
+
const trimmed = line.trim();
|
|
5592
|
+
if (trimmed === "") continue;
|
|
5593
|
+
try {
|
|
5594
|
+
const row = JSON.parse(trimmed);
|
|
5595
|
+
if (typeof row.schemaVersion === "string" && row.schemaVersion.trim() !== "") {
|
|
5596
|
+
versions.add(row.schemaVersion.trim());
|
|
5597
|
+
}
|
|
5598
|
+
} catch {
|
|
5599
|
+
}
|
|
5600
|
+
}
|
|
5601
|
+
return [...versions].sort((a, b) => a.localeCompare(b));
|
|
5602
|
+
}
|
|
5603
|
+
|
|
5604
|
+
// packages/core/src/exporters/helpers.ts
|
|
5605
|
+
function escapeHtml(value) {
|
|
5606
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
5607
|
+
}
|
|
5608
|
+
function sortKeysDeep(input) {
|
|
5609
|
+
if (input === null || typeof input !== "object") return input;
|
|
5610
|
+
if (Array.isArray(input)) return input.map(sortKeysDeep);
|
|
5611
|
+
const o = input;
|
|
5612
|
+
const out = {};
|
|
5613
|
+
for (const k of Object.keys(o).sort()) {
|
|
5614
|
+
out[k] = sortKeysDeep(o[k]);
|
|
5615
|
+
}
|
|
5616
|
+
return out;
|
|
5617
|
+
}
|
|
5618
|
+
function stableJson(value, pretty) {
|
|
5619
|
+
const sorted = sortKeysDeep(value);
|
|
5620
|
+
return JSON.stringify(sorted);
|
|
5621
|
+
}
|
|
5622
|
+
function flattenTree(tree) {
|
|
5623
|
+
const out = [];
|
|
5624
|
+
function walk(nodes) {
|
|
5625
|
+
for (const n of nodes) {
|
|
5626
|
+
out.push(n);
|
|
5627
|
+
if (n.children.length > 0) walk(n.children);
|
|
5628
|
+
}
|
|
5629
|
+
}
|
|
5630
|
+
walk(tree.children);
|
|
5631
|
+
return out;
|
|
5632
|
+
}
|
|
5633
|
+
|
|
5634
|
+
// packages/core/src/evidence/views.ts
|
|
5635
|
+
function renderTreeHtml(nodes, ulClass = "tree") {
|
|
5636
|
+
if (nodes.length === 0) return "";
|
|
5637
|
+
const parts = [`<ul class="${ulClass}">`];
|
|
5638
|
+
for (const n of nodes) {
|
|
5639
|
+
const ev = n.event;
|
|
5640
|
+
const status = ev.status ?? "?";
|
|
5641
|
+
const dur = ev.durationMs !== void 0 && Number.isFinite(ev.durationMs) ? `${ev.durationMs}ms` : "-";
|
|
5642
|
+
const errClass = ev.status === "error" ? " is-error" : "";
|
|
5643
|
+
parts.push(`<li class="tree-node${errClass}">`);
|
|
5644
|
+
parts.push(
|
|
5645
|
+
`<span class="nm">${escapeHtml(ev.name)}</span> <span class="meta">[${escapeHtml(ev.kind)}] ${escapeHtml(status)} (${escapeHtml(dur)})</span>`
|
|
5646
|
+
);
|
|
5647
|
+
if (n.children.length > 0) {
|
|
5648
|
+
parts.push(renderTreeHtml(n.children, "tree nested"));
|
|
5649
|
+
}
|
|
5650
|
+
parts.push("</li>");
|
|
5651
|
+
}
|
|
5652
|
+
parts.push("</ul>");
|
|
5653
|
+
return parts.join("");
|
|
5654
|
+
}
|
|
5655
|
+
function buildEvidenceTreeViewHtml(trees) {
|
|
5656
|
+
if (trees.length === 0) {
|
|
5657
|
+
return `<p class="muted">No execution trees available.</p>`;
|
|
5658
|
+
}
|
|
5659
|
+
const parts = [];
|
|
5660
|
+
for (const tree of trees) {
|
|
5661
|
+
parts.push(`<article class="run-block">`);
|
|
5662
|
+
parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
|
|
5663
|
+
if (tree.name) {
|
|
5664
|
+
parts.push(`<p class="muted">Name: ${escapeHtml(tree.name)}</p>`);
|
|
5665
|
+
}
|
|
5666
|
+
parts.push(
|
|
5667
|
+
`<p>Status: <strong>${escapeHtml(String(tree.status ?? "unknown"))}</strong>${tree.durationMs !== void 0 ? ` \xB7 ${escapeHtml(String(tree.durationMs))}ms` : ""}</p>`
|
|
5668
|
+
);
|
|
5669
|
+
parts.push(
|
|
5670
|
+
tree.children.length > 0 ? renderTreeHtml(tree.children) : `<p class="muted">No steps recorded.</p>`
|
|
5671
|
+
);
|
|
5672
|
+
parts.push(`</article>`);
|
|
5673
|
+
}
|
|
5674
|
+
return parts.join("\n");
|
|
5675
|
+
}
|
|
5676
|
+
function timelineRows(tree) {
|
|
5677
|
+
const flat = flattenTree(tree);
|
|
5678
|
+
const origin = tree.startedAt ?? flat.reduce((min, n) => {
|
|
5679
|
+
const t = n.event.timestamp;
|
|
5680
|
+
if (!Number.isFinite(t)) return min;
|
|
5681
|
+
return min === void 0 ? t : Math.min(min, t);
|
|
5682
|
+
}, void 0) ?? 0;
|
|
5683
|
+
return flat.filter((n) => n.event.kind !== "RUN").map((n) => {
|
|
5684
|
+
const started = Number.isFinite(n.event.timestamp) ? n.event.timestamp : origin;
|
|
5685
|
+
const durationMs2 = n.event.durationMs !== void 0 && Number.isFinite(n.event.durationMs) ? Math.max(0, n.event.durationMs) : 0;
|
|
5686
|
+
return {
|
|
5687
|
+
name: n.event.name,
|
|
5688
|
+
kind: n.event.kind,
|
|
5689
|
+
status: n.event.status ?? "?",
|
|
5690
|
+
offsetMs: Math.max(0, started - origin),
|
|
5691
|
+
durationMs: durationMs2,
|
|
5692
|
+
isError: n.event.status === "error"
|
|
5693
|
+
};
|
|
5694
|
+
}).sort((a, b) => a.offsetMs - b.offsetMs || a.name.localeCompare(b.name));
|
|
5695
|
+
}
|
|
5696
|
+
function buildEvidenceTimelineViewHtml(trees) {
|
|
5697
|
+
if (trees.length === 0) {
|
|
5698
|
+
return `<p class="muted">No timeline data available.</p>`;
|
|
5699
|
+
}
|
|
5700
|
+
const parts = [];
|
|
5701
|
+
for (const tree of trees) {
|
|
5702
|
+
const rows = timelineRows(tree);
|
|
5703
|
+
const maxEnd = rows.reduce(
|
|
5704
|
+
(max, row) => Math.max(max, row.offsetMs + Math.max(row.durationMs, 1)),
|
|
5705
|
+
1
|
|
5706
|
+
);
|
|
5707
|
+
parts.push(`<article class="run-block">`);
|
|
5708
|
+
parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
|
|
5709
|
+
if (rows.length === 0) {
|
|
5710
|
+
parts.push(`<p class="muted">No step timings recorded.</p>`);
|
|
5711
|
+
} else {
|
|
5712
|
+
parts.push(`<div class="waterfall" role="list">`);
|
|
5713
|
+
for (const row of rows) {
|
|
5714
|
+
const left = row.offsetMs / maxEnd * 100;
|
|
5715
|
+
const width = Math.max(0.8, Math.max(row.durationMs, 1) / maxEnd * 100);
|
|
5716
|
+
const err = row.isError ? " is-error" : "";
|
|
5717
|
+
parts.push(
|
|
5718
|
+
`<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>`
|
|
5719
|
+
);
|
|
5720
|
+
}
|
|
5721
|
+
parts.push(`</div>`);
|
|
5722
|
+
}
|
|
5723
|
+
parts.push(`</article>`);
|
|
5724
|
+
}
|
|
5725
|
+
return parts.join("\n");
|
|
5726
|
+
}
|
|
5727
|
+
function findNodeByEventId(nodes, eventId) {
|
|
5728
|
+
for (const node of nodes) {
|
|
5729
|
+
if (node.event.eventId === eventId) return node;
|
|
5730
|
+
const child = findNodeByEventId(node.children, eventId);
|
|
5731
|
+
if (child) return child;
|
|
5732
|
+
}
|
|
5733
|
+
return void 0;
|
|
5734
|
+
}
|
|
5735
|
+
function buildAncestorChain(tree, failure) {
|
|
5736
|
+
const chain = [failure];
|
|
5737
|
+
let parentId = failure.event.parentId;
|
|
5738
|
+
const guard = /* @__PURE__ */ new Set([failure.event.eventId]);
|
|
5739
|
+
while (parentId && !guard.has(parentId)) {
|
|
5740
|
+
guard.add(parentId);
|
|
5741
|
+
const parent = findNodeByEventId(tree.children, parentId);
|
|
5742
|
+
if (!parent) break;
|
|
5743
|
+
chain.unshift(parent);
|
|
5744
|
+
parentId = parent.event.parentId;
|
|
5745
|
+
}
|
|
5746
|
+
return chain;
|
|
5747
|
+
}
|
|
5748
|
+
function buildEvidenceCausalFailureViewHtml(trees) {
|
|
5749
|
+
if (trees.length === 0) {
|
|
5750
|
+
return `<p class="muted">No runs available for causal analysis.</p>`;
|
|
5751
|
+
}
|
|
5752
|
+
const parts = [];
|
|
5753
|
+
for (const tree of trees) {
|
|
5754
|
+
parts.push(`<article class="run-block">`);
|
|
5755
|
+
parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
|
|
5756
|
+
const errors = flattenTree(tree).filter((n) => n.event.status === "error" || n.event.kind === "ERROR").sort((a, b) => a.event.timestamp - b.event.timestamp);
|
|
5757
|
+
if (errors.length === 0) {
|
|
5758
|
+
parts.push(
|
|
5759
|
+
`<p class="muted">No error-status events found. Run status: <strong>${escapeHtml(String(tree.status ?? "unknown"))}</strong>.</p>`
|
|
5760
|
+
);
|
|
5761
|
+
parts.push(`</article>`);
|
|
5762
|
+
continue;
|
|
5763
|
+
}
|
|
5764
|
+
const first = errors[0];
|
|
5765
|
+
const chain = buildAncestorChain(tree, first);
|
|
5766
|
+
parts.push(`<p>First error by timestamp:</p>`);
|
|
5767
|
+
parts.push(`<ol class="causal-chain">`);
|
|
5768
|
+
for (const node of chain) {
|
|
5769
|
+
const isTip = node.event.eventId === first.event.eventId;
|
|
5770
|
+
const msg = typeof node.event.attributes?.message === "string" ? node.event.attributes.message : typeof node.event.attributes?.error === "string" ? node.event.attributes.error : void 0;
|
|
5771
|
+
parts.push(
|
|
5772
|
+
`<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>`
|
|
5773
|
+
);
|
|
5774
|
+
}
|
|
5775
|
+
parts.push(`</ol>`);
|
|
5776
|
+
if (errors.length > 1) {
|
|
5777
|
+
parts.push(
|
|
5778
|
+
`<p class="muted">${escapeHtml(String(errors.length - 1))} additional error event(s) not shown in the primary chain.</p>`
|
|
5779
|
+
);
|
|
5780
|
+
}
|
|
5781
|
+
parts.push(`</article>`);
|
|
5782
|
+
}
|
|
5783
|
+
return parts.join("\n");
|
|
5784
|
+
}
|
|
5785
|
+
var EVIDENCE_VIEW_CSS = `
|
|
5786
|
+
ul.tree{list-style:none;padding-left:1rem;margin:.5rem 0}
|
|
5787
|
+
ul.tree.nested{padding-left:1.25rem;border-left:1px solid var(--line);margin:.25rem 0}
|
|
5788
|
+
.tree-node.is-error .nm,.wf-row.is-error .nm,.causal-tip .nm{color:var(--unsafe)}
|
|
5789
|
+
.waterfall{display:flex;flex-direction:column;gap:.45rem;max-width:52rem}
|
|
5790
|
+
.wf-row{display:grid;grid-template-columns:minmax(10rem,18rem) 1fr;gap:.6rem;align-items:center}
|
|
5791
|
+
.wf-track{position:relative;height:.7rem;background:#e8e8e4;border-radius:.25rem;overflow:hidden}
|
|
5792
|
+
.wf-bar{position:absolute;top:0;bottom:0;background:var(--accent);border-radius:.25rem}
|
|
5793
|
+
.wf-row.is-error .wf-bar{background:var(--unsafe)}
|
|
5794
|
+
.causal-chain{max-width:44rem}
|
|
5795
|
+
.causal-msg{margin:.25rem 0 0;color:var(--muted);font-size:.92rem}
|
|
5796
|
+
.run-block{margin:0 0 1.25rem;padding-bottom:1rem;border-bottom:1px solid var(--line)}
|
|
5797
|
+
.run-block:last-child{border-bottom:0}
|
|
5798
|
+
@media (max-width:720px){
|
|
5799
|
+
.wf-row{grid-template-columns:1fr}
|
|
5800
|
+
}
|
|
5801
|
+
`.trim();
|
|
5802
|
+
|
|
5803
|
+
// packages/core/src/evidence/html-shell.ts
|
|
5804
|
+
var EVIDENCE_HTML_FILENAME = "evidence.html";
|
|
5805
|
+
var EVIDENCE_HTML_NOTE = "Generated locally by AgentInspect. Share-checked evidence for review \u2014 not a compliance or security certification.";
|
|
5806
|
+
var EVIDENCE_VIEW_IDS = [
|
|
5807
|
+
"summary",
|
|
5808
|
+
"tree",
|
|
5809
|
+
"timeline",
|
|
5810
|
+
"causal",
|
|
5811
|
+
"tools-llm",
|
|
5812
|
+
"outcomes",
|
|
5813
|
+
"contracts",
|
|
5814
|
+
"circuit",
|
|
5815
|
+
"diff",
|
|
5816
|
+
"safety",
|
|
5817
|
+
"provenance"
|
|
5818
|
+
];
|
|
5819
|
+
function statusClass(status) {
|
|
5820
|
+
if (status === "SAFE") return "st-safe";
|
|
5821
|
+
if (status === "SAFE WITH WARNINGS") return "st-warn";
|
|
5822
|
+
if (status === "UNSAFE") return "st-unsafe";
|
|
5823
|
+
return "st-unknown";
|
|
5824
|
+
}
|
|
5825
|
+
function viewLabel(id) {
|
|
5826
|
+
switch (id) {
|
|
5827
|
+
case "summary":
|
|
5828
|
+
return "Summary";
|
|
5829
|
+
case "tree":
|
|
5830
|
+
return "Tree";
|
|
5831
|
+
case "timeline":
|
|
5832
|
+
return "Timeline";
|
|
5833
|
+
case "causal":
|
|
5834
|
+
return "Causal failure";
|
|
5835
|
+
case "tools-llm":
|
|
5836
|
+
return "Tools / LLM";
|
|
5837
|
+
case "outcomes":
|
|
5838
|
+
return "Outcomes";
|
|
5839
|
+
case "contracts":
|
|
5840
|
+
return "Contracts / checks";
|
|
5841
|
+
case "circuit":
|
|
5842
|
+
return "Circuit / guardrails";
|
|
5843
|
+
case "diff":
|
|
5844
|
+
return "Diff";
|
|
5845
|
+
case "safety":
|
|
5846
|
+
return "Safety / redaction";
|
|
5847
|
+
case "provenance":
|
|
5848
|
+
return "Provenance";
|
|
5849
|
+
default: {
|
|
5850
|
+
const _exhaustive = id;
|
|
5851
|
+
return _exhaustive;
|
|
5852
|
+
}
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5855
|
+
function encodeEmbeddedEvidenceJson(value) {
|
|
5856
|
+
return JSON.stringify(value).replace(/</g, "\\u003c").replace(/>/g, "\\u003e");
|
|
5857
|
+
}
|
|
5858
|
+
function buildEmbeddedPayload(input) {
|
|
5859
|
+
return {
|
|
5860
|
+
evidenceFormatVersion: input.evidenceFormatVersion ?? "1.0",
|
|
5861
|
+
generator: {
|
|
5862
|
+
name: input.generatorName,
|
|
5863
|
+
version: input.generatorVersion
|
|
5864
|
+
},
|
|
5865
|
+
createdAt: input.createdAt,
|
|
5866
|
+
runIds: [...input.runIds],
|
|
5867
|
+
assessment: {
|
|
5868
|
+
status: input.assessmentStatus,
|
|
5869
|
+
...input.sourceStatus !== void 0 ? { sourceStatus: input.sourceStatus } : {}
|
|
5870
|
+
},
|
|
5871
|
+
policy: {
|
|
5872
|
+
redactionProfile: input.redactionProfile,
|
|
5873
|
+
verificationPolicy: input.verificationPolicy
|
|
5874
|
+
},
|
|
5875
|
+
checkSummary: input.checkSummary
|
|
5876
|
+
};
|
|
5877
|
+
}
|
|
5878
|
+
function buildEvidenceHtmlShell(input) {
|
|
5879
|
+
if (input.runIds.length === 0) {
|
|
5880
|
+
throw new Error("Evidence HTML shell requires at least one run id.");
|
|
5881
|
+
}
|
|
5882
|
+
const maxChars = input.maxEmbeddedJsonChars ?? 64 * 1024;
|
|
5883
|
+
let embedded = encodeEmbeddedEvidenceJson(buildEmbeddedPayload(input));
|
|
5884
|
+
if (embedded.length > maxChars) {
|
|
5885
|
+
embedded = encodeEmbeddedEvidenceJson({
|
|
5886
|
+
truncated: true,
|
|
5887
|
+
evidenceFormatVersion: input.evidenceFormatVersion ?? "1.0",
|
|
5888
|
+
runIds: [...input.runIds],
|
|
5889
|
+
assessment: { status: input.assessmentStatus },
|
|
5890
|
+
note: "Embedded payload truncated to bound; open evidence.json / trace files for full detail."
|
|
5891
|
+
});
|
|
5892
|
+
}
|
|
5893
|
+
const title = escapeHtml(input.title ?? "AgentInspect evidence");
|
|
5894
|
+
const runList = input.runIds.map((id) => `<li><code>${escapeHtml(id)}</code></li>`).join("");
|
|
5895
|
+
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>`;
|
|
5896
|
+
const checkRows = input.checkSummary?.runs.map(
|
|
5897
|
+
(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>`
|
|
5898
|
+
).join("") ?? "";
|
|
5899
|
+
const nav = EVIDENCE_VIEW_IDS.map(
|
|
5900
|
+
(id) => `<a class="nav-link" href="#view-${id}" data-view="${id}">${escapeHtml(viewLabel(id))}</a>`
|
|
5901
|
+
).join("\n");
|
|
5902
|
+
const stubPanels = EVIDENCE_VIEW_IDS.filter((id) => id !== "summary").map((id) => {
|
|
5903
|
+
const body = input.viewBodies?.[id];
|
|
5904
|
+
if (body !== void 0 && body.trim() !== "") {
|
|
5905
|
+
return ` <section id="view-${id}" class="panel" hidden>
|
|
5906
|
+
<h2>${escapeHtml(viewLabel(id))}</h2>
|
|
5907
|
+
${body}
|
|
5908
|
+
</section>`;
|
|
5909
|
+
}
|
|
5910
|
+
return ` <section id="view-${id}" class="panel" hidden>
|
|
5911
|
+
<h2>${escapeHtml(viewLabel(id))}</h2>
|
|
5912
|
+
<p class="muted">This view will be filled in a later AgentInspect 6.10 release. The shell is offline-ready.</p>
|
|
5913
|
+
</section>`;
|
|
5914
|
+
}).join("\n");
|
|
5915
|
+
return `<!doctype html>
|
|
5916
|
+
<html lang="en">
|
|
5917
|
+
<head>
|
|
5918
|
+
<meta charset="utf-8"/>
|
|
5919
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
5920
|
+
<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'"/>
|
|
5921
|
+
<meta name="referrer" content="no-referrer"/>
|
|
5922
|
+
<title>${title}</title>
|
|
5923
|
+
<style>
|
|
5924
|
+
:root{--bg:#f7f7f5;--fg:#1a1a1a;--muted:#5c5c5c;--line:#d8d8d4;--accent:#0b5fff;--safe:#0a7a3e;--warn:#9a6700;--unsafe:#b42318;--unknown:#5c5c5c}
|
|
5925
|
+
*{box-sizing:border-box}
|
|
5926
|
+
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}
|
|
5927
|
+
a{color:var(--accent)}
|
|
5928
|
+
header{padding:1.25rem 1.5rem;border-bottom:1px solid var(--line);background:#fff}
|
|
5929
|
+
header h1{margin:0 0 .35rem;font-size:1.35rem}
|
|
5930
|
+
.note{margin:0;color:var(--muted);font-size:.92rem;max-width:52rem}
|
|
5931
|
+
.layout{display:grid;grid-template-columns:14rem 1fr;min-height:70vh}
|
|
5932
|
+
nav{padding:1rem;border-right:1px solid var(--line);background:#fff}
|
|
5933
|
+
nav .nav-link{display:block;padding:.4rem .55rem;margin:0 0 .2rem;border-radius:.35rem;text-decoration:none;color:inherit}
|
|
5934
|
+
nav .nav-link:hover,nav .nav-link:focus{background:#eef3ff;outline:2px solid var(--accent);outline-offset:1px}
|
|
5935
|
+
main{padding:1.25rem 1.5rem}
|
|
5936
|
+
.panel[hidden]{display:none}
|
|
5937
|
+
.badge{display:inline-block;padding:.15rem .55rem;border-radius:.3rem;font-size:.85rem;font-weight:600}
|
|
5938
|
+
.st-safe{color:var(--safe)}.st-warn{color:var(--warn)}.st-unsafe{color:var(--unsafe)}.st-unknown{color:var(--unknown)}
|
|
5939
|
+
table{border-collapse:collapse;width:100%;max-width:48rem;background:#fff}
|
|
5940
|
+
th,td{border:1px solid var(--line);padding:.4rem .55rem;text-align:left;vertical-align:top}
|
|
5941
|
+
th{background:#f0f0ec}
|
|
5942
|
+
.summary-md,pre.data{white-space:pre-wrap;word-break:break-word;background:#fff;border:1px solid var(--line);padding:.75rem;max-width:52rem}
|
|
5943
|
+
.muted{color:var(--muted)}
|
|
5944
|
+
ul.runs{margin:.4rem 0 1rem;padding-left:1.2rem}
|
|
5945
|
+
@media print{
|
|
5946
|
+
nav{display:none}
|
|
5947
|
+
.layout{display:block}
|
|
5948
|
+
.panel[hidden]{display:block!important;page-break-before:always}
|
|
5949
|
+
header{border:0}
|
|
5950
|
+
}
|
|
5951
|
+
@media (max-width:720px){
|
|
5952
|
+
.layout{grid-template-columns:1fr}
|
|
5953
|
+
nav{border-right:0;border-bottom:1px solid var(--line);display:flex;flex-wrap:wrap;gap:.25rem}
|
|
5954
|
+
}
|
|
5955
|
+
${EVIDENCE_VIEW_CSS}
|
|
5956
|
+
</style>
|
|
5957
|
+
</head>
|
|
5958
|
+
<body>
|
|
5959
|
+
<header>
|
|
5960
|
+
<h1>${title}</h1>
|
|
5961
|
+
<p class="note">${escapeHtml(EVIDENCE_HTML_NOTE)}</p>
|
|
5962
|
+
</header>
|
|
5963
|
+
<div class="layout">
|
|
5964
|
+
<nav aria-label="Evidence views">
|
|
5965
|
+
${nav}
|
|
5966
|
+
</nav>
|
|
5967
|
+
<main id="main">
|
|
5968
|
+
<section id="view-summary" class="panel" tabindex="-1">
|
|
5969
|
+
<h2>Summary</h2>
|
|
5970
|
+
<p>Artifact status: <span class="badge ${statusClass(input.assessmentStatus)}">${escapeHtml(input.assessmentStatus)}</span>
|
|
5971
|
+
${input.sourceStatus !== void 0 ? ` \xB7 Source status: <span class="badge ${statusClass(input.sourceStatus)}">${escapeHtml(input.sourceStatus)}</span>` : ""}</p>
|
|
5972
|
+
<p>Profile: <code>${escapeHtml(input.redactionProfile)}</code> \xB7 Verification: <code>${escapeHtml(input.verificationPolicy)}</code></p>
|
|
5973
|
+
<p>Generator: <code>${escapeHtml(input.generatorName)}@${escapeHtml(input.generatorVersion)}</code>
|
|
5974
|
+
${input.createdAt ? ` \xB7 Created: <code>${escapeHtml(input.createdAt)}</code>` : ""}</p>
|
|
5975
|
+
<h3>Runs</h3>
|
|
5976
|
+
<ul class="runs">${runList}</ul>
|
|
5977
|
+
${checkRows ? `<h3>Check summary</h3>
|
|
5978
|
+
<table>
|
|
5979
|
+
<thead><tr><th>runId</th><th>artifact</th><th>errors</th><th>warnings</th><th>findings</th></tr></thead>
|
|
5980
|
+
<tbody>${checkRows}</tbody>
|
|
5981
|
+
</table>` : ""}
|
|
5982
|
+
<h3>Text summary</h3>
|
|
5983
|
+
${summaryBody}
|
|
5984
|
+
</section>
|
|
5985
|
+
${stubPanels}
|
|
5986
|
+
</main>
|
|
5987
|
+
</div>
|
|
5988
|
+
<script type="application/json" id="ai-evidence-data">${embedded}</script>
|
|
5989
|
+
<script>
|
|
5990
|
+
(function(){
|
|
5991
|
+
var links=document.querySelectorAll("nav .nav-link");
|
|
5992
|
+
var panels=document.querySelectorAll("main .panel");
|
|
5993
|
+
function show(id){
|
|
5994
|
+
for(var i=0;i<panels.length;i++){
|
|
5995
|
+
var p=panels[i];
|
|
5996
|
+
var on=p.id==="view-"+id;
|
|
5997
|
+
if(on){p.removeAttribute("hidden");}else{p.setAttribute("hidden","");}
|
|
5998
|
+
}
|
|
5999
|
+
for(var j=0;j<links.length;j++){
|
|
6000
|
+
var a=links[j];
|
|
6001
|
+
if(a.getAttribute("data-view")===id){a.setAttribute("aria-current","page");}
|
|
6002
|
+
else{a.removeAttribute("aria-current");}
|
|
6003
|
+
}
|
|
6004
|
+
}
|
|
6005
|
+
for(var k=0;k<links.length;k++){
|
|
6006
|
+
links[k].addEventListener("click",function(ev){
|
|
6007
|
+
var id=ev.currentTarget.getAttribute("data-view");
|
|
6008
|
+
if(!id)return;
|
|
6009
|
+
ev.preventDefault();
|
|
6010
|
+
if(history.replaceState){history.replaceState(null,"","#view-"+id);}
|
|
6011
|
+
show(id);
|
|
6012
|
+
var panel=document.getElementById("view-"+id);
|
|
6013
|
+
if(panel)panel.focus();
|
|
6014
|
+
});
|
|
6015
|
+
}
|
|
6016
|
+
var hash=(location.hash||"").replace(/^#view-/,"");
|
|
6017
|
+
var initial="summary";
|
|
6018
|
+
for(var n=0;n<links.length;n++){
|
|
6019
|
+
if(links[n].getAttribute("data-view")===hash){initial=hash;break;}
|
|
6020
|
+
}
|
|
6021
|
+
show(initial);
|
|
6022
|
+
})();
|
|
6023
|
+
</script>
|
|
6024
|
+
</body>
|
|
6025
|
+
</html>
|
|
6026
|
+
`;
|
|
6027
|
+
}
|
|
6028
|
+
function buildEvidenceHtmlShellFromManifest(manifest, extras) {
|
|
6029
|
+
return buildEvidenceHtmlShell({
|
|
6030
|
+
title: extras?.title,
|
|
6031
|
+
runIds: manifest.source.runIds,
|
|
6032
|
+
assessmentStatus: manifest.assessment.status,
|
|
6033
|
+
sourceStatus: manifest.assessment.sourceStatus,
|
|
6034
|
+
redactionProfile: manifest.policy.redactionProfile,
|
|
6035
|
+
verificationPolicy: manifest.policy.verificationPolicy,
|
|
6036
|
+
generatorName: manifest.generator.name,
|
|
6037
|
+
generatorVersion: manifest.generator.version,
|
|
6038
|
+
createdAt: manifest.createdAt,
|
|
6039
|
+
evidenceFormatVersion: manifest.evidenceFormatVersion,
|
|
6040
|
+
summaryText: extras?.summaryText,
|
|
6041
|
+
checkSummary: extras?.checkSummary,
|
|
6042
|
+
viewBodies: extras?.viewBodies
|
|
6043
|
+
});
|
|
6044
|
+
}
|
|
6045
|
+
|
|
6046
|
+
// packages/core/src/diff/comparable.ts
|
|
6047
|
+
function extractOutputPreview(meta) {
|
|
6048
|
+
if (meta === void 0) return void 0;
|
|
6049
|
+
if ("outputPreview" in meta) return meta.outputPreview;
|
|
6050
|
+
if ("resultPreview" in meta) return meta.resultPreview;
|
|
6051
|
+
return void 0;
|
|
6052
|
+
}
|
|
6053
|
+
function mapStepStatus(s) {
|
|
6054
|
+
if (s === void 0) return "running";
|
|
6055
|
+
return s;
|
|
6056
|
+
}
|
|
6057
|
+
function manualTraceEventsToComparableRun(events) {
|
|
6058
|
+
const started = events.find((e) => e.event === "run_started");
|
|
6059
|
+
if (!started || started.event !== "run_started") {
|
|
6060
|
+
throw new Error("Invalid trace: missing run_started");
|
|
6061
|
+
}
|
|
6062
|
+
const rs = started;
|
|
6063
|
+
const runId = rs.runId;
|
|
6064
|
+
const completedAll = events.filter((e) => e.event === "run_completed");
|
|
6065
|
+
const lastCompleted = completedAll[completedAll.length - 1];
|
|
6066
|
+
let runStatus;
|
|
6067
|
+
if (lastCompleted === void 0) runStatus = "running";
|
|
6068
|
+
else runStatus = lastCompleted.status;
|
|
6069
|
+
const durationMs2 = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
6070
|
+
const steps = /* @__PURE__ */ new Map();
|
|
6071
|
+
let order = 0;
|
|
6072
|
+
for (const e of events) {
|
|
6073
|
+
if (e.event !== "step_started") continue;
|
|
6074
|
+
const s = e;
|
|
6075
|
+
const meta = s.metadata ? { ...s.metadata } : void 0;
|
|
6076
|
+
steps.set(s.stepId, {
|
|
6077
|
+
id: s.stepId,
|
|
6078
|
+
parentId: s.parentId,
|
|
6079
|
+
name: s.name,
|
|
6080
|
+
type: s.type,
|
|
6081
|
+
order: order++,
|
|
6082
|
+
timestamp: s.timestamp,
|
|
6083
|
+
metadata: meta
|
|
6084
|
+
});
|
|
6085
|
+
}
|
|
6086
|
+
for (const e of events) {
|
|
6087
|
+
if (e.event !== "step_completed") continue;
|
|
6088
|
+
const acc = steps.get(e.stepId);
|
|
6089
|
+
if (!acc) continue;
|
|
6090
|
+
acc.status = e.status;
|
|
6091
|
+
acc.durationMs = e.durationMs;
|
|
6092
|
+
if (e.error?.message) acc.errorMsg = e.error.message;
|
|
6093
|
+
const extra = e;
|
|
6094
|
+
if (extra.metadata !== void 0 && typeof extra.metadata === "object") {
|
|
6095
|
+
acc.metadata = { ...acc.metadata ?? {}, ...extra.metadata };
|
|
6096
|
+
}
|
|
6097
|
+
}
|
|
6098
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
6099
|
+
for (const acc of steps.values()) {
|
|
6100
|
+
let meta = acc.metadata ? { ...acc.metadata } : void 0;
|
|
6101
|
+
if (acc.parentId !== void 0 && !steps.has(acc.parentId)) {
|
|
6102
|
+
meta = { ...meta ?? {}, agent_inspect_diff_parent_missing: true };
|
|
6103
|
+
}
|
|
6104
|
+
const outputPreview = extractOutputPreview(meta);
|
|
6105
|
+
if (meta !== void 0 && ("outputPreview" in meta || "resultPreview" in meta)) {
|
|
6106
|
+
delete meta.outputPreview;
|
|
6107
|
+
delete meta.resultPreview;
|
|
6108
|
+
}
|
|
6109
|
+
const sc = {
|
|
6110
|
+
id: acc.id,
|
|
6111
|
+
name: acc.name,
|
|
6112
|
+
type: acc.type,
|
|
6113
|
+
status: mapStepStatus(acc.status),
|
|
6114
|
+
durationMs: acc.durationMs,
|
|
6115
|
+
error: acc.errorMsg,
|
|
6116
|
+
metadata: meta && Object.keys(meta).length > 0 ? meta : void 0,
|
|
6117
|
+
outputPreview,
|
|
6118
|
+
children: []
|
|
6119
|
+
};
|
|
6120
|
+
nodes.set(acc.id, sc);
|
|
6121
|
+
}
|
|
6122
|
+
const roots = [];
|
|
6123
|
+
const sortByOrder = (a, b) => {
|
|
6124
|
+
const oa = steps.get(a.id)?.order ?? 0;
|
|
6125
|
+
const ob = steps.get(b.id)?.order ?? 0;
|
|
6126
|
+
return oa - ob;
|
|
6127
|
+
};
|
|
6128
|
+
for (const acc of steps.values()) {
|
|
6129
|
+
const node = nodes.get(acc.id);
|
|
6130
|
+
if (acc.parentId !== void 0 && nodes.has(acc.parentId)) {
|
|
6131
|
+
nodes.get(acc.parentId).children.push(node);
|
|
6132
|
+
} else {
|
|
6133
|
+
roots.push(node);
|
|
6134
|
+
}
|
|
6135
|
+
}
|
|
6136
|
+
roots.sort(sortByOrder);
|
|
6137
|
+
for (const n of nodes.values()) {
|
|
6138
|
+
n.children.sort(sortByOrder);
|
|
6139
|
+
}
|
|
6140
|
+
return {
|
|
6141
|
+
runId,
|
|
6142
|
+
name: rs.name,
|
|
6143
|
+
status: runStatus,
|
|
6144
|
+
durationMs: durationMs2,
|
|
6145
|
+
steps: roots
|
|
6146
|
+
};
|
|
6147
|
+
}
|
|
6148
|
+
|
|
6149
|
+
// packages/core/src/diff/engine.ts
|
|
6150
|
+
var DEFAULT_THRESHOLD_MS = 0;
|
|
6151
|
+
function pathSeg(step, index) {
|
|
6152
|
+
return { index, name: step.name, stepId: step.id };
|
|
6153
|
+
}
|
|
6154
|
+
function buildPath(segments) {
|
|
6155
|
+
return { path: [...segments] };
|
|
6156
|
+
}
|
|
6157
|
+
function pairSteps(left, right) {
|
|
6158
|
+
const usedRight = /* @__PURE__ */ new Set();
|
|
6159
|
+
const pairs = [];
|
|
6160
|
+
for (let i = 0; i < left.length; i++) {
|
|
6161
|
+
const L = left[i];
|
|
6162
|
+
let R = right.find((r) => !usedRight.has(r.id) && r.id === L.id);
|
|
6163
|
+
if (R === void 0 && i < right.length && !usedRight.has(right[i].id)) {
|
|
6164
|
+
const cand = right[i];
|
|
6165
|
+
if (cand.name === L.name && (cand.type ?? "") === (L.type ?? "")) {
|
|
6166
|
+
R = cand;
|
|
6167
|
+
}
|
|
6168
|
+
}
|
|
6169
|
+
if (R === void 0) {
|
|
6170
|
+
R = right.find(
|
|
6171
|
+
(r) => !usedRight.has(r.id) && r.name === L.name && (r.type ?? "") === (L.type ?? "")
|
|
6172
|
+
);
|
|
6173
|
+
}
|
|
6174
|
+
if (R !== void 0) {
|
|
6175
|
+
usedRight.add(R.id);
|
|
6176
|
+
pairs.push([L, R]);
|
|
6177
|
+
} else {
|
|
6178
|
+
pairs.push([L, void 0]);
|
|
6179
|
+
}
|
|
6180
|
+
}
|
|
6181
|
+
for (const R of right) {
|
|
6182
|
+
if (!usedRight.has(R.id)) {
|
|
6183
|
+
pairs.push([void 0, R]);
|
|
6184
|
+
}
|
|
6185
|
+
}
|
|
6186
|
+
return pairs;
|
|
6187
|
+
}
|
|
6188
|
+
function compareLeafSteps(L, R, segments, opts, out) {
|
|
6189
|
+
const path14 = buildPath(segments);
|
|
6190
|
+
if (L.name !== R.name) {
|
|
6191
|
+
out.push({
|
|
6192
|
+
kind: "structure",
|
|
6193
|
+
severity: "warning",
|
|
6194
|
+
message: "Step name differs",
|
|
6195
|
+
path: path14,
|
|
6196
|
+
left: L.name,
|
|
6197
|
+
right: R.name
|
|
6198
|
+
});
|
|
6199
|
+
}
|
|
6200
|
+
if ((L.type ?? "") !== (R.type ?? "")) {
|
|
6201
|
+
out.push({
|
|
6202
|
+
kind: "step-type",
|
|
6203
|
+
severity: "warning",
|
|
6204
|
+
message: "Step type differs",
|
|
6205
|
+
path: path14,
|
|
6206
|
+
left: L.type,
|
|
6207
|
+
right: R.type
|
|
6208
|
+
});
|
|
6209
|
+
}
|
|
6210
|
+
if ((L.status ?? "") !== (R.status ?? "")) {
|
|
6211
|
+
out.push({
|
|
6212
|
+
kind: "step-status",
|
|
6213
|
+
severity: "warning",
|
|
6214
|
+
message: "Step status differs",
|
|
6215
|
+
path: path14,
|
|
6216
|
+
left: L.status,
|
|
6217
|
+
right: R.status
|
|
6218
|
+
});
|
|
6219
|
+
}
|
|
6220
|
+
const le = L.error ?? "";
|
|
6221
|
+
const re = R.error ?? "";
|
|
6222
|
+
if (le !== re) {
|
|
6223
|
+
out.push({
|
|
6224
|
+
kind: "error",
|
|
6225
|
+
severity: "error",
|
|
6226
|
+
message: "Step error message differs",
|
|
6227
|
+
path: path14,
|
|
6228
|
+
left: le || void 0,
|
|
6229
|
+
right: re || void 0
|
|
6230
|
+
});
|
|
6231
|
+
}
|
|
6232
|
+
if (!opts.ignoreDuration) {
|
|
6233
|
+
const ld = L.durationMs;
|
|
6234
|
+
const rd = R.durationMs;
|
|
6235
|
+
const th = opts.durationThresholdMs;
|
|
6236
|
+
let differs = false;
|
|
6237
|
+
if (ld === void 0 && rd === void 0) differs = false;
|
|
6238
|
+
else if (ld === void 0 || rd === void 0) differs = true;
|
|
6239
|
+
else differs = Math.abs(ld - rd) > th;
|
|
6240
|
+
if (differs) {
|
|
6241
|
+
out.push({
|
|
6242
|
+
kind: "duration",
|
|
6243
|
+
severity: "info",
|
|
6244
|
+
message: "Step duration differs",
|
|
6245
|
+
path: path14,
|
|
6246
|
+
left: ld,
|
|
6247
|
+
right: rd
|
|
6248
|
+
});
|
|
6249
|
+
}
|
|
6250
|
+
}
|
|
6251
|
+
const lm = stableJson(L.metadata ?? {});
|
|
6252
|
+
const rm = stableJson(R.metadata ?? {});
|
|
6253
|
+
if (lm !== rm) {
|
|
6254
|
+
out.push({
|
|
6255
|
+
kind: "metadata",
|
|
6256
|
+
severity: "info",
|
|
6257
|
+
message: "Step metadata differs",
|
|
6258
|
+
path: path14,
|
|
6259
|
+
left: L.metadata,
|
|
6260
|
+
right: R.metadata
|
|
6261
|
+
});
|
|
6262
|
+
}
|
|
6263
|
+
const lo = stableJson(L.outputPreview ?? null);
|
|
6264
|
+
const ro = stableJson(R.outputPreview ?? null);
|
|
6265
|
+
if (lo !== ro) {
|
|
6266
|
+
out.push({
|
|
6267
|
+
kind: "output",
|
|
6268
|
+
severity: "info",
|
|
6269
|
+
message: "Output preview differs",
|
|
6270
|
+
path: path14,
|
|
6271
|
+
left: L.outputPreview,
|
|
6272
|
+
right: R.outputPreview
|
|
6273
|
+
});
|
|
6274
|
+
}
|
|
6275
|
+
}
|
|
6276
|
+
function compareRecursive(L, R, segments, opts, out) {
|
|
6277
|
+
compareLeafSteps(L, R, segments, opts, out);
|
|
6278
|
+
const pairs = pairSteps(L.children, R.children);
|
|
6279
|
+
let ci = 0;
|
|
6280
|
+
for (const [lch, rch] of pairs) {
|
|
6281
|
+
if (lch !== void 0 && rch !== void 0) {
|
|
6282
|
+
compareRecursive(lch, rch, [...segments, pathSeg(lch, ci)], opts, out);
|
|
6283
|
+
} else if (lch !== void 0) {
|
|
6284
|
+
out.push({
|
|
6285
|
+
kind: "step-removed",
|
|
6286
|
+
severity: "warning",
|
|
6287
|
+
message: `Step only in left run: ${lch.name}`,
|
|
6288
|
+
path: buildPath([...segments, pathSeg(lch, ci)]),
|
|
6289
|
+
left: lch.id,
|
|
6290
|
+
right: void 0
|
|
6291
|
+
});
|
|
6292
|
+
} else if (rch !== void 0) {
|
|
6293
|
+
out.push({
|
|
6294
|
+
kind: "step-added",
|
|
6295
|
+
severity: "warning",
|
|
6296
|
+
message: `Step only in right run: ${rch.name}`,
|
|
6297
|
+
path: buildPath([...segments, pathSeg(rch, ci)]),
|
|
6298
|
+
left: void 0,
|
|
6299
|
+
right: rch.id
|
|
6300
|
+
});
|
|
6301
|
+
}
|
|
6302
|
+
ci += 1;
|
|
6303
|
+
}
|
|
6304
|
+
}
|
|
6305
|
+
function mergeDiffDefaults(options) {
|
|
6306
|
+
return {
|
|
6307
|
+
ignoreDuration: false,
|
|
6308
|
+
durationThresholdMs: DEFAULT_THRESHOLD_MS,
|
|
6309
|
+
focus: "all",
|
|
6310
|
+
check: "all"
|
|
6311
|
+
};
|
|
6312
|
+
}
|
|
6313
|
+
function kindMatchesFilter(kind, merged) {
|
|
6314
|
+
return true;
|
|
6315
|
+
}
|
|
6316
|
+
function diffRuns(left, right, options) {
|
|
6317
|
+
const merged = mergeDiffDefaults();
|
|
6318
|
+
const opts = {
|
|
6319
|
+
ignoreDuration: merged.ignoreDuration,
|
|
6320
|
+
durationThresholdMs: merged.durationThresholdMs
|
|
6321
|
+
};
|
|
6322
|
+
const raw = [];
|
|
6323
|
+
if ((left.status ?? "") !== (right.status ?? "")) {
|
|
6324
|
+
raw.push({
|
|
6325
|
+
kind: "run-status",
|
|
6326
|
+
severity: "warning",
|
|
6327
|
+
message: "Run completion status differs",
|
|
6328
|
+
left: left.status,
|
|
6329
|
+
right: right.status
|
|
6330
|
+
});
|
|
6331
|
+
}
|
|
6332
|
+
{
|
|
6333
|
+
const ld = left.durationMs;
|
|
6334
|
+
const rd = right.durationMs;
|
|
6335
|
+
const th = merged.durationThresholdMs;
|
|
6336
|
+
let differs = false;
|
|
6337
|
+
if (ld === void 0 && rd === void 0) differs = false;
|
|
6338
|
+
else if (ld === void 0 || rd === void 0) differs = true;
|
|
6339
|
+
else differs = Math.abs(ld - rd) > th;
|
|
6340
|
+
if (differs) {
|
|
6341
|
+
raw.push({
|
|
6342
|
+
kind: "duration",
|
|
6343
|
+
severity: "info",
|
|
6344
|
+
message: "Run duration differs",
|
|
6345
|
+
left: ld,
|
|
6346
|
+
right: rd
|
|
6347
|
+
});
|
|
6348
|
+
}
|
|
6349
|
+
}
|
|
6350
|
+
const pairs = pairSteps(left.steps, right.steps);
|
|
6351
|
+
let idx = 0;
|
|
6352
|
+
for (const [ls, rs] of pairs) {
|
|
6353
|
+
if (ls !== void 0 && rs !== void 0) {
|
|
6354
|
+
compareRecursive(ls, rs, [pathSeg(ls, idx)], opts, raw);
|
|
6355
|
+
idx += 1;
|
|
6356
|
+
} else if (ls !== void 0) {
|
|
6357
|
+
raw.push({
|
|
6358
|
+
kind: "step-removed",
|
|
6359
|
+
severity: "warning",
|
|
6360
|
+
message: `Step only in left run: ${ls.name}`,
|
|
6361
|
+
path: buildPath([pathSeg(ls, idx)]),
|
|
6362
|
+
left: ls.id,
|
|
6363
|
+
right: void 0
|
|
6364
|
+
});
|
|
6365
|
+
idx += 1;
|
|
6366
|
+
} else if (rs !== void 0) {
|
|
6367
|
+
raw.push({
|
|
6368
|
+
kind: "step-added",
|
|
6369
|
+
severity: "warning",
|
|
6370
|
+
message: `Step only in right run: ${rs.name}`,
|
|
6371
|
+
path: buildPath([pathSeg(rs, idx)]),
|
|
6372
|
+
left: void 0,
|
|
6373
|
+
right: rs.id
|
|
6374
|
+
});
|
|
6375
|
+
idx += 1;
|
|
6376
|
+
}
|
|
6377
|
+
}
|
|
6378
|
+
const differences = raw.filter((d) => kindMatchesFilter(d.kind));
|
|
6379
|
+
let errors = 0;
|
|
6380
|
+
let warnings = 0;
|
|
6381
|
+
let info = 0;
|
|
6382
|
+
for (const d of differences) {
|
|
6383
|
+
if (d.severity === "error") errors += 1;
|
|
6384
|
+
else if (d.severity === "warning") warnings += 1;
|
|
6385
|
+
else info += 1;
|
|
6386
|
+
}
|
|
6387
|
+
const firstVisible = differences[0];
|
|
6388
|
+
const firstDivergence = firstVisible !== void 0 ? {
|
|
6389
|
+
kind: "first-divergence",
|
|
6390
|
+
severity: firstVisible.severity,
|
|
6391
|
+
message: `First divergence: ${firstVisible.message}`,
|
|
6392
|
+
path: firstVisible.path,
|
|
6393
|
+
left: firstVisible.left,
|
|
6394
|
+
right: firstVisible.right
|
|
6395
|
+
} : void 0;
|
|
6396
|
+
const summary = {
|
|
6397
|
+
leftRunId: left.runId,
|
|
6398
|
+
rightRunId: right.runId,
|
|
6399
|
+
totalDifferences: differences.length,
|
|
6400
|
+
errors,
|
|
6401
|
+
warnings,
|
|
6402
|
+
info,
|
|
6403
|
+
firstDivergence
|
|
6404
|
+
};
|
|
6405
|
+
return { summary, differences };
|
|
6406
|
+
}
|
|
6407
|
+
|
|
6408
|
+
// packages/core/src/diff/renderer.ts
|
|
6409
|
+
function formatPath(path14) {
|
|
6410
|
+
if (path14 === void 0 || path14.path.length === 0) {
|
|
6411
|
+
return "(run)";
|
|
6412
|
+
}
|
|
6413
|
+
return path14.path.map((s) => s.name).join(" > ");
|
|
6414
|
+
}
|
|
6415
|
+
function formatValue(v, verbose) {
|
|
6416
|
+
if (v === void 0) return "(undefined)";
|
|
6417
|
+
if (typeof v === "string") return v;
|
|
6418
|
+
if (typeof v === "number" || typeof v === "boolean") return String(v);
|
|
6419
|
+
const s = JSON.stringify(v);
|
|
6420
|
+
if (s.length <= 120) return s;
|
|
6421
|
+
return `${s.slice(0, 117)}...`;
|
|
6422
|
+
}
|
|
6423
|
+
function renderRunDiff(result, options) {
|
|
6424
|
+
const json = options?.json === true;
|
|
6425
|
+
if (json) {
|
|
6426
|
+
return JSON.stringify(result, null, 2);
|
|
6427
|
+
}
|
|
6428
|
+
const sev = (s, level) => {
|
|
6429
|
+
return s;
|
|
6430
|
+
};
|
|
6431
|
+
const lines = [];
|
|
6432
|
+
const { summary } = result;
|
|
6433
|
+
lines.push("Run diff");
|
|
6434
|
+
lines.push(`Left: ${summary.leftRunId}`);
|
|
6435
|
+
lines.push(`Right: ${summary.rightRunId}`);
|
|
6436
|
+
lines.push("");
|
|
6437
|
+
lines.push("Summary:");
|
|
6438
|
+
lines.push(` Differences: ${summary.totalDifferences}`);
|
|
6439
|
+
lines.push(` Errors: ${summary.errors}`);
|
|
6440
|
+
lines.push(` Warnings: ${summary.warnings}`);
|
|
6441
|
+
lines.push(` Info: ${summary.info}`);
|
|
6442
|
+
lines.push("");
|
|
6443
|
+
const fd = summary.firstDivergence;
|
|
6444
|
+
const firstKind = result.differences[0]?.kind;
|
|
6445
|
+
if (fd !== void 0) {
|
|
6446
|
+
lines.push("First divergence:");
|
|
6447
|
+
const where = formatPath(fd.path);
|
|
6448
|
+
const displayKind = firstKind ?? fd.kind;
|
|
6449
|
+
lines.push(` ${displayKind} at ${where}`);
|
|
6450
|
+
if (fd.left !== void 0 || fd.right !== void 0) {
|
|
6451
|
+
lines.push(` left: ${formatValue(fd.left)}`);
|
|
6452
|
+
lines.push(` right: ${formatValue(fd.right)}`);
|
|
6453
|
+
}
|
|
6454
|
+
lines.push("");
|
|
6455
|
+
}
|
|
6456
|
+
lines.push("Differences:");
|
|
6457
|
+
if (result.differences.length === 0) {
|
|
6458
|
+
lines.push(" (none)");
|
|
6459
|
+
return lines.join("\n");
|
|
6460
|
+
}
|
|
6461
|
+
const showSides = (kind) => [
|
|
6462
|
+
"run-status",
|
|
6463
|
+
"step-status",
|
|
6464
|
+
"error",
|
|
6465
|
+
"duration",
|
|
6466
|
+
"step-type",
|
|
6467
|
+
"structure",
|
|
6468
|
+
"step-added",
|
|
6469
|
+
"step-removed"
|
|
6470
|
+
].includes(kind);
|
|
6471
|
+
for (const d of result.differences) {
|
|
6472
|
+
const tag = sev(`[${d.severity}]`, d.severity);
|
|
6473
|
+
const pathStr = d.path !== void 0 ? ` ${formatPath(d.path)}` : "";
|
|
6474
|
+
lines.push(` ${tag} ${d.kind}${pathStr}`);
|
|
6475
|
+
lines.push(` ${d.message}`);
|
|
6476
|
+
if (d.left !== void 0 || d.right !== void 0) {
|
|
6477
|
+
if (showSides(d.kind)) {
|
|
6478
|
+
lines.push(` left: ${formatValue(d.left)}`);
|
|
6479
|
+
lines.push(` right: ${formatValue(d.right)}`);
|
|
6480
|
+
}
|
|
6481
|
+
}
|
|
6482
|
+
}
|
|
6483
|
+
return lines.join("\n");
|
|
6484
|
+
}
|
|
6485
|
+
|
|
6486
|
+
// packages/core/src/diff/index.ts
|
|
6487
|
+
function diffTraceEvents(leftEvents, rightEvents, options) {
|
|
6488
|
+
const left = manualTraceEventsToComparableRun(leftEvents);
|
|
6489
|
+
const right = manualTraceEventsToComparableRun(rightEvents);
|
|
6490
|
+
return diffRuns(left, right);
|
|
6491
|
+
}
|
|
6492
|
+
|
|
6493
|
+
// packages/core/src/evidence/views-contract.ts
|
|
6494
|
+
function boundMessage(message, max = 200) {
|
|
6495
|
+
const trimmed = message.trim();
|
|
6496
|
+
if (trimmed.length <= max) return trimmed;
|
|
6497
|
+
return `${trimmed.slice(0, max)}\u2026`;
|
|
6498
|
+
}
|
|
6499
|
+
function buildEvidenceContractsViewHtml(input) {
|
|
6500
|
+
const rows = input.runs.map(
|
|
6501
|
+
(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>`
|
|
6502
|
+
).join("");
|
|
6503
|
+
const findings = input.findingSummaries ?? [];
|
|
6504
|
+
const findingRows = findings.length === 0 ? `<p class="muted">No structured check findings recorded for the redacted artifact.</p>` : `<table>
|
|
6505
|
+
<thead><tr><th>runId</th><th>severity</th><th>rule</th><th>category</th><th>detector</th><th>message</th></tr></thead>
|
|
6506
|
+
<tbody>${findings.map(
|
|
6507
|
+
(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>`
|
|
6508
|
+
).join("")}</tbody>
|
|
6509
|
+
</table>`;
|
|
6510
|
+
return `<p>Aggregate artifact status: <strong>${escapeHtml(input.aggregateStatus)}</strong></p>
|
|
6511
|
+
<table>
|
|
6512
|
+
<thead><tr><th>runId</th><th>artifact</th><th>source</th><th>errors</th><th>warnings</th><th>findings</th></tr></thead>
|
|
6513
|
+
<tbody>${rows}</tbody>
|
|
6514
|
+
</table>
|
|
6515
|
+
<h3>Finding summaries</h3>
|
|
6516
|
+
${findingRows}
|
|
6517
|
+
<p class="muted">TraceContract / check details are best-effort local results \u2014 not a compliance certification.</p>`;
|
|
6518
|
+
}
|
|
6519
|
+
function buildEvidenceOutcomesViewHtml(runs) {
|
|
6520
|
+
if (runs.length === 0) {
|
|
6521
|
+
return `<p class="muted">No runs available for outcome extraction.</p>`;
|
|
6522
|
+
}
|
|
6523
|
+
const parts = [];
|
|
6524
|
+
for (const run of runs) {
|
|
6525
|
+
const forRun = run.events.filter((event) => event.runId === run.runId);
|
|
6526
|
+
const summary = summarizeObservedOutcomes(extractOutcomesFromPersistedEvents(forRun));
|
|
6527
|
+
parts.push(`<article class="run-block">`);
|
|
6528
|
+
parts.push(`<h3><code>${escapeHtml(run.runId)}</code></h3>`);
|
|
6529
|
+
parts.push(renderObservedOutcomesHtml(summary));
|
|
6530
|
+
parts.push(`</article>`);
|
|
6531
|
+
}
|
|
6532
|
+
return parts.join("\n");
|
|
6533
|
+
}
|
|
6534
|
+
function buildEvidenceDiffViewHtml(parts) {
|
|
6535
|
+
if (parts === void 0 || parts.leftEvents.length === 0 || parts.rightEvents.length === 0) {
|
|
6536
|
+
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>`;
|
|
6537
|
+
}
|
|
6538
|
+
try {
|
|
6539
|
+
const left = persistedInspectEventsToTraceEvents(
|
|
6540
|
+
parts.leftEvents.filter((e) => e.runId === parts.leftRunId)
|
|
6541
|
+
);
|
|
6542
|
+
const right = persistedInspectEventsToTraceEvents(
|
|
6543
|
+
parts.rightEvents.filter((e) => e.runId === parts.rightRunId)
|
|
6544
|
+
);
|
|
6545
|
+
if (left.length === 0 || right.length === 0) {
|
|
6546
|
+
return `<p class="muted">Could not normalize both runs for diff (missing v0.1-compatible events).</p>`;
|
|
6547
|
+
}
|
|
6548
|
+
const result = diffTraceEvents(left, right);
|
|
6549
|
+
const text = renderRunDiff(result, { color: false, verbose: false });
|
|
6550
|
+
return `<p>Comparing <code>${escapeHtml(parts.leftRunId)}</code> \u2192 <code>${escapeHtml(parts.rightRunId)}</code></p>
|
|
6551
|
+
<pre class="summary-md">${escapeHtml(text)}</pre>`;
|
|
6552
|
+
} catch (error) {
|
|
6553
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6554
|
+
return `<p class="muted">Diff unavailable: ${escapeHtml(message)}</p>`;
|
|
6555
|
+
}
|
|
6556
|
+
}
|
|
6557
|
+
|
|
6558
|
+
// packages/core/src/evidence/views-safety.ts
|
|
6559
|
+
function buildEvidenceSafetyViewHtml(input) {
|
|
6560
|
+
const findingRows = (input.findingSummaries ?? []).length === 0 ? `<p class="muted">No safety findings on the redacted artifact.</p>` : `<table>
|
|
6561
|
+
<thead><tr><th>runId</th><th>severity</th><th>category</th><th>detector</th><th>action</th><th>message</th></tr></thead>
|
|
6562
|
+
<tbody>${(input.findingSummaries ?? []).map((f) => {
|
|
6563
|
+
const msg = f.message.length > 160 ? `${f.message.slice(0, 160)}\u2026` : f.message;
|
|
6564
|
+
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>`;
|
|
6565
|
+
}).join("")}</tbody>
|
|
6566
|
+
</table>`;
|
|
6567
|
+
const redactionBlock = input.redaction === void 0 ? `<p class="muted">No redaction report attached.</p>` : `<p>Total redaction findings: <strong>${input.redaction.totalFindings}</strong></p>
|
|
6568
|
+
<ul>${input.redaction.runs.map(
|
|
6569
|
+
(run) => `<li><code>${escapeHtml(run.runId)}</code>: ${run.findings} finding(s); detectors: ${escapeHtml(run.detectors.join(", ") || "none")}</li>`
|
|
6570
|
+
).join("")}</ul>`;
|
|
6571
|
+
return `<p>Artifact status: <strong>${escapeHtml(String(input.artifactStatus))}</strong>
|
|
6572
|
+
${input.sourceStatus !== void 0 ? ` \xB7 Source status: <strong>${escapeHtml(String(input.sourceStatus))}</strong>` : ""}</p>
|
|
6573
|
+
<p>Redaction profile: <code>${escapeHtml(input.redactionProfile)}</code> \xB7 Verification: <code>${escapeHtml(input.verificationPolicy)}</code></p>
|
|
6574
|
+
<h3>Redaction</h3>
|
|
6575
|
+
${redactionBlock}
|
|
6576
|
+
<h3>Safety findings (artifact)</h3>
|
|
6577
|
+
${findingRows}
|
|
6578
|
+
<p class="muted">Best-effort local verification only \u2014 not a compliance certification. Gate sharing on artifact status.</p>`;
|
|
6579
|
+
}
|
|
6580
|
+
function buildEvidenceProvenanceViewHtml(input) {
|
|
6581
|
+
const hashes = input.sourceHashes.length === 0 ? `<p class="muted">No source hashes recorded.</p>` : `<table>
|
|
6582
|
+
<thead><tr><th>runId</th><th>algorithm</th><th>hash</th></tr></thead>
|
|
6583
|
+
<tbody>${input.sourceHashes.map(
|
|
6584
|
+
(h) => `<tr><td><code>${escapeHtml(h.runId)}</code></td><td>${escapeHtml(h.algorithm)}</td><td><code>${escapeHtml(h.hash)}</code></td></tr>`
|
|
6585
|
+
).join("")}</tbody>
|
|
6586
|
+
</table>`;
|
|
6587
|
+
const files = input.packagedFiles.length === 0 ? `<p class="muted">No packaged files listed.</p>` : `<ul>${input.packagedFiles.map(
|
|
6588
|
+
(f) => `<li><code>${escapeHtml(f.path)}</code>${f.role ? ` <span class="meta">(${escapeHtml(f.role)})</span>` : ""}</li>`
|
|
6589
|
+
).join("")}</ul>`;
|
|
6590
|
+
return `<p>Generator: <code>${escapeHtml(input.generatorName)}@${escapeHtml(input.generatorVersion)}</code>
|
|
6591
|
+
\xB7 Evidence format: <code>${escapeHtml(input.evidenceFormatVersion)}</code>
|
|
6592
|
+
${input.createdAt ? ` \xB7 Created: <code>${escapeHtml(input.createdAt)}</code>` : ""}</p>
|
|
6593
|
+
<p>Runs: ${input.runIds.map((id) => `<code>${escapeHtml(id)}</code>`).join(", ")}</p>
|
|
6594
|
+
<p>Trace schema versions: ${input.traceSchemaVersions.length > 0 ? input.traceSchemaVersions.map((v) => `<code>${escapeHtml(v)}</code>`).join(", ") : '<span class="muted">unknown</span>'}</p>
|
|
6595
|
+
<h3>Source hashes (pre-redaction input)</h3>
|
|
6596
|
+
${hashes}
|
|
6597
|
+
<h3>Packaged files</h3>
|
|
6598
|
+
${files}
|
|
6599
|
+
<p class="muted">${escapeHtml(input.note ?? "Reader/mapping losses are reported elsewhere when present; relationships are never invented without confidence policy.")}</p>`;
|
|
6600
|
+
}
|
|
6601
|
+
function buildEvidenceToolsLlmViewHtml(trees) {
|
|
6602
|
+
if (trees.length === 0) {
|
|
6603
|
+
return `<p class="muted">No runs available for tool/LLM metadata.</p>`;
|
|
6604
|
+
}
|
|
6605
|
+
const parts = [];
|
|
6606
|
+
for (const tree of trees) {
|
|
6607
|
+
const nodes = flattenTree(tree).filter(
|
|
6608
|
+
(n) => n.event.kind === "TOOL" || n.event.kind === "LLM" || n.event.kind === "AGENT"
|
|
6609
|
+
);
|
|
6610
|
+
parts.push(`<article class="run-block">`);
|
|
6611
|
+
parts.push(`<h3><code>${escapeHtml(tree.runId)}</code></h3>`);
|
|
6612
|
+
if (nodes.length === 0) {
|
|
6613
|
+
parts.push(`<p class="muted">No TOOL/LLM/AGENT events in this run.</p>`);
|
|
6614
|
+
} else {
|
|
6615
|
+
parts.push(`<table>
|
|
6616
|
+
<thead><tr><th>name</th><th>kind</th><th>status</th><th>durationMs</th></tr></thead>
|
|
6617
|
+
<tbody>${nodes.map((n) => {
|
|
6618
|
+
const dur = n.event.durationMs !== void 0 && Number.isFinite(n.event.durationMs) ? String(n.event.durationMs) : "\u2014";
|
|
6619
|
+
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>`;
|
|
6620
|
+
}).join("")}</tbody>
|
|
6621
|
+
</table>`);
|
|
6622
|
+
}
|
|
6623
|
+
parts.push(`</article>`);
|
|
6624
|
+
}
|
|
6625
|
+
return parts.join("\n");
|
|
6626
|
+
}
|
|
6627
|
+
function buildEvidenceCircuitViewHtml(parts) {
|
|
6628
|
+
const findings = parts?.findings ?? [];
|
|
6629
|
+
if (findings.length === 0) {
|
|
6630
|
+
return `<p class="muted">No circuit or guardrail findings were attached to this evidence bundle.</p>`;
|
|
6631
|
+
}
|
|
6632
|
+
return `<table>
|
|
6633
|
+
<thead><tr><th>runId</th><th>name</th><th>status</th><th>detail</th></tr></thead>
|
|
6634
|
+
<tbody>${findings.map(
|
|
6635
|
+
(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>`
|
|
6636
|
+
).join("")}</tbody>
|
|
6637
|
+
</table>`;
|
|
6638
|
+
}
|
|
6639
|
+
|
|
6640
|
+
// packages/core/src/evidence/zip.ts
|
|
6641
|
+
var CRC_TABLE = (() => {
|
|
6642
|
+
const table = new Uint32Array(256);
|
|
6643
|
+
for (let n = 0; n < 256; n += 1) {
|
|
6644
|
+
let c = n;
|
|
6645
|
+
for (let k = 0; k < 8; k += 1) {
|
|
6646
|
+
c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
6647
|
+
}
|
|
6648
|
+
table[n] = c >>> 0;
|
|
6649
|
+
}
|
|
6650
|
+
return table;
|
|
6651
|
+
})();
|
|
6652
|
+
function crc32(data) {
|
|
6653
|
+
let crc = 4294967295;
|
|
6654
|
+
for (let i = 0; i < data.length; i += 1) {
|
|
6655
|
+
crc = CRC_TABLE[(crc ^ data[i]) & 255] ^ crc >>> 8;
|
|
6656
|
+
}
|
|
6657
|
+
return (crc ^ 4294967295) >>> 0;
|
|
6658
|
+
}
|
|
6659
|
+
function toBytes(content) {
|
|
6660
|
+
return typeof content === "string" ? Buffer.from(content, "utf8") : content;
|
|
6661
|
+
}
|
|
6662
|
+
function u16(value) {
|
|
6663
|
+
const buf = Buffer.alloc(2);
|
|
6664
|
+
buf.writeUInt16LE(value >>> 0, 0);
|
|
6665
|
+
return buf;
|
|
6666
|
+
}
|
|
6667
|
+
function u32(value) {
|
|
6668
|
+
const buf = Buffer.alloc(4);
|
|
6669
|
+
buf.writeUInt32LE(value >>> 0, 0);
|
|
6670
|
+
return buf;
|
|
6671
|
+
}
|
|
6672
|
+
function buildZipArchive(entries) {
|
|
6673
|
+
if (entries.length === 0) {
|
|
6674
|
+
throw new Error("ZIP archive requires at least one entry.");
|
|
6675
|
+
}
|
|
6676
|
+
const locals = [];
|
|
6677
|
+
const centrals = [];
|
|
6678
|
+
let offset = 0;
|
|
6679
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6680
|
+
for (const entry of entries) {
|
|
6681
|
+
const name = assertEvidenceRelativePath(entry.path);
|
|
6682
|
+
if (seen.has(name)) {
|
|
6683
|
+
throw new Error(`Duplicate ZIP entry path: ${name}`);
|
|
6684
|
+
}
|
|
6685
|
+
seen.add(name);
|
|
6686
|
+
const nameBytes = Buffer.from(name, "utf8");
|
|
6687
|
+
const data = toBytes(entry.content);
|
|
6688
|
+
const checksum = crc32(data);
|
|
6689
|
+
const size = data.byteLength;
|
|
6690
|
+
const local = Buffer.concat([
|
|
6691
|
+
u32(67324752),
|
|
6692
|
+
u16(20),
|
|
6693
|
+
// version needed
|
|
6694
|
+
u16(0),
|
|
6695
|
+
// flags
|
|
6696
|
+
u16(0),
|
|
6697
|
+
// method STORE
|
|
6698
|
+
u16(0),
|
|
6699
|
+
// time
|
|
6700
|
+
u16(0),
|
|
6701
|
+
// date
|
|
6702
|
+
u32(checksum),
|
|
6703
|
+
u32(size),
|
|
6704
|
+
u32(size),
|
|
6705
|
+
u16(nameBytes.length),
|
|
6706
|
+
u16(0),
|
|
6707
|
+
// extra length
|
|
6708
|
+
nameBytes,
|
|
6709
|
+
Buffer.from(data)
|
|
6710
|
+
]);
|
|
6711
|
+
const central = Buffer.concat([
|
|
6712
|
+
u32(33639248),
|
|
6713
|
+
u16(20),
|
|
6714
|
+
// version made by
|
|
6715
|
+
u16(20),
|
|
6716
|
+
// version needed
|
|
6717
|
+
u16(0),
|
|
6718
|
+
u16(0),
|
|
6719
|
+
u16(0),
|
|
6720
|
+
u16(0),
|
|
6721
|
+
u32(checksum),
|
|
6722
|
+
u32(size),
|
|
6723
|
+
u32(size),
|
|
6724
|
+
u16(nameBytes.length),
|
|
6725
|
+
u16(0),
|
|
6726
|
+
u16(0),
|
|
6727
|
+
u16(0),
|
|
6728
|
+
u16(0),
|
|
6729
|
+
u32(0),
|
|
6730
|
+
u32(offset),
|
|
6731
|
+
nameBytes
|
|
6732
|
+
]);
|
|
6733
|
+
locals.push(local);
|
|
6734
|
+
centrals.push(central);
|
|
6735
|
+
offset += local.length;
|
|
6736
|
+
}
|
|
6737
|
+
const centralDir = Buffer.concat(centrals);
|
|
6738
|
+
const end = Buffer.concat([
|
|
6739
|
+
u32(101010256),
|
|
6740
|
+
u16(0),
|
|
6741
|
+
u16(0),
|
|
6742
|
+
u16(entries.length),
|
|
6743
|
+
u16(entries.length),
|
|
6744
|
+
u32(centralDir.length),
|
|
6745
|
+
u32(offset),
|
|
6746
|
+
u16(0)
|
|
6747
|
+
]);
|
|
6748
|
+
return Buffer.concat([...locals, centralDir, end]);
|
|
6749
|
+
}
|
|
6750
|
+
async function listFilesRecursive(root) {
|
|
6751
|
+
const out = [];
|
|
6752
|
+
async function walk(dir) {
|
|
6753
|
+
const entries = await promises.readdir(dir, { withFileTypes: true });
|
|
6754
|
+
for (const entry of entries) {
|
|
6755
|
+
const abs = path5__default.default.join(dir, entry.name);
|
|
6756
|
+
if (entry.isDirectory()) {
|
|
6757
|
+
await walk(abs);
|
|
6758
|
+
} else if (entry.isFile()) {
|
|
6759
|
+
const rel = path5__default.default.relative(root, abs).split(path5__default.default.sep).join("/");
|
|
6760
|
+
out.push(rel);
|
|
6761
|
+
}
|
|
6762
|
+
}
|
|
6763
|
+
}
|
|
6764
|
+
await walk(root);
|
|
6765
|
+
return out.sort((a, b) => a.localeCompare(b));
|
|
6766
|
+
}
|
|
6767
|
+
async function verifyEvidenceDirectory(rootPath, options = {}) {
|
|
6768
|
+
const unexpectedMode = options.unexpectedFiles ?? "fail";
|
|
6769
|
+
const root = path5__default.default.resolve(rootPath);
|
|
6770
|
+
const issues = [];
|
|
6771
|
+
let rootStat;
|
|
6772
|
+
try {
|
|
6773
|
+
rootStat = await promises.stat(root);
|
|
6774
|
+
} catch (error) {
|
|
6775
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6776
|
+
return {
|
|
6777
|
+
ok: false,
|
|
6778
|
+
status: "fail",
|
|
6779
|
+
root,
|
|
6780
|
+
issues: [{ code: "io_error", severity: "error", message: `Cannot read path: ${message}` }],
|
|
6781
|
+
checkedFiles: 0
|
|
6782
|
+
};
|
|
6783
|
+
}
|
|
6784
|
+
if (!rootStat.isDirectory()) {
|
|
6785
|
+
return {
|
|
6786
|
+
ok: false,
|
|
6787
|
+
status: "fail",
|
|
6788
|
+
root,
|
|
6789
|
+
issues: [
|
|
6790
|
+
{
|
|
6791
|
+
code: "io_error",
|
|
6792
|
+
severity: "error",
|
|
6793
|
+
message: "Evidence verify expects a directory containing evidence.json (unpack ZIP first)."
|
|
6794
|
+
}
|
|
6795
|
+
],
|
|
6796
|
+
checkedFiles: 0
|
|
6797
|
+
};
|
|
6798
|
+
}
|
|
6799
|
+
const manifestPath = path5__default.default.join(root, EVIDENCE_MANIFEST_FILENAME);
|
|
6800
|
+
let manifestText;
|
|
6801
|
+
try {
|
|
6802
|
+
manifestText = await promises.readFile(manifestPath, "utf-8");
|
|
6803
|
+
} catch {
|
|
6804
|
+
return {
|
|
6805
|
+
ok: false,
|
|
6806
|
+
status: "fail",
|
|
6807
|
+
root,
|
|
6808
|
+
issues: [
|
|
6809
|
+
{
|
|
6810
|
+
code: "manifest_missing",
|
|
6811
|
+
severity: "error",
|
|
6812
|
+
message: `Missing ${EVIDENCE_MANIFEST_FILENAME}`,
|
|
6813
|
+
path: EVIDENCE_MANIFEST_FILENAME
|
|
6814
|
+
}
|
|
6815
|
+
],
|
|
6816
|
+
checkedFiles: 0
|
|
6817
|
+
};
|
|
6818
|
+
}
|
|
6819
|
+
let manifest;
|
|
6820
|
+
try {
|
|
6821
|
+
manifest = parseEvidenceManifestJson(manifestText);
|
|
6822
|
+
} catch (error) {
|
|
6823
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6824
|
+
return {
|
|
6825
|
+
ok: false,
|
|
6826
|
+
status: "fail",
|
|
6827
|
+
root,
|
|
6828
|
+
issues: [
|
|
6829
|
+
{
|
|
6830
|
+
code: "manifest_invalid",
|
|
6831
|
+
severity: "error",
|
|
6832
|
+
message,
|
|
6833
|
+
path: EVIDENCE_MANIFEST_FILENAME
|
|
6834
|
+
}
|
|
6835
|
+
],
|
|
6836
|
+
checkedFiles: 0
|
|
6837
|
+
};
|
|
6838
|
+
}
|
|
6839
|
+
if (!manifest.assessment?.status) {
|
|
6840
|
+
issues.push({
|
|
6841
|
+
code: "assessment_missing",
|
|
6842
|
+
severity: "error",
|
|
6843
|
+
message: "Manifest assessment.status is required."
|
|
6844
|
+
});
|
|
6845
|
+
}
|
|
6846
|
+
if (!manifest.generator?.name || !manifest.generator?.version) {
|
|
6847
|
+
issues.push({
|
|
6848
|
+
code: "provenance_missing",
|
|
6849
|
+
severity: "error",
|
|
6850
|
+
message: "Manifest generator.name and generator.version are required."
|
|
6851
|
+
});
|
|
6852
|
+
}
|
|
6853
|
+
if (!manifest.source?.runIds?.length) {
|
|
6854
|
+
issues.push({
|
|
6855
|
+
code: "provenance_missing",
|
|
6856
|
+
severity: "error",
|
|
6857
|
+
message: "Manifest source.runIds must be non-empty."
|
|
6858
|
+
});
|
|
6859
|
+
}
|
|
6860
|
+
const listed = /* @__PURE__ */ new Set();
|
|
6861
|
+
for (const file of manifest.files) {
|
|
6862
|
+
let rel;
|
|
6863
|
+
try {
|
|
6864
|
+
rel = assertEvidenceRelativePath(file.path);
|
|
6865
|
+
} catch (error) {
|
|
6866
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6867
|
+
issues.push({
|
|
6868
|
+
code: "path_unsafe",
|
|
6869
|
+
severity: "error",
|
|
6870
|
+
message,
|
|
6871
|
+
path: file.path
|
|
6872
|
+
});
|
|
6873
|
+
continue;
|
|
6874
|
+
}
|
|
6875
|
+
if (rel === EVIDENCE_MANIFEST_FILENAME) {
|
|
6876
|
+
issues.push({
|
|
6877
|
+
code: "manifest_invalid",
|
|
6878
|
+
severity: "error",
|
|
6879
|
+
message: `${EVIDENCE_MANIFEST_FILENAME} must not list itself in files[].`,
|
|
6880
|
+
path: rel
|
|
6881
|
+
});
|
|
6882
|
+
continue;
|
|
6883
|
+
}
|
|
6884
|
+
listed.add(rel);
|
|
6885
|
+
const abs = path5__default.default.join(root, ...rel.split("/"));
|
|
6886
|
+
let bytes;
|
|
6887
|
+
try {
|
|
6888
|
+
bytes = await promises.readFile(abs);
|
|
6889
|
+
} catch {
|
|
6890
|
+
issues.push({
|
|
6891
|
+
code: "file_missing",
|
|
6892
|
+
severity: "error",
|
|
6893
|
+
message: `Listed file missing: ${rel}`,
|
|
6894
|
+
path: rel
|
|
6895
|
+
});
|
|
6896
|
+
continue;
|
|
6897
|
+
}
|
|
6898
|
+
const actual = sha256Hex(bytes);
|
|
6899
|
+
if (!sha256Equals(file.sha256, actual)) {
|
|
6900
|
+
issues.push({
|
|
6901
|
+
code: "hash_mismatch",
|
|
6902
|
+
severity: "error",
|
|
6903
|
+
message: `SHA-256 mismatch for ${rel}`,
|
|
6904
|
+
path: rel
|
|
6905
|
+
});
|
|
6906
|
+
}
|
|
6907
|
+
}
|
|
6908
|
+
let onDisk = [];
|
|
6909
|
+
try {
|
|
6910
|
+
onDisk = await listFilesRecursive(root);
|
|
6911
|
+
} catch (error) {
|
|
6912
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6913
|
+
issues.push({ code: "io_error", severity: "error", message });
|
|
6914
|
+
}
|
|
6915
|
+
for (const rel of onDisk) {
|
|
6916
|
+
if (rel === EVIDENCE_MANIFEST_FILENAME) continue;
|
|
6917
|
+
if (listed.has(rel)) continue;
|
|
6918
|
+
if (unexpectedMode === "ignore") continue;
|
|
6919
|
+
issues.push({
|
|
6920
|
+
code: "file_unexpected",
|
|
6921
|
+
severity: unexpectedMode === "warn" ? "warning" : "error",
|
|
6922
|
+
message: `Unexpected file not listed in manifest: ${rel}`,
|
|
6923
|
+
path: rel
|
|
6924
|
+
});
|
|
6925
|
+
}
|
|
6926
|
+
const hasError = issues.some((issue) => issue.severity === "error");
|
|
6927
|
+
return {
|
|
6928
|
+
ok: !hasError,
|
|
6929
|
+
status: hasError ? "fail" : "pass",
|
|
6930
|
+
root,
|
|
6931
|
+
manifest,
|
|
6932
|
+
issues,
|
|
6933
|
+
checkedFiles: listed.size
|
|
6934
|
+
};
|
|
6935
|
+
}
|
|
6936
|
+
|
|
6937
|
+
// packages/core/src/evidence/ci.ts
|
|
6938
|
+
function asMap(value) {
|
|
6939
|
+
if (value instanceof Map) return new Map(value);
|
|
6940
|
+
return new Map(Object.entries(value));
|
|
6941
|
+
}
|
|
6942
|
+
function buildEvidenceCiPackage(input) {
|
|
6943
|
+
const sources = asMap(input.sourceContents);
|
|
6944
|
+
const sourceHashes = input.runIds.map((runId) => ({
|
|
6945
|
+
runId,
|
|
6946
|
+
algorithm: "sha256",
|
|
6947
|
+
hash: sha256Hex(sources.get(runId) ?? "")
|
|
6948
|
+
}));
|
|
6949
|
+
const schemaVersions = /* @__PURE__ */ new Set();
|
|
6950
|
+
for (const content of sources.values()) {
|
|
6951
|
+
for (const version of collectTraceSchemaVersions(content)) {
|
|
6952
|
+
schemaVersions.add(version);
|
|
6953
|
+
}
|
|
6954
|
+
}
|
|
6955
|
+
for (const version of collectTraceSchemaVersions(input.redactedTraceJsonl)) {
|
|
6956
|
+
schemaVersions.add(version);
|
|
6957
|
+
}
|
|
6958
|
+
const createdAt = input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
6959
|
+
const evidenceHtml = buildEvidenceHtmlShell({
|
|
6960
|
+
title: "AgentInspect evidence",
|
|
6961
|
+
runIds: input.runIds,
|
|
6962
|
+
assessmentStatus: input.assessmentStatus,
|
|
6963
|
+
sourceStatus: input.sourceStatus,
|
|
6964
|
+
redactionProfile: input.redactionProfile,
|
|
6965
|
+
verificationPolicy: input.redactionProfile,
|
|
6966
|
+
generatorName: "agent-inspect",
|
|
6967
|
+
generatorVersion: input.generatorVersion,
|
|
6968
|
+
createdAt,
|
|
6969
|
+
summaryText: input.summaryText,
|
|
6970
|
+
checkSummary: {
|
|
6971
|
+
aggregateStatus: input.assessmentStatus,
|
|
6972
|
+
runs: input.runIds.map((runId) => ({
|
|
6973
|
+
runId,
|
|
6974
|
+
status: input.assessmentStatus,
|
|
6975
|
+
sourceStatus: input.sourceStatus,
|
|
6976
|
+
errors: input.assessmentStatus === "UNSAFE" || input.assessmentStatus === "UNKNOWN" ? 1 : 0,
|
|
6977
|
+
warnings: input.assessmentStatus === "SAFE WITH WARNINGS" ? 1 : 0,
|
|
6978
|
+
findings: 0
|
|
6979
|
+
}))
|
|
6980
|
+
}
|
|
6981
|
+
});
|
|
6982
|
+
const packaged = [
|
|
6983
|
+
{ path: EVIDENCE_HTML_FILENAME, content: evidenceHtml },
|
|
6984
|
+
{ path: "check-results.json", content: input.checkResultsJson },
|
|
6985
|
+
{ path: "trace.jsonl", content: input.redactedTraceJsonl }
|
|
6986
|
+
];
|
|
6987
|
+
const manifest = buildEvidenceManifest({
|
|
6988
|
+
generatorVersion: input.generatorVersion,
|
|
6989
|
+
runIds: input.runIds,
|
|
6990
|
+
traceSchemaVersions: [...schemaVersions].sort((a, b) => a.localeCompare(b)),
|
|
6991
|
+
sourceHashes,
|
|
6992
|
+
redactionProfile: input.redactionProfile,
|
|
6993
|
+
verificationPolicy: input.redactionProfile,
|
|
6994
|
+
assessmentStatus: input.assessmentStatus,
|
|
6995
|
+
sourceStatus: input.sourceStatus,
|
|
6996
|
+
files: packaged,
|
|
6997
|
+
createdAt,
|
|
6998
|
+
note: EVIDENCE_ASSESSMENT_NOTE
|
|
6999
|
+
});
|
|
7000
|
+
return {
|
|
7001
|
+
"evidence.html": evidenceHtml,
|
|
7002
|
+
"evidence.json": serializeEvidenceManifest(manifest),
|
|
7003
|
+
"check-results.json": input.checkResultsJson,
|
|
7004
|
+
"trace.jsonl": input.redactedTraceJsonl,
|
|
7005
|
+
manifest
|
|
7006
|
+
};
|
|
7007
|
+
}
|
|
7008
|
+
|
|
5345
7009
|
// packages/core/src/suite/types.ts
|
|
5346
7010
|
var DEFAULT_SUITE_CONFIG_NAMES = [
|
|
5347
7011
|
"agent-inspect.suite.json",
|
|
@@ -5833,7 +7497,11 @@ function normalizeFinding(rule, finding) {
|
|
|
5833
7497
|
message: finding.message,
|
|
5834
7498
|
...finding.expected !== void 0 ? { expected: finding.expected } : {},
|
|
5835
7499
|
...finding.actual !== void 0 ? { actual: finding.actual } : {},
|
|
5836
|
-
evidence: [...finding.evidence ?? []]
|
|
7500
|
+
evidence: [...finding.evidence ?? []],
|
|
7501
|
+
...finding.category !== void 0 ? { category: finding.category } : {},
|
|
7502
|
+
...finding.confidence !== void 0 ? { confidence: finding.confidence } : {},
|
|
7503
|
+
...finding.detector !== void 0 ? { detector: finding.detector } : {},
|
|
7504
|
+
...finding.action !== void 0 ? { action: finding.action } : {}
|
|
5837
7505
|
};
|
|
5838
7506
|
}
|
|
5839
7507
|
function summarize(findings, diagnostics) {
|
|
@@ -5861,7 +7529,7 @@ function stripPrefix(name, prefixes) {
|
|
|
5861
7529
|
}
|
|
5862
7530
|
return name;
|
|
5863
7531
|
}
|
|
5864
|
-
function eventEvidence(event,
|
|
7532
|
+
function eventEvidence(event, path14) {
|
|
5865
7533
|
return {
|
|
5866
7534
|
runId: event.runId,
|
|
5867
7535
|
eventId: event.eventId,
|
|
@@ -5871,21 +7539,25 @@ function eventEvidence(event, path12) {
|
|
|
5871
7539
|
kind: event.kind,
|
|
5872
7540
|
name: event.name,
|
|
5873
7541
|
status: event.status,
|
|
5874
|
-
...
|
|
7542
|
+
...path14 ? { path: path14 } : {}
|
|
5875
7543
|
};
|
|
5876
7544
|
}
|
|
5877
7545
|
function runEvidence(run) {
|
|
5878
7546
|
return run ? [{ runId: run.runId, name: run.name, status: run.status }] : [];
|
|
5879
7547
|
}
|
|
5880
|
-
function failFinding(ruleId, message, evidence, expected, actual) {
|
|
7548
|
+
function failFinding(ruleId, message, evidence, expected, actual, meta) {
|
|
5881
7549
|
return {
|
|
5882
7550
|
ruleId,
|
|
5883
|
-
severity: "error",
|
|
5884
|
-
status: "fail",
|
|
7551
|
+
severity: meta?.severity ?? "error",
|
|
7552
|
+
status: meta?.status ?? "fail",
|
|
5885
7553
|
message,
|
|
5886
7554
|
...expected !== void 0 ? { expected } : {},
|
|
5887
7555
|
...actual !== void 0 ? { actual } : {},
|
|
5888
|
-
evidence: [...evidence]
|
|
7556
|
+
evidence: [...evidence],
|
|
7557
|
+
...{},
|
|
7558
|
+
...{},
|
|
7559
|
+
...{},
|
|
7560
|
+
...{}
|
|
5889
7561
|
};
|
|
5890
7562
|
}
|
|
5891
7563
|
function toolName(event) {
|
|
@@ -9071,11 +10743,6 @@ async function analyzeCohort(runsInput, options) {
|
|
|
9071
10743
|
};
|
|
9072
10744
|
}
|
|
9073
10745
|
|
|
9074
|
-
// packages/core/src/exporters/helpers.ts
|
|
9075
|
-
function escapeHtml(value) {
|
|
9076
|
-
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
9077
|
-
}
|
|
9078
|
-
|
|
9079
10746
|
// packages/core/src/cohort/render.ts
|
|
9080
10747
|
function formatRate(value) {
|
|
9081
10748
|
if (value === void 0) return "n/a";
|
|
@@ -9707,6 +11374,12 @@ exports.DEFAULT_MAX_PREVIEW_LENGTH = DEFAULT_MAX_PREVIEW_LENGTH;
|
|
|
9707
11374
|
exports.DEFAULT_SUITE_ARTIFACTS_DIR = DEFAULT_SUITE_ARTIFACTS_DIR;
|
|
9708
11375
|
exports.DEFAULT_SUITE_CONFIG_NAMES = DEFAULT_SUITE_CONFIG_NAMES;
|
|
9709
11376
|
exports.DEFAULT_TRACE_DIR_NAME = DEFAULT_TRACE_DIR_NAME;
|
|
11377
|
+
exports.EVIDENCE_ASSESSMENT_NOTE = EVIDENCE_ASSESSMENT_NOTE;
|
|
11378
|
+
exports.EVIDENCE_FORMAT_VERSION = EVIDENCE_FORMAT_VERSION;
|
|
11379
|
+
exports.EVIDENCE_HTML_FILENAME = EVIDENCE_HTML_FILENAME;
|
|
11380
|
+
exports.EVIDENCE_MANIFEST_FILENAME = EVIDENCE_MANIFEST_FILENAME;
|
|
11381
|
+
exports.EVIDENCE_VIEW_CSS = EVIDENCE_VIEW_CSS;
|
|
11382
|
+
exports.EVIDENCE_VIEW_IDS = EVIDENCE_VIEW_IDS;
|
|
9710
11383
|
exports.FALLBACK_TRACE_DIR = FALLBACK_TRACE_DIR;
|
|
9711
11384
|
exports.MAX_NAME_LENGTH = MAX_NAME_LENGTH;
|
|
9712
11385
|
exports.MAX_TERMINAL_DEPTH = MAX_TERMINAL_DEPTH;
|
|
@@ -9720,9 +11393,25 @@ exports.aggregateBundleSafeStatus = aggregateBundleSafeStatus;
|
|
|
9720
11393
|
exports.aggregateSessionCheckResults = aggregateSessionCheckResults;
|
|
9721
11394
|
exports.analyzeCohort = analyzeCohort;
|
|
9722
11395
|
exports.assertBundlePathContained = assertBundlePathContained;
|
|
11396
|
+
exports.assertEvidenceRelativePath = assertEvidenceRelativePath;
|
|
9723
11397
|
exports.buildActivitySummary = buildActivitySummary;
|
|
9724
11398
|
exports.buildBundleMetadata = buildBundleMetadata;
|
|
9725
11399
|
exports.buildBundleSummaryMarkdown = buildBundleSummaryMarkdown;
|
|
11400
|
+
exports.buildEvidenceCausalFailureViewHtml = buildEvidenceCausalFailureViewHtml;
|
|
11401
|
+
exports.buildEvidenceCiPackage = buildEvidenceCiPackage;
|
|
11402
|
+
exports.buildEvidenceCircuitViewHtml = buildEvidenceCircuitViewHtml;
|
|
11403
|
+
exports.buildEvidenceContractsViewHtml = buildEvidenceContractsViewHtml;
|
|
11404
|
+
exports.buildEvidenceDiffViewHtml = buildEvidenceDiffViewHtml;
|
|
11405
|
+
exports.buildEvidenceFileEntries = buildEvidenceFileEntries;
|
|
11406
|
+
exports.buildEvidenceHtmlShell = buildEvidenceHtmlShell;
|
|
11407
|
+
exports.buildEvidenceHtmlShellFromManifest = buildEvidenceHtmlShellFromManifest;
|
|
11408
|
+
exports.buildEvidenceManifest = buildEvidenceManifest;
|
|
11409
|
+
exports.buildEvidenceOutcomesViewHtml = buildEvidenceOutcomesViewHtml;
|
|
11410
|
+
exports.buildEvidenceProvenanceViewHtml = buildEvidenceProvenanceViewHtml;
|
|
11411
|
+
exports.buildEvidenceSafetyViewHtml = buildEvidenceSafetyViewHtml;
|
|
11412
|
+
exports.buildEvidenceTimelineViewHtml = buildEvidenceTimelineViewHtml;
|
|
11413
|
+
exports.buildEvidenceToolsLlmViewHtml = buildEvidenceToolsLlmViewHtml;
|
|
11414
|
+
exports.buildEvidenceTreeViewHtml = buildEvidenceTreeViewHtml;
|
|
9726
11415
|
exports.buildLocalExplanation = buildLocalExplanation;
|
|
9727
11416
|
exports.buildPlaceholderArtifact = buildPlaceholderArtifact;
|
|
9728
11417
|
exports.buildRunSummary = buildRunSummary;
|
|
@@ -9730,8 +11419,10 @@ exports.buildRunTimeline = buildRunTimeline;
|
|
|
9730
11419
|
exports.buildRunWhatSummary = buildRunWhatSummary;
|
|
9731
11420
|
exports.buildSessionIndex = buildSessionIndex;
|
|
9732
11421
|
exports.buildTraceStats = buildTraceStats;
|
|
11422
|
+
exports.buildZipArchive = buildZipArchive;
|
|
9733
11423
|
exports.bundleFailsOnSafety = bundleFailsOnSafety;
|
|
9734
11424
|
exports.bundleRunAssetRelativePath = bundleRunAssetRelativePath;
|
|
11425
|
+
exports.collectTraceSchemaVersions = collectTraceSchemaVersions;
|
|
9735
11426
|
exports.compareCohortAggregates = compareCohortAggregates;
|
|
9736
11427
|
exports.createInspector = createInspector;
|
|
9737
11428
|
exports.createInspectorRuntime = createInspectorRuntime;
|
|
@@ -9740,6 +11431,7 @@ exports.createStepId = createStepId;
|
|
|
9740
11431
|
exports.defaultBundleOutputPath = defaultBundleOutputPath;
|
|
9741
11432
|
exports.defaultSuiteConfigTemplate = defaultSuiteConfigTemplate;
|
|
9742
11433
|
exports.deriveSessionStatus = deriveSessionStatus;
|
|
11434
|
+
exports.encodeEmbeddedEvidenceJson = encodeEmbeddedEvidenceJson;
|
|
9743
11435
|
exports.enrichSessionRunRecord = enrichSessionRunRecord;
|
|
9744
11436
|
exports.enrichSessionSummary = enrichSessionSummary;
|
|
9745
11437
|
exports.ensureTraceDir = ensureTraceDir;
|
|
@@ -9770,9 +11462,11 @@ exports.getTraceFilePath = getTraceFilePath;
|
|
|
9770
11462
|
exports.getTraceSafetyFromContext = getTraceSafetyFromContext;
|
|
9771
11463
|
exports.groupSessionCohorts = groupSessionCohorts;
|
|
9772
11464
|
exports.hasActiveContext = hasActiveContext;
|
|
11465
|
+
exports.inferEvidenceFileRole = inferEvidenceFileRole;
|
|
9773
11466
|
exports.initializeTraceFile = initializeTraceFile;
|
|
9774
11467
|
exports.isAgentInspectEnabled = isAgentInspectEnabled;
|
|
9775
11468
|
exports.isAgentInspectTrace = isAgentInspectTrace;
|
|
11469
|
+
exports.isSha256Hex = isSha256Hex;
|
|
9776
11470
|
exports.isSilentContext = isSilentContext;
|
|
9777
11471
|
exports.isStepStatus = isStepStatus;
|
|
9778
11472
|
exports.isStepType = isStepType;
|
|
@@ -9788,6 +11482,7 @@ exports.normalizeSuiteConfig = normalizeSuiteConfig;
|
|
|
9788
11482
|
exports.parseCohortMetricList = parseCohortMetricList;
|
|
9789
11483
|
exports.parseDuration = parseDuration;
|
|
9790
11484
|
exports.parseDurationFilter = parseDurationFilter;
|
|
11485
|
+
exports.parseEvidenceManifestJson = parseEvidenceManifestJson;
|
|
9791
11486
|
exports.parseGateList = parseGateList;
|
|
9792
11487
|
exports.parseGateNumber = parseGateNumber;
|
|
9793
11488
|
exports.parseGroupBySpec = parseGroupBySpec;
|
|
@@ -9831,13 +11526,18 @@ exports.runWithStepContext = runWithStepContext;
|
|
|
9831
11526
|
exports.sanitizeBundleRunId = sanitizeBundleRunId;
|
|
9832
11527
|
exports.searchTraces = searchTraces;
|
|
9833
11528
|
exports.serializeEvent = serializeEvent;
|
|
11529
|
+
exports.serializeEvidenceManifest = serializeEvidenceManifest;
|
|
9834
11530
|
exports.sessionKeyForRun = sessionKeyForRun;
|
|
11531
|
+
exports.sha256Equals = sha256Equals;
|
|
11532
|
+
exports.sha256Hex = sha256Hex;
|
|
9835
11533
|
exports.toMetadataSafeStatus = toMetadataSafeStatus;
|
|
9836
11534
|
exports.traceMetasToSessionRunRecords = traceMetasToSessionRunRecords;
|
|
9837
11535
|
exports.truncateName = truncateName;
|
|
9838
11536
|
exports.unknownTraceFormatMessage = unknownTraceFormatMessage;
|
|
9839
11537
|
exports.validateEvent = validateEvent;
|
|
11538
|
+
exports.validateEvidenceManifest = validateEvidenceManifest;
|
|
9840
11539
|
exports.validateSuiteConfig = validateSuiteConfig;
|
|
11540
|
+
exports.verifyEvidenceDirectory = verifyEvidenceDirectory;
|
|
9841
11541
|
exports.warn = warn;
|
|
9842
11542
|
exports.writeTraceEvent = writeTraceEvent;
|
|
9843
11543
|
//# sourceMappingURL=advanced.cjs.map
|