@deeplake/hivemind 0.6.48 → 0.7.4
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 +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +147 -20
- package/bundle/cli.js +552 -95
- package/codex/bundle/capture.js +509 -89
- package/codex/bundle/commands/auth-login.js +209 -66
- package/codex/bundle/embeddings/embed-daemon.js +243 -0
- package/codex/bundle/pre-tool-use.js +629 -104
- package/codex/bundle/session-start-setup.js +194 -57
- package/codex/bundle/session-start.js +25 -10
- package/codex/bundle/shell/deeplake-shell.js +679 -112
- package/codex/bundle/stop.js +476 -58
- package/codex/bundle/wiki-worker.js +312 -11
- package/cursor/bundle/capture.js +768 -57
- package/cursor/bundle/commands/auth-login.js +209 -66
- package/cursor/bundle/embeddings/embed-daemon.js +243 -0
- package/cursor/bundle/pre-tool-use.js +561 -70
- package/cursor/bundle/session-end.js +223 -2
- package/cursor/bundle/session-start.js +192 -54
- package/cursor/bundle/shell/deeplake-shell.js +679 -112
- package/cursor/bundle/wiki-worker.js +571 -0
- package/hermes/bundle/capture.js +771 -58
- package/hermes/bundle/commands/auth-login.js +209 -66
- package/hermes/bundle/embeddings/embed-daemon.js +243 -0
- package/hermes/bundle/pre-tool-use.js +560 -69
- package/hermes/bundle/session-end.js +224 -1
- package/hermes/bundle/session-start.js +195 -54
- package/hermes/bundle/shell/deeplake-shell.js +679 -112
- package/hermes/bundle/wiki-worker.js +572 -0
- package/mcp/bundle/server.js +253 -68
- package/openclaw/dist/chunks/auth-creds-AEKS6D3P.js +14 -0
- package/openclaw/dist/chunks/chunk-SRCBBT4H.js +37 -0
- package/openclaw/dist/chunks/config-G23NI5TV.js +33 -0
- package/openclaw/dist/chunks/index-marker-store-PGT5CW6T.js +33 -0
- package/openclaw/dist/chunks/setup-config-C35UK4LP.js +114 -0
- package/openclaw/dist/index.js +752 -702
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/package.json +2 -1
- package/pi/extension-source/hivemind.ts +473 -21
package/bundle/cli.js
CHANGED
|
@@ -1,4 +1,56 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// dist/src/index-marker-store.js
|
|
13
|
+
var index_marker_store_exports = {};
|
|
14
|
+
__export(index_marker_store_exports, {
|
|
15
|
+
buildIndexMarkerPath: () => buildIndexMarkerPath,
|
|
16
|
+
getIndexMarkerDir: () => getIndexMarkerDir,
|
|
17
|
+
hasFreshIndexMarker: () => hasFreshIndexMarker,
|
|
18
|
+
writeIndexMarker: () => writeIndexMarker
|
|
19
|
+
});
|
|
20
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
21
|
+
import { join as join14 } from "node:path";
|
|
22
|
+
import { tmpdir } from "node:os";
|
|
23
|
+
function getIndexMarkerDir() {
|
|
24
|
+
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join14(tmpdir(), "hivemind-deeplake-indexes");
|
|
25
|
+
}
|
|
26
|
+
function buildIndexMarkerPath(workspaceId, orgId, table, suffix) {
|
|
27
|
+
const markerKey = [workspaceId, orgId, table, suffix].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
28
|
+
return join14(getIndexMarkerDir(), `${markerKey}.json`);
|
|
29
|
+
}
|
|
30
|
+
function hasFreshIndexMarker(markerPath) {
|
|
31
|
+
if (!existsSync11(markerPath))
|
|
32
|
+
return false;
|
|
33
|
+
try {
|
|
34
|
+
const raw = JSON.parse(readFileSync8(markerPath, "utf-8"));
|
|
35
|
+
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
36
|
+
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
37
|
+
return false;
|
|
38
|
+
return true;
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function writeIndexMarker(markerPath) {
|
|
44
|
+
mkdirSync3(getIndexMarkerDir(), { recursive: true });
|
|
45
|
+
writeFileSync5(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
46
|
+
}
|
|
47
|
+
var INDEX_MARKER_TTL_MS;
|
|
48
|
+
var init_index_marker_store = __esm({
|
|
49
|
+
"dist/src/index-marker-store.js"() {
|
|
50
|
+
"use strict";
|
|
51
|
+
INDEX_MARKER_TTL_MS = Number(process.env.HIVEMIND_INDEX_MARKER_TTL_MS ?? 6 * 60 * 6e4);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
2
54
|
|
|
3
55
|
// dist/src/cli/install-claude.js
|
|
4
56
|
import { execFileSync } from "node:child_process";
|
|
@@ -10,6 +62,19 @@ import { homedir } from "node:os";
|
|
|
10
62
|
import { fileURLToPath } from "node:url";
|
|
11
63
|
var HOME = homedir();
|
|
12
64
|
function pkgRoot() {
|
|
65
|
+
let dir = fileURLToPath(new URL(".", import.meta.url));
|
|
66
|
+
for (let i = 0; i < 8; i++) {
|
|
67
|
+
try {
|
|
68
|
+
const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8"));
|
|
69
|
+
if (pkg.name === "@deeplake/hivemind" || pkg.name === "hivemind")
|
|
70
|
+
return dir;
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
const parent = dirname(dir);
|
|
74
|
+
if (parent === dir)
|
|
75
|
+
break;
|
|
76
|
+
dir = parent;
|
|
77
|
+
}
|
|
13
78
|
return fileURLToPath(new URL("..", import.meta.url));
|
|
14
79
|
}
|
|
15
80
|
function ensureDir(path, mode = 493) {
|
|
@@ -187,7 +252,15 @@ function buildHooksJson() {
|
|
|
187
252
|
}
|
|
188
253
|
};
|
|
189
254
|
}
|
|
190
|
-
|
|
255
|
+
var HIVEMIND_BUNDLE_FILES = [
|
|
256
|
+
"session-start.js",
|
|
257
|
+
"session-start-setup.js",
|
|
258
|
+
"capture.js",
|
|
259
|
+
"pre-tool-use.js",
|
|
260
|
+
"stop.js",
|
|
261
|
+
"wiki-worker.js"
|
|
262
|
+
];
|
|
263
|
+
function isHivemindHookEntry(entry, pluginDir = PLUGIN_DIR) {
|
|
191
264
|
if (!entry || typeof entry !== "object")
|
|
192
265
|
return false;
|
|
193
266
|
const e = entry;
|
|
@@ -196,9 +269,41 @@ function isHivemindHookEntry(entry) {
|
|
|
196
269
|
if (!h || typeof h !== "object")
|
|
197
270
|
return false;
|
|
198
271
|
const cmd = h.command;
|
|
199
|
-
|
|
272
|
+
if (typeof cmd !== "string")
|
|
273
|
+
return false;
|
|
274
|
+
if (cmd.includes(`${pluginDir}/bundle/`))
|
|
275
|
+
return true;
|
|
276
|
+
return HIVEMIND_BUNDLE_FILES.some((f) => cmd.includes(`/bundle/${f}`));
|
|
200
277
|
});
|
|
201
278
|
}
|
|
279
|
+
function isForeignHivemindHookEntry(entry, pluginDir = PLUGIN_DIR) {
|
|
280
|
+
if (!isHivemindHookEntry(entry, pluginDir))
|
|
281
|
+
return false;
|
|
282
|
+
const e = entry;
|
|
283
|
+
const hooks = Array.isArray(e.hooks) ? e.hooks : [];
|
|
284
|
+
return hooks.every((h) => {
|
|
285
|
+
if (!h || typeof h !== "object")
|
|
286
|
+
return false;
|
|
287
|
+
const cmd = h.command;
|
|
288
|
+
if (typeof cmd !== "string")
|
|
289
|
+
return false;
|
|
290
|
+
return !cmd.includes(`${pluginDir}/bundle/`);
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
function mergeHooks(existing, ours, pluginDir = PLUGIN_DIR) {
|
|
294
|
+
const existingHooks = existing.hooks && typeof existing.hooks === "object" ? existing.hooks : {};
|
|
295
|
+
const ourHooks = ours.hooks;
|
|
296
|
+
const merged = {};
|
|
297
|
+
for (const [event, entries] of Object.entries(existingHooks)) {
|
|
298
|
+
const surviving = (entries ?? []).filter((e) => !isHivemindHookEntry(e, pluginDir));
|
|
299
|
+
if (surviving.length)
|
|
300
|
+
merged[event] = surviving;
|
|
301
|
+
}
|
|
302
|
+
for (const [event, entries] of Object.entries(ourHooks)) {
|
|
303
|
+
merged[event] = [...merged[event] ?? [], ...entries ?? []];
|
|
304
|
+
}
|
|
305
|
+
return { ...existing, hooks: merged };
|
|
306
|
+
}
|
|
202
307
|
function mergeHooksJson(ours) {
|
|
203
308
|
let existing = {};
|
|
204
309
|
try {
|
|
@@ -210,18 +315,30 @@ function mergeHooksJson(ours) {
|
|
|
210
315
|
} catch {
|
|
211
316
|
warn(` Codex ${HOOKS_PATH} unparseable \u2014 ignoring prior content`);
|
|
212
317
|
}
|
|
318
|
+
reportForeignHivemindHooks(existing);
|
|
319
|
+
return mergeHooks(existing, ours);
|
|
320
|
+
}
|
|
321
|
+
function reportForeignHivemindHooks(existing) {
|
|
213
322
|
const existingHooks = existing.hooks && typeof existing.hooks === "object" ? existing.hooks : {};
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
323
|
+
const foreign = /* @__PURE__ */ new Set();
|
|
324
|
+
for (const entries of Object.values(existingHooks)) {
|
|
325
|
+
for (const e of entries ?? []) {
|
|
326
|
+
if (!isForeignHivemindHookEntry(e))
|
|
327
|
+
continue;
|
|
328
|
+
const hooks = Array.isArray(e.hooks) ? e.hooks : [];
|
|
329
|
+
for (const h of hooks) {
|
|
330
|
+
const cmd = h?.command;
|
|
331
|
+
if (typeof cmd === "string")
|
|
332
|
+
foreign.add(cmd);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
223
335
|
}
|
|
224
|
-
|
|
336
|
+
if (foreign.size === 0)
|
|
337
|
+
return;
|
|
338
|
+
warn(` Codex stripping ${foreign.size} hivemind hook(s) from a non-canonical path:`);
|
|
339
|
+
for (const cmd of foreign)
|
|
340
|
+
warn(` ${cmd}`);
|
|
341
|
+
warn(` (these were probably leftover from a local dev clone \u2014 re-add them manually if intentional)`);
|
|
225
342
|
}
|
|
226
343
|
function tryEnableCodexHooks() {
|
|
227
344
|
try {
|
|
@@ -253,8 +370,28 @@ function installCodex() {
|
|
|
253
370
|
}
|
|
254
371
|
function uninstallCodex() {
|
|
255
372
|
if (existsSync2(HOOKS_PATH)) {
|
|
256
|
-
|
|
257
|
-
|
|
373
|
+
let existing = {};
|
|
374
|
+
try {
|
|
375
|
+
const raw = JSON.parse(readFileSync3(HOOKS_PATH, "utf-8"));
|
|
376
|
+
if (raw && typeof raw === "object")
|
|
377
|
+
existing = raw;
|
|
378
|
+
} catch {
|
|
379
|
+
unlinkSync2(HOOKS_PATH);
|
|
380
|
+
log(` Codex removed unparseable ${HOOKS_PATH}`);
|
|
381
|
+
existing = {};
|
|
382
|
+
}
|
|
383
|
+
if (Object.keys(existing).length > 0) {
|
|
384
|
+
const stripped = mergeHooks(existing, { hooks: {} });
|
|
385
|
+
const survivingHooks = stripped.hooks ?? {};
|
|
386
|
+
const otherTopLevelKeys = Object.keys(stripped).filter((k) => k !== "hooks");
|
|
387
|
+
if (Object.keys(survivingHooks).length === 0 && otherTopLevelKeys.length === 0) {
|
|
388
|
+
unlinkSync2(HOOKS_PATH);
|
|
389
|
+
log(` Codex removed ${HOOKS_PATH}`);
|
|
390
|
+
} else {
|
|
391
|
+
writeJson(HOOKS_PATH, stripped);
|
|
392
|
+
log(` Codex stripped hivemind hooks from ${HOOKS_PATH}`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
258
395
|
}
|
|
259
396
|
if (existsSync2(SKILL_LINK)) {
|
|
260
397
|
unlinkSync2(SKILL_LINK);
|
|
@@ -336,7 +473,7 @@ function isHivemindEntry(entry) {
|
|
|
336
473
|
const cmd = entry.command;
|
|
337
474
|
return typeof cmd === "string" && cmd.includes("/.cursor/hivemind/bundle/");
|
|
338
475
|
}
|
|
339
|
-
function
|
|
476
|
+
function mergeHooks2(existing) {
|
|
340
477
|
const root = existing ?? { version: 1, hooks: {} };
|
|
341
478
|
if (!root.version)
|
|
342
479
|
root.version = 1;
|
|
@@ -375,7 +512,7 @@ function installCursor() {
|
|
|
375
512
|
ensureDir(PLUGIN_DIR3);
|
|
376
513
|
copyDir(srcBundle, join5(PLUGIN_DIR3, "bundle"));
|
|
377
514
|
const existing = readJson(HOOKS_PATH2);
|
|
378
|
-
const merged =
|
|
515
|
+
const merged = mergeHooks2(existing);
|
|
379
516
|
writeJson(HOOKS_PATH2, merged);
|
|
380
517
|
writeVersionStamp(PLUGIN_DIR3, getVersion());
|
|
381
518
|
log(` Cursor installed -> ${PLUGIN_DIR3}`);
|
|
@@ -3090,7 +3227,7 @@ function buildHooksBlock() {
|
|
|
3090
3227
|
on_session_end: [buildHookEntry("session-end.js", 30)]
|
|
3091
3228
|
};
|
|
3092
3229
|
}
|
|
3093
|
-
function
|
|
3230
|
+
function mergeHooks3(existing) {
|
|
3094
3231
|
const merged = { ...existing ?? {} };
|
|
3095
3232
|
const ours = buildHooksBlock();
|
|
3096
3233
|
for (const [event, entries] of Object.entries(ours)) {
|
|
@@ -3151,7 +3288,7 @@ function installHermes() {
|
|
|
3151
3288
|
command: "node",
|
|
3152
3289
|
args: [MCP_SERVER_PATH]
|
|
3153
3290
|
};
|
|
3154
|
-
cfg.hooks =
|
|
3291
|
+
cfg.hooks = mergeHooks3(cfg.hooks);
|
|
3155
3292
|
cfg.hooks_auto_accept = true;
|
|
3156
3293
|
writeConfig(cfg);
|
|
3157
3294
|
log(` Hermes config updated -> ${CONFIG_PATH} (mcp_servers + hooks + hooks_auto_accept)`);
|
|
@@ -3182,6 +3319,10 @@ function uninstallHermes() {
|
|
|
3182
3319
|
delete cfg.hooks;
|
|
3183
3320
|
touched = true;
|
|
3184
3321
|
}
|
|
3322
|
+
if ("hooks_auto_accept" in cfg) {
|
|
3323
|
+
delete cfg.hooks_auto_accept;
|
|
3324
|
+
touched = true;
|
|
3325
|
+
}
|
|
3185
3326
|
if (touched) {
|
|
3186
3327
|
if (Object.keys(cfg).length === 0) {
|
|
3187
3328
|
unlinkSync4(CONFIG_PATH);
|
|
@@ -3202,6 +3343,8 @@ var LEGACY_SKILL_DIR = join8(PI_AGENT_DIR, "skills", "hivemind-memory");
|
|
|
3202
3343
|
var EXTENSIONS_DIR = join8(PI_AGENT_DIR, "extensions");
|
|
3203
3344
|
var EXTENSION_PATH = join8(EXTENSIONS_DIR, "hivemind.ts");
|
|
3204
3345
|
var VERSION_DIR = join8(PI_AGENT_DIR, ".hivemind");
|
|
3346
|
+
var WIKI_WORKER_DIR = join8(PI_AGENT_DIR, "hivemind");
|
|
3347
|
+
var WIKI_WORKER_PATH = join8(WIKI_WORKER_DIR, "wiki-worker.js");
|
|
3205
3348
|
var HIVEMIND_BLOCK_START = "<!-- BEGIN hivemind-memory -->";
|
|
3206
3349
|
var HIVEMIND_BLOCK_END = "<!-- END hivemind-memory -->";
|
|
3207
3350
|
var HIVEMIND_BLOCK_BODY = `${HIVEMIND_BLOCK_START}
|
|
@@ -3281,10 +3424,18 @@ function installPi() {
|
|
|
3281
3424
|
}
|
|
3282
3425
|
ensureDir(EXTENSIONS_DIR);
|
|
3283
3426
|
copyFileSync2(srcExtension, EXTENSION_PATH);
|
|
3427
|
+
const srcWorker = join8(pkgRoot(), "pi", "bundle", "wiki-worker.js");
|
|
3428
|
+
if (existsSync7(srcWorker)) {
|
|
3429
|
+
ensureDir(WIKI_WORKER_DIR);
|
|
3430
|
+
copyFileSync2(srcWorker, WIKI_WORKER_PATH);
|
|
3431
|
+
}
|
|
3284
3432
|
ensureDir(VERSION_DIR);
|
|
3285
3433
|
writeVersionStamp(VERSION_DIR, getVersion());
|
|
3286
3434
|
log(` pi AGENTS.md updated -> ${AGENTS_MD}`);
|
|
3287
3435
|
log(` pi extension installed -> ${EXTENSION_PATH}`);
|
|
3436
|
+
if (existsSync7(WIKI_WORKER_PATH)) {
|
|
3437
|
+
log(` pi wiki-worker installed -> ${WIKI_WORKER_PATH}`);
|
|
3438
|
+
}
|
|
3288
3439
|
}
|
|
3289
3440
|
function uninstallPi() {
|
|
3290
3441
|
if (existsSync7(LEGACY_SKILL_DIR)) {
|
|
@@ -3295,6 +3446,10 @@ function uninstallPi() {
|
|
|
3295
3446
|
rmSync3(EXTENSION_PATH, { force: true });
|
|
3296
3447
|
log(` pi removed extension ${EXTENSION_PATH}`);
|
|
3297
3448
|
}
|
|
3449
|
+
if (existsSync7(WIKI_WORKER_DIR)) {
|
|
3450
|
+
rmSync3(WIKI_WORKER_DIR, { recursive: true, force: true });
|
|
3451
|
+
log(` pi removed wiki-worker dir ${WIKI_WORKER_DIR}`);
|
|
3452
|
+
}
|
|
3298
3453
|
if (existsSync7(AGENTS_MD)) {
|
|
3299
3454
|
const prior = readFileSync5(AGENTS_MD, "utf-8");
|
|
3300
3455
|
const stripped = stripHivemindBlock(prior);
|
|
@@ -3311,43 +3466,228 @@ function uninstallPi() {
|
|
|
3311
3466
|
}
|
|
3312
3467
|
}
|
|
3313
3468
|
|
|
3469
|
+
// dist/src/cli/embeddings.js
|
|
3470
|
+
import { copyFileSync as copyFileSync3, chmodSync, existsSync as existsSync8, lstatSync as lstatSync2, readdirSync, readlinkSync, rmSync as rmSync4, statSync, unlinkSync as unlinkSync5 } from "node:fs";
|
|
3471
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3472
|
+
import { join as join9 } from "node:path";
|
|
3473
|
+
var SHARED_DIR = join9(HOME, ".hivemind", "embed-deps");
|
|
3474
|
+
var SHARED_NODE_MODULES = join9(SHARED_DIR, "node_modules");
|
|
3475
|
+
var SHARED_DAEMON_PATH = join9(SHARED_DIR, "embed-daemon.js");
|
|
3476
|
+
var TRANSFORMERS_PKG = "@huggingface/transformers";
|
|
3477
|
+
var TRANSFORMERS_RANGE = "^3.0.0";
|
|
3478
|
+
function findHivemindInstalls(home = HOME) {
|
|
3479
|
+
const out = [];
|
|
3480
|
+
const fixed = [
|
|
3481
|
+
{ id: "codex", pluginDir: join9(home, ".codex", "hivemind") },
|
|
3482
|
+
{ id: "cursor", pluginDir: join9(home, ".cursor", "hivemind") },
|
|
3483
|
+
{ id: "hermes", pluginDir: join9(home, ".hermes", "hivemind") }
|
|
3484
|
+
];
|
|
3485
|
+
for (const inst of fixed) {
|
|
3486
|
+
if (existsSync8(join9(inst.pluginDir, "bundle")))
|
|
3487
|
+
out.push(inst);
|
|
3488
|
+
}
|
|
3489
|
+
const ccCache = join9(home, ".claude", "plugins", "cache", "hivemind", "hivemind");
|
|
3490
|
+
if (existsSync8(ccCache)) {
|
|
3491
|
+
let entries = [];
|
|
3492
|
+
try {
|
|
3493
|
+
entries = readdirSync(ccCache);
|
|
3494
|
+
} catch {
|
|
3495
|
+
}
|
|
3496
|
+
for (const ver of entries) {
|
|
3497
|
+
const dir = join9(ccCache, ver);
|
|
3498
|
+
try {
|
|
3499
|
+
if (!statSync(dir).isDirectory())
|
|
3500
|
+
continue;
|
|
3501
|
+
} catch {
|
|
3502
|
+
continue;
|
|
3503
|
+
}
|
|
3504
|
+
const candidates = [join9(dir, "bundle"), join9(dir, "claude-code", "bundle")];
|
|
3505
|
+
if (candidates.some((p) => existsSync8(p))) {
|
|
3506
|
+
out.push({ id: `claude (${ver})`, pluginDir: dir });
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
}
|
|
3510
|
+
return out;
|
|
3511
|
+
}
|
|
3512
|
+
function isSharedDepsInstalled(sharedNodeModules = SHARED_NODE_MODULES) {
|
|
3513
|
+
return existsSync8(join9(sharedNodeModules, TRANSFORMERS_PKG));
|
|
3514
|
+
}
|
|
3515
|
+
function isSymlinkToSharedDeps(linkPath, sharedNodeModules) {
|
|
3516
|
+
if (!existsSync8(linkPath))
|
|
3517
|
+
return false;
|
|
3518
|
+
try {
|
|
3519
|
+
if (!lstatSync2(linkPath).isSymbolicLink())
|
|
3520
|
+
return false;
|
|
3521
|
+
return readlinkSync(linkPath) === sharedNodeModules;
|
|
3522
|
+
} catch {
|
|
3523
|
+
return false;
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
function linkStateFor(install, sharedNodeModules = SHARED_NODE_MODULES) {
|
|
3527
|
+
const link = join9(install.pluginDir, "node_modules");
|
|
3528
|
+
if (!existsSync8(link) && !isSymbolicLink(link))
|
|
3529
|
+
return { kind: "no-node-modules" };
|
|
3530
|
+
try {
|
|
3531
|
+
if (lstatSync2(link).isSymbolicLink()) {
|
|
3532
|
+
const target = readlinkSync(link);
|
|
3533
|
+
return target === sharedNodeModules ? { kind: "linked-to-shared" } : { kind: "linked-elsewhere", target };
|
|
3534
|
+
}
|
|
3535
|
+
} catch {
|
|
3536
|
+
return { kind: "no-node-modules" };
|
|
3537
|
+
}
|
|
3538
|
+
return { kind: "owns-own-node-modules" };
|
|
3539
|
+
}
|
|
3540
|
+
function isSymbolicLink(path) {
|
|
3541
|
+
try {
|
|
3542
|
+
return lstatSync2(path).isSymbolicLink();
|
|
3543
|
+
} catch {
|
|
3544
|
+
return false;
|
|
3545
|
+
}
|
|
3546
|
+
}
|
|
3547
|
+
function ensureSharedDeps() {
|
|
3548
|
+
if (!isSharedDepsInstalled()) {
|
|
3549
|
+
log(` Embeddings installing ${TRANSFORMERS_PKG}@${TRANSFORMERS_RANGE} into ${SHARED_DIR}`);
|
|
3550
|
+
log(` (~600 MB; first install only \u2014 every agent will share this)`);
|
|
3551
|
+
ensureDir(SHARED_DIR);
|
|
3552
|
+
writeJson(join9(SHARED_DIR, "package.json"), {
|
|
3553
|
+
name: "hivemind-embed-deps",
|
|
3554
|
+
version: "1.0.0",
|
|
3555
|
+
private: true,
|
|
3556
|
+
dependencies: { [TRANSFORMERS_PKG]: TRANSFORMERS_RANGE }
|
|
3557
|
+
});
|
|
3558
|
+
execFileSync3("npm", ["install", "--omit=dev", "--no-package-lock", "--no-audit", "--no-fund"], {
|
|
3559
|
+
cwd: SHARED_DIR,
|
|
3560
|
+
stdio: "inherit"
|
|
3561
|
+
});
|
|
3562
|
+
} else {
|
|
3563
|
+
log(` Embeddings shared deps already present at ${SHARED_DIR}`);
|
|
3564
|
+
}
|
|
3565
|
+
ensureDir(SHARED_DIR);
|
|
3566
|
+
const src = join9(pkgRoot(), "embeddings", "embed-daemon.js");
|
|
3567
|
+
if (existsSync8(src)) {
|
|
3568
|
+
copyFileSync3(src, SHARED_DAEMON_PATH);
|
|
3569
|
+
chmodSync(SHARED_DAEMON_PATH, 493);
|
|
3570
|
+
} else {
|
|
3571
|
+
warn(` Embeddings standalone daemon bundle missing at ${src} (run 'npm run build' first)`);
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
function linkAgent(install) {
|
|
3575
|
+
const link = join9(install.pluginDir, "node_modules");
|
|
3576
|
+
symlinkForce(SHARED_NODE_MODULES, link);
|
|
3577
|
+
log(` Embeddings linked ${install.id.padEnd(20)} -> shared deps`);
|
|
3578
|
+
}
|
|
3579
|
+
function enableEmbeddings() {
|
|
3580
|
+
ensureSharedDeps();
|
|
3581
|
+
const installs = findHivemindInstalls();
|
|
3582
|
+
if (installs.length === 0) {
|
|
3583
|
+
warn(" Embeddings no hivemind installs detected \u2014 run `hivemind install` first");
|
|
3584
|
+
warn(" (the shared deps are in place; subsequent agent installs will pick them up if you re-run `hivemind embeddings install`)");
|
|
3585
|
+
return;
|
|
3586
|
+
}
|
|
3587
|
+
for (const inst of installs)
|
|
3588
|
+
linkAgent(inst);
|
|
3589
|
+
log(` Embeddings enabled. Restart your agents to pick up.`);
|
|
3590
|
+
}
|
|
3591
|
+
function disableEmbeddings(opts) {
|
|
3592
|
+
const installs = findHivemindInstalls();
|
|
3593
|
+
for (const inst of installs) {
|
|
3594
|
+
const link = join9(inst.pluginDir, "node_modules");
|
|
3595
|
+
if (isSymlinkToSharedDeps(link, SHARED_NODE_MODULES)) {
|
|
3596
|
+
unlinkSync5(link);
|
|
3597
|
+
log(` Embeddings unlinked ${inst.id}`);
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
if (opts?.prune && existsSync8(SHARED_DIR)) {
|
|
3601
|
+
rmSync4(SHARED_DIR, { recursive: true, force: true });
|
|
3602
|
+
log(` Embeddings pruned ${SHARED_DIR}`);
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
function statusEmbeddings() {
|
|
3606
|
+
log(`Shared deps: ${SHARED_DIR}`);
|
|
3607
|
+
log(`Installed: ${isSharedDepsInstalled() ? "yes" : "no"}`);
|
|
3608
|
+
log(`Daemon: ${existsSync8(SHARED_DAEMON_PATH) ? SHARED_DAEMON_PATH : "(not present)"}`);
|
|
3609
|
+
log("");
|
|
3610
|
+
log(`Agent installs:`);
|
|
3611
|
+
const installs = findHivemindInstalls();
|
|
3612
|
+
if (installs.length === 0) {
|
|
3613
|
+
log(` (none detected)`);
|
|
3614
|
+
return;
|
|
3615
|
+
}
|
|
3616
|
+
for (const inst of installs) {
|
|
3617
|
+
const state = linkStateFor(inst);
|
|
3618
|
+
let label;
|
|
3619
|
+
switch (state.kind) {
|
|
3620
|
+
case "linked-to-shared":
|
|
3621
|
+
label = "\u2713 linked \u2192 shared";
|
|
3622
|
+
break;
|
|
3623
|
+
case "no-node-modules":
|
|
3624
|
+
label = "\u2717 not linked (embeddings disabled)";
|
|
3625
|
+
break;
|
|
3626
|
+
case "owns-own-node-modules":
|
|
3627
|
+
label = "\u25B3 has its own node_modules (not shared)";
|
|
3628
|
+
break;
|
|
3629
|
+
case "linked-elsewhere":
|
|
3630
|
+
label = `\u25B3 linked \u2192 ${state.target}`;
|
|
3631
|
+
break;
|
|
3632
|
+
}
|
|
3633
|
+
log(` ${inst.id.padEnd(20)} ${label}`);
|
|
3634
|
+
log(` ${" ".repeat(20)} ${inst.pluginDir}`);
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3314
3638
|
// dist/src/cli/auth.js
|
|
3315
3639
|
import { existsSync as existsSync9 } from "node:fs";
|
|
3316
|
-
import { join as
|
|
3640
|
+
import { join as join11 } from "node:path";
|
|
3317
3641
|
|
|
3318
3642
|
// dist/src/commands/auth.js
|
|
3319
|
-
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync2, unlinkSync as unlinkSync5 } from "node:fs";
|
|
3320
|
-
import { join as join9 } from "node:path";
|
|
3321
|
-
import { homedir as homedir2 } from "node:os";
|
|
3322
3643
|
import { execSync } from "node:child_process";
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
var
|
|
3644
|
+
|
|
3645
|
+
// dist/src/utils/client-header.js
|
|
3646
|
+
var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client";
|
|
3647
|
+
function deeplakeClientValue() {
|
|
3648
|
+
return "hivemind";
|
|
3649
|
+
}
|
|
3650
|
+
function deeplakeClientHeader() {
|
|
3651
|
+
return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
// dist/src/commands/auth-creds.js
|
|
3655
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync2, unlinkSync as unlinkSync6 } from "node:fs";
|
|
3656
|
+
import { join as join10 } from "node:path";
|
|
3657
|
+
import { homedir as homedir2 } from "node:os";
|
|
3658
|
+
function configDir() {
|
|
3659
|
+
return join10(homedir2(), ".deeplake");
|
|
3660
|
+
}
|
|
3661
|
+
function credsPath() {
|
|
3662
|
+
return join10(configDir(), "credentials.json");
|
|
3663
|
+
}
|
|
3326
3664
|
function loadCredentials() {
|
|
3327
|
-
if (!existsSync8(CREDS_PATH))
|
|
3328
|
-
return null;
|
|
3329
3665
|
try {
|
|
3330
|
-
return JSON.parse(readFileSync6(
|
|
3666
|
+
return JSON.parse(readFileSync6(credsPath(), "utf-8"));
|
|
3331
3667
|
} catch {
|
|
3332
3668
|
return null;
|
|
3333
3669
|
}
|
|
3334
3670
|
}
|
|
3335
3671
|
function saveCredentials(creds) {
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
writeFileSync4(CREDS_PATH, JSON.stringify({ ...creds, savedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), { mode: 384 });
|
|
3672
|
+
mkdirSync2(configDir(), { recursive: true, mode: 448 });
|
|
3673
|
+
writeFileSync4(credsPath(), JSON.stringify({ ...creds, savedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), { mode: 384 });
|
|
3339
3674
|
}
|
|
3340
3675
|
function deleteCredentials() {
|
|
3341
|
-
|
|
3342
|
-
|
|
3676
|
+
try {
|
|
3677
|
+
unlinkSync6(credsPath());
|
|
3343
3678
|
return true;
|
|
3679
|
+
} catch {
|
|
3680
|
+
return false;
|
|
3344
3681
|
}
|
|
3345
|
-
return false;
|
|
3346
3682
|
}
|
|
3683
|
+
|
|
3684
|
+
// dist/src/commands/auth.js
|
|
3685
|
+
var DEFAULT_API_URL = "https://api.deeplake.ai";
|
|
3347
3686
|
async function apiGet(path, token, apiUrl, orgId) {
|
|
3348
3687
|
const headers = {
|
|
3349
3688
|
Authorization: `Bearer ${token}`,
|
|
3350
|
-
"Content-Type": "application/json"
|
|
3689
|
+
"Content-Type": "application/json",
|
|
3690
|
+
...deeplakeClientHeader()
|
|
3351
3691
|
};
|
|
3352
3692
|
if (orgId)
|
|
3353
3693
|
headers["X-Activeloop-Org-Id"] = orgId;
|
|
@@ -3359,7 +3699,8 @@ async function apiGet(path, token, apiUrl, orgId) {
|
|
|
3359
3699
|
async function apiPost(path, body, token, apiUrl, orgId) {
|
|
3360
3700
|
const headers = {
|
|
3361
3701
|
Authorization: `Bearer ${token}`,
|
|
3362
|
-
"Content-Type": "application/json"
|
|
3702
|
+
"Content-Type": "application/json",
|
|
3703
|
+
...deeplakeClientHeader()
|
|
3363
3704
|
};
|
|
3364
3705
|
if (orgId)
|
|
3365
3706
|
headers["X-Activeloop-Org-Id"] = orgId;
|
|
@@ -3371,7 +3712,8 @@ async function apiPost(path, body, token, apiUrl, orgId) {
|
|
|
3371
3712
|
async function apiDelete(path, token, apiUrl, orgId) {
|
|
3372
3713
|
const headers = {
|
|
3373
3714
|
Authorization: `Bearer ${token}`,
|
|
3374
|
-
"Content-Type": "application/json"
|
|
3715
|
+
"Content-Type": "application/json",
|
|
3716
|
+
...deeplakeClientHeader()
|
|
3375
3717
|
};
|
|
3376
3718
|
if (orgId)
|
|
3377
3719
|
headers["X-Activeloop-Org-Id"] = orgId;
|
|
@@ -3382,7 +3724,7 @@ async function apiDelete(path, token, apiUrl, orgId) {
|
|
|
3382
3724
|
async function requestDeviceCode(apiUrl = DEFAULT_API_URL) {
|
|
3383
3725
|
const resp = await fetch(`${apiUrl}/auth/device/code`, {
|
|
3384
3726
|
method: "POST",
|
|
3385
|
-
headers: { "Content-Type": "application/json" }
|
|
3727
|
+
headers: { "Content-Type": "application/json", ...deeplakeClientHeader() }
|
|
3386
3728
|
});
|
|
3387
3729
|
if (!resp.ok)
|
|
3388
3730
|
throw new Error(`Device flow unavailable: HTTP ${resp.status}`);
|
|
@@ -3391,7 +3733,7 @@ async function requestDeviceCode(apiUrl = DEFAULT_API_URL) {
|
|
|
3391
3733
|
async function pollForToken(deviceCode, apiUrl = DEFAULT_API_URL) {
|
|
3392
3734
|
const resp = await fetch(`${apiUrl}/auth/device/token`, {
|
|
3393
3735
|
method: "POST",
|
|
3394
|
-
headers: { "Content-Type": "application/json" },
|
|
3736
|
+
headers: { "Content-Type": "application/json", ...deeplakeClientHeader() },
|
|
3395
3737
|
body: JSON.stringify({ device_code: deviceCode })
|
|
3396
3738
|
});
|
|
3397
3739
|
if (resp.ok)
|
|
@@ -3517,9 +3859,9 @@ Using: ${orgName}
|
|
|
3517
3859
|
}
|
|
3518
3860
|
|
|
3519
3861
|
// dist/src/cli/auth.js
|
|
3520
|
-
var
|
|
3862
|
+
var CREDS_PATH = join11(HOME, ".deeplake", "credentials.json");
|
|
3521
3863
|
function isLoggedIn() {
|
|
3522
|
-
return existsSync9(
|
|
3864
|
+
return existsSync9(CREDS_PATH) && loadCredentials() !== null;
|
|
3523
3865
|
}
|
|
3524
3866
|
async function ensureLoggedIn() {
|
|
3525
3867
|
if (isLoggedIn())
|
|
@@ -3553,11 +3895,11 @@ async function maybeShowOrgChoice() {
|
|
|
3553
3895
|
|
|
3554
3896
|
// dist/src/config.js
|
|
3555
3897
|
import { readFileSync as readFileSync7, existsSync as existsSync10 } from "node:fs";
|
|
3556
|
-
import { join as
|
|
3898
|
+
import { join as join12 } from "node:path";
|
|
3557
3899
|
import { homedir as homedir3, userInfo } from "node:os";
|
|
3558
3900
|
function loadConfig() {
|
|
3559
3901
|
const home = homedir3();
|
|
3560
|
-
const credPath =
|
|
3902
|
+
const credPath = join12(home, ".deeplake", "credentials.json");
|
|
3561
3903
|
let creds = null;
|
|
3562
3904
|
if (existsSync10(credPath)) {
|
|
3563
3905
|
try {
|
|
@@ -3579,22 +3921,19 @@ function loadConfig() {
|
|
|
3579
3921
|
apiUrl: process.env.HIVEMIND_API_URL ?? creds?.apiUrl ?? "https://api.deeplake.ai",
|
|
3580
3922
|
tableName: process.env.HIVEMIND_TABLE ?? "memory",
|
|
3581
3923
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
3582
|
-
memoryPath: process.env.HIVEMIND_MEMORY_PATH ??
|
|
3924
|
+
memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join12(home, ".deeplake", "memory")
|
|
3583
3925
|
};
|
|
3584
3926
|
}
|
|
3585
3927
|
|
|
3586
3928
|
// dist/src/deeplake-api.js
|
|
3587
3929
|
import { randomUUID } from "node:crypto";
|
|
3588
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3589
|
-
import { join as join13 } from "node:path";
|
|
3590
|
-
import { tmpdir } from "node:os";
|
|
3591
3930
|
|
|
3592
3931
|
// dist/src/utils/debug.js
|
|
3593
3932
|
import { appendFileSync } from "node:fs";
|
|
3594
|
-
import { join as
|
|
3933
|
+
import { join as join13 } from "node:path";
|
|
3595
3934
|
import { homedir as homedir4 } from "node:os";
|
|
3596
3935
|
var DEBUG = process.env.HIVEMIND_DEBUG === "1";
|
|
3597
|
-
var LOG =
|
|
3936
|
+
var LOG = join13(homedir4(), ".deeplake", "hook-debug.log");
|
|
3598
3937
|
function log2(tag, msg) {
|
|
3599
3938
|
if (!DEBUG)
|
|
3600
3939
|
return;
|
|
@@ -3607,7 +3946,17 @@ function sqlStr(value) {
|
|
|
3607
3946
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
3608
3947
|
}
|
|
3609
3948
|
|
|
3949
|
+
// dist/src/embeddings/columns.js
|
|
3950
|
+
var SUMMARY_EMBEDDING_COL = "summary_embedding";
|
|
3951
|
+
var MESSAGE_EMBEDDING_COL = "message_embedding";
|
|
3952
|
+
|
|
3610
3953
|
// dist/src/deeplake-api.js
|
|
3954
|
+
var indexMarkerStorePromise = null;
|
|
3955
|
+
function getIndexMarkerStore() {
|
|
3956
|
+
if (!indexMarkerStorePromise)
|
|
3957
|
+
indexMarkerStorePromise = Promise.resolve().then(() => (init_index_marker_store(), index_marker_store_exports));
|
|
3958
|
+
return indexMarkerStorePromise;
|
|
3959
|
+
}
|
|
3611
3960
|
var log3 = (msg) => log2("sdk", msg);
|
|
3612
3961
|
function summarizeSql(sql, maxLen = 220) {
|
|
3613
3962
|
const compact = sql.replace(/\s+/g, " ").trim();
|
|
@@ -3627,7 +3976,6 @@ var MAX_RETRIES = 3;
|
|
|
3627
3976
|
var BASE_DELAY_MS = 500;
|
|
3628
3977
|
var MAX_CONCURRENCY = 5;
|
|
3629
3978
|
var QUERY_TIMEOUT_MS = Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
|
|
3630
|
-
var INDEX_MARKER_TTL_MS = Number(process.env.HIVEMIND_INDEX_MARKER_TTL_MS ?? 6 * 60 * 6e4);
|
|
3631
3979
|
function sleep(ms) {
|
|
3632
3980
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3633
3981
|
}
|
|
@@ -3647,9 +3995,6 @@ function isTransientHtml403(text) {
|
|
|
3647
3995
|
const body = text.toLowerCase();
|
|
3648
3996
|
return body.includes("<html") || body.includes("403 forbidden") || body.includes("cloudflare") || body.includes("nginx");
|
|
3649
3997
|
}
|
|
3650
|
-
function getIndexMarkerDir() {
|
|
3651
|
-
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join13(tmpdir(), "hivemind-deeplake-indexes");
|
|
3652
|
-
}
|
|
3653
3998
|
var Semaphore = class {
|
|
3654
3999
|
max;
|
|
3655
4000
|
waiting = [];
|
|
@@ -3718,7 +4063,8 @@ var DeeplakeApi = class {
|
|
|
3718
4063
|
headers: {
|
|
3719
4064
|
Authorization: `Bearer ${this.token}`,
|
|
3720
4065
|
"Content-Type": "application/json",
|
|
3721
|
-
"X-Activeloop-Org-Id": this.orgId
|
|
4066
|
+
"X-Activeloop-Org-Id": this.orgId,
|
|
4067
|
+
...deeplakeClientHeader()
|
|
3722
4068
|
},
|
|
3723
4069
|
signal,
|
|
3724
4070
|
body: JSON.stringify({ query: sql })
|
|
@@ -3745,7 +4091,8 @@ var DeeplakeApi = class {
|
|
|
3745
4091
|
}
|
|
3746
4092
|
const text = await resp.text().catch(() => "");
|
|
3747
4093
|
const retryable403 = isSessionInsertQuery(sql) && (resp.status === 401 || resp.status === 403 && (text.length === 0 || isTransientHtml403(text)));
|
|
3748
|
-
|
|
4094
|
+
const alreadyExists = resp.status === 500 && isDuplicateIndexError(text);
|
|
4095
|
+
if (!alreadyExists && attempt < MAX_RETRIES && (RETRYABLE_CODES.has(resp.status) || retryable403)) {
|
|
3749
4096
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
3750
4097
|
log3(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
|
|
3751
4098
|
await sleep(delay);
|
|
@@ -3779,7 +4126,7 @@ var DeeplakeApi = class {
|
|
|
3779
4126
|
const lud = row.lastUpdateDate ?? ts;
|
|
3780
4127
|
const exists = await this.query(`SELECT path FROM "${this.tableName}" WHERE path = '${sqlStr(row.path)}' LIMIT 1`);
|
|
3781
4128
|
if (exists.length > 0) {
|
|
3782
|
-
let setClauses = `summary = E'${sqlStr(row.contentText)}', mime_type = '${sqlStr(row.mimeType)}', size_bytes = ${row.sizeBytes}, last_update_date = '${lud}'`;
|
|
4129
|
+
let setClauses = `summary = E'${sqlStr(row.contentText)}', ${SUMMARY_EMBEDDING_COL} = NULL, mime_type = '${sqlStr(row.mimeType)}', size_bytes = ${row.sizeBytes}, last_update_date = '${lud}'`;
|
|
3783
4130
|
if (row.project !== void 0)
|
|
3784
4131
|
setClauses += `, project = '${sqlStr(row.project)}'`;
|
|
3785
4132
|
if (row.description !== void 0)
|
|
@@ -3787,8 +4134,8 @@ var DeeplakeApi = class {
|
|
|
3787
4134
|
await this.query(`UPDATE "${this.tableName}" SET ${setClauses} WHERE path = '${sqlStr(row.path)}'`);
|
|
3788
4135
|
} else {
|
|
3789
4136
|
const id = randomUUID();
|
|
3790
|
-
let cols =
|
|
3791
|
-
let vals = `'${id}', '${sqlStr(row.path)}', '${sqlStr(row.filename)}', E'${sqlStr(row.contentText)}', '${sqlStr(row.mimeType)}', ${row.sizeBytes}, '${cd}', '${lud}'`;
|
|
4137
|
+
let cols = `id, path, filename, summary, ${SUMMARY_EMBEDDING_COL}, mime_type, size_bytes, creation_date, last_update_date`;
|
|
4138
|
+
let vals = `'${id}', '${sqlStr(row.path)}', '${sqlStr(row.filename)}', E'${sqlStr(row.contentText)}', NULL, '${sqlStr(row.mimeType)}', ${row.sizeBytes}, '${cd}', '${lud}'`;
|
|
3792
4139
|
if (row.project !== void 0) {
|
|
3793
4140
|
cols += ", project";
|
|
3794
4141
|
vals += `, '${sqlStr(row.project)}'`;
|
|
@@ -3813,48 +4160,83 @@ var DeeplakeApi = class {
|
|
|
3813
4160
|
buildLookupIndexName(table, suffix) {
|
|
3814
4161
|
return `idx_${table}_${suffix}`.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
3815
4162
|
}
|
|
3816
|
-
getLookupIndexMarkerPath(table, suffix) {
|
|
3817
|
-
const markerKey = [
|
|
3818
|
-
this.workspaceId,
|
|
3819
|
-
this.orgId,
|
|
3820
|
-
table,
|
|
3821
|
-
suffix
|
|
3822
|
-
].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
3823
|
-
return join13(getIndexMarkerDir(), `${markerKey}.json`);
|
|
3824
|
-
}
|
|
3825
|
-
hasFreshLookupIndexMarker(table, suffix) {
|
|
3826
|
-
const markerPath = this.getLookupIndexMarkerPath(table, suffix);
|
|
3827
|
-
if (!existsSync11(markerPath))
|
|
3828
|
-
return false;
|
|
3829
|
-
try {
|
|
3830
|
-
const raw = JSON.parse(readFileSync8(markerPath, "utf-8"));
|
|
3831
|
-
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
3832
|
-
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
3833
|
-
return false;
|
|
3834
|
-
return true;
|
|
3835
|
-
} catch {
|
|
3836
|
-
return false;
|
|
3837
|
-
}
|
|
3838
|
-
}
|
|
3839
|
-
markLookupIndexReady(table, suffix) {
|
|
3840
|
-
mkdirSync3(getIndexMarkerDir(), { recursive: true });
|
|
3841
|
-
writeFileSync5(this.getLookupIndexMarkerPath(table, suffix), JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
3842
|
-
}
|
|
3843
4163
|
async ensureLookupIndex(table, suffix, columnsSql) {
|
|
3844
|
-
|
|
4164
|
+
const markers = await getIndexMarkerStore();
|
|
4165
|
+
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, suffix);
|
|
4166
|
+
if (markers.hasFreshIndexMarker(markerPath))
|
|
3845
4167
|
return;
|
|
3846
4168
|
const indexName = this.buildLookupIndexName(table, suffix);
|
|
3847
4169
|
try {
|
|
3848
4170
|
await this.query(`CREATE INDEX IF NOT EXISTS "${indexName}" ON "${table}" ${columnsSql}`);
|
|
3849
|
-
|
|
4171
|
+
markers.writeIndexMarker(markerPath);
|
|
3850
4172
|
} catch (e) {
|
|
3851
4173
|
if (isDuplicateIndexError(e)) {
|
|
3852
|
-
|
|
4174
|
+
markers.writeIndexMarker(markerPath);
|
|
3853
4175
|
return;
|
|
3854
4176
|
}
|
|
3855
4177
|
log3(`index "${indexName}" skipped: ${e.message}`);
|
|
3856
4178
|
}
|
|
3857
4179
|
}
|
|
4180
|
+
/**
|
|
4181
|
+
* Ensure a vector column exists on the given table.
|
|
4182
|
+
*
|
|
4183
|
+
* The previous implementation always issued `ALTER TABLE ADD COLUMN IF NOT
|
|
4184
|
+
* EXISTS …` on every SessionStart. On a long-running workspace that's
|
|
4185
|
+
* already migrated, every call returns 500 "Column already exists" — noisy
|
|
4186
|
+
* in the log and a wasted round-trip. Worse, the very first call after the
|
|
4187
|
+
* column is genuinely added triggers Deeplake's post-ALTER `vector::at`
|
|
4188
|
+
* window (~30s) during which subsequent INSERTs fail; minimising the
|
|
4189
|
+
* number of ALTER calls minimises exposure to that window.
|
|
4190
|
+
*
|
|
4191
|
+
* New flow:
|
|
4192
|
+
* 1. Check the local marker file (mirrors ensureLookupIndex). If fresh,
|
|
4193
|
+
* return — zero network calls.
|
|
4194
|
+
* 2. SELECT 1 FROM information_schema.columns WHERE table_name = T AND
|
|
4195
|
+
* column_name = C. Read-only, idempotent, can't tickle the post-ALTER
|
|
4196
|
+
* bug. If the column is present → mark + return.
|
|
4197
|
+
* 3. Only if step 2 says the column is missing, fall back to ALTER ADD
|
|
4198
|
+
* COLUMN IF NOT EXISTS. Mark on success, also mark if Deeplake reports
|
|
4199
|
+
* "already exists" (race: another client added it between our SELECT
|
|
4200
|
+
* and ALTER).
|
|
4201
|
+
*
|
|
4202
|
+
* Marker uses the same dir / TTL as ensureLookupIndex so both schema
|
|
4203
|
+
* caches share an opt-out (HIVEMIND_INDEX_MARKER_DIR) and a TTL knob.
|
|
4204
|
+
*/
|
|
4205
|
+
async ensureEmbeddingColumn(table, column) {
|
|
4206
|
+
await this.ensureColumn(table, column, "FLOAT4[]");
|
|
4207
|
+
}
|
|
4208
|
+
/**
|
|
4209
|
+
* Generic marker-gated column migration. Same SELECT-then-ALTER flow as
|
|
4210
|
+
* ensureEmbeddingColumn, parameterized by SQL type so it can patch up any
|
|
4211
|
+
* column that was added to the schema after the table was originally
|
|
4212
|
+
* created. Used today for `summary_embedding`, `message_embedding`, and
|
|
4213
|
+
* the `agent` column (added 2026-04-11) — the latter has no fallback if
|
|
4214
|
+
* a user upgraded over a pre-2026-04-11 table, so every INSERT fails
|
|
4215
|
+
* with `column "agent" does not exist`.
|
|
4216
|
+
*/
|
|
4217
|
+
async ensureColumn(table, column, sqlType) {
|
|
4218
|
+
const markers = await getIndexMarkerStore();
|
|
4219
|
+
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, `col_${column}`);
|
|
4220
|
+
if (markers.hasFreshIndexMarker(markerPath))
|
|
4221
|
+
return;
|
|
4222
|
+
const colCheck = `SELECT 1 FROM information_schema.columns WHERE table_name = '${sqlStr(table)}' AND column_name = '${sqlStr(column)}' AND table_schema = '${sqlStr(this.workspaceId)}' LIMIT 1`;
|
|
4223
|
+
const rows = await this.query(colCheck);
|
|
4224
|
+
if (rows.length > 0) {
|
|
4225
|
+
markers.writeIndexMarker(markerPath);
|
|
4226
|
+
return;
|
|
4227
|
+
}
|
|
4228
|
+
try {
|
|
4229
|
+
await this.query(`ALTER TABLE "${table}" ADD COLUMN ${column} ${sqlType}`);
|
|
4230
|
+
} catch (e) {
|
|
4231
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
4232
|
+
if (!/already exists/i.test(msg))
|
|
4233
|
+
throw e;
|
|
4234
|
+
const recheck = await this.query(colCheck);
|
|
4235
|
+
if (recheck.length === 0)
|
|
4236
|
+
throw e;
|
|
4237
|
+
}
|
|
4238
|
+
markers.writeIndexMarker(markerPath);
|
|
4239
|
+
}
|
|
3858
4240
|
/** List all tables in the workspace (with retry). */
|
|
3859
4241
|
async listTables(forceRefresh = false) {
|
|
3860
4242
|
if (!forceRefresh && this._tablesCache)
|
|
@@ -3870,7 +4252,8 @@ var DeeplakeApi = class {
|
|
|
3870
4252
|
const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, {
|
|
3871
4253
|
headers: {
|
|
3872
4254
|
Authorization: `Bearer ${this.token}`,
|
|
3873
|
-
"X-Activeloop-Org-Id": this.orgId
|
|
4255
|
+
"X-Activeloop-Org-Id": this.orgId,
|
|
4256
|
+
...deeplakeClientHeader()
|
|
3874
4257
|
}
|
|
3875
4258
|
});
|
|
3876
4259
|
if (resp.ok) {
|
|
@@ -3895,28 +4278,60 @@ var DeeplakeApi = class {
|
|
|
3895
4278
|
}
|
|
3896
4279
|
return { tables: [], cacheable: false };
|
|
3897
4280
|
}
|
|
4281
|
+
/**
|
|
4282
|
+
* Run a `CREATE TABLE` with an extra outer retry budget. The base
|
|
4283
|
+
* `query()` already retries 3 times on fetch errors (~3.5s total), but a
|
|
4284
|
+
* failed CREATE is permanent corruption — every subsequent SELECT against
|
|
4285
|
+
* the missing table fails. Wrapping in an outer loop with longer backoff
|
|
4286
|
+
* (2s, 5s, then 10s) gives us ~17s of reach across transient network
|
|
4287
|
+
* blips before giving up. Failures still propagate; getApi() resets its
|
|
4288
|
+
* cache on init failure (openclaw plugin) so the next call retries the
|
|
4289
|
+
* whole init flow.
|
|
4290
|
+
*/
|
|
4291
|
+
async createTableWithRetry(sql, label) {
|
|
4292
|
+
const OUTER_BACKOFFS_MS = [2e3, 5e3, 1e4];
|
|
4293
|
+
let lastErr = null;
|
|
4294
|
+
for (let attempt = 0; attempt <= OUTER_BACKOFFS_MS.length; attempt++) {
|
|
4295
|
+
try {
|
|
4296
|
+
await this.query(sql);
|
|
4297
|
+
return;
|
|
4298
|
+
} catch (err) {
|
|
4299
|
+
lastErr = err;
|
|
4300
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4301
|
+
log3(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
|
|
4302
|
+
if (attempt < OUTER_BACKOFFS_MS.length) {
|
|
4303
|
+
await sleep(OUTER_BACKOFFS_MS[attempt]);
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
}
|
|
4307
|
+
throw lastErr;
|
|
4308
|
+
}
|
|
3898
4309
|
/** Create the memory table if it doesn't already exist. Migrate columns on existing tables. */
|
|
3899
4310
|
async ensureTable(name) {
|
|
3900
4311
|
const tbl = name ?? this.tableName;
|
|
3901
4312
|
const tables = await this.listTables();
|
|
3902
4313
|
if (!tables.includes(tbl)) {
|
|
3903
4314
|
log3(`table "${tbl}" not found, creating`);
|
|
3904
|
-
await this.
|
|
4315
|
+
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${tbl}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', summary TEXT NOT NULL DEFAULT '', summary_embedding FLOAT4[], author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'text/plain', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, tbl);
|
|
3905
4316
|
log3(`table "${tbl}" created`);
|
|
3906
4317
|
if (!tables.includes(tbl))
|
|
3907
4318
|
this._tablesCache = [...tables, tbl];
|
|
3908
4319
|
}
|
|
4320
|
+
await this.ensureEmbeddingColumn(tbl, SUMMARY_EMBEDDING_COL);
|
|
4321
|
+
await this.ensureColumn(tbl, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
3909
4322
|
}
|
|
3910
4323
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
3911
4324
|
async ensureSessionsTable(name) {
|
|
3912
4325
|
const tables = await this.listTables();
|
|
3913
4326
|
if (!tables.includes(name)) {
|
|
3914
4327
|
log3(`table "${name}" not found, creating`);
|
|
3915
|
-
await this.
|
|
4328
|
+
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${name}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', message JSONB, message_embedding FLOAT4[], author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'application/json', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, name);
|
|
3916
4329
|
log3(`table "${name}" created`);
|
|
3917
4330
|
if (!tables.includes(name))
|
|
3918
4331
|
this._tablesCache = [...tables, name];
|
|
3919
4332
|
}
|
|
4333
|
+
await this.ensureEmbeddingColumn(name, MESSAGE_EMBEDDING_COL);
|
|
4334
|
+
await this.ensureColumn(name, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
3920
4335
|
await this.ensureLookupIndex(name, "path_creation_date", `("path", "creation_date")`);
|
|
3921
4336
|
}
|
|
3922
4337
|
};
|
|
@@ -4229,10 +4644,14 @@ var USAGE = `
|
|
|
4229
4644
|
hivemind \u2014 one brain for every agent on your team
|
|
4230
4645
|
|
|
4231
4646
|
Usage:
|
|
4232
|
-
hivemind install
|
|
4647
|
+
hivemind install [--only <platforms>] [--skip-auth]
|
|
4233
4648
|
Auto-detect assistants on this machine and install hivemind into each.
|
|
4234
4649
|
--only takes a comma-separated list: ${allPlatformIds().join(",")}
|
|
4235
4650
|
|
|
4651
|
+
hivemind uninstall [--only <platforms>]
|
|
4652
|
+
Auto-detect installed assistants and remove hivemind from each.
|
|
4653
|
+
--only takes the same list to scope the removal.
|
|
4654
|
+
|
|
4236
4655
|
hivemind claude install | uninstall
|
|
4237
4656
|
hivemind codex install | uninstall
|
|
4238
4657
|
hivemind claw install | uninstall
|
|
@@ -4244,6 +4663,18 @@ Usage:
|
|
|
4244
4663
|
hivemind login Run device-flow login (open browser).
|
|
4245
4664
|
hivemind status Show which assistants are wired up.
|
|
4246
4665
|
|
|
4666
|
+
Semantic search (embeddings):
|
|
4667
|
+
hivemind embeddings install Download @huggingface/transformers
|
|
4668
|
+
once (~600 MB) into a shared dir
|
|
4669
|
+
and symlink every detected agent
|
|
4670
|
+
plugin to it. Idempotent.
|
|
4671
|
+
hivemind embeddings uninstall [--prune] Remove the per-agent symlinks.
|
|
4672
|
+
--prune also deletes the shared dir.
|
|
4673
|
+
hivemind embeddings status Show shared-deps + per-agent state.
|
|
4674
|
+
|
|
4675
|
+
Add --with-embeddings to "hivemind install" (or "hivemind <agent> install")
|
|
4676
|
+
to run "embeddings install" automatically after installing the agent(s).
|
|
4677
|
+
|
|
4247
4678
|
Account / org / workspace:
|
|
4248
4679
|
hivemind whoami Show current user, org, workspace.
|
|
4249
4680
|
hivemind logout Remove credentials.
|
|
@@ -4284,6 +4715,7 @@ function hasFlag(args, flag) {
|
|
|
4284
4715
|
async function runInstallAll(args) {
|
|
4285
4716
|
const only = parseOnly(args);
|
|
4286
4717
|
const skipAuth = hasFlag(args, "--skip-auth");
|
|
4718
|
+
const withEmbeddings = hasFlag(args, "--with-embeddings");
|
|
4287
4719
|
const targets = only ?? detectPlatforms().map((p) => p.id);
|
|
4288
4720
|
if (targets.length === 0) {
|
|
4289
4721
|
log("No supported assistants detected.");
|
|
@@ -4302,6 +4734,10 @@ async function runInstallAll(args) {
|
|
|
4302
4734
|
}
|
|
4303
4735
|
for (const id of targets)
|
|
4304
4736
|
runSingleInstall(id);
|
|
4737
|
+
if (withEmbeddings) {
|
|
4738
|
+
log("");
|
|
4739
|
+
enableEmbeddings();
|
|
4740
|
+
}
|
|
4305
4741
|
await maybeShowOrgChoice();
|
|
4306
4742
|
log("");
|
|
4307
4743
|
log("Done. Restart each assistant to activate hooks.");
|
|
@@ -4383,6 +4819,23 @@ async function main() {
|
|
|
4383
4819
|
runStatus();
|
|
4384
4820
|
return;
|
|
4385
4821
|
}
|
|
4822
|
+
if (cmd === "embeddings") {
|
|
4823
|
+
const sub = args[1];
|
|
4824
|
+
if (sub === "install" || sub === "enable") {
|
|
4825
|
+
enableEmbeddings();
|
|
4826
|
+
return;
|
|
4827
|
+
}
|
|
4828
|
+
if (sub === "uninstall" || sub === "disable") {
|
|
4829
|
+
disableEmbeddings({ prune: hasFlag(args.slice(2), "--prune") });
|
|
4830
|
+
return;
|
|
4831
|
+
}
|
|
4832
|
+
if (sub === "status") {
|
|
4833
|
+
statusEmbeddings();
|
|
4834
|
+
return;
|
|
4835
|
+
}
|
|
4836
|
+
warn("Usage: hivemind embeddings install | uninstall [--prune] | status");
|
|
4837
|
+
process.exit(1);
|
|
4838
|
+
}
|
|
4386
4839
|
if (AUTH_SUBCOMMANDS.has(cmd)) {
|
|
4387
4840
|
await runAuthCommand(args);
|
|
4388
4841
|
return;
|
|
@@ -4390,12 +4843,16 @@ async function main() {
|
|
|
4390
4843
|
const platformCmds = ["claude", "codex", "claw", "cursor", "hermes", "pi"];
|
|
4391
4844
|
if (platformCmds.includes(cmd)) {
|
|
4392
4845
|
const sub = args[1];
|
|
4393
|
-
if (sub === "install")
|
|
4846
|
+
if (sub === "install") {
|
|
4394
4847
|
runSingleInstall(cmd);
|
|
4395
|
-
|
|
4848
|
+
if (hasFlag(args.slice(2), "--with-embeddings")) {
|
|
4849
|
+
log("");
|
|
4850
|
+
enableEmbeddings();
|
|
4851
|
+
}
|
|
4852
|
+
} else if (sub === "uninstall")
|
|
4396
4853
|
runSingleUninstall(cmd);
|
|
4397
4854
|
else {
|
|
4398
|
-
warn(`Usage: hivemind ${cmd} install|uninstall`);
|
|
4855
|
+
warn(`Usage: hivemind ${cmd} install [--with-embeddings] | uninstall`);
|
|
4399
4856
|
process.exit(1);
|
|
4400
4857
|
}
|
|
4401
4858
|
return;
|