@swarmvaultai/cli 0.8.0 → 0.10.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/dist/index.js +93 -30
- package/package.json +9 -8
- package/LICENSE +0 -21
package/dist/index.js
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
benchmarkVault,
|
|
15
15
|
blastRadiusVault,
|
|
16
16
|
compileVault,
|
|
17
|
+
consolidateVault,
|
|
18
|
+
createSupersessionEdge,
|
|
17
19
|
deleteManagedSource,
|
|
18
20
|
explainGraphVault,
|
|
19
21
|
exploreVault,
|
|
@@ -278,9 +280,9 @@ program.name("swarmvault").description("SwarmVault is a local-first knowledge co
|
|
|
278
280
|
function readCliVersion() {
|
|
279
281
|
try {
|
|
280
282
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
281
|
-
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.
|
|
283
|
+
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.10.0";
|
|
282
284
|
} catch {
|
|
283
|
-
return "0.
|
|
285
|
+
return "0.10.0";
|
|
284
286
|
}
|
|
285
287
|
}
|
|
286
288
|
function parsePositiveInt(value, fallback) {
|
|
@@ -306,6 +308,18 @@ function slugForCli(value) {
|
|
|
306
308
|
function isJson() {
|
|
307
309
|
return activeCommand?.opts().json === true || program.opts().json === true;
|
|
308
310
|
}
|
|
311
|
+
function summarizeRedactions(redactions) {
|
|
312
|
+
if (!redactions || redactions.length === 0) {
|
|
313
|
+
return void 0;
|
|
314
|
+
}
|
|
315
|
+
const totalMatches = redactions.reduce((total, entry) => total + entry.matches.reduce((sum, match) => sum + match.count, 0), 0);
|
|
316
|
+
if (totalMatches === 0) {
|
|
317
|
+
return void 0;
|
|
318
|
+
}
|
|
319
|
+
const secretsLabel = totalMatches === 1 ? "secret" : "secrets";
|
|
320
|
+
const sourceLabel = redactions.length === 1 ? "source" : "sources";
|
|
321
|
+
return `Redacted ${totalMatches} ${secretsLabel} across ${redactions.length} ${sourceLabel} (run --no-redact to disable).`;
|
|
322
|
+
}
|
|
309
323
|
function emitJson(data) {
|
|
310
324
|
process2.stdout.write(`${JSON.stringify(data)}
|
|
311
325
|
`);
|
|
@@ -424,20 +438,29 @@ program.hook("postAction", async (_thisCommand, actionCommand) => {
|
|
|
424
438
|
program.command("init").description("Initialize a SwarmVault workspace in the current directory.").option("--obsidian", "Generate a minimal .obsidian workspace alongside the vault", false).option(
|
|
425
439
|
"--profile <profile>",
|
|
426
440
|
"Starter workspace profile or comma-separated preset list (for example: personal-research or reader,timeline)"
|
|
441
|
+
).option(
|
|
442
|
+
"--lite",
|
|
443
|
+
"Minimal LLM-Wiki starter (raw/, wiki/, wiki/index.md, wiki/log.md, swarmvault.schema.md) without config, state, or agent installs",
|
|
444
|
+
false
|
|
427
445
|
).action(async (options) => {
|
|
428
|
-
await initVault(process2.cwd(), {
|
|
446
|
+
await initVault(process2.cwd(), {
|
|
447
|
+
obsidian: options.obsidian ?? false,
|
|
448
|
+
profile: options.profile,
|
|
449
|
+
lite: options.lite ?? false
|
|
450
|
+
});
|
|
429
451
|
if (isJson()) {
|
|
430
452
|
emitJson({
|
|
431
453
|
status: "initialized",
|
|
432
454
|
rootDir: process2.cwd(),
|
|
433
455
|
obsidian: options.obsidian ?? false,
|
|
434
|
-
profile: options.profile ?? "default"
|
|
456
|
+
profile: options.profile ?? "default",
|
|
457
|
+
lite: options.lite ?? false
|
|
435
458
|
});
|
|
436
459
|
} else {
|
|
437
|
-
log("Initialized SwarmVault workspace.");
|
|
460
|
+
log(options.lite ? "Initialized SwarmVault lite workspace." : "Initialized SwarmVault workspace.");
|
|
438
461
|
}
|
|
439
462
|
});
|
|
440
|
-
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").action(
|
|
463
|
+
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(
|
|
441
464
|
async (input, options) => {
|
|
442
465
|
const guideAnswers = readGuideAnswersFile(options.answersFile);
|
|
443
466
|
const vaultConfig = await loadVaultConfig(process2.cwd()).catch(() => null);
|
|
@@ -459,7 +482,8 @@ program.command("ingest").description("Ingest a local file path, directory path,
|
|
|
459
482
|
maxFiles,
|
|
460
483
|
gitignore: options.gitignore,
|
|
461
484
|
extractClasses,
|
|
462
|
-
resume: options.resume
|
|
485
|
+
resume: options.resume,
|
|
486
|
+
redact: options.redact
|
|
463
487
|
};
|
|
464
488
|
const directoryResult = !/^https?:\/\//i.test(input) ? await import("fs/promises").then(
|
|
465
489
|
(fs) => fs.stat(input).then((stat) => stat.isDirectory() ? ingestDirectory(process2.cwd(), input, commonOptions) : null).catch(() => null)
|
|
@@ -519,6 +543,10 @@ program.command("ingest").description("Ingest a local file path, directory path,
|
|
|
519
543
|
} else if (completedGuide2?.guidePath) {
|
|
520
544
|
log(`Staged guided session at ${completedGuide2.guidePath}.`);
|
|
521
545
|
}
|
|
546
|
+
const redactionLine = summarizeRedactions(directoryResult.redactions);
|
|
547
|
+
if (redactionLine) {
|
|
548
|
+
log(redactionLine);
|
|
549
|
+
}
|
|
522
550
|
}
|
|
523
551
|
if (options.commit) {
|
|
524
552
|
const msg = await autoCommitWikiChanges(process2.cwd(), "ingest", input, { force: true });
|
|
@@ -558,6 +586,10 @@ program.command("ingest").description("Ingest a local file path, directory path,
|
|
|
558
586
|
} else if (completedGuide?.guidePath) {
|
|
559
587
|
log(`Staged guided session at ${completedGuide.guidePath}.`);
|
|
560
588
|
}
|
|
589
|
+
const redactionLine = summarizeRedactions(ingest.redactions);
|
|
590
|
+
if (redactionLine) {
|
|
591
|
+
log(redactionLine);
|
|
592
|
+
}
|
|
561
593
|
}
|
|
562
594
|
if (options.commit) {
|
|
563
595
|
const msg = await autoCommitWikiChanges(process2.cwd(), "ingest", input, { force: true });
|
|
@@ -565,10 +597,11 @@ program.command("ingest").description("Ingest a local file path, directory path,
|
|
|
565
597
|
}
|
|
566
598
|
}
|
|
567
599
|
);
|
|
568
|
-
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) => {
|
|
600
|
+
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) => {
|
|
569
601
|
const result = await addInput(process2.cwd(), input, {
|
|
570
602
|
author: options.author,
|
|
571
|
-
contributor: options.contributor
|
|
603
|
+
contributor: options.contributor,
|
|
604
|
+
redact: options.redact
|
|
572
605
|
});
|
|
573
606
|
if (isJson()) {
|
|
574
607
|
emitJson(result);
|
|
@@ -725,14 +758,28 @@ program.command("compile").description("Compile manifests into wiki pages, graph
|
|
|
725
758
|
}
|
|
726
759
|
await maybeEmitHeuristicNotice(["compile"]);
|
|
727
760
|
});
|
|
728
|
-
program.command("
|
|
761
|
+
program.command("consolidate").description("Roll working-tier insights up into episodic, semantic, and procedural tiers.").option("--dry-run", "Return decisions without writing any files", false).action(async (options) => {
|
|
762
|
+
const result = await consolidateVault(process2.cwd(), { dryRun: options.dryRun ?? false });
|
|
763
|
+
if (isJson()) {
|
|
764
|
+
emitJson(result);
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
log(
|
|
768
|
+
`${options.dryRun ? "Would consolidate" : "Consolidated"} ${result.newPages.length} new tier page(s); ${result.promoted.length} promotion(s).`
|
|
769
|
+
);
|
|
770
|
+
for (const decision of result.decisions) {
|
|
771
|
+
log(decision);
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
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").option("--gap-fill", "Pull external web-search evidence when the local wiki has gaps (requires webSearch.tasks.queryProvider).").addOption(
|
|
729
775
|
new Option("--format <format>", "Output format").choices(["markdown", "report", "slides", "chart", "image"]).default("markdown")
|
|
730
776
|
).action(
|
|
731
777
|
async (question, options) => {
|
|
732
778
|
const result = await queryVault(process2.cwd(), {
|
|
733
779
|
question,
|
|
734
780
|
save: options.save ?? true,
|
|
735
|
-
format: options.format
|
|
781
|
+
format: options.format,
|
|
782
|
+
gapFill: options.gapFill ?? false
|
|
736
783
|
});
|
|
737
784
|
if (isJson()) {
|
|
738
785
|
emitJson(result);
|
|
@@ -749,23 +796,26 @@ program.command("query").description("Query the compiled SwarmVault wiki.").argu
|
|
|
749
796
|
await maybeEmitHeuristicNotice(["query"]);
|
|
750
797
|
}
|
|
751
798
|
);
|
|
752
|
-
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(
|
|
799
|
+
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").option("--gap-fill", "Pull external web-search evidence when the local wiki has gaps (requires webSearch.tasks.exploreProvider).").addOption(
|
|
753
800
|
new Option("--format <format>", "Output format for step pages").choices(["markdown", "report", "slides", "chart", "image"]).default("markdown")
|
|
754
|
-
).action(
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
801
|
+
).action(
|
|
802
|
+
async (question, options) => {
|
|
803
|
+
const stepCount = parsePositiveInt(options.steps, 3);
|
|
804
|
+
const result = await exploreVault(process2.cwd(), {
|
|
805
|
+
question,
|
|
806
|
+
steps: stepCount,
|
|
807
|
+
format: options.format,
|
|
808
|
+
gapFill: options.gapFill ?? false
|
|
809
|
+
});
|
|
810
|
+
if (isJson()) {
|
|
811
|
+
emitJson(result);
|
|
812
|
+
} else {
|
|
813
|
+
log(`Exploration hub saved to ${result.hubPath}`);
|
|
814
|
+
log(`Completed ${result.stepCount} step(s).`);
|
|
815
|
+
}
|
|
816
|
+
await maybeEmitHeuristicNotice(["explore"]);
|
|
766
817
|
}
|
|
767
|
-
|
|
768
|
-
});
|
|
818
|
+
);
|
|
769
819
|
program.command("benchmark").description("Measure graph-guided context reduction against a naive full-corpus read.").option("--question <text...>", "Optional custom benchmark question(s)").action(async (options) => {
|
|
770
820
|
const result = await benchmarkVault(process2.cwd(), {
|
|
771
821
|
questions: options.question
|
|
@@ -784,13 +834,15 @@ program.command("benchmark").description("Measure graph-guided context reduction
|
|
|
784
834
|
}
|
|
785
835
|
}
|
|
786
836
|
});
|
|
787
|
-
program.command("lint").description("Run anti-drift and wiki-health checks.").option("--deep", "Run LLM-powered advisory lint (default: from config)").option("--no-deep", "Skip deep lint even if enabled in config").option("--web", "Augment deep lint with configured web search", false).option("--conflicts", "Filter to contradiction findings only", false).action(async (options) => {
|
|
837
|
+
program.command("lint").description("Run anti-drift and wiki-health checks.").option("--deep", "Run LLM-powered advisory lint (default: from config)").option("--no-deep", "Skip deep lint even if enabled in config").option("--web", "Augment deep lint with configured web search", false).option("--conflicts", "Filter to contradiction findings only", false).option("--decay", "Filter to decay-related findings only", false).option("--tiers", "Filter to consolidation-tier findings only", false).action(async (options) => {
|
|
788
838
|
const lintConfig = await loadVaultConfig(process2.cwd()).catch(() => null);
|
|
789
|
-
const deepEnabled = options.deep ?? lintConfig?.config.profile.deepLintDefault ?? false;
|
|
839
|
+
const deepEnabled = options.decay || options.tiers ? false : options.deep ?? lintConfig?.config.profile.deepLintDefault ?? false;
|
|
790
840
|
const findings = await lintVault(process2.cwd(), {
|
|
791
841
|
deep: deepEnabled,
|
|
792
842
|
web: options.web ?? false,
|
|
793
|
-
conflicts: options.conflicts ?? false
|
|
843
|
+
conflicts: options.conflicts ?? false,
|
|
844
|
+
decay: options.decay ?? false,
|
|
845
|
+
tiers: options.tiers ?? false
|
|
794
846
|
});
|
|
795
847
|
if (isJson()) {
|
|
796
848
|
emitJson(findings);
|
|
@@ -960,6 +1012,14 @@ graph.command("blast").description("Show the blast radius of changing a file or
|
|
|
960
1012
|
log(` ${" ".repeat(mod.depth - 1)}${mod.label} (depth ${mod.depth})`);
|
|
961
1013
|
}
|
|
962
1014
|
});
|
|
1015
|
+
graph.command("supersession").description("Record that one page has been replaced by another (writes a superseded_by edge).").argument("<pageId>", "Page id or path of the older page").argument("<replacedById>", "Page id or path of the replacement page").action(async (pageId, replacedById) => {
|
|
1016
|
+
const result = await createSupersessionEdge(process2.cwd(), pageId, replacedById);
|
|
1017
|
+
if (isJson()) {
|
|
1018
|
+
emitJson(result);
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
log(`Superseded ${result.oldPageId} by ${result.newPageId} (edge ${result.edgeId}).`);
|
|
1022
|
+
});
|
|
963
1023
|
var review = program.command("review").description("Review staged compile approval bundles.");
|
|
964
1024
|
review.command("list").description("List staged approval bundles and their resolution status.").action(async () => {
|
|
965
1025
|
const approvals = await listApprovals(process2.cwd());
|
|
@@ -1214,7 +1274,10 @@ program.command("mcp").description("Run SwarmVault as a local MCP server over st
|
|
|
1214
1274
|
process2.exit(0);
|
|
1215
1275
|
});
|
|
1216
1276
|
});
|
|
1217
|
-
program.command("install").description("Install SwarmVault instructions for an agent in the current project.").requiredOption(
|
|
1277
|
+
program.command("install").description("Install SwarmVault instructions for an agent in the current project.").requiredOption(
|
|
1278
|
+
"--agent <agent>",
|
|
1279
|
+
"codex, claude, cursor, goose, pi, gemini, opencode, aider, copilot, trae, claw, droid, kiro, hermes, antigravity, or vscode"
|
|
1280
|
+
).option("--hook", "Also install hook/plugin guidance when the target agent supports it", false).action(
|
|
1218
1281
|
async (options) => {
|
|
1219
1282
|
const hookCapableAgents = /* @__PURE__ */ new Set(["claude", "opencode", "gemini", "copilot"]);
|
|
1220
1283
|
if (options.hook && !hookCapableAgents.has(options.agent)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmvaultai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
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.
|
|
47
|
+
"@swarmvaultai/engine": "0.10.0",
|
|
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.
|