@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.
Files changed (34) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/bundle/cli.js +332 -189
  4. package/codex/bundle/capture.js +365 -332
  5. package/codex/bundle/commands/auth-login.js +163 -30
  6. package/codex/bundle/pre-tool-use.js +334 -301
  7. package/codex/bundle/session-start-setup.js +193 -60
  8. package/codex/bundle/session-start.js +229 -87
  9. package/codex/bundle/shell/deeplake-shell.js +328 -295
  10. package/codex/bundle/skillify-worker.js +26 -18
  11. package/codex/bundle/stop.js +450 -394
  12. package/codex/bundle/wiki-worker.js +174 -292
  13. package/cursor/bundle/capture.js +448 -392
  14. package/cursor/bundle/commands/auth-login.js +163 -30
  15. package/cursor/bundle/pre-tool-use.js +324 -291
  16. package/cursor/bundle/session-end.js +43 -20
  17. package/cursor/bundle/session-start.js +272 -130
  18. package/cursor/bundle/shell/deeplake-shell.js +328 -295
  19. package/cursor/bundle/skillify-worker.js +26 -18
  20. package/cursor/bundle/wiki-worker.js +174 -292
  21. package/hermes/bundle/capture.js +448 -392
  22. package/hermes/bundle/commands/auth-login.js +163 -30
  23. package/hermes/bundle/pre-tool-use.js +324 -291
  24. package/hermes/bundle/session-end.js +43 -20
  25. package/hermes/bundle/session-start.js +269 -127
  26. package/hermes/bundle/shell/deeplake-shell.js +328 -295
  27. package/hermes/bundle/skillify-worker.js +26 -18
  28. package/hermes/bundle/wiki-worker.js +174 -292
  29. package/mcp/bundle/server.js +190 -57
  30. package/openclaw/dist/index.js +160 -32
  31. package/openclaw/dist/skillify-worker.js +26 -18
  32. package/openclaw/openclaw.plugin.json +1 -1
  33. package/openclaw/package.json +1 -1
  34. package/package.json +1 -1
@@ -17,21 +17,21 @@ __export(index_marker_store_exports, {
17
17
  hasFreshIndexMarker: () => hasFreshIndexMarker,
18
18
  writeIndexMarker: () => writeIndexMarker
19
19
  });
