@swarmvaultai/cli 3.8.0 → 3.10.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 +66 -0
  2. package/dist/index.js +105 -51
  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,8 +65,13 @@ 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 check-update ./src
69
+ swarmvault graph stats
70
+ swarmvault graph validate --strict
58
71
  swarmvault graph update .
72
+ swarmvault update .
59
73
  swarmvault graph cluster
74
+ swarmvault cluster-only
60
75
  swarmvault graph tree --output ./exports/tree.html
61
76
  swarmvault graph query "Which nodes bridge the biggest clusters?"
62
77
  swarmvault graph explain "concept:drift"
@@ -67,6 +82,7 @@ swarmvault graph serve
67
82
  swarmvault graph export --report ./exports/report.html
68
83
  swarmvault graph export --html ./exports/graph.html
69
84
  swarmvault graph export --cypher ./exports/graph.cypher
85
+ swarmvault graph export --neo4j ./exports/graph.cypher
70
86
  swarmvault graph merge ./exports/graph.json ./other-graph.json --out ./exports/merged-graph.json
71
87
  swarmvault graph push neo4j --dry-run
72
88
  ```
@@ -398,6 +414,22 @@ Refresh code-derived graph artifacts from tracked repo roots or one explicit rep
398
414
  - aborts if nodes or edges drop by more than 25% compared with the existing graph; pass `--force` or set `SWARMVAULT_FORCE_UPDATE=1` when the shrink is expected
399
415
  - `--json` returns the same one-shot watch result shape, including repo import/update/remove counts and pending semantic refresh entries
400
416
 
417
+ ### `swarmvault check-update [path]`
418
+
419
+ Compatibility alias for `swarmvault graph status [path]`.
420
+
421
+ - performs the same read-only graph/report freshness check
422
+ - keeps automation-friendly JSON output for cron or hook wrappers
423
+ - recommends `swarmvault update`/`swarmvault graph update` for code-only drift and `swarmvault compile` when semantic refresh is required
424
+
425
+ ### `swarmvault update [path]`
426
+
427
+ Compatibility alias for `swarmvault graph update [path]`.
428
+
429
+ - runs the same code-only repo refresh path
430
+ - accepts `--lint` and `--force`
431
+ - returns the same JSON shape as `graph update`
432
+
401
433
  ### `swarmvault graph tree [--output <html>] [--root <path>] [--label <name>] [--max-children <n>]`
402
434
 
403
435
  Write a collapsible HTML source tree for the current `state/graph.json`.
@@ -429,6 +461,25 @@ Read-only graph freshness check for tracked repo roots or one explicit repo path
429
461
  - recommends `swarmvault compile` when graph/report artifacts are missing, non-code files changed, or a semantic refresh is pending
430
462
  - supports global `--json` for automation
431
463
 
464
+ ### `swarmvault graph stats`
465
+
466
+ Summarize the current compiled graph without opening the viewer.
467
+
468
+ - reports source, page, node, edge, hyperedge, and community counts
469
+ - breaks down node types, evidence classes, source classes, edge relations, and hyperedge relations
470
+ - keeps the same lightweight shape as the MCP `graph_stats` tool
471
+ - supports global `--json` for automation
472
+
473
+ ### `swarmvault graph validate [graph] [--strict]`
474
+
475
+ Validate graph artifact integrity before exporting, merging, pushing, or publishing generated graph evidence.
476
+
477
+ - defaults to the current vault's compiled `state/graph.json`
478
+ - accepts an explicit graph JSON path for exported or merged graph artifacts
479
+ - checks duplicate ids, dangling node/page/community/hyperedge references, confidence bounds, empty critical fields, and conflicted-edge evidence consistency
480
+ - exits non-zero when errors are present; with `--strict`, warnings also fail the command
481
+ - supports global `--json` for automation
482
+
432
483
  ### `swarmvault graph cluster [--resolution <n>]`
433
484
 
434
485
  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.
@@ -439,6 +490,21 @@ Recompute communities, node degrees, bridge scores, god-node flags, and graph re
439
490
  - splits oversized or low-cohesion communities after the initial Louvain pass so large-repo reports stay scannable
440
491
  - `--json` returns counts plus the graph/report paths
441
492
 
493
+ ### `swarmvault cluster-only [vault] [--resolution <n>]`
494
+
495
+ Compatibility alias for `swarmvault graph cluster`.
496
+
497
+ - recomputes communities and graph report artifacts without ingest or semantic analysis
498
+ - accepts an optional vault root when the command is run from outside the vault
499
+ - returns the same JSON shape as `graph cluster`
500
+
501
+ ### `swarmvault graph export --neo4j <path>`
502
+
503
+ Compatibility alias for `swarmvault graph export --cypher <path>`.
504
+
505
+ - writes a Neo4j-ready Cypher import file
506
+ - can be combined with other `graph export` formats in the same run
507
+
442
508
  ### `swarmvault hook install|uninstall|status`
443
509
 
444
510
  Manage SwarmVault's local git hook blocks for the nearest git repository.
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.10.0";
317
319
  } catch {
318
- return "3.8.0";
320
+ return "3.10.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
  `);
