@deeplake/hivemind 0.7.44 → 0.7.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/bundle/cli.js +3116 -208
  4. package/codex/bundle/capture.js +43 -0
  5. package/codex/bundle/commands/auth-login.js +43 -0
  6. package/codex/bundle/graph-pull-worker.js +1185 -0
  7. package/codex/bundle/pre-tool-use.js +43 -0
  8. package/codex/bundle/session-start-setup.js +43 -0
  9. package/codex/bundle/session-start.js +70 -4
  10. package/codex/bundle/shell/deeplake-shell.js +577 -25
  11. package/codex/bundle/skillify-worker.js +30 -3
  12. package/codex/bundle/stop.js +97 -50
  13. package/cursor/bundle/capture.js +97 -50
  14. package/cursor/bundle/commands/auth-login.js +43 -0
  15. package/cursor/bundle/graph-pull-worker.js +1185 -0
  16. package/cursor/bundle/pre-tool-use.js +43 -0
  17. package/cursor/bundle/session-end.js +49 -44
  18. package/cursor/bundle/session-start.js +66 -0
  19. package/cursor/bundle/shell/deeplake-shell.js +577 -25
  20. package/cursor/bundle/skillify-worker.js +30 -3
  21. package/hermes/bundle/capture.js +97 -50
  22. package/hermes/bundle/commands/auth-login.js +43 -0
  23. package/hermes/bundle/graph-pull-worker.js +1185 -0
  24. package/hermes/bundle/pre-tool-use.js +43 -0
  25. package/hermes/bundle/session-end.js +49 -44
  26. package/hermes/bundle/session-start.js +66 -0
  27. package/hermes/bundle/shell/deeplake-shell.js +577 -25
  28. package/hermes/bundle/skillify-worker.js +30 -3
  29. package/mcp/bundle/server.js +43 -0
  30. package/openclaw/dist/chunks/{config-XEK4MJJS.js → config-O5PDJQ7Y.js} +1 -0
  31. package/openclaw/dist/index.js +47 -2
  32. package/openclaw/dist/skillify-worker.js +30 -3
  33. package/openclaw/openclaw.plugin.json +1 -1
  34. package/openclaw/package.json +1 -1
  35. package/package.json +3 -1
@@ -46081,14 +46081,14 @@ var require_turndown_cjs = __commonJS({
46081
46081
  } else if (node.nodeType === 1) {
46082
46082
  replacement = replacementForNode.call(self2, node);
46083
46083
  }
46084
- return join14(output, replacement);
46084
+ return join18(output, replacement);
46085
46085
  }, "");
46086
46086
  }
