@agentskit/doc-bridge 1.6.2 → 1.6.3
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 +6 -0
- package/action.yml +1 -1
- package/bin/ak-verify.js +9 -0
- package/dist/cli/program.js +303 -55
- package/dist/cli/program.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -1
- package/dist/{index-Di7PkJuf.d.ts → index-DudNuwI5.d.ts} +24 -1
- package/dist/index.d.ts +24 -5
- package/dist/index.js +249 -43
- package/dist/index.js.map +1 -1
- package/docs/knowledge-engine-runbook.md +14 -0
- package/docs/verification-harness.md +36 -0
- package/mcpb/manifest.json +1 -1
- package/package.json +52 -44
- package/scripts/report-visual-check.mjs +239 -0
- package/scripts/verification-harness.mjs +280 -0
- package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +1 -1
- package/src/cli/program.ts +64 -7
- package/src/config/index.ts +2 -0
- package/src/config/schema.ts +9 -0
- package/src/index.ts +8 -1
- package/src/lib/markdown.ts +5 -0
- package/src/reconciliation/reconcile.ts +9 -1
- package/src/report/html.ts +292 -40
- package/src/schemas/knowledge.ts +1 -0
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -204,6 +204,10 @@ var RulesConfigSchema = z.object({
|
|
|
204
204
|
criticalPaths: z.array(z.string().min(1).max(512)).max(128).optional(),
|
|
205
205
|
warningThresholds: z.record(RuleIdSchema, z.number().int().min(1).max(1e5)).optional()
|
|
206
206
|
}).strict();
|
|
207
|
+
var ReconciliationConfigSchema = z.object({
|
|
208
|
+
/** Relation kinds that must have documentation declarations. Omit to require all observed kinds; [] disables this signal. */
|
|
209
|
+
requiredRelationKinds: z.array(z.string().min(1).max(128)).max(128).optional()
|
|
210
|
+
}).strict();
|
|
207
211
|
var WorkflowConfigSchema = z.object({
|
|
208
212
|
stateDir: z.string().min(1).max(512).optional()
|
|
209
213
|
}).strict();
|
|
@@ -377,6 +381,7 @@ var DocBridgeConfigV1Schema = z.object({
|
|
|
377
381
|
index: IndexConfigSchema.optional(),
|
|
378
382
|
routing: RoutingConfigSchema.optional(),
|
|
379
383
|
gates: GatesConfigSchema.optional(),
|
|
384
|
+
reconciliation: ReconciliationConfigSchema.optional(),
|
|
380
385
|
rules: RulesConfigSchema.optional(),
|
|
381
386
|
workflow: WorkflowConfigSchema.optional(),
|
|
382
387
|
safety: RepositorySafetyConfigSchema.optional(),
|
|
@@ -1189,7 +1194,8 @@ var ReconciliationReportV1Schema = z5.object({
|
|
|
1189
1194
|
summary: z5.object({
|
|
1190
1195
|
entityCount: z5.number().int().nonnegative(),
|
|
1191
1196
|
relationCount: z5.number().int().nonnegative(),
|
|
1192
|
-
diagnosticCount: z5.number().int().nonnegative()
|
|
1197
|
+
diagnosticCount: z5.number().int().nonnegative(),
|
|
1198
|
+
requiredRelationKinds: z5.array(boundedString(128)).max(128).optional()
|
|
1193
1199
|
}).strict()
|
|
1194
1200
|
}).strict();
|
|
1195
1201
|
var WorkflowStateSchema = z5.enum([
|
|
@@ -1501,6 +1507,10 @@ var firstParagraph = (markdown, maxLen = 400) => {
|
|
|
1501
1507
|
if (buf.length) break;
|
|
1502
1508
|
continue;
|
|
1503
1509
|
}
|
|
1510
|
+
if (/^(?:!?)\[[^\]]*\]\([^)]*\)$/.test(t)) {
|
|
1511
|
+
if (buf.length) break;
|
|
1512
|
+
continue;
|
|
1513
|
+
}
|
|
1504
1514
|
buf.push(t);
|
|
1505
1515
|
if (buf.join(" ").length >= maxLen) break;
|
|
1506
1516
|
}
|
|
@@ -1853,7 +1863,7 @@ var buildLookup = (config, packages, corpus, indexOutFile, humanDocs = {}, root
|
|
|
1853
1863
|
};
|
|
1854
1864
|
|
|
1855
1865
|
// src/version.ts
|
|
1856
|
-
var PACKAGE_VERSION = "1.6.
|
|
1866
|
+
var PACKAGE_VERSION = "1.6.3";
|
|
1857
1867
|
|
|
1858
1868
|
// src/index-builder/capabilities.ts
|
|
1859
1869
|
var renderCapabilitiesJson = (config, index, paths) => {
|
|
@@ -3394,11 +3404,12 @@ var reportDiagnostic = (code, status, severity, message, evidence2, value, entit
|
|
|
3394
3404
|
...relationIds?.length ? { relationIds: [...relationIds] } : {},
|
|
3395
3405
|
...remediation ? { remediation } : {}
|
|
3396
3406
|
});
|
|
3397
|
-
var reconcileKnowledge = (observed, declared) => {
|
|
3407
|
+
var reconcileKnowledge = (observed, declared, options = {}) => {
|
|
3398
3408
|
const resolveEntity2 = entityResolver([observed, declared]);
|
|
3399
3409
|
const entities = entityById([observed, declared]);
|
|
3400
3410
|
const observedRelations = observed.relations.filter((relation) => relation.provenance === "observed" && !ignoredDocumentationRelations.has(relation.kind));
|
|
3401
3411
|
const declaredRelations = declared.relations.filter((relation) => relation.provenance === "declared" && !ignoredDocumentationRelations.has(relation.kind));
|
|
3412
|
+
const requiredRelationKinds = options.requiredRelationKinds === void 0 ? void 0 : new Set(options.requiredRelationKinds);
|
|
3402
3413
|
const diagnostics = [];
|
|
3403
3414
|
for (const entity of declared.entities.filter((item) => isUnresolved(item.id, entities)).sort((a, b) => a.id.localeCompare(b.id))) {
|
|
3404
3415
|
diagnostics.push(reportDiagnostic(
|
|
@@ -3449,7 +3460,7 @@ var reconcileKnowledge = (observed, declared) => {
|
|
|
3449
3460
|
void 0,
|
|
3450
3461
|
[relation.id, match.id]
|
|
3451
3462
|
));
|
|
3452
|
-
} else if (coverageAvailable(observed, relation)) {
|
|
3463
|
+
} else if (coverageAvailable(observed, relation) && (requiredRelationKinds === void 0 || requiredRelationKinds.has(relation.kind))) {
|
|
3453
3464
|
diagnostics.push(reportDiagnostic(
|
|
3454
3465
|
"RELATION_UNDOCUMENTED",
|
|
3455
3466
|
"undocumented",
|
|
@@ -3511,13 +3522,104 @@ var reconcileKnowledge = (observed, declared) => {
|
|
|
3511
3522
|
summary: {
|
|
3512
3523
|
entityCount: observed.entities.length,
|
|
3513
3524
|
relationCount: observedRelations.length,
|
|
3514
|
-
diagnosticCount: sortedDiagnostics.length
|
|
3525
|
+
diagnosticCount: sortedDiagnostics.length,
|
|
3526
|
+
...options.requiredRelationKinds === void 0 ? {} : { requiredRelationKinds: [...new Set(options.requiredRelationKinds)].sort() }
|
|
3515
3527
|
}
|
|
3516
3528
|
};
|
|
3517
3529
|
return ReconciliationReportV1Schema.parse({ ...base, contentHash: contentHashForArtifactV1(base) });
|
|
3518
3530
|
};
|
|
3519
3531
|
|
|
3520
3532
|
// src/report/html.ts
|
|
3533
|
+
var DEFAULT_LARGE_REPORT_THRESHOLD_BYTES = 5e6;
|
|
3534
|
+
var pathParts = (value) => (value ?? "").split("/").filter(Boolean);
|
|
3535
|
+
var packageFamily = (entity) => {
|
|
3536
|
+
const packageName2 = entity.name.replace(/^@[^/]+\//, "");
|
|
3537
|
+
const nameFamily = packageName2.split(/[-_./]/)[0];
|
|
3538
|
+
if (nameFamily) return nameFamily.toLowerCase();
|
|
3539
|
+
return pathParts(entity.path)[1] ?? pathParts(entity.path)[0] ?? "other";
|
|
3540
|
+
};
|
|
3541
|
+
var reportGroupKey = (entity, appLayout) => {
|
|
3542
|
+
const parts = pathParts(entity.path);
|
|
3543
|
+
if (appLayout && parts[0] === "apps" && parts[1]) return `app:${parts[1]}`;
|
|
3544
|
+
if (appLayout && parts[0] === "packages") return "shared-packages";
|
|
3545
|
+
if (appLayout && (parts.length === 0 || parts[0] === ".")) return "workspace";
|
|
3546
|
+
return packageFamily(entity);
|
|
3547
|
+
};
|
|
3548
|
+
var titleCase = (value) => value.split(/[-_]/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
3549
|
+
var buildReportViewModel = (snapshot) => {
|
|
3550
|
+
const entities = new Map(snapshot.entities.map((entity) => [entity.id, entity]));
|
|
3551
|
+
const packages = snapshot.entities.filter((entity) => entity.kind === "package");
|
|
3552
|
+
const packageForEntity = /* @__PURE__ */ new Map();
|
|
3553
|
+
const externalIds = /* @__PURE__ */ new Set();
|
|
3554
|
+
for (const relation of snapshot.relations) {
|
|
3555
|
+
if (relation.kind === "contains" && entities.get(relation.from)?.kind === "package") packageForEntity.set(relation.to, relation.from);
|
|
3556
|
+
if (entities.get(relation.from)?.kind === "external") externalIds.add(relation.from);
|
|
3557
|
+
if (entities.get(relation.to)?.kind === "external") externalIds.add(relation.to);
|
|
3558
|
+
}
|
|
3559
|
+
const appLayout = packages.some((entity) => pathParts(entity.path)[0] === "apps");
|
|
3560
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3561
|
+
const entityGroup = {};
|
|
3562
|
+
for (const entity of packages) {
|
|
3563
|
+
const family = reportGroupKey(entity, appLayout);
|
|
3564
|
+
const id = `group:${family}`;
|
|
3565
|
+
const current = groups.get(id) ?? {
|
|
3566
|
+
kind: family.startsWith("app:") ? "app" : family === "shared-packages" ? "shared" : family === "workspace" ? "workspace" : "domain",
|
|
3567
|
+
name: family.startsWith("app:") ? `${titleCase(family.slice(4))} app` : family === "shared-packages" ? "Shared packages" : family === "workspace" ? "Workspace root" : family,
|
|
3568
|
+
path: family.startsWith("app:") ? `apps/${family.slice(4)}` : family === "shared-packages" ? "packages" : family === "workspace" ? "." : void 0,
|
|
3569
|
+
members: []
|
|
3570
|
+
};
|
|
3571
|
+
current.members.push(entity.id);
|
|
3572
|
+
groups.set(id, current);
|
|
3573
|
+
entityGroup[entity.id] = id;
|
|
3574
|
+
}
|
|
3575
|
+
for (const [entityId2, packageId2] of packageForEntity) {
|
|
3576
|
+
const groupId = entityGroup[packageId2];
|
|
3577
|
+
if (groupId) entityGroup[entityId2] = groupId;
|
|
3578
|
+
}
|
|
3579
|
+
if (externalIds.size) {
|
|
3580
|
+
const externalGroupId = "group:external-dependencies";
|
|
3581
|
+
groups.set(externalGroupId, {
|
|
3582
|
+
kind: "external",
|
|
3583
|
+
name: "External dependencies",
|
|
3584
|
+
path: void 0,
|
|
3585
|
+
members: [...externalIds].sort()
|
|
3586
|
+
});
|
|
3587
|
+
for (const entityId2 of externalIds) entityGroup[entityId2] = externalGroupId;
|
|
3588
|
+
}
|
|
3589
|
+
const allOverviewNodes = [...groups.entries()].map(([id, group]) => ({
|
|
3590
|
+
id,
|
|
3591
|
+
kind: group.kind,
|
|
3592
|
+
name: group.name,
|
|
3593
|
+
path: group.path,
|
|
3594
|
+
memberCount: group.members.length
|
|
3595
|
+
}));
|
|
3596
|
+
const hasApplications = allOverviewNodes.some((node) => node.kind === "app");
|
|
3597
|
+
const overviewNodes = allOverviewNodes.filter(
|
|
3598
|
+
(node) => node.kind !== "external" && (!hasApplications || node.kind !== "workspace")
|
|
3599
|
+
);
|
|
3600
|
+
const overviewNodeIds = new Set(overviewNodes.map((node) => node.id));
|
|
3601
|
+
const edgeMap = /* @__PURE__ */ new Map();
|
|
3602
|
+
for (const relation of snapshot.relations) {
|
|
3603
|
+
if (relation.kind === "contains") continue;
|
|
3604
|
+
const from = entityGroup[relation.from];
|
|
3605
|
+
const to = entityGroup[relation.to];
|
|
3606
|
+
if (!from || !to || from === to) continue;
|
|
3607
|
+
const key = `${from}\u2192${to}`;
|
|
3608
|
+
const edge = edgeMap.get(key) ?? { from, to, count: 0, kinds: /* @__PURE__ */ new Set(), relationIds: /* @__PURE__ */ new Set() };
|
|
3609
|
+
edge.count += 1;
|
|
3610
|
+
edge.kinds.add(relation.kind);
|
|
3611
|
+
edge.relationIds.add(relation.id);
|
|
3612
|
+
edgeMap.set(key, edge);
|
|
3613
|
+
}
|
|
3614
|
+
return {
|
|
3615
|
+
overview: {
|
|
3616
|
+
nodes: overviewNodes.sort((left, right) => left.name.localeCompare(right.name) || left.id.localeCompare(right.id)),
|
|
3617
|
+
edges: [...edgeMap.values()].filter((edge) => overviewNodeIds.has(edge.from) && overviewNodeIds.has(edge.to)).map((edge) => ({ ...edge, kinds: [...edge.kinds].sort(), relationIds: [...edge.relationIds].sort() })).sort((left, right) => right.count - left.count || left.from.localeCompare(right.from) || left.to.localeCompare(right.to))
|
|
3618
|
+
},
|
|
3619
|
+
groups: Object.fromEntries([...groups.entries()].map(([id, group]) => [id, { ...group, members: [...group.members].sort() }])),
|
|
3620
|
+
entityGroup
|
|
3621
|
+
};
|
|
3622
|
+
};
|
|
3521
3623
|
var escapeHtml = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
3522
3624
|
var anchor = (prefix, value) => `${prefix}-${value.replace(/[^A-Za-z0-9_-]+/g, "-")}`;
|
|
3523
3625
|
var embeddedJson = (value) => JSON.stringify(value).replaceAll("<", "\\u003c");
|
|
@@ -3531,6 +3633,14 @@ var reportData = (snapshot, report, includeSnippets) => ({
|
|
|
3531
3633
|
configurationHash: snapshot.configurationHash,
|
|
3532
3634
|
pipelineVersion: snapshot.pipelineVersion,
|
|
3533
3635
|
analyzerVersions: snapshot.analyzerVersions,
|
|
3636
|
+
diagnosticCount: report.diagnostics.length,
|
|
3637
|
+
requiredRelationKinds: report.summary.requiredRelationKinds,
|
|
3638
|
+
diagnosticSummary: {
|
|
3639
|
+
errors: report.diagnostics.filter((diagnostic2) => diagnostic2.severity === "error").length,
|
|
3640
|
+
warnings: report.diagnostics.filter((diagnostic2) => diagnostic2.severity === "warn").length,
|
|
3641
|
+
undocumented: report.diagnostics.filter((diagnostic2) => diagnostic2.status === "undocumented").length,
|
|
3642
|
+
drift: report.diagnostics.filter((diagnostic2) => diagnostic2.status === "stale-or-unverified" || diagnostic2.status === "conflict").length
|
|
3643
|
+
},
|
|
3534
3644
|
entities: snapshot.entities.map((entity, index) => ({
|
|
3535
3645
|
id: entity.id,
|
|
3536
3646
|
anchor: entity.id.length > 64 ? `entity-n${index}` : anchor("entity", entity.id),
|
|
@@ -3559,67 +3669,161 @@ var reportData = (snapshot, report, includeSnippets) => ({
|
|
|
3559
3669
|
remediation: diagnostic2.remediation,
|
|
3560
3670
|
evidence: diagnostic2.evidence.map(({ context, ...item }) => includeSnippets && context ? { ...item, context: redactSecrets(context) } : item)
|
|
3561
3671
|
})),
|
|
3562
|
-
coverage: snapshot.coverage
|
|
3672
|
+
coverage: snapshot.coverage,
|
|
3673
|
+
view: buildReportViewModel(snapshot)
|
|
3563
3674
|
});
|
|
3564
3675
|
var styles = String.raw`
|
|
3565
3676
|
:root{color-scheme:light;--ink:#17251f;--muted:#60706a;--paper:#f5f7f3;--panel:#fff;--line:#d9e0da;--green:#18794e;--blue:#236b83;--amber:#a9640b;--red:#b33c35;--shadow:0 12px 32px rgba(23,37,31,.08)}
|
|
3566
|
-
*{box-sizing:border-box}body{margin:0;background:var(--paper);color:var(--ink);font:14px/1.5 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}button,input,select{font:inherit}button{cursor:pointer}a{color:var(--blue)}.shell{max-width:1500px;margin:auto;padding:24px}.masthead{display:flex;justify-content:space-between;gap:24px;align-items:flex-end;border-bottom:1px solid var(--line);padding:8px 0 24px}.eyebrow{color:var(--green);font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase}.masthead h1{font:700 clamp(28px,4vw,52px)/1.03 Georgia,serif;letter-spacing:-.04em;margin:8px 0}.lede{color:var(--muted);font-size:16px;max-width:720px;margin:0}.run-meta{text-align:right;color:var(--muted);font-size:12px}.run-meta strong{display:block;color:var(--green);font-size:14px}.read-only{border:1px solid #b9d7c6;background:#edf8f0;color:#185b3b;border-radius:999px;display:inline-flex;padding:4px 10px;font-weight:700;font-size:12px}.summary{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin:20px 0}.metric,.insight,.panel{background:var(--panel);border:1px solid var(--line);box-shadow:var(--shadow);border-radius:14px}.metric{padding:16px}.metric b{font-size:27px;display:block;line-height:1}.metric span{color:var(--muted);display:block;margin-top:7px}.metric.warn b{color:var(--amber)}.metric.bad b{color:var(--red)}.lens-bar{display:flex;align-items:center;justify-content:space-between;gap:14px;margin:22px 0 12px}.tabs{display:flex;gap:4px;flex-wrap:wrap}.tab,.level{border:1px solid transparent;background:transparent;border-radius:8px;padding:8px 11px;color:var(--muted)}.tab:hover,.level:hover{background:#e8eee9;color:var(--ink)}.tab[aria-selected=true],.level[aria-pressed=true]{background:var(--ink);color:#fff}.filters{display:flex;gap:8px;flex-wrap:wrap;margin:12px 0}.filters label{color:var(--muted);font-size:12px;display:flex;align-items:center;gap:6px}.filters input,.filters select,.filters button{border:1px solid var(--line);background:#fff;border-radius:8px;padding:8px 10px;color:var(--ink)}.filters input{min-width:220px}.filters button{color:var(--blue)}.insights{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:14px 0 20px}.insight{padding:14px}.insight h3{font-size:13px;margin:0 0 5px}.insight p{color:var(--muted);margin:0;font-size:12px}.tag{display:inline-block;border-radius:999px;padding:2px 7px;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;background:#edf0ee;color:var(--muted)}.tag.heuristic{background:#fff3dc;color:#8a570a}.tag.error{background:#fde8e6;color:var(--red)}.tag.warn{background:#fff2d9;color:var(--amber)}.tag.info{background:#e6f1f5;color:var(--blue)}.workspace{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:14px}.panel{padding:18px}.panel h2{font:700 23px Georgia,serif;margin:0}.panel h3{font-size:14px;margin:0}.panel-head{display:flex;justify-content:space-between;gap:12px;align-items:flex-start;margin-bottom:14px}.subtle{color:var(--muted);font-size:12px}.map-wrap{border:1px solid var(--line);border-radius:10px;overflow:auto;background:linear-gradient(135deg,#fbfcfa,#f0f5f0)}#graph{display:block;width:100%;min-width:760px;height:560px}.edge{stroke:#b8c6bd;stroke-width:1.3;opacity:.65}.edge.alert{stroke:#d08a35;stroke-width:2}.edge-label{fill:var(--muted);font-size:10px}.graph-node{cursor:pointer}.graph-node rect{fill:#fff;stroke:#9eb0a4;stroke-width:1.2}.graph-node:hover rect,.graph-node:focus rect{stroke:var(--blue);stroke-width:2}.graph-node.selected rect{stroke:var(--green);stroke-width:3}.graph-node.issue rect{fill:#fffaf0;stroke:#c98a2c}.graph-node text{pointer-events:none}.node-label{font-size:12px;font-weight:750}.node-kind{font-size:10px;fill:var(--muted)}.node-count{font-size:10px;fill:var(--green);font-weight:800}.empty{padding:32px;text-align:center;color:var(--muted)}.side{position:sticky;top:14px;align-self:start}.detail-title{font:700 22px Georgia,serif;margin:4px 0}.detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:12px 0;margin:14px 0}.detail-grid b{display:block;font-size:19px}.detail-grid span{color:var(--muted);font-size:11px}.path{overflow-wrap:anywhere;color:var(--muted);font-size:12px}.list{list-style:none;margin:10px 0 0;padding:0}.list li{border-top:1px solid var(--line);padding:8px 0;font-size:12px}.run{margin-top:14px}.run-summary{display:flex;gap:8px;flex-wrap:wrap;margin:12px 0}.chip{border:1px solid var(--line);border-radius:999px;padding:5px 9px;color:var(--muted);font-size:12px}.chip b{color:var(--ink)}.finding{border-top:1px solid var(--line);padding:14px 0}.finding-head{display:flex;justify-content:space-between;gap:10px}.finding h3{margin:0;font-size:14px}.finding p{margin:5px 0;color:var(--muted)}.finding ul{margin:8px 0 0;padding-left:18px;color:var(--muted);font-size:12px}.coverage-row{display:grid;grid-template-columns:170px 1fr 90px;gap:10px;align-items:center;border-top:1px solid var(--line);padding:10px 0;font-size:12px}.bar{height:7px;background:#e7ece8;border-radius:99px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green)}.bar i.partial{background:var(--amber)}.bar i.none{background:var(--red)}.metadata{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:14px}.metadata div{border-top:1px solid var(--line);padding-top:8px;color:var(--muted);font-size:12px;overflow-wrap:anywhere}.metadata b{display:block;color:var(--ink);font-size:11px;text-transform:uppercase;letter-spacing:.08em;margin-bottom:3px}.hidden{display:none!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(max-width:900px){.summary{grid-template-columns:repeat(3,minmax(0,1fr))}.insights{grid-template-columns:repeat(2,minmax(0,1fr))}.workspace{grid-template-columns:1fr}.side{position:static}.run-meta{display:none}}@media(max-width:560px){.shell{padding:14px}.summary{grid-template-columns:repeat(2,minmax(0,1fr))}.insights{grid-template-columns:1fr}.masthead{display:block}.filters input{min-width:0;width:100%}.filters label:first-child{width:100%}.metadata{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important}}
|
|
3677
|
+
*{box-sizing:border-box}body{margin:0;background:var(--paper);color:var(--ink);font:14px/1.5 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}button,input,select{font:inherit}button{cursor:pointer}a{color:var(--blue)}.shell{max-width:1500px;margin:auto;padding:24px}.masthead{display:flex;justify-content:space-between;gap:24px;align-items:flex-end;border-bottom:1px solid var(--line);padding:8px 0 24px}.eyebrow{color:var(--green);font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase}.masthead h1{font:700 clamp(28px,4vw,52px)/1.03 Georgia,serif;letter-spacing:-.04em;margin:8px 0}.lede{color:var(--muted);font-size:16px;max-width:720px;margin:0}.run-meta{text-align:right;color:var(--muted);font-size:12px}.run-meta strong{display:block;color:var(--green);font-size:14px}.read-only{border:1px solid #b9d7c6;background:#edf8f0;color:#185b3b;border-radius:999px;display:inline-flex;padding:4px 10px;font-weight:700;font-size:12px}.summary{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin:20px 0}.metric,.insight,.panel{background:var(--panel);border:1px solid var(--line);box-shadow:var(--shadow);border-radius:14px}.metric{padding:16px}.metric b{font-size:27px;display:block;line-height:1}.metric span{color:var(--muted);display:block;margin-top:7px}.metric.warn b{color:var(--amber)}.metric.bad b{color:var(--red)}.lens-bar{display:flex;align-items:center;justify-content:space-between;gap:14px;margin:22px 0 12px}.tabs{display:flex;gap:4px;flex-wrap:wrap}.tab,.level{border:1px solid transparent;background:transparent;border-radius:8px;padding:8px 11px;color:var(--muted)}.tab:hover,.level:hover{background:#e8eee9;color:var(--ink)}.tab[aria-selected=true],.level[aria-pressed=true]{background:var(--ink);color:#fff}.filters{display:flex;gap:8px;flex-wrap:wrap;margin:12px 0}.filters label{color:var(--muted);font-size:12px;display:flex;align-items:center;gap:6px}.filters input,.filters select,.filters button{border:1px solid var(--line);background:#fff;border-radius:8px;padding:8px 10px;color:var(--ink)}.filters input{min-width:220px}.filters button{color:var(--blue)}.insights{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:14px 0 20px}.insight{padding:14px}.insight h3{font-size:13px;margin:0 0 5px}.insight p{color:var(--muted);margin:0;font-size:12px}.tag{display:inline-block;border-radius:999px;padding:2px 7px;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;background:#edf0ee;color:var(--muted)}.tag.heuristic{background:#fff3dc;color:#8a570a}.tag.error{background:#fde8e6;color:var(--red)}.tag.warn{background:#fff2d9;color:var(--amber)}.tag.info{background:#e6f1f5;color:var(--blue)}.workspace{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:14px}.panel{padding:18px}.panel h2{font:700 23px Georgia,serif;margin:0}.panel h3{font-size:14px;margin:0}.panel-head{display:flex;justify-content:space-between;gap:12px;align-items:flex-start;margin-bottom:14px}.subtle{color:var(--muted);font-size:12px}.map-wrap{border:1px solid var(--line);border-radius:10px;overflow:auto;background:linear-gradient(135deg,#fbfcfa,#f0f5f0)}#graph{display:block;width:100%;min-width:760px;height:560px}.edge{stroke:#b8c6bd;stroke-width:1.3;opacity:.65}.edge.alert{stroke:#d08a35;stroke-width:2}.edge-label{fill:var(--muted);font-size:10px}.graph-node{cursor:pointer}.graph-node rect{fill:#fff;stroke:#9eb0a4;stroke-width:1.2}.graph-node:hover rect,.graph-node:focus rect{stroke:var(--blue);stroke-width:2}.graph-node.selected rect{stroke:var(--green);stroke-width:3}.graph-node.issue rect{fill:#fffaf0;stroke:#c98a2c}.graph-node text{pointer-events:none}.node-label{font-size:12px;font-weight:750}.node-kind{font-size:10px;fill:var(--muted)}.node-count{font-size:10px;fill:var(--green);font-weight:800}.empty{padding:32px;text-align:center;color:var(--muted)}.side{position:sticky;top:14px;align-self:start}.detail-title{font:700 22px Georgia,serif;margin:4px 0}.detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:12px 0;margin:14px 0}.detail-grid b{display:block;font-size:19px}.detail-grid span{color:var(--muted);font-size:11px}.path{overflow-wrap:anywhere;color:var(--muted);font-size:12px}.list{list-style:none;margin:10px 0 0;padding:0}.list li{border-top:1px solid var(--line);padding:8px 0;font-size:12px}.run{margin-top:14px}.run-summary{display:flex;gap:8px;flex-wrap:wrap;margin:12px 0}.chip{border:1px solid var(--line);border-radius:999px;padding:5px 9px;color:var(--muted);font-size:12px}.chip b{color:var(--ink)}.finding{border-top:1px solid var(--line);padding:14px 0}.finding-head{display:flex;justify-content:space-between;gap:10px}.finding h3{margin:0;font-size:14px}.finding p{margin:5px 0;color:var(--muted)}.finding ul{margin:8px 0 0;padding-left:18px;color:var(--muted);font-size:12px}.coverage-row{display:grid;grid-template-columns:170px 1fr 90px;gap:10px;align-items:center;border-top:1px solid var(--line);padding:10px 0;font-size:12px}.bar{height:7px;background:#e7ece8;border-radius:99px;overflow:hidden}.bar i{display:block;height:100%;background:var(--green)}.bar i.partial{background:var(--amber)}.bar i.none{background:var(--red)}.metadata{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:14px}.metadata div{border-top:1px solid var(--line);padding-top:8px;color:var(--muted);font-size:12px;overflow-wrap:anywhere}.metadata b{display:block;color:var(--ink);font-size:11px;text-transform:uppercase;letter-spacing:.08em;margin-bottom:3px}.hidden{display:none!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(max-width:900px){.summary{grid-template-columns:repeat(3,minmax(0,1fr))}.insights{grid-template-columns:repeat(2,minmax(0,1fr))}.workspace{grid-template-columns:1fr}.side{position:static}.run-meta{display:none}}@media(max-width:560px){.shell{padding:14px}.summary{grid-template-columns:repeat(2,minmax(0,1fr))}.insights{grid-template-columns:1fr}.masthead{display:block}.filters input{min-width:0;width:100%}.filters label:first-child{width:100%}.metadata{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important}}@media(prefers-color-scheme:dark){:root{color-scheme:dark;--ink:#edf5ef;--muted:#a8b8ae;--paper:#111815;--panel:#18221d;--line:#304037;--green:#6dd19c;--blue:#7dc4dc;--amber:#efb866;--red:#f08a80;--shadow:0 12px 32px rgba(0,0,0,.24)}.map-wrap{background:linear-gradient(135deg,#19231d,#101611)}.filters input,.filters select,.filters button{background:#1d2922;color:var(--ink)}.graph-node rect{fill:#1b2820;stroke:#719080}.graph-node.issue rect{fill:#332c1d}}
|
|
3678
|
+
`;
|
|
3679
|
+
styles += String.raw`
|
|
3680
|
+
:root{--ink:#182b2b;--muted:#536664;--paper:#efe9df;--panel:#f8f5ee;--line:#c8c8b9;--green:#176b51;--blue:#155a68;--amber:#93530b;--red:#9b302b;--shadow:none}
|
|
3681
|
+
*{box-sizing:border-box}body{background:var(--paper);font-family:"Avenir Next","Segoe UI",ui-sans-serif,system-ui,sans-serif;font-size:14px;line-height:1.5}.shell{max-width:1720px;padding:30px clamp(20px,4vw,64px) 56px}.masthead{align-items:flex-start;border-bottom:2px solid var(--ink);padding:4px 0 28px}.masthead>div:first-child{max-width:840px}.eyebrow{font-size:10px;letter-spacing:.16em}.masthead h1{font-family:"Iowan Old Style",Georgia,serif;font-size:clamp(3rem,7vw,7.2rem);letter-spacing:-.075em;line-height:.9;margin:16px 0 20px}.lede{font-size:17px;line-height:1.45;max-width:650px}.run-meta{padding-top:3px;min-width:210px}.read-only{border:0;border-radius:0;padding:0;background:none;color:var(--green);font-size:10px;letter-spacing:.1em;text-transform:uppercase}.run-meta strong{color:var(--ink);font-size:12px;overflow-wrap:anywhere;margin-top:16px}.summary{grid-template-columns:repeat(5,minmax(0,1fr));gap:0;margin:0;padding:18px 0 22px;border-bottom:1px solid var(--line)}.metric{border:0;border-left:1px solid var(--line);border-radius:0;background:none;box-shadow:none;padding:0 18px}.metric:first-child{border-left:0;padding-left:0}.metric b{font-family:"Iowan Old Style",Georgia,serif;font-size:38px;letter-spacing:-.05em}.metric span{font-size:11px;letter-spacing:.07em;text-transform:uppercase}.lens-bar{align-items:flex-end;margin:42px 0 6px}.tabs{gap:0}.tab,.level{border:0;border-bottom:2px solid transparent;border-radius:0;background:transparent;color:var(--muted);padding:8px 14px;min-height:38px;font-weight:700}.tab:first-child,.level:first-child{padding-left:0}.tab:hover,.level:hover{background:none;color:var(--ink);border-color:var(--line)}.tab[aria-selected=true],.level[aria-pressed=true]{background:none;color:var(--ink);border-color:var(--green)}.lens-bar>.subtle{max-width:430px;text-align:right}.filters{border-block:1px solid var(--line);padding:14px 0;margin:12px 0 24px}.filters input,.filters select,.filters button{border:1px solid var(--line);border-radius:3px;background:var(--panel);min-height:38px}.filters button{font-weight:700}.insights{grid-template-columns:repeat(4,minmax(0,1fr));gap:0;border-top:1px solid var(--line);border-bottom:1px solid var(--line);margin:18px 0 30px}.insight{border:0;border-left:1px solid var(--line);border-radius:0;background:none;box-shadow:none;padding:14px 16px 16px}.insight:first-child{border-left:0;padding-left:0}.insight h3{font-size:12px;letter-spacing:.02em}.insight p{font-size:13px}.tag{border-radius:2px;padding:2px 5px;font-size:9px}.workspace{grid-template-columns:minmax(0,1fr) 350px;gap:24px}.panel{border:1px solid var(--line);border-radius:3px;background:var(--panel);box-shadow:none;padding:24px}.panel h2{font-family:"Iowan Old Style",Georgia,serif;font-size:30px;letter-spacing:-.04em}.map-wrap{border:1px solid #aeb9ae;border-radius:2px;background-color:#e8eee7;background-image:linear-gradient(rgba(24,43,43,.07) 1px,transparent 1px),linear-gradient(90deg,rgba(24,43,43,.07) 1px,transparent 1px);background-size:24px 24px}.map-wrap::-webkit-scrollbar{height:10px}.map-wrap::-webkit-scrollbar-thumb{background:var(--line)}#graph{height:620px}.graph-node rect{fill:#f8f5ee;stroke:#274744;stroke-width:1.4;rx:2}.graph-node:hover rect,.graph-node:focus rect{stroke:var(--blue);stroke-width:2.5}.graph-node.selected rect{fill:#dceee1;stroke:var(--green);stroke-width:3}.graph-node.issue rect{fill:#fff0d4;stroke:var(--amber)}.edge{stroke:#69857d;stroke-width:1.5;opacity:.8}.edge.alert{stroke:var(--amber);stroke-width:2.5}.edge-label{fill:var(--ink);font-size:10px;font-weight:700}.node-label{font-size:12px;font-weight:800}.node-kind{font-size:10px;fill:var(--muted)}.node-count{font-size:10px;fill:var(--green);font-weight:800}.side{top:20px}.side .panel-head{border-bottom:1px solid var(--line);padding-bottom:14px}.detail-title{font-family:"Iowan Old Style",Georgia,serif;font-size:28px}.detail-grid{gap:0}.detail-grid>div{border-left:1px solid var(--line);padding-left:10px}.detail-grid>div:nth-child(odd){border-left:0;padding-left:0}.detail-grid b{font-family:"Iowan Old Style",Georgia,serif;font-size:26px}.run{margin-top:24px}.run-summary{border-bottom:1px solid var(--line);padding-bottom:12px}.chip{border:0;border-left:1px solid var(--line);border-radius:0;padding:2px 10px}.chip:first-child{border-left:0;padding-left:0}.finding-groups{grid-template-columns:repeat(2,minmax(0,1fr));gap:0}.finding-group{border:0;border-top:1px solid var(--line);border-radius:0;background:none;padding:16px 14px 16px 0}.finding-group:nth-child(even){padding-left:14px;border-left:1px solid var(--line)}.finding-group h3{font-size:13px;letter-spacing:.02em}.finding-detail{border-top:2px solid var(--ink)}.finding{padding:16px 0}.metadata{gap:24px;margin-top:26px}.metadata div{border-top:1px solid var(--line);padding-top:9px}.map-wrap,.panel,.finding-group,.insight{transition:background-color .16s ease,border-color .16s ease}@media(max-width:900px){.masthead{display:block}.run-meta{padding-top:24px;text-align:left}.summary{grid-template-columns:repeat(3,minmax(0,1fr));row-gap:18px}.metric:nth-child(4){border-left:0;padding-left:0}.workspace{grid-template-columns:1fr}.side{position:static}.lens-bar{display:block}.lens-bar>.subtle{text-align:left;margin-top:10px}.finding-groups{grid-template-columns:1fr}.finding-group:nth-child(even){padding-left:0;border-left:0}}@media(max-width:560px){.shell{padding:20px 16px 40px}.masthead h1{font-size:clamp(3rem,16vw,5rem)}.summary{grid-template-columns:repeat(2,minmax(0,1fr))}.metric:nth-child(odd){border-left:0;padding-left:0}.metric:nth-child(even){border-left:1px solid var(--line);padding-left:12px}.insights{grid-template-columns:1fr}.insight,.insight:first-child{border-left:0;border-top:1px solid var(--line);padding-left:0}.insight:first-child{border-top:0}.panel{padding:16px}.panel-head{display:block}.panel-head>.tabs{margin-top:12px}.filters label{width:100%}.filters input,.filters select{width:100%}.metadata{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){.map-wrap,.panel,.finding-group,.insight{transition:none}}@media(prefers-color-scheme:dark){:root{--ink:#e8eee7;--muted:#b0beb3;--paper:#131c1a;--panel:#1b2824;--line:#42534b;--green:#72d09d;--blue:#86cfe1;--amber:#f0bc6b;--red:#ff9186}.map-wrap{background-color:#17231e;background-image:linear-gradient(rgba(232,238,231,.07) 1px,transparent 1px),linear-gradient(90deg,rgba(232,238,231,.07) 1px,transparent 1px)}.graph-node rect{fill:#1c2b25;stroke:#90aa99}.graph-node.selected rect{fill:#294936}.graph-node.issue rect{fill:#40321e}.filters input,.filters select,.filters button{background:#202f29;color:var(--ink)}}
|
|
3567
3682
|
`;
|
|
3683
|
+
styles += String.raw`.graph-node .node-label,.graph-node text.node-label{fill:var(--ink)}.graph-node .node-kind{fill:var(--muted)}.edge-label{fill:var(--ink)}@media(max-width:1100px){.workspace{grid-template-columns:1fr}.side{position:static}.map-wrap #graph{min-width:0!important;width:100%!important}.panel-head>.tabs{margin-top:12px}}@media(max-width:700px){.summary{grid-template-columns:repeat(2,minmax(0,1fr))}.lens-bar{display:block}.lens-bar>.subtle{text-align:left;margin-top:10px}.filters label{width:100%}.filters input,.filters select{width:100%}.finding-groups{grid-template-columns:1fr}.finding-group:nth-child(even){padding-left:0;border-left:0}}`;
|
|
3684
|
+
styles += String.raw`.level{display:none!important}.report-tabs{display:flex;gap:0;align-items:flex-end;border-bottom:1px solid var(--line);margin:24px 0 0}.report-tabs .tab{font-size:13px}.breadcrumbs{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin:0 0 14px;color:var(--muted);font-size:12px}.breadcrumbs button{border:0;background:none;color:var(--blue);padding:3px 0;font-weight:700}.breadcrumbs button:hover{text-decoration:underline}.breadcrumbs .current{color:var(--ink);font-weight:700}.scope-note{margin:0 0 12px}.report-dashboard{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(280px,1fr);gap:24px}.report-table{width:100%;border-collapse:collapse;font-size:12px}.report-table th,.report-table td{border-top:1px solid var(--line);padding:10px 8px;text-align:left;vertical-align:top}.report-table th{color:var(--muted);font-size:10px;letter-spacing:.08em;text-transform:uppercase}.report-table td:first-child{font-weight:750}.bar-list{display:grid;gap:10px}.bar-item{display:grid;grid-template-columns:minmax(120px,1fr) 2fr auto;gap:10px;align-items:center;font-size:12px}.bar-item i{height:8px;background:var(--line);display:block;overflow:hidden}.bar-item i b{display:block;height:100%;background:var(--green)}.map-wrap{touch-action:none;cursor:grab}.map-wrap.dragging{cursor:grabbing}@media(max-width:700px){.report-tabs{overflow:auto}.report-tabs .tab{white-space:nowrap}.report-dashboard{grid-template-columns:1fr}.bar-item{grid-template-columns:minmax(100px,1fr) 1fr auto}}`;
|
|
3685
|
+
styles += String.raw`body[data-report-view="architecture"] #insights,body[data-report-view="architecture"] .filters,body[data-report-view="architecture"] .run,body[data-report-view="architecture"] .metadata{display:none}body[data-report-view="insights"] .workspace,body[data-report-view="insights"] .filters,body[data-report-view="insights"] .run,body[data-report-view="insights"] .metadata{display:none}body[data-report-view="findings"] .workspace,body[data-report-view="findings"] #insights,body[data-report-view="findings"] #report-dashboard,body[data-report-view="findings"] #coverage-title,body[data-report-view="findings"] #coverage-title~*{display:none}body[data-report-view="findings"] .run[aria-labelledby="coverage-title"]{display:none}body[data-report-view="coverage"] .workspace,body[data-report-view="coverage"] #insights,body[data-report-view="coverage"] #report-dashboard,body[data-report-view="coverage"] .filters,body[data-report-view="coverage"] .run[aria-labelledby="run-title"],body[data-report-view="coverage"] .metadata{display:none}body[data-report-view="insights"] #report-dashboard{display:block}body[data-report-view="map"] #report-dashboard{display:none}`;
|
|
3686
|
+
styles += String.raw`body[data-report-view="architecture"] #report-dashboard{display:none!important}.edge{fill:none}`;
|
|
3687
|
+
styles += String.raw`:root{--ink:#17251f;--muted:#586b63;--paper:#f2f5f1;--panel:#fbfcf9;--line:#c9d5cc;--green:#13734a;--blue:#155f78;--amber:#995d08;--red:#a52e2b}html,body{max-width:100%;overflow-x:hidden}body{font-size:15px;line-height:1.55}.shell{width:100%;max-width:1600px;margin:0 auto;padding:28px clamp(16px,3vw,48px) 56px}.masthead{gap:32px;padding:0 0 24px;align-items:flex-start}.masthead h1{font-size:clamp(2.8rem,5.5vw,5.4rem);line-height:.94;margin:12px 0 16px;max-width:100%;overflow-wrap:anywhere}.lede{max-width:60ch;font-size:16px}.run-meta{min-width:0;max-width:300px}.summary{margin:0;padding:18px 0 20px;grid-template-columns:repeat(5,minmax(0,1fr));gap:0}.metric{min-width:0;padding:0 16px;border-inline-start:1px solid var(--line)}.metric:first-child{padding-inline-start:0;border-inline-start:0}.metric b{font-size:clamp(1.8rem,3vw,3rem);max-width:100%;overflow-wrap:anywhere}.metric span{font-size:10px;letter-spacing:.06em;line-height:1.25}.lens-bar{margin:24px 0 4px;align-items:flex-end}.lens-bar>.subtle{max-width:52ch}.report-tabs{max-width:100%;overflow-x:auto}.tab,.level{min-height:40px;padding:8px 12px}.filters{max-width:100%;align-items:center}.filters label{min-width:0}.filters input,.filters select{max-width:100%;min-width:0}.workspace{min-width:0;grid-template-columns:minmax(0,1fr) minmax(280px,340px);gap:20px}.panel{min-width:0}.map-wrap{min-width:0;max-width:100%;width:100%;overflow:hidden;contain:layout paint}#graph{display:block;width:100%!important;min-width:0!important;max-width:100%;height:clamp(480px,60vh,680px)!important}.side{min-width:0}.detail-title,.path,.list,.finding,.finding-group,.report-table{min-width:0;overflow-wrap:anywhere}.report-dashboard{min-width:0}.report-table{table-layout:fixed}.report-table th,.report-table td{overflow-wrap:anywhere}.bar-item{min-width:0}.bar-item span{min-width:0;overflow-wrap:anywhere}.tab:focus-visible,.level:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid var(--blue);outline-offset:2px}@media(max-width:1100px){.workspace{grid-template-columns:1fr}.side{position:static}.summary{grid-template-columns:repeat(3,minmax(0,1fr));row-gap:16px}.summary .metric:nth-child(4){border-inline-start:0;padding-inline-start:0}}@media(max-width:700px){.shell{padding:12px 16px 32px}.masthead{padding-bottom:14px}.masthead h1{font-size:clamp(2.2rem,11vw,3.4rem);margin:6px 0 10px}.lede{font-size:14px;line-height:1.35}.run-meta{display:none}.summary{padding:10px 0 12px;grid-template-columns:repeat(2,minmax(0,1fr));row-gap:8px}.summary .metric:nth-child(even){border-inline-start:1px solid var(--line);padding-inline-start:12px}.summary .metric:nth-child(odd){border-inline-start:0;padding-inline-start:0}.metric{padding-inline:10px}.metric b{font-size:1.65rem}.lens-bar{display:block;margin-top:14px}.lens-bar>.subtle{display:none}.filters{display:grid;grid-template-columns:1fr;gap:10px}.filters label{display:grid;grid-template-columns:1fr;gap:5px}.filters input,.filters select,.filters button{width:100%;min-height:44px}.panel{padding:16px}.panel-head{display:block}.panel-head>.tabs{margin-top:12px}.finding-groups{grid-template-columns:1fr}.report-dashboard{grid-template-columns:1fr}#graph{height:520px!important}.lens-bar + #lens-caption{margin:8px 0}.lens-bar + #lens-caption + #insights{margin-top:8px}}@media(prefers-color-scheme:dark){:root{--ink:#edf5ef;--muted:#b7c6ba;--paper:#111815;--panel:#1a2821;--line:#405248;--green:#73d19d;--blue:#8bd1e6;--amber:#f0bd70;--red:#ff9389}}`;
|
|
3688
|
+
styles += String.raw`@media(max-width:700px){.map-wrap{overflow:auto;contain:layout paint}#graph{width:720px!important;min-width:720px!important;max-width:none!important}}`;
|
|
3689
|
+
styles += String.raw`#lens-caption + p.subtle{display:none}`;
|
|
3568
3690
|
var script = String.raw`
|
|
3569
3691
|
const data=${"${DATA}"};
|
|
3570
|
-
|
|
3571
|
-
const
|
|
3572
|
-
const
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
const
|
|
3576
|
-
const
|
|
3577
|
-
|
|
3578
|
-
const
|
|
3692
|
+
data.entities=data.entities||[];data.relations=data.relations||[];data.diagnostics=data.diagnostics||[];
|
|
3693
|
+
const policySuffix=data.requiredRelationKinds===undefined?"Policy: all observed relation kinds require declarations.":data.requiredRelationKinds.length?"Policy: declarations required for "+data.requiredRelationKinds.join(", ")+".":"Policy: missing relation declarations disabled; stale, conflicting, and unresolved declarations remain checked.";
|
|
3694
|
+
const ensurePolicyNote=()=>{const note=document.querySelector("#map-note");if(note&&!note.textContent.includes(policySuffix))note.textContent=(note.textContent+" · "+policySuffix).trim()};
|
|
3695
|
+
new MutationObserver(ensurePolicyNote).observe(document.querySelector("#map-note"),{childList:true,characterData:true});
|
|
3696
|
+
const lazyChunks=globalThis.__DOC_BRIDGE_LAZY_CHUNKS__||[],loadedChunks=new Set(),loadingChunks=new Map();
|
|
3697
|
+
const esc=(value)=>String(value??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll("\"",""").replaceAll("'","'");
|
|
3698
|
+
const byId=new Map(),parent=new Map(),relationById=new Map(),packageMembers=new Map(),findingIndex=new Map(),relationFindingIndex=new Map(),relationsByEntity=new Map(),groupEntityIds=new Map(),groupFindingCounts=new Map(),packageCache=new Map(),nodeIssueCache=new Map();
|
|
3699
|
+
const groupById=new Map(Object.entries(data.view?.groups||{}));
|
|
3700
|
+
const addFinding=(index,id,finding)=>{const values=index.get(id)||[];values.push(finding);index.set(id,values)};
|
|
3701
|
+
const addRelation=(id,relation)=>{const values=relationsByEntity.get(id)||[];values.push(relation);relationsByEntity.set(id,values)};
|
|
3702
|
+
const hydrate=()=>{byId.clear();parent.clear();relationById.clear();packageMembers.clear();findingIndex.clear();relationFindingIndex.clear();relationsByEntity.clear();groupEntityIds.clear();groupFindingCounts.clear();packageCache.clear();nodeIssueCache.clear();data.entities.forEach((entity)=>{byId.set(entity.id,entity);const groupId=data.view?.entityGroup?.[entity.id];if(groupId){const ids=groupEntityIds.get(groupId)||new Set();ids.add(entity.id);groupEntityIds.set(groupId,ids)}});data.relations.forEach((relation)=>{relationById.set(relation.id,relation);addRelation(relation.from,relation);addRelation(relation.to,relation);if(relation.kind==="contains"){if(!parent.has(relation.to))parent.set(relation.to,relation.from);const members=packageMembers.get(relation.from)||new Set();members.add(relation.to);packageMembers.set(relation.from,members)}});data.diagnostics.forEach((finding)=>{(finding.entityIds||[]).forEach((id)=>addFinding(findingIndex,id,finding));(finding.relationIds||[]).forEach((id)=>addFinding(relationFindingIndex,id,finding));const scopes=new Set();(finding.entityIds||[]).forEach((id)=>{const scope=data.view?.entityGroup?.[id];if(scope)scopes.add(scope)});(finding.relationIds||[]).forEach((id)=>{const relation=relationById.get(id);if(!relation)return;[relation.from,relation.to].forEach((endpoint)=>{const scope=data.view?.entityGroup?.[endpoint];if(scope)scopes.add(scope)})});scopes.forEach((scope)=>groupFindingCounts.set(scope,(groupFindingCounts.get(scope)||0)+1))})};
|
|
3703
|
+
const hasChunk=(name)=>!lazyChunks.includes(name)||loadedChunks.has(name);
|
|
3704
|
+
const loadChunk=(name)=>{if(hasChunk(name))return Promise.resolve();if(loadingChunks.has(name))return loadingChunks.get(name);const promise=new Promise((resolve,reject)=>{const element=document.createElement("script");element.src=name;element.onload=()=>{loadedChunks.add(name);hydrate();resolve()};element.onerror=()=>reject(new Error("Unable to load offline report chunk: "+name));document.head.append(element)});loadingChunks.set(name,promise);return promise};
|
|
3705
|
+
const readHash=()=>new URLSearchParams(location.hash.slice(1));
|
|
3706
|
+
const hash=readHash();
|
|
3707
|
+
const state={lens:hash.get("lens")||"architecture",level:hash.get("level")||"overview",selected:hash.get("selected"),query:hash.get("query")||"",status:hash.get("status")||"",severity:hash.get("severity")||"",findingGroup:hash.get("findingGroup"),findingPage:Number(hash.get("findingPage")||0)};
|
|
3708
|
+
const syncHash=()=>{const params=new URLSearchParams();[["lens",state.lens,"architecture"],["level",state.level,"overview"],["selected",state.selected,""],["query",state.query,""],["status",state.status,""],["severity",state.severity,""],["findingGroup",state.findingGroup,""],["findingPage",state.findingPage,"0"]].forEach(([key,value,defaultValue])=>{if(value&&value!==defaultValue)params.set(key,String(value))});const next=params.toString();try{if(location.hash.slice(1)!==next)history.replaceState(null,"",next?"#"+next:"")}catch{}};
|
|
3579
3709
|
const rootOf=(id)=>{let current=id;const seen=new Set();while(parent.has(current)&&!seen.has(current)){seen.add(current);current=parent.get(current)}return current};
|
|
3580
|
-
const
|
|
3581
|
-
const groupFor=(id)=>
|
|
3582
|
-
const
|
|
3583
|
-
const
|
|
3584
|
-
const
|
|
3585
|
-
const
|
|
3710
|
+
const packageOf=(id)=>{if(packageCache.has(id))return packageCache.get(id);let current=id;const seen=new Set();while(current&&!seen.has(current)){seen.add(current);if(byId.get(current)?.kind==="package"){packageCache.set(id,current);return current}current=parent.get(current)}packageCache.set(id,id);return id};
|
|
3711
|
+
const groupFor=(id)=>data.view?.entityGroup?.[id]||id;
|
|
3712
|
+
const packageNodes=()=>data.entities.filter((entity)=>entity.kind==="package");
|
|
3713
|
+
const viewLabels={architecture:"Architecture",drift:"Insights",risks:"Findings",evidence:"Coverage"};
|
|
3714
|
+
const ensureReportChrome=()=>{document.querySelectorAll(".tab[data-lens]").forEach((tab)=>{tab.textContent=viewLabels[tab.dataset.lens]||tab.dataset.lens;tab.closest(".tabs")?.classList.add("report-tabs")});let breadcrumbs=document.querySelector("#breadcrumbs");if(!breadcrumbs){breadcrumbs=document.createElement("nav");breadcrumbs.id="breadcrumbs";breadcrumbs.className="breadcrumbs";breadcrumbs.setAttribute("aria-label","Report location");document.querySelector(".workspace")?.before(breadcrumbs)}return breadcrumbs};
|
|
3715
|
+
const label=(entity)=>entity?.name||entity?.id||"Unknown";
|
|
3716
|
+
const short=(value,max)=>{const text=String(value??""),limit=text==="External dependencies"?16:max;return text.length>limit?text.slice(0,limit-1)+"…":text};
|
|
3717
|
+
const renderBreadcrumbs=()=>{const breadcrumbs=ensureReportChrome(),items=[{label:"Repository",selected:"",level:"overview"}];if(state.selected){const group=groupById.get(state.selected),entity=byId.get(state.selected);if(group)items.push({label:group.name,selected:group.id,level:"package"});else if(entity){const packageId=packageOf(entity.id),packageEntity=byId.get(packageId),groupId=groupFor(packageId);if(groupById.has(groupId))items.push({label:groupById.get(groupId).name,selected:groupId,level:"package"});if(packageEntity&&packageEntity.id!==entity.id)items.push({label:label(packageEntity),selected:packageEntity.id,level:"module"});items.push({label:label(entity),selected:entity.id,level:state.level})}}breadcrumbs.innerHTML=items.map((item,index)=>{const separator="<span aria-hidden=\"true\">"+(index?" / ":"")+"</span>";if(index===items.length-1)return separator+"<span class=\"current\">"+esc(item.label)+"</span>";return separator+"<button type=\"button\" data-breadcrumb-selected=\""+esc(item.selected)+"\" data-breadcrumb-level=\""+esc(item.level)+"\">"+esc(item.label)+"</button>"}).join("")};
|
|
3586
3718
|
const degreeMap=(relations)=>{const degrees=new Map();relations.forEach((relation)=>{degrees.set(relation.from,(degrees.get(relation.from)||0)+1);degrees.set(relation.to,(degrees.get(relation.to)||0)+1)});return degrees};
|
|
3587
|
-
const
|
|
3588
|
-
const
|
|
3589
|
-
const
|
|
3590
|
-
const
|
|
3591
|
-
const
|
|
3592
|
-
const
|
|
3593
|
-
const
|
|
3594
|
-
const
|
|
3595
|
-
const
|
|
3596
|
-
const
|
|
3597
|
-
|
|
3598
|
-
|
|
3719
|
+
const relationHealth=(relation)=>{if(!relation)return "";const findings=relationFindingIndex.get(relation.id)||[];return findings.some((finding)=>finding.severity==="error")?"error":findings.length?"warn":""};
|
|
3720
|
+
const nodeIssues=(nodeId)=>{if(nodeIssueCache.has(nodeId))return nodeIssueCache.get(nodeId);const ids=groupEntityIds.get(nodeId)||new Set([nodeId]),findings=new Set(),relations=new Set();for(const id of ids){(findingIndex.get(id)||[]).forEach((finding)=>findings.add(finding));(relationsByEntity.get(id)||[]).forEach((relation)=>relations.add(relation))}relations.forEach((relation)=>(relationFindingIndex.get(relation.id)||[]).forEach((finding)=>findings.add(finding)));const result=[...findings];nodeIssueCache.set(nodeId,result);return result};
|
|
3721
|
+
const findingInLens=(finding)=>state.lens==="architecture"||(state.lens==="drift"&&finding.status!=="confirmed")||(state.lens==="risks"&&(finding.severity==="error"||finding.severity==="warn"))||(state.lens==="evidence"&&finding.evidence.length>0);
|
|
3722
|
+
const relationInLens=(id)=>{const findings=relationFindingIndex.get(id)||[];return findings.some(findingInLens)};
|
|
3723
|
+
const externalFor=(ids)=>{const externalIds=new Set();for(const id of ids)for(const relation of relationsByEntity.get(id)||[]){const other=relation.from===id?relation.to:relation.from;if(byId.get(other)?.kind==="external")externalIds.add(other)}return [...externalIds].map((id)=>byId.get(id)).filter(Boolean)};
|
|
3724
|
+
const nodesFor=()=>{if(state.level==="overview")return data.view?.overview?.nodes||[];const packages=packageNodes(),selectedEntity=state.selected?byId.get(state.selected):null,groupScope=state.selected&&groupById.has(state.selected)?state.selected:null,packageScope=selectedEntity?.kind==="package"?selectedEntity.id:state.selected&&!groupScope?packageOf(state.selected):null;if(state.level==="package"&&!state.selected){const packageIds=new Set(packages.map((node)=>node.id));return packages.concat(state.lens==="architecture"?[]:externalFor(packageIds))}if((state.level==="module"||state.level==="file")&&!state.selected)return[];let nodes=data.entities.filter((entity)=>{if(state.level==="package")return entity.kind==="package"&&(!groupScope||groupFor(entity.id)===groupScope)&&(!packageScope||entity.id===packageScope);if(state.level==="module")return entity.kind==="module"&&(groupScope?groupFor(entity.id)===groupScope:packageOf(entity.id)===packageScope);return Boolean(entity.path)&&(groupScope?groupFor(entity.id)===groupScope:packageOf(entity.id)===packageScope)});if(state.level==="module"&&selectedEntity?.kind==="module"){const neighborhood=new Set([selectedEntity.id]);(relationsByEntity.get(selectedEntity.id)||[]).forEach((relation)=>{if(!["imports","re-exports"].includes(relation.kind))return;if(relation.from===selectedEntity.id)neighborhood.add(relation.to);if(relation.to===selectedEntity.id)neighborhood.add(relation.from)});nodes=data.entities.filter((entity)=>entity.kind==="module"&&neighborhood.has(entity.id))}const scopedIds=new Set(nodes.map((node)=>node.id)),external=state.lens==="architecture"?[]:externalFor(scopedIds),degrees=degreeMap(data.relations);return nodes.concat(external).sort((a,b)=>(degrees.get(b.id)||0)-(degrees.get(a.id)||0)||a.id.localeCompare(b.id)).slice(0,state.level==="file"?80:60)};
|
|
3725
|
+
const graphModel=()=>{if(state.level==="overview"){const overviewNodes=data.view?.overview?.nodes||[],overviewNodeIds=new Set(overviewNodes.map((node)=>node.id)),base=(data.view?.overview?.edges||[]).filter((edge)=>overviewNodeIds.has(edge.from)&&overviewNodeIds.has(edge.to)),edges=state.lens==="architecture"?base:base.filter((edge)=>edge.relationIds.some(relationInLens)),visible=new Set(edges.flatMap((edge)=>[edge.from,edge.to]));return{nodes:state.lens==="architecture"?overviewNodes:overviewNodes.filter((node)=>visible.has(node.id)||nodeIssues(node.id).some((finding)=>findingInLens(finding))),edges:edges.map((edge)=>({...edge,health:edge.relationIds.some((id)=>relationHealth(relationById.get(id)))?"error":""}))}}const nodes=nodesFor(),ids=new Set(nodes.map((node)=>node.id)),aggregate=state.level==="package"&&(!state.selected||state.selected.startsWith("group:")),edges=new Map();data.relations.forEach((relation)=>{const essential=state.level==="package"?relation.kind==="depends-on":relation.kind==="imports"||relation.kind==="re-exports";if(relation.kind==="contains"|| (state.lens==="architecture"&&!essential)||(state.lens!=="architecture"&&!relationInLens(relation.id)))return;const from=aggregate?packageOf(relation.from):relation.from,to=aggregate?packageOf(relation.to):relation.to;if(from===to||!ids.has(from)||!ids.has(to))return;const key=from+"→"+to,current=edges.get(key)||{from,to,count:0,kinds:new Set(),relationIds:new Set(),health:""};current.count++;current.kinds.add(relation.kind);current.relationIds.add(relation.id);current.health=current.health==="error"||relationHealth(relation)==="error"?"error":current.health||relationHealth(relation);edges.set(key,current)});const visibleEdges=[...edges.values()].sort((a,b)=>b.count-a.count||a.from.localeCompare(b.from)||a.to.localeCompare(b.to));const visible=new Set(visibleEdges.flatMap((edge)=>[edge.from,edge.to]));return{nodes:state.lens==="architecture"?nodes:nodes.filter((node)=>visible.has(node.id)||nodeIssues(node.id).some((finding)=>findingInLens(finding))),edges:visibleEdges}};
|
|
3726
|
+
const renderInsights=()=>{const summary=data.diagnosticSummary||{},undocumented=summary.undocumented??data.diagnostics.filter((finding)=>finding.status==="undocumented").length,drift=summary.drift??data.diagnostics.filter((finding)=>finding.status==="stale-or-unverified"||finding.status==="conflict").length,unsupported=(data.coverage||[]).filter((entry)=>entry.status==="not-analyzed"||entry.status==="partial").length,model=graphModel(),degrees=degreeMap(model.edges),values=[...degrees.values()].sort((a,b)=>a-b),median=values.length?values[Math.floor(values.length/2)]:0,hot=[...degrees.values()].filter((value)=>value>=Math.max(4,median*2)).length,isolated=model.nodes.filter((node)=>!model.edges.some((edge)=>edge.from===node.id||edge.to===node.id)).length;document.querySelector("#insights").innerHTML=[["Documentation drift",undocumented+drift,"Relations or docs needing comparison.",""],["Unanalyzed scope",unsupported,"Coverage gaps are explicit.",""],["Connectivity hotspots",hot,"Heuristic: unusually connected nodes.","heuristic"],["Disconnected nodes",isolated,"Heuristic: no visible edge at this level.","heuristic"]].map(([title,count,copy,tag])=>"<article class=\"insight\"><h3>"+esc(title)+" <span class=\"tag "+tag+"\">"+(tag?"heuristic":"signal")+"</span></h3><p><strong>"+count+"</strong> · "+esc(copy)+"</p></article>").join("")};
|
|
3727
|
+
const renderInsightsDashboard=()=>{let dashboard=document.querySelector("#report-dashboard");if(!dashboard){dashboard=document.createElement("section");dashboard.id="report-dashboard";dashboard.className="report-dashboard";document.querySelector(".filters")?.before(dashboard)}if(!data.diagnostics.length){dashboard.innerHTML="<p class=\"empty\">Open Findings or load the findings data to calculate insights.</p>";return}const degrees=degreeMap(data.relations),groups=[...groupById.entries()].filter(([,group])=>group.kind!=="external"),rows=groups.map(([id,group])=>{const members=groupEntityIds.get(id)||new Set(),modules=[...members].filter((entityId)=>byId.get(entityId)?.kind==="module").length;return{name:group.name,packages:group.members.length,modules,findings:groupFindingCounts.get(id)||0}}).sort((a,b)=>b.findings-a.findings||a.name.localeCompare(b.name)),topPackages=[...data.entities].filter((entity)=>entity.kind==="package").map((entity)=>({name:label(entity),degree:degrees.get(entity.id)||0})).sort((a,b)=>b.degree-a.degree||a.name.localeCompare(b.name)).slice(0,10),max=Math.max(1,...topPackages.map((row)=>row.degree));dashboard.innerHTML="<section><div class=\"eyebrow\">Attention by scope</div><h2>Where the map needs a closer look</h2><table class=\"report-table\"><thead><tr><th>Scope</th><th>Packages</th><th>Modules</th><th>Findings</th></tr></thead><tbody>"+rows.map((row)=>"<tr><td>"+esc(row.name)+"</td><td>"+row.packages+"</td><td>"+row.modules+"</td><td><strong>"+row.findings+"</strong></td></tr>").join("")+"</tbody></table></section><section><div class=\"eyebrow\">Connectivity</div><h2>Most connected packages</h2><div class=\"bar-list\">"+topPackages.map((row)=>"<div class=\"bar-item\"><span>"+esc(row.name)+"</span><i><b style=\"width:"+Math.round(row.degree/max*100)+"%\"></b></i><strong>"+row.degree+"</strong></div>").join("")+"</div></section>"};
|
|
3728
|
+
const mapState={scale:1,dragging:false,x:0,y:0};
|
|
3729
|
+
const applyMapTransform=()=>{const svg=document.querySelector("#graph");if(!svg)return;svg.style.transform="translate("+mapState.x+"px,"+mapState.y+"px) scale("+mapState.scale+")";svg.style.transformOrigin="center center"};
|
|
3730
|
+
const routeGraphEdges=()=>{const svg=document.querySelector("#graph");if(!svg)return;svg.querySelectorAll("line.edge").forEach((line,index)=>{const x1=Number(line.getAttribute("x1")),y1=Number(line.getAttribute("y1")),x2=Number(line.getAttribute("x2")),y2=Number(line.getAttribute("y2")),midX=(x1+x2)/2+((index%5)-2)*14,path=document.createElementNS("http://www.w3.org/2000/svg","path");path.setAttribute("class",line.getAttribute("class")||"edge");path.setAttribute("fill","none");path.setAttribute("marker-end",line.getAttribute("marker-end")||"url(#arrow)");path.setAttribute("d","M "+x1+" "+y1+" H "+midX+" V "+y2+" H "+x2);const label=line.parentElement?.querySelector("text.edge-label");if(label){label.setAttribute("x",String(midX+3));label.setAttribute("y",String((y1+y2)/2))}line.replaceWith(path)})};
|
|
3731
|
+
const enterNode=(id)=>{const group=groupById.get(id),entity=byId.get(id);if(group){state.selected=id;state.level="package"}else if(entity?.kind==="package"){state.selected=id;state.level="module"}else if(entity?.kind==="module"){state.selected=id;state.level="file"}else return;mapState.scale=1;mapState.x=0;mapState.y=0;render()};
|
|
3732
|
+
let nodeClickTimer;
|
|
3733
|
+
document.addEventListener("dblclick",(event)=>{const node=event.target.closest?.("[data-node]");if(!node)return;event.preventDefault();event.stopImmediatePropagation();clearTimeout(nodeClickTimer);enterNode(node.dataset.node)},true);
|
|
3734
|
+
document.addEventListener("click",(event)=>{const node=event.target.closest?.("[data-node]");if(!node)return;event.preventDefault();event.stopImmediatePropagation();clearTimeout(nodeClickTimer);if(event.detail>=2){enterNode(node.dataset.node);return}nodeClickTimer=setTimeout(()=>{state.selected=node.dataset.node;render()},380)},true);
|
|
3735
|
+
document.addEventListener("click",(event)=>{const crumb=event.target.closest?.("[data-breadcrumb-level]");if(!crumb)return;event.preventDefault();event.stopImmediatePropagation();state.level=crumb.dataset.breadcrumbLevel;state.selected=crumb.dataset.breadcrumbSelected||null;mapState.scale=1;mapState.x=0;mapState.y=0;render()},true);
|
|
3736
|
+
const diagnosticsFor=(id)=>findingIndex.get(id)||[];
|
|
3737
|
+
const renderDetails=()=>{const panel=document.querySelector("#details"),entity=state.selected?byId.get(state.selected):null,group=state.selected?groupById.get(state.selected):null;if(group){const members=group.members.map((id)=>byId.get(id)).filter(Boolean),relations=new Set(),ids=groupEntityIds.get(state.selected)||new Set();ids.forEach((id)=>(relationsByEntity.get(id)||[]).forEach((relation)=>relations.add(relation)));const findings=nodeIssues(state.selected),evidence=members.flatMap((member)=>member.evidence||[]).slice(0,8),unit=group.kind==="external"?"dependencies":"packages";panel.innerHTML="<div class=\"eyebrow\">Selected group</div><h2 class=\"detail-title\">"+esc(group.name)+"</h2><span class=\"tag\">"+esc(group.kind)+"</span><p class=\"path\">"+esc(group.path||"Derived from stable package identity and repository structure")+"</p><div class=\"detail-grid\"><div><b>"+members.length+"</b><span>"+unit+"</span></div><div><b>"+relations.size+"</b><span>relations</span></div><div><b>"+findings.length+"</b><span>findings</span></div><div><b>"+evidence.length+"</b><span>evidence items</span></div></div><h3>Members</h3><ul class=\"list\">"+(members.length?members.slice(0,8).map((member)=>"<li>"+esc(label(member))+"</li>").join(""):"<li>No members recorded.</li>")+(members.length>8?"<li class=\"subtle\">+"+(members.length-8)+" more — choose Package level to inspect all.</li>":"")+"</ul>"+(findings.length?"<h3 style=\"margin-top:16px\">Attention</h3><ul class=\"list\">"+findings.slice(0,5).map((finding)=>"<li><span class=\"tag "+esc(finding.severity)+"\">"+esc(finding.severity)+"</span> "+esc(finding.code)+"</li>").join("")+"</ul>":"");return}if(!entity){panel.innerHTML="<p class=\"subtle\">Select a node in the map to inspect its evidence, connectivity, and findings.</p>";return}const relations=relationsByEntity.get(entity.id)||[],incoming=relations.filter((relation)=>relation.to===entity.id),outgoing=relations.filter((relation)=>relation.from===entity.id),findings=diagnosticsFor(entity.id),evidence=[...(entity.evidence||[]),...incoming.flatMap((relation)=>relation.evidence||[]),...outgoing.flatMap((relation)=>relation.evidence||[])].slice(0,8);panel.innerHTML="<div class=\"eyebrow\">Selected entity</div><h2 class=\"detail-title\">"+esc(label(entity))+"</h2><span class=\"tag\">"+esc(entity.kind)+"</span><p class=\"path\">"+esc(entity.path||entity.id)+"</p><div class=\"detail-grid\"><div><b>"+incoming.length+"</b><span>incoming</span></div><div><b>"+outgoing.length+"</b><span>outgoing</span></div><div><b>"+findings.length+"</b><span>findings</span></div><div><b>"+evidence.length+"</b><span>evidence items</span></div></div><h3>Evidence</h3><ul class=\"list\">"+(evidence.length?evidence.map((item)=>"<li>"+esc(item.path+(item.lineStart?":"+item.lineStart:"")+(item.context?" — "+item.context:""))+"</li>").join(""):"<li>No evidence recorded.</li>")+"</ul>"+(findings.length?"<h3 style=\"margin-top:16px\">Attention</h3><ul class=\"list\">"+findings.slice(0,5).map((finding)=>"<li><span class=\"tag "+esc(finding.severity)+"\">"+esc(finding.severity)+"</span> "+esc(finding.code)+"</li>").join("")+"</ul>":"")};
|
|
3738
|
+
const renderGraph=()=>{const model=graphModel(),svg=document.querySelector("#graph");if(!model.nodes.length){svg.innerHTML="<text x=\"500\" y=\"270\" text-anchor=\"middle\" class=\"subtle\">Select an app or package to expand this view.</text>";return}const ids=new Set(model.nodes.map((node)=>node.id)),incoming=new Map(model.nodes.map((node)=>[node.id,0])),outgoing=new Map(model.nodes.map((node)=>[node.id,[]]));model.edges.forEach((edge)=>{if(!ids.has(edge.from)||!ids.has(edge.to))return;incoming.set(edge.to,(incoming.get(edge.to)||0)+1);outgoing.get(edge.from).push(edge.to)});const rank=new Map(),work=[];model.nodes.filter((node)=>(incoming.get(node.id)||0)===0).sort((a,b)=>label(a).localeCompare(label(b))||a.id.localeCompare(b.id)).forEach((node)=>{rank.set(node.id,0);work.push(node)});for(let index=0;index<work.length;index++){const node=work[index];for(const next of outgoing.get(node.id)||[]){const nextRank=Math.max(rank.get(next)||0,(rank.get(node.id)||0)+1);rank.set(next,nextRank);if(!work.some((item)=>item.id===next))work.push(byId.get(next)||{id:next,name:next})}}model.nodes.forEach((node)=>{if(!rank.has(node.id))rank.set(node.id,0)});const columns=new Map();model.nodes.forEach((node)=>{const items=columns.get(rank.get(node.id))||[];items.push(node);columns.set(rank.get(node.id),items)});for(const items of columns.values())items.sort((a,b)=>label(a).localeCompare(label(b))||a.id.localeCompare(b.id));const maxRows=Math.max(1,...[...columns.values()].map((items)=>items.length)),cellWidth=190,cellHeight=82,pad=28,columnCount=Math.max(1,...columns.keys())+1,width=Math.max(620,columnCount*cellWidth+pad*2,Math.min(1000,svg.clientWidth*1.05)),height=Math.max(520,maxRows*cellHeight+pad*2);svg.setAttribute("viewBox","0 0 "+width+" "+height);svg.style.width="100%";svg.style.minWidth="0";svg.style.height="100%";const positions=new Map();for(const [column,items] of columns)items.forEach((node,row)=>positions.set(node.id,{x:pad+column*cellWidth+78,y:pad+row*cellHeight+27}));const defs="<defs><marker id=\"arrow\" markerWidth=\"8\" markerHeight=\"8\" refX=\"7\" refY=\"3\" orient=\"auto\"><path d=\"M0,0 L0,6 L7,3 z\" fill=\"#789087\"/></marker></defs>",edges=model.edges.map((edge)=>{const from=positions.get(edge.from),to=positions.get(edge.to);if(!from||!to)return "";const midX=(from.x+to.x)/2,midY=(from.y+to.y)/2;return "<g><line class=\"edge "+(edge.health?"alert":"")+"\" x1=\""+from.x+"\" y1=\""+from.y+"\" x2=\""+to.x+"\" y2=\""+to.y+"\" marker-end=\"url(#arrow)\"/><text class=\"edge-label\" x=\""+midX+"\" y=\""+midY+"\">"+esc(edge.count>1?edge.count+"×":"")+"</text></g>"}).join(""),nodes=model.nodes.map((node)=>{const pos=positions.get(node.id),issues=nodeIssues(node.id),degree=degreeMap(model.edges).get(node.id)||0,selected=state.selected===node.id?" selected":"",issue=issues.length?" issue":"",nodeLabel=label(node),nodeKind=node.kind==="domain"?(node.memberCount||0)+" packages":node.kind;return "<g class=\"graph-node"+selected+issue+"\" transform=\"translate("+(pos.x-78)+","+(pos.y-27)+")\"><title>"+esc(nodeLabel)+" · "+esc(nodeKind)+"</title><rect width=\"156\" height=\"54\" rx=\"8\" role=\"button\" tabindex=\"0\" aria-label=\""+esc(nodeLabel+" "+nodeKind)+"\" data-node=\""+esc(node.id)+"\"></rect><text class=\"node-label\" x=\"10\" y=\"19\">"+esc(short(nodeLabel,22))+"</text><text class=\"node-kind\" x=\"10\" y=\"34\">"+esc(short(nodeKind,22))+"</text><text class=\"node-count\" x=\"144\" y=\"19\" text-anchor=\"end\">"+(degree||"")+"</text></g>"}).join("");svg.innerHTML=defs+edges+nodes;routeGraphEdges();applyMapTransform();document.querySelector("#map-note").textContent=(state.level==="overview"?"Bounded domain view. ":state.level+" view. ")+"Directional edges are aggregated from canonical relations; "+model.edges.length+" visible connection groups."};
|
|
3739
|
+
const findingMatches=(finding)=>{const query=state.query.toLowerCase();return(!query||[finding.id,finding.code,finding.message,...finding.entityIds,...finding.relationIds].join(" ").toLowerCase().includes(query))&&(!state.status||finding.status===state.status)&&(!state.severity||finding.severity===state.severity)};
|
|
3740
|
+
const findingScope=(finding)=>{const ids=[...(finding.entityIds||[])];(finding.relationIds||[]).forEach((id)=>{const relation=relationById.get(id);if(relation)ids.push(relation.from,relation.to)});return ids.map(groupFor).sort()[0]||"repository"};
|
|
3741
|
+
const findingGroups=(findings)=>{const groups=new Map();findings.forEach((finding)=>{const scope=findingScope(finding),key=[scope,finding.code,finding.status,finding.severity].join("|"),group=groups.get(key)||{key,scope,code:finding.code,status:finding.status,severity:finding.severity,findings:[]};group.findings.push(finding);groups.set(key,group)});return[...groups.values()].sort((left,right)=>right.findings.length-left.findings.length||left.code.localeCompare(right.code)||left.key.localeCompare(right.key))};
|
|
3742
|
+
const renderFinding=(finding)=>"<article class=\"finding\" id=\""+esc("diagnostic-"+finding.id.replace(/[^A-Za-z0-9_-]+/g,"-"))+"\"><div class=\"finding-head\"><h3>"+esc(finding.code)+"</h3><span><span class=\"tag "+esc(finding.severity)+"\">"+esc(finding.severity)+"</span> <span class=\"tag\">"+esc(finding.status)+"</span></span></div><p>"+esc(finding.message)+"</p>"+(finding.evidence.length?"<ul>"+finding.evidence.slice(0,4).map((item)=>"<li>"+esc(item.path+(item.lineStart?":"+item.lineStart:"")+(item.context?" — "+item.context:""))+"</li>").join("")+"</ul>":"")+(finding.remediation?"<p><strong>Next check:</strong> "+esc(finding.remediation)+"</p>":"")+"</article>";
|
|
3743
|
+
const renderFindings=()=>{let findings=data.diagnostics.filter(findingMatches);if(state.lens==="risks")findings=findings.filter((finding)=>finding.severity==="error"||finding.severity==="warn");if(state.lens==="evidence")findings=findings.filter((finding)=>finding.evidence.length);if(state.lens==="drift")findings=findings.filter((finding)=>finding.status!=="confirmed");const groups=findingGroups(findings),active=groups.find((group)=>group.key===state.findingGroup);if(!active){state.findingGroup=null;state.findingPage=0}syncHash();const selected=active||null,pageSize=40,pageCount=selected?Math.ceil(selected.findings.length/pageSize):0,page=Math.max(0,Math.min(state.findingPage,Math.max(0,pageCount-1))),start=page*pageSize;document.querySelector("#finding-count").textContent=findings.length+" findings · "+groups.length+" groups";document.querySelector("#findings").innerHTML=findings.length?"<div class=\"finding-groups\">"+groups.map((group)=>"<article class=\"finding-group\"><div class=\"finding-head\"><h3>"+esc(group.code)+"</h3><span><span class=\"tag "+esc(group.severity)+"\">"+esc(group.severity)+"</span> <span class=\"tag\">"+esc(group.status)+"</span></span></div><p><strong>"+group.findings.length+"</strong> finding"+(group.findings.length===1?"":"s")+" · "+esc(groupById.get(group.scope)?.name||group.scope)+"</p><p>"+esc(group.findings[0].message)+"</p><button class=\"tab\" type=\"button\" data-finding-group=\""+esc(group.key)+"\" aria-expanded=\""+String(selected?.key===group.key)+"\">Inspect group</button></article>").join("")+"</div>"+(selected?"<div class=\"finding-detail\"><div class=\"finding-head\"><h3>"+esc(selected.code)+" · "+esc(groupById.get(selected.scope)?.name||selected.scope)+"</h3><span class=\"subtle\">"+selected.findings.length+" total</span></div>"+selected.findings.slice(start,start+pageSize).map(renderFinding).join("")+"<div class=\"finding-actions\"><button class=\"tab\" type=\"button\" data-finding-group=\""+esc(selected.key)+"\" data-finding-page=\""+(page-1)+"\" "+(page===0?"disabled":"")+">Previous</button><span class=\"subtle\">Showing "+(start+1)+"–"+Math.min(start+pageSize,selected.findings.length)+" of "+selected.findings.length+" · page "+(page+1)+"/"+pageCount+"</span><button class=\"tab\" type=\"button\" data-finding-group=\""+esc(selected.key)+"\" data-finding-page=\""+(page+1)+"\" "+(page+1>=pageCount?"disabled":"")+">Next</button></div></div>":""):"<p class=\"empty\">No findings match the current lens and filters.</p>"};
|
|
3744
|
+
const renderCoverage=()=>{document.querySelector("#coverage-list").innerHTML=(data.coverage||[]).map((entry)=>{const width=entry.status==="complete"?100:entry.status==="partial"?55:12;return"<div class=\"coverage-row\"><div><b>"+esc(entry.analyzer)+"</b><br><span class=\"subtle\">"+esc(entry.scope)+"</span></div><div class=\"bar\"><i class=\""+(entry.status==="complete"?"":entry.status==="partial"?"partial":"none")+"\" style=\"width:"+width+"%\"></i></div><div>"+esc(entry.status)+"</div></div>"}).join("")||"<p class=\"empty\">No coverage metadata.</p>"};
|
|
3745
|
+
const deferFindings=()=>{if(findingsLoaded())return;const count=data.diagnosticCount||0;document.querySelector("#finding-count").textContent=count+" findings · available on demand";document.querySelector("#findings").innerHTML="<div class=\"empty\"><p>Findings stay out of the first paint so large repositories remain responsive.</p><button id=\"load-findings\" class=\"tab\" type=\"button\">Load findings</button></div>"};
|
|
3746
|
+
const scopePrompt=()=>{if((state.level==="module"||state.level==="file")&&!state.selected){document.querySelector("#map-note").textContent="Select an app or package to inspect this level.";document.querySelector("#graph").innerHTML="<text x=\"500\" y=\"270\" text-anchor=\"middle\" class=\"subtle\">Select an app or package to expand this view.</text>"}};
|
|
3747
|
+
const findingsLoaded=()=>!lazyChunks.includes("chunks/findings.js")||loadedChunks.has("chunks/findings.js");
|
|
3748
|
+
const levelsLoaded=()=>!lazyChunks.includes("chunks/levels.js")||loadedChunks.has("chunks/levels.js");
|
|
3749
|
+
const setReportView=()=>{document.body.dataset.reportView={architecture:"architecture",drift:"insights",risks:"findings",evidence:"coverage"}[state.lens]||"architecture";ensureReportChrome()};
|
|
3750
|
+
const render=()=>{if(state.level!=="overview"&&!levelsLoaded()){document.querySelector("#map-note").textContent="Loading canonical entities…";loadChunk("chunks/levels.js").then(render).catch((error)=>{document.querySelector("#map-note").textContent=error.message});return}if(state.lens!=="architecture"&&!findingsLoaded()){document.querySelector("#lens-caption").textContent="Loading findings for this lens…";loadChunk("chunks/findings.js").then(render).catch((error)=>{document.querySelector("#lens-caption").textContent=error.message});return}syncHash();setReportView();renderBreadcrumbs();document.querySelectorAll(".tab[data-lens]").forEach((tab)=>tab.setAttribute("aria-selected",String(tab.dataset.lens===state.lens)));document.querySelectorAll(".level").forEach((button)=>button.setAttribute("aria-pressed",String(button.dataset.level===state.level)));document.querySelector("#lens-caption").textContent=state.lens==="architecture"?"The repository topology at the selected level.":state.lens==="drift"?"Where canonical code relations and documentation declarations need attention.":state.lens==="risks"?"Signals that deserve human review; connectivity warnings are heuristics, not architectural proof.":"What the analyzers observed, declared, or could not analyze.";renderInsights();renderInsightsDashboard();renderGraph();renderDetails();renderFindings();deferFindings();renderCoverage()};
|
|
3751
|
+
document.addEventListener("click",async(event)=>{const target=event.target.closest?.("[data-level],[data-lens],#load-findings");if(!target)return;if(target.id==="load-findings"){event.preventDefault();event.stopImmediatePropagation();await loadChunk("chunks/findings.js");render();return}if(target.dataset.level&&!levelsLoaded()){event.preventDefault();event.stopImmediatePropagation();state.level=target.dataset.level;await loadChunk("chunks/levels.js");render();return}if(target.dataset.lens&&target.dataset.lens!=="architecture"&&!findingsLoaded()){event.preventDefault();event.stopImmediatePropagation();state.lens=target.dataset.lens;state.findingGroup=null;await loadChunk("chunks/findings.js");render()}},true);
|
|
3752
|
+
document.addEventListener("click",(event)=>{const node=event.target.closest?.("[data-node]");if(!node)return;event.preventDefault();event.stopImmediatePropagation();clearTimeout(nodeClickTimer);if(event.detail>=2){enterNode(node.dataset.node);return}nodeClickTimer=setTimeout(()=>{state.selected=node.dataset.node;render()},380)},true);
|
|
3753
|
+
document.addEventListener("click",(event)=>{const crumb=event.target.closest?.("[data-breadcrumb-level]");if(!crumb)return;event.preventDefault();event.stopImmediatePropagation();state.level=crumb.dataset.breadcrumbLevel;state.selected=crumb.dataset.breadcrumbSelected||null;mapState.scale=1;mapState.x=0;mapState.y=0;render()},true);
|
|
3754
|
+
document.addEventListener("input",async(event)=>{const target=event.target;if(target?.id!=="search"||findingsLoaded())return;event.stopImmediatePropagation();state.query=target.value;state.findingGroup=null;await loadChunk("chunks/findings.js");render()},true);
|
|
3755
|
+
document.addEventListener("change",async(event)=>{const target=event.target;if(!["status","severity"].includes(target?.id)||findingsLoaded())return;event.stopImmediatePropagation();state[target.id]=target.value;state.findingGroup=null;await loadChunk("chunks/findings.js");render()},true);
|
|
3756
|
+
document.addEventListener("wheel",(event)=>{const wrap=event.target.closest?.(".map-wrap");if(!wrap)return;event.preventDefault();mapState.scale=Math.max(.65,Math.min(2.5,mapState.scale*(event.deltaY<0?1.12:.89)));applyMapTransform()},{passive:false});
|
|
3757
|
+
document.addEventListener("pointerdown",(event)=>{const wrap=event.target.closest?.(".map-wrap");if(!wrap)return;mapState.dragging=true;mapState.lastX=event.clientX;mapState.lastY=event.clientY;wrap.classList.add("dragging")},true);
|
|
3758
|
+
document.addEventListener("pointermove",(event)=>{if(!mapState.dragging)return;mapState.x+=event.clientX-mapState.lastX;mapState.y+=event.clientY-mapState.lastY;mapState.lastX=event.clientX;mapState.lastY=event.clientY;applyMapTransform()});
|
|
3759
|
+
document.addEventListener("pointerup",()=>{mapState.dragging=false;document.querySelector(".map-wrap")?.classList.remove("dragging")},true);
|
|
3760
|
+
document.addEventListener("keydown",(event)=>{if(event.target.matches?.("input,select,textarea"))return;if(event.key==="+"||event.key==="="){mapState.scale=Math.min(2.5,mapState.scale*1.15);applyMapTransform()}if(event.key==="-"){mapState.scale=Math.max(.65,mapState.scale*.87);applyMapTransform()}if(event.key==="0"){mapState.scale=1;mapState.x=0;mapState.y=0;applyMapTransform()}if(event.key==="Escape"){if(state.selected){state.selected=null}else if(state.level==="file"){state.level="module"}else if(state.level==="module"){state.level="package"}else if(state.level==="package"){state.level="overview"}render()}},true);
|
|
3761
|
+
document.querySelectorAll(".tab[data-lens]").forEach((tab)=>tab.addEventListener("click",()=>{state.lens=tab.dataset.lens;state.findingGroup=null;render()}));
|
|
3762
|
+
document.querySelectorAll(".level").forEach((button)=>button.addEventListener("click",()=>{state.level=button.dataset.level;render()}));
|
|
3763
|
+
document.querySelector("#search").addEventListener("input",(event)=>{state.query=event.target.value;state.findingGroup=null;renderFindings()});
|
|
3764
|
+
document.querySelector("#status").addEventListener("change",(event)=>{state.status=event.target.value;state.findingGroup=null;renderFindings()});
|
|
3765
|
+
document.querySelector("#severity").addEventListener("change",(event)=>{state.severity=event.target.value;state.findingGroup=null;renderFindings()});
|
|
3766
|
+
document.querySelector("#findings").addEventListener("click",(event)=>{const button=event.target.closest("[data-finding-group]");if(!button)return;state.findingGroup=button.dataset.findingGroup;state.findingPage=Number(button.dataset.findingPage||0);renderFindings()});
|
|
3767
|
+
document.querySelector("#reset").addEventListener("click",()=>{state.query="";state.status="";state.severity="";state.findingGroup=null;state.findingPage=0;renderFindings()});
|
|
3768
|
+
document.querySelector("#clear-selection").addEventListener("click",()=>{state.selected=null;render()});
|
|
3769
|
+
const keepMobileGraphReadable=()=>{const svg=document.querySelector("#graph");if(!svg)return;if(window.innerWidth<=700){svg.style.setProperty("width","720px","important");svg.style.setProperty("min-width","720px","important");svg.style.setProperty("max-width","none","important")}else{svg.style.removeProperty("width");svg.style.removeProperty("min-width");svg.style.removeProperty("max-width")}};
|
|
3770
|
+
new MutationObserver(keepMobileGraphReadable).observe(document.querySelector("#graph"),{attributes:true,attributeFilter:["style"]});
|
|
3771
|
+
window.addEventListener("resize",keepMobileGraphReadable);
|
|
3772
|
+
window.addEventListener("hashchange",()=>{const next=readHash();state.lens=next.get("lens")||"architecture";state.level=next.get("level")||"overview";state.selected=next.get("selected");state.query=next.get("query")||"";state.status=next.get("status")||"";state.severity=next.get("severity")||"";state.findingGroup=next.get("findingGroup");state.findingPage=Number(next.get("findingPage")||0);render()});
|
|
3773
|
+
hydrate();render();keepMobileGraphReadable();ensurePolicyNote();
|
|
3599
3774
|
`;
|
|
3600
3775
|
var render = (input, options) => {
|
|
3601
3776
|
const { snapshot, report } = input;
|
|
3602
3777
|
const includeSnippets = options.includeSnippets === true;
|
|
3603
3778
|
const data = reportData(snapshot, report, includeSnippets);
|
|
3604
|
-
const scriptBody = script.replace("${DATA}", embeddedJson(data));
|
|
3779
|
+
const scriptBody = script.replace("${DATA}", options.dataExpression ?? embeddedJson(data));
|
|
3605
3780
|
const largeNote = snapshot.entities.length > 500 || report.diagnostics.length > 1e3 ? "Large snapshots are rendered from compact canonical data with progressive graph levels." : "The viewer starts with a grouped topology and expands into canonical entities on demand.";
|
|
3606
3781
|
const issueCount = report.diagnostics.filter((diagnostic2) => diagnostic2.severity === "error" || diagnostic2.severity === "warn").length;
|
|
3607
3782
|
const unsupportedCount = snapshot.coverage.filter((entry) => entry.status !== "complete").length;
|
|
3783
|
+
const policyNote = report.summary.requiredRelationKinds === void 0 ? "Missing relation declarations are checked for every observed relation kind." : report.summary.requiredRelationKinds.length ? `Missing relation declarations are checked for: ${report.summary.requiredRelationKinds.join(", ")}.` : "Missing relation declarations are disabled by configuration; stale, conflicting, and unresolved declarations remain checked.";
|
|
3608
3784
|
const statusOptions = ["confirmed", "undocumented", "stale-or-unverified", "conflict", "unresolved", "not-analyzed"];
|
|
3609
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Doc Bridge \u2014 ${escapeHtml(snapshot.project.name)}</title><style>${styles}</style></head><body
|
|
3610
|
-
};
|
|
3785
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Doc Bridge \u2014 ${escapeHtml(snapshot.project.name)}</title><style>${styles}</style></head><body>${options.dataScripts ?? ""}<main class="shell"><header class="masthead"><div><div class="eyebrow">Doc Bridge / Knowledge report</div><h1>${escapeHtml(snapshot.project.name)}</h1><p class="lede">A read-only architecture and documentation map. Start broad, then follow evidence to the exact entity, relation, or finding.</p></div><div class="run-meta"><span class="read-only">Read-only snapshot</span><strong>${escapeHtml(snapshot.sourceRevision)}</strong><span>${escapeHtml(snapshot.sourceRevisionKind)} \xB7 pipeline ${escapeHtml(snapshot.pipelineVersion)}</span></div></header><section class="summary" aria-label="Snapshot summary"><div class="metric"><b>${snapshot.entities.length}</b><span>entities</span></div><div class="metric"><b>${snapshot.relations.length}</b><span>canonical relations</span></div><div class="metric ${issueCount ? "warn" : ""}"><b>${issueCount}</b><span>warn/error findings</span></div><div class="metric ${report.diagnostics.length ? "warn" : ""}"><b>${report.diagnostics.length}</b><span>total findings</span></div><div class="metric ${unsupportedCount ? "bad" : ""}"><b>${unsupportedCount}</b><span>partial / unanalyzed scopes</span></div></section><div class="lens-bar"><nav class="tabs" aria-label="Report lenses"><button class="tab" data-lens="architecture" aria-selected="true">Architecture</button><button class="tab" data-lens="drift" aria-selected="false">Documentation drift</button><button class="tab" data-lens="risks" aria-selected="false">Risks & hotspots</button><button class="tab" data-lens="evidence" aria-selected="false">Evidence</button></nav><span class="subtle">${escapeHtml(largeNote)}</span></div><p id="lens-caption" class="subtle">The repository topology at the selected level.</p><p class="subtle">${escapeHtml(policyNote)}</p><section id="insights" class="insights" aria-label="Attention signals"></section><section class="filters" aria-label="Finding filters"><label>Search <input id="search" type="search" placeholder="Press / to search findings"></label><label>Status <select id="status"><option value="">Any status</option>${statusOptions.map((value) => `<option>${escapeHtml(value)}</option>`).join("")}</select></label><label>Severity <select id="severity"><option value="">Any severity</option><option>error</option><option>warn</option><option>info</option></select></label><button id="reset" type="button">Reset filters</button></section><div class="workspace"><section class="panel" aria-labelledby="architecture-title"><div class="panel-head"><div><h2 id="architecture-title">Architecture map</h2><p id="map-note" class="subtle">Grouped package/external view.</p></div><div class="tabs" aria-label="Graph level"><button class="level" data-level="overview" aria-pressed="true">Overview</button><button class="level" data-level="package" aria-pressed="false">Package</button><button class="level" data-level="module" aria-pressed="false">Module</button><button class="level" data-level="file" aria-pressed="false">File</button></div></div><div class="map-wrap"><svg id="graph" viewBox="0 0 1000 560" role="img" aria-label="Interactive architecture graph"></svg></div><p class="subtle">Node number = visible connection degree. Amber nodes/edges have findings. Click or focus a node to inspect its evidence, connectivity, and findings. Grouped edges preserve canonical relation direction and count.</p></section><aside class="panel side" aria-labelledby="details-title"><div class="panel-head"><div><div class="eyebrow">Evidence trail</div><h2 id="details-title">Details</h2></div><button id="clear-selection" class="tab" type="button">Clear</button></div><div id="details"><p class="subtle">Select a node in the map to inspect its evidence, connectivity, and findings.</p></div></aside></div><section class="panel run" aria-labelledby="run-title"><div class="panel-head"><div><div class="eyebrow">Jest-like diagnostics</div><h2 id="run-title">Run report</h2></div><span id="finding-count" class="subtle">${report.diagnostics.length} shown</span></div><div class="run-summary"><span class="chip"><b>${report.diagnostics.filter((item) => item.severity === "error").length}</b> errors</span><span class="chip"><b>${report.diagnostics.filter((item) => item.severity === "warn").length}</b> warnings</span><span class="chip"><b>${report.diagnostics.filter((item) => item.status === "undocumented").length}</b> undocumented</span><span class="chip"><b>${report.diagnostics.filter((item) => item.status === "stale-or-unverified" || item.status === "conflict").length}</b> drift/conflict</span></div><div id="findings"></div></section><section class="panel run" aria-labelledby="coverage-title"><div class="panel-head"><div><div class="eyebrow">Analyzer boundaries</div><h2 id="coverage-title">Coverage & unsupported areas</h2></div><span class="subtle">Explicit limits are part of the evidence</span></div><div id="coverage-list"></div></section><section class="metadata" aria-label="Run metadata"><div><b>Snapshot</b>${escapeHtml(snapshot.contentHash)}</div><div><b>Report</b>${escapeHtml(report.contentHash)}</div><div><b>Configuration</b>${escapeHtml(snapshot.configurationHash)}</div><div><b>Analyzers</b>${escapeHtml(Object.entries(snapshot.analyzerVersions).map(([name, version]) => `${name} ${version}`).join(", "))}</div><div><b>Source revision</b>${escapeHtml(snapshot.sourceRevision)} (${escapeHtml(snapshot.sourceRevisionKind)})</div><div><b>Mode</b>Read-only browser viewer; approvals and fixes remain outside this artifact.</div></section></main><script>${scriptBody}</script></body></html>`;
|
|
3786
|
+
};
|
|
3787
|
+
var parseReportInput = (input) => {
|
|
3788
|
+
if (!input || typeof input !== "object") throw new Error("Input must contain snapshot and report artifacts.");
|
|
3789
|
+
const value = input;
|
|
3790
|
+
const snapshot = DiscoverySnapshotV1Schema.parse(value.snapshot);
|
|
3791
|
+
const report = ReconciliationReportV1Schema.parse(value.report);
|
|
3792
|
+
if (report.snapshotHash !== snapshot.contentHash) throw new Error("Report snapshotHash does not match snapshot contentHash.");
|
|
3793
|
+
return { snapshot, report };
|
|
3794
|
+
};
|
|
3795
|
+
var chunkScript = (payload) => `globalThis.__DOC_BRIDGE_DATA__=Object.assign(globalThis.__DOC_BRIDGE_DATA__||{},${embeddedJson(payload)});`;
|
|
3796
|
+
var byteLength = (value) => new TextEncoder().encode(value).byteLength;
|
|
3611
3797
|
var renderOfflineReport = (input, options = {}) => {
|
|
3612
3798
|
try {
|
|
3613
|
-
|
|
3614
|
-
const value = input;
|
|
3615
|
-
const snapshot = DiscoverySnapshotV1Schema.parse(value.snapshot);
|
|
3616
|
-
const report = ReconciliationReportV1Schema.parse(value.report);
|
|
3617
|
-
if (report.snapshotHash !== snapshot.contentHash) throw new Error("Report snapshotHash does not match snapshot contentHash.");
|
|
3618
|
-
return render({ snapshot, report }, options);
|
|
3799
|
+
return render(parseReportInput(input), options);
|
|
3619
3800
|
} catch (error) {
|
|
3620
3801
|
return errorPage(error instanceof Error ? error.message : String(error));
|
|
3621
3802
|
}
|
|
3622
3803
|
};
|
|
3804
|
+
var renderOfflineReportArtifact = (input, options = {}) => {
|
|
3805
|
+
const parsed = parseReportInput(input);
|
|
3806
|
+
const thresholdBytes = options.thresholdBytes ?? DEFAULT_LARGE_REPORT_THRESHOLD_BYTES;
|
|
3807
|
+
const renderOptions = { includeSnippets: options.includeSnippets === true, thresholdBytes };
|
|
3808
|
+
const singleFile = render(parsed, options);
|
|
3809
|
+
if (byteLength(singleFile) <= thresholdBytes) {
|
|
3810
|
+
const files2 = { "index.html": sha256NormalizedV1(singleFile) };
|
|
3811
|
+
const manifestPayload2 = { schemaVersion: 1, mode: "single-file", generatedBy: "@agentskit/doc-bridge", snapshotHash: parsed.snapshot.contentHash, reportHash: parsed.report.contentHash, configurationHash: parsed.snapshot.configurationHash, sourceRevision: parsed.snapshot.sourceRevision, renderOptions, files: files2 };
|
|
3812
|
+
const manifest2 = JSON.stringify({ ...manifestPayload2, artifactHash: sha256NormalizedV1(manifestPayload2) }, null, 2);
|
|
3813
|
+
return { mode: "single-file", indexHtml: singleFile, files: { "index.html": singleFile }, manifest: manifest2 };
|
|
3814
|
+
}
|
|
3815
|
+
const data = reportData(parsed.snapshot, parsed.report, options.includeSnippets === true);
|
|
3816
|
+
const files = {
|
|
3817
|
+
"chunks/overview.js": chunkScript({ project: data.project, revision: data.revision, revisionKind: data.revisionKind, snapshotHash: data.snapshotHash, reportHash: data.reportHash, configurationHash: data.configurationHash, pipelineVersion: data.pipelineVersion, analyzerVersions: data.analyzerVersions, coverage: data.coverage, diagnosticCount: data.diagnosticCount, diagnosticSummary: data.diagnosticSummary, requiredRelationKinds: data.requiredRelationKinds, view: data.view }),
|
|
3818
|
+
"chunks/levels.js": chunkScript({ entities: data.entities, relations: data.relations }),
|
|
3819
|
+
"chunks/findings.js": chunkScript({ diagnostics: data.diagnostics })
|
|
3820
|
+
};
|
|
3821
|
+
const indexHtml = render(parsed, { ...options, dataExpression: "globalThis.__DOC_BRIDGE_DATA__", dataScripts: `<script>globalThis.__DOC_BRIDGE_LAZY_CHUNKS__=${embeddedJson(["chunks/levels.js", "chunks/findings.js"])}</script><script src="chunks/overview.js"></script>` });
|
|
3822
|
+
const fileHashes = Object.fromEntries(Object.entries({ ...files, "index.html": indexHtml }).map(([file, content]) => [file, sha256NormalizedV1(content)]));
|
|
3823
|
+
const manifestPayload = { schemaVersion: 1, mode: "directory", generatedBy: "@agentskit/doc-bridge", snapshotHash: parsed.snapshot.contentHash, reportHash: parsed.report.contentHash, configurationHash: parsed.snapshot.configurationHash, sourceRevision: parsed.snapshot.sourceRevision, renderOptions, files: fileHashes };
|
|
3824
|
+
const manifest = JSON.stringify({ ...manifestPayload, artifactHash: sha256NormalizedV1(manifestPayload) }, null, 2);
|
|
3825
|
+
return { mode: "directory", indexHtml, files: { ...files, "index.html": indexHtml }, manifest };
|
|
3826
|
+
};
|
|
3623
3827
|
|
|
3624
3828
|
// src/fixes/proposals.ts
|
|
3625
3829
|
import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync10, realpathSync as realpathSync7, renameSync, statSync as statSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
@@ -6628,6 +6832,7 @@ export {
|
|
|
6628
6832
|
AgentSearchV1Schema,
|
|
6629
6833
|
ConfigNotFoundError,
|
|
6630
6834
|
CoverageSchema,
|
|
6835
|
+
DEFAULT_LARGE_REPORT_THRESHOLD_BYTES,
|
|
6631
6836
|
DEFAULT_REGISTRY_AGENT_ID,
|
|
6632
6837
|
DEFAULT_SAFETY_EXCLUDES,
|
|
6633
6838
|
DOCUMENTATION_STANDARD_V1_ID,
|
|
@@ -6748,6 +6953,7 @@ export {
|
|
|
6748
6953
|
redactSecrets,
|
|
6749
6954
|
redactValue,
|
|
6750
6955
|
renderOfflineReport,
|
|
6956
|
+
renderOfflineReportArtifact,
|
|
6751
6957
|
resolveGateIds,
|
|
6752
6958
|
resolveProjectRoot,
|
|
6753
6959
|
resolveRoot,
|