@swarmvaultai/cli 3.14.1 → 3.15.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 +17 -7
  2. package/dist/index.js +32 -16
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -105,25 +105,26 @@ Set `SWARMVAULT_OUT=<dir>` when generated artifacts should be isolated from the
105
105
 
106
106
  `--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`.
107
107
 
108
- ### `swarmvault quickstart <directory|github-url> [--port <port>] [--no-serve] [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>]`
108
+ ### `swarmvault quickstart <file|directory|github-url> [--port <port>] [--no-serve] [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>] [--install-agent-rules]`
109
109
 
110
110
  Beginner-friendly alias for `swarmvault scan`.
111
111
 
112
112
  - initializes the current directory as a SwarmVault workspace
113
- - ingests the supplied local directory, or registers/syncs the supplied public GitHub repo root URL
113
+ - ingests the supplied local file or directory, or registers/syncs the supplied public GitHub repo root URL
114
114
  - compiles wiki, graph, search, and share artifacts immediately
115
115
  - prints the generated `raw/`, `wiki/`, `state/graph.json`, and `wiki/graph/` paths in human output
116
116
  - starts `graph serve` unless you pass `--no-serve` or `--no-viz`
117
117
  - keeps the same JSON output contract as `scan`
118
+ - leaves agent rule files alone unless you pass `--install-agent-rules`
118
119
 
119
120
  Use this as the default first-run command in docs and onboarding.
120
121
 
121
- ### `swarmvault scan <directory|github-url> [--port <port>] [--no-serve] [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>]`
122
+ ### `swarmvault scan <file|directory|github-url> [--port <port>] [--no-serve] [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>] [--install-agent-rules]`
122
123
 
123
- Quick-start a scratch vault from a local directory or public GitHub repo root URL in one command.
124
+ Quick-start a scratch vault from a local file, directory, or public GitHub repo root URL in one command.
124
125
 
125
126
  - initializes the current directory as a SwarmVault workspace
126
- - ingests the supplied directory as local sources, or registers/syncs the supplied public GitHub repo root URL
127
+ - ingests the supplied file or directory as local sources, or registers/syncs the supplied public GitHub repo root URL
127
128
  - compiles the vault immediately
128
129
  - writes `wiki/graph/share-card.md`, `wiki/graph/share-card.svg`, and `wiki/graph/share-kit/`, then prints the paths
129
130
  - starts `graph serve` unless you pass `--no-serve` or `--no-viz`
@@ -131,10 +132,11 @@ Quick-start a scratch vault from a local directory or public GitHub repo root UR
131
132
  - `--mcp` starts the MCP stdio server after compile instead of the graph viewer
132
133
  - respects `--port` when you want a specific viewer port
133
134
  - for GitHub repo URLs, supports `--branch`, `--ref`, and `--checkout-dir`
135
+ - `--install-agent-rules` installs the configured `agents` targets during initialization
134
136
 
135
137
  Use this when you want the fastest repo or docs-tree walkthrough without first deciding on managed-source registration.
136
138
 
137
- ### `swarmvault clone <directory|github-url> [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>]`
139
+ ### `swarmvault clone <file|directory|github-url> [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>] [--install-agent-rules]`
138
140
 
139
141
  Compatibility alias for `swarmvault scan`.
140
142
 
@@ -268,7 +270,7 @@ Useful flags:
268
270
 
269
271
  Repo ingest defaults to `first_party` material. The extra `--include-*` flags opt dependency trees, resource bundles, and generated output back in when you actually want them in the vault.
270
272
 
271
- Large repo ingest now emits low-noise progress on materially large batches, and parser compatibility failures stay local to the affected source instead of aborting unrelated analysis.
273
+ Interactive file and directory ingest now emits bounded stderr progress, including the active file and processed content size. JSON, MCP, watch, and CI-style flows stay quiet, and parser compatibility failures stay local to the affected source instead of aborting unrelated analysis.
272
274
 
