@swarmvaultai/engine 0.7.22 → 0.7.24
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/dist/index.d.ts +2 -1
- package/dist/index.js +81 -31
- package/package.json +4 -1
package/dist/index.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ type PageStatus = "draft" | "candidate" | "active" | "archived";
|
|
|
57
57
|
type PageManager = "system" | "human";
|
|
58
58
|
type ApprovalEntryStatus = "pending" | "accepted" | "rejected";
|
|
59
59
|
type ApprovalChangeType = "create" | "update" | "delete" | "promote";
|
|
60
|
-
type ApprovalBundleType = "compile" | "
|
|
60
|
+
type ApprovalBundleType = "compile" | "generated-output" | "source-review" | "guided-source" | "guided-session";
|
|
61
61
|
type ApprovalEntryLabel = "source-brief" | "source-review" | "source-guide" | "guided-update";
|
|
62
62
|
type GuidedSourceSessionStatus = "awaiting_input" | "ready_to_stage" | "staged" | "accepted" | "rejected";
|
|
63
63
|
type VaultProfilePreset = "reader" | "timeline" | "diligence" | "thesis";
|
|
@@ -767,6 +767,7 @@ interface WatchOptions {
|
|
|
767
767
|
lint?: boolean;
|
|
768
768
|
debounceMs?: number;
|
|
769
769
|
repo?: boolean;
|
|
770
|
+
codeOnly?: boolean;
|
|
770
771
|
}
|
|
771
772
|
interface PendingSemanticRefreshEntry {
|
|
772
773
|
id: string;
|
package/dist/index.js
CHANGED
|
@@ -2263,7 +2263,7 @@ function managedHookBlock(vaultRoot) {
|
|
|
2263
2263
|
`swarmvault_bin=${shellQuote(resolvedExecutable)}`,
|
|
2264
2264
|
'[ ! -x "$swarmvault_bin" ] && swarmvault_bin=$(command -v swarmvault 2>/dev/null || true)',
|
|
2265
2265
|
'if [ -n "$swarmvault_bin" ] && [ -x "$swarmvault_bin" ]; then',
|
|
2266
|
-
` "$swarmvault_bin" watch --repo --once >/dev/null 2>&1 || printf '[swarmvault hook] refresh failed\\n' >&2`,
|
|
2266
|
+
` "$swarmvault_bin" watch --repo --once --code-only >/dev/null 2>&1 || printf '[swarmvault hook] refresh failed\\n' >&2`,
|
|
2267
2267
|
"fi",
|
|
2268
2268
|
hookEnd,
|
|
2269
2269
|
""
|
|
@@ -12748,6 +12748,8 @@ function buildSchemaPrompt(schema, instruction) {
|
|
|
12748
12748
|
// src/vault.ts
|
|
12749
12749
|
import fs19 from "fs/promises";
|
|
12750
12750
|
import path23 from "path";
|
|
12751
|
+
import Graph from "graphology";
|
|
12752
|
+
import louvain from "graphology-communities-louvain";
|
|
12751
12753
|
import matter9 from "gray-matter";
|
|
12752
12754
|
import { z as z7 } from "zod";
|
|
12753
12755
|
|
|
@@ -17483,8 +17485,8 @@ async function buildDashboardRecords(config, paths, graph, schemaHash, report) {
|
|
|
17483
17485
|
).slice(0, 20);
|
|
17484
17486
|
const sourceSessions = await listGuidedSourceSessions(paths.rootDir);
|
|
17485
17487
|
const stagedGuideBundles = (await Promise.all(
|
|
17486
|
-
(await fs19.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => await
|
|
17487
|
-
)).filter((manifest) => Boolean(manifest)).filter((manifest) => manifest.bundleType === "
|
|
17488
|
+
(await fs19.readdir(paths.approvalsDir, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.isDirectory()).map(async (entry) => await readApprovalManifest(paths, entry.name).catch(() => null))
|
|
17489
|
+
)).filter((manifest) => Boolean(manifest)).filter((manifest) => manifest.bundleType === "guided-source" || manifest.bundleType === "guided-session").sort((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, 12);
|
|
17488
17490
|
const readerFocusPages = uniqueBy([...guidePages, ...briefPages, ...conceptPages, ...entityPages], (page) => page.id).slice(0, 8);
|
|
17489
17491
|
const diligenceSessions = sourceSessions.filter((session) => session.status === "staged" || session.status === "awaiting_input").slice(0, 8);
|
|
17490
17492
|
const dashboards = [
|
|
@@ -18026,26 +18028,32 @@ function deriveGraphMetrics(nodes, edges) {
|
|
|
18026
18028
|
}
|
|
18027
18029
|
const communityMap = /* @__PURE__ */ new Map();
|
|
18028
18030
|
const communities = [];
|
|
18029
|
-
const
|
|
18031
|
+
const nonSourceIdSet = new Set(nonSourceNodes.map((node) => node.id));
|
|
18032
|
+
const louvainGraph = new Graph({ type: "undirected" });
|
|
18030
18033
|
for (const node of nonSourceNodes) {
|
|
18031
|
-
|
|
18032
|
-
|
|
18033
|
-
|
|
18034
|
-
const
|
|
18035
|
-
|
|
18036
|
-
|
|
18037
|
-
while (queue.length) {
|
|
18038
|
-
const current = queue.shift();
|
|
18039
|
-
memberIds.push(current);
|
|
18040
|
-
for (const neighbor of adjacency.get(current) ?? []) {
|
|
18041
|
-
if (!visited.has(neighbor) && nodes.find((candidate) => candidate.id === neighbor)?.type !== "source") {
|
|
18042
|
-
visited.add(neighbor);
|
|
18043
|
-
queue.push(neighbor);
|
|
18044
|
-
}
|
|
18034
|
+
louvainGraph.addNode(node.id);
|
|
18035
|
+
}
|
|
18036
|
+
for (const node of nonSourceNodes) {
|
|
18037
|
+
for (const neighbor of adjacency.get(node.id) ?? []) {
|
|
18038
|
+
if (nonSourceIdSet.has(neighbor) && !louvainGraph.hasEdge(node.id, neighbor)) {
|
|
18039
|
+
louvainGraph.addEdge(node.id, neighbor);
|
|
18045
18040
|
}
|
|
18046
18041
|
}
|
|
18047
|
-
|
|
18048
|
-
|
|
18042
|
+
}
|
|
18043
|
+
const louvainMapping = louvainGraph.size > 0 ? louvain(louvainGraph, { resolution: 1 }) : {};
|
|
18044
|
+
const groupByCommunity = /* @__PURE__ */ new Map();
|
|
18045
|
+
let nextIsolated = -1;
|
|
18046
|
+
for (const node of nonSourceNodes) {
|
|
18047
|
+
const communityNumber = louvainMapping[node.id] ?? nextIsolated--;
|
|
18048
|
+
if (!groupByCommunity.has(communityNumber)) {
|
|
18049
|
+
groupByCommunity.set(communityNumber, []);
|
|
18050
|
+
}
|
|
18051
|
+
groupByCommunity.get(communityNumber).push(node.id);
|
|
18052
|
+
}
|
|
18053
|
+
let communityIndex = 0;
|
|
18054
|
+
for (const memberIds of groupByCommunity.values()) {
|
|
18055
|
+
const labelSeed = nodes.find((candidate) => candidate.id === memberIds[0])?.label ?? `cluster-${communityIndex + 1}`;
|
|
18056
|
+
const communityId = buildCommunityId(labelSeed, communityIndex);
|
|
18049
18057
|
communities.push({
|
|
18050
18058
|
id: communityId,
|
|
18051
18059
|
label: labelSeed,
|
|
@@ -18054,6 +18062,7 @@ function deriveGraphMetrics(nodes, edges) {
|
|
|
18054
18062
|
for (const memberId of memberIds) {
|
|
18055
18063
|
communityMap.set(memberId, communityId);
|
|
18056
18064
|
}
|
|
18065
|
+
communityIndex++;
|
|
18057
18066
|
}
|
|
18058
18067
|
const degreeMap = /* @__PURE__ */ new Map();
|
|
18059
18068
|
for (const node of nodes) {
|
|
@@ -18704,11 +18713,22 @@ function approvalManifestPath(paths, approvalId) {
|
|
|
18704
18713
|
function approvalGraphPath(paths, approvalId) {
|
|
18705
18714
|
return path23.join(paths.approvalsDir, approvalId, "state", "graph.json");
|
|
18706
18715
|
}
|
|
18716
|
+
function normalizeApprovalBundleType(raw) {
|
|
18717
|
+
if (!raw) return void 0;
|
|
18718
|
+
const legacy = {
|
|
18719
|
+
generated_output: "generated-output",
|
|
18720
|
+
source_review: "source-review",
|
|
18721
|
+
guided_source: "guided-source",
|
|
18722
|
+
guided_session: "guided-session"
|
|
18723
|
+
};
|
|
18724
|
+
return legacy[raw] ?? raw;
|
|
18725
|
+
}
|
|
18707
18726
|
async function readApprovalManifest(paths, approvalId) {
|
|
18708
18727
|
const manifest = await readJsonFile(approvalManifestPath(paths, approvalId));
|
|
18709
18728
|
if (!manifest) {
|
|
18710
18729
|
throw new Error(`Approval bundle not found: ${approvalId}`);
|
|
18711
18730
|
}
|
|
18731
|
+
manifest.bundleType = normalizeApprovalBundleType(manifest.bundleType);
|
|
18712
18732
|
return manifest;
|
|
18713
18733
|
}
|
|
18714
18734
|
async function writeApprovalManifest(paths, manifest) {
|
|
@@ -19551,7 +19571,7 @@ async function stageOutputApprovalBundle(rootDir, stagedPages, options = {}) {
|
|
|
19551
19571
|
await writeApprovalManifest(paths, {
|
|
19552
19572
|
approvalId,
|
|
19553
19573
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19554
|
-
bundleType: options.bundleType ?? "
|
|
19574
|
+
bundleType: options.bundleType ?? "generated-output",
|
|
19555
19575
|
title: options.title,
|
|
19556
19576
|
sourceSessionId: options.sourceSessionId,
|
|
19557
19577
|
entries: await buildApprovalEntries(
|
|
@@ -21243,7 +21263,7 @@ async function bootstrapDemo(rootDir, input) {
|
|
|
21243
21263
|
}
|
|
21244
21264
|
|
|
21245
21265
|
// src/mcp.ts
|
|
21246
|
-
var SERVER_VERSION = "0.7.
|
|
21266
|
+
var SERVER_VERSION = "0.7.24";
|
|
21247
21267
|
async function createMcpServer(rootDir) {
|
|
21248
21268
|
const server = new McpServer({
|
|
21249
21269
|
name: "swarmvault",
|
|
@@ -23069,7 +23089,7 @@ async function buildSourceGuideStagedPage(rootDir, scope) {
|
|
|
23069
23089
|
async function stageSourceReviewForScope(rootDir, scope) {
|
|
23070
23090
|
const output = await buildSourceReviewStagedPage(rootDir, scope);
|
|
23071
23091
|
const approval = await stageGeneratedOutputPages(rootDir, [{ page: output.page, content: output.content, label: "source-review" }], {
|
|
23072
|
-
bundleType: "
|
|
23092
|
+
bundleType: "source-review",
|
|
23073
23093
|
title: `Source Review: ${scope.title}`
|
|
23074
23094
|
});
|
|
23075
23095
|
return {
|
|
@@ -23421,7 +23441,7 @@ async function stageSourceGuideForScope(rootDir, scope, options = {}) {
|
|
|
23421
23441
|
...guidedUpdates
|
|
23422
23442
|
],
|
|
23423
23443
|
{
|
|
23424
|
-
bundleType: "
|
|
23444
|
+
bundleType: "guided-session",
|
|
23425
23445
|
title: `Guided Session: ${scope.title}`,
|
|
23426
23446
|
sourceSessionId: session.sessionId
|
|
23427
23447
|
}
|
|
@@ -23875,16 +23895,38 @@ var CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
23875
23895
|
".r",
|
|
23876
23896
|
".R"
|
|
23877
23897
|
]);
|
|
23898
|
+
var FILE_CHANGE_RE = /^(?:add|change|unlink):(.+)$/;
|
|
23878
23899
|
function isCodeOnlyChange(reasons) {
|
|
23879
23900
|
for (const reason of reasons) {
|
|
23880
|
-
const match = reason.match(
|
|
23881
|
-
if (!match)
|
|
23882
|
-
const
|
|
23883
|
-
const ext = path27.extname(filePath).toLowerCase();
|
|
23901
|
+
const match = reason.match(FILE_CHANGE_RE);
|
|
23902
|
+
if (!match) return false;
|
|
23903
|
+
const ext = path27.extname(match[1]).toLowerCase();
|
|
23884
23904
|
if (!ext || !CODE_EXTENSIONS.has(ext)) return false;
|
|
23885
23905
|
}
|
|
23886
23906
|
return reasons.size > 0;
|
|
23887
23907
|
}
|
|
23908
|
+
function hasNonCodeChanges(reasons) {
|
|
23909
|
+
for (const reason of reasons) {
|
|
23910
|
+
const match = reason.match(FILE_CHANGE_RE);
|
|
23911
|
+
if (!match) return true;
|
|
23912
|
+
const ext = path27.extname(match[1]).toLowerCase();
|
|
23913
|
+
if (!ext || !CODE_EXTENSIONS.has(ext)) return true;
|
|
23914
|
+
}
|
|
23915
|
+
return false;
|
|
23916
|
+
}
|
|
23917
|
+
function collectNonCodePaths(reasons) {
|
|
23918
|
+
const result = [];
|
|
23919
|
+
for (const reason of reasons) {
|
|
23920
|
+
const match = reason.match(FILE_CHANGE_RE);
|
|
23921
|
+
if (!match) {
|
|
23922
|
+
result.push(reason);
|
|
23923
|
+
continue;
|
|
23924
|
+
}
|
|
23925
|
+
const ext = path27.extname(match[1]).toLowerCase();
|
|
23926
|
+
if (!ext || !CODE_EXTENSIONS.has(ext)) result.push(match[1]);
|
|
23927
|
+
}
|
|
23928
|
+
return result;
|
|
23929
|
+
}
|
|
23888
23930
|
function hasIgnoredRepoSegment(baseDir, targetPath) {
|
|
23889
23931
|
const relativePath = path27.relative(baseDir, targetPath);
|
|
23890
23932
|
if (!relativePath || relativePath.startsWith("..")) {
|
|
@@ -23957,7 +23999,7 @@ async function runWatchCycle(rootDir, options = {}) {
|
|
|
23957
23999
|
changedPages: []
|
|
23958
24000
|
};
|
|
23959
24001
|
try {
|
|
23960
|
-
result = await performWatchCycle(rootDir, paths, options);
|
|
24002
|
+
result = await performWatchCycle(rootDir, paths, options, options.codeOnly ?? false);
|
|
23961
24003
|
return result;
|
|
23962
24004
|
} catch (caught) {
|
|
23963
24005
|
success = false;
|
|
@@ -24107,10 +24149,18 @@ async function watchVault(rootDir, options = {}) {
|
|
|
24107
24149
|
pending = false;
|
|
24108
24150
|
running = true;
|
|
24109
24151
|
const startedAt = /* @__PURE__ */ new Date();
|
|
24110
|
-
const
|
|
24152
|
+
const detectedCodeOnly = isCodeOnlyChange(reasons);
|
|
24153
|
+
const hasDeferredNonCode = !detectedCodeOnly && hasNonCodeChanges(reasons);
|
|
24154
|
+
const codeOnlyChange = options.codeOnly || detectedCodeOnly || hasDeferredNonCode;
|
|
24111
24155
|
const runReasons = [...reasons];
|
|
24112
24156
|
reasons.clear();
|
|
24113
|
-
if (
|
|
24157
|
+
if (hasDeferredNonCode) {
|
|
24158
|
+
const nonCodePaths = collectNonCodePaths(new Set(runReasons));
|
|
24159
|
+
process3.stderr.write(
|
|
24160
|
+
`[swarmvault watch] Non-code changes detected (${nonCodePaths.length} file(s)) \u2014 run \`swarmvault compile\` to include LLM re-analysis.
|
|
24161
|
+
`
|
|
24162
|
+
);
|
|
24163
|
+
} else if (codeOnlyChange) {
|
|
24114
24164
|
process3.stderr.write("[swarmvault watch] Code-only changes detected \u2014 skipping LLM re-analysis.\n");
|
|
24115
24165
|
}
|
|
24116
24166
|
let importedCount = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmvaultai/engine",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.24",
|
|
4
4
|
"description": "Core engine for SwarmVault: ingest, compile, query, lint, and provider abstractions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -50,6 +50,8 @@
|
|
|
50
50
|
"csv-parse": "^6.2.1",
|
|
51
51
|
"fast-xml-parser": "^5.5.11",
|
|
52
52
|
"fflate": "^0.8.2",
|
|
53
|
+
"graphology": "^0.26.0",
|
|
54
|
+
"graphology-communities-louvain": "^2.0.2",
|
|
53
55
|
"gray-matter": "^4.0.3",
|
|
54
56
|
"ignore": "^7.0.5",
|
|
55
57
|
"ini": "^6.0.0",
|
|
@@ -81,6 +83,7 @@
|
|
|
81
83
|
"@types/mime-types": "^3.0.1",
|
|
82
84
|
"@types/node": "^24.6.0",
|
|
83
85
|
"@types/turndown": "^5.0.5",
|
|
86
|
+
"graphology-types": "^0.24.8",
|
|
84
87
|
"tsup": "^8.5.0",
|
|
85
88
|
"vitest": "^3.2.4"
|
|
86
89
|
},
|