@deeplake/hivemind 0.7.45 → 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 +2215 -341
  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((resolve3) => {
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
- resolve3(defaultYes);
152
+ resolve6(defaultYes);
153
153
  else
154
- resolve3(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((resolve3) => {
160
+ return new Promise((resolve6) => {
161
161
  rl.question(message, (answer) => {
162
162
  rl.close();
163
- resolve3(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((resolve3) => setTimeout(resolve3, 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((resolve3) => this.waiting.push(resolve3));
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();
@@ -5347,96 +5390,1950 @@ async function runAuthCommand(args) {
5347
5390
  console.log(`Invited ${email} with ${mode} access`);
5348
5391
  break;
5349
5392
  }
5350
- case "members": {
5351
- if (!creds) {
5352
- console.log("Not logged in.");
5353
- process.exit(1);
5354
- }
5355
- const members = await listMembers(creds.token, creds.orgId, apiUrl);
5356
- members.forEach((m) => console.log(`${m.role.padEnd(8)} ${m.email ?? m.name}`));
5393
+ case "members": {
5394
+ if (!creds) {
5395
+ console.log("Not logged in.");
5396
+ process.exit(1);
5397
+ }
5398
+ const members = await listMembers(creds.token, creds.orgId, apiUrl);
5399
+ members.forEach((m) => console.log(`${m.role.padEnd(8)} ${m.email ?? m.name}`));
5400
+ break;
5401
+ }
5402
+ case "remove": {
5403
+ if (!creds) {
5404
+ console.log("Not logged in.");
5405
+ process.exit(1);
5406
+ }
5407
+ const userId = args[1];
5408
+ if (!userId) {
5409
+ console.log("Usage: remove <user-id>");
5410
+ process.exit(1);
5411
+ }
5412
+ await removeMember(userId, creds.token, creds.orgId, apiUrl);
5413
+ console.log(`Removed user ${userId}`);
5414
+ break;
5415
+ }
5416
+ case "sessions": {
5417
+ const sub = args[1];
5418
+ if (sub === "prune") {
5419
+ await sessionPrune(args.slice(2));
5420
+ } else {
5421
+ console.log("Usage: sessions prune [--all | --before <date> | --session-id <id>] [--yes]");
5422
+ }
5423
+ break;
5424
+ }
5425
+ case "autoupdate": {
5426
+ if (!creds) {
5427
+ console.log("Not logged in.");
5428
+ process.exit(1);
5429
+ }
5430
+ const val = args[1]?.toLowerCase();
5431
+ if (val === "on" || val === "true") {
5432
+ saveCredentials({ ...creds, autoupdate: true });
5433
+ console.log("Autoupdate enabled. Plugin will update automatically on session start.");
5434
+ } else if (val === "off" || val === "false") {
5435
+ saveCredentials({ ...creds, autoupdate: false });
5436
+ console.log("Autoupdate disabled. You'll see a notice when updates are available.");
5437
+ } else {
5438
+ const current = creds.autoupdate !== false ? "on" : "off";
5439
+ console.log(`Autoupdate is currently: ${current}`);
5440
+ console.log("Usage: autoupdate [on|off]");
5441
+ }
5442
+ break;
5443
+ }
5444
+ case "logout": {
5445
+ if (deleteCredentials()) {
5446
+ console.log("Logged out. Credentials removed.");
5447
+ } else {
5448
+ console.log("Not logged in.");
5449
+ }
5450
+ break;
5451
+ }
5452
+ default:
5453
+ console.log("Commands: login, logout, whoami, org list, org switch, workspaces, workspace, sessions prune, invite, members, remove, autoupdate");
5454
+ }
5455
+ }
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}`);
5357
6897
  break;
5358
- }
5359
- case "remove": {
5360
- if (!creds) {
5361
- console.log("Not logged in.");
5362
- process.exit(1);
5363
- }
5364
- const userId = args[1];
5365
- if (!userId) {
5366
- console.log("Usage: remove <user-id>");
5367
- process.exit(1);
5368
- }
5369
- await removeMember(userId, creds.token, creds.orgId, apiUrl);
5370
- console.log(`Removed user ${userId}`);
6898
+ case "already-ours":
6899
+ console.log(`Post-commit hook already managed by hivemind (no change): ${status.path}`);
5371
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);
5372
6928
  }
5373
- case "sessions": {
5374
- const sub = args[1];
5375
- if (sub === "prune") {
5376
- await sessionPrune(args.slice(2));
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}`);
5377
6939
  } else {
5378
- console.log("Usage: sessions prune [--all | --before <date> | --session-id <id>] [--yes]");
6940
+ console.log(`Removed managed block from post-commit hook (other content preserved): ${status.path}`);
5379
6941
  }
6942
+ console.log("Local snapshots + history.jsonl are untouched.");
5380
6943
  break;
5381
- }
5382
- case "autoupdate": {
5383
- if (!creds) {
5384
- console.log("Not logged in.");
5385
- process.exit(1);
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);
5386
6966
  }
5387
- const val = args[1]?.toLowerCase();
5388
- if (val === "on" || val === "true") {
5389
- saveCredentials({ ...creds, autoupdate: true });
5390
- console.log("Autoupdate enabled. Plugin will update automatically on session start.");
5391
- } else if (val === "off" || val === "false") {
5392
- saveCredentials({ ...creds, autoupdate: false });
5393
- console.log("Autoupdate disabled. You'll see a notice when updates are available.");
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;
5394
7081
  } else {
5395
- const current = creds.autoupdate !== false ? "on" : "off";
5396
- console.log(`Autoupdate is currently: ${current}`);
5397
- console.log("Usage: autoupdate [on|off]");
7082
+ console.error(`hivemind graph build: --trigger must be one of manual|session-end|post-commit|unknown (got '${v}')`);
7083
+ process.exit(2);
5398
7084
  }
5399
- break;
5400
- }
5401
- case "logout": {
5402
- if (deleteCredentials()) {
5403
- console.log("Logged out. Credentials removed.");
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);
5404
7126
  } else {
5405
- console.log("Not logged in.");
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
+ }
5406
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).`);
5407
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);
5408
7282
  }
5409
- default:
5410
- console.log("Commands: login, logout, whoami, org list, org switch, workspaces, workspace, sessions prune, invite, members, remove, autoupdate");
5411
7283
  }
5412
7284
  }
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
- });
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
+ }
5418
7315
  }
5419
7316
 
5420
7317
  // dist/src/commands/dashboard.js
5421
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync13 } from "node:fs";
5422
- import { homedir as homedir14 } from "node:os";
5423
- import { dirname as dirname6, join as join27, resolve as resolve2 } from "node:path";
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";
5424
7321
 
5425
7322
  // dist/src/dashboard/data.js
5426
- import { existsSync as existsSync19, readFileSync as readFileSync18, readdirSync as readdirSync3, statSync as statSync3 } from "node:fs";
5427
- import { homedir as homedir13 } from "node:os";
5428
- import { join as join25 } from "node:path";
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";
5429
7326
 
5430
7327
  // dist/src/notifications/sources/org-stats.js
5431
- import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
5432
- import { homedir as homedir10 } from "node:os";
5433
- import { dirname as dirname3, join as join20 } from "node:path";
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";
5434
7331
  var log5 = (msg) => log2("notifications-org-stats", msg);
5435
7332
  var FETCH_TIMEOUT_MS = 1500;
5436
7333
  var DEFAULT_API_URL3 = "https://api.deeplake.ai";
5437
7334
  var CACHE_TTL_MS = 60 * 60 * 1e3;
5438
7335
  function cacheFilePath() {
5439
- return join20(homedir10(), ".deeplake", "hivemind-stats-cache.json");
7336
+ return join28(homedir11(), ".deeplake", "hivemind-stats-cache.json");
5440
7337
  }
5441
7338
  function cacheScopeKey(creds) {
5442
7339
  return JSON.stringify({
@@ -5453,11 +7350,11 @@ function scopeFromServer(s) {
5453
7350
  memorySearchBytes: n(s?.memory_search_bytes)
5454
7351
  };
5455
7352
  }
5456
- function readCache(scopeKey) {
5457
- if (!existsSync15(cacheFilePath()))
7353
+ function readCache2(scopeKey) {
7354
+ if (!existsSync21(cacheFilePath()))
5458
7355
  return {};
5459
7356
  try {
5460
- const parsed = JSON.parse(readFileSync15(cacheFilePath(), "utf-8"));
7357
+ const parsed = JSON.parse(readFileSync21(cacheFilePath(), "utf-8"));
5461
7358
  if (!parsed || typeof parsed !== "object")
5462
7359
  return {};
5463
7360
  if (parsed.scopeKey !== scopeKey)
@@ -5476,11 +7373,11 @@ function readCache(scopeKey) {
5476
7373
  return {};
5477
7374
  }
5478
7375
  }
5479
- function writeCache(scopeKey, data) {
7376
+ function writeCache2(scopeKey, data) {
5480
7377
  try {
5481
- mkdirSync7(dirname3(cacheFilePath()), { recursive: true });
7378
+ mkdirSync13(dirname9(cacheFilePath()), { recursive: true });
5482
7379
  const body = { fetchedAt: Date.now(), scopeKey, data };
5483
- writeFileSync11(cacheFilePath(), JSON.stringify(body), "utf-8");
7380
+ writeFileSync16(cacheFilePath(), JSON.stringify(body), "utf-8");
5484
7381
  } catch (e) {
5485
7382
  log5(`cache write failed: ${e?.message ?? String(e)}`);
5486
7383
  }
@@ -5490,7 +7387,7 @@ async function fetchOrgStats(creds) {
5490
7387
  return null;
5491
7388
  const apiUrl = creds.apiUrl ?? DEFAULT_API_URL3;
5492
7389
  const scopeKey = cacheScopeKey(creds);
5493
- const { fresh, stale } = readCache(scopeKey);
7390
+ const { fresh, stale } = readCache2(scopeKey);
5494
7391
  if (fresh) {
5495
7392
  log5("cache hit \u2014 returning fresh org stats");
5496
7393
  return fresh;
@@ -5519,7 +7416,7 @@ async function fetchOrgStats(creds) {
5519
7416
  org: scopeFromServer(body.org),
5520
7417
  user: scopeFromServer(body.user)
5521
7418
  };
5522
- writeCache(scopeKey, data);
7419
+ writeCache2(scopeKey, data);
5523
7420
  log5(`fetched org stats from ${apiUrl}`);
5524
7421
  return data;
5525
7422
  } catch (e) {
@@ -5531,18 +7428,18 @@ async function fetchOrgStats(creds) {
5531
7428
  }
5532
7429
 
5533
7430
  // dist/src/notifications/usage-tracker.js
5534
- import { appendFileSync as appendFileSync2, existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync16, readdirSync as readdirSync2 } from "node:fs";
5535
- import { dirname as dirname4, join as join21 } from "node:path";
5536
- import { homedir as homedir11 } from "node:os";
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";
5537
7434
  var log6 = (msg) => log2("usage-tracker", msg);
5538
7435
  function statsFilePath() {
5539
- return join21(homedir11(), ".deeplake", "usage-stats.jsonl");
7436
+ return join29(homedir12(), ".deeplake", "usage-stats.jsonl");
5540
7437
  }
5541
7438
  function readUsageRecords() {
5542
7439
  try {
5543
- if (!existsSync16(statsFilePath()))
7440
+ if (!existsSync22(statsFilePath()))
5544
7441
  return [];
5545
- const raw = readFileSync16(statsFilePath(), "utf-8");
7442
+ const raw = readFileSync22(statsFilePath(), "utf-8");
5546
7443
  const out = [];
5547
7444
  for (const line of raw.split("\n")) {
5548
7445
  const trimmed = line.trim();
@@ -5579,13 +7476,13 @@ function sumMetric(records, key) {
5579
7476
  function countUserGeneratedSkills(userName) {
5580
7477
  if (!userName)
5581
7478
  return 0;
5582
- const dir = join21(homedir11(), ".claude", "skills");
5583
- if (!existsSync16(dir))
7479
+ const dir = join29(homedir12(), ".claude", "skills");
7480
+ if (!existsSync22(dir))
5584
7481
  return 0;
5585
7482
  const suffix = `--${userName}`;
5586
7483
  try {
5587
7484
  let count = 0;
5588
- for (const name of readdirSync2(dir)) {
7485
+ for (const name of readdirSync3(dir)) {
5589
7486
  const idx = name.lastIndexOf(suffix);
5590
7487
  if (idx > 0 && idx + suffix.length === name.length)
5591
7488
  count += 1;
@@ -5598,21 +7495,19 @@ function countUserGeneratedSkills(userName) {
5598
7495
  }
5599
7496
 
5600
7497
  // dist/src/skillify/state.js
5601
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync12, writeSync, mkdirSync as mkdirSync9, renameSync as renameSync5, rmdirSync, existsSync as existsSync18, lstatSync as lstatSync3, unlinkSync as unlinkSync8, openSync as openSync2, closeSync as closeSync2 } from "node:fs";
5602
- import { execSync as execSync2 } from "node:child_process";
5603
- import { createHash } from "node:crypto";
5604
- import { join as join24, basename } from "node:path";
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";
5605
7500
 
5606
7501
  // dist/src/skillify/legacy-migration.js
5607
- import { existsSync as existsSync17, renameSync as renameSync4 } from "node:fs";
5608
- import { dirname as dirname5, join as join23 } 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";
5609
7504
 
5610
7505
  // dist/src/skillify/state-dir.js
5611
- import { homedir as homedir12 } from "node:os";
5612
- import { join as join22 } from "node:path";
7506
+ import { homedir as homedir13 } from "node:os";
7507
+ import { join as join30 } from "node:path";
5613
7508
  function getStateDir() {
5614
7509
  const override = process.env.HIVEMIND_STATE_DIR?.trim();
5615
- return override && override.length > 0 ? override : join22(homedir12(), ".deeplake", "state", "skillify");
7510
+ return override && override.length > 0 ? override : join30(homedir13(), ".deeplake", "state", "skillify");
5616
7511
  }
5617
7512
 
5618
7513
  // dist/src/skillify/legacy-migration.js
@@ -5625,13 +7520,13 @@ function migrateLegacyStateDir() {
5625
7520
  return;
5626
7521
  attempted = true;
5627
7522
  const current = getStateDir();
5628
- const legacy = join23(dirname5(current), "skilify");
5629
- if (!existsSync17(legacy))
7523
+ const legacy = join31(dirname11(current), "skilify");
7524
+ if (!existsSync23(legacy))
5630
7525
  return;
5631
- if (existsSync17(current))
7526
+ if (existsSync23(current))
5632
7527
  return;
5633
7528
  try {
5634
- renameSync4(legacy, current);
7529
+ renameSync8(legacy, current);
5635
7530
  dlog(`migrated ${legacy} -> ${current}`);
5636
7531
  } catch (err) {
5637
7532
  const code = err.code;
@@ -5649,54 +7544,13 @@ var TRIGGER_THRESHOLD = (() => {
5649
7544
  const n = Number(process.env.HIVEMIND_SKILLIFY_EVERY_N_TURNS ?? "");
5650
7545
  return Number.isInteger(n) && n > 0 ? n : 20;
5651
7546
  })();
5652
- var DEFAULT_PORTS = {
5653
- http: "80",
5654
- https: "443",
5655
- ssh: "22",
5656
- git: "9418"
5657
- };
5658
- function normalizeGitRemoteUrl(url) {
5659
- let s = url.trim();
5660
- const schemeMatch = s.match(/^([a-z][a-z0-9+.-]*):\/\//i);
5661
- const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null;
5662
- if (schemeMatch)
5663
- s = s.slice(schemeMatch[0].length);
5664
- if (!scheme) {
5665
- const scp = s.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);
5666
- if (scp)
5667
- s = `${scp[1]}/${scp[2]}`;
5668
- }
5669
- s = s.replace(/^[^@/]+@/, "");
5670
- if (scheme && DEFAULT_PORTS[scheme]) {
5671
- s = s.replace(new RegExp(`^([^/]+):${DEFAULT_PORTS[scheme]}(/|$)`), "$1$2");
5672
- }
5673
- s = s.replace(/\.git\/?$/i, "");
5674
- s = s.replace(/\/+$/, "");
5675
- return s.toLowerCase();
5676
- }
5677
- function deriveProjectKey(cwd) {
5678
- const project = basename(cwd) || "unknown";
5679
- let signature = null;
5680
- try {
5681
- const raw = execSync2("git config --get remote.origin.url", {
5682
- cwd,
5683
- encoding: "utf-8",
5684
- stdio: ["ignore", "pipe", "ignore"]
5685
- }).trim();
5686
- signature = raw ? normalizeGitRemoteUrl(raw) : null;
5687
- } catch {
5688
- }
5689
- const input = signature ?? cwd;
5690
- const key = createHash("sha1").update(input).digest("hex").slice(0, 16);
5691
- return { key, project };
5692
- }
5693
7547
 
5694
7548
  // dist/src/dashboard/data.js
5695
7549
  var log7 = (msg) => log2("dashboard-data", msg);
5696
7550
  var BYTES_PER_TOKEN = 4;
5697
7551
  var SAVINGS_MULTIPLIER = 1.7;
5698
- function graphsRoot() {
5699
- return process.env.HIVEMIND_GRAPHS_HOME ?? join25(homedir13(), ".hivemind", "graphs");
7552
+ function graphsRoot2() {
7553
+ return process.env.HIVEMIND_GRAPHS_HOME ?? join33(homedir14(), ".hivemind", "graphs");
5700
7554
  }
5701
7555
  function bytesToSavedTokens(bytes) {
5702
7556
  if (!Number.isFinite(bytes) || bytes <= 0)
@@ -5704,18 +7558,18 @@ function bytesToSavedTokens(bytes) {
5704
7558
  const delivered = bytes / BYTES_PER_TOKEN;
5705
7559
  return (SAVINGS_MULTIPLIER - 1) * delivered;
5706
7560
  }
5707
- function resolveSnapshot(repoDir) {
5708
- const snapshotsDir = join25(repoDir, "snapshots");
5709
- if (!existsSync19(snapshotsDir))
7561
+ function resolveSnapshot(repoDir2) {
7562
+ const snapshotsDir = join33(repoDir2, "snapshots");
7563
+ if (!existsSync25(snapshotsDir))
5710
7564
  return null;
5711
7565
  let snapshotPath = null;
5712
- const pointer = join25(repoDir, "latest-commit.txt");
5713
- if (existsSync19(pointer)) {
7566
+ const pointer = join33(repoDir2, "latest-commit.txt");
7567
+ if (existsSync25(pointer)) {
5714
7568
  try {
5715
- const sha = readFileSync18(pointer, "utf-8").trim();
7569
+ const sha = readFileSync24(pointer, "utf-8").trim();
5716
7570
  if (sha) {
5717
- const candidate = join25(snapshotsDir, `${sha}.json`);
5718
- if (existsSync19(candidate))
7571
+ const candidate = join33(snapshotsDir, `${sha}.json`);
7572
+ if (existsSync25(candidate))
5719
7573
  snapshotPath = candidate;
5720
7574
  else
5721
7575
  log7(`latest-commit.txt points at missing ${sha}.json \u2014 scanning snapshots/`);
@@ -5726,8 +7580,8 @@ function resolveSnapshot(repoDir) {
5726
7580
  }
5727
7581
  if (!snapshotPath) {
5728
7582
  try {
5729
- const candidates = readdirSync3(snapshotsDir).filter((name) => name.endsWith(".json")).map((name) => {
5730
- const full = join25(snapshotsDir, name);
7583
+ const candidates = readdirSync4(snapshotsDir).filter((name) => name.endsWith(".json")).map((name) => {
7584
+ const full = join33(snapshotsDir, name);
5731
7585
  return { full, mtime: statSync3(full).mtimeMs };
5732
7586
  }).sort((a, b) => b.mtime - a.mtime);
5733
7587
  if (candidates.length > 0)
@@ -5740,7 +7594,7 @@ function resolveSnapshot(repoDir) {
5740
7594
  return null;
5741
7595
  let raw;
5742
7596
  try {
5743
- raw = readFileSync18(snapshotPath, "utf-8");
7597
+ raw = readFileSync24(snapshotPath, "utf-8");
5744
7598
  } catch (e) {
5745
7599
  log7(`snapshot read failed: ${e?.message ?? String(e)}`);
5746
7600
  return null;
@@ -5810,8 +7664,8 @@ async function loadKpis(creds) {
5810
7664
  async function loadDashboardData(opts = {}) {
5811
7665
  const cwd = opts.cwd ?? process.cwd();
5812
7666
  const { key: repoKey, project: repoProject } = deriveProjectKey(cwd);
5813
- const repoDir = join25(opts.graphsHome ?? graphsRoot(), repoKey);
5814
- const graph = resolveSnapshot(repoDir);
7667
+ const repoDir2 = join33(opts.graphsHome ?? graphsRoot2(), repoKey);
7668
+ const graph = resolveSnapshot(repoDir2);
5815
7669
  const creds = opts.creds === void 0 ? loadCredentials() : opts.creds;
5816
7670
  const kpis = await loadKpis(creds);
5817
7671
  return {
@@ -5827,7 +7681,7 @@ async function loadDashboardData(opts = {}) {
5827
7681
  import { spawn } from "node:child_process";
5828
7682
  import { accessSync, constants as fsConstants, statSync as statSync4 } from "node:fs";
5829
7683
  import { platform as nodePlatform } from "node:os";
5830
- import { delimiter, join as join26 } from "node:path";
7684
+ import { delimiter, join as join34 } from "node:path";
5831
7685
  function resolveOpenPlatform() {
5832
7686
  const p = nodePlatform();
5833
7687
  if (p === "linux" || p === "darwin" || p === "win32")
@@ -5854,7 +7708,7 @@ function findBinaryOnPath(name) {
5854
7708
  if (!dir)
5855
7709
  continue;
5856
7710
  for (const ext of exts) {
5857
- const candidate = join26(dir, name + ext);
7711
+ const candidate = join34(dir, name + ext);
5858
7712
  try {
5859
7713
  const st = statSync4(candidate);
5860
7714
  if (!st.isFile())
@@ -6193,7 +8047,7 @@ function handleRequest(html) {
6193
8047
  };
6194
8048
  }
6195
8049
  function tryListen(server, host, port) {
6196
- return new Promise((resolve3, reject) => {
8050
+ return new Promise((resolve6, reject) => {
6197
8051
  const onError = (err) => {
6198
8052
  server.off("listening", onListening);
6199
8053
  reject(err);
@@ -6205,7 +8059,7 @@ function tryListen(server, host, port) {
6205
8059
  reject(new Error("server bound to a non-IP address"));
6206
8060
  return;
6207
8061
  }
6208
- resolve3(addr.port);
8062
+ resolve6(addr.port);
6209
8063
  };
6210
8064
  server.once("error", onError);
6211
8065
  server.once("listening", onListening);
@@ -6231,22 +8085,22 @@ async function serveDashboardHtml(opts) {
6231
8085
  }
6232
8086
  function makeHandle(server, host, port) {
6233
8087
  let resolveStopped;
6234
- const stopped = new Promise((resolve3) => {
6235
- resolveStopped = resolve3;
8088
+ const stopped = new Promise((resolve6) => {
8089
+ resolveStopped = resolve6;
6236
8090
  });
6237
8091
  server.on("close", () => resolveStopped());
6238
8092
  return {
6239
8093
  host,
6240
8094
  port,
6241
8095
  stopped,
6242
- close: () => new Promise((resolve3, reject) => {
6243
- server.close((err) => err ? reject(err) : resolve3());
8096
+ close: () => new Promise((resolve6, reject) => {
8097
+ server.close((err) => err ? reject(err) : resolve6());
6244
8098
  })
6245
8099
  };
6246
8100
  }
6247
8101
 
6248
8102
  // dist/src/commands/dashboard.js
6249
- var USAGE = `hivemind dashboard \u2014 codebase graph + KPI dashboard (HTML)
8103
+ var USAGE2 = `hivemind dashboard \u2014 codebase graph + KPI dashboard (HTML)
6250
8104
 
6251
8105
  Usage:
6252
8106
  hivemind dashboard [--cwd <path>] [--out <path>] [--no-open]
@@ -6364,7 +8218,7 @@ function parseDashboardArgs(args) {
6364
8218
  };
6365
8219
  }
6366
8220
  function defaultDashboardOutPath(repoKey) {
6367
- return join27(homedir14(), ".hivemind", "dashboards", repoKey, "index.html");
8221
+ return join35(homedir15(), ".hivemind", "dashboards", repoKey, "index.html");
6368
8222
  }
6369
8223
  async function runDashboardCommand(rawArgs, runOpts = {}) {
6370
8224
  const out = runOpts.out ?? ((s) => {
@@ -6376,13 +8230,13 @@ async function runDashboardCommand(rawArgs, runOpts = {}) {
6376
8230
  const opener = runOpts.opener ?? openInBrowser;
6377
8231
  const parsed = parseDashboardArgs(rawArgs);
6378
8232
  if (parsed.help) {
6379
- out(USAGE);
8233
+ out(USAGE2);
6380
8234
  return 0;
6381
8235
  }
6382
8236
  if (parsed.error || !parsed.args) {
6383
8237
  err(`hivemind dashboard: ${parsed.error ?? "invalid arguments"}
6384
8238
  `);
6385
- err(USAGE);
8239
+ err(USAGE2);
6386
8240
  return 2;
6387
8241
  }
6388
8242
  const { cwd, outPath, open } = parsed.args;
@@ -6396,10 +8250,10 @@ async function runDashboardCommand(rawArgs, runOpts = {}) {
6396
8250
  }
6397
8251
  const html = renderDashboardHtml(data);
6398
8252
  const finalOut = outPath || defaultDashboardOutPath(data.repoKey);
6399
- const absOut = resolve2(finalOut);
8253
+ const absOut = resolve5(finalOut);
6400
8254
  try {
6401
- mkdirSync10(dirname6(absOut), { recursive: true });
6402
- writeFileSync13(absOut, html, "utf-8");
8255
+ mkdirSync16(dirname12(absOut), { recursive: true });
8256
+ writeFileSync18(absOut, html, "utf-8");
6403
8257
  } catch (e) {
6404
8258
  err(`hivemind dashboard: failed to write ${absOut}: ${e?.message ?? String(e)}
6405
8259
  `);
@@ -6478,24 +8332,24 @@ function defaultOnSignal(signal, handler) {
6478
8332
  }
6479
8333
 
6480
8334
  // dist/src/commands/skillify.js
6481
- import { readdirSync as readdirSync7, existsSync as existsSync30, readFileSync as readFileSync26, mkdirSync as mkdirSync17, renameSync as renameSync8 } from "node:fs";
6482
- import { homedir as homedir23 } from "node:os";
6483
- import { dirname as dirname11, join as join38 } from "node:path";
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";
6484
8338
 
6485
8339
  // dist/src/skillify/scope-config.js
6486
- import { existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync19, writeFileSync as writeFileSync14 } from "node:fs";
6487
- import { join as join28 } from "node:path";
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";
6488
8342
  function configPath() {
6489
- return join28(getStateDir(), "config.json");
8343
+ return join36(getStateDir(), "config.json");
6490
8344
  }
6491
8345
  var DEFAULT = { scope: "me", team: [], install: "project" };
6492
8346
  function loadScopeConfig() {
6493
8347
  migrateLegacyStateDir();
6494
8348
  const CONFIG_PATH2 = configPath();
6495
- if (!existsSync20(CONFIG_PATH2))
8349
+ if (!existsSync26(CONFIG_PATH2))
6496
8350
  return DEFAULT;
6497
8351
  try {
6498
- const raw = JSON.parse(readFileSync19(CONFIG_PATH2, "utf-8"));
8352
+ const raw = JSON.parse(readFileSync25(CONFIG_PATH2, "utf-8"));
6499
8353
  const scope = raw.scope === "team" ? "team" : raw.scope === "org" ? "team" : "me";
6500
8354
  const team = Array.isArray(raw.team) ? raw.team.filter((s) => typeof s === "string") : [];
6501
8355
  const install = raw.install === "global" ? "global" : "project";
@@ -6506,19 +8360,19 @@ function loadScopeConfig() {
6506
8360
  }
6507
8361
  function saveScopeConfig(cfg) {
6508
8362
  migrateLegacyStateDir();
6509
- mkdirSync11(getStateDir(), { recursive: true });
6510
- writeFileSync14(configPath(), JSON.stringify(cfg, null, 2));
8363
+ mkdirSync17(getStateDir(), { recursive: true });
8364
+ writeFileSync19(configPath(), JSON.stringify(cfg, null, 2));
6511
8365
  }
6512
8366
 
6513
8367
  // dist/src/skillify/pull.js
6514
- import { existsSync as existsSync24, readFileSync as readFileSync22, writeFileSync as writeFileSync17, mkdirSync as mkdirSync14, renameSync as renameSync7, lstatSync as lstatSync5, readlinkSync as readlinkSync2, symlinkSync as symlinkSync2, unlinkSync as unlinkSync10 } from "node:fs";
6515
- import { homedir as homedir17 } from "node:os";
6516
- import { dirname as dirname8, join as join32 } 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";
6517
8371
 
6518
8372
  // dist/src/skillify/skill-writer.js
6519
- import { existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync20, readdirSync as readdirSync4, statSync as statSync5, writeFileSync as writeFileSync15 } from "node:fs";
6520
- import { homedir as homedir15 } from "node:os";
6521
- import { join as join29 } 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";
6522
8376
  function assertValidSkillName(name) {
6523
8377
  if (typeof name !== "string" || name.length === 0) {
6524
8378
  throw new Error(`invalid skill name: empty or non-string`);
@@ -6534,10 +8388,10 @@ function assertValidSkillName(name) {
6534
8388
  }
6535
8389
  }
6536
8390
  function skillDir(skillsRoot, name) {
6537
- return join29(skillsRoot, name);
8391
+ return join37(skillsRoot, name);
6538
8392
  }
6539
8393
  function skillPath(skillsRoot, name) {
6540
- return join29(skillDir(skillsRoot, name), "SKILL.md");
8394
+ return join37(skillDir(skillsRoot, name), "SKILL.md");
6541
8395
  }
6542
8396
  function renderFrontmatter(fm) {
6543
8397
  const lines = ["---"];
@@ -6615,10 +8469,10 @@ function writeNewSkill(args) {
6615
8469
  assertValidSkillName(args.name);
6616
8470
  const dir = skillDir(args.skillsRoot, args.name);
6617
8471
  const path = skillPath(args.skillsRoot, args.name);
6618
- if (existsSync21(path)) {
8472
+ if (existsSync27(path)) {
6619
8473
  throw new Error(`skill already exists at ${path}; use mergeSkill`);
6620
8474
  }
6621
- mkdirSync12(dir, { recursive: true });
8475
+ mkdirSync18(dir, { recursive: true });
6622
8476
  const now = (/* @__PURE__ */ new Date()).toISOString();
6623
8477
  const author = args.author && args.author.length > 0 ? args.author : void 0;
6624
8478
  const contributors = author ? [author] : [];
@@ -6638,7 +8492,7 @@ function writeNewSkill(args) {
6638
8492
 
6639
8493
  ${args.body.trim()}
6640
8494
  `;
6641
- writeFileSync15(path, text);
8495
+ writeFileSync20(path, text);
6642
8496
  return {
6643
8497
  path,
6644
8498
  action: "created",
@@ -6650,40 +8504,40 @@ ${args.body.trim()}
6650
8504
  };
6651
8505
  }
6652
8506
  function listSkills(skillsRoot) {
6653
- if (!existsSync21(skillsRoot))
8507
+ if (!existsSync27(skillsRoot))
6654
8508
  return [];
6655
8509
  const out = [];
6656
- for (const name of readdirSync4(skillsRoot)) {
6657
- const skillFile = join29(skillsRoot, name, "SKILL.md");
6658
- if (existsSync21(skillFile) && statSync5(skillFile).isFile()) {
6659
- out.push({ name, body: readFileSync20(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") });
6660
8514
  }
6661
8515
  }
6662
8516
  return out;
6663
8517
  }
6664
8518
  function resolveSkillsRoot(install, cwd) {
6665
8519
  if (install === "global") {
6666
- return join29(homedir15(), ".claude", "skills");
8520
+ return join37(homedir16(), ".claude", "skills");
6667
8521
  }
6668
- return join29(cwd, ".claude", "skills");
8522
+ return join37(cwd, ".claude", "skills");
6669
8523
  }
6670
8524
 
6671
8525
  // dist/src/skillify/manifest.js
6672
- import { existsSync as existsSync22, lstatSync as lstatSync4, mkdirSync as mkdirSync13, readFileSync as readFileSync21, renameSync as renameSync6, unlinkSync as unlinkSync9, writeFileSync as writeFileSync16 } from "node:fs";
6673
- import { dirname as dirname7, join as join30 } 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";
6674
8528
  function emptyManifest() {
6675
8529
  return { version: 1, entries: [] };
6676
8530
  }
6677
8531
  function manifestPath() {
6678
- return join30(getStateDir(), "pulled.json");
8532
+ return join38(getStateDir(), "pulled.json");
6679
8533
  }
6680
8534
  function loadManifest(path = manifestPath()) {
6681
8535
  migrateLegacyStateDir();
6682
- if (!existsSync22(path))
8536
+ if (!existsSync28(path))
6683
8537
  return emptyManifest();
6684
8538
  let raw;
6685
8539
  try {
6686
- raw = readFileSync21(path, "utf-8");
8540
+ raw = readFileSync27(path, "utf-8");
6687
8541
  } catch {
6688
8542
  return emptyManifest();
6689
8543
  }
@@ -6730,10 +8584,10 @@ function loadManifest(path = manifestPath()) {
6730
8584
  }
6731
8585
  function saveManifest(m, path = manifestPath()) {
6732
8586
  migrateLegacyStateDir();
6733
- mkdirSync13(dirname7(path), { recursive: true });
8587
+ mkdirSync19(dirname13(path), { recursive: true });
6734
8588
  const tmp = `${path}.tmp`;
6735
- writeFileSync16(tmp, JSON.stringify(m, null, 2) + "\n", { mode: 384 });
6736
- renameSync6(tmp, path);
8589
+ writeFileSync21(tmp, JSON.stringify(m, null, 2) + "\n", { mode: 384 });
8590
+ renameSync10(tmp, path);
6737
8591
  }
6738
8592
  function recordPull(entry, path = manifestPath()) {
6739
8593
  const m = loadManifest(path);
@@ -6765,7 +8619,7 @@ function unlinkSymlinks(paths) {
6765
8619
  if (!st.isSymbolicLink())
6766
8620
  continue;
6767
8621
  try {
6768
- unlinkSync9(path);
8622
+ unlinkSync10(path);
6769
8623
  } catch {
6770
8624
  }
6771
8625
  }
@@ -6775,7 +8629,7 @@ function pruneOrphanedEntries(path = manifestPath()) {
6775
8629
  const live = [];
6776
8630
  let pruned = 0;
6777
8631
  for (const e of m.entries) {
6778
- if (existsSync22(join30(e.installRoot, e.dirName))) {
8632
+ if (existsSync28(join38(e.installRoot, e.dirName))) {
6779
8633
  live.push(e);
6780
8634
  continue;
6781
8635
  }
@@ -6788,26 +8642,26 @@ function pruneOrphanedEntries(path = manifestPath()) {
6788
8642
  }
6789
8643
 
6790
8644
  // dist/src/skillify/agent-roots.js
6791
- import { existsSync as existsSync23 } from "node:fs";
6792
- import { homedir as homedir16 } from "node:os";
6793
- import { join as join31 } 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";
6794
8648
  function resolveDetected(home) {
6795
8649
  const out = [];
6796
- const codexInstalled = existsSync23(join31(home, ".codex"));
6797
- const piInstalled = existsSync23(join31(home, ".pi", "agent"));
6798
- const hermesInstalled = existsSync23(join31(home, ".hermes"));
8650
+ const codexInstalled = existsSync29(join39(home, ".codex"));
8651
+ const piInstalled = existsSync29(join39(home, ".pi", "agent"));
8652
+ const hermesInstalled = existsSync29(join39(home, ".hermes"));
6799
8653
  if (codexInstalled || piInstalled) {
6800
- out.push(join31(home, ".agents", "skills"));
8654
+ out.push(join39(home, ".agents", "skills"));
6801
8655
  }
6802
8656
  if (hermesInstalled) {
6803
- out.push(join31(home, ".hermes", "skills"));
8657
+ out.push(join39(home, ".hermes", "skills"));
6804
8658
  }
6805
8659
  if (piInstalled) {
6806
- out.push(join31(home, ".pi", "agent", "skills"));
8660
+ out.push(join39(home, ".pi", "agent", "skills"));
6807
8661
  }
6808
8662
  return out;
6809
8663
  }
6810
- function detectAgentSkillsRoots(canonicalRoot, home = homedir16()) {
8664
+ function detectAgentSkillsRoots(canonicalRoot, home = homedir17()) {
6811
8665
  return resolveDetected(home).filter((p) => p !== canonicalRoot);
6812
8666
  }
6813
8667
 
@@ -6851,15 +8705,15 @@ function isMissingTableError(message) {
6851
8705
  }
6852
8706
  function resolvePullDestination(install, cwd) {
6853
8707
  if (install === "global")
6854
- return join32(homedir17(), ".claude", "skills");
8708
+ return join40(homedir18(), ".claude", "skills");
6855
8709
  if (!cwd)
6856
8710
  throw new Error("install=project requires a cwd");
6857
- return join32(cwd, ".claude", "skills");
8711
+ return join40(cwd, ".claude", "skills");
6858
8712
  }
6859
8713
  function fanOutSymlinks(canonicalDir, dirName, agentRoots) {
6860
8714
  const out = [];
6861
8715
  for (const root of agentRoots) {
6862
- const link = join32(root, dirName);
8716
+ const link = join40(root, dirName);
6863
8717
  let existing;
6864
8718
  try {
6865
8719
  existing = lstatSync5(link);
@@ -6881,13 +8735,13 @@ function fanOutSymlinks(canonicalDir, dirName, agentRoots) {
6881
8735
  continue;
6882
8736
  }
6883
8737
  try {
6884
- unlinkSync10(link);
8738
+ unlinkSync11(link);
6885
8739
  } catch {
6886
8740
  continue;
6887
8741
  }
6888
8742
  }
6889
8743
  try {
6890
- mkdirSync14(dirname8(link), { recursive: true });
8744
+ mkdirSync20(dirname14(link), { recursive: true });
6891
8745
  symlinkSync2(canonicalDir, link, "dir");
6892
8746
  out.push(link);
6893
8747
  } catch {
@@ -6902,8 +8756,8 @@ function backfillSymlinks(installRoot) {
6902
8756
  return;
6903
8757
  const detected = detectAgentSkillsRoots(installRoot);
6904
8758
  for (const entry of entries) {
6905
- const canonical = join32(entry.installRoot, entry.dirName);
6906
- if (!existsSync24(canonical))
8759
+ const canonical = join40(entry.installRoot, entry.dirName);
8760
+ if (!existsSync30(canonical))
6907
8761
  continue;
6908
8762
  const fresh = fanOutSymlinks(canonical, entry.dirName, detected);
6909
8763
  if (sameSorted(fresh, entry.symlinks))
@@ -7013,10 +8867,10 @@ function renderFrontmatter2(fm) {
7013
8867
  return lines.join("\n");
7014
8868
  }
7015
8869
  function readLocalVersion(path) {
7016
- if (!existsSync24(path))
8870
+ if (!existsSync30(path))
7017
8871
  return null;
7018
8872
  try {
7019
- const text = readFileSync22(path, "utf-8");
8873
+ const text = readFileSync28(path, "utf-8");
7020
8874
  const parsed = parseFrontmatter(text);
7021
8875
  if (!parsed)
7022
8876
  return null;
@@ -7111,8 +8965,8 @@ async function runPull(opts) {
7111
8965
  summary.skipped++;
7112
8966
  continue;
7113
8967
  }
7114
- const skillDir2 = join32(root, dirName);
7115
- const skillFile = join32(skillDir2, "SKILL.md");
8968
+ const skillDir2 = join40(root, dirName);
8969
+ const skillFile = join40(skillDir2, "SKILL.md");
7116
8970
  const remoteVersion = Number(row.version ?? 1);
7117
8971
  const localVersion = readLocalVersion(skillFile);
7118
8972
  const action = decideAction({
@@ -7123,14 +8977,14 @@ async function runPull(opts) {
7123
8977
  });
7124
8978
  let manifestError;
7125
8979
  if (action === "wrote") {
7126
- mkdirSync14(skillDir2, { recursive: true });
7127
- if (existsSync24(skillFile)) {
8980
+ mkdirSync20(skillDir2, { recursive: true });
8981
+ if (existsSync30(skillFile)) {
7128
8982
  try {
7129
- renameSync7(skillFile, `${skillFile}.bak`);
8983
+ renameSync11(skillFile, `${skillFile}.bak`);
7130
8984
  } catch {
7131
8985
  }
7132
8986
  }
7133
- writeFileSync17(skillFile, renderSkillFile(row));
8987
+ writeFileSync22(skillFile, renderSkillFile(row));
7134
8988
  const symlinks = opts.install === "global" ? fanOutSymlinks(skillDir2, dirName, detectAgentSkillsRoots(root)) : [];
7135
8989
  try {
7136
8990
  recordPull({
@@ -7172,15 +9026,15 @@ async function runPull(opts) {
7172
9026
  }
7173
9027
 
7174
9028
  // dist/src/skillify/unpull.js
7175
- import { existsSync as existsSync25, readdirSync as readdirSync5, rmSync as rmSync5, statSync as statSync6 } from "node:fs";
7176
- import { homedir as homedir18 } from "node:os";
7177
- import { join as join33 } 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";
7178
9032
  function resolveUnpullRoot(install, cwd) {
7179
9033
  if (install === "global")
7180
- return join33(homedir18(), ".claude", "skills");
9034
+ return join41(homedir19(), ".claude", "skills");
7181
9035
  if (!cwd)
7182
9036
  throw new Error("cwd required when install === 'project'");
7183
- return join33(cwd, ".claude", "skills");
9037
+ return join41(cwd, ".claude", "skills");
7184
9038
  }
7185
9039
  function runUnpull(opts) {
7186
9040
  const root = resolveUnpullRoot(opts.install, opts.cwd);
@@ -7203,8 +9057,8 @@ function runUnpull(opts) {
7203
9057
  const entries = entriesForRoot(manifest, opts.install, root);
7204
9058
  for (const entry of entries) {
7205
9059
  summary.scanned++;
7206
- const path = join33(root, entry.dirName);
7207
- if (!existsSync25(path)) {
9060
+ const path = join41(root, entry.dirName);
9061
+ if (!existsSync31(path)) {
7208
9062
  if (!opts.dryRun) {
7209
9063
  unlinkSymlinks(entry.symlinks);
7210
9064
  removePullEntry(opts.install, entry.installRoot, entry.dirName);
@@ -7257,12 +9111,12 @@ function runUnpull(opts) {
7257
9111
  }
7258
9112
  summary.entries.push(result);
7259
9113
  }
7260
- if (existsSync25(root) && (opts.all || opts.legacyCleanup)) {
9114
+ if (existsSync31(root) && (opts.all || opts.legacyCleanup)) {
7261
9115
  const manifestDirNames = new Set(entries.map((e) => e.dirName));
7262
- for (const dirName of readdirSync5(root)) {
9116
+ for (const dirName of readdirSync6(root)) {
7263
9117
  if (manifestDirNames.has(dirName))
7264
9118
  continue;
7265
- const path = join33(root, dirName);
9119
+ const path = join41(root, dirName);
7266
9120
  let st;
7267
9121
  try {
7268
9122
  st = statSync6(path);
@@ -7341,30 +9195,30 @@ function decideTargetForManifestEntry(entry, opts, userFilter, haveUserFilter) {
7341
9195
 
7342
9196
  // dist/src/commands/mine-local.js
7343
9197
  import { spawn as spawn2 } from "node:child_process";
7344
- import { existsSync as existsSync29, mkdirSync as mkdirSync16, readFileSync as readFileSync25, writeFileSync as writeFileSync19 } from "node:fs";
7345
- import { homedir as homedir22 } from "node:os";
7346
- import { basename as basename2, dirname as dirname10, join as join37 } from "node:path";
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";
7347
9201
 
7348
9202
  // dist/src/skillify/local-source.js
7349
- import { readdirSync as readdirSync6, readFileSync as readFileSync23, existsSync as existsSync26, statSync as statSync7 } from "node:fs";
7350
- import { homedir as homedir19 } from "node:os";
7351
- import { join as join34 } from "node:path";
7352
- var HOME2 = homedir19();
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();
7353
9207
  function encodeCwdClaudeCode(cwd) {
7354
9208
  return cwd.replace(/[/_]/g, "-");
7355
9209
  }
7356
9210
  function detectInstalledAgents() {
7357
9211
  const installs = [];
7358
- const claudeRoot = join34(HOME2, ".claude", "projects");
7359
- if (existsSync26(claudeRoot)) {
9212
+ const claudeRoot = join42(HOME2, ".claude", "projects");
9213
+ if (existsSync32(claudeRoot)) {
7360
9214
  installs.push({
7361
9215
  agent: "claude_code",
7362
9216
  sessionRoot: claudeRoot,
7363
9217
  encodeCwd: encodeCwdClaudeCode
7364
9218
  });
7365
9219
  }
7366
- const codexRoot = join34(HOME2, ".codex", "sessions");
7367
- if (existsSync26(codexRoot)) {
9220
+ const codexRoot = join42(HOME2, ".codex", "sessions");
9221
+ if (existsSync32(codexRoot)) {
7368
9222
  installs.push({
7369
9223
  agent: "codex",
7370
9224
  sessionRoot: codexRoot,
@@ -7386,12 +9240,12 @@ function listLocalSessions(installs, cwd) {
7386
9240
  const cwdEncoded = install.encodeCwd(cwd);
7387
9241
  let subdirs = [];
7388
9242
  try {
7389
- subdirs = readdirSync6(install.sessionRoot);
9243
+ subdirs = readdirSync7(install.sessionRoot);
7390
9244
  } catch {
7391
9245
  continue;
7392
9246
  }
7393
9247
  for (const sub of subdirs) {
7394
- const subdirPath = join34(install.sessionRoot, sub);
9248
+ const subdirPath = join42(install.sessionRoot, sub);
7395
9249
  try {
7396
9250
  if (!statSync7(subdirPath).isDirectory())
7397
9251
  continue;
@@ -7401,14 +9255,14 @@ function listLocalSessions(installs, cwd) {
7401
9255
  const inCwd = sub === cwdEncoded;
7402
9256
  let files = [];
7403
9257
  try {
7404
- files = readdirSync6(subdirPath);
9258
+ files = readdirSync7(subdirPath);
7405
9259
  } catch {
7406
9260
  continue;
7407
9261
  }
7408
9262
  for (const f of files) {
7409
9263
  if (!f.endsWith(".jsonl"))
7410
9264
  continue;
7411
- const fullPath = join34(subdirPath, f);
9265
+ const fullPath = join42(subdirPath, f);
7412
9266
  let stats;
7413
9267
  try {
7414
9268
  stats = statSync7(fullPath);
@@ -7469,7 +9323,7 @@ function pickSessions(candidates, opts) {
7469
9323
  function nativeJsonlToRows(filePath, sessionId, agent) {
7470
9324
  let raw;
7471
9325
  try {
7472
- raw = readFileSync23(filePath, "utf-8");
9326
+ raw = readFileSync29(filePath, "utf-8");
7473
9327
  } catch {
7474
9328
  return [];
7475
9329
  }
@@ -7559,22 +9413,22 @@ function extractPairs(rows) {
7559
9413
  }
7560
9414
 
7561
9415
  // dist/src/skillify/gate-runner.js
7562
- import { existsSync as existsSync27 } from "node:fs";
9416
+ import { existsSync as existsSync33 } from "node:fs";
7563
9417
  import { createRequire } from "node:module";
7564
- import { homedir as homedir20 } from "node:os";
7565
- import { join as join35 } from "node:path";
9418
+ import { homedir as homedir21 } from "node:os";
9419
+ import { join as join43 } from "node:path";
7566
9420
  var requireForCp = createRequire(import.meta.url);
7567
9421
  var { execFileSync: runChildProcess } = requireForCp("node:child_process");
7568
9422
  var inheritedEnv = process;
7569
9423
  function firstExistingPath(candidates) {
7570
9424
  for (const c of candidates) {
7571
- if (existsSync27(c))
9425
+ if (existsSync33(c))
7572
9426
  return c;
7573
9427
  }
7574
9428
  return null;
7575
9429
  }
7576
9430
  function findAgentBin(agent) {
7577
- const home = homedir20();
9431
+ const home = homedir21();
7578
9432
  switch (agent) {
7579
9433
  // /usr/bin/<name> is included in every candidate list — that's the
7580
9434
  // common Linux package-manager install path (apt, dnf, pacman). Old
@@ -7583,45 +9437,45 @@ function findAgentBin(agent) {
7583
9437
  // #170 caught the gap.
7584
9438
  case "claude_code":
7585
9439
  return firstExistingPath([
7586
- join35(home, ".claude", "local", "claude"),
9440
+ join43(home, ".claude", "local", "claude"),
7587
9441
  "/usr/local/bin/claude",
7588
9442
  "/usr/bin/claude",
7589
- join35(home, ".npm-global", "bin", "claude"),
7590
- join35(home, ".local", "bin", "claude"),
9443
+ join43(home, ".npm-global", "bin", "claude"),
9444
+ join43(home, ".local", "bin", "claude"),
7591
9445
  "/opt/homebrew/bin/claude"
7592
- ]) ?? join35(home, ".claude", "local", "claude");
9446
+ ]) ?? join43(home, ".claude", "local", "claude");
7593
9447
  case "codex":
7594
9448
  return firstExistingPath([
7595
9449
  "/usr/local/bin/codex",
7596
9450
  "/usr/bin/codex",
7597
- join35(home, ".npm-global", "bin", "codex"),
7598
- join35(home, ".local", "bin", "codex"),
9451
+ join43(home, ".npm-global", "bin", "codex"),
9452
+ join43(home, ".local", "bin", "codex"),
7599
9453
  "/opt/homebrew/bin/codex"
7600
9454
  ]) ?? "/usr/local/bin/codex";
7601
9455
  case "cursor":
7602
9456
  return firstExistingPath([
7603
9457
  "/usr/local/bin/cursor-agent",
7604
9458
  "/usr/bin/cursor-agent",
7605
- join35(home, ".npm-global", "bin", "cursor-agent"),
7606
- join35(home, ".local", "bin", "cursor-agent"),
9459
+ join43(home, ".npm-global", "bin", "cursor-agent"),
9460
+ join43(home, ".local", "bin", "cursor-agent"),
7607
9461
  "/opt/homebrew/bin/cursor-agent"
7608
9462
  ]) ?? "/usr/local/bin/cursor-agent";
7609
9463
  case "hermes":
7610
9464
  return firstExistingPath([
7611
- join35(home, ".local", "bin", "hermes"),
9465
+ join43(home, ".local", "bin", "hermes"),
7612
9466
  "/usr/local/bin/hermes",
7613
9467
  "/usr/bin/hermes",
7614
- join35(home, ".npm-global", "bin", "hermes"),
9468
+ join43(home, ".npm-global", "bin", "hermes"),
7615
9469
  "/opt/homebrew/bin/hermes"
7616
- ]) ?? join35(home, ".local", "bin", "hermes");
9470
+ ]) ?? join43(home, ".local", "bin", "hermes");
7617
9471
  case "pi":
7618
9472
  return firstExistingPath([
7619
- join35(home, ".local", "bin", "pi"),
9473
+ join43(home, ".local", "bin", "pi"),
7620
9474
  "/usr/local/bin/pi",
7621
9475
  "/usr/bin/pi",
7622
- join35(home, ".npm-global", "bin", "pi"),
9476
+ join43(home, ".npm-global", "bin", "pi"),
7623
9477
  "/opt/homebrew/bin/pi"
7624
- ]) ?? join35(home, ".local", "bin", "pi");
9478
+ ]) ?? join43(home, ".local", "bin", "pi");
7625
9479
  }
7626
9480
  }
7627
9481
 
@@ -7651,28 +9505,28 @@ function extractJsonBlock(s) {
7651
9505
  }
7652
9506
 
7653
9507
  // dist/src/skillify/local-manifest.js
7654
- import { existsSync as existsSync28, mkdirSync as mkdirSync15, readFileSync as readFileSync24, writeFileSync as writeFileSync18 } from "node:fs";
7655
- import { homedir as homedir21 } from "node:os";
7656
- import { dirname as dirname9, join as join36 } from "node:path";
7657
- var LOCAL_MANIFEST_PATH = join36(homedir21(), ".claude", "hivemind", "local-mined.json");
7658
- var LOCAL_MINE_LOCK_PATH = join36(homedir21(), ".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");
7659
9513
  function readLocalManifest(path = LOCAL_MANIFEST_PATH) {
7660
- if (!existsSync28(path))
9514
+ if (!existsSync34(path))
7661
9515
  return null;
7662
9516
  try {
7663
- return JSON.parse(readFileSync24(path, "utf-8"));
9517
+ return JSON.parse(readFileSync30(path, "utf-8"));
7664
9518
  } catch {
7665
9519
  return null;
7666
9520
  }
7667
9521
  }
7668
9522
  function writeLocalManifest(m, path = LOCAL_MANIFEST_PATH) {
7669
- mkdirSync15(dirname9(path), { recursive: true });
7670
- writeFileSync18(path, JSON.stringify(m, null, 2));
9523
+ mkdirSync21(dirname15(path), { recursive: true });
9524
+ writeFileSync23(path, JSON.stringify(m, null, 2));
7671
9525
  }
7672
9526
  var LATEST_RUN_WINDOW_MS = 5 * 60 * 1e3;
7673
9527
 
7674
9528
  // dist/src/commands/mine-local.js
7675
- import { unlinkSync as unlinkSync11 } from "node:fs";
9529
+ import { unlinkSync as unlinkSync12 } from "node:fs";
7676
9530
  var EPSILON = 0.3;
7677
9531
  var DEFAULT_N = 8;
7678
9532
  var PAIR_CHAR_CAP = 4e3;
@@ -7683,9 +9537,9 @@ var IN_FLIGHT_MAX_AGE_MS = 6e4;
7683
9537
  var GATE_TIMEOUT_MS = 24e4;
7684
9538
  var MANIFEST_PATH = LOCAL_MANIFEST_PATH;
7685
9539
  function runGateViaStdin(opts) {
7686
- return new Promise((resolve3) => {
9540
+ return new Promise((resolve6) => {
7687
9541
  if (opts.agent !== "claude_code") {
7688
- resolve3({
9542
+ resolve6({
7689
9543
  stdout: "",
7690
9544
  stderr: "",
7691
9545
  errored: true,
@@ -7693,8 +9547,8 @@ function runGateViaStdin(opts) {
7693
9547
  });
7694
9548
  return;
7695
9549
  }
7696
- if (!existsSync29(opts.bin)) {
7697
- resolve3({
9550
+ if (!existsSync35(opts.bin)) {
9551
+ resolve6({
7698
9552
  stdout: "",
7699
9553
  stderr: "",
7700
9554
  errored: true,
@@ -7721,7 +9575,7 @@ function runGateViaStdin(opts) {
7721
9575
  if (settled)
7722
9576
  return;
7723
9577
  settled = true;
7724
- resolve3(r);
9578
+ resolve6(r);
7725
9579
  };
7726
9580
  const timer = setTimeout(() => {
7727
9581
  try {
@@ -8000,7 +9854,7 @@ async function runMineLocal(args) {
8000
9854
  return;
8001
9855
  lockReleased = true;
8002
9856
  try {
8003
- unlinkSync11(LOCAL_MINE_LOCK_PATH);
9857
+ unlinkSync12(LOCAL_MINE_LOCK_PATH);
8004
9858
  } catch {
8005
9859
  }
8006
9860
  };
@@ -8057,8 +9911,8 @@ async function runMineLocalImpl(args) {
8057
9911
  console.log(`Dry-run: would invoke ${gateAgent} gate on ${picked.length} session(s) in parallel (concurrency=${GATE_CONCURRENCY}).`);
8058
9912
  return;
8059
9913
  }
8060
- const tmpDir = join37(homedir22(), ".claude", "hivemind", `mine-local-${Date.now()}`);
8061
- mkdirSync16(tmpDir, { recursive: true });
9914
+ const tmpDir = join45(homedir23(), ".claude", "hivemind", `mine-local-${Date.now()}`);
9915
+ mkdirSync22(tmpDir, { recursive: true });
8062
9916
  console.log(`Running ${picked.length} gate call(s) in parallel (concurrency=${GATE_CONCURRENCY}, timeout=${GATE_TIMEOUT_MS / 1e3}s each)...`);
8063
9917
  const results = await parallelMap(picked, GATE_CONCURRENCY, async (s) => {
8064
9918
  const shortId = s.sessionId.slice(0, 8);
@@ -8069,23 +9923,23 @@ async function runMineLocalImpl(args) {
8069
9923
  return { session: s, skills: [], reason: "no pairs", error: null };
8070
9924
  }
8071
9925
  const tail = pairs2.slice(-PER_SESSION_PAIR_CAP);
8072
- const sessionTmp = join37(tmpDir, `s-${shortId}`);
8073
- mkdirSync16(sessionTmp, { recursive: true });
8074
- const verdictPath = join37(sessionTmp, "verdict.json");
9926
+ const sessionTmp = join45(tmpDir, `s-${shortId}`);
9927
+ mkdirSync22(sessionTmp, { recursive: true });
9928
+ const verdictPath = join45(sessionTmp, "verdict.json");
8075
9929
  const prompt = buildSessionPrompt(tail, s, verdictPath);
8076
- writeFileSync19(join37(sessionTmp, "prompt.txt"), prompt);
9930
+ writeFileSync24(join45(sessionTmp, "prompt.txt"), prompt);
8077
9931
  const gate = await runGateViaStdin({ agent: gateAgent, bin: gateBin, prompt, timeoutMs: GATE_TIMEOUT_MS });
8078
9932
  try {
8079
- writeFileSync19(join37(sessionTmp, "gate-stdout.txt"), gate.stdout);
9933
+ writeFileSync24(join45(sessionTmp, "gate-stdout.txt"), gate.stdout);
8080
9934
  if (gate.stderr)
8081
- writeFileSync19(join37(sessionTmp, "gate-stderr.txt"), gate.stderr);
9935
+ writeFileSync24(join45(sessionTmp, "gate-stderr.txt"), gate.stderr);
8082
9936
  } catch {
8083
9937
  }
8084
9938
  if (gate.errored) {
8085
9939
  console.log(` [${shortId}] gate failed: ${gate.errorMessage}`);
8086
9940
  return { session: s, skills: [], reason: null, error: gate.errorMessage ?? "gate failed" };
8087
9941
  }
8088
- const verdictText = existsSync29(verdictPath) ? readFileSync25(verdictPath, "utf-8") : gate.stdout;
9942
+ const verdictText = existsSync35(verdictPath) ? readFileSync31(verdictPath, "utf-8") : gate.stdout;
8089
9943
  const mv = parseMultiVerdict(verdictText);
8090
9944
  if (!mv) {
8091
9945
  console.log(` [${shortId}] unparseable verdict (kept at ${sessionTmp})`);
@@ -8137,7 +9991,7 @@ async function runMineLocalImpl(args) {
8137
9991
  sourceSessions: [session.sessionId],
8138
9992
  agent: gateAgent
8139
9993
  });
8140
- const canonicalDir = dirname10(result.path);
9994
+ const canonicalDir = dirname16(result.path);
8141
9995
  const symlinks = fanOutRoots.length > 0 ? fanOutSymlinks(canonicalDir, basename2(canonicalDir), fanOutRoots) : [];
8142
9996
  const symlinkSuffix = symlinks.length > 0 ? `, fan-out \u2192 ${symlinks.length} root(s)` : "";
8143
9997
  console.log(` wrote ${skill.name} \u2190 session ${session.sessionId.slice(0, 8)} (${session.agent}${symlinkSuffix})`);
@@ -8314,11 +10168,11 @@ function showStatus() {
8314
10168
  console.log(`team: ${cfg.team.length === 0 ? "(empty)" : cfg.team.join(", ")}`);
8315
10169
  console.log(`install: ${cfg.install} (${cfg.install === "global" ? "~/.claude/skills/" : "<project>/.claude/skills/"})`);
8316
10170
  const dir = stateDir();
8317
- if (!existsSync30(dir)) {
10171
+ if (!existsSync36(dir)) {
8318
10172
  console.log(`state: (no projects tracked yet)`);
8319
10173
  return;
8320
10174
  }
8321
- const files = readdirSync7(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");
8322
10176
  if (files.length === 0) {
8323
10177
  console.log(`state: (no projects tracked yet)`);
8324
10178
  return;
@@ -8326,7 +10180,7 @@ function showStatus() {
8326
10180
  console.log(`state: ${files.length} project(s) tracked`);
8327
10181
  for (const f of files) {
8328
10182
  try {
8329
- const s = JSON.parse(readFileSync26(join38(dir, f), "utf-8"));
10183
+ const s = JSON.parse(readFileSync32(join46(dir, f), "utf-8"));
8330
10184
  const last = typeof s.updatedAt === "number" ? new Date(s.updatedAt).toISOString() : s.lastDate ?? "never";
8331
10185
  const skills = Array.isArray(s.skillsGenerated) && s.skillsGenerated.length > 0 ? s.skillsGenerated.join(", ") : "none";
8332
10186
  console.log(` - ${s.project} (counter=${s.counter}, last=${last}, skills=${skills})`);
@@ -8353,7 +10207,7 @@ function setInstall(loc) {
8353
10207
  }
8354
10208
  const cfg = loadScopeConfig();
8355
10209
  saveScopeConfig({ ...cfg, install: loc });
8356
- const path = loc === "global" ? join38(homedir23(), ".claude", "skills") : "<cwd>/.claude/skills";
10210
+ const path = loc === "global" ? join46(homedir24(), ".claude", "skills") : "<cwd>/.claude/skills";
8357
10211
  console.log(`Install location set to '${loc}'. New skills will be written to ${path}/<name>/SKILL.md.`);
8358
10212
  }
8359
10213
  function promoteSkill(name, cwd) {
@@ -8361,18 +10215,18 @@ function promoteSkill(name, cwd) {
8361
10215
  console.error("Usage: hivemind skillify promote <skill-name>");
8362
10216
  process.exit(1);
8363
10217
  }
8364
- const projectPath = join38(cwd, ".claude", "skills", name);
8365
- const globalPath = join38(homedir23(), ".claude", "skills", name);
8366
- if (!existsSync30(join38(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"))) {
8367
10221
  console.error(`Skill '${name}' not found at ${projectPath}/SKILL.md`);
8368
10222
  process.exit(1);
8369
10223
  }
8370
- if (existsSync30(join38(globalPath, "SKILL.md"))) {
10224
+ if (existsSync36(join46(globalPath, "SKILL.md"))) {
8371
10225
  console.error(`Skill '${name}' already exists at ${globalPath}/SKILL.md \u2014 refusing to overwrite. Remove it first or rename the project skill.`);
8372
10226
  process.exit(1);
8373
10227
  }
8374
- mkdirSync17(dirname11(globalPath), { recursive: true });
8375
- renameSync8(projectPath, globalPath);
10228
+ mkdirSync23(dirname17(globalPath), { recursive: true });
10229
+ renameSync12(projectPath, globalPath);
8376
10230
  console.log(`Promoted '${name}' from ${projectPath} \u2192 ${globalPath}.`);
8377
10231
  }
8378
10232
  function teamAdd(name) {
@@ -8478,7 +10332,7 @@ async function pullSkills(args) {
8478
10332
  console.error(`pull failed: ${e?.message ?? e}`);
8479
10333
  process.exit(1);
8480
10334
  }
8481
- const dest = toRaw === "global" ? join38(homedir23(), ".claude", "skills") : `${process.cwd()}/.claude/skills`;
10335
+ const dest = toRaw === "global" ? join46(homedir24(), ".claude", "skills") : `${process.cwd()}/.claude/skills`;
8482
10336
  const filterDesc = users.length === 0 ? "all users" : users.join(", ");
8483
10337
  console.log(`Destination: ${dest}`);
8484
10338
  console.log(`Filter: ${filterDesc}${skillName ? ` \xB7 skill='${skillName}'` : ""}${dryRun ? " \xB7 dry-run" : ""}${force ? " \xB7 force" : ""}`);
@@ -8528,7 +10382,7 @@ async function unpullSkills(args) {
8528
10382
  all,
8529
10383
  legacyCleanup
8530
10384
  });
8531
- const dest = toRaw === "global" ? join38(homedir23(), ".claude", "skills") : `${process.cwd()}/.claude/skills`;
10385
+ const dest = toRaw === "global" ? join46(homedir24(), ".claude", "skills") : `${process.cwd()}/.claude/skills`;
8532
10386
  const filterParts = [];
8533
10387
  if (users.length > 0)
8534
10388
  filterParts.push(`users=${users.join(",")}`);
@@ -8623,15 +10477,15 @@ if (process.argv[1] && process.argv[1].endsWith("skillify.js")) {
8623
10477
  }
8624
10478
 
8625
10479
  // dist/src/cli/update.js
8626
- import { execFileSync as execFileSync4 } from "node:child_process";
8627
- import { closeSync as closeSync3, existsSync as existsSync31, mkdirSync as mkdirSync18, openSync as openSync3, readFileSync as readFileSync28, realpathSync, unlinkSync as unlinkSync12, writeSync as writeSync2 } from "node:fs";
8628
- import { homedir as homedir24 } from "node:os";
8629
- import { dirname as dirname13, join as join40, 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";
8630
10484
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8631
10485
 
8632
10486
  // dist/src/utils/version-check.js
8633
- import { readFileSync as readFileSync27 } from "node:fs";
8634
- import { dirname as dirname12, join as join39 } from "node:path";
10487
+ import { readFileSync as readFileSync33 } from "node:fs";
10488
+ import { dirname as dirname18, join as join47 } from "node:path";
8635
10489
  function isNewer(latest, current) {
8636
10490
  const parse = (v) => v.split(".").map(Number);
8637
10491
  const [la, lb, lc] = parse(latest);
@@ -8643,7 +10497,7 @@ function isNewer(latest, current) {
8643
10497
  var NPM_REGISTRY_URL = "https://registry.npmjs.org/@deeplake/hivemind/latest";
8644
10498
  var PKG_NAME = "@deeplake/hivemind";
8645
10499
  function defaultLockPath() {
8646
- return join40(homedir24(), ".deeplake", "hivemind-update.lock");
10500
+ return join48(homedir25(), ".deeplake", "hivemind-update.lock");
8647
10501
  }
8648
10502
  function detectInstallKind(argv1) {
8649
10503
  const realArgv1 = (() => {
@@ -8653,36 +10507,36 @@ function detectInstallKind(argv1) {
8653
10507
  return argv1 ?? process.argv[1] ?? fileURLToPath2(import.meta.url);
8654
10508
  }
8655
10509
  })();
8656
- let dir = dirname13(realArgv1);
10510
+ let dir = dirname19(realArgv1);
8657
10511
  let installDir = null;
8658
10512
  for (let i = 0; i < 10; i++) {
8659
- const pkgPath = `${dir}${sep}package.json`;
10513
+ const pkgPath = `${dir}${sep2}package.json`;
8660
10514
  try {
8661
- const pkg = JSON.parse(readFileSync28(pkgPath, "utf-8"));
10515
+ const pkg = JSON.parse(readFileSync34(pkgPath, "utf-8"));
8662
10516
  if (pkg.name === PKG_NAME || pkg.name === "hivemind") {
8663
10517
  installDir = dir;
8664
10518
  break;
8665
10519
  }
8666
10520
  } catch {
8667
10521
  }
8668
- const parent = dirname13(dir);
10522
+ const parent = dirname19(dir);
8669
10523
  if (parent === dir)
8670
10524
  break;
8671
10525
  dir = parent;
8672
10526
  }
8673
- installDir ??= dirname13(realArgv1);
8674
- 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}`)) {
8675
10529
  return { kind: "npx", installDir };
8676
10530
  }
8677
- 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`)) {
8678
10532
  return { kind: "npm-global", installDir };
8679
10533
  }
8680
10534
  let gitDir = installDir;
8681
10535
  for (let i = 0; i < 6; i++) {
8682
- if (existsSync31(`${gitDir}${sep}.git`)) {
10536
+ if (existsSync37(`${gitDir}${sep2}.git`)) {
8683
10537
  return { kind: "local-dev", installDir };
8684
10538
  }
8685
- const parent = dirname13(gitDir);
10539
+ const parent = dirname19(gitDir);
8686
10540
  if (parent === gitDir)
8687
10541
  break;
8688
10542
  gitDir = parent;
@@ -8701,10 +10555,10 @@ async function getLatestNpmVersion(timeoutMs = 5e3) {
8701
10555
  }
8702
10556
  }
8703
10557
  var defaultSpawn = (cmd, args) => {
8704
- execFileSync4(cmd, args, { stdio: "inherit" });
10558
+ execFileSync6(cmd, args, { stdio: "inherit" });
8705
10559
  };
8706
10560
  function tryAcquireLock(path) {
8707
- mkdirSync18(dirname13(path), { recursive: true, mode: 448 });
10561
+ mkdirSync24(dirname19(path), { recursive: true, mode: 448 });
8708
10562
  const claim = () => {
8709
10563
  const fd = openSync3(path, "wx", 384);
8710
10564
  writeSync2(fd, String(process.pid));
@@ -8718,7 +10572,7 @@ function tryAcquireLock(path) {
8718
10572
  }
8719
10573
  let holderPid = 0;
8720
10574
  try {
8721
- holderPid = Number(readFileSync28(path, "utf-8").trim()) || 0;
10575
+ holderPid = Number(readFileSync34(path, "utf-8").trim()) || 0;
8722
10576
  } catch {
8723
10577
  try {
8724
10578
  return claim();
@@ -8735,7 +10589,7 @@ function tryAcquireLock(path) {
8735
10589
  }
8736
10590
  }
8737
10591
  try {
8738
- unlinkSync12(path);
10592
+ unlinkSync13(path);
8739
10593
  } catch {
8740
10594
  }
8741
10595
  try {
@@ -8751,7 +10605,7 @@ function releaseLock(fd, path) {
8751
10605
  } catch {
8752
10606
  }
8753
10607
  try {
8754
- unlinkSync12(path);
10608
+ unlinkSync13(path);
8755
10609
  } catch {
8756
10610
  }
8757
10611
  }
@@ -8857,7 +10711,7 @@ var AUTH_SUBCOMMANDS = /* @__PURE__ */ new Set([
8857
10711
  "autoupdate",
8858
10712
  "sessions"
8859
10713
  ]);
8860
- var USAGE2 = `
10714
+ var USAGE3 = `
8861
10715
  hivemind \u2014 one brain for every agent on your team
8862
10716
 
8863
10717
  Usage:
@@ -8927,6 +10781,22 @@ Semantic search (embeddings):
8927
10781
  Add --with-embeddings to "hivemind install" (or "hivemind <agent> install")
8928
10782
  to run "embeddings install" automatically after installing the agent(s).
8929
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
+
8930
10800
  Skill management (mine + share reusable Claude skills across the org):
8931
10801
  ${renderCliHelpBlock()}
8932
10802
 
@@ -9117,7 +10987,7 @@ async function main() {
9117
10987
  const args = process.argv.slice(2);
9118
10988
  const cmd = args[0];
9119
10989
  if (!cmd || cmd === "--help" || cmd === "-h" || cmd === "help") {
9120
- log(USAGE2);
10990
+ log(USAGE3);
9121
10991
  return;
9122
10992
  }
9123
10993
  if (cmd === "--version" || cmd === "-v" || cmd === "version") {
@@ -9151,6 +11021,10 @@ async function main() {
9151
11021
  runSkillifyCommand(args.slice(1));
9152
11022
  return;
9153
11023
  }
11024
+ if (cmd === "graph") {
11025
+ await runGraphCommand(args.slice(1));
11026
+ return;
11027
+ }
9154
11028
  if (cmd === "dashboard") {
9155
11029
  const code = await runDashboardCommand(args.slice(1));
9156
11030
  process.exit(code);
@@ -9202,7 +11076,7 @@ async function main() {
9202
11076
  return;
9203
11077
  }
9204
11078
  warn(`Unknown command: ${cmd}`);
9205
- log(USAGE2);
11079
+ log(USAGE3);
9206
11080
  process.exit(1);
9207
11081
  }
9208
11082
  main().catch((err) => {