@swarmvaultai/cli 3.10.0 → 3.11.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 +38 -2
  2. package/dist/index.js +122 -101
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -73,6 +73,7 @@ swarmvault update .
73
73
  swarmvault graph cluster
74
74
  swarmvault cluster-only
75
75
  swarmvault graph tree --output ./exports/tree.html
76
+ swarmvault tree --output ./exports/tree.html
76
77
  swarmvault graph query "Which nodes bridge the biggest clusters?"
77
78
  swarmvault graph explain "concept:drift"
78
79
  swarmvault watch status
@@ -84,7 +85,9 @@ swarmvault graph export --html ./exports/graph.html
84
85
  swarmvault graph export --cypher ./exports/graph.cypher
85
86
  swarmvault graph export --neo4j ./exports/graph.cypher
86
87
  swarmvault graph merge ./exports/graph.json ./other-graph.json --out ./exports/merged-graph.json
88
+ swarmvault merge-graphs ./exports/graph.json ./other-graph.json --out ./exports/merged-graph.json
87
89
  swarmvault graph push neo4j --dry-run
90
+ swarmvault clone https://github.com/owner/repo --no-viz
88
91
  ```
89
92
 
90
93
  ## Commands
@@ -110,7 +113,7 @@ Set `SWARMVAULT_OUT=<dir>` when generated artifacts should be isolated from the
110
113
 
111
114
  `--profile` accepts `default`, `personal-research`, or a comma-separated preset list such as `reader,timeline`. For fully custom vault behavior, edit the `profile` block in `swarmvault.config.json`; that deterministic profile layer works alongside the human-written `swarmvault.schema.md`. The `personal-research` preset also sets `profile.guidedIngestDefault: true` and `profile.deepLintDefault: true`, so guided ingest/source and lint flows are on by default until you override them with `--no-guide` or `--no-deep`.
112
115
 
113
- ### `swarmvault scan <directory|github-url> [--port <port>] [--no-serve] [--branch <name>] [--ref <ref>] [--checkout-dir <path>]`
116
+ ### `swarmvault scan <directory|github-url> [--port <port>] [--no-serve] [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>]`
114
117
 
115
118
  Quick-start a scratch vault from a local directory or public GitHub repo root URL in one command.
116
119
 
@@ -118,12 +121,22 @@ Quick-start a scratch vault from a local directory or public GitHub repo root UR
118
121
  - ingests the supplied directory as local sources, or registers/syncs the supplied public GitHub repo root URL
119
122
  - compiles the vault immediately
120
123
  - writes `wiki/graph/share-card.md`, `wiki/graph/share-card.svg`, and `wiki/graph/share-kit/`, then prints the paths
121
- - starts `graph serve` unless you pass `--no-serve`
124
+ - starts `graph serve` unless you pass `--no-serve` or `--no-viz`
125
+ - `--no-viz` is a compatibility alias for `--no-serve`
126
+ - `--mcp` starts the MCP stdio server after compile instead of the graph viewer
122
127
  - respects `--port` when you want a specific viewer port
123
128
  - for GitHub repo URLs, supports `--branch`, `--ref`, and `--checkout-dir`
124
129
 
125
130
  Use this when you want the fastest repo or docs-tree walkthrough without first deciding on managed-source registration.
126
131
 
132
+ ### `swarmvault clone <directory|github-url> [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>]`
133
+
134
+ Compatibility alias for `swarmvault scan`.
135
+
136
+ - initializes, ingests or registers the input, and compiles in one command
137
+ - supports the same public GitHub repo checkout flags as `scan`
138
+ - accepts `--no-serve`, `--no-viz`, `--mcp`, and `--port`
139
+
127
140
  ### `swarmvault demo [--port <port>] [--no-serve]`
128
141
 
129
142
  Create a temporary sample vault with bundled sources, compile it immediately, and launch the graph viewer unless you pass `--no-serve`.
@@ -440,6 +453,13 @@ Write a collapsible HTML source tree for the current `state/graph.json`.
440
453
  - `--max-children` caps very wide folders or modules with a `+N more` row
441
454
  - `--json` returns the output path, source count, node count, and tree payload
442
455
 
456
+ ### `swarmvault tree [--output <html>] [--root <path>] [--label <name>] [--max-children <n>]`
457
+
458
+ Compatibility alias for `swarmvault graph tree`.
459
+
460
+ - writes the same source/module/symbol tree
461
+ - returns the same JSON shape as `graph tree`
462
+
443
463
  ### `swarmvault graph merge <graph...> --out <path> [--label <name>]`
444
464
 
445
465
  Merge multiple graph JSON files into one namespaced graph artifact.
@@ -450,6 +470,13 @@ Merge multiple graph JSON files into one namespaced graph artifact.
450
470
  - maps explicit extracted/inferred/ambiguous edge evidence into SwarmVault edge semantics
451
471
  - `--json` returns the merged graph, input summaries, and warnings
452
472
 
473
+ ### `swarmvault merge-graphs <graph...> --out <path> [--label <name>]`
474
+
475
+ Compatibility alias for `swarmvault graph merge`.
476
+
477
+ - accepts the same SwarmVault and NetworkX/node-link graph inputs
478
+ - returns the same JSON shape as `graph merge`
479
+
453
480
  ### `swarmvault graph status [path]`
454
481
 
455
482
  Read-only graph freshness check for tracked repo roots or one explicit repo path.
@@ -461,6 +488,15 @@ Read-only graph freshness check for tracked repo roots or one explicit repo path
461
488
  - recommends `swarmvault compile` when graph/report artifacts are missing, non-code files changed, or a semantic refresh is pending
462
489
  - supports global `--json` for automation
463
490
 
491
+ ### `swarmvault watch [path] [--once] [--code-only] [--lint]`
492
+
493
+ Watch or refresh one explicit repo root without first writing `watch.repoRoots`.
494
+
495
+ - positional `[path]` is treated as a repo-root override and turns on repo mode
496
+ - `--once` runs one refresh cycle and exits
497
+ - `--code-only` limits the refresh to parser-backed repo graph artifacts
498
+ - repeated `--root <path>` remains available when you need multiple roots
499
+
464
500
  ### `swarmvault graph stats`
465
501
 
466
502
  Summarize the current compiled graph without opening the viewer.
package/dist/index.js CHANGED
@@ -315,9 +315,9 @@ program.name("swarmvault").description("SwarmVault is a local-first knowledge co
315
315
  function readCliVersion() {
316
316
  try {
317
317
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
318
- return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.10.0";
318
+ return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.11.0";
319
319
  } catch {
320
- return "3.10.0";
320
+ return "3.11.0";
321
321
  }
322
322
  }
323
323
  function parsePositiveInt(value, fallback) {
@@ -545,6 +545,110 @@ async function runGraphClusterCommand(options, rootDir = process2.cwd()) {
545
545
  `Refreshed ${result.communityCount} communities across ${result.nodeCount} nodes and ${result.edgeCount} edges. Report: ${result.reportPath}`
546
546
  );
547
547
  }
548
+ async function runGraphTreeCommand(options) {
549
+ const rootDir = options.root ? path2.resolve(process2.cwd(), options.root) : process2.cwd();
550
+ const result = await exportGraphTree(rootDir, options.output, {
551
+ label: options.label,
552
+ maxChildren: parsePositiveInt(options.maxChildren, 250)
553
+ });
554
+ if (isJson()) {
555
+ emitJson(result);
556
+ return;
557
+ }
558
+ log(`Graph tree: ${result.outputPath}`);
559
+ log(`Sources: ${result.sourceCount}; nodes: ${result.nodeCount}.`);
560
+ }
561
+ async function runGraphMergeCommand(graphPaths, options) {
562
+ const result = await mergeGraphFiles(
563
+ graphPaths.map((inputPath) => path2.resolve(process2.cwd(), inputPath)),
564
+ path2.resolve(process2.cwd(), options.out),
565
+ { label: options.label }
566
+ );
567
+ if (isJson()) {
568
+ emitJson(result);
569
+ return;
570
+ }
571
+ log(
572
+ `Merged ${result.inputGraphs.length} graph${result.inputGraphs.length === 1 ? "" : "s"} into ${result.outputPath}. Nodes ${result.graph.nodes.length}, edges ${result.graph.edges.length}.`
573
+ );
574
+ for (const warning of result.warnings) {
575
+ log(`Warning: ${warning}`);
576
+ }
577
+ }
578
+ async function runScanCommand(input, options) {
579
+ const rootDir = process2.cwd();
580
+ await initVault(rootDir, {});
581
+ if (!isJson()) {
582
+ log("Initialized workspace.");
583
+ }
584
+ const result = isHttpUrlInput(input) ? await addManagedSource(rootDir, input, {
585
+ compile: true,
586
+ brief: false,
587
+ branch: options.branch,
588
+ ref: options.ref,
589
+ checkoutDir: options.checkoutDir
590
+ }) : await ingestDirectory(rootDir, input, {});
591
+ if (!isJson()) {
592
+ if ("source" in result) {
593
+ log(
594
+ `Registered ${result.source.kind} source ${result.source.id}. Imported ${result.source.lastSyncCounts?.importedCount ?? 0}, updated ${result.source.lastSyncCounts?.updatedCount ?? 0}.`
595
+ );
596
+ } else {
597
+ log(`Ingested ${result.imported.length} file(s).`);
598
+ }
599
+ }
600
+ const compiled = "compile" in result && result.compile ? result.compile : await compileVault(rootDir, {});
601
+ const { paths } = await loadVaultConfig(rootDir);
602
+ const shareCardPath = path2.join(paths.wikiDir, "graph", "share-card.md");
603
+ const shareCardSvgPath = path2.join(paths.wikiDir, "graph", "share-card.svg");
604
+ const shareKitPath = path2.join(paths.wikiDir, "graph", "share-kit");
605
+ if (!isJson()) {
606
+ log(`Compiled ${compiled.sourceCount} source(s), ${compiled.pageCount} page(s).`);
607
+ log(`Share card: ${shareCardPath}`);
608
+ log(`Visual card: ${shareCardSvgPath}`);
609
+ log(`Share kit: ${shareKitPath}`);
610
+ log("Post text: swarmvault graph share --post");
611
+ }
612
+ if (options.mcp) {
613
+ process2.stderr.write(`${JSON.stringify({ status: "running", transport: "stdio", compiled: compiled.sourceCount })}
614
+ `);
615
+ const controller = await startMcpServer(rootDir);
616
+ process2.on("SIGINT", async () => {
617
+ try {
618
+ await controller.close();
619
+ } catch {
620
+ }
621
+ process2.exit(0);
622
+ });
623
+ return;
624
+ }
625
+ if (options.serve !== false && options.viz !== false) {
626
+ const port = options.port ? parsePositiveInt(options.port, 0) || void 0 : void 0;
627
+ const server = await startGraphServer(rootDir, port, { full: false });
628
+ if (isJson()) {
629
+ emitJson({
630
+ ...result,
631
+ compiled,
632
+ shareCardPath,
633
+ shareCardSvgPath,
634
+ shareKitPath,
635
+ port: server.port,
636
+ url: `http://localhost:${server.port}`
637
+ });
638
+ } else {
639
+ log(`Graph viewer running at http://localhost:${server.port}`);
640
+ }
641
+ process2.on("SIGINT", async () => {
642
+ try {
643
+ await server.close();
644
+ } catch {
645
+ }
646
+ process2.exit(0);
647
+ });
648
+ } else if (isJson()) {
649
+ emitJson({ ...result, compiled, shareCardPath, shareCardSvgPath, shareKitPath });
650
+ }
651
+ }
548
652
  program.hook("postAction", async (_thisCommand, actionCommand) => {
549
653
  const notices = await collectCliNotices({
550
654
  commandPath: getCommandPath(actionCommand),
@@ -1215,36 +1319,8 @@ program.command("lint").description("Run anti-drift and wiki-health checks.").op
1215
1319
  var graph = program.command("graph").description("Graph-related commands.").enablePositionalOptions();
1216
1320
  var graphPush = graph.command("push").description("Push the compiled graph into external sinks.");
1217
1321
  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);
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) => {
1219
- const rootDir = options.root ? path2.resolve(process2.cwd(), options.root) : process2.cwd();
1220
- const result = await exportGraphTree(rootDir, options.output, {
1221
- label: options.label,
1222
- maxChildren: parsePositiveInt(options.maxChildren, 250)
1223
- });
1224
- if (isJson()) {
1225
- emitJson(result);
1226
- return;
1227
- }
1228
- log(`Graph tree: ${result.outputPath}`);
1229
- log(`Sources: ${result.sourceCount}; nodes: ${result.nodeCount}.`);
1230
- });
1231
- graph.command("merge").description("Merge SwarmVault or node-link JSON graph files into one namespaced graph artifact.").argument("<graphs...>", "Graph JSON files to merge").requiredOption("--out <path>", "Output graph JSON path").option("--label <name>", "Label/prefix to use when merging one graph").action(async (graphPaths, options) => {
1232
- const result = await mergeGraphFiles(
1233
- graphPaths.map((inputPath) => path2.resolve(process2.cwd(), inputPath)),
1234
- path2.resolve(process2.cwd(), options.out),
1235
- { label: options.label }
1236
- );
1237
- if (isJson()) {
1238
- emitJson(result);
1239
- return;
1240
- }
1241
- log(
1242
- `Merged ${result.inputGraphs.length} graph${result.inputGraphs.length === 1 ? "" : "s"} into ${result.outputPath}. Nodes ${result.graph.nodes.length}, edges ${result.graph.edges.length}.`
1243
- );
1244
- for (const warning of result.warnings) {
1245
- log(`Warning: ${warning}`);
1246
- }
1247
- });
1322
+ 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(runGraphTreeCommand);
1323
+ graph.command("merge").description("Merge SwarmVault or node-link JSON graph files into one namespaced graph artifact.").argument("<graphs...>", "Graph JSON files to merge").requiredOption("--out <path>", "Output graph JSON path").option("--label <name>", "Label/prefix to use when merging one graph").action(runGraphMergeCommand);
1248
1324
  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
1325
  graph.command("stats").description("Summarize compiled graph counts, node types, evidence classes, and relation mix.").action(async () => {
1250
1326
  const stats = await graphStatsVault(process2.cwd());
@@ -1691,14 +1767,16 @@ async function confirmInteractive(message) {
1691
1767
  rl.close();
1692
1768
  }
1693
1769
  }
1694
- var watch = program.command("watch").description("Watch the inbox directory and optionally tracked repos, or run one refresh cycle immediately.").option("--lint", "Run lint after each compile cycle", false).option("--repo", "Also refresh tracked repo sources and watch their repo roots", false).option("--once", "Run one import/refresh cycle immediately instead of starting a watcher", false).option("--code-only", "Only re-extract code sources (AST-only, no LLM re-analysis)", false).option("--debounce <ms>", "Debounce window in milliseconds", "900").option("--root <path>", "Watch this repo root instead of config/auto-discovery (repeat for multiple)", collectRepeated, []).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(
1695
- async (options) => {
1770
+ var watch = program.command("watch").description("Watch the inbox directory and optionally tracked repos, or run one refresh cycle immediately.").argument("[path]", "Optional repo root to watch or refresh instead of config/auto-discovery").option("--lint", "Run lint after each compile cycle", false).option("--repo", "Also refresh tracked repo sources and watch their repo roots", false).option("--once", "Run one import/refresh cycle immediately instead of starting a watcher", false).option("--code-only", "Only re-extract code sources (AST-only, no LLM re-analysis)", false).option("--debounce <ms>", "Debounce window in milliseconds", "900").option("--root <path>", "Watch this repo root instead of config/auto-discovery (repeat for multiple)", collectRepeated, []).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(
1771
+ async (targetPath, options) => {
1696
1772
  const debounceMs = parsePositiveInt(options.debounce, 900);
1697
- const overrideRoots = options.root && options.root.length > 0 ? options.root : void 0;
1773
+ const rootOverrides = [...targetPath ? [targetPath] : [], ...options.root ?? []];
1774
+ const overrideRoots = rootOverrides.length > 0 ? rootOverrides : void 0;
1775
+ const repoMode = options.repo || Boolean(targetPath);
1698
1776
  if (options.once) {
1699
1777
  const result = await runWatchCycle(process2.cwd(), {
1700
1778
  lint: options.lint ?? false,
1701
- repo: options.repo ?? false,
1779
+ repo: repoMode,
1702
1780
  codeOnly: options.codeOnly ?? false,
1703
1781
  debounceMs,
1704
1782
  force: options.force ?? false,
@@ -1708,7 +1786,7 @@ var watch = program.command("watch").description("Watch the inbox directory and
1708
1786
  emitJson(result);
1709
1787
  } else {
1710
1788
  log(
1711
- `Refreshed inbox${options.repo ? " and tracked repos" : ""}. Imported ${result.importedCount}, repo imported ${result.repoImportedCount}, repo updated ${result.repoUpdatedCount}, repo removed ${result.repoRemovedCount}.`
1789
+ `Refreshed inbox${repoMode ? " and tracked repos" : ""}. Imported ${result.importedCount}, repo imported ${result.repoImportedCount}, repo updated ${result.repoUpdatedCount}, repo removed ${result.repoRemovedCount}.`
1712
1790
  );
1713
1791
  }
1714
1792
  return;
@@ -1716,16 +1794,16 @@ var watch = program.command("watch").description("Watch the inbox directory and
1716
1794
  const { paths } = await loadVaultConfig(process2.cwd());
1717
1795
  const controller = await watchVault(process2.cwd(), {
1718
1796
  lint: options.lint ?? false,
1719
- repo: options.repo ?? false,
1797
+ repo: repoMode,
1720
1798
  codeOnly: options.codeOnly ?? false,
1721
1799
  debounceMs,
1722
1800
  force: options.force ?? false,
1723
1801
  overrideRoots
1724
1802
  });
1725
1803
  if (isJson()) {
1726
- emitJson({ status: "watching", inboxDir: paths.inboxDir, repo: options.repo ?? false });
1804
+ emitJson({ status: "watching", inboxDir: paths.inboxDir, repo: repoMode });
1727
1805
  } else {
1728
- log(`Watching inbox${options.repo ? " and tracked repos" : ""} for changes. Press Ctrl+C to stop.`);
1806
+ log(`Watching inbox${repoMode ? " and tracked repos" : ""} for changes. Press Ctrl+C to stop.`);
1729
1807
  }
1730
1808
  process2.on("SIGINT", async () => {
1731
1809
  try {
@@ -1785,6 +1863,8 @@ program.command("update").description("Compatibility alias for graph update: ref
1785
1863
  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
1864
  (vaultPath, options) => runGraphClusterCommand(options, vaultPath ? path2.resolve(process2.cwd(), vaultPath) : process2.cwd())
1787
1865
  );
1866
+ program.command("tree").description("Compatibility alias for graph tree: 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(runGraphTreeCommand);
1867
+ program.command("merge-graphs").description("Compatibility alias for graph merge: combine graph JSON files into one namespaced graph artifact.").argument("<graphs...>", "Graph JSON files to merge").requiredOption("--out <path>", "Output graph JSON path").option("--label <name>", "Label/prefix to use when merging one graph").action(runGraphMergeCommand);
1788
1868
  var hook = program.command("hook").description("Install local git hooks that keep tracked repos and the vault in sync.");
1789
1869
  hook.command("install").description("Install post-commit and post-checkout hooks for the nearest git repository.").action(async () => {
1790
1870
  const status = await installGitHooks(process2.cwd());
@@ -2265,67 +2345,8 @@ retrieval.command("doctor").description("Diagnose retrieval index problems and o
2265
2345
  log(`Warning: ${warning}`);
2266
2346
  }
2267
2347
  });
2268
- program.command("scan").description("Quick-start: initialize, ingest, compile, and serve a graph viewer in one command.").argument("<input>", "Directory or public GitHub repo root URL to scan").option("--port <port>", "Port for the graph viewer").option("--no-serve", "Skip launching the graph viewer after compile").option("--branch <name>", "GitHub branch to clone when scanning a public repo URL").option("--ref <ref>", "Git ref, tag, or commit to check out when scanning a public repo URL").option("--checkout-dir <path>", "Persistent checkout directory for a public GitHub repo scan").action(async (input, options) => {
2269
- const rootDir = process2.cwd();
2270
- await initVault(rootDir, {});
2271
- if (!isJson()) {
2272
- log("Initialized workspace.");
2273
- }
2274
- const result = isHttpUrlInput(input) ? await addManagedSource(rootDir, input, {
2275
- compile: true,
2276
- brief: false,
2277
- branch: options.branch,
2278
- ref: options.ref,
2279
- checkoutDir: options.checkoutDir
2280
- }) : await ingestDirectory(rootDir, input, {});
2281
- if (!isJson()) {
2282
- if ("source" in result) {
2283
- log(
2284
- `Registered ${result.source.kind} source ${result.source.id}. Imported ${result.source.lastSyncCounts?.importedCount ?? 0}, updated ${result.source.lastSyncCounts?.updatedCount ?? 0}.`
2285
- );
2286
- } else {
2287
- log(`Ingested ${result.imported.length} file(s).`);
2288
- }
2289
- }
2290
- const compiled = "compile" in result && result.compile ? result.compile : await compileVault(rootDir, {});
2291
- const { paths } = await loadVaultConfig(rootDir);
2292
- const shareCardPath = path2.join(paths.wikiDir, "graph", "share-card.md");
2293
- const shareCardSvgPath = path2.join(paths.wikiDir, "graph", "share-card.svg");
2294
- const shareKitPath = path2.join(paths.wikiDir, "graph", "share-kit");
2295
- if (!isJson()) {
2296
- log(`Compiled ${compiled.sourceCount} source(s), ${compiled.pageCount} page(s).`);
2297
- log(`Share card: ${shareCardPath}`);
2298
- log(`Visual card: ${shareCardSvgPath}`);
2299
- log(`Share kit: ${shareKitPath}`);
2300
- log("Post text: swarmvault graph share --post");
2301
- }
2302
- if (options.serve !== false) {
2303
- const port = options.port ? parsePositiveInt(options.port, 0) || void 0 : void 0;
2304
- const server = await startGraphServer(rootDir, port, { full: false });
2305
- if (isJson()) {
2306
- emitJson({
2307
- ...result,
2308
- compiled,
2309
- shareCardPath,
2310
- shareCardSvgPath,
2311
- shareKitPath,
2312
- port: server.port,
2313
- url: `http://localhost:${server.port}`
2314
- });
2315
- } else {
2316
- log(`Graph viewer running at http://localhost:${server.port}`);
2317
- }
2318
- process2.on("SIGINT", async () => {
2319
- try {
2320
- await server.close();
2321
- } catch {
2322
- }
2323
- process2.exit(0);
2324
- });
2325
- } else if (isJson()) {
2326
- emitJson({ ...result, compiled, shareCardPath, shareCardSvgPath, shareKitPath });
2327
- }
2328
- });
2348
+ program.command("scan").description("Quick-start: initialize, ingest, compile, and serve a graph viewer in one command.").argument("<input>", "Directory or public GitHub repo root URL to scan").option("--port <port>", "Port for the graph viewer").option("--no-serve", "Skip launching the graph viewer after compile").option("--no-viz", "Compatibility alias for --no-serve; skip launching the graph viewer after compile").option("--mcp", "Start the MCP stdio server after compile instead of launching the graph viewer", false).option("--branch <name>", "GitHub branch to clone when scanning a public repo URL").option("--ref <ref>", "Git ref, tag, or commit to check out when scanning a public repo URL").option("--checkout-dir <path>", "Persistent checkout directory for a public GitHub repo scan").action(runScanCommand);
2349
+ program.command("clone").description("Compatibility alias for scan: initialize, clone/register a public repo URL, and compile it into the vault.").argument("<input>", "Public GitHub repo URL or local directory to scan").option("--port <port>", "Port for the graph viewer").option("--no-serve", "Skip launching the graph viewer after compile").option("--no-viz", "Compatibility alias for --no-serve; skip launching the graph viewer after compile").option("--mcp", "Start the MCP stdio server after compile instead of launching the graph viewer", false).option("--branch <name>", "GitHub branch to clone when scanning a public repo URL").option("--ref <ref>", "Git ref, tag, or commit to check out when scanning a public repo URL").option("--checkout-dir <path>", "Persistent checkout directory for a public GitHub repo scan").action(runScanCommand);
2329
2350
  function enableStructuredJsonOnSubcommands(command) {
2330
2351
  for (const subcommand of command.commands) {
2331
2352
  const hasJsonOption = subcommand.options.some((option) => option.attributeName() === "json");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmvaultai/cli",
3
- "version": "3.10.0",
3
+ "version": "3.11.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.10.0",
47
+ "@swarmvaultai/engine": "3.11.0",
48
48
  "commander": "^14.0.1"
49
49
  },
50
50
  "devDependencies": {