20
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
21
- import { join as join3 } from "node:path";
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 ?? join3(tmpdir(), "hivemind-deeplake-indexes");
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 join3(getIndexMarkerDir(), `${markerKey}.json`);
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(readFileSync2(markerPath, "utf-8"));
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
- mkdirSync(getIndexMarkerDir(), { recursive: true });
45
- writeFileSync(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
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 log2 = (msg) => log("sdk", msg);
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
- log2(msg);
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 sleep(ms) {
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
- log2(`query retry ${attempt + 1}/${MAX_RETRIES} (fetch error: ${lastError.message}) in ${delay.toFixed(0)}ms`);
281
- await sleep(delay);
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
- log2(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
298
- await sleep(delay);
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
- log2(`commit: ${rows.length} rows`);
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
- log2(`index "${indexName}" skipped: ${e.message}`);
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 sleep(BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200);
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 sleep(BASE_DELAY_MS * Math.pow(2, attempt));
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
- log2(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
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 sleep(OUTER_BACKOFFS_MS[attempt]);
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
- log2(`table "${tbl}" not found, creating`);
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
- log2(`table "${tbl}" created`);
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
- log2(`table "${safe}" not found, creating`);
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
- log2(`table "${safe}" created`);
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
- log2(`table "${safe}" not found, creating`);
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
- log2(`table "${safe}" created`);
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 unlinkSync2, existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
574
- import { homedir as homedir6 } from "node:os";
575
- import { join as join7 } from "node:path";
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 = join7(homedir6(), ".hivemind", "embed-deps", "embed-daemon.js");
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 ?? (existsSync4(SHARED_DAEMON_PATH) ? SHARED_DAEMON_PATH : void 0);
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 (existsSync4(this.socketPath))
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 && !existsSync4(hello.daemonPath)) {
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. Also enqueue a one-time
968
- * notification telling the user to run `hivemind embeddings install`
969
- * but only when the user has opted in. Suppressed when
970
- * embeddingsStatus() === "user-disabled" so we don't nag users who
971
- * explicitly chose to turn embeddings off.
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(detail) {
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 && existsSync4(this.socketPath)) {
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
- unlinkSync2(this.socketPath);
944
+ unlinkSync3(this.socketPath);
1030
945
  } catch {
1031
946
  }
1032
947
  try {
1033
- unlinkSync2(this.pidPath);
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
- unlinkSync2(this.pidPath);
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 || !existsSync4(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
- unlinkSync2(this.pidPath);
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 (!existsSync4(this.socketPath))
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/self-heal.js
1205
- import { existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync4, readlinkSync, renameSync as renameSync3, rmSync, symlinkSync, statSync as statSync2 } from "node:fs";
1119
+ // dist/src/embeddings/disable.js
1120
+ import { createRequire } from "node:module";
1206
1121
  import { homedir as homedir7 } from "node:os";
1207
- import { basename, dirname as dirname2, join as join8 } from "node:path";
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 ?? join8(homedir7(), ".hivemind", "embed-deps", "node_modules");
1245
+ const target = opts.sharedNodeModules ?? join9(homedir8(), ".hivemind", "embed-deps", "node_modules");
1213
1246
  const pluginDir = dirname2(opts.bundleDir);
1214
- const link = join8(pluginDir, "node_modules");
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
- mkdirSync4(parent, { recursive: true });
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/cursor/capture.js
1270
1303
  import { fileURLToPath as fileURLToPath3 } from "node:url";
1271
- import { dirname as dirname6, join as join18 } from "node:path";
1304
+ import { dirname as dirname7, join as join20 } from "node:path";
1272
1305
 
1273
1306
  // dist/src/hooks/summary-state.js
1274
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, writeSync as writeSync2, mkdirSync as mkdirSync5, renameSync as renameSync4, existsSync as existsSync6, unlinkSync as unlinkSync3, openSync as openSync3, closeSync as closeSync3 } from "node:fs";
1275
- import { homedir as homedir8 } from "node:os";
1276
- import { join as join9 } from "node:path";
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 = join9(homedir8(), ".claude", "hooks", "summary-state");
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 join9(STATE_DIR, `${sessionId}.json`);
1314
+ return join10(STATE_DIR, `${sessionId}.json`);
1282
1315
  }
1283
1316
  function lockPath2(sessionId) {
1284
- return join9(STATE_DIR, `${sessionId}.lock`);
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(readFileSync6(p, "utf-8"));
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
- mkdirSync5(STATE_DIR, { recursive: true });
1330
+ mkdirSync6(STATE_DIR, { recursive: true });
1298
1331
  const p = statePath(sessionId);
1299
1332
  const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
1300
- writeFileSync4(tmp, JSON.stringify(state));
1333
+ writeFileSync5(tmp, JSON.stringify(state));
1301
1334
  renameSync4(tmp, p);
1302
1335
  }
1303
1336
  function withRmwLock(sessionId, fn) {
1304
- mkdirSync5(STATE_DIR, { recursive: true });
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
- unlinkSync3(rmwLock);
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
- unlinkSync3(rmwLock);
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
- mkdirSync5(STATE_DIR, { recursive: true });
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(readFileSync6(p, "utf-8"), 10);
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
- unlinkSync3(p);
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
- unlinkSync3(lockPath2(sessionId));
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/cursor/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 join12 } from "node:path";
1411
- import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync7 } from "node:fs";
1412
- import { homedir as homedir9, tmpdir as tmpdir2 } from "node:os";
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 mkdirSync6, appendFileSync as appendFileSync2 } from "node:fs";
1416
- import { join as join10 } from "node:path";
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 = join10(hooksDir, filename);
1451
+ const path = join11(hooksDir, filename);
1419
1452
  return {
1420
1453
  path,
1421
1454
  log(msg) {
1422
1455
  try {
1423
- mkdirSync6(hooksDir, { recursive: true });
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 readFileSync7 } from "node:fs";
1434
- import { dirname as dirname3, join as join11 } from "node:path";
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 = join11(bundleDir, "..", pluginManifestDir, "plugin.json");
1438
- const plugin = JSON.parse(readFileSync7(pluginJson, "utf-8"));
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 = readFileSync7(join11(bundleDir, "..", ".hivemind_version"), "utf-8").trim();
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 = join11(dir, "package.json");
1492
+ const candidate = join12(dir, "package.json");
1460
1493
  try {
1461
- const pkg = JSON.parse(readFileSync7(candidate, "utf-8"));
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/cursor/spawn-wiki-worker.js
1475
- var HOME = homedir9();
1476
- var wikiLogger = makeWikiLogger(join12(HOME, ".cursor", "hooks"));
1508
+ var HOME = homedir10();
1509
+ var wikiLogger = makeWikiLogger(join13(HOME, ".cursor", "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 findCursorBin() {
1535
1568
  function spawnCursorWikiWorker(opts) {
1536
1569
  const { config, sessionId, cwd, bundleDir, reason } = opts;
1537
1570
  const projectName = cwd.split("/").pop() || "unknown";
1538
- const tmpDir = join12(tmpdir2(), `deeplake-wiki-${sessionId}-${Date.now()}`);
1539
- mkdirSync7(tmpDir, { recursive: true });
1571
+ const tmpDir = join13(tmpdir2(), `deeplake-wiki-${sessionId}-${Date.now()}`);
1572
+ mkdirSync8(tmpDir, { recursive: true });
1540
1573
  const pluginVersion = getInstalledVersion(bundleDir, ".claude-plugin") ?? "";
1541
- const configFile = join12(tmpDir, "config.json");
1542
- writeFileSync5(configFile, JSON.stringify({
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,
@@ -1554,11 +1587,11 @@ function spawnCursorWikiWorker(opts) {
1554
1587
  cursorBin: findCursorBin(),
1555
1588
  cursorModel: process.env.HIVEMIND_CURSOR_MODEL ?? "auto",
1556
1589
  wikiLog: WIKI_LOG,
1557
- hooksDir: join12(HOME, ".cursor", "hooks"),
1590
+ hooksDir: join13(HOME, ".cursor", "hooks"),
1558
1591
  promptTemplate: WIKI_PROMPT_TEMPLATE
1559
1592
  }));
1560
1593
  wikiLog(`${reason}: spawning summary worker for ${sessionId}`);
1561
- const workerPath = join12(bundleDir, "wiki-worker.js");
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 join14 } from "node:path";
1576
- import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync8, appendFileSync as appendFileSync3, chmodSync } from "node:fs";
1577
- import { homedir as homedir11, tmpdir as tmpdir3 } from "node:os";
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 homedir10 } from "node:os";
1583
- import { join as join13 } from "node:path";
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 = homedir10();
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
- join13(home, ".claude", "local", "claude"),
1637
+ join14(home, ".claude", "local", "claude"),
1605
1638
  "/usr/local/bin/claude",
1606
1639
  "/usr/bin/claude",
1607
- join13(home, ".npm-global", "bin", "claude"),
1608
- join13(home, ".local", "bin", "claude"),
1640
+ join14(home, ".npm-global", "bin", "claude"),
1641
+ join14(home, ".local", "bin", "claude"),
1609
1642
  "/opt/homebrew/bin/claude"
1610
- ]) ?? join13(home, ".claude", "local", "claude");
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
- join13(home, ".npm-global", "bin", "codex"),
1616
- join13(home, ".local", "bin", "codex"),
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
- join13(home, ".npm-global", "bin", "cursor-agent"),
1624
- join13(home, ".local", "bin", "cursor-agent"),
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
- join13(home, ".local", "bin", "hermes"),
1662
+ join14(home, ".local", "bin", "hermes"),
1630
1663
  "/usr/local/bin/hermes",
1631
1664
  "/usr/bin/hermes",
1632
- join13(home, ".npm-global", "bin", "hermes"),
1665
+ join14(home, ".npm-global", "bin", "hermes"),
1633
1666
  "/opt/homebrew/bin/hermes"
1634
- ]) ?? join13(home, ".local", "bin", "hermes");
1667
+ ]) ?? join14(home, ".local", "bin", "hermes");
1635
1668
  case "pi":
