@swarmvaultai/engine 1.0.1 → 1.2.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 +3 -2
- package/dist/chunk-UQCF65BN.js +1623 -0
- package/dist/hooks/claude.js +0 -0
- package/dist/hooks/copilot.js +0 -0
- package/dist/hooks/gemini.js +0 -0
- package/dist/index.d.ts +185 -1
- package/dist/index.js +522 -91
- package/dist/registry-GH4O3A7H.js +12 -0
- package/dist/viewer/assets/{index-TXBR63qb.js → index-DwLzGcBF.js} +1 -1
- package/dist/viewer/index.html +1 -1
- package/package.json +8 -9
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
LocalWhisperProviderAdapter,
|
|
2
3
|
PRIMARY_SCHEMA_FILENAME,
|
|
3
4
|
appendJsonLine,
|
|
4
5
|
assertProviderCapability,
|
|
@@ -23,7 +24,7 @@ import {
|
|
|
23
24
|
uniqueBy,
|
|
24
25
|
writeFileIfChanged,
|
|
25
26
|
writeJsonFile
|
|
26
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-UQCF65BN.js";
|
|
27
28
|
import {
|
|
28
29
|
estimatePageTokens,
|
|
29
30
|
estimateTokens,
|
|
@@ -7072,6 +7073,202 @@ function enrichGraph(graph, manifests, analyses, extraSimilarityEdges = [], opti
|
|
|
7072
7073
|
};
|
|
7073
7074
|
}
|
|
7074
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 buildGraphShareArtifact(input) {
|
|
7117
|
+
const { graph, report } = input;
|
|
7118
|
+
const vaultName = displayVaultName(input.vaultName);
|
|
7119
|
+
const nodesById = graphNodeMap(graph);
|
|
7120
|
+
const fallbackHubs = sortedFallbackHubs(graph);
|
|
7121
|
+
const reportHubs = report?.godNodes.map((node) => {
|
|
7122
|
+
const graphNode = nodesById.get(node.nodeId);
|
|
7123
|
+
return {
|
|
7124
|
+
nodeId: node.nodeId,
|
|
7125
|
+
label: node.label ?? graphNode?.label ?? node.nodeId,
|
|
7126
|
+
degree: node.degree ?? graphNode?.degree
|
|
7127
|
+
};
|
|
7128
|
+
}) ?? [];
|
|
7129
|
+
const fallbackHubHighlights = fallbackHubs.map((node) => ({
|
|
7130
|
+
nodeId: node.id,
|
|
7131
|
+
label: node.label,
|
|
7132
|
+
degree: node.degree
|
|
7133
|
+
}));
|
|
7134
|
+
const topHubs = (reportHubs.length ? reportHubs : fallbackHubHighlights).slice(0, 5);
|
|
7135
|
+
const reportBridgeNodes = report?.bridgeNodes.map((node) => {
|
|
7136
|
+
const graphNode = nodesById.get(node.nodeId);
|
|
7137
|
+
return {
|
|
7138
|
+
nodeId: node.nodeId,
|
|
7139
|
+
label: node.label ?? graphNode?.label ?? node.nodeId,
|
|
7140
|
+
bridgeScore: node.bridgeScore ?? graphNode?.bridgeScore
|
|
7141
|
+
};
|
|
7142
|
+
}) ?? [];
|
|
7143
|
+
const fallbackBridgeNodes = fallbackHubs.map((node) => ({
|
|
7144
|
+
nodeId: node.id,
|
|
7145
|
+
label: node.label,
|
|
7146
|
+
bridgeScore: node.bridgeScore
|
|
7147
|
+
}));
|
|
7148
|
+
const bridgeNodes = (reportBridgeNodes.length ? reportBridgeNodes : fallbackBridgeNodes).slice(0, 3).filter((node) => node.label);
|
|
7149
|
+
const surprisingConnections = (report?.surprisingConnections ?? []).slice(0, 3).map((connection) => {
|
|
7150
|
+
const source = nodesById.get(connection.sourceNodeId);
|
|
7151
|
+
const target = nodesById.get(connection.targetNodeId);
|
|
7152
|
+
return {
|
|
7153
|
+
sourceLabel: source?.label ?? connection.sourceNodeId,
|
|
7154
|
+
targetLabel: target?.label ?? connection.targetNodeId,
|
|
7155
|
+
relation: connection.relation,
|
|
7156
|
+
why: truncate(connection.why || connection.explanation || "Cross-community connection", 180)
|
|
7157
|
+
};
|
|
7158
|
+
});
|
|
7159
|
+
const overview = {
|
|
7160
|
+
sources: graph.sources.length,
|
|
7161
|
+
nodes: report?.overview.nodes ?? graph.nodes.length,
|
|
7162
|
+
edges: report?.overview.edges ?? graph.edges.length,
|
|
7163
|
+
pages: report?.overview.pages ?? graph.pages.length,
|
|
7164
|
+
communities: report?.overview.communities ?? graph.communities?.length ?? 0
|
|
7165
|
+
};
|
|
7166
|
+
const firstPartyOverview = report?.firstPartyOverview ?? {
|
|
7167
|
+
nodes: graph.nodes.filter((node) => node.sourceClass === "first_party").length,
|
|
7168
|
+
edges: graph.edges.length,
|
|
7169
|
+
pages: graph.pages.filter((page) => page.sourceClass === "first_party").length,
|
|
7170
|
+
communities: graph.communities?.length ?? 0
|
|
7171
|
+
};
|
|
7172
|
+
const relatedNodeIds = uniqueBy([...topHubs.map((node) => node.nodeId), ...bridgeNodes.map((node) => node.nodeId)], (value) => value);
|
|
7173
|
+
const relatedPageIds = uniqueBy(
|
|
7174
|
+
relatedNodeIds.map((nodeId) => nodesById.get(nodeId)?.pageId).filter((pageId) => Boolean(pageId)),
|
|
7175
|
+
(value) => value
|
|
7176
|
+
);
|
|
7177
|
+
const relatedSourceIds = uniqueBy(
|
|
7178
|
+
[...graph.sources.map((source) => source.sourceId), ...relatedNodeIds.flatMap((nodeId) => nodesById.get(nodeId)?.sourceIds ?? [])],
|
|
7179
|
+
(value) => value
|
|
7180
|
+
);
|
|
7181
|
+
const knowledgeGaps = report?.knowledgeGaps?.warnings?.length ? report.knowledgeGaps.warnings.slice(0, 3) : report?.warnings?.length ? report.warnings.slice(0, 3) : [];
|
|
7182
|
+
const tagline = `A local-first map of ${vaultName}: ${overview.sources} sources compiled into ${overview.nodes} graph nodes and ${overview.pages} wiki pages.`;
|
|
7183
|
+
const artifact = {
|
|
7184
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7185
|
+
vaultName,
|
|
7186
|
+
tagline,
|
|
7187
|
+
overview,
|
|
7188
|
+
firstPartyOverview,
|
|
7189
|
+
highlights: {
|
|
7190
|
+
topHubs,
|
|
7191
|
+
bridgeNodes,
|
|
7192
|
+
surprisingConnections,
|
|
7193
|
+
suggestedQuestions: (report?.suggestedQuestions ?? []).slice(0, 5)
|
|
7194
|
+
},
|
|
7195
|
+
knowledgeGaps,
|
|
7196
|
+
shortPost: "",
|
|
7197
|
+
relatedNodeIds,
|
|
7198
|
+
relatedPageIds,
|
|
7199
|
+
relatedSourceIds
|
|
7200
|
+
};
|
|
7201
|
+
return {
|
|
7202
|
+
...artifact,
|
|
7203
|
+
shortPost: buildShortPost({
|
|
7204
|
+
vaultName,
|
|
7205
|
+
overview,
|
|
7206
|
+
topHubs,
|
|
7207
|
+
surprisingConnections
|
|
7208
|
+
})
|
|
7209
|
+
};
|
|
7210
|
+
}
|
|
7211
|
+
function renderGraphShareMarkdown(artifact) {
|
|
7212
|
+
const lines = [
|
|
7213
|
+
"# SwarmVault Share Card",
|
|
7214
|
+
"",
|
|
7215
|
+
`> ${artifact.tagline}`,
|
|
7216
|
+
"",
|
|
7217
|
+
"## Snapshot",
|
|
7218
|
+
"",
|
|
7219
|
+
`- Sources: ${artifact.overview.sources}`,
|
|
7220
|
+
`- Wiki pages: ${artifact.overview.pages}`,
|
|
7221
|
+
`- Graph nodes: ${artifact.overview.nodes}`,
|
|
7222
|
+
`- Graph edges: ${artifact.overview.edges}`,
|
|
7223
|
+
`- Communities: ${artifact.overview.communities}`,
|
|
7224
|
+
`- First-party focus: ${artifact.firstPartyOverview.nodes} nodes, ${artifact.firstPartyOverview.edges} edges, ${artifact.firstPartyOverview.pages} pages`,
|
|
7225
|
+
"",
|
|
7226
|
+
"## Highlights",
|
|
7227
|
+
"",
|
|
7228
|
+
artifact.highlights.topHubs.length ? `- Top hubs: ${compactJoin(
|
|
7229
|
+
artifact.highlights.topHubs.slice(0, 5).map((node) => node.degree ? `${node.label} (${node.degree})` : node.label),
|
|
7230
|
+
"none yet"
|
|
7231
|
+
)}` : "- Top hubs: none yet",
|
|
7232
|
+
artifact.highlights.bridgeNodes.length ? `- Bridge nodes: ${compactJoin(
|
|
7233
|
+
artifact.highlights.bridgeNodes.slice(0, 3).map((node) => node.label),
|
|
7234
|
+
"none yet"
|
|
7235
|
+
)}` : "- Bridge nodes: none yet",
|
|
7236
|
+
...artifact.highlights.surprisingConnections.length ? artifact.highlights.surprisingConnections.map(
|
|
7237
|
+
(connection) => `- Surprising link: ${connection.sourceLabel} ${connection.relation} ${connection.targetLabel}. ${connection.why}`
|
|
7238
|
+
) : ["- Surprising link: not enough cross-community evidence yet"],
|
|
7239
|
+
"",
|
|
7240
|
+
"## Ask Next",
|
|
7241
|
+
"",
|
|
7242
|
+
...artifact.highlights.suggestedQuestions.length ? artifact.highlights.suggestedQuestions.map((question) => `- ${question}`) : ["- Add more sources, run `swarmvault compile`, then ask the graph what changed."],
|
|
7243
|
+
"",
|
|
7244
|
+
"## Share Post",
|
|
7245
|
+
"",
|
|
7246
|
+
"```text",
|
|
7247
|
+
artifact.shortPost,
|
|
7248
|
+
"```",
|
|
7249
|
+
"",
|
|
7250
|
+
"## Reproduce",
|
|
7251
|
+
"",
|
|
7252
|
+
"```bash",
|
|
7253
|
+
"npm install -g @swarmvaultai/cli",
|
|
7254
|
+
"swarmvault scan ./your-repo",
|
|
7255
|
+
"swarmvault graph share --post",
|
|
7256
|
+
"```",
|
|
7257
|
+
""
|
|
7258
|
+
];
|
|
7259
|
+
if (artifact.knowledgeGaps.length) {
|
|
7260
|
+
lines.splice(
|
|
7261
|
+
lines.indexOf("## Ask Next"),
|
|
7262
|
+
0,
|
|
7263
|
+
"## Gaps To Strengthen",
|
|
7264
|
+
"",
|
|
7265
|
+
...artifact.knowledgeGaps.map((warning) => `- ${warning}`),
|
|
7266
|
+
""
|
|
7267
|
+
);
|
|
7268
|
+
}
|
|
7269
|
+
return `${lines.join("\n")}`;
|
|
7270
|
+
}
|
|
7271
|
+
|
|
7075
7272
|
// src/graph-query-core.ts
|
|
7076
7273
|
var NODE_TYPE_PRIORITY = {
|
|
7077
7274
|
concept: 6,
|
|
@@ -8379,15 +8576,15 @@ function sourceTypeForNode(node, pagesById) {
|
|
|
8379
8576
|
return pagesById.get(node.pageId)?.sourceType;
|
|
8380
8577
|
}
|
|
8381
8578
|
function supportingPathDetails(graph, edge) {
|
|
8382
|
-
const
|
|
8579
|
+
const path33 = shortestGraphPath(graph, edge.source, edge.target);
|
|
8383
8580
|
const edgesById = new Map(graph.edges.map((item) => [item.id, item]));
|
|
8384
|
-
const pathEdges =
|
|
8581
|
+
const pathEdges = path33.edgeIds.map((edgeId) => edgesById.get(edgeId)).filter((item) => Boolean(item));
|
|
8385
8582
|
return {
|
|
8386
|
-
pathNodeIds:
|
|
8387
|
-
pathEdgeIds:
|
|
8583
|
+
pathNodeIds: path33.nodeIds,
|
|
8584
|
+
pathEdgeIds: path33.edgeIds,
|
|
8388
8585
|
pathRelations: pathEdges.map((item) => item.relation),
|
|
8389
8586
|
pathEvidenceClasses: pathEdges.map((item) => item.evidenceClass),
|
|
8390
|
-
pathSummary:
|
|
8587
|
+
pathSummary: path33.summary
|
|
8391
8588
|
};
|
|
8392
8589
|
}
|
|
8393
8590
|
function surpriseScore(edge, graph, pagesById, hyperedgesByNodeId) {
|
|
@@ -8456,7 +8653,7 @@ function topSurprisingConnections(graph, pagesById) {
|
|
|
8456
8653
|
}).map((edge) => {
|
|
8457
8654
|
const source = nodesById.get(edge.source);
|
|
8458
8655
|
const target = nodesById.get(edge.target);
|
|
8459
|
-
const
|
|
8656
|
+
const path33 = supportingPathDetails(graph, edge);
|
|
8460
8657
|
const scored = surpriseScore(edge, graph, pagesById, hyperedgesByNodeId);
|
|
8461
8658
|
return {
|
|
8462
8659
|
id: edge.id,
|
|
@@ -8467,11 +8664,11 @@ function topSurprisingConnections(graph, pagesById) {
|
|
|
8467
8664
|
relation: edge.relation,
|
|
8468
8665
|
evidenceClass: edge.evidenceClass,
|
|
8469
8666
|
confidence: edge.confidence,
|
|
8470
|
-
pathNodeIds:
|
|
8471
|
-
pathEdgeIds:
|
|
8472
|
-
pathRelations:
|
|
8473
|
-
pathEvidenceClasses:
|
|
8474
|
-
pathSummary:
|
|
8667
|
+
pathNodeIds: path33.pathNodeIds,
|
|
8668
|
+
pathEdgeIds: path33.pathEdgeIds,
|
|
8669
|
+
pathRelations: path33.pathRelations,
|
|
8670
|
+
pathEvidenceClasses: path33.pathEvidenceClasses,
|
|
8671
|
+
pathSummary: path33.pathSummary,
|
|
8475
8672
|
why: scored.why,
|
|
8476
8673
|
explanation: scored.explanation,
|
|
8477
8674
|
surpriseScore: scored.score
|
|
@@ -8906,6 +9103,65 @@ function buildGraphReportPage(input) {
|
|
|
8906
9103
|
content: matter2.stringify(body, frontmatter)
|
|
8907
9104
|
};
|
|
8908
9105
|
}
|
|
9106
|
+
function buildGraphSharePage(input) {
|
|
9107
|
+
const pageId = "graph:share-card";
|
|
9108
|
+
const pathValue = "graph/share-card.md";
|
|
9109
|
+
const artifact = buildGraphShareArtifact({
|
|
9110
|
+
graph: input.graph,
|
|
9111
|
+
report: input.report,
|
|
9112
|
+
vaultName: input.vaultName
|
|
9113
|
+
});
|
|
9114
|
+
const frontmatter = {
|
|
9115
|
+
page_id: pageId,
|
|
9116
|
+
kind: "graph_report",
|
|
9117
|
+
cssclasses: cssclassesFor("graph_report"),
|
|
9118
|
+
title: "Share Card",
|
|
9119
|
+
tags: ["graph", "share"],
|
|
9120
|
+
source_ids: artifact.relatedSourceIds,
|
|
9121
|
+
project_ids: [],
|
|
9122
|
+
node_ids: artifact.relatedNodeIds,
|
|
9123
|
+
freshness: "fresh",
|
|
9124
|
+
status: input.metadata.status,
|
|
9125
|
+
confidence: input.metadata.confidence,
|
|
9126
|
+
created_at: input.metadata.createdAt,
|
|
9127
|
+
updated_at: input.metadata.updatedAt,
|
|
9128
|
+
compiled_from: input.metadata.compiledFrom,
|
|
9129
|
+
managed_by: input.metadata.managedBy,
|
|
9130
|
+
backlinks: [],
|
|
9131
|
+
schema_hash: input.schemaHash,
|
|
9132
|
+
source_hashes: {},
|
|
9133
|
+
source_semantic_hashes: {},
|
|
9134
|
+
related_page_ids: artifact.relatedPageIds,
|
|
9135
|
+
related_node_ids: artifact.relatedNodeIds,
|
|
9136
|
+
related_source_ids: artifact.relatedSourceIds
|
|
9137
|
+
};
|
|
9138
|
+
return {
|
|
9139
|
+
page: {
|
|
9140
|
+
id: pageId,
|
|
9141
|
+
path: pathValue,
|
|
9142
|
+
title: "Share Card",
|
|
9143
|
+
kind: "graph_report",
|
|
9144
|
+
sourceIds: artifact.relatedSourceIds,
|
|
9145
|
+
projectIds: [],
|
|
9146
|
+
nodeIds: artifact.relatedNodeIds,
|
|
9147
|
+
freshness: "fresh",
|
|
9148
|
+
status: input.metadata.status,
|
|
9149
|
+
confidence: input.metadata.confidence,
|
|
9150
|
+
backlinks: [],
|
|
9151
|
+
schemaHash: input.schemaHash,
|
|
9152
|
+
sourceHashes: {},
|
|
9153
|
+
sourceSemanticHashes: {},
|
|
9154
|
+
relatedPageIds: artifact.relatedPageIds,
|
|
9155
|
+
relatedNodeIds: artifact.relatedNodeIds,
|
|
9156
|
+
relatedSourceIds: artifact.relatedSourceIds,
|
|
9157
|
+
createdAt: input.metadata.createdAt,
|
|
9158
|
+
updatedAt: input.metadata.updatedAt,
|
|
9159
|
+
compiledFrom: input.metadata.compiledFrom,
|
|
9160
|
+
managedBy: input.metadata.managedBy
|
|
9161
|
+
},
|
|
9162
|
+
content: matter2.stringify(renderGraphShareMarkdown(artifact), frontmatter)
|
|
9163
|
+
};
|
|
9164
|
+
}
|
|
8909
9165
|
function buildCommunitySummaryPage(input) {
|
|
8910
9166
|
const pageId = `graph:${input.community.id}`;
|
|
8911
9167
|
const pathValue = communityPagePath(input.community.id);
|
|
@@ -18310,7 +18566,8 @@ function isSupportedInboxKind(sourceKind) {
|
|
|
18310
18566
|
"chat_export",
|
|
18311
18567
|
"email",
|
|
18312
18568
|
"calendar",
|
|
18313
|
-
"image"
|
|
18569
|
+
"image",
|
|
18570
|
+
"audio"
|
|
18314
18571
|
].includes(sourceKind);
|
|
18315
18572
|
}
|
|
18316
18573
|
async function ingestInputDetailed(rootDir, input, options) {
|
|
@@ -20897,7 +21154,7 @@ async function resolveImageGenerationProvider(rootDir) {
|
|
|
20897
21154
|
if (!providerConfig) {
|
|
20898
21155
|
throw new Error(`No provider configured with id "${preferredProviderId}" for task "imageProvider".`);
|
|
20899
21156
|
}
|
|
20900
|
-
const { createProvider: createProvider2 } = await import("./registry-
|
|
21157
|
+
const { createProvider: createProvider2 } = await import("./registry-GH4O3A7H.js");
|
|
20901
21158
|
return createProvider2(preferredProviderId, providerConfig, rootDir);
|
|
20902
21159
|
}
|
|
20903
21160
|
async function generateOutputArtifacts(rootDir, input) {
|
|
@@ -22639,8 +22896,23 @@ async function buildGraphOrientationPages(graph, paths, schemaHash, previousComp
|
|
|
22639
22896
|
report
|
|
22640
22897
|
})
|
|
22641
22898
|
);
|
|
22899
|
+
const shareRecord = await buildManagedGraphPage(
|
|
22900
|
+
path26.join(paths.wikiDir, "graph", "share-card.md"),
|
|
22901
|
+
{
|
|
22902
|
+
managedBy: "system",
|
|
22903
|
+
compiledFrom: uniqueStrings4(graph.pages.flatMap((page) => page.sourceIds)),
|
|
22904
|
+
confidence: 1
|
|
22905
|
+
},
|
|
22906
|
+
(metadata) => buildGraphSharePage({
|
|
22907
|
+
graph,
|
|
22908
|
+
schemaHash,
|
|
22909
|
+
metadata,
|
|
22910
|
+
report,
|
|
22911
|
+
vaultName: path26.basename(paths.rootDir)
|
|
22912
|
+
})
|
|
22913
|
+
);
|
|
22642
22914
|
return {
|
|
22643
|
-
records: [reportRecord, ...communityRecords],
|
|
22915
|
+
records: [reportRecord, shareRecord, ...communityRecords],
|
|
22644
22916
|
report
|
|
22645
22917
|
};
|
|
22646
22918
|
}
|
|
@@ -26613,7 +26885,7 @@ async function getWatchStatus(rootDir) {
|
|
|
26613
26885
|
}
|
|
26614
26886
|
|
|
26615
26887
|
// src/mcp.ts
|
|
26616
|
-
var SERVER_VERSION = "1.0
|
|
26888
|
+
var SERVER_VERSION = "1.2.0";
|
|
26617
26889
|
async function createMcpServer(rootDir) {
|
|
26618
26890
|
const server = new McpServer({
|
|
26619
26891
|
name: "swarmvault",
|
|
@@ -27149,6 +27421,155 @@ function asTextResource(uri, text) {
|
|
|
27149
27421
|
};
|
|
27150
27422
|
}
|
|
27151
27423
|
|
|
27424
|
+
// src/providers/local-whisper-setup.ts
|
|
27425
|
+
import { createWriteStream, constants as fsConstants } from "fs";
|
|
27426
|
+
import fs25 from "fs/promises";
|
|
27427
|
+
import os3 from "os";
|
|
27428
|
+
import path29 from "path";
|
|
27429
|
+
import { Readable as Readable2 } from "stream";
|
|
27430
|
+
import { pipeline } from "stream/promises";
|
|
27431
|
+
var BINARY_CANDIDATES = ["whisper-cli", "whisper-cpp", "whisper"];
|
|
27432
|
+
var HUGGINGFACE_BASE = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main";
|
|
27433
|
+
var LOCAL_WHISPER_MODEL_SIZES = Object.freeze({
|
|
27434
|
+
"tiny.en": "78 MB",
|
|
27435
|
+
tiny: "78 MB",
|
|
27436
|
+
"base.en": "147 MB",
|
|
27437
|
+
base: "147 MB",
|
|
27438
|
+
"small.en": "488 MB",
|
|
27439
|
+
small: "488 MB",
|
|
27440
|
+
"medium.en": "1.5 GB",
|
|
27441
|
+
medium: "1.5 GB",
|
|
27442
|
+
"large-v3": "3.1 GB",
|
|
27443
|
+
"large-v3-turbo": "1.6 GB"
|
|
27444
|
+
});
|
|
27445
|
+
async function discoverLocalWhisperBinary(options = {}) {
|
|
27446
|
+
const env = options.env ?? process.env;
|
|
27447
|
+
if (env.SWARMVAULT_WHISPER_BINARY) {
|
|
27448
|
+
return {
|
|
27449
|
+
binaryPath: env.SWARMVAULT_WHISPER_BINARY,
|
|
27450
|
+
candidates: [env.SWARMVAULT_WHISPER_BINARY],
|
|
27451
|
+
source: "env"
|
|
27452
|
+
};
|
|
27453
|
+
}
|
|
27454
|
+
const pathValue = env.PATH ?? "";
|
|
27455
|
+
const candidates = [];
|
|
27456
|
+
for (const dir of pathValue.split(path29.delimiter)) {
|
|
27457
|
+
if (!dir) continue;
|
|
27458
|
+
for (const name of BINARY_CANDIDATES) {
|
|
27459
|
+
const full = path29.join(dir, name);
|
|
27460
|
+
candidates.push(full);
|
|
27461
|
+
if (await isExecutable(full)) {
|
|
27462
|
+
return { binaryPath: full, candidates, source: "path" };
|
|
27463
|
+
}
|
|
27464
|
+
}
|
|
27465
|
+
}
|
|
27466
|
+
return { binaryPath: null, candidates, source: "not-found" };
|
|
27467
|
+
}
|
|
27468
|
+
function expectedModelPath(modelName, homeDir) {
|
|
27469
|
+
const home = homeDir ?? os3.homedir();
|
|
27470
|
+
return path29.join(home, ".swarmvault", "models", `ggml-${modelName}.bin`);
|
|
27471
|
+
}
|
|
27472
|
+
function modelDownloadUrl(modelName) {
|
|
27473
|
+
return `${HUGGINGFACE_BASE}/ggml-${modelName}.bin`;
|
|
27474
|
+
}
|
|
27475
|
+
async function downloadWhisperModel(options) {
|
|
27476
|
+
const destPath = expectedModelPath(options.modelName, options.homeDir);
|
|
27477
|
+
await ensureDir(path29.dirname(destPath));
|
|
27478
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
27479
|
+
const url = modelDownloadUrl(options.modelName);
|
|
27480
|
+
const response = await doFetch(url);
|
|
27481
|
+
if (!response.ok) {
|
|
27482
|
+
throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`);
|
|
27483
|
+
}
|
|
27484
|
+
if (!response.body) {
|
|
27485
|
+
throw new Error(`Response body missing for ${url}`);
|
|
27486
|
+
}
|
|
27487
|
+
const totalHeader = response.headers.get("content-length");
|
|
27488
|
+
const totalBytes = totalHeader ? Number.parseInt(totalHeader, 10) : void 0;
|
|
27489
|
+
let downloadedBytes = 0;
|
|
27490
|
+
const webStream = response.body;
|
|
27491
|
+
const source = Readable2.fromWeb(webStream);
|
|
27492
|
+
source.on("data", (chunk) => {
|
|
27493
|
+
downloadedBytes += chunk.length;
|
|
27494
|
+
options.onProgress?.({ downloadedBytes, totalBytes });
|
|
27495
|
+
});
|
|
27496
|
+
const tmpPath = `${destPath}.part`;
|
|
27497
|
+
await pipeline(source, createWriteStream(tmpPath));
|
|
27498
|
+
await fs25.rename(tmpPath, destPath);
|
|
27499
|
+
const stat = await fs25.stat(destPath);
|
|
27500
|
+
return { path: destPath, bytes: stat.size };
|
|
27501
|
+
}
|
|
27502
|
+
async function registerLocalWhisperProvider(options) {
|
|
27503
|
+
const { config, paths } = await loadVaultConfig(options.rootDir);
|
|
27504
|
+
const providerId = options.providerId ?? "local-whisper";
|
|
27505
|
+
const desired = buildProviderEntry(options);
|
|
27506
|
+
const existing = config.providers[providerId];
|
|
27507
|
+
const providerWasAdded = !existing;
|
|
27508
|
+
const providerWasUpdated = !providerWasAdded && !providerEntryMatches(existing, desired);
|
|
27509
|
+
const previousAudioProvider = config.tasks.audioProvider;
|
|
27510
|
+
const shouldSetAudio = options.setAsAudioProvider !== false && (options.setAsAudioProvider === true || !previousAudioProvider);
|
|
27511
|
+
const next = {
|
|
27512
|
+
...config,
|
|
27513
|
+
providers: {
|
|
27514
|
+
...config.providers,
|
|
27515
|
+
[providerId]: desired
|
|
27516
|
+
},
|
|
27517
|
+
tasks: {
|
|
27518
|
+
...config.tasks,
|
|
27519
|
+
audioProvider: shouldSetAudio ? providerId : previousAudioProvider
|
|
27520
|
+
}
|
|
27521
|
+
};
|
|
27522
|
+
await writeJsonFile(paths.configPath, next);
|
|
27523
|
+
return {
|
|
27524
|
+
providerId,
|
|
27525
|
+
configPath: paths.configPath,
|
|
27526
|
+
providerWasAdded,
|
|
27527
|
+
providerWasUpdated,
|
|
27528
|
+
audioProviderSet: shouldSetAudio && previousAudioProvider !== providerId,
|
|
27529
|
+
previousAudioProvider
|
|
27530
|
+
};
|
|
27531
|
+
}
|
|
27532
|
+
function buildProviderEntry(options) {
|
|
27533
|
+
const entry = {
|
|
27534
|
+
type: "local-whisper",
|
|
27535
|
+
model: options.model
|
|
27536
|
+
};
|
|
27537
|
+
if (options.binaryPath) entry.binaryPath = options.binaryPath;
|
|
27538
|
+
if (options.modelPath) entry.modelPath = options.modelPath;
|
|
27539
|
+
if (options.threads !== void 0) entry.threads = options.threads;
|
|
27540
|
+
return entry;
|
|
27541
|
+
}
|
|
27542
|
+
function providerEntryMatches(existing, desired) {
|
|
27543
|
+
return existing.type === desired.type && existing.model === desired.model && existing.binaryPath === desired.binaryPath && existing.modelPath === desired.modelPath && existing.threads === desired.threads;
|
|
27544
|
+
}
|
|
27545
|
+
async function summarizeLocalWhisperSetup(options) {
|
|
27546
|
+
const discovery = await discoverLocalWhisperBinary({ env: options.env });
|
|
27547
|
+
const modelPath = expectedModelPath(options.modelName, options.homeDir);
|
|
27548
|
+
return {
|
|
27549
|
+
binary: {
|
|
27550
|
+
found: discovery.binaryPath !== null,
|
|
27551
|
+
path: discovery.binaryPath,
|
|
27552
|
+
source: discovery.source,
|
|
27553
|
+
installHint: 'Install whisper.cpp \u2014 macOS: "brew install whisper-cpp"; Debian/Ubuntu: "sudo apt install whisper.cpp" (or build from https://github.com/ggerganov/whisper.cpp).'
|
|
27554
|
+
},
|
|
27555
|
+
model: {
|
|
27556
|
+
name: options.modelName,
|
|
27557
|
+
expectedPath: modelPath,
|
|
27558
|
+
exists: await fileExists(modelPath),
|
|
27559
|
+
downloadUrl: modelDownloadUrl(options.modelName),
|
|
27560
|
+
approximateSize: LOCAL_WHISPER_MODEL_SIZES[options.modelName]
|
|
27561
|
+
}
|
|
27562
|
+
};
|
|
27563
|
+
}
|
|
27564
|
+
async function isExecutable(p) {
|
|
27565
|
+
try {
|
|
27566
|
+
await fs25.access(p, fsConstants.X_OK);
|
|
27567
|
+
return true;
|
|
27568
|
+
} catch {
|
|
27569
|
+
return false;
|
|
27570
|
+
}
|
|
27571
|
+
}
|
|
27572
|
+
|
|
27152
27573
|
// src/providers/openai-compatible-capabilities.ts
|
|
27153
27574
|
var OPENAI_COMPATIBLE_CAPABILITY_MATRIX = Object.freeze({
|
|
27154
27575
|
openai: {
|
|
@@ -27212,13 +27633,13 @@ async function withCapabilityFallback(provider, capability, run, fallback) {
|
|
|
27212
27633
|
}
|
|
27213
27634
|
|
|
27214
27635
|
// src/schedule.ts
|
|
27215
|
-
import
|
|
27216
|
-
import
|
|
27636
|
+
import fs26 from "fs/promises";
|
|
27637
|
+
import path30 from "path";
|
|
27217
27638
|
function scheduleStatePath(schedulesDir, jobId) {
|
|
27218
|
-
return
|
|
27639
|
+
return path30.join(schedulesDir, `${encodeURIComponent(jobId)}.json`);
|
|
27219
27640
|
}
|
|
27220
27641
|
function scheduleLockPath(schedulesDir, jobId) {
|
|
27221
|
-
return
|
|
27642
|
+
return path30.join(schedulesDir, `${encodeURIComponent(jobId)}.lock`);
|
|
27222
27643
|
}
|
|
27223
27644
|
function parseEveryDuration(value) {
|
|
27224
27645
|
const match = value.trim().match(/^(\d+)(m|h|d)$/i);
|
|
@@ -27321,13 +27742,13 @@ async function acquireJobLease(rootDir, jobId) {
|
|
|
27321
27742
|
const { paths } = await loadVaultConfig(rootDir);
|
|
27322
27743
|
const leasePath = scheduleLockPath(paths.schedulesDir, jobId);
|
|
27323
27744
|
await ensureDir(paths.schedulesDir);
|
|
27324
|
-
const handle = await
|
|
27745
|
+
const handle = await fs26.open(leasePath, "wx");
|
|
27325
27746
|
await handle.writeFile(`${process.pid}
|
|
27326
27747
|
${(/* @__PURE__ */ new Date()).toISOString()}
|
|
27327
27748
|
`);
|
|
27328
27749
|
await handle.close();
|
|
27329
27750
|
return async () => {
|
|
27330
|
-
await
|
|
27751
|
+
await fs26.rm(leasePath, { force: true });
|
|
27331
27752
|
};
|
|
27332
27753
|
}
|
|
27333
27754
|
async function listSchedules(rootDir) {
|
|
@@ -27486,8 +27907,8 @@ async function serveSchedules(rootDir, pollMs = 3e4) {
|
|
|
27486
27907
|
|
|
27487
27908
|
// src/sources.ts
|
|
27488
27909
|
import { spawn as spawn2 } from "child_process";
|
|
27489
|
-
import
|
|
27490
|
-
import
|
|
27910
|
+
import fs27 from "fs/promises";
|
|
27911
|
+
import path31 from "path";
|
|
27491
27912
|
import matter14 from "gray-matter";
|
|
27492
27913
|
import { JSDOM as JSDOM3 } from "jsdom";
|
|
27493
27914
|
var DEFAULT_CRAWL_MAX_PAGES = 12;
|
|
@@ -27533,24 +27954,24 @@ function emptyManagedSourceSyncCounts() {
|
|
|
27533
27954
|
};
|
|
27534
27955
|
}
|
|
27535
27956
|
function withinRoot2(rootPath, targetPath) {
|
|
27536
|
-
const relative =
|
|
27537
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
27957
|
+
const relative = path31.relative(rootPath, targetPath);
|
|
27958
|
+
return relative === "" || !relative.startsWith("..") && !path31.isAbsolute(relative);
|
|
27538
27959
|
}
|
|
27539
27960
|
async function findNearestGitRoot3(startPath) {
|
|
27540
|
-
let current =
|
|
27961
|
+
let current = path31.resolve(startPath);
|
|
27541
27962
|
try {
|
|
27542
|
-
const stat = await
|
|
27963
|
+
const stat = await fs27.stat(current);
|
|
27543
27964
|
if (!stat.isDirectory()) {
|
|
27544
|
-
current =
|
|
27965
|
+
current = path31.dirname(current);
|
|
27545
27966
|
}
|
|
27546
27967
|
} catch {
|
|
27547
|
-
current =
|
|
27968
|
+
current = path31.dirname(current);
|
|
27548
27969
|
}
|
|
27549
27970
|
while (true) {
|
|
27550
|
-
if (await fileExists(
|
|
27971
|
+
if (await fileExists(path31.join(current, ".git"))) {
|
|
27551
27972
|
return current;
|
|
27552
27973
|
}
|
|
27553
|
-
const parent =
|
|
27974
|
+
const parent = path31.dirname(current);
|
|
27554
27975
|
if (parent === current) {
|
|
27555
27976
|
return null;
|
|
27556
27977
|
}
|
|
@@ -27624,7 +28045,7 @@ function isAllowedDocsCandidate(candidate, startUrl) {
|
|
|
27624
28045
|
if (candidate.origin !== startUrl.origin) {
|
|
27625
28046
|
return false;
|
|
27626
28047
|
}
|
|
27627
|
-
const extension =
|
|
28048
|
+
const extension = path31.extname(candidate.pathname).toLowerCase();
|
|
27628
28049
|
if (extension && extension !== ".html" && extension !== ".htm" && extension !== ".md") {
|
|
27629
28050
|
return false;
|
|
27630
28051
|
}
|
|
@@ -27713,14 +28134,14 @@ function matchesManagedSourceSpec(existing, input) {
|
|
|
27713
28134
|
return false;
|
|
27714
28135
|
}
|
|
27715
28136
|
if (input.kind === "directory" || input.kind === "file") {
|
|
27716
|
-
return
|
|
28137
|
+
return path31.resolve(existing.path ?? "") === path31.resolve(input.path);
|
|
27717
28138
|
}
|
|
27718
28139
|
return (existing.url ?? "") === input.url;
|
|
27719
28140
|
}
|
|
27720
28141
|
async function resolveManagedSourceInput(rootDir, input) {
|
|
27721
|
-
const absoluteInput =
|
|
28142
|
+
const absoluteInput = path31.resolve(rootDir, input);
|
|
27722
28143
|
if (!(input.startsWith("http://") || input.startsWith("https://"))) {
|
|
27723
|
-
const stat = await
|
|
28144
|
+
const stat = await fs27.stat(absoluteInput).catch(() => null);
|
|
27724
28145
|
if (!stat) {
|
|
27725
28146
|
throw new Error(`Source not found: ${input}`);
|
|
27726
28147
|
}
|
|
@@ -27728,7 +28149,7 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
27728
28149
|
return {
|
|
27729
28150
|
kind: "file",
|
|
27730
28151
|
path: absoluteInput,
|
|
27731
|
-
title:
|
|
28152
|
+
title: path31.basename(absoluteInput, path31.extname(absoluteInput)) || absoluteInput
|
|
27732
28153
|
};
|
|
27733
28154
|
}
|
|
27734
28155
|
if (!stat.isDirectory()) {
|
|
@@ -27740,7 +28161,7 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
27740
28161
|
kind: "directory",
|
|
27741
28162
|
path: absoluteInput,
|
|
27742
28163
|
repoRoot,
|
|
27743
|
-
title:
|
|
28164
|
+
title: path31.basename(absoluteInput) || absoluteInput
|
|
27744
28165
|
};
|
|
27745
28166
|
}
|
|
27746
28167
|
const github = normalizeGitHubRepoRootUrl(input);
|
|
@@ -27763,16 +28184,16 @@ async function resolveManagedSourceInput(rootDir, input) {
|
|
|
27763
28184
|
};
|
|
27764
28185
|
}
|
|
27765
28186
|
function directorySourceIdsFor(manifests, inputPath) {
|
|
27766
|
-
return manifests.filter((manifest) => manifest.originalPath && withinRoot2(
|
|
28187
|
+
return manifests.filter((manifest) => manifest.originalPath && withinRoot2(path31.resolve(inputPath), path31.resolve(manifest.originalPath))).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
|
|
27767
28188
|
}
|
|
27768
28189
|
function fileSourceIdsFor(manifests, inputPath) {
|
|
27769
|
-
const absoluteInput =
|
|
27770
|
-
return manifests.filter((manifest) => manifest.originalPath &&
|
|
28190
|
+
const absoluteInput = path31.resolve(inputPath);
|
|
28191
|
+
return manifests.filter((manifest) => manifest.originalPath && path31.resolve(manifest.originalPath) === absoluteInput).map((manifest) => manifest.sourceId).sort((left, right) => left.localeCompare(right));
|
|
27771
28192
|
}
|
|
27772
28193
|
async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
27773
28194
|
const manifestsBefore = await listManifests(rootDir);
|
|
27774
28195
|
const previousInScope = manifestsBefore.filter(
|
|
27775
|
-
(manifest) => manifest.originalPath && withinRoot2(
|
|
28196
|
+
(manifest) => manifest.originalPath && withinRoot2(path31.resolve(inputPath), path31.resolve(manifest.originalPath))
|
|
27776
28197
|
);
|
|
27777
28198
|
const result = await ingestDirectory(rootDir, inputPath, { repoRoot });
|
|
27778
28199
|
const removed = [];
|
|
@@ -27780,7 +28201,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
|
27780
28201
|
if (!manifest.originalPath) {
|
|
27781
28202
|
continue;
|
|
27782
28203
|
}
|
|
27783
|
-
if (await fileExists(
|
|
28204
|
+
if (await fileExists(path31.resolve(manifest.originalPath))) {
|
|
27784
28205
|
continue;
|
|
27785
28206
|
}
|
|
27786
28207
|
const removedManifest = await removeManifestBySourceId(rootDir, manifest.sourceId);
|
|
@@ -27790,7 +28211,7 @@ async function syncDirectorySource(rootDir, inputPath, repoRoot) {
|
|
|
27790
28211
|
}
|
|
27791
28212
|
const manifestsAfter = await listManifests(rootDir);
|
|
27792
28213
|
return {
|
|
27793
|
-
title:
|
|
28214
|
+
title: path31.basename(inputPath) || inputPath,
|
|
27794
28215
|
sourceIds: directorySourceIdsFor(manifestsAfter, inputPath),
|
|
27795
28216
|
counts: {
|
|
27796
28217
|
scannedCount: result.scannedCount,
|
|
@@ -27806,7 +28227,7 @@ async function syncFileSource(rootDir, inputPath) {
|
|
|
27806
28227
|
const result = await ingestInputDetailed(rootDir, inputPath);
|
|
27807
28228
|
const manifestsAfter = await listManifests(rootDir);
|
|
27808
28229
|
return {
|
|
27809
|
-
title:
|
|
28230
|
+
title: path31.basename(inputPath, path31.extname(inputPath)) || inputPath,
|
|
27810
28231
|
sourceIds: fileSourceIdsFor(manifestsAfter, inputPath),
|
|
27811
28232
|
counts: {
|
|
27812
28233
|
scannedCount: result.scannedCount,
|
|
@@ -27840,8 +28261,8 @@ async function runGitCommand(cwd, args) {
|
|
|
27840
28261
|
}
|
|
27841
28262
|
async function syncGitHubRepoSource(rootDir, entry) {
|
|
27842
28263
|
const workingDir = await managedSourceWorkingDir(rootDir, entry.id);
|
|
27843
|
-
const checkoutDir =
|
|
27844
|
-
await
|
|
28264
|
+
const checkoutDir = path31.join(workingDir, "checkout");
|
|
28265
|
+
await fs27.rm(checkoutDir, { recursive: true, force: true });
|
|
27845
28266
|
await ensureDir(workingDir);
|
|
27846
28267
|
if (!entry.url) {
|
|
27847
28268
|
throw new Error(`Managed source ${entry.id} is missing its repository URL.`);
|
|
@@ -27971,7 +28392,7 @@ function scopedNodeIds(graph, sourceIds) {
|
|
|
27971
28392
|
async function loadSourceAnalyses(rootDir, sourceIds) {
|
|
27972
28393
|
const { paths } = await loadVaultConfig(rootDir);
|
|
27973
28394
|
const analyses = await Promise.all(
|
|
27974
|
-
sourceIds.map(async (sourceId) => await readJsonFile(
|
|
28395
|
+
sourceIds.map(async (sourceId) => await readJsonFile(path31.join(paths.analysesDir, `${sourceId}.json`)))
|
|
27975
28396
|
);
|
|
27976
28397
|
return analyses.filter((analysis) => Boolean(analysis?.sourceId));
|
|
27977
28398
|
}
|
|
@@ -28132,9 +28553,9 @@ async function writeSourceBriefForScope(rootDir, source) {
|
|
|
28132
28553
|
confidence: 0.82
|
|
28133
28554
|
}
|
|
28134
28555
|
});
|
|
28135
|
-
const absolutePath =
|
|
28136
|
-
await ensureDir(
|
|
28137
|
-
await
|
|
28556
|
+
const absolutePath = path31.join(paths.wikiDir, output.page.path);
|
|
28557
|
+
await ensureDir(path31.dirname(absolutePath));
|
|
28558
|
+
await fs27.writeFile(absolutePath, output.content, "utf8");
|
|
28138
28559
|
return absolutePath;
|
|
28139
28560
|
}
|
|
28140
28561
|
async function writeSourceBrief(rootDir, source) {
|
|
@@ -28422,7 +28843,7 @@ function selectGuidedTargetPages(scope, sourcePages, questions) {
|
|
|
28422
28843
|
return (matchedTargets.length ? matchedTargets : canonicalPages).slice(0, 6);
|
|
28423
28844
|
}
|
|
28424
28845
|
function insightRelativePathForTarget(page, scope) {
|
|
28425
|
-
const basename =
|
|
28846
|
+
const basename = path31.basename(page.path);
|
|
28426
28847
|
if (page.kind === "concept") {
|
|
28427
28848
|
return `insights/concepts/${basename}`;
|
|
28428
28849
|
}
|
|
@@ -28649,7 +29070,7 @@ async function stageSourceReviewForScope(rootDir, scope) {
|
|
|
28649
29070
|
return {
|
|
28650
29071
|
sourceId: scope.id,
|
|
28651
29072
|
pageId: output.page.id,
|
|
28652
|
-
reviewPath:
|
|
29073
|
+
reviewPath: path31.join(approval.approvalDir, "wiki", output.page.path),
|
|
28653
29074
|
staged: true,
|
|
28654
29075
|
approvalId: approval.approvalId,
|
|
28655
29076
|
approvalDir: approval.approvalDir
|
|
@@ -28716,7 +29137,7 @@ async function buildSourceSessionSavedPage(rootDir, scope, session) {
|
|
|
28716
29137
|
const evidenceState = contradictions.length > 0 ? "conflicting" : session.targetedPagePaths.some(
|
|
28717
29138
|
(targetPath) => sourcePages.some((page) => page.path === targetPath && page.sourceIds.some((sourceId) => !scope.sourceIds.includes(sourceId)))
|
|
28718
29139
|
) ? "reinforcing" : session.targetedPagePaths.length ? "new" : "needs_judgment";
|
|
28719
|
-
const relativeBriefPath = session.briefPath &&
|
|
29140
|
+
const relativeBriefPath = session.briefPath && path31.isAbsolute(session.briefPath) ? path31.relative(paths.wikiDir, session.briefPath) : session.briefPath;
|
|
28720
29141
|
const sessionMarkdown = [
|
|
28721
29142
|
`# Guided Session: ${scope.title}`,
|
|
28722
29143
|
"",
|
|
@@ -28799,9 +29220,9 @@ async function buildSourceSessionSavedPage(rootDir, scope, session) {
|
|
|
28799
29220
|
async function persistSourceSessionPage(rootDir, scope, session) {
|
|
28800
29221
|
const { paths } = await loadVaultConfig(rootDir);
|
|
28801
29222
|
const output = await buildSourceSessionSavedPage(rootDir, scope, session);
|
|
28802
|
-
const absolutePath =
|
|
28803
|
-
await ensureDir(
|
|
28804
|
-
await
|
|
29223
|
+
const absolutePath = path31.join(paths.wikiDir, output.page.path);
|
|
29224
|
+
await ensureDir(path31.dirname(absolutePath));
|
|
29225
|
+
await fs27.writeFile(absolutePath, output.content, "utf8");
|
|
28805
29226
|
return { pageId: output.page.id, sessionPath: absolutePath };
|
|
28806
29227
|
}
|
|
28807
29228
|
async function buildGuidedUpdatePages(rootDir, scope, session) {
|
|
@@ -28829,8 +29250,8 @@ async function buildGuidedUpdatePages(rootDir, scope, session) {
|
|
|
28829
29250
|
targetPages.map(async (targetPage) => {
|
|
28830
29251
|
const evidenceState = classifyGuidedEvidenceState(scope, targetPage, contradictions);
|
|
28831
29252
|
const relativePath = useCanonicalTargets && targetPage ? targetPage.path : targetPage ? insightRelativePathForTarget(targetPage, scope) : `insights/topics/${slugify(scope.title)}.md`;
|
|
28832
|
-
const absolutePath =
|
|
28833
|
-
const existingContent = await fileExists(absolutePath) ? await
|
|
29253
|
+
const absolutePath = path31.join(paths.wikiDir, relativePath);
|
|
29254
|
+
const existingContent = await fileExists(absolutePath) ? await fs27.readFile(absolutePath, "utf8") : "";
|
|
28834
29255
|
const parsed = existingContent ? matter14(existingContent) : { data: {}, content: "" };
|
|
28835
29256
|
const existingData = parsed.data;
|
|
28836
29257
|
const existingSourceIds = Array.isArray(existingData.source_ids) ? existingData.source_ids.filter((value) => typeof value === "string") : [];
|
|
@@ -29001,8 +29422,8 @@ async function stageSourceGuideForScope(rootDir, scope, options = {}) {
|
|
|
29001
29422
|
}
|
|
29002
29423
|
);
|
|
29003
29424
|
session.status = "staged";
|
|
29004
|
-
session.reviewPath =
|
|
29005
|
-
session.guidePath =
|
|
29425
|
+
session.reviewPath = path31.join(approval.approvalDir, "wiki", reviewOutput.page.path);
|
|
29426
|
+
session.guidePath = path31.join(approval.approvalDir, "wiki", guideOutput.page.path);
|
|
29006
29427
|
session.approvalId = approval.approvalId;
|
|
29007
29428
|
session.approvalDir = approval.approvalDir;
|
|
29008
29429
|
const persisted = await persistSourceSessionPage(rootDir, scope, session);
|
|
@@ -29140,7 +29561,7 @@ async function addManagedSource(rootDir, input, options = {}) {
|
|
|
29140
29561
|
const existing = sources.find((candidate) => matchesManagedSourceSpec(candidate, resolved));
|
|
29141
29562
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
29142
29563
|
const source = existing ?? {
|
|
29143
|
-
id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind,
|
|
29564
|
+
id: resolved.kind === "directory" || resolved.kind === "file" ? stableManagedSourceId(resolved.kind, path31.resolve(resolved.path), resolved.title) : stableManagedSourceId(resolved.kind, resolved.url, resolved.title),
|
|
29144
29565
|
kind: resolved.kind,
|
|
29145
29566
|
title: resolved.title,
|
|
29146
29567
|
path: resolved.kind === "directory" || resolved.kind === "file" ? resolved.path : void 0,
|
|
@@ -29268,7 +29689,7 @@ async function deleteManagedSource(rootDir, id) {
|
|
|
29268
29689
|
sources.filter((source) => source.id !== id)
|
|
29269
29690
|
);
|
|
29270
29691
|
const workingDir = await managedSourceWorkingDir(rootDir, id);
|
|
29271
|
-
await
|
|
29692
|
+
await fs27.rm(workingDir, { recursive: true, force: true });
|
|
29272
29693
|
return { removed: target };
|
|
29273
29694
|
}
|
|
29274
29695
|
|
|
@@ -29276,9 +29697,9 @@ async function deleteManagedSource(rootDir, id) {
|
|
|
29276
29697
|
import { execFile as execFile2 } from "child_process";
|
|
29277
29698
|
import { randomUUID } from "crypto";
|
|
29278
29699
|
import { EventEmitter } from "events";
|
|
29279
|
-
import
|
|
29700
|
+
import fs28 from "fs/promises";
|
|
29280
29701
|
import http from "http";
|
|
29281
|
-
import
|
|
29702
|
+
import path32 from "path";
|
|
29282
29703
|
import { promisify as promisify2 } from "util";
|
|
29283
29704
|
import matter15 from "gray-matter";
|
|
29284
29705
|
import mime2 from "mime-types";
|
|
@@ -29432,7 +29853,7 @@ function toViewerLintFindings(findings) {
|
|
|
29432
29853
|
var execFileAsync2 = promisify2(execFile2);
|
|
29433
29854
|
async function isReadableFile(absolutePath) {
|
|
29434
29855
|
try {
|
|
29435
|
-
const stats = await
|
|
29856
|
+
const stats = await fs28.stat(absolutePath);
|
|
29436
29857
|
return stats.isFile();
|
|
29437
29858
|
} catch {
|
|
29438
29859
|
return false;
|
|
@@ -29443,15 +29864,15 @@ async function readViewerPage(rootDir, relativePath) {
|
|
|
29443
29864
|
return null;
|
|
29444
29865
|
}
|
|
29445
29866
|
const { paths } = await loadVaultConfig(rootDir);
|
|
29446
|
-
const absolutePath =
|
|
29867
|
+
const absolutePath = path32.resolve(paths.wikiDir, relativePath);
|
|
29447
29868
|
if (!isPathWithin(paths.wikiDir, absolutePath) || !await isReadableFile(absolutePath)) {
|
|
29448
29869
|
return null;
|
|
29449
29870
|
}
|
|
29450
|
-
const raw = await
|
|
29871
|
+
const raw = await fs28.readFile(absolutePath, "utf8");
|
|
29451
29872
|
const parsed = matter15(raw);
|
|
29452
29873
|
return {
|
|
29453
29874
|
path: relativePath,
|
|
29454
|
-
title: typeof parsed.data.title === "string" ? parsed.data.title :
|
|
29875
|
+
title: typeof parsed.data.title === "string" ? parsed.data.title : path32.basename(relativePath, path32.extname(relativePath)),
|
|
29455
29876
|
frontmatter: parsed.data,
|
|
29456
29877
|
content: parsed.content,
|
|
29457
29878
|
assets: normalizeOutputAssets(parsed.data.output_assets)
|
|
@@ -29462,12 +29883,12 @@ async function readViewerAsset(rootDir, relativePath) {
|
|
|
29462
29883
|
return null;
|
|
29463
29884
|
}
|
|
29464
29885
|
const { paths } = await loadVaultConfig(rootDir);
|
|
29465
|
-
const absolutePath =
|
|
29886
|
+
const absolutePath = path32.resolve(paths.wikiDir, relativePath);
|
|
29466
29887
|
if (!isPathWithin(paths.wikiDir, absolutePath) || !await isReadableFile(absolutePath)) {
|
|
29467
29888
|
return null;
|
|
29468
29889
|
}
|
|
29469
29890
|
return {
|
|
29470
|
-
buffer: await
|
|
29891
|
+
buffer: await fs28.readFile(absolutePath),
|
|
29471
29892
|
mimeType: mime2.lookup(absolutePath) || "application/octet-stream"
|
|
29472
29893
|
};
|
|
29473
29894
|
}
|
|
@@ -29490,12 +29911,12 @@ async function readJsonBody(request) {
|
|
|
29490
29911
|
return JSON.parse(raw);
|
|
29491
29912
|
}
|
|
29492
29913
|
async function ensureViewerDist(viewerDistDir) {
|
|
29493
|
-
const indexPath =
|
|
29914
|
+
const indexPath = path32.join(viewerDistDir, "index.html");
|
|
29494
29915
|
if (await fileExists(indexPath)) {
|
|
29495
29916
|
return;
|
|
29496
29917
|
}
|
|
29497
|
-
const viewerProjectDir =
|
|
29498
|
-
if (await fileExists(
|
|
29918
|
+
const viewerProjectDir = path32.dirname(viewerDistDir);
|
|
29919
|
+
if (await fileExists(path32.join(viewerProjectDir, "package.json"))) {
|
|
29499
29920
|
await execFileAsync2("pnpm", ["build"], { cwd: viewerProjectDir });
|
|
29500
29921
|
}
|
|
29501
29922
|
}
|
|
@@ -29518,7 +29939,7 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
29518
29939
|
response.end(JSON.stringify({ error: "Graph artifact not found. Run `swarmvault compile` first." }));
|
|
29519
29940
|
return;
|
|
29520
29941
|
}
|
|
29521
|
-
const reportPath =
|
|
29942
|
+
const reportPath = path32.join(paths.wikiDir, "graph", "report.json");
|
|
29522
29943
|
const report = await readJsonFile(reportPath) ?? null;
|
|
29523
29944
|
response.writeHead(200, { "content-type": "application/json" });
|
|
29524
29945
|
response.end(JSON.stringify(buildViewerGraphArtifact(graph, { report, full: options.full ?? false })));
|
|
@@ -29582,13 +30003,13 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
29582
30003
|
return;
|
|
29583
30004
|
}
|
|
29584
30005
|
if (url.pathname === "/api/graph-report") {
|
|
29585
|
-
const reportPath =
|
|
30006
|
+
const reportPath = path32.join(paths.wikiDir, "graph", "report.json");
|
|
29586
30007
|
if (!await fileExists(reportPath)) {
|
|
29587
30008
|
response.writeHead(404, { "content-type": "application/json" });
|
|
29588
30009
|
response.end(JSON.stringify({ error: "Graph report artifact not found. Run `swarmvault compile` first." }));
|
|
29589
30010
|
return;
|
|
29590
30011
|
}
|
|
29591
|
-
const body = await
|
|
30012
|
+
const body = await fs28.readFile(reportPath, "utf8");
|
|
29592
30013
|
response.writeHead(200, { "content-type": "application/json" });
|
|
29593
30014
|
response.end(body);
|
|
29594
30015
|
return;
|
|
@@ -29689,7 +30110,7 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
29689
30110
|
return;
|
|
29690
30111
|
}
|
|
29691
30112
|
if (url.pathname === "/api/workspace") {
|
|
29692
|
-
const reportPath =
|
|
30113
|
+
const reportPath = path32.join(paths.wikiDir, "graph", "report.json");
|
|
29693
30114
|
const [graphRaw, reportRaw, approvalsRaw, candidatesRaw, watchStatusRaw, lintRaw] = await Promise.all([
|
|
29694
30115
|
readJsonFile(paths.graphPath).catch(() => null),
|
|
29695
30116
|
readJsonFile(reportPath).catch(() => null),
|
|
@@ -29785,15 +30206,15 @@ async function startGraphServer(rootDir, port, options = {}) {
|
|
|
29785
30206
|
return;
|
|
29786
30207
|
}
|
|
29787
30208
|
const relativePath = url.pathname === "/" ? "index.html" : url.pathname.slice(1);
|
|
29788
|
-
const target =
|
|
29789
|
-
const fallback =
|
|
30209
|
+
const target = path32.join(paths.viewerDistDir, relativePath);
|
|
30210
|
+
const fallback = path32.join(paths.viewerDistDir, "index.html");
|
|
29790
30211
|
const filePath = await fileExists(target) ? target : fallback;
|
|
29791
30212
|
if (!await fileExists(filePath)) {
|
|
29792
30213
|
response.writeHead(503, { "content-type": "text/plain" });
|
|
29793
30214
|
response.end("Viewer build not found. Run `pnpm build` first.");
|
|
29794
30215
|
return;
|
|
29795
30216
|
}
|
|
29796
|
-
const staticBody = await
|
|
30217
|
+
const staticBody = await fs28.readFile(filePath);
|
|
29797
30218
|
response.writeHead(200, { "content-type": mime2.lookup(filePath) || "text/plain" });
|
|
29798
30219
|
response.end(staticBody);
|
|
29799
30220
|
} catch (error) {
|
|
@@ -29833,7 +30254,7 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
29833
30254
|
throw new Error("Graph artifact not found. Run `swarmvault compile` first.");
|
|
29834
30255
|
}
|
|
29835
30256
|
await ensureViewerDist(paths.viewerDistDir);
|
|
29836
|
-
const indexPath =
|
|
30257
|
+
const indexPath = path32.join(paths.viewerDistDir, "index.html");
|
|
29837
30258
|
if (!await fileExists(indexPath)) {
|
|
29838
30259
|
throw new Error("Viewer build not found. Run `pnpm build` first.");
|
|
29839
30260
|
}
|
|
@@ -29859,17 +30280,17 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
29859
30280
|
} : null;
|
|
29860
30281
|
})
|
|
29861
30282
|
);
|
|
29862
|
-
const rawHtml = await
|
|
30283
|
+
const rawHtml = await fs28.readFile(indexPath, "utf8");
|
|
29863
30284
|
const scriptMatch = rawHtml.match(/<script type="module" crossorigin src="([^"]+)"><\/script>/);
|
|
29864
30285
|
const styleMatch = rawHtml.match(/<link rel="stylesheet" crossorigin href="([^"]+)">/);
|
|
29865
|
-
const scriptPath = scriptMatch?.[1] ?
|
|
29866
|
-
const stylePath = styleMatch?.[1] ?
|
|
30286
|
+
const scriptPath = scriptMatch?.[1] ? path32.join(paths.viewerDistDir, scriptMatch[1].replace(/^\//, "")) : null;
|
|
30287
|
+
const stylePath = styleMatch?.[1] ? path32.join(paths.viewerDistDir, styleMatch[1].replace(/^\//, "")) : null;
|
|
29867
30288
|
if (!scriptPath || !await fileExists(scriptPath)) {
|
|
29868
30289
|
throw new Error("Viewer script bundle not found. Run `pnpm build` first.");
|
|
29869
30290
|
}
|
|
29870
|
-
const script = await
|
|
29871
|
-
const style = stylePath && await fileExists(stylePath) ? await
|
|
29872
|
-
const report = await readJsonFile(
|
|
30291
|
+
const script = await fs28.readFile(scriptPath, "utf8");
|
|
30292
|
+
const style = stylePath && await fileExists(stylePath) ? await fs28.readFile(stylePath, "utf8") : "";
|
|
30293
|
+
const report = await readJsonFile(path32.join(paths.wikiDir, "graph", "report.json"));
|
|
29873
30294
|
const embeddedData = JSON.stringify(
|
|
29874
30295
|
{ graph: buildViewerGraphArtifact(graph, { report, full: options.full ?? false }), pages: pages.filter(Boolean), report },
|
|
29875
30296
|
null,
|
|
@@ -29892,9 +30313,9 @@ async function exportGraphHtml(rootDir, outputPath, options = {}) {
|
|
|
29892
30313
|
"</html>",
|
|
29893
30314
|
""
|
|
29894
30315
|
].filter(Boolean).join("\n");
|
|
29895
|
-
await
|
|
29896
|
-
await
|
|
29897
|
-
return
|
|
30316
|
+
await fs28.mkdir(path32.dirname(outputPath), { recursive: true });
|
|
30317
|
+
await fs28.writeFile(outputPath, html, "utf8");
|
|
30318
|
+
return path32.resolve(outputPath);
|
|
29898
30319
|
}
|
|
29899
30320
|
export {
|
|
29900
30321
|
ALL_MIGRATIONS,
|
|
@@ -29905,6 +30326,8 @@ export {
|
|
|
29905
30326
|
DEFAULT_REDACTION_PATTERNS,
|
|
29906
30327
|
DEFAULT_STALE_THRESHOLD,
|
|
29907
30328
|
LARGE_REPO_NODE_THRESHOLD,
|
|
30329
|
+
LOCAL_WHISPER_MODEL_SIZES,
|
|
30330
|
+
LocalWhisperProviderAdapter,
|
|
29908
30331
|
OPENAI_COMPATIBLE_CAPABILITY_MATRIX,
|
|
29909
30332
|
acceptApproval,
|
|
29910
30333
|
addInput,
|
|
@@ -29919,6 +30342,7 @@ export {
|
|
|
29919
30342
|
blastRadiusVault,
|
|
29920
30343
|
bootstrapDemo,
|
|
29921
30344
|
buildConfiguredRedactor,
|
|
30345
|
+
buildGraphShareArtifact,
|
|
29922
30346
|
buildRedactor,
|
|
29923
30347
|
compileVault,
|
|
29924
30348
|
computeDecayScore,
|
|
@@ -29931,9 +30355,12 @@ export {
|
|
|
29931
30355
|
defaultVaultSchema,
|
|
29932
30356
|
deleteManagedSource,
|
|
29933
30357
|
detectVaultVersion,
|
|
30358
|
+
discoverLocalWhisperBinary,
|
|
30359
|
+
downloadWhisperModel,
|
|
29934
30360
|
estimatePageTokens,
|
|
29935
30361
|
estimateTokens,
|
|
29936
30362
|
evaluateCandidateForPromotion,
|
|
30363
|
+
expectedModelPath,
|
|
29937
30364
|
explainGraphVault,
|
|
29938
30365
|
exploreVault,
|
|
29939
30366
|
exportGraphFormat,
|
|
@@ -29974,6 +30401,7 @@ export {
|
|
|
29974
30401
|
loadVaultSchemas,
|
|
29975
30402
|
lookupPresetCapabilities,
|
|
29976
30403
|
markSuperseded,
|
|
30404
|
+
modelDownloadUrl,
|
|
29977
30405
|
pathGraphVault,
|
|
29978
30406
|
persistDecayFrontmatter,
|
|
29979
30407
|
planMigration,
|
|
@@ -29986,9 +30414,11 @@ export {
|
|
|
29986
30414
|
readExtractedText,
|
|
29987
30415
|
readGraphReport,
|
|
29988
30416
|
readPage,
|
|
30417
|
+
registerLocalWhisperProvider,
|
|
29989
30418
|
rejectApproval,
|
|
29990
30419
|
reloadManagedSources,
|
|
29991
30420
|
removeWatchedRoot,
|
|
30421
|
+
renderGraphShareMarkdown,
|
|
29992
30422
|
resetDecay,
|
|
29993
30423
|
resolveConsolidationConfig,
|
|
29994
30424
|
resolveDecayConfig,
|
|
@@ -30010,6 +30440,7 @@ export {
|
|
|
30010
30440
|
stageGeneratedOutputPages,
|
|
30011
30441
|
startGraphServer,
|
|
30012
30442
|
startMcpServer,
|
|
30443
|
+
summarizeLocalWhisperSetup,
|
|
30013
30444
|
syncTrackedRepos,
|
|
30014
30445
|
syncTrackedReposForWatch,
|
|
30015
30446
|
synthesizeHyperedgeHubs,
|