@swarmvaultai/cli 0.1.17 → 0.1.19
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 +41 -5
- package/dist/index.js +79 -13
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -25,11 +25,14 @@ cd my-vault
|
|
|
25
25
|
swarmvault init --obsidian
|
|
26
26
|
sed -n '1,120p' swarmvault.schema.md
|
|
27
27
|
swarmvault ingest ./notes.md
|
|
28
|
+
swarmvault ingest ./repo
|
|
28
29
|
swarmvault compile
|
|
29
30
|
swarmvault query "What keeps recurring?"
|
|
30
31
|
swarmvault query "Turn this into slides" --format slides
|
|
31
32
|
swarmvault explore "What should I research next?" --steps 3
|
|
32
33
|
swarmvault lint --deep
|
|
34
|
+
swarmvault graph query "Which nodes bridge the biggest clusters?"
|
|
35
|
+
swarmvault graph explain "concept:drift"
|
|
33
36
|
swarmvault graph serve
|
|
34
37
|
swarmvault graph export --html ./exports/graph.html
|
|
35
38
|
```
|
|
@@ -55,7 +58,22 @@ The schema file is the vault-specific instruction layer. Edit it to define namin
|
|
|
55
58
|
|
|
56
59
|
### `swarmvault ingest <path-or-url>`
|
|
57
60
|
|
|
58
|
-
Ingest a local file path or URL into immutable source storage and write
|
|
61
|
+
Ingest a local file path, directory path, or URL into immutable source storage and write manifests to `state/manifests/`.
|
|
62
|
+
|
|
63
|
+
- local directories recurse by default
|
|
64
|
+
- directory ingest respects `.gitignore` unless you pass `--no-gitignore`
|
|
65
|
+
- repo-aware directory ingest records `repoRelativePath` and later compile writes `state/code-index.json`
|
|
66
|
+
- URL ingest still localizes remote image references by default
|
|
67
|
+
|
|
68
|
+
Useful flags:
|
|
69
|
+
|
|
70
|
+
- `--repo-root <path>`
|
|
71
|
+
- `--include <glob...>`
|
|
72
|
+
- `--exclude <glob...>`
|
|
73
|
+
- `--max-files <n>`
|
|
74
|
+
- `--no-gitignore`
|
|
75
|
+
- `--no-include-assets`
|
|
76
|
+
- `--max-asset-size <bytes>`
|
|
59
77
|
|
|
60
78
|
### `swarmvault inbox import [dir]`
|
|
61
79
|
|
|
@@ -71,6 +89,8 @@ Compile the current manifests into:
|
|
|
71
89
|
|
|
72
90
|
The compiler also reads `swarmvault.schema.md` and records a `schema_hash` plus lifecycle metadata such as `status`, `created_at`, `updated_at`, `compiled_from`, and `managed_by` in generated pages so schema edits can mark pages stale without losing lifecycle state.
|
|
73
91
|
|
|
92
|
+
For ingested code trees, compile also writes `state/code-index.json` so local imports and module aliases can resolve across the repo-aware code graph.
|
|
93
|
+
|
|
74
94
|
New concept and entity pages are staged into `wiki/candidates/` first. A later matching compile promotes them into `wiki/concepts/` or `wiki/entities/`.
|
|
75
95
|
|
|
76
96
|
With `--approve`, compile writes a staged review bundle into `state/approvals/` without applying active wiki changes.
|
|
@@ -96,7 +116,7 @@ Inspect and resolve staged concept and entity candidates.
|
|
|
96
116
|
|
|
97
117
|
Targets can be page ids or relative paths under `wiki/candidates/`.
|
|
98
118
|
|
|
99
|
-
### `swarmvault query "<question>" [--no-save] [--format markdown|report|slides]`
|
|
119
|
+
### `swarmvault query "<question>" [--no-save] [--format markdown|report|slides|chart|image]`
|
|
100
120
|
|
|
101
121
|
Query the compiled vault. The query layer also reads `swarmvault.schema.md`, so answers follow the vault’s own structure and grounding rules.
|
|
102
122
|
|
|
@@ -111,7 +131,7 @@ Saved outputs also carry related page, node, and source metadata so SwarmVault c
|
|
|
111
131
|
|
|
112
132
|
Human-authored pages in `wiki/insights/` are also indexed into search and query context, but SwarmVault does not rewrite them after initialization.
|
|
113
133
|
|
|
114
|
-
### `swarmvault explore "<question>" [--steps <n>]`
|
|
134
|
+
### `swarmvault explore "<question>" [--steps <n>] [--format markdown|report|slides|chart|image]`
|
|
115
135
|
|
|
116
136
|
Run a save-first multi-step research loop.
|
|
117
137
|
|
|
@@ -159,11 +179,27 @@ The MCP surface also exposes `swarmvault://schema`, `swarmvault://sessions`, `sw
|
|
|
159
179
|
|
|
160
180
|
### `swarmvault graph serve`
|
|
161
181
|
|
|
162
|
-
Start the local graph workspace backed by `state/graph.json`, `/api/search`,
|
|
182
|
+
Start the local graph workspace backed by `state/graph.json`, `/api/search`, `/api/page`, and local graph query/path/explain endpoints.
|
|
183
|
+
|
|
184
|
+
### `swarmvault graph query "<question>" [--dfs] [--budget <n>]`
|
|
185
|
+
|
|
186
|
+
Run a deterministic local graph traversal seeded from local search and graph labels.
|
|
187
|
+
|
|
188
|
+
### `swarmvault graph path <from> <to>`
|
|
189
|
+
|
|
190
|
+
Return the shortest high-confidence path between two graph targets.
|
|
191
|
+
|
|
192
|
+
### `swarmvault graph explain <target>`
|
|
193
|
+
|
|
194
|
+
Inspect graph metadata, community membership, neighbors, and provenance for a node or page.
|
|
195
|
+
|
|
196
|
+
### `swarmvault graph god-nodes [--limit <n>]`
|
|
197
|
+
|
|
198
|
+
List the most connected bridge-heavy nodes in the current graph.
|
|
163
199
|
|
|
164
200
|
### `swarmvault graph export --html <output>`
|
|
165
201
|
|
|
166
|
-
Export the graph workspace as a standalone HTML file with embedded graph and page data for offline sharing.
|
|
202
|
+
Export the graph workspace as a standalone HTML file with embedded graph and page data for offline sharing. The exported file keeps read-only graph browsing, search, and page preview. The live graph query/path/explain actions remain part of `graph serve` and the MCP surface.
|
|
167
203
|
|
|
168
204
|
### `swarmvault install --agent <codex|claude|cursor|goose|pi|gemini|opencode>`
|
|
169
205
|
|
package/dist/index.js
CHANGED
|
@@ -7,18 +7,23 @@ import {
|
|
|
7
7
|
acceptApproval,
|
|
8
8
|
archiveCandidate,
|
|
9
9
|
compileVault,
|
|
10
|
+
explainGraphVault,
|
|
10
11
|
exploreVault,
|
|
11
12
|
exportGraphHtml,
|
|
12
13
|
importInbox,
|
|
14
|
+
ingestDirectory,
|
|
13
15
|
ingestInput,
|
|
14
16
|
initVault,
|
|
15
17
|
installAgent,
|
|
16
18
|
lintVault,
|
|
17
19
|
listApprovals,
|
|
18
20
|
listCandidates,
|
|
21
|
+
listGodNodes,
|
|
19
22
|
listSchedules,
|
|
20
23
|
loadVaultConfig,
|
|
24
|
+
pathGraphVault,
|
|
21
25
|
promoteCandidate,
|
|
26
|
+
queryGraphVault,
|
|
22
27
|
queryVault,
|
|
23
28
|
readApproval,
|
|
24
29
|
rejectApproval,
|
|
@@ -35,9 +40,9 @@ program.name("swarmvault").description("SwarmVault is a local-first LLM wiki com
|
|
|
35
40
|
function readCliVersion() {
|
|
36
41
|
try {
|
|
37
42
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
38
|
-
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.1.
|
|
43
|
+
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "0.1.19";
|
|
39
44
|
} catch {
|
|
40
|
-
return "0.1.
|
|
45
|
+
return "0.1.19";
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
48
|
function isJson() {
|
|
@@ -64,18 +69,40 @@ program.command("init").description("Initialize a SwarmVault workspace in the cu
|
|
|
64
69
|
log("Initialized SwarmVault workspace.");
|
|
65
70
|
}
|
|
66
71
|
});
|
|
67
|
-
program.command("ingest").description("Ingest a local file path or URL into the raw SwarmVault workspace.").argument("<input>", "Local file path or URL").option("--include-assets", "Download remote image assets when ingesting URLs", true).option("--no-include-assets", "Skip downloading remote image assets when ingesting URLs").option("--max-asset-size <bytes>", "Maximum number of bytes to fetch for a single remote image asset").
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
program.command("ingest").description("Ingest a local file path, directory path, or URL into the raw SwarmVault workspace.").argument("<input>", "Local file path, directory path, or URL").option("--include-assets", "Download remote image assets when ingesting URLs", true).option("--no-include-assets", "Skip downloading remote image assets when ingesting URLs").option("--max-asset-size <bytes>", "Maximum number of bytes to fetch for a single remote image asset").option("--repo-root <path>", "Override the detected repo root when ingesting a directory").option("--include <glob...>", "Only ingest files matching one or more glob patterns").option("--exclude <glob...>", "Skip files matching one or more glob patterns").option("--max-files <n>", "Maximum number of files to ingest from a directory").option("--no-gitignore", "Ignore .gitignore rules when ingesting a directory").action(
|
|
73
|
+
async (input, options) => {
|
|
74
|
+
const maxAssetSize = typeof options.maxAssetSize === "string" && options.maxAssetSize.trim() ? Number.parseInt(options.maxAssetSize, 10) : void 0;
|
|
75
|
+
const maxFiles = typeof options.maxFiles === "string" && options.maxFiles.trim() ? Number.parseInt(options.maxFiles, 10) : void 0;
|
|
76
|
+
const commonOptions = {
|
|
77
|
+
includeAssets: options.includeAssets,
|
|
78
|
+
maxAssetSize: Number.isFinite(maxAssetSize) ? maxAssetSize : void 0,
|
|
79
|
+
repoRoot: options.repoRoot,
|
|
80
|
+
include: options.include,
|
|
81
|
+
exclude: options.exclude,
|
|
82
|
+
maxFiles: Number.isFinite(maxFiles) ? maxFiles : void 0,
|
|
83
|
+
gitignore: options.gitignore
|
|
84
|
+
};
|
|
85
|
+
const directoryResult = !/^https?:\/\//i.test(input) ? await import("fs/promises").then(
|
|
86
|
+
(fs) => fs.stat(input).then((stat) => stat.isDirectory() ? ingestDirectory(process.cwd(), input, commonOptions) : null).catch(() => null)
|
|
87
|
+
) : null;
|
|
88
|
+
if (directoryResult) {
|
|
89
|
+
if (isJson()) {
|
|
90
|
+
emitJson(directoryResult);
|
|
91
|
+
} else {
|
|
92
|
+
log(
|
|
93
|
+
`Imported ${directoryResult.imported.length} file(s), updated ${directoryResult.updated.length}, skipped ${directoryResult.skipped.length}.`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const manifest = await ingestInput(process.cwd(), input, commonOptions);
|
|
99
|
+
if (isJson()) {
|
|
100
|
+
emitJson(manifest);
|
|
101
|
+
} else {
|
|
102
|
+
log(manifest.sourceId);
|
|
103
|
+
}
|
|
77
104
|
}
|
|
78
|
-
|
|
105
|
+
);
|
|
79
106
|
var inbox = program.command("inbox").description("Inbox and capture workflows.");
|
|
80
107
|
inbox.command("import").description("Import supported files from the configured inbox directory.").argument("[dir]", "Optional inbox directory override").action(async (dir) => {
|
|
81
108
|
const result = await importInbox(process.cwd(), dir);
|
|
@@ -171,6 +198,45 @@ graph.command("export").description("Export the graph viewer as a single self-co
|
|
|
171
198
|
log(`Exported graph HTML to ${outputPath}`);
|
|
172
199
|
}
|
|
173
200
|
});
|
|
201
|
+
graph.command("query").description("Traverse the compiled graph deterministically from local search seeds.").argument("<question>", "Question or graph search seed").option("--dfs", "Prefer a depth-first traversal instead of breadth-first", false).option("--budget <n>", "Maximum number of graph nodes to summarize").action(async (question, options) => {
|
|
202
|
+
const budget = options.budget ? Number.parseInt(options.budget, 10) : void 0;
|
|
203
|
+
const result = await queryGraphVault(process.cwd(), question, {
|
|
204
|
+
traversal: options.dfs ? "dfs" : "bfs",
|
|
205
|
+
budget: Number.isFinite(budget) ? budget : void 0
|
|
206
|
+
});
|
|
207
|
+
if (isJson()) {
|
|
208
|
+
emitJson(result);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
log(result.summary);
|
|
212
|
+
});
|
|
213
|
+
graph.command("path").description("Find the shortest graph path between two nodes or pages.").argument("<from>", "Source node/page label or id").argument("<to>", "Target node/page label or id").action(async (from, to) => {
|
|
214
|
+
const result = await pathGraphVault(process.cwd(), from, to);
|
|
215
|
+
if (isJson()) {
|
|
216
|
+
emitJson(result);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
log(result.summary);
|
|
220
|
+
});
|
|
221
|
+
graph.command("explain").description("Explain a graph node, its page, community, and neighbors.").argument("<target>", "Node/page label or id").action(async (target) => {
|
|
222
|
+
const result = await explainGraphVault(process.cwd(), target);
|
|
223
|
+
if (isJson()) {
|
|
224
|
+
emitJson(result);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
log(result.summary);
|
|
228
|
+
});
|
|
229
|
+
graph.command("god-nodes").description("List the highest-connectivity non-source graph nodes.").option("--limit <n>", "Maximum number of nodes to return", "10").action(async (options) => {
|
|
230
|
+
const limit = Number.parseInt(options.limit ?? "10", 10);
|
|
231
|
+
const result = await listGodNodes(process.cwd(), Number.isFinite(limit) ? limit : 10);
|
|
232
|
+
if (isJson()) {
|
|
233
|
+
emitJson(result);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
for (const node of result) {
|
|
237
|
+
log(`${node.label} degree=${node.degree ?? 0} bridge=${node.bridgeScore ?? 0}`);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
174
240
|
var review = program.command("review").description("Review staged compile approval bundles.");
|
|
175
241
|
review.command("list").description("List staged approval bundles and their resolution status.").action(async () => {
|
|
176
242
|
const approvals = await listApprovals(process.cwd());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmvaultai/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "Global CLI for SwarmVault.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"commander": "^14.0.1",
|
|
42
|
-
"@swarmvaultai/engine": "0.1.
|
|
42
|
+
"@swarmvaultai/engine": "0.1.19"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^24.6.0",
|