@deeplake/hivemind 0.6.48 → 0.7.9

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 (45) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +244 -20
  4. package/bundle/cli.js +1369 -112
  5. package/codex/bundle/capture.js +546 -96
  6. package/codex/bundle/commands/auth-login.js +290 -81
  7. package/codex/bundle/embeddings/embed-daemon.js +243 -0
  8. package/codex/bundle/pre-tool-use.js +666 -111
  9. package/codex/bundle/session-start-setup.js +231 -64
  10. package/codex/bundle/session-start.js +52 -13
  11. package/codex/bundle/shell/deeplake-shell.js +716 -119
  12. package/codex/bundle/skilify-worker.js +907 -0
  13. package/codex/bundle/stop.js +819 -79
  14. package/codex/bundle/wiki-worker.js +312 -11
  15. package/cursor/bundle/capture.js +1116 -64
  16. package/cursor/bundle/commands/auth-login.js +290 -81
  17. package/cursor/bundle/embeddings/embed-daemon.js +243 -0
  18. package/cursor/bundle/pre-tool-use.js +598 -77
  19. package/cursor/bundle/session-end.js +520 -2
  20. package/cursor/bundle/session-start.js +257 -65
  21. package/cursor/bundle/shell/deeplake-shell.js +716 -119
  22. package/cursor/bundle/skilify-worker.js +907 -0
  23. package/cursor/bundle/wiki-worker.js +571 -0
  24. package/hermes/bundle/capture.js +1119 -65
  25. package/hermes/bundle/commands/auth-login.js +290 -81
  26. package/hermes/bundle/embeddings/embed-daemon.js +243 -0
  27. package/hermes/bundle/pre-tool-use.js +597 -76
  28. package/hermes/bundle/session-end.js +522 -1
  29. package/hermes/bundle/session-start.js +260 -65
  30. package/hermes/bundle/shell/deeplake-shell.js +716 -119
  31. package/hermes/bundle/skilify-worker.js +907 -0
  32. package/hermes/bundle/wiki-worker.js +572 -0
  33. package/mcp/bundle/server.js +290 -75
  34. package/openclaw/dist/chunks/auth-creds-AEKS6D3P.js +14 -0
  35. package/openclaw/dist/chunks/chunk-SRCBBT4H.js +37 -0
  36. package/openclaw/dist/chunks/config-ZLH6JFJS.js +34 -0
  37. package/openclaw/dist/chunks/index-marker-store-PGT5CW6T.js +33 -0
  38. package/openclaw/dist/chunks/setup-config-C35UK4LP.js +114 -0
  39. package/openclaw/dist/index.js +929 -710
  40. package/openclaw/dist/skilify-worker.js +907 -0
  41. package/openclaw/openclaw.plugin.json +1 -1
  42. package/openclaw/package.json +1 -1
  43. package/openclaw/skills/SKILL.md +19 -0
  44. package/package.json +7 -1
  45. package/pi/extension-source/hivemind.ts +603 -22
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // dist/src/hooks/codex/wiki-worker.js
4
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, appendFileSync as appendFileSync2, mkdirSync as mkdirSync2, rmSync } from "node:fs";
4
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, appendFileSync as appendFileSync2, mkdirSync as mkdirSync2, rmSync } from "node:fs";
5
5
  import { execFileSync } from "node:child_process";
6
- import { join as join3 } from "node:path";
6
+ import { dirname, join as join5 } from "node:path";
7
+ import { fileURLToPath } from "node:url";
7
8
 
8
9
  // dist/src/hooks/summary-state.js
9
10
  import { readFileSync, writeFileSync, writeSync, mkdirSync, renameSync, existsSync, unlinkSync, openSync, closeSync } from "node:fs";
