@deeplake/hivemind 0.7.76 → 0.7.78

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.
@@ -67672,7 +67672,7 @@ var DeeplakeApi = class {
67672
67672
  };
67673
67673
 
67674
67674
  // dist/src/shell/deeplake-fs.js
67675
- import { basename as basename5, posix } from "node:path";
67675
+ import { basename as basename5, posix as posix2 } from "node:path";
67676
67676
  import { randomUUID as randomUUID2 } from "node:crypto";
67677
67677
  import { fileURLToPath } from "node:url";
67678
67678
  import { dirname as dirname9, join as join16 } from "node:path";
@@ -68822,6 +68822,9 @@ import { dirname as dirname7, join as join14 } from "node:path";
68822
68822
  import { appendFileSync as appendFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "node:fs";
68823
68823
  import { dirname as dirname6, join as join13 } from "node:path";
68824
68824
 
68825
+ // dist/src/graph/resolve/cross-file.js
68826
+ import { posix } from "node:path";
68827
+
68825
68828
  // dist/src/graph/snapshot.js
68826
68829
  function graphsRoot() {
68827
68830
  return process.env.HIVEMIND_GRAPHS_HOME ?? join14(homedir8(), ".hivemind", "graphs");
@@ -68877,6 +68880,513 @@ function deriveProjectKey(cwd) {
68877
68880
  return { key, project };
68878
68881
  }
68879
68882
 
68883
+ // dist/src/graph/render/neighborhood.js
68884
+ var CAP = 25;
68885
+ function renderNeighborhood(snap, file) {
68886
+ const allFiles = [...new Set(snap.nodes.map((n24) => n24.source_file))];
68887
+ let resolved = null;
68888
+ if (allFiles.includes(file)) {
68889
+ resolved = file;
68890
+ } else {
68891
+ const matches = allFiles.filter((f11) => f11.endsWith(file) || f11.includes(file));
68892
+ if (matches.length === 1) {
68893
+ resolved = matches[0];
68894
+ } else if (matches.length > 1) {
68895
+ const lines2 = [];
68896
+ lines2.push(`"${file}" matches multiple files \u2014 which did you mean?`);
68897
+ lines2.push("");
68898
+ for (const m26 of matches.slice(0, 10))
68899
+ lines2.push(` ${m26}`);
68900
+ if (matches.length > 10)
68901
+ lines2.push(` ... and ${matches.length - 10} more`);
68902
+ return lines2.join("\n");
68903
+ }
68904
+ }
68905
+ if (resolved === null) {
68906
+ const lines2 = [];
68907
+ lines2.push(`No nodes for "${file}".`);
68908
+ const parts = file.split("/").filter((p22) => p22.length > 2);
68909
+ const close = allFiles.filter((f11) => parts.some((p22) => f11.includes(p22))).slice(0, 3);
68910
+ if (close.length > 0) {
68911
+ lines2.push("Did you mean:");
68912
+ for (const c15 of close)
68913
+ lines2.push(` ${c15}`);
68914
+ }
68915
+ return lines2.join("\n");
68916
+ }
68917
+ const fileNodes = snap.nodes.filter((n24) => n24.source_file === resolved);
68918
+ const fileNodeIds = new Set(fileNodes.map((n24) => n24.id));
68919
+ const fileOf = /* @__PURE__ */ new Map();
68920
+ for (const n24 of snap.nodes)
68921
+ fileOf.set(n24.id, n24.source_file);
68922
+ const sorted = [...fileNodes].sort((a15, b26) => {
68923
+ const la2 = parseLocation(a15.source_location);
68924
+ const lb = parseLocation(b26.source_location);
68925
+ if (la2 !== lb)
68926
+ return la2 - lb;
68927
+ return a15.label.localeCompare(b26.label);
68928
+ });
68929
+ const lines = [];
68930
+ lines.push(`## Symbols in ${resolved}`);
68931
+ lines.push("");
68932
+ if (sorted.length === 0) {
68933
+ lines.push(" (no symbols)");
68934
+ } else {
68935
+ for (const n24 of sorted) {
68936
+ const exp = n24.exported ? "exported" : "internal";
68937
+ lines.push(` ${n24.label.padEnd(32)} ${n24.kind.padEnd(12)} ${exp.padEnd(10)} ${n24.source_location}`);
68938
+ }
68939
+ }
68940
+ lines.push("");
68941
+ lines.push("## Cross-file neighbors");
68942
+ lines.push("");
68943
+ lines.push("Note: 'calls' edges are intra-file only in the current extractor \u2014 cross-file");
68944
+ lines.push("neighbors here are driven mainly by 'imports' edges.");
68945
+ lines.push("");
68946
+ const outgoing = [];
68947
+ const incoming = [];
68948
+ for (const e6 of snap.links) {
68949
+ const srcIn = fileNodeIds.has(e6.source);
68950
+ const tgtIn = fileNodeIds.has(e6.target);
68951
+ if (srcIn === tgtIn)
68952
+ continue;
68953
+ if (srcIn) {
68954
+ const tgtFile = fileOf.get(e6.target);
68955
+ if (tgtFile !== void 0 && tgtFile !== resolved)
68956
+ outgoing.push(e6);
68957
+ } else {
68958
+ const srcFile = fileOf.get(e6.source);
68959
+ if (srcFile !== void 0 && srcFile !== resolved)
68960
+ incoming.push(e6);
68961
+ }
68962
+ }
68963
+ renderDirectionGroup(lines, outgoing, "Outgoing", "source");
68964
+ renderDirectionGroup(lines, incoming, "Incoming", "target");
68965
+ return lines.join("\n");
68966
+ }
68967
+ function renderDirectionGroup(lines, edges, label, selfField) {
68968
+ const otherField = selfField === "source" ? "target" : "source";
68969
+ const byRelation = /* @__PURE__ */ new Map();
68970
+ for (const e6 of edges) {
68971
+ const otherId = e6[otherField];
68972
+ const rel = e6.relation;
68973
+ let nodeMap = byRelation.get(rel);
68974
+ if (!nodeMap) {
68975
+ nodeMap = /* @__PURE__ */ new Map();
68976
+ byRelation.set(rel, nodeMap);
68977
+ }
68978
+ nodeMap.set(otherId, (nodeMap.get(otherId) ?? 0) + 1);
68979
+ }
68980
+ if (byRelation.size === 0) {
68981
+ lines.push(`${label}: (none)`);
68982
+ lines.push("");
68983
+ return;
68984
+ }
68985
+ lines.push(`${label}:`);
68986
+ let totalShown = 0;
68987
+ const sortedRels = [...byRelation.entries()].sort(([a15], [b26]) => a15.localeCompare(b26));
68988
+ for (const [rel, nodeMap] of sortedRels) {
68989
+ const entries = [...nodeMap.entries()].sort(([a15], [b26]) => a15.localeCompare(b26));
68990
+ lines.push(` ${rel} (${entries.length}):`);
68991
+ let shownInRel = 0;
68992
+ for (const [otherId, cnt] of entries) {
68993
+ if (totalShown >= CAP)
68994
+ break;
68995
+ const suffix = cnt > 1 ? ` \xD7${cnt}` : "";
68996
+ lines.push(` ${otherId}${suffix}`);
68997
+ shownInRel++;
68998
+ totalShown++;
68999
+ }
69000
+ const remaining = entries.length - shownInRel;
69001
+ if (remaining > 0)
69002
+ lines.push(` ... and ${remaining} more`);
69003
+ }
69004
+ if (totalShown >= CAP) {
69005
+ const total = [...byRelation.values()].reduce((s10, m26) => s10 + m26.size, 0);
69006
+ if (total > CAP)
69007
+ lines.push(` ... and ${total - CAP} more`);
69008
+ }
69009
+ lines.push("");
69010
+ }
69011
+ function parseLocation(loc) {
69012
+ const m26 = loc.match(/^L(\d+)/);
69013
+ return m26 ? parseInt(m26[1], 10) : 0;
69014
+ }
69015
+
69016
+ // dist/src/graph/render/layers.js
69017
+ var LAYER_RULES = [
69018
+ { layer: "Tests", test: (p22) => p22.includes("/tests/") || p22.includes(".test.") || p22.includes("/__tests__/") },
69019
+ { layer: "Hooks", test: (p22) => p22.includes("/hooks/") },
69020
+ { layer: "CLI", test: (p22) => p22.includes("/cli/") || p22.includes("/commands/") },
69021
+ { layer: "Graph", test: (p22) => p22.includes("/graph/") },
69022
+ { layer: "Shell/VFS", test: (p22) => p22.includes("/shell/") },
69023
+ { layer: "Embeddings", test: (p22) => p22.includes("/embeddings/") },
69024
+ { layer: "Skillify", test: (p22) => p22.includes("/skillify/") },
69025
+ { layer: "Config", test: (p22) => /(?:^|\/)config\.[^/]+$/.test(p22) || /\.config\.[^/]+$/.test(p22) },
69026
+ { layer: "Utils", test: (p22) => p22.includes("/utils/") }
69027
+ ];
69028
+ function layerOf(sourceFile) {
69029
+ const p22 = sourceFile.startsWith("/") ? sourceFile : `/${sourceFile}`;
69030
+ for (const rule of LAYER_RULES) {
69031
+ if (rule.test(p22))
69032
+ return rule.layer;
69033
+ }
69034
+ return "Core";
69035
+ }
69036
+ function renderLayers(snap) {
69037
+ try {
69038
+ const layerNodes = /* @__PURE__ */ new Map();
69039
+ const layerFiles = /* @__PURE__ */ new Map();
69040
+ for (const node of snap.nodes) {
69041
+ const layer = layerOf(node.source_file);
69042
+ layerNodes.set(layer, (layerNodes.get(layer) ?? 0) + 1);
69043
+ let fileMap = layerFiles.get(layer);
69044
+ if (!fileMap) {
69045
+ fileMap = /* @__PURE__ */ new Map();
69046
+ layerFiles.set(layer, fileMap);
69047
+ }
69048
+ fileMap.set(node.source_file, (fileMap.get(node.source_file) ?? 0) + 1);
69049
+ }
69050
+ if (layerNodes.size === 0) {
69051
+ return "No nodes in snapshot \u2014 nothing to layer.";
69052
+ }
69053
+ const sorted = [...layerNodes.entries()].sort(([, a15], [, b26]) => b26 - a15);
69054
+ const lines = [];
69055
+ lines.push("## Architectural Layers");
69056
+ lines.push("");
69057
+ for (const [layer, count] of sorted) {
69058
+ lines.push(`${layer.padEnd(14)} ${String(count).padStart(4)} node${count === 1 ? "" : "s"}`);
69059
+ const fileMap = layerFiles.get(layer);
69060
+ const topFiles = [...fileMap.entries()].sort(([, a15], [, b26]) => b26 - a15).slice(0, 5);
69061
+ for (const [file, n24] of topFiles) {
69062
+ lines.push(` ${String(n24).padStart(3)} ${file}`);
69063
+ }
69064
+ if (fileMap.size > 5) {
69065
+ lines.push(` ... and ${fileMap.size - 5} more file${fileMap.size - 5 === 1 ? "" : "s"}`);
69066
+ }
69067
+ }
69068
+ lines.push("");
69069
+ lines.push(`Total: ${snap.nodes.length} node${snap.nodes.length === 1 ? "" : "s"} across ${sorted.length} layer${sorted.length === 1 ? "" : "s"}`);
69070
+ return lines.join("\n");
69071
+ } catch {
69072
+ return "Failed to render layer view.";
69073
+ }
69074
+ }
69075
+
69076
+ // dist/src/graph/render/tour.js
69077
+ var LINE_CAP = 60;
69078
+ function renderTour(snap) {
69079
+ if (snap.nodes.length === 0) {
69080
+ return "Graph is empty \u2014 no nodes to tour.";
69081
+ }
69082
+ const nodeMap = /* @__PURE__ */ new Map();
69083
+ for (const n24 of snap.nodes)
69084
+ nodeMap.set(n24.id, n24);
69085
+ const inDegOrig = /* @__PURE__ */ new Map();
69086
+ for (const n24 of snap.nodes)
69087
+ inDegOrig.set(n24.id, 0);
69088
+ for (const e6 of snap.links) {
69089
+ if (nodeMap.has(e6.source) && nodeMap.has(e6.target)) {
69090
+ inDegOrig.set(e6.target, (inDegOrig.get(e6.target) ?? 0) + 1);
69091
+ }
69092
+ }
69093
+ const entryPoints = snap.nodes.filter((n24) => n24.exported && inDegOrig.get(n24.id) === 0).sort((a15, b26) => a15.id.localeCompare(b26.id));
69094
+ const entrySet = new Set(entryPoints.map((n24) => n24.id));
69095
+ const revAdj = /* @__PURE__ */ new Map();
69096
+ const inDegRev = /* @__PURE__ */ new Map();
69097
+ for (const n24 of snap.nodes) {
69098
+ revAdj.set(n24.id, []);
69099
+ inDegRev.set(n24.id, 0);
69100
+ }
69101
+ for (const e6 of snap.links) {
69102
+ if (!nodeMap.has(e6.source) || !nodeMap.has(e6.target))
69103
+ continue;
69104
+ revAdj.get(e6.target).push(e6.source);
69105
+ inDegRev.set(e6.source, (inDegRev.get(e6.source) ?? 0) + 1);
69106
+ }
69107
+ const queue = [];
69108
+ for (const n24 of snap.nodes) {
69109
+ if (inDegRev.get(n24.id) === 0)
69110
+ queue.push(n24.id);
69111
+ }
69112
+ queue.sort();
69113
+ const topoOrder = [];
69114
+ while (queue.length > 0) {
69115
+ const id = queue.shift();
69116
+ topoOrder.push(id);
69117
+ const newReady = [];
69118
+ for (const dep of revAdj.get(id) ?? []) {
69119
+ const d15 = (inDegRev.get(dep) ?? 0) - 1;
69120
+ inDegRev.set(dep, d15);
69121
+ if (d15 === 0)
69122
+ newReady.push(dep);
69123
+ }
69124
+ if (newReady.length > 0) {
69125
+ for (const x28 of newReady)
69126
+ queue.push(x28);
69127
+ queue.sort();
69128
+ }
69129
+ }
69130
+ const topoSet = new Set(topoOrder);
69131
+ const cyclic = snap.nodes.filter((n24) => !topoSet.has(n24.id)).sort((a15, b26) => a15.id.localeCompare(b26.id));
69132
+ const walkthrough = topoOrder.filter((id) => !entrySet.has(id));
69133
+ const totalNodes = snap.nodes.length;
69134
+ const lines = [];
69135
+ lines.push(`# Code Graph Tour \u2014 ${totalNodes} node${totalNodes !== 1 ? "s" : ""}`);
69136
+ lines.push("");
69137
+ lines.push(`## Entry points (${entryPoints.length})`);
69138
+ if (entryPoints.length === 0) {
69139
+ lines.push(" (none \u2014 all exported nodes have at least one incoming edge)");
69140
+ } else {
69141
+ lines.push(" Exported symbols with no incoming edges \u2014 likely top-level public API.");
69142
+ lines.push("");
69143
+ for (let i11 = 0; i11 < entryPoints.length; i11++) {
69144
+ if (lines.length >= LINE_CAP) {
69145
+ lines.push(` ... and ${entryPoints.length - i11} more`);
69146
+ break;
69147
+ }
69148
+ lines.push(` ${i11 + 1}. ${entryPoints[i11].id} [${entryPoints[i11].kind}]`);
69149
+ }
69150
+ }
69151
+ lines.push("");
69152
+ lines.push(`## Walkthrough \u2014 dependency order (${walkthrough.length})`);
69153
+ if (walkthrough.length === 0) {
69154
+ lines.push(" (all non-entry nodes are cyclic)");
69155
+ } else {
69156
+ lines.push(" Dependencies before dependents (bottom-up).");
69157
+ lines.push("");
69158
+ for (let i11 = 0; i11 < walkthrough.length; i11++) {
69159
+ if (lines.length >= LINE_CAP) {
69160
+ lines.push(` ... and ${walkthrough.length - i11} more`);
69161
+ break;
69162
+ }
69163
+ const n24 = nodeMap.get(walkthrough[i11]);
69164
+ lines.push(` ${i11 + 1}. ${n24.id} [${n24.kind}]`);
69165
+ }
69166
+ }
69167
+ lines.push("");
69168
+ if (cyclic.length > 0) {
69169
+ lines.push(`## Cyclic / remaining (${cyclic.length})`);
69170
+ lines.push(" These nodes form cycles and were not reached by topological sort.");
69171
+ lines.push("");
69172
+ for (let i11 = 0; i11 < cyclic.length; i11++) {
69173
+ if (lines.length >= LINE_CAP) {
69174
+ lines.push(` ... and ${cyclic.length - i11} more`);
69175
+ break;
69176
+ }
69177
+ lines.push(` ${i11 + 1}. ${cyclic[i11].id} [${cyclic[i11].kind}]`);
69178
+ }
69179
+ lines.push("");
69180
+ }
69181
+ lines.push(`Total: ${entryPoints.length} entry + ${walkthrough.length} walkthrough` + (cyclic.length > 0 ? ` + ${cyclic.length} cyclic` : "") + ` = ${totalNodes} nodes`);
69182
+ return lines.join("\n");
69183
+ }
69184
+
69185
+ // dist/src/graph/render/path.js
69186
+ function resolvePattern(snap, pattern) {
69187
+ const needle = pattern.toLowerCase();
69188
+ return snap.nodes.filter((n24) => n24.id.toLowerCase().includes(needle) || n24.label.toLowerCase().includes(needle)).map((n24) => n24.id).sort();
69189
+ }
69190
+ function buildAdjacency(snap, undirected) {
69191
+ const adj = /* @__PURE__ */ new Map();
69192
+ const nodeIds = /* @__PURE__ */ new Set();
69193
+ for (const n24 of snap.nodes) {
69194
+ adj.set(n24.id, []);
69195
+ nodeIds.add(n24.id);
69196
+ }
69197
+ for (const edge of snap.links) {
69198
+ if (!nodeIds.has(edge.source) || !nodeIds.has(edge.target))
69199
+ continue;
69200
+ adj.get(edge.source).push({ neighborId: edge.target, edge, reversed: false });
69201
+ if (undirected) {
69202
+ adj.get(edge.target).push({ neighborId: edge.source, edge, reversed: true });
69203
+ }
69204
+ }
69205
+ for (const neighbors of adj.values()) {
69206
+ neighbors.sort((a15, b26) => a15.neighborId.localeCompare(b26.neighborId) || a15.edge.relation.localeCompare(b26.edge.relation) || (a15.reversed === b26.reversed ? 0 : a15.reversed ? 1 : -1));
69207
+ }
69208
+ return adj;
69209
+ }
69210
+ function bfs(adj, fromId, toId) {
69211
+ if (fromId === toId)
69212
+ return [];
69213
+ const parent = /* @__PURE__ */ new Map();
69214
+ const visited = /* @__PURE__ */ new Set([fromId]);
69215
+ const queue = [fromId];
69216
+ while (queue.length > 0) {
69217
+ const current = queue.shift();
69218
+ for (const { neighborId, edge, reversed } of adj.get(current) ?? []) {
69219
+ if (visited.has(neighborId))
69220
+ continue;
69221
+ visited.add(neighborId);
69222
+ parent.set(neighborId, { parentId: current, hop: { edge, reversed } });
69223
+ if (neighborId === toId) {
69224
+ const hops = [];
69225
+ let cur = toId;
69226
+ while (cur !== fromId) {
69227
+ const p22 = parent.get(cur);
69228
+ hops.unshift(p22.hop);
69229
+ cur = p22.parentId;
69230
+ }
69231
+ return hops;
69232
+ }
69233
+ queue.push(neighborId);
69234
+ }
69235
+ }
69236
+ return null;
69237
+ }
69238
+ function renderHops(fromId, hops, undirected) {
69239
+ const lines = [];
69240
+ lines.push(`${undirected ? "Undirected path" : "Directed path"} (${hops.length} hop${hops.length === 1 ? "" : "s"}):`);
69241
+ lines.push("");
69242
+ lines.push(` ${fromId}`);
69243
+ for (const { edge, reversed } of hops) {
69244
+ if (reversed) {
69245
+ lines.push(` <--${edge.relation}-- ${edge.source} [real edge: ${edge.source} \u2192 ${edge.target}]`);
69246
+ } else {
69247
+ lines.push(` --${edge.relation}--> ${edge.target}`);
69248
+ }
69249
+ }
69250
+ if (undirected) {
69251
+ lines.push("");
69252
+ lines.push("Note: no directed path exists. Arrows with <-- are traversed against their declared direction.");
69253
+ }
69254
+ return lines.join("\n");
69255
+ }
69256
+ function candidateList(pattern, ids) {
69257
+ const lines = [`"${pattern}" matches ${ids.length} nodes \u2014 be more specific:`];
69258
+ lines.push("");
69259
+ const shown = ids.slice(0, 20);
69260
+ for (let i11 = 0; i11 < shown.length; i11++)
69261
+ lines.push(` [${i11 + 1}] ${shown[i11]}`);
69262
+ if (ids.length > 20)
69263
+ lines.push(` ... and ${ids.length - 20} more`);
69264
+ return lines.join("\n");
69265
+ }
69266
+ function renderPath(snap, fromPattern, toPattern) {
69267
+ const fromIds = resolvePattern(snap, fromPattern);
69268
+ const toIds = resolvePattern(snap, toPattern);
69269
+ if (fromIds.length === 0) {
69270
+ return `No node matches "${fromPattern}". Try cat memory/graph/find/<pattern> to explore.`;
69271
+ }
69272
+ if (toIds.length === 0) {
69273
+ return `No node matches "${toPattern}". Try cat memory/graph/find/<pattern> to explore.`;
69274
+ }
69275
+ if (fromIds.length > 1)
69276
+ return candidateList(fromPattern, fromIds);
69277
+ if (toIds.length > 1)
69278
+ return candidateList(toPattern, toIds);
69279
+ const fromId = fromIds[0];
69280
+ const toId = toIds[0];
69281
+ if (fromId === toId) {
69282
+ return `"${fromId}" is the same node on both ends \u2014 path length 0.`;
69283
+ }
69284
+ const dirPath = bfs(buildAdjacency(snap, false), fromId, toId);
69285
+ if (dirPath !== null)
69286
+ return renderHops(fromId, dirPath, false);
69287
+ const undirPath = bfs(buildAdjacency(snap, true), fromId, toId);
69288
+ if (undirPath !== null)
69289
+ return renderHops(fromId, undirPath, true);
69290
+ const fromNode = snap.nodes.find((n24) => n24.id === fromId);
69291
+ const toNode = snap.nodes.find((n24) => n24.id === toId);
69292
+ const sameFile = fromNode && toNode && fromNode.source_file === toNode.source_file;
69293
+ const context = sameFile ? `Both are in ${fromNode.source_file} \u2014 same file but no connecting edges.` : `Sources: ${fromNode?.source_file ?? "?"} vs ${toNode?.source_file ?? "?"} \u2014 they appear disconnected.`;
69294
+ return [`No path found between:`, ` from: ${fromId}`, ` to: ${toId}`, ``, context].join("\n");
69295
+ }
69296
+
69297
+ // dist/src/graph/render/impact.js
69298
+ var IMPACT_CAP = 80;
69299
+ var MAX_DEPTH = 25;
69300
+ function renderImpact(snap, pattern) {
69301
+ const needle = pattern.toLowerCase();
69302
+ const matches = snap.nodes.filter((n24) => n24.id.toLowerCase().includes(needle));
69303
+ if (matches.length === 0) {
69304
+ return `No node matches "${pattern}". Try cat memory/graph/find/${pattern} to explore.`;
69305
+ }
69306
+ if (matches.length > 1) {
69307
+ const lines2 = [`"${pattern}" matches ${matches.length} nodes \u2014 be more specific:`, ""];
69308
+ for (const m26 of matches.slice(0, 20))
69309
+ lines2.push(` ${m26.id}`);
69310
+ if (matches.length > 20)
69311
+ lines2.push(` ... and ${matches.length - 20} more`);
69312
+ return lines2.join("\n");
69313
+ }
69314
+ const target = matches[0];
69315
+ const nodeIds = new Set(snap.nodes.map((n24) => n24.id));
69316
+ const incoming = /* @__PURE__ */ new Map();
69317
+ for (const e6 of snap.links) {
69318
+ if (!nodeIds.has(e6.source))
69319
+ continue;
69320
+ const list = incoming.get(e6.target);
69321
+ if (list)
69322
+ list.push(e6);
69323
+ else
69324
+ incoming.set(e6.target, [e6]);
69325
+ }
69326
+ const depthOf = /* @__PURE__ */ new Map();
69327
+ const viaOf = /* @__PURE__ */ new Map();
69328
+ depthOf.set(target.id, 0);
69329
+ let frontier = [target.id];
69330
+ let depth = 0;
69331
+ while (frontier.length > 0 && depth < MAX_DEPTH) {
69332
+ depth++;
69333
+ const next = [];
69334
+ for (const id of frontier) {
69335
+ const edges = (incoming.get(id) ?? []).slice().sort((a15, b26) => a15.source.localeCompare(b26.source) || a15.relation.localeCompare(b26.relation));
69336
+ for (const e6 of edges) {
69337
+ if (depthOf.has(e6.source))
69338
+ continue;
69339
+ depthOf.set(e6.source, depth);
69340
+ viaOf.set(e6.source, { rel: e6.relation, from: id });
69341
+ next.push(e6.source);
69342
+ }
69343
+ }
69344
+ next.sort();
69345
+ frontier = next;
69346
+ }
69347
+ const dependents = [...depthOf.entries()].filter(([id]) => id !== target.id);
69348
+ const total = dependents.length;
69349
+ const lines = [];
69350
+ lines.push(`Impact of ${target.id}`);
69351
+ if (target.signature)
69352
+ lines.push(` ${target.signature}`);
69353
+ lines.push("");
69354
+ if (total === 0) {
69355
+ lines.push("No resolved dependents \u2014 nothing in the graph reaches this symbol.");
69356
+ lines.push("(Cross-file resolution is partial; this is a lower bound, not proof it's unused.)");
69357
+ return lines.join("\n");
69358
+ }
69359
+ lines.push(`${total} dependent${total === 1 ? "" : "s"} (transitive), by depth:`);
69360
+ lines.push("");
69361
+ const byDepth = /* @__PURE__ */ new Map();
69362
+ for (const [id, d15] of dependents) {
69363
+ const list = byDepth.get(d15) ?? [];
69364
+ list.push(id);
69365
+ byDepth.set(d15, list);
69366
+ }
69367
+ let shown = 0;
69368
+ for (const d15 of [...byDepth.keys()].sort((a15, b26) => a15 - b26)) {
69369
+ const ids = byDepth.get(d15).sort();
69370
+ lines.push(` depth ${d15} (${ids.length}):`);
69371
+ for (const id of ids) {
69372
+ if (shown >= IMPACT_CAP)
69373
+ break;
69374
+ const via = viaOf.get(id);
69375
+ const tag = via ? ` [${via.rel} \u2192 ${via.from}]` : "";
69376
+ lines.push(` ${id}${tag}`);
69377
+ shown++;
69378
+ }
69379
+ if (shown >= IMPACT_CAP)
69380
+ break;
69381
+ }
69382
+ if (total > shown)
69383
+ lines.push(` ... and ${total - shown} more`);
69384
+ lines.push("");
69385
+ lines.push("Note: only RESOLVED edges are traversed (cross-file resolution is partial),");
69386
+ lines.push("so this is a lower bound on impact, not a completeness guarantee.");
69387
+ return lines.join("\n");
69388
+ }
69389
+
68880
69390
  // dist/src/graph/vfs-handler.js
68881
69391
  function workTreeIdFor(cwd) {
68882
69392
  return createHash3("sha256").update(cwd).digest("hex").slice(0, 16);
@@ -68912,10 +69422,50 @@ function handleGraphVfs(subpath, cwd) {
68912
69422
  body: renderShow(snap, key, baseDir, workTreeIdFor(cwd))
68913
69423
  }));
68914
69424
  }
