@swarmvaultai/cli 3.9.0 → 3.11.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 +73 -2
- package/dist/index.js +190 -160
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -65,11 +65,15 @@ swarmvault explore "What should I research next?" --steps 3
|
|
|
65
65
|
swarmvault lint --deep
|
|
66
66
|
swarmvault graph blast ./src/index.ts
|
|
67
67
|
swarmvault graph status ./src
|
|
68
|
+
swarmvault check-update ./src
|
|
68
69
|
swarmvault graph stats
|
|
69
70
|
swarmvault graph validate --strict
|
|
70
71
|
swarmvault graph update .
|
|
72
|
+
swarmvault update .
|
|
71
73
|
swarmvault graph cluster
|
|
74
|
+
swarmvault cluster-only
|
|
72
75
|
swarmvault graph tree --output ./exports/tree.html
|
|
76
|
+
swarmvault tree --output ./exports/tree.html
|
|
73
77
|
swarmvault graph query "Which nodes bridge the biggest clusters?"
|
|
74
78
|
swarmvault graph explain "concept:drift"
|
|
75
79
|
swarmvault watch status
|
|
@@ -79,8 +83,11 @@ swarmvault graph serve
|
|
|
79
83
|
swarmvault graph export --report ./exports/report.html
|
|
80
84
|
swarmvault graph export --html ./exports/graph.html
|
|
81
85
|
swarmvault graph export --cypher ./exports/graph.cypher
|
|
86
|
+
swarmvault graph export --neo4j ./exports/graph.cypher
|
|
82
87
|
swarmvault graph merge ./exports/graph.json ./other-graph.json --out ./exports/merged-graph.json
|
|
88
|
+
swarmvault merge-graphs ./exports/graph.json ./other-graph.json --out ./exports/merged-graph.json
|
|
83
89
|
swarmvault graph push neo4j --dry-run
|
|
90
|
+
swarmvault clone https://github.com/owner/repo --no-viz
|
|
84
91
|
```
|
|
85
92
|
|
|
86
93
|
## Commands
|
|
@@ -106,7 +113,7 @@ Set `SWARMVAULT_OUT=<dir>` when generated artifacts should be isolated from the
|
|
|
106
113
|
|
|
107
114
|
`--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`.
|
|
108
115
|
|
|
109
|
-
### `swarmvault scan <directory|github-url> [--port <port>] [--no-serve] [--branch <name>] [--ref <ref>] [--checkout-dir <path>]`
|
|
116
|
+
### `swarmvault scan <directory|github-url> [--port <port>] [--no-serve] [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>]`
|
|
110
117
|
|
|
111
118
|
Quick-start a scratch vault from a local directory or public GitHub repo root URL in one command.
|
|
112
119
|
|
|
@@ -114,12 +121,22 @@ Quick-start a scratch vault from a local directory or public GitHub repo root UR
|
|
|
114
121
|
- ingests the supplied directory as local sources, or registers/syncs the supplied public GitHub repo root URL
|
|
115
122
|
- compiles the vault immediately
|
|
116
123
|
- writes `wiki/graph/share-card.md`, `wiki/graph/share-card.svg`, and `wiki/graph/share-kit/`, then prints the paths
|
|
117
|
-
- starts `graph serve` unless you pass `--no-serve`
|
|
124
|
+
- starts `graph serve` unless you pass `--no-serve` or `--no-viz`
|
|
125
|
+
- `--no-viz` is a compatibility alias for `--no-serve`
|
|
126
|
+
- `--mcp` starts the MCP stdio server after compile instead of the graph viewer
|
|
118
127
|
- respects `--port` when you want a specific viewer port
|
|
119
128
|
- for GitHub repo URLs, supports `--branch`, `--ref`, and `--checkout-dir`
|
|
120
129
|
|
|
121
130
|
Use this when you want the fastest repo or docs-tree walkthrough without first deciding on managed-source registration.
|
|
122
131
|
|
|
132
|
+
### `swarmvault clone <directory|github-url> [--no-viz] [--mcp] [--branch <name>] [--ref <ref>] [--checkout-dir <path>]`
|
|
133
|
+
|
|
134
|
+
Compatibility alias for `swarmvault scan`.
|
|
135
|
+
|
|
136
|
+
- initializes, ingests or registers the input, and compiles in one command
|
|
137
|
+
- supports the same public GitHub repo checkout flags as `scan`
|
|
138
|
+
- accepts `--no-serve`, `--no-viz`, `--mcp`, and `--port`
|
|
139
|
+
|
|
123
140
|
### `swarmvault demo [--port <port>] [--no-serve]`
|
|
124
141
|
|
|
125
142
|
Create a temporary sample vault with bundled sources, compile it immediately, and launch the graph viewer unless you pass `--no-serve`.
|
|
@@ -410,6 +427,22 @@ Refresh code-derived graph artifacts from tracked repo roots or one explicit rep
|
|
|
410
427
|
- 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
|
|
411
428
|
- `--json` returns the same one-shot watch result shape, including repo import/update/remove counts and pending semantic refresh entries
|
|
412
429
|
|
|
430
|
+
### `swarmvault check-update [path]`
|
|
431
|
+
|
|
432
|
+
Compatibility alias for `swarmvault graph status [path]`.
|
|
433
|
+
|
|
434
|
+
- performs the same read-only graph/report freshness check
|
|
435
|
+
- keeps automation-friendly JSON output for cron or hook wrappers
|
|
436
|
+
- recommends `swarmvault update`/`swarmvault graph update` for code-only drift and `swarmvault compile` when semantic refresh is required
|
|
437
|
+
|
|
438
|
+
### `swarmvault update [path]`
|
|
439
|
+
|
|
440
|
+
Compatibility alias for `swarmvault graph update [path]`.
|
|
441
|
+
|
|
442
|
+
- runs the same code-only repo refresh path
|
|
443
|
+
- accepts `--lint` and `--force`
|
|
444
|
+
- returns the same JSON shape as `graph update`
|
|
445
|
+
|
|
413
446
|
### `swarmvault graph tree [--output <html>] [--root <path>] [--label <name>] [--max-children <n>]`
|
|
414
447
|
|
|
415
448
|
Write a collapsible HTML source tree for the current `state/graph.json`.
|
|
@@ -420,6 +453,13 @@ Write a collapsible HTML source tree for the current `state/graph.json`.
|
|
|
420
453
|
- `--max-children` caps very wide folders or modules with a `+N more` row
|
|
421
454
|
- `--json` returns the output path, source count, node count, and tree payload
|
|
422
455
|
|
|
456
|
+
### `swarmvault tree [--output <html>] [--root <path>] [--label <name>] [--max-children <n>]`
|
|
457
|
+
|
|
458
|
+
Compatibility alias for `swarmvault graph tree`.
|
|
459
|
+
|
|
460
|
+
- writes the same source/module/symbol tree
|
|
461
|
+
- returns the same JSON shape as `graph tree`
|
|
462
|
+
|
|
423
463
|
### `swarmvault graph merge <graph...> --out <path> [--label <name>]`
|
|
424
464
|
|
|
425
465
|
Merge multiple graph JSON files into one namespaced graph artifact.
|
|
@@ -430,6 +470,13 @@ Merge multiple graph JSON files into one namespaced graph artifact.
|
|
|
430
470
|
- maps explicit extracted/inferred/ambiguous edge evidence into SwarmVault edge semantics
|
|
431
471
|
- `--json` returns the merged graph, input summaries, and warnings
|
|
432
472
|
|
|
473
|
+
### `swarmvault merge-graphs <graph...> --out <path> [--label <name>]`
|
|
474
|
+
|
|
475
|
+
Compatibility alias for `swarmvault graph merge`.
|
|
476
|
+
|
|
477
|
+
- accepts the same SwarmVault and NetworkX/node-link graph inputs
|
|
478
|
+
- returns the same JSON shape as `graph merge`
|
|
479
|
+
|
|
433
480
|
### `swarmvault graph status [path]`
|
|
434
481
|
|
|
435
482
|
Read-only graph freshness check for tracked repo roots or one explicit repo path.
|
|
@@ -441,6 +488,15 @@ Read-only graph freshness check for tracked repo roots or one explicit repo path
|
|
|
441
488
|
- recommends `swarmvault compile` when graph/report artifacts are missing, non-code files changed, or a semantic refresh is pending
|
|
442
489
|
- supports global `--json` for automation
|
|
443
490
|
|
|
491
|
+
### `swarmvault watch [path] [--once] [--code-only] [--lint]`
|
|
492
|
+
|
|
493
|
+
Watch or refresh one explicit repo root without first writing `watch.repoRoots`.
|
|
494
|
+
|
|
495
|
+
- positional `[path]` is treated as a repo-root override and turns on repo mode
|
|
496
|
+
- `--once` runs one refresh cycle and exits
|
|
497
|
+
- `--code-only` limits the refresh to parser-backed repo graph artifacts
|
|
498
|
+
- repeated `--root <path>` remains available when you need multiple roots
|
|
499
|
+
|
|
444
500
|
### `swarmvault graph stats`
|
|
445
501
|
|
|
446
502
|
Summarize the current compiled graph without opening the viewer.
|
|
@@ -470,6 +526,21 @@ Recompute communities, node degrees, bridge scores, god-node flags, and graph re
|
|
|
470
526
|
- splits oversized or low-cohesion communities after the initial Louvain pass so large-repo reports stay scannable
|
|
471
527
|
- `--json` returns counts plus the graph/report paths
|
|
472
528
|
|
|
529
|
+
### `swarmvault cluster-only [vault] [--resolution <n>]`
|
|
530
|
+
|
|
531
|
+
Compatibility alias for `swarmvault graph cluster`.
|
|
532
|
+
|
|
533
|
+
- recomputes communities and graph report artifacts without ingest or semantic analysis
|
|
534
|
+
- accepts an optional vault root when the command is run from outside the vault
|
|
535
|
+
- returns the same JSON shape as `graph cluster`
|
|
536
|
+
|
|
537
|
+
### `swarmvault graph export --neo4j <path>`
|
|
538
|
+
|
|
539
|
+
Compatibility alias for `swarmvault graph export --cypher <path>`.
|
|
540
|
+
|
|
541
|
+
- writes a Neo4j-ready Cypher import file
|
|
542
|
+
- can be combined with other `graph export` formats in the same run
|
|
543
|
+
|
|
473
544
|
### `swarmvault hook install|uninstall|status`
|
|
474
545
|
|
|
475
546
|
Manage SwarmVault's local git hook blocks for the nearest git repository.
|
package/dist/index.js
CHANGED
|
@@ -315,9 +315,9 @@ program.name("swarmvault").description("SwarmVault is a local-first knowledge co
|
|
|
315
315
|
function readCliVersion() {
|
|
316
316
|
try {
|
|
317
317
|
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
318
|
-
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.
|
|
318
|
+
return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "3.11.0";
|
|
319
319
|
} catch {
|
|
320
|
-
return "3.
|
|
320
|
+
return "3.11.0";
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
function parsePositiveInt(value, fallback) {
|
|
@@ -488,6 +488,167 @@ function getCommandPath(command) {
|
|
|
488
488
|
}
|
|
489
489
|
return names;
|
|
490
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
|
+
}
|
|
548
|
+
async function runGraphTreeCommand(options) {
|
|
549
|
+
const rootDir = options.root ? path2.resolve(process2.cwd(), options.root) : process2.cwd();
|
|
550
|
+
const result = await exportGraphTree(rootDir, options.output, {
|
|
551
|
+
label: options.label,
|
|
552
|
+
maxChildren: parsePositiveInt(options.maxChildren, 250)
|
|
553
|
+
});
|
|
554
|
+
if (isJson()) {
|
|
555
|
+
emitJson(result);
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
log(`Graph tree: ${result.outputPath}`);
|
|
559
|
+
log(`Sources: ${result.sourceCount}; nodes: ${result.nodeCount}.`);
|
|
560
|
+
}
|
|
561
|
+
async function runGraphMergeCommand(graphPaths, options) {
|
|
562
|
+
const result = await mergeGraphFiles(
|
|
563
|
+
graphPaths.map((inputPath) => path2.resolve(process2.cwd(), inputPath)),
|
|
564
|
+
path2.resolve(process2.cwd(), options.out),
|
|
565
|
+
{ label: options.label }
|
|
566
|
+
);
|
|
567
|
+
if (isJson()) {
|
|
568
|
+
emitJson(result);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
log(
|
|
572
|
+
`Merged ${result.inputGraphs.length} graph${result.inputGraphs.length === 1 ? "" : "s"} into ${result.outputPath}. Nodes ${result.graph.nodes.length}, edges ${result.graph.edges.length}.`
|
|
573
|
+
);
|
|
574
|
+
for (const warning of result.warnings) {
|
|
575
|
+
log(`Warning: ${warning}`);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
async function runScanCommand(input, options) {
|
|
579
|
+
const rootDir = process2.cwd();
|
|
580
|
+
await initVault(rootDir, {});
|
|
581
|
+
if (!isJson()) {
|
|
582
|
+
log("Initialized workspace.");
|
|
583
|
+
}
|
|
584
|
+
const result = isHttpUrlInput(input) ? await addManagedSource(rootDir, input, {
|
|
585
|
+
compile: true,
|
|
586
|
+
brief: false,
|
|
587
|
+
branch: options.branch,
|
|
588
|
+
ref: options.ref,
|
|
589
|
+
checkoutDir: options.checkoutDir
|
|
590
|
+
}) : await ingestDirectory(rootDir, input, {});
|
|
591
|
+
if (!isJson()) {
|
|
592
|
+
if ("source" in result) {
|
|
593
|
+
log(
|
|
594
|
+
`Registered ${result.source.kind} source ${result.source.id}. Imported ${result.source.lastSyncCounts?.importedCount ?? 0}, updated ${result.source.lastSyncCounts?.updatedCount ?? 0}.`
|
|
595
|
+
);
|
|
596
|
+
} else {
|
|
597
|
+
log(`Ingested ${result.imported.length} file(s).`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
const compiled = "compile" in result && result.compile ? result.compile : await compileVault(rootDir, {});
|
|
601
|
+
const { paths } = await loadVaultConfig(rootDir);
|
|
602
|
+
const shareCardPath = path2.join(paths.wikiDir, "graph", "share-card.md");
|
|
603
|
+
const shareCardSvgPath = path2.join(paths.wikiDir, "graph", "share-card.svg");
|
|
604
|
+
const shareKitPath = path2.join(paths.wikiDir, "graph", "share-kit");
|
|
605
|
+
if (!isJson()) {
|
|
606
|
+
log(`Compiled ${compiled.sourceCount} source(s), ${compiled.pageCount} page(s).`);
|
|
607
|
+
log(`Share card: ${shareCardPath}`);
|
|
608
|
+
log(`Visual card: ${shareCardSvgPath}`);
|
|
609
|
+
log(`Share kit: ${shareKitPath}`);
|
|
610
|
+
log("Post text: swarmvault graph share --post");
|
|
611
|
+
}
|
|
612
|
+
if (options.mcp) {
|
|
613
|
+
process2.stderr.write(`${JSON.stringify({ status: "running", transport: "stdio", compiled: compiled.sourceCount })}
|
|
614
|
+
`);
|
|
615
|
+
const controller = await startMcpServer(rootDir);
|
|
616
|
+
process2.on("SIGINT", async () => {
|
|
617
|
+
try {
|
|
618
|
+
await controller.close();
|
|
619
|
+
} catch {
|
|
620
|
+
}
|
|
621
|
+
process2.exit(0);
|
|
622
|
+
});
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
if (options.serve !== false && options.viz !== false) {
|
|
626
|
+
const port = options.port ? parsePositiveInt(options.port, 0) || void 0 : void 0;
|
|
627
|
+
const server = await startGraphServer(rootDir, port, { full: false });
|
|
628
|
+
if (isJson()) {
|
|
629
|
+
emitJson({
|
|
630
|
+
...result,
|
|
631
|
+
compiled,
|
|
632
|
+
shareCardPath,
|
|
633
|
+
shareCardSvgPath,
|
|
634
|
+
shareKitPath,
|
|
635
|
+
port: server.port,
|
|
636
|
+
url: `http://localhost:${server.port}`
|
|
637
|
+
});
|
|
638
|
+
} else {
|
|
639
|
+
log(`Graph viewer running at http://localhost:${server.port}`);
|
|
640
|
+
}
|
|
641
|
+
process2.on("SIGINT", async () => {
|
|
642
|
+
try {
|
|
643
|
+
await server.close();
|
|
644
|
+
} catch {
|
|
645
|
+
}
|
|
646
|
+
process2.exit(0);
|
|
647
|
+
});
|
|
648
|
+
} else if (isJson()) {
|
|
649
|
+
emitJson({ ...result, compiled, shareCardPath, shareCardSvgPath, shareKitPath });
|
|
650
|
+
}
|
|
651
|
+
}
|
|
491
652
|
program.hook("postAction", async (_thisCommand, actionCommand) => {
|
|
492
653
|
const notices = await collectCliNotices({
|
|
493
654
|
commandPath: getCommandPath(actionCommand),
|
|
@@ -1157,79 +1318,10 @@ program.command("lint").description("Run anti-drift and wiki-health checks.").op
|
|
|
1157
1318
|
});
|
|
1158
1319
|
var graph = program.command("graph").description("Graph-related commands.").enablePositionalOptions();
|
|
1159
1320
|
var graphPush = graph.command("push").description("Push the compiled graph into external sinks.");
|
|
1160
|
-
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(
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
codeOnly: true,
|
|
1165
|
-
lint: options.lint ?? false,
|
|
1166
|
-
force: options.force ?? false,
|
|
1167
|
-
overrideRoots
|
|
1168
|
-
});
|
|
1169
|
-
if (isJson()) {
|
|
1170
|
-
emitJson(result);
|
|
1171
|
-
return;
|
|
1172
|
-
}
|
|
1173
|
-
log(
|
|
1174
|
-
`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}.`
|
|
1175
|
-
);
|
|
1176
|
-
});
|
|
1177
|
-
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) => {
|
|
1178
|
-
const rootDir = options.root ? path2.resolve(process2.cwd(), options.root) : process2.cwd();
|
|
1179
|
-
const result = await exportGraphTree(rootDir, options.output, {
|
|
1180
|
-
label: options.label,
|
|
1181
|
-
maxChildren: parsePositiveInt(options.maxChildren, 250)
|
|
1182
|
-
});
|
|
1183
|
-
if (isJson()) {
|
|
1184
|
-
emitJson(result);
|
|
1185
|
-
return;
|
|
1186
|
-
}
|
|
1187
|
-
log(`Graph tree: ${result.outputPath}`);
|
|
1188
|
-
log(`Sources: ${result.sourceCount}; nodes: ${result.nodeCount}.`);
|
|
1189
|
-
});
|
|
1190
|
-
graph.command("merge").description("Merge SwarmVault or node-link JSON graph files into one namespaced graph artifact.").argument("<graphs...>", "Graph JSON files to merge").requiredOption("--out <path>", "Output graph JSON path").option("--label <name>", "Label/prefix to use when merging one graph").action(async (graphPaths, options) => {
|
|
1191
|
-
const result = await mergeGraphFiles(
|
|
1192
|
-
graphPaths.map((inputPath) => path2.resolve(process2.cwd(), inputPath)),
|
|
1193
|
-
path2.resolve(process2.cwd(), options.out),
|
|
1194
|
-
{ label: options.label }
|
|
1195
|
-
);
|
|
1196
|
-
if (isJson()) {
|
|
1197
|
-
emitJson(result);
|
|
1198
|
-
return;
|
|
1199
|
-
}
|
|
1200
|
-
log(
|
|
1201
|
-
`Merged ${result.inputGraphs.length} graph${result.inputGraphs.length === 1 ? "" : "s"} into ${result.outputPath}. Nodes ${result.graph.nodes.length}, edges ${result.graph.edges.length}.`
|
|
1202
|
-
);
|
|
1203
|
-
for (const warning of result.warnings) {
|
|
1204
|
-
log(`Warning: ${warning}`);
|
|
1205
|
-
}
|
|
1206
|
-
});
|
|
1207
|
-
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) => {
|
|
1208
|
-
const overrideRoots = targetPath ? [path2.resolve(process2.cwd(), targetPath)] : void 0;
|
|
1209
|
-
const status = await getGraphStatus(process2.cwd(), { repoRoots: overrideRoots });
|
|
1210
|
-
if (isJson()) {
|
|
1211
|
-
emitJson(status);
|
|
1212
|
-
return;
|
|
1213
|
-
}
|
|
1214
|
-
log(`Graph: ${status.graphExists ? status.graphPath : `missing (${status.graphPath})`}`);
|
|
1215
|
-
log(`Report: ${status.reportExists ? status.reportPath : `missing (${status.reportPath})`}`);
|
|
1216
|
-
log(`Tracked repo roots: ${status.trackedRepoRoots.length ? status.trackedRepoRoots.join(", ") : "none"}`);
|
|
1217
|
-
log(`Code changes: ${status.codeChangeCount}`);
|
|
1218
|
-
log(`Semantic changes: ${status.semanticChangeCount}`);
|
|
1219
|
-
log(`Pending semantic refresh: ${status.pendingSemanticRefresh.length}`);
|
|
1220
|
-
if (status.changes.length) {
|
|
1221
|
-
for (const change of status.changes.slice(0, 20)) {
|
|
1222
|
-
log(`- ${change.refreshType} ${change.changeType} ${change.path}`);
|
|
1223
|
-
}
|
|
1224
|
-
if (status.changes.length > 20) {
|
|
1225
|
-
log(`... and ${status.changes.length - 20} more`);
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
log(`State: ${status.stale ? "stale" : "fresh"}`);
|
|
1229
|
-
if (status.recommendedCommand) {
|
|
1230
|
-
log(`Recommended: ${status.recommendedCommand}`);
|
|
1231
|
-
}
|
|
1232
|
-
});
|
|
1321
|
+
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);
|
|
1322
|
+
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(runGraphTreeCommand);
|
|
1323
|
+
graph.command("merge").description("Merge SwarmVault or node-link JSON graph files into one namespaced graph artifact.").argument("<graphs...>", "Graph JSON files to merge").requiredOption("--out <path>", "Output graph JSON path").option("--label <name>", "Label/prefix to use when merging one graph").action(runGraphMergeCommand);
|
|
1324
|
+
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);
|
|
1233
1325
|
graph.command("stats").description("Summarize compiled graph counts, node types, evidence classes, and relation mix.").action(async () => {
|
|
1234
1326
|
const stats = await graphStatsVault(process2.cwd());
|
|
1235
1327
|
if (isJson()) {
|
|
@@ -1270,20 +1362,7 @@ graph.command("validate").description("Validate a compiled graph artifact for da
|
|
|
1270
1362
|
process2.exitCode = 1;
|
|
1271
1363
|
}
|
|
1272
1364
|
});
|
|
1273
|
-
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(
|
|
1274
|
-
const resolution = parsePositiveNumber(options.resolution);
|
|
1275
|
-
if (options.resolution && resolution === void 0) {
|
|
1276
|
-
throw new Error("--resolution must be a positive number.");
|
|
1277
|
-
}
|
|
1278
|
-
const result = await refreshGraphClusters(process2.cwd(), { resolution });
|
|
1279
|
-
if (isJson()) {
|
|
1280
|
-
emitJson(result);
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
1283
|
-
log(
|
|
1284
|
-
`Refreshed ${result.communityCount} communities across ${result.nodeCount} nodes and ${result.edgeCount} edges. Report: ${result.reportPath}`
|
|
1285
|
-
);
|
|
1286
|
-
});
|
|
1365
|
+
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));
|
|
1287
1366
|
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(
|
|
1288
1367
|
async (options) => {
|
|
1289
1368
|
const batchSize = typeof options.batchSize === "string" && options.batchSize.trim() ? parsePositiveInt(options.batchSize, 0) || void 0 : void 0;
|
|
@@ -1339,7 +1418,7 @@ graph.command("serve").description("Serve the local graph viewer.").option("--po
|
|
|
1339
1418
|
});
|
|
1340
1419
|
graph.command("export").description(
|
|
1341
1420
|
"Export the graph as HTML, report, SVG, GraphML, Cypher, JSON, Obsidian vault, or Obsidian canvas. Combine flags to write multiple formats in one run."
|
|
1342
|
-
).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(
|
|
1421
|
+
).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(
|
|
1343
1422
|
async (options) => {
|
|
1344
1423
|
const useFullGraph = options.overview ? false : options.full ?? true;
|
|
1345
1424
|
const targets = [
|
|
@@ -1349,13 +1428,14 @@ graph.command("export").description(
|
|
|
1349
1428
|
options.svg ? { format: "svg", outputPath: options.svg } : null,
|
|
1350
1429
|
options.graphml ? { format: "graphml", outputPath: options.graphml } : null,
|
|
1351
1430
|
options.cypher ? { format: "cypher", outputPath: options.cypher } : null,
|
|
1431
|
+
options.neo4j ? { format: "cypher", outputPath: options.neo4j } : null,
|
|
1352
1432
|
options.json ? { format: "json", outputPath: options.json } : null,
|
|
1353
1433
|
options.obsidian ? { format: "obsidian", outputPath: options.obsidian } : null,
|
|
1354
1434
|
options.canvas ? { format: "canvas", outputPath: options.canvas } : null
|
|
1355
1435
|
].filter((target) => Boolean(target));
|
|
1356
1436
|
if (targets.length === 0) {
|
|
1357
1437
|
throw new Error(
|
|
1358
|
-
"Pass at least one of --html, --html-standalone, --report, --svg, --graphml, --cypher, --json, --obsidian, or --canvas."
|
|
1438
|
+
"Pass at least one of --html, --html-standalone, --report, --svg, --graphml, --cypher, --neo4j, --json, --obsidian, or --canvas."
|
|
1359
1439
|
);
|
|
1360
1440
|
}
|
|
1361
1441
|
const results = [];
|
|
@@ -1687,14 +1767,16 @@ async function confirmInteractive(message) {
|
|
|
1687
1767
|
rl.close();
|
|
1688
1768
|
}
|
|
1689
1769
|
}
|
|
1690
|
-
var watch = program.command("watch").description("Watch the inbox directory and optionally tracked repos, or run one refresh cycle immediately.").option("--lint", "Run lint after each compile cycle", false).option("--repo", "Also refresh tracked repo sources and watch their repo roots", false).option("--once", "Run one import/refresh cycle immediately instead of starting a watcher", false).option("--code-only", "Only re-extract code sources (AST-only, no LLM re-analysis)", false).option("--debounce <ms>", "Debounce window in milliseconds", "900").option("--root <path>", "Watch this repo root instead of config/auto-discovery (repeat for multiple)", collectRepeated, []).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(
|
|
1691
|
-
async (options) => {
|
|
1770
|
+
var watch = program.command("watch").description("Watch the inbox directory and optionally tracked repos, or run one refresh cycle immediately.").argument("[path]", "Optional repo root to watch or refresh instead of config/auto-discovery").option("--lint", "Run lint after each compile cycle", false).option("--repo", "Also refresh tracked repo sources and watch their repo roots", false).option("--once", "Run one import/refresh cycle immediately instead of starting a watcher", false).option("--code-only", "Only re-extract code sources (AST-only, no LLM re-analysis)", false).option("--debounce <ms>", "Debounce window in milliseconds", "900").option("--root <path>", "Watch this repo root instead of config/auto-discovery (repeat for multiple)", collectRepeated, []).option("--force", "Allow graph updates even when node or edge counts shrink sharply", false).action(
|
|
1771
|
+
async (targetPath, options) => {
|
|
1692
1772
|
const debounceMs = parsePositiveInt(options.debounce, 900);
|
|
1693
|
-
const
|
|
1773
|
+
const rootOverrides = [...targetPath ? [targetPath] : [], ...options.root ?? []];
|
|
1774
|
+
const overrideRoots = rootOverrides.length > 0 ? rootOverrides : void 0;
|
|
1775
|
+
const repoMode = options.repo || Boolean(targetPath);
|
|
1694
1776
|
if (options.once) {
|
|
1695
1777
|
const result = await runWatchCycle(process2.cwd(), {
|
|
1696
1778
|
lint: options.lint ?? false,
|
|
1697
|
-
repo:
|
|
1779
|
+
repo: repoMode,
|
|
1698
1780
|
codeOnly: options.codeOnly ?? false,
|
|
1699
1781
|
debounceMs,
|
|
1700
1782
|
force: options.force ?? false,
|
|
@@ -1704,7 +1786,7 @@ var watch = program.command("watch").description("Watch the inbox directory and
|
|
|
1704
1786
|
emitJson(result);
|
|
1705
1787
|
} else {
|
|
1706
1788
|
log(
|
|
1707
|
-
`Refreshed inbox${
|
|
1789
|
+
`Refreshed inbox${repoMode ? " and tracked repos" : ""}. Imported ${result.importedCount}, repo imported ${result.repoImportedCount}, repo updated ${result.repoUpdatedCount}, repo removed ${result.repoRemovedCount}.`
|
|
1708
1790
|
);
|
|
1709
1791
|
}
|
|
1710
1792
|
return;
|
|
@@ -1712,16 +1794,16 @@ var watch = program.command("watch").description("Watch the inbox directory and
|
|
|
1712
1794
|
const { paths } = await loadVaultConfig(process2.cwd());
|
|
1713
1795
|
const controller = await watchVault(process2.cwd(), {
|
|
1714
1796
|
lint: options.lint ?? false,
|
|
1715
|
-
repo:
|
|
1797
|
+
repo: repoMode,
|
|
1716
1798
|
codeOnly: options.codeOnly ?? false,
|
|
1717
1799
|
debounceMs,
|
|
1718
1800
|
force: options.force ?? false,
|
|
1719
1801
|
overrideRoots
|
|
1720
1802
|
});
|
|
1721
1803
|
if (isJson()) {
|
|
1722
|
-
emitJson({ status: "watching", inboxDir: paths.inboxDir, repo:
|
|
1804
|
+
emitJson({ status: "watching", inboxDir: paths.inboxDir, repo: repoMode });
|
|
1723
1805
|
} else {
|
|
1724
|
-
log(`Watching inbox${
|
|
1806
|
+
log(`Watching inbox${repoMode ? " and tracked repos" : ""} for changes. Press Ctrl+C to stop.`);
|
|
1725
1807
|
}
|
|
1726
1808
|
process2.on("SIGINT", async () => {
|
|
1727
1809
|
try {
|
|
@@ -1776,6 +1858,13 @@ async function showWatchStatus() {
|
|
|
1776
1858
|
}
|
|
1777
1859
|
watch.command("status").description("Show the latest watch run plus pending semantic refresh entries.").action(showWatchStatus);
|
|
1778
1860
|
program.command("watch-status").description("Show the latest watch run plus pending semantic refresh entries.").action(showWatchStatus);
|
|
1861
|
+
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);
|
|
1862
|
+
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);
|
|
1863
|
+
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(
|
|
1864
|
+
(vaultPath, options) => runGraphClusterCommand(options, vaultPath ? path2.resolve(process2.cwd(), vaultPath) : process2.cwd())
|
|
1865
|
+
);
|
|
1866
|
+
program.command("tree").description("Compatibility alias for graph tree: 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(runGraphTreeCommand);
|
|
1867
|
+
program.command("merge-graphs").description("Compatibility alias for graph merge: combine graph JSON files into one namespaced graph artifact.").argument("<graphs...>", "Graph JSON files to merge").requiredOption("--out <path>", "Output graph JSON path").option("--label <name>", "Label/prefix to use when merging one graph").action(runGraphMergeCommand);
|
|
1779
1868
|
var hook = program.command("hook").description("Install local git hooks that keep tracked repos and the vault in sync.");
|
|
1780
1869
|
hook.command("install").description("Install post-commit and post-checkout hooks for the nearest git repository.").action(async () => {
|
|
1781
1870
|
const status = await installGitHooks(process2.cwd());
|
|
@@ -2256,67 +2345,8 @@ retrieval.command("doctor").description("Diagnose retrieval index problems and o
|
|
|
2256
2345
|
log(`Warning: ${warning}`);
|
|
2257
2346
|
}
|
|
2258
2347
|
});
|
|
2259
|
-
program.command("scan").description("Quick-start: initialize, ingest, compile, and serve a graph viewer in one command.").argument("<input>", "Directory or public GitHub repo root URL to scan").option("--port <port>", "Port for the graph viewer").option("--no-serve", "Skip launching the graph viewer after compile").option("--branch <name>", "GitHub branch to clone when scanning a public repo URL").option("--ref <ref>", "Git ref, tag, or commit to check out when scanning a public repo URL").option("--checkout-dir <path>", "Persistent checkout directory for a public GitHub repo scan").action(
|
|
2260
|
-
|
|
2261
|
-
await initVault(rootDir, {});
|
|
2262
|
-
if (!isJson()) {
|
|
2263
|
-
log("Initialized workspace.");
|
|
2264
|
-
}
|
|
2265
|
-
const result = isHttpUrlInput(input) ? await addManagedSource(rootDir, input, {
|
|
2266
|
-
compile: true,
|
|
2267
|
-
brief: false,
|
|
2268
|
-
branch: options.branch,
|
|
2269
|
-
ref: options.ref,
|
|
2270
|
-
checkoutDir: options.checkoutDir
|
|
2271
|
-
}) : await ingestDirectory(rootDir, input, {});
|
|
2272
|
-
if (!isJson()) {
|
|
2273
|
-
if ("source" in result) {
|
|
2274
|
-
log(
|
|
2275
|
-
`Registered ${result.source.kind} source ${result.source.id}. Imported ${result.source.lastSyncCounts?.importedCount ?? 0}, updated ${result.source.lastSyncCounts?.updatedCount ?? 0}.`
|
|
2276
|
-
);
|
|
2277
|
-
} else {
|
|
2278
|
-
log(`Ingested ${result.imported.length} file(s).`);
|
|
2279
|
-
}
|
|
2280
|
-
}
|
|
2281
|
-
const compiled = "compile" in result && result.compile ? result.compile : await compileVault(rootDir, {});
|
|
2282
|
-
const { paths } = await loadVaultConfig(rootDir);
|
|
2283
|
-
const shareCardPath = path2.join(paths.wikiDir, "graph", "share-card.md");
|
|
2284
|
-
const shareCardSvgPath = path2.join(paths.wikiDir, "graph", "share-card.svg");
|
|
2285
|
-
const shareKitPath = path2.join(paths.wikiDir, "graph", "share-kit");
|
|
2286
|
-
if (!isJson()) {
|
|
2287
|
-
log(`Compiled ${compiled.sourceCount} source(s), ${compiled.pageCount} page(s).`);
|
|
2288
|
-
log(`Share card: ${shareCardPath}`);
|
|
2289
|
-
log(`Visual card: ${shareCardSvgPath}`);
|
|
2290
|
-
log(`Share kit: ${shareKitPath}`);
|
|
2291
|
-
log("Post text: swarmvault graph share --post");
|
|
2292
|
-
}
|
|
2293
|
-
if (options.serve !== false) {
|
|
2294
|
-
const port = options.port ? parsePositiveInt(options.port, 0) || void 0 : void 0;
|
|
2295
|
-
const server = await startGraphServer(rootDir, port, { full: false });
|
|
2296
|
-
if (isJson()) {
|
|
2297
|
-
emitJson({
|
|
2298
|
-
...result,
|
|
2299
|
-
compiled,
|
|
2300
|
-
shareCardPath,
|
|
2301
|
-
shareCardSvgPath,
|
|
2302
|
-
shareKitPath,
|
|
2303
|
-
port: server.port,
|
|
2304
|
-
url: `http://localhost:${server.port}`
|
|
2305
|
-
});
|
|
2306
|
-
} else {
|
|
2307
|
-
log(`Graph viewer running at http://localhost:${server.port}`);
|
|
2308
|
-
}
|
|
2309
|
-
process2.on("SIGINT", async () => {
|
|
2310
|
-
try {
|
|
2311
|
-
await server.close();
|
|
2312
|
-
} catch {
|
|
2313
|
-
}
|
|
2314
|
-
process2.exit(0);
|
|
2315
|
-
});
|
|
2316
|
-
} else if (isJson()) {
|
|
2317
|
-
emitJson({ ...result, compiled, shareCardPath, shareCardSvgPath, shareKitPath });
|
|
2318
|
-
}
|
|
2319
|
-
});
|
|
2348
|
+
program.command("scan").description("Quick-start: initialize, ingest, compile, and serve a graph viewer in one command.").argument("<input>", "Directory or public GitHub repo root URL to scan").option("--port <port>", "Port for the graph viewer").option("--no-serve", "Skip launching the graph viewer after compile").option("--no-viz", "Compatibility alias for --no-serve; skip launching the graph viewer after compile").option("--mcp", "Start the MCP stdio server after compile instead of launching the graph viewer", false).option("--branch <name>", "GitHub branch to clone when scanning a public repo URL").option("--ref <ref>", "Git ref, tag, or commit to check out when scanning a public repo URL").option("--checkout-dir <path>", "Persistent checkout directory for a public GitHub repo scan").action(runScanCommand);
|
|
2349
|
+
program.command("clone").description("Compatibility alias for scan: initialize, clone/register a public repo URL, and compile it into the vault.").argument("<input>", "Public GitHub repo URL or local directory to scan").option("--port <port>", "Port for the graph viewer").option("--no-serve", "Skip launching the graph viewer after compile").option("--no-viz", "Compatibility alias for --no-serve; skip launching the graph viewer after compile").option("--mcp", "Start the MCP stdio server after compile instead of launching the graph viewer", false).option("--branch <name>", "GitHub branch to clone when scanning a public repo URL").option("--ref <ref>", "Git ref, tag, or commit to check out when scanning a public repo URL").option("--checkout-dir <path>", "Persistent checkout directory for a public GitHub repo scan").action(runScanCommand);
|
|
2320
2350
|
function enableStructuredJsonOnSubcommands(command) {
|
|
2321
2351
|
for (const subcommand of command.commands) {
|
|
2322
2352
|
const hasJsonOption = subcommand.options.some((option) => option.attributeName() === "json");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmvaultai/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.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.11.0",
|
|
48
48
|
"commander": "^14.0.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|