273
275
  Audio and video files use `tasks.audioProvider` when you configure a provider with `audio` capability. Local video extraction shells out to `ffmpeg`; public video URL extraction with `--video` shells out to `yt-dlp`. When no audio provider or extractor binary is configured, SwarmVault still ingests the source and records an explicit extraction warning instead of failing. YouTube transcript ingest does not require a model provider.
274
276
 
@@ -303,6 +305,8 @@ Compile the current manifests into:
303
305
 
304
306
  The compiler also reads `swarmvault.schema.md` and records a `schema_hash` plus lifecycle metadata such as `status`, `created_at`, `updated_at`, `compiled_from`, and `managed_by` in generated pages so schema edits can mark pages stale without losing lifecycle state.
305
307
 
308
+ Large compile runs process source analysis in bounded batches and use a sparse graph co-occurrence projection so high-overlap note sets do not explode into unbounded pairwise graph work.
309
+
306
310
  For ingested code trees, compile also writes `state/code-index.json` so local imports and module aliases can resolve across the repo-aware code graph.
307
311
 
308
312
  New concept and entity pages are staged into `wiki/candidates/` first. A later matching compile promotes them into `wiki/concepts/` or `wiki/entities/`.
@@ -713,6 +717,8 @@ Defaults:
713
717
 
714
718
  Install agent-specific rules into the current project so an agent understands the SwarmVault workspace contract and workflow.
715
719
 
720
+ `init`, `quickstart`, `scan`, and `clone` do not write project-local agent rule files by default. Run `swarmvault install --agent <agent>` for one target at a time, or list targets in `swarmvault.config.json` and pass `--install-agent-rules` to `init`, `quickstart`, `scan`, or `clone` when you intentionally want configured targets installed together.
721
+
716
722
  Hook-capable installs:
717
723
 
