@swarmvaultai/cli 1.1.0 → 1.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
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.
package/README.md CHANGED
@@ -39,6 +39,7 @@ swarmvault ingest ./repo
39
39
  swarmvault add https://arxiv.org/abs/2401.12345
40
40
  swarmvault compile --max-tokens 120000
41
41
  swarmvault diff
42
+ swarmvault graph share --post
42
43
  swarmvault benchmark
43
44
  swarmvault query "What keeps recurring?" --commit
44
45
  swarmvault query "Turn this into slides" --format slides
@@ -85,6 +86,7 @@ Quick-start a scratch vault from a local directory in one command.
85
86
  - initializes the current directory as a SwarmVault workspace
86
87
  - ingests the supplied directory as local sources
87
88
  - compiles the vault immediately
89
+ - writes `wiki/graph/share-card.md` and prints the path
88
90
  - starts `graph serve` unless you pass `--no-serve`
89
91
  - respects `--port` when you want a specific viewer port
90
92
 
@@ -97,6 +99,7 @@ Create a temporary sample vault with bundled sources, compile it immediately, an
97
99
  - writes the demo vault under the system temp directory
98
100
  - requires no API keys or extra setup
99
101
  - is the fastest way to inspect the full init + ingest + compile + graph workflow on a clean machine
102
+ - writes `wiki/graph/share-card.md` inside the demo vault
100
103
  - respects `--port` when you want a specific viewer port
101
104
 
102
105
  ### `swarmvault diff`
@@ -207,6 +210,7 @@ Compile the current manifests into:
207
210
  - generated markdown in `wiki/`
208
211
  - structured graph data in `state/graph.json`
209
212
  - local search data in `state/search.sqlite`
213
+ - a share card at `wiki/graph/share-card.md`
210
214
 
211
215
  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.
212
216
 
@@ -366,6 +370,15 @@ Inspect graph metadata, community membership, neighbors, provenance, and group-p
366
370
 
367
371
  List the most connected bridge-heavy nodes in the current graph.
368
372
 
373
+ ### `swarmvault graph share [--post]`
374
+
375
+ Print a shareable summary of the compiled graph.
376
+
377
+ - default output is the same markdown shape written to `wiki/graph/share-card.md`
378
+ - `--post` prints only the concise social-post text
379
+ - `--json` emits the structured share artifact for automation
380
+ - useful immediately after `swarmvault scan`, `swarmvault demo`, or a normal compile
381
+
369
382
  ### `swarmvault graph blast <target> [--depth <n>]`
370
383
 
371
384
  Trace the reverse-import blast radius of changing a file or module.
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  // src/index.ts
4
4
  import { readFileSync } from "fs";
5
5
  import { readFile as readFile2 } from "fs/promises";
6
+ import path2 from "path";
6
7
  import process2 from "process";
7
8
  import { createInterface } from "readline/promises";