46087
46087
  function postProcess(output) {
46088
46088
  var self2 = this;
46089
46089
  this.rules.forEach(function(rule) {
46090
46090
  if (typeof rule.append === "function") {
46091
- output = join14(output, rule.append(self2.options));
46091
+ output = join18(output, rule.append(self2.options));
46092
46092
  }
46093
46093
  });
46094
46094
  return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
@@ -46100,7 +46100,7 @@ var require_turndown_cjs = __commonJS({
46100
46100
  if (whitespace.leading || whitespace.trailing) content = content.trim();
46101
46101
  return whitespace.leading + rule.replacement(content, node, this.options) + whitespace.trailing;
46102
46102
  }
46103
- function join14(output, replacement) {
46103
+ function join18(output, replacement) {
46104
46104
  var s12 = trimTrailingNewlines(output);
46105
46105
  var s22 = trimLeadingNewlines(replacement);
46106
46106
  var nls = Math.max(output.length - s12.length, replacement.length - s22.length);
@@ -66792,6 +66792,7 @@ function loadConfig() {
66792
66792
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
66793
66793
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
66794
66794
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
66795
+ codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
66795
66796
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join4(home, ".deeplake", "memory")
66796
66797
  };
66797
66798
  }
@@ -66909,9 +66910,33 @@ function validateSchema(label, cols) {
66909
66910
  }
66910
66911
  }
66911
66912
  }
66913
+ var CODEBASE_COLUMNS = Object.freeze([
66914
+ // Identity key (matches the PK below)
66915
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
66916
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
66917
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
66918
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
66919
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
66920
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
66921
+ // Observation metadata
66922
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
66923
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
66924
+ { name: "ts", sql: "TIMESTAMP" },
66925
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
66926
+ // Snapshot payload
66927
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
66928
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
66929
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
66930
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
66931
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
66932
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
66933
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
66934
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
66935
+ ]);
66912
66936
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
66913
66937
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
66914
66938
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
66939
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
66915
66940
  function buildCreateTableSql(tableName, cols) {
66916
66941
  const safe = sqlIdent(tableName);
66917
66942
  const colSql = cols.map((c15) => `${c15.name} ${c15.sql}`).join(", ");
@@ -67136,7 +67161,7 @@ function getQueryTimeoutMs() {
67136
67161
  return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
67137
67162
  }
67138
67163
  function sleep2(ms3) {
67139
- return new Promise((resolve6) => setTimeout(resolve6, ms3));
67164
+ return new Promise((resolve7) => setTimeout(resolve7, ms3));
67140
67165
  }
67141
67166
  function isTimeoutError(error) {
67142
67167
  const name = error instanceof Error ? error.name.toLowerCase() : "";
@@ -67166,7 +67191,7 @@ var Semaphore = class {
67166
67191
  this.active++;
67167
67192
  return;
67168
67193
  }
67169
- await new Promise((resolve6) => this.waiting.push(resolve6));
67194
+ await new Promise((resolve7) => this.waiting.push(resolve7));
67170
67195
  }
67171
67196
  release() {
67172
67197
  this.active--;
@@ -67476,6 +67501,24 @@ var DeeplakeApi = class {
67476
67501
  * This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
67477
67502
  * worker.
67478
67503
  */
67504
+ /**
67505
+ * Create the codebase table. One row per (org, workspace, repo, user,
67506
+ * worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
67507
+ * + index follow the same pattern as ensureSessionsTable.
67508
+ */
67509
+ async ensureCodebaseTable(name) {
67510
+ const safe = sqlIdent(name);
67511
+ const tables = await this.listTables();
67512
+ if (!tables.includes(safe)) {
67513
+ log3(`table "${safe}" not found, creating`);
67514
+ await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
67515
+ log3(`table "${safe}" created`);
67516
+ if (!tables.includes(safe))
67517
+ this._tablesCache = [...tables, safe];
67518
+ }
67519
+ await this.healSchema(safe, CODEBASE_COLUMNS);
67520
+ await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
67521
+ }
67479
67522
  async ensureSkillsTable(name) {
67480
67523
  const safe = sqlIdent(name);
67481
67524
  const tables = await this.listTables();
@@ -67492,10 +67535,10 @@ var DeeplakeApi = class {
67492
67535
  };
67493
67536
 
67494
67537
  // dist/src/shell/deeplake-fs.js
67495
- import { basename as basename4, posix } from "node:path";
67538
+ import { basename as basename5, posix } from "node:path";
67496
67539
  import { randomUUID as randomUUID2 } from "node:crypto";
67497
67540
  import { fileURLToPath } from "node:url";
67498
- import { dirname as dirname5, join as join12 } from "node:path";
67541
+ import { dirname as dirname9, join as join16 } from "node:path";
67499
67542
 
67500
67543
  // dist/src/shell/grep-core.js
67501
67544
  var TOOL_INPUT_FIELDS = [
@@ -68176,7 +68219,7 @@ var EmbedClient = class {
68176
68219
  }
68177
68220
  }
68178
68221
  connectOnce() {
68179
- return new Promise((resolve6, reject) => {
68222
+ return new Promise((resolve7, reject) => {
68180
68223
  const sock = connect(this.socketPath);
68181
68224
  const to3 = setTimeout(() => {
68182
68225
  sock.destroy();
@@ -68184,7 +68227,7 @@ var EmbedClient = class {
68184
68227
  }, this.timeoutMs);
68185
68228
  sock.once("connect", () => {
68186
68229
  clearTimeout(to3);
68187
- resolve6(sock);
68230
+ resolve7(sock);
68188
68231
  });
68189
68232
  sock.once("error", (e6) => {
68190
68233
  clearTimeout(to3);
@@ -68266,7 +68309,7 @@ var EmbedClient = class {
68266
68309
  throw new Error("daemon did not become ready within spawnWaitMs");
68267
68310
  }
68268
68311
  sendAndWait(sock, req) {
68269
- return new Promise((resolve6, reject) => {
68312
+ return new Promise((resolve7, reject) => {
68270
68313
  let buf = "";
68271
68314
  const to3 = setTimeout(() => {
68272
68315
  sock.destroy();
@@ -68281,7 +68324,7 @@ var EmbedClient = class {
68281
68324
  const line = buf.slice(0, nl3);
68282
68325
  clearTimeout(to3);
68283
68326
  try {
68284
- resolve6(JSON.parse(line));
68327
+ resolve7(JSON.parse(line));
68285
68328
  } catch (e6) {
68286
68329
  reject(e6);
68287
68330
  }
@@ -68501,6 +68544,440 @@ function buildVirtualIndexContent(summaryRows, sessionRows = [], opts = {}) {
68501
68544
  return lines.join("\n");
68502
68545
  }
68503
68546
 
68547
+ // dist/src/graph/vfs-handler.js
68548
+ import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync9, renameSync as renameSync5, writeFileSync as writeFileSync7 } from "node:fs";
68549
+ import { createHash as createHash3 } from "node:crypto";
68550
+ import { join as join15, dirname as dirname8 } from "node:path";
68551
+
68552
+ // dist/src/graph/last-build.js
68553
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync7, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "node:fs";
68554
+ import { dirname as dirname5, join as join12 } from "node:path";
68555
+ function lastBuildPath(baseDir, worktreeId) {
68556
+ if (worktreeId !== void 0) {
68557
+ return join12(baseDir, "worktrees", worktreeId, ".last-build.json");
68558
+ }
68559
+ return join12(baseDir, ".last-build.json");
68560
+ }
68561
+ function readLastBuild(baseDir, worktreeId) {
68562
+ let path2 = lastBuildPath(baseDir, worktreeId);
68563
+ if (!existsSync6(path2)) {
68564
+ if (worktreeId === void 0)
68565
+ return null;
68566
+ const legacy = lastBuildPath(baseDir, void 0);
68567
+ if (!existsSync6(legacy))
68568
+ return null;
68569
+ path2 = legacy;
68570
+ }
68571
+ let raw;
68572
+ try {
68573
+ raw = readFileSync7(path2, "utf8");
68574
+ } catch {
68575
+ return null;
68576
+ }
68577
+ let parsed;
68578
+ try {
68579
+ parsed = JSON.parse(raw);
68580
+ } catch {
68581
+ return null;
68582
+ }
68583
+ if (parsed === null || typeof parsed !== "object")
68584
+ return null;
68585
+ const o14 = parsed;
68586
+ if (typeof o14.ts !== "number" || !Number.isFinite(o14.ts))
68587
+ return null;
68588
+ if (o14.commit_sha !== null && typeof o14.commit_sha !== "string")
68589
+ return null;
68590
+ if (typeof o14.snapshot_sha256 !== "string")
68591
+ return null;
68592
+ const out = { ts: o14.ts, commit_sha: o14.commit_sha, snapshot_sha256: o14.snapshot_sha256 };
68593
+ if (typeof o14.node_count === "number" && Number.isFinite(o14.node_count) && o14.node_count >= 0) {
68594
+ out.node_count = o14.node_count;
68595
+ }
68596
+ if (typeof o14.edge_count === "number" && Number.isFinite(o14.edge_count) && o14.edge_count >= 0) {
68597
+ out.edge_count = o14.edge_count;
68598
+ }
68599
+ return out;
68600
+ }
68601
+
68602
+ // dist/src/graph/snapshot.js
68603
+ import { createHash } from "node:crypto";
68604
+ import { mkdirSync as mkdirSync7, renameSync as renameSync4, writeFileSync as writeFileSync6 } from "node:fs";
68605
+ import { homedir as homedir8 } from "node:os";
68606
+ import { dirname as dirname7, join as join14 } from "node:path";
68607
+
68608
+ // dist/src/graph/history.js
68609
+ import { appendFileSync as appendFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "node:fs";
68610
+ import { dirname as dirname6, join as join13 } from "node:path";
68611
+
68612
+ // dist/src/graph/snapshot.js
68613
+ function graphsRoot() {
68614
+ return process.env.HIVEMIND_GRAPHS_HOME ?? join14(homedir8(), ".hivemind", "graphs");
68615
+ }
68616
+ function repoDir(repoKey) {
68617
+ return join14(graphsRoot(), repoKey);
68618
+ }
68619
+
68620
+ // dist/src/utils/repo-identity.js
68621
+ import { execSync } from "node:child_process";
68622
+ import { createHash as createHash2 } from "node:crypto";
68623
+ import { basename as basename4, resolve as resolve5 } from "node:path";
68624
+ var DEFAULT_PORTS = {
68625
+ http: "80",
68626
+ https: "443",
68627
+ ssh: "22",
68628
+ git: "9418"
68629
+ };
68630
+ function normalizeGitRemoteUrl(url) {
68631
+ let s10 = url.trim();
68632
+ const schemeMatch = s10.match(/^([a-z][a-z0-9+.-]*):\/\//i);
68633
+ const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null;
68634
+ if (schemeMatch)
68635
+ s10 = s10.slice(schemeMatch[0].length);
68636
+ if (!scheme) {
68637
+ const scp = s10.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);
68638
+ if (scp)
68639
+ s10 = `${scp[1]}/${scp[2]}`;
68640
+ }
68641
+ s10 = s10.replace(/^[^@/]+@/, "");
68642
+ if (scheme && DEFAULT_PORTS[scheme]) {
68643
+ s10 = s10.replace(new RegExp(`^([^/]+):${DEFAULT_PORTS[scheme]}(/|$)`), "$1$2");
68644
+ }
68645
+ s10 = s10.replace(/\.git\/?$/i, "");
68646
+ s10 = s10.replace(/\/+$/, "");
68647
+ return s10.toLowerCase();
68648
+ }
68649
+ function deriveProjectKey(cwd) {
68650
+ const absCwd = resolve5(cwd);
68651
+ const project = basename4(absCwd) || "unknown";
68652
+ let signature = null;
68653
+ try {
68654
+ const raw = execSync("git config --get remote.origin.url", {
68655
+ cwd: absCwd,
68656
+ encoding: "utf-8",
68657
+ stdio: ["ignore", "pipe", "ignore"]
68658
+ }).trim();
68659
+ signature = raw ? normalizeGitRemoteUrl(raw) : null;
68660
+ } catch {
68661
+ }
68662
+ const input = signature ?? absCwd;
68663
+ const key = createHash2("sha1").update(input).digest("hex").slice(0, 16);
68664
+ return { key, project };
68665
+ }
68666
+
68667
+ // dist/src/graph/vfs-handler.js
68668
+ function workTreeIdFor(cwd) {
68669
+ return createHash3("sha256").update(cwd).digest("hex").slice(0, 16);
68670
+ }
68671
+ function handleGraphVfs(subpath, cwd) {
68672
+ const path2 = subpath.replace(/^\/+/, "");
68673
+ if (path2 === "" || path2 === "/") {
68674
+ return { kind: "ok", body: dirListing() };
68675
+ }
68676
+ if (path2 === "index.md" || path2 === "index") {
68677
+ return loadSnapshotOrError(cwd, (snap, baseDir) => ({
68678
+ kind: "ok",
68679
+ body: renderIndex(snap, baseDir, cwd)
68680
+ }));
68681
+ }
68682
+ if (path2.startsWith("find/")) {
68683
+ const pattern = path2.slice("find/".length);
68684
+ if (pattern === "") {
68685
+ return { kind: "not-found", message: "find/ requires a pattern: cat memory/graph/find/<keyword>" };
68686
+ }
68687
+ return loadSnapshotOrError(cwd, (snap, baseDir) => ({
68688
+ kind: "ok",
68689
+ body: renderFind(snap, pattern, baseDir, workTreeIdFor(cwd))
68690
+ }));
68691
+ }
68692
+ if (path2.startsWith("show/")) {
68693
+ const key = path2.slice("show/".length);
68694
+ if (key === "") {
68695
+ return { kind: "not-found", message: "show/ requires a handle or pattern" };
68696
+ }
68697
+ return loadSnapshotOrError(cwd, (snap, baseDir) => ({
68698
+ kind: "ok",
68699
+ body: renderShow(snap, key, baseDir, workTreeIdFor(cwd))
68700
+ }));
68701
+ }
68702
+ return {
68703
+ kind: "not-found",
68704
+ message: `Unknown endpoint: graph/${path2}
68705
+ Available: index.md, find/<pattern>, show/<handle-or-pattern>`
68706
+ };
68707
+ }
68708
+ function loadSnapshotOrError(cwd, fn4) {
68709
+ let key;
68710
+ let baseDir;
68711
+ try {
68712
+ key = deriveProjectKey(cwd).key;
68713
+ baseDir = repoDir(key);
68714
+ } catch (e6) {
68715
+ return { kind: "no-graph", message: `Cannot derive repo identity: ${e6 instanceof Error ? e6.message : String(e6)}` };
68716
+ }
68717
+ const wt3 = workTreeIdFor(cwd);
68718
+ const last = readLastBuild(baseDir, wt3);
68719
+ if (last === null) {
68720
+ return {
68721
+ kind: "no-graph",
68722
+ message: "No local graph for this worktree yet. Run `hivemind graph build` (or `hivemind graph pull` if a teammate has built this commit)."
68723
+ };
68724
+ }
68725
+ const fileBase = last.commit_sha ?? last.snapshot_sha256;
68726
+ const snapPath = join15(baseDir, "snapshots", `${fileBase}.json`);
68727
+ if (!existsSync8(snapPath)) {
68728
+ return { kind: "no-graph", message: `Snapshot file missing on disk: ${snapPath}` };
68729
+ }
68730
+ let snap;
68731
+ try {
68732
+ snap = JSON.parse(readFileSync9(snapPath, "utf8"));
68733
+ } catch (e6) {
68734
+ return { kind: "no-graph", message: `Failed to parse snapshot: ${e6 instanceof Error ? e6.message : String(e6)}` };
68735
+ }
68736
+ if (!Array.isArray(snap.nodes) || !Array.isArray(snap.links)) {
68737
+ return { kind: "no-graph", message: "Snapshot schema is invalid (missing nodes/links arrays)." };
68738
+ }
68739
+ try {
68740
+ return fn4(snap, baseDir);
68741
+ } catch (e6) {
68742
+ return { kind: "no-graph", message: `Failed to render graph view: ${e6 instanceof Error ? e6.message : String(e6)}` };
68743
+ }
68744
+ }
68745
+ function dirListing() {
68746
+ return [
68747
+ "index.md",
68748
+ "find/",
68749
+ "show/"
68750
+ ].join("\n");
68751
+ }
68752
+ function renderIndex(snap, baseDir, cwd) {
68753
+ const commit = snap.graph.commit_sha?.slice(0, 7) ?? "no-commit";
68754
+ const fullCommit = snap.graph.commit_sha ?? "no-commit";
68755
+ const totalNodes = snap.nodes.length;
68756
+ const totalEdges = snap.links.length;
68757
+ const byFile = {};
68758
+ for (const n24 of snap.nodes)
68759
+ byFile[n24.source_file] = (byFile[n24.source_file] ?? 0) + 1;
68760
+ const topFiles = Object.entries(byFile).sort(([, a15], [, b26]) => b26 - a15).slice(0, 8);
68761
+ const byRel = {};
68762
+ for (const e6 of snap.links)
68763
+ byRel[e6.relation] = (byRel[e6.relation] ?? 0) + 1;
68764
+ const byKind = {};
68765
+ for (const n24 of snap.nodes)
68766
+ byKind[n24.kind] = (byKind[n24.kind] ?? 0) + 1;
68767
+ const lines = [];
68768
+ lines.push(`# Code Graph \u2014 ${snap.observation.repo_project}`);
68769
+ lines.push("");
68770
+ lines.push(`Commit: ${fullCommit} (built ${snap.observation.ts})`);
68771
+ lines.push(`Branch: ${snap.observation.branch ?? "(detached)"}`);
68772
+ lines.push(`Source: ${join15(baseDir, "snapshots", `${commit ? snap.graph.commit_sha : "?"}.json`)}`);
68773
+ lines.push("");
68774
+ lines.push(`Nodes: ${totalNodes} Edges: ${totalEdges}`);
68775
+ lines.push("");
68776
+ lines.push("## How to query");
68777
+ lines.push(" cat ~/.deeplake/memory/graph/find/<pattern>");
68778
+ lines.push(" Case-insensitive substring match on node id + label.");
68779
+ lines.push(" Emits numbered handles [1] [2] ... saved for this worktree.");
68780
+ lines.push("");
68781
+ lines.push(" cat ~/.deeplake/memory/graph/show/<handle-or-pattern>");
68782
+ lines.push(" <handle>: a digit from a prior `find/` (e.g. 3).");
68783
+ lines.push(" <pattern>: a substring; resolves to a unique node if possible,");
68784
+ lines.push(" or shows candidates if ambiguous.");
68785
+ lines.push(" Output: node detail + 1-hop neighbors grouped by edge kind.");
68786
+ lines.push("");
68787
+ lines.push("## Node kinds");
68788
+ for (const [k17, n24] of Object.entries(byKind).sort(([, a15], [, b26]) => b26 - a15)) {
68789
+ lines.push(` ${k17.padEnd(12)} ${n24}`);
68790
+ }
68791
+ lines.push("");
68792
+ lines.push("## Edge kinds");
68793
+ for (const [k17, n24] of Object.entries(byRel).sort(([, a15], [, b26]) => b26 - a15)) {
68794
+ lines.push(` ${k17.padEnd(12)} ${n24}`);
68795
+ }
68796
+ lines.push("");
68797
+ lines.push("## Top files by node count");
68798
+ for (const [f11, n24] of topFiles) {
68799
+ lines.push(` ${String(n24).padStart(4)} ${f11}`);
68800
+ }
68801
+ lines.push("");
68802
+ lines.push(`Limitations:`);
68803
+ lines.push(` - TypeScript only. AST-based, no semantic similarity edges.`);
68804
+ lines.push(` - 'calls' edges are intra-file only (Phase 1 extractor doesn't resolve cross-file).`);
68805
+ lines.push(` A node showing "Incoming (0)" may still have callers in OTHER files \u2014`);
68806
+ lines.push(` treat it as "no callers in the same file", not "unused".`);
68807
+ lines.push(` - 'imports' edges are file-level and DO span files; trust them.`);
68808
+ lines.push(` - Stale after edits \u2014 if a file's mtime is newer than the build, read the live source.`);
68809
+ void cwd;
68810
+ return lines.join("\n");
68811
+ }
68812
+ function renderFind(snap, pattern, baseDir, worktreeId) {
68813
+ const needle = pattern.toLowerCase();
68814
+ const matches = [];
68815
+ for (const n24 of snap.nodes) {
68816
+ const id = n24.id.toLowerCase();
68817
+ const lbl = n24.label.toLowerCase();
68818
+ if (id.includes(needle) || lbl.includes(needle))
68819
+ matches.push(n24);
68820
+ }
68821
+ matches.sort((a15, b26) => {
68822
+ const ra2 = rank(a15, needle);
68823
+ const rb = rank(b26, needle);
68824
+ if (ra2 !== rb)
68825
+ return ra2 - rb;
68826
+ return a15.id.localeCompare(b26.id);
68827
+ });
68828
+ const capped = matches.slice(0, 50);
68829
+ if (capped.length === 0) {
68830
+ return `No matches for "${pattern}" in ${snap.nodes.length} nodes.
68831
+ Try a shorter or different substring.`;
68832
+ }
68833
+ saveHandles(baseDir, worktreeId, capped.map((n24) => n24.id), pattern);
68834
+ const lines = [];
68835
+ lines.push(`${matches.length} match${matches.length === 1 ? "" : "es"} for "${pattern}"${matches.length > capped.length ? ` (showing first ${capped.length})` : ""}:`);
68836
+ lines.push("");
68837
+ for (let i11 = 0; i11 < capped.length; i11++) {
68838
+ const n24 = capped[i11];
68839
+ const tag = n24.exported ? "exported" : "internal";
68840
+ lines.push(` [${i11 + 1}] ${n24.id} ${n24.kind} (${tag})`);
68841
+ }
68842
+ lines.push("");
68843
+ lines.push("Use: cat ~/.deeplake/memory/graph/show/<N> to see node + 1-hop neighbors");
68844
+ return lines.join("\n");
68845
+ }
68846
+ function renderShow(snap, key, baseDir, worktreeId) {
68847
+ if (/^\d+$/.test(key)) {
68848
+ const idx = parseInt(key, 10);
68849
+ const handles = loadHandles(baseDir, worktreeId);
68850
+ if (handles === null) {
68851
+ return `Handle [${idx}] not resolvable: no recent find/ in this worktree. Run cat memory/graph/find/<pattern> first.`;
68852
+ }
68853
+ if (idx < 1 || idx > handles.ids.length) {
68854
+ return `Handle [${idx}] out of range. Last find/${handles.pattern} produced ${handles.ids.length} matches.`;
68855
+ }
68856
+ const nodeId = handles.ids[idx - 1];
68857
+ const node = snap.nodes.find((n24) => n24.id === nodeId);
68858
+ if (!node) {
68859
+ return `Handle [${idx}] points at "${nodeId}" but that node is no longer in the snapshot (graph rebuilt since last find?). Re-run find.`;
68860
+ }
68861
+ return renderNodeDetail(snap, node);
68862
+ }
68863
+ const needle = key.toLowerCase();
68864
+ const matches = snap.nodes.filter((n24) => n24.id.toLowerCase().includes(needle));
68865
+ if (matches.length === 0) {
68866
+ return `No node matches "${key}". Try cat memory/graph/find/${key} for fuzzy search.`;
68867
+ }
68868
+ if (matches.length === 1) {
68869
+ return renderNodeDetail(snap, matches[0]);
68870
+ }
68871
+ saveHandles(baseDir, worktreeId, matches.slice(0, 50).map((n24) => n24.id), key);
68872
+ const lines = [];
68873
+ lines.push(`"${key}" matches ${matches.length} nodes. Pick one:`);
68874
+ lines.push("");
68875
+ for (let i11 = 0; i11 < Math.min(matches.length, 50); i11++) {
68876
+ lines.push(` [${i11 + 1}] ${matches[i11].id}`);
68877
+ }
68878
+ lines.push("");
68879
+ lines.push("Use: cat ~/.deeplake/memory/graph/show/<N>");
68880
+ return lines.join("\n");
68881
+ }
68882
+ function renderNodeDetail(snap, node) {
68883
+ const incoming = [];
68884
+ const outgoing = [];
68885
+ for (const e6 of snap.links) {
68886
+ if (e6.target === node.id)
68887
+ incoming.push(e6);
68888
+ if (e6.source === node.id)
68889
+ outgoing.push(e6);
68890
+ }
68891
+ const groupBy = (es3) => {
68892
+ const m26 = /* @__PURE__ */ new Map();
68893
+ for (const e6 of es3) {
68894
+ const list = m26.get(e6.relation) ?? [];
68895
+ list.push(e6);
68896
+ m26.set(e6.relation, list);
68897
+ }
68898
+ return m26;
68899
+ };
68900
+ const inGrp = groupBy(incoming);
68901
+ const outGrp = groupBy(outgoing);
68902
+ const lines = [];
68903
+ lines.push(`Node: ${node.id}`);
68904
+ lines.push(` source: ${node.source_file}:${node.source_location}`);
68905
+ lines.push(` kind: ${node.kind}`);
68906
+ lines.push(` label: ${node.label}`);
68907
+ lines.push(` ${node.exported ? "exported" : "internal"}`);
68908
+ lines.push("");
68909
+ const inHint = incoming.length === 0 ? " \u2014 no edges from THIS file (intra-file only; may still be called from other files)" : ":";
68910
+ lines.push(`Incoming (${incoming.length})${inHint}`);
68911
+ for (const [rel, es3] of [...inGrp.entries()].sort(([a15], [b26]) => a15.localeCompare(b26))) {
68912
+ lines.push(` ${rel} (${es3.length}):`);
68913
+ for (const e6 of es3.slice(0, 20)) {
68914
+ lines.push(` ${e6.source}`);
68915
+ }
68916
+ if (es3.length > 20)
68917
+ lines.push(` ... and ${es3.length - 20} more`);
68918
+ }
68919
+ lines.push("");
68920
+ lines.push(`Outgoing (${outgoing.length})${outgoing.length === 0 ? " \u2014 this node has no edges out" : ":"}`);
68921
+ for (const [rel, es3] of [...outGrp.entries()].sort(([a15], [b26]) => a15.localeCompare(b26))) {
68922
+ lines.push(` ${rel} (${es3.length}):`);
68923
+ for (const e6 of es3.slice(0, 20)) {
68924
+ lines.push(` ${e6.target}`);
68925
+ }
68926
+ if (es3.length > 20)
68927
+ lines.push(` ... and ${es3.length - 20} more`);
68928
+ }
68929
+ return lines.join("\n");
68930
+ }
68931
+ function rank(n24, needle) {
68932
+ const lbl = n24.label.toLowerCase();
68933
+ const id = n24.id.toLowerCase();
68934
+ if (lbl === needle)
68935
+ return 0;
68936
+ if (lbl.startsWith(needle))
68937
+ return 1;
68938
+ if (lbl.includes(needle))
68939
+ return 2;
68940
+ if (id.includes(needle))
68941
+ return 3;
68942
+ return 4;
68943
+ }
68944
+ function handlesPath(baseDir, worktreeId) {
68945
+ return join15(baseDir, "worktrees", worktreeId, ".find-handles.json");
68946
+ }
68947
+ function saveHandles(baseDir, worktreeId, ids, pattern) {
68948
+ const path2 = handlesPath(baseDir, worktreeId);
68949
+ const payload = { pattern, ts: Date.now(), ids };
68950
+ try {
68951
+ mkdirSync8(dirname8(path2), { recursive: true });
68952
+ const tmp = `${path2}.tmp.${process.pid}.${Date.now()}`;
68953
+ writeFileSync7(tmp, JSON.stringify(payload));
68954
+ renameSync5(tmp, path2);
68955
+ } catch {
68956
+ }
68957
+ }
68958
+ function loadHandles(baseDir, worktreeId) {
68959
+ const path2 = handlesPath(baseDir, worktreeId);
68960
+ if (!existsSync8(path2))
68961
+ return null;
68962
+ try {
68963
+ const parsed = JSON.parse(readFileSync9(path2, "utf8"));
68964
+ if (parsed === null || typeof parsed !== "object")
68965
+ return null;
68966
+ const o14 = parsed;
68967
+ if (typeof o14.pattern !== "string")
68968
+ return null;
68969
+ if (typeof o14.ts !== "number")
68970
+ return null;
68971
+ if (!Array.isArray(o14.ids))
68972
+ return null;
68973
+ if (!o14.ids.every((s10) => typeof s10 === "string"))
68974
+ return null;
68975
+ return { pattern: o14.pattern, ts: o14.ts, ids: o14.ids };
68976
+ } catch {
68977
+ return null;
68978
+ }
68979
+ }
68980
+
68504
68981
  // dist/src/shell/deeplake-fs.js
68505
68982
  var BATCH_SIZE = 10;
68506
68983
  var PREFETCH_BATCH_SIZE = 50;
@@ -68530,7 +69007,7 @@ function normalizeSessionMessage(path2, message) {
68530
69007
  return normalizeContent(path2, raw);
68531
69008
  }
68532
69009
  function resolveEmbedDaemonPath() {
68533
- return join12(dirname5(fileURLToPath(import.meta.url)), "..", "embeddings", "embed-daemon.js");
69010
+ return join16(dirname9(fileURLToPath(import.meta.url)), "..", "embeddings", "embed-daemon.js");
68534
69011
  }
68535
69012
  function joinSessionMessages(path2, messages) {
68536
69013
  return messages.map((message) => normalizeSessionMessage(path2, message)).join("\n");
@@ -68538,6 +69015,29 @@ function joinSessionMessages(path2, messages) {
68538
69015
  function fsErr(code, msg, path2) {
68539
69016
  return Object.assign(new Error(`${code}: ${msg}, '${path2}'`), { code });
68540
69017
  }
69018
+ var GRAPH_ROOT = "/graph";
69019
+ var GRAPH_PREFIX = "/graph/";
69020
+ var GRAPH_DIRS = /* @__PURE__ */ new Set([GRAPH_ROOT, "/graph/find", "/graph/show"]);
69021
+ function isGraphPath(p22) {
69022
+ return p22 === GRAPH_ROOT || p22.startsWith(GRAPH_PREFIX);
69023
+ }
69024
+ function isGraphDir(p22) {
69025
+ return GRAPH_DIRS.has(p22);
69026
+ }
69027
+ function graphSubpathOf(p22) {
69028
+ if (p22 === GRAPH_ROOT)
69029
+ return "";
69030
+ return p22.slice(GRAPH_PREFIX.length);
69031
+ }
69032
+ function readGraphFile(p22, cwd) {
69033
+ const sub = graphSubpathOf(p22);
69034
+ const r10 = handleGraphVfs(sub, cwd);
69035
+ if (r10.kind === "ok")
69036
+ return r10.body;
69037
+ if (r10.kind === "no-graph")
69038
+ return `(no-graph) ${r10.message}`;
69039
+ throw fsErr("ENOENT", `${r10.message}`, p22);
69040
+ }
68541
69041
  var DeeplakeFs = class _DeeplakeFs {
68542
69042
  client;
68543
69043
  table;
@@ -68639,7 +69139,7 @@ var DeeplakeFs = class _DeeplakeFs {
68639
69139
  this.pending.delete(filePath);
68640
69140
  this.flushed.delete(filePath);
68641
69141
  const parent = parentOf(filePath);
68642
- this.dirs.get(parent)?.delete(basename4(filePath));
69142
+ this.dirs.get(parent)?.delete(basename5(filePath));
68643
69143
  }
68644
69144
  // ── flush / write batching ────────────────────────────────────────────────
68645
69145
  scheduleFlush() {
@@ -68813,6 +69313,11 @@ var DeeplakeFs = class _DeeplakeFs {
68813
69313
  }
68814
69314
  async readFile(path2, _opts) {
68815
69315
  const p22 = normPath(path2);
69316
+ if (isGraphPath(p22)) {
69317
+ if (isGraphDir(p22))
69318
+ throw fsErr("EISDIR", "illegal operation on a directory", p22);
69319
+ return readGraphFile(p22, process.cwd());
69320
+ }
68816
69321
  if (this.dirs.has(p22) && !this.files.has(p22))
68817
69322
  throw fsErr("EISDIR", "illegal operation on a directory", p22);
68818
69323
  if (p22 === "/index.md" && !this.files.has(p22)) {
@@ -68860,13 +69365,13 @@ var DeeplakeFs = class _DeeplakeFs {
68860
69365
  throw fsErr("EISDIR", "illegal operation on a directory", p22);
68861
69366
  const text = typeof content === "string" ? content : Buffer.from(content).toString("utf-8");
68862
69367
  const buf = Buffer.from(text, "utf-8");
68863
- const mime = guessMime(basename4(p22));
69368
+ const mime = guessMime(basename5(p22));
68864
69369
  this.files.set(p22, buf);
68865
69370
  this.meta.set(p22, { size: buf.length, mime, mtime: /* @__PURE__ */ new Date() });
68866
69371
  this.addToTree(p22);
68867
69372
  this.pending.set(p22, {
68868
69373
  path: p22,
68869
- filename: basename4(p22),
69374
+ filename: basename5(p22),
68870
69375
  contentText: text,
68871
69376
  mimeType: mime,
68872
69377
  sizeBytes: buf.length,
@@ -68885,13 +69390,13 @@ var DeeplakeFs = class _DeeplakeFs {
68885
69390
  throw fsErr("EISDIR", "illegal operation on a directory", p22);
68886
69391
  const text = typeof content === "string" ? content : Buffer.from(content).toString("utf-8");
68887
69392
  const buf = Buffer.from(text, "utf-8");
68888
- const mime = guessMime(basename4(p22));
69393
+ const mime = guessMime(basename5(p22));
68889
69394
  this.files.set(p22, buf);
68890
69395
  this.meta.set(p22, { size: buf.length, mime, mtime: /* @__PURE__ */ new Date() });
68891
69396
  this.addToTree(p22);
68892
69397
  this.pending.set(p22, {
68893
69398
  path: p22,
68894
- filename: basename4(p22),
69399
+ filename: basename5(p22),
68895
69400
  contentText: text,
68896
69401
  mimeType: mime,
68897
69402
  sizeBytes: buf.length
@@ -68925,10 +69430,33 @@ var DeeplakeFs = class _DeeplakeFs {
68925
69430
  const p22 = normPath(path2);
68926
69431
  if (p22 === "/index.md")
68927
69432
  return true;
69433
+ if (isGraphPath(p22)) {
69434
+ if (isGraphDir(p22))
69435
+ return true;
69436
+ const r10 = handleGraphVfs(graphSubpathOf(p22), process.cwd());
69437
+ return r10.kind === "ok" || r10.kind === "no-graph";
69438
+ }
68928
69439
  return this.files.has(p22) || this.dirs.has(p22);
68929
69440
  }
68930
69441
  async stat(path2) {
68931
69442
  const p22 = normPath(path2);
69443
+ if (isGraphPath(p22)) {
69444
+ if (!isGraphDir(p22)) {
69445
+ const r10 = handleGraphVfs(graphSubpathOf(p22), process.cwd());
69446
+ if (r10.kind === "not-found")
69447
+ throw fsErr("ENOENT", "no such file or directory", p22);
69448
+ }
69449
+ const dir = isGraphDir(p22);
69450
+ return {
69451
+ isFile: !dir,
69452
+ isDirectory: dir,
69453
+ isSymbolicLink: false,
69454
+ mode: dir ? 493 : 420,
69455
+ size: 0,
69456
+ // synthesized; cheaper than computing the body just to size it
69457
+ mtime: /* @__PURE__ */ new Date()
69458
+ };
69459
+ }
68932
69460
  const isFile = this.files.has(p22);
68933
69461
  const isDir = this.dirs.has(p22);
68934
69462
  if (p22 === "/index.md" && !isFile && !isDir) {
@@ -68973,6 +69501,14 @@ var DeeplakeFs = class _DeeplakeFs {
68973
69501
  const p22 = normPath(path2);
68974
69502
  if (p22 === "/index.md")
68975
69503
  return p22;
69504
+ if (isGraphPath(p22)) {
69505
+ if (isGraphDir(p22))
69506
+ return p22;
69507
+ const r10 = handleGraphVfs(graphSubpathOf(p22), process.cwd());
69508
+ if (r10.kind === "ok" || r10.kind === "no-graph")
69509
+ return p22;
69510
+ throw fsErr("ENOENT", "no such file or directory", p22);
69511
+ }
68976
69512
  if (!this.files.has(p22) && !this.dirs.has(p22))
68977
69513
  throw fsErr("ENOENT", "no such file or directory", p22);
68978
69514
  return p22;
@@ -68996,16 +69532,24 @@ var DeeplakeFs = class _DeeplakeFs {
68996
69532
  const parent = parentOf(p22);
68997
69533
  if (!this.dirs.has(parent))
68998
69534
  this.dirs.set(parent, /* @__PURE__ */ new Set());
68999
- this.dirs.get(parent).add(basename4(p22));
69535
+ this.dirs.get(parent).add(basename5(p22));
69000
69536
  }
69001
69537
  async readdir(path2) {
69002
69538
  const p22 = normPath(path2);
69539
+ if (p22 === GRAPH_ROOT)
69540
+ return ["index.md", "find", "show"];
69541
+ if (p22 === "/graph/find" || p22 === "/graph/show") {
69542
+ return [];
69543
+ }
69003
69544
  if (!this.dirs.has(p22))
69004
69545
  throw fsErr("ENOTDIR", "not a directory", p22);
69005
69546
  const entries = [...this.dirs.get(p22) ?? []];
69006
69547
  if (p22 === "/" && !entries.includes("index.md")) {
69007
69548
  entries.push("index.md");
69008
69549
  }
69550
+ if (p22 === "/" && !entries.includes("graph")) {
69551
+ entries.push("graph");
69552
+ }
69009
69553
  return entries;
69010
69554
  }
69011
69555
  async readdirWithFileTypes(path2) {
@@ -69013,6 +69557,14 @@ var DeeplakeFs = class _DeeplakeFs {
69013
69557
  const p22 = normPath(path2);
69014
69558
  return names.map((name) => {
69015
69559
  const child = p22 === "/" ? `/${name}` : `${p22}/${name}`;
69560
+ if (isGraphPath(child)) {
69561
+ return {
69562
+ name,
69563
+ isFile: !isGraphDir(child),
69564
+ isDirectory: isGraphDir(child),
69565
+ isSymbolicLink: false
69566
+ };
69567
+ }
69016
69568
  return {
69017
69569
  name,
69018
69570
  isFile: (this.files.has(child) || child === "/index.md") && !this.dirs.has(child),
@@ -69051,7 +69603,7 @@ var DeeplakeFs = class _DeeplakeFs {
69051
69603
  for (const fp of safeToDelete)
69052
69604
  this.removeFromTree(fp);
69053
69605
  this.dirs.delete(p22);
69054
- this.dirs.get(parentOf(p22))?.delete(basename4(p22));
69606
+ this.dirs.get(parentOf(p22))?.delete(basename5(p22));
69055
69607
  if (safeToDelete.length > 0) {
69056
69608
  const inList = safeToDelete.map((fp) => `'${sqlStr(fp)}'`).join(", ");
69057
69609
  await this.client.query(`DELETE FROM "${this.table}" WHERE path IN (${inList})`);
@@ -69096,7 +69648,7 @@ var DeeplakeFs = class _DeeplakeFs {
69096
69648
 
69097
69649
  // node_modules/yargs-parser/build/lib/index.js
69098
69650
  import { format } from "util";
69099
- import { normalize, resolve as resolve5 } from "path";
69651
+ import { normalize, resolve as resolve6 } from "path";
69100
69652
 
69101
69653
  // node_modules/yargs-parser/build/lib/string-utils.js
69102
69654
  function camelCase2(str) {
@@ -70034,7 +70586,7 @@ function stripQuotes(val) {
70034
70586
  }
70035
70587
 
70036
70588
  // node_modules/yargs-parser/build/lib/index.js
70037
- import { readFileSync as readFileSync7 } from "fs";
70589
+ import { readFileSync as readFileSync10 } from "fs";
70038
70590
  import { createRequire as createRequire2 } from "node:module";
70039
70591
  var _a3;
70040
70592
  var _b;
@@ -70056,12 +70608,12 @@ var parser = new YargsParser({
70056
70608
  },
70057
70609
  format,
70058
70610
  normalize,
70059
- resolve: resolve5,
70611
+ resolve: resolve6,
70060
70612
  require: (path2) => {
70061
70613
  if (typeof require2 !== "undefined") {
70062
70614
  return require2(path2);
70063
70615
  } else if (path2.match(/\.json$/)) {
70064
- return JSON.parse(readFileSync7(path2, "utf8"));
70616
+ return JSON.parse(readFileSync10(path2, "utf8"));
70065
70617
  } else {
70066
70618
  throw Error("only .json config files are supported in ESM");
70067
70619
  }
@@ -70081,11 +70633,11 @@ var lib_default = yargsParser;
70081
70633
 
70082
70634
  // dist/src/shell/grep-interceptor.js
70083
70635
  import { fileURLToPath as fileURLToPath2 } from "node:url";
70084
- import { dirname as dirname6, join as join13 } from "node:path";
70636
+ import { dirname as dirname10, join as join17 } from "node:path";
70085
70637
  var SEMANTIC_SEARCH_ENABLED = process.env.HIVEMIND_SEMANTIC_SEARCH !== "false" && !embeddingsDisabled();
70086
70638
  var SEMANTIC_EMBED_TIMEOUT_MS = Number(process.env.HIVEMIND_SEMANTIC_EMBED_TIMEOUT_MS ?? "500");
70087
70639
  function resolveGrepEmbedDaemonPath() {
70088
- return join13(dirname6(fileURLToPath2(import.meta.url)), "..", "embeddings", "embed-daemon.js");
70640
+ return join17(dirname10(fileURLToPath2(import.meta.url)), "..", "embeddings", "embed-daemon.js");
70089
70641
  }
70090
70642
  var sharedGrepEmbedClient = null;
70091
70643
  function getGrepEmbedClient() {