@swarmvaultai/cli 3.7.3 → 3.9.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 +31 -0
- package/dist/index.js +73 -13
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -17,6 +17,16 @@ Installed commands:
|
|
|
17
17
|
- `swarmvault`
|
|
18
18
|
- `vault` as a compatibility alias
|
|
19
19
|
|
|
20
|
+
## Maintainer Validation
|
|
21
|
+
|
|
22
|
+
Release preflight includes a direct CLI surface smoke before tarball smoke:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pnpm live:cli-surface
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The smoke parses `packages/cli/src/index.ts` with the TypeScript compiler API, checks that every stable Commander command path and alias is classified in the surface manifest, runs `--help` across the full command tree, and exercises direct JSON behavior checks for the core local workflows.
|
|
29
|
+
|
|
20
30
|
## First Run
|
|
21
31
|
|
|
22
32
|
```bash
|
|
@@ -55,6 +65,8 @@ swarmvault explore "What should I research next?" --steps 3
|
|
|
55
65
|
swarmvault lint --deep
|
|
56
66
|
swarmvault graph blast ./src/index.ts
|
|
57
67
|
swarmvault graph status ./src
|
|
68
|
+
swarmvault graph stats
|
|
69
|
+
swarmvault graph validate --strict
|
|
58
70
|
swarmvault graph update .
|
|
59
71
|
swarmvault graph cluster
|
|
60
72
|
swarmvault graph tree --output ./exports/tree.html
|
|
@@ -429,6 +441,25 @@ Read-only graph freshness check for tracked repo roots or one explicit repo path
|
|
|
429
441
|
- recommends `swarmvault compile` when graph/report artifacts are missing, non-code files changed, or a semantic refresh is pending
|
|
430
442
|
- supports global `--json` for automation
|
|
431
443
|
|
|
444
|
+
### `swarmvault graph stats`
|
|
445
|
+
|
|
446
|
+
Summarize the current compiled graph without opening the viewer.
|
|
447
|
+
|
|
448
|
+
- reports source, page, node, edge, hyperedge, and community counts
|
|
449
|
+
- breaks down node types, evidence classes, source classes, edge relations, and hyperedge relations
|
|
450
|
+
- keeps the same lightweight shape as the MCP `graph_stats` tool
|
|
451
|
+
- supports global `--json` for automation
|
|
452
|
+
|
|
453
|
+
### `swarmvault graph validate [graph] [--strict]`
|
|
454
|
+
|
|
455
|
+
Validate graph artifact integrity before exporting, merging, pushing, or publishing generated graph evidence.
|
|
456
|
+
|
|
457
|
+
- defaults to the current vault's compiled `state/graph.json`
|
|
458
|
+
- accepts an explicit graph JSON path for exported or merged graph artifacts
|
|
459
|
+
- checks duplicate ids, dangling node/page/community/hyperedge references, confidence bounds, empty critical fields, and conflicted-edge evidence consistency
|
|
460
|
+
- exits non-zero when errors are present; with `--strict`, warnings also fail the command
|
|
461
|
+
- supports global `--json` for automation
|
|
462
|
+
|
|
432
463
|
### `swarmvault graph cluster [--resolution <n>]`
|
|
433
464
|
|
|
434
465
|
Recompute communities, node degrees, bridge scores, god-node flags, and graph report artifacts from the existing `state/graph.json` without re-ingesting or re-analyzing sources.
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
getRetrievalStatus,
|
|
40
40
|
getWatchStatus,
|
|
41
41
|
graphDiff,
|
|
42
|
+
graphStatsVault,
|
|
42
43
|
guideManagedSource,
|
|
43
44
|
guideSourceScope,
|
|
44
45
|
importInbox,
|
|
@@ -95,6 +96,7 @@ import {
|
|
|
95
96
|
summarizeLocalWhisperSetup,
|
|
96
97
|
uninstallGitHooks,
|
|
97
98
|
updateMemoryTask,
|
|
99
|
+
validateGraphVault,
|
|
98
100
|
watchVault
|
|
99
101
|
} from "@swarmvaultai/engine";
|
|
100
102
|
import { Command, Option } from "commander";
|
|
@@ -313,9 +315,9 @@ program.name("swarmvault").description("SwarmVault is a local-first knowledge co
|
|
|
313
315
|
function readCliVersion() {
|
|
314
316
|
try {
|
|
315
317
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
316
|
-
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.
|
|
318
|
+
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.9.0";
|
|
317
319
|
} catch {
|
|
318
|
-
return "3.
|
|
320
|
+
return "3.9.0";
|
|
319
321
|
}
|
|
320
322
|
}
|
|
321
323
|
function parsePositiveInt(value, fallback) {
|
|
@@ -364,6 +366,9 @@ function summarizeRedactions(redactions) {
|
|
|
364
366
|
const sourceLabel = redactions.length === 1 ? "source" : "sources";
|
|
365
367
|
return `Redacted ${totalMatches} ${secretsLabel} across ${redactions.length} ${sourceLabel} (run --no-redact to disable).`;
|
|
366
368
|
}
|
|
369
|
+
function topCountEntries(record, limit = 8) {
|
|
370
|
+
return Object.entries(record).filter(([, count]) => count > 0).sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).slice(0, limit);
|
|
371
|
+
}
|
|
367
372
|
function emitJson(data) {
|
|
368
373
|
process2.stdout.write(`${JSON.stringify(data)}
|
|
369
374
|
`);
|
|
@@ -1225,6 +1230,46 @@ graph.command("status").description("Read-only check for graph/report presence a
|
|
|
1225
1230
|
log(`Recommended: ${status.recommendedCommand}`);
|
|
1226
1231
|
}
|
|
1227
1232
|
});
|
|
1233
|
+
graph.command("stats").description("Summarize compiled graph counts, node types, evidence classes, and relation mix.").action(async () => {
|
|
1234
|
+
const stats = await graphStatsVault(process2.cwd());
|
|
1235
|
+
if (isJson()) {
|
|
1236
|
+
emitJson(stats);
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
log(
|
|
1240
|
+
`Graph stats: ${stats.counts.nodes} nodes, ${stats.counts.edges} edges, ${stats.counts.pages} pages, ${stats.counts.hyperedges} hyperedges, ${stats.counts.communities} communities.`
|
|
1241
|
+
);
|
|
1242
|
+
const nodeTypes = topCountEntries(stats.nodeTypes);
|
|
1243
|
+
if (nodeTypes.length) {
|
|
1244
|
+
log(`Node types: ${nodeTypes.map(([name, count]) => `${name}=${count}`).join(", ")}`);
|
|
1245
|
+
}
|
|
1246
|
+
const evidence = topCountEntries(stats.evidenceClasses);
|
|
1247
|
+
if (evidence.length) {
|
|
1248
|
+
log(`Evidence: ${evidence.map(([name, count]) => `${name}=${count}`).join(", ")}`);
|
|
1249
|
+
}
|
|
1250
|
+
const relations = topCountEntries(stats.edgeRelations);
|
|
1251
|
+
if (relations.length) {
|
|
1252
|
+
log(`Top relations: ${relations.map(([name, count]) => `${name}=${count}`).join(", ")}`);
|
|
1253
|
+
}
|
|
1254
|
+
});
|
|
1255
|
+
graph.command("validate").description("Validate a compiled graph artifact for dangling references, duplicate ids, and confidence bounds.").argument("[graph]", "Optional graph JSON path; defaults to the current vault graph").option("--strict", "Treat warnings as failures", false).action(async (graphPath, options) => {
|
|
1256
|
+
const result = await validateGraphVault(process2.cwd(), {
|
|
1257
|
+
graphPath,
|
|
1258
|
+
strict: options.strict ?? false
|
|
1259
|
+
});
|
|
1260
|
+
if (isJson()) {
|
|
1261
|
+
emitJson(result);
|
|
1262
|
+
} else {
|
|
1263
|
+
log(result.summary);
|
|
1264
|
+
for (const issue of result.issues) {
|
|
1265
|
+
const location = issue.path ? ` ${issue.path}` : "";
|
|
1266
|
+
log(`[${issue.severity}] ${issue.code}${location}: ${issue.message}`);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
if (!result.ok) {
|
|
1270
|
+
process2.exitCode = 1;
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1228
1273
|
graph.command("cluster").alias("clusters").description("Recompute graph communities, degrees, god-node flags, and graph report artifacts without re-ingesting sources.").option("--resolution <number>", "Override the Louvain community resolution for this run").action(async (options) => {
|
|
1229
1274
|
const resolution = parsePositiveNumber(options.resolution);
|
|
1230
1275
|
if (options.resolution && resolution === void 0) {
|
|
@@ -1383,18 +1428,33 @@ graph.command("share").description("Print a shareable summary of the compiled gr
|
|
|
1383
1428
|
}
|
|
1384
1429
|
log(options.post ? artifact.shortPost : renderGraphShareMarkdown(artifact));
|
|
1385
1430
|
});
|
|
1386
|
-
graph.command("query").description("Traverse the compiled graph deterministically from local search seeds.").argument("<question>", "Question or graph search seed").option("--dfs", "Prefer a depth-first traversal instead of breadth-first", false).option("--budget <n>", "Maximum number of graph nodes to summarize").
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1431
|
+
graph.command("query").description("Traverse the compiled graph deterministically from local search seeds.").argument("<question>", "Question or graph search seed").option("--dfs", "Prefer a depth-first traversal instead of breadth-first", false).option("--budget <n>", "Maximum number of graph nodes to summarize").option("--relation <name>", "Only traverse edges with this relation name (repeatable)", collectRepeated, []).option(
|
|
1432
|
+
"--context <group>",
|
|
1433
|
+
"Relation group context: calls, imports, types, data, rationale, or evidence (repeatable)",
|
|
1434
|
+
collectRepeated,
|
|
1435
|
+
[]
|
|
1436
|
+
).option("--evidence <class>", "Evidence class: extracted, inferred, or ambiguous (repeatable)", collectRepeated, []).option("--node-type <type>", "Prefer traversal around this graph node type (repeatable)", collectRepeated, []).option("--language <lang>", "Prefer traversal around this code language (repeatable)", collectRepeated, []).action(
|
|
1437
|
+
async (question, options) => {
|
|
1438
|
+
const budget = options.budget ? parsePositiveInt(options.budget, 0) || void 0 : void 0;
|
|
1439
|
+
const filters = {
|
|
1440
|
+
relations: options.relation,
|
|
1441
|
+
relationGroups: options.context,
|
|
1442
|
+
evidenceClasses: options.evidence,
|
|
1443
|
+
nodeTypes: options.nodeType,
|
|
1444
|
+
languages: options.language
|
|
1445
|
+
};
|
|
1446
|
+
const result = await queryGraphVault(process2.cwd(), question, {
|
|
1447
|
+
traversal: options.dfs ? "dfs" : "bfs",
|
|
1448
|
+
budget,
|
|
1449
|
+
filters
|
|
1450
|
+
});
|
|
1451
|
+
if (isJson()) {
|
|
1452
|
+
emitJson(result);
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
log(result.summary);
|
|
1395
1456
|
}
|
|
1396
|
-
|
|
1397
|
-
});
|
|
1457
|
+
);
|
|
1398
1458
|
graph.command("path").description("Find the shortest graph path between two nodes or pages.").argument("<from>", "Source node/page label or id").argument("<to>", "Target node/page label or id").action(async (from, to) => {
|
|
1399
1459
|
const result = await pathGraphVault(process2.cwd(), from, to);
|
|
1400
1460
|
if (isJson()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmvaultai/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "Global CLI for SwarmVault.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"prepublishOnly": "node ../../scripts/check-release-sync.mjs && node ../../scripts/check-published-manifests.mjs"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@swarmvaultai/engine": "3.
|
|
47
|
+
"@swarmvaultai/engine": "3.9.0",
|
|
48
48
|
"commander": "^14.0.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|