@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.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/bundle/cli.js +2215 -341
- package/codex/bundle/capture.js +43 -0
- package/codex/bundle/commands/auth-login.js +43 -0
- package/codex/bundle/graph-pull-worker.js +1185 -0
- package/codex/bundle/pre-tool-use.js +43 -0
- package/codex/bundle/session-start-setup.js +43 -0
- package/codex/bundle/session-start.js +70 -4
- package/codex/bundle/shell/deeplake-shell.js +577 -25
- package/codex/bundle/skillify-worker.js +30 -3
- package/codex/bundle/stop.js +97 -50
- package/cursor/bundle/capture.js +97 -50
- package/cursor/bundle/commands/auth-login.js +43 -0
- package/cursor/bundle/graph-pull-worker.js +1185 -0
- package/cursor/bundle/pre-tool-use.js +43 -0
- package/cursor/bundle/session-end.js +49 -44
- package/cursor/bundle/session-start.js +66 -0
- package/cursor/bundle/shell/deeplake-shell.js +577 -25
- package/cursor/bundle/skillify-worker.js +30 -3
- package/hermes/bundle/capture.js +97 -50
- package/hermes/bundle/commands/auth-login.js +43 -0
- package/hermes/bundle/graph-pull-worker.js +1185 -0
- package/hermes/bundle/pre-tool-use.js +43 -0
- package/hermes/bundle/session-end.js +49 -44
- package/hermes/bundle/session-start.js +66 -0
- package/hermes/bundle/shell/deeplake-shell.js +577 -25
- package/hermes/bundle/skillify-worker.js +30 -3
- package/mcp/bundle/server.js +43 -0
- package/openclaw/dist/chunks/{config-XEK4MJJS.js → config-O5PDJQ7Y.js} +1 -0
- package/openclaw/dist/index.js +47 -2
- package/openclaw/dist/skillify-worker.js +30 -3
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- 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 {
|
|
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((
|
|
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((
|
|
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)}`);
|
package/codex/bundle/stop.js
CHANGED
|
@@ -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((
|
|
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
|
-
|
|
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((
|
|
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((
|
|
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 {
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
1840
|
+
resolve3(JSON.parse(line));
|
|
1794
1841
|
} catch (e) {
|
|
1795
1842
|
reject(e);
|
|
1796
1843
|
}
|
package/cursor/bundle/capture.js
CHANGED
|
@@ -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((
|
|
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
|
-
|
|
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((
|
|
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((
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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 {
|
|
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();
|