718
724
  ```bash
@@ -739,6 +745,8 @@ Agent target mapping:
739
745
  - `antigravity` writes `.agents/rules/swarmvault.md` and `.agents/workflows/swarmvault.md`, and removes older fully managed `.agent/` files during reinstall
740
746
  - `vscode` writes `.github/chatmodes/swarmvault.chatmode.md` plus `.github/copilot-instructions.md`
741
747
 
748
+ SwarmVault only owns the managed block inside shared markdown rule files. It keeps the SwarmVault block aligned across targets while preserving any user-owned text before or after the block, so `AGENTS.md` and `CLAUDE.md` do not need to be byte-identical.
749
+
742
750
  Hook semantics:
743
751
 
744
752
  - `codex --hook` writes `.codex/hooks.json` plus `.codex/hooks/swarmvault-graph-first.js` and emits model-visible guidance before broad shell search
@@ -841,6 +849,8 @@ Search behavior is configurable separately from provider routing:
841
849
  - If a provider claims OpenAI compatibility but fails structured generation, declare only the capabilities it actually supports
842
850
  - If `lint --deep --web` fails immediately, make sure a `webSearch` provider is configured and mapped to `tasks.deepLintProvider`
843
851
  - If you still see a `node:sqlite` experimental warning on Node 24, upgrade to the latest CLI; current releases suppress that upstream warning during normal runs
852
+ - If compile reports `Failed to parse JSON file ...`, the named derived state file is corrupt or empty. Remove the named file or restore it from git, then rerun `swarmvault compile`; current releases write JSON state atomically to reduce partial-file failures.
853
+ - If a large heuristic vault fails with heap exhaustion or `Map maximum size exceeded` on an older CLI, upgrade and rerun compile. Current releases bound analysis concurrency and graph projection during compile.
844
854
 
845
855
  ## Links
846
856
 
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { readFileSync } from "fs";
5
- import { access, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
5
+ import { access, mkdir as mkdir2, readFile as readFile2, stat, writeFile as writeFile2 } from "fs/promises";
6
6
  import path2 from "path";
7
7
  import process2 from "process";
8
8
  import { createInterface } from "readline/promises";
@@ -330,9 +330,9 @@ program.addHelpText(
330
330
  function readCliVersion() {
331
331
  try {
332
332
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
333
- return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.14.1";
333
+ return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.15.0";
334
334
  } catch {
335
- return "3.14.1";
335
+ return "3.15.0";
336
336
  }
337
337
  }
338
338
  function parsePositiveInt(value, fallback) {
@@ -818,7 +818,8 @@ async function runGraphMergeCommand(graphPaths, options) {
818
818
  }
819
819
  async function runScanCommand(input, options) {
820
820
  const rootDir = process2.cwd();
821
- await initVault(rootDir, {});
821
+ const progress = !isJson() && !options.mcp;
822
+ await initVault(rootDir, { installAgentRules: options.installAgentRules ?? false });
822
823
  if (!isJson()) {
823
824
  log("Initialized workspace.");
824
825
  }
@@ -828,14 +829,17 @@ async function runScanCommand(input, options) {
828
829
  branch: options.branch,
829
830
  ref: options.ref,
830
831
  checkoutDir: options.checkoutDir
831
- }) : await ingestDirectory(rootDir, input, {});
832
+ }) : await ingestScanInput(rootDir, input, progress);
832
833
  if (!isJson()) {
833
834
  if ("source" in result) {
834
835
  log(
835
836
  `Registered ${result.source.kind} source ${result.source.id}. Imported ${result.source.lastSyncCounts?.importedCount ?? 0}, updated ${result.source.lastSyncCounts?.updatedCount ?? 0}.`
836
837
  );
837
- } else {
838
+ } else if ("inputDir" in result) {
838
839
  log(`Ingested ${result.imported.length} file(s).`);
840
+ } else {
841
+ const sourceCount = result.created.length + result.updated.length + result.unchanged.length;
842
+ log(`Ingested ${sourceCount} source(s).`);
839
843
  }
840
844
  }
841
845
  const compiled = "compile" in result && result.compile ? result.compile : await compileVault(rootDir, {});
@@ -901,6 +905,17 @@ async function runScanCommand(input, options) {
901
905
  emitJson({ ...result, compiled, shareCardPath, shareCardSvgPath, shareKitPath });
902
906
  }
903
907
  }
908
+ async function ingestScanInput(rootDir, input, progress) {
909
+ const absoluteInput = path2.resolve(rootDir, input);
910
+ const inputStat = await stat(absoluteInput);
911
+ if (inputStat.isDirectory()) {
912
+ return ingestDirectory(rootDir, input, { progress });
913
+ }
914
+ if (inputStat.isFile()) {
915
+ return ingestInputDetailed(rootDir, input, { progress });
916
+ }
917
+ throw new Error(`Input must be a file or directory: ${input}`);
918
+ }
904
919
  async function resolveChatResumeId(resume) {
905
920
  if (!resume) {
906
921
  return void 0;
@@ -1022,7 +1037,7 @@ program.command("next").description("Show the safest next command for this direc
1022
1037
  }
1023
1038
  printNextCommandReport(report);
1024
1039
  });
1025
- program.command("quickstart").description("Beginner path: initialize, ingest, compile, and optionally open the graph viewer in one command.").argument("<input>", "Directory or public GitHub repo root URL to turn into a vault").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 the input is a public repo URL").option("--ref <ref>", "Git ref, tag, or commit to check out when the input is a public repo URL").option("--checkout-dir <path>", "Persistent checkout directory for a public GitHub repo input").action(runScanCommand);
1040
+ program.command("quickstart").description("Beginner path: initialize, ingest, compile, and optionally open the graph viewer in one command.").argument("<input>", "Directory or public GitHub repo root URL to turn into a vault").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 the input is a public repo URL").option("--ref <ref>", "Git ref, tag, or commit to check out when the input is a public repo URL").option("--checkout-dir <path>", "Persistent checkout directory for a public GitHub repo input").option("--install-agent-rules", "Install configured agent rule files during initialization", false).action(runScanCommand);
1026
1041
  program.command("init").description("Initialize a SwarmVault workspace in the current directory.").option("--obsidian", "Generate a minimal .obsidian workspace alongside the vault", false).option(
1027
1042
  "--profile <profile>",
1028
1043
  "Starter workspace profile or comma-separated preset list (for example: personal-research or reader,timeline)"
@@ -1030,11 +1045,12 @@ program.command("init").description("Initialize a SwarmVault workspace in the cu
1030
1045
  "--lite",
1031
1046
  "Minimal LLM-Wiki starter (raw/, wiki/, wiki/index.md, wiki/log.md, swarmvault.schema.md) without config, state, or agent installs",
1032
1047
  false
1033
- ).action(async (options) => {
1048
+ ).option("--install-agent-rules", "Install configured agent rule files during initialization", false).action(async (options) => {
1034
1049
  await initVault(process2.cwd(), {
1035
1050
  obsidian: options.obsidian ?? false,
1036
1051
  profile: options.profile,
1037
- lite: options.lite ?? false
1052
+ lite: options.lite ?? false,
1053
+ installAgentRules: options.installAgentRules ?? false
1038
1054
  });
1039
1055
  if (isJson()) {
1040
1056
  emitJson({
@@ -1042,7 +1058,8 @@ program.command("init").description("Initialize a SwarmVault workspace in the cu
1042
1058
  rootDir: process2.cwd(),
1043
1059
  obsidian: options.obsidian ?? false,
1044
1060
  profile: options.profile ?? "default",
1045
- lite: options.lite ?? false
1061
+ lite: options.lite ?? false,
1062
+ installAgentRules: options.installAgentRules ?? false
1046
1063
  });
1047
1064
  } else {
1048
1065
  log(options.lite ? "Initialized SwarmVault lite workspace." : "Initialized SwarmVault workspace.");
@@ -1074,11 +1091,10 @@ program.command("ingest").description("Ingest a local file path, directory path,
1074
1091
  video: options.video,
1075
1092
  extractClasses,
1076
1093
  resume: options.resume,
1077
- redact: options.redact
1094
+ redact: options.redact,
1095
+ progress: !isJson()
1078
1096
  };
1079
- const directoryResult = !/^https?:\/\//i.test(input) ? await import("fs/promises").then(
1080
- (fs) => fs.stat(input).then((stat) => stat.isDirectory() ? ingestDirectory(process2.cwd(), input, commonOptions) : null).catch(() => null)
1081
- ) : null;
1097
+ const directoryResult = !/^https?:\/\//i.test(input) ? await stat(input).then((inputStat) => inputStat.isDirectory() ? ingestDirectory(process2.cwd(), input, commonOptions) : null).catch(() => null) : null;
1082
1098
  if (directoryResult) {
1083
1099
  const scope2 = options.review || guideEnabled ? await (async () => {
1084
1100
  const pathModule = await import("path");
@@ -2765,8 +2781,8 @@ retrieval.command("doctor").description("Diagnose retrieval index problems and o
2765
2781
  log(`Warning: ${warning}`);
2766
2782
  }
2767
2783
  });
2768
- program.command("scan", { hidden: true }).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);
2769
- program.command("clone", { hidden: true }).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);
2784
+ program.command("scan", { hidden: true }).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").option("--install-agent-rules", "Install configured agent rule files during initialization", false).action(runScanCommand);
2785
+ program.command("clone", { hidden: true }).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").option("--install-agent-rules", "Install configured agent rule files during initialization", false).action(runScanCommand);
2770
2786
  function enableStructuredJsonOnSubcommands(command) {
2771
2787
  for (const subcommand of command.commands) {
2772
2788
  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.14.1",
3
+ "version": "3.15.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.14.1",
47
+ "@swarmvaultai/engine": "3.15.0",
48
48
  "commander": "^14.0.1"
49
49
  },
50
50
  "devDependencies": {