@swarmvaultai/cli 3.16.1 → 3.17.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 (2) hide show
  1. package/dist/index.js +41 -10
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -80,6 +80,7 @@ import {
80
80
  readContextPack,
81
81
  readGraphReport,
82
82
  readMemoryTask,
83
+ readPage,
83
84
  rebuildRetrievalIndex,
84
85
  refreshGraphClusters,
85
86
  registerLocalWhisperProvider,
@@ -336,9 +337,9 @@ program.addHelpText(
336
337
  function readCliVersion() {
337
338
  try {
338
339
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
339
- return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.16.1";
340
+ return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.17.0";
340
341
  } catch {
341
- return "3.16.1";
342
+ return "3.17.0";
342
343
  }
343
344
  }
344
345
  function parsePositiveInt(value, fallback) {
@@ -791,17 +792,29 @@ function getCommandPath(command) {
791
792
  }
792
793
  async function runGraphUpdateCommand(targetPath, options) {
793
794
  const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
795
+ const files = options.file?.length ? options.file.map((candidate2) => path2.resolve(process2.cwd(), candidate2)) : void 0;
794
796
  const result = await runWatchCycle(process2.cwd(), {
795
797
  repo: true,
796
798
  codeOnly: true,
797
799
  lint: options.lint ?? false,
798
800
  force: options.force ?? false,
799
- overrideRoots
801
+ overrideRoots,
802
+ files
800
803
  });
801
804
  if (isJson()) {
802
805
  emitJson(result);
803
806
  return;
804
807
  }
808
+ if (result.queuedFiles?.length && result.scannedCount === 0) {
809
+ log(`Another refresh holds the lock. Queued ${result.queuedFiles.length} file(s) for the active refresh to fold in.`);
810
+ return;
811
+ }
812
+ if (files) {
813
+ log(
814
+ `Refreshed ${result.scannedCount} file(s). Imported ${result.repoImportedCount}, updated ${result.repoUpdatedCount}, removed ${result.repoRemovedCount}, pending semantic refresh ${result.pendingSemanticRefreshCount}.`
815
+ );
816
+ return;
817
+ }
805
818
  log(
806
819
  `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}.`
807
820
  );
@@ -1814,7 +1827,7 @@ program.command("lint").description("Run anti-drift and wiki-health checks.").op
1814
1827
  });
1815
1828
  var graph = program.command("graph").description("Graph-related commands.").enablePositionalOptions();
1816
1829
  var graphPush = graph.command("push").description("Push the compiled graph into external sinks.");
1817
- 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);
1830
+ graph.command("update").alias("refresh").description("Refresh code-derived graph artifacts from tracked repo roots, one explicit repo path, or explicit files.").argument("[path]", "Optional repo root to refresh instead of configured/tracked roots").option("--file <path>", "Refresh only this file (repeatable); skips the full tracked-root walk", collectRepeated, []).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);
1818
1831
  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);
1819
1832
  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);
1820
1833
  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);
@@ -2030,6 +2043,17 @@ graph.command("query").description("Traverse the compiled graph deterministicall
2030
2043
  return;
2031
2044
  }
2032
2045
  log(result.summary);
2046
+ if (result.topMatchPagePath) {
2047
+ const page = await readPage(process2.cwd(), result.topMatchPagePath).catch(() => null);
2048
+ if (page?.content) {
2049
+ const limit = 1600;
2050
+ const excerpt = page.content.length > limit ? `${page.content.slice(0, limit)}
2051
+ \u2026 (truncated \u2014 read wiki/${result.topMatchPagePath} for the rest)` : page.content;
2052
+ log(`
2053
+ --- Top match page: wiki/${result.topMatchPagePath} ---
2054
+ ${excerpt}`);
2055
+ }
2056
+ }
2033
2057
  }
2034
2058
  );
2035
2059
  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) => {
@@ -2459,7 +2483,7 @@ async function showWatchStatus() {
2459
2483
  watch.command("status").description("Show the latest watch run plus pending semantic refresh entries.").action(showWatchStatus);
2460
2484
  program.command("watch-status").description("Show the latest watch run plus pending semantic refresh entries.").action(showWatchStatus);
2461
2485
  program.command("check-update", { hidden: true }).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);
2462
- program.command("update", { hidden: true }).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);
2486
+ program.command("update", { hidden: true }).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("--file <path>", "Refresh only this file (repeatable); skips the full tracked-root walk", collectRepeated, []).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);
2463
2487
  program.command("cluster-only", { hidden: true }).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(
2464
2488
  (vaultPath, options) => runGraphClusterCommand(options, vaultPath ? path2.resolve(process2.cwd(), vaultPath) : process2.cwd())
2465
2489
  );
