@swarmvaultai/cli 0.1.32 → 0.2.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SwarmVault
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  `@swarmvaultai/cli` is the global command-line entry point for SwarmVault.
4
4
 
5
- It gives you the `swarmvault` command for building a local-first knowledge vault from files, DOCX documents, URLs, browser clips, saved query outputs, and guided exploration runs.
5
+ It gives you the `swarmvault` command for building a local-first knowledge vault from files, reStructuredText and DOCX documents, URLs, browser clips, saved query outputs, and guided exploration runs.
6
6
 
7
7
  ## Install
8
8
 
@@ -23,6 +23,10 @@ Installed commands:
23
23
  mkdir my-vault
24
24
  cd my-vault
25
25
  swarmvault init --obsidian
26
+ swarmvault source add https://github.com/karpathy/micrograd
27
+ swarmvault source add https://example.com/docs/getting-started
28
+ swarmvault source list
29
+ swarmvault source reload --all
26
30
  sed -n '1,120p' swarmvault.schema.md
27
31
  swarmvault ingest ./notes.md
28
32
  swarmvault ingest ./repo
@@ -63,6 +67,26 @@ Create a workspace with:
63
67
 
64
68
  The schema file is the vault-specific instruction layer. Edit it to define naming rules, categories, grounding expectations, and exclusions before a serious compile.
65
69
 
70
+ ### `swarmvault source add|list|reload|delete`
71
+
72
+ Manage recurring source roots through a registry-backed workflow.
73
+
74
+ - `source add <input>` supports local directories, public GitHub repo root URLs such as `https://github.com/karpathy/micrograd`, and docs/wiki/help/reference/tutorial hubs
75
+ - by default `source add` registers the source, syncs it into the vault, runs one compile, and writes a source brief to `wiki/outputs/source-briefs/<source-id>.md`
76
+ - `source list` shows every managed source with its kind, status, and current brief path
77
+ - `source reload [id]` re-syncs one source, or use `--all` to refresh everything in the registry and compile once
78
+ - `source delete <id>` unregisters the source and removes transient sync state under `state/sources/<id>/`, but leaves canonical `raw/`, `wiki/`, and saved output artifacts intact
79
+
80
+ Useful flags:
81
+
82
+ - `--all`
83
+ - `--no-compile`
84
+ - `--no-brief`
85
+ - `--max-pages <n>`
86
+ - `--max-depth <n>`
87
+
88
+ Managed sources write registry state to `state/sources.json`. Local directory entries remain compatible with `watch --repo`; remote GitHub and docs-crawl sources are manual `source reload` sources in this release.
89
+
66
90
  ### `swarmvault ingest <path-or-url>`
67
91
 
68
92
  Ingest a local file path, directory path, or URL into immutable source storage and write manifests to `state/manifests/`.
@@ -70,9 +94,10 @@ Ingest a local file path, directory path, or URL into immutable source storage a
70
94
  - local directories recurse by default
71
95
  - directory ingest respects `.gitignore` unless you pass `--no-gitignore`
72
96
  - repo-aware directory ingest records `repoRelativePath` and later compile writes `state/code-index.json`
97
+ - use `source add` instead when the same local directory, public GitHub repo root, or docs hub should stay registered and reloadable
73
98
  - URL ingest still localizes remote image references by default
74
- - local file ingest supports markdown, text, HTML, PDF, DOCX, images, and code
75
- - code-aware directory ingest currently covers JavaScript, TypeScript, Python, Go, Rust, Java, C#, C, C++, PHP, Ruby, and PowerShell
99
+ - local file ingest supports markdown, text, reStructuredText, HTML, PDF, DOCX, images, and code
100
+ - code-aware directory ingest currently covers JavaScript, TypeScript, Python, Go, Rust, Java, C#, C, C++, PHP, Ruby, PowerShell, Kotlin, and Scala
76
101
 
77
102
  Useful flags:
78
103
 
@@ -89,6 +114,8 @@ Useful flags:
89
114
 
90
115
  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.
91
116
 
117
+ 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.
118
+
92
119
  ### `swarmvault add <url>`
93
120
 
