@deeplake/hivemind 0.7.32 → 0.7.34
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 +332 -189
- 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 +229 -87
- package/codex/bundle/shell/deeplake-shell.js +328 -295
- package/codex/bundle/skillify-worker.js +26 -18
- package/codex/bundle/stop.js +450 -394
- package/codex/bundle/wiki-worker.js +174 -292
- package/cursor/bundle/capture.js +448 -392
- package/cursor/bundle/commands/auth-login.js +163 -30
- package/cursor/bundle/pre-tool-use.js +324 -291
- package/cursor/bundle/session-end.js +43 -20
- package/cursor/bundle/session-start.js +272 -130
- package/cursor/bundle/shell/deeplake-shell.js +328 -295
- package/cursor/bundle/skillify-worker.js +26 -18
- package/cursor/bundle/wiki-worker.js +174 -292
- package/hermes/bundle/capture.js +448 -392
- package/hermes/bundle/commands/auth-login.js +163 -30
- package/hermes/bundle/pre-tool-use.js +324 -291
- package/hermes/bundle/session-end.js +43 -20
- package/hermes/bundle/session-start.js +269 -127
- package/hermes/bundle/shell/deeplake-shell.js +328 -295
- package/hermes/bundle/skillify-worker.js +26 -18
- package/hermes/bundle/wiki-worker.js +174 -292
- package/mcp/bundle/server.js +190 -57
- package/openclaw/dist/index.js +160 -32
- package/openclaw/dist/skillify-worker.js +26 -18
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/package.json +1 -1
package/hermes/bundle/capture.js
CHANGED
|
@@ -16,21 +16,21 @@ __export(index_marker_store_exports, {
|
|
|
16
16
|
hasFreshIndexMarker: () => hasFreshIndexMarker,
|
|
17
17
|
writeIndexMarker: () => writeIndexMarker
|
|
18
18
|
});
|
|
19
|
-
import { existsSync as existsSync2, mkdirSync, readFileSync as
|
|
20
|
-
import { join as
|
|
19
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
20
|
+
import { join as join5 } from "node:path";
|
|
21
21
|
import { tmpdir } from "node:os";
|
|
22
22
|
function getIndexMarkerDir() {
|
|
23
|
-
return process.env.HIVEMIND_INDEX_MARKER_DIR ??
|
|
23
|
+
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join5(tmpdir(), "hivemind-deeplake-indexes");
|
|
24
24
|
}
|
|
25
25
|
function buildIndexMarkerPath(workspaceId, orgId, table, suffix) {
|
|
26
26
|
const markerKey = [workspaceId, orgId, table, suffix].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
27
|
-
return
|
|
27
|
+
return join5(getIndexMarkerDir(), `${markerKey}.json`);
|
|
28
28
|
}
|
|
29
29
|
function hasFreshIndexMarker(markerPath) {
|
|
30
30
|
if (!existsSync2(markerPath))
|
|
31
31
|
return false;
|
|
32
32
|
try {
|
|
33
|
-
const raw = JSON.parse(
|
|
33
|
+
const raw = JSON.parse(readFileSync4(markerPath, "utf-8"));
|
|
34
34
|
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
35
35
|
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
36
36
|
return false;
|
|
@@ -40,8 +40,8 @@ function hasFreshIndexMarker(markerPath) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
function writeIndexMarker(markerPath) {
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
mkdirSync3(getIndexMarkerDir(), { recursive: true });
|
|
44
|
+
writeFileSync3(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
45
45
|
}
|
|
46
46
|
var INDEX_MARKER_TTL_MS;
|
|
47
47
|
var init_index_marker_store = __esm({
|
|
@@ -146,6 +146,125 @@ function deeplakeClientHeader() {
|
|
|
146
146
|
return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
// dist/src/notifications/queue.js
|
|
150
|
+
import { readFileSync as readFileSync2, writeFileSync, renameSync, mkdirSync, openSync, closeSync, unlinkSync, statSync } from "node:fs";
|
|
151
|
+
import { join as join3, resolve } from "node:path";
|
|
152
|
+
import { homedir as homedir3 } from "node:os";
|
|
153
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
154
|
+
var log2 = (msg) => log("notifications-queue", msg);
|
|
155
|
+
var LOCK_RETRY_MAX = 50;
|
|
156
|
+
var LOCK_RETRY_BASE_MS = 5;
|
|
157
|
+
var LOCK_STALE_MS = 5e3;
|
|
158
|
+
function queuePath() {
|
|
159
|
+
return join3(homedir3(), ".deeplake", "notifications-queue.json");
|
|
160
|
+
}
|
|
161
|
+
function lockPath() {
|
|
162
|
+
return `${queuePath()}.lock`;
|
|
163
|
+
}
|
|
164
|
+
function readQueue() {
|
|
165
|
+
try {
|
|
166
|
+
const raw = readFileSync2(queuePath(), "utf-8");
|
|
167
|
+
const parsed = JSON.parse(raw);
|
|
168
|
+
if (!parsed || !Array.isArray(parsed.queue)) {
|
|
169
|
+
log2(`queue malformed \u2192 treating as empty`);
|
|
170
|
+
return { queue: [] };
|
|
171
|
+
}
|
|
172
|
+
return { queue: parsed.queue };
|
|
173
|
+
} catch {
|
|
174
|
+
return { queue: [] };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function _isQueuePathInsideHome(path, home) {
|
|
178
|
+
const r = resolve(path);
|
|
179
|
+
const h = resolve(home);
|
|
180
|
+
return r.startsWith(h + "/") || r === h;
|
|
181
|
+
}
|
|
182
|
+
function writeQueue(q) {
|
|
183
|
+
const path = queuePath();
|
|
184
|
+
const home = resolve(homedir3());
|
|
185
|
+
if (!_isQueuePathInsideHome(path, home)) {
|
|
186
|
+
throw new Error(`notifications-queue write blocked: ${path} is outside ${home}`);
|
|
187
|
+
}
|
|
188
|
+
mkdirSync(join3(home, ".deeplake"), { recursive: true, mode: 448 });
|
|
189
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
190
|
+
writeFileSync(tmp, JSON.stringify(q, null, 2), { mode: 384 });
|
|
191
|
+
renameSync(tmp, path);
|
|
192
|
+
}
|
|
193
|
+
async function withQueueLock(fn) {
|
|
194
|
+
const path = lockPath();
|
|
195
|
+
mkdirSync(join3(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
|
|
196
|
+
let fd = null;
|
|
197
|
+
for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
|
|
198
|
+
try {
|
|
199
|
+
fd = openSync(path, "wx", 384);
|
|
200
|
+
break;
|
|
201
|
+
} catch (e) {
|
|
202
|
+
const code = e.code;
|
|
203
|
+
if (code !== "EEXIST")
|
|
204
|
+
throw e;
|
|
205
|
+
try {
|
|
206
|
+
const age = Date.now() - statSync(path).mtimeMs;
|
|
207
|
+
if (age > LOCK_STALE_MS) {
|
|
208
|
+
unlinkSync(path);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
} catch {
|
|
212
|
+
}
|
|
213
|
+
const delay = LOCK_RETRY_BASE_MS * (attempt + 1);
|
|
214
|
+
await sleep(delay);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (fd === null) {
|
|
218
|
+
log2(`lock acquisition gave up after ${LOCK_RETRY_MAX} attempts \u2014 proceeding unlocked (last-writer-wins)`);
|
|
219
|
+
return fn();
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
return fn();
|
|
223
|
+
} finally {
|
|
224
|
+
try {
|
|
225
|
+
closeSync(fd);
|
|
226
|
+
} catch {
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
unlinkSync(path);
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function sameDedupKey(a, b) {
|
|
235
|
+
if (a.id !== b.id)
|
|
236
|
+
return false;
|
|
237
|
+
return JSON.stringify(a.dedupKey) === JSON.stringify(b.dedupKey);
|
|
238
|
+
}
|
|
239
|
+
async function enqueueNotification(n) {
|
|
240
|
+
await withQueueLock(() => {
|
|
241
|
+
const q = readQueue();
|
|
242
|
+
if (q.queue.some((existing) => sameDedupKey(existing, n))) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
q.queue.push(n);
|
|
246
|
+
writeQueue(q);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// dist/src/commands/auth-creds.js
|
|
251
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "node:fs";
|
|
252
|
+
import { join as join4 } from "node:path";
|
|
253
|
+
import { homedir as homedir4 } from "node:os";
|
|
254
|
+
function configDir() {
|
|
255
|
+
return join4(homedir4(), ".deeplake");
|
|
256
|
+
}
|
|
257
|
+
function credsPath() {
|
|
258
|
+
return join4(configDir(), "credentials.json");
|
|
259
|
+
}
|
|
260
|
+
function loadCredentials() {
|
|
261
|
+
try {
|
|
262
|
+
return JSON.parse(readFileSync3(credsPath(), "utf-8"));
|
|
263
|
+
} catch {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
149
268
|
// dist/src/deeplake-api.js
|
|
150
269
|
var indexMarkerStorePromise = null;
|
|
151
270
|
function getIndexMarkerStore() {
|
|
@@ -153,7 +272,7 @@ function getIndexMarkerStore() {
|
|
|
153
272
|
indexMarkerStorePromise = Promise.resolve().then(() => (init_index_marker_store(), index_marker_store_exports));
|
|
154
273
|
return indexMarkerStorePromise;
|
|
155
274
|
}
|
|
156
|
-
var
|
|
275
|
+
var log3 = (msg) => log("sdk", msg);
|
|
157
276
|
function summarizeSql(sql, maxLen = 220) {
|
|
158
277
|
const compact = sql.replace(/\s+/g, " ").trim();
|
|
159
278
|
return compact.length > maxLen ? `${compact.slice(0, maxLen)}...` : compact;
|
|
@@ -165,7 +284,38 @@ function traceSql(msg) {
|
|
|
165
284
|
process.stderr.write(`[deeplake-sql] ${msg}
|
|
166
285
|
`);
|
|
167
286
|
if (process.env.HIVEMIND_DEBUG === "1")
|
|
168
|
-
|
|
287
|
+
log3(msg);
|
|
288
|
+
}
|
|
289
|
+
var _signalledBalanceExhausted = false;
|
|
290
|
+
function maybeSignalBalanceExhausted(status, bodyText) {
|
|
291
|
+
if (status !== 402)
|
|
292
|
+
return;
|
|
293
|
+
if (!bodyText.includes("balance_cents"))
|
|
294
|
+
return;
|
|
295
|
+
if (_signalledBalanceExhausted)
|
|
296
|
+
return;
|
|
297
|
+
_signalledBalanceExhausted = true;
|
|
298
|
+
log3(`balance exhausted \u2014 enqueuing session-start banner (body=${bodyText.slice(0, 120)})`);
|
|
299
|
+
enqueueNotification({
|
|
300
|
+
id: "balance-exhausted",
|
|
301
|
+
severity: "warn",
|
|
302
|
+
transient: true,
|
|
303
|
+
title: "Hivemind credits exhausted \u2014 top up to keep capturing",
|
|
304
|
+
body: `Sessions are not being saved and memory recall is returning empty. Top up at ${billingUrl()} to restore capture and recall.`,
|
|
305
|
+
dedupKey: { reason: "balance-zero" }
|
|
306
|
+
}).catch((e) => {
|
|
307
|
+
log3(`enqueue balance-exhausted failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
function billingUrl() {
|
|
311
|
+
try {
|
|
312
|
+
const c = loadCredentials();
|
|
313
|
+
if (c?.orgName && c?.workspaceId) {
|
|
314
|
+
return `https://deeplake.ai/${encodeURIComponent(c.orgName)}/workspace/${encodeURIComponent(c.workspaceId)}/billing`;
|
|
315
|
+
}
|
|
316
|
+
} catch {
|
|
317
|
+
}
|
|
318
|
+
return "https://deeplake.ai";
|
|
169
319
|
}
|
|
170
320
|
var RETRYABLE_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
171
321
|
var MAX_RETRIES = 3;
|
|
@@ -174,7 +324,7 @@ var MAX_CONCURRENCY = 5;
|
|
|
174
324
|
function getQueryTimeoutMs() {
|
|
175
325
|
return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
|
|
176
326
|
}
|
|
177
|
-
function
|
|
327
|
+
function sleep2(ms) {
|
|
178
328
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
179
329
|
}
|
|
180
330
|
function isTimeoutError(error) {
|
|
@@ -276,8 +426,8 @@ var DeeplakeApi = class {
|
|
|
276
426
|
lastError = e instanceof Error ? e : new Error(String(e));
|
|
277
427
|
if (attempt < MAX_RETRIES) {
|
|
278
428
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
279
|
-
|
|
280
|
-
await
|
|
429
|
+
log3(`query retry ${attempt + 1}/${MAX_RETRIES} (fetch error: ${lastError.message}) in ${delay.toFixed(0)}ms`);
|
|
430
|
+
await sleep2(delay);
|
|
281
431
|
continue;
|
|
282
432
|
}
|
|
283
433
|
throw lastError;
|
|
@@ -293,10 +443,11 @@ var DeeplakeApi = class {
|
|
|
293
443
|
const alreadyExists = resp.status === 500 && isDuplicateIndexError(text);
|
|
294
444
|
if (!alreadyExists && attempt < MAX_RETRIES && (RETRYABLE_CODES.has(resp.status) || retryable403)) {
|
|
295
445
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
296
|
-
|
|
297
|
-
await
|
|
446
|
+
log3(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
|
|
447
|
+
await sleep2(delay);
|
|
298
448
|
continue;
|
|
299
449
|
}
|
|
450
|
+
maybeSignalBalanceExhausted(resp.status, text);
|
|
300
451
|
throw new Error(`Query failed: ${resp.status}: ${text.slice(0, 200)}`);
|
|
301
452
|
}
|
|
302
453
|
throw lastError ?? new Error("Query failed: max retries exceeded");
|
|
@@ -317,7 +468,7 @@ var DeeplakeApi = class {
|
|
|
317
468
|
const chunk = rows.slice(i, i + CONCURRENCY);
|
|
318
469
|
await Promise.allSettled(chunk.map((r) => this.upsertRowSql(r)));
|
|
319
470
|
}
|
|
320
|
-
|
|
471
|
+
log3(`commit: ${rows.length} rows`);
|
|
321
472
|
}
|
|
322
473
|
async upsertRowSql(row) {
|
|
323
474
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -373,7 +524,7 @@ var DeeplakeApi = class {
|
|
|
373
524
|
markers.writeIndexMarker(markerPath);
|
|
374
525
|
return;
|
|
375
526
|
}
|
|
376
|
-
|
|
527
|
+
log3(`index "${indexName}" skipped: ${e.message}`);
|
|
377
528
|
}
|
|
378
529
|
}
|
|
379
530
|
/**
|
|
@@ -463,13 +614,13 @@ var DeeplakeApi = class {
|
|
|
463
614
|
};
|
|
464
615
|
}
|
|
465
616
|
if (attempt < MAX_RETRIES && RETRYABLE_CODES.has(resp.status)) {
|
|
466
|
-
await
|
|
617
|
+
await sleep2(BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200);
|
|
467
618
|
continue;
|
|
468
619
|
}
|
|
469
620
|
return { tables: [], cacheable: false };
|
|
470
621
|
} catch {
|
|
471
622
|
if (attempt < MAX_RETRIES) {
|
|
472
|
-
await
|
|
623
|
+
await sleep2(BASE_DELAY_MS * Math.pow(2, attempt));
|
|
473
624
|
continue;
|
|
474
625
|
}
|
|
475
626
|
return { tables: [], cacheable: false };
|
|
@@ -497,9 +648,9 @@ var DeeplakeApi = class {
|
|
|
497
648
|
} catch (err) {
|
|
498
649
|
lastErr = err;
|
|
499
650
|
const msg = err instanceof Error ? err.message : String(err);
|
|
500
|
-
|
|
651
|
+
log3(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
|
|
501
652
|
if (attempt < OUTER_BACKOFFS_MS.length) {
|
|
502
|
-
await
|
|
653
|
+
await sleep2(OUTER_BACKOFFS_MS[attempt]);
|
|
503
654
|
}
|
|
504
655
|
}
|
|
505
656
|
}
|
|
@@ -510,9 +661,9 @@ var DeeplakeApi = class {
|
|
|
510
661
|
const tbl = sqlIdent(name ?? this.tableName);
|
|
511
662
|
const tables = await this.listTables();
|
|
512
663
|
if (!tables.includes(tbl)) {
|
|
513
|
-
|
|
664
|
+
log3(`table "${tbl}" not found, creating`);
|
|
514
665
|
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);
|
|
515
|
-
|
|
666
|
+
log3(`table "${tbl}" created`);
|
|
516
667
|
if (!tables.includes(tbl))
|
|
517
668
|
this._tablesCache = [...tables, tbl];
|
|
518
669
|
}
|
|
@@ -525,9 +676,9 @@ var DeeplakeApi = class {
|
|
|
525
676
|
const safe = sqlIdent(name);
|
|
526
677
|
const tables = await this.listTables();
|
|
527
678
|
if (!tables.includes(safe)) {
|
|
528
|
-
|
|
679
|
+
log3(`table "${safe}" not found, creating`);
|
|
529
680
|
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);
|
|
530
|
-
|
|
681
|
+
log3(`table "${safe}" created`);
|
|
531
682
|
if (!tables.includes(safe))
|
|
532
683
|
this._tablesCache = [...tables, safe];
|
|
533
684
|
}
|
|
@@ -550,9 +701,9 @@ var DeeplakeApi = class {
|
|
|
550
701
|
const safe = sqlIdent(name);
|
|
551
702
|
const tables = await this.listTables();
|
|
552
703
|
if (!tables.includes(safe)) {
|
|
553
|
-
|
|
704
|
+
log3(`table "${safe}" not found, creating`);
|
|
554
705
|
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);
|
|
555
|
-
|
|
706
|
+
log3(`table "${safe}" created`);
|
|
556
707
|
if (!tables.includes(safe))
|
|
557
708
|
this._tablesCache = [...tables, safe];
|
|
558
709
|
}
|
|
@@ -569,9 +720,9 @@ function buildSessionPath(config, sessionId) {
|
|
|
569
720
|
// dist/src/embeddings/client.js
|
|
570
721
|
import { connect } from "node:net";
|
|
571
722
|
import { spawn } from "node:child_process";
|
|
572
|
-
import { openSync as openSync2, closeSync as closeSync2, writeSync, unlinkSync as
|
|
573
|
-
import { homedir as
|
|
574
|
-
import { join as
|
|
723
|
+
import { openSync as openSync2, closeSync as closeSync2, writeSync, unlinkSync as unlinkSync3, existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
|
|
724
|
+
import { homedir as homedir5 } from "node:os";
|
|
725
|
+
import { join as join6 } from "node:path";
|
|
575
726
|
|
|
576
727
|
// dist/src/embeddings/protocol.js
|
|
577
728
|
var DEFAULT_SOCKET_DIR = "/tmp";
|
|
@@ -584,233 +735,13 @@ function pidPathFor(uid, dir = DEFAULT_SOCKET_DIR) {
|
|
|
584
735
|
return `${dir}/hivemind-embed-${uid}.pid`;
|
|
585
736
|
}
|
|
586
737
|
|
|
587
|
-
// dist/src/notifications/queue.js
|
|
588
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync, mkdirSync as mkdirSync2, openSync, closeSync, unlinkSync, statSync } from "node:fs";
|
|
589
|
-
import { join as join4, resolve } from "node:path";
|
|
590
|
-
import { homedir as homedir3 } from "node:os";
|
|
591
|
-
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
592
|
-
var log3 = (msg) => log("notifications-queue", msg);
|
|
593
|
-
var LOCK_RETRY_MAX = 50;
|
|
594
|
-
var LOCK_RETRY_BASE_MS = 5;
|
|
595
|
-
var LOCK_STALE_MS = 5e3;
|
|
596
|
-
function queuePath() {
|
|
597
|
-
return join4(homedir3(), ".deeplake", "notifications-queue.json");
|
|
598
|
-
}
|
|
599
|
-
function lockPath() {
|
|
600
|
-
return `${queuePath()}.lock`;
|
|
601
|
-
}
|
|
602
|
-
function readQueue() {
|
|
603
|
-
try {
|
|
604
|
-
const raw = readFileSync3(queuePath(), "utf-8");
|
|
605
|
-
const parsed = JSON.parse(raw);
|
|
606
|
-
if (!parsed || !Array.isArray(parsed.queue)) {
|
|
607
|
-
log3(`queue malformed \u2192 treating as empty`);
|
|
608
|
-
return { queue: [] };
|
|
609
|
-
}
|
|
610
|
-
return { queue: parsed.queue };
|
|
611
|
-
} catch {
|
|
612
|
-
return { queue: [] };
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
function _isQueuePathInsideHome(path, home) {
|
|
616
|
-
const r = resolve(path);
|
|
617
|
-
const h = resolve(home);
|
|
618
|
-
return r.startsWith(h + "/") || r === h;
|
|
619
|
-
}
|
|
620
|
-
function writeQueue(q) {
|
|
621
|
-
const path = queuePath();
|
|
622
|
-
const home = resolve(homedir3());
|
|
623
|
-
if (!_isQueuePathInsideHome(path, home)) {
|
|
624
|
-
throw new Error(`notifications-queue write blocked: ${path} is outside ${home}`);
|
|
625
|
-
}
|
|
626
|
-
mkdirSync2(join4(home, ".deeplake"), { recursive: true, mode: 448 });
|
|
627
|
-
const tmp = `${path}.${process.pid}.tmp`;
|
|
628
|
-
writeFileSync2(tmp, JSON.stringify(q, null, 2), { mode: 384 });
|
|
629
|
-
renameSync(tmp, path);
|
|
630
|
-
}
|
|
631
|
-
async function withQueueLock(fn) {
|
|
632
|
-
const path = lockPath();
|
|
633
|
-
mkdirSync2(join4(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
|
|
634
|
-
let fd = null;
|
|
635
|
-
for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
|
|
636
|
-
try {
|
|
637
|
-
fd = openSync(path, "wx", 384);
|
|
638
|
-
break;
|
|
639
|
-
} catch (e) {
|
|
640
|
-
const code = e.code;
|
|
641
|
-
if (code !== "EEXIST")
|
|
642
|
-
throw e;
|
|
643
|
-
try {
|
|
644
|
-
const age = Date.now() - statSync(path).mtimeMs;
|
|
645
|
-
if (age > LOCK_STALE_MS) {
|
|
646
|
-
unlinkSync(path);
|
|
647
|
-
continue;
|
|
648
|
-
}
|
|
649
|
-
} catch {
|
|
650
|
-
}
|
|
651
|
-
const delay = LOCK_RETRY_BASE_MS * (attempt + 1);
|
|
652
|
-
await sleep2(delay);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
if (fd === null) {
|
|
656
|
-
log3(`lock acquisition gave up after ${LOCK_RETRY_MAX} attempts \u2014 proceeding unlocked (last-writer-wins)`);
|
|
657
|
-
return fn();
|
|
658
|
-
}
|
|
659
|
-
try {
|
|
660
|
-
return fn();
|
|
661
|
-
} finally {
|
|
662
|
-
try {
|
|
663
|
-
closeSync(fd);
|
|
664
|
-
} catch {
|
|
665
|
-
}
|
|
666
|
-
try {
|
|
667
|
-
unlinkSync(path);
|
|
668
|
-
} catch {
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
function sameDedupKey(a, b) {
|
|
673
|
-
if (a.id !== b.id)
|
|
674
|
-
return false;
|
|
675
|
-
return JSON.stringify(a.dedupKey) === JSON.stringify(b.dedupKey);
|
|
676
|
-
}
|
|
677
|
-
async function enqueueNotification(n) {
|
|
678
|
-
await withQueueLock(() => {
|
|
679
|
-
const q = readQueue();
|
|
680
|
-
if (q.queue.some((existing) => sameDedupKey(existing, n))) {
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
q.queue.push(n);
|
|
684
|
-
writeQueue(q);
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
// dist/src/embeddings/disable.js
|
|
689
|
-
import { createRequire } from "node:module";
|
|
690
|
-
import { homedir as homedir5 } from "node:os";
|
|
691
|
-
import { join as join6 } from "node:path";
|
|
692
|
-
import { pathToFileURL } from "node:url";
|
|
693
|
-
|
|
694
|
-
// dist/src/user-config.js
|
|
695
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
696
|
-
import { homedir as homedir4 } from "node:os";
|
|
697
|
-
import { dirname, join as join5 } from "node:path";
|
|
698
|
-
var _configPath = () => process.env.HIVEMIND_CONFIG_PATH ?? join5(homedir4(), ".deeplake", "config.json");
|
|
699
|
-
var _cache = null;
|
|
700
|
-
var _migrated = false;
|
|
701
|
-
function readUserConfig() {
|
|
702
|
-
if (_cache !== null)
|
|
703
|
-
return _cache;
|
|
704
|
-
const path = _configPath();
|
|
705
|
-
if (!existsSync3(path)) {
|
|
706
|
-
_cache = {};
|
|
707
|
-
return _cache;
|
|
708
|
-
}
|
|
709
|
-
try {
|
|
710
|
-
const raw = readFileSync4(path, "utf-8");
|
|
711
|
-
const parsed = JSON.parse(raw);
|
|
712
|
-
_cache = isPlainObject(parsed) ? parsed : {};
|
|
713
|
-
} catch {
|
|
714
|
-
_cache = {};
|
|
715
|
-
}
|
|
716
|
-
return _cache;
|
|
717
|
-
}
|
|
718
|
-
function writeUserConfig(patch) {
|
|
719
|
-
const current = readUserConfig();
|
|
720
|
-
const merged = deepMerge(current, patch);
|
|
721
|
-
const path = _configPath();
|
|
722
|
-
const dir = dirname(path);
|
|
723
|
-
if (!existsSync3(dir))
|
|
724
|
-
mkdirSync3(dir, { recursive: true });
|
|
725
|
-
const tmp = `${path}.tmp.${process.pid}`;
|
|
726
|
-
writeFileSync3(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
727
|
-
renameSync2(tmp, path);
|
|
728
|
-
_cache = merged;
|
|
729
|
-
return merged;
|
|
730
|
-
}
|
|
731
|
-
function getEmbeddingsEnabled() {
|
|
732
|
-
const cfg = readUserConfig();
|
|
733
|
-
if (cfg.embeddings && typeof cfg.embeddings.enabled === "boolean") {
|
|
734
|
-
return cfg.embeddings.enabled;
|
|
735
|
-
}
|
|
736
|
-
if (_migrated) {
|
|
737
|
-
return migrationValueFromEnv();
|
|
738
|
-
}
|
|
739
|
-
_migrated = true;
|
|
740
|
-
const enabled = migrationValueFromEnv();
|
|
741
|
-
try {
|
|
742
|
-
writeUserConfig({ embeddings: { enabled } });
|
|
743
|
-
} catch {
|
|
744
|
-
_cache = { ...cfg ?? {}, embeddings: { ...cfg?.embeddings ?? {}, enabled } };
|
|
745
|
-
}
|
|
746
|
-
return enabled;
|
|
747
|
-
}
|
|
748
|
-
function migrationValueFromEnv() {
|
|
749
|
-
const raw = process.env.HIVEMIND_EMBEDDINGS;
|
|
750
|
-
if (raw === void 0)
|
|
751
|
-
return false;
|
|
752
|
-
if (raw === "false")
|
|
753
|
-
return false;
|
|
754
|
-
return true;
|
|
755
|
-
}
|
|
756
|
-
function isPlainObject(value) {
|
|
757
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
758
|
-
}
|
|
759
|
-
function deepMerge(base, patch) {
|
|
760
|
-
const out = { ...base };
|
|
761
|
-
for (const key of Object.keys(patch)) {
|
|
762
|
-
const patchVal = patch[key];
|
|
763
|
-
const baseVal = base[key];
|
|
764
|
-
if (isPlainObject(patchVal) && isPlainObject(baseVal)) {
|
|
765
|
-
out[key] = { ...baseVal, ...patchVal };
|
|
766
|
-
} else if (patchVal !== void 0) {
|
|
767
|
-
out[key] = patchVal;
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
return out;
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
// dist/src/embeddings/disable.js
|
|
774
|
-
var cachedStatus = null;
|
|
775
|
-
function defaultResolveTransformers() {
|
|
776
|
-
const sharedDir = join6(homedir5(), ".hivemind", "embed-deps");
|
|
777
|
-
try {
|
|
778
|
-
createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
|
|
779
|
-
return;
|
|
780
|
-
} catch {
|
|
781
|
-
}
|
|
782
|
-
createRequire(import.meta.url).resolve("@huggingface/transformers");
|
|
783
|
-
}
|
|
784
|
-
var _resolve = defaultResolveTransformers;
|
|
785
|
-
var _readEnabled = getEmbeddingsEnabled;
|
|
786
|
-
function detectStatus() {
|
|
787
|
-
if (!_readEnabled())
|
|
788
|
-
return "user-disabled";
|
|
789
|
-
try {
|
|
790
|
-
_resolve();
|
|
791
|
-
return "enabled";
|
|
792
|
-
} catch {
|
|
793
|
-
return "no-transformers";
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
function embeddingsStatus() {
|
|
797
|
-
if (cachedStatus !== null)
|
|
798
|
-
return cachedStatus;
|
|
799
|
-
cachedStatus = detectStatus();
|
|
800
|
-
return cachedStatus;
|
|
801
|
-
}
|
|
802
|
-
function embeddingsDisabled() {
|
|
803
|
-
return embeddingsStatus() !== "enabled";
|
|
804
|
-
}
|
|
805
|
-
|
|
806
738
|
// dist/src/embeddings/client.js
|
|
807
|
-
var SHARED_DAEMON_PATH =
|
|
739
|
+
var SHARED_DAEMON_PATH = join6(homedir5(), ".hivemind", "embed-deps", "embed-daemon.js");
|
|
808
740
|
var log4 = (m) => log("embed-client", m);
|
|
809
741
|
function getUid() {
|
|
810
742
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
811
743
|
return uid !== void 0 ? String(uid) : process.env.USER ?? "default";
|
|
812
744
|
}
|
|
813
|
-
var _signalledMissingDeps = false;
|
|
814
745
|
var _recycledStuckDaemon = false;
|
|
815
746
|
var EmbedClient = class {
|
|
816
747
|
socketPath;
|
|
@@ -827,7 +758,7 @@ var EmbedClient = class {
|
|
|
827
758
|
this.socketPath = socketPathFor(uid, dir);
|
|
828
759
|
this.pidPath = pidPathFor(uid, dir);
|
|
829
760
|
this.timeoutMs = opts.timeoutMs ?? DEFAULT_CLIENT_TIMEOUT_MS;
|
|
830
|
-
this.daemonEntry = opts.daemonEntry ?? process.env.HIVEMIND_EMBED_DAEMON ?? (
|
|
761
|
+
this.daemonEntry = opts.daemonEntry ?? process.env.HIVEMIND_EMBED_DAEMON ?? (existsSync3(SHARED_DAEMON_PATH) ? SHARED_DAEMON_PATH : void 0);
|
|
831
762
|
this.autoSpawn = opts.autoSpawn ?? true;
|
|
832
763
|
this.spawnWaitMs = opts.spawnWaitMs ?? 5e3;
|
|
833
764
|
}
|
|
@@ -908,7 +839,7 @@ var EmbedClient = class {
|
|
|
908
839
|
async waitForDaemonReady() {
|
|
909
840
|
const deadline = Date.now() + this.spawnWaitMs;
|
|
910
841
|
while (Date.now() < deadline) {
|
|
911
|
-
if (
|
|
842
|
+
if (existsSync3(this.socketPath))
|
|
912
843
|
return;
|
|
913
844
|
await new Promise((r) => setTimeout(r, 50));
|
|
914
845
|
}
|
|
@@ -951,7 +882,7 @@ var EmbedClient = class {
|
|
|
951
882
|
this.recycleDaemon(hello.pid);
|
|
952
883
|
return true;
|
|
953
884
|
}
|
|
954
|
-
if (hello.daemonPath !== this.daemonEntry && !
|
|
885
|
+
if (hello.daemonPath !== this.daemonEntry && !existsSync3(hello.daemonPath)) {
|
|
955
886
|
_recycledStuckDaemon = true;
|
|
956
887
|
log4(`daemon path no longer on disk \u2014 running=${hello.daemonPath} (gone) expected=${this.daemonEntry}; recycling`);
|
|
957
888
|
this.recycleDaemon(hello.pid);
|
|
@@ -963,37 +894,21 @@ var EmbedClient = class {
|
|
|
963
894
|
/**
|
|
964
895
|
* On a transformers-missing error from the daemon, SIGTERM the stuck
|
|
965
896
|
* daemon (the bundle daemon that can't find its deps) and clear
|
|
966
|
-
* sock/pid so the next call spawns fresh.
|
|
967
|
-
*
|
|
968
|
-
*
|
|
969
|
-
*
|
|
970
|
-
*
|
|
897
|
+
* sock/pid so the next call spawns fresh.
|
|
898
|
+
*
|
|
899
|
+
* Previously this also enqueued a user-visible "Hivemind embeddings
|
|
900
|
+
* disabled — deps missing" notification telling the user to run
|
|
901
|
+
* `hivemind embeddings install`. The notification was removed because
|
|
902
|
+
* (a) the recycle alone often fixes the issue silently, and (b) the
|
|
903
|
+
* warning kept stacking on top of the primary session-start banner
|
|
904
|
+
* which clashed with the single-slot priority model. The `detail`
|
|
905
|
+
* argument is retained for future telemetry / debug logging.
|
|
971
906
|
*/
|
|
972
|
-
handleTransformersMissing(
|
|
907
|
+
handleTransformersMissing(_detail) {
|
|
973
908
|
if (!_recycledStuckDaemon) {
|
|
974
909
|
_recycledStuckDaemon = true;
|
|
975
910
|
this.recycleDaemon(null);
|
|
976
911
|
}
|
|
977
|
-
if (_signalledMissingDeps)
|
|
978
|
-
return;
|
|
979
|
-
_signalledMissingDeps = true;
|
|
980
|
-
let status;
|
|
981
|
-
try {
|
|
982
|
-
status = embeddingsStatus();
|
|
983
|
-
} catch {
|
|
984
|
-
status = "enabled";
|
|
985
|
-
}
|
|
986
|
-
if (status === "user-disabled")
|
|
987
|
-
return;
|
|
988
|
-
enqueueNotification({
|
|
989
|
-
id: "embed-deps-missing",
|
|
990
|
-
severity: "warn",
|
|
991
|
-
title: "Hivemind embeddings disabled \u2014 deps missing",
|
|
992
|
-
body: `Semantic memory search is off because @huggingface/transformers is not installed where the daemon can find it. Run \`hivemind embeddings install\` to enable.`,
|
|
993
|
-
dedupKey: { reason: "transformers-missing", detail: detail.slice(0, 200) }
|
|
994
|
-
}).catch((e) => {
|
|
995
|
-
log4(`enqueue embed-deps-missing failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
996
|
-
});
|
|
997
912
|
}
|
|
998
913
|
/**
|
|
999
914
|
* Best-effort SIGTERM + sock/pid cleanup. Tolerant of every missing-file
|
|
@@ -1016,7 +931,7 @@ var EmbedClient = class {
|
|
|
1016
931
|
} catch {
|
|
1017
932
|
}
|
|
1018
933
|
}
|
|
1019
|
-
if (Number.isFinite(pid) && pid !== null && pid > 0 &&
|
|
934
|
+
if (Number.isFinite(pid) && pid !== null && pid > 0 && existsSync3(this.socketPath)) {
|
|
1020
935
|
try {
|
|
1021
936
|
process.kill(pid, "SIGTERM");
|
|
1022
937
|
} catch {
|
|
@@ -1025,11 +940,11 @@ var EmbedClient = class {
|
|
|
1025
940
|
log4(`recycle: socket gone, skipping SIGTERM on possibly-stale pid ${pid}`);
|
|
1026
941
|
}
|
|
1027
942
|
try {
|
|
1028
|
-
|
|
943
|
+
unlinkSync3(this.socketPath);
|
|
1029
944
|
} catch {
|
|
1030
945
|
}
|
|
1031
946
|
try {
|
|
1032
|
-
|
|
947
|
+
unlinkSync3(this.pidPath);
|
|
1033
948
|
} catch {
|
|
1034
949
|
}
|
|
1035
950
|
}
|
|
@@ -1080,7 +995,7 @@ var EmbedClient = class {
|
|
|
1080
995
|
} catch (e) {
|
|
1081
996
|
if (this.isPidFileStale()) {
|
|
1082
997
|
try {
|
|
1083
|
-
|
|
998
|
+
unlinkSync3(this.pidPath);
|
|
1084
999
|
} catch {
|
|
1085
1000
|
}
|
|
1086
1001
|
try {
|
|
@@ -1093,11 +1008,11 @@ var EmbedClient = class {
|
|
|
1093
1008
|
return;
|
|
1094
1009
|
}
|
|
1095
1010
|
}
|
|
1096
|
-
if (!this.daemonEntry || !
|
|
1011
|
+
if (!this.daemonEntry || !existsSync3(this.daemonEntry)) {
|
|
1097
1012
|
log4(`daemonEntry not configured or missing: ${this.daemonEntry}`);
|
|
1098
1013
|
try {
|
|
1099
1014
|
closeSync2(fd);
|
|
1100
|
-
|
|
1015
|
+
unlinkSync3(this.pidPath);
|
|
1101
1016
|
} catch {
|
|
1102
1017
|
}
|
|
1103
1018
|
return;
|
|
@@ -1136,7 +1051,7 @@ var EmbedClient = class {
|
|
|
1136
1051
|
while (Date.now() < deadline) {
|
|
1137
1052
|
await sleep3(delay);
|
|
1138
1053
|
delay = Math.min(delay * 1.5, 300);
|
|
1139
|
-
if (!
|
|
1054
|
+
if (!existsSync3(this.socketPath))
|
|
1140
1055
|
continue;
|
|
1141
1056
|
try {
|
|
1142
1057
|
return await this.connectOnce();
|
|
@@ -1200,17 +1115,135 @@ function embeddingSqlLiteral(vec) {
|
|
|
1200
1115
|
return `ARRAY[${parts.join(",")}]::float4[]`;
|
|
1201
1116
|
}
|
|
1202
1117
|
|
|
1203
|
-
// dist/src/embeddings/
|
|
1204
|
-
import {
|
|
1118
|
+
// dist/src/embeddings/disable.js
|
|
1119
|
+
import { createRequire } from "node:module";
|
|
1205
1120
|
import { homedir as homedir7 } from "node:os";
|
|
1206
|
-
import {
|
|
1121
|
+
import { join as join8 } from "node:path";
|
|
1122
|
+
import { pathToFileURL } from "node:url";
|
|
1123
|
+
|
|
1124
|
+
// dist/src/user-config.js
|
|
1125
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1126
|
+
import { homedir as homedir6 } from "node:os";
|
|
1127
|
+
import { dirname, join as join7 } from "node:path";
|
|
1128
|
+
var _configPath = () => process.env.HIVEMIND_CONFIG_PATH ?? join7(homedir6(), ".deeplake", "config.json");
|
|
1129
|
+
var _cache = null;
|
|
1130
|
+
var _migrated = false;
|
|
1131
|
+
function readUserConfig() {
|
|
1132
|
+
if (_cache !== null)
|
|
1133
|
+
return _cache;
|
|
1134
|
+
const path = _configPath();
|
|
1135
|
+
if (!existsSync4(path)) {
|
|
1136
|
+
_cache = {};
|
|
1137
|
+
return _cache;
|
|
1138
|
+
}
|
|
1139
|
+
try {
|
|
1140
|
+
const raw = readFileSync6(path, "utf-8");
|
|
1141
|
+
const parsed = JSON.parse(raw);
|
|
1142
|
+
_cache = isPlainObject(parsed) ? parsed : {};
|
|
1143
|
+
} catch {
|
|
1144
|
+
_cache = {};
|
|
1145
|
+
}
|
|
1146
|
+
return _cache;
|
|
1147
|
+
}
|
|
1148
|
+
function writeUserConfig(patch) {
|
|
1149
|
+
const current = readUserConfig();
|
|
1150
|
+
const merged = deepMerge(current, patch);
|
|
1151
|
+
const path = _configPath();
|
|
1152
|
+
const dir = dirname(path);
|
|
1153
|
+
if (!existsSync4(dir))
|
|
1154
|
+
mkdirSync4(dir, { recursive: true });
|
|
1155
|
+
const tmp = `${path}.tmp.${process.pid}`;
|
|
1156
|
+
writeFileSync4(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
1157
|
+
renameSync2(tmp, path);
|
|
1158
|
+
_cache = merged;
|
|
1159
|
+
return merged;
|
|
1160
|
+
}
|
|
1161
|
+
function getEmbeddingsEnabled() {
|
|
1162
|
+
const cfg = readUserConfig();
|
|
1163
|
+
if (cfg.embeddings && typeof cfg.embeddings.enabled === "boolean") {
|
|
1164
|
+
return cfg.embeddings.enabled;
|
|
1165
|
+
}
|
|
1166
|
+
if (_migrated) {
|
|
1167
|
+
return migrationValueFromEnv();
|
|
1168
|
+
}
|
|
1169
|
+
_migrated = true;
|
|
1170
|
+
const enabled = migrationValueFromEnv();
|
|
1171
|
+
try {
|
|
1172
|
+
writeUserConfig({ embeddings: { enabled } });
|
|
1173
|
+
} catch {
|
|
1174
|
+
_cache = { ...cfg ?? {}, embeddings: { ...cfg?.embeddings ?? {}, enabled } };
|
|
1175
|
+
}
|
|
1176
|
+
return enabled;
|
|
1177
|
+
}
|
|
1178
|
+
function migrationValueFromEnv() {
|
|
1179
|
+
const raw = process.env.HIVEMIND_EMBEDDINGS;
|
|
1180
|
+
if (raw === void 0)
|
|
1181
|
+
return false;
|
|
1182
|
+
if (raw === "false")
|
|
1183
|
+
return false;
|
|
1184
|
+
return true;
|
|
1185
|
+
}
|
|
1186
|
+
function isPlainObject(value) {
|
|
1187
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1188
|
+
}
|
|
1189
|
+
function deepMerge(base, patch) {
|
|
1190
|
+
const out = { ...base };
|
|
1191
|
+
for (const key of Object.keys(patch)) {
|
|
1192
|
+
const patchVal = patch[key];
|
|
1193
|
+
const baseVal = base[key];
|
|
1194
|
+
if (isPlainObject(patchVal) && isPlainObject(baseVal)) {
|
|
1195
|
+
out[key] = { ...baseVal, ...patchVal };
|
|
1196
|
+
} else if (patchVal !== void 0) {
|
|
1197
|
+
out[key] = patchVal;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return out;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// dist/src/embeddings/disable.js
|
|
1204
|
+
var cachedStatus = null;
|
|
1205
|
+
function defaultResolveTransformers() {
|
|
1206
|
+
const sharedDir = join8(homedir7(), ".hivemind", "embed-deps");
|
|
1207
|
+
try {
|
|
1208
|
+
createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
|
|
1209
|
+
return;
|
|
1210
|
+
} catch {
|
|
1211
|
+
}
|
|
1212
|
+
createRequire(import.meta.url).resolve("@huggingface/transformers");
|
|
1213
|
+
}
|
|
1214
|
+
var _resolve = defaultResolveTransformers;
|
|
1215
|
+
var _readEnabled = getEmbeddingsEnabled;
|
|
1216
|
+
function detectStatus() {
|
|
1217
|
+
if (!_readEnabled())
|
|
1218
|
+
return "user-disabled";
|
|
1219
|
+
try {
|
|
1220
|
+
_resolve();
|
|
1221
|
+
return "enabled";
|
|
1222
|
+
} catch {
|
|
1223
|
+
return "no-transformers";
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
function embeddingsStatus() {
|
|
1227
|
+
if (cachedStatus !== null)
|
|
1228
|
+
return cachedStatus;
|
|
1229
|
+
cachedStatus = detectStatus();
|
|
1230
|
+
return cachedStatus;
|
|
1231
|
+
}
|
|
1232
|
+
function embeddingsDisabled() {
|
|
1233
|
+
return embeddingsStatus() !== "enabled";
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// dist/src/embeddings/self-heal.js
|
|
1237
|
+
import { existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync5, readlinkSync, renameSync as renameSync3, rmSync, symlinkSync, statSync as statSync2 } from "node:fs";
|
|
1238
|
+
import { homedir as homedir8 } from "node:os";
|
|
1239
|
+
import { basename, dirname as dirname2, join as join9 } from "node:path";
|
|
1207
1240
|
function ensurePluginNodeModulesLink(opts) {
|
|
1208
1241
|
if (basename(opts.bundleDir) !== "bundle") {
|
|
1209
1242
|
return { kind: "not-bundle-layout", bundleDir: opts.bundleDir };
|
|
1210
1243
|
}
|
|
1211
|
-
const target = opts.sharedNodeModules ??
|
|
1244
|
+
const target = opts.sharedNodeModules ?? join9(homedir8(), ".hivemind", "embed-deps", "node_modules");
|
|
1212
1245
|
const pluginDir = dirname2(opts.bundleDir);
|
|
1213
|
-
const link =
|
|
1246
|
+
const link = join9(pluginDir, "node_modules");
|
|
1214
1247
|
if (!existsSync5(target)) {
|
|
1215
1248
|
return { kind: "shared-deps-missing", target };
|
|
1216
1249
|
}
|
|
@@ -1251,7 +1284,7 @@ function createSymlinkAtomic(target, link) {
|
|
|
1251
1284
|
try {
|
|
1252
1285
|
const parent = dirname2(link);
|
|
1253
1286
|
if (!existsSync5(parent))
|
|
1254
|
-
|
|
1287
|
+
mkdirSync5(parent, { recursive: true });
|
|
1255
1288
|
const tmp = `${link}.tmp.${process.pid}`;
|
|
1256
1289
|
try {
|
|
1257
1290
|
rmSync(tmp, { force: true });
|
|
@@ -1267,40 +1300,40 @@ function createSymlinkAtomic(target, link) {
|
|
|
1267
1300
|
|
|
1268
1301
|
// dist/src/hooks/hermes/capture.js
|
|
1269
1302
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1270
|
-
import { dirname as
|
|
1303
|
+
import { dirname as dirname7, join as join20 } from "node:path";
|
|
1271
1304
|
|
|
1272
1305
|
// dist/src/hooks/summary-state.js
|
|
1273
|
-
import { readFileSync as
|
|
1274
|
-
import { homedir as
|
|
1275
|
-
import { join as
|
|
1306
|
+
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";
|
|
1307
|
+
import { homedir as homedir9 } from "node:os";
|
|
1308
|
+
import { join as join10 } from "node:path";
|
|
1276
1309
|
var dlog = (msg) => log("summary-state", msg);
|
|
1277
|
-
var STATE_DIR =
|
|
1310
|
+
var STATE_DIR = join10(homedir9(), ".claude", "hooks", "summary-state");
|
|
1278
1311
|
var YIELD_BUF = new Int32Array(new SharedArrayBuffer(4));
|
|
1279
1312
|
function statePath(sessionId) {
|
|
1280
|
-
return
|
|
1313
|
+
return join10(STATE_DIR, `${sessionId}.json`);
|
|
1281
1314
|
}
|
|
1282
1315
|
function lockPath2(sessionId) {
|
|
1283
|
-
return
|
|
1316
|
+
return join10(STATE_DIR, `${sessionId}.lock`);
|
|
1284
1317
|
}
|
|
1285
1318
|
function readState(sessionId) {
|
|
1286
1319
|
const p = statePath(sessionId);
|
|
1287
1320
|
if (!existsSync6(p))
|
|
1288
1321
|
return null;
|
|
1289
1322
|
try {
|
|
1290
|
-
return JSON.parse(
|
|
1323
|
+
return JSON.parse(readFileSync7(p, "utf-8"));
|
|
1291
1324
|
} catch {
|
|
1292
1325
|
return null;
|
|
1293
1326
|
}
|
|
1294
1327
|
}
|
|
1295
1328
|
function writeState(sessionId, state) {
|
|
1296
|
-
|
|
1329
|
+
mkdirSync6(STATE_DIR, { recursive: true });
|
|
1297
1330
|
const p = statePath(sessionId);
|
|
1298
1331
|
const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
|
|
1299
|
-
|
|
1332
|
+
writeFileSync5(tmp, JSON.stringify(state));
|
|
1300
1333
|
renameSync4(tmp, p);
|
|
1301
1334
|
}
|
|
1302
1335
|
function withRmwLock(sessionId, fn) {
|
|
1303
|
-
|
|
1336
|
+
mkdirSync6(STATE_DIR, { recursive: true });
|
|
1304
1337
|
const rmwLock = statePath(sessionId) + ".rmw";
|
|
1305
1338
|
const deadline = Date.now() + 2e3;
|
|
1306
1339
|
let fd = null;
|
|
@@ -1313,7 +1346,7 @@ function withRmwLock(sessionId, fn) {
|
|
|
1313
1346
|
if (Date.now() > deadline) {
|
|
1314
1347
|
dlog(`rmw lock deadline exceeded for ${sessionId}, reclaiming stale lock`);
|
|
1315
1348
|
try {
|
|
1316
|
-
|
|
1349
|
+
unlinkSync4(rmwLock);
|
|
1317
1350
|
} catch (unlinkErr) {
|
|
1318
1351
|
dlog(`stale rmw lock unlink failed for ${sessionId}: ${unlinkErr.message}`);
|
|
1319
1352
|
}
|
|
@@ -1327,7 +1360,7 @@ function withRmwLock(sessionId, fn) {
|
|
|
1327
1360
|
} finally {
|
|
1328
1361
|
closeSync3(fd);
|
|
1329
1362
|
try {
|
|
1330
|
-
|
|
1363
|
+
unlinkSync4(rmwLock);
|
|
1331
1364
|
} catch (unlinkErr) {
|
|
1332
1365
|
dlog(`rmw lock cleanup failed for ${sessionId}: ${unlinkErr.message}`);
|
|
1333
1366
|
}
|
|
@@ -1362,18 +1395,18 @@ function shouldTrigger(state, cfg, now = Date.now()) {
|
|
|
1362
1395
|
return false;
|
|
1363
1396
|
}
|
|
1364
1397
|
function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
|
|
1365
|
-
|
|
1398
|
+
mkdirSync6(STATE_DIR, { recursive: true });
|
|
1366
1399
|
const p = lockPath2(sessionId);
|
|
1367
1400
|
if (existsSync6(p)) {
|
|
1368
1401
|
try {
|
|
1369
|
-
const ageMs = Date.now() - parseInt(
|
|
1402
|
+
const ageMs = Date.now() - parseInt(readFileSync7(p, "utf-8"), 10);
|
|
1370
1403
|
if (Number.isFinite(ageMs) && ageMs < maxAgeMs)
|
|
1371
1404
|
return false;
|
|
1372
1405
|
} catch (readErr) {
|
|
1373
1406
|
dlog(`lock file unreadable for ${sessionId}, treating as stale: ${readErr.message}`);
|
|
1374
1407
|
}
|
|
1375
1408
|
try {
|
|
1376
|
-
|
|
1409
|
+
unlinkSync4(p);
|
|
1377
1410
|
} catch (unlinkErr) {
|
|
1378
1411
|
dlog(`could not unlink stale lock for ${sessionId}: ${unlinkErr.message}`);
|
|
1379
1412
|
return false;
|
|
@@ -1395,7 +1428,7 @@ function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
|
|
|
1395
1428
|
}
|
|
1396
1429
|
function releaseLock(sessionId) {
|
|
1397
1430
|
try {
|
|
1398
|
-
|
|
1431
|
+
unlinkSync4(lockPath2(sessionId));
|
|
1399
1432
|
} catch (e) {
|
|
1400
1433
|
if (e?.code !== "ENOENT") {
|
|
1401
1434
|
dlog(`releaseLock unlink failed for ${sessionId}: ${e.message}`);
|
|
@@ -1406,20 +1439,20 @@ function releaseLock(sessionId) {
|
|
|
1406
1439
|
// dist/src/hooks/hermes/spawn-wiki-worker.js
|
|
1407
1440
|
import { spawn as spawn2, execSync } from "node:child_process";
|
|
1408
1441
|
import { fileURLToPath } from "node:url";
|
|
1409
|
-
import { dirname as dirname4, join as
|
|
1410
|
-
import { writeFileSync as
|
|
1411
|
-
import { homedir as
|
|
1442
|
+
import { dirname as dirname4, join as join13 } from "node:path";
|
|
1443
|
+
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync8 } from "node:fs";
|
|
1444
|
+
import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
|
|
1412
1445
|
|
|
1413
1446
|
// dist/src/utils/wiki-log.js
|
|
1414
|
-
import { mkdirSync as
|
|
1415
|
-
import { join as
|
|
1447
|
+
import { mkdirSync as mkdirSync7, appendFileSync as appendFileSync2 } from "node:fs";
|
|
1448
|
+
import { join as join11 } from "node:path";
|
|
1416
1449
|
function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") {
|
|
1417
|
-
const path =
|
|
1450
|
+
const path = join11(hooksDir, filename);
|
|
1418
1451
|
return {
|
|
1419
1452
|
path,
|
|
1420
1453
|
log(msg) {
|
|
1421
1454
|
try {
|
|
1422
|
-
|
|
1455
|
+
mkdirSync7(hooksDir, { recursive: true });
|
|
1423
1456
|
appendFileSync2(path, `[${utcTimestamp()}] ${msg}
|
|
1424
1457
|
`);
|
|
1425
1458
|
} catch {
|
|
@@ -1429,18 +1462,18 @@ function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") {
|
|
|
1429
1462
|
}
|
|
1430
1463
|
|
|
1431
1464
|
// dist/src/utils/version-check.js
|
|
1432
|
-
import { readFileSync as
|
|
1433
|
-
import { dirname as dirname3, join as
|
|
1465
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
1466
|
+
import { dirname as dirname3, join as join12 } from "node:path";
|
|
1434
1467
|
function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
1435
1468
|
try {
|
|
1436
|
-
const pluginJson =
|
|
1437
|
-
const plugin = JSON.parse(
|
|
1469
|
+
const pluginJson = join12(bundleDir, "..", pluginManifestDir, "plugin.json");
|
|
1470
|
+
const plugin = JSON.parse(readFileSync8(pluginJson, "utf-8"));
|
|
1438
1471
|
if (plugin.version)
|
|
1439
1472
|
return plugin.version;
|
|
1440
1473
|
} catch {
|
|
1441
1474
|
}
|
|
1442
1475
|
try {
|
|
1443
|
-
const stamp =
|
|
1476
|
+
const stamp = readFileSync8(join12(bundleDir, "..", ".hivemind_version"), "utf-8").trim();
|
|
1444
1477
|
if (stamp)
|
|
1445
1478
|
return stamp;
|
|
1446
1479
|
} catch {
|
|
@@ -1455,9 +1488,9 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
|
1455
1488
|
]);
|
|
1456
1489
|
let dir = bundleDir;
|
|
1457
1490
|
for (let i = 0; i < 5; i++) {
|
|
1458
|
-
const candidate =
|
|
1491
|
+
const candidate = join12(dir, "package.json");
|
|
1459
1492
|
try {
|
|
1460
|
-
const pkg = JSON.parse(
|
|
1493
|
+
const pkg = JSON.parse(readFileSync8(candidate, "utf-8"));
|
|
1461
1494
|
if (HIVEMIND_PKG_NAMES.has(pkg.name) && pkg.version)
|
|
1462
1495
|
return pkg.version;
|
|
1463
1496
|
} catch {
|
|
@@ -1471,8 +1504,8 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
|
1471
1504
|
}
|
|
1472
1505
|
|
|
1473
1506
|
// dist/src/hooks/hermes/spawn-wiki-worker.js
|
|
1474
|
-
var HOME =
|
|
1475
|
-
var wikiLogger = makeWikiLogger(
|
|
1507
|
+
var HOME = homedir10();
|
|
1508
|
+
var wikiLogger = makeWikiLogger(join13(HOME, ".hermes", "hooks"));
|
|
1476
1509
|
var WIKI_LOG = wikiLogger.path;
|
|
1477
1510
|
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.
|
|
1478
1511
|
|
|
@@ -1534,11 +1567,11 @@ function findHermesBin() {
|
|
|
1534
1567
|
function spawnHermesWikiWorker(opts) {
|
|
1535
1568
|
const { config, sessionId, cwd, bundleDir, reason } = opts;
|
|
1536
1569
|
const projectName = cwd.split("/").pop() || "unknown";
|
|
1537
|
-
const tmpDir =
|
|
1538
|
-
|
|
1570
|
+
const tmpDir = join13(tmpdir2(), `deeplake-wiki-${sessionId}-${Date.now()}`);
|
|
1571
|
+
mkdirSync8(tmpDir, { recursive: true });
|
|
1539
1572
|
const pluginVersion = getInstalledVersion(bundleDir, ".claude-plugin") ?? "";
|
|
1540
|
-
const configFile =
|
|
1541
|
-
|
|
1573
|
+
const configFile = join13(tmpDir, "config.json");
|
|
1574
|
+
writeFileSync6(configFile, JSON.stringify({
|
|
1542
1575
|
apiUrl: config.apiUrl,
|
|
1543
1576
|
token: config.token,
|
|
1544
1577
|
orgId: config.orgId,
|
|
@@ -1554,11 +1587,11 @@ function spawnHermesWikiWorker(opts) {
|
|
|
1554
1587
|
hermesProvider: process.env.HIVEMIND_HERMES_PROVIDER ?? "openrouter",
|
|
1555
1588
|
hermesModel: process.env.HIVEMIND_HERMES_MODEL ?? "anthropic/claude-haiku-4-5",
|
|
1556
1589
|
wikiLog: WIKI_LOG,
|
|
1557
|
-
hooksDir:
|
|
1590
|
+
hooksDir: join13(HOME, ".hermes", "hooks"),
|
|
1558
1591
|
promptTemplate: WIKI_PROMPT_TEMPLATE
|
|
1559
1592
|
}));
|
|
1560
1593
|
wikiLog(`${reason}: spawning summary worker for ${sessionId}`);
|
|
1561
|
-
const workerPath =
|
|
1594
|
+
const workerPath = join13(bundleDir, "wiki-worker.js");
|
|
1562
1595
|
spawn2("nohup", ["node", workerPath, configFile], {
|
|
1563
1596
|
detached: true,
|
|
1564
1597
|
stdio: ["ignore", "ignore", "ignore"]
|
|
@@ -1572,15 +1605,15 @@ function bundleDirFromImportMeta(importMetaUrl) {
|
|
|
1572
1605
|
// dist/src/skillify/spawn-skillify-worker.js
|
|
1573
1606
|
import { spawn as spawn3 } from "node:child_process";
|
|
1574
1607
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1575
|
-
import { dirname as dirname5, join as
|
|
1576
|
-
import { writeFileSync as
|
|
1577
|
-
import { homedir as
|
|
1608
|
+
import { dirname as dirname5, join as join15 } from "node:path";
|
|
1609
|
+
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync9, appendFileSync as appendFileSync3, chmodSync } from "node:fs";
|
|
1610
|
+
import { homedir as homedir12, tmpdir as tmpdir3 } from "node:os";
|
|
1578
1611
|
|
|
1579
1612
|
// dist/src/skillify/gate-runner.js
|
|
1580
1613
|
import { existsSync as existsSync7 } from "node:fs";
|
|
1581
1614
|
import { createRequire as createRequire2 } from "node:module";
|
|
1582
|
-
import { homedir as
|
|
1583
|
-
import { join as
|
|
1615
|
+
import { homedir as homedir11 } from "node:os";
|
|
1616
|
+
import { join as join14 } from "node:path";
|
|
1584
1617
|
var requireForCp = createRequire2(import.meta.url);
|
|
1585
1618
|
var { execFileSync: runChildProcess } = requireForCp("node:child_process");
|
|
1586
1619
|
var inheritedEnv = process;
|
|
@@ -1592,7 +1625,7 @@ function firstExistingPath(candidates) {
|
|
|
1592
1625
|
return null;
|
|
1593
1626
|
}
|
|
1594
1627
|
function findAgentBin(agent) {
|
|
1595
|
-
const home =
|
|
1628
|
+
const home = homedir11();
|
|
1596
1629
|
switch (agent) {
|
|
1597
1630
|
// /usr/bin/<name> is included in every candidate list — that's the
|
|
1598
1631
|
// common Linux package-manager install path (apt, dnf, pacman). Old
|
|
@@ -1601,54 +1634,54 @@ function findAgentBin(agent) {
|
|
|
1601
1634
|
// #170 caught the gap.
|
|
1602
1635
|
case "claude_code":
|
|
1603
1636
|
return firstExistingPath([
|
|
1604
|
-
|
|
1637
|
+
join14(home, ".claude", "local", "claude"),
|
|
1605
1638
|
"/usr/local/bin/claude",
|
|
1606
1639
|
"/usr/bin/claude",
|
|
1607
|
-
|
|
1608
|
-
|
|
1640
|
+
join14(home, ".npm-global", "bin", "claude"),
|
|
1641
|
+
join14(home, ".local", "bin", "claude"),
|
|
1609
1642
|
"/opt/homebrew/bin/claude"
|
|
1610
|
-
]) ??
|
|
1643
|
+
]) ?? join14(home, ".claude", "local", "claude");
|
|
1611
1644
|
case "codex":
|
|
1612
1645
|
return firstExistingPath([
|
|
1613
1646
|
"/usr/local/bin/codex",
|
|
1614
1647
|
"/usr/bin/codex",
|
|
1615
|
-
|
|
1616
|
-
|
|
1648
|
+
join14(home, ".npm-global", "bin", "codex"),
|
|
1649
|
+
join14(home, ".local", "bin", "codex"),
|
|
1617
1650
|
"/opt/homebrew/bin/codex"
|
|
1618
1651
|
]) ?? "/usr/local/bin/codex";
|
|
1619
1652
|
case "cursor":
|
|
1620
1653
|
return firstExistingPath([
|
|
1621
1654
|
"/usr/local/bin/cursor-agent",
|
|
1622
1655
|
"/usr/bin/cursor-agent",
|
|
1623
|
-
|
|
1624
|
-
|
|
1656
|
+
join14(home, ".npm-global", "bin", "cursor-agent"),
|
|
1657
|
+
join14(home, ".local", "bin", "cursor-agent"),
|
|
1625
1658
|
"/opt/homebrew/bin/cursor-agent"
|
|
1626
1659
|
]) ?? "/usr/local/bin/cursor-agent";
|
|
1627
1660
|
case "hermes":
|
|
1628
1661
|
return firstExistingPath([
|
|
1629
|
-
|
|
1662
|
+
join14(home, ".local", "bin", "hermes"),
|
|
1630
1663
|
"/usr/local/bin/hermes",
|
|
1631
1664
|
"/usr/bin/hermes",
|
|
1632
|
-
|
|
1665
|
+
join14(home, ".npm-global", "bin", "hermes"),
|
|
1633
1666
|
"/opt/homebrew/bin/hermes"
|
|
1634
|
-
]) ??
|
|
1667
|
+
]) ?? join14(home, ".local", "bin", "hermes");
|
|
1635
1668
|
case "pi":
|
|
1636
1669
|
return firstExistingPath([
|
|
1637
|
-
|
|
1670
|
+
join14(home, ".local", "bin", "pi"),
|
|
1638
1671
|
"/usr/local/bin/pi",
|
|
1639
1672
|
"/usr/bin/pi",
|
|
1640
|
-
|
|
1673
|
+
join14(home, ".npm-global", "bin", "pi"),
|
|
1641
1674
|
"/opt/homebrew/bin/pi"
|
|
1642
|
-
]) ??
|
|
1675
|
+
]) ?? join14(home, ".local", "bin", "pi");
|
|
1643
1676
|
}
|
|
1644
1677
|
}
|
|
1645
1678
|
|
|
1646
1679
|
// dist/src/skillify/spawn-skillify-worker.js
|
|
1647
|
-
var HOME2 =
|
|
1648
|
-
var SKILLIFY_LOG =
|
|
1680
|
+
var HOME2 = homedir12();
|
|
1681
|
+
var SKILLIFY_LOG = join15(HOME2, ".claude", "hooks", "skillify.log");
|
|
1649
1682
|
function skillifyLog(msg) {
|
|
1650
1683
|
try {
|
|
1651
|
-
|
|
1684
|
+
mkdirSync9(dirname5(SKILLIFY_LOG), { recursive: true });
|
|
1652
1685
|
appendFileSync3(SKILLIFY_LOG, `[${utcTimestamp()}] ${msg}
|
|
1653
1686
|
`);
|
|
1654
1687
|
} catch {
|
|
@@ -1656,11 +1689,11 @@ function skillifyLog(msg) {
|
|
|
1656
1689
|
}
|
|
1657
1690
|
function spawnSkillifyWorker(opts) {
|
|
1658
1691
|
const { config, cwd, projectKey, project, bundleDir, agent, scopeConfig, currentSessionId, reason } = opts;
|
|
1659
|
-
const tmpDir =
|
|
1660
|
-
|
|
1692
|
+
const tmpDir = join15(tmpdir3(), `deeplake-skillify-${projectKey}-${Date.now()}`);
|
|
1693
|
+
mkdirSync9(tmpDir, { recursive: true, mode: 448 });
|
|
1661
1694
|
const gateBin = findAgentBin(agent);
|
|
1662
|
-
const configFile =
|
|
1663
|
-
|
|
1695
|
+
const configFile = join15(tmpDir, "config.json");
|
|
1696
|
+
writeFileSync7(configFile, JSON.stringify({
|
|
1664
1697
|
apiUrl: config.apiUrl,
|
|
1665
1698
|
token: config.token,
|
|
1666
1699
|
orgId: config.orgId,
|
|
@@ -1690,7 +1723,7 @@ function spawnSkillifyWorker(opts) {
|
|
|
1690
1723
|
} catch {
|
|
1691
1724
|
}
|
|
1692
1725
|
skillifyLog(`${reason}: spawning skillify worker for project=${project} key=${projectKey}`);
|
|
1693
|
-
const workerPath =
|
|
1726
|
+
const workerPath = join15(bundleDir, "skillify-worker.js");
|
|
1694
1727
|
spawn3("nohup", ["node", workerPath, configFile], {
|
|
1695
1728
|
detached: true,
|
|
1696
1729
|
stdio: ["ignore", "ignore", "ignore"]
|
|
@@ -1699,25 +1732,34 @@ function spawnSkillifyWorker(opts) {
|
|
|
1699
1732
|
}
|
|
1700
1733
|
|
|
1701
1734
|
// dist/src/skillify/state.js
|
|
1702
|
-
import { readFileSync as
|
|
1735
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, writeSync as writeSync3, mkdirSync as mkdirSync10, renameSync as renameSync6, rmdirSync, existsSync as existsSync9, lstatSync as lstatSync2, unlinkSync as unlinkSync5, openSync as openSync4, closeSync as closeSync4 } from "node:fs";
|
|
1703
1736
|
import { execSync as execSync2 } from "node:child_process";
|
|
1704
|
-
import { homedir as homedir13 } from "node:os";
|
|
1705
1737
|
import { createHash } from "node:crypto";
|
|
1706
|
-
import { join as
|
|
1738
|
+
import { join as join18, basename as basename2 } from "node:path";
|
|
1707
1739
|
|
|
1708
1740
|
// dist/src/skillify/legacy-migration.js
|
|
1709
1741
|
import { existsSync as existsSync8, renameSync as renameSync5 } from "node:fs";
|
|
1710
|
-
import {
|
|
1711
|
-
|
|
1742
|
+
import { dirname as dirname6, join as join17 } from "node:path";
|
|
1743
|
+
|
|
1744
|
+
// dist/src/skillify/state-dir.js
|
|
1745
|
+
import { homedir as homedir13 } from "node:os";
|
|
1746
|
+
import { join as join16 } from "node:path";
|
|
1747
|
+
function getStateDir() {
|
|
1748
|
+
const override = process.env.HIVEMIND_STATE_DIR?.trim();
|
|
1749
|
+
return override && override.length > 0 ? override : join16(homedir13(), ".deeplake", "state", "skillify");
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
// dist/src/skillify/legacy-migration.js
|
|
1712
1753
|
var dlog2 = (msg) => log("skillify-migrate", msg);
|
|
1713
1754
|
var attempted = false;
|
|
1714
1755
|
function migrateLegacyStateDir() {
|
|
1756
|
+
if (process.env.HIVEMIND_STATE_DIR?.trim())
|
|
1757
|
+
return;
|
|
1715
1758
|
if (attempted)
|
|
1716
1759
|
return;
|
|
1717
1760
|
attempted = true;
|
|
1718
|
-
const
|
|
1719
|
-
const legacy =
|
|
1720
|
-
const current = join15(root, "skillify");
|
|
1761
|
+
const current = getStateDir();
|
|
1762
|
+
const legacy = join17(dirname6(current), "skilify");
|
|
1721
1763
|
if (!existsSync8(legacy))
|
|
1722
1764
|
return;
|
|
1723
1765
|
if (existsSync8(current))
|
|
@@ -1727,8 +1769,8 @@ function migrateLegacyStateDir() {
|
|
|
1727
1769
|
dlog2(`migrated ${legacy} -> ${current}`);
|
|
1728
1770
|
} catch (err) {
|
|
1729
1771
|
const code = err.code;
|
|
1730
|
-
if (code === "EXDEV" || code === "EPERM") {
|
|
1731
|
-
dlog2(`migration
|
|
1772
|
+
if (code === "EXDEV" || code === "EPERM" || code === "ENOENT" || code === "EEXIST" || code === "ENOTEMPTY") {
|
|
1773
|
+
dlog2(`migration skipped (${code}); legacy dir left as-is or another process handled it`);
|
|
1732
1774
|
return;
|
|
1733
1775
|
}
|
|
1734
1776
|
throw err;
|
|
@@ -1737,17 +1779,16 @@ function migrateLegacyStateDir() {
|
|
|
1737
1779
|
|
|
1738
1780
|
// dist/src/skillify/state.js
|
|
1739
1781
|
var dlog3 = (msg) => log("skillify-state", msg);
|
|
1740
|
-
var STATE_DIR2 = join16(homedir13(), ".deeplake", "state", "skillify");
|
|
1741
1782
|
var YIELD_BUF2 = new Int32Array(new SharedArrayBuffer(4));
|
|
1742
1783
|
var TRIGGER_THRESHOLD = (() => {
|
|
1743
1784
|
const n = Number(process.env.HIVEMIND_SKILLIFY_EVERY_N_TURNS ?? "");
|
|
1744
1785
|
return Number.isInteger(n) && n > 0 ? n : 20;
|
|
1745
1786
|
})();
|
|
1746
1787
|
function statePath2(projectKey) {
|
|
1747
|
-
return
|
|
1788
|
+
return join18(getStateDir(), `${projectKey}.json`);
|
|
1748
1789
|
}
|
|
1749
1790
|
function lockPath3(projectKey) {
|
|
1750
|
-
return
|
|
1791
|
+
return join18(getStateDir(), `${projectKey}.lock`);
|
|
1751
1792
|
}
|
|
1752
1793
|
var DEFAULT_PORTS = {
|
|
1753
1794
|
http: "80",
|
|
@@ -1796,22 +1837,22 @@ function readState2(projectKey) {
|
|
|
1796
1837
|
if (!existsSync9(p))
|
|
1797
1838
|
return null;
|
|
1798
1839
|
try {
|
|
1799
|
-
return JSON.parse(
|
|
1840
|
+
return JSON.parse(readFileSync9(p, "utf-8"));
|
|
1800
1841
|
} catch {
|
|
1801
1842
|
return null;
|
|
1802
1843
|
}
|
|
1803
1844
|
}
|
|
1804
1845
|
function writeState2(projectKey, state) {
|
|
1805
1846
|
migrateLegacyStateDir();
|
|
1806
|
-
|
|
1847
|
+
mkdirSync10(getStateDir(), { recursive: true });
|
|
1807
1848
|
const p = statePath2(projectKey);
|
|
1808
1849
|
const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
|
|
1809
|
-
|
|
1850
|
+
writeFileSync8(tmp, JSON.stringify(state, null, 2));
|
|
1810
1851
|
renameSync6(tmp, p);
|
|
1811
1852
|
}
|
|
1812
1853
|
function withRmwLock2(projectKey, fn) {
|
|
1813
1854
|
migrateLegacyStateDir();
|
|
1814
|
-
|
|
1855
|
+
mkdirSync10(getStateDir(), { recursive: true });
|
|
1815
1856
|
const rmw = lockPath3(projectKey) + ".rmw";
|
|
1816
1857
|
const deadline = Date.now() + 2e3;
|
|
1817
1858
|
let fd = null;
|
|
@@ -1824,7 +1865,7 @@ function withRmwLock2(projectKey, fn) {
|
|
|
1824
1865
|
if (Date.now() > deadline) {
|
|
1825
1866
|
dlog3(`rmw lock deadline exceeded for ${projectKey}, reclaiming stale lock`);
|
|
1826
1867
|
try {
|
|
1827
|
-
|
|
1868
|
+
unlinkSync5(rmw);
|
|
1828
1869
|
} catch (unlinkErr) {
|
|
1829
1870
|
dlog3(`stale rmw lock unlink failed for ${projectKey}: ${unlinkErr.message}`);
|
|
1830
1871
|
}
|
|
@@ -1838,7 +1879,7 @@ function withRmwLock2(projectKey, fn) {
|
|
|
1838
1879
|
} finally {
|
|
1839
1880
|
closeSync4(fd);
|
|
1840
1881
|
try {
|
|
1841
|
-
|
|
1882
|
+
unlinkSync5(rmw);
|
|
1842
1883
|
} catch (unlinkErr) {
|
|
1843
1884
|
dlog3(`rmw lock cleanup failed for ${projectKey}: ${unlinkErr.message}`);
|
|
1844
1885
|
}
|
|
@@ -1871,21 +1912,35 @@ function resetCounter(projectKey) {
|
|
|
1871
1912
|
}
|
|
1872
1913
|
function tryAcquireWorkerLock(projectKey, maxAgeMs = 10 * 60 * 1e3) {
|
|
1873
1914
|
migrateLegacyStateDir();
|
|
1874
|
-
|
|
1915
|
+
mkdirSync10(getStateDir(), { recursive: true });
|
|
1875
1916
|
const p = lockPath3(projectKey);
|
|
1876
1917
|
if (existsSync9(p)) {
|
|
1877
1918
|
try {
|
|
1878
|
-
const ageMs = Date.now() - parseInt(
|
|
1919
|
+
const ageMs = Date.now() - parseInt(readFileSync9(p, "utf-8"), 10);
|
|
1879
1920
|
if (Number.isFinite(ageMs) && ageMs < maxAgeMs)
|
|
1880
1921
|
return false;
|
|
1881
1922
|
} catch (readErr) {
|
|
1882
1923
|
dlog3(`worker lock unreadable for ${projectKey}, treating as stale: ${readErr.message}`);
|
|
1883
1924
|
}
|
|
1884
1925
|
try {
|
|
1885
|
-
|
|
1926
|
+
unlinkSync5(p);
|
|
1886
1927
|
} catch (unlinkErr) {
|
|
1887
|
-
|
|
1888
|
-
|
|
1928
|
+
if (unlinkErr?.code !== "EISDIR" && unlinkErr?.code !== "EPERM" && unlinkErr?.code !== "ENOENT") {
|
|
1929
|
+
dlog3(`could not unlink stale worker lock for ${projectKey}: ${unlinkErr.message}`);
|
|
1930
|
+
return false;
|
|
1931
|
+
}
|
|
1932
|
+
let isDir = false;
|
|
1933
|
+
try {
|
|
1934
|
+
isDir = lstatSync2(p).isDirectory();
|
|
1935
|
+
} catch {
|
|
1936
|
+
}
|
|
1937
|
+
if (isDir) {
|
|
1938
|
+
try {
|
|
1939
|
+
rmdirSync(p);
|
|
1940
|
+
} catch (rmErr) {
|
|
1941
|
+
dlog3(`rmdir stale lock skipped for ${projectKey}: ${rmErr.message}`);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1889
1944
|
}
|
|
1890
1945
|
}
|
|
1891
1946
|
try {
|
|
@@ -1903,24 +1958,25 @@ function tryAcquireWorkerLock(projectKey, maxAgeMs = 10 * 60 * 1e3) {
|
|
|
1903
1958
|
function releaseWorkerLock(projectKey) {
|
|
1904
1959
|
const p = lockPath3(projectKey);
|
|
1905
1960
|
try {
|
|
1906
|
-
|
|
1961
|
+
unlinkSync5(p);
|
|
1907
1962
|
} catch {
|
|
1908
1963
|
}
|
|
1909
1964
|
}
|
|
1910
1965
|
|
|
1911
1966
|
// dist/src/skillify/scope-config.js
|
|
1912
|
-
import { existsSync as existsSync10, mkdirSync as
|
|
1913
|
-
import {
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1967
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "node:fs";
|
|
1968
|
+
import { join as join19 } from "node:path";
|
|
1969
|
+
function configPath() {
|
|
1970
|
+
return join19(getStateDir(), "config.json");
|
|
1971
|
+
}
|
|
1917
1972
|
var DEFAULT = { scope: "me", team: [], install: "project" };
|
|
1918
1973
|
function loadScopeConfig() {
|
|
1919
1974
|
migrateLegacyStateDir();
|
|
1975
|
+
const CONFIG_PATH = configPath();
|
|
1920
1976
|
if (!existsSync10(CONFIG_PATH))
|
|
1921
1977
|
return DEFAULT;
|
|
1922
1978
|
try {
|
|
1923
|
-
const raw = JSON.parse(
|
|
1979
|
+
const raw = JSON.parse(readFileSync10(CONFIG_PATH, "utf-8"));
|
|
1924
1980
|
const scope = raw.scope === "team" ? "team" : raw.scope === "org" ? "team" : "me";
|
|
1925
1981
|
const team = Array.isArray(raw.team) ? raw.team.filter((s) => typeof s === "string") : [];
|
|
1926
1982
|
const install = raw.install === "global" ? "global" : "project";
|
|
@@ -1973,9 +2029,9 @@ function tryStopCounterTrigger(opts) {
|
|
|
1973
2029
|
// dist/src/hooks/hermes/capture.js
|
|
1974
2030
|
var log5 = (msg) => log("hermes-capture", msg);
|
|
1975
2031
|
function resolveEmbedDaemonPath() {
|
|
1976
|
-
return
|
|
2032
|
+
return join20(dirname7(fileURLToPath3(import.meta.url)), "embeddings", "embed-daemon.js");
|
|
1977
2033
|
}
|
|
1978
|
-
var __bundleDir =
|
|
2034
|
+
var __bundleDir = dirname7(fileURLToPath3(import.meta.url));
|
|
1979
2035
|
var PLUGIN_VERSION = getInstalledVersion(__bundleDir, ".claude-plugin") ?? "";
|
|
1980
2036
|
if (!embeddingsDisabled()) {
|
|
1981
2037
|
try {
|