@deeplake/hivemind 0.7.29 → 0.7.30

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.
@@ -6,13 +6,13 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Cloud-backed persistent shared memory for AI agents powered by Deeplake",
9
- "version": "0.7.29"
9
+ "version": "0.7.30"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "hivemind",
14
14
  "description": "Persistent shared memory powered by Deeplake — captures all session activity and provides cross-session, cross-agent memory search",
15
- "version": "0.7.29",
15
+ "version": "0.7.30",
16
16
  "source": "./claude-code",
17
17
  "homepage": "https://github.com/activeloopai/hivemind"
18
18
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hivemind",
3
3
  "description": "Cloud-backed persistent memory powered by Deeplake — read, write, and share memory across Claude Code sessions and agents",
4
- "version": "0.7.29",
4
+ "version": "0.7.30",
5
5
  "author": {
6
6
  "name": "Activeloop",
7
7
  "url": "https://deeplake.ai"
@@ -1036,7 +1036,10 @@ import {
1036
1036
  closeSync as fsClose,
1037
1037
  writeFileSync as fsWriteFile,
1038
1038
  constants as fsConstants,
1039
- renameSync as fsRename
1039
+ readFileSync as fsReadFile,
1040
+ renameSync as fsRename,
1041
+ unlinkSync as fsUnlink,
1042
+ statSync as fsStat
1040
1043
  } from "node:fs";
1041
1044
  import { createHash } from "node:crypto";
1042
1045
  import { createRequire } from "node:module";
@@ -1108,7 +1111,7 @@ function extractLatestVersion(body) {
1108
1111
  return typeof v === "string" && v.length > 0 ? v : null;
1109
1112
  }
1110
1113
  function getInstalledVersion() {
1111
- return "0.7.29".length > 0 ? "0.7.29" : null;
1114
+ return "0.7.30".length > 0 ? "0.7.30" : null;
1112
1115
  }
1113
1116
  function isNewer(latest, current) {
1114
1117
  const parse = (v) => v.replace(/-.*$/, "").split(".").map(Number);
@@ -1211,6 +1214,7 @@ var skillsTable = "skills";
1211
1214
  var captureEnabled = true;
1212
1215
  var capturedCounts = /* @__PURE__ */ new Map();
1213
1216
  var fallbackSessionId = crypto.randomUUID();
1217
+ var skillifySpawnedFor = /* @__PURE__ */ new Set();
1214
1218
  var __openclaw_filename = fileURLToPath(import.meta.url);
1215
1219
  var __openclaw_dirname = dirnamePath(__openclaw_filename);
1216
1220
  var OPENCLAW_SKILLIFY_WORKER_PATH = joinPath(__openclaw_dirname, "skillify-worker.js");
@@ -1235,14 +1239,51 @@ function deriveOpenclawProjectKey(channel) {
1235
1239
  const key = createHash("sha1").update(project).digest("hex").slice(0, 16);
1236
1240
  return { key, project };
1237
1241
  }
1242
+ var LOCK_MAX_AGE_MS = 10 * 60 * 1e3;
1238
1243
  function tryAcquireOpenclawSkillifyLock(projectKey) {
1239
1244
  try {
1240
1245
  migrateOpenclawSkillifyLegacyStateDir();
1241
1246
  fsMkdir(OPENCLAW_SKILLIFY_STATE_DIR, { recursive: true });
1242
1247
  const lockPath = joinPath(OPENCLAW_SKILLIFY_STATE_DIR, `${projectKey}.worker.lock`);
1243
- const fd = fsOpen(lockPath, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY);
1244
- fsClose(fd);
1245
- return true;
1248
+ const acquire = () => {
1249
+ const fd = fsOpen(lockPath, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY);
1250
+ try {
1251
+ fsWriteFile(fd, String(Date.now()));
1252
+ } finally {
1253
+ fsClose(fd);
1254
+ }
1255
+ return true;
1256
+ };
1257
+ try {
1258
+ return acquire();
1259
+ } catch {
1260
+ try {
1261
+ const body = fsReadFile(lockPath, "utf-8");
1262
+ const ts = Number.parseInt(body.trim(), 10);
1263
+ const ageByBody = Number.isFinite(ts) ? Date.now() - ts : Number.POSITIVE_INFINITY;
1264
+ let ageByMtime = 0;
1265
+ try {
1266
+ ageByMtime = Date.now() - fsStat(lockPath).mtimeMs;
1267
+ } catch {
1268
+ ageByMtime = 0;
1269
+ }
1270
+ const effectiveAge = Number.isFinite(ts) ? ageByBody : ageByMtime;
1271
+ if (effectiveAge > LOCK_MAX_AGE_MS) {
1272
+ try {
1273
+ fsUnlink(lockPath);
1274
+ } catch {
1275
+ }
1276
+ try {
1277
+ return acquire();
1278
+ } catch {
1279
+ return false;
1280
+ }
1281
+ }
1282
+ return false;
1283
+ } catch {
1284
+ return false;
1285
+ }
1286
+ }
1246
1287
  } catch {
1247
1288
  return false;
1248
1289
  }
@@ -1267,23 +1308,23 @@ function detectOpenclawGateAgent() {
1267
1308
  function spawnOpenclawSkillifyWorker(a) {
1268
1309
  if (!fsExists(OPENCLAW_SKILLIFY_WORKER_PATH)) {
1269
1310
  a.loggerWarn?.(`skillify worker missing at ${OPENCLAW_SKILLIFY_WORKER_PATH} \u2014 reinstall openclaw plugin`);
1270
- return;
1311
+ return false;
1271
1312
  }
1272
1313
  const gateAgent = detectOpenclawGateAgent();
1273
1314
  if (!gateAgent) {
1274
1315
  a.loggerWarn?.(`skillify spawn: no delegate gate CLI found on PATH (need one of: claude, codex, cursor-agent, hermes, pi). Mining skipped.`);
1275
- return;
1316
+ return false;
1276
1317
  }
1277
1318
  const { key: projectKey, project } = deriveOpenclawProjectKey(a.channel);
1278
1319
  if (!tryAcquireOpenclawSkillifyLock(projectKey)) {
1279
- return;
1320
+ return false;
1280
1321
  }
1281
1322
  const tmpDir = joinPath(tmpdir(), `deeplake-skillify-openclaw-${projectKey}-${Date.now()}`);
1282
1323
  try {
1283
1324
  fsMkdir(tmpDir, { recursive: true, mode: 448 });
1284
1325
  } catch (e) {
1285
1326
  a.loggerWarn?.(`skillify spawn: mkdir failed: ${e?.message ?? e}`);
1286
- return;
1327
+ return false;
1287
1328
  }
1288
1329
  const configPath = joinPath(tmpDir, "config.json");
1289
1330
  const config = {
@@ -1326,7 +1367,7 @@ function spawnOpenclawSkillifyWorker(a) {
1326
1367
  fsWriteFile(configPath, JSON.stringify(config), { mode: 384 });
1327
1368
  } catch (e) {
1328
1369
  a.loggerWarn?.(`skillify spawn: config write failed: ${e?.message ?? e}`);
1329
- return;
1370
+ return false;
1330
1371
  }
1331
1372
  try {
1332
1373
  realSpawn(process.execPath, [OPENCLAW_SKILLIFY_WORKER_PATH, configPath], {
@@ -1334,8 +1375,10 @@ function spawnOpenclawSkillifyWorker(a) {
1334
1375
  stdio: "ignore",
1335
1376
  env: { ...inheritedEnv.env, HIVEMIND_SKILLIFY_WORKER: "1", HIVEMIND_CAPTURE: "false" }
1336
1377
  }).unref();
1378
+ return true;
1337
1379
  } catch (e) {
1338
1380
  a.loggerWarn?.(`skillify spawn: spawn failed: ${e?.message ?? e}`);
1381
+ return false;
1339
1382
  }
1340
1383
  }
1341
1384
  function buildSessionPath(config, sessionId) {
@@ -1939,23 +1982,27 @@ One brain for every agent on your team.
1939
1982
  }
1940
1983
  }
1941
1984
  logger.info?.(`Auto-captured ${newMessages.length} messages`);
1942
- try {
1943
- spawnOpenclawSkillifyWorker({
1944
- apiUrl: cfg.apiUrl,
1945
- token: cfg.token,
1946
- orgId: cfg.orgId,
1947
- workspaceId: cfg.workspaceId,
1948
- userName: cfg.userName,
1949
- channel: ev.channel || "openclaw",
1950
- sessionId: sid,
1951
- loggerWarn: (msg) => logger.error(`Skillify spawn: ${msg}`),
1952
- // Pass the same tuning dispatch the plugin populated at
1953
- // register-time. The worker will repopulate its own
1954
- // globalThis from this.
1955
- tuning: globalThis.__hivemind_tuning__
1956
- });
1957
- } catch (e) {
1958
- logger.error(`Skillify spawn threw: ${e?.message ?? e}`);
1985
+ if (!skillifySpawnedFor.has(sid)) {
1986
+ try {
1987
+ if (spawnOpenclawSkillifyWorker({
1988
+ apiUrl: cfg.apiUrl,
1989
+ token: cfg.token,
1990
+ orgId: cfg.orgId,
1991
+ workspaceId: cfg.workspaceId,
1992
+ userName: cfg.userName,
1993
+ channel: ev.channel || "openclaw",
1994
+ sessionId: sid,
1995
+ loggerWarn: (msg) => logger.error(`Skillify spawn: ${msg}`),
1996
+ // Pass the same tuning dispatch the plugin populated at
1997
+ // register-time. The worker will repopulate its own
1998
+ // globalThis from this.
1999
+ tuning: globalThis.__hivemind_tuning__
2000
+ })) {
2001
+ skillifySpawnedFor.add(sid);
2002
+ }
2003
+ } catch (e) {
2004
+ logger.error(`Skillify spawn threw: ${e?.message ?? e}`);
2005
+ }
1959
2006
  }
1960
2007
  } catch (err) {
1961
2008
  logger.error(`Auto-capture failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -52,5 +52,5 @@
52
52
  }
53
53
  }
54
54
  },
55
- "version": "0.7.29"
55
+ "version": "0.7.30"
56
56
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hivemind",
3
- "version": "0.7.29",
3
+ "version": "0.7.30",
4
4
  "type": "module",
5
5
  "description": "Hivemind — cloud-backed persistent shared memory for AI agents, powered by DeepLake",
6
6
  "license": "Apache-2.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeplake/hivemind",
3
- "version": "0.7.29",
3
+ "version": "0.7.30",
4
4
  "description": "Cloud-backed persistent shared memory for AI agents powered by Deeplake",
5
5
  "type": "module",
6
6
  "repository": {