@swarmvaultai/cli 3.4.0 → 3.6.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/README.md +65 -8
- package/dist/index.js +76 -9
- package/package.json +2 -2
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, audio transcripts, YouTube URLs, reStructuredText and DOCX documents, 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, audio/video transcripts, YouTube URLs, reStructuredText and DOCX documents, browser clips, saved query outputs, and guided exploration runs.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -35,6 +35,7 @@ sed -n '1,120p' swarmvault.schema.md
|
|
|
35
35
|
swarmvault ingest ./notes.md
|
|
36
36
|
swarmvault ingest ./customer-call.mp3
|
|
37
37
|
swarmvault ingest https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
38
|
+
swarmvault ingest --video https://example.com/product-demo.mp4
|
|
38
39
|
swarmvault ingest ./repo
|
|
39
40
|
swarmvault add https://arxiv.org/abs/2401.12345
|
|
40
41
|
swarmvault compile --max-tokens 120000
|
|
@@ -52,6 +53,9 @@ swarmvault query "Turn this into slides" --format slides
|
|
|
52
53
|
swarmvault explore "What should I research next?" --steps 3
|
|
53
54
|
swarmvault lint --deep
|
|
54
55
|
swarmvault graph blast ./src/index.ts
|
|
56
|
+
swarmvault graph status ./src
|
|
57
|
+
swarmvault graph update .
|
|
58
|
+
swarmvault graph cluster
|
|
55
59
|
swarmvault graph query "Which nodes bridge the biggest clusters?"
|
|
56
60
|
swarmvault graph explain "concept:drift"
|
|
57
61
|
swarmvault watch status
|
|
@@ -83,6 +87,8 @@ Create a workspace with:
|
|
|
83
87
|
|
|
84
88
|
The schema file is the vault-specific instruction layer. Edit it to define naming rules, categories, grounding expectations, and exclusions before a serious compile.
|
|
85
89
|
|
|
90
|
+
Set `SWARMVAULT_OUT=<dir>` when generated artifacts should be isolated from the project root. Config and schema files stay at the root; relative `raw/`, `wiki/`, `state/`, `agent/`, and `inbox/` workspace directories resolve under the output root.
|
|
91
|
+
|
|
86
92
|
`--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`.
|
|
87
93
|
|
|
88
94
|
### `swarmvault scan <directory> [--port <port>] [--no-serve]`
|
|
@@ -170,15 +176,16 @@ Source-scoped artifacts are intentionally split by role:
|
|
|
170
176
|
Ingest a local file path, directory path, or URL into immutable source storage and write manifests to `state/manifests/`.
|
|
171
177
|
|
|
172
178
|
- local directories recurse by default
|
|
173
|
-
- directory ingest respects `.gitignore` unless you pass `--no-gitignore`
|
|
179
|
+
- directory ingest respects `.gitignore` and `.swarmvaultignore` unless you pass `--no-gitignore` or `--no-swarmvaultignore`
|
|
174
180
|
- repo-aware directory ingest records `repoRelativePath` and later compile writes `state/code-index.json`
|
|
175
181
|
- use `source add` instead when the same local directory, public GitHub repo root, or docs hub should stay registered and reloadable
|
|
176
182
|
- URL ingest still localizes remote image references by default
|
|
177
183
|
- YouTube URLs short-circuit to direct transcript capture instead of generic HTML fetch
|
|
178
|
-
-
|
|
184
|
+
- public video URLs passed with `--video` use `yt-dlp` for audio extraction before provider-backed transcription
|
|
185
|
+
- local file and archive ingest supports markdown, text, reStructuredText, HTML, PDF, Word, RTF, OpenDocument, EPUB, CSV/TSV, Excel, PowerPoint, Jupyter notebooks, BibTeX, Org-mode, AsciiDoc, transcripts, Slack exports, email, calendar, audio, video, structured config/data, developer manifests, images, and code
|
|
179
186
|
- add `--guide` when you want a resumable source session, source brief, source review, source guide, and approval-bundled canonical page edits when `profile.guidedSessionMode` is `canonical_review`, with `wiki/insights/` fallback for `insights_only`
|
|
180
187
|
- set `profile.guidedIngestDefault: true` when guided mode should be the default for `ingest`, and use `--no-guide` to force a plain ingest for one run
|
|
181
|
-
- code-aware directory ingest currently covers JavaScript, JSX, TypeScript, TSX, Bash/shell scripts, Python, Go, Rust, Java, Kotlin, Scala, Dart, Lua, Zig, C#, C, C++, PHP, Ruby, PowerShell, Elixir, OCaml, Objective-C, ReScript, Solidity, HTML, CSS,
|
|
188
|
+
- code-aware directory ingest currently covers JavaScript, JSX, TypeScript, TSX, Bash/shell scripts, Python, Go, Rust, Java, Kotlin, Scala, Dart, Lua, Zig, C#, C, C++, PHP, Ruby, PowerShell, Elixir, OCaml, Objective-C, ReScript, Solidity, HTML, CSS, Vue single-file components, and SQL files with table/view graph relations
|
|
182
189
|
|
|
183
190
|
Useful flags:
|
|
184
191
|
|
|
@@ -192,6 +199,8 @@ Useful flags:
|
|
|
192
199
|
- `--include-resources`
|
|
193
200
|
- `--include-generated`
|
|
194
201
|
- `--no-gitignore`
|
|
202
|
+
- `--no-swarmvaultignore`
|
|
203
|
+
- `--video`
|
|
195
204
|
- `--no-include-assets`
|
|
196
205
|
- `--max-asset-size <bytes>`
|
|
197
206
|
- `--commit`
|
|
@@ -200,7 +209,7 @@ Repo ingest defaults to `first_party` material. The extra `--include-*` flags op
|
|
|
200
209
|
|
|
201
210
|
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.
|
|
202
211
|
|
|
203
|
-
Audio files use `tasks.audioProvider` when you configure a provider with `audio` capability. When no
|
|
212
|
+
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.
|
|
204
213
|
|
|
205
214
|
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.
|
|
206
215
|
|
|
@@ -214,6 +223,7 @@ Capture supported URLs through a normalized markdown layer before ingesting them
|
|
|
214
223
|
- X/Twitter URLs use a graceful public capture path
|
|
215
224
|
- unsupported URLs fall back to generic URL ingest instead of failing
|
|
216
225
|
- optional metadata: `--author <name>` and `--contributor <name>`
|
|
226
|
+
- `--video` treats the URL as a public video and routes extracted audio through `tasks.audioProvider`
|
|
217
227
|
- normalized captures record fields such as `source_type`, `source_url`, `canonical_url`, `title`, `authors`, `published_at`, `updated_at`, `doi`, and `tags` when available
|
|
218
228
|
- use `source add` instead when the URL is a public GitHub repo root or a docs hub that should stay synced over time
|
|
219
229
|
|
|
@@ -372,6 +382,37 @@ When `--repo` sees only code-file changes under tracked repo roots, SwarmVault t
|
|
|
372
382
|
|
|
373
383
|
Show watched repo roots, the latest watch run, and any pending semantic refresh entries for tracked non-code repo changes.
|
|
374
384
|
|
|
385
|
+
### `swarmvault graph update [path]`
|
|
386
|
+
|
|
387
|
+
Refresh code-derived graph artifacts from tracked repo roots or one explicit repo path.
|
|
388
|
+
|
|
389
|
+
- aliases to `swarmvault graph refresh [path]`
|
|
390
|
+
- runs the same code-only repo refresh path as `swarmvault watch --repo --code-only --once`
|
|
391
|
+
- without `path`, uses configured or auto-discovered watched repo roots
|
|
392
|
+
- with `path`, refreshes that repo root instead of the tracked set
|
|
393
|
+
- `--json` returns the same one-shot watch result shape, including repo import/update/remove counts and pending semantic refresh entries
|
|
394
|
+
|
|
395
|
+
### `swarmvault graph status [path]`
|
|
396
|
+
|
|
397
|
+
Read-only graph freshness check for tracked repo roots or one explicit repo path.
|
|
398
|
+
|
|
399
|
+
- reports graph and graph-report presence
|
|
400
|
+
- lists tracked repo roots and changed files without writing watch status
|
|
401
|
+
- separates code-only changes from semantic refresh changes
|
|
402
|
+
- recommends `swarmvault graph update` for code-only graph drift
|
|
403
|
+
- recommends `swarmvault compile` when graph/report artifacts are missing, non-code files changed, or a semantic refresh is pending
|
|
404
|
+
- supports global `--json` for automation
|
|
405
|
+
|
|
406
|
+
### `swarmvault graph cluster [--resolution <n>]`
|
|
407
|
+
|
|
408
|
+
Recompute communities, node degrees, bridge scores, god-node flags, and graph report artifacts from the existing `state/graph.json` without re-ingesting or re-analyzing sources.
|
|
409
|
+
|
|
410
|
+
- writes refreshed graph metrics back to `state/graph.json`
|
|
411
|
+
- updates `wiki/graph/report.md`, `wiki/graph/report.json`, share artifacts, and per-community graph pages
|
|
412
|
+
- uses `graph.communityResolution` by default, or `--resolution <n>` for a one-off override
|
|
413
|
+
- splits oversized or low-cohesion communities after the initial Louvain pass so large-repo reports stay scannable
|
|
414
|
+
- `--json` returns counts plus the graph/report paths
|
|
415
|
+
|
|
375
416
|
### `swarmvault hook install|uninstall|status`
|
|
376
417
|
|
|
377
418
|
Manage SwarmVault's local git hook blocks for the nearest git repository.
|
|
@@ -414,8 +455,18 @@ Run SwarmVault as a local MCP server over stdio. This exposes the vault to compa
|
|
|
414
455
|
- `rebuild_retrieval`
|
|
415
456
|
- `doctor_retrieval`
|
|
416
457
|
- `doctor_vault`
|
|
417
|
-
|
|
418
|
-
|
|
458
|
+
- `query_graph`
|
|
459
|
+
- `graph_report`
|
|
460
|
+
- `graph_stats`
|
|
461
|
+
- `cluster_graph`
|
|
462
|
+
- `get_node`
|
|
463
|
+
- `get_community`
|
|
464
|
+
- `get_neighbors`
|
|
465
|
+
- `get_hyperedges`
|
|
466
|
+
- `shortest_path`
|
|
467
|
+
- `god_nodes`
|
|
468
|
+
|
|
469
|
+
`compile_vault` also accepts `maxTokens` for bounded wiki output, `graph_stats` returns lightweight graph counts, `cluster_graph` mirrors `swarmvault graph cluster`, `get_community` resolves community members and pages, `blast_radius` traces reverse import impact for a file or module target, `build_context_pack` creates the same bounded agent evidence bundles as `swarmvault context build`, the task tools mirror `swarmvault task`, the memory tools mirror the compatibility command group, `doctor_vault` mirrors `swarmvault doctor`, and retrieval tools inspect or repair the local index.
|
|
419
470
|
|
|
420
471
|
The MCP surface also exposes `swarmvault://schema`, `swarmvault://sessions`, `swarmvault://sessions/{path}`, `swarmvault://context-packs`, `swarmvault://tasks`, `swarmvault://memory-tasks`, and includes `schemaPath` in `workspace_info`.
|
|
421
472
|
|
|
@@ -503,13 +554,14 @@ Defaults:
|
|
|
503
554
|
- namespaces every remote record by `vaultId` so multiple vaults can safely share one Neo4j database
|
|
504
555
|
- upserts current graph records and does not prune stale remote data yet
|
|
505
556
|
|
|
506
|
-
### `swarmvault install --agent <
|
|
557
|
+
### `swarmvault install --agent <agent>`
|
|
507
558
|
|
|
508
559
|
Install agent-specific rules into the current project so an agent understands the SwarmVault workspace contract and workflow.
|
|
509
560
|
|
|
510
561
|
Hook-capable installs:
|
|
511
562
|
|
|
512
563
|
```bash
|
|
564
|
+
swarmvault install --agent codex --hook
|
|
513
565
|
swarmvault install --agent claude --hook
|
|
514
566
|
swarmvault install --agent gemini --hook
|
|
515
567
|
swarmvault install --agent opencode --hook
|
|
@@ -527,9 +579,14 @@ Agent target mapping:
|
|
|
527
579
|
- `trae` writes `.trae/rules/swarmvault.md`
|
|
528
580
|
- `claw` writes `.claw/skills/swarmvault/SKILL.md`
|
|
529
581
|
- `droid` writes `.factory/rules/swarmvault.md`
|
|
582
|
+
- `kiro` writes `.kiro/skills/swarmvault/SKILL.md` and `.kiro/steering/swarmvault.md`
|
|
583
|
+
- `hermes` writes `~/.hermes/skills/swarmvault/SKILL.md` plus `AGENTS.md`
|
|
584
|
+
- `antigravity` writes `.agents/rules/swarmvault.md` and `.agents/workflows/swarmvault.md`, and removes older fully managed `.agent/` files during reinstall
|
|
585
|
+
- `vscode` writes `.github/chatmodes/swarmvault.chatmode.md` plus `.github/copilot-instructions.md`
|
|
530
586
|
|
|
531
587
|
Hook semantics:
|
|
532
588
|
|
|
589
|
+
- `codex --hook` writes `.codex/hooks.json` plus `.codex/hooks/swarmvault-graph-first.js` and emits model-visible guidance before broad shell search
|
|
533
590
|
- `claude --hook` writes `.claude/settings.json` plus `.claude/hooks/swarmvault-graph-first.js` and adds model-visible advisory context through structured hook JSON
|
|
534
591
|
- `gemini --hook` writes `.gemini/settings.json` plus `.gemini/hooks/swarmvault-graph-first.js` and stays advisory/model-visible
|
|
535
592
|
- `opencode --hook` writes `.opencode/plugins/swarmvault-graph-first.js` and stays advisory/log-only
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
exportObsidianVault,
|
|
35
35
|
finishMemoryTask,
|
|
36
36
|
getGitHookStatus,
|
|
37
|
+
getGraphStatus,
|
|
37
38
|
getRetrievalStatus,
|
|
38
39
|
getWatchStatus,
|
|
39
40
|
graphDiff,
|
|
@@ -67,6 +68,7 @@ import {
|
|
|
67
68
|
readGraphReport,
|
|
68
69
|
readMemoryTask,
|
|
69
70
|
rebuildRetrievalIndex,
|
|
71
|
+
refreshGraphClusters,
|
|
70
72
|
registerLocalWhisperProvider,
|
|
71
73
|
rejectApproval,
|
|
72
74
|
reloadManagedSources,
|
|
@@ -309,9 +311,9 @@ program.name("swarmvault").description("SwarmVault is a local-first knowledge co
|
|
|
309
311
|
function readCliVersion() {
|
|
310
312
|
try {
|
|
311
313
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
312
|
-
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.
|
|
314
|
+
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.6.0";
|
|
313
315
|
} catch {
|
|
314
|
-
return "3.
|
|
316
|
+
return "3.6.0";
|
|
315
317
|
}
|
|
316
318
|
}
|
|
317
319
|
function parsePositiveInt(value, fallback) {
|
|
@@ -319,6 +321,11 @@ function parsePositiveInt(value, fallback) {
|
|
|
319
321
|
const parsed = Number.parseInt(value, 10);
|
|
320
322
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
321
323
|
}
|
|
324
|
+
function parsePositiveNumber(value) {
|
|
325
|
+
if (value === void 0) return void 0;
|
|
326
|
+
const parsed = Number.parseFloat(value);
|
|
327
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
328
|
+
}
|
|
322
329
|
function collectRepeated(value, previous) {
|
|
323
330
|
return [...previous, value];
|
|
324
331
|
}
|
|
@@ -506,7 +513,7 @@ program.command("init").description("Initialize a SwarmVault workspace in the cu
|
|
|
506
513
|
log(options.lite ? "Initialized SwarmVault lite workspace." : "Initialized SwarmVault workspace.");
|
|
507
514
|
}
|
|
508
515
|
});
|
|
509
|
-
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("--resume <run-id>", "Re-run only the failed files from a prior ingest run id").option("--commit", "Auto-commit wiki and state changes after ingest").option("--no-redact", "Skip PII/secret redaction for this run (overrides config)").action(
|
|
516
|
+
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("--no-swarmvaultignore", "Ignore .swarmvaultignore rules when ingesting a directory").option("--video", "Treat a URL input as a public video and transcribe extracted audio", false).option("--resume <run-id>", "Re-run only the failed files from a prior ingest run id").option("--commit", "Auto-commit wiki and state changes after ingest").option("--no-redact", "Skip PII/secret redaction for this run (overrides config)").action(
|
|
510
517
|
async (input, options) => {
|
|
511
518
|
const guideAnswers = readGuideAnswersFile(options.answersFile);
|
|
512
519
|
const vaultConfig = await loadVaultConfig(process2.cwd()).catch(() => null);
|
|
@@ -527,6 +534,8 @@ program.command("ingest").description("Ingest a local file path, directory path,
|
|
|
527
534
|
exclude: options.exclude,
|
|
528
535
|
maxFiles,
|
|
529
536
|
gitignore: options.gitignore,
|
|
537
|
+
swarmvaultignore: options.swarmvaultignore,
|
|
538
|
+
video: options.video,
|
|
530
539
|
extractClasses,
|
|
531
540
|
resume: options.resume,
|
|
532
541
|
redact: options.redact
|
|
@@ -643,10 +652,11 @@ program.command("ingest").description("Ingest a local file path, directory path,
|
|
|
643
652
|
}
|
|
644
653
|
}
|
|
645
654
|
);
|
|
646
|
-
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").option("--no-redact", "Skip PII/secret redaction for this capture (overrides config)").action(async (input, options) => {
|
|
655
|
+
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").option("--video", "Treat the URL as a public video and transcribe extracted audio", false).option("--no-redact", "Skip PII/secret redaction for this capture (overrides config)").action(async (input, options) => {
|
|
647
656
|
const result = await addInput(process2.cwd(), input, {
|
|
648
657
|
author: options.author,
|
|
649
658
|
contributor: options.contributor,
|
|
659
|
+
video: options.video,
|
|
650
660
|
redact: options.redact
|
|
651
661
|
});
|
|
652
662
|
if (isJson()) {
|
|
@@ -1134,6 +1144,62 @@ program.command("lint").description("Run anti-drift and wiki-health checks.").op
|
|
|
1134
1144
|
});
|
|
1135
1145
|
var graph = program.command("graph").description("Graph-related commands.").enablePositionalOptions();
|
|
1136
1146
|
var graphPush = graph.command("push").description("Push the compiled graph into external sinks.");
|
|
1147
|
+
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).action(async (targetPath, options) => {
|
|
1148
|
+
const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
|
|
1149
|
+
const result = await runWatchCycle(process2.cwd(), {
|
|
1150
|
+
repo: true,
|
|
1151
|
+
codeOnly: true,
|
|
1152
|
+
lint: options.lint ?? false,
|
|
1153
|
+
overrideRoots
|
|
1154
|
+
});
|
|
1155
|
+
if (isJson()) {
|
|
1156
|
+
emitJson(result);
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
log(
|
|
1160
|
+
`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}.`
|
|
1161
|
+
);
|
|
1162
|
+
});
|
|
1163
|
+
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(async (targetPath) => {
|
|
1164
|
+
const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
|
|
1165
|
+
const status = await getGraphStatus(process2.cwd(), { repoRoots: overrideRoots });
|
|
1166
|
+
if (isJson()) {
|
|
1167
|
+
emitJson(status);
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
log(`Graph: ${status.graphExists ? status.graphPath : `missing (${status.graphPath})`}`);
|
|
1171
|
+
log(`Report: ${status.reportExists ? status.reportPath : `missing (${status.reportPath})`}`);
|
|
1172
|
+
log(`Tracked repo roots: ${status.trackedRepoRoots.length ? status.trackedRepoRoots.join(", ") : "none"}`);
|
|
1173
|
+
log(`Code changes: ${status.codeChangeCount}`);
|
|
1174
|
+
log(`Semantic changes: ${status.semanticChangeCount}`);
|
|
1175
|
+
log(`Pending semantic refresh: ${status.pendingSemanticRefresh.length}`);
|
|
1176
|
+
if (status.changes.length) {
|
|
1177
|
+
for (const change of status.changes.slice(0, 20)) {
|
|
1178
|
+
log(`- ${change.refreshType} ${change.changeType} ${change.path}`);
|
|
1179
|
+
}
|
|
1180
|
+
if (status.changes.length > 20) {
|
|
1181
|
+
log(`... and ${status.changes.length - 20} more`);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
log(`State: ${status.stale ? "stale" : "fresh"}`);
|
|
1185
|
+
if (status.recommendedCommand) {
|
|
1186
|
+
log(`Recommended: ${status.recommendedCommand}`);
|
|
1187
|
+
}
|
|
1188
|
+
});
|
|
1189
|
+
graph.command("cluster").alias("clusters").description("Recompute graph communities, degrees, god-node flags, and graph report artifacts without re-ingesting sources.").option("--resolution <number>", "Override the Louvain community resolution for this run").action(async (options) => {
|
|
1190
|
+
const resolution = parsePositiveNumber(options.resolution);
|
|
1191
|
+
if (options.resolution && resolution === void 0) {
|
|
1192
|
+
throw new Error("--resolution must be a positive number.");
|
|
1193
|
+
}
|
|
1194
|
+
const result = await refreshGraphClusters(process2.cwd(), { resolution });
|
|
1195
|
+
if (isJson()) {
|
|
1196
|
+
emitJson(result);
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
log(
|
|
1200
|
+
`Refreshed ${result.communityCount} communities across ${result.nodeCount} nodes and ${result.edgeCount} edges. Report: ${result.reportPath}`
|
|
1201
|
+
);
|
|
1202
|
+
});
|
|
1137
1203
|
graphPush.command("neo4j").description("Push the compiled graph directly into Neo4j over Bolt/Aura.").option("--uri <bolt-uri>", "Neo4j Bolt or Aura URI").option("--username <user>", "Neo4j username").option("--password-env <env-var>", "Environment variable containing the Neo4j password").option("--database <name>", "Neo4j database name").option("--vault-id <id>", "Stable vault identifier used for shared-database namespacing").option("--batch-size <n>", "Maximum rows to write per Neo4j transaction batch").option("--include-third-party", "Also push third-party repo material", false).option("--include-resources", "Also push resource-like content", false).option("--include-generated", "Also push generated output", false).option("--dry-run", "Show what would be pushed without writing to Neo4j", false).action(
|
|
1138
1204
|
async (options) => {
|
|
1139
1205
|
const batchSize = typeof options.batchSize === "string" && options.batchSize.trim() ? parsePositiveInt(options.batchSize, 0) || void 0 : void 0;
|
|
@@ -1717,9 +1783,9 @@ program.command("install").description("Install SwarmVault instructions for an a
|
|
|
1717
1783
|
"claude, codex, cursor, gemini, goose, opencode, copilot, aider, droid, pi, trae, claw, kiro, hermes, antigravity, vscode, amp, augment, adal, bob, cline, codebuddy, command-code, continue, cortex, crush, deepagents, 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"
|
|
1718
1784
|
).option("--hook", "Also install hook/plugin guidance when the target agent supports it", false).action(
|
|
1719
1785
|
async (options) => {
|
|
1720
|
-
const hookCapableAgents = /* @__PURE__ */ new Set(["claude", "opencode", "gemini", "copilot"]);
|
|
1786
|
+
const hookCapableAgents = /* @__PURE__ */ new Set(["codex", "claude", "opencode", "gemini", "copilot"]);
|
|
1721
1787
|
if (options.hook && !hookCapableAgents.has(options.agent)) {
|
|
1722
|
-
throw new Error("--hook is only supported for --agent claude, opencode, gemini, or copilot");
|
|
1788
|
+
throw new Error("--hook is only supported for --agent codex, claude, opencode, gemini, or copilot");
|
|
1723
1789
|
}
|
|
1724
1790
|
const result = await installAgent(process2.cwd(), options.agent, { hook: options.hook ?? false });
|
|
1725
1791
|
if (isJson()) {
|
|
@@ -2098,9 +2164,10 @@ program.command("scan").description("Quick-start: initialize, ingest, compile, a
|
|
|
2098
2164
|
log(`Ingested ${result.imported.length} file(s).`);
|
|
2099
2165
|
}
|
|
2100
2166
|
const compiled = await compileVault(rootDir, {});
|
|
2101
|
-
const
|
|
2102
|
-
const
|
|
2103
|
-
const
|
|
2167
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
2168
|
+
const shareCardPath = path2.join(paths.wikiDir, "graph", "share-card.md");
|
|
2169
|
+
const shareCardSvgPath = path2.join(paths.wikiDir, "graph", "share-card.svg");
|
|
2170
|
+
const shareKitPath = path2.join(paths.wikiDir, "graph", "share-kit");
|
|
2104
2171
|
if (!isJson()) {
|
|
2105
2172
|
log(`Compiled ${compiled.sourceCount} source(s), ${compiled.pageCount} page(s).`);
|
|
2106
2173
|
log(`Share card: ${shareCardPath}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmvaultai/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.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.
|
|
47
|
+
"@swarmvaultai/engine": "3.6.0",
|
|
48
48
|
"commander": "^14.0.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|