69425
+ if (path2.startsWith("query/")) {
69426
+ const pattern = path2.slice("query/".length);
69427
+ if (pattern === "") {
69428
+ return { kind: "not-found", message: "query/ requires a pattern: cat memory/graph/query/<keyword>" };
69429
+ }
69430
+ return loadSnapshotOrError(cwd, (snap, baseDir) => ({
69431
+ kind: "ok",
69432
+ body: renderQuery(snap, pattern, baseDir, workTreeIdFor(cwd))
69433
+ }));
69434
+ }
69435
+ if (path2.startsWith("impact/")) {
69436
+ const pattern = path2.slice("impact/".length);
69437
+ if (pattern === "") {
69438
+ return { kind: "not-found", message: "impact/ requires a pattern: cat memory/graph/impact/<symbol>" };
69439
+ }
69440
+ return loadSnapshotOrError(cwd, (snap) => ({ kind: "ok", body: renderImpact(snap, pattern) }));
69441
+ }
69442
+ if (path2.startsWith("neighborhood/")) {
69443
+ const file = path2.slice("neighborhood/".length);
69444
+ if (file === "") {
69445
+ return { kind: "not-found", message: "neighborhood/ requires a file path: cat memory/graph/neighborhood/<file>" };
69446
+ }
69447
+ return loadSnapshotOrError(cwd, (snap) => ({ kind: "ok", body: renderNeighborhood(snap, file) }));
69448
+ }
69449
+ if (path2 === "layers" || path2 === "layers/" || path2 === "layers/index.md") {
69450
+ return loadSnapshotOrError(cwd, (snap) => ({ kind: "ok", body: renderLayers(snap) }));
69451
+ }
69452
+ if (path2 === "tour" || path2 === "tour/" || path2 === "tour/index.md") {
69453
+ return loadSnapshotOrError(cwd, (snap) => ({ kind: "ok", body: renderTour(snap) }));
69454
+ }
69455
+ if (path2.startsWith("path/")) {
69456
+ const rest = path2.slice("path/".length);
69457
+ const slash = rest.indexOf("/");
69458
+ if (slash <= 0 || slash === rest.length - 1) {
69459
+ return { kind: "not-found", message: "path/ needs two patterns: cat memory/graph/path/<from>/<to> (each a symbol-name substring, no slash)" };
69460
+ }
69461
+ const fromPattern = rest.slice(0, slash);
69462
+ const toPattern = rest.slice(slash + 1);
69463
+ return loadSnapshotOrError(cwd, (snap) => ({ kind: "ok", body: renderPath(snap, fromPattern, toPattern) }));
69464
+ }
68915
69465
  return {
68916
69466
  kind: "not-found",
68917
69467
  message: `Unknown endpoint: graph/${path2}
68918
- Available: index.md, find/<pattern>, show/<handle-or-pattern>`
69468
+ Available: index.md, find/<pattern>, query/<pattern>, show/<handle-or-pattern>, impact/<pattern>, neighborhood/<file>, layers, tour, path/<from>/<to>`
68919
69469
  };
68920
69470
  }
68921
69471
  function loadSnapshotOrError(cwd, fn4) {
@@ -68959,7 +69509,13 @@ function dirListing() {
68959
69509
  return [
68960
69510
  "index.md",
68961
69511
  "find/",
68962
- "show/"
69512
+ "query/",
69513
+ "show/",
69514
+ "impact/",
69515
+ "neighborhood/",
69516
+ "layers",
69517
+ "tour",
69518
+ "path/"
68963
69519
  ].join("\n");
68964
69520
  }
68965
69521
  function renderIndex(snap, baseDir, cwd) {
@@ -68987,16 +69543,23 @@ function renderIndex(snap, baseDir, cwd) {
68987
69543
  lines.push(`Nodes: ${totalNodes} Edges: ${totalEdges}`);
68988
69544
  lines.push("");
68989
69545
  lines.push("## How to query");
69546
+ lines.push(" cat ~/.deeplake/memory/graph/query/<pattern>");
69547
+ lines.push(" 2-in-1: search + expand the top matches with their 1-hop");
69548
+ lines.push(" neighbors (callers/callees/imports/heritage). Start here.");
69549
+ lines.push(" Multi-token AND: query/<a>+<b> requires both tokens.");
69550
+ lines.push("");
68990
69551
  lines.push(" cat ~/.deeplake/memory/graph/find/<pattern>");
68991
69552
  lines.push(" Case-insensitive substring match on node id + label.");
68992
69553
  lines.push(" Emits numbered handles [1] [2] ... saved for this worktree.");
68993
69554
  lines.push("");
68994
69555
  lines.push(" cat ~/.deeplake/memory/graph/show/<handle-or-pattern>");
68995
- lines.push(" <handle>: a digit from a prior `find/` (e.g. 3).");
69556
+ lines.push(" <handle>: a digit from a prior `find/`/`query/` (e.g. 3).");
68996
69557
  lines.push(" <pattern>: a substring; resolves to a unique node if possible,");
68997
69558
  lines.push(" or shows candidates if ambiguous.");
68998
69559
  lines.push(" Output: node detail + 1-hop neighbors grouped by edge kind.");
68999
69560
  lines.push("");
69561
+ lines.push(" Also: neighborhood/<file> \xB7 layers \xB7 tour \xB7 path/<from>/<to>");
69562
+ lines.push("");
69000
69563
  lines.push("## Node kinds");
69001
69564
  for (const [k17, n24] of Object.entries(byKind).sort(([, a15], [, b26]) => b26 - a15)) {
69002
69565
  lines.push(` ${k17.padEnd(12)} ${n24}`);
@@ -69013,31 +69576,92 @@ function renderIndex(snap, baseDir, cwd) {
69013
69576
  }
69014
69577
  lines.push("");
69015
69578
  lines.push(`Limitations:`);
69016
- lines.push(` - TypeScript only. AST-based, no semantic similarity edges.`);
69017
- lines.push(` - 'calls' edges are intra-file only (Phase 1 extractor doesn't resolve cross-file).`);
69018
- lines.push(` A node showing "Incoming (0)" may still have callers in OTHER files \u2014`);
69019
- lines.push(` treat it as "no callers in the same file", not "unused".`);
69020
- lines.push(` - 'imports' edges are file-level and DO span files; trust them.`);
69579
+ lines.push(` - TypeScript / JavaScript / Python. AST-based, no semantic similarity edges yet.`);
69580
+ lines.push(` - Cross-file 'calls'/'imports'/'extends' ARE resolved for relative named/namespace`);
69581
+ lines.push(` imports; bare (npm)/aliased/barrel/dynamic imports stay unresolved. So a node`);
69582
+ lines.push(` with "Incoming (0)" is not proof of dead code \u2014 a caller may reach it via an`);
69583
+ lines.push(` unresolved import path. (Python cross-file resolution is a follow-up; Python is`);
69584
+ lines.push(` intra-file + structure only for now.)`);
69021
69585
  lines.push(` - Stale after edits \u2014 if a file's mtime is newer than the build, read the live source.`);
69022
69586
  void cwd;
69023
69587
  return lines.join("\n");
69024
69588
  }
69025
- function renderFind(snap, pattern, baseDir, worktreeId) {
69026
- const needle = pattern.toLowerCase();
69589
+ function findMatches(snap, pattern) {
69590
+ const tokens = pattern.toLowerCase().split(/[\s+]+/).filter((t6) => t6.length > 0);
69591
+ if (tokens.length === 0)
69592
+ return [];
69593
+ if (tokens.length === 1) {
69594
+ const needle = tokens[0];
69595
+ const matches2 = [];
69596
+ for (const n24 of snap.nodes) {
69597
+ if (n24.id.toLowerCase().includes(needle) || n24.label.toLowerCase().includes(needle))
69598
+ matches2.push(n24);
69599
+ }
69600
+ matches2.sort((a15, b26) => {
69601
+ const ra2 = rank(a15, needle);
69602
+ const rb = rank(b26, needle);
69603
+ if (ra2 !== rb)
69604
+ return ra2 - rb;
69605
+ return a15.id.localeCompare(b26.id);
69606
+ });
69607
+ if (matches2.length === 0)
69608
+ return fuzzyMatches(snap, needle);
69609
+ return matches2;
69610
+ }
69027
69611
  const matches = [];
69028
69612
  for (const n24 of snap.nodes) {
69029
69613
  const id = n24.id.toLowerCase();
69030
69614
  const lbl = n24.label.toLowerCase();
69031
- if (id.includes(needle) || lbl.includes(needle))
69615
+ if (tokens.every((t6) => id.includes(t6) || lbl.includes(t6)))
69032
69616
  matches.push(n24);
69033
69617
  }
69618
+ const score = (n24) => tokens.reduce((s10, t6) => s10 + rank(n24, t6), 0);
69034
69619
  matches.sort((a15, b26) => {
69035
- const ra2 = rank(a15, needle);
69036
- const rb = rank(b26, needle);
69037
- if (ra2 !== rb)
69038
- return ra2 - rb;
69620
+ const sa2 = score(a15);
69621
+ const sb = score(b26);
69622
+ if (sa2 !== sb)
69623
+ return sa2 - sb;
69039
69624
  return a15.id.localeCompare(b26.id);
69040
69625
  });
69626
+ return matches;
69627
+ }
69628
+ function fuzzyMatches(snap, needle) {
69629
+ if (needle.length < 3)
69630
+ return [];
69631
+ const maxDist = Math.max(1, Math.floor(needle.length / 4));
69632
+ const scored = [];
69633
+ for (const n24 of snap.nodes) {
69634
+ const d15 = editDistance(needle, n24.label.toLowerCase(), maxDist);
69635
+ if (d15 <= maxDist)
69636
+ scored.push({ n: n24, d: d15 });
69637
+ }
69638
+ scored.sort((a15, b26) => a15.d !== b26.d ? a15.d - b26.d : a15.n.id.localeCompare(b26.n.id));
69639
+ return scored.slice(0, 25).map((s10) => s10.n);
69640
+ }
69641
+ function editDistance(a15, b26, cap) {
69642
+ if (Math.abs(a15.length - b26.length) > cap)
69643
+ return cap + 1;
69644
+ let prev = new Array(b26.length + 1);
69645
+ let cur = new Array(b26.length + 1);
69646
+ for (let j14 = 0; j14 <= b26.length; j14++)
69647
+ prev[j14] = j14;
69648
+ for (let i11 = 1; i11 <= a15.length; i11++) {
69649
+ cur[0] = i11;
69650
+ let rowMin = cur[0];
69651
+ for (let j14 = 1; j14 <= b26.length; j14++) {
69652
+ const cost = a15[i11 - 1] === b26[j14 - 1] ? 0 : 1;
69653
+ cur[j14] = Math.min(prev[j14] + 1, cur[j14 - 1] + 1, prev[j14 - 1] + cost);
69654
+ if (cur[j14] < rowMin)
69655
+ rowMin = cur[j14];
69656
+ }
69657
+ if (rowMin > cap)
69658
+ return cap + 1;
69659
+ [prev, cur] = [cur, prev];
69660
+ }
69661
+ return prev[b26.length];
69662
+ }
69663
+ function renderFind(snap, pattern, baseDir, worktreeId) {
69664
+ const matches = findMatches(snap, pattern);
69041
69665
  const capped = matches.slice(0, 50);
69042
69666
  if (capped.length === 0) {
69043
69667
  return `No matches for "${pattern}" in ${snap.nodes.length} nodes.
@@ -69056,6 +69680,76 @@ Try a shorter or different substring.`;
69056
69680
  lines.push("Use: cat ~/.deeplake/memory/graph/show/<N> to see node + 1-hop neighbors");
69057
69681
  return lines.join("\n");
69058
69682
  }
69683
+ var QUERY_TOP_N = 5;
69684
+ var QUERY_NEIGHBOR_CAP = 8;
69685
+ function renderQuery(snap, pattern, baseDir, worktreeId) {
69686
+ const matches = findMatches(snap, pattern);
69687
+ if (matches.length === 0) {
69688
+ return `No matches for "${pattern}" in ${snap.nodes.length} nodes.
69689
+ Try a shorter or different substring, or cat memory/graph/find/<pattern>.`;
69690
+ }
69691
+ const top = matches.slice(0, QUERY_TOP_N);
69692
+ saveHandles(baseDir, worktreeId, top.map((n24) => n24.id), pattern);
69693
+ const topIds = new Set(top.map((n24) => n24.id));
69694
+ const outByNode = /* @__PURE__ */ new Map();
69695
+ const inByNode = /* @__PURE__ */ new Map();
69696
+ for (const e6 of snap.links) {
69697
+ if (topIds.has(e6.source))
69698
+ (outByNode.get(e6.source) ?? setGet(outByNode, e6.source)).push(e6);
69699
+ if (topIds.has(e6.target))
69700
+ (inByNode.get(e6.target) ?? setGet(inByNode, e6.target)).push(e6);
69701
+ }
69702
+ const lines = [];
69703
+ lines.push(`Query "${pattern}" \u2014 ${matches.length} match${matches.length === 1 ? "" : "es"}, expanded top ${top.length} (1 hop)`);
69704
+ lines.push("");
69705
+ for (let i11 = 0; i11 < top.length; i11++) {
69706
+ const n24 = top[i11];
69707
+ const tags = [n24.exported ? "exported" : "internal"];
69708
+ if (n24.is_entrypoint)
69709
+ tags.push("entrypoint");
69710
+ if (n24.fan_in !== void 0)
69711
+ tags.push(`fan_in=${n24.fan_in}`);
69712
+ if (n24.fan_out !== void 0)
69713
+ tags.push(`fan_out=${n24.fan_out}`);
69714
+ lines.push(`[${i11 + 1}] ${n24.id} ${n24.kind} (${tags.join(", ")})`);
69715
+ if (n24.signature)
69716
+ lines.push(` ${n24.signature}`);
69717
+ renderHopGroup(lines, outByNode.get(n24.id) ?? [], "OUT", "target");
69718
+ renderHopGroup(lines, inByNode.get(n24.id) ?? [], "IN", "source");
69719
+ lines.push("");
69720
+ }
69721
+ lines.push("Use: cat ~/.deeplake/memory/graph/show/<N> for full detail on a match.");
69722
+ return lines.join("\n");
69723
+ }
69724
+ function setGet(m26, key) {
69725
+ const list = [];
69726
+ m26.set(key, list);
69727
+ return list;
69728
+ }
69729
+ function renderHopGroup(lines, edges, dir, otherField) {
69730
+ if (edges.length === 0)
69731
+ return;
69732
+ const byRel = /* @__PURE__ */ new Map();
69733
+ for (const e6 of edges) {
69734
+ let counts = byRel.get(e6.relation);
69735
+ if (!counts) {
69736
+ counts = /* @__PURE__ */ new Map();
69737
+ byRel.set(e6.relation, counts);
69738
+ }
69739
+ const id = e6[otherField];
69740
+ counts.set(id, (counts.get(id) ?? 0) + 1);
69741
+ }
69742
+ for (const [rel, counts] of [...byRel.entries()].sort(([a15], [b26]) => a15.localeCompare(b26))) {
69743
+ const arrow = dir === "OUT" ? `--${rel}-->` : `<--${rel}--`;
69744
+ const ids = [...counts.keys()].sort();
69745
+ const shown = ids.slice(0, QUERY_NEIGHBOR_CAP).map((id) => {
69746
+ const c15 = counts.get(id);
69747
+ return c15 > 1 ? `${id} \xD7${c15}` : id;
69748
+ });
69749
+ const more = ids.length > shown.length ? ` (+${ids.length - shown.length} more)` : "";
69750
+ lines.push(` ${arrow} ${shown.join(", ")}${more}`);
69751
+ }
69752
+ }
69059
69753
  function renderShow(snap, key, baseDir, worktreeId) {
69060
69754
  if (/^\d+$/.test(key)) {
69061
69755
  const idx = parseInt(key, 10);
@@ -69117,9 +69811,20 @@ function renderNodeDetail(snap, node) {
69117
69811
  lines.push(` source: ${node.source_file}:${node.source_location}`);
69118
69812
  lines.push(` kind: ${node.kind}`);
69119
69813
  lines.push(` label: ${node.label}`);
69120
- lines.push(` ${node.exported ? "exported" : "internal"}`);
69814
+ if (node.signature)
69815
+ lines.push(` sig: ${node.signature}`);
69816
+ if (node.doc)
69817
+ lines.push(` doc: ${node.doc}`);
69818
+ const tags = [node.exported ? "exported" : "internal"];
69819
+ if (node.is_entrypoint)
69820
+ tags.push("entrypoint");
69821
+ if (node.fan_in !== void 0)
69822
+ tags.push(`fan_in=${node.fan_in}`);
69823
+ if (node.fan_out !== void 0)
69824
+ tags.push(`fan_out=${node.fan_out}`);
69825
+ lines.push(` ${tags.join(" ")}`);
69121
69826
  lines.push("");
69122
- const inHint = incoming.length === 0 ? " \u2014 no edges from THIS file (intra-file only; may still be called from other files)" : ":";
69827
+ const inHint = incoming.length === 0 ? " \u2014 no resolved callers (cross-file resolution is partial; not proof of dead code)" : ":";
69123
69828
  lines.push(`Incoming (${incoming.length})${inHint}`);
69124
69829
  for (const [rel, es3] of [...inGrp.entries()].sort(([a15], [b26]) => a15.localeCompare(b26))) {
69125
69830
  lines.push(` ${rel} (${es3.length}):`);
@@ -69196,7 +69901,7 @@ var BATCH_SIZE = 10;
69196
69901
  var PREFETCH_BATCH_SIZE = 50;
69197
69902
  var FLUSH_DEBOUNCE_MS = 200;
69198
69903
  function normPath(p22) {
69199
- const r10 = posix.normalize(p22.startsWith("/") ? p22 : "/" + p22);
69904
+ const r10 = posix2.normalize(p22.startsWith("/") ? p22 : "/" + p22);
69200
69905
  return r10 === "/" ? r10 : r10.replace(/\/$/, "");
69201
69906
  }
69202
69907
  function parentOf(p22) {
@@ -70045,7 +70750,7 @@ var DeeplakeFs = class _DeeplakeFs {
70045
70750
  resolvePath(base, path2) {
70046
70751
  if (path2.startsWith("/"))
70047
70752
  return normPath(path2);
70048
- return normPath(posix.join(base, path2));
70753
+ return normPath(posix2.join(base, path2));
70049
70754
  }
70050
70755
  getAllPaths() {
70051
70756
  return [.../* @__PURE__ */ new Set([...this.files.keys(), ...this.dirs.keys()])];