@@ -106,6 +107,21 @@ function releaseLock(sessionId) {
106
107
 
107
108
  // dist/src/hooks/upload-summary.js
108
109
  import { randomUUID } from "node:crypto";
110
+
111
+ // dist/src/embeddings/sql.js
112
+ function embeddingSqlLiteral(vec) {
113
+ if (!vec || vec.length === 0)
114
+ return "NULL";
115
+ const parts = [];
116
+ for (const v of vec) {
117
+ if (!Number.isFinite(v))
118
+ return "NULL";
119
+ parts.push(String(v));
120
+ }
121
+ return `ARRAY[${parts.join(",")}]::float4[]`;
122
+ }
123
+
124
+ // dist/src/hooks/upload-summary.js
109
125
  function esc(s) {
110
126
  return s.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
111
127
  }
@@ -118,23 +134,297 @@ async function uploadSummary(query2, params) {
118
134
  const ts = params.ts ?? (/* @__PURE__ */ new Date()).toISOString();
119
135
  const desc = extractDescription(text);
120
136
  const sizeBytes = Buffer.byteLength(text);
137
+ const embSql = embeddingSqlLiteral(params.embedding ?? null);
121
138
  const existing = await query2(`SELECT path FROM "${tableName}" WHERE path = '${esc(vpath)}' LIMIT 1`);
122
139
  if (existing.length > 0) {
123
- const sql2 = `UPDATE "${tableName}" SET summary = E'${esc(text)}', size_bytes = ${sizeBytes}, description = E'${esc(desc)}', last_update_date = '${ts}' WHERE path = '${esc(vpath)}'`;
140
+ const sql2 = `UPDATE "${tableName}" SET summary = E'${esc(text)}', summary_embedding = ${embSql}, size_bytes = ${sizeBytes}, description = E'${esc(desc)}', last_update_date = '${ts}' WHERE path = '${esc(vpath)}'`;
124
141
  await query2(sql2);
125
142
  return { path: "update", sql: sql2, descLength: desc.length, summaryLength: text.length };
126
143
  }
127
- const sql = `INSERT INTO "${tableName}" (id, path, filename, summary, author, mime_type, size_bytes, project, description, agent, creation_date, last_update_date) VALUES ('${randomUUID()}', '${esc(vpath)}', '${esc(fname)}', E'${esc(text)}', '${esc(userName)}', 'text/markdown', ${sizeBytes}, '${esc(project)}', E'${esc(desc)}', '${esc(agent)}', '${ts}', '${ts}')`;
144
+ const sql = `INSERT INTO "${tableName}" (id, path, filename, summary, summary_embedding, author, mime_type, size_bytes, project, description, agent, creation_date, last_update_date) VALUES ('${randomUUID()}', '${esc(vpath)}', '${esc(fname)}', E'${esc(text)}', ${embSql}, '${esc(userName)}', 'text/markdown', ${sizeBytes}, '${esc(project)}', E'${esc(desc)}', '${esc(agent)}', '${ts}', '${ts}')`;
128
145
  await query2(sql);
129
146
  return { path: "insert", sql, descLength: desc.length, summaryLength: text.length };
130
147
  }
131
148
 
149
+ // dist/src/embeddings/client.js
150
+ import { connect } from "node:net";
151
+ import { spawn } from "node:child_process";
152
+ import { openSync as openSync2, closeSync as closeSync2, writeSync as writeSync2, unlinkSync as unlinkSync2, existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
153
+ import { homedir as homedir3 } from "node:os";
154
+ import { join as join3 } from "node:path";
155
+
156
+ // dist/src/embeddings/protocol.js
157
+ var DEFAULT_SOCKET_DIR = "/tmp";
158
+ var DEFAULT_IDLE_TIMEOUT_MS = 10 * 60 * 1e3;
159
+ var DEFAULT_CLIENT_TIMEOUT_MS = 2e3;
160
+ function socketPathFor(uid, dir = DEFAULT_SOCKET_DIR) {
161
+ return `${dir}/hivemind-embed-${uid}.sock`;
162
+ }
163
+ function pidPathFor(uid, dir = DEFAULT_SOCKET_DIR) {
164
+ return `${dir}/hivemind-embed-${uid}.pid`;
165
+ }
166
+
167
+ // dist/src/embeddings/client.js
168
+ var SHARED_DAEMON_PATH = join3(homedir3(), ".hivemind", "embed-deps", "embed-daemon.js");
169
+ var log2 = (m) => log("embed-client", m);
170
+ function getUid() {
171
+ const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
172
+ return uid !== void 0 ? String(uid) : process.env.USER ?? "default";
173
+ }
174
+ var EmbedClient = class {
175
+ socketPath;
176
+ pidPath;
177
+ timeoutMs;
178
+ daemonEntry;
179
+ autoSpawn;
180
+ spawnWaitMs;
181
+ nextId = 0;
182
+ constructor(opts = {}) {
183
+ const uid = getUid();
184
+ const dir = opts.socketDir ?? "/tmp";
185
+ this.socketPath = socketPathFor(uid, dir);
186
+ this.pidPath = pidPathFor(uid, dir);
187
+ this.timeoutMs = opts.timeoutMs ?? DEFAULT_CLIENT_TIMEOUT_MS;
188
+ this.daemonEntry = opts.daemonEntry ?? process.env.HIVEMIND_EMBED_DAEMON ?? (existsSync2(SHARED_DAEMON_PATH) ? SHARED_DAEMON_PATH : void 0);
189
+ this.autoSpawn = opts.autoSpawn ?? true;
190
+ this.spawnWaitMs = opts.spawnWaitMs ?? 5e3;
191
+ }
192
+ /**
193
+ * Returns an embedding vector, or null on timeout/failure. Hooks MUST treat
194
+ * null as "skip embedding column" — never block the write path on us.
195
+ *
196
+ * Fire-and-forget spawn on miss: if the daemon isn't up, this call returns
197
+ * null AND kicks off a background spawn. The next call finds a ready daemon.
198
+ */
199
+ async embed(text, kind = "document") {
200
+ let sock;
201
+ try {
202
+ sock = await this.connectOnce();
203
+ } catch {
204
+ if (this.autoSpawn)
205
+ this.trySpawnDaemon();
206
+ return null;
207
+ }
208
+ try {
209
+ const id = String(++this.nextId);
210
+ const req = { op: "embed", id, kind, text };
211
+ const resp = await this.sendAndWait(sock, req);
212
+ if (resp.error || !("embedding" in resp) || !resp.embedding) {
213
+ log2(`embed err: ${resp.error ?? "no embedding"}`);
214
+ return null;
215
+ }
216
+ return resp.embedding;
217
+ } catch (e) {
218
+ const err = e instanceof Error ? e.message : String(e);
219
+ log2(`embed failed: ${err}`);
220
+ return null;
221
+ } finally {
222
+ try {
223
+ sock.end();
224
+ } catch {
225
+ }
226
+ }
227
+ }
228
+ /**
229
+ * Wait up to spawnWaitMs for the daemon to accept connections, spawning if
230
+ * necessary. Meant for SessionStart / long-running batches — not the hot path.
231
+ */
232
+ async warmup() {
233
+ try {
234
+ const s = await this.connectOnce();
235
+ s.end();
236
+ return true;
237
+ } catch {
238
+ if (!this.autoSpawn)
239
+ return false;
240
+ this.trySpawnDaemon();
241
+ try {
242
+ const s = await this.waitForSocket();
243
+ s.end();
244
+ return true;
245
+ } catch {
246
+ return false;
247
+ }
248
+ }
249
+ }
250
+ connectOnce() {
251
+ return new Promise((resolve, reject) => {
252
+ const sock = connect(this.socketPath);
253
+ const to = setTimeout(() => {
254
+ sock.destroy();
255
+ reject(new Error("connect timeout"));
256
+ }, this.timeoutMs);
257
+ sock.once("connect", () => {
258
+ clearTimeout(to);
259
+ resolve(sock);
260
+ });
261
+ sock.once("error", (e) => {
262
+ clearTimeout(to);
263
+ reject(e);
264
+ });
265
+ });
266
+ }
267
+ trySpawnDaemon() {
268
+ let fd;
269
+ try {
270
+ fd = openSync2(this.pidPath, "wx", 384);
271
+ writeSync2(fd, String(process.pid));
272
+ } catch (e) {
273
+ if (this.isPidFileStale()) {
274
+ try {
275
+ unlinkSync2(this.pidPath);
276
+ } catch {
277
+ }
278
+ try {
279
+ fd = openSync2(this.pidPath, "wx", 384);
280
+ writeSync2(fd, String(process.pid));
281
+ } catch {
282
+ return;
283
+ }
284
+ } else {
285
+ return;
286
+ }
287
+ }
288
+ if (!this.daemonEntry || !existsSync2(this.daemonEntry)) {
289
+ log2(`daemonEntry not configured or missing: ${this.daemonEntry}`);
290
+ try {
291
+ closeSync2(fd);
292
+ unlinkSync2(this.pidPath);
293
+ } catch {
294
+ }
295
+ return;
296
+ }
297
+ try {
298
+ const child = spawn(process.execPath, [this.daemonEntry], {
299
+ detached: true,
300
+ stdio: "ignore",
301
+ env: process.env
302
+ });
303
+ child.unref();
304
+ log2(`spawned daemon pid=${child.pid}`);
305
+ } finally {
306
+ closeSync2(fd);
307
+ }
308
+ }
309
+ isPidFileStale() {
310
+ try {
311
+ const raw = readFileSync2(this.pidPath, "utf-8").trim();
312
+ const pid = Number(raw);
313
+ if (!pid || Number.isNaN(pid))
314
+ return true;
315
+ try {
316
+ process.kill(pid, 0);
317
+ return false;
318
+ } catch {
319
+ return true;
320
+ }
321
+ } catch {
322
+ return true;
323
+ }
324
+ }
325
+ async waitForSocket() {
326
+ const deadline = Date.now() + this.spawnWaitMs;
327
+ let delay = 30;
328
+ while (Date.now() < deadline) {
329
+ await sleep(delay);
330
+ delay = Math.min(delay * 1.5, 300);
331
+ if (!existsSync2(this.socketPath))
332
+ continue;
333
+ try {
334
+ return await this.connectOnce();
335
+ } catch {
336
+ }
337
+ }
338
+ throw new Error("daemon did not become ready within spawnWaitMs");
339
+ }
340
+ sendAndWait(sock, req) {
341
+ return new Promise((resolve, reject) => {
342
+ let buf = "";
343
+ const to = setTimeout(() => {
344
+ sock.destroy();
345
+ reject(new Error("request timeout"));
346
+ }, this.timeoutMs);
347
+ sock.setEncoding("utf-8");
348
+ sock.on("data", (chunk) => {
349
+ buf += chunk;
350
+ const nl = buf.indexOf("\n");
351
+ if (nl === -1)
352
+ return;
353
+ const line = buf.slice(0, nl);
354
+ clearTimeout(to);
355
+ try {
356
+ resolve(JSON.parse(line));
357
+ } catch (e) {
358
+ reject(e);
359
+ }
360
+ });
361
+ sock.on("error", (e) => {
362
+ clearTimeout(to);
363
+ reject(e);
364
+ });
365
+ sock.on("end", () => {
366
+ clearTimeout(to);
367
+ reject(new Error("connection closed without response"));
368
+ });
369
+ sock.write(JSON.stringify(req) + "\n");
370
+ });
371
+ }
372
+ };
373
+ function sleep(ms) {
374
+ return new Promise((r) => setTimeout(r, ms));
375
+ }
376
+
377
+ // dist/src/embeddings/disable.js
378
+ import { createRequire } from "node:module";
379
+ import { homedir as homedir4 } from "node:os";
380
+ import { join as join4 } from "node:path";
381
+ import { pathToFileURL } from "node:url";
382
+ var cachedStatus = null;
383
+ function defaultResolveTransformers() {
384
+ try {
385
+ createRequire(import.meta.url).resolve("@huggingface/transformers");
386
+ return;
387
+ } catch {
388
+ }
389
+ const sharedDir = join4(homedir4(), ".hivemind", "embed-deps");
390
+ createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
391
+ }
392
+ var _resolve = defaultResolveTransformers;
393
+ function detectStatus() {
394
+ if (process.env.HIVEMIND_EMBEDDINGS === "false")
395
+ return "env-disabled";
396
+ try {
397
+ _resolve();
398
+ return "enabled";
399
+ } catch {
400
+ return "no-transformers";
401
+ }
402
+ }
403
+ function embeddingsStatus() {
404
+ if (cachedStatus !== null)
405
+ return cachedStatus;
406
+ cachedStatus = detectStatus();
407
+ return cachedStatus;
408
+ }
409
+ function embeddingsDisabled() {
410
+ return embeddingsStatus() !== "enabled";
411
+ }
412
+
413
+ // dist/src/utils/client-header.js
414
+ var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client";
415
+ function deeplakeClientValue() {
416
+ return "hivemind";
417
+ }
418
+ function deeplakeClientHeader() {
419
+ return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
420
+ }
421
+
132
422
  // dist/src/hooks/codex/wiki-worker.js
133
423
  var dlog2 = (msg) => log("codex-wiki-worker", msg);
134
- var cfg = JSON.parse(readFileSync2(process.argv[2], "utf-8"));
424
+ var cfg = JSON.parse(readFileSync3(process.argv[2], "utf-8"));
135
425
  var tmpDir = cfg.tmpDir;
136
- var tmpJsonl = join3(tmpDir, "session.jsonl");
137
- var tmpSummary = join3(tmpDir, "summary.md");
426
+ var tmpJsonl = join5(tmpDir, "session.jsonl");
427
+ var tmpSummary = join5(tmpDir, "summary.md");
138
428
  function wlog(msg) {
139
429
  try {
140
430
  mkdirSync2(cfg.hooksDir, { recursive: true });
@@ -153,7 +443,8 @@ async function query(sql, retries = 4) {
153
443
  headers: {
154
444
  Authorization: `Bearer ${cfg.token}`,
155
445
  "Content-Type": "application/json",
156
- "X-Activeloop-Org-Id": cfg.orgId
446
+ "X-Activeloop-Org-Id": cfg.orgId,
447
+ ...deeplakeClientHeader()
157
448
  },
158
449
  body: JSON.stringify({ query: sql })
159
450
  });
@@ -225,11 +516,20 @@ async function main() {
225
516
  } catch (e) {
226
517
  wlog(`codex exec failed: ${e.status ?? e.message}`);
227
518
  }
228
- if (existsSync2(tmpSummary)) {
229
- const text = readFileSync2(tmpSummary, "utf-8");
519
+ if (existsSync3(tmpSummary)) {
520
+ const text = readFileSync3(tmpSummary, "utf-8");
230
521
  if (text.trim()) {
231
522
  const fname = `${cfg.sessionId}.md`;
232
523
  const vpath = `/summaries/${cfg.userName}/${fname}`;
524
+ let embedding = null;
525
+ if (!embeddingsDisabled()) {
526
+ try {
527
+ const daemonEntry = join5(dirname(fileURLToPath(import.meta.url)), "embeddings", "embed-daemon.js");
528
+ embedding = await new EmbedClient({ daemonEntry }).embed(text, "document");
529
+ } catch (e) {
530
+ wlog(`summary embedding failed, writing NULL: ${e.message}`);
531
+ }
532
+ }
233
533
  const result = await uploadSummary(query, {
234
534
  tableName: cfg.memoryTable,
235
535
  vpath,
@@ -238,7 +538,8 @@ async function main() {
238
538
  project: cfg.project,
239
539
  agent: "codex",
240
540
  sessionId: cfg.sessionId,
241
- text
541
+ text,
542
+ embedding
242
543
  });
243
544
  wlog(`uploaded ${vpath} (summary=${result.summaryLength}, desc=${result.descLength})`);
244
545
  try {