@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
@@ -395,9 +395,33 @@ function validateSchema(label, cols) {
395
395
  }
396
396
  }
397
397
  }
398
+ var CODEBASE_COLUMNS = Object.freeze([
399
+ // Identity key (matches the PK below)
400
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
401
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
402
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
403
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
404
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
405
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
406
+ // Observation metadata
407
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
408
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
409
+ { name: "ts", sql: "TIMESTAMP" },
410
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
411
+ // Snapshot payload
412
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
413
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
414
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
415
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
416
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
417
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
418
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
419
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
420
+ ]);
398
421
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
399
422
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
400
423
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
424
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
401
425
  function buildCreateTableSql(tableName, cols) {
402
426
  const safe = sqlIdent(tableName);
403
427
  const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
@@ -693,9 +717,12 @@ function resolveRecordScope(args) {
693
717
 
694
718
  // dist/src/skillify/state.js
695
719
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, writeSync, mkdirSync as mkdirSync2, renameSync as renameSync2, rmdirSync, existsSync as existsSync4, lstatSync, unlinkSync, openSync, closeSync } from "node:fs";
720
+ import { join as join6 } from "node:path";
721
+
722
+ // dist/src/utils/repo-identity.js
696
723
  import { execSync } from "node:child_process";
697
724
  import { createHash } from "node:crypto";
698
- import { join as join6, basename } from "node:path";
725
+ import { basename, resolve } from "node:path";
699
726
 
700
727
  // dist/src/skillify/legacy-migration.js
701
728
  import { existsSync as existsSync3, renameSync } from "node:fs";
@@ -881,7 +908,7 @@ async function query(sql, retries = 4) {
881
908
  const base = Math.min(3e4, 2e3 * Math.pow(2, attempt));
882
909
  const delay = base + Math.floor(Math.random() * 1e3);
883
910
  wlog(`fetch failed (${e?.name ?? e?.code ?? e?.message}), retrying in ${delay}ms (attempt ${attempt + 1}/${retries})`);
884
- await new Promise((resolve) => setTimeout(resolve, delay));
911
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
885
912
  continue;
886
913
  }
887
914
  throw e;
@@ -897,7 +924,7 @@ async function query(sql, retries = 4) {
897
924
  const base = Math.min(3e4, 2e3 * Math.pow(2, attempt));
898
925
  const delay = base + Math.floor(Math.random() * 1e3);
899
926
  wlog(`API ${r.status}, retrying in ${delay}ms (attempt ${attempt + 1}/${retries})`);
900
- await new Promise((resolve) => setTimeout(resolve, delay));
927
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
901
928
  continue;
902
929
  }
903
930
  throw new Error(`API ${r.status}: ${(await r.text()).slice(0, 200)}`);
@@ -59,13 +59,13 @@ import { dirname as dirname6, join as join19 } from "node:path";
59
59
 
60
60
  // dist/src/utils/stdin.js
61
61
  function readStdin() {
62
- return new Promise((resolve2, reject) => {
62
+ return new Promise((resolve3, reject) => {
63
63
  let data = "";
64
64
  process.stdin.setEncoding("utf-8");
65
65
  process.stdin.on("data", (chunk) => data += chunk);
66
66
  process.stdin.on("end", () => {
67
67
  try {
68
- resolve2(JSON.parse(data));
68
+ resolve3(JSON.parse(data));
69
69
  } catch (err) {
70
70
  reject(new Error(`Failed to parse hook input: ${err}`));
71
71
  }
@@ -103,6 +103,7 @@ function loadConfig() {
103
103
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
104
104
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
105
105
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
106
+ codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
106
107
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join(home, ".deeplake", "memory")
107
108
  };
108
109
  }
@@ -220,9 +221,33 @@ function validateSchema(label, cols) {
220
221
  }
221
222
  }
222
223
  }
224
+ var CODEBASE_COLUMNS = Object.freeze([
225
+ // Identity key (matches the PK below)
226
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
227
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
228
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
229
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
230
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
231
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
232
+ // Observation metadata
233
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
234
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
235
+ { name: "ts", sql: "TIMESTAMP" },
236
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
237
+ // Snapshot payload
238
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
239
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
240
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
241
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
242
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
243
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
244
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
245
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
246
+ ]);
223
247
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
224
248
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
225
249
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
250
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
226
251
  function buildCreateTableSql(tableName, cols) {
227
252
  const safe = sqlIdent(tableName);
228
253
  const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
@@ -447,7 +472,7 @@ function getQueryTimeoutMs() {
447
472
  return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
448
473
  }
449
474
  function sleep2(ms) {
450
- return new Promise((resolve2) => setTimeout(resolve2, ms));
475
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
451
476
  }
452
477
  function isTimeoutError(error) {
453
478
  const name = error instanceof Error ? error.name.toLowerCase() : "";
@@ -477,7 +502,7 @@ var Semaphore = class {
477
502
  this.active++;
478
503
  return;
479
504
  }
480
- await new Promise((resolve2) => this.waiting.push(resolve2));
505
+ await new Promise((resolve3) => this.waiting.push(resolve3));
481
506
  }
482
507
  release() {
483
508
  this.active--;
@@ -787,6 +812,24 @@ var DeeplakeApi = class {
787
812
  * This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
788
813
  * worker.
789
814
  */
815
+ /**
816
+ * Create the codebase table. One row per (org, workspace, repo, user,
817
+ * worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
818
+ * + index follow the same pattern as ensureSessionsTable.
819
+ */
820
+ async ensureCodebaseTable(name) {
821
+ const safe = sqlIdent(name);
822
+ const tables = await this.listTables();
823
+ if (!tables.includes(safe)) {
824
+ log3(`table "${safe}" not found, creating`);
825
+ await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
826
+ log3(`table "${safe}" created`);
827
+ if (!tables.includes(safe))
828
+ this._tablesCache = [...tables, safe];
829
+ }
830
+ await this.healSchema(safe, CODEBASE_COLUMNS);
831
+ await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
832
+ }
790
833
  async ensureSkillsTable(name) {
791
834
  const safe = sqlIdent(name);
792
835
  const tables = await this.listTables();
@@ -1097,9 +1140,54 @@ function spawnSkillifyWorker(opts) {
1097
1140
 
1098
1141
  // dist/src/skillify/state.js
1099
1142
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, writeSync, mkdirSync as mkdirSync7, renameSync as renameSync3, rmdirSync, existsSync as existsSync5, lstatSync, unlinkSync as unlinkSync3, openSync as openSync2, closeSync as closeSync2 } from "node:fs";
1143
+ import { join as join13 } from "node:path";
1144
+
1145
+ // dist/src/utils/repo-identity.js
1100
1146
  import { execSync as execSync2 } from "node:child_process";
1101
1147
  import { createHash } from "node:crypto";
1102
- import { join as join13, basename } from "node:path";
1148
+ import { basename, resolve as resolve2 } from "node:path";
1149
+ var DEFAULT_PORTS = {
1150
+ http: "80",
1151
+ https: "443",
1152
+ ssh: "22",
1153
+ git: "9418"
1154
+ };
1155
+ function normalizeGitRemoteUrl(url) {
1156
+ let s = url.trim();
1157
+ const schemeMatch = s.match(/^([a-z][a-z0-9+.-]*):\/\//i);
1158
+ const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null;
1159
+ if (schemeMatch)
1160
+ s = s.slice(schemeMatch[0].length);
1161
+ if (!scheme) {
1162
+ const scp = s.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);
1163
+ if (scp)
1164
+ s = `${scp[1]}/${scp[2]}`;
1165
+ }
1166
+ s = s.replace(/^[^@/]+@/, "");
1167
+ if (scheme && DEFAULT_PORTS[scheme]) {
1168
+ s = s.replace(new RegExp(`^([^/]+):${DEFAULT_PORTS[scheme]}(/|$)`), "$1$2");
1169
+ }
1170
+ s = s.replace(/\.git\/?$/i, "");
1171
+ s = s.replace(/\/+$/, "");
1172
+ return s.toLowerCase();
1173
+ }
1174
+ function deriveProjectKey(cwd) {
1175
+ const absCwd = resolve2(cwd);
1176
+ const project = basename(absCwd) || "unknown";
1177
+ let signature = null;
1178
+ try {
1179
+ const raw = execSync2("git config --get remote.origin.url", {
1180
+ cwd: absCwd,
1181
+ encoding: "utf-8",
1182
+ stdio: ["ignore", "pipe", "ignore"]
1183
+ }).trim();
1184
+ signature = raw ? normalizeGitRemoteUrl(raw) : null;
1185
+ } catch {
1186
+ }
1187
+ const input = signature ?? absCwd;
1188
+ const key = createHash("sha1").update(input).digest("hex").slice(0, 16);
1189
+ return { key, project };
1190
+ }
1103
1191
 
1104
1192
  // dist/src/skillify/legacy-migration.js
1105
1193
  import { existsSync as existsSync4, renameSync as renameSync2 } from "node:fs";
@@ -1154,47 +1242,6 @@ function statePath(projectKey) {
1154
1242
  function lockPath2(projectKey) {
1155
1243
  return join13(getStateDir(), `${projectKey}.lock`);
1156
1244
  }
1157
- var DEFAULT_PORTS = {
1158
- http: "80",
1159
- https: "443",
1160
- ssh: "22",
1161
- git: "9418"
1162
- };
1163
- function normalizeGitRemoteUrl(url) {
1164
- let s = url.trim();
1165
- const schemeMatch = s.match(/^([a-z][a-z0-9+.-]*):\/\//i);
1166
- const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null;
1167
- if (schemeMatch)
1168
- s = s.slice(schemeMatch[0].length);
1169
- if (!scheme) {
1170
- const scp = s.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);
1171
- if (scp)
1172
- s = `${scp[1]}/${scp[2]}`;
1173
- }
1174
- s = s.replace(/^[^@/]+@/, "");
1175
- if (scheme && DEFAULT_PORTS[scheme]) {
1176
- s = s.replace(new RegExp(`^([^/]+):${DEFAULT_PORTS[scheme]}(/|$)`), "$1$2");
1177
- }
1178
- s = s.replace(/\.git\/?$/i, "");
1179
- s = s.replace(/\/+$/, "");
1180
- return s.toLowerCase();
1181
- }
1182
- function deriveProjectKey(cwd) {
1183
- const project = basename(cwd) || "unknown";
1184
- let signature = null;
1185
- try {
1186
- const raw = execSync2("git config --get remote.origin.url", {
1187
- cwd,
1188
- encoding: "utf-8",
1189
- stdio: ["ignore", "pipe", "ignore"]
1190
- }).trim();
1191
- signature = raw ? normalizeGitRemoteUrl(raw) : null;
1192
- } catch {
1193
- }
1194
- const input = signature ?? cwd;
1195
- const key = createHash("sha1").update(input).digest("hex").slice(0, 16);
1196
- return { key, project };
1197
- }
1198
1245
  function readState(projectKey) {
1199
1246
  migrateLegacyStateDir();
1200
1247
  const p = statePath(projectKey);
@@ -1685,7 +1732,7 @@ var EmbedClient = class {
1685
1732
  }
1686
1733
  }
1687
1734
  connectOnce() {
1688
- return new Promise((resolve2, reject) => {
1735
+ return new Promise((resolve3, reject) => {
1689
1736
  const sock = connect(this.socketPath);
1690
1737
  const to = setTimeout(() => {
1691
1738
  sock.destroy();
@@ -1693,7 +1740,7 @@ var EmbedClient = class {
1693
1740
  }, this.timeoutMs);
1694
1741
  sock.once("connect", () => {
1695
1742
  clearTimeout(to);
1696
- resolve2(sock);
1743
+ resolve3(sock);
1697
1744
  });
1698
1745
  sock.once("error", (e) => {
1699
1746
  clearTimeout(to);
@@ -1775,7 +1822,7 @@ var EmbedClient = class {
1775
1822
  throw new Error("daemon did not become ready within spawnWaitMs");
1776
1823
  }
1777
1824
  sendAndWait(sock, req) {
1778
- return new Promise((resolve2, reject) => {
1825
+ return new Promise((resolve3, reject) => {
1779
1826
  let buf = "";
1780
1827
  const to = setTimeout(() => {
1781
1828
  sock.destroy();
@@ -1790,7 +1837,7 @@ var EmbedClient = class {
1790
1837
  const line = buf.slice(0, nl);
1791
1838
  clearTimeout(to);
1792
1839
  try {
1793
- resolve2(JSON.parse(line));
1840
+ resolve3(JSON.parse(line));
1794
1841
  } catch (e) {
1795
1842
  reject(e);
1796
1843
  }
@@ -54,13 +54,13 @@ var init_index_marker_store = __esm({
54
54
 
55
55
  // dist/src/utils/stdin.js
56
56
  function readStdin() {
57
- return new Promise((resolve2, reject) => {
57
+ return new Promise((resolve3, reject) => {
58
58
  let data = "";
59
59
  process.stdin.setEncoding("utf-8");
60
60
  process.stdin.on("data", (chunk) => data += chunk);
61
61
  process.stdin.on("end", () => {
62
62
  try {
63
- resolve2(JSON.parse(data));
63
+ resolve3(JSON.parse(data));
64
64
  } catch (err) {
65
65
  reject(new Error(`Failed to parse hook input: ${err}`));
66
66
  }
@@ -98,6 +98,7 @@ function loadConfig() {
98
98
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
99
99
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
100
100
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
101
+ codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
101
102
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join(home, ".deeplake", "memory")
102
103
  };
103
104
  }
@@ -215,9 +216,33 @@ function validateSchema(label, cols) {
215
216
  }
216
217
  }
217
218
  }
219
+ var CODEBASE_COLUMNS = Object.freeze([
220
+ // Identity key (matches the PK below)
221
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
222
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
223
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
224
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
225
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
226
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
227
+ // Observation metadata
228
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
229
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
230
+ { name: "ts", sql: "TIMESTAMP" },
231
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
232
+ // Snapshot payload
233
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
234
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
235
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
236
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
237
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
238
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
239
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
240
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
241
+ ]);
218
242
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
219
243
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
220
244
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
245
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
221
246
  function buildCreateTableSql(tableName, cols) {
222
247
  const safe = sqlIdent(tableName);
223
248
  const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
@@ -442,7 +467,7 @@ function getQueryTimeoutMs() {
442
467
  return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
443
468
  }
444
469
  function sleep2(ms) {
445
- return new Promise((resolve2) => setTimeout(resolve2, ms));
470
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
446
471
  }
447
472
  function isTimeoutError(error) {
448
473
  const name = error instanceof Error ? error.name.toLowerCase() : "";
@@ -472,7 +497,7 @@ var Semaphore = class {
472
497
  this.active++;
473
498
  return;
474
499
  }
475
- await new Promise((resolve2) => this.waiting.push(resolve2));
500
+ await new Promise((resolve3) => this.waiting.push(resolve3));
476
501
  }
477
502
  release() {
478
503
  this.active--;
@@ -782,6 +807,24 @@ var DeeplakeApi = class {
782
807
  * This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
783
808
  * worker.
784
809
  */
810
+ /**
811
+ * Create the codebase table. One row per (org, workspace, repo, user,
812
+ * worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
813
+ * + index follow the same pattern as ensureSessionsTable.
814
+ */
815
+ async ensureCodebaseTable(name) {
816
+ const safe = sqlIdent(name);
817
+ const tables = await this.listTables();
818
+ if (!tables.includes(safe)) {
819
+ log3(`table "${safe}" not found, creating`);
820
+ await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
821
+ log3(`table "${safe}" created`);
822
+ if (!tables.includes(safe))
823
+ this._tablesCache = [...tables, safe];
824
+ }
825
+ await this.healSchema(safe, CODEBASE_COLUMNS);
826
+ await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
827
+ }
785
828
  async ensureSkillsTable(name) {
786
829
  const safe = sqlIdent(name);
787
830
  const tables = await this.listTables();
@@ -1057,7 +1100,7 @@ var EmbedClient = class {
1057
1100
  }
1058
1101
  }
1059
1102
  connectOnce() {
1060
- return new Promise((resolve2, reject) => {
1103
+ return new Promise((resolve3, reject) => {
1061
1104
  const sock = connect(this.socketPath);
1062
1105
  const to = setTimeout(() => {
1063
1106
  sock.destroy();
@@ -1065,7 +1108,7 @@ var EmbedClient = class {
1065
1108
  }, this.timeoutMs);
1066
1109
  sock.once("connect", () => {
1067
1110
  clearTimeout(to);
1068
- resolve2(sock);
1111
+ resolve3(sock);
1069
1112
  });
1070
1113
  sock.once("error", (e) => {
1071
1114
  clearTimeout(to);
@@ -1147,7 +1190,7 @@ var EmbedClient = class {
1147
1190
  throw new Error("daemon did not become ready within spawnWaitMs");
1148
1191
  }
1149
1192
  sendAndWait(sock, req) {
1150
- return new Promise((resolve2, reject) => {
1193
+ return new Promise((resolve3, reject) => {
1151
1194
  let buf = "";
1152
1195
  const to = setTimeout(() => {
1153
1196
  sock.destroy();
@@ -1162,7 +1205,7 @@ var EmbedClient = class {
1162
1205
  const line = buf.slice(0, nl);
1163
1206
  clearTimeout(to);
1164
1207
  try {
1165
- resolve2(JSON.parse(line));
1208
+ resolve3(JSON.parse(line));
1166
1209
  } catch (e) {
1167
1210
  reject(e);
1168
1211
  }
@@ -1818,9 +1861,54 @@ function spawnSkillifyWorker(opts) {
1818
1861
 
1819
1862
  // dist/src/skillify/state.js
1820
1863
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, writeSync as writeSync3, mkdirSync as mkdirSync10, renameSync as renameSync6, rmdirSync, existsSync as existsSync9, lstatSync as lstatSync2, unlinkSync as unlinkSync5, openSync as openSync4, closeSync as closeSync4 } from "node:fs";
1864
+ import { join as join18 } from "node:path";
1865
+
1866
+ // dist/src/utils/repo-identity.js
1821
1867
  import { execSync as execSync2 } from "node:child_process";
1822
1868
  import { createHash } from "node:crypto";
1823
- import { join as join18, basename as basename2 } from "node:path";
1869
+ import { basename as basename2, resolve as resolve2 } from "node:path";
1870
+ var DEFAULT_PORTS = {
1871
+ http: "80",
1872
+ https: "443",
1873
+ ssh: "22",
1874
+ git: "9418"
1875
+ };
1876
+ function normalizeGitRemoteUrl(url) {
1877
+ let s = url.trim();
1878
+ const schemeMatch = s.match(/^([a-z][a-z0-9+.-]*):\/\//i);
1879
+ const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null;
1880
+ if (schemeMatch)
1881
+ s = s.slice(schemeMatch[0].length);
1882
+ if (!scheme) {
1883
+ const scp = s.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);
1884
+ if (scp)
1885
+ s = `${scp[1]}/${scp[2]}`;
1886
+ }
1887
+ s = s.replace(/^[^@/]+@/, "");
1888
+ if (scheme && DEFAULT_PORTS[scheme]) {
1889
+ s = s.replace(new RegExp(`^([^/]+):${DEFAULT_PORTS[scheme]}(/|$)`), "$1$2");
1890
+ }
1891
+ s = s.replace(/\.git\/?$/i, "");
1892
+ s = s.replace(/\/+$/, "");
1893
+ return s.toLowerCase();
1894
+ }
1895
+ function deriveProjectKey(cwd) {
1896
+ const absCwd = resolve2(cwd);
1897
+ const project = basename2(absCwd) || "unknown";
1898
+ let signature = null;
1899
+ try {
1900
+ const raw = execSync2("git config --get remote.origin.url", {
1901
+ cwd: absCwd,
1902
+ encoding: "utf-8",
1903
+ stdio: ["ignore", "pipe", "ignore"]
1904
+ }).trim();
1905
+ signature = raw ? normalizeGitRemoteUrl(raw) : null;
1906
+ } catch {
1907
+ }
1908
+ const input = signature ?? absCwd;
1909
+ const key = createHash("sha1").update(input).digest("hex").slice(0, 16);
1910
+ return { key, project };
1911
+ }
1824
1912
 
1825
1913
  // dist/src/skillify/legacy-migration.js
1826
1914
  import { existsSync as existsSync8, renameSync as renameSync5 } from "node:fs";
@@ -1875,47 +1963,6 @@ function statePath2(projectKey) {
1875
1963
  function lockPath3(projectKey) {
1876
1964
  return join18(getStateDir(), `${projectKey}.lock`);
1877
1965
  }
1878
- var DEFAULT_PORTS = {
1879
- http: "80",
1880
- https: "443",
1881
- ssh: "22",
1882
- git: "9418"
1883
- };
1884
- function normalizeGitRemoteUrl(url) {
1885
- let s = url.trim();
1886
- const schemeMatch = s.match(/^([a-z][a-z0-9+.-]*):\/\//i);
1887
- const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null;
1888
- if (schemeMatch)
1889
- s = s.slice(schemeMatch[0].length);
1890
- if (!scheme) {
1891
- const scp = s.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);
1892
- if (scp)
1893
- s = `${scp[1]}/${scp[2]}`;
1894
- }
1895
- s = s.replace(/^[^@/]+@/, "");
1896
- if (scheme && DEFAULT_PORTS[scheme]) {
1897
- s = s.replace(new RegExp(`^([^/]+):${DEFAULT_PORTS[scheme]}(/|$)`), "$1$2");
1898
- }
1899
- s = s.replace(/\.git\/?$/i, "");
1900
- s = s.replace(/\/+$/, "");
1901
- return s.toLowerCase();
1902
- }
1903
- function deriveProjectKey(cwd) {
1904
- const project = basename2(cwd) || "unknown";
1905
- let signature = null;
1906
- try {
1907
- const raw = execSync2("git config --get remote.origin.url", {
1908
- cwd,
1909
- encoding: "utf-8",
1910
- stdio: ["ignore", "pipe", "ignore"]
1911
- }).trim();
1912
- signature = raw ? normalizeGitRemoteUrl(raw) : null;
1913
- } catch {
1914
- }
1915
- const input = signature ?? cwd;
1916
- const key = createHash("sha1").update(input).digest("hex").slice(0, 16);
1917
- return { key, project };
1918
- }
1919
1966
  function readState2(projectKey) {
1920
1967
  migrateLegacyStateDir();
1921
1968
  const p = statePath2(projectKey);
@@ -384,6 +384,7 @@ function loadConfig() {
384
384
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
385
385
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
386
386
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
387
+ codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
387
388
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join3(home, ".deeplake", "memory")
388
389
  };
389
390
  }
@@ -489,9 +490,33 @@ function validateSchema(label, cols) {
489
490
  }
490
491
  }
491
492
  }
493
+ var CODEBASE_COLUMNS = Object.freeze([
494
+ // Identity key (matches the PK below)
495
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
496
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
497
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
498
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
499
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
500
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
501
+ // Observation metadata
502
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
503
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
504
+ { name: "ts", sql: "TIMESTAMP" },
505
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
506
+ // Snapshot payload
507
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
508
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
509
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
510
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
511
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
512
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
513
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
514
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
515
+ ]);
492
516
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
493
517
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
494
518
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
519
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
495
520
  function buildCreateTableSql(tableName, cols) {
496
521
  const safe = sqlIdent(tableName);
497
522
  const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
@@ -1038,6 +1063,24 @@ var DeeplakeApi = class {
1038
1063
  * This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
1039
1064
  * worker.
1040
1065
  */
1066
+ /**
1067
+ * Create the codebase table. One row per (org, workspace, repo, user,
1068
+ * worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
1069
+ * + index follow the same pattern as ensureSessionsTable.
1070
+ */
1071
+ async ensureCodebaseTable(name) {
1072
+ const safe = sqlIdent(name);
1073
+ const tables = await this.listTables();
1074
+ if (!tables.includes(safe)) {
1075
+ log3(`table "${safe}" not found, creating`);
1076
+ await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
1077
+ log3(`table "${safe}" created`);
1078
+ if (!tables.includes(safe))
1079
+ this._tablesCache = [...tables, safe];
1080
+ }
1081
+ await this.healSchema(safe, CODEBASE_COLUMNS);
1082
+ await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
1083
+ }
1041
1084
  async ensureSkillsTable(name) {
1042
1085
  const safe = sqlIdent(name);
1043
1086
  const tables = await this.listTables();