@@ -2571,9 +2595,13 @@ program.command("mcp").description("Run SwarmVault as a local MCP server over st
2571
2595
  });
2572
2596
  });
2573
2597
  var install = program.command("install").description("Install SwarmVault instructions for an agent in the current project.");
2574
- install.command("status").description("Show whether SwarmVault instructions are installed for an agent.").requiredOption("--agent <agent>", "Agent name").option("--hook", "Include hook/plugin targets in the status check", false).option("--scope <scope>", "Install scope to inspect: project or user", "project").action(async (options) => {
2598
+ install.command("status").description("Show whether SwarmVault instructions are installed for an agent.").requiredOption("--agent <agent>", "Agent name").option("--hook", "Include hook/plugin targets in the status check", false).option("--mcp", "Include MCP config targets in the status check", false).option("--scope <scope>", "Install scope to inspect: project or user", "project").action(async (options) => {
2575
2599
  const scope = options.scope === "user" ? "user" : "project";
2576
- const result = await getAgentInstallStatus(process2.cwd(), options.agent, { hook: options.hook ?? false, scope });
2600
+ const result = await getAgentInstallStatus(process2.cwd(), options.agent, {
2601
+ hook: options.hook ?? false,
2602
+ mcp: options.mcp ?? false,
2603
+ scope
2604
+ });
2577
2605
  if (isJson()) {
2578
2606
  emitJson(result);
2579
2607
  return;
@@ -2586,7 +2614,7 @@ install.command("status").description("Show whether SwarmVault instructions are
2586
2614
  install.option(
2587
2615
  "--agent <agent>",
2588
2616
  "claude, codex, cursor, gemini, goose, opencode, copilot, aider, droid, pi, trae, claw, kiro, kilo, hermes, antigravity, vscode, amp, augment, adal, bob, cline, codebuddy, command-code, continue, cortex, crush, deepagents, devin, firebender, iflow, junie, kilo-code, kimi, kode, mcpjam, mistral-vibe, mux, neovate, openclaw, openhands, pochi, qoder, qwen-code, replit, roo-code, trae-cn, warp, windsurf, or zencoder"
2589
- ).option("--hook", "Also install hook/plugin guidance when the target agent supports it", false).option("--scope <scope>", "Install scope: project or user", "project").action(async (options) => {
2617
+ ).option("--hook", "Also install hook/plugin guidance when the target agent supports it", false).option("--mcp", "Also register the SwarmVault MCP server in the agent's project MCP config", false).option("--scope <scope>", "Install scope: project or user", "project").action(async (options) => {
2590
2618
  if (!options.agent) {
2591
2619
  throw new Error("Specify --agent <agent>.");
2592
2620
  }
@@ -2594,10 +2622,13 @@ install.option(
2594
2622
  if (options.hook && !hookCapableAgents.has(options.agent)) {
2595
2623
  throw new Error("--hook is only supported for --agent codex, claude, opencode, gemini, copilot, or kilo");
2596
2624
  }
2625
+ if (options.mcp && options.agent !== "claude") {
2626
+ throw new Error("--mcp is currently only supported for --agent claude (project-level .mcp.json)");
2627
+ }
2597
2628
  const scope = options.scope === "user" ? "user" : "project";
2598
- const result = await installAgent(process2.cwd(), options.agent, { hook: options.hook ?? false, scope });
2629
+ const result = await installAgent(process2.cwd(), options.agent, { hook: options.hook ?? false, mcp: options.mcp ?? false, scope });
2599
2630
  if (isJson()) {
2600
- emitJson({ ...result, hook: options.hook ?? false, scope });
2631
+ emitJson({ ...result, hook: options.hook ?? false, mcp: options.mcp ?? false, scope });
2601
2632
  } else {
2602
2633
  log(`Installed rules into ${result.target}`);
2603
2634
  if (result.targets.length > 1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmvaultai/cli",
3
- "version": "3.16.1",
3
+ "version": "3.17.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.16.1",
47
+ "@swarmvaultai/engine": "3.17.0",
48
48
  "commander": "^14.0.1"
49
49
  },
50
50
  "devDependencies": {