@deeplake/hivemind 0.7.44 → 0.7.46

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.
Files changed (35) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/bundle/cli.js +3116 -208
  4. package/codex/bundle/capture.js +43 -0
  5. package/codex/bundle/commands/auth-login.js +43 -0
  6. package/codex/bundle/graph-pull-worker.js +1185 -0
  7. package/codex/bundle/pre-tool-use.js +43 -0
  8. package/codex/bundle/session-start-setup.js +43 -0
  9. package/codex/bundle/session-start.js +70 -4
  10. package/codex/bundle/shell/deeplake-shell.js +577 -25
  11. package/codex/bundle/skillify-worker.js +30 -3
  12. package/codex/bundle/stop.js +97 -50
  13. package/cursor/bundle/capture.js +97 -50
  14. package/cursor/bundle/commands/auth-login.js +43 -0
  15. package/cursor/bundle/graph-pull-worker.js +1185 -0
  16. package/cursor/bundle/pre-tool-use.js +43 -0
  17. package/cursor/bundle/session-end.js +49 -44
  18. package/cursor/bundle/session-start.js +66 -0
  19. package/cursor/bundle/shell/deeplake-shell.js +577 -25
  20. package/cursor/bundle/skillify-worker.js +30 -3
  21. package/hermes/bundle/capture.js +97 -50
  22. package/hermes/bundle/commands/auth-login.js +43 -0
  23. package/hermes/bundle/graph-pull-worker.js +1185 -0
  24. package/hermes/bundle/pre-tool-use.js +43 -0
  25. package/hermes/bundle/session-end.js +49 -44
  26. package/hermes/bundle/session-start.js +66 -0
  27. package/hermes/bundle/shell/deeplake-shell.js +577 -25
  28. package/hermes/bundle/skillify-worker.js +30 -3
  29. package/mcp/bundle/server.js +43 -0
  30. package/openclaw/dist/chunks/{config-XEK4MJJS.js → config-O5PDJQ7Y.js} +1 -0
  31. package/openclaw/dist/index.js +47 -2
  32. package/openclaw/dist/skillify-worker.js +30 -3
  33. package/openclaw/openclaw.plugin.json +1 -1
  34. package/openclaw/package.json +1 -1
  35. package/package.json +3 -1
