@deeplake/hivemind 0.7.32 → 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 +304 -171
- package/codex/bundle/capture.js +365 -332
- package/codex/bundle/commands/auth-login.js +163 -30
- package/codex/bundle/pre-tool-use.js +334 -301
- package/codex/bundle/session-start-setup.js +193 -60
- package/codex/bundle/session-start.js +221 -88
- package/codex/bundle/shell/deeplake-shell.js +328 -295
- package/codex/bundle/stop.js +424 -391
- package/codex/bundle/wiki-worker.js +174 -292
- package/cursor/bundle/capture.js +420 -387
- package/cursor/bundle/commands/auth-login.js +163 -30
- package/cursor/bundle/pre-tool-use.js +324 -291
- package/cursor/bundle/session-start.js +263 -130
- package/cursor/bundle/shell/deeplake-shell.js +328 -295
- package/cursor/bundle/wiki-worker.js +174 -292
- package/hermes/bundle/capture.js +420 -387
- package/hermes/bundle/commands/auth-login.js +163 -30
- package/hermes/bundle/pre-tool-use.js +324 -291
- package/hermes/bundle/session-start.js +260 -127
- package/hermes/bundle/shell/deeplake-shell.js +328 -295
- package/hermes/bundle/wiki-worker.js +174 -292
- 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
package/codex/bundle/capture.js
CHANGED
|
@@ -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({
|
|
@@ -147,6 +147,125 @@ function deeplakeClientHeader() {
|
|
|
147
147
|
return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// dist/src/notifications/queue.js
|
|
151
|
+
import { readFileSync as readFileSync2, writeFileSync, renameSync, mkdirSync, openSync, closeSync, unlinkSync, statSync } from "node:fs";
|
|
152
|
+
import { join as join3, resolve } from "node:path";
|
|
153
|
+
import { homedir as homedir3 } from "node:os";
|
|
154
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
155
|
+
var log2 = (msg) => log("notifications-queue", msg);
|
|
156
|
+
var LOCK_RETRY_MAX = 50;
|
|
157
|
+
var LOCK_RETRY_BASE_MS = 5;
|
|
158
|
+
var LOCK_STALE_MS = 5e3;
|
|
159
|
+
function queuePath() {
|
|
160
|
+
return join3(homedir3(), ".deeplake", "notifications-queue.json");
|
|
161
|
+
}
|
|
162
|
+
function lockPath() {
|
|
163
|
+
return `${queuePath()}.lock`;
|
|
164
|
+
}
|
|
165
|
+
function readQueue() {
|
|
166
|
+
try {
|
|
167
|
+
const raw = readFileSync2(queuePath(), "utf-8");
|
|
168
|
+
const parsed = JSON.parse(raw);
|
|
169
|
+
if (!parsed || !Array.isArray(parsed.queue)) {
|
|
170
|
+
log2(`queue malformed \u2192 treating as empty`);
|
|
171
|
+
return { queue: [] };
|
|
172
|
+
}
|
|
173
|
+
return { queue: parsed.queue };
|
|
174
|
+
} catch {
|
|
175
|
+
return { queue: [] };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function _isQueuePathInsideHome(path, home) {
|
|
179
|
+
const r = resolve(path);
|
|
180
|
+
const h = resolve(home);
|
|
181
|
+
return r.startsWith(h + "/") || r === h;
|
|
182
|
+
}
|
|
183
|
+
function writeQueue(q) {
|
|
184
|
+
const path = queuePath();
|
|
185
|
+
const home = resolve(homedir3());
|
|
186
|
+
if (!_isQueuePathInsideHome(path, home)) {
|
|
187
|
+
throw new Error(`notifications-queue write blocked: ${path} is outside ${home}`);
|
|
188
|
+
}
|
|
189
|
+
mkdirSync(join3(home, ".deeplake"), { recursive: true, mode: 448 });
|
|
190
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
191
|
+
writeFileSync(tmp, JSON.stringify(q, null, 2), { mode: 384 });
|
|
192
|
+
renameSync(tmp, path);
|
|
193
|
+
}
|
|
194
|
+
async function withQueueLock(fn) {
|
|
195
|
+
const path = lockPath();
|
|
196
|
+
mkdirSync(join3(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
|
|
197
|
+
let fd = null;
|
|
198
|
+
for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
|
|
199
|
+
try {
|
|
200
|
+
fd = openSync(path, "wx", 384);
|
|
201
|
+
break;
|
|
202
|
+
} catch (e) {
|
|
203
|
+
const code = e.code;
|
|
204
|
+
if (code !== "EEXIST")
|
|
205
|
+
throw e;
|
|
206
|
+
try {
|
|
207
|
+
const age = Date.now() - statSync(path).mtimeMs;
|
|
208
|
+
if (age > LOCK_STALE_MS) {
|
|
209
|
+
unlinkSync(path);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
} catch {
|
|
213
|
+
}
|
|
214
|
+
const delay = LOCK_RETRY_BASE_MS * (attempt + 1);
|
|
215
|
+
await sleep(delay);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (fd === null) {
|
|
219
|
+
log2(`lock acquisition gave up after ${LOCK_RETRY_MAX} attempts \u2014 proceeding unlocked (last-writer-wins)`);
|
|
220
|
+
return fn();
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
return fn();
|
|
224
|
+
} finally {
|
|
225
|
+
try {
|
|
226
|
+
closeSync(fd);
|
|
227
|
+
} catch {
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
230
|
+
unlinkSync(path);
|
|
231
|
+
} catch {
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function sameDedupKey(a, b) {
|
|
236
|
+
if (a.id !== b.id)
|
|
237
|
+
return false;
|
|
238
|
+
return JSON.stringify(a.dedupKey) === JSON.stringify(b.dedupKey);
|
|
239
|
+
}
|
|
240
|
+
async function enqueueNotification(n) {
|
|
241
|
+
await withQueueLock(() => {
|
|
242
|
+
const q = readQueue();
|
|
243
|
+
if (q.queue.some((existing) => sameDedupKey(existing, n))) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
q.queue.push(n);
|
|
247
|
+
writeQueue(q);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// dist/src/commands/auth-creds.js
|
|
252
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "node:fs";
|
|
253
|
+
import { join as join4 } from "node:path";
|
|
254
|
+
import { homedir as homedir4 } from "node:os";
|
|
255
|
+
function configDir() {
|
|
256
|
+
return join4(homedir4(), ".deeplake");
|
|
257
|
+
}
|
|
258
|
+
function credsPath() {
|
|
259
|
+
return join4(configDir(), "credentials.json");
|
|
260
|
+
}
|
|
261
|
+
function loadCredentials() {
|
|
262
|
+
try {
|
|
263
|
+
return JSON.parse(readFileSync3(credsPath(), "utf-8"));
|
|
264
|
+
} catch {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
150
269
|
// dist/src/deeplake-api.js
|
|
151
270
|
var indexMarkerStorePromise = null;
|
|
152
271
|
function getIndexMarkerStore() {
|
|
@@ -154,7 +273,7 @@ function getIndexMarkerStore() {
|
|
|
154
273
|
indexMarkerStorePromise = Promise.resolve().then(() => (init_index_marker_store(), index_marker_store_exports));
|
|
155
274
|
return indexMarkerStorePromise;
|
|
156
275
|
}
|
|
157
|
-
var
|
|
276
|
+
var log3 = (msg) => log("sdk", msg);
|
|
158
277
|
function summarizeSql(sql, maxLen = 220) {
|
|
159
278
|
const compact = sql.replace(/\s+/g, " ").trim();
|
|
160
279
|
return compact.length > maxLen ? `${compact.slice(0, maxLen)}...` : compact;
|
|
@@ -166,7 +285,38 @@ function traceSql(msg) {
|
|
|
166
285
|
process.stderr.write(`[deeplake-sql] ${msg}
|
|
167
286
|
`);
|
|
168
287
|
if (process.env.HIVEMIND_DEBUG === "1")
|
|
169
|
-
|
|
288
|
+
log3(msg);
|
|
289
|
+
}
|
|
290
|
+
var _signalledBalanceExhausted = false;
|
|
291
|
+
function maybeSignalBalanceExhausted(status, bodyText) {
|
|
292
|
+
if (status !== 402)
|
|
293
|
+
return;
|
|
294
|
+
if (!bodyText.includes("balance_cents"))
|
|
295
|
+
return;
|
|
296
|
+
if (_signalledBalanceExhausted)
|
|
297
|
+
return;
|
|
298
|
+
_signalledBalanceExhausted = true;
|
|
299
|
+
log3(`balance exhausted \u2014 enqueuing session-start banner (body=${bodyText.slice(0, 120)})`);
|
|
300
|
+
enqueueNotification({
|
|
301
|
+
id: "balance-exhausted",
|
|
302
|
+
severity: "warn",
|
|
303
|
+
transient: true,
|
|
304
|
+
title: "Hivemind credits exhausted \u2014 top up to keep capturing",
|
|
305
|
+
body: `Sessions are not being saved and memory recall is returning empty. Top up at ${billingUrl()} to restore capture and recall.`,
|
|
306
|
+
dedupKey: { reason: "balance-zero" }
|
|
307
|
+
}).catch((e) => {
|
|
308
|
+
log3(`enqueue balance-exhausted failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
function billingUrl() {
|
|
312
|
+
try {
|
|
313
|
+
const c = loadCredentials();
|
|
314
|
+
if (c?.orgName && c?.workspaceId) {
|
|
315
|
+
return `https://deeplake.ai/${encodeURIComponent(c.orgName)}/workspace/${encodeURIComponent(c.workspaceId)}/billing`;
|
|
316
|
+
}
|
|
317
|
+
} catch {
|
|
318
|
+
}
|
|
319
|
+
return "https://deeplake.ai";
|
|
170
320
|
}
|
|
171
321
|
var RETRYABLE_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
172
322
|
var MAX_RETRIES = 3;
|
|
@@ -175,7 +325,7 @@ var MAX_CONCURRENCY = 5;
|
|
|
175
325
|
function getQueryTimeoutMs() {
|
|
176
326
|
return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
|
|
177
327
|
}
|
|
178
|
-
function
|
|
328
|
+
function sleep2(ms) {
|
|
179
329
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
180
330
|
}
|
|
181
331
|
function isTimeoutError(error) {
|
|
@@ -277,8 +427,8 @@ var DeeplakeApi = class {
|
|
|
277
427
|
lastError = e instanceof Error ? e : new Error(String(e));
|
|
278
428
|
if (attempt < MAX_RETRIES) {
|
|
279
429
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
280
|
-
|
|
281
|
-
await
|
|
430
|
+
log3(`query retry ${attempt + 1}/${MAX_RETRIES} (fetch error: ${lastError.message}) in ${delay.toFixed(0)}ms`);
|
|
431
|
+
await sleep2(delay);
|
|
282
432
|
continue;
|
|
283
433
|
}
|
|
284
434
|
throw lastError;
|
|
@@ -294,10 +444,11 @@ var DeeplakeApi = class {
|
|
|
294
444
|
const alreadyExists = resp.status === 500 && isDuplicateIndexError(text);
|
|
295
445
|
if (!alreadyExists && attempt < MAX_RETRIES && (RETRYABLE_CODES.has(resp.status) || retryable403)) {
|
|
296
446
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
297
|
-
|
|
298
|
-
await
|
|
447
|
+
log3(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
|
|
448
|
+
await sleep2(delay);
|
|
299
449
|
continue;
|
|
300
450
|
}
|
|
451
|
+
maybeSignalBalanceExhausted(resp.status, text);
|
|
301
452
|
throw new Error(`Query failed: ${resp.status}: ${text.slice(0, 200)}`);
|
|
302
453
|
}
|
|
303
454
|
throw lastError ?? new Error("Query failed: max retries exceeded");
|
|
@@ -318,7 +469,7 @@ var DeeplakeApi = class {
|
|
|
318
469
|
const chunk = rows.slice(i, i + CONCURRENCY);
|
|
319
470
|
await Promise.allSettled(chunk.map((r) => this.upsertRowSql(r)));
|
|
320
471
|
}
|
|
321
|
-
|
|
472
|
+
log3(`commit: ${rows.length} rows`);
|
|
322
473
|
}
|
|
323
474
|
async upsertRowSql(row) {
|
|
324
475
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -374,7 +525,7 @@ var DeeplakeApi = class {
|
|
|
374
525
|
markers.writeIndexMarker(markerPath);
|
|
375
526
|
return;
|
|
376
527
|
}
|
|
377
|
-
|
|
528
|
+
log3(`index "${indexName}" skipped: ${e.message}`);
|
|
378
529
|
}
|
|
379
530
|
}
|
|
380
531
|
/**
|
|
@@ -464,13 +615,13 @@ var DeeplakeApi = class {
|
|
|
464
615
|
};
|
|
465
616
|
}
|
|
466
617
|
if (attempt < MAX_RETRIES && RETRYABLE_CODES.has(resp.status)) {
|
|
467
|
-
await
|
|
618
|
+
await sleep2(BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200);
|
|
468
619
|
continue;
|
|
469
620
|
}
|
|
470
621
|
return { tables: [], cacheable: false };
|
|
471
622
|
} catch {
|
|
472
623
|
if (attempt < MAX_RETRIES) {
|
|
473
|
-
await
|
|
624
|
+
await sleep2(BASE_DELAY_MS * Math.pow(2, attempt));
|
|
474
625
|
continue;
|
|
475
626
|
}
|
|
476
627
|
return { tables: [], cacheable: false };
|
|
@@ -498,9 +649,9 @@ var DeeplakeApi = class {
|
|
|
498
649
|
} catch (err) {
|
|
499
650
|
lastErr = err;
|
|
500
651
|
const msg = err instanceof Error ? err.message : String(err);
|
|
501
|
-
|
|
652
|
+
log3(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
|
|
502
653
|
if (attempt < OUTER_BACKOFFS_MS.length) {
|
|
503
|
-
await
|
|
654
|
+
await sleep2(OUTER_BACKOFFS_MS[attempt]);
|
|
504
655
|
}
|
|
505
656
|
}
|
|
506
657
|
}
|
|
@@ -511,9 +662,9 @@ var DeeplakeApi = class {
|
|
|
511
662
|
const tbl = sqlIdent(name ?? this.tableName);
|
|
512
663
|
const tables = await this.listTables();
|
|
513
664
|
if (!tables.includes(tbl)) {
|
|
514
|
-
|
|
665
|
+
log3(`table "${tbl}" not found, creating`);
|
|
515
666
|
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);
|
|
516
|
-
|
|
667
|
+
log3(`table "${tbl}" created`);
|
|
517
668
|
if (!tables.includes(tbl))
|
|
518
669
|
this._tablesCache = [...tables, tbl];
|
|
519
670
|
}
|
|
@@ -526,9 +677,9 @@ var DeeplakeApi = class {
|
|
|
526
677
|
const safe = sqlIdent(name);
|
|
527
678
|
const tables = await this.listTables();
|
|
528
679
|
if (!tables.includes(safe)) {
|
|
529
|
-
|
|
680
|
+
log3(`table "${safe}" not found, creating`);
|
|
530
681
|
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);
|
|
531
|
-
|
|
682
|
+
log3(`table "${safe}" created`);
|
|
532
683
|
if (!tables.includes(safe))
|
|
533
684
|
this._tablesCache = [...tables, safe];
|
|
534
685
|
}
|
|
@@ -551,9 +702,9 @@ var DeeplakeApi = class {
|
|
|
551
702
|
const safe = sqlIdent(name);
|
|
552
703
|
const tables = await this.listTables();
|
|
553
704
|
if (!tables.includes(safe)) {
|
|
554
|
-
|
|
705
|
+
log3(`table "${safe}" not found, creating`);
|
|
555
706
|
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);
|
|
556
|
-
|
|
707
|
+
log3(`table "${safe}" created`);
|
|
557
708
|
if (!tables.includes(safe))
|
|
558
709
|
this._tablesCache = [...tables, safe];
|
|
559
710
|
}
|
|
@@ -570,9 +721,9 @@ function buildSessionPath(config, sessionId) {
|
|
|
570
721
|
// dist/src/embeddings/client.js
|
|
571
722
|
import { connect } from "node:net";
|
|
572
723
|
import { spawn } from "node:child_process";
|
|
573
|
-
import { openSync as openSync2, closeSync as closeSync2, writeSync, unlinkSync as
|
|
574
|
-
import { homedir as
|
|
575
|
-
import { join as
|
|
724
|
+
import { openSync as openSync2, closeSync as closeSync2, writeSync, unlinkSync as unlinkSync3, existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
|
|
725
|
+
import { homedir as homedir5 } from "node:os";
|
|
726
|
+
import { join as join6 } from "node:path";
|
|
576
727
|
|
|
577
728
|
// dist/src/embeddings/protocol.js
|
|
578
729
|
var DEFAULT_SOCKET_DIR = "/tmp";
|
|
@@ -585,233 +736,13 @@ function pidPathFor(uid, dir = DEFAULT_SOCKET_DIR) {
|
|
|
585
736
|
return `${dir}/hivemind-embed-${uid}.pid`;
|
|
586
737
|
}
|
|
587
738
|
|
|
588
|
-
// dist/src/notifications/queue.js
|
|
589
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync, mkdirSync as mkdirSync2, openSync, closeSync, unlinkSync, statSync } from "node:fs";
|
|
590
|
-
import { join as join4, resolve } from "node:path";
|
|
591
|
-
import { homedir as homedir3 } from "node:os";
|
|
592
|
-
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
593
|
-
var log3 = (msg) => log("notifications-queue", msg);
|
|
594
|
-
var LOCK_RETRY_MAX = 50;
|
|
595
|
-
var LOCK_RETRY_BASE_MS = 5;
|
|
596
|
-
var LOCK_STALE_MS = 5e3;
|
|
597
|
-
function queuePath() {
|
|
598
|
-
return join4(homedir3(), ".deeplake", "notifications-queue.json");
|
|
599
|
-
}
|
|
600
|
-
function lockPath() {
|
|
601
|
-
return `${queuePath()}.lock`;
|
|
602
|
-
}
|
|
603
|
-
function readQueue() {
|
|
604
|
-
try {
|
|
605
|
-
const raw = readFileSync3(queuePath(), "utf-8");
|
|
606
|
-
const parsed = JSON.parse(raw);
|
|
607
|
-
if (!parsed || !Array.isArray(parsed.queue)) {
|
|
608
|
-
log3(`queue malformed \u2192 treating as empty`);
|
|
609
|
-
return { queue: [] };
|
|
610
|
-
}
|
|
611
|
-
return { queue: parsed.queue };
|
|
612
|
-
} catch {
|
|
613
|
-
return { queue: [] };
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
function _isQueuePathInsideHome(path, home) {
|
|
617
|
-
const r = resolve(path);
|
|
618
|
-
const h = resolve(home);
|
|
619
|
-
return r.startsWith(h + "/") || r === h;
|
|
620
|
-
}
|
|
621
|
-
function writeQueue(q) {
|
|
622
|
-
const path = queuePath();
|
|
623
|
-
const home = resolve(homedir3());
|
|
624
|
-
if (!_isQueuePathInsideHome(path, home)) {
|
|
625
|
-
throw new Error(`notifications-queue write blocked: ${path} is outside ${home}`);
|
|
626
|
-
}
|
|
627
|
-
mkdirSync2(join4(home, ".deeplake"), { recursive: true, mode: 448 });
|
|
628
|
-
const tmp = `${path}.${process.pid}.tmp`;
|
|
629
|
-
writeFileSync2(tmp, JSON.stringify(q, null, 2), { mode: 384 });
|
|
630
|
-
renameSync(tmp, path);
|
|
631
|
-
}
|
|
632
|
-
async function withQueueLock(fn) {
|
|
633
|
-
const path = lockPath();
|
|
634
|
-
mkdirSync2(join4(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
|
|
635
|
-
let fd = null;
|
|
636
|
-
for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
|
|
637
|
-
try {
|
|
638
|
-
fd = openSync(path, "wx", 384);
|
|
639
|
-
break;
|
|
640
|
-
} catch (e) {
|
|
641
|
-
const code = e.code;
|
|
642
|
-
if (code !== "EEXIST")
|
|
643
|
-
throw e;
|
|
644
|
-
try {
|
|
645
|
-
const age = Date.now() - statSync(path).mtimeMs;
|
|
646
|
-
if (age > LOCK_STALE_MS) {
|
|
647
|
-
unlinkSync(path);
|
|
648
|
-
continue;
|
|
649
|
-
}
|
|
650
|
-
} catch {
|
|
651
|
-
}
|
|
652
|
-
const delay = LOCK_RETRY_BASE_MS * (attempt + 1);
|
|
653
|
-
await sleep2(delay);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
if (fd === null) {
|
|
657
|
-
log3(`lock acquisition gave up after ${LOCK_RETRY_MAX} attempts \u2014 proceeding unlocked (last-writer-wins)`);
|
|
658
|
-
return fn();
|
|
659
|
-
}
|
|
660
|
-
try {
|
|
661
|
-
return fn();
|
|
662
|
-
} finally {
|
|
663
|
-
try {
|
|
664
|
-
closeSync(fd);
|
|
665
|
-
} catch {
|
|
666
|
-
}
|
|
667
|
-
try {
|
|
668
|
-
unlinkSync(path);
|
|
669
|
-
} catch {
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
function sameDedupKey(a, b) {
|
|
674
|
-
if (a.id !== b.id)
|
|
675
|
-
return false;
|
|
676
|
-
return JSON.stringify(a.dedupKey) === JSON.stringify(b.dedupKey);
|
|
677
|
-
}
|
|
678
|
-
async function enqueueNotification(n) {
|
|
679
|
-
await withQueueLock(() => {
|
|
680
|
-
const q = readQueue();
|
|
681
|
-
if (q.queue.some((existing) => sameDedupKey(existing, n))) {
|
|
682
|
-
return;
|
|
683
|
-
}
|
|
684
|
-
q.queue.push(n);
|
|
685
|
-
writeQueue(q);
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
// dist/src/embeddings/disable.js
|
|
690
|
-
import { createRequire } from "node:module";
|
|
691
|
-
import { homedir as homedir5 } from "node:os";
|
|
692
|
-
import { join as join6 } from "node:path";
|
|
693
|
-
import { pathToFileURL } from "node:url";
|
|
694
|
-
|
|
695
|
-
// dist/src/user-config.js
|
|
696
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
697
|
-
import { homedir as homedir4 } from "node:os";
|
|
698
|
-
import { dirname, join as join5 } from "node:path";
|
|
699
|
-
var _configPath = () => process.env.HIVEMIND_CONFIG_PATH ?? join5(homedir4(), ".deeplake", "config.json");
|
|
700
|
-
var _cache = null;
|
|
701
|
-
var _migrated = false;
|
|
702
|
-
function readUserConfig() {
|
|
703
|
-
if (_cache !== null)
|
|
704
|
-
return _cache;
|
|
705
|
-
const path = _configPath();
|
|
706
|
-
if (!existsSync3(path)) {
|
|
707
|
-
_cache = {};
|
|
708
|
-
return _cache;
|
|
709
|
-
}
|
|
710
|
-
try {
|
|
711
|
-
const raw = readFileSync4(path, "utf-8");
|
|
712
|
-
const parsed = JSON.parse(raw);
|
|
713
|
-
_cache = isPlainObject(parsed) ? parsed : {};
|
|
714
|
-
} catch {
|
|
715
|
-
_cache = {};
|
|
716
|
-
}
|
|
717
|
-
return _cache;
|
|
718
|
-
}
|
|
719
|
-
function writeUserConfig(patch) {
|
|
720
|
-
const current = readUserConfig();
|
|
721
|
-
const merged = deepMerge(current, patch);
|
|
722
|
-
const path = _configPath();
|
|
723
|
-
const dir = dirname(path);
|
|
724
|
-
if (!existsSync3(dir))
|
|
725
|
-
mkdirSync3(dir, { recursive: true });
|
|
726
|
-
const tmp = `${path}.tmp.${process.pid}`;
|
|
727
|
-
writeFileSync3(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
728
|
-
renameSync2(tmp, path);
|
|
729
|
-
_cache = merged;
|
|
730
|
-
return merged;
|
|
731
|
-
}
|
|
732
|
-
function getEmbeddingsEnabled() {
|
|
733
|
-
const cfg = readUserConfig();
|
|
734
|
-
if (cfg.embeddings && typeof cfg.embeddings.enabled === "boolean") {
|
|
735
|
-
return cfg.embeddings.enabled;
|
|
736
|
-
}
|
|
737
|
-
if (_migrated) {
|
|
738
|
-
return migrationValueFromEnv();
|
|
739
|
-
}
|
|
740
|
-
_migrated = true;
|
|
741
|
-
const enabled = migrationValueFromEnv();
|
|
742
|
-
try {
|
|
743
|
-
writeUserConfig({ embeddings: { enabled } });
|
|
744
|
-
} catch {
|
|
745
|
-
_cache = { ...cfg ?? {}, embeddings: { ...cfg?.embeddings ?? {}, enabled } };
|
|
746
|
-
}
|
|
747
|
-
return enabled;
|
|
748
|
-
}
|
|
749
|
-
function migrationValueFromEnv() {
|
|
750
|
-
const raw = process.env.HIVEMIND_EMBEDDINGS;
|
|
751
|
-
if (raw === void 0)
|
|
752
|
-
return false;
|
|
753
|
-
if (raw === "false")
|
|
754
|
-
return false;
|
|
755
|
-
return true;
|
|
756
|
-
}
|
|
757
|
-
function isPlainObject(value) {
|
|
758
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
759
|
-
}
|
|
760
|
-
function deepMerge(base, patch) {
|
|
761
|
-
const out = { ...base };
|
|
762
|
-
for (const key of Object.keys(patch)) {
|
|
763
|
-
const patchVal = patch[key];
|
|
764
|
-
const baseVal = base[key];
|
|
765
|
-
if (isPlainObject(patchVal) && isPlainObject(baseVal)) {
|
|
766
|
-
out[key] = { ...baseVal, ...patchVal };
|
|
767
|
-
} else if (patchVal !== void 0) {
|
|
768
|
-
out[key] = patchVal;
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
return out;
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// dist/src/embeddings/disable.js
|
|
775
|
-
var cachedStatus = null;
|
|
776
|
-
function defaultResolveTransformers() {
|
|
777
|
-
const sharedDir = join6(homedir5(), ".hivemind", "embed-deps");
|
|
778
|
-
try {
|
|
779
|
-
createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
|
|
780
|
-
return;
|
|
781
|
-
} catch {
|
|
782
|
-
}
|
|
783
|
-
createRequire(import.meta.url).resolve("@huggingface/transformers");
|
|
784
|
-
}
|
|
785
|
-
var _resolve = defaultResolveTransformers;
|
|
786
|
-
var _readEnabled = getEmbeddingsEnabled;
|
|
787
|
-
function detectStatus() {
|
|
788
|
-
if (!_readEnabled())
|
|
789
|
-
return "user-disabled";
|
|
790
|
-
try {
|
|
791
|
-
_resolve();
|
|
792
|
-
return "enabled";
|
|
793
|
-
} catch {
|
|
794
|
-
return "no-transformers";
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
function embeddingsStatus() {
|
|
798
|
-
if (cachedStatus !== null)
|
|
799
|
-
return cachedStatus;
|
|
800
|
-
cachedStatus = detectStatus();
|
|
801
|
-
return cachedStatus;
|
|
802
|
-
}
|
|
803
|
-
function embeddingsDisabled() {
|
|
804
|
-
return embeddingsStatus() !== "enabled";
|
|
805
|
-
}
|
|
806
|
-
|
|
807
739
|
// dist/src/embeddings/client.js
|
|
808
|
-
var SHARED_DAEMON_PATH =
|
|
740
|
+
var SHARED_DAEMON_PATH = join6(homedir5(), ".hivemind", "embed-deps", "embed-daemon.js");
|
|
809
741
|
var log4 = (m) => log("embed-client", m);
|
|
810
742
|
function getUid() {
|
|
811
743
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
812
744
|
return uid !== void 0 ? String(uid) : process.env.USER ?? "default";
|
|
813
745
|
}
|
|
814
|
-
var _signalledMissingDeps = false;
|
|
815
746
|
var _recycledStuckDaemon = false;
|
|
816
747
|
var EmbedClient = class {
|
|
817
748
|
socketPath;
|
|
@@ -828,7 +759,7 @@ var EmbedClient = class {
|
|
|
828
759
|
this.socketPath = socketPathFor(uid, dir);
|
|
829
760
|
this.pidPath = pidPathFor(uid, dir);
|
|
830
761
|
this.timeoutMs = opts.timeoutMs ?? DEFAULT_CLIENT_TIMEOUT_MS;
|
|
831
|
-
this.daemonEntry = opts.daemonEntry ?? process.env.HIVEMIND_EMBED_DAEMON ?? (
|
|
762
|
+
this.daemonEntry = opts.daemonEntry ?? process.env.HIVEMIND_EMBED_DAEMON ?? (existsSync3(SHARED_DAEMON_PATH) ? SHARED_DAEMON_PATH : void 0);
|
|
832
763
|
this.autoSpawn = opts.autoSpawn ?? true;
|
|
833
764
|
this.spawnWaitMs = opts.spawnWaitMs ?? 5e3;
|
|
834
765
|
}
|
|
@@ -909,7 +840,7 @@ var EmbedClient = class {
|
|
|
909
840
|
async waitForDaemonReady() {
|
|
910
841
|
const deadline = Date.now() + this.spawnWaitMs;
|
|
911
842
|
while (Date.now() < deadline) {
|
|
912
|
-
if (
|
|
843
|
+
if (existsSync3(this.socketPath))
|
|
913
844
|
return;
|
|
914
845
|
await new Promise((r) => setTimeout(r, 50));
|
|
915
846
|
}
|
|
@@ -952,7 +883,7 @@ var EmbedClient = class {
|
|
|
952
883
|
this.recycleDaemon(hello.pid);
|
|
953
884
|
return true;
|
|
954
885
|
}
|
|
955
|
-
if (hello.daemonPath !== this.daemonEntry && !
|
|
886
|
+
if (hello.daemonPath !== this.daemonEntry && !existsSync3(hello.daemonPath)) {
|
|
956
887
|
_recycledStuckDaemon = true;
|
|
957
888
|
log4(`daemon path no longer on disk \u2014 running=${hello.daemonPath} (gone) expected=${this.daemonEntry}; recycling`);
|
|
958
889
|
this.recycleDaemon(hello.pid);
|
|
@@ -964,37 +895,21 @@ var EmbedClient = class {
|
|
|
964
895
|
/**
|
|
965
896
|
* On a transformers-missing error from the daemon, SIGTERM the stuck
|
|
966
897
|
* daemon (the bundle daemon that can't find its deps) and clear
|
|
967
|
-
* sock/pid so the next call spawns fresh.
|
|
968
|
-
*
|
|
969
|
-
*
|
|
970
|
-
*
|
|
971
|
-
*
|
|
898
|
+
* sock/pid so the next call spawns fresh.
|
|
899
|
+
*
|
|
900
|
+
* Previously this also enqueued a user-visible "Hivemind embeddings
|
|
901
|
+
* disabled — deps missing" notification telling the user to run
|
|
902
|
+
* `hivemind embeddings install`. The notification was removed because
|
|
903
|
+
* (a) the recycle alone often fixes the issue silently, and (b) the
|
|
904
|
+
* warning kept stacking on top of the primary session-start banner
|
|
905
|
+
* which clashed with the single-slot priority model. The `detail`
|
|
906
|
+
* argument is retained for future telemetry / debug logging.
|
|
972
907
|
*/
|
|
973
|
-
handleTransformersMissing(
|
|
908
|
+
handleTransformersMissing(_detail) {
|
|
974
909
|
if (!_recycledStuckDaemon) {
|
|
975
910
|
_recycledStuckDaemon = true;
|
|
976
911
|
this.recycleDaemon(null);
|
|
977
912
|
}
|
|
978
|
-
if (_signalledMissingDeps)
|
|
979
|
-
return;
|
|
980
|
-
_signalledMissingDeps = true;
|
|
981
|
-
let status;
|
|
982
|
-
try {
|
|
983
|
-
status = embeddingsStatus();
|
|
984
|
-
} catch {
|
|
985
|
-
status = "enabled";
|
|
986
|
-
}
|
|
987
|
-
if (status === "user-disabled")
|
|
988
|
-
return;
|
|
989
|
-
enqueueNotification({
|
|
990
|
-
id: "embed-deps-missing",
|
|
991
|
-
severity: "warn",
|
|
992
|
-
title: "Hivemind embeddings disabled \u2014 deps missing",
|
|
993
|
-
body: `Semantic memory search is off because @huggingface/transformers is not installed where the daemon can find it. Run \`hivemind embeddings install\` to enable.`,
|
|
994
|
-
dedupKey: { reason: "transformers-missing", detail: detail.slice(0, 200) }
|
|
995
|
-
}).catch((e) => {
|
|
996
|
-
log4(`enqueue embed-deps-missing failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
997
|
-
});
|
|
998
913
|
}
|
|
999
914
|
/**
|
|
1000
915
|
* Best-effort SIGTERM + sock/pid cleanup. Tolerant of every missing-file
|
|
@@ -1017,7 +932,7 @@ var EmbedClient = class {
|
|
|
1017
932
|
} catch {
|
|
1018
933
|
}
|
|
1019
934
|
}
|
|
1020
|
-
if (Number.isFinite(pid) && pid !== null && pid > 0 &&
|
|
935
|
+
if (Number.isFinite(pid) && pid !== null && pid > 0 && existsSync3(this.socketPath)) {
|
|
1021
936
|
try {
|
|
1022
937
|
process.kill(pid, "SIGTERM");
|
|
1023
938
|
} catch {
|
|
@@ -1026,11 +941,11 @@ var EmbedClient = class {
|
|
|
1026
941
|
log4(`recycle: socket gone, skipping SIGTERM on possibly-stale pid ${pid}`);
|
|
1027
942
|
}
|
|
1028
943
|
try {
|
|
1029
|
-
|
|
944
|
+
unlinkSync3(this.socketPath);
|
|
1030
945
|
} catch {
|
|
1031
946
|
}
|
|
1032
947
|
try {
|
|
1033
|
-
|
|
948
|
+
unlinkSync3(this.pidPath);
|
|
1034
949
|
} catch {
|
|
1035
950
|
}
|
|
1036
951
|
}
|
|
@@ -1081,7 +996,7 @@ var EmbedClient = class {
|
|
|
1081
996
|
} catch (e) {
|
|
1082
997
|
if (this.isPidFileStale()) {
|
|
1083
998
|
try {
|
|
1084
|
-
|
|
999
|
+
unlinkSync3(this.pidPath);
|
|
1085
1000
|
} catch {
|
|
1086
1001
|
}
|
|
1087
1002
|
try {
|
|
@@ -1094,11 +1009,11 @@ var EmbedClient = class {
|
|
|
1094
1009
|
return;
|
|
1095
1010
|
}
|
|
1096
1011
|
}
|
|
1097
|
-
if (!this.daemonEntry || !
|
|
1012
|
+
if (!this.daemonEntry || !existsSync3(this.daemonEntry)) {
|
|
1098
1013
|
log4(`daemonEntry not configured or missing: ${this.daemonEntry}`);
|
|
1099
1014
|
try {
|
|
1100
1015
|
closeSync2(fd);
|
|
1101
|
-
|
|
1016
|
+
unlinkSync3(this.pidPath);
|
|
1102
1017
|
} catch {
|
|
1103
1018
|
}
|
|
1104
1019
|
return;
|
|
@@ -1137,7 +1052,7 @@ var EmbedClient = class {
|
|
|
1137
1052
|
while (Date.now() < deadline) {
|
|
1138
1053
|
await sleep3(delay);
|
|
1139
1054
|
delay = Math.min(delay * 1.5, 300);
|
|
1140
|
-
if (!
|
|
1055
|
+
if (!existsSync3(this.socketPath))
|
|
1141
1056
|
continue;
|
|
1142
1057
|
try {
|
|
1143
1058
|
return await this.connectOnce();
|
|
@@ -1201,17 +1116,135 @@ function embeddingSqlLiteral(vec) {
|
|
|
1201
1116
|
return `ARRAY[${parts.join(",")}]::float4[]`;
|
|
1202
1117
|
}
|
|
1203
1118
|
|
|
1204
|
-
// dist/src/embeddings/
|
|
1205
|
-
import {
|
|
1119
|
+
// dist/src/embeddings/disable.js
|
|
1120
|
+
import { createRequire } from "node:module";
|
|
1206
1121
|
import { homedir as homedir7 } from "node:os";
|
|
1207
|
-
import {
|
|
1122
|
+
import { join as join8 } from "node:path";
|
|
1123
|
+
import { pathToFileURL } from "node:url";
|
|
1124
|
+
|
|
1125
|
+
// dist/src/user-config.js
|
|
1126
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1127
|
+
import { homedir as homedir6 } from "node:os";
|
|
1128
|
+
import { dirname, join as join7 } from "node:path";
|
|
1129
|
+
var _configPath = () => process.env.HIVEMIND_CONFIG_PATH ?? join7(homedir6(), ".deeplake", "config.json");
|
|
1130
|
+
var _cache = null;
|
|
1131
|
+
var _migrated = false;
|
|
1132
|
+
function readUserConfig() {
|
|
1133
|
+
if (_cache !== null)
|
|
1134
|
+
return _cache;
|
|
1135
|
+
const path = _configPath();
|
|
1136
|
+
if (!existsSync4(path)) {
|
|
1137
|
+
_cache = {};
|
|
1138
|
+
return _cache;
|
|
1139
|
+
}
|
|
1140
|
+
try {
|
|
1141
|
+
const raw = readFileSync6(path, "utf-8");
|
|
1142
|
+
const parsed = JSON.parse(raw);
|
|
1143
|
+
_cache = isPlainObject(parsed) ? parsed : {};
|
|
1144
|
+
} catch {
|
|
1145
|
+
_cache = {};
|
|
1146
|
+
}
|
|
1147
|
+
return _cache;
|
|
1148
|
+
}
|
|
1149
|
+
function writeUserConfig(patch) {
|
|
1150
|
+
const current = readUserConfig();
|
|
1151
|
+
const merged = deepMerge(current, patch);
|
|
1152
|
+
const path = _configPath();
|
|
1153
|
+
const dir = dirname(path);
|
|
1154
|
+
if (!existsSync4(dir))
|
|
1155
|
+
mkdirSync4(dir, { recursive: true });
|
|
1156
|
+
const tmp = `${path}.tmp.${process.pid}`;
|
|
1157
|
+
writeFileSync4(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
1158
|
+
renameSync2(tmp, path);
|
|
1159
|
+
_cache = merged;
|
|
1160
|
+
return merged;
|
|
1161
|
+
}
|
|
1162
|
+
function getEmbeddingsEnabled() {
|
|
1163
|
+
const cfg = readUserConfig();
|
|
1164
|
+
if (cfg.embeddings && typeof cfg.embeddings.enabled === "boolean") {
|
|
1165
|
+
return cfg.embeddings.enabled;
|
|
1166
|
+
}
|
|
1167
|
+
if (_migrated) {
|
|
1168
|
+
return migrationValueFromEnv();
|
|
1169
|
+
}
|
|
1170
|
+
_migrated = true;
|
|
1171
|
+
const enabled = migrationValueFromEnv();
|
|
1172
|
+
try {
|
|
1173
|
+
writeUserConfig({ embeddings: { enabled } });
|
|
1174
|
+
} catch {
|
|
1175
|
+
_cache = { ...cfg ?? {}, embeddings: { ...cfg?.embeddings ?? {}, enabled } };
|
|
1176
|
+
}
|
|
1177
|
+
return enabled;
|
|
1178
|
+
}
|
|
1179
|
+
function migrationValueFromEnv() {
|
|
1180
|
+
const raw = process.env.HIVEMIND_EMBEDDINGS;
|
|
1181
|
+
if (raw === void 0)
|
|
1182
|
+
return false;
|
|
1183
|
+
if (raw === "false")
|
|
1184
|
+
return false;
|
|
1185
|
+
return true;
|
|
1186
|
+
}
|
|
1187
|
+
function isPlainObject(value) {
|
|
1188
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1189
|
+
}
|
|
1190
|
+
function deepMerge(base, patch) {
|
|
1191
|
+
const out = { ...base };
|
|
1192
|
+
for (const key of Object.keys(patch)) {
|
|
1193
|
+
const patchVal = patch[key];
|
|
1194
|
+
const baseVal = base[key];
|
|
1195
|
+
if (isPlainObject(patchVal) && isPlainObject(baseVal)) {
|
|
1196
|
+
out[key] = { ...baseVal, ...patchVal };
|
|
1197
|
+
} else if (patchVal !== void 0) {
|
|
1198
|
+
out[key] = patchVal;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
return out;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// dist/src/embeddings/disable.js
|
|
1205
|
+
var cachedStatus = null;
|
|
1206
|
+
function defaultResolveTransformers() {
|
|
1207
|
+
const sharedDir = join8(homedir7(), ".hivemind", "embed-deps");
|
|
1208
|
+
try {
|
|
1209
|
+
createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
|
|
1210
|
+
return;
|
|
1211
|
+
} catch {
|
|
1212
|
+
}
|
|
1213
|
+
createRequire(import.meta.url).resolve("@huggingface/transformers");
|
|
1214
|
+
}
|
|
1215
|
+
var _resolve = defaultResolveTransformers;
|
|
1216
|
+
var _readEnabled = getEmbeddingsEnabled;
|
|
1217
|
+
function detectStatus() {
|
|
1218
|
+
if (!_readEnabled())
|
|
1219
|
+
return "user-disabled";
|
|
1220
|
+
try {
|
|
1221
|
+
_resolve();
|
|
1222
|
+
return "enabled";
|
|
1223
|
+
} catch {
|
|
1224
|
+
return "no-transformers";
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
function embeddingsStatus() {
|
|
1228
|
+
if (cachedStatus !== null)
|
|
1229
|
+
return cachedStatus;
|
|
1230
|
+
cachedStatus = detectStatus();
|
|
1231
|
+
return cachedStatus;
|
|
1232
|
+
}
|
|
1233
|
+
function embeddingsDisabled() {
|
|
1234
|
+
return embeddingsStatus() !== "enabled";
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// dist/src/embeddings/self-heal.js
|
|
1238
|
+
import { existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync5, readlinkSync, renameSync as renameSync3, rmSync, symlinkSync, statSync as statSync2 } from "node:fs";
|
|
1239
|
+
import { homedir as homedir8 } from "node:os";
|
|
1240
|
+
import { basename, dirname as dirname2, join as join9 } from "node:path";
|
|
1208
1241
|
function ensurePluginNodeModulesLink(opts) {
|
|
1209
1242
|
if (basename(opts.bundleDir) !== "bundle") {
|
|
1210
1243
|
return { kind: "not-bundle-layout", bundleDir: opts.bundleDir };
|
|
1211
1244
|
}
|
|
1212
|
-
const target = opts.sharedNodeModules ??
|
|
1245
|
+
const target = opts.sharedNodeModules ?? join9(homedir8(), ".hivemind", "embed-deps", "node_modules");
|
|
1213
1246
|
const pluginDir = dirname2(opts.bundleDir);
|
|
1214
|
-
const link =
|
|
1247
|
+
const link = join9(pluginDir, "node_modules");
|
|
1215
1248
|
if (!existsSync5(target)) {
|
|
1216
1249
|
return { kind: "shared-deps-missing", target };
|
|
1217
1250
|
}
|
|
@@ -1252,7 +1285,7 @@ function createSymlinkAtomic(target, link) {
|
|
|
1252
1285
|
try {
|
|
1253
1286
|
const parent = dirname2(link);
|
|
1254
1287
|
if (!existsSync5(parent))
|
|
1255
|
-
|
|
1288
|
+
mkdirSync5(parent, { recursive: true });
|
|
1256
1289
|
const tmp = `${link}.tmp.${process.pid}`;
|
|
1257
1290
|
try {
|
|
1258
1291
|
rmSync(tmp, { force: true });
|
|
@@ -1268,40 +1301,40 @@ function createSymlinkAtomic(target, link) {
|
|
|
1268
1301
|
|
|
1269
1302
|
// dist/src/hooks/codex/capture.js
|
|
1270
1303
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1271
|
-
import { dirname as dirname5, join as
|
|
1304
|
+
import { dirname as dirname5, join as join14 } from "node:path";
|
|
1272
1305
|
|
|
1273
1306
|
// dist/src/hooks/summary-state.js
|
|
1274
|
-
import { readFileSync as
|
|
1275
|
-
import { homedir as
|
|
1276
|
-
import { join as
|
|
1307
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, writeSync as writeSync2, mkdirSync as mkdirSync6, renameSync as renameSync4, existsSync as existsSync6, unlinkSync as unlinkSync4, openSync as openSync3, closeSync as closeSync3 } from "node:fs";
|
|
1308
|
+
import { homedir as homedir9 } from "node:os";
|
|
1309
|
+
import { join as join10 } from "node:path";
|
|
1277
1310
|
var dlog = (msg) => log("summary-state", msg);
|
|
1278
|
-
var STATE_DIR =
|
|
1311
|
+
var STATE_DIR = join10(homedir9(), ".claude", "hooks", "summary-state");
|
|
1279
1312
|
var YIELD_BUF = new Int32Array(new SharedArrayBuffer(4));
|
|
1280
1313
|
function statePath(sessionId) {
|
|
1281
|
-
return
|
|
1314
|
+
return join10(STATE_DIR, `${sessionId}.json`);
|
|
1282
1315
|
}
|
|
1283
1316
|
function lockPath2(sessionId) {
|
|
1284
|
-
return
|
|
1317
|
+
return join10(STATE_DIR, `${sessionId}.lock`);
|
|
1285
1318
|
}
|
|
1286
1319
|
function readState(sessionId) {
|
|
1287
1320
|
const p = statePath(sessionId);
|
|
1288
1321
|
if (!existsSync6(p))
|
|
1289
1322
|
return null;
|
|
1290
1323
|
try {
|
|
1291
|
-
return JSON.parse(
|
|
1324
|
+
return JSON.parse(readFileSync7(p, "utf-8"));
|
|
1292
1325
|
} catch {
|
|
1293
1326
|
return null;
|
|
1294
1327
|
}
|
|
1295
1328
|
}
|
|
1296
1329
|
function writeState(sessionId, state) {
|
|
1297
|
-
|
|
1330
|
+
mkdirSync6(STATE_DIR, { recursive: true });
|
|
1298
1331
|
const p = statePath(sessionId);
|
|
1299
1332
|
const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
|
|
1300
|
-
|
|
1333
|
+
writeFileSync5(tmp, JSON.stringify(state));
|
|
1301
1334
|
renameSync4(tmp, p);
|
|
1302
1335
|
}
|
|
1303
1336
|
function withRmwLock(sessionId, fn) {
|
|
1304
|
-
|
|
1337
|
+
mkdirSync6(STATE_DIR, { recursive: true });
|
|
1305
1338
|
const rmwLock = statePath(sessionId) + ".rmw";
|
|
1306
1339
|
const deadline = Date.now() + 2e3;
|
|
1307
1340
|
let fd = null;
|
|
@@ -1314,7 +1347,7 @@ function withRmwLock(sessionId, fn) {
|
|
|
1314
1347
|
if (Date.now() > deadline) {
|
|
1315
1348
|
dlog(`rmw lock deadline exceeded for ${sessionId}, reclaiming stale lock`);
|
|
1316
1349
|
try {
|
|
1317
|
-
|
|
1350
|
+
unlinkSync4(rmwLock);
|
|
1318
1351
|
} catch (unlinkErr) {
|
|
1319
1352
|
dlog(`stale rmw lock unlink failed for ${sessionId}: ${unlinkErr.message}`);
|
|
1320
1353
|
}
|
|
@@ -1328,7 +1361,7 @@ function withRmwLock(sessionId, fn) {
|
|
|
1328
1361
|
} finally {
|
|
1329
1362
|
closeSync3(fd);
|
|
1330
1363
|
try {
|
|
1331
|
-
|
|
1364
|
+
unlinkSync4(rmwLock);
|
|
1332
1365
|
} catch (unlinkErr) {
|
|
1333
1366
|
dlog(`rmw lock cleanup failed for ${sessionId}: ${unlinkErr.message}`);
|
|
1334
1367
|
}
|
|
@@ -1363,18 +1396,18 @@ function shouldTrigger(state, cfg, now = Date.now()) {
|
|
|
1363
1396
|
return false;
|
|
1364
1397
|
}
|
|
1365
1398
|
function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
|
|
1366
|
-
|
|
1399
|
+
mkdirSync6(STATE_DIR, { recursive: true });
|
|
1367
1400
|
const p = lockPath2(sessionId);
|
|
1368
1401
|
if (existsSync6(p)) {
|
|
1369
1402
|
try {
|
|
1370
|
-
const ageMs = Date.now() - parseInt(
|
|
1403
|
+
const ageMs = Date.now() - parseInt(readFileSync7(p, "utf-8"), 10);
|
|
1371
1404
|
if (Number.isFinite(ageMs) && ageMs < maxAgeMs)
|
|
1372
1405
|
return false;
|
|
1373
1406
|
} catch (readErr) {
|
|
1374
1407
|
dlog(`lock file unreadable for ${sessionId}, treating as stale: ${readErr.message}`);
|
|
1375
1408
|
}
|
|
1376
1409
|
try {
|
|
1377
|
-
|
|
1410
|
+
unlinkSync4(p);
|
|
1378
1411
|
} catch (unlinkErr) {
|
|
1379
1412
|
dlog(`could not unlink stale lock for ${sessionId}: ${unlinkErr.message}`);
|
|
1380
1413
|
return false;
|
|
@@ -1396,7 +1429,7 @@ function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
|
|
|
1396
1429
|
}
|
|
1397
1430
|
function releaseLock(sessionId) {
|
|
1398
1431
|
try {
|
|
1399
|
-
|
|
1432
|
+
unlinkSync4(lockPath2(sessionId));
|
|
1400
1433
|
} catch (e) {
|
|
1401
1434
|
if (e?.code !== "ENOENT") {
|
|
1402
1435
|
dlog(`releaseLock unlink failed for ${sessionId}: ${e.message}`);
|
|
@@ -1407,20 +1440,20 @@ function releaseLock(sessionId) {
|
|
|
1407
1440
|
// dist/src/hooks/codex/spawn-wiki-worker.js
|
|
1408
1441
|
import { spawn as spawn2, execSync } from "node:child_process";
|
|
1409
1442
|
import { fileURLToPath } from "node:url";
|
|
1410
|
-
import { dirname as dirname4, join as
|
|
1411
|
-
import { writeFileSync as
|
|
1412
|
-
import { homedir as
|
|
1443
|
+
import { dirname as dirname4, join as join13 } from "node:path";
|
|
1444
|
+
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync8 } from "node:fs";
|
|
1445
|
+
import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
|
|
1413
1446
|
|
|
1414
1447
|
// dist/src/utils/wiki-log.js
|
|
1415
|
-
import { mkdirSync as
|
|
1416
|
-
import { join as
|
|
1448
|
+
import { mkdirSync as mkdirSync7, appendFileSync as appendFileSync2 } from "node:fs";
|
|
1449
|
+
import { join as join11 } from "node:path";
|
|
1417
1450
|
function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") {
|
|
1418
|
-
const path =
|
|
1451
|
+
const path = join11(hooksDir, filename);
|
|
1419
1452
|
return {
|
|
1420
1453
|
path,
|
|
1421
1454
|
log(msg) {
|
|
1422
1455
|
try {
|
|
1423
|
-
|
|
1456
|
+
mkdirSync7(hooksDir, { recursive: true });
|
|
1424
1457
|
appendFileSync2(path, `[${utcTimestamp()}] ${msg}
|
|
1425
1458
|
`);
|
|
1426
1459
|
} catch {
|
|
@@ -1430,18 +1463,18 @@ function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") {
|
|
|
1430
1463
|
}
|
|
1431
1464
|
|
|
1432
1465
|
// dist/src/utils/version-check.js
|
|
1433
|
-
import { readFileSync as
|
|
1434
|
-
import { dirname as dirname3, join as
|
|
1466
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
1467
|
+
import { dirname as dirname3, join as join12 } from "node:path";
|
|
1435
1468
|
function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
1436
1469
|
try {
|
|
1437
|
-
const pluginJson =
|
|
1438
|
-
const plugin = JSON.parse(
|
|
1470
|
+
const pluginJson = join12(bundleDir, "..", pluginManifestDir, "plugin.json");
|
|
1471
|
+
const plugin = JSON.parse(readFileSync8(pluginJson, "utf-8"));
|
|
1439
1472
|
if (plugin.version)
|
|
1440
1473
|
return plugin.version;
|
|
1441
1474
|
} catch {
|
|
1442
1475
|
}
|
|
1443
1476
|
try {
|
|
1444
|
-
const stamp =
|
|
1477
|
+
const stamp = readFileSync8(join12(bundleDir, "..", ".hivemind_version"), "utf-8").trim();
|
|
1445
1478
|
if (stamp)
|
|
1446
1479
|
return stamp;
|
|
1447
1480
|
} catch {
|
|
@@ -1456,9 +1489,9 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
|
1456
1489
|
]);
|
|
1457
1490
|
let dir = bundleDir;
|
|
1458
1491
|
for (let i = 0; i < 5; i++) {
|
|
1459
|
-
const candidate =
|
|
1492
|
+
const candidate = join12(dir, "package.json");
|
|
1460
1493
|
try {
|
|
1461
|
-
const pkg = JSON.parse(
|
|
1494
|
+
const pkg = JSON.parse(readFileSync8(candidate, "utf-8"));
|
|
1462
1495
|
if (HIVEMIND_PKG_NAMES.has(pkg.name) && pkg.version)
|
|
1463
1496
|
return pkg.version;
|
|
1464
1497
|
} catch {
|
|
@@ -1472,8 +1505,8 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
|
1472
1505
|
}
|
|
1473
1506
|
|
|
1474
1507
|
// dist/src/hooks/codex/spawn-wiki-worker.js
|
|
1475
|
-
var HOME =
|
|
1476
|
-
var wikiLogger = makeWikiLogger(
|
|
1508
|
+
var HOME = homedir10();
|
|
1509
|
+
var wikiLogger = makeWikiLogger(join13(HOME, ".codex", "hooks"));
|
|
1477
1510
|
var WIKI_LOG = wikiLogger.path;
|
|
1478
1511
|
var WIKI_PROMPT_TEMPLATE = `You are building a personal wiki from a coding session. Your goal is to extract every piece of knowledge \u2014 entities, decisions, relationships, and facts \u2014 into a structured, searchable wiki entry.
|
|
1479
1512
|
|
|
@@ -1535,11 +1568,11 @@ function findCodexBin() {
|
|
|
1535
1568
|
function spawnCodexWikiWorker(opts) {
|
|
1536
1569
|
const { config, sessionId, cwd, bundleDir, reason } = opts;
|
|
1537
1570
|
const projectName = cwd.split("/").pop() || "unknown";
|
|
1538
|
-
const tmpDir =
|
|
1539
|
-
|
|
1571
|
+
const tmpDir = join13(tmpdir2(), `deeplake-wiki-${sessionId}-${Date.now()}`);
|
|
1572
|
+
mkdirSync8(tmpDir, { recursive: true });
|
|
1540
1573
|
const pluginVersion = getInstalledVersion(bundleDir, ".codex-plugin") ?? "";
|
|
1541
|
-
const configFile =
|
|
1542
|
-
|
|
1574
|
+
const configFile = join13(tmpDir, "config.json");
|
|
1575
|
+
writeFileSync6(configFile, JSON.stringify({
|
|
1543
1576
|
apiUrl: config.apiUrl,
|
|
1544
1577
|
token: config.token,
|
|
1545
1578
|
orgId: config.orgId,
|
|
@@ -1553,11 +1586,11 @@ function spawnCodexWikiWorker(opts) {
|
|
|
1553
1586
|
tmpDir,
|
|
1554
1587
|
codexBin: findCodexBin(),
|
|
1555
1588
|
wikiLog: WIKI_LOG,
|
|
1556
|
-
hooksDir:
|
|
1589
|
+
hooksDir: join13(HOME, ".codex", "hooks"),
|
|
1557
1590
|
promptTemplate: WIKI_PROMPT_TEMPLATE
|
|
1558
1591
|
}));
|
|
1559
1592
|
wikiLog(`${reason}: spawning summary worker for ${sessionId}`);
|
|
1560
|
-
const workerPath =
|
|
1593
|
+
const workerPath = join13(bundleDir, "wiki-worker.js");
|
|
1561
1594
|
spawn2("nohup", ["node", workerPath, configFile], {
|
|
1562
1595
|
detached: true,
|
|
1563
1596
|
stdio: ["ignore", "ignore", "ignore"]
|
|
@@ -1571,7 +1604,7 @@ function bundleDirFromImportMeta(importMetaUrl) {
|
|
|
1571
1604
|
// dist/src/hooks/codex/capture.js
|
|
1572
1605
|
var log5 = (msg) => log("codex-capture", msg);
|
|
1573
1606
|
function resolveEmbedDaemonPath() {
|
|
1574
|
-
return
|
|
1607
|
+
return join14(dirname5(fileURLToPath2(import.meta.url)), "embeddings", "embed-daemon.js");
|
|
1575
1608
|
}
|
|
1576
1609
|
var __bundleDir = dirname5(fileURLToPath2(import.meta.url));
|
|
1577
1610
|
var PLUGIN_VERSION = getInstalledVersion(__bundleDir, ".codex-plugin") ?? "";
|