@deeplake/hivemind 0.7.31 → 0.7.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -46081,14 +46081,14 @@ var require_turndown_cjs = __commonJS({
46081
46081
  } else if (node.nodeType === 1) {
46082
46082
  replacement = replacementForNode.call(self2, node);
46083
46083
  }
46084
- return join11(output, replacement);
46084
+ return join14(output, replacement);
46085
46085
  }, "");
46086
46086
  }
46087
46087
  function postProcess(output) {
46088
46088
  var self2 = this;
46089
46089
  this.rules.forEach(function(rule) {
46090
46090
  if (typeof rule.append === "function") {
46091
- output = join11(output, rule.append(self2.options));
46091
+ output = join14(output, rule.append(self2.options));
46092
46092
  }
46093
46093
  });
46094
46094
  return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
@@ -46100,7 +46100,7 @@ var require_turndown_cjs = __commonJS({
46100
46100
  if (whitespace.leading || whitespace.trailing) content = content.trim();
46101
46101
  return whitespace.leading + rule.replacement(content, node, this.options) + whitespace.trailing;
46102
46102
  }
46103
- function join11(output, replacement) {
46103
+ function join14(output, replacement) {
46104
46104
  var s12 = trimTrailingNewlines(output);
46105
46105
  var s22 = trimLeadingNewlines(replacement);
46106
46106
  var nls = Math.max(output.length - s12.length, replacement.length - s22.length);
@@ -59941,21 +59941,21 @@ __export(index_marker_store_exports, {
59941
59941
  hasFreshIndexMarker: () => hasFreshIndexMarker,
59942
59942
  writeIndexMarker: () => writeIndexMarker
59943
59943
  });
59944
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
59945
- import { join as join6 } from "node:path";
59944
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
59945
+ import { join as join8 } from "node:path";
59946
59946
  import { tmpdir } from "node:os";
59947
59947
  function getIndexMarkerDir() {
59948
- return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join6(tmpdir(), "hivemind-deeplake-indexes");
59948
+ return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join8(tmpdir(), "hivemind-deeplake-indexes");
59949
59949
  }
59950
59950
  function buildIndexMarkerPath(workspaceId, orgId, table, suffix) {
59951
59951
  const markerKey = [workspaceId, orgId, table, suffix].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
59952
- return join6(getIndexMarkerDir(), `${markerKey}.json`);
59952
+ return join8(getIndexMarkerDir(), `${markerKey}.json`);
59953
59953
  }
59954
59954
  function hasFreshIndexMarker(markerPath) {
59955
59955
  if (!existsSync3(markerPath))
59956
59956
  return false;
59957
59957
  try {
59958
- const raw = JSON.parse(readFileSync2(markerPath, "utf-8"));
59958
+ const raw = JSON.parse(readFileSync4(markerPath, "utf-8"));
59959
59959
  const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
59960
59960
  if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
59961
59961
  return false;
@@ -59965,8 +59965,8 @@ function hasFreshIndexMarker(markerPath) {
59965
59965
  }
59966
59966
  }
59967
59967
  function writeIndexMarker(markerPath) {
59968
- mkdirSync(getIndexMarkerDir(), { recursive: true });
59969
- writeFileSync(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
59968
+ mkdirSync3(getIndexMarkerDir(), { recursive: true });
59969
+ writeFileSync3(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
59970
59970
  }
59971
59971
  var INDEX_MARKER_TTL_MS;
59972
59972
  var init_index_marker_store = __esm({
@@ -66841,6 +66841,125 @@ function deeplakeClientHeader() {
66841
66841
  return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
66842
66842
  }
66843
66843
 
66844
+ // dist/src/notifications/queue.js
66845
+ import { readFileSync as readFileSync2, writeFileSync, renameSync, mkdirSync, openSync, closeSync, unlinkSync, statSync as statSync2 } from "node:fs";
66846
+ import { join as join6, resolve as resolve4 } from "node:path";
66847
+ import { homedir as homedir3 } from "node:os";
66848
+ import { setTimeout as sleep } from "node:timers/promises";
66849
+ var log2 = (msg) => log("notifications-queue", msg);
66850
+ var LOCK_RETRY_MAX = 50;
66851
+ var LOCK_RETRY_BASE_MS = 5;
66852
+ var LOCK_STALE_MS = 5e3;
66853
+ function queuePath() {
66854
+ return join6(homedir3(), ".deeplake", "notifications-queue.json");
66855
+ }
66856
+ function lockPath() {
66857
+ return `${queuePath()}.lock`;
66858
+ }
66859
+ function readQueue() {
66860
+ try {
66861
+ const raw = readFileSync2(queuePath(), "utf-8");
66862
+ const parsed = JSON.parse(raw);
66863
+ if (!parsed || !Array.isArray(parsed.queue)) {
66864
+ log2(`queue malformed \u2192 treating as empty`);
66865
+ return { queue: [] };
66866
+ }
66867
+ return { queue: parsed.queue };
66868
+ } catch {
66869
+ return { queue: [] };
66870
+ }
66871
+ }
66872
+ function _isQueuePathInsideHome(path2, home) {
66873
+ const r10 = resolve4(path2);
66874
+ const h18 = resolve4(home);
66875
+ return r10.startsWith(h18 + "/") || r10 === h18;
66876
+ }
66877
+ function writeQueue(q17) {
66878
+ const path2 = queuePath();
66879
+ const home = resolve4(homedir3());
66880
+ if (!_isQueuePathInsideHome(path2, home)) {
66881
+ throw new Error(`notifications-queue write blocked: ${path2} is outside ${home}`);
66882
+ }
66883
+ mkdirSync(join6(home, ".deeplake"), { recursive: true, mode: 448 });
66884
+ const tmp = `${path2}.${process.pid}.tmp`;
66885
+ writeFileSync(tmp, JSON.stringify(q17, null, 2), { mode: 384 });
66886
+ renameSync(tmp, path2);
66887
+ }
66888
+ async function withQueueLock(fn4) {
66889
+ const path2 = lockPath();
66890
+ mkdirSync(join6(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
66891
+ let fd = null;
66892
+ for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
66893
+ try {
66894
+ fd = openSync(path2, "wx", 384);
66895
+ break;
66896
+ } catch (e6) {
66897
+ const code = e6.code;
66898
+ if (code !== "EEXIST")
66899
+ throw e6;
66900
+ try {
66901
+ const age = Date.now() - statSync2(path2).mtimeMs;
66902
+ if (age > LOCK_STALE_MS) {
66903
+ unlinkSync(path2);
66904
+ continue;
66905
+ }
66906
+ } catch {
66907
+ }
66908
+ const delay = LOCK_RETRY_BASE_MS * (attempt + 1);
66909
+ await sleep(delay);
66910
+ }
66911
+ }
66912
+ if (fd === null) {
66913
+ log2(`lock acquisition gave up after ${LOCK_RETRY_MAX} attempts \u2014 proceeding unlocked (last-writer-wins)`);
66914
+ return fn4();
66915
+ }
66916
+ try {
66917
+ return fn4();
66918
+ } finally {
66919
+ try {
66920
+ closeSync(fd);
66921
+ } catch {
66922
+ }
66923
+ try {
66924
+ unlinkSync(path2);
66925
+ } catch {
66926
+ }
66927
+ }
66928
+ }
66929
+ function sameDedupKey(a15, b26) {
66930
+ if (a15.id !== b26.id)
66931
+ return false;
66932
+ return JSON.stringify(a15.dedupKey) === JSON.stringify(b26.dedupKey);
66933
+ }
66934
+ async function enqueueNotification(n24) {
66935
+ await withQueueLock(() => {
66936
+ const q17 = readQueue();
66937
+ if (q17.queue.some((existing) => sameDedupKey(existing, n24))) {
66938
+ return;
66939
+ }
66940
+ q17.queue.push(n24);
66941
+ writeQueue(q17);
66942
+ });
66943
+ }
66944
+
66945
+ // dist/src/commands/auth-creds.js
66946
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "node:fs";
66947
+ import { join as join7 } from "node:path";
66948
+ import { homedir as homedir4 } from "node:os";
66949
+ function configDir() {
66950
+ return join7(homedir4(), ".deeplake");
66951
+ }
66952
+ function credsPath() {
66953
+ return join7(configDir(), "credentials.json");
66954
+ }
66955
+ function loadCredentials() {
66956
+ try {
66957
+ return JSON.parse(readFileSync3(credsPath(), "utf-8"));
66958
+ } catch {
66959
+ return null;
66960
+ }
66961
+ }
66962
+
66844
66963
  // dist/src/deeplake-api.js
66845
66964
  var indexMarkerStorePromise = null;
66846
66965
  function getIndexMarkerStore() {
@@ -66848,7 +66967,7 @@ function getIndexMarkerStore() {
66848
66967
  indexMarkerStorePromise = Promise.resolve().then(() => (init_index_marker_store(), index_marker_store_exports));
66849
66968
  return indexMarkerStorePromise;
66850
66969
  }
66851
- var log2 = (msg) => log("sdk", msg);
66970
+ var log3 = (msg) => log("sdk", msg);
66852
66971
  function summarizeSql(sql, maxLen = 220) {
66853
66972
  const compact = sql.replace(/\s+/g, " ").trim();
66854
66973
  return compact.length > maxLen ? `${compact.slice(0, maxLen)}...` : compact;
@@ -66860,7 +66979,38 @@ function traceSql(msg) {
66860
66979
  process.stderr.write(`[deeplake-sql] ${msg}
66861
66980
  `);
66862
66981
  if (process.env.HIVEMIND_DEBUG === "1")
66863
- log2(msg);
66982
+ log3(msg);
66983
+ }
66984
+ var _signalledBalanceExhausted = false;
66985
+ function maybeSignalBalanceExhausted(status, bodyText) {
66986
+ if (status !== 402)
66987
+ return;
66988
+ if (!bodyText.includes("balance_cents"))
66989
+ return;
66990
+ if (_signalledBalanceExhausted)
66991
+ return;
66992
+ _signalledBalanceExhausted = true;
66993
+ log3(`balance exhausted \u2014 enqueuing session-start banner (body=${bodyText.slice(0, 120)})`);
66994
+ enqueueNotification({
66995
+ id: "balance-exhausted",
66996
+ severity: "warn",
66997
+ transient: true,
66998
+ title: "Hivemind credits exhausted \u2014 top up to keep capturing",
66999
+ body: `Sessions are not being saved and memory recall is returning empty. Top up at ${billingUrl()} to restore capture and recall.`,
67000
+ dedupKey: { reason: "balance-zero" }
67001
+ }).catch((e6) => {
67002
+ log3(`enqueue balance-exhausted failed: ${e6 instanceof Error ? e6.message : String(e6)}`);
67003
+ });
67004
+ }
67005
+ function billingUrl() {
67006
+ try {
67007
+ const c15 = loadCredentials();
67008
+ if (c15?.orgName && c15?.workspaceId) {
67009
+ return `https://deeplake.ai/${encodeURIComponent(c15.orgName)}/workspace/${encodeURIComponent(c15.workspaceId)}/billing`;
67010
+ }
67011
+ } catch {
67012
+ }
67013
+ return "https://deeplake.ai";
66864
67014
  }
66865
67015
  var RETRYABLE_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
66866
67016
  var MAX_RETRIES = 3;
@@ -66869,8 +67019,8 @@ var MAX_CONCURRENCY = 5;
66869
67019
  function getQueryTimeoutMs() {
66870
67020
  return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
66871
67021
  }
66872
- function sleep(ms3) {
66873
- return new Promise((resolve5) => setTimeout(resolve5, ms3));
67022
+ function sleep2(ms3) {
67023
+ return new Promise((resolve6) => setTimeout(resolve6, ms3));
66874
67024
  }
66875
67025
  function isTimeoutError(error) {
66876
67026
  const name = error instanceof Error ? error.name.toLowerCase() : "";
@@ -66900,7 +67050,7 @@ var Semaphore = class {
66900
67050
  this.active++;
66901
67051
  return;
66902
67052
  }
66903
- await new Promise((resolve5) => this.waiting.push(resolve5));
67053
+ await new Promise((resolve6) => this.waiting.push(resolve6));
66904
67054
  }
66905
67055
  release() {
66906
67056
  this.active--;
@@ -66971,8 +67121,8 @@ var DeeplakeApi = class {
66971
67121
  lastError = e6 instanceof Error ? e6 : new Error(String(e6));
66972
67122
  if (attempt < MAX_RETRIES) {
66973
67123
  const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
66974
- log2(`query retry ${attempt + 1}/${MAX_RETRIES} (fetch error: ${lastError.message}) in ${delay.toFixed(0)}ms`);
66975
- await sleep(delay);
67124
+ log3(`query retry ${attempt + 1}/${MAX_RETRIES} (fetch error: ${lastError.message}) in ${delay.toFixed(0)}ms`);
67125
+ await sleep2(delay);
66976
67126
  continue;
66977
67127
  }
66978
67128
  throw lastError;
@@ -66988,10 +67138,11 @@ var DeeplakeApi = class {
66988
67138
  const alreadyExists = resp.status === 500 && isDuplicateIndexError(text);
66989
67139
  if (!alreadyExists && attempt < MAX_RETRIES && (RETRYABLE_CODES.has(resp.status) || retryable403)) {
66990
67140
  const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
66991
- log2(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
66992
- await sleep(delay);
67141
+ log3(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
67142
+ await sleep2(delay);
66993
67143
  continue;
66994
67144
  }
67145
+ maybeSignalBalanceExhausted(resp.status, text);
66995
67146
  throw new Error(`Query failed: ${resp.status}: ${text.slice(0, 200)}`);
66996
67147
  }
66997
67148
  throw lastError ?? new Error("Query failed: max retries exceeded");
@@ -67012,7 +67163,7 @@ var DeeplakeApi = class {
67012
67163
  const chunk = rows.slice(i11, i11 + CONCURRENCY);
67013
67164
  await Promise.allSettled(chunk.map((r10) => this.upsertRowSql(r10)));
67014
67165
  }
67015
- log2(`commit: ${rows.length} rows`);
67166
+ log3(`commit: ${rows.length} rows`);
67016
67167
  }
67017
67168
  async upsertRowSql(row) {
67018
67169
  const ts3 = (/* @__PURE__ */ new Date()).toISOString();
@@ -67068,7 +67219,7 @@ var DeeplakeApi = class {
67068
67219
  markers.writeIndexMarker(markerPath);
67069
67220
  return;
67070
67221
  }
67071
- log2(`index "${indexName}" skipped: ${e6.message}`);
67222
+ log3(`index "${indexName}" skipped: ${e6.message}`);
67072
67223
  }
67073
67224
  }
67074
67225
  /**
@@ -67158,13 +67309,13 @@ var DeeplakeApi = class {
67158
67309
  };
67159
67310
  }
67160
67311
  if (attempt < MAX_RETRIES && RETRYABLE_CODES.has(resp.status)) {
67161
- await sleep(BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200);
67312
+ await sleep2(BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200);
67162
67313
  continue;
67163
67314
  }
67164
67315
  return { tables: [], cacheable: false };
67165
67316
  } catch {
67166
67317
  if (attempt < MAX_RETRIES) {
67167
- await sleep(BASE_DELAY_MS * Math.pow(2, attempt));
67318
+ await sleep2(BASE_DELAY_MS * Math.pow(2, attempt));
67168
67319
  continue;
67169
67320
  }
67170
67321
  return { tables: [], cacheable: false };
@@ -67192,9 +67343,9 @@ var DeeplakeApi = class {
67192
67343
  } catch (err) {
67193
67344
  lastErr = err;
67194
67345
  const msg = err instanceof Error ? err.message : String(err);
67195
- log2(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
67346
+ log3(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
67196
67347
  if (attempt < OUTER_BACKOFFS_MS.length) {
67197
- await sleep(OUTER_BACKOFFS_MS[attempt]);
67348
+ await sleep2(OUTER_BACKOFFS_MS[attempt]);
67198
67349
  }
67199
67350
  }
67200
67351
  }
@@ -67205,9 +67356,9 @@ var DeeplakeApi = class {
67205
67356
  const tbl = sqlIdent(name ?? this.tableName);
67206
67357
  const tables = await this.listTables();
67207
67358
  if (!tables.includes(tbl)) {
67208
- log2(`table "${tbl}" not found, creating`);
67359
+ log3(`table "${tbl}" not found, creating`);
67209
67360
  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);
67210
- log2(`table "${tbl}" created`);
67361
+ log3(`table "${tbl}" created`);
67211
67362
  if (!tables.includes(tbl))
67212
67363
  this._tablesCache = [...tables, tbl];
67213
67364
  }
@@ -67220,9 +67371,9 @@ var DeeplakeApi = class {
67220
67371
  const safe = sqlIdent(name);
67221
67372
  const tables = await this.listTables();
67222
67373
  if (!tables.includes(safe)) {
67223
- log2(`table "${safe}" not found, creating`);
67374
+ log3(`table "${safe}" not found, creating`);
67224
67375
  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);
67225
- log2(`table "${safe}" created`);
67376
+ log3(`table "${safe}" created`);
67226
67377
  if (!tables.includes(safe))
67227
67378
  this._tablesCache = [...tables, safe];
67228
67379
  }
@@ -67245,9 +67396,9 @@ var DeeplakeApi = class {
67245
67396
  const safe = sqlIdent(name);
67246
67397
  const tables = await this.listTables();
67247
67398
  if (!tables.includes(safe)) {
67248
- log2(`table "${safe}" not found, creating`);
67399
+ log3(`table "${safe}" not found, creating`);
67249
67400
  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);
67250
- log2(`table "${safe}" created`);
67401
+ log3(`table "${safe}" created`);
67251
67402
  if (!tables.includes(safe))
67252
67403
  this._tablesCache = [...tables, safe];
67253
67404
  }
@@ -67259,7 +67410,7 @@ var DeeplakeApi = class {
67259
67410
  import { basename as basename4, posix } from "node:path";
67260
67411
  import { randomUUID as randomUUID2 } from "node:crypto";
67261
67412
  import { fileURLToPath } from "node:url";
67262
- import { dirname as dirname4, join as join9 } from "node:path";
67413
+ import { dirname as dirname5, join as join12 } from "node:path";
67263
67414
 
67264
67415
  // dist/src/shell/grep-core.js
67265
67416
  var TOOL_INPUT_FIELDS = [
@@ -67689,9 +67840,9 @@ function refineGrepMatches(rows, params, forceMultiFilePrefix) {
67689
67840
  // dist/src/embeddings/client.js
67690
67841
  import { connect } from "node:net";
67691
67842
  import { spawn } from "node:child_process";
67692
- import { openSync, closeSync, writeSync, unlinkSync, existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
67693
- import { homedir as homedir3 } from "node:os";
67694
- import { join as join7 } from "node:path";
67843
+ import { openSync as openSync2, closeSync as closeSync2, writeSync, unlinkSync as unlinkSync3, existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
67844
+ import { homedir as homedir5 } from "node:os";
67845
+ import { join as join9 } from "node:path";
67695
67846
 
67696
67847
  // dist/src/embeddings/protocol.js
67697
67848
  var DEFAULT_SOCKET_DIR = "/tmp";
@@ -67705,12 +67856,13 @@ function pidPathFor(uid, dir = DEFAULT_SOCKET_DIR) {
67705
67856
  }
67706
67857
 
67707
67858
  // dist/src/embeddings/client.js
67708
- var SHARED_DAEMON_PATH = join7(homedir3(), ".hivemind", "embed-deps", "embed-daemon.js");
67709
- var log3 = (m26) => log("embed-client", m26);
67859
+ var SHARED_DAEMON_PATH = join9(homedir5(), ".hivemind", "embed-deps", "embed-daemon.js");
67860
+ var log4 = (m26) => log("embed-client", m26);
67710
67861
  function getUid() {
67711
67862
  const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
67712
67863
  return uid !== void 0 ? String(uid) : process.env.USER ?? "default";
67713
67864
  }
67865
+ var _recycledStuckDaemon = false;
67714
67866
  var EmbedClient = class {
67715
67867
  socketPath;
67716
67868
  pidPath;
@@ -67719,6 +67871,7 @@ var EmbedClient = class {
67719
67871
  autoSpawn;
67720
67872
  spawnWaitMs;
67721
67873
  nextId = 0;
67874
+ helloVerified = false;
67722
67875
  constructor(opts = {}) {
67723
67876
  const uid = getUid();
67724
67877
  const dir = opts.socketDir ?? "/tmp";
@@ -67735,8 +67888,33 @@ var EmbedClient = class {
67735
67888
  *
67736
67889
  * Fire-and-forget spawn on miss: if the daemon isn't up, this call returns
67737
67890
  * null AND kicks off a background spawn. The next call finds a ready daemon.
67891
+ *
67892
+ * Stuck-daemon recycle: if the daemon returns a transformers-missing
67893
+ * error (typical after a marketplace upgrade left an older daemon process
67894
+ * alive but with no node_modules accessible from its bundle path), we
67895
+ * SIGTERM it and clear its sock/pid so the very next call spawns a fresh
67896
+ * daemon from the current bundle. Without this, the stuck daemon would
67897
+ * keep poisoning every session until its 10-minute idle-out fires.
67738
67898
  */
67739
67899
  async embed(text, kind = "document") {
67900
+ const v27 = await this.embedAttempt(text, kind);
67901
+ if (v27 !== "recycled")
67902
+ return v27;
67903
+ if (!this.autoSpawn)
67904
+ return null;
67905
+ this.trySpawnDaemon();
67906
+ await this.waitForDaemonReady();
67907
+ const retry = await this.embedAttempt(text, kind);
67908
+ return retry === "recycled" ? null : retry;
67909
+ }
67910
+ /**
67911
+ * One round-trip: connect → verify → embed. Returns:
67912
+ * - number[] : embedding vector (happy path)
67913
+ * - null : timeout / daemon error / transformers-missing
67914
+ * - "recycled": verifyDaemonOnce killed the daemon mid-call;
67915
+ * caller should respawn and retry once.
67916
+ */
67917
+ async embedAttempt(text, kind) {
67740
67918
  let sock;
67741
67919
  try {
67742
67920
  sock = await this.connectOnce();
@@ -67746,17 +67924,25 @@ var EmbedClient = class {
67746
67924
  return null;
67747
67925
  }
67748
67926
  try {
67927
+ const recycled = await this.verifyDaemonOnce(sock);
67928
+ if (recycled) {
67929
+ return "recycled";
67930
+ }
67749
67931
  const id = String(++this.nextId);
67750
67932
  const req = { op: "embed", id, kind, text };
67751
67933
  const resp = await this.sendAndWait(sock, req);
67752
67934
  if (resp.error || !("embedding" in resp) || !resp.embedding) {
67753
- log3(`embed err: ${resp.error ?? "no embedding"}`);
67935
+ const err = resp.error ?? "no embedding";
67936
+ log4(`embed err: ${err}`);
67937
+ if (isTransformersMissingError(err)) {
67938
+ this.handleTransformersMissing(err);
67939
+ }
67754
67940
  return null;
67755
67941
  }
67756
67942
  return resp.embedding;
67757
67943
  } catch (e6) {
67758
67944
  const err = e6 instanceof Error ? e6.message : String(e6);
67759
- log3(`embed failed: ${err}`);
67945
+ log4(`embed failed: ${err}`);
67760
67946
  return null;
67761
67947
  } finally {
67762
67948
  try {
@@ -67765,6 +67951,123 @@ var EmbedClient = class {
67765
67951
  }
67766
67952
  }
67767
67953
  }
67954
+ /**
67955
+ * Poll for the sock file to come back after `trySpawnDaemon` — used by
67956
+ * the recycle retry path. Best-effort: caps at `spawnWaitMs` and
67957
+ * returns regardless so the retry attempt can run.
67958
+ */
67959
+ async waitForDaemonReady() {
67960
+ const deadline = Date.now() + this.spawnWaitMs;
67961
+ while (Date.now() < deadline) {
67962
+ if (existsSync4(this.socketPath))
67963
+ return;
67964
+ await new Promise((r10) => setTimeout(r10, 50));
67965
+ }
67966
+ }
67967
+ /**
67968
+ * Send a `hello` on first successful connect per EmbedClient instance.
67969
+ * If the daemon answers with a path that doesn't match our configured
67970
+ * daemonEntry — typical after a marketplace upgrade replaced the bundle
67971
+ * — SIGTERM the daemon + clear sock/pid so the next call spawns from the
67972
+ * current bundle.
67973
+ *
67974
+ * `helloVerified` is set ONLY after we've seen a compatible response,
67975
+ * so a transient probe failure or a recycle-triggering mismatch leaves
67976
+ * the flag false; the next reconnect re-runs verification against
67977
+ * whatever daemon is then live (typically the fresh spawn).
67978
+ */
67979
+ async verifyDaemonOnce(sock) {
67980
+ if (this.helloVerified)
67981
+ return false;
67982
+ if (!this.daemonEntry) {
67983
+ this.helloVerified = true;
67984
+ return false;
67985
+ }
67986
+ const id = String(++this.nextId);
67987
+ const req = { op: "hello", id };
67988
+ let resp;
67989
+ try {
67990
+ resp = await this.sendAndWait(sock, req);
67991
+ } catch (e6) {
67992
+ log4(`hello probe failed (inconclusive, will retry next connect): ${e6 instanceof Error ? e6.message : String(e6)}`);
67993
+ return false;
67994
+ }
67995
+ const hello = resp;
67996
+ if (_recycledStuckDaemon) {
67997
+ return false;
67998
+ }
67999
+ if (!hello.daemonPath) {
68000
+ _recycledStuckDaemon = true;
68001
+ log4(`daemon does not implement hello (older protocol); recycling`);
68002
+ this.recycleDaemon(hello.pid);
68003
+ return true;
68004
+ }
68005
+ if (hello.daemonPath !== this.daemonEntry && !existsSync4(hello.daemonPath)) {
68006
+ _recycledStuckDaemon = true;
68007
+ log4(`daemon path no longer on disk \u2014 running=${hello.daemonPath} (gone) expected=${this.daemonEntry}; recycling`);
68008
+ this.recycleDaemon(hello.pid);
68009
+ return true;
68010
+ }
68011
+ this.helloVerified = true;
68012
+ return false;
68013
+ }
68014
+ /**
68015
+ * On a transformers-missing error from the daemon, SIGTERM the stuck
68016
+ * daemon (the bundle daemon that can't find its deps) and clear
68017
+ * sock/pid so the next call spawns fresh.
68018
+ *
68019
+ * Previously this also enqueued a user-visible "Hivemind embeddings
68020
+ * disabled — deps missing" notification telling the user to run
68021
+ * `hivemind embeddings install`. The notification was removed because
68022
+ * (a) the recycle alone often fixes the issue silently, and (b) the
68023
+ * warning kept stacking on top of the primary session-start banner
68024
+ * which clashed with the single-slot priority model. The `detail`
68025
+ * argument is retained for future telemetry / debug logging.
68026
+ */
68027
+ handleTransformersMissing(_detail) {
68028
+ if (!_recycledStuckDaemon) {
68029
+ _recycledStuckDaemon = true;
68030
+ this.recycleDaemon(null);
68031
+ }
68032
+ }
68033
+ /**
68034
+ * Best-effort SIGTERM + sock/pid cleanup. Tolerant of every missing-file
68035
+ * combination and dead-PID cases.
68036
+ *
68037
+ * Identity check: gate the SIGTERM on the daemon's socket file still
68038
+ * existing. We know the daemon was alive moments ago (we either just
68039
+ * got a hello response or the caller saw a transformers-missing error
68040
+ * the daemon emitted), but if the socket file is gone by the time we
68041
+ * try to kill, the daemon process is also gone and the PID we
68042
+ * captured may already have been recycled by the OS to an unrelated
68043
+ * user process. Mirrors the gate added to `killEmbedDaemon` in the
68044
+ * CLI — same failure mode, rarer trigger.
68045
+ */
68046
+ recycleDaemon(reportedPid) {
68047
+ let pid = reportedPid;
68048
+ if (pid === null) {
68049
+ try {
68050
+ pid = Number.parseInt(readFileSync5(this.pidPath, "utf-8").trim(), 10);
68051
+ } catch {
68052
+ }
68053
+ }
68054
+ if (Number.isFinite(pid) && pid !== null && pid > 0 && existsSync4(this.socketPath)) {
68055
+ try {
68056
+ process.kill(pid, "SIGTERM");
68057
+ } catch {
68058
+ }
68059
+ } else if (pid !== null) {
68060
+ log4(`recycle: socket gone, skipping SIGTERM on possibly-stale pid ${pid}`);
68061
+ }
68062
+ try {
68063
+ unlinkSync3(this.socketPath);
68064
+ } catch {
68065
+ }
68066
+ try {
68067
+ unlinkSync3(this.pidPath);
68068
+ } catch {
68069
+ }
68070
+ }
67768
68071
  /**
67769
68072
  * Wait up to spawnWaitMs for the daemon to accept connections, spawning if
67770
68073
  * necessary. Meant for SessionStart / long-running batches — not the hot path.
@@ -67788,7 +68091,7 @@ var EmbedClient = class {
67788
68091
  }
67789
68092
  }
67790
68093
  connectOnce() {
67791
- return new Promise((resolve5, reject) => {
68094
+ return new Promise((resolve6, reject) => {
67792
68095
  const sock = connect(this.socketPath);
67793
68096
  const to3 = setTimeout(() => {
67794
68097
  sock.destroy();
@@ -67796,7 +68099,7 @@ var EmbedClient = class {
67796
68099
  }, this.timeoutMs);
67797
68100
  sock.once("connect", () => {
67798
68101
  clearTimeout(to3);
67799
- resolve5(sock);
68102
+ resolve6(sock);
67800
68103
  });
67801
68104
  sock.once("error", (e6) => {
67802
68105
  clearTimeout(to3);
@@ -67807,16 +68110,16 @@ var EmbedClient = class {
67807
68110
  trySpawnDaemon() {
67808
68111
  let fd;
67809
68112
  try {
67810
- fd = openSync(this.pidPath, "wx", 384);
68113
+ fd = openSync2(this.pidPath, "wx", 384);
67811
68114
  writeSync(fd, String(process.pid));
67812
68115
  } catch (e6) {
67813
68116
  if (this.isPidFileStale()) {
67814
68117
  try {
67815
- unlinkSync(this.pidPath);
68118
+ unlinkSync3(this.pidPath);
67816
68119
  } catch {
67817
68120
  }
67818
68121
  try {
67819
- fd = openSync(this.pidPath, "wx", 384);
68122
+ fd = openSync2(this.pidPath, "wx", 384);
67820
68123
  writeSync(fd, String(process.pid));
67821
68124
  } catch {
67822
68125
  return;
@@ -67826,10 +68129,10 @@ var EmbedClient = class {
67826
68129
  }
67827
68130
  }
67828
68131
  if (!this.daemonEntry || !existsSync4(this.daemonEntry)) {
67829
- log3(`daemonEntry not configured or missing: ${this.daemonEntry}`);
68132
+ log4(`daemonEntry not configured or missing: ${this.daemonEntry}`);
67830
68133
  try {
67831
- closeSync(fd);
67832
- unlinkSync(this.pidPath);
68134
+ closeSync2(fd);
68135
+ unlinkSync3(this.pidPath);
67833
68136
  } catch {
67834
68137
  }
67835
68138
  return;
@@ -67841,14 +68144,14 @@ var EmbedClient = class {
67841
68144
  env: process.env
67842
68145
  });
67843
68146
  child.unref();
67844
- log3(`spawned daemon pid=${child.pid}`);
68147
+ log4(`spawned daemon pid=${child.pid}`);
67845
68148
  } finally {
67846
- closeSync(fd);
68149
+ closeSync2(fd);
67847
68150
  }
67848
68151
  }
67849
68152
  isPidFileStale() {
67850
68153
  try {
67851
- const raw = readFileSync3(this.pidPath, "utf-8").trim();
68154
+ const raw = readFileSync5(this.pidPath, "utf-8").trim();
67852
68155
  const pid = Number(raw);
67853
68156
  if (!pid || Number.isNaN(pid))
67854
68157
  return true;
@@ -67866,7 +68169,7 @@ var EmbedClient = class {
67866
68169
  const deadline = Date.now() + this.spawnWaitMs;
67867
68170
  let delay = 30;
67868
68171
  while (Date.now() < deadline) {
67869
- await sleep2(delay);
68172
+ await sleep3(delay);
67870
68173
  delay = Math.min(delay * 1.5, 300);
67871
68174
  if (!existsSync4(this.socketPath))
67872
68175
  continue;
@@ -67878,7 +68181,7 @@ var EmbedClient = class {
67878
68181
  throw new Error("daemon did not become ready within spawnWaitMs");
67879
68182
  }
67880
68183
  sendAndWait(sock, req) {
67881
- return new Promise((resolve5, reject) => {
68184
+ return new Promise((resolve6, reject) => {
67882
68185
  let buf = "";
67883
68186
  const to3 = setTimeout(() => {
67884
68187
  sock.destroy();
@@ -67893,7 +68196,7 @@ var EmbedClient = class {
67893
68196
  const line = buf.slice(0, nl3);
67894
68197
  clearTimeout(to3);
67895
68198
  try {
67896
- resolve5(JSON.parse(line));
68199
+ resolve6(JSON.parse(line));
67897
68200
  } catch (e6) {
67898
68201
  reject(e6);
67899
68202
  }
@@ -67910,9 +68213,14 @@ var EmbedClient = class {
67910
68213
  });
67911
68214
  }
67912
68215
  };
67913
- function sleep2(ms3) {
68216
+ function sleep3(ms3) {
67914
68217
  return new Promise((r10) => setTimeout(r10, ms3));
67915
68218
  }
68219
+ function isTransformersMissingError(err) {
68220
+ if (/hivemind embeddings install/i.test(err))
68221
+ return true;
68222
+ return /@huggingface\/transformers/i.test(err);
68223
+ }
67916
68224
 
67917
68225
  // dist/src/embeddings/sql.js
67918
68226
  function embeddingSqlLiteral(vec) {
@@ -67929,23 +68237,105 @@ function embeddingSqlLiteral(vec) {
67929
68237
 
67930
68238
  // dist/src/embeddings/disable.js
67931
68239
  import { createRequire } from "node:module";
67932
- import { homedir as homedir4 } from "node:os";
67933
- import { join as join8 } from "node:path";
68240
+ import { homedir as homedir7 } from "node:os";
68241
+ import { join as join11 } from "node:path";
67934
68242
  import { pathToFileURL } from "node:url";
68243
+
68244
+ // dist/src/user-config.js
68245
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
68246
+ import { homedir as homedir6 } from "node:os";
68247
+ import { dirname as dirname4, join as join10 } from "node:path";
68248
+ var _configPath = () => process.env.HIVEMIND_CONFIG_PATH ?? join10(homedir6(), ".deeplake", "config.json");
68249
+ var _cache = null;
68250
+ var _migrated = false;
68251
+ function readUserConfig() {
68252
+ if (_cache !== null)
68253
+ return _cache;
68254
+ const path2 = _configPath();
68255
+ if (!existsSync5(path2)) {
68256
+ _cache = {};
68257
+ return _cache;
68258
+ }
68259
+ try {
68260
+ const raw = readFileSync6(path2, "utf-8");
68261
+ const parsed = JSON.parse(raw);
68262
+ _cache = isPlainObject(parsed) ? parsed : {};
68263
+ } catch {
68264
+ _cache = {};
68265
+ }
68266
+ return _cache;
68267
+ }
68268
+ function writeUserConfig(patch) {
68269
+ const current = readUserConfig();
68270
+ const merged = deepMerge(current, patch);
68271
+ const path2 = _configPath();
68272
+ const dir = dirname4(path2);
68273
+ if (!existsSync5(dir))
68274
+ mkdirSync4(dir, { recursive: true });
68275
+ const tmp = `${path2}.tmp.${process.pid}`;
68276
+ writeFileSync4(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
68277
+ renameSync2(tmp, path2);
68278
+ _cache = merged;
68279
+ return merged;
68280
+ }
68281
+ function getEmbeddingsEnabled() {
68282
+ const cfg = readUserConfig();
68283
+ if (cfg.embeddings && typeof cfg.embeddings.enabled === "boolean") {
68284
+ return cfg.embeddings.enabled;
68285
+ }
68286
+ if (_migrated) {
68287
+ return migrationValueFromEnv();
68288
+ }
68289
+ _migrated = true;
68290
+ const enabled = migrationValueFromEnv();
68291
+ try {
68292
+ writeUserConfig({ embeddings: { enabled } });
68293
+ } catch {
68294
+ _cache = { ...cfg ?? {}, embeddings: { ...cfg?.embeddings ?? {}, enabled } };
68295
+ }
68296
+ return enabled;
68297
+ }
68298
+ function migrationValueFromEnv() {
68299
+ const raw = process.env.HIVEMIND_EMBEDDINGS;
68300
+ if (raw === void 0)
68301
+ return false;
68302
+ if (raw === "false")
68303
+ return false;
68304
+ return true;
68305
+ }
68306
+ function isPlainObject(value) {
68307
+ return typeof value === "object" && value !== null && !Array.isArray(value);
68308
+ }
68309
+ function deepMerge(base, patch) {
68310
+ const out = { ...base };
68311
+ for (const key of Object.keys(patch)) {
68312
+ const patchVal = patch[key];
68313
+ const baseVal = base[key];
68314
+ if (isPlainObject(patchVal) && isPlainObject(baseVal)) {
68315
+ out[key] = { ...baseVal, ...patchVal };
68316
+ } else if (patchVal !== void 0) {
68317
+ out[key] = patchVal;
68318
+ }
68319
+ }
68320
+ return out;
68321
+ }
68322
+
68323
+ // dist/src/embeddings/disable.js
67935
68324
  var cachedStatus = null;
67936
68325
  function defaultResolveTransformers() {
68326
+ const sharedDir = join11(homedir7(), ".hivemind", "embed-deps");
67937
68327
  try {
67938
- createRequire(import.meta.url).resolve("@huggingface/transformers");
68328
+ createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
67939
68329
  return;
67940
68330
  } catch {
67941
68331
  }
67942
- const sharedDir = join8(homedir4(), ".hivemind", "embed-deps");
67943
- createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
68332
+ createRequire(import.meta.url).resolve("@huggingface/transformers");
67944
68333
  }
67945
68334
  var _resolve = defaultResolveTransformers;
68335
+ var _readEnabled = getEmbeddingsEnabled;
67946
68336
  function detectStatus() {
67947
- if (process.env.HIVEMIND_EMBEDDINGS === "false")
67948
- return "env-disabled";
68337
+ if (!_readEnabled())
68338
+ return "user-disabled";
67949
68339
  try {
67950
68340
  _resolve();
67951
68341
  return "enabled";
@@ -68055,7 +68445,7 @@ function normalizeSessionMessage(path2, message) {
68055
68445
  return normalizeContent(path2, raw);
68056
68446
  }
68057
68447
  function resolveEmbedDaemonPath() {
68058
- return join9(dirname4(fileURLToPath(import.meta.url)), "embeddings", "embed-daemon.js");
68448
+ return join12(dirname5(fileURLToPath(import.meta.url)), "..", "embeddings", "embed-daemon.js");
68059
68449
  }
68060
68450
  function joinSessionMessages(path2, messages) {
68061
68451
  return messages.map((message) => normalizeSessionMessage(path2, message)).join("\n");
@@ -68621,7 +69011,7 @@ var DeeplakeFs = class _DeeplakeFs {
68621
69011
 
68622
69012
  // node_modules/yargs-parser/build/lib/index.js
68623
69013
  import { format } from "util";
68624
- import { normalize, resolve as resolve4 } from "path";
69014
+ import { normalize, resolve as resolve5 } from "path";
68625
69015
 
68626
69016
  // node_modules/yargs-parser/build/lib/string-utils.js
68627
69017
  function camelCase2(str) {
@@ -69559,7 +69949,7 @@ function stripQuotes(val) {
69559
69949
  }
69560
69950
 
69561
69951
  // node_modules/yargs-parser/build/lib/index.js
69562
- import { readFileSync as readFileSync4 } from "fs";
69952
+ import { readFileSync as readFileSync7 } from "fs";
69563
69953
  import { createRequire as createRequire2 } from "node:module";
69564
69954
  var _a3;
69565
69955
  var _b;
@@ -69581,12 +69971,12 @@ var parser = new YargsParser({
69581
69971
  },
69582
69972
  format,
69583
69973
  normalize,
69584
- resolve: resolve4,
69974
+ resolve: resolve5,
69585
69975
  require: (path2) => {
69586
69976
  if (typeof require2 !== "undefined") {
69587
69977
  return require2(path2);
69588
69978
  } else if (path2.match(/\.json$/)) {
69589
- return JSON.parse(readFileSync4(path2, "utf8"));
69979
+ return JSON.parse(readFileSync7(path2, "utf8"));
69590
69980
  } else {
69591
69981
  throw Error("only .json config files are supported in ESM");
69592
69982
  }
@@ -69606,11 +69996,11 @@ var lib_default = yargsParser;
69606
69996
 
69607
69997
  // dist/src/shell/grep-interceptor.js
69608
69998
  import { fileURLToPath as fileURLToPath2 } from "node:url";
69609
- import { dirname as dirname5, join as join10 } from "node:path";
69999
+ import { dirname as dirname6, join as join13 } from "node:path";
69610
70000
  var SEMANTIC_SEARCH_ENABLED = process.env.HIVEMIND_SEMANTIC_SEARCH !== "false" && !embeddingsDisabled();
69611
70001
  var SEMANTIC_EMBED_TIMEOUT_MS = Number(process.env.HIVEMIND_SEMANTIC_EMBED_TIMEOUT_MS ?? "500");
69612
70002
  function resolveGrepEmbedDaemonPath() {
69613
- return join10(dirname5(fileURLToPath2(import.meta.url)), "..", "embeddings", "embed-daemon.js");
70003
+ return join13(dirname6(fileURLToPath2(import.meta.url)), "..", "embeddings", "embed-daemon.js");
69614
70004
  }
69615
70005
  var sharedGrepEmbedClient = null;
69616
70006
  function getGrepEmbedClient() {