package/bundle/cli.js CHANGED
@@ -144,23 +144,23 @@ function warn(msg) {
144
144
  function confirm(message, defaultYes = true) {
145
145
  const hint = defaultYes ? "[Y/n]" : "[y/N]";
146
146
  const rl = createInterface({ input: process.stdin, output: process.stderr });
147
- return new Promise((resolve2) => {
147
+ return new Promise((resolve6) => {
148
148
  rl.question(`${message} ${hint} `, (answer) => {
149
149
  rl.close();
150
150
  const a = answer.trim().toLowerCase();
151
151
  if (a === "")
152
- resolve2(defaultYes);
152
+ resolve6(defaultYes);
153
153
  else
154
- resolve2(a === "y" || a === "yes");
154
+ resolve6(a === "y" || a === "yes");
155
155
  });
156
156
  });
157
157
  }
158
158
  function promptLine(message) {
159
159
  const rl = createInterface({ input: process.stdin, output: process.stderr });
160
- return new Promise((resolve2) => {
160
+ return new Promise((resolve6) => {
161
161
  rl.question(message, (answer) => {
162
162
  rl.close();
163
- resolve2(answer.trim());
163
+ resolve6(answer.trim());
164
164
  });
165
165
  });
166
166
  }
@@ -4431,6 +4431,7 @@ function loadConfig() {
4431
4431
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
4432
4432
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
4433
4433
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
4434
+ codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
4434
4435
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join16(home, ".deeplake", "memory")
4435
4436
  };
4436
4437
  }
@@ -4536,9 +4537,33 @@ function validateSchema(label, cols) {
4536
4537
  }
4537
4538
  }
4538
4539
  }
4540
+ var CODEBASE_COLUMNS = Object.freeze([
4541
+ // Identity key (matches the PK below)
4542
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
4543
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
4544
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
4545
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
4546
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
4547
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
4548
+ // Observation metadata
4549
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
4550
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
4551
+ { name: "ts", sql: "TIMESTAMP" },
4552
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
4553
+ // Snapshot payload
4554
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
4555
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
4556
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
4557
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
4558
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
4559
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
4560
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
4561
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
4562
+ ]);
4539
4563
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
4540
4564
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
4541
4565
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
4566
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
4542
4567
  function buildCreateTableSql(tableName, cols) {
4543
4568
  const safe = sqlIdent(tableName);
4544
4569
  const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
@@ -4745,7 +4770,7 @@ function getQueryTimeoutMs() {
4745
4770
  return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
4746
4771
  }
4747
4772
  function sleep2(ms) {
4748
- return new Promise((resolve2) => setTimeout(resolve2, ms));
4773
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
4749
4774
  }
4750
4775
  function isTimeoutError(error) {
4751
4776
  const name = error instanceof Error ? error.name.toLowerCase() : "";
@@ -4775,7 +4800,7 @@ var Semaphore = class {
4775
4800
  this.active++;
4776
4801
  return;
4777
4802
  }
4778
- await new Promise((resolve2) => this.waiting.push(resolve2));
4803
+ await new Promise((resolve6) => this.waiting.push(resolve6));
4779
4804
  }
4780
4805
  release() {
4781
4806
  this.active--;
@@ -5085,6 +5110,24 @@ var DeeplakeApi = class {
5085
5110
  * This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
5086
5111
  * worker.
5087
5112
  */
5113
+ /**
5114
+ * Create the codebase table. One row per (org, workspace, repo, user,
5115
+ * worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
5116
+ * + index follow the same pattern as ensureSessionsTable.
5117
+ */
5118
+ async ensureCodebaseTable(name) {
5119
+ const safe = sqlIdent(name);
5120
+ const tables = await this.listTables();
5121
+ if (!tables.includes(safe)) {
5122
+ log4(`table "${safe}" not found, creating`);
5123
+ await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
5124
+ log4(`table "${safe}" created`);
5125
+ if (!tables.includes(safe))
5126
+ this._tablesCache = [...tables, safe];
5127
+ }
5128
+ await this.healSchema(safe, CODEBASE_COLUMNS);
5129
+ await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
5130
+ }
5088
5131
  async ensureSkillsTable(name) {
5089
5132
  const safe = sqlIdent(name);
5090
5133
  const tables = await this.listTables();
@@ -5410,32 +5453,2061 @@ async function runAuthCommand(args) {
5410
5453
  console.log("Commands: login, logout, whoami, org list, org switch, workspaces, workspace, sessions prune, invite, members, remove, autoupdate");
5411
5454
  }
5412
5455
  }
5413
- if (process.argv[1] && process.argv[1].endsWith("auth-login.js")) {
5414
- runAuthCommand(process.argv.slice(2)).catch((e) => {
5415
- console.error(e.message);
5416
- process.exit(1);
5417
- });
5456
+ if (process.argv[1] && process.argv[1].endsWith("auth-login.js")) {
5457
+ runAuthCommand(process.argv.slice(2)).catch((e) => {
5458
+ console.error(e.message);
5459
+ process.exit(1);
5460
+ });
5461
+ }
5462
+
5463
+ // dist/src/commands/graph.js
5464
+ import { execSync as execSync3 } from "node:child_process";
5465
+ import { readFileSync as readFileSync20, readdirSync as readdirSync2 } from "node:fs";
5466
+ import { join as join27, relative, resolve as resolve4, sep } from "node:path";
5467
+ import { createHash as createHash6 } from "node:crypto";
5468
+
5469
+ // dist/src/graph/cache.js
5470
+ import { createHash } from "node:crypto";
5471
+ import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync15, renameSync as renameSync4, writeFileSync as writeFileSync11 } from "node:fs";
5472
+ import { dirname as dirname3, join as join20 } from "node:path";
5473
+ var CACHE_SCHEMA_VERSION = 1;
5474
+ function fileContentHash(contents) {
5475
+ return createHash("sha256").update(contents).digest("hex");
5476
+ }
5477
+ function cacheDir(baseDir) {
5478
+ return join20(baseDir, ".cache");
5479
+ }
5480
+ function cachePath(baseDir, contentSha256) {
5481
+ return join20(cacheDir(baseDir), `${contentSha256}.json`);
5482
+ }
5483
+ function readCache(baseDir, contentSha256, relativePath) {
5484
+ const path = cachePath(baseDir, contentSha256);
5485
+ if (!existsSync15(path))
5486
+ return null;
5487
+ let raw;
5488
+ try {
5489
+ raw = readFileSync15(path, "utf8");
5490
+ } catch {
5491
+ return null;
5492
+ }
5493
+ let parsed;
5494
+ try {
5495
+ parsed = JSON.parse(raw);
5496
+ } catch {
5497
+ return null;
5498
+ }
5499
+ if (parsed === null || typeof parsed !== "object" || parsed.schema !== CACHE_SCHEMA_VERSION || parsed.content_sha256 !== contentSha256) {
5500
+ return null;
5501
+ }
5502
+ const cached = parsed.extraction;
5503
+ if (cached === void 0 || typeof cached !== "object" || !Array.isArray(cached.nodes) || !Array.isArray(cached.edges) || !Array.isArray(cached.parse_errors)) {
5504
+ return null;
5505
+ }
5506
+ if (!validateItems(cached)) {
5507
+ return null;
5508
+ }
5509
+ try {
5510
+ return rewriteSourceFile(cached, relativePath);
5511
+ } catch {
5512
+ return null;
5513
+ }
5514
+ }
5515
+ function validateItems(ex) {
5516
+ if (typeof ex.source_file !== "string")
5517
+ return false;
5518
+ if (typeof ex.language !== "string")
5519
+ return false;
5520
+ for (const n of ex.nodes) {
5521
+ if (n === null || typeof n !== "object")
5522
+ return false;
5523
+ if (typeof n.id !== "string")
5524
+ return false;
5525
+ if (typeof n.label !== "string")
5526
+ return false;
5527
+ if (typeof n.kind !== "string")
5528
+ return false;
5529
+ if (typeof n.source_file !== "string")
5530
+ return false;
5531
+ if (typeof n.source_location !== "string")
5532
+ return false;
5533
+ if (typeof n.language !== "string")
5534
+ return false;
5535
+ if (typeof n.exported !== "boolean")
5536
+ return false;
5537
+ }
5538
+ for (const e of ex.edges) {
5539
+ if (e === null || typeof e !== "object")
5540
+ return false;
5541
+ if (typeof e.source !== "string")
5542
+ return false;
5543
+ if (typeof e.target !== "string")
5544
+ return false;
5545
+ if (typeof e.relation !== "string")
5546
+ return false;
5547
+ if (typeof e.confidence !== "string")
5548
+ return false;
5549
+ if (e.ord !== void 0 && typeof e.ord !== "number")
5550
+ return false;
5551
+ }
5552
+ for (const p of ex.parse_errors) {
5553
+ if (p === null || typeof p !== "object")
5554
+ return false;
5555
+ if (typeof p.source_file !== "string")
5556
+ return false;
5557
+ if (typeof p.message !== "string")
5558
+ return false;
5559
+ if (p.location !== void 0 && typeof p.location !== "string")
5560
+ return false;
5561
+ }
5562
+ return true;
5563
+ }
5564
+ function writeCache(baseDir, contentSha256, extraction) {
5565
+ const entry = {
5566
+ schema: CACHE_SCHEMA_VERSION,
5567
+ content_sha256: contentSha256,
5568
+ extraction
5569
+ };
5570
+ const path = cachePath(baseDir, contentSha256);
5571
+ try {
5572
+ mkdirSync7(dirname3(path), { recursive: true });
5573
+ const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
5574
+ writeFileSync11(tmp, JSON.stringify(entry));
5575
+ renameSync4(tmp, path);
5576
+ } catch {
5577
+ }
5578
+ }
5579
+ function rewriteSourceFile(cached, newPath) {
5580
+ const oldPath = cached.source_file;
5581
+ if (oldPath === newPath) {
5582
+ return cached;
5583
+ }
5584
+ const swap = (id) => {
5585
+ if (id.startsWith(`${oldPath}:`))
5586
+ return `${newPath}${id.slice(oldPath.length)}`;
5587
+ if (id.startsWith(`unresolved:${oldPath}:`)) {
5588
+ return `unresolved:${newPath}${id.slice(`unresolved:${oldPath}`.length)}`;
5589
+ }
5590
+ return id;
5591
+ };
5592
+ return {
5593
+ source_file: newPath,
5594
+ language: cached.language,
5595
+ // The synthetic module node uses source_file as its `label` (see
5596
+ // makeModuleNode in the extractor). On a cache hit after a rename/copy
5597
+ // we already rewrite `id` + `source_file`, but were leaving `label`
5598
+ // pointing at the OLD path — the snapshot then disagreed with a
5599
+ // fresh (non-cached) extraction. Rewrite `label` for module nodes too.
5600
+ // CodeRabbit P1.
5601
+ nodes: cached.nodes.map((n) => ({
5602
+ ...n,
5603
+ id: swap(n.id),
5604
+ label: n.kind === "module" ? newPath : n.label,
5605
+ source_file: newPath
5606
+ })),
5607
+ edges: cached.edges.map((e) => ({ ...e, source: swap(e.source), target: swap(e.target) })),
5608
+ parse_errors: cached.parse_errors.map((p) => ({ ...p, source_file: newPath }))
5609
+ };
5610
+ }
5611
+
5612
+ // dist/src/graph/deeplake-push.js
5613
+ import { createHash as createHash2 } from "node:crypto";
5614
+ async function pushSnapshot(snapshot, worktreeId, deps = {}) {
5615
+ if (process.env.HIVEMIND_GRAPH_PUSH === "0") {
5616
+ return { kind: "skipped-disabled" };
5617
+ }
5618
+ const config = (deps.loadConfig ?? loadConfig)();
5619
+ if (config === null) {
5620
+ return { kind: "skipped-no-auth" };
5621
+ }
5622
+ const commitSha = snapshot.graph.commit_sha;
5623
+ if (commitSha === null) {
5624
+ return { kind: "skipped-no-commit" };
5625
+ }
5626
+ const api = (deps.makeApi ?? defaultMakeApi)(config);
5627
+ try {
5628
+ await api.ensureCodebaseTable(config.codebaseTableName);
5629
+ } catch (err) {
5630
+ return errorOutcome("ensureCodebaseTable", err);
5631
+ }
5632
+ const snapshotSha256 = computeSnapshotSha256(snapshot);
5633
+ const tableId = sqlIdent(config.codebaseTableName);
5634
+ const repoSlug = snapshot.graph.repo_key;
5635
+ const userId = config.userName;
5636
+ const selectSql = `SELECT snapshot_sha256 FROM "${tableId}" WHERE org_id = '${sqlStr(config.orgId)}' AND workspace_id = '${sqlStr(config.workspaceId)}' AND repo_slug = '${sqlStr(repoSlug)}' AND user_id = '${sqlStr(userId)}' AND worktree_id = '${sqlStr(worktreeId)}' AND commit_sha = '${sqlStr(commitSha)}'`;
5637
+ let existing;
5638
+ try {
5639
+ existing = await api.query(selectSql);
5640
+ } catch (err) {
5641
+ return errorOutcome("SELECT existing", err);
5642
+ }
5643
+ if (existing.length > 0) {
5644
+ const cloudSha = String(existing[0].snapshot_sha256 ?? "");
5645
+ if (cloudSha === snapshotSha256) {
5646
+ return { kind: "already-current", commitSha };
5647
+ }
5648
+ return {
5649
+ kind: "drift",
5650
+ commitSha,
5651
+ localSha256: snapshotSha256,
5652
+ cloudSha256: cloudSha
5653
+ };
5654
+ }
5655
+ const canonical = canonicalJSON(snapshot);
5656
+ const observation = snapshot.observation;
5657
+ const insertSql = `INSERT INTO "${tableId}" (org_id, workspace_id, repo_slug, user_id, worktree_id, commit_sha, parent_sha, branch, ts, pushed_by, snapshot_sha256, snapshot_jsonb, node_count, edge_count, generator, generator_version, schema_version) VALUES ('${sqlStr(config.orgId)}', '${sqlStr(config.workspaceId)}', '${sqlStr(repoSlug)}', '${sqlStr(userId)}', '${sqlStr(worktreeId)}', '${sqlStr(commitSha)}', '', '${sqlStr(observation.branch ?? "")}', '${sqlStr(observation.ts)}', '${sqlStr(userId)}', '${sqlStr(snapshotSha256)}', '${sqlStr(canonical)}', ${snapshot.nodes.length}, ${snapshot.links.length}, '${sqlStr(snapshot.graph.generator)}', '${sqlStr(observation.generator_version)}', ${snapshot.graph.schema_version})`;
5658
+ try {
5659
+ await api.query(insertSql);
5660
+ } catch (err) {
5661
+ return errorOutcome("INSERT", err);
5662
+ }
5663
+ try {
5664
+ const verify = await api.query(selectSql);
5665
+ if (verify.length > 1) {
5666
+ return { kind: "inserted-with-duplicate-race", commitSha, rowCount: verify.length };
5667
+ }
5668
+ } catch {
5669
+ }
5670
+ return { kind: "inserted", commitSha };
5671
+ }
5672
+ function defaultMakeApi(config) {
5673
+ return new DeeplakeApi(config.token, config.apiUrl, config.orgId, config.workspaceId, config.tableName);
5674
+ }
5675
+ function errorOutcome(stage, err) {
5676
+ const message = err instanceof Error ? err.message : String(err);
5677
+ return { kind: "error", message: `${stage}: ${message}` };
5678
+ }
5679
+ function computeSnapshotSha256(snapshot) {
5680
+ const stable = {
5681
+ directed: snapshot.directed,
5682
+ multigraph: snapshot.multigraph,
5683
+ graph: snapshot.graph,
5684
+ nodes: snapshot.nodes,
5685
+ links: snapshot.links
5686
+ };
5687
+ return createHash2("sha256").update(canonicalJSON(stable)).digest("hex");
5688
+ }
5689
+ function canonicalJSON(value) {
5690
+ return JSON.stringify(value, (_key, v) => {
5691
+ if (v !== null && typeof v === "object" && !Array.isArray(v)) {
5692
+ const sorted = {};
5693
+ for (const k of Object.keys(v).sort()) {
5694
+ sorted[k] = v[k];
5695
+ }
5696
+ return sorted;
5697
+ }
5698
+ return v;
5699
+ });
5700
+ }
5701
+
5702
+ // dist/src/graph/deeplake-pull.js
5703
+ import { execFileSync as execFileSync4 } from "node:child_process";
5704
+ import { createHash as createHash5 } from "node:crypto";
5705
+ import { existsSync as existsSync18, mkdirSync as mkdirSync11, renameSync as renameSync7, writeFileSync as writeFileSync14 } from "node:fs";
5706
+ import { dirname as dirname7, join as join24 } from "node:path";
5707
+
5708
+ // dist/src/utils/repo-identity.js
5709
+ import { execSync as execSync2 } from "node:child_process";
5710
+ import { createHash as createHash3 } from "node:crypto";
5711
+ import { basename, resolve as resolve2 } from "node:path";
5712
+ var DEFAULT_PORTS = {
5713
+ http: "80",
5714
+ https: "443",
5715
+ ssh: "22",
5716
+ git: "9418"
5717
+ };
5718
+ function normalizeGitRemoteUrl(url) {
5719
+ let s = url.trim();
5720
+ const schemeMatch = s.match(/^([a-z][a-z0-9+.-]*):\/\//i);
5721
+ const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null;
5722
+ if (schemeMatch)
5723
+ s = s.slice(schemeMatch[0].length);
5724
+ if (!scheme) {
5725
+ const scp = s.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);
5726
+ if (scp)
5727
+ s = `${scp[1]}/${scp[2]}`;
5728
+ }
5729
+ s = s.replace(/^[^@/]+@/, "");
5730
+ if (scheme && DEFAULT_PORTS[scheme]) {
5731
+ s = s.replace(new RegExp(`^([^/]+):${DEFAULT_PORTS[scheme]}(/|$)`), "$1$2");
5732
+ }
5733
+ s = s.replace(/\.git\/?$/i, "");
5734
+ s = s.replace(/\/+$/, "");
5735
+ return s.toLowerCase();
5736
+ }
5737
+ function deriveProjectKey(cwd) {
5738
+ const absCwd = resolve2(cwd);
5739
+ const project = basename(absCwd) || "unknown";
5740
+ let signature = null;
5741
+ try {
5742
+ const raw = execSync2("git config --get remote.origin.url", {
5743
+ cwd: absCwd,
5744
+ encoding: "utf-8",
5745
+ stdio: ["ignore", "pipe", "ignore"]
5746
+ }).trim();
5747
+ signature = raw ? normalizeGitRemoteUrl(raw) : null;
5748
+ } catch {
5749
+ }
5750
+ const input = signature ?? absCwd;
5751
+ const key = createHash3("sha1").update(input).digest("hex").slice(0, 16);
5752
+ return { key, project };
5753
+ }
5754
+
5755
+ // dist/src/graph/last-build.js
5756
+ import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync16, renameSync as renameSync5, writeFileSync as writeFileSync12 } from "node:fs";
5757
+ import { dirname as dirname4, join as join21 } from "node:path";
5758
+ function lastBuildPath(baseDir, worktreeId) {
5759
+ if (worktreeId !== void 0) {
5760
+ return join21(baseDir, "worktrees", worktreeId, ".last-build.json");
5761
+ }
5762
+ return join21(baseDir, ".last-build.json");
5763
+ }
5764
+ function writeLastBuild(baseDir, state, worktreeId) {
5765
+ const path = lastBuildPath(baseDir, worktreeId);
5766
+ try {
5767
+ mkdirSync8(dirname4(path), { recursive: true });
5768
+ const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
5769
+ writeFileSync12(tmp, JSON.stringify(state));
5770
+ renameSync5(tmp, path);
5771
+ } catch {
5772
+ }
5773
+ }
5774
+ function readLastBuild(baseDir, worktreeId) {
5775
+ let path = lastBuildPath(baseDir, worktreeId);
5776
+ if (!existsSync16(path)) {
5777
+ if (worktreeId === void 0)
5778
+ return null;
5779
+ const legacy = lastBuildPath(baseDir, void 0);
5780
+ if (!existsSync16(legacy))
5781
+ return null;
5782
+ path = legacy;
5783
+ }
5784
+ let raw;
5785
+ try {
5786
+ raw = readFileSync16(path, "utf8");
5787
+ } catch {
5788
+ return null;
5789
+ }
5790
+ let parsed;
5791
+ try {
5792
+ parsed = JSON.parse(raw);
5793
+ } catch {
5794
+ return null;
5795
+ }
5796
+ if (parsed === null || typeof parsed !== "object")
5797
+ return null;
5798
+ const o = parsed;
5799
+ if (typeof o.ts !== "number" || !Number.isFinite(o.ts))
5800
+ return null;
5801
+ if (o.commit_sha !== null && typeof o.commit_sha !== "string")
5802
+ return null;
5803
+ if (typeof o.snapshot_sha256 !== "string")
5804
+ return null;
5805
+ const out = { ts: o.ts, commit_sha: o.commit_sha, snapshot_sha256: o.snapshot_sha256 };
5806
+ if (typeof o.node_count === "number" && Number.isFinite(o.node_count) && o.node_count >= 0) {
5807
+ out.node_count = o.node_count;
5808
+ }
5809
+ if (typeof o.edge_count === "number" && Number.isFinite(o.edge_count) && o.edge_count >= 0) {
5810
+ out.edge_count = o.edge_count;
5811
+ }
5812
+ return out;
5813
+ }
5814
+
5815
+ // dist/src/graph/history.js
5816
+ import { appendFileSync as appendFileSync2, existsSync as existsSync17, mkdirSync as mkdirSync9, readFileSync as readFileSync17 } from "node:fs";
5817
+ import { dirname as dirname5, join as join22 } from "node:path";
5818
+ function historyPath(baseDir) {
5819
+ return join22(baseDir, "history.jsonl");
5820
+ }
5821
+ function appendHistoryEntry(baseDir, entry) {
5822
+ const path = historyPath(baseDir);
5823
+ try {
5824
+ mkdirSync9(dirname5(path), { recursive: true });
5825
+ appendFileSync2(path, JSON.stringify(entry) + "\n");
5826
+ } catch {
5827
+ }
5828
+ }
5829
+ function entryFromSnapshot(snapshot, snapshot_sha256, trigger) {
5830
+ return {
5831
+ ts: snapshot.observation.ts,
5832
+ commit_sha: snapshot.graph.commit_sha,
5833
+ snapshot_sha256,
5834
+ node_count: snapshot.nodes.length,
5835
+ edge_count: snapshot.links.length,
5836
+ trigger
5837
+ };
5838
+ }
5839
+ function readHistoryTail(baseDir, n) {
5840
+ const path = historyPath(baseDir);
5841
+ if (!existsSync17(path))
5842
+ return [];
5843
+ let raw;
5844
+ try {
5845
+ raw = readFileSync17(path, "utf8");
5846
+ } catch {
5847
+ return [];
5848
+ }
5849
+ const lines = raw.split("\n").filter((l) => l.length > 0);
5850
+ const entries = [];
5851
+ for (let i = lines.length - 1; i >= 0 && entries.length < n; i--) {
5852
+ const parsed = parseLine(lines[i]);
5853
+ if (parsed !== null)
5854
+ entries.unshift(parsed);
5855
+ }
5856
+ return entries;
5857
+ }
5858
+ function countHistoryEntries(baseDir) {
5859
+ const path = historyPath(baseDir);
5860
+ if (!existsSync17(path))
5861
+ return 0;
5862
+ try {
5863
+ const raw = readFileSync17(path, "utf8");
5864
+ return raw.split("\n").filter((l) => l.length > 0).length;
5865
+ } catch {
5866
+ return 0;
5867
+ }
5868
+ }
5869
+ function parseLine(line) {
5870
+ let obj;
5871
+ try {
5872
+ obj = JSON.parse(line);
5873
+ } catch {
5874
+ return null;
5875
+ }
5876
+ if (obj === null || typeof obj !== "object")
5877
+ return null;
5878
+ const o = obj;
5879
+ if (typeof o.ts !== "string")
5880
+ return null;
5881
+ if (o.commit_sha !== null && typeof o.commit_sha !== "string")
5882
+ return null;
5883
+ if (typeof o.snapshot_sha256 !== "string")
5884
+ return null;
5885
+ if (typeof o.node_count !== "number")
5886
+ return null;
5887
+ if (typeof o.edge_count !== "number")
5888
+ return null;
5889
+ if (typeof o.trigger !== "string")
5890
+ return null;
5891
+ return {
5892
+ ts: o.ts,
5893
+ commit_sha: o.commit_sha,
5894
+ snapshot_sha256: o.snapshot_sha256,
5895
+ node_count: o.node_count,
5896
+ edge_count: o.edge_count,
5897
+ trigger: o.trigger
5898
+ };
5899
+ }
5900
+
5901
+ // dist/src/graph/snapshot.js
5902
+ import { createHash as createHash4 } from "node:crypto";
5903
+ import { mkdirSync as mkdirSync10, renameSync as renameSync6, writeFileSync as writeFileSync13 } from "node:fs";
5904
+ import { homedir as homedir10 } from "node:os";
5905
+ import { dirname as dirname6, join as join23 } from "node:path";
5906
+ function graphsRoot() {
5907
+ return process.env.HIVEMIND_GRAPHS_HOME ?? join23(homedir10(), ".hivemind", "graphs");
5908
+ }
5909
+ function repoDir(repoKey) {
5910
+ return join23(graphsRoot(), repoKey);
5911
+ }
5912
+ function buildSnapshot(extractions, metadata, observation) {
5913
+ const nodes = [];
5914
+ const links = [];
5915
+ for (const ex of extractions) {
5916
+ for (const n of ex.nodes)
5917
+ nodes.push(n);
5918
+ for (const e of ex.edges)
5919
+ links.push(e);
5920
+ }
5921
+ nodes.sort(compareNodes);
5922
+ links.sort(compareEdges);
5923
+ return {
5924
+ directed: true,
5925
+ multigraph: true,
5926
+ graph: metadata,
5927
+ observation,
5928
+ nodes,
5929
+ links
5930
+ };
5931
+ }
5932
+ function compareNodes(a, b) {
5933
+ return cmp(a.id, b.id);
5934
+ }
5935
+ function compareEdges(a, b) {
5936
+ let c = cmp(a.source, b.source);
5937
+ if (c !== 0)
5938
+ return c;
5939
+ c = cmp(a.target, b.target);
5940
+ if (c !== 0)
5941
+ return c;
5942
+ c = cmp(a.relation, b.relation);
5943
+ if (c !== 0)
5944
+ return c;
5945
+ return (a.ord ?? 0) - (b.ord ?? 0);
5946
+ }
5947
+ function cmp(a, b) {
5948
+ return a < b ? -1 : a > b ? 1 : 0;
5949
+ }
5950
+ function canonicalSnapshot(snapshot) {
5951
+ return canonicalJSON2(snapshot);
5952
+ }
5953
+ function computeSnapshotSha2562(snapshot) {
5954
+ const stable = {
5955
+ directed: snapshot.directed,
5956
+ multigraph: snapshot.multigraph,
5957
+ graph: snapshot.graph,
5958
+ nodes: snapshot.nodes,
5959
+ links: snapshot.links
5960
+ };
5961
+ return createHash4("sha256").update(canonicalJSON2(stable)).digest("hex");
5962
+ }
5963
+ function canonicalJSON2(value) {
5964
+ return JSON.stringify(value, (_key, v) => {
5965
+ if (v !== null && typeof v === "object" && !Array.isArray(v)) {
5966
+ const sorted = {};
5967
+ for (const k of Object.keys(v).sort()) {
5968
+ sorted[k] = v[k];
5969
+ }
5970
+ return sorted;
5971
+ }
5972
+ return v;
5973
+ });
5974
+ }
5975
+ function writeSnapshot(snapshot, baseDir, trigger = "unknown", worktreeId) {
5976
+ const sha256 = computeSnapshotSha2562(snapshot);
5977
+ const commitSha = snapshot.graph.commit_sha;
5978
+ const fileBase = commitSha ?? sha256;
5979
+ const snapshotsDir = join23(baseDir, "snapshots");
5980
+ const snapshotPath = join23(snapshotsDir, `${fileBase}.json`);
5981
+ const canonical = canonicalSnapshot(snapshot);
5982
+ writeFileAtomic(snapshotPath, canonical);
5983
+ const worktreeRoot = worktreeId !== void 0 ? join23(baseDir, "worktrees", worktreeId) : baseDir;
5984
+ let latestCommitPath = null;
5985
+ if (commitSha !== null) {
5986
+ latestCommitPath = join23(worktreeRoot, "latest-commit.txt");
5987
+ writeFileAtomic(latestCommitPath, `${commitSha}
5988
+ `);
5989
+ }
5990
+ writeLastBuild(baseDir, {
5991
+ ts: Date.now(),
5992
+ commit_sha: commitSha,
5993
+ snapshot_sha256: sha256,
5994
+ node_count: snapshot.nodes.length,
5995
+ edge_count: snapshot.links.length
5996
+ }, worktreeId);
5997
+ appendHistoryEntry(baseDir, entryFromSnapshot(snapshot, sha256, trigger));
5998
+ return { snapshotPath, latestCommitPath, snapshotSha256: sha256 };
5999
+ }
6000
+ function writeFileAtomic(filePath, contents) {
6001
+ mkdirSync10(dirname6(filePath), { recursive: true });
6002
+ const tmp = `${filePath}.tmp.${process.pid}.${Date.now()}`;
6003
+ writeFileSync13(tmp, contents);
6004
+ renameSync6(tmp, filePath);
6005
+ }
6006
+
6007
+ // dist/src/graph/deeplake-pull.js
6008
+ function workTreeIdFor(cwd) {
6009
+ return createHash5("sha256").update(cwd).digest("hex").slice(0, 16);
6010
+ }
6011
+ async function pullSnapshot(cwd, deps = {}) {
6012
+ if (process.env.HIVEMIND_GRAPH_PULL === "0") {
6013
+ return { kind: "skipped-disabled" };
6014
+ }
6015
+ const config = (deps.loadConfig ?? loadConfig)();
6016
+ if (config === null) {
6017
+ return { kind: "skipped-no-auth" };
6018
+ }
6019
+ const head = (deps.readHead ?? defaultReadHead)(cwd);
6020
+ if (head === null) {
6021
+ return { kind: "skipped-no-head" };
6022
+ }
6023
+ const api = (deps.makeApi ?? defaultMakeApi2)(config);
6024
+ try {
6025
+ await api.ensureCodebaseTable(config.codebaseTableName);
6026
+ } catch (err) {
6027
+ return errorOutcome2("ensureCodebaseTable", err);
6028
+ }
6029
+ const tableId = sqlIdent(config.codebaseTableName);
6030
+ const { key: repoKey } = deriveProjectKey(cwd);
6031
+ const selectSql = `SELECT snapshot_jsonb, snapshot_sha256, ts, node_count, edge_count, branch, generator_version, worktree_id FROM "${tableId}" WHERE org_id = '${sqlStr(config.orgId)}' AND workspace_id = '${sqlStr(config.workspaceId)}' AND repo_slug = '${sqlStr(repoKey)}' AND user_id = '${sqlStr(config.userName)}' AND commit_sha = '${sqlStr(head)}' ORDER BY ts DESC LIMIT 1`;
6032
+ let rows;
6033
+ try {
6034
+ rows = await api.query(selectSql);
6035
+ } catch (err) {
6036
+ return errorOutcome2("SELECT cloud row", err);
6037
+ }
6038
+ if (rows.length === 0) {
6039
+ return { kind: "no-cloud-row", commitSha: head };
6040
+ }
6041
+ const row = rows[0];
6042
+ const cloudSha256 = String(row.snapshot_sha256 ?? "").trim();
6043
+ const cloudPayload = coerceSnapshotPayload(row.snapshot_jsonb);
6044
+ if (cloudPayload === null) {
6045
+ return errorOutcome2("SELECT cloud row", new Error("invalid snapshot_jsonb payload"));
6046
+ }
6047
+ if (cloudSha256 !== "") {
6048
+ const computedSha = createHash5("sha256").update(cloudPayload).digest("hex");
6049
+ if (cloudSha256 !== computedSha) {
6050
+ return errorOutcome2("SELECT cloud row", new Error(`snapshot_sha256 mismatch (expected ${cloudSha256}, got ${computedSha})`));
6051
+ }
6052
+ }
6053
+ const cloudTs = parseTs(row.ts);
6054
+ const baseDir = repoDir(repoKey);
6055
+ const worktreeId = workTreeIdFor(cwd);
6056
+ const local = readLastBuild(baseDir, worktreeId);
6057
+ if (local !== null && local.commit_sha === head) {
6058
+ if (cloudSha256 !== "" && local.snapshot_sha256 === cloudSha256) {
6059
+ return { kind: "up-to-date", commitSha: head, snapshotSha256: cloudSha256 };
6060
+ }
6061
+ if (local.ts > cloudTs) {
6062
+ return {
6063
+ kind: "local-newer",
6064
+ commitSha: head,
6065
+ localTs: local.ts,
6066
+ cloudTs
6067
+ };
6068
+ }
6069
+ }
6070
+ const snapshotsDir = join24(baseDir, "snapshots");
6071
+ const snapshotPath = join24(snapshotsDir, `${head}.json`);
6072
+ const worktreeRoot = join24(baseDir, "worktrees", worktreeId);
6073
+ try {
6074
+ writeFileAtomic2(snapshotPath, cloudPayload);
6075
+ writeFileAtomic2(join24(worktreeRoot, "latest-commit.txt"), `${head}
6076
+ `);
6077
+ writeLastBuild(baseDir, {
6078
+ ts: cloudTs,
6079
+ commit_sha: head,
6080
+ snapshot_sha256: cloudSha256,
6081
+ node_count: numOrUndefined(row.node_count),
6082
+ edge_count: numOrUndefined(row.edge_count)
6083
+ }, worktreeId);
6084
+ appendHistoryEntry(baseDir, {
6085
+ ts: new Date(cloudTs).toISOString(),
6086
+ commit_sha: head,
6087
+ snapshot_sha256: cloudSha256,
6088
+ node_count: Number(row.node_count ?? 0),
6089
+ edge_count: Number(row.edge_count ?? 0),
6090
+ trigger: "pull"
6091
+ });
6092
+ } catch (err) {
6093
+ return errorOutcome2("write local files", err);
6094
+ }
6095
+ return {
6096
+ kind: "pulled",
6097
+ commitSha: head,
6098
+ snapshotSha256: cloudSha256,
6099
+ bytes: Buffer.byteLength(cloudPayload, "utf8"),
6100
+ cloudTs,
6101
+ sourceWorktreePath: String(row.worktree_id ?? "")
6102
+ };
6103
+ }
6104
+ function defaultReadHead(cwd) {
6105
+ try {
6106
+ return execFileSync4("git", ["rev-parse", "HEAD"], {
6107
+ cwd,
6108
+ encoding: "utf8",
6109
+ stdio: ["ignore", "pipe", "ignore"]
6110
+ }).trim();
6111
+ } catch {
6112
+ return null;
6113
+ }
6114
+ }
6115
+ function defaultMakeApi2(config) {
6116
+ return new DeeplakeApi(config.token, config.apiUrl, config.orgId, config.workspaceId, config.tableName);
6117
+ }
6118
+ function parseTs(raw) {
6119
+ if (typeof raw === "number" && Number.isFinite(raw)) {
6120
+ return raw < 1e12 ? raw * 1e3 : raw;
6121
+ }
6122
+ if (typeof raw === "string") {
6123
+ const parsed = Date.parse(raw);
6124
+ return Number.isFinite(parsed) ? parsed : 0;
6125
+ }
6126
+ return 0;
6127
+ }
6128
+ function numOrUndefined(raw) {
6129
+ if (typeof raw === "number" && Number.isFinite(raw) && raw >= 0)
6130
+ return raw;
6131
+ if (typeof raw === "string") {
6132
+ const n = Number(raw);
6133
+ if (Number.isFinite(n) && n >= 0)
6134
+ return n;
6135
+ }
6136
+ return void 0;
6137
+ }
6138
+ function coerceSnapshotPayload(raw) {
6139
+ if (typeof raw === "string")
6140
+ return raw;
6141
+ if (raw !== null && typeof raw === "object")
6142
+ return JSON.stringify(raw);
6143
+ return null;
6144
+ }
6145
+ function writeFileAtomic2(filePath, contents) {
6146
+ mkdirSync11(dirname7(filePath), { recursive: true });
6147
+ const tmp = `${filePath}.tmp.${process.pid}.${Date.now()}`;
6148
+ writeFileSync14(tmp, contents);
6149
+ renameSync7(tmp, filePath);
6150
+ }
6151
+ function errorOutcome2(stage, err) {
6152
+ const message = err instanceof Error ? err.message : String(err);
6153
+ return { kind: "error", message: `${stage}: ${message}` };
6154
+ }
6155
+
6156
+ // dist/src/graph/diff.js
6157
+ import { existsSync as existsSync19, readFileSync as readFileSync18 } from "node:fs";
6158
+ import { join as join25 } from "node:path";
6159
+ function edgeKey(e) {
6160
+ return `${e.source}${e.target}${e.relation}${e.ord ?? 0}`;
6161
+ }
6162
+ function diffSnapshots(from, to) {
6163
+ const fromNodeIds = new Set(from.nodes.map((n) => n.id));
6164
+ const toNodeIds = new Set(to.nodes.map((n) => n.id));
6165
+ const nodesAdded = to.nodes.filter((n) => !fromNodeIds.has(n.id));
6166
+ const nodesRemoved = from.nodes.filter((n) => !toNodeIds.has(n.id));
6167
+ const fromEdgeKeys = new Set(from.links.map(edgeKey));
6168
+ const toEdgeKeys = new Set(to.links.map(edgeKey));
6169
+ const edgesAdded = to.links.filter((e) => !fromEdgeKeys.has(edgeKey(e)));
6170
+ const edgesRemoved = from.links.filter((e) => !toEdgeKeys.has(edgeKey(e)));
6171
+ return {
6172
+ nodes: { added: nodesAdded, removed: nodesRemoved },
6173
+ edges: { added: edgesAdded, removed: edgesRemoved },
6174
+ counts: {
6175
+ nodes_added: nodesAdded.length,
6176
+ nodes_removed: nodesRemoved.length,
6177
+ edges_added: edgesAdded.length,
6178
+ edges_removed: edgesRemoved.length
6179
+ }
6180
+ };
6181
+ }
6182
+ function loadSnapshotByCommit(baseDir, commitSha) {
6183
+ if (!/^[0-9a-f]{4,64}$/i.test(commitSha))
6184
+ return null;
6185
+ const path = join25(baseDir, "snapshots", `${commitSha}.json`);
6186
+ if (!existsSync19(path))
6187
+ return null;
6188
+ let raw;
6189
+ try {
6190
+ raw = readFileSync18(path, "utf8");
6191
+ } catch {
6192
+ return null;
6193
+ }
6194
+ try {
6195
+ const parsed = JSON.parse(raw);
6196
+ if (!isGraphSnapshotLike(parsed))
6197
+ return null;
6198
+ return parsed;
6199
+ } catch {
6200
+ return null;
6201
+ }
6202
+ }
6203
+ function isGraphSnapshotLike(v) {
6204
+ if (v === null || typeof v !== "object")
6205
+ return false;
6206
+ const s = v;
6207
+ return Array.isArray(s.nodes) && Array.isArray(s.links);
6208
+ }
6209
+ function printDiffHuman(diff, sampleSize = 10) {
6210
+ const { counts } = diff;
6211
+ console.log(`Nodes: +${counts.nodes_added} -${counts.nodes_removed} Edges: +${counts.edges_added} -${counts.edges_removed}`);
6212
+ const showNodes = (label, ns) => {
6213
+ if (ns.length === 0)
6214
+ return;
6215
+ console.log("");
6216
+ console.log(`${label} (${ns.length}, showing up to ${sampleSize}):`);
6217
+ const sorted = [...ns].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
6218
+ for (const n of sorted.slice(0, sampleSize)) {
6219
+ console.log(` ${n.id} [${n.kind}]${n.exported ? " (exported)" : ""} ${n.source_file}:${n.source_location}`);
6220
+ }
6221
+ if (sorted.length > sampleSize)
6222
+ console.log(` \u2026 and ${sorted.length - sampleSize} more`);
6223
+ };
6224
+ const showEdges = (label, es) => {
6225
+ if (es.length === 0)
6226
+ return;
6227
+ console.log("");
6228
+ console.log(`${label} (${es.length}, showing up to ${sampleSize}):`);
6229
+ const sorted = [...es].sort((a, b) => edgeKey(a) < edgeKey(b) ? -1 : edgeKey(a) > edgeKey(b) ? 1 : 0);
6230
+ for (const e of sorted.slice(0, sampleSize)) {
6231
+ console.log(` ${e.source} --${e.relation}--> ${e.target}${e.ord !== void 0 ? ` (ord=${e.ord})` : ""}`);
6232
+ }
6233
+ if (sorted.length > sampleSize)
6234
+ console.log(` \u2026 and ${sorted.length - sampleSize} more`);
6235
+ };
6236
+ showNodes("Nodes added", diff.nodes.added);
6237
+ showNodes("Nodes removed", diff.nodes.removed);
6238
+ showEdges("Edges added", diff.edges.added);
6239
+ showEdges("Edges removed", diff.edges.removed);
6240
+ }
6241
+
6242
+ // dist/src/graph/extract/typescript.js
6243
+ import Parser from "tree-sitter";
6244
+ import TypeScript from "tree-sitter-typescript";
6245
+ var _typescriptParser = null;
6246
+ var _tsxParser = null;
6247
+ function getTypescriptParser() {
6248
+ if (_typescriptParser === null) {
6249
+ _typescriptParser = new Parser();
6250
+ _typescriptParser.setLanguage(TypeScript.typescript);
6251
+ }
6252
+ return _typescriptParser;
6253
+ }
6254
+ function getTsxParser() {
6255
+ if (_tsxParser === null) {
6256
+ _tsxParser = new Parser();
6257
+ _tsxParser.setLanguage(TypeScript.tsx);
6258
+ }
6259
+ return _tsxParser;
6260
+ }
6261
+ function pickParserForPath(relativePath) {
6262
+ return relativePath.endsWith(".tsx") || relativePath.endsWith(".jsx") ? getTsxParser() : getTypescriptParser();
6263
+ }
6264
+ function extractTypeScript(sourceCode, relativePath) {
6265
+ const parser = pickParserForPath(relativePath);
6266
+ const CHUNK_BYTES = 16384;
6267
+ const tree = parser.parse((index) => {
6268
+ if (index >= sourceCode.length)
6269
+ return null;
6270
+ return sourceCode.slice(index, index + CHUNK_BYTES);
6271
+ });
6272
+ const root = tree.rootNode;
6273
+ const result = {
6274
+ source_file: relativePath,
6275
+ language: "typescript",
6276
+ nodes: [],
6277
+ edges: [],
6278
+ parse_errors: []
6279
+ };
6280
+ collectParseErrors(root, relativePath, result.parse_errors);
6281
+ const moduleNode = makeModuleNode(relativePath);
6282
+ result.nodes.push(moduleNode);
6283
+ const declByName = /* @__PURE__ */ new Map();
6284
+ extractDeclarations(root, relativePath, result, declByName, moduleNode);
6285
+ extractImports(root, relativePath, result, moduleNode);
6286
+ extractCalls(root, relativePath, result, declByName);
6287
+ return result;
6288
+ }
6289
+ function collectParseErrors(node, relativePath, out) {
6290
+ if (node.isError || node.isMissing) {
6291
+ out.push({
6292
+ source_file: relativePath,
6293
+ message: node.isMissing ? `missing node: ${node.type}` : `parse error at ${locationStr(node)}`,
6294
+ location: locationStr(node)
6295
+ });
6296
+ return;
6297
+ }
6298
+ for (let i = 0; i < node.namedChildCount; i++) {
6299
+ const child = node.namedChild(i);
6300
+ if (child !== null)
6301
+ collectParseErrors(child, relativePath, out);
6302
+ }
6303
+ }
6304
+ function extractDeclarations(node, relativePath, result, declByName, moduleNode) {
6305
+ for (let i = 0; i < node.namedChildCount; i++) {
6306
+ const child = node.namedChild(i);
6307
+ if (child === null)
6308
+ continue;
6309
+ const { decl, exported } = unwrapExport(child);
6310
+ if (decl !== null) {
6311
+ handleDeclaration(decl, exported, relativePath, result, declByName, moduleNode);
6312
+ }
6313
+ if (child.type === "internal_module" || child.type === "module") {
6314
+ extractDeclarations(child, relativePath, result, declByName, moduleNode);
6315
+ }
6316
+ }
6317
+ }
6318
+ function unwrapExport(node) {
6319
+ if (node.type === "export_statement") {
6320
+ const decl = node.childForFieldName("declaration") ?? firstNamedChildOfTypes(node, [
6321
+ "function_declaration",
6322
+ "class_declaration",
6323
+ "interface_declaration",
6324
+ "type_alias_declaration",
6325
+ "enum_declaration",
6326
+ "lexical_declaration"
6327
+ ]);
6328
+ return { decl, exported: true };
6329
+ }
6330
+ return { decl: node, exported: false };
6331
+ }
6332
+ function handleDeclaration(node, exported, relativePath, result, declByName, moduleNode) {
6333
+ switch (node.type) {
6334
+ case "function_declaration": {
6335
+ const name = textOfField(node, "name");
6336
+ if (name === null)
6337
+ return;
6338
+ const decl = makeNode(relativePath, name, "function", node, exported);
6339
+ pushNode(result, declByName, decl);
6340
+ return;
6341
+ }
6342
+ case "class_declaration": {
6343
+ const name = textOfField(node, "name");
6344
+ if (name === null)
6345
+ return;
6346
+ const classNode = makeNode(relativePath, name, "class", node, exported);
6347
+ pushNode(result, declByName, classNode);
6348
+ const heritage = firstNamedChildOfTypes(node, ["class_heritage"]);
6349
+ if (heritage !== null) {
6350
+ for (let i = 0; i < heritage.namedChildCount; i++) {
6351
+ const clause = heritage.namedChild(i);
6352
+ if (clause === null)
6353
+ continue;
6354
+ const relation = clause.type === "extends_clause" ? "extends" : clause.type === "implements_clause" ? "implements" : null;
6355
+ if (relation === null)
6356
+ continue;
6357
+ for (let j = 0; j < clause.namedChildCount; j++) {
6358
+ const base = clause.namedChild(j);
6359
+ if (base === null)
6360
+ continue;
6361
+ const baseName = base.text;
6362
+ if (baseName.length === 0)
6363
+ continue;
6364
+ result.edges.push({
6365
+ source: classNode.id,
6366
+ target: nodeIdUnresolved(relativePath, baseName, relation === "extends" ? "class" : "interface"),
6367
+ relation,
6368
+ confidence: "EXTRACTED"
6369
+ });
6370
+ }
6371
+ }
6372
+ }
6373
+ const body = firstNamedChildOfTypes(node, ["class_body"]);
6374
+ if (body !== null) {
6375
+ for (let i = 0; i < body.namedChildCount; i++) {
6376
+ const member = body.namedChild(i);
6377
+ if (member === null)
6378
+ continue;
6379
+ if (member.type === "method_definition") {
6380
+ const methodName = textOfField(member, "name");
6381
+ if (methodName === null)
6382
+ continue;
6383
+ const accessibility = firstNamedChildOfTypes(member, ["accessibility_modifier"]);
6384
+ const isHardPrivate = firstNamedChildOfTypes(member, ["private_property_identifier"]) !== null;
6385
+ const isPublic = !isHardPrivate && (accessibility === null || accessibility.text === "public");
6386
+ const methodExported = exported && isPublic;
6387
+ const methodKey = `${classNode.label}.${methodName}`;
6388
+ const methodNode = makeNodeWithExplicitLabel(relativePath, methodKey, methodName, "method", member, methodExported);
6389
+ pushNode(result, declByName, methodNode, methodKey);
6390
+ result.edges.push({
6391
+ source: classNode.id,
6392
+ target: methodNode.id,
6393
+ relation: "method_of",
6394
+ confidence: "EXTRACTED"
6395
+ });
6396
+ }
6397
+ }
6398
+ }
6399
+ return;
6400
+ }
6401
+ case "interface_declaration": {
6402
+ const name = textOfField(node, "name");
6403
+ if (name === null)
6404
+ return;
6405
+ const decl = makeNode(relativePath, name, "interface", node, exported);
6406
+ pushNode(result, declByName, decl);
6407
+ return;
6408
+ }
6409
+ case "type_alias_declaration": {
6410
+ const name = textOfField(node, "name");
6411
+ if (name === null)
6412
+ return;
6413
+ const decl = makeNode(relativePath, name, "type_alias", node, exported);
6414
+ pushNode(result, declByName, decl);
6415
+ return;
6416
+ }
6417
+ case "enum_declaration": {
6418
+ const name = textOfField(node, "name");
6419
+ if (name === null)
6420
+ return;
6421
+ const decl = makeNode(relativePath, name, "enum", node, exported);
6422
+ pushNode(result, declByName, decl);
6423
+ return;
6424
+ }
6425
+ case "lexical_declaration": {
6426
+ for (let i = 0; i < node.namedChildCount; i++) {
6427
+ const declarator = node.namedChild(i);
6428
+ if (declarator === null || declarator.type !== "variable_declarator")
6429
+ continue;
6430
+ const ident = declarator.childForFieldName("name");
6431
+ if (ident === null || ident.type !== "identifier")
6432
+ continue;
6433
+ const decl = makeNode(relativePath, ident.text, "const", declarator, exported);
6434
+ pushNode(result, declByName, decl);
6435
+ }
6436
+ return;
6437
+ }
6438
+ }
6439
+ }
6440
+ function extractImports(node, relativePath, result, moduleNode) {
6441
+ if (node.type === "import_statement") {
6442
+ const src = firstNamedChildOfTypes(node, ["string"]);
6443
+ if (src !== null) {
6444
+ const frag = firstNamedChildOfTypes(src, ["string_fragment"]);
6445
+ const specifier = (frag !== null ? frag.text : src.text).replace(/^['"]|['"]$/g, "");
6446
+ if (specifier.length > 0) {
6447
+ result.edges.push({
6448
+ source: moduleNode.id,
6449
+ target: `external:${specifier}`,
6450
+ relation: "imports",
6451
+ confidence: "EXTRACTED"
6452
+ });
6453
+ }
6454
+ }
6455
+ return;
6456
+ }
6457
+ for (let i = 0; i < node.namedChildCount; i++) {
6458
+ const child = node.namedChild(i);
6459
+ if (child !== null)
6460
+ extractImports(child, relativePath, result, moduleNode);
6461
+ }
6462
+ }
6463
+ function extractCalls(node, relativePath, result, declByName) {
6464
+ if (node.type === "call_expression") {
6465
+ const callee = node.childForFieldName("function");
6466
+ if (callee !== null) {
6467
+ const calleeKey = resolveCalleeKey(callee, declByName);
6468
+ if (calleeKey !== null) {
6469
+ const targetNode = declByName.get(calleeKey);
6470
+ if (targetNode !== void 0) {
6471
+ const callerNode = findEnclosingDeclaration(node, declByName);
6472
+ if (callerNode !== null) {
6473
+ result.edges.push({
6474
+ source: callerNode.id,
6475
+ target: targetNode.id,
6476
+ relation: "calls",
6477
+ confidence: "EXTRACTED"
6478
+ });
6479
+ }
6480
+ }
6481
+ }
6482
+ }
6483
+ }
6484
+ for (let i = 0; i < node.namedChildCount; i++) {
6485
+ const child = node.namedChild(i);
6486
+ if (child !== null)
6487
+ extractCalls(child, relativePath, result, declByName);
6488
+ }
6489
+ }
6490
+ function resolveCalleeKey(callee, declByName) {
6491
+ if (callee.type === "identifier")
6492
+ return callee.text;
6493
+ if (callee.type === "member_expression") {
6494
+ const object = callee.childForFieldName("object");
6495
+ const property = callee.childForFieldName("property");
6496
+ if (object !== null && object.type === "this" && property !== null && property.type === "property_identifier") {
6497
+ const className = findEnclosingClassName(callee);
6498
+ if (className !== null)
6499
+ return `${className}.${property.text}`;
6500
+ }
6501
+ }
6502
+ return null;
6503
+ }
6504
+ function findEnclosingDeclaration(node, declByName) {
6505
+ let cur = node.parent;
6506
+ while (cur !== null) {
6507
+ if (cur.type === "function_declaration") {
6508
+ const name = textOfField(cur, "name");
6509
+ if (name !== null) {
6510
+ const n = declByName.get(name);
6511
+ if (n !== void 0)
6512
+ return n;
6513
+ }
6514
+ } else if (cur.type === "method_definition") {
6515
+ const methodName = textOfField(cur, "name");
6516
+ const className = findEnclosingClassName(cur);
6517
+ if (methodName !== null && className !== null) {
6518
+ const n = declByName.get(`${className}.${methodName}`);
6519
+ if (n !== void 0)
6520
+ return n;
6521
+ }
6522
+ } else if (cur.type === "variable_declarator") {
6523
+ const value = cur.childForFieldName("value");
6524
+ if (value?.type === "arrow_function" || value?.type === "function_expression") {
6525
+ const ident = cur.childForFieldName("name");
6526
+ if (ident !== null && ident.type === "identifier") {
6527
+ const n = declByName.get(ident.text);
6528
+ if (n !== void 0)
6529
+ return n;
6530
+ }
6531
+ }
6532
+ }
6533
+ cur = cur.parent;
6534
+ }
6535
+ return null;
6536
+ }
6537
+ function findEnclosingClassName(node) {
6538
+ let cur = node.parent;
6539
+ while (cur !== null) {
6540
+ if (cur.type === "class_declaration") {
6541
+ return textOfField(cur, "name");
6542
+ }
6543
+ cur = cur.parent;
6544
+ }
6545
+ return null;
6546
+ }
6547
+ function makeModuleNode(relativePath) {
6548
+ return {
6549
+ id: `${relativePath}::module`,
6550
+ label: relativePath,
6551
+ kind: "module",
6552
+ source_file: relativePath,
6553
+ source_location: "L1",
6554
+ language: "typescript",
6555
+ exported: false
6556
+ };
6557
+ }
6558
+ function makeNode(relativePath, name, kind, node, exported) {
6559
+ return {
6560
+ id: nodeId(relativePath, name, kind),
6561
+ label: name,
6562
+ kind,
6563
+ source_file: relativePath,
6564
+ source_location: locationStr(node),
6565
+ language: "typescript",
6566
+ exported
6567
+ };
6568
+ }
6569
+ function makeNodeWithExplicitLabel(relativePath, idName, label, kind, node, exported) {
6570
+ return {
6571
+ id: nodeId(relativePath, idName, kind),
6572
+ label,
6573
+ kind,
6574
+ source_file: relativePath,
6575
+ source_location: locationStr(node),
6576
+ language: "typescript",
6577
+ exported
6578
+ };
6579
+ }
6580
+ function pushNode(result, declByName, node, lookupKey) {
6581
+ if (result.nodes.some((n) => n.id === node.id)) {
6582
+ if (!declByName.has(lookupKey ?? node.label)) {
6583
+ declByName.set(lookupKey ?? node.label, node);
6584
+ }
6585
+ return;
6586
+ }
6587
+ result.nodes.push(node);
6588
+ declByName.set(lookupKey ?? node.label, node);
6589
+ }
6590
+ function nodeId(relativePath, name, kind) {
6591
+ return `${relativePath}:${name}:${kind}`;
6592
+ }
6593
+ function nodeIdUnresolved(relativePath, name, kind) {
6594
+ return `unresolved:${relativePath}:${name}:${kind}`;
6595
+ }
6596
+ function locationStr(node) {
6597
+ const start = node.startPosition.row + 1;
6598
+ const end = node.endPosition.row + 1;
6599
+ return start === end ? `L${start}` : `L${start}-${end}`;
6600
+ }
6601
+ function textOfField(node, fieldName) {
6602
+ const child = node.childForFieldName(fieldName);
6603
+ if (child === null)
6604
+ return null;
6605
+ const text = child.text;
6606
+ return text.length > 0 ? text : null;
6607
+ }
6608
+ function firstNamedChildOfTypes(node, types) {
6609
+ for (let i = 0; i < node.namedChildCount; i++) {
6610
+ const child = node.namedChild(i);
6611
+ if (child !== null && types.includes(child.type))
6612
+ return child;
6613
+ }
6614
+ return null;
6615
+ }
6616
+
6617
+ // dist/src/graph/git-hook-install.js
6618
+ import { chmodSync as chmodSync2, existsSync as existsSync20, mkdirSync as mkdirSync12, readFileSync as readFileSync19, unlinkSync as unlinkSync8, writeFileSync as writeFileSync15 } from "node:fs";
6619
+ import { dirname as dirname8, join as join26, resolve as resolve3 } from "node:path";
6620
+ import { execFileSync as execFileSync5 } from "node:child_process";
6621
+ var HOOK_BEGIN_MARKER = "# HIVEMIND_GRAPH_HOOK_BEGIN \u2014 managed by `hivemind graph init`";
6622
+ var HOOK_END_MARKER = "# HIVEMIND_GRAPH_HOOK_END";
6623
+ var SHEBANG = "#!/bin/sh";
6624
+ function hookBodyLines(hivemindPath) {
6625
+ return [
6626
+ "# Async-detached so commits never wait. Threshold-gate + cache make",
6627
+ "# typical re-runs ~85ms. Logs go to ~/.hivemind/post-commit.log",
6628
+ "# mkdir is robust against first-run: $HOME/.hivemind may not exist yet,",
6629
+ "# in which case the > redirect would fail and the build would never start.",
6630
+ 'mkdir -p "$HOME/.hivemind" 2>/dev/null || true',
6631
+ `nohup ${quoteForShell(hivemindPath)} graph build --trigger post-commit >> "$HOME/.hivemind/post-commit.log" 2>&1 &`
6632
+ ];
6633
+ }
6634
+ function quoteForShell(path) {
6635
+ return `'${path.replace(/'/g, `'\\''`)}'`;
6636
+ }
6637
+ function gitHooksDir(cwd) {
6638
+ const configured = tryGitConfig(cwd, "core.hooksPath");
6639
+ if (configured !== null) {
6640
+ const top = tryGitTopLevel(cwd);
6641
+ return top !== null ? resolve3(top, configured) : resolve3(cwd, configured);
6642
+ }
6643
+ try {
6644
+ const out = execFileSync5("git", ["rev-parse", "--git-path", "hooks"], {
6645
+ cwd,
6646
+ encoding: "utf8",
6647
+ stdio: ["ignore", "pipe", "ignore"]
6648
+ }).trim();
6649
+ if (out === "")
6650
+ return null;
6651
+ return resolve3(cwd, out);
6652
+ } catch {
6653
+ return null;
6654
+ }
6655
+ }
6656
+ function tryGitConfig(cwd, key) {
6657
+ try {
6658
+ const out = execFileSync5("git", ["config", "--get", key], {
6659
+ cwd,
6660
+ encoding: "utf8",
6661
+ stdio: ["ignore", "pipe", "ignore"]
6662
+ }).trim();
6663
+ return out === "" ? null : out;
6664
+ } catch {
6665
+ return null;
6666
+ }
6667
+ }
6668
+ function tryGitTopLevel(cwd) {
6669
+ try {
6670
+ const out = execFileSync5("git", ["rev-parse", "--show-toplevel"], {
6671
+ cwd,
6672
+ encoding: "utf8",
6673
+ stdio: ["ignore", "pipe", "ignore"]
6674
+ }).trim();
6675
+ return out === "" ? null : out;
6676
+ } catch {
6677
+ return null;
6678
+ }
6679
+ }
6680
+ function postCommitHookPath(cwd) {
6681
+ const hooksDir = gitHooksDir(cwd);
6682
+ return hooksDir === null ? null : join26(hooksDir, "post-commit");
6683
+ }
6684
+ function installPostCommitHook(cwd, opts = {}) {
6685
+ const path = postCommitHookPath(cwd);
6686
+ if (path === null) {
6687
+ return { kind: "foreign-hook", path: "", hint: "not in a git repo (no .git directory found)" };
6688
+ }
6689
+ const existed = existsSync20(path);
6690
+ if (existed) {
6691
+ const content = readFileSync19(path, "utf8");
6692
+ if (containsOurMarkers(content)) {
6693
+ return { kind: "already-ours", path };
6694
+ }
6695
+ if (!opts.force) {
6696
+ return {
6697
+ kind: "foreign-hook",
6698
+ path,
6699
+ hint: `existing hook at ${path} is not managed by hivemind; pass --force to overwrite, or merge our block manually (between '${HOOK_BEGIN_MARKER}' and '${HOOK_END_MARKER}')`
6700
+ };
6701
+ }
6702
+ }
6703
+ const hivemindPath = resolveHivemindPath();
6704
+ if (hivemindPath === null) {
6705
+ return {
6706
+ kind: "foreign-hook",
6707
+ path,
6708
+ hint: "hivemind binary not found on PATH. Install hivemind globally (`npm install -g @deeplake/hivemind`) before running `hivemind graph init`, so the hook can find a stable absolute path to call."
6709
+ };
6710
+ }
6711
+ mkdirSync12(dirname8(path), { recursive: true });
6712
+ writeFileSync15(path, buildHookFile(hivemindPath), { mode: 493 });
6713
+ try {
6714
+ chmodSync2(path, 493);
6715
+ } catch {
6716
+ }
6717
+ return { kind: "installed", path, wasNew: !existed };
6718
+ }
6719
+ function resolveHivemindPath() {
6720
+ try {
6721
+ const out = execFileSync5("which", ["hivemind"], {
6722
+ encoding: "utf8",
6723
+ stdio: ["ignore", "pipe", "ignore"]
6724
+ }).trim();
6725
+ if (out !== "" && out.includes("hivemind"))
6726
+ return out.split("\n")[0].trim();
6727
+ } catch {
6728
+ }
6729
+ return null;
6730
+ }
6731
+ function uninstallPostCommitHook(cwd) {
6732
+ const path = postCommitHookPath(cwd);
6733
+ if (path === null) {
6734
+ return { kind: "no-hook", path: "" };
6735
+ }
6736
+ if (!existsSync20(path)) {
6737
+ return { kind: "no-hook", path };
6738
+ }
6739
+ const content = readFileSync19(path, "utf8");
6740
+ if (!containsOurMarkers(content)) {
6741
+ return {
6742
+ kind: "not-ours",
6743
+ path,
6744
+ hint: `existing hook at ${path} is not managed by hivemind; remove it manually if you want it gone`
6745
+ };
6746
+ }
6747
+ const stripped = stripOurBlock(content);
6748
+ const meaningful = stripped.split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#!"));
6749
+ if (meaningful.length === 0) {
6750
+ unlinkSync8(path);
6751
+ return { kind: "removed", path, wholeFileDeleted: true };
6752
+ }
6753
+ writeFileSync15(path, stripped);
6754
+ return { kind: "removed", path, wholeFileDeleted: false };
6755
+ }
6756
+ function containsOurMarkers(content) {
6757
+ return content.includes(HOOK_BEGIN_MARKER) && content.includes(HOOK_END_MARKER);
6758
+ }
6759
+ function stripOurBlock(content) {
6760
+ const beginIdx = content.indexOf(HOOK_BEGIN_MARKER);
6761
+ const endIdx = content.indexOf(HOOK_END_MARKER);
6762
+ if (beginIdx === -1 || endIdx === -1 || endIdx < beginIdx)
6763
+ return content;
6764
+ const blockEnd = endIdx + HOOK_END_MARKER.length;
6765
+ return content.slice(0, beginIdx) + content.slice(blockEnd);
6766
+ }
6767
+ function buildHookFile(hivemindPath) {
6768
+ return [
6769
+ SHEBANG,
6770
+ "",
6771
+ HOOK_BEGIN_MARKER,
6772
+ ...hookBodyLines(hivemindPath),
6773
+ HOOK_END_MARKER,
6774
+ ""
6775
+ ].join("\n");
6776
+ }
6777
+
6778
+ // dist/src/commands/graph.js
6779
+ var USAGE = `hivemind graph \u2014 codebase-graph commands (Phase 1 \u2014 TypeScript only)
6780
+
6781
+ Usage:
6782
+ hivemind graph build [--cwd <path>]
6783
+ Walk the project for TypeScript source files, extract symbols + edges,
6784
+ and write a snapshot to ~/.hivemind/graphs/<repo-key>/snapshots/<commit-sha>.json.
6785
+ Also updates ~/.hivemind/graphs/<repo-key>/latest-commit.txt and the
6786
+ per-repo .last-build.json (consumed by the SessionEnd auto-build hook).
6787
+
6788
+ hivemind graph diff <sha1> <sha2> [--cwd <path>] [--json] [--limit N]
6789
+ Diff two snapshots by their git commit SHA. Prints added/removed
6790
+ counts for nodes and edges, plus up to N=10 (default) examples of each.
6791
+ --json: emit machine-readable JSON instead of the human format.
6792
+ --limit N: cap the per-category examples (human format only).
6793
+
6794
+ hivemind graph history [--cwd <path>] [-n N] [--json]
6795
+ Print the last N (default 20) entries from the per-repo history.jsonl,
6796
+ newest last. Each entry shows ts, commit_sha (short), snapshot_sha256
6797
+ (short), node/edge counts, and the trigger that fired the build.
6798
+ --json: emit raw JSONL (one parsed entry per line, full fields).
6799
+
6800
+ hivemind graph init [--cwd <path>] [--force] [--no-initial-build]
6801
+ Install a managed block in .git/hooks/post-commit that fires
6802
+ \`hivemind graph build --trigger post-commit\` after each commit
6803
+ (async, non-blocking, exit 0 always). Idempotent: re-running on
6804
+ an already-installed hook is a no-op. Refuses to clobber an
6805
+ existing non-managed hook unless --force is passed.
6806
+ Also runs an initial \`hivemind graph build\` unless
6807
+ --no-initial-build is passed.
6808
+
6809
+ hivemind graph uninstall [--cwd <path>]
6810
+ Remove our managed block from .git/hooks/post-commit. If our block
6811
+ was the only content, deletes the file; otherwise leaves the rest
6812
+ intact. Snapshots and history are NOT touched (\`rm -rf
6813
+ ~/.hivemind/graphs/<key>\` if you really want them gone).
6814
+
6815
+ hivemind graph pull [--cwd <path>]
6816
+ Download the freshest cloud snapshot for HEAD into the local graph
6817
+ dir (any worktree of this user counts). No-op if local already
6818
+ matches cloud sha256 or local was built later than cloud. Requires
6819
+ \`hivemind login\`. Best-effort: any network/auth failure leaves
6820
+ the local files untouched. Disable via HIVEMIND_GRAPH_PULL=0.
6821
+
6822
+ hivemind graph --help
6823
+ Show this message.
6824
+
6825
+ Future subcommands (Phase 1.5+): daemon, search, latest, push, pull, prune.
6826
+ `;
6827
+ var DEFAULT_IGNORES = /* @__PURE__ */ new Set([
6828
+ "node_modules",
6829
+ ".git",
6830
+ "bundle",
6831
+ "dist",
6832
+ "coverage",
6833
+ ".cache",
6834
+ ".nyc_output"
6835
+ ]);
6836
+ function runGraphCommand(args) {
6837
+ const sub = args[0];
6838
+ if (sub === void 0 || sub === "--help" || sub === "-h" || sub === "help") {
6839
+ console.log(USAGE);
6840
+ return;
6841
+ }
6842
+ if (sub === "build") {
6843
+ return runBuildCommand(args.slice(1));
6844
+ }
6845
+ if (sub === "diff") {
6846
+ runDiffCommand(args.slice(1));
6847
+ return;
6848
+ }
6849
+ if (sub === "history") {
6850
+ runHistoryCommand(args.slice(1));
6851
+ return;
6852
+ }
6853
+ if (sub === "init") {
6854
+ return runInitCommand(args.slice(1));
6855
+ }
6856
+ if (sub === "uninstall") {
6857
+ runUninstallCommand(args.slice(1));
6858
+ return;
6859
+ }
6860
+ if (sub === "pull") {
6861
+ return runPullCommand(args.slice(1));
6862
+ }
6863
+ console.error(`hivemind graph: unknown subcommand '${sub}'`);
6864
+ console.error(USAGE);
6865
+ process.exit(2);
6866
+ }
6867
+ function parseInitArgs(args) {
6868
+ let cwd = process.cwd();
6869
+ let force = false;
6870
+ let initialBuild = true;
6871
+ for (let i = 0; i < args.length; i++) {
6872
+ const a = args[i];
6873
+ if (a === "--cwd" && i + 1 < args.length) {
6874
+ cwd = args[i + 1];
6875
+ i += 1;
6876
+ } else if (a === "--force") {
6877
+ force = true;
6878
+ } else if (a === "--no-initial-build") {
6879
+ initialBuild = false;
6880
+ } else if (a === "--help" || a === "-h") {
6881
+ console.log(USAGE);
6882
+ process.exit(0);
6883
+ } else {
6884
+ console.error(`hivemind graph init: unknown argument '${a}'`);
6885
+ console.error(USAGE);
6886
+ process.exit(2);
6887
+ }
6888
+ }
6889
+ return { cwd, force, initialBuild };
6890
+ }
6891
+ async function runInitCommand(args) {
6892
+ const opts = parseInitArgs(args);
6893
+ const status = installPostCommitHook(opts.cwd, { force: opts.force });
6894
+ switch (status.kind) {
6895
+ case "installed":
6896
+ console.log(`Installed post-commit hook at ${status.path}`);
6897
+ break;
6898
+ case "already-ours":
6899
+ console.log(`Post-commit hook already managed by hivemind (no change): ${status.path}`);
6900
+ break;
6901
+ case "foreign-hook":
6902
+ console.error(`hivemind graph init: ${status.hint}`);
6903
+ process.exit(1);
6904
+ }
6905
+ if (opts.initialBuild) {
6906
+ console.log("");
6907
+ console.log("Running initial build...");
6908
+ await runBuildCommand(["--cwd", opts.cwd, "--trigger", "manual"]);
6909
+ } else {
6910
+ console.log("");
6911
+ console.log("Skipped initial build (--no-initial-build). Run `hivemind graph build` when ready.");
6912
+ }
6913
+ }
6914
+ function parseUninstallArgs(args) {
6915
+ let cwd = process.cwd();
6916
+ for (let i = 0; i < args.length; i++) {
6917
+ const a = args[i];
6918
+ if (a === "--cwd" && i + 1 < args.length) {
6919
+ cwd = args[i + 1];
6920
+ i += 1;
6921
+ } else if (a === "--help" || a === "-h") {
6922
+ console.log(USAGE);
6923
+ process.exit(0);
6924
+ } else {
6925
+ console.error(`hivemind graph uninstall: unknown argument '${a}'`);
6926
+ console.error(USAGE);
6927
+ process.exit(2);
6928
+ }
6929
+ }
6930
+ return { cwd };
6931
+ }
6932
+ function runUninstallCommand(args) {
6933
+ const opts = parseUninstallArgs(args);
6934
+ const status = uninstallPostCommitHook(opts.cwd);
6935
+ switch (status.kind) {
6936
+ case "removed":
6937
+ if (status.wholeFileDeleted) {
6938
+ console.log(`Removed post-commit hook (file deleted): ${status.path}`);
6939
+ } else {
6940
+ console.log(`Removed managed block from post-commit hook (other content preserved): ${status.path}`);
6941
+ }
6942
+ console.log("Local snapshots + history.jsonl are untouched.");
6943
+ break;
6944
+ case "no-hook":
6945
+ console.log(status.path === "" ? "No git repo here (nothing to uninstall)." : `No post-commit hook at ${status.path} (nothing to uninstall).`);
6946
+ break;
6947
+ case "not-ours":
6948
+ console.error(`hivemind graph uninstall: ${status.hint}`);
6949
+ process.exit(1);
6950
+ }
6951
+ }
6952
+ function parseHistoryArgs(args) {
6953
+ let cwd = process.cwd();
6954
+ let n = 20;
6955
+ let json2 = false;
6956
+ for (let i = 0; i < args.length; i++) {
6957
+ const a = args[i];
6958
+ if (a === "--cwd" && i + 1 < args.length) {
6959
+ cwd = args[i + 1];
6960
+ i += 1;
6961
+ } else if (a === "-n" && i + 1 < args.length) {
6962
+ const raw = args[i + 1];
6963
+ if (!/^\d+$/.test(raw)) {
6964
+ console.error("hivemind graph history: -n must be a non-negative integer");
6965
+ process.exit(2);
6966
+ }
6967
+ n = Number(raw);
6968
+ i += 1;
6969
+ } else if (a === "--json") {
6970
+ json2 = true;
6971
+ } else if (a === "--help" || a === "-h") {
6972
+ console.log(USAGE);
6973
+ process.exit(0);
6974
+ } else {
6975
+ console.error(`hivemind graph history: unknown argument '${a}'`);
6976
+ console.error(USAGE);
6977
+ process.exit(2);
6978
+ }
6979
+ }
6980
+ return { cwd, n, json: json2 };
6981
+ }
6982
+ function runHistoryCommand(args) {
6983
+ const opts = parseHistoryArgs(args);
6984
+ const { key: repoKey } = deriveProjectKey(opts.cwd);
6985
+ const baseDir = repoDir(repoKey);
6986
+ const total = countHistoryEntries(baseDir);
6987
+ const entries = readHistoryTail(baseDir, opts.n);
6988
+ if (opts.json) {
6989
+ for (const e of entries)
6990
+ console.log(JSON.stringify(e));
6991
+ return;
6992
+ }
6993
+ if (total === 0) {
6994
+ console.log("No history yet. Run `hivemind graph build` to record one.");
6995
+ return;
6996
+ }
6997
+ console.log(`history.jsonl: ${total} total entries; showing last ${entries.length}`);
6998
+ console.log("");
6999
+ for (const e of entries) {
7000
+ const commit = e.commit_sha === null ? "(no-git)" : e.commit_sha.slice(0, 7);
7001
+ const snap = e.snapshot_sha256.slice(0, 7);
7002
+ console.log(` ${e.ts} commit=${commit} snap=${snap} nodes=${e.node_count} edges=${e.edge_count} trigger=${e.trigger}`);
7003
+ }
7004
+ }
7005
+ function parseDiffArgs(args) {
7006
+ let cwd = process.cwd();
7007
+ let json2 = false;
7008
+ let limit = 10;
7009
+ const positional = [];
7010
+ for (let i = 0; i < args.length; i++) {
7011
+ const a = args[i];
7012
+ if (a === "--cwd" && i + 1 < args.length) {
7013
+ cwd = args[i + 1];
7014
+ i += 1;
7015
+ } else if (a === "--json") {
7016
+ json2 = true;
7017
+ } else if (a === "--limit" && i + 1 < args.length) {
7018
+ const raw = args[i + 1];
7019
+ if (!/^\d+$/.test(raw)) {
7020
+ console.error("hivemind graph diff: --limit must be a non-negative integer");
7021
+ process.exit(2);
7022
+ }
7023
+ limit = Number(raw);
7024
+ i += 1;
7025
+ } else if (a === "--help" || a === "-h") {
7026
+ console.log(USAGE);
7027
+ process.exit(0);
7028
+ } else if (a !== void 0 && !a.startsWith("--")) {
7029
+ positional.push(a);
7030
+ } else {
7031
+ console.error(`hivemind graph diff: unknown argument '${a}'`);
7032
+ console.error(USAGE);
7033
+ process.exit(2);
7034
+ }
7035
+ }
7036
+ if (positional.length !== 2) {
7037
+ console.error("hivemind graph diff: expected exactly two commit SHAs");
7038
+ console.error(USAGE);
7039
+ process.exit(2);
7040
+ }
7041
+ return { cwd, sha1: positional[0], sha2: positional[1], json: json2, limit };
7042
+ }
7043
+ function runDiffCommand(args) {
7044
+ const opts = parseDiffArgs(args);
7045
+ const { key: repoKey } = deriveProjectKey(opts.cwd);
7046
+ const baseDir = repoDir(repoKey);
7047
+ const from = loadSnapshotByCommit(baseDir, opts.sha1);
7048
+ if (from === null) {
7049
+ console.error(`hivemind graph diff: snapshot not found for ${opts.sha1}`);
7050
+ console.error(` expected: ${baseDir}/snapshots/${opts.sha1}.json`);
7051
+ console.error(" hint: run 'hivemind graph build' on the relevant commit, or check the commit sha");
7052
+ process.exit(1);
7053
+ }
7054
+ const to = loadSnapshotByCommit(baseDir, opts.sha2);
7055
+ if (to === null) {
7056
+ console.error(`hivemind graph diff: snapshot not found for ${opts.sha2}`);
7057
+ console.error(` expected: ${baseDir}/snapshots/${opts.sha2}.json`);
7058
+ process.exit(1);
7059
+ }
7060
+ const diff = diffSnapshots(from, to);
7061
+ if (opts.json) {
7062
+ console.log(JSON.stringify(diff, null, 2));
7063
+ return;
7064
+ }
7065
+ console.log(`Diff: ${opts.sha1} \u2192 ${opts.sha2}`);
7066
+ console.log("");
7067
+ printDiffHuman(diff, opts.limit);
7068
+ }
7069
+ function parseBuildArgs(args) {
7070
+ let cwd = process.cwd();
7071
+ let trigger = "manual";
7072
+ for (let i = 0; i < args.length; i++) {
7073
+ const a = args[i];
7074
+ if (a === "--cwd" && i + 1 < args.length) {
7075
+ cwd = args[i + 1];
7076
+ i += 1;
7077
+ } else if (a === "--trigger" && i + 1 < args.length) {
7078
+ const v = args[i + 1];
7079
+ if (v === "manual" || v === "session-end" || v === "post-commit" || v === "unknown") {
7080
+ trigger = v;
7081
+ } else {
7082
+ console.error(`hivemind graph build: --trigger must be one of manual|session-end|post-commit|unknown (got '${v}')`);
7083
+ process.exit(2);
7084
+ }
7085
+ i += 1;
7086
+ } else if (a === "--help" || a === "-h") {
7087
+ console.log(USAGE);
7088
+ process.exit(0);
7089
+ } else {
7090
+ console.error(`hivemind graph build: unknown argument '${a}'`);
7091
+ console.error(USAGE);
7092
+ process.exit(2);
7093
+ }
7094
+ }
7095
+ return { cwd, trigger };
7096
+ }
7097
+ async function runBuildCommand(args) {
7098
+ const opts = parseBuildArgs(args);
7099
+ const cwd = resolve4(opts.cwd);
7100
+ const { key: repoKey, project } = deriveProjectKey(cwd);
7101
+ const baseDir = repoDir(repoKey);
7102
+ const commitSha = readGitCommit(cwd);
7103
+ const branch = readGitBranch(cwd);
7104
+ const version = getVersion();
7105
+ console.log(`Building codebase graph for ${project}`);
7106
+ console.log(` repo_key: ${repoKey}`);
7107
+ console.log(` commit_sha: ${commitSha ?? "(not in a git repo)"}`);
7108
+ console.log(` branch: ${branch ?? "(none / detached)"}`);
7109
+ console.log(` output: ${baseDir}`);
7110
+ console.log("");
7111
+ const sourceFiles = discoverSourceFiles(cwd);
7112
+ console.log(`Discovered ${sourceFiles.length} TypeScript source files. Extracting...`);
7113
+ const extractions = [];
7114
+ let skipped = 0;
7115
+ let totalParseErrors = 0;
7116
+ let cacheHits = 0;
7117
+ for (const abs of sourceFiles) {
7118
+ const rel = toForwardSlash(relative(cwd, abs));
7119
+ try {
7120
+ const content = readFileSync20(abs, "utf8");
7121
+ const contentSha = fileContentHash(content);
7122
+ let extraction = readCache(baseDir, contentSha, rel);
7123
+ if (extraction === null) {
7124
+ extraction = extractTypeScript(content, rel);
7125
+ writeCache(baseDir, contentSha, extraction);
7126
+ } else {
7127
+ cacheHits += 1;
7128
+ }
7129
+ if (extraction.parse_errors.length > 0) {
7130
+ totalParseErrors += extraction.parse_errors.length;
7131
+ for (const err of extraction.parse_errors) {
7132
+ console.warn(` warn: parse issue in ${err.source_file} ${err.location ?? ""}: ${err.message}`);
7133
+ }
7134
+ }
7135
+ extractions.push(extraction);
7136
+ } catch (err) {
7137
+ const msg = err instanceof Error ? err.message : String(err);
7138
+ console.warn(` warn: skipping ${rel}: ${msg}`);
7139
+ skipped += 1;
7140
+ }
7141
+ }
7142
+ const metadata = {
7143
+ schema_version: 1,
7144
+ generator: "hivemind-graph",
7145
+ commit_sha: commitSha,
7146
+ repo_key: repoKey
7147
+ };
7148
+ const observation = {
7149
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
7150
+ branch,
7151
+ worktree_path: cwd,
7152
+ repo_project: project,
7153
+ generator_version: version,
7154
+ source_files_extracted: extractions.length,
7155
+ source_files_skipped: skipped
7156
+ };
7157
+ const snapshot = buildSnapshot(extractions, metadata, observation);
7158
+ const worktreeId = workTreeIdFor2(cwd);
7159
+ const result = writeSnapshot(snapshot, baseDir, opts.trigger, worktreeId);
7160
+ console.log("");
7161
+ console.log(`Snapshot: ${result.snapshotPath}`);
7162
+ console.log(`Latest: ${result.latestCommitPath ?? "(no commit context \u2014 latest-commit.txt not updated)"}`);
7163
+ console.log(`SHA-256: ${result.snapshotSha256}`);
7164
+ console.log(`Nodes: ${snapshot.nodes.length}`);
7165
+ console.log(`Edges: ${snapshot.links.length}`);
7166
+ console.log(`Files extracted: ${extractions.length} (skipped: ${skipped}, parse warnings: ${totalParseErrors}, cache hits: ${cacheHits}/${sourceFiles.length})`);
7167
+ const pushOutcome = await pushSnapshot(snapshot, worktreeId);
7168
+ switch (pushOutcome.kind) {
7169
+ case "inserted":
7170
+ console.log(`Cloud: pushed to codebase table (commit ${pushOutcome.commitSha.slice(0, 7)})`);
7171
+ break;
7172
+ case "inserted-with-duplicate-race":
7173
+ console.warn(`Cloud: pushed (commit ${pushOutcome.commitSha.slice(0, 7)}) but ${pushOutcome.rowCount} rows now share`);
7174
+ console.warn(` this identity key \u2014 a concurrent writer raced. v1.1 adds a server-side`);
7175
+ console.warn(` UNIQUE constraint; until then, the older row(s) should be deleted manually.`);
7176
+ break;
7177
+ case "already-current":
7178
+ console.log(`Cloud: already up-to-date (commit ${pushOutcome.commitSha.slice(0, 7)})`);
7179
+ break;
7180
+ case "skipped-no-auth":
7181
+ console.log(`Cloud: skipped (not authenticated; run \`hivemind login\` to enable cloud sync)`);
7182
+ break;
7183
+ case "skipped-no-commit":
7184
+ console.log(`Cloud: skipped (no commit context \u2014 not in a git repo)`);
7185
+ break;
7186
+ case "skipped-disabled":
7187
+ console.log(`Cloud: skipped (HIVEMIND_GRAPH_PUSH=0)`);
7188
+ break;
7189
+ case "drift":
7190
+ console.warn(`Cloud: DRIFT \u2014 commit ${pushOutcome.commitSha.slice(0, 7)} is in cloud with`);
7191
+ console.warn(` sha256=${pushOutcome.cloudSha256.slice(0, 12)}... but local rebuild produced`);
7192
+ console.warn(` sha256=${pushOutcome.localSha256.slice(0, 12)}...`);
7193
+ console.warn(` (probably extractor version drift; investigate before forcing.)`);
7194
+ break;
7195
+ case "error":
7196
+ console.warn(`Cloud: push error (non-fatal): ${pushOutcome.message}`);
7197
+ break;
7198
+ }
7199
+ }
7200
+ function parsePullArgs(args) {
7201
+ let cwd = process.cwd();
7202
+ for (let i = 0; i < args.length; i++) {
7203
+ const a = args[i];
7204
+ if (a === "--cwd" && i + 1 < args.length) {
7205
+ cwd = args[i + 1];
7206
+ i += 1;
7207
+ } else if (a === "--help" || a === "-h") {
7208
+ console.log(USAGE);
7209
+ process.exit(0);
7210
+ } else {
7211
+ console.error(`hivemind graph pull: unknown argument '${a}'`);
7212
+ console.error(USAGE);
7213
+ process.exit(2);
7214
+ }
7215
+ }
7216
+ return { cwd };
7217
+ }
7218
+ async function runPullCommand(args) {
7219
+ const opts = parsePullArgs(args);
7220
+ const outcome = await pullSnapshot(opts.cwd);
7221
+ switch (outcome.kind) {
7222
+ case "pulled":
7223
+ console.log(`Pulled commit ${outcome.commitSha.slice(0, 7)}`);
7224
+ console.log(` sha256: ${outcome.snapshotSha256.slice(0, 12)}...`);
7225
+ console.log(` bytes: ${outcome.bytes}`);
7226
+ console.log(` origin: worktree_id=${outcome.sourceWorktreePath}`);
7227
+ console.log(` cloud ts: ${new Date(outcome.cloudTs).toISOString()}`);
7228
+ break;
7229
+ case "up-to-date":
7230
+ console.log(`Already up-to-date (commit ${outcome.commitSha.slice(0, 7)}, sha256 ${outcome.snapshotSha256.slice(0, 12)}...)`);
7231
+ break;
7232
+ case "local-newer":
7233
+ console.log(`Local is newer than cloud \u2014 not pulling.`);
7234
+ console.log(` commit: ${outcome.commitSha.slice(0, 7)}`);
7235
+ console.log(` local ts: ${new Date(outcome.localTs).toISOString()}`);
7236
+ console.log(` cloud ts: ${new Date(outcome.cloudTs).toISOString()}`);
7237
+ break;
7238
+ case "no-cloud-row":
7239
+ console.log(`No cloud snapshot for commit ${outcome.commitSha.slice(0, 7)} \u2014 run \`hivemind graph build\` to create one.`);
7240
+ break;
7241
+ case "skipped-no-auth":
7242
+ console.log(`Skipped: not authenticated (run \`hivemind login\`).`);
7243
+ break;
7244
+ case "skipped-disabled":
7245
+ console.log(`Skipped: HIVEMIND_GRAPH_PULL=0.`);
7246
+ break;
7247
+ case "skipped-no-head":
7248
+ console.log(`Skipped: not in a git repo (\`git rev-parse HEAD\` failed).`);
7249
+ break;
7250
+ case "error":
7251
+ console.warn(`Pull error (non-fatal): ${outcome.message}`);
7252
+ process.exitCode = 1;
7253
+ break;
7254
+ }
7255
+ }
7256
+ function workTreeIdFor2(cwd) {
7257
+ return createHash6("sha256").update(cwd).digest("hex").slice(0, 16);
7258
+ }
7259
+ function discoverSourceFiles(rootDir) {
7260
+ const out = [];
7261
+ walk(rootDir, out);
7262
+ out.sort();
7263
+ return out;
7264
+ }
7265
+ function walk(dir, out) {
7266
+ let entries;
7267
+ try {
7268
+ entries = readdirSync2(dir, { withFileTypes: true });
7269
+ } catch {
7270
+ return;
7271
+ }
7272
+ for (const entry of entries) {
7273
+ if (DEFAULT_IGNORES.has(entry.name))
7274
+ continue;
7275
+ if (entry.name.startsWith("."))
7276
+ continue;
7277
+ const abs = join27(dir, entry.name);
7278
+ if (entry.isDirectory()) {
7279
+ walk(abs, out);
7280
+ } else if (entry.isFile() && isSourceFile(entry.name)) {
7281
+ out.push(abs);
7282
+ }
7283
+ }
7284
+ }
7285
+ function isSourceFile(name) {
7286
+ if (name.endsWith(".d.ts"))
7287
+ return false;
7288
+ return name.endsWith(".ts") || name.endsWith(".tsx");
7289
+ }
7290
+ function toForwardSlash(p) {
7291
+ return sep === "\\" ? p.replace(/\\/g, "/") : p;
7292
+ }
7293
+ function readGitCommit(cwd) {
7294
+ try {
7295
+ return execSync3("git rev-parse HEAD", {
7296
+ cwd,
7297
+ encoding: "utf8",
7298
+ stdio: ["ignore", "pipe", "ignore"]
7299
+ }).trim();
7300
+ } catch {
7301
+ return null;
7302
+ }
7303
+ }
7304
+ function readGitBranch(cwd) {
7305
+ try {
7306
+ const out = execSync3("git rev-parse --abbrev-ref HEAD", {
7307
+ cwd,
7308
+ encoding: "utf8",
7309
+ stdio: ["ignore", "pipe", "ignore"]
7310
+ }).trim();
7311
+ return out === "" || out === "HEAD" ? null : out;
7312
+ } catch {
7313
+ return null;
7314
+ }
7315
+ }
7316
+
7317
+ // dist/src/commands/dashboard.js
7318
+ import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync18 } from "node:fs";
7319
+ import { homedir as homedir15 } from "node:os";
7320
+ import { dirname as dirname12, join as join35, resolve as resolve5 } from "node:path";
7321
+
7322
+ // dist/src/dashboard/data.js
7323
+ import { existsSync as existsSync25, readFileSync as readFileSync24, readdirSync as readdirSync4, statSync as statSync3 } from "node:fs";
7324
+ import { homedir as homedir14 } from "node:os";
7325
+ import { join as join33 } from "node:path";
7326
+
7327
+ // dist/src/notifications/sources/org-stats.js
7328
+ import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
7329
+ import { homedir as homedir11 } from "node:os";
7330
+ import { dirname as dirname9, join as join28 } from "node:path";
7331
+ var log5 = (msg) => log2("notifications-org-stats", msg);
7332
+ var FETCH_TIMEOUT_MS = 1500;
7333
+ var DEFAULT_API_URL3 = "https://api.deeplake.ai";
7334
+ var CACHE_TTL_MS = 60 * 60 * 1e3;
7335
+ function cacheFilePath() {
7336
+ return join28(homedir11(), ".deeplake", "hivemind-stats-cache.json");
7337
+ }
7338
+ function cacheScopeKey(creds) {
7339
+ return JSON.stringify({
7340
+ apiUrl: creds.apiUrl ?? DEFAULT_API_URL3,
7341
+ orgId: creds.orgId ?? "",
7342
+ userName: creds.userName ?? ""
7343
+ });
7344
+ }
7345
+ function scopeFromServer(s) {
7346
+ const n = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0;
7347
+ return {
7348
+ sessionsCount: n(s?.sessions_count),
7349
+ memoryRecallCount: n(s?.memory_recall_count),
7350
+ memorySearchBytes: n(s?.memory_search_bytes)
7351
+ };
7352
+ }
7353
+ function readCache2(scopeKey) {
7354
+ if (!existsSync21(cacheFilePath()))
7355
+ return {};
7356
+ try {
7357
+ const parsed = JSON.parse(readFileSync21(cacheFilePath(), "utf-8"));
7358
+ if (!parsed || typeof parsed !== "object")
7359
+ return {};
7360
+ if (parsed.scopeKey !== scopeKey)
7361
+ return {};
7362
+ if (typeof parsed.fetchedAt !== "number")
7363
+ return {};
7364
+ const age = Date.now() - parsed.fetchedAt;
7365
+ const data = parsed.data;
7366
+ if (!data || typeof data !== "object" || !data.org || !data.user)
7367
+ return {};
7368
+ if (age >= 0 && age < CACHE_TTL_MS)
7369
+ return { fresh: data };
7370
+ return { stale: data };
7371
+ } catch (e) {
7372
+ log5(`cache read failed: ${e?.message ?? String(e)}`);
7373
+ return {};
7374
+ }
7375
+ }
7376
+ function writeCache2(scopeKey, data) {
7377
+ try {
7378
+ mkdirSync13(dirname9(cacheFilePath()), { recursive: true });
7379
+ const body = { fetchedAt: Date.now(), scopeKey, data };
7380
+ writeFileSync16(cacheFilePath(), JSON.stringify(body), "utf-8");
7381
+ } catch (e) {
7382
+ log5(`cache write failed: ${e?.message ?? String(e)}`);
7383
+ }
7384
+ }
7385
+ async function fetchOrgStats(creds) {
7386
+ if (!creds?.token)
7387
+ return null;
7388
+ const apiUrl = creds.apiUrl ?? DEFAULT_API_URL3;
7389
+ const scopeKey = cacheScopeKey(creds);
7390
+ const { fresh, stale } = readCache2(scopeKey);
7391
+ if (fresh) {
7392
+ log5("cache hit \u2014 returning fresh org stats");
7393
+ return fresh;
7394
+ }
7395
+ const url = `${apiUrl}/me/hivemind-stats`;
7396
+ const ctrl = new AbortController();
7397
+ const timeoutHandle = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
7398
+ try {
7399
+ const resp = await fetch(url, {
7400
+ headers: {
7401
+ Authorization: `Bearer ${creds.token}`,
7402
+ ...creds.orgId ? { "X-Activeloop-Org-Id": creds.orgId } : {}
7403
+ },
7404
+ signal: ctrl.signal
7405
+ });
7406
+ if (!resp.ok) {
7407
+ log5(`fetch ${url} returned ${resp.status}`);
7408
+ return stale ?? null;
7409
+ }
7410
+ const body = await resp.json();
7411
+ if (!body || typeof body !== "object") {
7412
+ log5(`fetch ${url} returned malformed body`);
7413
+ return stale ?? null;
7414
+ }
7415
+ const data = {
7416
+ org: scopeFromServer(body.org),
7417
+ user: scopeFromServer(body.user)
7418
+ };
7419
+ writeCache2(scopeKey, data);
7420
+ log5(`fetched org stats from ${apiUrl}`);
7421
+ return data;
7422
+ } catch (e) {
7423
+ log5(`fetch ${url} failed: ${e?.message ?? String(e)}`);
7424
+ return stale ?? null;
7425
+ } finally {
7426
+ clearTimeout(timeoutHandle);
7427
+ }
7428
+ }
7429
+
7430
+ // dist/src/notifications/usage-tracker.js
7431
+ import { appendFileSync as appendFileSync3, existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync22, readdirSync as readdirSync3 } from "node:fs";
7432
+ import { dirname as dirname10, join as join29 } from "node:path";
7433
+ import { homedir as homedir12 } from "node:os";
7434
+ var log6 = (msg) => log2("usage-tracker", msg);
7435
+ function statsFilePath() {
7436
+ return join29(homedir12(), ".deeplake", "usage-stats.jsonl");
7437
+ }
7438
+ function readUsageRecords() {
7439
+ try {
7440
+ if (!existsSync22(statsFilePath()))
7441
+ return [];
7442
+ const raw = readFileSync22(statsFilePath(), "utf-8");
7443
+ const out = [];
7444
+ for (const line of raw.split("\n")) {
7445
+ const trimmed = line.trim();
7446
+ if (!trimmed)
7447
+ continue;
7448
+ try {
7449
+ const rec = JSON.parse(trimmed);
7450
+ if (typeof rec.endedAt === "string" && typeof rec.sessionId === "string") {
7451
+ out.push({
7452
+ endedAt: rec.endedAt,
7453
+ sessionId: rec.sessionId,
7454
+ memorySearchBytes: typeof rec.memorySearchBytes === "number" ? rec.memorySearchBytes : 0,
7455
+ memorySearchCount: typeof rec.memorySearchCount === "number" ? rec.memorySearchCount : 0
7456
+ });
7457
+ }
7458
+ } catch {
7459
+ }
7460
+ }
7461
+ return out;
7462
+ } catch (e) {
7463
+ log6(`readUsageRecords failed: ${e?.message ?? String(e)}`);
7464
+ return [];
7465
+ }
7466
+ }
7467
+ function sumMetric(records, key) {
7468
+ let total = 0;
7469
+ for (const r of records) {
7470
+ const v = r[key];
7471
+ if (typeof v === "number" && Number.isFinite(v))
7472
+ total += v;
7473
+ }
7474
+ return total;
7475
+ }
7476
+ function countUserGeneratedSkills(userName) {
7477
+ if (!userName)
7478
+ return 0;
7479
+ const dir = join29(homedir12(), ".claude", "skills");
7480
+ if (!existsSync22(dir))
7481
+ return 0;
7482
+ const suffix = `--${userName}`;
7483
+ try {
7484
+ let count = 0;
7485
+ for (const name of readdirSync3(dir)) {
7486
+ const idx = name.lastIndexOf(suffix);
7487
+ if (idx > 0 && idx + suffix.length === name.length)
7488
+ count += 1;
7489
+ }
7490
+ return count;
7491
+ } catch (e) {
7492
+ log6(`countUserGeneratedSkills readdir failed: ${e?.message ?? String(e)}`);
7493
+ return 0;
7494
+ }
5418
7495
  }
5419
7496
 
5420
- // dist/src/commands/skillify.js
5421
- import { readdirSync as readdirSync5, existsSync as existsSync26, readFileSync as readFileSync22, mkdirSync as mkdirSync13, renameSync as renameSync7 } from "node:fs";
5422
- import { homedir as homedir19 } from "node:os";
5423
- import { dirname as dirname8, join as join32 } from "node:path";
5424
-
5425
- // dist/src/skillify/scope-config.js
5426
- import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
5427
- import { join as join22 } from "node:path";
7497
+ // dist/src/skillify/state.js
7498
+ import { readFileSync as readFileSync23, writeFileSync as writeFileSync17, writeSync, mkdirSync as mkdirSync15, renameSync as renameSync9, rmdirSync, existsSync as existsSync24, lstatSync as lstatSync3, unlinkSync as unlinkSync9, openSync as openSync2, closeSync as closeSync2 } from "node:fs";
7499
+ import { join as join32 } from "node:path";
5428
7500
 
5429
7501
  // dist/src/skillify/legacy-migration.js
5430
- import { existsSync as existsSync15, renameSync as renameSync4 } from "node:fs";
5431
- import { dirname as dirname3, join as join21 } from "node:path";
7502
+ import { existsSync as existsSync23, renameSync as renameSync8 } from "node:fs";
7503
+ import { dirname as dirname11, join as join31 } from "node:path";
5432
7504
 
5433
7505
  // dist/src/skillify/state-dir.js
5434
- import { homedir as homedir10 } from "node:os";
5435
- import { join as join20 } from "node:path";
7506
+ import { homedir as homedir13 } from "node:os";
7507
+ import { join as join30 } from "node:path";
5436
7508
  function getStateDir() {
5437
7509
  const override = process.env.HIVEMIND_STATE_DIR?.trim();
5438
- return override && override.length > 0 ? override : join20(homedir10(), ".deeplake", "state", "skillify");
7510
+ return override && override.length > 0 ? override : join30(homedir13(), ".deeplake", "state", "skillify");
5439
7511
  }
5440
7512
 
5441
7513
  // dist/src/skillify/legacy-migration.js
@@ -5448,13 +7520,13 @@ function migrateLegacyStateDir() {
5448
7520
  return;
5449
7521
  attempted = true;
5450
7522
  const current = getStateDir();
5451
- const legacy = join21(dirname3(current), "skilify");
5452
- if (!existsSync15(legacy))
7523
+ const legacy = join31(dirname11(current), "skilify");
7524
+ if (!existsSync23(legacy))
5453
7525
  return;
5454
- if (existsSync15(current))
7526
+ if (existsSync23(current))
5455
7527
  return;
5456
7528
  try {
5457
- renameSync4(legacy, current);
7529
+ renameSync8(legacy, current);
5458
7530
  dlog(`migrated ${legacy} -> ${current}`);
5459
7531
  } catch (err) {
5460
7532
  const code = err.code;
@@ -5466,18 +7538,818 @@ function migrateLegacyStateDir() {
5466
7538
  }
5467
7539
  }
5468
7540
 
7541
+ // dist/src/skillify/state.js
7542
+ var YIELD_BUF = new Int32Array(new SharedArrayBuffer(4));
7543
+ var TRIGGER_THRESHOLD = (() => {
7544
+ const n = Number(process.env.HIVEMIND_SKILLIFY_EVERY_N_TURNS ?? "");
7545
+ return Number.isInteger(n) && n > 0 ? n : 20;
7546
+ })();
7547
+
7548
+ // dist/src/dashboard/data.js
7549
+ var log7 = (msg) => log2("dashboard-data", msg);
7550
+ var BYTES_PER_TOKEN = 4;
7551
+ var SAVINGS_MULTIPLIER = 1.7;
7552
+ function graphsRoot2() {
7553
+ return process.env.HIVEMIND_GRAPHS_HOME ?? join33(homedir14(), ".hivemind", "graphs");
7554
+ }
7555
+ function bytesToSavedTokens(bytes) {
7556
+ if (!Number.isFinite(bytes) || bytes <= 0)
7557
+ return 0;
7558
+ const delivered = bytes / BYTES_PER_TOKEN;
7559
+ return (SAVINGS_MULTIPLIER - 1) * delivered;
7560
+ }
7561
+ function resolveSnapshot(repoDir2) {
7562
+ const snapshotsDir = join33(repoDir2, "snapshots");
7563
+ if (!existsSync25(snapshotsDir))
7564
+ return null;
7565
+ let snapshotPath = null;
7566
+ const pointer = join33(repoDir2, "latest-commit.txt");
7567
+ if (existsSync25(pointer)) {
7568
+ try {
7569
+ const sha = readFileSync24(pointer, "utf-8").trim();
7570
+ if (sha) {
7571
+ const candidate = join33(snapshotsDir, `${sha}.json`);
7572
+ if (existsSync25(candidate))
7573
+ snapshotPath = candidate;
7574
+ else
7575
+ log7(`latest-commit.txt points at missing ${sha}.json \u2014 scanning snapshots/`);
7576
+ }
7577
+ } catch (e) {
7578
+ log7(`latest-commit.txt read failed: ${e?.message ?? String(e)}`);
7579
+ }
7580
+ }
7581
+ if (!snapshotPath) {
7582
+ try {
7583
+ const candidates = readdirSync4(snapshotsDir).filter((name) => name.endsWith(".json")).map((name) => {
7584
+ const full = join33(snapshotsDir, name);
7585
+ return { full, mtime: statSync3(full).mtimeMs };
7586
+ }).sort((a, b) => b.mtime - a.mtime);
7587
+ if (candidates.length > 0)
7588
+ snapshotPath = candidates[0].full;
7589
+ } catch (e) {
7590
+ log7(`snapshots/ scan failed: ${e?.message ?? String(e)}`);
7591
+ }
7592
+ }
7593
+ if (!snapshotPath)
7594
+ return null;
7595
+ let raw;
7596
+ try {
7597
+ raw = readFileSync24(snapshotPath, "utf-8");
7598
+ } catch (e) {
7599
+ log7(`snapshot read failed: ${e?.message ?? String(e)}`);
7600
+ return null;
7601
+ }
7602
+ let parsed;
7603
+ try {
7604
+ parsed = JSON.parse(raw);
7605
+ } catch (e) {
7606
+ log7(`snapshot parse failed: ${e?.message ?? String(e)}`);
7607
+ return null;
7608
+ }
7609
+ if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.nodes) || !Array.isArray(parsed.links)) {
7610
+ log7("snapshot shape invalid (missing nodes/links arrays)");
7611
+ return null;
7612
+ }
7613
+ return {
7614
+ commitSha: parsed.graph?.commit_sha ?? null,
7615
+ snapshotPath,
7616
+ nodeCount: parsed.nodes.length,
7617
+ edgeCount: parsed.links.length,
7618
+ snapshot: parsed
7619
+ };
7620
+ }
7621
+ async function loadKpis(creds) {
7622
+ const userName = creds?.userName;
7623
+ const skillsCreated = countUserGeneratedSkills(userName);
7624
+ const records = readUsageRecords();
7625
+ const localBytes = sumMetric(records, "memorySearchBytes");
7626
+ const localCount = sumMetric(records, "memorySearchCount");
7627
+ let orgStats = null;
7628
+ if (creds?.token) {
7629
+ try {
7630
+ orgStats = await fetchOrgStats(creds);
7631
+ } catch (e) {
7632
+ log7(`fetchOrgStats threw: ${e?.message ?? String(e)}`);
7633
+ }
7634
+ }
7635
+ if (orgStats) {
7636
+ return {
7637
+ tokensSaved: bytesToSavedTokens(orgStats.org.memorySearchBytes),
7638
+ tokensSource: "org",
7639
+ skillsCreated,
7640
+ memorySearches: orgStats.org.memoryRecallCount,
7641
+ sessionsCount: orgStats.org.sessionsCount,
7642
+ userTokensSaved: bytesToSavedTokens(orgStats.user.memorySearchBytes)
7643
+ };
7644
+ }
7645
+ if (records.length > 0) {
7646
+ return {
7647
+ tokensSaved: bytesToSavedTokens(localBytes),
7648
+ tokensSource: "local",
7649
+ skillsCreated,
7650
+ memorySearches: localCount,
7651
+ sessionsCount: records.length,
7652
+ userTokensSaved: bytesToSavedTokens(localBytes)
7653
+ };
7654
+ }
7655
+ return {
7656
+ tokensSaved: null,
7657
+ tokensSource: "none",
7658
+ skillsCreated,
7659
+ memorySearches: 0,
7660
+ sessionsCount: null,
7661
+ userTokensSaved: null
7662
+ };
7663
+ }
7664
+ async function loadDashboardData(opts = {}) {
7665
+ const cwd = opts.cwd ?? process.cwd();
7666
+ const { key: repoKey, project: repoProject } = deriveProjectKey(cwd);
7667
+ const repoDir2 = join33(opts.graphsHome ?? graphsRoot2(), repoKey);
7668
+ const graph = resolveSnapshot(repoDir2);
7669
+ const creds = opts.creds === void 0 ? loadCredentials() : opts.creds;
7670
+ const kpis = await loadKpis(creds);
7671
+ return {
7672
+ repoKey,
7673
+ repoProject,
7674
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
7675
+ kpis,
7676
+ graph
7677
+ };
7678
+ }
7679
+
7680
+ // dist/src/dashboard/open.js
7681
+ import { spawn } from "node:child_process";
7682
+ import { accessSync, constants as fsConstants, statSync as statSync4 } from "node:fs";
7683
+ import { platform as nodePlatform } from "node:os";
7684
+ import { delimiter, join as join34 } from "node:path";
7685
+ function resolveOpenPlatform() {
7686
+ const p = nodePlatform();
7687
+ if (p === "linux" || p === "darwin" || p === "win32")
7688
+ return p;
7689
+ return null;
7690
+ }
7691
+ function openCommandFor(p, path) {
7692
+ switch (p) {
7693
+ case "linux":
7694
+ return { command: "xdg-open", args: [path] };
7695
+ case "darwin":
7696
+ return { command: "open", args: [path] };
7697
+ case "win32":
7698
+ return { command: "cmd", args: ["/c", "start", "", path] };
7699
+ }
7700
+ }
7701
+ function findBinaryOnPath(name) {
7702
+ const PATH = process.env.PATH ?? "";
7703
+ if (!PATH)
7704
+ return null;
7705
+ const isWin = nodePlatform() === "win32";
7706
+ const exts = isWin ? (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean) : [""];
7707
+ for (const dir of PATH.split(delimiter)) {
7708
+ if (!dir)
7709
+ continue;
7710
+ for (const ext of exts) {
7711
+ const candidate = join34(dir, name + ext);
7712
+ try {
7713
+ const st = statSync4(candidate);
7714
+ if (!st.isFile())
7715
+ continue;
7716
+ if (isWin)
7717
+ return candidate;
7718
+ try {
7719
+ accessSync(candidate, fsConstants.X_OK);
7720
+ return candidate;
7721
+ } catch {
7722
+ }
7723
+ } catch {
7724
+ }
7725
+ }
7726
+ }
7727
+ return null;
7728
+ }
7729
+ function openInBrowser(path, opts = {}) {
7730
+ const p = opts.platformOverride === void 0 ? resolveOpenPlatform() : opts.platformOverride;
7731
+ if (!p)
7732
+ return { attempted: false };
7733
+ const { command, args } = openCommandFor(p, path);
7734
+ const exists = opts.binaryExists ?? ((cmd) => findBinaryOnPath(cmd) !== null);
7735
+ if (!exists(command))
7736
+ return { attempted: false };
7737
+ const useSpawn = opts.spawner ?? spawn;
7738
+ try {
7739
+ const child = useSpawn(command, args, { stdio: "ignore", detached: true });
7740
+ child.on("error", () => {
7741
+ });
7742
+ if (typeof child.unref === "function") {
7743
+ child.unref();
7744
+ }
7745
+ return { attempted: true, command };
7746
+ } catch {
7747
+ return { attempted: false };
7748
+ }
7749
+ }
7750
+
7751
+ // dist/src/dashboard/render.js
7752
+ var VIS_NETWORK_CDN = "https://unpkg.com/vis-network@9.1.9/standalone/umd/vis-network.min.js";
7753
+ var KIND_COLORS = {
7754
+ function: "#7aa2f7",
7755
+ // soft blue
7756
+ class: "#bb9af7",
7757
+ // purple
7758
+ method: "#9ece6a",
7759
+ // green
7760
+ interface: "#e0af68",
7761
+ // amber
7762
+ type_alias: "#7dcfff",
7763
+ // cyan
7764
+ enum: "#f7768e",
7765
+ // pink
7766
+ const: "#9d7cd8",
7767
+ // muted purple
7768
+ module: "#565f89"
7769
+ // slate
7770
+ };
7771
+ var DEFAULT_NODE_COLOR = "#565f89";
7772
+ function isObject2(v) {
7773
+ return v !== null && typeof v === "object" && !Array.isArray(v);
7774
+ }
7775
+ function asString(v) {
7776
+ return typeof v === "string" ? v : null;
7777
+ }
7778
+ function transformSnapshotToVis(snapshot) {
7779
+ if (!isObject2(snapshot))
7780
+ return { nodes: [], edges: [] };
7781
+ const raw = snapshot;
7782
+ const visNodes = [];
7783
+ const ids = /* @__PURE__ */ new Set();
7784
+ if (Array.isArray(raw.nodes)) {
7785
+ for (const n of raw.nodes) {
7786
+ if (!isObject2(n))
7787
+ continue;
7788
+ const node = n;
7789
+ const id = asString(node.id);
7790
+ if (!id)
7791
+ continue;
7792
+ if (ids.has(id))
7793
+ continue;
7794
+ ids.add(id);
7795
+ const label = asString(node.label) ?? id;
7796
+ const kind = asString(node.kind);
7797
+ const sourceFile = asString(node.source_file);
7798
+ const sourceLoc = asString(node.source_location);
7799
+ const titleParts = [];
7800
+ if (kind)
7801
+ titleParts.push(kind);
7802
+ if (sourceFile) {
7803
+ const loc = sourceLoc ? `${sourceFile}:${sourceLoc}` : sourceFile;
7804
+ titleParts.push(loc);
7805
+ }
7806
+ const color = kind && KIND_COLORS[kind] ? KIND_COLORS[kind] : DEFAULT_NODE_COLOR;
7807
+ visNodes.push({
7808
+ id,
7809
+ label,
7810
+ title: titleParts.length > 0 ? titleParts.map(escHtml).join(" \xB7 ") : escHtml(id),
7811
+ group: kind ?? void 0,
7812
+ color: { background: color, border: color }
7813
+ });
7814
+ }
7815
+ }
7816
+ const visEdges = [];
7817
+ if (Array.isArray(raw.links)) {
7818
+ for (const l of raw.links) {
7819
+ if (!isObject2(l))
7820
+ continue;
7821
+ const edge = l;
7822
+ const from = asString(edge.source);
7823
+ const to = asString(edge.target);
7824
+ if (!from || !to)
7825
+ continue;
7826
+ const relation = asString(edge.relation);
7827
+ const confidence = asString(edge.confidence);
7828
+ const titleParts = [];
7829
+ if (relation)
7830
+ titleParts.push(relation);
7831
+ if (confidence)
7832
+ titleParts.push(`[${confidence}]`);
7833
+ visEdges.push({
7834
+ from,
7835
+ to,
7836
+ title: titleParts.length > 0 ? titleParts.map(escHtml).join(" ") : `${escHtml(from)} \u2192 ${escHtml(to)}`
7837
+ });
7838
+ }
7839
+ }
7840
+ return { nodes: visNodes, edges: visEdges };
7841
+ }
7842
+ function escHtml(s) {
7843
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
7844
+ }
7845
+ function safeJsonForScript(value) {
7846
+ return JSON.stringify(value).replace(/<\//g, "<\\/").replace(/<!--/g, "<\\u0021--").replace(/-->/g, "--\\u003e");
7847
+ }
7848
+ function formatTokensCompact(n) {
7849
+ if (!Number.isFinite(n) || n <= 0)
7850
+ return "0";
7851
+ if (n < 1e3)
7852
+ return `${Math.round(n)}`;
7853
+ if (n < 1e5)
7854
+ return `${(n / 1e3).toFixed(1)}k`;
7855
+ if (n < 1e6)
7856
+ return `${Math.round(n / 1e3)}k`;
7857
+ return `${(n / 1e6).toFixed(1)}M`;
7858
+ }
7859
+ function formatInt(n) {
7860
+ if (!Number.isFinite(n))
7861
+ return "0";
7862
+ return Math.round(n).toLocaleString("en-US");
7863
+ }
7864
+ function renderKpiCards(kpis) {
7865
+ const tokensValue = kpis.tokensSaved == null ? "\u2014" : `~${formatTokensCompact(kpis.tokensSaved)}`;
7866
+ const tokensSub = (() => {
7867
+ if (kpis.tokensSource === "org") {
7868
+ return kpis.userTokensSaved != null ? `Org-wide \xB7 you ~${formatTokensCompact(kpis.userTokensSaved)}` : "Org-wide";
7869
+ }
7870
+ if (kpis.tokensSource === "local")
7871
+ return "Local (this machine)";
7872
+ return "Run a session to start tracking";
7873
+ })();
7874
+ const memoryValue = kpis.memorySearches > 0 ? formatInt(kpis.memorySearches) : kpis.tokensSource === "none" ? "\u2014" : "0";
7875
+ const sessionsValue = kpis.sessionsCount == null ? "\u2014" : formatInt(kpis.sessionsCount);
7876
+ const cards = [
7877
+ {
7878
+ label: "Tokens saved",
7879
+ value: tokensValue,
7880
+ sub: tokensSub
7881
+ },
7882
+ {
7883
+ label: "Skills created",
7884
+ value: formatInt(kpis.skillsCreated),
7885
+ sub: "~/.claude/skills/"
7886
+ },
7887
+ {
7888
+ label: "Memory recalls",
7889
+ value: memoryValue,
7890
+ sub: kpis.tokensSource === "org" ? "Org-wide" : kpis.tokensSource === "local" ? "Local" : ""
7891
+ },
7892
+ {
7893
+ label: "Sessions",
7894
+ value: sessionsValue,
7895
+ sub: kpis.tokensSource === "org" ? "Org-wide" : kpis.tokensSource === "local" ? "Local" : ""
7896
+ }
7897
+ ];
7898
+ return cards.map((c) => `
7899
+ <div class="kpi">
7900
+ <div class="kpi-label">${escHtml(c.label)}</div>
7901
+ <div class="kpi-value">${escHtml(c.value)}</div>
7902
+ <div class="kpi-sub">${escHtml(c.sub)}</div>
7903
+ </div>`).join("");
7904
+ }
7905
+ function renderGraphSection(data) {
7906
+ if (data.graph == null) {
7907
+ return `
7908
+ <div class="graph-card">
7909
+ <h2>Codebase graph</h2>
7910
+ <div class="empty">
7911
+ No graph snapshot yet for this repo.<br>
7912
+ Run <code>hivemind graph build</code> to generate one.
7913
+ </div>
7914
+ </div>`;
7915
+ }
7916
+ const visPayload = transformSnapshotToVis(data.graph.snapshot);
7917
+ const commitLabel = data.graph.commitSha ? `commit ${data.graph.commitSha.slice(0, 12)}` : "no commit (loose dir)";
7918
+ const meta = `${formatInt(data.graph.nodeCount)} nodes \xB7 ${formatInt(data.graph.edgeCount)} edges \xB7 ${commitLabel}`;
7919
+ return `
7920
+ <div class="graph-card">
7921
+ <h2>Codebase graph</h2>
7922
+ <div class="graph-meta">${escHtml(meta)}</div>
7923
+ <div id="graph"></div>
7924
+ </div>
7925
+ <script type="application/json" id="hm-graph-data">${safeJsonForScript(visPayload)}</script>
7926
+ <script src="${VIS_NETWORK_CDN}"></script>
7927
+ <script>
7928
+ (function () {
7929
+ var holder = document.getElementById('hm-graph-data');
7930
+ var container = document.getElementById('graph');
7931
+ if (!holder || !container || typeof vis === 'undefined') return;
7932
+ var payload;
7933
+ try { payload = JSON.parse(holder.textContent); }
7934
+ catch (e) { container.textContent = 'graph payload parse failed'; return; }
7935
+ if (!payload || !Array.isArray(payload.nodes) || payload.nodes.length === 0) {
7936
+ container.textContent = 'snapshot has no nodes';
7937
+ return;
7938
+ }
7939
+ new vis.Network(container, payload, {
7940
+ nodes: {
7941
+ shape: 'dot',
7942
+ size: 9,
7943
+ font: { color: '#e8eaed', size: 11, face: 'system-ui, sans-serif' },
7944
+ borderWidth: 1,
7945
+ },
7946
+ edges: {
7947
+ color: { color: 'rgba(120, 130, 150, 0.45)', highlight: '#f5b80a', hover: '#e8eaed' },
7948
+ arrows: { to: { enabled: true, scaleFactor: 0.45 } },
7949
+ smooth: { enabled: true, type: 'continuous', roundness: 0.2 },
7950
+ width: 1,
7951
+ },
7952
+ physics: {
7953
+ stabilization: { iterations: 120 },
7954
+ barnesHut: { gravitationalConstant: -2200, springLength: 80, springConstant: 0.04 },
7955
+ },
7956
+ interaction: { hover: true, dragNodes: true, tooltipDelay: 120 },
7957
+ });
7958
+ }());
7959
+ </script>`;
7960
+ }
7961
+ var STYLES = `
7962
+ :root {
7963
+ color-scheme: dark;
7964
+ --bg: #0b0d10;
7965
+ --fg: #e8eaed;
7966
+ --muted: #8b9099;
7967
+ --accent: #f5b80a;
7968
+ --card: #15181d;
7969
+ --border: #22272e;
7970
+ }
7971
+ * { box-sizing: border-box; }
7972
+ html, body { margin: 0; padding: 0; }
7973
+ body {
7974
+ font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
7975
+ background: var(--bg);
7976
+ color: var(--fg);
7977
+ padding: 24px;
7978
+ }
7979
+ .header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 24px; gap: 16px; flex-wrap: wrap; }
7980
+ .brand { font-weight: 600; font-size: 18px; }
7981
+ .brand .bee { color: var(--accent); margin-right: 4px; }
7982
+ .brand .repo { color: var(--muted); font-weight: 400; margin-left: 8px; }
7983
+ .header .ts { color: var(--muted); font-size: 12px; }
7984
+ .kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-bottom: 32px; }
7985
+ .kpi { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 16px 20px; }
7986
+ .kpi-label { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; }
7987
+ .kpi-value { font-size: 28px; font-weight: 600; margin-top: 6px; line-height: 1.1; }
7988
+ .kpi-sub { color: var(--muted); font-size: 12px; margin-top: 4px; }
7989
+ .graph-card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 16px; }
7990
+ .graph-card h2 { margin: 0 0 8px; font-size: 15px; font-weight: 500; }
7991
+ .graph-meta { color: var(--muted); font-size: 12px; margin-bottom: 12px; }
7992
+ #graph { height: 70vh; border: 1px solid var(--border); border-radius: 4px; background: #0e1116; }
7993
+ .empty { padding: 48px 16px; text-align: center; color: var(--muted); }
7994
+ .empty code { background: #1c2128; padding: 2px 6px; border-radius: 3px; color: var(--fg); font-family: ui-monospace, "SFMono-Regular", monospace; }
7995
+ .footer { color: var(--muted); font-size: 11px; margin-top: 24px; text-align: right; }
7996
+ `;
7997
+ function renderDashboardHtml(data) {
7998
+ const title = `Hivemind Dashboard \xB7 ${data.repoProject}`;
7999
+ return `<!DOCTYPE html>
8000
+ <html lang="en">
8001
+ <head>
8002
+ <meta charset="utf-8">
8003
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8004
+ <title>${escHtml(title)}</title>
8005
+ <style>${STYLES}</style>
8006
+ </head>
8007
+ <body>
8008
+ <div class="header">
8009
+ <div class="brand">
8010
+ <span class="bee">\u{1F41D}</span>hivemind dashboard
8011
+ <span class="repo">/ ${escHtml(data.repoProject)}</span>
8012
+ </div>
8013
+ <div class="ts">${escHtml(data.generatedAt)}</div>
8014
+ </div>
8015
+ <div class="kpi-grid">${renderKpiCards(data.kpis)}
8016
+ </div>
8017
+ ${renderGraphSection(data)}
8018
+ <div class="footer">repo_key ${escHtml(data.repoKey)}</div>
8019
+ </body>
8020
+ </html>
8021
+ `;
8022
+ }
8023
+
8024
+ // dist/src/dashboard/serve.js
8025
+ import { createServer } from "node:http";
8026
+ var DEFAULT_PORT = 8123;
8027
+ var DEFAULT_HOST = "127.0.0.1";
8028
+ function handleRequest(html) {
8029
+ return (req, res) => {
8030
+ const url = req.url ?? "/";
8031
+ const path = url.split("?")[0];
8032
+ if (req.method === "GET" && (path === "/" || path === "/index.html")) {
8033
+ res.statusCode = 200;
8034
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
8035
+ res.setHeader("Cache-Control", "no-store");
8036
+ res.end(html);
8037
+ return;
8038
+ }
8039
+ if (req.method === "GET" && path === "/health") {
8040
+ res.statusCode = 204;
8041
+ res.end();
8042
+ return;
8043
+ }
8044
+ res.statusCode = 404;
8045
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
8046
+ res.end("Not found. The dashboard lives at /.\n");
8047
+ };
8048
+ }
8049
+ function tryListen(server, host, port) {
8050
+ return new Promise((resolve6, reject) => {
8051
+ const onError = (err) => {
8052
+ server.off("listening", onListening);
8053
+ reject(err);
8054
+ };
8055
+ const onListening = () => {
8056
+ server.off("error", onError);
8057
+ const addr = server.address();
8058
+ if (!addr || typeof addr === "string") {
8059
+ reject(new Error("server bound to a non-IP address"));
8060
+ return;
8061
+ }
8062
+ resolve6(addr.port);
8063
+ };
8064
+ server.once("error", onError);
8065
+ server.once("listening", onListening);
8066
+ server.listen(port, host);
8067
+ });
8068
+ }
8069
+ async function serveDashboardHtml(opts) {
8070
+ const host = opts.host ?? DEFAULT_HOST;
8071
+ const requested = opts.port === void 0 || !Number.isFinite(opts.port) || opts.port < 0 ? DEFAULT_PORT : opts.port;
8072
+ const server = createServer(handleRequest(opts.html));
8073
+ let bound;
8074
+ try {
8075
+ bound = await tryListen(server, host, requested);
8076
+ } catch (e) {
8077
+ if (e?.code !== "EADDRINUSE")
8078
+ throw e;
8079
+ const fallback = createServer(handleRequest(opts.html));
8080
+ bound = await tryListen(fallback, host, 0);
8081
+ server.removeAllListeners();
8082
+ return makeHandle(fallback, host, bound);
8083
+ }
8084
+ return makeHandle(server, host, bound);
8085
+ }
8086
+ function makeHandle(server, host, port) {
8087
+ let resolveStopped;
8088
+ const stopped = new Promise((resolve6) => {
8089
+ resolveStopped = resolve6;
8090
+ });
8091
+ server.on("close", () => resolveStopped());
8092
+ return {
8093
+ host,
8094
+ port,
8095
+ stopped,
8096
+ close: () => new Promise((resolve6, reject) => {
8097
+ server.close((err) => err ? reject(err) : resolve6());
8098
+ })
8099
+ };
8100
+ }
8101
+
8102
+ // dist/src/commands/dashboard.js
8103
+ var USAGE2 = `hivemind dashboard \u2014 codebase graph + KPI dashboard (HTML)
8104
+
8105
+ Usage:
8106
+ hivemind dashboard [--cwd <path>] [--out <path>] [--no-open]
8107
+ [--serve] [--port <n>]
8108
+ Build a self-contained HTML dashboard for this repo, write it
8109
+ to disk, and either open it in the default browser or serve
8110
+ it over loopback HTTP for headless / SSH workflows.
8111
+
8112
+ --cwd <path> Use a different project root (defaults to cwd).
8113
+ --out <path> Write to a custom path (defaults to
8114
+ ~/.hivemind/dashboards/<repo-key>/index.html).
8115
+ --no-open Don't open the browser. Combine with --serve
8116
+ to start the server without auto-launching.
8117
+ --serve Start a loopback HTTP server (127.0.0.1) so the
8118
+ dashboard is reachable at a URL. Stays alive
8119
+ until Ctrl+C. Ideal for VS Code / Cursor
8120
+ Remote-SSH (auto-forwards the port \u2192 click to
8121
+ open in the integrated browser tab).
8122
+ --port <n> Port for --serve (default 8123). Falls back to
8123
+ a kernel-assigned port if <n> is in use.
8124
+
8125
+ hivemind dashboard --help
8126
+ Show this message.
8127
+
8128
+ Data sources (all read-only):
8129
+ - Graph snapshot at ~/.hivemind/graphs/<repo-key>/ (produced by
8130
+ \`hivemind graph build\`; the dashboard works without it and shows
8131
+ an empty-state until the producer has run)
8132
+ - KPIs via the org stats endpoint (cached) with a local fallback
8133
+ to ~/.deeplake/usage-stats.jsonl
8134
+ - Skills created from ~/.claude/skills/<name>--<author>/ directories
8135
+ `;
8136
+ function parsePort(raw) {
8137
+ if (raw === void 0 || raw === "")
8138
+ return { error: "--port requires a value" };
8139
+ const n = Number(raw);
8140
+ if (!Number.isInteger(n) || n < 0 || n > 65535) {
8141
+ return { error: `--port must be an integer in [0, 65535], got '${raw}'` };
8142
+ }
8143
+ return n;
8144
+ }
8145
+ function parseDashboardArgs(args) {
8146
+ let cwd;
8147
+ let outPath = "";
8148
+ let open = true;
8149
+ let serve = false;
8150
+ let port;
8151
+ for (let i = 0; i < args.length; i++) {
8152
+ const a = args[i];
8153
+ if (a === "--help" || a === "-h")
8154
+ return { help: true };
8155
+ if (a === "--no-open") {
8156
+ open = false;
8157
+ continue;
8158
+ }
8159
+ if (a === "--serve") {
8160
+ serve = true;
8161
+ continue;
8162
+ }
8163
+ if (a === "--cwd") {
8164
+ const v = args[++i];
8165
+ if (v === void 0 || v.startsWith("-")) {
8166
+ return { error: "--cwd requires a value" };
8167
+ }
8168
+ cwd = v;
8169
+ continue;
8170
+ }
8171
+ if (a.startsWith("--cwd=")) {
8172
+ cwd = a.slice("--cwd=".length);
8173
+ continue;
8174
+ }
8175
+ if (a === "--out") {
8176
+ const v = args[++i];
8177
+ if (v === void 0 || v.startsWith("-")) {
8178
+ return { error: "--out requires a value" };
8179
+ }
8180
+ outPath = v;
8181
+ continue;
8182
+ }
8183
+ if (a.startsWith("--out=")) {
8184
+ outPath = a.slice("--out=".length);
8185
+ continue;
8186
+ }
8187
+ if (a === "--port") {
8188
+ const v = args[++i];
8189
+ if (v === void 0 || v.startsWith("-")) {
8190
+ return { error: "--port requires a value" };
8191
+ }
8192
+ const parsed = parsePort(v);
8193
+ if (typeof parsed === "object")
8194
+ return { error: parsed.error };
8195
+ port = parsed;
8196
+ continue;
8197
+ }
8198
+ if (a.startsWith("--port=")) {
8199
+ const parsed = parsePort(a.slice("--port=".length));
8200
+ if (typeof parsed === "object")
8201
+ return { error: parsed.error };
8202
+ port = parsed;
8203
+ continue;
8204
+ }
8205
+ return { error: `unknown arg '${a}'` };
8206
+ }
8207
+ if (port !== void 0 && !serve) {
8208
+ return { error: "--port requires --serve" };
8209
+ }
8210
+ return {
8211
+ args: {
8212
+ cwd: cwd ?? process.cwd(),
8213
+ outPath,
8214
+ open,
8215
+ serve,
8216
+ port
8217
+ }
8218
+ };
8219
+ }
8220
+ function defaultDashboardOutPath(repoKey) {
8221
+ return join35(homedir15(), ".hivemind", "dashboards", repoKey, "index.html");
8222
+ }
8223
+ async function runDashboardCommand(rawArgs, runOpts = {}) {
8224
+ const out = runOpts.out ?? ((s) => {
8225
+ process.stdout.write(s);
8226
+ });
8227
+ const err = runOpts.err ?? ((s) => {
8228
+ process.stderr.write(s);
8229
+ });
8230
+ const opener = runOpts.opener ?? openInBrowser;
8231
+ const parsed = parseDashboardArgs(rawArgs);
8232
+ if (parsed.help) {
8233
+ out(USAGE2);
8234
+ return 0;
8235
+ }
8236
+ if (parsed.error || !parsed.args) {
8237
+ err(`hivemind dashboard: ${parsed.error ?? "invalid arguments"}
8238
+ `);
8239
+ err(USAGE2);
8240
+ return 2;
8241
+ }
8242
+ const { cwd, outPath, open } = parsed.args;
8243
+ let data;
8244
+ try {
8245
+ data = await loadDashboardData({ cwd });
8246
+ } catch (e) {
8247
+ err(`hivemind dashboard: failed to load data: ${e?.message ?? String(e)}
8248
+ `);
8249
+ return 1;
8250
+ }
8251
+ const html = renderDashboardHtml(data);
8252
+ const finalOut = outPath || defaultDashboardOutPath(data.repoKey);
8253
+ const absOut = resolve5(finalOut);
8254
+ try {
8255
+ mkdirSync16(dirname12(absOut), { recursive: true });
8256
+ writeFileSync18(absOut, html, "utf-8");
8257
+ } catch (e) {
8258
+ err(`hivemind dashboard: failed to write ${absOut}: ${e?.message ?? String(e)}
8259
+ `);
8260
+ return 1;
8261
+ }
8262
+ out(`Wrote ${absOut}
8263
+ `);
8264
+ if (data.graph == null) {
8265
+ out(`(no codebase graph yet \u2014 run 'hivemind graph build' to populate)
8266
+ `);
8267
+ }
8268
+ if (parsed.args.serve) {
8269
+ return await runServeLoop(html, parsed.args, runOpts, out, err);
8270
+ }
8271
+ if (open) {
8272
+ const result = opener(absOut);
8273
+ if (result.attempted) {
8274
+ out(`Opening via ${result.command}
8275
+ `);
8276
+ } else {
8277
+ out(`(no opener for this platform; open the file above manually)
8278
+ `);
8279
+ }
8280
+ }
8281
+ return 0;
8282
+ }
8283
+ async function runServeLoop(html, args, runOpts, out, err) {
8284
+ const server = runOpts.server ?? serveDashboardHtml;
8285
+ const opener = runOpts.opener ?? openInBrowser;
8286
+ const onSignal = runOpts.onSignal ?? defaultOnSignal;
8287
+ let handle;
8288
+ try {
8289
+ handle = await server({ html, port: args.port });
8290
+ } catch (e) {
8291
+ err(`hivemind dashboard: failed to start server: ${e?.message ?? String(e)}
8292
+ `);
8293
+ return 1;
8294
+ }
8295
+ const url = `http://${handle.host}:${handle.port}/`;
8296
+ out(`Serving dashboard at ${url} (Ctrl+C to stop)
8297
+ `);
8298
+ if (args.open) {
8299
+ const result = opener(url);
8300
+ if (result.attempted) {
8301
+ out(`Opening via ${result.command}
8302
+ `);
8303
+ } else {
8304
+ out(`(no opener for this platform; click the URL above or open it manually)
8305
+ `);
8306
+ }
8307
+ }
8308
+ let resolveDone;
8309
+ const done = new Promise((r) => {
8310
+ resolveDone = r;
8311
+ });
8312
+ const shutdown = async () => {
8313
+ try {
8314
+ await handle.close();
8315
+ } catch {
8316
+ }
8317
+ resolveDone(0);
8318
+ };
8319
+ const offInt = onSignal("SIGINT", shutdown);
8320
+ const offTerm = onSignal("SIGTERM", shutdown);
8321
+ handle.stopped.then(() => resolveDone(0));
8322
+ try {
8323
+ return await done;
8324
+ } finally {
8325
+ offInt();
8326
+ offTerm();
8327
+ }
8328
+ }
8329
+ function defaultOnSignal(signal, handler) {
8330
+ process.on(signal, handler);
8331
+ return () => process.off(signal, handler);
8332
+ }
8333
+
8334
+ // dist/src/commands/skillify.js
8335
+ import { readdirSync as readdirSync8, existsSync as existsSync36, readFileSync as readFileSync32, mkdirSync as mkdirSync23, renameSync as renameSync12 } from "node:fs";
8336
+ import { homedir as homedir24 } from "node:os";
8337
+ import { dirname as dirname17, join as join46 } from "node:path";
8338
+
5469
8339
  // dist/src/skillify/scope-config.js
8340
+ import { existsSync as existsSync26, mkdirSync as mkdirSync17, readFileSync as readFileSync25, writeFileSync as writeFileSync19 } from "node:fs";
8341
+ import { join as join36 } from "node:path";
5470
8342
  function configPath() {
5471
- return join22(getStateDir(), "config.json");
8343
+ return join36(getStateDir(), "config.json");
5472
8344
  }
5473
8345
  var DEFAULT = { scope: "me", team: [], install: "project" };
5474
8346
  function loadScopeConfig() {
5475
8347
  migrateLegacyStateDir();
5476
8348
  const CONFIG_PATH2 = configPath();
5477
- if (!existsSync16(CONFIG_PATH2))
8349
+ if (!existsSync26(CONFIG_PATH2))
5478
8350
  return DEFAULT;
5479
8351
  try {
5480
- const raw = JSON.parse(readFileSync15(CONFIG_PATH2, "utf-8"));
8352
+ const raw = JSON.parse(readFileSync25(CONFIG_PATH2, "utf-8"));
5481
8353
  const scope = raw.scope === "team" ? "team" : raw.scope === "org" ? "team" : "me";
5482
8354
  const team = Array.isArray(raw.team) ? raw.team.filter((s) => typeof s === "string") : [];
5483
8355
  const install = raw.install === "global" ? "global" : "project";
@@ -5488,19 +8360,19 @@ function loadScopeConfig() {
5488
8360
  }
5489
8361
  function saveScopeConfig(cfg) {
5490
8362
  migrateLegacyStateDir();
5491
- mkdirSync7(getStateDir(), { recursive: true });
5492
- writeFileSync11(configPath(), JSON.stringify(cfg, null, 2));
8363
+ mkdirSync17(getStateDir(), { recursive: true });
8364
+ writeFileSync19(configPath(), JSON.stringify(cfg, null, 2));
5493
8365
  }
5494
8366
 
5495
8367
  // dist/src/skillify/pull.js
5496
- import { existsSync as existsSync20, readFileSync as readFileSync18, writeFileSync as writeFileSync14, mkdirSync as mkdirSync10, renameSync as renameSync6, lstatSync as lstatSync4, readlinkSync as readlinkSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync9 } from "node:fs";
5497
- import { homedir as homedir13 } from "node:os";
5498
- import { dirname as dirname5, join as join26 } from "node:path";
8368
+ import { existsSync as existsSync30, readFileSync as readFileSync28, writeFileSync as writeFileSync22, mkdirSync as mkdirSync20, renameSync as renameSync11, lstatSync as lstatSync5, readlinkSync as readlinkSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync11 } from "node:fs";
8369
+ import { homedir as homedir18 } from "node:os";
8370
+ import { dirname as dirname14, join as join40 } from "node:path";
5499
8371
 
5500
8372
  // dist/src/skillify/skill-writer.js
5501
- import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync16, readdirSync as readdirSync2, statSync as statSync3, writeFileSync as writeFileSync12 } from "node:fs";
5502
- import { homedir as homedir11 } from "node:os";
5503
- import { join as join23 } from "node:path";
8373
+ import { existsSync as existsSync27, mkdirSync as mkdirSync18, readFileSync as readFileSync26, readdirSync as readdirSync5, statSync as statSync5, writeFileSync as writeFileSync20 } from "node:fs";
8374
+ import { homedir as homedir16 } from "node:os";
8375
+ import { join as join37 } from "node:path";
5504
8376
  function assertValidSkillName(name) {
5505
8377
  if (typeof name !== "string" || name.length === 0) {
5506
8378
  throw new Error(`invalid skill name: empty or non-string`);
@@ -5516,10 +8388,10 @@ function assertValidSkillName(name) {
5516
8388
  }
5517
8389
  }
5518
8390
  function skillDir(skillsRoot, name) {
5519
- return join23(skillsRoot, name);
8391
+ return join37(skillsRoot, name);
5520
8392
  }
5521
8393
  function skillPath(skillsRoot, name) {
5522
- return join23(skillDir(skillsRoot, name), "SKILL.md");
8394
+ return join37(skillDir(skillsRoot, name), "SKILL.md");
5523
8395
  }
5524
8396
  function renderFrontmatter(fm) {
5525
8397
  const lines = ["---"];
@@ -5597,10 +8469,10 @@ function writeNewSkill(args) {
5597
8469
  assertValidSkillName(args.name);
5598
8470
  const dir = skillDir(args.skillsRoot, args.name);
5599
8471
  const path = skillPath(args.skillsRoot, args.name);
5600
- if (existsSync17(path)) {
8472
+ if (existsSync27(path)) {
5601
8473
  throw new Error(`skill already exists at ${path}; use mergeSkill`);
5602
8474
  }
5603
- mkdirSync8(dir, { recursive: true });
8475
+ mkdirSync18(dir, { recursive: true });
5604
8476
  const now = (/* @__PURE__ */ new Date()).toISOString();
5605
8477
  const author = args.author && args.author.length > 0 ? args.author : void 0;
5606
8478
  const contributors = author ? [author] : [];
@@ -5620,7 +8492,7 @@ function writeNewSkill(args) {
5620
8492
 
5621
8493
  ${args.body.trim()}
5622
8494
  `;
5623
- writeFileSync12(path, text);
8495
+ writeFileSync20(path, text);
5624
8496
  return {
5625
8497
  path,
5626
8498
  action: "created",
@@ -5632,40 +8504,40 @@ ${args.body.trim()}
5632
8504
  };
5633
8505
  }
5634
8506
  function listSkills(skillsRoot) {
5635
- if (!existsSync17(skillsRoot))
8507
+ if (!existsSync27(skillsRoot))
5636
8508
  return [];
5637
8509
  const out = [];
5638
- for (const name of readdirSync2(skillsRoot)) {
5639
- const skillFile = join23(skillsRoot, name, "SKILL.md");
5640
- if (existsSync17(skillFile) && statSync3(skillFile).isFile()) {
5641
- out.push({ name, body: readFileSync16(skillFile, "utf-8") });
8510
+ for (const name of readdirSync5(skillsRoot)) {
8511
+ const skillFile = join37(skillsRoot, name, "SKILL.md");
8512
+ if (existsSync27(skillFile) && statSync5(skillFile).isFile()) {
8513
+ out.push({ name, body: readFileSync26(skillFile, "utf-8") });
5642
8514
  }
5643
8515
  }
5644
8516
  return out;
5645
8517
  }
5646
8518
  function resolveSkillsRoot(install, cwd) {
5647
8519
  if (install === "global") {
5648
- return join23(homedir11(), ".claude", "skills");
8520
+ return join37(homedir16(), ".claude", "skills");
5649
8521
  }
5650
- return join23(cwd, ".claude", "skills");
8522
+ return join37(cwd, ".claude", "skills");
5651
8523
  }
5652
8524
 
5653
8525
  // dist/src/skillify/manifest.js
5654
- import { existsSync as existsSync18, lstatSync as lstatSync3, mkdirSync as mkdirSync9, readFileSync as readFileSync17, renameSync as renameSync5, unlinkSync as unlinkSync8, writeFileSync as writeFileSync13 } from "node:fs";
5655
- import { dirname as dirname4, join as join24 } from "node:path";
8526
+ import { existsSync as existsSync28, lstatSync as lstatSync4, mkdirSync as mkdirSync19, readFileSync as readFileSync27, renameSync as renameSync10, unlinkSync as unlinkSync10, writeFileSync as writeFileSync21 } from "node:fs";
8527
+ import { dirname as dirname13, join as join38 } from "node:path";
5656
8528
  function emptyManifest() {
5657
8529
  return { version: 1, entries: [] };
5658
8530
  }
5659
8531
  function manifestPath() {
5660
- return join24(getStateDir(), "pulled.json");
8532
+ return join38(getStateDir(), "pulled.json");
5661
8533
  }
5662
8534
  function loadManifest(path = manifestPath()) {
5663
8535
  migrateLegacyStateDir();
5664
- if (!existsSync18(path))
8536
+ if (!existsSync28(path))
5665
8537
  return emptyManifest();
5666
8538
  let raw;
5667
8539
  try {
5668
- raw = readFileSync17(path, "utf-8");
8540
+ raw = readFileSync27(path, "utf-8");
5669
8541
  } catch {
5670
8542
  return emptyManifest();
5671
8543
  }
@@ -5712,10 +8584,10 @@ function loadManifest(path = manifestPath()) {
5712
8584
  }
5713
8585
  function saveManifest(m, path = manifestPath()) {
5714
8586
  migrateLegacyStateDir();
5715
- mkdirSync9(dirname4(path), { recursive: true });
8587
+ mkdirSync19(dirname13(path), { recursive: true });
5716
8588
  const tmp = `${path}.tmp`;
5717
- writeFileSync13(tmp, JSON.stringify(m, null, 2) + "\n", { mode: 384 });
5718
- renameSync5(tmp, path);
8589
+ writeFileSync21(tmp, JSON.stringify(m, null, 2) + "\n", { mode: 384 });
8590
+ renameSync10(tmp, path);
5719
8591
  }
5720
8592
  function recordPull(entry, path = manifestPath()) {
5721
8593
  const m = loadManifest(path);
@@ -5740,14 +8612,14 @@ function unlinkSymlinks(paths) {
5740
8612
  for (const path of paths) {
5741
8613
  let st;
5742
8614
  try {
5743
- st = lstatSync3(path);
8615
+ st = lstatSync4(path);
5744
8616
  } catch {
5745
8617
  continue;
5746
8618
  }
5747
8619
  if (!st.isSymbolicLink())
5748
8620
  continue;
5749
8621
  try {
5750
- unlinkSync8(path);
8622
+ unlinkSync10(path);
5751
8623
  } catch {
5752
8624
  }
5753
8625
  }
@@ -5757,7 +8629,7 @@ function pruneOrphanedEntries(path = manifestPath()) {
5757
8629
  const live = [];
5758
8630
  let pruned = 0;
5759
8631
  for (const e of m.entries) {
5760
- if (existsSync18(join24(e.installRoot, e.dirName))) {
8632
+ if (existsSync28(join38(e.installRoot, e.dirName))) {
5761
8633
  live.push(e);
5762
8634
  continue;
5763
8635
  }
@@ -5770,26 +8642,26 @@ function pruneOrphanedEntries(path = manifestPath()) {
5770
8642
  }
5771
8643
 
5772
8644
  // dist/src/skillify/agent-roots.js
5773
- import { existsSync as existsSync19 } from "node:fs";
5774
- import { homedir as homedir12 } from "node:os";
5775
- import { join as join25 } from "node:path";
8645
+ import { existsSync as existsSync29 } from "node:fs";
8646
+ import { homedir as homedir17 } from "node:os";
8647
+ import { join as join39 } from "node:path";
5776
8648
  function resolveDetected(home) {
5777
8649
  const out = [];
5778
- const codexInstalled = existsSync19(join25(home, ".codex"));
5779
- const piInstalled = existsSync19(join25(home, ".pi", "agent"));
5780
- const hermesInstalled = existsSync19(join25(home, ".hermes"));
8650
+ const codexInstalled = existsSync29(join39(home, ".codex"));
8651
+ const piInstalled = existsSync29(join39(home, ".pi", "agent"));
8652
+ const hermesInstalled = existsSync29(join39(home, ".hermes"));
5781
8653
  if (codexInstalled || piInstalled) {
5782
- out.push(join25(home, ".agents", "skills"));
8654
+ out.push(join39(home, ".agents", "skills"));
5783
8655
  }
5784
8656
  if (hermesInstalled) {
5785
- out.push(join25(home, ".hermes", "skills"));
8657
+ out.push(join39(home, ".hermes", "skills"));
5786
8658
  }
5787
8659
  if (piInstalled) {
5788
- out.push(join25(home, ".pi", "agent", "skills"));
8660
+ out.push(join39(home, ".pi", "agent", "skills"));
5789
8661
  }
5790
8662
  return out;
5791
8663
  }
5792
- function detectAgentSkillsRoots(canonicalRoot, home = homedir12()) {
8664
+ function detectAgentSkillsRoots(canonicalRoot, home = homedir17()) {
5793
8665
  return resolveDetected(home).filter((p) => p !== canonicalRoot);
5794
8666
  }
5795
8667
 
@@ -5833,18 +8705,18 @@ function isMissingTableError(message) {
5833
8705
  }
5834
8706
  function resolvePullDestination(install, cwd) {
5835
8707
  if (install === "global")
5836
- return join26(homedir13(), ".claude", "skills");
8708
+ return join40(homedir18(), ".claude", "skills");
5837
8709
  if (!cwd)
5838
8710
  throw new Error("install=project requires a cwd");
5839
- return join26(cwd, ".claude", "skills");
8711
+ return join40(cwd, ".claude", "skills");
5840
8712
  }
5841
8713
  function fanOutSymlinks(canonicalDir, dirName, agentRoots) {
5842
8714
  const out = [];
5843
8715
  for (const root of agentRoots) {
5844
- const link = join26(root, dirName);
8716
+ const link = join40(root, dirName);
5845
8717
  let existing;
5846
8718
  try {
5847
- existing = lstatSync4(link);
8719
+ existing = lstatSync5(link);
5848
8720
  } catch {
5849
8721
  existing = null;
5850
8722
  }
@@ -5863,13 +8735,13 @@ function fanOutSymlinks(canonicalDir, dirName, agentRoots) {
5863
8735
  continue;
5864
8736
  }
5865
8737
  try {
5866
- unlinkSync9(link);
8738
+ unlinkSync11(link);
5867
8739
  } catch {
5868
8740
  continue;
5869
8741
  }
5870
8742
  }
5871
8743
  try {
5872
- mkdirSync10(dirname5(link), { recursive: true });
8744
+ mkdirSync20(dirname14(link), { recursive: true });
5873
8745
  symlinkSync2(canonicalDir, link, "dir");
5874
8746
  out.push(link);
5875
8747
  } catch {
@@ -5884,8 +8756,8 @@ function backfillSymlinks(installRoot) {
5884
8756
  return;
5885
8757
  const detected = detectAgentSkillsRoots(installRoot);
5886
8758
  for (const entry of entries) {
5887
- const canonical = join26(entry.installRoot, entry.dirName);
5888
- if (!existsSync20(canonical))
8759
+ const canonical = join40(entry.installRoot, entry.dirName);
8760
+ if (!existsSync30(canonical))
5889
8761
  continue;
5890
8762
  const fresh = fanOutSymlinks(canonical, entry.dirName, detected);
5891
8763
  if (sameSorted(fresh, entry.symlinks))
@@ -5995,10 +8867,10 @@ function renderFrontmatter2(fm) {
5995
8867
  return lines.join("\n");
5996
8868
  }
5997
8869
  function readLocalVersion(path) {
5998
- if (!existsSync20(path))
8870
+ if (!existsSync30(path))
5999
8871
  return null;
6000
8872
  try {
6001
- const text = readFileSync18(path, "utf-8");
8873
+ const text = readFileSync28(path, "utf-8");
6002
8874
  const parsed = parseFrontmatter(text);
6003
8875
  if (!parsed)
6004
8876
  return null;
@@ -6093,8 +8965,8 @@ async function runPull(opts) {
6093
8965
  summary.skipped++;
6094
8966
  continue;
6095
8967
  }
6096
- const skillDir2 = join26(root, dirName);
6097
- const skillFile = join26(skillDir2, "SKILL.md");
8968
+ const skillDir2 = join40(root, dirName);
8969
+ const skillFile = join40(skillDir2, "SKILL.md");
6098
8970
  const remoteVersion = Number(row.version ?? 1);
6099
8971
  const localVersion = readLocalVersion(skillFile);
6100
8972
  const action = decideAction({
@@ -6105,14 +8977,14 @@ async function runPull(opts) {
6105
8977
  });
6106
8978
  let manifestError;
6107
8979
  if (action === "wrote") {
6108
- mkdirSync10(skillDir2, { recursive: true });
6109
- if (existsSync20(skillFile)) {
8980
+ mkdirSync20(skillDir2, { recursive: true });
8981
+ if (existsSync30(skillFile)) {
6110
8982
  try {
6111
- renameSync6(skillFile, `${skillFile}.bak`);
8983
+ renameSync11(skillFile, `${skillFile}.bak`);
6112
8984
  } catch {
6113
8985
  }
6114
8986
  }
6115
- writeFileSync14(skillFile, renderSkillFile(row));
8987
+ writeFileSync22(skillFile, renderSkillFile(row));
6116
8988
  const symlinks = opts.install === "global" ? fanOutSymlinks(skillDir2, dirName, detectAgentSkillsRoots(root)) : [];
6117
8989
  try {
6118
8990
  recordPull({
@@ -6154,15 +9026,15 @@ async function runPull(opts) {
6154
9026
  }
6155
9027
 
6156
9028
  // dist/src/skillify/unpull.js
6157
- import { existsSync as existsSync21, readdirSync as readdirSync3, rmSync as rmSync5, statSync as statSync4 } from "node:fs";
6158
- import { homedir as homedir14 } from "node:os";
6159
- import { join as join27 } from "node:path";
9029
+ import { existsSync as existsSync31, readdirSync as readdirSync6, rmSync as rmSync5, statSync as statSync6 } from "node:fs";
9030
+ import { homedir as homedir19 } from "node:os";
9031
+ import { join as join41 } from "node:path";
6160
9032
  function resolveUnpullRoot(install, cwd) {
6161
9033
  if (install === "global")
6162
- return join27(homedir14(), ".claude", "skills");
9034
+ return join41(homedir19(), ".claude", "skills");
6163
9035
  if (!cwd)
6164
9036
  throw new Error("cwd required when install === 'project'");
6165
- return join27(cwd, ".claude", "skills");
9037
+ return join41(cwd, ".claude", "skills");
6166
9038
  }
6167
9039
  function runUnpull(opts) {
6168
9040
  const root = resolveUnpullRoot(opts.install, opts.cwd);
@@ -6185,8 +9057,8 @@ function runUnpull(opts) {
6185
9057
  const entries = entriesForRoot(manifest, opts.install, root);
6186
9058
  for (const entry of entries) {
6187
9059
  summary.scanned++;
6188
- const path = join27(root, entry.dirName);
6189
- if (!existsSync21(path)) {
9060
+ const path = join41(root, entry.dirName);
9061
+ if (!existsSync31(path)) {
6190
9062
  if (!opts.dryRun) {
6191
9063
  unlinkSymlinks(entry.symlinks);
6192
9064
  removePullEntry(opts.install, entry.installRoot, entry.dirName);
@@ -6239,15 +9111,15 @@ function runUnpull(opts) {
6239
9111
  }
6240
9112
  summary.entries.push(result);
6241
9113
  }
6242
- if (existsSync21(root) && (opts.all || opts.legacyCleanup)) {
9114
+ if (existsSync31(root) && (opts.all || opts.legacyCleanup)) {
6243
9115
  const manifestDirNames = new Set(entries.map((e) => e.dirName));
6244
- for (const dirName of readdirSync3(root)) {
9116
+ for (const dirName of readdirSync6(root)) {
6245
9117
  if (manifestDirNames.has(dirName))
6246
9118
  continue;
6247
- const path = join27(root, dirName);
9119
+ const path = join41(root, dirName);
6248
9120
  let st;
6249
9121
  try {
6250
- st = statSync4(path);
9122
+ st = statSync6(path);
6251
9123
  } catch {
6252
9124
  continue;
6253
9125
  }
@@ -6322,31 +9194,31 @@ function decideTargetForManifestEntry(entry, opts, userFilter, haveUserFilter) {
6322
9194
  }
6323
9195
 
6324
9196
  // dist/src/commands/mine-local.js
6325
- import { spawn } from "node:child_process";
6326
- import { existsSync as existsSync25, mkdirSync as mkdirSync12, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
6327
- import { homedir as homedir18 } from "node:os";
6328
- import { basename, dirname as dirname7, join as join31 } from "node:path";
9197
+ import { spawn as spawn2 } from "node:child_process";
9198
+ import { existsSync as existsSync35, mkdirSync as mkdirSync22, readFileSync as readFileSync31, writeFileSync as writeFileSync24 } from "node:fs";
9199
+ import { homedir as homedir23 } from "node:os";
9200
+ import { basename as basename2, dirname as dirname16, join as join45 } from "node:path";
6329
9201
 
6330
9202
  // dist/src/skillify/local-source.js
6331
- import { readdirSync as readdirSync4, readFileSync as readFileSync19, existsSync as existsSync22, statSync as statSync5 } from "node:fs";
6332
- import { homedir as homedir15 } from "node:os";
6333
- import { join as join28 } from "node:path";
6334
- var HOME2 = homedir15();
9203
+ import { readdirSync as readdirSync7, readFileSync as readFileSync29, existsSync as existsSync32, statSync as statSync7 } from "node:fs";
9204
+ import { homedir as homedir20 } from "node:os";
9205
+ import { join as join42 } from "node:path";
9206
+ var HOME2 = homedir20();
6335
9207
  function encodeCwdClaudeCode(cwd) {
6336
9208
  return cwd.replace(/[/_]/g, "-");
6337
9209
  }
6338
9210
  function detectInstalledAgents() {
6339
9211
  const installs = [];
6340
- const claudeRoot = join28(HOME2, ".claude", "projects");
6341
- if (existsSync22(claudeRoot)) {
9212
+ const claudeRoot = join42(HOME2, ".claude", "projects");
9213
+ if (existsSync32(claudeRoot)) {
6342
9214
  installs.push({
6343
9215
  agent: "claude_code",
6344
9216
  sessionRoot: claudeRoot,
6345
9217
  encodeCwd: encodeCwdClaudeCode
6346
9218
  });
6347
9219
  }
6348
- const codexRoot = join28(HOME2, ".codex", "sessions");
6349
- if (existsSync22(codexRoot)) {
9220
+ const codexRoot = join42(HOME2, ".codex", "sessions");
9221
+ if (existsSync32(codexRoot)) {
6350
9222
  installs.push({
6351
9223
  agent: "codex",
6352
9224
  sessionRoot: codexRoot,
@@ -6368,14 +9240,14 @@ function listLocalSessions(installs, cwd) {
6368
9240
  const cwdEncoded = install.encodeCwd(cwd);
6369
9241
  let subdirs = [];
6370
9242
  try {
6371
- subdirs = readdirSync4(install.sessionRoot);
9243
+ subdirs = readdirSync7(install.sessionRoot);
6372
9244
  } catch {
6373
9245
  continue;
6374
9246
  }
6375
9247
  for (const sub of subdirs) {
6376
- const subdirPath = join28(install.sessionRoot, sub);
9248
+ const subdirPath = join42(install.sessionRoot, sub);
6377
9249
  try {
6378
- if (!statSync5(subdirPath).isDirectory())
9250
+ if (!statSync7(subdirPath).isDirectory())
6379
9251
  continue;
6380
9252
  } catch {
6381
9253
  continue;
@@ -6383,17 +9255,17 @@ function listLocalSessions(installs, cwd) {
6383
9255
  const inCwd = sub === cwdEncoded;
6384
9256
  let files = [];
6385
9257
  try {
6386
- files = readdirSync4(subdirPath);
9258
+ files = readdirSync7(subdirPath);
6387
9259
  } catch {
6388
9260
  continue;
6389
9261
  }
6390
9262
  for (const f of files) {
6391
9263
  if (!f.endsWith(".jsonl"))
6392
9264
  continue;
6393
- const fullPath = join28(subdirPath, f);
9265
+ const fullPath = join42(subdirPath, f);
6394
9266
  let stats;
6395
9267
  try {
6396
- stats = statSync5(fullPath);
9268
+ stats = statSync7(fullPath);
6397
9269
  } catch {
6398
9270
  continue;
6399
9271
  }
@@ -6451,7 +9323,7 @@ function pickSessions(candidates, opts) {
6451
9323
  function nativeJsonlToRows(filePath, sessionId, agent) {
6452
9324
  let raw;
6453
9325
  try {
6454
- raw = readFileSync19(filePath, "utf-8");
9326
+ raw = readFileSync29(filePath, "utf-8");
6455
9327
  } catch {
6456
9328
  return [];
6457
9329
  }
@@ -6541,22 +9413,22 @@ function extractPairs(rows) {
6541
9413
  }
6542
9414
 
6543
9415
  // dist/src/skillify/gate-runner.js
6544
- import { existsSync as existsSync23 } from "node:fs";
9416
+ import { existsSync as existsSync33 } from "node:fs";
6545
9417
  import { createRequire } from "node:module";
6546
- import { homedir as homedir16 } from "node:os";
6547
- import { join as join29 } from "node:path";
9418
+ import { homedir as homedir21 } from "node:os";
9419
+ import { join as join43 } from "node:path";
6548
9420
  var requireForCp = createRequire(import.meta.url);
6549
9421
  var { execFileSync: runChildProcess } = requireForCp("node:child_process");
6550
9422
  var inheritedEnv = process;
6551
9423
  function firstExistingPath(candidates) {
6552
9424
  for (const c of candidates) {
6553
- if (existsSync23(c))
9425
+ if (existsSync33(c))
6554
9426
  return c;
6555
9427
  }
6556
9428
  return null;
6557
9429
  }
6558
9430
  function findAgentBin(agent) {
6559
- const home = homedir16();
9431
+ const home = homedir21();
6560
9432
  switch (agent) {
6561
9433
  // /usr/bin/<name> is included in every candidate list — that's the
6562
9434
  // common Linux package-manager install path (apt, dnf, pacman). Old
@@ -6565,45 +9437,45 @@ function findAgentBin(agent) {
6565
9437
  // #170 caught the gap.
6566
9438
  case "claude_code":
6567
9439
  return firstExistingPath([
6568
- join29(home, ".claude", "local", "claude"),
9440
+ join43(home, ".claude", "local", "claude"),
6569
9441
  "/usr/local/bin/claude",
6570
9442
  "/usr/bin/claude",
6571
- join29(home, ".npm-global", "bin", "claude"),
6572
- join29(home, ".local", "bin", "claude"),
9443
+ join43(home, ".npm-global", "bin", "claude"),
9444
+ join43(home, ".local", "bin", "claude"),
6573
9445
  "/opt/homebrew/bin/claude"
6574
- ]) ?? join29(home, ".claude", "local", "claude");
9446
+ ]) ?? join43(home, ".claude", "local", "claude");
6575
9447
  case "codex":
6576
9448
  return firstExistingPath([
6577
9449
  "/usr/local/bin/codex",
6578
9450
  "/usr/bin/codex",
6579
- join29(home, ".npm-global", "bin", "codex"),
6580
- join29(home, ".local", "bin", "codex"),
9451
+ join43(home, ".npm-global", "bin", "codex"),
9452
+ join43(home, ".local", "bin", "codex"),
6581
9453
  "/opt/homebrew/bin/codex"
6582
9454
  ]) ?? "/usr/local/bin/codex";
6583
9455
  case "cursor":
6584
9456
  return firstExistingPath([
6585
9457
  "/usr/local/bin/cursor-agent",
6586
9458
  "/usr/bin/cursor-agent",
6587
- join29(home, ".npm-global", "bin", "cursor-agent"),
6588
- join29(home, ".local", "bin", "cursor-agent"),
9459
+ join43(home, ".npm-global", "bin", "cursor-agent"),
9460
+ join43(home, ".local", "bin", "cursor-agent"),
6589
9461
  "/opt/homebrew/bin/cursor-agent"
6590
9462
  ]) ?? "/usr/local/bin/cursor-agent";
6591
9463
  case "hermes":
6592
9464
  return firstExistingPath([
6593
- join29(home, ".local", "bin", "hermes"),
9465
+ join43(home, ".local", "bin", "hermes"),
6594
9466
  "/usr/local/bin/hermes",
6595
9467
  "/usr/bin/hermes",
6596
- join29(home, ".npm-global", "bin", "hermes"),
9468
+ join43(home, ".npm-global", "bin", "hermes"),
6597
9469
  "/opt/homebrew/bin/hermes"
6598
- ]) ?? join29(home, ".local", "bin", "hermes");
9470
+ ]) ?? join43(home, ".local", "bin", "hermes");
6599
9471
  case "pi":
6600
9472
  return firstExistingPath([
6601
- join29(home, ".local", "bin", "pi"),
9473
+ join43(home, ".local", "bin", "pi"),
6602
9474
  "/usr/local/bin/pi",
6603
9475
  "/usr/bin/pi",
6604
- join29(home, ".npm-global", "bin", "pi"),
9476
+ join43(home, ".npm-global", "bin", "pi"),
6605
9477
  "/opt/homebrew/bin/pi"
6606
- ]) ?? join29(home, ".local", "bin", "pi");
9478
+ ]) ?? join43(home, ".local", "bin", "pi");
6607
9479
  }
6608
9480
  }
6609
9481
 
@@ -6633,28 +9505,28 @@ function extractJsonBlock(s) {
6633
9505
  }
6634
9506
 
6635
9507
  // dist/src/skillify/local-manifest.js
6636
- import { existsSync as existsSync24, mkdirSync as mkdirSync11, readFileSync as readFileSync20, writeFileSync as writeFileSync15 } from "node:fs";
6637
- import { homedir as homedir17 } from "node:os";
6638
- import { dirname as dirname6, join as join30 } from "node:path";
6639
- var LOCAL_MANIFEST_PATH = join30(homedir17(), ".claude", "hivemind", "local-mined.json");
6640
- var LOCAL_MINE_LOCK_PATH = join30(homedir17(), ".claude", "hivemind", "local-mined.lock");
9508
+ import { existsSync as existsSync34, mkdirSync as mkdirSync21, readFileSync as readFileSync30, writeFileSync as writeFileSync23 } from "node:fs";
9509
+ import { homedir as homedir22 } from "node:os";
9510
+ import { dirname as dirname15, join as join44 } from "node:path";
9511
+ var LOCAL_MANIFEST_PATH = join44(homedir22(), ".claude", "hivemind", "local-mined.json");
9512
+ var LOCAL_MINE_LOCK_PATH = join44(homedir22(), ".claude", "hivemind", "local-mined.lock");
6641
9513
  function readLocalManifest(path = LOCAL_MANIFEST_PATH) {
6642
- if (!existsSync24(path))
9514
+ if (!existsSync34(path))
6643
9515
  return null;
6644
9516
  try {
6645
- return JSON.parse(readFileSync20(path, "utf-8"));
9517
+ return JSON.parse(readFileSync30(path, "utf-8"));
6646
9518
  } catch {
6647
9519
  return null;
6648
9520
  }
6649
9521
  }
6650
9522
  function writeLocalManifest(m, path = LOCAL_MANIFEST_PATH) {
6651
- mkdirSync11(dirname6(path), { recursive: true });
6652
- writeFileSync15(path, JSON.stringify(m, null, 2));
9523
+ mkdirSync21(dirname15(path), { recursive: true });
9524
+ writeFileSync23(path, JSON.stringify(m, null, 2));
6653
9525
  }
6654
9526
  var LATEST_RUN_WINDOW_MS = 5 * 60 * 1e3;
6655
9527
 
6656
9528
  // dist/src/commands/mine-local.js
6657
- import { unlinkSync as unlinkSync10 } from "node:fs";
9529
+ import { unlinkSync as unlinkSync12 } from "node:fs";
6658
9530
  var EPSILON = 0.3;
6659
9531
  var DEFAULT_N = 8;
6660
9532
  var PAIR_CHAR_CAP = 4e3;
@@ -6665,9 +9537,9 @@ var IN_FLIGHT_MAX_AGE_MS = 6e4;
6665
9537
  var GATE_TIMEOUT_MS = 24e4;
6666
9538
  var MANIFEST_PATH = LOCAL_MANIFEST_PATH;
6667
9539
  function runGateViaStdin(opts) {
6668
- return new Promise((resolve2) => {
9540
+ return new Promise((resolve6) => {
6669
9541
  if (opts.agent !== "claude_code") {
6670
- resolve2({
9542
+ resolve6({
6671
9543
  stdout: "",
6672
9544
  stderr: "",
6673
9545
  errored: true,
@@ -6675,8 +9547,8 @@ function runGateViaStdin(opts) {
6675
9547
  });
6676
9548
  return;
6677
9549
  }
6678
- if (!existsSync25(opts.bin)) {
6679
- resolve2({
9550
+ if (!existsSync35(opts.bin)) {
9551
+ resolve6({
6680
9552
  stdout: "",
6681
9553
  stderr: "",
6682
9554
  errored: true,
@@ -6692,7 +9564,7 @@ function runGateViaStdin(opts) {
6692
9564
  "--permission-mode",
6693
9565
  "bypassPermissions"
6694
9566
  ];
6695
- const child = spawn(opts.bin, args, {
9567
+ const child = spawn2(opts.bin, args, {
6696
9568
  stdio: ["pipe", "pipe", "pipe"],
6697
9569
  env: { ...process.env, HIVEMIND_WIKI_WORKER: "1", HIVEMIND_CAPTURE: "false" }
6698
9570
  });
@@ -6703,7 +9575,7 @@ function runGateViaStdin(opts) {
6703
9575
  if (settled)
6704
9576
  return;
6705
9577
  settled = true;
6706
- resolve2(r);
9578
+ resolve6(r);
6707
9579
  };
6708
9580
  const timer = setTimeout(() => {
6709
9581
  try {
@@ -6982,7 +9854,7 @@ async function runMineLocal(args) {
6982
9854
  return;
6983
9855
  lockReleased = true;
6984
9856
  try {
6985
- unlinkSync10(LOCAL_MINE_LOCK_PATH);
9857
+ unlinkSync12(LOCAL_MINE_LOCK_PATH);
6986
9858
  } catch {
6987
9859
  }
6988
9860
  };
@@ -7039,8 +9911,8 @@ async function runMineLocalImpl(args) {
7039
9911
  console.log(`Dry-run: would invoke ${gateAgent} gate on ${picked.length} session(s) in parallel (concurrency=${GATE_CONCURRENCY}).`);
7040
9912
  return;
7041
9913
  }
7042
- const tmpDir = join31(homedir18(), ".claude", "hivemind", `mine-local-${Date.now()}`);
7043
- mkdirSync12(tmpDir, { recursive: true });
9914
+ const tmpDir = join45(homedir23(), ".claude", "hivemind", `mine-local-${Date.now()}`);
9915
+ mkdirSync22(tmpDir, { recursive: true });
7044
9916
  console.log(`Running ${picked.length} gate call(s) in parallel (concurrency=${GATE_CONCURRENCY}, timeout=${GATE_TIMEOUT_MS / 1e3}s each)...`);
7045
9917
  const results = await parallelMap(picked, GATE_CONCURRENCY, async (s) => {
7046
9918
  const shortId = s.sessionId.slice(0, 8);
@@ -7051,23 +9923,23 @@ async function runMineLocalImpl(args) {
7051
9923
  return { session: s, skills: [], reason: "no pairs", error: null };
7052
9924
  }
7053
9925
  const tail = pairs2.slice(-PER_SESSION_PAIR_CAP);
7054
- const sessionTmp = join31(tmpDir, `s-${shortId}`);
7055
- mkdirSync12(sessionTmp, { recursive: true });
7056
- const verdictPath = join31(sessionTmp, "verdict.json");
9926
+ const sessionTmp = join45(tmpDir, `s-${shortId}`);
9927
+ mkdirSync22(sessionTmp, { recursive: true });
9928
+ const verdictPath = join45(sessionTmp, "verdict.json");
7057
9929
  const prompt = buildSessionPrompt(tail, s, verdictPath);
7058
- writeFileSync16(join31(sessionTmp, "prompt.txt"), prompt);
9930
+ writeFileSync24(join45(sessionTmp, "prompt.txt"), prompt);
7059
9931
  const gate = await runGateViaStdin({ agent: gateAgent, bin: gateBin, prompt, timeoutMs: GATE_TIMEOUT_MS });
7060
9932
  try {
7061
- writeFileSync16(join31(sessionTmp, "gate-stdout.txt"), gate.stdout);
9933
+ writeFileSync24(join45(sessionTmp, "gate-stdout.txt"), gate.stdout);
7062
9934
  if (gate.stderr)
7063
- writeFileSync16(join31(sessionTmp, "gate-stderr.txt"), gate.stderr);
9935
+ writeFileSync24(join45(sessionTmp, "gate-stderr.txt"), gate.stderr);
7064
9936
  } catch {
7065
9937
  }
7066
9938
  if (gate.errored) {
7067
9939
  console.log(` [${shortId}] gate failed: ${gate.errorMessage}`);
7068
9940
  return { session: s, skills: [], reason: null, error: gate.errorMessage ?? "gate failed" };
7069
9941
  }
7070
- const verdictText = existsSync25(verdictPath) ? readFileSync21(verdictPath, "utf-8") : gate.stdout;
9942
+ const verdictText = existsSync35(verdictPath) ? readFileSync31(verdictPath, "utf-8") : gate.stdout;
7071
9943
  const mv = parseMultiVerdict(verdictText);
7072
9944
  if (!mv) {
7073
9945
  console.log(` [${shortId}] unparseable verdict (kept at ${sessionTmp})`);
@@ -7119,8 +9991,8 @@ async function runMineLocalImpl(args) {
7119
9991
  sourceSessions: [session.sessionId],
7120
9992
  agent: gateAgent
7121
9993
  });
7122
- const canonicalDir = dirname7(result.path);
7123
- const symlinks = fanOutRoots.length > 0 ? fanOutSymlinks(canonicalDir, basename(canonicalDir), fanOutRoots) : [];
9994
+ const canonicalDir = dirname16(result.path);
9995
+ const symlinks = fanOutRoots.length > 0 ? fanOutSymlinks(canonicalDir, basename2(canonicalDir), fanOutRoots) : [];
7124
9996
  const symlinkSuffix = symlinks.length > 0 ? `, fan-out \u2192 ${symlinks.length} root(s)` : "";
7125
9997
  console.log(` wrote ${skill.name} \u2190 session ${session.sessionId.slice(0, 8)} (${session.agent}${symlinkSuffix})`);
7126
9998
  written.push({ skill, session, result, symlinks });
@@ -7296,11 +10168,11 @@ function showStatus() {
7296
10168
  console.log(`team: ${cfg.team.length === 0 ? "(empty)" : cfg.team.join(", ")}`);
7297
10169
  console.log(`install: ${cfg.install} (${cfg.install === "global" ? "~/.claude/skills/" : "<project>/.claude/skills/"})`);
7298
10170
  const dir = stateDir();
7299
- if (!existsSync26(dir)) {
10171
+ if (!existsSync36(dir)) {
7300
10172
  console.log(`state: (no projects tracked yet)`);
7301
10173
  return;
7302
10174
  }
7303
- const files = readdirSync5(dir).filter((f) => f.endsWith(".json") && f !== "config.json" && f !== "pulled.json" && f !== "autopull-last-run.json");
10175
+ const files = readdirSync8(dir).filter((f) => f.endsWith(".json") && f !== "config.json" && f !== "pulled.json" && f !== "autopull-last-run.json");
7304
10176
  if (files.length === 0) {
7305
10177
  console.log(`state: (no projects tracked yet)`);
7306
10178
  return;
@@ -7308,7 +10180,7 @@ function showStatus() {
7308
10180
  console.log(`state: ${files.length} project(s) tracked`);
7309
10181
  for (const f of files) {
7310
10182
  try {
7311
- const s = JSON.parse(readFileSync22(join32(dir, f), "utf-8"));
10183
+ const s = JSON.parse(readFileSync32(join46(dir, f), "utf-8"));
7312
10184
  const last = typeof s.updatedAt === "number" ? new Date(s.updatedAt).toISOString() : s.lastDate ?? "never";
7313
10185
  const skills = Array.isArray(s.skillsGenerated) && s.skillsGenerated.length > 0 ? s.skillsGenerated.join(", ") : "none";
7314
10186
  console.log(` - ${s.project} (counter=${s.counter}, last=${last}, skills=${skills})`);
@@ -7335,7 +10207,7 @@ function setInstall(loc) {
7335
10207
  }
7336
10208
  const cfg = loadScopeConfig();
7337
10209
  saveScopeConfig({ ...cfg, install: loc });
7338
- const path = loc === "global" ? join32(homedir19(), ".claude", "skills") : "<cwd>/.claude/skills";
10210
+ const path = loc === "global" ? join46(homedir24(), ".claude", "skills") : "<cwd>/.claude/skills";
7339
10211
  console.log(`Install location set to '${loc}'. New skills will be written to ${path}/<name>/SKILL.md.`);
7340
10212
  }
7341
10213
  function promoteSkill(name, cwd) {
@@ -7343,18 +10215,18 @@ function promoteSkill(name, cwd) {
7343
10215
  console.error("Usage: hivemind skillify promote <skill-name>");
7344
10216
  process.exit(1);
7345
10217
  }
7346
- const projectPath = join32(cwd, ".claude", "skills", name);
7347
- const globalPath = join32(homedir19(), ".claude", "skills", name);
7348
- if (!existsSync26(join32(projectPath, "SKILL.md"))) {
10218
+ const projectPath = join46(cwd, ".claude", "skills", name);
10219
+ const globalPath = join46(homedir24(), ".claude", "skills", name);
10220
+ if (!existsSync36(join46(projectPath, "SKILL.md"))) {
7349
10221
  console.error(`Skill '${name}' not found at ${projectPath}/SKILL.md`);
7350
10222
  process.exit(1);
7351
10223
  }
7352
- if (existsSync26(join32(globalPath, "SKILL.md"))) {
10224
+ if (existsSync36(join46(globalPath, "SKILL.md"))) {
7353
10225
  console.error(`Skill '${name}' already exists at ${globalPath}/SKILL.md \u2014 refusing to overwrite. Remove it first or rename the project skill.`);
7354
10226
  process.exit(1);
7355
10227
  }
7356
- mkdirSync13(dirname8(globalPath), { recursive: true });
7357
- renameSync7(projectPath, globalPath);
10228
+ mkdirSync23(dirname17(globalPath), { recursive: true });
10229
+ renameSync12(projectPath, globalPath);
7358
10230
  console.log(`Promoted '${name}' from ${projectPath} \u2192 ${globalPath}.`);
7359
10231
  }
7360
10232
  function teamAdd(name) {
@@ -7460,7 +10332,7 @@ async function pullSkills(args) {
7460
10332
  console.error(`pull failed: ${e?.message ?? e}`);
7461
10333
  process.exit(1);
7462
10334
  }
7463
- const dest = toRaw === "global" ? join32(homedir19(), ".claude", "skills") : `${process.cwd()}/.claude/skills`;
10335
+ const dest = toRaw === "global" ? join46(homedir24(), ".claude", "skills") : `${process.cwd()}/.claude/skills`;
7464
10336
  const filterDesc = users.length === 0 ? "all users" : users.join(", ");
7465
10337
  console.log(`Destination: ${dest}`);
7466
10338
  console.log(`Filter: ${filterDesc}${skillName ? ` \xB7 skill='${skillName}'` : ""}${dryRun ? " \xB7 dry-run" : ""}${force ? " \xB7 force" : ""}`);
@@ -7510,7 +10382,7 @@ async function unpullSkills(args) {
7510
10382
  all,
7511
10383
  legacyCleanup
7512
10384
  });
7513
- const dest = toRaw === "global" ? join32(homedir19(), ".claude", "skills") : `${process.cwd()}/.claude/skills`;
10385
+ const dest = toRaw === "global" ? join46(homedir24(), ".claude", "skills") : `${process.cwd()}/.claude/skills`;
7514
10386
  const filterParts = [];
7515
10387
  if (users.length > 0)
7516
10388
  filterParts.push(`users=${users.join(",")}`);
@@ -7605,15 +10477,15 @@ if (process.argv[1] && process.argv[1].endsWith("skillify.js")) {
7605
10477
  }
7606
10478
 
7607
10479
  // dist/src/cli/update.js
7608
- import { execFileSync as execFileSync4 } from "node:child_process";
7609
- import { closeSync as closeSync2, existsSync as existsSync27, mkdirSync as mkdirSync14, openSync as openSync2, readFileSync as readFileSync24, realpathSync, unlinkSync as unlinkSync11, writeSync } from "node:fs";
7610
- import { homedir as homedir20 } from "node:os";
7611
- import { dirname as dirname10, join as join34, sep } from "node:path";
10480
+ import { execFileSync as execFileSync6 } from "node:child_process";
10481
+ import { closeSync as closeSync3, existsSync as existsSync37, mkdirSync as mkdirSync24, openSync as openSync3, readFileSync as readFileSync34, realpathSync, unlinkSync as unlinkSync13, writeSync as writeSync2 } from "node:fs";
10482
+ import { homedir as homedir25 } from "node:os";
10483
+ import { dirname as dirname19, join as join48, sep as sep2 } from "node:path";
7612
10484
  import { fileURLToPath as fileURLToPath2 } from "node:url";
7613
10485
 
7614
10486
  // dist/src/utils/version-check.js
7615
- import { readFileSync as readFileSync23 } from "node:fs";
7616
- import { dirname as dirname9, join as join33 } from "node:path";
10487
+ import { readFileSync as readFileSync33 } from "node:fs";
10488
+ import { dirname as dirname18, join as join47 } from "node:path";
7617
10489
  function isNewer(latest, current) {
7618
10490
  const parse = (v) => v.split(".").map(Number);
7619
10491
  const [la, lb, lc] = parse(latest);
@@ -7625,7 +10497,7 @@ function isNewer(latest, current) {
7625
10497
  var NPM_REGISTRY_URL = "https://registry.npmjs.org/@deeplake/hivemind/latest";
7626
10498
  var PKG_NAME = "@deeplake/hivemind";
7627
10499
  function defaultLockPath() {
7628
- return join34(homedir20(), ".deeplake", "hivemind-update.lock");
10500
+ return join48(homedir25(), ".deeplake", "hivemind-update.lock");
7629
10501
  }
7630
10502
  function detectInstallKind(argv1) {
7631
10503
  const realArgv1 = (() => {
@@ -7635,36 +10507,36 @@ function detectInstallKind(argv1) {
7635
10507
  return argv1 ?? process.argv[1] ?? fileURLToPath2(import.meta.url);
7636
10508
  }
7637
10509
  })();
7638
- let dir = dirname10(realArgv1);
10510
+ let dir = dirname19(realArgv1);
7639
10511
  let installDir = null;
7640
10512
  for (let i = 0; i < 10; i++) {
7641
- const pkgPath = `${dir}${sep}package.json`;
10513
+ const pkgPath = `${dir}${sep2}package.json`;
7642
10514
  try {
7643
- const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
10515
+ const pkg = JSON.parse(readFileSync34(pkgPath, "utf-8"));
7644
10516
  if (pkg.name === PKG_NAME || pkg.name === "hivemind") {
7645
10517
  installDir = dir;
7646
10518
  break;
7647
10519
  }
7648
10520
  } catch {
7649
10521
  }
7650
- const parent = dirname10(dir);
10522
+ const parent = dirname19(dir);
7651
10523
  if (parent === dir)
7652
10524
  break;
7653
10525
  dir = parent;
7654
10526
  }
7655
- installDir ??= dirname10(realArgv1);
7656
- if (realArgv1.includes(`${sep}_npx${sep}`) || realArgv1.includes(`${sep}.npx${sep}`)) {
10527
+ installDir ??= dirname19(realArgv1);
10528
+ if (realArgv1.includes(`${sep2}_npx${sep2}`) || realArgv1.includes(`${sep2}.npx${sep2}`)) {
7657
10529
  return { kind: "npx", installDir };
7658
10530
  }
7659
- if (realArgv1.includes(`${sep}node_modules${sep}@deeplake${sep}hivemind`) || realArgv1.includes(`${sep}node_modules${sep}hivemind`)) {
10531
+ if (realArgv1.includes(`${sep2}node_modules${sep2}@deeplake${sep2}hivemind`) || realArgv1.includes(`${sep2}node_modules${sep2}hivemind`)) {
7660
10532
  return { kind: "npm-global", installDir };
7661
10533
  }
7662
10534
  let gitDir = installDir;
7663
10535
  for (let i = 0; i < 6; i++) {
7664
- if (existsSync27(`${gitDir}${sep}.git`)) {
10536
+ if (existsSync37(`${gitDir}${sep2}.git`)) {
7665
10537
  return { kind: "local-dev", installDir };
7666
10538
  }
7667
- const parent = dirname10(gitDir);
10539
+ const parent = dirname19(gitDir);
7668
10540
  if (parent === gitDir)
7669
10541
  break;
7670
10542
  gitDir = parent;
@@ -7683,13 +10555,13 @@ async function getLatestNpmVersion(timeoutMs = 5e3) {
7683
10555
  }
7684
10556
  }
7685
10557
  var defaultSpawn = (cmd, args) => {
7686
- execFileSync4(cmd, args, { stdio: "inherit" });
10558
+ execFileSync6(cmd, args, { stdio: "inherit" });
7687
10559
  };
7688
10560
  function tryAcquireLock(path) {
7689
- mkdirSync14(dirname10(path), { recursive: true, mode: 448 });
10561
+ mkdirSync24(dirname19(path), { recursive: true, mode: 448 });
7690
10562
  const claim = () => {
7691
- const fd = openSync2(path, "wx", 384);
7692
- writeSync(fd, String(process.pid));
10563
+ const fd = openSync3(path, "wx", 384);
10564
+ writeSync2(fd, String(process.pid));
7693
10565
  return fd;
7694
10566
  };
7695
10567
  try {
@@ -7700,7 +10572,7 @@ function tryAcquireLock(path) {
7700
10572
  }
7701
10573
  let holderPid = 0;
7702
10574
  try {
7703
- holderPid = Number(readFileSync24(path, "utf-8").trim()) || 0;
10575
+ holderPid = Number(readFileSync34(path, "utf-8").trim()) || 0;
7704
10576
  } catch {
7705
10577
  try {
7706
10578
  return claim();
@@ -7717,7 +10589,7 @@ function tryAcquireLock(path) {
7717
10589
  }
7718
10590
  }
7719
10591
  try {
7720
- unlinkSync11(path);
10592
+ unlinkSync13(path);
7721
10593
  } catch {
7722
10594
  }
7723
10595
  try {
@@ -7729,11 +10601,11 @@ function tryAcquireLock(path) {
7729
10601
  }
7730
10602
  function releaseLock(fd, path) {
7731
10603
  try {
7732
- closeSync2(fd);
10604
+ closeSync3(fd);
7733
10605
  } catch {
7734
10606
  }
7735
10607
  try {
7736
- unlinkSync11(path);
10608
+ unlinkSync13(path);
7737
10609
  } catch {
7738
10610
  }
7739
10611
  }
@@ -7751,7 +10623,7 @@ async function runUpdate(opts = {}) {
7751
10623
  }
7752
10624
  log(`Update available: ${current} \u2192 ${latest}`);
7753
10625
  const detected = opts.installKindOverride ?? detectInstallKind();
7754
- const spawn2 = opts.spawn ?? defaultSpawn;
10626
+ const spawn3 = opts.spawn ?? defaultSpawn;
7755
10627
  switch (detected.kind) {
7756
10628
  case "npm-global": {
7757
10629
  if (opts.dryRun) {
@@ -7766,7 +10638,7 @@ async function runUpdate(opts = {}) {
7766
10638
  try {
7767
10639
  log(`Upgrading via npm\u2026`);
7768
10640
  try {
7769
- spawn2("npm", ["install", "-g", `${PKG_NAME}@latest`]);
10641
+ spawn3("npm", ["install", "-g", `${PKG_NAME}@latest`]);
7770
10642
  } catch (e) {
7771
10643
  warn(`npm install failed: ${e.message}`);
7772
10644
  warn(`Try running it manually: npm install -g ${PKG_NAME}@latest`);
@@ -7775,7 +10647,7 @@ async function runUpdate(opts = {}) {
7775
10647
  log(``);
7776
10648
  log(`Refreshing agent bundles\u2026`);
7777
10649
  try {
7778
- spawn2("hivemind", ["install", "--skip-auth"]);
10650
+ spawn3("hivemind", ["install", "--skip-auth"]);
7779
10651
  } catch (e) {
7780
10652
  warn(`Agent refresh failed: ${e.message}`);
7781
10653
  warn(`Run manually: hivemind install`);
@@ -7839,7 +10711,7 @@ var AUTH_SUBCOMMANDS = /* @__PURE__ */ new Set([
7839
10711
  "autoupdate",
7840
10712
  "sessions"
7841
10713
  ]);
7842
- var USAGE = `
10714
+ var USAGE3 = `
7843
10715
  hivemind \u2014 one brain for every agent on your team
7844
10716
 
7845
10717
  Usage:
@@ -7869,6 +10741,18 @@ Usage:
7869
10741
  Check npm for a newer @deeplake/hivemind, upgrade the CLI, and refresh
7870
10742
  every detected agent bundle. Single command for all agents.
7871
10743
 
10744
+ hivemind dashboard [--cwd <path>] [--out <path>] [--no-open]
10745
+ [--serve] [--port <n>]
10746
+ Build a self-contained HTML dashboard for this repo. Combines
10747
+ KPI cards (tokens saved, skills created, memory recalls,
10748
+ sessions) with the codebase-graph visualization. Writes to
10749
+ ~/.hivemind/dashboards/<repo-key>/index.html by default.
10750
+ --no-open skips the browser launch (headless / CI scenarios).
10751
+ --serve starts a loopback HTTP server at http://127.0.0.1:<port>
10752
+ (default 8123) so the dashboard is reachable via a URL \u2014 useful
10753
+ over SSH; VS Code / Cursor Remote-SSH auto-forwards the port
10754
+ and opens it in the integrated Simple Browser tab on click.
10755
+
7872
10756
  Semantic search (embeddings):
7873
10757
  hivemind embeddings install Download @huggingface/transformers
7874
10758
  once (~600 MB) into a shared dir,
@@ -7897,6 +10781,22 @@ Semantic search (embeddings):
7897
10781
  Add --with-embeddings to "hivemind install" (or "hivemind <agent> install")
7898
10782
  to run "embeddings install" automatically after installing the agent(s).
7899
10783
 
10784
+ Codebase graph (per-repo AST snapshot + cloud sync):
10785
+ hivemind graph build [--cwd <path>] Walk TypeScript sources, extract
10786
+ AST nodes + edges, write a
10787
+ snapshot, and push to cloud.
10788
+ hivemind graph diff <sha1> <sha2> Diff two snapshots by commit.
10789
+ hivemind graph history [-n N] [--json] Show last N build entries.
10790
+ hivemind graph init [--force] Install a managed
10791
+ .git/hooks/post-commit hook
10792
+ that rebuilds on each commit.
10793
+ hivemind graph pull Download the freshest cloud
10794
+ snapshot for HEAD into local.
10795
+ hivemind graph uninstall Remove the managed post-commit
10796
+ hook.
10797
+ Agents query the local snapshot via the Deeplake mount at
10798
+ ~/.deeplake/memory/graph/{index.md,find/<pattern>,show/<handle-or-pattern>}.
10799
+
7900
10800
  Skill management (mine + share reusable Claude skills across the org):
7901
10801
  ${renderCliHelpBlock()}
7902
10802
 
@@ -8087,7 +10987,7 @@ async function main() {
8087
10987
  const args = process.argv.slice(2);
8088
10988
  const cmd = args[0];
8089
10989
  if (!cmd || cmd === "--help" || cmd === "-h" || cmd === "help") {
8090
- log(USAGE);
10990
+ log(USAGE3);
8091
10991
  return;
8092
10992
  }
8093
10993
  if (cmd === "--version" || cmd === "-v" || cmd === "version") {
@@ -8121,6 +11021,14 @@ async function main() {
8121
11021
  runSkillifyCommand(args.slice(1));
8122
11022
  return;
8123
11023
  }
11024
+ if (cmd === "graph") {
11025
+ await runGraphCommand(args.slice(1));
11026
+ return;
11027
+ }
11028
+ if (cmd === "dashboard") {
11029
+ const code = await runDashboardCommand(args.slice(1));
11030
+ process.exit(code);
11031
+ }
8124
11032
  if (cmd === "embeddings") {
8125
11033
  const sub = args[1];
8126
11034
  if (sub === "install") {
@@ -8168,7 +11076,7 @@ async function main() {
8168
11076
  return;
8169
11077
  }
8170
11078
  warn(`Unknown command: ${cmd}`);
8171
- log(USAGE);
11079
+ log(USAGE3);
8172
11080
  process.exit(1);
8173
11081
  }
8174
11082
  main().catch((err) => {