@swarmvaultai/cli 0.1.16 → 0.1.18

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 +22 -4
  2. package/dist/index.js +37 -14
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -25,6 +25,7 @@ cd my-vault
25
25
  swarmvault init --obsidian
26
26
  sed -n '1,120p' swarmvault.schema.md
27
27
  swarmvault ingest ./notes.md
28
+ swarmvault ingest ./repo
28
29
  swarmvault compile
29
30
  swarmvault query "What keeps recurring?"
30
31
  swarmvault query "Turn this into slides" --format slides
@@ -55,7 +56,22 @@ The schema file is the vault-specific instruction layer. Edit it to define namin
55
56
 
56
57
  ### `swarmvault ingest <path-or-url>`
57
58
 
58
- Ingest a local file path or URL into immutable source storage and write a manifest to `state/manifests/`.
59
+ Ingest a local file path, directory path, or URL into immutable source storage and write manifests to `state/manifests/`.
60
+
61
+ - local directories recurse by default
62
+ - directory ingest respects `.gitignore` unless you pass `--no-gitignore`
63
+ - repo-aware directory ingest records `repoRelativePath` and later compile writes `state/code-index.json`
64
+ - URL ingest still localizes remote image references by default
65
+
66
+ Useful flags:
67
+
68
+ - `--repo-root <path>`
69
+ - `--include <glob...>`
70
+ - `--exclude <glob...>`
71
+ - `--max-files <n>`
72
+ - `--no-gitignore`
73
+ - `--no-include-assets`
74
+ - `--max-asset-size <bytes>`
59
75
 
60
76
  ### `swarmvault inbox import [dir]`
61
77
 
@@ -71,6 +87,8 @@ Compile the current manifests into:
71
87
 
72
88
  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.
73
89
 
90
+ 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.
91
+
74
92
  New concept and entity pages are staged into `wiki/candidates/` first. A later matching compile promotes them into `wiki/concepts/` or `wiki/entities/`.
75
93
 
76
94
  With `--approve`, compile writes a staged review bundle into `state/approvals/` without applying active wiki changes.
@@ -96,7 +114,7 @@ Inspect and resolve staged concept and entity candidates.
96
114
 
97
115
  Targets can be page ids or relative paths under `wiki/candidates/`.
98
116
 
99
- ### `swarmvault query "<question>" [--no-save] [--format markdown|report|slides]`
117
+ ### `swarmvault query "<question>" [--no-save] [--format markdown|report|slides|chart|image]`
100
118
 
101
119
  Query the compiled vault. The query layer also reads `swarmvault.schema.md`, so answers follow the vault’s own structure and grounding rules.
102
120
 
@@ -111,7 +129,7 @@ Saved outputs also carry related page, node, and source metadata so SwarmVault c
111
129
 
112
130
  Human-authored pages in `wiki/insights/` are also indexed into search and query context, but SwarmVault does not rewrite them after initialization.
113
131
 
114
- ### `swarmvault explore "<question>" [--steps <n>]`
132
+ ### `swarmvault explore "<question>" [--steps <n>] [--format markdown|report|slides|chart|image]`
115
133
 
116
134
  Run a save-first multi-step research loop.
117
135
 
@@ -165,7 +183,7 @@ Start the local graph workspace backed by `state/graph.json`, `/api/search`, and
165
183
 
166
184
  Export the graph workspace as a standalone HTML file with embedded graph and page data for offline sharing.
167
185
 
168
- ### `swarmvault install --agent <codex|claude|cursor|goose|pi|gemini>`
186
+ ### `swarmvault install --agent <codex|claude|cursor|goose|pi|gemini|opencode>`
169
187
 
170
188
  Install agent-specific rules into the current project so an agent understands the SwarmVault workspace contract and workflow.
171
189
 
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  exploreVault,
11
11
  exportGraphHtml,
12
12
  importInbox,
13
+ ingestDirectory,
13
14
  ingestInput,
14
15
  initVault,
15
16
  installAgent,
@@ -35,9 +36,9 @@ program.name("swarmvault").description("SwarmVault is a local-first LLM wiki com
35
36
  function readCliVersion() {
36
37
  try {
37
38
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
38
- return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.1.16";
39
+ return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.1.18";
39
40
  } catch {
40
- return "0.1.16";
41
+ return "0.1.18";
41
42
  }
42
43
  }
43
44
  function isJson() {
@@ -64,18 +65,40 @@ program.command("init").description("Initialize a SwarmVault workspace in the cu
64
65
  log("Initialized SwarmVault workspace.");
65
66
  }
66
67
  });