94
121
  Capture supported URLs through a normalized markdown layer before ingesting them into the vault.
@@ -100,6 +127,7 @@ Capture supported URLs through a normalized markdown layer before ingesting them
100
127
  - unsupported URLs fall back to generic URL ingest instead of failing
101
128
  - optional metadata: `--author <name>` and `--contributor <name>`
102
129
  - normalized captures record fields such as `source_type`, `source_url`, `canonical_url`, `title`, `authors`, `published_at`, `updated_at`, `doi`, and `tags` when available
130
+ - use `source add` instead when the URL is a public GitHub repo root or a docs hub that should stay synced over time
103
131
 
104
132
  ### `swarmvault inbox import [dir]`
105
133
 
@@ -315,6 +343,20 @@ Hook semantics:
315
343
 
316
344
  `aider` is intentionally file/config-based in this release rather than hook-based.
317
345
 
346
+ ### OpenClaw / ClawHub Skill
347
+
348
+ If you use OpenClaw through ClawHub, install the packaged skill:
349
+
350
+ ```bash
351
+ clawhub install swarmvault
352
+ ```
353
+
354
+ That published bundle includes `SKILL.md`, a ClawHub README, examples, references, troubleshooting notes, and release-validation prompts. The CLI binary still comes from npm:
355
+
356
+ ```bash
357
+ npm install -g @swarmvaultai/cli
358
+ ```
359
+
318
360
  ## Provider Configuration
319
361
 
320
362
  SwarmVault defaults to a local `heuristic` provider so the CLI works without API keys, but real vaults will usually point at an actual model provider.
