@swarmvaultai/cli 3.8.0 → 3.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/README.md +66 -0
- package/dist/index.js +105 -51
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -17,6 +17,16 @@ Installed commands:
|
|
|
17
17
|
- `swarmvault`
|
|
18
18
|
- `vault` as a compatibility alias
|
|
19
19
|
|
|
20
|
+
## Maintainer Validation
|
|
21
|
+
|
|
22
|
+
Release preflight includes a direct CLI surface smoke before tarball smoke:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pnpm live:cli-surface
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The smoke parses `packages/cli/src/index.ts` with the TypeScript compiler API, checks that every stable Commander command path and alias is classified in the surface manifest, runs `--help` across the full command tree, and exercises direct JSON behavior checks for the core local workflows.
|
|
29
|
+
|
|
20
30
|
## First Run
|
|
21
31
|
|
|
22
32
|
```bash
|
|
@@ -55,8 +65,13 @@ swarmvault explore "What should I research next?" --steps 3
|
|
|
55
65
|
swarmvault lint --deep
|
|
56
66
|
swarmvault graph blast ./src/index.ts
|
|
57
67
|
swarmvault graph status ./src
|
|
68
|
+
swarmvault check-update ./src
|
|
69
|
+
swarmvault graph stats
|
|
70
|
+
swarmvault graph validate --strict
|
|
58
71
|
swarmvault graph update .
|
|
72
|
+
swarmvault update .
|
|
59
73
|
swarmvault graph cluster
|
|
74
|
+
swarmvault cluster-only
|
|
60
75
|
swarmvault graph tree --output ./exports/tree.html
|
|
61
76
|
swarmvault graph query "Which nodes bridge the biggest clusters?"
|
|
62
77
|
swarmvault graph explain "concept:drift"
|
|
@@ -67,6 +82,7 @@ swarmvault graph serve
|
|
|
67
82
|
swarmvault graph export --report ./exports/report.html
|
|
68
83
|
swarmvault graph export --html ./exports/graph.html
|
|
69
84
|
swarmvault graph export --cypher ./exports/graph.cypher
|
|
85
|
+
swarmvault graph export --neo4j ./exports/graph.cypher
|
|
70
86
|
swarmvault graph merge ./exports/graph.json ./other-graph.json --out ./exports/merged-graph.json
|
|
71
87
|
swarmvault graph push neo4j --dry-run
|
|
72
88
|
```
|
|
@@ -398,6 +414,22 @@ Refresh code-derived graph artifacts from tracked repo roots or one explicit rep
|
|
|
398
414
|
- aborts if nodes or edges drop by more than 25% compared with the existing graph; pass `--force` or set `SWARMVAULT_FORCE_UPDATE=1` when the shrink is expected
|
|
399
415
|
- `--json` returns the same one-shot watch result shape, including repo import/update/remove counts and pending semantic refresh entries
|
|
400
416
|
|
|
417
|
+
### `swarmvault check-update [path]`
|
|
418
|
+
|
|
419
|
+
Compatibility alias for `swarmvault graph status [path]`.
|
|
420
|
+
|
|
421
|
+
- performs the same read-only graph/report freshness check
|
|
422
|
+
- keeps automation-friendly JSON output for cron or hook wrappers
|
|
423
|
+
- recommends `swarmvault update`/`swarmvault graph update` for code-only drift and `swarmvault compile` when semantic refresh is required
|
|
424
|
+
|
|
425
|
+
### `swarmvault update [path]`
|
|
426
|
+
|
|
427
|
+
Compatibility alias for `swarmvault graph update [path]`.
|
|
428
|
+
|
|
429
|
+
- runs the same code-only repo refresh path
|
|
430
|
+
- accepts `--lint` and `--force`
|
|
431
|
+
- returns the same JSON shape as `graph update`
|
|
432
|
+
|
|
401
433
|
### `swarmvault graph tree [--output <html>] [--root <path>] [--label <name>] [--max-children <n>]`
|
|
402
434
|
|
|
403
435
|
Write a collapsible HTML source tree for the current `state/graph.json`.
|
|
@@ -429,6 +461,25 @@ Read-only graph freshness check for tracked repo roots or one explicit repo path
|
|
|
429
461
|
- recommends `swarmvault compile` when graph/report artifacts are missing, non-code files changed, or a semantic refresh is pending
|
|
430
462
|
- supports global `--json` for automation
|
|
431
463
|
|
|
464
|
+
### `swarmvault graph stats`
|
|
465
|
+
|
|
466
|
+
Summarize the current compiled graph without opening the viewer.
|
|
467
|
+
|
|
468
|
+
- reports source, page, node, edge, hyperedge, and community counts
|
|
469
|
+
- breaks down node types, evidence classes, source classes, edge relations, and hyperedge relations
|
|
470
|
+
- keeps the same lightweight shape as the MCP `graph_stats` tool
|
|
471
|
+
- supports global `--json` for automation
|
|
472
|
+
|
|
473
|
+
### `swarmvault graph validate [graph] [--strict]`
|
|
474
|
+
|
|
475
|
+
Validate graph artifact integrity before exporting, merging, pushing, or publishing generated graph evidence.
|
|
476
|
+
|
|
477
|
+
- defaults to the current vault's compiled `state/graph.json`
|
|
478
|
+
- accepts an explicit graph JSON path for exported or merged graph artifacts
|
|
479
|
+
- checks duplicate ids, dangling node/page/community/hyperedge references, confidence bounds, empty critical fields, and conflicted-edge evidence consistency
|
|
480
|
+
- exits non-zero when errors are present; with `--strict`, warnings also fail the command
|
|
481
|
+
- supports global `--json` for automation
|
|
482
|
+
|
|
432
483
|
### `swarmvault graph cluster [--resolution <n>]`
|
|
433
484
|
|
|
434
485
|
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.
|
|
@@ -439,6 +490,21 @@ Recompute communities, node degrees, bridge scores, god-node flags, and graph re
|
|
|
439
490
|
- splits oversized or low-cohesion communities after the initial Louvain pass so large-repo reports stay scannable
|
|
440
491
|
- `--json` returns counts plus the graph/report paths
|
|
441
492
|
|
|
493
|
+
### `swarmvault cluster-only [vault] [--resolution <n>]`
|
|
494
|
+
|
|
495
|
+
Compatibility alias for `swarmvault graph cluster`.
|
|
496
|
+
|
|
497
|
+
- recomputes communities and graph report artifacts without ingest or semantic analysis
|
|
498
|
+
- accepts an optional vault root when the command is run from outside the vault
|
|
499
|
+
- returns the same JSON shape as `graph cluster`
|
|
500
|
+
|
|
501
|
+
### `swarmvault graph export --neo4j <path>`
|
|
502
|
+
|
|
503
|
+
Compatibility alias for `swarmvault graph export --cypher <path>`.
|
|
504
|
+
|
|
505
|
+
- writes a Neo4j-ready Cypher import file
|
|
506
|
+
- can be combined with other `graph export` formats in the same run
|
|
507
|
+
|
|
442
508
|
### `swarmvault hook install|uninstall|status`
|
|
443
509
|
|
|
444
510
|
Manage SwarmVault's local git hook blocks for the nearest git repository.
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
getRetrievalStatus,
|
|
40
40
|
getWatchStatus,
|
|
41
41
|
graphDiff,
|
|
42
|
+
graphStatsVault,
|
|
42
43
|
guideManagedSource,
|
|
43
44
|
guideSourceScope,
|
|
44
45
|
importInbox,
|
|
@@ -95,6 +96,7 @@ import {
|
|
|
95
96
|
summarizeLocalWhisperSetup,
|
|
96
97
|
uninstallGitHooks,
|
|
97
98
|
updateMemoryTask,
|
|
99
|
+
validateGraphVault,
|
|
98
100
|
watchVault
|
|
99
101
|
} from "@swarmvaultai/engine";
|
|
100
102
|
import { Command, Option } from "commander";
|
|
@@ -313,9 +315,9 @@ program.name("swarmvault").description("SwarmVault is a local-first knowledge co
|
|
|
313
315
|
function readCliVersion() {
|
|
314
316
|
try {
|
|
315
317
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
316
|
-
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.
|
|
318
|
+
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.10.0";
|
|
317
319
|
} catch {
|
|
318
|
-
return "3.
|
|
320
|
+
return "3.10.0";
|
|
319
321
|
}
|
|
320
322
|
}
|
|
321
323
|
function parsePositiveInt(value, fallback) {
|
|
@@ -364,6 +366,9 @@ function summarizeRedactions(redactions) {
|
|
|
364
366
|
const sourceLabel = redactions.length === 1 ? "source" : "sources";
|
|
365
367
|
return `Redacted ${totalMatches} ${secretsLabel} across ${redactions.length} ${sourceLabel} (run --no-redact to disable).`;
|
|
366
368
|
}
|
|
369
|
+
function topCountEntries(record, limit = 8) {
|
|
370
|
+
return Object.entries(record).filter(([, count]) => count > 0).sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).slice(0, limit);
|
|
371
|
+
}
|
|
367
372
|
function emitJson(data) {
|
|
368
373
|
process2.stdout.write(`${JSON.stringify(data)}
|
|
369
374
|
`);
|
|
@@ -483,6 +488,63 @@ function getCommandPath(command) {
|
|
|
483
488
|
}
|
|
484
489
|
return names;
|
|
485
490
|
}
|
|
491
|
+
async function runGraphUpdateCommand(targetPath, options) {
|
|
492
|
+
const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
|
|
493
|
+
const result = await runWatchCycle(process2.cwd(), {
|
|
494
|
+
repo: true,
|
|
495
|
+
codeOnly: true,
|
|
496
|
+
lint: options.lint ?? false,
|
|
497
|
+
force: options.force ?? false,
|
|
498
|
+
overrideRoots
|
|
499
|
+
});
|
|
500
|
+
if (isJson()) {
|
|
501
|
+
emitJson(result);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
log(
|
|
505
|
+
`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}.`
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
async function showGraphStatusCommand(targetPath) {
|
|
509
|
+
const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
|
|
510
|
+
const status = await getGraphStatus(process2.cwd(), { repoRoots: overrideRoots });
|
|
511
|
+
if (isJson()) {
|
|
512
|
+
emitJson(status);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
log(`Graph: ${status.graphExists ? status.graphPath : `missing (${status.graphPath})`}`);
|
|
516
|
+
log(`Report: ${status.reportExists ? status.reportPath : `missing (${status.reportPath})`}`);
|
|
517
|
+
log(`Tracked repo roots: ${status.trackedRepoRoots.length ? status.trackedRepoRoots.join(", ") : "none"}`);
|
|
518
|
+
log(`Code changes: ${status.codeChangeCount}`);
|
|
519
|
+
log(`Semantic changes: ${status.semanticChangeCount}`);
|
|
520
|
+
log(`Pending semantic refresh: ${status.pendingSemanticRefresh.length}`);
|
|
521
|
+
if (status.changes.length) {
|
|
522
|
+
for (const change of status.changes.slice(0, 20)) {
|
|
523
|
+
log(`- ${change.refreshType} ${change.changeType} ${change.path}`);
|
|
524
|
+
}
|
|
525
|
+
if (status.changes.length > 20) {
|
|
526
|
+
log(`... and ${status.changes.length - 20} more`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
log(`State: ${status.stale ? "stale" : "fresh"}`);
|
|
530
|
+
if (status.recommendedCommand) {
|
|
531
|
+
log(`Recommended: ${status.recommendedCommand}`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
async function runGraphClusterCommand(options, rootDir = process2.cwd()) {
|
|
535
|
+
const resolution = parsePositiveNumber(options.resolution);
|
|
536
|
+
if (options.resolution && resolution === void 0) {
|
|
537
|
+
throw new Error("--resolution must be a positive number.");
|
|
538
|
+
}
|
|
539
|
+
const result = await refreshGraphClusters(rootDir, { resolution });
|
|
540
|
+
if (isJson()) {
|
|
541
|
+
emitJson(result);
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
log(
|
|
545
|
+
`Refreshed ${result.communityCount} communities across ${result.nodeCount} nodes and ${result.edgeCount} edges. Report: ${result.reportPath}`
|
|
546
|
+
);
|
|
547
|
+
}
|
|
486
548
|
program.hook("postAction", async (_thisCommand, actionCommand) => {
|
|
487
549
|
const notices = await collectCliNotices({
|
|
488
550
|
commandPath: getCommandPath(actionCommand),
|
|
@@ -1152,23 +1214,7 @@ program.command("lint").description("Run anti-drift and wiki-health checks.").op
|
|
|
1152
1214
|
});
|
|
1153
1215
|
var graph = program.command("graph").description("Graph-related commands.").enablePositionalOptions();
|
|
1154
1216
|
var graphPush = graph.command("push").description("Push the compiled graph into external sinks.");
|
|
1155
|
-
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).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(
|
|
1156
|
-
const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
|
|
1157
|
-
const result = await runWatchCycle(process2.cwd(), {
|
|
1158
|
-
repo: true,
|
|
1159
|
-
codeOnly: true,
|
|
1160
|
-
lint: options.lint ?? false,
|
|
1161
|
-
force: options.force ?? false,
|
|
1162
|
-
overrideRoots
|
|
1163
|
-
});
|
|
1164
|
-
if (isJson()) {
|
|
1165
|
-
emitJson(result);
|
|
1166
|
-
return;
|
|
1167
|
-
}
|
|
1168
|
-
log(
|
|
1169
|
-
`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}.`
|
|
1170
|
-
);
|
|
1171
|
-
});
|
|
1217
|
+
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).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(runGraphUpdateCommand);
|
|
1172
1218
|
graph.command("tree").description("Write a collapsible source/module/symbol tree for the compiled graph.").option("--output <html>", "Output HTML path (default: wiki/graph/tree.html)").option("--root <path>", "Vault root to read instead of the current directory").option("--label <name>", "Tree title").option("--max-children <n>", "Maximum children to render per tree node", "250").action(async (options) => {
|
|
1173
1219
|
const rootDir = options.root ? path2.resolve(process2.cwd(), options.root) : process2.cwd();
|
|
1174
1220
|
const result = await exportGraphTree(rootDir, options.output, {
|
|
@@ -1199,46 +1245,48 @@ graph.command("merge").description("Merge SwarmVault or node-link JSON graph fil
|
|
|
1199
1245
|
log(`Warning: ${warning}`);
|
|
1200
1246
|
}
|
|
1201
1247
|
});
|
|
1202
|
-
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(
|
|
1203
|
-
|
|
1204
|
-
const
|
|
1248
|
+
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(showGraphStatusCommand);
|
|
1249
|
+
graph.command("stats").description("Summarize compiled graph counts, node types, evidence classes, and relation mix.").action(async () => {
|
|
1250
|
+
const stats = await graphStatsVault(process2.cwd());
|
|
1205
1251
|
if (isJson()) {
|
|
1206
|
-
emitJson(
|
|
1252
|
+
emitJson(stats);
|
|
1207
1253
|
return;
|
|
1208
1254
|
}
|
|
1209
|
-
log(
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
if (status.changes.length) {
|
|
1216
|
-
for (const change of status.changes.slice(0, 20)) {
|
|
1217
|
-
log(`- ${change.refreshType} ${change.changeType} ${change.path}`);
|
|
1218
|
-
}
|
|
1219
|
-
if (status.changes.length > 20) {
|
|
1220
|
-
log(`... and ${status.changes.length - 20} more`);
|
|
1221
|
-
}
|
|
1255
|
+
log(
|
|
1256
|
+
`Graph stats: ${stats.counts.nodes} nodes, ${stats.counts.edges} edges, ${stats.counts.pages} pages, ${stats.counts.hyperedges} hyperedges, ${stats.counts.communities} communities.`
|
|
1257
|
+
);
|
|
1258
|
+
const nodeTypes = topCountEntries(stats.nodeTypes);
|
|
1259
|
+
if (nodeTypes.length) {
|
|
1260
|
+
log(`Node types: ${nodeTypes.map(([name, count]) => `${name}=${count}`).join(", ")}`);
|
|
1222
1261
|
}
|
|
1223
|
-
|
|
1224
|
-
if (
|
|
1225
|
-
log(`
|
|
1262
|
+
const evidence = topCountEntries(stats.evidenceClasses);
|
|
1263
|
+
if (evidence.length) {
|
|
1264
|
+
log(`Evidence: ${evidence.map(([name, count]) => `${name}=${count}`).join(", ")}`);
|
|
1226
1265
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
if (options.resolution && resolution === void 0) {
|
|
1231
|
-
throw new Error("--resolution must be a positive number.");
|
|
1266
|
+
const relations = topCountEntries(stats.edgeRelations);
|
|
1267
|
+
if (relations.length) {
|
|
1268
|
+
log(`Top relations: ${relations.map(([name, count]) => `${name}=${count}`).join(", ")}`);
|
|
1232
1269
|
}
|
|
1233
|
-
|
|
1270
|
+
});
|
|
1271
|
+
graph.command("validate").description("Validate a compiled graph artifact for dangling references, duplicate ids, and confidence bounds.").argument("[graph]", "Optional graph JSON path; defaults to the current vault graph").option("--strict", "Treat warnings as failures", false).action(async (graphPath, options) => {
|
|
1272
|
+
const result = await validateGraphVault(process2.cwd(), {
|
|
1273
|
+
graphPath,
|
|
1274
|
+
strict: options.strict ?? false
|
|
1275
|
+
});
|
|
1234
1276
|
if (isJson()) {
|
|
1235
1277
|
emitJson(result);
|
|
1236
|
-
|
|
1278
|
+
} else {
|
|
1279
|
+
log(result.summary);
|
|
1280
|
+
for (const issue of result.issues) {
|
|
1281
|
+
const location = issue.path ? ` ${issue.path}` : "";
|
|
1282
|
+
log(`[${issue.severity}] ${issue.code}${location}: ${issue.message}`);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
if (!result.ok) {
|
|
1286
|
+
process2.exitCode = 1;
|
|
1237
1287
|
}
|
|
1238
|
-
log(
|
|
1239
|
-
`Refreshed ${result.communityCount} communities across ${result.nodeCount} nodes and ${result.edgeCount} edges. Report: ${result.reportPath}`
|
|
1240
|
-
);
|
|
1241
1288
|
});
|
|
1289
|
+
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((options) => runGraphClusterCommand(options));
|
|
1242
1290
|
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(
|
|
1243
1291
|
async (options) => {
|
|
1244
1292
|
const batchSize = typeof options.batchSize === "string" && options.batchSize.trim() ? parsePositiveInt(options.batchSize, 0) || void 0 : void 0;
|
|
@@ -1294,7 +1342,7 @@ graph.command("serve").description("Serve the local graph viewer.").option("--po
|
|
|
1294
1342
|
});
|
|
1295
1343
|
graph.command("export").description(
|
|
1296
1344
|
"Export the graph as HTML, report, SVG, GraphML, Cypher, JSON, Obsidian vault, or Obsidian canvas. Combine flags to write multiple formats in one run."
|
|
1297
|
-
).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", "Include the full graph in HTML export (default; queries traverse complete graph)", true).option("--overview", "Use overview sampling for HTML export (smaller file, queries limited to sampled nodes)", false).action(
|
|
1345
|
+
).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("--neo4j <output>", "Compatibility alias for --cypher, writing a Neo4j Cypher import file").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", "Include the full graph in HTML export (default; queries traverse complete graph)", true).option("--overview", "Use overview sampling for HTML export (smaller file, queries limited to sampled nodes)", false).action(
|
|
1298
1346
|
async (options) => {
|
|
1299
1347
|
const useFullGraph = options.overview ? false : options.full ?? true;
|
|
1300
1348
|
const targets = [
|
|
@@ -1304,13 +1352,14 @@ graph.command("export").description(
|
|
|
1304
1352
|
options.svg ? { format: "svg", outputPath: options.svg } : null,
|
|
1305
1353
|
options.graphml ? { format: "graphml", outputPath: options.graphml } : null,
|
|
1306
1354
|
options.cypher ? { format: "cypher", outputPath: options.cypher } : null,
|
|
1355
|
+
options.neo4j ? { format: "cypher", outputPath: options.neo4j } : null,
|
|
1307
1356
|
options.json ? { format: "json", outputPath: options.json } : null,
|
|
1308
1357
|
options.obsidian ? { format: "obsidian", outputPath: options.obsidian } : null,
|
|
1309
1358
|
options.canvas ? { format: "canvas", outputPath: options.canvas } : null
|
|
1310
1359
|
].filter((target) => Boolean(target));
|
|
1311
1360
|
if (targets.length === 0) {
|
|
1312
1361
|
throw new Error(
|
|
1313
|
-
"Pass at least one of --html, --html-standalone, --report, --svg, --graphml, --cypher, --json, --obsidian, or --canvas."
|
|
1362
|
+
"Pass at least one of --html, --html-standalone, --report, --svg, --graphml, --cypher, --neo4j, --json, --obsidian, or --canvas."
|
|
1314
1363
|
);
|
|
1315
1364
|
}
|
|
1316
1365
|
const results = [];
|
|
@@ -1731,6 +1780,11 @@ async function showWatchStatus() {
|
|
|
1731
1780
|
}
|
|
1732
1781
|
watch.command("status").description("Show the latest watch run plus pending semantic refresh entries.").action(showWatchStatus);
|
|
1733
1782
|
program.command("watch-status").description("Show the latest watch run plus pending semantic refresh entries.").action(showWatchStatus);
|
|
1783
|
+
program.command("check-update").description("Compatibility alias for graph status: read-only graph/report freshness and tracked repo change check.").argument("[path]", "Optional repo root to check instead of configured/tracked roots").action(showGraphStatusCommand);
|
|
1784
|
+
program.command("update").description("Compatibility alias for graph update: refresh code-derived graph artifacts from tracked repo roots.").argument("[path]", "Optional repo root to refresh instead of configured/tracked roots").option("--lint", "Run lint after the refresh cycle", false).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(runGraphUpdateCommand);
|
|
1785
|
+
program.command("cluster-only").description("Compatibility alias for graph cluster: recompute graph communities and report artifacts without re-ingesting.").argument("[vault]", "Optional vault root to cluster instead of the current directory").option("--resolution <number>", "Override the Louvain community resolution for this run").action(
|
|
1786
|
+
(vaultPath, options) => runGraphClusterCommand(options, vaultPath ? path2.resolve(process2.cwd(), vaultPath) : process2.cwd())
|
|
1787
|
+
);
|
|
1734
1788
|
var hook = program.command("hook").description("Install local git hooks that keep tracked repos and the vault in sync.");
|
|
1735
1789
|
hook.command("install").description("Install post-commit and post-checkout hooks for the nearest git repository.").action(async () => {
|
|
1736
1790
|
const status = await installGitHooks(process2.cwd());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmvaultai/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.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.10.0",
|
|
48
48
|
"commander": "^14.0.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|