8
9
  import {
@@ -14,6 +15,7 @@ import {
14
15
  autoCommitWikiChanges,
15
16
  benchmarkVault,
16
17
  blastRadiusVault,
18
+ buildGraphShareArtifact,
17
19
  compileVault,
18
20
  consolidateVault,
19
21
  createSupersessionEdge,
@@ -53,10 +55,12 @@ import {
53
55
  queryGraphVault,
54
56
  queryVault,
55
57
  readApproval,
58
+ readGraphReport,
56
59
  registerLocalWhisperProvider,
57
60
  rejectApproval,
58
61
  reloadManagedSources,
59
62
  removeWatchedRoot,
63
+ renderGraphShareMarkdown,
60
64
  resumeSourceSession,
61
65
  reviewManagedSource,
62
66
  reviewSourceScope,
@@ -287,9 +291,9 @@ program.name("swarmvault").description("SwarmVault is a local-first knowledge co
287
291
  function readCliVersion() {
288
292
  try {
289
293
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
290
- return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "1.1.0";
294
+ return typeof packageJson.version === "string" && packageJson.version.trim() ? packageJson.version : "1.2.0";
291
295
  } catch {
292
- return "1.1.0";
296
+ return "1.2.0";
293
297
  }
294
298
  }
295
299
  function parsePositiveInt(value, fallback) {
@@ -971,6 +975,22 @@ graph.command("export").description(
971
975
  }
972
976
  }
973
977
  );
978
+ graph.command("share").description("Print a shareable summary of the compiled graph.").option("--post", "Print only the short social post text", false).action(async (options) => {
979
+ const { paths } = await loadVaultConfig(process2.cwd());
980
+ const raw = await readFile2(paths.graphPath, "utf-8");
981
+ const graph2 = JSON.parse(raw);
982
+ const report = await readGraphReport(process2.cwd());
983
+ const artifact = buildGraphShareArtifact({
984
+ graph: graph2,
985
+ report,
986
+ vaultName: path2.basename(paths.rootDir)
987
+ });
988
+ if (isJson()) {
989
+ emitJson(artifact);
990
+ return;
991
+ }
992
+ log(options.post ? artifact.shortPost : renderGraphShareMarkdown(artifact));
993
+ });
974
994
  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) => {
975
995
  const budget = options.budget ? parsePositiveInt(options.budget, 0) || void 0 : void 0;
976
996
  const result = await queryGraphVault(process2.cwd(), question, {
@@ -1431,15 +1451,15 @@ program.command("install").description("Install SwarmVault instructions for an a
1431
1451
  program.command("demo").description("Try SwarmVault with a bundled sample vault \u2014 zero config, zero API keys.").option("--port <port>", "Port for the graph viewer").option("--no-serve", "Skip launching the graph viewer after compile").action(async (options) => {
1432
1452
  const { mkdtemp, writeFile: writeFile2, mkdir: mkdir2 } = await import("fs/promises");
1433
1453
  const { tmpdir } = await import("os");
1434
- const path2 = await import("path");
1435
- const demoDir = await mkdtemp(path2.join(tmpdir(), "swarmvault-demo-"));
1454
+ const path3 = await import("path");
1455
+ const demoDir = await mkdtemp(path3.join(tmpdir(), "swarmvault-demo-"));
1436
1456
  if (!isJson()) {
1437
1457
  log(`Creating demo vault in ${demoDir}`);
1438
1458
  }
1439
- const rawDir = path2.join(demoDir, "raw", "sources");
1459
+ const rawDir = path3.join(demoDir, "raw", "sources");
1440
1460
  await mkdir2(rawDir, { recursive: true });
1441
1461
  await writeFile2(
1442
- path2.join(rawDir, "llm-wiki-pattern.md"),
1462
+ path3.join(rawDir, "llm-wiki-pattern.md"),
1443
1463
  [
1444
1464
  "# The LLM Wiki Pattern",
1445
1465
  "",
@@ -1468,7 +1488,7 @@ program.command("demo").description("Try SwarmVault with a bundled sample vault
1468
1488
  ].join("\n")
1469
1489
  );
1470
1490
  await writeFile2(
1471
- path2.join(rawDir, "knowledge-graphs.md"),
1491
+ path3.join(rawDir, "knowledge-graphs.md"),
1472
1492
  [
1473
1493
  "# Knowledge Graphs for AI",
1474
1494
  "",
@@ -1501,7 +1521,7 @@ program.command("demo").description("Try SwarmVault with a bundled sample vault
1501
1521
  ].join("\n")
1502
1522
  );
1503
1523
  await writeFile2(
1504
- path2.join(rawDir, "local-first-tools.md"),
1524
+ path3.join(rawDir, "local-first-tools.md"),
1505
1525
  [
1506
1526
  "# Local-First AI Tools",
1507
1527
  "",
@@ -1531,6 +1551,7 @@ program.command("demo").description("Try SwarmVault with a bundled sample vault
1531
1551
  await ingestDirectory(demoDir, rawDir, {});
1532
1552
  await compileVault(demoDir, {});
1533
1553
  const { paths } = await loadVaultConfig(demoDir);
1554
+ const shareCardPath = path3.join(demoDir, "wiki", "graph", "share-card.md");
1534
1555
  let graphStats = "";
1535
1556
  try {
1536
1557
  const raw = await readFile2(paths.graphPath, "utf-8");
@@ -1548,17 +1569,19 @@ program.command("demo").description("Try SwarmVault with a bundled sample vault
1548
1569
  log(" 3. Generated wiki pages with cross-references and a graph report");
1549
1570
  log("");
1550
1571
  log(`Vault location: ${demoDir}`);
1572
+ log(`Share card: ${shareCardPath}`);
1551
1573
  }
1552
1574
  if (options.serve !== false) {
1553
1575
  const port = options.port ? parsePositiveInt(options.port, 0) || void 0 : void 0;
1554
1576
  const server = await startGraphServer(demoDir, port, { full: false });
1555
1577
  if (isJson()) {
1556
- emitJson({ demoDir, graphStats: graphStats.trim(), port: server.port, url: `http://localhost:${server.port}` });
1578
+ emitJson({ demoDir, graphStats: graphStats.trim(), shareCardPath, port: server.port, url: `http://localhost:${server.port}` });
1557
1579
  } else {
1558
1580
  log(`Graph viewer running at http://localhost:${server.port}`);
1559
1581
  log("");
1560
1582
  log("Try next:");
1561
1583
  log(` cd ${demoDir}`);
1584
+ log(" swarmvault graph share --post");
1562
1585
  log(' swarmvault query "How does contradiction detection work?"');
1563
1586
  log(" swarmvault lint");
1564
1587
  }
@@ -1570,11 +1593,12 @@ program.command("demo").description("Try SwarmVault with a bundled sample vault
1570
1593
  process2.exit(0);
1571
1594
  });
1572
1595
  } else if (isJson()) {
1573
- emitJson({ demoDir, graphStats: graphStats.trim() });
1596
+ emitJson({ demoDir, graphStats: graphStats.trim(), shareCardPath });
1574
1597
  } else {
1575
1598
  log("");
1576
1599
  log("Try next:");
1577
1600
  log(` cd ${demoDir}`);
1601
+ log(" swarmvault graph share --post");
1578
1602
  log(" swarmvault graph serve");
1579
1603
  log(' swarmvault query "How does contradiction detection work?"');
1580
1604
  }
@@ -1702,14 +1726,17 @@ program.command("scan").description("Quick-start: initialize, ingest, compile, a
1702
1726
  log(`Ingested ${result.imported.length} file(s).`);
1703
1727
  }
1704
1728
  const compiled = await compileVault(rootDir, {});
1729
+ const shareCardPath = path2.join(rootDir, "wiki", "graph", "share-card.md");
1705
1730
  if (!isJson()) {
1706
1731
  log(`Compiled ${compiled.sourceCount} source(s), ${compiled.pageCount} page(s).`);
1732
+ log(`Share card: ${shareCardPath}`);
1733
+ log("Post text: swarmvault graph share --post");
1707
1734
  }
1708
1735
  if (options.serve !== false) {
1709
1736
  const port = options.port ? parsePositiveInt(options.port, 0) || void 0 : void 0;
1710
1737
  const server = await startGraphServer(rootDir, port, { full: false });
1711
1738
  if (isJson()) {
1712
- emitJson({ ...result, compiled, port: server.port, url: `http://localhost:${server.port}` });
1739
+ emitJson({ ...result, compiled, shareCardPath, port: server.port, url: `http://localhost:${server.port}` });
1713
1740
  } else {
1714
1741
  log(`Graph viewer running at http://localhost:${server.port}`);
1715
1742
  }
@@ -1721,7 +1748,7 @@ program.command("scan").description("Quick-start: initialize, ingest, compile, a
1721
1748
  process2.exit(0);
1722
1749
  });
1723
1750
  } else if (isJson()) {
1724
- emitJson({ ...result, compiled });
1751
+ emitJson({ ...result, compiled, shareCardPath });
1725
1752
  }
1726
1753
  });
1727
1754
  function enableStructuredJsonOnSubcommands(command) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarmvaultai/cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Global CLI for SwarmVault.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -37,19 +37,18 @@
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
- },
46
40
  "dependencies": {
47
- "@swarmvaultai/engine": "1.1.0",
41
+ "@swarmvaultai/engine": "1.2.0",
48
42
  "commander": "^14.0.1"
49
43
  },
50
44
  "devDependencies": {
51
45
  "@types/node": "^24.6.0",
52
46
  "tsup": "^8.5.0",
53
47
  "vitest": "^3.2.4"
48
+ },
49
+ "scripts": {
50
+ "build": "tsup src/index.ts --format esm --dts",
51
+ "test": "vitest run",
52
+ "typecheck": "tsc --noEmit"
54
53
  }
55
- }
54
+ }