@deeplake/hivemind 0.7.31 → 0.7.33
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/bundle/cli.js +594 -267
- package/codex/bundle/capture.js +585 -124
- package/codex/bundle/commands/auth-login.js +163 -30
- package/codex/bundle/embeddings/embed-daemon.js +55 -4
- package/codex/bundle/pre-tool-use.js +475 -85
- package/codex/bundle/session-start-setup.js +193 -60
- package/codex/bundle/session-start.js +221 -88
- package/codex/bundle/shell/deeplake-shell.js +458 -68
- package/codex/bundle/stop.js +565 -175
- package/codex/bundle/wiki-worker.js +258 -19
- package/cursor/bundle/capture.js +660 -199
- package/cursor/bundle/commands/auth-login.js +163 -30
- package/cursor/bundle/embeddings/embed-daemon.js +55 -4
- package/cursor/bundle/pre-tool-use.js +460 -70
- package/cursor/bundle/session-start.js +271 -131
- package/cursor/bundle/shell/deeplake-shell.js +458 -68
- package/cursor/bundle/wiki-worker.js +258 -19
- package/hermes/bundle/capture.js +661 -200
- package/hermes/bundle/commands/auth-login.js +163 -30
- package/hermes/bundle/embeddings/embed-daemon.js +55 -4
- package/hermes/bundle/pre-tool-use.js +459 -69
- package/hermes/bundle/session-start.js +268 -128
- package/hermes/bundle/shell/deeplake-shell.js +458 -68
- package/hermes/bundle/wiki-worker.js +258 -19
- package/mcp/bundle/server.js +190 -57
- package/openclaw/dist/index.js +160 -32
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/package.json +1 -1
|
@@ -17,21 +17,21 @@ __export(index_marker_store_exports, {
|
|
|
17
17
|
hasFreshIndexMarker: () => hasFreshIndexMarker,
|
|
18
18
|
writeIndexMarker: () => writeIndexMarker
|
|
19
19
|
});
|
|
20
|
-
import { existsSync as existsSync2, mkdirSync, readFileSync as
|
|
21
|
-
import { join as
|
|
20
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
21
|
+
import { join as join5 } from "node:path";
|
|
22
22
|
import { tmpdir } from "node:os";
|
|
23
23
|
function getIndexMarkerDir() {
|
|
24
|
-
return process.env.HIVEMIND_INDEX_MARKER_DIR ??
|
|
24
|
+
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join5(tmpdir(), "hivemind-deeplake-indexes");
|
|
25
25
|
}
|
|
26
26
|
function buildIndexMarkerPath(workspaceId, orgId, table, suffix) {
|
|
27
27
|
const markerKey = [workspaceId, orgId, table, suffix].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
28
|
-
return
|
|
28
|
+
return join5(getIndexMarkerDir(), `${markerKey}.json`);
|
|
29
29
|
}
|
|
30
30
|
function hasFreshIndexMarker(markerPath) {
|
|
31
31
|
if (!existsSync2(markerPath))
|
|
32
32
|
return false;
|
|
33
33
|
try {
|
|
34
|
-
const raw = JSON.parse(
|
|
34
|
+
const raw = JSON.parse(readFileSync4(markerPath, "utf-8"));
|
|
35
35
|
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
36
36
|
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
37
37
|
return false;
|
|
@@ -41,8 +41,8 @@ function hasFreshIndexMarker(markerPath) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
function writeIndexMarker(markerPath) {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
mkdirSync3(getIndexMarkerDir(), { recursive: true });
|
|
45
|
+
writeFileSync3(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
46
46
|
}
|
|
47
47
|
var INDEX_MARKER_TTL_MS;
|
|
48
48
|
var init_index_marker_store = __esm({
|
|
@@ -54,19 +54,19 @@ var init_index_marker_store = __esm({
|
|
|
54
54
|
|
|
55
55
|
// dist/src/hooks/codex/pre-tool-use.js
|
|
56
56
|
import { execFileSync } from "node:child_process";
|
|
57
|
-
import { existsSync as
|
|
58
|
-
import { join as
|
|
57
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
58
|
+
import { join as join12, dirname as dirname3 } from "node:path";
|
|
59
59
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
60
60
|
|
|
61
61
|
// dist/src/utils/stdin.js
|
|
62
62
|
function readStdin() {
|
|
63
|
-
return new Promise((
|
|
63
|
+
return new Promise((resolve3, reject) => {
|
|
64
64
|
let data = "";
|
|
65
65
|
process.stdin.setEncoding("utf-8");
|
|
66
66
|
process.stdin.on("data", (chunk) => data += chunk);
|
|
67
67
|
process.stdin.on("end", () => {
|
|
68
68
|
try {
|
|
69
|
-
|
|
69
|
+
resolve3(JSON.parse(data));
|
|
70
70
|
} catch (err) {
|
|
71
71
|
reject(new Error(`Failed to parse hook input: ${err}`));
|
|
72
72
|
}
|
|
@@ -153,6 +153,125 @@ function deeplakeClientHeader() {
|
|
|
153
153
|
return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
// dist/src/notifications/queue.js
|
|
157
|
+
import { readFileSync as readFileSync2, writeFileSync, renameSync, mkdirSync, openSync, closeSync, unlinkSync, statSync } from "node:fs";
|
|
158
|
+
import { join as join3, resolve } from "node:path";
|
|
159
|
+
import { homedir as homedir3 } from "node:os";
|
|
160
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
161
|
+
var log2 = (msg) => log("notifications-queue", msg);
|
|
162
|
+
var LOCK_RETRY_MAX = 50;
|
|
163
|
+
var LOCK_RETRY_BASE_MS = 5;
|
|
164
|
+
var LOCK_STALE_MS = 5e3;
|
|
165
|
+
function queuePath() {
|
|
166
|
+
return join3(homedir3(), ".deeplake", "notifications-queue.json");
|
|
167
|
+
}
|
|
168
|
+
function lockPath() {
|
|
169
|
+
return `${queuePath()}.lock`;
|
|
170
|
+
}
|
|
171
|
+
function readQueue() {
|
|
172
|
+
try {
|
|
173
|
+
const raw = readFileSync2(queuePath(), "utf-8");
|
|
174
|
+
const parsed = JSON.parse(raw);
|
|
175
|
+
if (!parsed || !Array.isArray(parsed.queue)) {
|
|
176
|
+
log2(`queue malformed \u2192 treating as empty`);
|
|
177
|
+
return { queue: [] };
|
|
178
|
+
}
|
|
179
|
+
return { queue: parsed.queue };
|
|
180
|
+
} catch {
|
|
181
|
+
return { queue: [] };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function _isQueuePathInsideHome(path, home) {
|
|
185
|
+
const r = resolve(path);
|
|
186
|
+
const h = resolve(home);
|
|
187
|
+
return r.startsWith(h + "/") || r === h;
|
|
188
|
+
}
|
|
189
|
+
function writeQueue(q) {
|
|
190
|
+
const path = queuePath();
|
|
191
|
+
const home = resolve(homedir3());
|
|
192
|
+
if (!_isQueuePathInsideHome(path, home)) {
|
|
193
|
+
throw new Error(`notifications-queue write blocked: ${path} is outside ${home}`);
|
|
194
|
+
}
|
|
195
|
+
mkdirSync(join3(home, ".deeplake"), { recursive: true, mode: 448 });
|
|
196
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
197
|
+
writeFileSync(tmp, JSON.stringify(q, null, 2), { mode: 384 });
|
|
198
|
+
renameSync(tmp, path);
|
|
199
|
+
}
|
|
200
|
+
async function withQueueLock(fn) {
|
|
201
|
+
const path = lockPath();
|
|
202
|
+
mkdirSync(join3(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
|
|
203
|
+
let fd = null;
|
|
204
|
+
for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
|
|
205
|
+
try {
|
|
206
|
+
fd = openSync(path, "wx", 384);
|
|
207
|
+
break;
|
|
208
|
+
} catch (e) {
|
|
209
|
+
const code = e.code;
|
|
210
|
+
if (code !== "EEXIST")
|
|
211
|
+
throw e;
|
|
212
|
+
try {
|
|
213
|
+
const age = Date.now() - statSync(path).mtimeMs;
|
|
214
|
+
if (age > LOCK_STALE_MS) {
|
|
215
|
+
unlinkSync(path);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
} catch {
|
|
219
|
+
}
|
|
220
|
+
const delay = LOCK_RETRY_BASE_MS * (attempt + 1);
|
|
221
|
+
await sleep(delay);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (fd === null) {
|
|
225
|
+
log2(`lock acquisition gave up after ${LOCK_RETRY_MAX} attempts \u2014 proceeding unlocked (last-writer-wins)`);
|
|
226
|
+
return fn();
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
return fn();
|
|
230
|
+
} finally {
|
|
231
|
+
try {
|
|
232
|
+
closeSync(fd);
|
|
233
|
+
} catch {
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
unlinkSync(path);
|
|
237
|
+
} catch {
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function sameDedupKey(a, b) {
|
|
242
|
+
if (a.id !== b.id)
|
|
243
|
+
return false;
|
|
244
|
+
return JSON.stringify(a.dedupKey) === JSON.stringify(b.dedupKey);
|
|
245
|
+
}
|
|
246
|
+
async function enqueueNotification(n) {
|
|
247
|
+
await withQueueLock(() => {
|
|
248
|
+
const q = readQueue();
|
|
249
|
+
if (q.queue.some((existing) => sameDedupKey(existing, n))) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
q.queue.push(n);
|
|
253
|
+
writeQueue(q);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// dist/src/commands/auth-creds.js
|
|
258
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "node:fs";
|
|
259
|
+
import { join as join4 } from "node:path";
|
|
260
|
+
import { homedir as homedir4 } from "node:os";
|
|
261
|
+
function configDir() {
|
|
262
|
+
return join4(homedir4(), ".deeplake");
|
|
263
|
+
}
|
|
264
|
+
function credsPath() {
|
|
265
|
+
return join4(configDir(), "credentials.json");
|
|
266
|
+
}
|
|
267
|
+
function loadCredentials() {
|
|
268
|
+
try {
|
|
269
|
+
return JSON.parse(readFileSync3(credsPath(), "utf-8"));
|
|
270
|
+
} catch {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
156
275
|
// dist/src/deeplake-api.js
|
|
157
276
|
var indexMarkerStorePromise = null;
|
|
158
277
|
function getIndexMarkerStore() {
|
|
@@ -160,7 +279,7 @@ function getIndexMarkerStore() {
|
|
|
160
279
|
indexMarkerStorePromise = Promise.resolve().then(() => (init_index_marker_store(), index_marker_store_exports));
|
|
161
280
|
return indexMarkerStorePromise;
|
|
162
281
|
}
|
|
163
|
-
var
|
|
282
|
+
var log3 = (msg) => log("sdk", msg);
|
|
164
283
|
function summarizeSql(sql, maxLen = 220) {
|
|
165
284
|
const compact = sql.replace(/\s+/g, " ").trim();
|
|
166
285
|
return compact.length > maxLen ? `${compact.slice(0, maxLen)}...` : compact;
|
|
@@ -172,7 +291,38 @@ function traceSql(msg) {
|
|
|
172
291
|
process.stderr.write(`[deeplake-sql] ${msg}
|
|
173
292
|
`);
|
|
174
293
|
if (process.env.HIVEMIND_DEBUG === "1")
|
|
175
|
-
|
|
294
|
+
log3(msg);
|
|
295
|
+
}
|
|
296
|
+
var _signalledBalanceExhausted = false;
|
|
297
|
+
function maybeSignalBalanceExhausted(status, bodyText) {
|
|
298
|
+
if (status !== 402)
|
|
299
|
+
return;
|
|
300
|
+
if (!bodyText.includes("balance_cents"))
|
|
301
|
+
return;
|
|
302
|
+
if (_signalledBalanceExhausted)
|
|
303
|
+
return;
|
|
304
|
+
_signalledBalanceExhausted = true;
|
|
305
|
+
log3(`balance exhausted \u2014 enqueuing session-start banner (body=${bodyText.slice(0, 120)})`);
|
|
306
|
+
enqueueNotification({
|
|
307
|
+
id: "balance-exhausted",
|
|
308
|
+
severity: "warn",
|
|
309
|
+
transient: true,
|
|
310
|
+
title: "Hivemind credits exhausted \u2014 top up to keep capturing",
|
|
311
|
+
body: `Sessions are not being saved and memory recall is returning empty. Top up at ${billingUrl()} to restore capture and recall.`,
|
|
312
|
+
dedupKey: { reason: "balance-zero" }
|
|
313
|
+
}).catch((e) => {
|
|
314
|
+
log3(`enqueue balance-exhausted failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
function billingUrl() {
|
|
318
|
+
try {
|
|
319
|
+
const c = loadCredentials();
|
|
320
|
+
if (c?.orgName && c?.workspaceId) {
|
|
321
|
+
return `https://deeplake.ai/${encodeURIComponent(c.orgName)}/workspace/${encodeURIComponent(c.workspaceId)}/billing`;
|
|
322
|
+
}
|
|
323
|
+
} catch {
|
|
324
|
+
}
|
|
325
|
+
return "https://deeplake.ai";
|
|
176
326
|
}
|
|
177
327
|
var RETRYABLE_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
178
328
|
var MAX_RETRIES = 3;
|
|
@@ -181,8 +331,8 @@ var MAX_CONCURRENCY = 5;
|
|
|
181
331
|
function getQueryTimeoutMs() {
|
|
182
332
|
return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
|
|
183
333
|
}
|
|
184
|
-
function
|
|
185
|
-
return new Promise((
|
|
334
|
+
function sleep2(ms) {
|
|
335
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
186
336
|
}
|
|
187
337
|
function isTimeoutError(error) {
|
|
188
338
|
const name = error instanceof Error ? error.name.toLowerCase() : "";
|
|
@@ -212,7 +362,7 @@ var Semaphore = class {
|
|
|
212
362
|
this.active++;
|
|
213
363
|
return;
|
|
214
364
|
}
|
|
215
|
-
await new Promise((
|
|
365
|
+
await new Promise((resolve3) => this.waiting.push(resolve3));
|
|
216
366
|
}
|
|
217
367
|
release() {
|
|
218
368
|
this.active--;
|
|
@@ -283,8 +433,8 @@ var DeeplakeApi = class {
|
|
|
283
433
|
lastError = e instanceof Error ? e : new Error(String(e));
|
|
284
434
|
if (attempt < MAX_RETRIES) {
|
|
285
435
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
286
|
-
|
|
287
|
-
await
|
|
436
|
+
log3(`query retry ${attempt + 1}/${MAX_RETRIES} (fetch error: ${lastError.message}) in ${delay.toFixed(0)}ms`);
|
|
437
|
+
await sleep2(delay);
|
|
288
438
|
continue;
|
|
289
439
|
}
|
|
290
440
|
throw lastError;
|
|
@@ -300,10 +450,11 @@ var DeeplakeApi = class {
|
|
|
300
450
|
const alreadyExists = resp.status === 500 && isDuplicateIndexError(text);
|
|
301
451
|
if (!alreadyExists && attempt < MAX_RETRIES && (RETRYABLE_CODES.has(resp.status) || retryable403)) {
|
|
302
452
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
303
|
-
|
|
304
|
-
await
|
|
453
|
+
log3(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
|
|
454
|
+
await sleep2(delay);
|
|
305
455
|
continue;
|
|
306
456
|
}
|
|
457
|
+
maybeSignalBalanceExhausted(resp.status, text);
|
|
307
458
|
throw new Error(`Query failed: ${resp.status}: ${text.slice(0, 200)}`);
|
|
308
459
|
}
|
|
309
460
|
throw lastError ?? new Error("Query failed: max retries exceeded");
|
|
@@ -324,7 +475,7 @@ var DeeplakeApi = class {
|
|
|
324
475
|
const chunk = rows.slice(i, i + CONCURRENCY);
|
|
325
476
|
await Promise.allSettled(chunk.map((r) => this.upsertRowSql(r)));
|
|
326
477
|
}
|
|
327
|
-
|
|
478
|
+
log3(`commit: ${rows.length} rows`);
|
|
328
479
|
}
|
|
329
480
|
async upsertRowSql(row) {
|
|
330
481
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -380,7 +531,7 @@ var DeeplakeApi = class {
|
|
|
380
531
|
markers.writeIndexMarker(markerPath);
|
|
381
532
|
return;
|
|
382
533
|
}
|
|
383
|
-
|
|
534
|
+
log3(`index "${indexName}" skipped: ${e.message}`);
|
|
384
535
|
}
|
|
385
536
|
}
|
|
386
537
|
/**
|
|
@@ -470,13 +621,13 @@ var DeeplakeApi = class {
|
|
|
470
621
|
};
|
|
471
622
|
}
|
|
472
623
|
if (attempt < MAX_RETRIES && RETRYABLE_CODES.has(resp.status)) {
|
|
473
|
-
await
|
|
624
|
+
await sleep2(BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200);
|
|
474
625
|
continue;
|
|
475
626
|
}
|
|
476
627
|
return { tables: [], cacheable: false };
|
|
477
628
|
} catch {
|
|
478
629
|
if (attempt < MAX_RETRIES) {
|
|
479
|
-
await
|
|
630
|
+
await sleep2(BASE_DELAY_MS * Math.pow(2, attempt));
|
|
480
631
|
continue;
|
|
481
632
|
}
|
|
482
633
|
return { tables: [], cacheable: false };
|
|
@@ -504,9 +655,9 @@ var DeeplakeApi = class {
|
|
|
504
655
|
} catch (err) {
|
|
505
656
|
lastErr = err;
|
|
506
657
|
const msg = err instanceof Error ? err.message : String(err);
|
|
507
|
-
|
|
658
|
+
log3(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
|
|
508
659
|
if (attempt < OUTER_BACKOFFS_MS.length) {
|
|
509
|
-
await
|
|
660
|
+
await sleep2(OUTER_BACKOFFS_MS[attempt]);
|
|
510
661
|
}
|
|
511
662
|
}
|
|
512
663
|
}
|
|
@@ -517,9 +668,9 @@ var DeeplakeApi = class {
|
|
|
517
668
|
const tbl = sqlIdent(name ?? this.tableName);
|
|
518
669
|
const tables = await this.listTables();
|
|
519
670
|
if (!tables.includes(tbl)) {
|
|
520
|
-
|
|
671
|
+
log3(`table "${tbl}" not found, creating`);
|
|
521
672
|
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 '', plugin_version TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, tbl);
|
|
522
|
-
|
|
673
|
+
log3(`table "${tbl}" created`);
|
|
523
674
|
if (!tables.includes(tbl))
|
|
524
675
|
this._tablesCache = [...tables, tbl];
|
|
525
676
|
}
|
|
@@ -532,9 +683,9 @@ var DeeplakeApi = class {
|
|
|
532
683
|
const safe = sqlIdent(name);
|
|
533
684
|
const tables = await this.listTables();
|
|
534
685
|
if (!tables.includes(safe)) {
|
|
535
|
-
|
|
686
|
+
log3(`table "${safe}" not found, creating`);
|
|
536
687
|
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${safe}" (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 '', plugin_version TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
|
|
537
|
-
|
|
688
|
+
log3(`table "${safe}" created`);
|
|
538
689
|
if (!tables.includes(safe))
|
|
539
690
|
this._tablesCache = [...tables, safe];
|
|
540
691
|
}
|
|
@@ -557,9 +708,9 @@ var DeeplakeApi = class {
|
|
|
557
708
|
const safe = sqlIdent(name);
|
|
558
709
|
const tables = await this.listTables();
|
|
559
710
|
if (!tables.includes(safe)) {
|
|
560
|
-
|
|
711
|
+
log3(`table "${safe}" not found, creating`);
|
|
561
712
|
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${safe}" (id TEXT NOT NULL DEFAULT '', name TEXT NOT NULL DEFAULT '', project TEXT NOT NULL DEFAULT '', project_key TEXT NOT NULL DEFAULT '', local_path TEXT NOT NULL DEFAULT '', install TEXT NOT NULL DEFAULT 'project', source_sessions TEXT NOT NULL DEFAULT '[]', source_agent TEXT NOT NULL DEFAULT '', scope TEXT NOT NULL DEFAULT 'me', author TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', trigger_text TEXT NOT NULL DEFAULT '', body TEXT NOT NULL DEFAULT '', version BIGINT NOT NULL DEFAULT 1, created_at TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
|
|
562
|
-
|
|
713
|
+
log3(`table "${safe}" created`);
|
|
563
714
|
if (!tables.includes(safe))
|
|
564
715
|
this._tablesCache = [...tables, safe];
|
|
565
716
|
}
|
|
@@ -1049,9 +1200,9 @@ function capOutputForClaude(output, options = {}) {
|
|
|
1049
1200
|
// dist/src/embeddings/client.js
|
|
1050
1201
|
import { connect } from "node:net";
|
|
1051
1202
|
import { spawn } from "node:child_process";
|
|
1052
|
-
import { openSync, closeSync, writeSync, unlinkSync, existsSync as existsSync3, readFileSync as
|
|
1053
|
-
import { homedir as
|
|
1054
|
-
import { join as
|
|
1203
|
+
import { openSync as openSync2, closeSync as closeSync2, writeSync, unlinkSync as unlinkSync3, existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
|
|
1204
|
+
import { homedir as homedir5 } from "node:os";
|
|
1205
|
+
import { join as join6 } from "node:path";
|
|
1055
1206
|
|
|
1056
1207
|
// dist/src/embeddings/protocol.js
|
|
1057
1208
|
var DEFAULT_SOCKET_DIR = "/tmp";
|
|
@@ -1065,12 +1216,13 @@ function pidPathFor(uid, dir = DEFAULT_SOCKET_DIR) {
|
|
|
1065
1216
|
}
|
|
1066
1217
|
|
|
1067
1218
|
// dist/src/embeddings/client.js
|
|
1068
|
-
var SHARED_DAEMON_PATH =
|
|
1069
|
-
var
|
|
1219
|
+
var SHARED_DAEMON_PATH = join6(homedir5(), ".hivemind", "embed-deps", "embed-daemon.js");
|
|
1220
|
+
var log4 = (m) => log("embed-client", m);
|
|
1070
1221
|
function getUid() {
|
|
1071
1222
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
1072
1223
|
return uid !== void 0 ? String(uid) : process.env.USER ?? "default";
|
|
1073
1224
|
}
|
|
1225
|
+
var _recycledStuckDaemon = false;
|
|
1074
1226
|
var EmbedClient = class {
|
|
1075
1227
|
socketPath;
|
|
1076
1228
|
pidPath;
|
|
@@ -1079,6 +1231,7 @@ var EmbedClient = class {
|
|
|
1079
1231
|
autoSpawn;
|
|
1080
1232
|
spawnWaitMs;
|
|
1081
1233
|
nextId = 0;
|
|
1234
|
+
helloVerified = false;
|
|
1082
1235
|
constructor(opts = {}) {
|
|
1083
1236
|
const uid = getUid();
|
|
1084
1237
|
const dir = opts.socketDir ?? "/tmp";
|
|
@@ -1095,8 +1248,33 @@ var EmbedClient = class {
|
|
|
1095
1248
|
*
|
|
1096
1249
|
* Fire-and-forget spawn on miss: if the daemon isn't up, this call returns
|
|
1097
1250
|
* null AND kicks off a background spawn. The next call finds a ready daemon.
|
|
1251
|
+
*
|
|
1252
|
+
* Stuck-daemon recycle: if the daemon returns a transformers-missing
|
|
1253
|
+
* error (typical after a marketplace upgrade left an older daemon process
|
|
1254
|
+
* alive but with no node_modules accessible from its bundle path), we
|
|
1255
|
+
* SIGTERM it and clear its sock/pid so the very next call spawns a fresh
|
|
1256
|
+
* daemon from the current bundle. Without this, the stuck daemon would
|
|
1257
|
+
* keep poisoning every session until its 10-minute idle-out fires.
|
|
1098
1258
|
*/
|
|
1099
1259
|
async embed(text, kind = "document") {
|
|
1260
|
+
const v = await this.embedAttempt(text, kind);
|
|
1261
|
+
if (v !== "recycled")
|
|
1262
|
+
return v;
|
|
1263
|
+
if (!this.autoSpawn)
|
|
1264
|
+
return null;
|
|
1265
|
+
this.trySpawnDaemon();
|
|
1266
|
+
await this.waitForDaemonReady();
|
|
1267
|
+
const retry = await this.embedAttempt(text, kind);
|
|
1268
|
+
return retry === "recycled" ? null : retry;
|
|
1269
|
+
}
|
|
1270
|
+
/**
|
|
1271
|
+
* One round-trip: connect → verify → embed. Returns:
|
|
1272
|
+
* - number[] : embedding vector (happy path)
|
|
1273
|
+
* - null : timeout / daemon error / transformers-missing
|
|
1274
|
+
* - "recycled": verifyDaemonOnce killed the daemon mid-call;
|
|
1275
|
+
* caller should respawn and retry once.
|
|
1276
|
+
*/
|
|
1277
|
+
async embedAttempt(text, kind) {
|
|
1100
1278
|
let sock;
|
|
1101
1279
|
try {
|
|
1102
1280
|
sock = await this.connectOnce();
|
|
@@ -1106,17 +1284,25 @@ var EmbedClient = class {
|
|
|
1106
1284
|
return null;
|
|
1107
1285
|
}
|
|
1108
1286
|
try {
|
|
1287
|
+
const recycled = await this.verifyDaemonOnce(sock);
|
|
1288
|
+
if (recycled) {
|
|
1289
|
+
return "recycled";
|
|
1290
|
+
}
|
|
1109
1291
|
const id = String(++this.nextId);
|
|
1110
1292
|
const req = { op: "embed", id, kind, text };
|
|
1111
1293
|
const resp = await this.sendAndWait(sock, req);
|
|
1112
1294
|
if (resp.error || !("embedding" in resp) || !resp.embedding) {
|
|
1113
|
-
|
|
1295
|
+
const err = resp.error ?? "no embedding";
|
|
1296
|
+
log4(`embed err: ${err}`);
|
|
1297
|
+
if (isTransformersMissingError(err)) {
|
|
1298
|
+
this.handleTransformersMissing(err);
|
|
1299
|
+
}
|
|
1114
1300
|
return null;
|
|
1115
1301
|
}
|
|
1116
1302
|
return resp.embedding;
|
|
1117
1303
|
} catch (e) {
|
|
1118
1304
|
const err = e instanceof Error ? e.message : String(e);
|
|
1119
|
-
|
|
1305
|
+
log4(`embed failed: ${err}`);
|
|
1120
1306
|
return null;
|
|
1121
1307
|
} finally {
|
|
1122
1308
|
try {
|
|
@@ -1125,6 +1311,123 @@ var EmbedClient = class {
|
|
|
1125
1311
|
}
|
|
1126
1312
|
}
|
|
1127
1313
|
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Poll for the sock file to come back after `trySpawnDaemon` — used by
|
|
1316
|
+
* the recycle retry path. Best-effort: caps at `spawnWaitMs` and
|
|
1317
|
+
* returns regardless so the retry attempt can run.
|
|
1318
|
+
*/
|
|
1319
|
+
async waitForDaemonReady() {
|
|
1320
|
+
const deadline = Date.now() + this.spawnWaitMs;
|
|
1321
|
+
while (Date.now() < deadline) {
|
|
1322
|
+
if (existsSync3(this.socketPath))
|
|
1323
|
+
return;
|
|
1324
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Send a `hello` on first successful connect per EmbedClient instance.
|
|
1329
|
+
* If the daemon answers with a path that doesn't match our configured
|
|
1330
|
+
* daemonEntry — typical after a marketplace upgrade replaced the bundle
|
|
1331
|
+
* — SIGTERM the daemon + clear sock/pid so the next call spawns from the
|
|
1332
|
+
* current bundle.
|
|
1333
|
+
*
|
|
1334
|
+
* `helloVerified` is set ONLY after we've seen a compatible response,
|
|
1335
|
+
* so a transient probe failure or a recycle-triggering mismatch leaves
|
|
1336
|
+
* the flag false; the next reconnect re-runs verification against
|
|
1337
|
+
* whatever daemon is then live (typically the fresh spawn).
|
|
1338
|
+
*/
|
|
1339
|
+
async verifyDaemonOnce(sock) {
|
|
1340
|
+
if (this.helloVerified)
|
|
1341
|
+
return false;
|
|
1342
|
+
if (!this.daemonEntry) {
|
|
1343
|
+
this.helloVerified = true;
|
|
1344
|
+
return false;
|
|
1345
|
+
}
|
|
1346
|
+
const id = String(++this.nextId);
|
|
1347
|
+
const req = { op: "hello", id };
|
|
1348
|
+
let resp;
|
|
1349
|
+
try {
|
|
1350
|
+
resp = await this.sendAndWait(sock, req);
|
|
1351
|
+
} catch (e) {
|
|
1352
|
+
log4(`hello probe failed (inconclusive, will retry next connect): ${e instanceof Error ? e.message : String(e)}`);
|
|
1353
|
+
return false;
|
|
1354
|
+
}
|
|
1355
|
+
const hello = resp;
|
|
1356
|
+
if (_recycledStuckDaemon) {
|
|
1357
|
+
return false;
|
|
1358
|
+
}
|
|
1359
|
+
if (!hello.daemonPath) {
|
|
1360
|
+
_recycledStuckDaemon = true;
|
|
1361
|
+
log4(`daemon does not implement hello (older protocol); recycling`);
|
|
1362
|
+
this.recycleDaemon(hello.pid);
|
|
1363
|
+
return true;
|
|
1364
|
+
}
|
|
1365
|
+
if (hello.daemonPath !== this.daemonEntry && !existsSync3(hello.daemonPath)) {
|
|
1366
|
+
_recycledStuckDaemon = true;
|
|
1367
|
+
log4(`daemon path no longer on disk \u2014 running=${hello.daemonPath} (gone) expected=${this.daemonEntry}; recycling`);
|
|
1368
|
+
this.recycleDaemon(hello.pid);
|
|
1369
|
+
return true;
|
|
1370
|
+
}
|
|
1371
|
+
this.helloVerified = true;
|
|
1372
|
+
return false;
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* On a transformers-missing error from the daemon, SIGTERM the stuck
|
|
1376
|
+
* daemon (the bundle daemon that can't find its deps) and clear
|
|
1377
|
+
* sock/pid so the next call spawns fresh.
|
|
1378
|
+
*
|
|
1379
|
+
* Previously this also enqueued a user-visible "Hivemind embeddings
|
|
1380
|
+
* disabled — deps missing" notification telling the user to run
|
|
1381
|
+
* `hivemind embeddings install`. The notification was removed because
|
|
1382
|
+
* (a) the recycle alone often fixes the issue silently, and (b) the
|
|
1383
|
+
* warning kept stacking on top of the primary session-start banner
|
|
1384
|
+
* which clashed with the single-slot priority model. The `detail`
|
|
1385
|
+
* argument is retained for future telemetry / debug logging.
|
|
1386
|
+
*/
|
|
1387
|
+
handleTransformersMissing(_detail) {
|
|
1388
|
+
if (!_recycledStuckDaemon) {
|
|
1389
|
+
_recycledStuckDaemon = true;
|
|
1390
|
+
this.recycleDaemon(null);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Best-effort SIGTERM + sock/pid cleanup. Tolerant of every missing-file
|
|
1395
|
+
* combination and dead-PID cases.
|
|
1396
|
+
*
|
|
1397
|
+
* Identity check: gate the SIGTERM on the daemon's socket file still
|
|
1398
|
+
* existing. We know the daemon was alive moments ago (we either just
|
|
1399
|
+
* got a hello response or the caller saw a transformers-missing error
|
|
1400
|
+
* the daemon emitted), but if the socket file is gone by the time we
|
|
1401
|
+
* try to kill, the daemon process is also gone and the PID we
|
|
1402
|
+
* captured may already have been recycled by the OS to an unrelated
|
|
1403
|
+
* user process. Mirrors the gate added to `killEmbedDaemon` in the
|
|
1404
|
+
* CLI — same failure mode, rarer trigger.
|
|
1405
|
+
*/
|
|
1406
|
+
recycleDaemon(reportedPid) {
|
|
1407
|
+
let pid = reportedPid;
|
|
1408
|
+
if (pid === null) {
|
|
1409
|
+
try {
|
|
1410
|
+
pid = Number.parseInt(readFileSync5(this.pidPath, "utf-8").trim(), 10);
|
|
1411
|
+
} catch {
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
if (Number.isFinite(pid) && pid !== null && pid > 0 && existsSync3(this.socketPath)) {
|
|
1415
|
+
try {
|
|
1416
|
+
process.kill(pid, "SIGTERM");
|
|
1417
|
+
} catch {
|
|
1418
|
+
}
|
|
1419
|
+
} else if (pid !== null) {
|
|
1420
|
+
log4(`recycle: socket gone, skipping SIGTERM on possibly-stale pid ${pid}`);
|
|
1421
|
+
}
|
|
1422
|
+
try {
|
|
1423
|
+
unlinkSync3(this.socketPath);
|
|
1424
|
+
} catch {
|
|
1425
|
+
}
|
|
1426
|
+
try {
|
|
1427
|
+
unlinkSync3(this.pidPath);
|
|
1428
|
+
} catch {
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1128
1431
|
/**
|
|
1129
1432
|
* Wait up to spawnWaitMs for the daemon to accept connections, spawning if
|
|
1130
1433
|
* necessary. Meant for SessionStart / long-running batches — not the hot path.
|
|
@@ -1148,7 +1451,7 @@ var EmbedClient = class {
|
|
|
1148
1451
|
}
|
|
1149
1452
|
}
|
|
1150
1453
|
connectOnce() {
|
|
1151
|
-
return new Promise((
|
|
1454
|
+
return new Promise((resolve3, reject) => {
|
|
1152
1455
|
const sock = connect(this.socketPath);
|
|
1153
1456
|
const to = setTimeout(() => {
|
|
1154
1457
|
sock.destroy();
|
|
@@ -1156,7 +1459,7 @@ var EmbedClient = class {
|
|
|
1156
1459
|
}, this.timeoutMs);
|
|
1157
1460
|
sock.once("connect", () => {
|
|
1158
1461
|
clearTimeout(to);
|
|
1159
|
-
|
|
1462
|
+
resolve3(sock);
|
|
1160
1463
|
});
|
|
1161
1464
|
sock.once("error", (e) => {
|
|
1162
1465
|
clearTimeout(to);
|
|
@@ -1167,16 +1470,16 @@ var EmbedClient = class {
|
|
|
1167
1470
|
trySpawnDaemon() {
|
|
1168
1471
|
let fd;
|
|
1169
1472
|
try {
|
|
1170
|
-
fd =
|
|
1473
|
+
fd = openSync2(this.pidPath, "wx", 384);
|
|
1171
1474
|
writeSync(fd, String(process.pid));
|
|
1172
1475
|
} catch (e) {
|
|
1173
1476
|
if (this.isPidFileStale()) {
|
|
1174
1477
|
try {
|
|
1175
|
-
|
|
1478
|
+
unlinkSync3(this.pidPath);
|
|
1176
1479
|
} catch {
|
|
1177
1480
|
}
|
|
1178
1481
|
try {
|
|
1179
|
-
fd =
|
|
1482
|
+
fd = openSync2(this.pidPath, "wx", 384);
|
|
1180
1483
|
writeSync(fd, String(process.pid));
|
|
1181
1484
|
} catch {
|
|
1182
1485
|
return;
|
|
@@ -1186,10 +1489,10 @@ var EmbedClient = class {
|
|
|
1186
1489
|
}
|
|
1187
1490
|
}
|
|
1188
1491
|
if (!this.daemonEntry || !existsSync3(this.daemonEntry)) {
|
|
1189
|
-
|
|
1492
|
+
log4(`daemonEntry not configured or missing: ${this.daemonEntry}`);
|
|
1190
1493
|
try {
|
|
1191
|
-
|
|
1192
|
-
|
|
1494
|
+
closeSync2(fd);
|
|
1495
|
+
unlinkSync3(this.pidPath);
|
|
1193
1496
|
} catch {
|
|
1194
1497
|
}
|
|
1195
1498
|
return;
|
|
@@ -1201,14 +1504,14 @@ var EmbedClient = class {
|
|
|
1201
1504
|
env: process.env
|
|
1202
1505
|
});
|
|
1203
1506
|
child.unref();
|
|
1204
|
-
|
|
1507
|
+
log4(`spawned daemon pid=${child.pid}`);
|
|
1205
1508
|
} finally {
|
|
1206
|
-
|
|
1509
|
+
closeSync2(fd);
|
|
1207
1510
|
}
|
|
1208
1511
|
}
|
|
1209
1512
|
isPidFileStale() {
|
|
1210
1513
|
try {
|
|
1211
|
-
const raw =
|
|
1514
|
+
const raw = readFileSync5(this.pidPath, "utf-8").trim();
|
|
1212
1515
|
const pid = Number(raw);
|
|
1213
1516
|
if (!pid || Number.isNaN(pid))
|
|
1214
1517
|
return true;
|
|
@@ -1226,7 +1529,7 @@ var EmbedClient = class {
|
|
|
1226
1529
|
const deadline = Date.now() + this.spawnWaitMs;
|
|
1227
1530
|
let delay = 30;
|
|
1228
1531
|
while (Date.now() < deadline) {
|
|
1229
|
-
await
|
|
1532
|
+
await sleep3(delay);
|
|
1230
1533
|
delay = Math.min(delay * 1.5, 300);
|
|
1231
1534
|
if (!existsSync3(this.socketPath))
|
|
1232
1535
|
continue;
|
|
@@ -1238,7 +1541,7 @@ var EmbedClient = class {
|
|
|
1238
1541
|
throw new Error("daemon did not become ready within spawnWaitMs");
|
|
1239
1542
|
}
|
|
1240
1543
|
sendAndWait(sock, req) {
|
|
1241
|
-
return new Promise((
|
|
1544
|
+
return new Promise((resolve3, reject) => {
|
|
1242
1545
|
let buf = "";
|
|
1243
1546
|
const to = setTimeout(() => {
|
|
1244
1547
|
sock.destroy();
|
|
@@ -1253,7 +1556,7 @@ var EmbedClient = class {
|
|
|
1253
1556
|
const line = buf.slice(0, nl);
|
|
1254
1557
|
clearTimeout(to);
|
|
1255
1558
|
try {
|
|
1256
|
-
|
|
1559
|
+
resolve3(JSON.parse(line));
|
|
1257
1560
|
} catch (e) {
|
|
1258
1561
|
reject(e);
|
|
1259
1562
|
}
|
|
@@ -1270,29 +1573,116 @@ var EmbedClient = class {
|
|
|
1270
1573
|
});
|
|
1271
1574
|
}
|
|
1272
1575
|
};
|
|
1273
|
-
function
|
|
1576
|
+
function sleep3(ms) {
|
|
1274
1577
|
return new Promise((r) => setTimeout(r, ms));
|
|
1275
1578
|
}
|
|
1579
|
+
function isTransformersMissingError(err) {
|
|
1580
|
+
if (/hivemind embeddings install/i.test(err))
|
|
1581
|
+
return true;
|
|
1582
|
+
return /@huggingface\/transformers/i.test(err);
|
|
1583
|
+
}
|
|
1276
1584
|
|
|
1277
1585
|
// dist/src/embeddings/disable.js
|
|
1278
1586
|
import { createRequire } from "node:module";
|
|
1279
|
-
import { homedir as
|
|
1280
|
-
import { join as
|
|
1587
|
+
import { homedir as homedir7 } from "node:os";
|
|
1588
|
+
import { join as join8 } from "node:path";
|
|
1281
1589
|
import { pathToFileURL } from "node:url";
|
|
1590
|
+
|
|
1591
|
+
// dist/src/user-config.js
|
|
1592
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1593
|
+
import { homedir as homedir6 } from "node:os";
|
|
1594
|
+
import { dirname, join as join7 } from "node:path";
|
|
1595
|
+
var _configPath = () => process.env.HIVEMIND_CONFIG_PATH ?? join7(homedir6(), ".deeplake", "config.json");
|
|
1596
|
+
var _cache = null;
|
|
1597
|
+
var _migrated = false;
|
|
1598
|
+
function readUserConfig() {
|
|
1599
|
+
if (_cache !== null)
|
|
1600
|
+
return _cache;
|
|
1601
|
+
const path = _configPath();
|
|
1602
|
+
if (!existsSync4(path)) {
|
|
1603
|
+
_cache = {};
|
|
1604
|
+
return _cache;
|
|
1605
|
+
}
|
|
1606
|
+
try {
|
|
1607
|
+
const raw = readFileSync6(path, "utf-8");
|
|
1608
|
+
const parsed = JSON.parse(raw);
|
|
1609
|
+
_cache = isPlainObject(parsed) ? parsed : {};
|
|
1610
|
+
} catch {
|
|
1611
|
+
_cache = {};
|
|
1612
|
+
}
|
|
1613
|
+
return _cache;
|
|
1614
|
+
}
|
|
1615
|
+
function writeUserConfig(patch) {
|
|
1616
|
+
const current = readUserConfig();
|
|
1617
|
+
const merged = deepMerge(current, patch);
|
|
1618
|
+
const path = _configPath();
|
|
1619
|
+
const dir = dirname(path);
|
|
1620
|
+
if (!existsSync4(dir))
|
|
1621
|
+
mkdirSync4(dir, { recursive: true });
|
|
1622
|
+
const tmp = `${path}.tmp.${process.pid}`;
|
|
1623
|
+
writeFileSync4(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
1624
|
+
renameSync2(tmp, path);
|
|
1625
|
+
_cache = merged;
|
|
1626
|
+
return merged;
|
|
1627
|
+
}
|
|
1628
|
+
function getEmbeddingsEnabled() {
|
|
1629
|
+
const cfg = readUserConfig();
|
|
1630
|
+
if (cfg.embeddings && typeof cfg.embeddings.enabled === "boolean") {
|
|
1631
|
+
return cfg.embeddings.enabled;
|
|
1632
|
+
}
|
|
1633
|
+
if (_migrated) {
|
|
1634
|
+
return migrationValueFromEnv();
|
|
1635
|
+
}
|
|
1636
|
+
_migrated = true;
|
|
1637
|
+
const enabled = migrationValueFromEnv();
|
|
1638
|
+
try {
|
|
1639
|
+
writeUserConfig({ embeddings: { enabled } });
|
|
1640
|
+
} catch {
|
|
1641
|
+
_cache = { ...cfg ?? {}, embeddings: { ...cfg?.embeddings ?? {}, enabled } };
|
|
1642
|
+
}
|
|
1643
|
+
return enabled;
|
|
1644
|
+
}
|
|
1645
|
+
function migrationValueFromEnv() {
|
|
1646
|
+
const raw = process.env.HIVEMIND_EMBEDDINGS;
|
|
1647
|
+
if (raw === void 0)
|
|
1648
|
+
return false;
|
|
1649
|
+
if (raw === "false")
|
|
1650
|
+
return false;
|
|
1651
|
+
return true;
|
|
1652
|
+
}
|
|
1653
|
+
function isPlainObject(value) {
|
|
1654
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1655
|
+
}
|
|
1656
|
+
function deepMerge(base, patch) {
|
|
1657
|
+
const out = { ...base };
|
|
1658
|
+
for (const key of Object.keys(patch)) {
|
|
1659
|
+
const patchVal = patch[key];
|
|
1660
|
+
const baseVal = base[key];
|
|
1661
|
+
if (isPlainObject(patchVal) && isPlainObject(baseVal)) {
|
|
1662
|
+
out[key] = { ...baseVal, ...patchVal };
|
|
1663
|
+
} else if (patchVal !== void 0) {
|
|
1664
|
+
out[key] = patchVal;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
return out;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
// dist/src/embeddings/disable.js
|
|
1282
1671
|
var cachedStatus = null;
|
|
1283
1672
|
function defaultResolveTransformers() {
|
|
1673
|
+
const sharedDir = join8(homedir7(), ".hivemind", "embed-deps");
|
|
1284
1674
|
try {
|
|
1285
|
-
createRequire(
|
|
1675
|
+
createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
|
|
1286
1676
|
return;
|
|
1287
1677
|
} catch {
|
|
1288
1678
|
}
|
|
1289
|
-
|
|
1290
|
-
createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
|
|
1679
|
+
createRequire(import.meta.url).resolve("@huggingface/transformers");
|
|
1291
1680
|
}
|
|
1292
1681
|
var _resolve = defaultResolveTransformers;
|
|
1682
|
+
var _readEnabled = getEmbeddingsEnabled;
|
|
1293
1683
|
function detectStatus() {
|
|
1294
|
-
if (
|
|
1295
|
-
return "
|
|
1684
|
+
if (!_readEnabled())
|
|
1685
|
+
return "user-disabled";
|
|
1296
1686
|
try {
|
|
1297
1687
|
_resolve();
|
|
1298
1688
|
return "enabled";
|
|
@@ -1312,11 +1702,11 @@ function embeddingsDisabled() {
|
|
|
1312
1702
|
|
|
1313
1703
|
// dist/src/hooks/grep-direct.js
|
|
1314
1704
|
import { fileURLToPath } from "node:url";
|
|
1315
|
-
import { dirname, join as
|
|
1705
|
+
import { dirname as dirname2, join as join9 } from "node:path";
|
|
1316
1706
|
var SEMANTIC_ENABLED = process.env.HIVEMIND_SEMANTIC_SEARCH !== "false" && !embeddingsDisabled();
|
|
1317
1707
|
var SEMANTIC_TIMEOUT_MS = Number(process.env.HIVEMIND_SEMANTIC_EMBED_TIMEOUT_MS ?? "500");
|
|
1318
1708
|
function resolveDaemonPath() {
|
|
1319
|
-
return
|
|
1709
|
+
return join9(dirname2(fileURLToPath(import.meta.url)), "..", "embeddings", "embed-daemon.js");
|
|
1320
1710
|
}
|
|
1321
1711
|
var sharedEmbedClient = null;
|
|
1322
1712
|
function getEmbedClient() {
|
|
@@ -2319,20 +2709,20 @@ async function executeCompiledBashCommand(api, memoryTable, sessionsTable, cmd,
|
|
|
2319
2709
|
}
|
|
2320
2710
|
|
|
2321
2711
|
// dist/src/hooks/query-cache.js
|
|
2322
|
-
import { mkdirSync as
|
|
2323
|
-
import { join as
|
|
2324
|
-
import { homedir as
|
|
2325
|
-
var
|
|
2326
|
-
var DEFAULT_CACHE_ROOT =
|
|
2712
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, rmSync, writeFileSync as writeFileSync5 } from "node:fs";
|
|
2713
|
+
import { join as join10 } from "node:path";
|
|
2714
|
+
import { homedir as homedir8 } from "node:os";
|
|
2715
|
+
var log5 = (msg) => log("query-cache", msg);
|
|
2716
|
+
var DEFAULT_CACHE_ROOT = join10(homedir8(), ".deeplake", "query-cache");
|
|
2327
2717
|
var INDEX_CACHE_FILE = "index.md";
|
|
2328
2718
|
function getSessionQueryCacheDir(sessionId, deps = {}) {
|
|
2329
2719
|
const { cacheRoot = DEFAULT_CACHE_ROOT } = deps;
|
|
2330
|
-
return
|
|
2720
|
+
return join10(cacheRoot, sessionId);
|
|
2331
2721
|
}
|
|
2332
2722
|
function readCachedIndexContent(sessionId, deps = {}) {
|
|
2333
|
-
const { logFn =
|
|
2723
|
+
const { logFn = log5 } = deps;
|
|
2334
2724
|
try {
|
|
2335
|
-
return
|
|
2725
|
+
return readFileSync7(join10(getSessionQueryCacheDir(sessionId, deps), INDEX_CACHE_FILE), "utf-8");
|
|
2336
2726
|
} catch (e) {
|
|
2337
2727
|
if (e?.code === "ENOENT")
|
|
2338
2728
|
return null;
|
|
@@ -2341,34 +2731,34 @@ function readCachedIndexContent(sessionId, deps = {}) {
|
|
|
2341
2731
|
}
|
|
2342
2732
|
}
|
|
2343
2733
|
function writeCachedIndexContent(sessionId, content, deps = {}) {
|
|
2344
|
-
const { logFn =
|
|
2734
|
+
const { logFn = log5 } = deps;
|
|
2345
2735
|
try {
|
|
2346
2736
|
const dir = getSessionQueryCacheDir(sessionId, deps);
|
|
2347
|
-
|
|
2348
|
-
|
|
2737
|
+
mkdirSync5(dir, { recursive: true });
|
|
2738
|
+
writeFileSync5(join10(dir, INDEX_CACHE_FILE), content, "utf-8");
|
|
2349
2739
|
} catch (e) {
|
|
2350
2740
|
logFn(`write failed for session=${sessionId}: ${e.message}`);
|
|
2351
2741
|
}
|
|
2352
2742
|
}
|
|
2353
2743
|
|
|
2354
2744
|
// dist/src/utils/direct-run.js
|
|
2355
|
-
import { resolve } from "node:path";
|
|
2745
|
+
import { resolve as resolve2 } from "node:path";
|
|
2356
2746
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
2357
2747
|
function isDirectRun(metaUrl) {
|
|
2358
2748
|
const entry = process.argv[1];
|
|
2359
2749
|
if (!entry)
|
|
2360
2750
|
return false;
|
|
2361
2751
|
try {
|
|
2362
|
-
return
|
|
2752
|
+
return resolve2(fileURLToPath2(metaUrl)) === resolve2(entry);
|
|
2363
2753
|
} catch {
|
|
2364
2754
|
return false;
|
|
2365
2755
|
}
|
|
2366
2756
|
}
|
|
2367
2757
|
|
|
2368
2758
|
// dist/src/hooks/memory-path-utils.js
|
|
2369
|
-
import { homedir as
|
|
2370
|
-
import { join as
|
|
2371
|
-
var MEMORY_PATH =
|
|
2759
|
+
import { homedir as homedir9 } from "node:os";
|
|
2760
|
+
import { join as join11 } from "node:path";
|
|
2761
|
+
var MEMORY_PATH = join11(homedir9(), ".deeplake", "memory");
|
|
2372
2762
|
var TILDE_PATH = "~/.deeplake/memory";
|
|
2373
2763
|
var HOME_VAR_PATH = "$HOME/.deeplake/memory";
|
|
2374
2764
|
var SAFE_BUILTINS = /* @__PURE__ */ new Set([
|
|
@@ -2484,13 +2874,13 @@ function rewritePaths(cmd) {
|
|
|
2484
2874
|
}
|
|
2485
2875
|
|
|
2486
2876
|
// dist/src/hooks/codex/pre-tool-use.js
|
|
2487
|
-
var
|
|
2488
|
-
var __bundleDir =
|
|
2489
|
-
var SHELL_BUNDLE =
|
|
2877
|
+
var log6 = (msg) => log("codex-pre", msg);
|
|
2878
|
+
var __bundleDir = dirname3(fileURLToPath3(import.meta.url));
|
|
2879
|
+
var SHELL_BUNDLE = existsSync5(join12(__bundleDir, "shell", "deeplake-shell.js")) ? join12(__bundleDir, "shell", "deeplake-shell.js") : join12(__bundleDir, "..", "shell", "deeplake-shell.js");
|
|
2490
2880
|
function buildUnsupportedGuidance() {
|
|
2491
2881
|
return "This command is not supported for ~/.deeplake/memory/ operations. Only bash builtins are available: cat, ls, grep, echo, jq, head, tail, sed, awk, wc, sort, find, etc. Do NOT use python, python3, node, curl, or other interpreters. Rewrite your command using only bash tools and retry.";
|
|
2492
2882
|
}
|
|
2493
|
-
function runVirtualShell(cmd, shellBundle = SHELL_BUNDLE, logFn =
|
|
2883
|
+
function runVirtualShell(cmd, shellBundle = SHELL_BUNDLE, logFn = log6) {
|
|
2494
2884
|
try {
|
|
2495
2885
|
return execFileSync("node", [shellBundle, "-c", cmd], {
|
|
2496
2886
|
encoding: "utf-8",
|
|
@@ -2515,7 +2905,7 @@ function buildIndexContent(rows) {
|
|
|
2515
2905
|
return lines.join("\n");
|
|
2516
2906
|
}
|
|
2517
2907
|
async function processCodexPreToolUse(input, deps = {}) {
|
|
2518
|
-
const { config = loadConfig(), createApi = (table, activeConfig) => new DeeplakeApi(activeConfig.token, activeConfig.apiUrl, activeConfig.orgId, activeConfig.workspaceId, table), executeCompiledBashCommandFn = executeCompiledBashCommand, readVirtualPathContentsFn = readVirtualPathContents, readVirtualPathContentFn = readVirtualPathContent, listVirtualPathRowsFn = listVirtualPathRows, findVirtualPathsFn = findVirtualPaths, handleGrepDirectFn = handleGrepDirect, readCachedIndexContentFn = readCachedIndexContent, writeCachedIndexContentFn = writeCachedIndexContent, runVirtualShellFn = runVirtualShell, shellBundle = SHELL_BUNDLE, logFn =
|
|
2908
|
+
const { config = loadConfig(), createApi = (table, activeConfig) => new DeeplakeApi(activeConfig.token, activeConfig.apiUrl, activeConfig.orgId, activeConfig.workspaceId, table), executeCompiledBashCommandFn = executeCompiledBashCommand, readVirtualPathContentsFn = readVirtualPathContents, readVirtualPathContentFn = readVirtualPathContent, listVirtualPathRowsFn = listVirtualPathRows, findVirtualPathsFn = findVirtualPaths, handleGrepDirectFn = handleGrepDirect, readCachedIndexContentFn = readCachedIndexContent, writeCachedIndexContentFn = writeCachedIndexContent, runVirtualShellFn = runVirtualShell, shellBundle = SHELL_BUNDLE, logFn = log6 } = deps;
|
|
2519
2909
|
const cmd = input.tool_input?.command ?? "";
|
|
2520
2910
|
logFn(`hook fired: cmd=${cmd}`);
|
|
2521
2911
|
if (!touchesMemory(cmd))
|
|
@@ -2725,7 +3115,7 @@ async function main() {
|
|
|
2725
3115
|
}
|
|
2726
3116
|
if (isDirectRun(import.meta.url)) {
|
|
2727
3117
|
main().catch((e) => {
|
|
2728
|
-
|
|
3118
|
+
log6(`fatal: ${e.message}`);
|
|
2729
3119
|
process.exit(0);
|
|
2730
3120
|
});
|
|
2731
3121
|
}
|