@swarmvaultai/cli 0.7.24 → 0.7.25
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/README.md +49 -6
- package/dist/index.js +71 -23
- package/package.json +9 -8
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -34,18 +34,20 @@ sed -n '1,120p' swarmvault.schema.md
|
|
|
34
34
|
swarmvault ingest ./notes.md
|
|
35
35
|
swarmvault ingest ./repo
|
|
36
36
|
swarmvault add https://arxiv.org/abs/2401.12345
|
|
37
|
-
swarmvault compile
|
|
37
|
+
swarmvault compile --max-tokens 120000
|
|
38
38
|
swarmvault benchmark
|
|
39
|
-
swarmvault query "What keeps recurring?"
|
|
39
|
+
swarmvault query "What keeps recurring?" --commit
|
|
40
40
|
swarmvault query "Turn this into slides" --format slides
|
|
41
41
|
swarmvault explore "What should I research next?" --steps 3
|
|
42
42
|
swarmvault lint --deep
|
|
43
|
+
swarmvault graph blast ./src/index.ts
|
|
43
44
|
swarmvault graph query "Which nodes bridge the biggest clusters?"
|
|
44
45
|
swarmvault graph explain "concept:drift"
|
|
45
46
|
swarmvault watch status
|
|
46
47
|
swarmvault watch --repo --once
|
|
47
48
|
swarmvault hook install
|
|
48
49
|
swarmvault graph serve
|
|
50
|
+
swarmvault graph export --report ./exports/report.html
|
|
49
51
|
swarmvault graph export --html ./exports/graph.html
|
|
50
52
|
swarmvault graph export --cypher ./exports/graph.cypher
|
|
51
53
|
swarmvault graph push neo4j --dry-run
|
|
@@ -121,7 +123,7 @@ Source-scoped artifacts are intentionally split by role:
|
|
|
121
123
|
| Source guide | `source guide`, `source add --guide`, `ingest --guide` | Guided walkthrough with approval-bundled updates in `wiki/outputs/source-guides/` |
|
|
122
124
|
| Source session | `source session`, `source add --guide`, `ingest --guide` | Resumable workflow state in `wiki/outputs/source-sessions/` and `state/source-sessions/` |
|
|
123
125
|
|
|
124
|
-
### `swarmvault ingest <path-or-url
|
|
126
|
+
### `swarmvault ingest <path-or-url> [--commit]`
|
|
125
127
|
|
|
126
128
|
Ingest a local file path, directory path, or URL into immutable source storage and write manifests to `state/manifests/`.
|
|
127
129
|
|
|
@@ -149,11 +151,14 @@ Useful flags:
|
|
|
149
151
|
- `--no-gitignore`
|
|
150
152
|
- `--no-include-assets`
|
|
151
153
|
- `--max-asset-size <bytes>`
|
|
154
|
+
- `--commit`
|
|
152
155
|
|
|
153
156
|
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.
|
|
154
157
|
|
|
155
158
|
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.
|
|
156
159
|
|
|
160
|
+
When `--commit` is set, SwarmVault stages `wiki/` and `state/` changes and creates a git commit when the vault root is inside a git worktree. Outside git, it becomes a no-op instead of failing.
|
|
161
|
+
|
|
157
162
|
### `swarmvault add <url>`
|
|
158
163
|
|
|
159
164
|
Capture supported URLs through a normalized markdown layer before ingesting them into the vault.
|
|
@@ -171,7 +176,7 @@ Capture supported URLs through a normalized markdown layer before ingesting them
|
|
|
171
176
|
|
|
172
177
|
Import supported files from the configured inbox directory. This is meant for browser-clipper style markdown bundles, HTML clip bundles, and other capture workflows. Local image and asset references are preserved and copied into canonical storage under `raw/assets/`.
|
|
173
178
|
|
|
174
|
-
### `swarmvault compile [--approve]`
|
|
179
|
+
### `swarmvault compile [--approve] [--commit] [--max-tokens <n>]`
|
|
175
180
|
|
|
176
181
|
Compile the current manifests into:
|
|
177
182
|
|
|
@@ -187,6 +192,14 @@ New concept and entity pages are staged into `wiki/candidates/` first. A later m
|
|
|
187
192
|
|
|
188
193
|
With `--approve`, compile writes a staged review bundle into `state/approvals/` without applying active wiki changes.
|
|
189
194
|
|
|
195
|
+
Useful flags:
|
|
196
|
+
|
|
197
|
+
- `--approve`
|
|
198
|
+
- `--commit`
|
|
199
|
+
- `--max-tokens <n>`
|
|
200
|
+
|
|
201
|
+
`--max-tokens <n>` keeps the generated wiki inside a bounded token budget by dropping lower-priority pages from final `wiki/` output and reporting token-budget stats in the compile result. `--commit` immediately commits `wiki/` and `state/` changes when the vault lives in a git repo.
|
|
202
|
+
|
|
190
203
|
### `swarmvault benchmark [--question "<text>" ...]`
|
|
191
204
|
|
|
192
205
|
Measure graph-guided context reduction against a naive full-corpus read.
|
|
@@ -218,7 +231,7 @@ Inspect and resolve staged concept and entity candidates.
|
|
|
218
231
|
|
|
219
232
|
Targets can be page ids or relative paths under `wiki/candidates/`.
|
|
220
233
|
|
|
221
|
-
### `swarmvault query "<question>" [--no-save] [--format markdown|report|slides|chart|image]`
|
|
234
|
+
### `swarmvault query "<question>" [--no-save] [--commit] [--format markdown|report|slides|chart|image]`
|
|
222
235
|
|
|
223
236
|
Query the compiled vault. The query layer also reads `swarmvault.schema.md`, so answers follow the vault’s own structure and grounding rules.
|
|
224
237
|
|
|
@@ -233,6 +246,8 @@ Saved outputs also carry related page, node, and source metadata so SwarmVault c
|
|
|
233
246
|
|
|
234
247
|
Human-authored pages in `wiki/insights/` are also indexed into search and query context, but SwarmVault does not rewrite them after initialization.
|
|
235
248
|
|
|
249
|
+
By default, query uses the local SQLite search index. When an embedding-capable provider is available and `search.hybrid` is not disabled, semantic page matches are fused into the same candidate set before answer generation. `tasks.embeddingProvider` is the explicit way to choose that backend, but SwarmVault can also fall back to a `queryProvider` with embeddings support. Set `search.rerank: true` when you want the configured `queryProvider` to rerank the merged top hits. `--commit` immediately commits saved `wiki/` and `state/` changes when the vault root is inside a git repo.
|
|
250
|
+
|
|
236
251
|
### `swarmvault explore "<question>" [--steps <n>] [--format markdown|report|slides|chart|image]`
|
|
237
252
|
|
|
238
253
|
Run a save-first multi-step research loop.
|
|
@@ -299,6 +314,9 @@ Run SwarmVault as a local MCP server over stdio. This exposes the vault to compa
|
|
|
299
314
|
- `ingest_input`
|
|
300
315
|
- `compile_vault`
|
|
301
316
|
- `lint_vault`
|
|
317
|
+
- `blast_radius`
|
|
318
|
+
|
|
319
|
+
`compile_vault` also accepts `maxTokens` for bounded wiki output, and `blast_radius` traces reverse import impact for a file or module target.
|
|
302
320
|
|
|
303
321
|
The MCP surface also exposes `swarmvault://schema`, `swarmvault://sessions`, `swarmvault://sessions/{path}`, and includes `schemaPath` in `workspace_info`.
|
|
304
322
|
|
|
@@ -306,6 +324,8 @@ The MCP surface also exposes `swarmvault://schema`, `swarmvault://sessions`, `sw
|
|
|
306
324
|
|
|
307
325
|
Start the local graph workspace backed by `state/graph.json`, `/api/search`, `/api/page`, and local graph query/path/explain endpoints.
|
|
308
326
|
|
|
327
|
+
It also exposes `/api/bookmarklet` and `/api/clip`, so a running local viewer can ingest the current browser page through a bookmarklet without leaving the browser.
|
|
328
|
+
|
|
309
329
|
### `swarmvault graph query "<question>" [--dfs] [--budget <n>]`
|
|
310
330
|
|
|
311
331
|
Run a deterministic local graph traversal seeded from local search, graph labels, and matching group patterns.
|
|
@@ -322,12 +342,21 @@ Inspect graph metadata, community membership, neighbors, provenance, and group-p
|
|
|
322
342
|
|
|
323
343
|
List the most connected bridge-heavy nodes in the current graph.
|
|
324
344
|
|
|
325
|
-
### `swarmvault graph
|
|
345
|
+
### `swarmvault graph blast <target> [--depth <n>]`
|
|
346
|
+
|
|
347
|
+
Trace the reverse-import blast radius of changing a file or module.
|
|
348
|
+
|
|
349
|
+
- accepts a file path, module label, or module id
|
|
350
|
+
- follows reverse `imports` edges through the compiled graph
|
|
351
|
+
- reports affected modules by depth so you can estimate downstream impact before editing
|
|
352
|
+
|
|
353
|
+
### `swarmvault graph export --html|--html-standalone|--report|--svg|--graphml|--cypher|--json|--obsidian|--canvas <output>`
|
|
326
354
|
|
|
327
355
|
Export the current graph as one or more shareable formats:
|
|
328
356
|
|
|
329
357
|
- `--html` for the full self-contained read-only graph workspace
|
|
330
358
|
- `--html-standalone` for a lighter vis.js export with node search, legend, and sidebar inspection
|
|
359
|
+
- `--report` for a self-contained HTML graph report with stats, key nodes, communities, and warnings
|
|
331
360
|
- `--svg` for a static shareable diagram
|
|
332
361
|
- `--graphml` for graph-tool interoperability
|
|
333
362
|
- `--cypher` for Neo4j-style import scripts
|
|
@@ -463,6 +492,20 @@ Deep lint web augmentation uses a separate `webSearch` config block. Example:
|
|
|
463
492
|
}
|
|
464
493
|
```
|
|
465
494
|
|
|
495
|
+
Search behavior is configurable separately from provider routing:
|
|
496
|
+
|
|
497
|
+
```json
|
|
498
|
+
{
|
|
499
|
+
"search": {
|
|
500
|
+
"hybrid": true,
|
|
501
|
+
"rerank": false
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
- `search.hybrid` defaults to enabled and merges full-text hits with semantic page matches when an embedding-capable provider is available
|
|
507
|
+
- `search.rerank` optionally asks the current `queryProvider` to rerank the merged top hits before query answers are generated
|
|
508
|
+
|
|
466
509
|
## Troubleshooting
|
|
467
510
|
|
|
468
511
|
- If you are running from a source checkout and `graph serve` says the viewer build is missing, run `pnpm build` in the repository first
|
package/dist/index.js
CHANGED
|
@@ -9,13 +9,16 @@ import {
|
|
|
9
9
|
addInput,
|
|
10
10
|
addManagedSource,
|
|
11
11
|
archiveCandidate,
|
|
12
|
+
autoCommitWikiChanges,
|
|
12
13
|
benchmarkVault,
|
|
14
|
+
blastRadiusVault,
|
|
13
15
|
compileVault,
|
|
14
16
|
deleteManagedSource,
|
|
15
17
|
explainGraphVault,
|
|
16
18
|
exploreVault,
|
|
17
19
|
exportGraphFormat,
|
|
18
20
|
exportGraphHtml,
|
|
21
|
+
exportGraphReportHtml,
|
|
19
22
|
exportObsidianCanvas,
|
|
20
23
|
exportObsidianVault,
|
|
21
24
|
getGitHookStatus,
|
|
@@ -270,9 +273,9 @@ program.name("swarmvault").description("SwarmVault is a local-first knowledge co
|
|
|
270
273
|
function readCliVersion() {
|
|
271
274
|
try {
|
|
272
275
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
273
|
-
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.7.
|
|
276
|
+
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.7.25";
|
|
274
277
|
} catch {
|
|
275
|
-
return "0.7.
|
|
278
|
+
return "0.7.25";
|
|
276
279
|
}
|
|
277
280
|
}
|
|
278
281
|
function parsePositiveInt(value, fallback) {
|
|
@@ -429,7 +432,7 @@ program.command("init").description("Initialize a SwarmVault workspace in the cu
|
|
|
429
432
|
log("Initialized SwarmVault workspace.");
|
|
430
433
|
}
|
|
431
434
|
});
|
|
432
|
-
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("--review", "Stage a source review artifact after ingest and compile", false).option("--guide", "Stage a guided source integration bundle after ingest and compile (default: from config)").option("--no-guide", "Skip guided mode even if enabled in config").option("--answers-file <path>", "JSON file with guided-session answers keyed by question id or listed in prompt order").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("--include-third-party", "Also ingest repo files classified as third-party", false).option("--include-resources", "Also ingest repo files classified as resources", false).option("--include-generated", "Also ingest repo files classified as generated output", false).option("--no-gitignore", "Ignore .gitignore rules when ingesting a directory").action(
|
|
435
|
+
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("--review", "Stage a source review artifact after ingest and compile", false).option("--guide", "Stage a guided source integration bundle after ingest and compile (default: from config)").option("--no-guide", "Skip guided mode even if enabled in config").option("--answers-file <path>", "JSON file with guided-session answers keyed by question id or listed in prompt order").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("--include-third-party", "Also ingest repo files classified as third-party", false).option("--include-resources", "Also ingest repo files classified as resources", false).option("--include-generated", "Also ingest repo files classified as generated output", false).option("--no-gitignore", "Ignore .gitignore rules when ingesting a directory").option("--commit", "Auto-commit wiki and state changes after ingest").action(
|
|
433
436
|
async (input, options) => {
|
|
434
437
|
const guideAnswers = readGuideAnswersFile(options.answersFile);
|
|
435
438
|
const vaultConfig = await loadVaultConfig(process2.cwd()).catch(() => null);
|
|
@@ -502,6 +505,10 @@ program.command("ingest").description("Ingest a local file path, directory path,
|
|
|
502
505
|
log(`Staged guided session at ${completedGuide2.guidePath}.`);
|
|
503
506
|
}
|
|
504
507
|
}
|
|
508
|
+
if (options.commit) {
|
|
509
|
+
const msg = await autoCommitWikiChanges(process2.cwd(), "ingest", input, { force: true });
|
|
510
|
+
if (msg && !isJson()) log(`Committed: ${msg}`);
|
|
511
|
+
}
|
|
505
512
|
return;
|
|
506
513
|
}
|
|
507
514
|
const ingest = await ingestInputDetailed(process2.cwd(), input, commonOptions);
|
|
@@ -537,6 +544,10 @@ program.command("ingest").description("Ingest a local file path, directory path,
|
|
|
537
544
|
log(`Staged guided session at ${completedGuide.guidePath}.`);
|
|
538
545
|
}
|
|
539
546
|
}
|
|
547
|
+
if (options.commit) {
|
|
548
|
+
const msg = await autoCommitWikiChanges(process2.cwd(), "ingest", input, { force: true });
|
|
549
|
+
if (msg && !isJson()) log(`Committed: ${msg}`);
|
|
550
|
+
}
|
|
540
551
|
}
|
|
541
552
|
);
|
|
542
553
|
program.command("add").description("Capture supported URLs into normalized markdown before ingesting them.").argument("<input>", "Supported URL or bare arXiv id").option("--author <name>", "Human author or curator for this capture").option("--contributor <name>", "Additional contributor metadata for this capture").action(async (input, options) => {
|
|
@@ -674,8 +685,9 @@ inbox.command("import").description("Import supported files from the configured
|
|
|
674
685
|
);
|
|
675
686
|
}
|
|
676
687
|
});
|
|
677
|
-
program.command("compile").description("Compile manifests into wiki pages, graph JSON, and search index.").option("--approve", "Stage a review bundle without applying active page changes", false).action(async (options) => {
|
|
678
|
-
const
|
|
688
|
+
program.command("compile").description("Compile manifests into wiki pages, graph JSON, and search index.").option("--approve", "Stage a review bundle without applying active page changes", false).option("--commit", "Auto-commit wiki and state changes after compile").option("--max-tokens <n>", "Cap wiki output by trimming lower-priority pages").action(async (options) => {
|
|
689
|
+
const maxTokens = options.maxTokens ? parsePositiveInt(options.maxTokens, 0) || void 0 : void 0;
|
|
690
|
+
const result = await compileVault(process2.cwd(), { approve: options.approve ?? false, maxTokens });
|
|
679
691
|
if (isJson()) {
|
|
680
692
|
emitJson(result);
|
|
681
693
|
} else {
|
|
@@ -684,27 +696,44 @@ program.command("compile").description("Compile manifests into wiki pages, graph
|
|
|
684
696
|
} else {
|
|
685
697
|
log(`Compiled ${result.sourceCount} source(s), ${result.pageCount} page(s). Changed: ${result.changedPages.length}.`);
|
|
686
698
|
}
|
|
699
|
+
if (result.tokenStats) {
|
|
700
|
+
log(
|
|
701
|
+
`Token budget: ~${result.tokenStats.estimatedTokens} tokens, kept ${result.tokenStats.pagesKept} pages, dropped ${result.tokenStats.pagesDropped}.`
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
if (options.commit) {
|
|
706
|
+
const msg = await autoCommitWikiChanges(process2.cwd(), "compile", `${result.sourceCount} sources, ${result.pageCount} pages`, {
|
|
707
|
+
force: true
|
|
708
|
+
});
|
|
709
|
+
if (msg && !isJson()) log(`Committed: ${msg}`);
|
|
687
710
|
}
|
|
688
711
|
await maybeEmitHeuristicNotice(["compile"]);
|
|
689
712
|
});
|
|
690
|
-
program.command("query").description("Query the compiled SwarmVault wiki.").argument("<question>", "Question to ask SwarmVault").option("--no-save", "Do not persist the answer to wiki/outputs").addOption(
|
|
713
|
+
program.command("query").description("Query the compiled SwarmVault wiki.").argument("<question>", "Question to ask SwarmVault").option("--no-save", "Do not persist the answer to wiki/outputs").option("--commit", "Auto-commit wiki changes after query").addOption(
|
|
691
714
|
new Option("--format <format>", "Output format").choices(["markdown", "report", "slides", "chart", "image"]).default("markdown")
|
|
692
|
-
).action(
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
715
|
+
).action(
|
|
716
|
+
async (question, options) => {
|
|
717
|
+
const result = await queryVault(process2.cwd(), {
|
|
718
|
+
question,
|
|
719
|
+
save: options.save ?? true,
|
|
720
|
+
format: options.format
|
|
721
|
+
});
|
|
722
|
+
if (isJson()) {
|
|
723
|
+
emitJson(result);
|
|
724
|
+
} else {
|
|
725
|
+
log(result.answer);
|
|
726
|
+
if (result.savedPath) {
|
|
727
|
+
log(`Saved to ${result.savedPath}`);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
if (options.commit) {
|
|
731
|
+
const msg = await autoCommitWikiChanges(process2.cwd(), "query", question.slice(0, 72), { force: true });
|
|
732
|
+
if (msg && !isJson()) log(`Committed: ${msg}`);
|
|
704
733
|
}
|
|
734
|
+
await maybeEmitHeuristicNotice(["query"]);
|
|
705
735
|
}
|
|
706
|
-
|
|
707
|
-
});
|
|
736
|
+
);
|
|
708
737
|
program.command("explore").description("Run a save-first multi-step exploration loop against the vault.").argument("<question>", "Root question to explore").option("--steps <n>", "Maximum number of exploration steps", "3").addOption(
|
|
709
738
|
new Option("--format <format>", "Output format for step pages").choices(["markdown", "report", "slides", "chart", "image"]).default("markdown")
|
|
710
739
|
).action(async (question, options) => {
|
|
@@ -805,6 +834,7 @@ graph.command("serve").description("Serve the local graph viewer.").option("--po
|
|
|
805
834
|
emitJson({ port: server.port, url: `http://localhost:${server.port}` });
|
|
806
835
|
} else {
|
|
807
836
|
log(`Graph viewer running at http://localhost:${server.port}`);
|
|
837
|
+
log(`Browser clipper: http://localhost:${server.port}/api/bookmarklet`);
|
|
808
838
|
}
|
|
809
839
|
process2.on("SIGINT", async () => {
|
|
810
840
|
try {
|
|
@@ -815,12 +845,13 @@ graph.command("serve").description("Serve the local graph viewer.").option("--po
|
|
|
815
845
|
});
|
|
816
846
|
});
|
|
817
847
|
graph.command("export").description(
|
|
818
|
-
"Export the graph as HTML, SVG, GraphML, Cypher, JSON, Obsidian vault, or Obsidian canvas. Combine flags to write multiple formats in one run."
|
|
819
|
-
).option("--html <output>", "Output HTML file path").option("--html-standalone <output>", "Output lightweight standalone HTML file path (vis.js, no build tooling)").option("--svg <output>", "Output SVG file path").option("--graphml <output>", "Output GraphML file path").option("--cypher <output>", "Output Cypher file path").option("--json <output>", "Output JSON file path").option("--obsidian <output>", "Output Obsidian vault directory path").option("--canvas <output>", "Output Obsidian canvas file path").option("--full", "Disable overview sampling for HTML export", false).action(
|
|
848
|
+
"Export the graph as HTML, report, SVG, GraphML, Cypher, JSON, Obsidian vault, or Obsidian canvas. Combine flags to write multiple formats in one run."
|
|
849
|
+
).option("--html <output>", "Output HTML file path").option("--html-standalone <output>", "Output lightweight standalone HTML file path (vis.js, no build tooling)").option("--report <output>", "Output self-contained HTML report (graph stats, key nodes, communities)").option("--svg <output>", "Output SVG file path").option("--graphml <output>", "Output GraphML file path").option("--cypher <output>", "Output Cypher file path").option("--json <output>", "Output JSON file path").option("--obsidian <output>", "Output Obsidian vault directory path").option("--canvas <output>", "Output Obsidian canvas file path").option("--full", "Disable overview sampling for HTML export", false).action(
|
|
820
850
|
async (options) => {
|
|
821
851
|
const targets = [
|
|
822
852
|
options.html ? { format: "html", outputPath: options.html } : null,
|
|
823
853
|
options.htmlStandalone ? { format: "html-standalone", outputPath: options.htmlStandalone } : null,
|
|
854
|
+
options.report ? { format: "report", outputPath: options.report } : null,
|
|
824
855
|
options.svg ? { format: "svg", outputPath: options.svg } : null,
|
|
825
856
|
options.graphml ? { format: "graphml", outputPath: options.graphml } : null,
|
|
826
857
|
options.cypher ? { format: "cypher", outputPath: options.cypher } : null,
|
|
@@ -829,13 +860,18 @@ graph.command("export").description(
|
|
|
829
860
|
options.canvas ? { format: "canvas", outputPath: options.canvas } : null
|
|
830
861
|
].filter((target) => Boolean(target));
|
|
831
862
|
if (targets.length === 0) {
|
|
832
|
-
throw new Error(
|
|
863
|
+
throw new Error(
|
|
864
|
+
"Pass at least one of --html, --html-standalone, --report, --svg, --graphml, --cypher, --json, --obsidian, or --canvas."
|
|
865
|
+
);
|
|
833
866
|
}
|
|
834
867
|
const results = [];
|
|
835
868
|
for (const target of targets) {
|
|
836
869
|
if (target.format === "html") {
|
|
837
870
|
const outputPath = await exportGraphHtml(process2.cwd(), target.outputPath, { full: options.full ?? false });
|
|
838
871
|
results.push({ format: target.format, outputPath });
|
|
872
|
+
} else if (target.format === "report") {
|
|
873
|
+
const result = await exportGraphReportHtml(process2.cwd(), target.outputPath);
|
|
874
|
+
results.push({ format: result.format, outputPath: result.outputPath });
|
|
839
875
|
} else if (target.format === "obsidian") {
|
|
840
876
|
const result = await exportObsidianVault(process2.cwd(), target.outputPath);
|
|
841
877
|
results.push({ format: result.format, outputPath: result.outputPath, fileCount: result.fileCount });
|
|
@@ -896,6 +932,18 @@ graph.command("god-nodes").description("List the highest-connectivity non-source
|
|
|
896
932
|
log(`${node.label} degree=${node.degree ?? 0} bridge=${node.bridgeScore ?? 0}`);
|
|
897
933
|
}
|
|
898
934
|
});
|
|
935
|
+
graph.command("blast").description("Show the blast radius of changing a file or module.").argument("<target>", "File path, module label, or module id").option("--depth <n>", "Maximum traversal depth", "3").action(async (target, options) => {
|
|
936
|
+
const depth = parsePositiveInt(options.depth, 3);
|
|
937
|
+
const result = await blastRadiusVault(process2.cwd(), target, { maxDepth: depth });
|
|
938
|
+
if (isJson()) {
|
|
939
|
+
emitJson(result);
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
log(result.summary);
|
|
943
|
+
for (const mod of result.affectedModules) {
|
|
944
|
+
log(` ${" ".repeat(mod.depth - 1)}${mod.label} (depth ${mod.depth})`);
|
|
945
|
+
}
|
|
946
|
+
});
|
|
899
947
|
var review = program.command("review").description("Review staged compile approval bundles.");
|
|
900
948
|
review.command("list").description("List staged approval bundles and their resolution status.").action(async () => {
|
|
901
949
|
const approvals = await listApprovals(process2.cwd());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmvaultai/cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.25",
|
|
4
4
|
"description": "Global CLI for SwarmVault.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -37,18 +37,19 @@
|
|
|
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
|
+
"prepublishOnly": "node ../../scripts/check-release-sync.mjs && node ../../scripts/check-published-manifests.mjs"
|
|
45
|
+
},
|
|
40
46
|
"dependencies": {
|
|
41
|
-
"@swarmvaultai/engine": "0.7.
|
|
47
|
+
"@swarmvaultai/engine": "0.7.25",
|
|
42
48
|
"commander": "^14.0.1"
|
|
43
49
|
},
|
|
44
50
|
"devDependencies": {
|
|
45
51
|
"@types/node": "^24.6.0",
|
|
46
52
|
"tsup": "^8.5.0",
|
|
47
53
|
"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
54
|
}
|
|
54
|
-
}
|
|
55
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
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.
|