package/dist/index.js CHANGED
@@ -6,9 +6,11 @@ import process2 from "process";
6
6
  import {
7
7
  acceptApproval,
8
8
  addInput,
9
+ addManagedSource,
9
10
  archiveCandidate,
10
11
  benchmarkVault,
11
12
  compileVault,
13
+ deleteManagedSource,
12
14
  explainGraphVault,
13
15
  exploreVault,
14
16
  exportGraphFormat,
@@ -25,6 +27,7 @@ import {
25
27
  listApprovals,
26
28
  listCandidates,
27
29
  listGodNodes,
30
+ listManagedSourceRecords,
28
31
  listSchedules,
29
32
  loadVaultConfig,
30
33
  pathGraphVault,
@@ -34,6 +37,7 @@ import {
34
37
  queryVault,
35
38
  readApproval,
36
39
  rejectApproval,
40
+ reloadManagedSources,
37
41
  runSchedule,
38
42
  runWatchCycle,
39
43
  serveSchedules,
@@ -217,9 +221,9 @@ program.name("swarmvault").description("SwarmVault is a local-first LLM wiki com
217
221
  function readCliVersion() {
218
222
  try {
219
223
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
220
- return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.1.32";
224
+ return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.2.0";
221
225
  } catch {
222
- return "0.1.32";
226
+ return "0.2.0";
223
227
  }
224
228
  }
225
229
  function parsePositiveInt(value, fallback) {
@@ -329,6 +333,61 @@ program.command("add").description("Capture supported URLs into normalized markd
329
333
  log(`${result.captureType}${result.fallback ? " (fallback)" : ""}: ${result.manifest.sourceId}`);
330
334
  }
331
335
  });
336
+ var source = program.command("source").description("Manage recurring directory, public repo, and docs sources.");
337
+ source.command("add").description("Register and sync a managed source from a directory, public GitHub repo root URL, or docs hub URL.").argument("<input>", "Directory path, public GitHub repo root URL, or docs hub URL").option("--no-compile", "Register and sync without compiling the vault").option("--no-brief", "Skip source brief generation after sync").option("--max-pages <n>", "Maximum number of pages to crawl for docs sources").option("--max-depth <n>", "Maximum crawl depth for docs sources").action(async (input, options) => {
338
+ const result = await addManagedSource(process2.cwd(), input, {
339
+ compile: options.compile,
340
+ brief: options.brief,
341
+ maxPages: options.maxPages ? parsePositiveInt(options.maxPages, 0) || void 0 : void 0,
342
+ maxDepth: options.maxDepth ? parsePositiveInt(options.maxDepth, 0) || void 0 : void 0
343
+ });
344
+ if (isJson()) {
345
+ emitJson(result);
346
+ } else {
347
+ log(
348
+ `Registered ${result.source.kind} source ${result.source.id}. Status: ${result.source.status}.${result.compile ? ` Compiled ${result.compile.sourceCount} source(s).` : ""}${result.briefGenerated ? ` Brief: ${result.source.briefPath}` : ""}`
349
+ );
350
+ }
351
+ });
352
+ source.command("list").description("List managed sources registered in this vault.").action(async () => {
353
+ const sources = await listManagedSourceRecords(process2.cwd());
354
+ if (isJson()) {
355
+ emitJson(sources);
356
+ } else if (sources.length === 0) {
357
+ log("No managed sources registered.");
358
+ } else {
359
+ for (const entry of sources) {
360
+ log(`${entry.id} ${entry.kind} ${entry.status} ${entry.title}`);
361
+ }
362
+ }
363
+ });
364
+ source.command("reload").description("Re-sync one managed source or all managed sources, then optionally compile and refresh briefs.").argument("[id]", "Managed source id").option("--all", "Reload all managed sources", false).option("--no-compile", "Re-sync without compiling the vault").option("--no-brief", "Skip source brief generation after sync").option("--max-pages <n>", "Maximum number of pages to crawl for docs sources").option("--max-depth <n>", "Maximum crawl depth for docs sources").action(
365
+ async (id, options) => {
366
+ const result = await reloadManagedSources(process2.cwd(), {
367
+ id,
368
+ all: options.all ?? false,
369
+ compile: options.compile,
370
+ brief: options.brief,
371
+ maxPages: options.maxPages ? parsePositiveInt(options.maxPages, 0) || void 0 : void 0,
372
+ maxDepth: options.maxDepth ? parsePositiveInt(options.maxDepth, 0) || void 0 : void 0
373
+ });
374
+ if (isJson()) {
375
+ emitJson(result);
376
+ } else {
377
+ log(
378
+ `Reloaded ${result.sources.length} source(s).${result.compile ? ` Compiled ${result.compile.sourceCount} source(s).` : ""}${result.briefPaths.length ? ` Briefs: ${result.briefPaths.length}.` : ""}`
379
+ );
380
+ }
381
+ }
382
+ );
383
+ source.command("delete").description("Unregister a managed source and remove its transient sync state without deleting canonical vault content.").argument("<id>", "Managed source id").action(async (id) => {
384
+ const result = await deleteManagedSource(process2.cwd(), id);
385
+ if (isJson()) {
386
+ emitJson(result);
387
+ } else {
388
+ log(`Deleted managed source ${result.removed.id}. Canonical vault content was left in place.`);
389
+ }
390
+ });
332
391
  var inbox = program.command("inbox").description("Inbox and capture workflows.");
333
392
  inbox.command("import").description("Import supported files from the configured inbox directory.").argument("[dir]", "Optional inbox directory override").action(async (dir) => {
334
393
  const result = await importInbox(process2.cwd(), dir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmvaultai/cli",
3
- "version": "0.1.32",
3
+ "version": "0.2.0",
4
4
  "description": "Global CLI for SwarmVault.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -37,18 +37,18 @@
37
37
  "engines": {
38
38
  "node": ">=24.0.0"
39
39
  },
40
- "scripts": {
41
- "build": "tsup src/index.ts --format esm --dts",
42
- "test": "vitest run",
43
- "typecheck": "tsc --noEmit"
44
- },
45
40
  "dependencies": {
46
- "@swarmvaultai/engine": "0.1.32",
41
+ "@swarmvaultai/engine": "0.2.0",
47
42
  "commander": "^14.0.1"
48
43
  },
49
44
  "devDependencies": {
50
45
  "@types/node": "^24.6.0",
51
46
  "tsup": "^8.5.0",
52
47
  "vitest": "^3.2.4"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup src/index.ts --format esm --dts",
51
+ "test": "vitest run",
52
+ "typecheck": "tsc --noEmit"
53
53
  }
54
- }
54
+ }