dna-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/adapters/embedding/onnx.d.ts +32 -0
- package/dist/adapters/embedding/onnx.js +51 -0
- package/dist/adapters/filesystem/cache.d.ts +16 -0
- package/dist/adapters/filesystem/cache.js +113 -0
- package/dist/adapters/filesystem/index.d.ts +2 -0
- package/dist/adapters/filesystem/index.js +2 -0
- package/dist/adapters/filesystem/source.d.ts +82 -0
- package/dist/adapters/filesystem/source.js +357 -0
- package/dist/adapters/postgres/index.d.ts +2 -0
- package/dist/adapters/postgres/index.js +2 -0
- package/dist/adapters/postgres/migrations.d.ts +14 -0
- package/dist/adapters/postgres/migrations.js +88 -0
- package/dist/adapters/postgres/source.d.ts +172 -0
- package/dist/adapters/postgres/source.js +569 -0
- package/dist/adapters/resolvers/github.d.ts +12 -0
- package/dist/adapters/resolvers/github.js +47 -0
- package/dist/adapters/resolvers/http.d.ts +22 -0
- package/dist/adapters/resolvers/http.js +145 -0
- package/dist/adapters/resolvers/index.d.ts +3 -0
- package/dist/adapters/resolvers/index.js +3 -0
- package/dist/adapters/resolvers/local.d.ts +24 -0
- package/dist/adapters/resolvers/local.js +132 -0
- package/dist/adapters/search/driver.d.ts +45 -0
- package/dist/adapters/search/driver.js +138 -0
- package/dist/adapters/search/migrations.d.ts +26 -0
- package/dist/adapters/search/migrations.js +58 -0
- package/dist/adapters/search/rrf.d.ts +23 -0
- package/dist/adapters/search/rrf.js +42 -0
- package/dist/adapters/search/sqlite-vec.d.ts +66 -0
- package/dist/adapters/search/sqlite-vec.js +294 -0
- package/dist/bootstrap.d.ts +45 -0
- package/dist/bootstrap.js +134 -0
- package/dist/extensions/agentskills/DOCS.md +18 -0
- package/dist/extensions/agentskills.d.ts +28 -0
- package/dist/extensions/agentskills.js +252 -0
- package/dist/extensions/agentsmd/DOCS.md +18 -0
- package/dist/extensions/agentsmd.d.ts +22 -0
- package/dist/extensions/agentsmd.js +170 -0
- package/dist/extensions/audit/kinds/audit-log.kind.yaml +148 -0
- package/dist/extensions/audit.d.ts +25 -0
- package/dist/extensions/audit.js +62 -0
- package/dist/extensions/automation/kinds/automation.kind.yaml +296 -0
- package/dist/extensions/automation/query.d.ts +49 -0
- package/dist/extensions/automation/query.js +77 -0
- package/dist/extensions/automation/write-guards.d.ts +59 -0
- package/dist/extensions/automation/write-guards.js +153 -0
- package/dist/extensions/automation.d.ts +41 -0
- package/dist/extensions/automation.js +54 -0
- package/dist/extensions/collab.d.ts +16 -0
- package/dist/extensions/collab.js +79 -0
- package/dist/extensions/doc/kinds/doc.kind.yaml +118 -0
- package/dist/extensions/doc.d.ts +25 -0
- package/dist/extensions/doc.js +10 -0
- package/dist/extensions/eval/kinds/eval-baseline.kind.yaml +65 -0
- package/dist/extensions/eval/kinds/eval-case.kind.yaml +140 -0
- package/dist/extensions/eval/kinds/eval-run.kind.yaml +134 -0
- package/dist/extensions/eval/kinds/eval-suite.kind.yaml +87 -0
- package/dist/extensions/eval.d.ts +24 -0
- package/dist/extensions/eval.js +31 -0
- package/dist/extensions/evidence/kinds/evidence.kind.yaml +92 -0
- package/dist/extensions/evidence.d.ts +17 -0
- package/dist/extensions/evidence.js +94 -0
- package/dist/extensions/federation.d.ts +22 -0
- package/dist/extensions/federation.js +173 -0
- package/dist/extensions/guardrails/DOCS.md +20 -0
- package/dist/extensions/guardrails.d.ts +31 -0
- package/dist/extensions/guardrails.js +228 -0
- package/dist/extensions/helix/DOCS-Actor.md +20 -0
- package/dist/extensions/helix/DOCS-Agent.md +20 -0
- package/dist/extensions/helix/DOCS-UseCase.md +20 -0
- package/dist/extensions/helix/layers.d.ts +12 -0
- package/dist/extensions/helix/layers.js +18 -0
- package/dist/extensions/helix/write-guards.d.ts +70 -0
- package/dist/extensions/helix/write-guards.js +172 -0
- package/dist/extensions/helix.d.ts +29 -0
- package/dist/extensions/helix.js +963 -0
- package/dist/extensions/helix_extras.d.ts +124 -0
- package/dist/extensions/helix_extras.js +328 -0
- package/dist/extensions/hooks.d.ts +31 -0
- package/dist/extensions/hooks.js +247 -0
- package/dist/extensions/kinddef/DOCS.md +24 -0
- package/dist/extensions/kinddef.d.ts +40 -0
- package/dist/extensions/kinddef.js +171 -0
- package/dist/extensions/lesson.d.ts +6 -0
- package/dist/extensions/lesson.js +194 -0
- package/dist/extensions/modelreg/kinds/model-profile.kind.yaml +155 -0
- package/dist/extensions/modelreg.d.ts +30 -0
- package/dist/extensions/modelreg.js +38 -0
- package/dist/extensions/recognizer.d.ts +34 -0
- package/dist/extensions/recognizer.js +272 -0
- package/dist/extensions/research.d.ts +32 -0
- package/dist/extensions/research.js +292 -0
- package/dist/extensions/safety.d.ts +33 -0
- package/dist/extensions/safety.js +230 -0
- package/dist/extensions/sdlc/kinds/adr.kind.yaml +136 -0
- package/dist/extensions/sdlc/kinds/archive-proposal.kind.yaml +107 -0
- package/dist/extensions/sdlc/kinds/changelog.kind.yaml +108 -0
- package/dist/extensions/sdlc/kinds/cognitive-policy.kind.yaml +470 -0
- package/dist/extensions/sdlc/kinds/forecast.kind.yaml +125 -0
- package/dist/extensions/sdlc/kinds/insight.kind.yaml +87 -0
- package/dist/extensions/sdlc/kinds/kaizen.kind.yaml +106 -0
- package/dist/extensions/sdlc/kinds/lesson-learned.kind.yaml +270 -0
- package/dist/extensions/sdlc/kinds/narrative.kind.yaml +189 -0
- package/dist/extensions/sdlc/kinds/pattern-insight.kind.yaml +204 -0
- package/dist/extensions/sdlc/kinds/postmortem.kind.yaml +168 -0
- package/dist/extensions/sdlc/kinds/pre-mortem.kind.yaml +145 -0
- package/dist/extensions/sdlc/kinds/prompt-template.kind.yaml +109 -0
- package/dist/extensions/sdlc/kinds/retrospective.kind.yaml +186 -0
- package/dist/extensions/sdlc/kinds/risk-register.kind.yaml +178 -0
- package/dist/extensions/sdlc/kinds/saved-view.kind.yaml +127 -0
- package/dist/extensions/sdlc/kinds/status-report.kind.yaml +129 -0
- package/dist/extensions/sdlc/kinds/synthesis-run.kind.yaml +279 -0
- package/dist/extensions/sdlc/kinds/synthesizer-state.kind.yaml +196 -0
- package/dist/extensions/sdlc/kinds/workflow-event.kind.yaml +195 -0
- package/dist/extensions/sdlc.d.ts +32 -0
- package/dist/extensions/sdlc.js +1318 -0
- package/dist/extensions/soulspec/DOCS.md +19 -0
- package/dist/extensions/soulspec.d.ts +22 -0
- package/dist/extensions/soulspec.js +287 -0
- package/dist/extensions/tenant.d.ts +6 -0
- package/dist/extensions/tenant.js +291 -0
- package/dist/extensions/testkit.d.ts +24 -0
- package/dist/extensions/testkit.js +211 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +102 -0
- package/dist/kernel/_text.d.ts +28 -0
- package/dist/kernel/_text.js +42 -0
- package/dist/kernel/bundle-handle.d.ts +83 -0
- package/dist/kernel/bundle-handle.js +184 -0
- package/dist/kernel/capabilities.d.ts +157 -0
- package/dist/kernel/capabilities.js +109 -0
- package/dist/kernel/collaborator-ports.d.ts +91 -0
- package/dist/kernel/collaborator-ports.js +1 -0
- package/dist/kernel/composition-resolver.d.ts +215 -0
- package/dist/kernel/composition-resolver.js +558 -0
- package/dist/kernel/composition.d.ts +10 -0
- package/dist/kernel/composition.js +1 -0
- package/dist/kernel/descriptor-loader.d.ts +13 -0
- package/dist/kernel/descriptor-loader.js +48 -0
- package/dist/kernel/document.d.ts +43 -0
- package/dist/kernel/document.js +71 -0
- package/dist/kernel/embedding.d.ts +28 -0
- package/dist/kernel/embedding.js +78 -0
- package/dist/kernel/errors.d.ts +62 -0
- package/dist/kernel/errors.js +82 -0
- package/dist/kernel/events.d.ts +6 -0
- package/dist/kernel/events.js +21 -0
- package/dist/kernel/evidence-capture.d.ts +69 -0
- package/dist/kernel/evidence-capture.js +138 -0
- package/dist/kernel/fs.d.ts +20 -0
- package/dist/kernel/fs.js +128 -0
- package/dist/kernel/generic-rw.d.ts +33 -0
- package/dist/kernel/generic-rw.js +235 -0
- package/dist/kernel/hooks.d.ts +172 -0
- package/dist/kernel/hooks.js +256 -0
- package/dist/kernel/index.d.ts +624 -0
- package/dist/kernel/index.js +1638 -0
- package/dist/kernel/instance.d.ts +211 -0
- package/dist/kernel/instance.js +487 -0
- package/dist/kernel/kind-registry.d.ts +183 -0
- package/dist/kernel/kind-registry.js +710 -0
- package/dist/kernel/kind_base.d.ts +106 -0
- package/dist/kernel/kind_base.js +244 -0
- package/dist/kernel/layer-resolver.d.ts +48 -0
- package/dist/kernel/layer-resolver.js +284 -0
- package/dist/kernel/lock-manager.d.ts +21 -0
- package/dist/kernel/lock-manager.js +43 -0
- package/dist/kernel/lock.d.ts +38 -0
- package/dist/kernel/lock.js +115 -0
- package/dist/kernel/meta.d.ts +135 -0
- package/dist/kernel/meta.js +817 -0
- package/dist/kernel/models.d.ts +3089 -0
- package/dist/kernel/models.js +764 -0
- package/dist/kernel/navigator.d.ts +36 -0
- package/dist/kernel/navigator.js +132 -0
- package/dist/kernel/port-surface.d.ts +33 -0
- package/dist/kernel/port-surface.js +180 -0
- package/dist/kernel/preview.d.ts +60 -0
- package/dist/kernel/preview.js +54 -0
- package/dist/kernel/prompt-budget.d.ts +39 -0
- package/dist/kernel/prompt-budget.js +43 -0
- package/dist/kernel/prompt-builder.d.ts +25 -0
- package/dist/kernel/prompt-builder.js +237 -0
- package/dist/kernel/protocols.d.ts +751 -0
- package/dist/kernel/protocols.js +493 -0
- package/dist/kernel/reports.d.ts +26 -0
- package/dist/kernel/reports.js +215 -0
- package/dist/kernel/resolver.d.ts +146 -0
- package/dist/kernel/resolver.js +232 -0
- package/dist/kernel/resource.d.ts +57 -0
- package/dist/kernel/resource.js +97 -0
- package/dist/kernel/runtime.d.ts +16 -0
- package/dist/kernel/runtime.js +18 -0
- package/dist/kernel/safety-scanner.d.ts +38 -0
- package/dist/kernel/safety-scanner.js +228 -0
- package/dist/kernel/serialize-to-files.d.ts +29 -0
- package/dist/kernel/serialize-to-files.js +23 -0
- package/dist/kernel/spec-access.d.ts +23 -0
- package/dist/kernel/spec-access.js +40 -0
- package/dist/kernel/studio_ui.d.ts +88 -0
- package/dist/kernel/studio_ui.js +135 -0
- package/dist/kernel/templates.d.ts +77 -0
- package/dist/kernel/templates.js +116 -0
- package/dist/kernel/tool-registry.d.ts +52 -0
- package/dist/kernel/tool-registry.js +89 -0
- package/dist/kernel/write-pipeline.d.ts +65 -0
- package/dist/kernel/write-pipeline.js +271 -0
- package/dist/kernel/writer-helpers.d.ts +24 -0
- package/dist/kernel/writer-helpers.js +42 -0
- package/dist/memory/decay.d.ts +31 -0
- package/dist/memory/decay.js +97 -0
- package/dist/memory/ecphory.d.ts +25 -0
- package/dist/memory/ecphory.js +178 -0
- package/dist/memory/encodingContext.d.ts +21 -0
- package/dist/memory/encodingContext.js +62 -0
- package/dist/memory/index.d.ts +23 -0
- package/dist/memory/index.js +23 -0
- package/dist/memory/memoryType.d.ts +7 -0
- package/dist/memory/memoryType.js +24 -0
- package/dist/memory/policy.d.ts +35 -0
- package/dist/memory/policy.js +35 -0
- package/dist/memory/retrieval.d.ts +21 -0
- package/dist/memory/retrieval.js +145 -0
- package/dist/testing/index.d.ts +8 -0
- package/dist/testing/index.js +8 -0
- package/dist/testing/recordSearchConformance.d.ts +43 -0
- package/dist/testing/recordSearchConformance.js +147 -0
- package/dist/viz/ascii.d.ts +7 -0
- package/dist/viz/ascii.js +60 -0
- package/dist/viz/health.d.ts +8 -0
- package/dist/viz/health.js +161 -0
- package/dist/viz/index.d.ts +10 -0
- package/dist/viz/index.js +10 -0
- package/dist/viz/matrix.d.ts +8 -0
- package/dist/viz/matrix.js +84 -0
- package/dist/viz/mermaid.d.ts +38 -0
- package/dist/viz/mermaid.js +706 -0
- package/package.json +82 -0
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mermaid diagram generators — standalone functions that operate on a ManifestInstance.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from ManifestInstance to keep the kernel class focused on
|
|
5
|
+
* query/prompt/composition. The original methods on ManifestInstance are
|
|
6
|
+
* preserved for backwards compat; these functions are the canonical
|
|
7
|
+
* implementation going forward.
|
|
8
|
+
*/
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Helpers (private access via cast)
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
function _kinds(mi) {
|
|
13
|
+
return mi._kinds;
|
|
14
|
+
}
|
|
15
|
+
function _profiles(mi) {
|
|
16
|
+
return mi._profiles;
|
|
17
|
+
}
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Dependency Tree Mermaid
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
export function dependencyTreeMermaid(mi) {
|
|
22
|
+
const tree = mi.dependencyTree();
|
|
23
|
+
if (Object.keys(tree).length === 0) {
|
|
24
|
+
return "graph TB\n empty[No dependencies found]";
|
|
25
|
+
}
|
|
26
|
+
const kinds = _kinds(mi);
|
|
27
|
+
// Dynamic style lookup via KindPort.graphStyle — no hardcoded palette.
|
|
28
|
+
const _styleFor = (kind, apiVersion) => {
|
|
29
|
+
let kp;
|
|
30
|
+
if (apiVersion) {
|
|
31
|
+
kp = kinds.get(`${apiVersion}\0${kind}`);
|
|
32
|
+
}
|
|
33
|
+
if (!kp)
|
|
34
|
+
kp = mi.kindFor(kind) ?? undefined;
|
|
35
|
+
const gs = kp?.graphStyle;
|
|
36
|
+
if (gs)
|
|
37
|
+
return `fill:${gs.fill},color:${gs.textColor},stroke:${gs.stroke}`;
|
|
38
|
+
return "fill:#95A5A6,color:#fff,stroke:#64748B";
|
|
39
|
+
};
|
|
40
|
+
const nodeIds = new Map();
|
|
41
|
+
let counter = 0;
|
|
42
|
+
const declaredNodes = new Map();
|
|
43
|
+
const styles = new Map();
|
|
44
|
+
const edges = [];
|
|
45
|
+
const nodeId = (name) => {
|
|
46
|
+
if (!nodeIds.has(name)) {
|
|
47
|
+
nodeIds.set(name, `n${counter++}`);
|
|
48
|
+
}
|
|
49
|
+
return nodeIds.get(name);
|
|
50
|
+
};
|
|
51
|
+
const truncate = (text, max = 45) => text.length > max ? text.slice(0, max) + "..." : text;
|
|
52
|
+
for (const [docName, info] of Object.entries(tree)) {
|
|
53
|
+
const i = info;
|
|
54
|
+
const nid = nodeId(docName);
|
|
55
|
+
const kind = i.kind;
|
|
56
|
+
const desc = i.description ?? "";
|
|
57
|
+
const label = desc ? `${docName}<br/><i>${truncate(desc)}</i>` : docName;
|
|
58
|
+
declaredNodes.set(nid, ` ${nid}["${label}"]`);
|
|
59
|
+
styles.set(nid, _styleFor(kind));
|
|
60
|
+
const dependsOn = i.depends_on ?? {};
|
|
61
|
+
for (const [depType, deps] of Object.entries(dependsOn)) {
|
|
62
|
+
for (const [depName, depInfo] of Object.entries(deps)) {
|
|
63
|
+
const di = depInfo;
|
|
64
|
+
const depNid = nodeId(depName);
|
|
65
|
+
const depKind = di.kind ?? "";
|
|
66
|
+
if (!declaredNodes.has(depNid)) {
|
|
67
|
+
// Use kp.graphMeta (or summary fallback) for kind-specific labels
|
|
68
|
+
const depKp = mi.kindFor(depKind);
|
|
69
|
+
const depDoc = mi._one(depKind, depName);
|
|
70
|
+
const meta = (depKp && depDoc)
|
|
71
|
+
? (depKp.graphMeta?.(depDoc) ?? depKp.summary(depDoc) ?? {})
|
|
72
|
+
: {};
|
|
73
|
+
let depLabel;
|
|
74
|
+
if (meta.severity) {
|
|
75
|
+
const m = meta;
|
|
76
|
+
const sevIcon = m.severity === "error" ? "\u{1F534}" : "\u{1F7E1}";
|
|
77
|
+
depLabel = `${sevIcon} ${depName}<br/>${m.rules ?? 0} rules \u00B7 ${m.severity}`;
|
|
78
|
+
// Guardrail severity-specific style override
|
|
79
|
+
const sevStyles = {
|
|
80
|
+
error: "fill:#E74C3C,color:#fff,stroke:#C0392B",
|
|
81
|
+
warn: "fill:#F39C12,color:#fff,stroke:#D68910",
|
|
82
|
+
};
|
|
83
|
+
styles.set(depNid, sevStyles[m.severity] ?? _styleFor(depKind));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
const depDesc = di.description ?? "";
|
|
87
|
+
depLabel = depDesc ? `${depName}<br/><i>${truncate(depDesc)}</i>` : depName;
|
|
88
|
+
styles.set(depNid, _styleFor(depKind));
|
|
89
|
+
}
|
|
90
|
+
declaredNodes.set(depNid, ` ${depNid}["${depLabel}"]`);
|
|
91
|
+
}
|
|
92
|
+
const found = di.found !== false;
|
|
93
|
+
const arrow = found ? "-->|" : "-.->|";
|
|
94
|
+
edges.push(` ${nid} ${arrow}${depType}| ${depNid}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const lines = ["graph TB"];
|
|
99
|
+
lines.push(...declaredNodes.values());
|
|
100
|
+
lines.push("");
|
|
101
|
+
lines.push(...edges);
|
|
102
|
+
lines.push("");
|
|
103
|
+
for (const [nid, style] of styles) {
|
|
104
|
+
lines.push(` style ${nid} ${style}`);
|
|
105
|
+
}
|
|
106
|
+
return lines.join("\n");
|
|
107
|
+
}
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Composition Flowchart Mermaid
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
export function compositionFlowchartMermaid(mi) {
|
|
112
|
+
const kinds = _kinds(mi);
|
|
113
|
+
const profiles = _profiles(mi);
|
|
114
|
+
const lines = ["graph LR"];
|
|
115
|
+
const root = mi.root;
|
|
116
|
+
const packageName = root?.name ?? mi.scope;
|
|
117
|
+
const esc = (s) => s.replace(/"/g, "'").replace(/\n/g, " ");
|
|
118
|
+
const safe = (s) => s.replace(/-/g, "_").replace(/[^a-zA-Z0-9_]/g, "_");
|
|
119
|
+
const classFor = (kind) => safe(kind).toLowerCase();
|
|
120
|
+
const paletteFor = (kind) => {
|
|
121
|
+
const kp = mi.kindFor(kind);
|
|
122
|
+
return kp?.graphStyle ?? { fill: "#6B7280", stroke: "#4B5563", textColor: "#fff" };
|
|
123
|
+
};
|
|
124
|
+
// Emit classDef for every kind present in the manifest.
|
|
125
|
+
const presentKinds = new Set();
|
|
126
|
+
if (root)
|
|
127
|
+
presentKinds.add(root.kind);
|
|
128
|
+
for (const d of mi.documents)
|
|
129
|
+
presentKinds.add(d.kind);
|
|
130
|
+
for (const kind of Array.from(presentKinds).sort()) {
|
|
131
|
+
const p = paletteFor(kind);
|
|
132
|
+
lines.push(` classDef ${classFor(kind)} fill:${p.fill},color:${p.textColor},stroke:${p.stroke},stroke-width:2px`);
|
|
133
|
+
}
|
|
134
|
+
lines.push("");
|
|
135
|
+
// Genome node
|
|
136
|
+
const rootKp = root ? kinds.get(`${root.apiVersion}\0${root.kind}`) : null;
|
|
137
|
+
const rootLabel = rootKp?.displayLabel ?? root?.kind ?? "Genome";
|
|
138
|
+
lines.push(` mod["<b>${esc(packageName)}</b><br/><i>${rootLabel}</i>"]:::${classFor(root?.kind ?? "Genome")}`);
|
|
139
|
+
lines.push("");
|
|
140
|
+
const declaredNodes = new Set();
|
|
141
|
+
const nodeIdFor = (kind, name) => `n_${safe(kind)}_${safe(name)}`;
|
|
142
|
+
const declareNode = (kind, name, label) => {
|
|
143
|
+
const id = nodeIdFor(kind, name);
|
|
144
|
+
if (declaredNodes.has(id))
|
|
145
|
+
return id;
|
|
146
|
+
declaredNodes.add(id);
|
|
147
|
+
lines.push(` ${id}["${esc(label ?? name)}"]:::${classFor(kind)}`);
|
|
148
|
+
return id;
|
|
149
|
+
};
|
|
150
|
+
// Richer label via kp.graphMeta or kp.summary — no kind-name branching.
|
|
151
|
+
const makeLabel = (doc) => {
|
|
152
|
+
const kp = kinds.get(`${doc.apiVersion}\0${doc.kind}`);
|
|
153
|
+
const meta = kp?.graphMeta?.(doc) ?? kp?.summary(doc) ?? null;
|
|
154
|
+
if (!meta)
|
|
155
|
+
return doc.name;
|
|
156
|
+
const m = meta;
|
|
157
|
+
if (typeof m.model === "string" && m.model) {
|
|
158
|
+
return `<b>${doc.name}</b><br/><i>${m.model}</i>`;
|
|
159
|
+
}
|
|
160
|
+
if (typeof m.severity === "string") {
|
|
161
|
+
return `${doc.name}<br/><i>${m.severity}</i>`;
|
|
162
|
+
}
|
|
163
|
+
if (typeof m.type === "string") {
|
|
164
|
+
return `${doc.name}<br/><i>${m.type}</i>`;
|
|
165
|
+
}
|
|
166
|
+
return doc.name;
|
|
167
|
+
};
|
|
168
|
+
// Orchestrator kinds from profiles — used for default_agent edge styling.
|
|
169
|
+
const orchestratorKinds = new Set();
|
|
170
|
+
for (const p of profiles) {
|
|
171
|
+
const kp = mi.kindForAlias(p.orchestratorAlias);
|
|
172
|
+
if (kp)
|
|
173
|
+
orchestratorKinds.add(kp.kind);
|
|
174
|
+
}
|
|
175
|
+
// Walk every non-root document and declare it as a node.
|
|
176
|
+
for (const doc of mi.documents) {
|
|
177
|
+
if (mi.isRootDoc(doc))
|
|
178
|
+
continue;
|
|
179
|
+
declareNode(doc.kind, doc.name, makeLabel(doc));
|
|
180
|
+
}
|
|
181
|
+
lines.push("");
|
|
182
|
+
// Edges from the Module root via its declared dep_filters.
|
|
183
|
+
if (root) {
|
|
184
|
+
const defaultAgent = root.spec.default_agent ?? "";
|
|
185
|
+
for (const dep of mi.iterDocDeps(root)) {
|
|
186
|
+
for (const name of dep.names) {
|
|
187
|
+
const tid = nodeIdFor(dep.targetKind, name);
|
|
188
|
+
if (!declaredNodes.has(tid)) {
|
|
189
|
+
declareNode(dep.targetKind, name, `${name}<br/><i>(missing)</i>`);
|
|
190
|
+
}
|
|
191
|
+
if (orchestratorKinds.has(dep.targetKind) && name === defaultAgent) {
|
|
192
|
+
lines.push(` mod ==>|default| ${tid}`);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
lines.push(` mod -->|${dep.label}| ${tid}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Edges from every orchestrator (agent) via its declared dep_filters.
|
|
201
|
+
for (const agent of mi.allWhere(kp => kp.isPromptTarget && !kp.isRoot && !kp.flattenInContext)) {
|
|
202
|
+
const src = nodeIdFor(agent.kind, agent.name);
|
|
203
|
+
for (const dep of mi.iterDocDeps(agent)) {
|
|
204
|
+
for (const name of dep.names) {
|
|
205
|
+
const tid = nodeIdFor(dep.targetKind, name);
|
|
206
|
+
if (!declaredNodes.has(tid)) {
|
|
207
|
+
declareNode(dep.targetKind, name, `${name}<br/><i>(missing)</i>`);
|
|
208
|
+
}
|
|
209
|
+
lines.push(` ${src} -->|${dep.label}| ${tid}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Edges from every non-root, non-agent doc that has depFilters.
|
|
214
|
+
for (const depDoc of mi.documents.filter(d => {
|
|
215
|
+
const kp = kinds.get(`${d.apiVersion}\0${d.kind}`);
|
|
216
|
+
return kp && !kp.isRoot && !kp.isPromptTarget && kp.depFilters();
|
|
217
|
+
})) {
|
|
218
|
+
const src = nodeIdFor(depDoc.kind, depDoc.name);
|
|
219
|
+
for (const dep of mi.iterDocDeps(depDoc)) {
|
|
220
|
+
for (const name of dep.names) {
|
|
221
|
+
const tid = nodeIdFor(dep.targetKind, name);
|
|
222
|
+
if (!declaredNodes.has(tid)) {
|
|
223
|
+
declareNode(dep.targetKind, name, `${name}<br/><i>(missing)</i>`);
|
|
224
|
+
}
|
|
225
|
+
lines.push(` ${src} -.->|${dep.label}| ${tid}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return lines.join("\n");
|
|
230
|
+
}
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
// C4 Component Mermaid
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
export function c4ComponentMermaid(mi) {
|
|
235
|
+
const profiles = _profiles(mi);
|
|
236
|
+
const lines = ["graph LR"];
|
|
237
|
+
const root = mi.root;
|
|
238
|
+
const packageName = root?.name ?? mi.scope;
|
|
239
|
+
const agents = mi.allWhere(kp => kp.isPromptTarget && !kp.isRoot && !kp.flattenInContext);
|
|
240
|
+
const esc = (s) => s.replace(/"/g, "'").replace(/\n/g, " ");
|
|
241
|
+
const safe = (s) => s.replace(/-/g, "_").replace(/[^a-zA-Z0-9_]/g, "_");
|
|
242
|
+
lines.push(" classDef module fill:#3B82F6,color:#fff,stroke:#2563EB,stroke-width:2px,font-size:14px");
|
|
243
|
+
lines.push(" classDef agent fill:#F97316,color:#fff,stroke:#EA580C,stroke-width:2px");
|
|
244
|
+
lines.push(" classDef stat fill:#F8FAFC,color:#334155,stroke:#CBD5E1,stroke-width:1px");
|
|
245
|
+
lines.push("");
|
|
246
|
+
const kindCounts = new Map();
|
|
247
|
+
for (const d of mi.documents) {
|
|
248
|
+
if (mi.isRootDoc(d))
|
|
249
|
+
continue;
|
|
250
|
+
kindCounts.set(d.kind, (kindCounts.get(d.kind) ?? 0) + 1);
|
|
251
|
+
}
|
|
252
|
+
const orchestratorKinds = new Set();
|
|
253
|
+
for (const p of profiles) {
|
|
254
|
+
const kp = mi.kindForAlias(p.orchestratorAlias);
|
|
255
|
+
if (kp)
|
|
256
|
+
orchestratorKinds.add(kp.kind);
|
|
257
|
+
}
|
|
258
|
+
const countParts = [];
|
|
259
|
+
for (const ok of orchestratorKinds) {
|
|
260
|
+
const n = kindCounts.get(ok) ?? 0;
|
|
261
|
+
const label = mi.kindFor(ok)?.displayLabel ?? ok;
|
|
262
|
+
if (n > 0)
|
|
263
|
+
countParts.push(`${n} ${label.toLowerCase()}`);
|
|
264
|
+
}
|
|
265
|
+
const otherKinds = Array.from(kindCounts.entries())
|
|
266
|
+
.filter(([k]) => !orchestratorKinds.has(k))
|
|
267
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
268
|
+
for (const [k, n] of otherKinds) {
|
|
269
|
+
const label = mi.kindFor(k)?.displayLabel ?? k;
|
|
270
|
+
countParts.push(`${n} ${label.toLowerCase()}${n === 1 ? "" : "s"}`);
|
|
271
|
+
}
|
|
272
|
+
const countLabel = countParts.join(" \u00B7 ") || "empty";
|
|
273
|
+
lines.push(` mod["<b>${esc(packageName)}</b><br/><i>${countLabel}</i>"]:::module`);
|
|
274
|
+
lines.push("");
|
|
275
|
+
const defaultAgent = root?.spec.default_agent ?? "";
|
|
276
|
+
for (const agent of agents) {
|
|
277
|
+
const agentId = `a_${safe(agent.name)}`;
|
|
278
|
+
const model = agent.spec.model ?? "";
|
|
279
|
+
const isDefault = agent.name === defaultAgent;
|
|
280
|
+
const deps = mi.iterDocDeps(agent);
|
|
281
|
+
const statParts = [];
|
|
282
|
+
for (const dep of deps) {
|
|
283
|
+
if (dep.names.length === 1) {
|
|
284
|
+
statParts.push(`${dep.label}: ${dep.names[0]}`);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
statParts.push(`${dep.names.length} ${dep.label}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const label = `<b>${esc(agent.name)}</b><br/><i>${esc(model)}</i><br/>${statParts.join(" \u00B7 ")}`;
|
|
291
|
+
lines.push(` ${agentId}["${label}"]:::agent`);
|
|
292
|
+
const edgeLabel = isDefault ? "default agent" : "agent";
|
|
293
|
+
const edgeStyle = isDefault ? "==>" : "-->";
|
|
294
|
+
lines.push(` mod ${edgeStyle}|${edgeLabel}| ${agentId}`);
|
|
295
|
+
}
|
|
296
|
+
if (root) {
|
|
297
|
+
const rootDeps = mi.iterDocDeps(root);
|
|
298
|
+
for (const dep of rootDeps) {
|
|
299
|
+
if (dep.label === "agents")
|
|
300
|
+
continue;
|
|
301
|
+
const nodeId = `m_${safe(dep.label)}`;
|
|
302
|
+
const preview = dep.names.slice(0, 4).join(", ") + (dep.names.length > 4 ? ", \u2026" : "");
|
|
303
|
+
lines.push(` ${nodeId}["<b>${dep.names.length} ${dep.targetKind}${dep.names.length === 1 ? "" : "s"}</b><br/>${esc(preview)}"]:::stat`);
|
|
304
|
+
lines.push(` mod -->|${dep.label}| ${nodeId}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return lines.join("\n");
|
|
308
|
+
}
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
// ER Model (structured)
|
|
311
|
+
// ---------------------------------------------------------------------------
|
|
312
|
+
export function erModel(mi) {
|
|
313
|
+
const kinds = _kinds(mi);
|
|
314
|
+
const profiles = _profiles(mi);
|
|
315
|
+
const _SKIP_TEXT = new Set([
|
|
316
|
+
"instruction", "content", "soul_content", "identity_content",
|
|
317
|
+
"style_content", "heartbeat_content", "agents_content", "soul_json",
|
|
318
|
+
]);
|
|
319
|
+
const _SKIP_REF = new Set(["dependencies", "default_agent"]);
|
|
320
|
+
for (const profile of profiles) {
|
|
321
|
+
for (const slot of profile.slots)
|
|
322
|
+
_SKIP_REF.add(slot.name);
|
|
323
|
+
}
|
|
324
|
+
const _SKIP_OBJ = new Set([
|
|
325
|
+
"scripts", "references", "assets", "extras", "root_files", "budget", "layers", "custom_kinds",
|
|
326
|
+
]);
|
|
327
|
+
const entityId = (kind, name) => {
|
|
328
|
+
const raw = `${kind}_${name}`;
|
|
329
|
+
return raw.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_{2,}/g, "_").replace(/_$/, "").slice(0, 80);
|
|
330
|
+
};
|
|
331
|
+
const cleanVal = (v, max = 50) => v.replace(/"/g, "'").replace(/\n/g, " ").slice(0, max);
|
|
332
|
+
const entities = [];
|
|
333
|
+
const relationships = [];
|
|
334
|
+
for (const d of mi.documents) {
|
|
335
|
+
const attrs = [];
|
|
336
|
+
const spec = d.spec;
|
|
337
|
+
for (const [k, v] of Object.entries(spec)) {
|
|
338
|
+
if (_SKIP_TEXT.has(k) || _SKIP_REF.has(k))
|
|
339
|
+
continue;
|
|
340
|
+
if ((typeof v === "object" && v !== null && !Array.isArray(v)) && _SKIP_OBJ.has(k))
|
|
341
|
+
continue;
|
|
342
|
+
if (Array.isArray(v) && _SKIP_OBJ.has(k))
|
|
343
|
+
continue;
|
|
344
|
+
if (typeof v === "string" && v.length > 0 && v.length < 60 && !v.includes("\n")) {
|
|
345
|
+
attrs.push({ key: k, type: "string", value: cleanVal(v) });
|
|
346
|
+
}
|
|
347
|
+
else if (Array.isArray(v)) {
|
|
348
|
+
const strItems = v.filter((x) => typeof x === "string");
|
|
349
|
+
if (strItems.length > 0 && strItems.length === v.length) {
|
|
350
|
+
attrs.push({ key: k, type: "list", value: cleanVal(strItems.join(", ")) });
|
|
351
|
+
}
|
|
352
|
+
else if (v.length > 0) {
|
|
353
|
+
attrs.push({ key: k, type: "list", value: `${v.length} items` });
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
entities.push({ id: entityId(d.kind, d.name), kind: d.kind, name: d.name, attrs });
|
|
358
|
+
}
|
|
359
|
+
// Build relationships from depFilters
|
|
360
|
+
for (const d of mi.documents) {
|
|
361
|
+
const kp = kinds.get(`${d.apiVersion}\0${d.kind}`);
|
|
362
|
+
if (!kp)
|
|
363
|
+
continue;
|
|
364
|
+
const filters = kp.depFilters();
|
|
365
|
+
if (!filters)
|
|
366
|
+
continue;
|
|
367
|
+
const spec = d.spec;
|
|
368
|
+
const srcId = entityId(d.kind, d.name);
|
|
369
|
+
for (const [field, targetAlias] of Object.entries(filters)) {
|
|
370
|
+
const declared = spec[field];
|
|
371
|
+
if (!declared)
|
|
372
|
+
continue;
|
|
373
|
+
const refs = Array.isArray(declared)
|
|
374
|
+
? declared
|
|
375
|
+
: typeof declared === "string" ? [declared] : [];
|
|
376
|
+
let targetKindName = null;
|
|
377
|
+
for (const [, tkp] of kinds) {
|
|
378
|
+
if (tkp.alias === targetAlias) {
|
|
379
|
+
targetKindName = tkp.kind;
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
for (const ref of refs) {
|
|
384
|
+
const targetDoc = mi.documents.find((td) => td.name === ref && (targetKindName ? td.kind === targetKindName : true));
|
|
385
|
+
const tgtId = targetDoc
|
|
386
|
+
? entityId(targetDoc.kind, targetDoc.name)
|
|
387
|
+
: ref.replace(/-/g, "_").replace(/ /g, "_");
|
|
388
|
+
relationships.push({ sourceId: srcId, targetId: tgtId, label: field, isMany: field.endsWith("s") });
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// Root -> default_agent
|
|
393
|
+
const root = mi.root;
|
|
394
|
+
if (root) {
|
|
395
|
+
const da = root.spec.default_agent ?? null;
|
|
396
|
+
if (da) {
|
|
397
|
+
const targetDoc = mi.documents.find((td) => {
|
|
398
|
+
if (td.name !== da)
|
|
399
|
+
return false;
|
|
400
|
+
const kp = kinds.get(`${td.apiVersion}\0${td.kind}`);
|
|
401
|
+
return kp?.isPromptTarget && !kp.flattenInContext;
|
|
402
|
+
});
|
|
403
|
+
const tgtId = targetDoc ? entityId(targetDoc.kind, da) : da.replace(/-/g, "_");
|
|
404
|
+
relationships.push({ sourceId: entityId(root.kind, root.name), targetId: tgtId, label: "default_agent", isMany: false });
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return { entities, relationships };
|
|
408
|
+
}
|
|
409
|
+
// ---------------------------------------------------------------------------
|
|
410
|
+
// ER Diagram Mermaid
|
|
411
|
+
// ---------------------------------------------------------------------------
|
|
412
|
+
export function erDiagramMermaid(mi) {
|
|
413
|
+
const { entities, relationships } = erModel(mi);
|
|
414
|
+
const lines = ["erDiagram"];
|
|
415
|
+
const safeId = (s) => s.replace(/-/g, "_").replace(/ /g, "_").replace(/\./g, "_");
|
|
416
|
+
for (const e of entities) {
|
|
417
|
+
lines.push(` ${e.id} {`);
|
|
418
|
+
lines.push(` string kind "${e.kind}"`);
|
|
419
|
+
for (const a of e.attrs) {
|
|
420
|
+
lines.push(` ${a.type} ${safeId(a.key)} "${a.value.replace(/"/g, "'")}"`);
|
|
421
|
+
}
|
|
422
|
+
lines.push(` }`);
|
|
423
|
+
}
|
|
424
|
+
for (const r of relationships) {
|
|
425
|
+
const rel = r.isMany ? "}o--||" : "||--||";
|
|
426
|
+
lines.push(` ${r.sourceId} ${rel} ${r.targetId} : "${r.label}"`);
|
|
427
|
+
}
|
|
428
|
+
return lines.join("\n");
|
|
429
|
+
}
|
|
430
|
+
// ---------------------------------------------------------------------------
|
|
431
|
+
// Mindmap Mermaid
|
|
432
|
+
// ---------------------------------------------------------------------------
|
|
433
|
+
export function mindmapMermaid(mi) {
|
|
434
|
+
const root = mi.root;
|
|
435
|
+
const rootName = root?.name ?? mi.scope;
|
|
436
|
+
const lines = ["mindmap", ` root((${rootName}))`];
|
|
437
|
+
const tree = mi.dependencyTree();
|
|
438
|
+
if (Object.keys(tree).length === 0) {
|
|
439
|
+
const byKind = new Map();
|
|
440
|
+
for (const d of mi.documents) {
|
|
441
|
+
if (!byKind.has(d.kind))
|
|
442
|
+
byKind.set(d.kind, []);
|
|
443
|
+
byKind.get(d.kind).push(d.name);
|
|
444
|
+
}
|
|
445
|
+
for (const [kind, names] of byKind) {
|
|
446
|
+
lines.push(` ${kind}`);
|
|
447
|
+
for (const n of names)
|
|
448
|
+
lines.push(` ${n}`);
|
|
449
|
+
}
|
|
450
|
+
return lines.join("\n");
|
|
451
|
+
}
|
|
452
|
+
for (const [docName, info] of Object.entries(tree)) {
|
|
453
|
+
const i = info;
|
|
454
|
+
lines.push(` ${docName}`);
|
|
455
|
+
const dependsOn = i.depends_on ?? {};
|
|
456
|
+
for (const deps of Object.values(dependsOn)) {
|
|
457
|
+
for (const depName of Object.keys(deps)) {
|
|
458
|
+
lines.push(` ${depName}`);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return lines.join("\n");
|
|
463
|
+
}
|
|
464
|
+
// ---------------------------------------------------------------------------
|
|
465
|
+
// Pie Chart Mermaid
|
|
466
|
+
// ---------------------------------------------------------------------------
|
|
467
|
+
export function pieChartMermaid(mi) {
|
|
468
|
+
const counts = new Map();
|
|
469
|
+
for (const d of mi.documents) {
|
|
470
|
+
counts.set(d.kind, (counts.get(d.kind) ?? 0) + 1);
|
|
471
|
+
}
|
|
472
|
+
const lines = [`pie title Documents by Kind (${mi.documents.length} total)`];
|
|
473
|
+
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]);
|
|
474
|
+
for (const [kind, count] of sorted) {
|
|
475
|
+
lines.push(` "${kind}" : ${count}`);
|
|
476
|
+
}
|
|
477
|
+
return lines.join("\n");
|
|
478
|
+
}
|
|
479
|
+
// ---------------------------------------------------------------------------
|
|
480
|
+
// Quadrant Mermaid
|
|
481
|
+
// ---------------------------------------------------------------------------
|
|
482
|
+
export function quadrantMermaid(mi) {
|
|
483
|
+
const profiles = _profiles(mi);
|
|
484
|
+
let xSlot = null;
|
|
485
|
+
let ySlot = null;
|
|
486
|
+
for (const profile of profiles) {
|
|
487
|
+
for (const slot of profile.slots) {
|
|
488
|
+
if (slot.quadrant?.axis === "x")
|
|
489
|
+
xSlot = { name: slot.name, label: slot.quadrant.label, maxScale: slot.quadrant.maxScale };
|
|
490
|
+
if (slot.quadrant?.axis === "y")
|
|
491
|
+
ySlot = { name: slot.name, label: slot.quadrant.label, maxScale: slot.quadrant.maxScale };
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const xLabel = xSlot?.label ?? "X-axis";
|
|
495
|
+
const yLabel = ySlot?.label ?? "Y-axis";
|
|
496
|
+
const lines = [
|
|
497
|
+
"quadrantChart",
|
|
498
|
+
" title Agent Complexity",
|
|
499
|
+
` x-axis ${xLabel}`,
|
|
500
|
+
` y-axis ${yLabel}`,
|
|
501
|
+
" quadrant-1 High safety + High capability",
|
|
502
|
+
" quadrant-2 High safety + Low capability",
|
|
503
|
+
" quadrant-3 Low safety + Low capability",
|
|
504
|
+
" quadrant-4 Low safety + High capability",
|
|
505
|
+
];
|
|
506
|
+
const tree = mi.dependencyTree();
|
|
507
|
+
for (const [docName, info] of Object.entries(tree)) {
|
|
508
|
+
const i = info;
|
|
509
|
+
const dependsOn = i.depends_on ?? {};
|
|
510
|
+
const nX = xSlot ? Object.keys(dependsOn[xSlot.name] ?? {}).length : 0;
|
|
511
|
+
const nY = ySlot ? Object.keys(dependsOn[ySlot.name] ?? {}).length : 0;
|
|
512
|
+
const x = nX > 0 ? Math.min(nX / (xSlot?.maxScale ?? 10), 1.0) : 0.05;
|
|
513
|
+
const y = nY > 0 ? Math.min(nY / (ySlot?.maxScale ?? 10), 1.0) : 0.05;
|
|
514
|
+
lines.push(` ${docName}: [${x.toFixed(2)}, ${y.toFixed(2)}]`);
|
|
515
|
+
}
|
|
516
|
+
return lines.join("\n");
|
|
517
|
+
}
|
|
518
|
+
// ---------------------------------------------------------------------------
|
|
519
|
+
// Timeline Mermaid
|
|
520
|
+
// ---------------------------------------------------------------------------
|
|
521
|
+
export function timelineMermaid(mi) {
|
|
522
|
+
const kinds = _kinds(mi);
|
|
523
|
+
const root = mi.root;
|
|
524
|
+
let agentDoc = null;
|
|
525
|
+
if (root) {
|
|
526
|
+
const kp = kinds.get(`${root.apiVersion}\0${root.kind}`);
|
|
527
|
+
if (kp) {
|
|
528
|
+
const agentName = kp.getDefaultAgentName(root);
|
|
529
|
+
if (agentName) {
|
|
530
|
+
// Find agent by name + highest promptTargetPriority (same logic as PromptBuilder._findAgent)
|
|
531
|
+
let best = null;
|
|
532
|
+
let bestPriority = -1;
|
|
533
|
+
for (const d of mi.documents) {
|
|
534
|
+
const dkp = kinds.get(`${d.apiVersion}\0${d.kind}`);
|
|
535
|
+
if (dkp?.isPromptTarget && d.name === agentName) {
|
|
536
|
+
const priority = dkp.promptTargetPriority ?? 0;
|
|
537
|
+
if (priority > bestPriority) {
|
|
538
|
+
best = d;
|
|
539
|
+
bestPriority = priority;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
agentDoc = best;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
const lines = ["timeline", " title Prompt Composition Phases"];
|
|
548
|
+
if (root) {
|
|
549
|
+
lines.push(" section 1. Root Module");
|
|
550
|
+
lines.push(` ${root.name} : Module loaded`);
|
|
551
|
+
}
|
|
552
|
+
if (agentDoc) {
|
|
553
|
+
lines.push(" section 2. Agent Resolution");
|
|
554
|
+
lines.push(` ${agentDoc.name} : default_agent resolved`);
|
|
555
|
+
const profile = mi.profileFor(agentDoc);
|
|
556
|
+
if (profile) {
|
|
557
|
+
const sortedSlots = [...profile.slots]
|
|
558
|
+
.filter(s => s.timeline)
|
|
559
|
+
.sort((a, b) => a.order - b.order);
|
|
560
|
+
let sectionNum = 3;
|
|
561
|
+
for (const slot of sortedSlots) {
|
|
562
|
+
const deps = mi.iterDocDeps(agentDoc);
|
|
563
|
+
const slotDeps = deps.find(d => d.label === slot.name);
|
|
564
|
+
const names = slotDeps?.names ?? [];
|
|
565
|
+
if (names.length > 0 || slot.cardinality === "one") {
|
|
566
|
+
if (slot.cardinality === "one" && names.length > 0) {
|
|
567
|
+
lines.push(` section ${sectionNum}. ${slot.timeline.label} (flatten)`);
|
|
568
|
+
lines.push(` ${names[0]} : ${slot.timeline.itemLabel}`);
|
|
569
|
+
}
|
|
570
|
+
else if (names.length > 0) {
|
|
571
|
+
lines.push(` section ${sectionNum}. ${slot.timeline.label}`);
|
|
572
|
+
for (const n of names) {
|
|
573
|
+
lines.push(` ${n} : ${slot.timeline.itemLabel}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
sectionNum++;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
lines.push(" section 6. Render");
|
|
582
|
+
lines.push(" Template cascade : agent \u2192 kind \u2192 fallback");
|
|
583
|
+
lines.push(" Mustache render : final prompt");
|
|
584
|
+
return lines.join("\n");
|
|
585
|
+
}
|
|
586
|
+
// ---------------------------------------------------------------------------
|
|
587
|
+
// Sankey Mermaid
|
|
588
|
+
// ---------------------------------------------------------------------------
|
|
589
|
+
export function sankeyMermaid(mi) {
|
|
590
|
+
const lines = ["sankey-beta", ""];
|
|
591
|
+
const tree = mi.dependencyTree();
|
|
592
|
+
const rootName = mi.root?.name ?? "";
|
|
593
|
+
const seen = new Set();
|
|
594
|
+
for (const [docName, info] of Object.entries(tree)) {
|
|
595
|
+
const i = info;
|
|
596
|
+
const docKind = i.kind ?? "";
|
|
597
|
+
const docKp = mi.kindFor(docKind);
|
|
598
|
+
if (!docKp?.isPromptTarget || docKp.isRoot)
|
|
599
|
+
continue;
|
|
600
|
+
const dependsOn = i.depends_on ?? {};
|
|
601
|
+
for (const deps of Object.values(dependsOn)) {
|
|
602
|
+
for (const depName of Object.keys(deps)) {
|
|
603
|
+
if (depName === rootName)
|
|
604
|
+
continue;
|
|
605
|
+
const key = `${depName}\u2192${docName}`;
|
|
606
|
+
if (seen.has(key))
|
|
607
|
+
continue;
|
|
608
|
+
seen.add(key);
|
|
609
|
+
lines.push(`"${depName}","${docName}",1`);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return lines.join("\n");
|
|
614
|
+
}
|
|
615
|
+
// ---------------------------------------------------------------------------
|
|
616
|
+
// Kind Catalog Mermaid
|
|
617
|
+
// ---------------------------------------------------------------------------
|
|
618
|
+
export function kindCatalogMermaid(mi) {
|
|
619
|
+
const kinds = _kinds(mi);
|
|
620
|
+
const seen = new Set();
|
|
621
|
+
const lines = ["classDiagram"];
|
|
622
|
+
const edgeLines = [];
|
|
623
|
+
for (const doc of mi.documents) {
|
|
624
|
+
const kp = kinds.get(`${doc.apiVersion}\0${doc.kind}`);
|
|
625
|
+
if (!kp || seen.has(kp.kind))
|
|
626
|
+
continue;
|
|
627
|
+
seen.add(kp.kind);
|
|
628
|
+
const safe = kp.kind.replace(/ /g, "_");
|
|
629
|
+
lines.push(` class ${safe} {`);
|
|
630
|
+
lines.push(` <<${kp.alias}>>`);
|
|
631
|
+
lines.push(` ${kp.apiVersion}`);
|
|
632
|
+
lines.push(` ---`);
|
|
633
|
+
const flags = [];
|
|
634
|
+
if (kp.isRoot)
|
|
635
|
+
flags.push("is_root");
|
|
636
|
+
if (kp.isPromptTarget)
|
|
637
|
+
flags.push(`prompt_target (priority=${kp.promptTargetPriority})`);
|
|
638
|
+
if (kp.flattenInContext)
|
|
639
|
+
flags.push("flatten_in_context");
|
|
640
|
+
if (flags.length > 0) {
|
|
641
|
+
for (const f of flags)
|
|
642
|
+
lines.push(` ${f}`);
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
lines.push(` passive`);
|
|
646
|
+
}
|
|
647
|
+
const filters = kp.depFilters();
|
|
648
|
+
if (filters) {
|
|
649
|
+
lines.push(` ---`);
|
|
650
|
+
for (const [field, alias] of Object.entries(filters)) {
|
|
651
|
+
lines.push(` ${field} -> ${alias}`);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
lines.push(` }`);
|
|
655
|
+
if (filters) {
|
|
656
|
+
for (const [field, alias] of Object.entries(filters)) {
|
|
657
|
+
for (const tkp of kinds.values()) {
|
|
658
|
+
if (tkp.alias === alias) {
|
|
659
|
+
edgeLines.push(` ${safe} --> ${tkp.kind.replace(/ /g, "_")} : ${field}`);
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
if (edgeLines.length > 0) {
|
|
667
|
+
lines.push("");
|
|
668
|
+
lines.push(...edgeLines);
|
|
669
|
+
}
|
|
670
|
+
return lines.join("\n");
|
|
671
|
+
}
|
|
672
|
+
// ---------------------------------------------------------------------------
|
|
673
|
+
// Export Diagrams Markdown
|
|
674
|
+
// ---------------------------------------------------------------------------
|
|
675
|
+
export function exportDiagramsMd(mi, path) {
|
|
676
|
+
const diagrams = [
|
|
677
|
+
["c4-component", "C4 Component (Architecture)", c4ComponentMermaid(mi)],
|
|
678
|
+
["composition-flowchart", "Composition Flowchart", compositionFlowchartMermaid(mi)],
|
|
679
|
+
["er-diagram", "Entity Relationship", erDiagramMermaid(mi)],
|
|
680
|
+
["dependency-tree", "[Deprecated] Dependency Tree", dependencyTreeMermaid(mi)],
|
|
681
|
+
["kind-catalog", "Kind Catalog", kindCatalogMermaid(mi)],
|
|
682
|
+
["mindmap", "Mindmap", mindmapMermaid(mi)],
|
|
683
|
+
["pie-chart", "Document Distribution", pieChartMermaid(mi)],
|
|
684
|
+
["quadrant", "Agent Complexity", quadrantMermaid(mi)],
|
|
685
|
+
["timeline", "Prompt Composition", timelineMermaid(mi)],
|
|
686
|
+
["sankey", "Document Flow", sankeyMermaid(mi)],
|
|
687
|
+
];
|
|
688
|
+
const files = {};
|
|
689
|
+
for (const [slug, title, mermaid] of diagrams) {
|
|
690
|
+
files[`${slug}.md`] = `# ${title}\n\n\`\`\`mermaid\n${mermaid}\n\`\`\`\n`;
|
|
691
|
+
}
|
|
692
|
+
const allLines = [`# ${mi.scope} \u2014 All Diagrams\n`];
|
|
693
|
+
for (const [, title, mermaid] of diagrams) {
|
|
694
|
+
allLines.push(`## ${title}\n\n\`\`\`mermaid\n${mermaid}\n\`\`\`\n`);
|
|
695
|
+
}
|
|
696
|
+
files["all-diagrams.md"] = allLines.join("\n");
|
|
697
|
+
if (path) {
|
|
698
|
+
const { mkdirSync, writeFileSync } = require("node:fs");
|
|
699
|
+
const { join } = require("node:path");
|
|
700
|
+
mkdirSync(path, { recursive: true });
|
|
701
|
+
for (const [fname, content] of Object.entries(files)) {
|
|
702
|
+
writeFileSync(join(path, fname), content, "utf-8");
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return files;
|
|
706
|
+
}
|