@swarmvaultai/cli 3.8.0 → 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.
Files changed (3) hide show
  1. package/README.md +31 -0
  2. package/dist/index.js +47 -2
  3. 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.8.0";
318
+ return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.9.0";
317
319
  } catch {
318
- return "3.8.0";
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmvaultai/cli",
3
- "version": "3.8.0",
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.8.0",
47
+ "@swarmvaultai/engine": "3.9.0",
48
48
  "commander": "^14.0.1"
49
49
  },
50
50
  "devDependencies": {