@swarmvaultai/engine 1.1.0 → 1.3.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/README.md +3 -2
- package/dist/index.d.ts +51 -1
- package/dist/index.js +430 -28
- package/dist/viewer/assets/{index-TXBR63qb.js → index-DwLzGcBF.js} +1 -1
- package/dist/viewer/index.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7073,6 +7073,322 @@ function enrichGraph(graph, manifests, analyses, extraSimilarityEdges = [], opti
|
|
|
7073
7073
|
};
|
|
7074
7074
|
}
|
|
7075
7075
|
|
|
7076
|
+
// src/graph-share.ts
|
|
7077
|
+
function displayVaultName(value) {
|
|
7078
|
+
const trimmed = value?.trim();
|
|
7079
|
+
return trimmed ? trimmed : "this vault";
|
|
7080
|
+
}
|
|
7081
|
+
function sortedFallbackHubs(graph) {
|
|
7082
|
+
return graph.nodes.filter((node) => node.type !== "source").sort(
|
|
7083
|
+
(left, right) => (right.degree ?? 0) - (left.degree ?? 0) || (right.bridgeScore ?? 0) - (left.bridgeScore ?? 0) || left.label.localeCompare(right.label)
|
|
7084
|
+
).slice(0, 5);
|
|
7085
|
+
}
|
|
7086
|
+
function graphNodeMap(graph) {
|
|
7087
|
+
return new Map(graph.nodes.map((node) => [node.id, node]));
|
|
7088
|
+
}
|
|
7089
|
+
function compactJoin(values, fallback) {
|
|
7090
|
+
const filtered = values.filter(Boolean);
|
|
7091
|
+
if (!filtered.length) {
|
|
7092
|
+
return fallback;
|
|
7093
|
+
}
|
|
7094
|
+
if (filtered.length === 1) {
|
|
7095
|
+
return filtered[0] ?? fallback;
|
|
7096
|
+
}
|
|
7097
|
+
if (filtered.length === 2) {
|
|
7098
|
+
return `${filtered[0]} and ${filtered[1]}`;
|
|
7099
|
+
}
|
|
7100
|
+
return `${filtered.slice(0, -1).join(", ")}, and ${filtered[filtered.length - 1]}`;
|
|
7101
|
+
}
|
|
7102
|
+
function buildShortPost(input) {
|
|
7103
|
+
const topHubLine = input.topHubs.length ? `Top hubs: ${compactJoin(
|
|
7104
|
+
input.topHubs.slice(0, 3).map((node) => node.label),
|
|
7105
|
+
"still emerging"
|
|
7106
|
+
)}.` : "Top hubs are still emerging.";
|
|
7107
|
+
const surprise = input.surprisingConnections[0];
|
|
7108
|
+
const surpriseLine = surprise ? `Most surprising link: ${surprise.sourceLabel} ${surprise.relation} ${surprise.targetLabel}.` : "The graph is ready for its first surprising connection.";
|
|
7109
|
+
return [
|
|
7110
|
+
`I scanned ${input.vaultName} with SwarmVault: ${input.overview.sources} sources -> ${input.overview.pages} wiki pages, ${input.overview.nodes} graph nodes, ${input.overview.edges} edges.`,
|
|
7111
|
+
topHubLine,
|
|
7112
|
+
surpriseLine,
|
|
7113
|
+
"Everything stays local. Try: npm install -g @swarmvaultai/cli && swarmvault scan ./your-repo"
|
|
7114
|
+
].join("\n");
|
|
7115
|
+
}
|
|
7116
|
+
function escapeXml(value) {
|
|
7117
|
+
return String(value ?? "").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
7118
|
+
}
|
|
7119
|
+
function clipText(value, maxLength) {
|
|
7120
|
+
const normalized = value.replaceAll("\n", " ").replaceAll("\r", " ").trim();
|
|
7121
|
+
if (normalized.length <= maxLength) {
|
|
7122
|
+
return normalized;
|
|
7123
|
+
}
|
|
7124
|
+
return `${normalized.slice(0, Math.max(0, maxLength - 3)).trimEnd()}...`;
|
|
7125
|
+
}
|
|
7126
|
+
function svgText(input) {
|
|
7127
|
+
const attrs = [
|
|
7128
|
+
`x="${input.x}"`,
|
|
7129
|
+
`y="${input.y}"`,
|
|
7130
|
+
`font-size="${input.size}"`,
|
|
7131
|
+
`fill="${input.fill ?? "#f8fafc"}"`,
|
|
7132
|
+
`font-weight="${input.weight ?? 500}"`,
|
|
7133
|
+
`text-anchor="${input.anchor ?? "start"}"`,
|
|
7134
|
+
input.opacity === void 0 ? "" : `opacity="${input.opacity}"`
|
|
7135
|
+
].filter(Boolean);
|
|
7136
|
+
return ` <text ${attrs.join(" ")}>${escapeXml(input.text)}</text>`;
|
|
7137
|
+
}
|
|
7138
|
+
function svgStatCard(input) {
|
|
7139
|
+
return [
|
|
7140
|
+
` <rect x="${input.x}" y="${input.y}" width="168" height="92" rx="14" fill="#111827" stroke="#334155" />`,
|
|
7141
|
+
svgText({ x: input.x + 20, y: input.y + 36, text: String(input.value), size: 30, fill: "#ecfeff", weight: 800 }),
|
|
7142
|
+
svgText({ x: input.x + 20, y: input.y + 66, text: input.label, size: 16, fill: "#94a3b8", weight: 600 })
|
|
7143
|
+
];
|
|
7144
|
+
}
|
|
7145
|
+
function svgListLines(input) {
|
|
7146
|
+
const items = input.items.length ? input.items.slice(0, input.maxItems) : [input.empty];
|
|
7147
|
+
const lines = [svgText({ x: input.x, y: input.y, text: input.title, size: 19, fill: "#a7f3d0", weight: 800 })];
|
|
7148
|
+
for (const [index, item] of items.entries()) {
|
|
7149
|
+
lines.push(
|
|
7150
|
+
svgText({ x: input.x, y: input.y + 38 + index * 30, text: `- ${clipText(item, 58)}`, size: 19, fill: "#e2e8f0", weight: 600 })
|
|
7151
|
+
);
|
|
7152
|
+
}
|
|
7153
|
+
return lines;
|
|
7154
|
+
}
|
|
7155
|
+
function buildGraphShareArtifact(input) {
|
|
7156
|
+
const { graph, report } = input;
|
|
7157
|
+
const vaultName = displayVaultName(input.vaultName);
|
|
7158
|
+
const nodesById = graphNodeMap(graph);
|
|
7159
|
+
const fallbackHubs = sortedFallbackHubs(graph);
|
|
7160
|
+
const reportHubs = report?.godNodes.map((node) => {
|
|
7161
|
+
const graphNode = nodesById.get(node.nodeId);
|
|
7162
|
+
return {
|
|
7163
|
+
nodeId: node.nodeId,
|
|
7164
|
+
label: node.label ?? graphNode?.label ?? node.nodeId,
|
|
7165
|
+
degree: node.degree ?? graphNode?.degree
|
|
7166
|
+
};
|
|
7167
|
+
}) ?? [];
|
|
7168
|
+
const fallbackHubHighlights = fallbackHubs.map((node) => ({
|
|
7169
|
+
nodeId: node.id,
|
|
7170
|
+
label: node.label,
|
|
7171
|
+
degree: node.degree
|
|
7172
|
+
}));
|
|
7173
|
+
const topHubs = (reportHubs.length ? reportHubs : fallbackHubHighlights).slice(0, 5);
|
|
7174
|
+
const reportBridgeNodes = report?.bridgeNodes.map((node) => {
|
|
7175
|
+
const graphNode = nodesById.get(node.nodeId);
|
|
7176
|
+
return {
|
|
7177
|
+
nodeId: node.nodeId,
|
|
7178
|
+
label: node.label ?? graphNode?.label ?? node.nodeId,
|
|
7179
|
+
bridgeScore: node.bridgeScore ?? graphNode?.bridgeScore
|
|
7180
|
+
};
|
|
7181
|
+
}) ?? [];
|
|
7182
|
+
const fallbackBridgeNodes = fallbackHubs.map((node) => ({
|
|
7183
|
+
nodeId: node.id,
|
|
7184
|
+
label: node.label,
|
|
7185
|
+
bridgeScore: node.bridgeScore
|
|
7186
|
+
}));
|
|
7187
|
+
const bridgeNodes = (reportBridgeNodes.length ? reportBridgeNodes : fallbackBridgeNodes).slice(0, 3).filter((node) => node.label);
|
|
7188
|
+
const surprisingConnections = (report?.surprisingConnections ?? []).slice(0, 3).map((connection) => {
|
|
7189
|
+
const source = nodesById.get(connection.sourceNodeId);
|
|
7190
|
+
const target = nodesById.get(connection.targetNodeId);
|
|
7191
|
+
return {
|
|
7192
|
+
sourceLabel: source?.label ?? connection.sourceNodeId,
|
|
7193
|
+
targetLabel: target?.label ?? connection.targetNodeId,
|
|
7194
|
+
relation: connection.relation,
|
|
7195
|
+
why: truncate(connection.why || connection.explanation || "Cross-community connection", 180)
|
|
7196
|
+
};
|
|
7197
|
+
});
|
|
7198
|
+
const overview = {
|
|
7199
|
+
sources: graph.sources.length,
|
|
7200
|
+
nodes: report?.overview.nodes ?? graph.nodes.length,
|
|
7201
|
+
edges: report?.overview.edges ?? graph.edges.length,
|
|
7202
|
+
pages: report?.overview.pages ?? graph.pages.length,
|
|
7203
|
+
communities: report?.overview.communities ?? graph.communities?.length ?? 0
|
|
7204
|
+
};
|
|
7205
|
+
const firstPartyOverview = report?.firstPartyOverview ?? {
|
|
7206
|
+
nodes: graph.nodes.filter((node) => node.sourceClass === "first_party").length,
|
|
7207
|
+
edges: graph.edges.length,
|
|
7208
|
+
pages: graph.pages.filter((page) => page.sourceClass === "first_party").length,
|
|
7209
|
+
communities: graph.communities?.length ?? 0
|
|
7210
|
+
};
|
|
7211
|
+
const relatedNodeIds = uniqueBy([...topHubs.map((node) => node.nodeId), ...bridgeNodes.map((node) => node.nodeId)], (value) => value);
|
|
7212
|
+
const relatedPageIds = uniqueBy(
|
|
7213
|
+
relatedNodeIds.map((nodeId) => nodesById.get(nodeId)?.pageId).filter((pageId) => Boolean(pageId)),
|
|
7214
|
+
(value) => value
|
|
7215
|
+
);
|
|
7216
|
+
const relatedSourceIds = uniqueBy(
|
|
7217
|
+
[...graph.sources.map((source) => source.sourceId), ...relatedNodeIds.flatMap((nodeId) => nodesById.get(nodeId)?.sourceIds ?? [])],
|
|
7218
|
+
(value) => value
|
|
7219
|
+
);
|
|
7220
|
+
const knowledgeGaps = report?.knowledgeGaps?.warnings?.length ? report.knowledgeGaps.warnings.slice(0, 3) : report?.warnings?.length ? report.warnings.slice(0, 3) : [];
|
|
7221
|
+
const tagline = `A local-first map of ${vaultName}: ${overview.sources} sources compiled into ${overview.nodes} graph nodes and ${overview.pages} wiki pages.`;
|
|
7222
|
+
const artifact = {
|
|
7223
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7224
|
+
vaultName,
|
|
7225
|
+
tagline,
|
|
7226
|
+
overview,
|
|
7227
|
+
firstPartyOverview,
|
|
7228
|
+
highlights: {
|
|
7229
|
+
topHubs,
|
|
7230
|
+
bridgeNodes,
|
|
7231
|
+
surprisingConnections,
|
|
7232
|
+
suggestedQuestions: (report?.suggestedQuestions ?? []).slice(0, 5)
|
|
7233
|
+
},
|
|
7234
|
+
knowledgeGaps,
|
|
7235
|
+
shortPost: "",
|
|
7236
|
+
relatedNodeIds,
|
|
7237
|
+
relatedPageIds,
|
|
7238
|
+
relatedSourceIds
|
|
7239
|
+
};
|
|
7240
|
+
return {
|
|
7241
|
+
...artifact,
|
|
7242
|
+
shortPost: buildShortPost({
|
|
7243
|
+
vaultName,
|
|
7244
|
+
overview,
|
|
7245
|
+
topHubs,
|
|
7246
|
+
surprisingConnections
|
|
7247
|
+
})
|
|
7248
|
+
};
|
|
7249
|
+
}
|
|
7250
|
+
function renderGraphShareMarkdown(artifact) {
|
|
7251
|
+
const lines = [
|
|
7252
|
+
"# SwarmVault Share Card",
|
|
7253
|
+
"",
|
|
7254
|
+
`> ${artifact.tagline}`,
|
|
7255
|
+
"",
|
|
7256
|
+
"## Snapshot",
|
|
7257
|
+
"",
|
|
7258
|
+
`- Sources: ${artifact.overview.sources}`,
|
|
7259
|
+
`- Wiki pages: ${artifact.overview.pages}`,
|
|
7260
|
+
`- Graph nodes: ${artifact.overview.nodes}`,
|
|
7261
|
+
`- Graph edges: ${artifact.overview.edges}`,
|
|
7262
|
+
`- Communities: ${artifact.overview.communities}`,
|
|
7263
|
+
`- First-party focus: ${artifact.firstPartyOverview.nodes} nodes, ${artifact.firstPartyOverview.edges} edges, ${artifact.firstPartyOverview.pages} pages`,
|
|
7264
|
+
"",
|
|
7265
|
+
"## Highlights",
|
|
7266
|
+
"",
|
|
7267
|
+
artifact.highlights.topHubs.length ? `- Top hubs: ${compactJoin(
|
|
7268
|
+
artifact.highlights.topHubs.slice(0, 5).map((node) => node.degree ? `${node.label} (${node.degree})` : node.label),
|
|
7269
|
+
"none yet"
|
|
7270
|
+
)}` : "- Top hubs: none yet",
|
|
7271
|
+
artifact.highlights.bridgeNodes.length ? `- Bridge nodes: ${compactJoin(
|
|
7272
|
+
artifact.highlights.bridgeNodes.slice(0, 3).map((node) => node.label),
|
|
7273
|
+
"none yet"
|
|
7274
|
+
)}` : "- Bridge nodes: none yet",
|
|
7275
|
+
...artifact.highlights.surprisingConnections.length ? artifact.highlights.surprisingConnections.map(
|
|
7276
|
+
(connection) => `- Surprising link: ${connection.sourceLabel} ${connection.relation} ${connection.targetLabel}. ${connection.why}`
|
|
7277
|
+
) : ["- Surprising link: not enough cross-community evidence yet"],
|
|
7278
|
+
"",
|
|
7279
|
+
"## Ask Next",
|
|
7280
|
+
"",
|
|
7281
|
+
...artifact.highlights.suggestedQuestions.length ? artifact.highlights.suggestedQuestions.map((question) => `- ${question}`) : ["- Add more sources, run `swarmvault compile`, then ask the graph what changed."],
|
|
7282
|
+
"",
|
|
7283
|
+
"## Share Post",
|
|
7284
|
+
"",
|
|
7285
|
+
"```text",
|
|
7286
|
+
artifact.shortPost,
|
|
7287
|
+
"```",
|
|
7288
|
+
"",
|
|
7289
|
+
"## Reproduce",
|
|
7290
|
+
"",
|
|
7291
|
+
"```bash",
|
|
7292
|
+
"npm install -g @swarmvaultai/cli",
|
|
7293
|
+
"swarmvault scan ./your-repo",
|
|
7294
|
+
"swarmvault graph share --post",
|
|
7295
|
+
"```",
|
|
7296
|
+
""
|
|
7297
|
+
];
|
|
7298
|
+
if (artifact.knowledgeGaps.length) {
|
|
7299
|
+
lines.splice(
|
|
7300
|
+
lines.indexOf("## Ask Next"),
|
|
7301
|
+
0,
|
|
7302
|
+
"## Gaps To Strengthen",
|
|
7303
|
+
"",
|
|
7304
|
+
...artifact.knowledgeGaps.map((warning) => `- ${warning}`),
|
|
7305
|
+
""
|
|
7306
|
+
);
|
|
7307
|
+
}
|
|
7308
|
+
return `${lines.join("\n")}`;
|
|
7309
|
+
}
|
|
7310
|
+
function renderGraphShareSvg(artifact) {
|
|
7311
|
+
const topHubs = artifact.highlights.topHubs.map((node) => node.degree ? `${node.label} (${node.degree})` : node.label);
|
|
7312
|
+
const bridges = artifact.highlights.bridgeNodes.map((node) => node.label);
|
|
7313
|
+
const surprise = artifact.highlights.surprisingConnections[0];
|
|
7314
|
+
const surpriseLine = surprise ? `${surprise.sourceLabel} ${surprise.relation} ${surprise.targetLabel}` : "Add more sources to reveal the first surprising link";
|
|
7315
|
+
const generated = new Date(artifact.generatedAt);
|
|
7316
|
+
const generatedLabel = Number.isNaN(generated.getTime()) ? artifact.generatedAt : generated.toISOString().slice(0, 10);
|
|
7317
|
+
const lines = [
|
|
7318
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
7319
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630" role="img" aria-labelledby="title desc">`,
|
|
7320
|
+
` <title>SwarmVault share card for ${escapeXml(artifact.vaultName)}</title>`,
|
|
7321
|
+
` <desc>${escapeXml(artifact.tagline)}</desc>`,
|
|
7322
|
+
" <defs>",
|
|
7323
|
+
' <linearGradient id="background" x1="0" y1="0" x2="1" y2="1">',
|
|
7324
|
+
' <stop offset="0%" stop-color="#020617" />',
|
|
7325
|
+
' <stop offset="58%" stop-color="#0f172a" />',
|
|
7326
|
+
' <stop offset="100%" stop-color="#063f37" />',
|
|
7327
|
+
" </linearGradient>",
|
|
7328
|
+
' <linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">',
|
|
7329
|
+
' <stop offset="0%" stop-color="#22c55e" />',
|
|
7330
|
+
' <stop offset="100%" stop-color="#06b6d4" />',
|
|
7331
|
+
" </linearGradient>",
|
|
7332
|
+
" </defs>",
|
|
7333
|
+
' <rect width="1200" height="630" fill="url(#background)" />',
|
|
7334
|
+
' <rect x="34" y="34" width="1132" height="562" rx="28" fill="#020617" opacity="0.72" stroke="#1f2937" />',
|
|
7335
|
+
' <path d="M92 512 C214 386 314 456 438 326 C540 218 648 284 746 194 C860 88 1004 152 1110 84" fill="none" stroke="#22c55e" stroke-width="4" opacity="0.35" />',
|
|
7336
|
+
' <circle cx="92" cy="512" r="9" fill="#22c55e" />',
|
|
7337
|
+
' <circle cx="438" cy="326" r="10" fill="#06b6d4" />',
|
|
7338
|
+
' <circle cx="746" cy="194" r="10" fill="#a7f3d0" />',
|
|
7339
|
+
' <circle cx="1110" cy="84" r="9" fill="#22c55e" />',
|
|
7340
|
+
svgText({ x: 78, y: 96, text: "SwarmVault", size: 28, fill: "#86efac", weight: 900 }),
|
|
7341
|
+
svgText({ x: 78, y: 152, text: clipText(artifact.vaultName, 42), size: 54, fill: "#f8fafc", weight: 900 }),
|
|
7342
|
+
svgText({ x: 78, y: 196, text: clipText(artifact.tagline, 86), size: 22, fill: "#cbd5e1", weight: 600 }),
|
|
7343
|
+
...svgStatCard({ x: 78, y: 242, label: "Sources", value: artifact.overview.sources }),
|
|
7344
|
+
...svgStatCard({ x: 270, y: 242, label: "Wiki pages", value: artifact.overview.pages }),
|
|
7345
|
+
...svgStatCard({ x: 462, y: 242, label: "Graph nodes", value: artifact.overview.nodes }),
|
|
7346
|
+
...svgStatCard({ x: 654, y: 242, label: "Edges", value: artifact.overview.edges }),
|
|
7347
|
+
` <rect x="870" y="240" width="246" height="94" rx="18" fill="url(#accent)" opacity="0.95" />`,
|
|
7348
|
+
svgText({ x: 993, y: 278, text: "Local-first", size: 22, fill: "#052e16", weight: 900, anchor: "middle" }),
|
|
7349
|
+
svgText({ x: 993, y: 307, text: "no API keys required", size: 18, fill: "#064e3b", weight: 800, anchor: "middle" }),
|
|
7350
|
+
...svgListLines({
|
|
7351
|
+
x: 82,
|
|
7352
|
+
y: 398,
|
|
7353
|
+
title: "Top hubs",
|
|
7354
|
+
items: topHubs,
|
|
7355
|
+
empty: "Still emerging",
|
|
7356
|
+
maxItems: 3
|
|
7357
|
+
}),
|
|
7358
|
+
...svgListLines({
|
|
7359
|
+
x: 470,
|
|
7360
|
+
y: 398,
|
|
7361
|
+
title: "Bridge nodes",
|
|
7362
|
+
items: bridges,
|
|
7363
|
+
empty: "Still emerging",
|
|
7364
|
+
maxItems: 3
|
|
7365
|
+
}),
|
|
7366
|
+
svgText({ x: 820, y: 398, text: "Surprising link", size: 19, fill: "#a7f3d0", weight: 800 }),
|
|
7367
|
+
svgText({ x: 820, y: 436, text: clipText(surpriseLine, 40), size: 21, fill: "#e2e8f0", weight: 800 }),
|
|
7368
|
+
svgText({
|
|
7369
|
+
x: 820,
|
|
7370
|
+
y: 470,
|
|
7371
|
+
text: clipText(surprise?.why ?? "Run compile again after adding more sources.", 44),
|
|
7372
|
+
size: 17,
|
|
7373
|
+
fill: "#94a3b8",
|
|
7374
|
+
weight: 600
|
|
7375
|
+
}),
|
|
7376
|
+
` <rect x="78" y="536" width="744" height="42" rx="12" fill="#0f172a" stroke="#1e293b" />`,
|
|
7377
|
+
svgText({
|
|
7378
|
+
x: 100,
|
|
7379
|
+
y: 564,
|
|
7380
|
+
text: "npm install -g @swarmvaultai/cli && swarmvault scan ./your-repo",
|
|
7381
|
+
size: 18,
|
|
7382
|
+
fill: "#d1fae5",
|
|
7383
|
+
weight: 800
|
|
7384
|
+
}),
|
|
7385
|
+
svgText({ x: 1116, y: 564, text: `Generated ${generatedLabel}`, size: 16, fill: "#94a3b8", weight: 600, anchor: "end" }),
|
|
7386
|
+
"</svg>",
|
|
7387
|
+
""
|
|
7388
|
+
];
|
|
7389
|
+
return lines.join("\n");
|
|
7390
|
+
}
|
|
7391
|
+
|
|
7076
7392
|
// src/graph-query-core.ts
|
|
7077
7393
|
var NODE_TYPE_PRIORITY = {
|
|
7078
7394
|
concept: 6,
|
|
@@ -8907,6 +9223,65 @@ function buildGraphReportPage(input) {
|
|
|
8907
9223
|
content: matter2.stringify(body, frontmatter)
|
|
8908
9224
|
};
|
|
8909
9225
|
}
|
|
9226
|
+
function buildGraphSharePage(input) {
|
|
9227
|
+
const pageId = "graph:share-card";
|
|
9228
|
+
const pathValue = "graph/share-card.md";
|
|
9229
|
+
const artifact = input.artifact ?? buildGraphShareArtifact({
|
|
9230
|
+
graph: input.graph,
|
|
9231
|
+
report: input.report,
|
|
9232
|
+
vaultName: input.vaultName
|
|
9233
|
+
});
|
|
9234
|
+
const frontmatter = {
|
|
9235
|
+
page_id: pageId,
|
|
9236
|
+
kind: "graph_report",
|
|
9237
|
+
cssclasses: cssclassesFor("graph_report"),
|
|
9238
|
+
title: "Share Card",
|
|
9239
|
+
tags: ["graph", "share"],
|
|
9240
|
+
source_ids: artifact.relatedSourceIds,
|
|
9241
|
+
project_ids: [],
|
|
9242
|
+
node_ids: artifact.relatedNodeIds,
|
|
9243
|
+
freshness: "fresh",
|
|
9244
|
+
status: input.metadata.status,
|
|
9245
|
+
confidence: input.metadata.confidence,
|
|
9246
|
+
created_at: input.metadata.createdAt,
|
|
9247
|
+
updated_at: input.metadata.updatedAt,
|
|
9248
|
+
compiled_from: input.metadata.compiledFrom,
|
|
9249
|
+
managed_by: input.metadata.managedBy,
|
|
9250
|
+
backlinks: [],
|
|
9251
|
+
schema_hash: input.schemaHash,
|
|
9252
|
+
source_hashes: {},
|
|
9253
|
+
source_semantic_hashes: {},
|
|
9254
|
+
related_page_ids: artifact.relatedPageIds,
|
|
9255
|
+
related_node_ids: artifact.relatedNodeIds,
|
|
9256
|
+
related_source_ids: artifact.relatedSourceIds
|
|
9257
|
+
};
|
|
9258
|
+
return {
|
|
9259
|
+
page: {
|
|
9260
|
+
id: pageId,
|
|
9261
|
+
path: pathValue,
|
|
9262
|
+
title: "Share Card",
|
|
9263
|
+
kind: "graph_report",
|
|
9264
|
+
sourceIds: artifact.relatedSourceIds,
|
|
9265
|
+
projectIds: [],
|
|
9266
|
+
nodeIds: artifact.relatedNodeIds,
|
|
9267
|
+
freshness: "fresh",
|
|
9268
|
+
status: input.metadata.status,
|
|
9269
|
+
confidence: input.metadata.confidence,
|
|
9270
|
+
backlinks: [],
|
|
9271
|
+
schemaHash: input.schemaHash,
|
|
9272
|
+
sourceHashes: {},
|
|
9273
|
+
sourceSemanticHashes: {},
|
|
9274
|
+
relatedPageIds: artifact.relatedPageIds,
|
|
9275
|
+
relatedNodeIds: artifact.relatedNodeIds,
|
|
9276
|
+
relatedSourceIds: artifact.relatedSourceIds,
|
|
9277
|
+
createdAt: input.metadata.createdAt,
|
|
9278
|
+
updatedAt: input.metadata.updatedAt,
|
|
9279
|
+
compiledFrom: input.metadata.compiledFrom,
|
|
9280
|
+
managedBy: input.metadata.managedBy
|
|
9281
|
+
},
|
|
9282
|
+
content: matter2.stringify(renderGraphShareMarkdown(artifact), frontmatter)
|
|
9283
|
+
};
|
|
9284
|
+
}
|
|
8910
9285
|
function buildCommunitySummaryPage(input) {
|
|
8911
9286
|
const pageId = `graph:${input.community.id}`;
|
|
8912
9287
|
const pathValue = communityPagePath(input.community.id);
|
|
@@ -20099,7 +20474,7 @@ async function runDeepLint(rootDir, structuralFindings, options = {}) {
|
|
|
20099
20474
|
|
|
20100
20475
|
// src/output-artifacts.ts
|
|
20101
20476
|
import { z as z6 } from "zod";
|
|
20102
|
-
function
|
|
20477
|
+
function escapeXml2(value) {
|
|
20103
20478
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
20104
20479
|
}
|
|
20105
20480
|
function clampNumber(value, min, max) {
|
|
@@ -20170,7 +20545,7 @@ function renderChartSvg(spec) {
|
|
|
20170
20545
|
const y = projectY(value);
|
|
20171
20546
|
return [
|
|
20172
20547
|
`<line x1="${margin.left}" y1="${y}" x2="${width - margin.right}" y2="${y}" stroke="#dbe4ec" stroke-width="1" />`,
|
|
20173
|
-
`<text x="${margin.left - 16}" y="${y + 4}" text-anchor="end" font-size="14" fill="#475569">${
|
|
20548
|
+
`<text x="${margin.left - 16}" y="${y + 4}" text-anchor="end" font-size="14" fill="#475569">${escapeXml2(value.toFixed(0))}</text>`
|
|
20174
20549
|
].join("");
|
|
20175
20550
|
}).join("");
|
|
20176
20551
|
const bars = spec.kind === "bar" ? points.map((point) => {
|
|
@@ -20178,7 +20553,7 @@ function renderChartSvg(spec) {
|
|
|
20178
20553
|
const barHeight = Math.max(8, Math.abs(zeroY - point.y));
|
|
20179
20554
|
return [
|
|
20180
20555
|
`<rect x="${point.centerX - barWidth / 2}" y="${top}" width="${barWidth}" height="${barHeight}" rx="12" fill="#0ea5e9" opacity="0.92" />`,
|
|
20181
|
-
`<text x="${point.centerX}" y="${top - 10}" text-anchor="middle" font-size="13" fill="#0f172a">${
|
|
20556
|
+
`<text x="${point.centerX}" y="${top - 10}" text-anchor="middle" font-size="13" fill="#0f172a">${escapeXml2(
|
|
20182
20557
|
point.value.toFixed(0)
|
|
20183
20558
|
)}</text>`
|
|
20184
20559
|
].join("");
|
|
@@ -20188,33 +20563,33 @@ function renderChartSvg(spec) {
|
|
|
20188
20563
|
`<path d="${linePath}" fill="none" stroke="#0ea5e9" stroke-width="5" stroke-linecap="round" stroke-linejoin="round" />`,
|
|
20189
20564
|
...points.map(
|
|
20190
20565
|
(point) => `<circle cx="${point.centerX}" cy="${point.y}" r="8" fill="#f8fafc" stroke="#0ea5e9" stroke-width="4" />
|
|
20191
|
-
<text x="${point.centerX}" y="${point.y - 18}" text-anchor="middle" font-size="13" fill="#0f172a">${
|
|
20566
|
+
<text x="${point.centerX}" y="${point.y - 18}" text-anchor="middle" font-size="13" fill="#0f172a">${escapeXml2(
|
|
20192
20567
|
point.value.toFixed(0)
|
|
20193
20568
|
)}</text>`
|
|
20194
20569
|
)
|
|
20195
20570
|
].join("") : "";
|
|
20196
20571
|
const labels = points.map(
|
|
20197
|
-
(point) => `<text x="${point.centerX}" y="${height - margin.bottom + 28}" text-anchor="middle" font-size="14" fill="#334155">${
|
|
20572
|
+
(point) => `<text x="${point.centerX}" y="${height - margin.bottom + 28}" text-anchor="middle" font-size="14" fill="#334155">${escapeXml2(
|
|
20198
20573
|
point.label
|
|
20199
20574
|
)}</text>`
|
|
20200
20575
|
).join("");
|
|
20201
20576
|
const notes = (spec.notes ?? []).map(
|
|
20202
|
-
(note, index) => `<text x="${margin.left}" y="${height - 26 - index * 18}" font-size="13" fill="#475569">${
|
|
20577
|
+
(note, index) => `<text x="${margin.left}" y="${height - 26 - index * 18}" font-size="13" fill="#475569">${escapeXml2(note)}</text>`
|
|
20203
20578
|
).join("");
|
|
20204
20579
|
const svg = [
|
|
20205
|
-
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${
|
|
20580
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeXml2(spec.title)}">`,
|
|
20206
20581
|
'<rect width="100%" height="100%" fill="#f8fafc" />',
|
|
20207
|
-
`<text x="${margin.left}" y="56" font-size="34" font-weight="700" fill="#0f172a">${
|
|
20208
|
-
spec.subtitle ? `<text x="${margin.left}" y="86" font-size="18" fill="#475569">${
|
|
20582
|
+
`<text x="${margin.left}" y="56" font-size="34" font-weight="700" fill="#0f172a">${escapeXml2(spec.title)}</text>`,
|
|
20583
|
+
spec.subtitle ? `<text x="${margin.left}" y="86" font-size="18" fill="#475569">${escapeXml2(spec.subtitle)}</text>` : "",
|
|
20209
20584
|
gridLines,
|
|
20210
20585
|
`<line x1="${margin.left}" y1="${zeroY}" x2="${width - margin.right}" y2="${zeroY}" stroke="#0f172a" stroke-width="2" />`,
|
|
20211
20586
|
`<line x1="${margin.left}" y1="${margin.top}" x2="${margin.left}" y2="${height - margin.bottom}" stroke="#0f172a" stroke-width="2" />`,
|
|
20212
20587
|
bars,
|
|
20213
20588
|
lineMarks,
|
|
20214
20589
|
labels,
|
|
20215
|
-
spec.xLabel ? `<text x="${margin.left + chartWidth / 2}" y="${height - 46}" text-anchor="middle" font-size="15" fill="#475569">${
|
|
20216
|
-
spec.yLabel ? `<text x="34" y="${margin.top + chartHeight / 2}" text-anchor="middle" font-size="15" fill="#475569" transform="rotate(-90 34 ${margin.top + chartHeight / 2})">${
|
|
20217
|
-
spec.seriesLabel ? `<text x="${width - margin.right}" y="56" text-anchor="end" font-size="15" fill="#475569">${
|
|
20590
|
+
spec.xLabel ? `<text x="${margin.left + chartWidth / 2}" y="${height - 46}" text-anchor="middle" font-size="15" fill="#475569">${escapeXml2(spec.xLabel)}</text>` : "",
|
|
20591
|
+
spec.yLabel ? `<text x="34" y="${margin.top + chartHeight / 2}" text-anchor="middle" font-size="15" fill="#475569" transform="rotate(-90 34 ${margin.top + chartHeight / 2})">${escapeXml2(spec.yLabel)}</text>` : "",
|
|
20592
|
+
spec.seriesLabel ? `<text x="${width - margin.right}" y="56" text-anchor="end" font-size="15" fill="#475569">${escapeXml2(spec.seriesLabel)}</text>` : "",
|
|
20218
20593
|
notes,
|
|
20219
20594
|
"</svg>"
|
|
20220
20595
|
].filter(Boolean).join("");
|
|
@@ -20226,33 +20601,33 @@ function renderSceneSvg(spec) {
|
|
|
20226
20601
|
const elements = spec.elements.map((element) => {
|
|
20227
20602
|
const opacity = element.opacity === void 0 ? 1 : clampNumber(element.opacity, 0, 1);
|
|
20228
20603
|
if (element.kind === "label") {
|
|
20229
|
-
return `<text x="${element.x}" y="${element.y}" font-size="${clampNumber(element.fontSize ?? 28, 10, 72)}" fill="${
|
|
20604
|
+
return `<text x="${element.x}" y="${element.y}" font-size="${clampNumber(element.fontSize ?? 28, 10, 72)}" fill="${escapeXml2(
|
|
20230
20605
|
element.fill ?? "#0f172a"
|
|
20231
|
-
)}" opacity="${opacity}" font-family="'Avenir Next', 'Segoe UI', sans-serif">${
|
|
20606
|
+
)}" opacity="${opacity}" font-family="'Avenir Next', 'Segoe UI', sans-serif">${escapeXml2(element.text ?? "")}</text>`;
|
|
20232
20607
|
}
|
|
20233
20608
|
switch (element.shape) {
|
|
20234
20609
|
case "circle":
|
|
20235
|
-
return `<circle cx="${element.x}" cy="${element.y}" r="${Math.max(6, element.radius ?? 40)}" fill="${
|
|
20610
|
+
return `<circle cx="${element.x}" cy="${element.y}" r="${Math.max(6, element.radius ?? 40)}" fill="${escapeXml2(
|
|
20236
20611
|
element.fill ?? "#dbeafe"
|
|
20237
|
-
)}" stroke="${
|
|
20612
|
+
)}" stroke="${escapeXml2(element.stroke ?? "#0ea5e9")}" stroke-width="${Math.max(1, element.strokeWidth ?? 2)}" opacity="${opacity}" />`;
|
|
20238
20613
|
case "line":
|
|
20239
|
-
return `<line x1="${element.x}" y1="${element.y}" x2="${element.x + (element.width ?? 120)}" y2="${element.y + (element.height ?? 0)}" stroke="${
|
|
20614
|
+
return `<line x1="${element.x}" y1="${element.y}" x2="${element.x + (element.width ?? 120)}" y2="${element.y + (element.height ?? 0)}" stroke="${escapeXml2(element.stroke ?? "#475569")}" stroke-width="${Math.max(1, element.strokeWidth ?? 3)}" opacity="${opacity}" />`;
|
|
20240
20615
|
default:
|
|
20241
20616
|
return `<rect x="${element.x}" y="${element.y}" width="${Math.max(8, element.width ?? 160)}" height="${Math.max(
|
|
20242
20617
|
8,
|
|
20243
20618
|
element.height ?? 120
|
|
20244
|
-
)}" rx="22" fill="${
|
|
20619
|
+
)}" rx="22" fill="${escapeXml2(element.fill ?? "#e2e8f0")}" stroke="${escapeXml2(element.stroke ?? "#94a3b8")}" stroke-width="${Math.max(
|
|
20245
20620
|
1,
|
|
20246
20621
|
element.strokeWidth ?? 2
|
|
20247
20622
|
)}" opacity="${opacity}" />`;
|
|
20248
20623
|
}
|
|
20249
20624
|
}).join("");
|
|
20250
20625
|
const svg = [
|
|
20251
|
-
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${
|
|
20626
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeXml2(
|
|
20252
20627
|
spec.alt
|
|
20253
20628
|
)}">`,
|
|
20254
|
-
`<rect width="100%" height="100%" fill="${
|
|
20255
|
-
`<text x="48" y="64" font-size="34" font-weight="700" fill="#0f172a">${
|
|
20629
|
+
`<rect width="100%" height="100%" fill="${escapeXml2(spec.background ?? "#f8fafc")}" />`,
|
|
20630
|
+
`<text x="48" y="64" font-size="34" font-weight="700" fill="#0f172a">${escapeXml2(spec.title)}</text>`,
|
|
20256
20631
|
elements,
|
|
20257
20632
|
`</svg>`
|
|
20258
20633
|
].join("");
|
|
@@ -20263,12 +20638,12 @@ function renderRasterPosterSvg(input) {
|
|
|
20263
20638
|
const height = clampNumber(input.height ?? 720, 320, 1200);
|
|
20264
20639
|
const inset = 42;
|
|
20265
20640
|
const svg = [
|
|
20266
|
-
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${
|
|
20641
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" role="img" aria-label="${escapeXml2(
|
|
20267
20642
|
input.alt
|
|
20268
20643
|
)}">`,
|
|
20269
20644
|
'<rect width="100%" height="100%" fill="#f8fafc" />',
|
|
20270
|
-
`<text x="${inset}" y="56" font-size="34" font-weight="700" fill="#0f172a">${
|
|
20271
|
-
`<image href="${
|
|
20645
|
+
`<text x="${inset}" y="56" font-size="34" font-weight="700" fill="#0f172a">${escapeXml2(input.title)}</text>`,
|
|
20646
|
+
`<image href="${escapeXml2(input.rasterFileName)}" x="${inset}" y="92" width="${width - inset * 2}" height="${height - 148}" preserveAspectRatio="xMidYMid meet" />`,
|
|
20272
20647
|
`</svg>`
|
|
20273
20648
|
].join("");
|
|
20274
20649
|
return { svg, width, height };
|
|
@@ -22641,9 +23016,31 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
|
|
|
22641
23016
|
report
|
|
22642
23017
|
})
|
|
22643
23018
|
);
|
|
23019
|
+
const shareArtifact = buildGraphShareArtifact({
|
|
23020
|
+
graph,
|
|
23021
|
+
report,
|
|
23022
|
+
vaultName: path26.basename(paths.rootDir)
|
|
23023
|
+
});
|
|
23024
|
+
const shareRecord = await buildManagedGraphPage(
|
|
23025
|
+
path26.join(paths.wikiDir, "graph", "share-card.md"),
|
|
23026
|
+
{
|
|
23027
|
+
managedBy: "system",
|
|
23028
|
+
compiledFrom: uniqueStrings4(graph.pages.flatMap((page) => page.sourceIds)),
|
|
23029
|
+
confidence: 1
|
|
23030
|
+
},
|
|
23031
|
+
(metadata) => buildGraphSharePage({
|
|
23032
|
+
graph,
|
|
23033
|
+
schemaHash,
|
|
23034
|
+
metadata,
|
|
23035
|
+
artifact: shareArtifact,
|
|
23036
|
+
report,
|
|
23037
|
+
vaultName: path26.basename(paths.rootDir)
|
|
23038
|
+
})
|
|
23039
|
+
);
|
|
22644
23040
|
return {
|
|
22645
|
-
records: [reportRecord, ...communityRecords],
|
|
22646
|
-
report
|
|
23041
|
+
records: [reportRecord, shareRecord, ...communityRecords],
|
|
23042
|
+
report,
|
|
23043
|
+
shareSvg: renderGraphShareSvg(shareArtifact)
|
|
22647
23044
|
};
|
|
22648
23045
|
}
|
|
22649
23046
|
async function writePage(wikiDir, relativePath, content, changedPages) {
|
|
@@ -23264,6 +23661,7 @@ async function syncVaultArtifacts(rootDir, input) {
|
|
|
23264
23661
|
}
|
|
23265
23662
|
await writeJsonFile(paths.graphPath, graph);
|
|
23266
23663
|
await writeJsonFile(path26.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
|
|
23664
|
+
await writeFileIfChanged(path26.join(paths.wikiDir, "graph", "share-card.svg"), graphOrientation.shareSvg);
|
|
23267
23665
|
await writeJsonFile(paths.codeIndexPath, input.codeIndex);
|
|
23268
23666
|
await writeJsonFile(paths.compileStatePath, {
|
|
23269
23667
|
generatedAt: graph.generatedAt,
|
|
@@ -23322,7 +23720,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
23322
23720
|
compileState?.generatedAt,
|
|
23323
23721
|
[],
|
|
23324
23722
|
config
|
|
23325
|
-
) : { records: [], report: null };
|
|
23723
|
+
) : { records: [], report: null, shareSvg: "" };
|
|
23326
23724
|
const dashboardRecords = currentGraph ? await buildDashboardRecords(
|
|
23327
23725
|
config,
|
|
23328
23726
|
paths,
|
|
@@ -23458,6 +23856,7 @@ async function refreshIndexesAndSearch(rootDir, pages) {
|
|
|
23458
23856
|
}
|
|
23459
23857
|
if (graphOrientation.report) {
|
|
23460
23858
|
await writeJsonFile(path26.join(paths.wikiDir, "graph", "report.json"), graphOrientation.report);
|
|
23859
|
+
await writeFileIfChanged(path26.join(paths.wikiDir, "graph", "share-card.svg"), graphOrientation.shareSvg);
|
|
23461
23860
|
}
|
|
23462
23861
|
const existingProjectIndexPaths = (await listFilesRecursive(paths.projectsDir)).filter((absolutePath) => absolutePath.endsWith(".md")).map((absolutePath) => toPosix(path26.relative(paths.wikiDir, absolutePath)));
|
|
23463
23862
|
const allowedProjectIndexPaths = /* @__PURE__ */ new Set([
|
|
@@ -26615,7 +27014,7 @@ async function getWatchStatus(rootDir) {
|
|
|
26615
27014
|
}
|
|
26616
27015
|
|
|
26617
27016
|
// src/mcp.ts
|
|
26618
|
-
var SERVER_VERSION = "1.
|
|
27017
|
+
var SERVER_VERSION = "1.3.0";
|
|
26619
27018
|
async function createMcpServer(rootDir) {
|
|
26620
27019
|
const server = new McpServer({
|
|
26621
27020
|
name: "swarmvault",
|
|
@@ -30072,6 +30471,7 @@ export {
|
|
|
30072
30471
|
blastRadiusVault,
|
|
30073
30472
|
bootstrapDemo,
|
|
30074
30473
|
buildConfiguredRedactor,
|
|
30474
|
+
buildGraphShareArtifact,
|
|
30075
30475
|
buildRedactor,
|
|
30076
30476
|
compileVault,
|
|
30077
30477
|
computeDecayScore,
|
|
@@ -30147,6 +30547,8 @@ export {
|
|
|
30147
30547
|
rejectApproval,
|
|
30148
30548
|
reloadManagedSources,
|
|
30149
30549
|
removeWatchedRoot,
|
|
30550
|
+
renderGraphShareMarkdown,
|
|
30551
|
+
renderGraphShareSvg,
|
|
30150
30552
|
resetDecay,
|
|
30151
30553
|
resolveConsolidationConfig,
|
|
30152
30554
|
resolveDecayConfig,
|