1636
1669
  return firstExistingPath([
1637
- join13(home, ".local", "bin", "pi"),
1670
+ join14(home, ".local", "bin", "pi"),
1638
1671
  "/usr/local/bin/pi",
1639
1672
  "/usr/bin/pi",
1640
- join13(home, ".npm-global", "bin", "pi"),
1673
+ join14(home, ".npm-global", "bin", "pi"),
1641
1674
  "/opt/homebrew/bin/pi"
1642
- ]) ?? join13(home, ".local", "bin", "pi");
1675
+ ]) ?? join14(home, ".local", "bin", "pi");
1643
1676
  }
1644
1677
  }
1645
1678
 
1646
1679
  // dist/src/skillify/spawn-skillify-worker.js
1647
- var HOME2 = homedir11();
1648
- var SKILLIFY_LOG = join14(HOME2, ".claude", "hooks", "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
- mkdirSync8(dirname5(SKILLIFY_LOG), { recursive: true });
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 = join14(tmpdir3(), `deeplake-skillify-${projectKey}-${Date.now()}`);
1660
- mkdirSync8(tmpDir, { recursive: true, mode: 448 });
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 = join14(tmpDir, "config.json");
1663
- writeFileSync6(configFile, JSON.stringify({
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 = join14(bundleDir, "skillify-worker.js");
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 readFileSync8, writeFileSync as writeFileSync7, writeSync as writeSync3, mkdirSync as mkdirSync9, renameSync as renameSync6, existsSync as existsSync9, unlinkSync as unlinkSync4, openSync as openSync4, closeSync as closeSync4 } from "node:fs";
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 join16, basename as basename2 } from "node:path";
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 { homedir as homedir12 } from "node:os";
1711
- import { join as join15 } from "node:path";
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 root = join15(homedir12(), ".deeplake", "state");
1719
- const legacy = join15(root, "skilify");
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 failed (${code}); leaving legacy dir in place`);
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 join16(STATE_DIR2, `${projectKey}.json`);
1788
+ return join18(getStateDir(), `${projectKey}.json`);
1748
1789
  }
1749
1790
  function lockPath3(projectKey) {
1750
- return join16(STATE_DIR2, `${projectKey}.lock`);
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(readFileSync8(p, "utf-8"));
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
- mkdirSync9(STATE_DIR2, { recursive: true });
1847
+ mkdirSync10(getStateDir(), { recursive: true });
1807
1848
  const p = statePath2(projectKey);
1808
1849
  const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
1809
- writeFileSync7(tmp, JSON.stringify(state, null, 2));
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
- mkdirSync9(STATE_DIR2, { recursive: true });
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
- unlinkSync4(rmw);
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
- unlinkSync4(rmw);
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
- mkdirSync9(STATE_DIR2, { recursive: true });
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(readFileSync8(p, "utf-8"), 10);
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
- unlinkSync4(p);
1926
+ unlinkSync5(p);
1886
1927
  } catch (unlinkErr) {
1887
- dlog3(`could not unlink stale worker lock for ${projectKey}: ${unlinkErr.message}`);
1888
- return false;
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
- unlinkSync4(p);
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 mkdirSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "node:fs";
1913
- import { homedir as homedir14 } from "node:os";
1914
- import { join as join17 } from "node:path";
1915
- var STATE_DIR3 = join17(homedir14(), ".deeplake", "state", "skillify");
1916
- var CONFIG_PATH = join17(STATE_DIR3, "config.json");
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(readFileSync9(CONFIG_PATH, "utf-8"));
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/cursor/capture.js
1974
2030
  var log5 = (msg) => log("cursor-capture", msg);
1975
2031
  function resolveEmbedDaemonPath() {
1976
- return join18(dirname6(fileURLToPath3(import.meta.url)), "embeddings", "embed-daemon.js");
2032
+ return join20(dirname7(fileURLToPath3(import.meta.url)), "embeddings", "embed-daemon.js");
1977
2033
  }
1978
- var __bundleDir = dirname6(fileURLToPath3(import.meta.url));
2034
+ var __bundleDir = dirname7(fileURLToPath3(import.meta.url));
1979
2035
  var PLUGIN_VERSION = getInstalledVersion(__bundleDir, ".claude-plugin") ?? "";
1980
2036
  if (!embeddingsDisabled()) {
1981
2037
  try {