@@ -483,6 +488,63 @@ function getCommandPath(command) {
483
488
  }
484
489
  return names;
485
490
  }
491
+ async function runGraphUpdateCommand(targetPath, options) {
492
+ const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
493
+ const result = await runWatchCycle(process2.cwd(), {
494
+ repo: true,
495
+ codeOnly: true,
496
+ lint: options.lint ?? false,
497
+ force: options.force ?? false,
498
+ overrideRoots
499
+ });
500
+ if (isJson()) {
501
+ emitJson(result);
502
+ return;
503
+ }
504
+ log(
505
+ `Updated graph from ${result.watchedRepoRoots.length} repo root${result.watchedRepoRoots.length === 1 ? "" : "s"}. Imported ${result.repoImportedCount}, updated ${result.repoUpdatedCount}, removed ${result.repoRemovedCount}, pending semantic refresh ${result.pendingSemanticRefreshCount}.`
506
+ );
507
+ }
508
+ async function showGraphStatusCommand(targetPath) {
509
+ const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
510
+ const status = await getGraphStatus(process2.cwd(), { repoRoots: overrideRoots });
511
+ if (isJson()) {
512
+ emitJson(status);
513
+ return;
514
+ }
515
+ log(`Graph: ${status.graphExists ? status.graphPath : `missing (${status.graphPath})`}`);
516
+ log(`Report: ${status.reportExists ? status.reportPath : `missing (${status.reportPath})`}`);
517
+ log(`Tracked repo roots: ${status.trackedRepoRoots.length ? status.trackedRepoRoots.join(", ") : "none"}`);
518
+ log(`Code changes: ${status.codeChangeCount}`);
519
+ log(`Semantic changes: ${status.semanticChangeCount}`);
520
+ log(`Pending semantic refresh: ${status.pendingSemanticRefresh.length}`);
521
+ if (status.changes.length) {
522
+ for (const change of status.changes.slice(0, 20)) {
523
+ log(`- ${change.refreshType} ${change.changeType} ${change.path}`);
524
+ }
525
+ if (status.changes.length > 20) {
526
+ log(`... and ${status.changes.length - 20} more`);
527
+ }
528
+ }
529
+ log(`State: ${status.stale ? "stale" : "fresh"}`);
530
+ if (status.recommendedCommand) {
531
+ log(`Recommended: ${status.recommendedCommand}`);
532
+ }
533
+ }
534
+ async function runGraphClusterCommand(options, rootDir = process2.cwd()) {
535
+ const resolution = parsePositiveNumber(options.resolution);
536
+ if (options.resolution && resolution === void 0) {
537
+ throw new Error("--resolution must be a positive number.");
538
+ }
539
+ const result = await refreshGraphClusters(rootDir, { resolution });
540
+ if (isJson()) {
541
+ emitJson(result);
542
+ return;
543
+ }
544
+ log(
545
+ `Refreshed ${result.communityCount} communities across ${result.nodeCount} nodes and ${result.edgeCount} edges. Report: ${result.reportPath}`
546
+ );
547
+ }
486
548
  program.hook("postAction", async (_thisCommand, actionCommand) => {
487
549
  const notices = await collectCliNotices({
488
550
  commandPath: getCommandPath(actionCommand),
@@ -1152,23 +1214,7 @@ program.command("lint").description("Run anti-drift and wiki-health checks.").op
1152
1214
  });
1153
1215
  var graph = program.command("graph").description("Graph-related commands.").enablePositionalOptions();
1154
1216
  var graphPush = graph.command("push").description("Push the compiled graph into external sinks.");
1155
- graph.command("update").alias("refresh").description("Refresh code-derived graph artifacts from tracked repo roots or one explicit repo path.").argument("[path]", "Optional repo root to refresh instead of configured/tracked roots").option("--lint", "Run lint after the refresh cycle", false).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(async (targetPath, options) => {
1156
- const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
1157
- const result = await runWatchCycle(process2.cwd(), {
1158
- repo: true,
1159
- codeOnly: true,
1160
- lint: options.lint ?? false,
1161
- force: options.force ?? false,
1162
- overrideRoots
1163
- });
1164
- if (isJson()) {
1165
- emitJson(result);
1166
- return;
1167
- }
1168
- log(
1169
- `Updated graph from ${result.watchedRepoRoots.length} repo root${result.watchedRepoRoots.length === 1 ? "" : "s"}. Imported ${result.repoImportedCount}, updated ${result.repoUpdatedCount}, removed ${result.repoRemovedCount}, pending semantic refresh ${result.pendingSemanticRefreshCount}.`
1170
- );
1171
- });
1217
+ graph.command("update").alias("refresh").description("Refresh code-derived graph artifacts from tracked repo roots or one explicit repo path.").argument("[path]", "Optional repo root to refresh instead of configured/tracked roots").option("--lint", "Run lint after the refresh cycle", false).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(runGraphUpdateCommand);
1172
1218
  graph.command("tree").description("Write a collapsible source/module/symbol tree for the compiled graph.").option("--output <html>", "Output HTML path (default: wiki/graph/tree.html)").option("--root <path>", "Vault root to read instead of the current directory").option("--label <name>", "Tree title").option("--max-children <n>", "Maximum children to render per tree node", "250").action(async (options) => {
1173
1219
  const rootDir = options.root ? path2.resolve(process2.cwd(), options.root) : process2.cwd();
1174
1220
  const result = await exportGraphTree(rootDir, options.output, {
@@ -1199,46 +1245,48 @@ graph.command("merge").description("Merge SwarmVault or node-link JSON graph fil
1199
1245
  log(`Warning: ${warning}`);
1200
1246
  }
1201
1247
  });
1202
- graph.command("status").description("Read-only check for graph/report presence and tracked repo changes.").argument("[path]", "Optional repo root to check instead of configured/tracked roots").action(async (targetPath) => {
1203
- const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
1204
- const status = await getGraphStatus(process2.cwd(), { repoRoots: overrideRoots });
1248
+ graph.command("status").description("Read-only check for graph/report presence and tracked repo changes.").argument("[path]", "Optional repo root to check instead of configured/tracked roots").action(showGraphStatusCommand);
1249
+ graph.command("stats").description("Summarize compiled graph counts, node types, evidence classes, and relation mix.").action(async () => {
1250
+ const stats = await graphStatsVault(process2.cwd());
1205
1251
  if (isJson()) {
1206
- emitJson(status);
1252
+ emitJson(stats);
1207
1253
  return;
1208
1254
  }
1209
- log(`Graph: ${status.graphExists ? status.graphPath : `missing (${status.graphPath})`}`);
1210
- log(`Report: ${status.reportExists ? status.reportPath : `missing (${status.reportPath})`}`);
1211
- log(`Tracked repo roots: ${status.trackedRepoRoots.length ? status.trackedRepoRoots.join(", ") : "none"}`);
1212
- log(`Code changes: ${status.codeChangeCount}`);
1213
- log(`Semantic changes: ${status.semanticChangeCount}`);
1214
- log(`Pending semantic refresh: ${status.pendingSemanticRefresh.length}`);
1215
- if (status.changes.length) {
1216
- for (const change of status.changes.slice(0, 20)) {
1217
- log(`- ${change.refreshType} ${change.changeType} ${change.path}`);
1218
- }
1219
- if (status.changes.length > 20) {
1220
- log(`... and ${status.changes.length - 20} more`);
1221
- }
1255
+ log(
1256
+ `Graph stats: ${stats.counts.nodes} nodes, ${stats.counts.edges} edges, ${stats.counts.pages} pages, ${stats.counts.hyperedges} hyperedges, ${stats.counts.communities} communities.`
1257
+ );
1258
+ const nodeTypes = topCountEntries(stats.nodeTypes);
1259
+ if (nodeTypes.length) {
1260
+ log(`Node types: ${nodeTypes.map(([name, count]) => `${name}=${count}`).join(", ")}`);
1222
1261
  }
1223
- log(`State: ${status.stale ? "stale" : "fresh"}`);
1224
- if (status.recommendedCommand) {
1225
- log(`Recommended: ${status.recommendedCommand}`);
1262
+ const evidence = topCountEntries(stats.evidenceClasses);
1263
+ if (evidence.length) {
1264
+ log(`Evidence: ${evidence.map(([name, count]) => `${name}=${count}`).join(", ")}`);
1226
1265
  }
1227
- });
1228
- 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
- const resolution = parsePositiveNumber(options.resolution);
1230
- if (options.resolution && resolution === void 0) {
1231
- throw new Error("--resolution must be a positive number.");
1266
+ const relations = topCountEntries(stats.edgeRelations);
1267
+ if (relations.length) {
1268
+ log(`Top relations: ${relations.map(([name, count]) => `${name}=${count}`).join(", ")}`);
1232
1269
  }
1233
- const result = await refreshGraphClusters(process2.cwd(), { resolution });
1270
+ });
1271
+ 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) => {
1272
+ const result = await validateGraphVault(process2.cwd(), {
1273
+ graphPath,
1274
+ strict: options.strict ?? false
1275
+ });
1234
1276
  if (isJson()) {
1235
1277
  emitJson(result);
1236
- return;
1278
+ } else {
1279
+ log(result.summary);
1280
+ for (const issue of result.issues) {
1281
+ const location = issue.path ? ` ${issue.path}` : "";
1282
+ log(`[${issue.severity}] ${issue.code}${location}: ${issue.message}`);
1283
+ }
1284
+ }
1285
+ if (!result.ok) {
1286
+ process2.exitCode = 1;
1237
1287
  }
1238
- log(
1239
- `Refreshed ${result.communityCount} communities across ${result.nodeCount} nodes and ${result.edgeCount} edges. Report: ${result.reportPath}`
1240
- );
1241
1288
  });
1289
+ 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((options) => runGraphClusterCommand(options));
1242
1290
  graphPush.command("neo4j").description("Push the compiled graph directly into Neo4j over Bolt/Aura.").option("--uri <bolt-uri>", "Neo4j Bolt or Aura URI").option("--username <user>", "Neo4j username").option("--password-env <env-var>", "Environment variable containing the Neo4j password").option("--database <name>", "Neo4j database name").option("--vault-id <id>", "Stable vault identifier used for shared-database namespacing").option("--batch-size <n>", "Maximum rows to write per Neo4j transaction batch").option("--include-third-party", "Also push third-party repo material", false).option("--include-resources", "Also push resource-like content", false).option("--include-generated", "Also push generated output", false).option("--dry-run", "Show what would be pushed without writing to Neo4j", false).action(
1243
1291
  async (options) => {
1244
1292
  const batchSize = typeof options.batchSize === "string" && options.batchSize.trim() ? parsePositiveInt(options.batchSize, 0) || void 0 : void 0;
@@ -1294,7 +1342,7 @@ graph.command("serve").description("Serve the local graph viewer.").option("--po
1294
1342
  });
1295
1343
  graph.command("export").description(
1296
1344
  "Export the graph as HTML, report, SVG, GraphML, Cypher, JSON, Obsidian vault, or Obsidian canvas. Combine flags to write multiple formats in one run."
1297
- ).option("--html <output>", "Output HTML file path").option("--html-standalone <output>", "Output lightweight standalone HTML file path (vis.js, no build tooling)").option("--report <output>", "Output self-contained HTML report (graph stats, key nodes, communities)").option("--svg <output>", "Output SVG file path").option("--graphml <output>", "Output GraphML file path").option("--cypher <output>", "Output Cypher file path").option("--json <output>", "Output JSON file path").option("--obsidian <output>", "Output Obsidian vault directory path").option("--canvas <output>", "Output Obsidian canvas file path").option("--full", "Include the full graph in HTML export (default; queries traverse complete graph)", true).option("--overview", "Use overview sampling for HTML export (smaller file, queries limited to sampled nodes)", false).action(
1345
+ ).option("--html <output>", "Output HTML file path").option("--html-standalone <output>", "Output lightweight standalone HTML file path (vis.js, no build tooling)").option("--report <output>", "Output self-contained HTML report (graph stats, key nodes, communities)").option("--svg <output>", "Output SVG file path").option("--graphml <output>", "Output GraphML file path").option("--cypher <output>", "Output Cypher file path").option("--neo4j <output>", "Compatibility alias for --cypher, writing a Neo4j Cypher import file").option("--json <output>", "Output JSON file path").option("--obsidian <output>", "Output Obsidian vault directory path").option("--canvas <output>", "Output Obsidian canvas file path").option("--full", "Include the full graph in HTML export (default; queries traverse complete graph)", true).option("--overview", "Use overview sampling for HTML export (smaller file, queries limited to sampled nodes)", false).action(
1298
1346
  async (options) => {
1299
1347
  const useFullGraph = options.overview ? false : options.full ?? true;
1300
1348
  const targets = [
@@ -1304,13 +1352,14 @@ graph.command("export").description(
1304
1352
  options.svg ? { format: "svg", outputPath: options.svg } : null,
1305
1353
  options.graphml ? { format: "graphml", outputPath: options.graphml } : null,
1306
1354
  options.cypher ? { format: "cypher", outputPath: options.cypher } : null,
1355
+ options.neo4j ? { format: "cypher", outputPath: options.neo4j } : null,
1307
1356
  options.json ? { format: "json", outputPath: options.json } : null,
1308
1357
  options.obsidian ? { format: "obsidian", outputPath: options.obsidian } : null,
1309
1358
  options.canvas ? { format: "canvas", outputPath: options.canvas } : null
1310
1359
  ].filter((target) => Boolean(target));
1311
1360
  if (targets.length === 0) {
1312
1361
  throw new Error(
1313
- "Pass at least one of --html, --html-standalone, --report, --svg, --graphml, --cypher, --json, --obsidian, or --canvas."
1362
+ "Pass at least one of --html, --html-standalone, --report, --svg, --graphml, --cypher, --neo4j, --json, --obsidian, or --canvas."
1314
1363
  );
1315
1364
  }
1316
1365
  const results = [];
@@ -1731,6 +1780,11 @@ async function showWatchStatus() {
1731
1780
  }
1732
1781
  watch.command("status").description("Show the latest watch run plus pending semantic refresh entries.").action(showWatchStatus);
1733
1782
  program.command("watch-status").description("Show the latest watch run plus pending semantic refresh entries.").action(showWatchStatus);
1783
+ program.command("check-update").description("Compatibility alias for graph status: read-only graph/report freshness and tracked repo change check.").argument("[path]", "Optional repo root to check instead of configured/tracked roots").action(showGraphStatusCommand);
1784
+ program.command("update").description("Compatibility alias for graph update: refresh code-derived graph artifacts from tracked repo roots.").argument("[path]", "Optional repo root to refresh instead of configured/tracked roots").option("--lint", "Run lint after the refresh cycle", false).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(runGraphUpdateCommand);
1785
+ program.command("cluster-only").description("Compatibility alias for graph cluster: recompute graph communities and report artifacts without re-ingesting.").argument("[vault]", "Optional vault root to cluster instead of the current directory").option("--resolution <number>", "Override the Louvain community resolution for this run").action(
1786
+ (vaultPath, options) => runGraphClusterCommand(options, vaultPath ? path2.resolve(process2.cwd(), vaultPath) : process2.cwd())
1787
+ );
1734
1788
  var hook = program.command("hook").description("Install local git hooks that keep tracked repos and the vault in sync.");
1735
1789
  hook.command("install").description("Install post-commit and post-checkout hooks for the nearest git repository.").action(async () => {
1736
1790
  const status = await installGitHooks(process2.cwd());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmvaultai/cli",
3
- "version": "3.8.0",
3
+ "version": "3.10.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.10.0",
48
48
  "commander": "^14.0.1"
49
49
  },
50
50
  "devDependencies": {