67
- program.command("ingest").description("Ingest a local file path or URL into the raw SwarmVault workspace.").argument("<input>", "Local file path or URL").option("--include-assets", "Download remote image assets when ingesting URLs", true).option("--no-include-assets", "Skip downloading remote image assets when ingesting URLs").option("--max-asset-size <bytes>", "Maximum number of bytes to fetch for a single remote image asset").action(async (input, options) => {
68
- const maxAssetSize = typeof options.maxAssetSize === "string" && options.maxAssetSize.trim() ? Number.parseInt(options.maxAssetSize, 10) : void 0;
69
- const manifest = await ingestInput(process.cwd(), input, {
70
- includeAssets: options.includeAssets,
71
- maxAssetSize: Number.isFinite(maxAssetSize) ? maxAssetSize : void 0
72
- });
73
- if (isJson()) {
74
- emitJson(manifest);
75
- } else {
76
- log(manifest.sourceId);
68
+ program.command("ingest").description("Ingest a local file path, directory path, or URL into the raw SwarmVault workspace.").argument("<input>", "Local file path, directory path, or URL").option("--include-assets", "Download remote image assets when ingesting URLs", true).option("--no-include-assets", "Skip downloading remote image assets when ingesting URLs").option("--max-asset-size <bytes>", "Maximum number of bytes to fetch for a single remote image asset").option("--repo-root <path>", "Override the detected repo root when ingesting a directory").option("--include <glob...>", "Only ingest files matching one or more glob patterns").option("--exclude <glob...>", "Skip files matching one or more glob patterns").option("--max-files <n>", "Maximum number of files to ingest from a directory").option("--no-gitignore", "Ignore .gitignore rules when ingesting a directory").action(
69
+ async (input, options) => {
70
+ const maxAssetSize = typeof options.maxAssetSize === "string" && options.maxAssetSize.trim() ? Number.parseInt(options.maxAssetSize, 10) : void 0;
71
+ const maxFiles = typeof options.maxFiles === "string" && options.maxFiles.trim() ? Number.parseInt(options.maxFiles, 10) : void 0;
72
+ const commonOptions = {
73
+ includeAssets: options.includeAssets,
74
+ maxAssetSize: Number.isFinite(maxAssetSize) ? maxAssetSize : void 0,
75
+ repoRoot: options.repoRoot,
76
+ include: options.include,
77
+ exclude: options.exclude,
78
+ maxFiles: Number.isFinite(maxFiles) ? maxFiles : void 0,
79
+ gitignore: options.gitignore
80
+ };
81
+ const directoryResult = !/^https?:\/\//i.test(input) ? await import("fs/promises").then(
82
+ (fs) => fs.stat(input).then((stat) => stat.isDirectory() ? ingestDirectory(process.cwd(), input, commonOptions) : null).catch(() => null)
83
+ ) : null;
84
+ if (directoryResult) {
85
+ if (isJson()) {
86
+ emitJson(directoryResult);
87
+ } else {
88
+ log(
89
+ `Imported ${directoryResult.imported.length} file(s), updated ${directoryResult.updated.length}, skipped ${directoryResult.skipped.length}.`
90
+ );
91
+ }
92
+ return;
93
+ }
94
+ const manifest = await ingestInput(process.cwd(), input, commonOptions);
95
+ if (isJson()) {
96
+ emitJson(manifest);
97
+ } else {
98
+ log(manifest.sourceId);
99
+ }
77
100
  }
78
- });
101
+ );
79
102
  var inbox = program.command("inbox").description("Inbox and capture workflows.");
80
103
  inbox.command("import").description("Import supported files from the configured inbox directory.").argument("[dir]", "Optional inbox directory override").action(async (dir) => {
81
104
  const result = await importInbox(process.cwd(), dir);
@@ -314,7 +337,7 @@ program.command("mcp").description("Run SwarmVault as a local MCP server over st
314
337
  process.exit(0);
315
338
  });
316
339
  });
317
- program.command("install").description("Install SwarmVault instructions for an agent in the current project.").requiredOption("--agent <agent>", "codex, claude, cursor, goose, pi, or gemini").action(async (options) => {
340
+ program.command("install").description("Install SwarmVault instructions for an agent in the current project.").requiredOption("--agent <agent>", "codex, claude, cursor, goose, pi, gemini, or opencode").action(async (options) => {
318
341
  const target = await installAgent(process.cwd(), options.agent);
319
342
  if (isJson()) {
320
343
  emitJson({ agent: options.agent, target });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmvaultai/cli",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Global CLI for SwarmVault.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "commander": "^14.0.1",
42
- "@swarmvaultai/engine": "0.1.16"
42
+ "@swarmvaultai/engine": "0.1.18"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^24.6.0",