@deeplake/hivemind 0.7.79 → 0.7.81

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 (46) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/bundle/cli.js +140 -94
  4. package/codex/bundle/capture.js +232 -72
  5. package/codex/bundle/commands/auth-login.js +14 -10
  6. package/codex/bundle/embeddings/embed-daemon.js +9 -5
  7. package/codex/bundle/graph-on-stop.js +32 -28
  8. package/codex/bundle/graph-pull-worker.js +27 -23
  9. package/codex/bundle/pre-tool-use.js +366 -123
  10. package/codex/bundle/session-start-setup.js +18 -14
  11. package/codex/bundle/session-start.js +26 -22
  12. package/codex/bundle/shell/deeplake-shell.js +30 -26
  13. package/codex/bundle/skillify-worker.js +14 -10
  14. package/codex/bundle/skillopt-worker.js +2061 -0
  15. package/codex/bundle/stop.js +50 -45
  16. package/codex/bundle/wiki-worker.js +18 -14
  17. package/cursor/bundle/capture.js +71 -44
  18. package/cursor/bundle/commands/auth-login.js +14 -10
  19. package/cursor/bundle/embeddings/embed-daemon.js +9 -5
  20. package/cursor/bundle/graph-on-stop.js +32 -28
  21. package/cursor/bundle/graph-pull-worker.js +27 -23
  22. package/cursor/bundle/pre-tool-use.js +28 -24
  23. package/cursor/bundle/session-end.js +40 -36
  24. package/cursor/bundle/session-start.js +39 -35
  25. package/cursor/bundle/shell/deeplake-shell.js +30 -26
  26. package/cursor/bundle/skillify-worker.js +14 -10
  27. package/cursor/bundle/wiki-worker.js +18 -14
  28. package/hermes/bundle/capture.js +235 -85
  29. package/hermes/bundle/commands/auth-login.js +14 -10
  30. package/hermes/bundle/embeddings/embed-daemon.js +9 -5
  31. package/hermes/bundle/graph-on-stop.js +32 -28
  32. package/hermes/bundle/graph-pull-worker.js +27 -23
  33. package/hermes/bundle/pre-tool-use.js +298 -74
  34. package/hermes/bundle/session-end.js +40 -36
  35. package/hermes/bundle/session-start.js +39 -35
  36. package/hermes/bundle/shell/deeplake-shell.js +30 -26
  37. package/hermes/bundle/skillify-worker.js +14 -10
  38. package/hermes/bundle/skillopt-worker.js +2061 -0
  39. package/hermes/bundle/wiki-worker.js +18 -14
  40. package/mcp/bundle/server.js +15 -11
  41. package/openclaw/dist/index.js +11 -7
  42. package/openclaw/dist/skillify-worker.js +14 -10
  43. package/openclaw/openclaw.plugin.json +1 -1
  44. package/openclaw/package.json +1 -1
  45. package/package.json +1 -1
  46. package/pi/extension-source/hivemind.ts +93 -0
@@ -16,7 +16,7 @@ __export(index_marker_store_exports, {
16
16
  hasFreshIndexMarker: () => hasFreshIndexMarker,
17
17
  writeIndexMarker: () => writeIndexMarker
18
18
  });
19
- import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
19
+ import { existsSync as existsSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
20
20
  import { join as join5 } from "node:path";
21
21
  import { tmpdir } from "node:os";
22
22
  function getIndexMarkerDir() {
@@ -40,7 +40,7 @@ function hasFreshIndexMarker(markerPath) {
40
40
  }
41
41
  }
42
42
  function writeIndexMarker(markerPath) {
43
- mkdirSync3(getIndexMarkerDir(), { recursive: true });
43
+ mkdirSync4(getIndexMarkerDir(), { recursive: true });
44
44
  writeFileSync3(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
45
45
  }
46
46
  var INDEX_MARKER_TTL_MS;
@@ -119,8 +119,8 @@ function loadConfig() {
119
119
  import { randomUUID } from "node:crypto";
120
120
 
121
121
  // dist/src/utils/debug.js
122
- import { appendFileSync } from "node:fs";
123
- import { join as join2 } from "node:path";
122
+ import { appendFileSync, mkdirSync } from "node:fs";
123
+ import { dirname, join as join2 } from "node:path";
124
124
  import { homedir as homedir2 } from "node:os";
125
125
  var LOG = join2(homedir2(), ".deeplake", "hook-debug.log");
126
126
  function isDebug() {
@@ -132,8 +132,12 @@ function utcTimestamp(d = /* @__PURE__ */ new Date()) {
132
132
  function log(tag, msg) {
133
133
  if (!isDebug())
134
134
  return;
135
- appendFileSync(LOG, `${(/* @__PURE__ */ new Date()).toISOString()} [${tag}] ${msg}
135
+ try {
136
+ mkdirSync(dirname(LOG), { recursive: true });
137
+ appendFileSync(LOG, `${(/* @__PURE__ */ new Date()).toISOString()} [${tag}] ${msg}
136
138
  `);
139
+ } catch {
140
+ }
137
141
  }
138
142
 
139
143
  // dist/src/utils/sql.js
@@ -339,7 +343,7 @@ async function healMissingColumns(args) {
339
343
  }
340
344
 
341
345
  // dist/src/notifications/queue.js
342
- import { readFileSync as readFileSync2, writeFileSync, renameSync, mkdirSync, openSync, closeSync, unlinkSync, statSync } from "node:fs";
346
+ import { readFileSync as readFileSync2, writeFileSync, renameSync, mkdirSync as mkdirSync2, openSync, closeSync, unlinkSync, statSync } from "node:fs";
343
347
  import { join as join3, resolve } from "node:path";
344
348
  import { homedir as homedir3 } from "node:os";
345
349
  import { setTimeout as sleep } from "node:timers/promises";
@@ -366,38 +370,38 @@ function readQueue() {
366
370
  return { queue: [] };
367
371
  }
368
372
  }
369
- function _isQueuePathInsideHome(path, home) {
370
- const r = resolve(path);
373
+ function _isQueuePathInsideHome(path2, home) {
374
+ const r = resolve(path2);
371
375
  const h = resolve(home);
372
376
  return r.startsWith(h + "/") || r === h;
373
377
  }
374
378
  function writeQueue(q) {
375
- const path = queuePath();
379
+ const path2 = queuePath();
376
380
  const home = resolve(homedir3());
377
- if (!_isQueuePathInsideHome(path, home)) {
378
- throw new Error(`notifications-queue write blocked: ${path} is outside ${home}`);
381
+ if (!_isQueuePathInsideHome(path2, home)) {
382
+ throw new Error(`notifications-queue write blocked: ${path2} is outside ${home}`);
379
383
  }
380
- mkdirSync(join3(home, ".deeplake"), { recursive: true, mode: 448 });
381
- const tmp = `${path}.${process.pid}.tmp`;
384
+ mkdirSync2(join3(home, ".deeplake"), { recursive: true, mode: 448 });
385
+ const tmp = `${path2}.${process.pid}.tmp`;
382
386
  writeFileSync(tmp, JSON.stringify(q, null, 2), { mode: 384 });
383
- renameSync(tmp, path);
387
+ renameSync(tmp, path2);
384
388
  }
385
389
  async function withQueueLock(fn) {
386
- const path = lockPath();
387
- mkdirSync(join3(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
390
+ const path2 = lockPath();
391
+ mkdirSync2(join3(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
388
392
  let fd = null;
389
393
  for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
390
394
  try {
391
- fd = openSync(path, "wx", 384);
395
+ fd = openSync(path2, "wx", 384);
392
396
  break;
393
397
  } catch (e) {
394
398
  const code = e.code;
395
399
  if (code !== "EEXIST")
396
400
  throw e;
397
401
  try {
398
- const age = Date.now() - statSync(path).mtimeMs;
402
+ const age = Date.now() - statSync(path2).mtimeMs;
399
403
  if (age > LOCK_STALE_MS) {
400
- unlinkSync(path);
404
+ unlinkSync(path2);
401
405
  continue;
402
406
  }
403
407
  } catch {
@@ -418,7 +422,7 @@ async function withQueueLock(fn) {
418
422
  } catch {
419
423
  }
420
424
  try {
421
- unlinkSync(path);
425
+ unlinkSync(path2);
422
426
  } catch {
423
427
  }
424
428
  }
@@ -440,7 +444,7 @@ async function enqueueNotification(n) {
440
444
  }
441
445
 
442
446
  // dist/src/commands/auth-creds.js
443
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "node:fs";
447
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2 } from "node:fs";
444
448
  import { join as join4 } from "node:path";
445
449
  import { homedir as homedir4 } from "node:os";
446
450
  function configDir() {
@@ -694,9 +698,9 @@ var DeeplakeApi = class {
694
698
  }
695
699
  }
696
700
  /** Update specific columns on a row by path. */
697
- async updateColumns(path, columns) {
701
+ async updateColumns(path2, columns) {
698
702
  const setClauses = Object.entries(columns).map(([col, val]) => typeof val === "number" ? `${col} = ${val}` : `${col} = '${sqlStr(String(val))}'`).join(", ");
699
- await this.query(`UPDATE "${this.tableName}" SET ${setClauses} WHERE path = '${sqlStr(path)}'`);
703
+ await this.query(`UPDATE "${this.tableName}" SET ${setClauses} WHERE path = '${sqlStr(path2)}'`);
700
704
  }
701
705
  // ── Convenience ─────────────────────────────────────────────────────────────
702
706
  /** Create a BM25 search index on a column. */
@@ -1393,22 +1397,22 @@ import { join as join8 } from "node:path";
1393
1397
  import { pathToFileURL } from "node:url";
1394
1398
 
1395
1399
  // dist/src/user-config.js
1396
- import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
1400
+ import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
1397
1401
  import { homedir as homedir6 } from "node:os";
1398
- import { dirname, join as join7 } from "node:path";
1402
+ import { dirname as dirname2, join as join7 } from "node:path";
1399
1403
  var _configPath = () => process.env.HIVEMIND_CONFIG_PATH ?? join7(homedir6(), ".deeplake", "config.json");
1400
1404
  var _cache = null;
1401
1405
  var _migrated = false;
1402
1406
  function readUserConfig() {
1403
1407
  if (_cache !== null)
1404
1408
  return _cache;
1405
- const path = _configPath();
1406
- if (!existsSync4(path)) {
1409
+ const path2 = _configPath();
1410
+ if (!existsSync4(path2)) {
1407
1411
  _cache = {};
1408
1412
  return _cache;
1409
1413
  }
1410
1414
  try {
1411
- const raw = readFileSync6(path, "utf-8");
1415
+ const raw = readFileSync6(path2, "utf-8");
1412
1416
  const parsed = JSON.parse(raw);
1413
1417
  _cache = isPlainObject(parsed) ? parsed : {};
1414
1418
  } catch {
@@ -1419,13 +1423,13 @@ function readUserConfig() {
1419
1423
  function writeUserConfig(patch) {
1420
1424
  const current = readUserConfig();
1421
1425
  const merged = deepMerge(current, patch);
1422
- const path = _configPath();
1423
- const dir = dirname(path);
1426
+ const path2 = _configPath();
1427
+ const dir = dirname2(path2);
1424
1428
  if (!existsSync4(dir))
1425
- mkdirSync4(dir, { recursive: true });
1426
- const tmp = `${path}.tmp.${process.pid}`;
1429
+ mkdirSync5(dir, { recursive: true });
1430
+ const tmp = `${path2}.tmp.${process.pid}`;
1427
1431
  writeFileSync4(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
1428
- renameSync2(tmp, path);
1432
+ renameSync2(tmp, path2);
1429
1433
  _cache = merged;
1430
1434
  return merged;
1431
1435
  }
@@ -1505,15 +1509,15 @@ function embeddingsDisabled() {
1505
1509
  }
1506
1510
 
1507
1511
  // dist/src/embeddings/self-heal.js
1508
- import { existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync5, readlinkSync, renameSync as renameSync3, rmSync, symlinkSync, statSync as statSync2 } from "node:fs";
1512
+ import { existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync6, readlinkSync, renameSync as renameSync3, rmSync, symlinkSync, statSync as statSync2 } from "node:fs";
1509
1513
  import { homedir as homedir8 } from "node:os";
1510
- import { basename as basename2, dirname as dirname2, join as join9 } from "node:path";
1514
+ import { basename as basename2, dirname as dirname3, join as join9 } from "node:path";
1511
1515
  function ensurePluginNodeModulesLink(opts) {
1512
1516
  if (basename2(opts.bundleDir) !== "bundle") {
1513
1517
  return { kind: "not-bundle-layout", bundleDir: opts.bundleDir };
1514
1518
  }
1515
1519
  const target = opts.sharedNodeModules ?? join9(homedir8(), ".hivemind", "embed-deps", "node_modules");
1516
- const pluginDir = dirname2(opts.bundleDir);
1520
+ const pluginDir = dirname3(opts.bundleDir);
1517
1521
  const link = join9(pluginDir, "node_modules");
1518
1522
  if (!existsSync5(target)) {
1519
1523
  return { kind: "shared-deps-missing", target };
@@ -1553,9 +1557,9 @@ function ensurePluginNodeModulesLink(opts) {
1553
1557
  }
1554
1558
  function createSymlinkAtomic(target, link) {
1555
1559
  try {
1556
- const parent = dirname2(link);
1560
+ const parent = dirname3(link);
1557
1561
  if (!existsSync5(parent))
1558
- mkdirSync5(parent, { recursive: true });
1562
+ mkdirSync6(parent, { recursive: true });
1559
1563
  const tmp = `${link}.tmp.${process.pid}`;
1560
1564
  try {
1561
1565
  rmSync(tmp, { force: true });
@@ -1570,11 +1574,11 @@ function createSymlinkAtomic(target, link) {
1570
1574
  }
1571
1575
 
1572
1576
  // dist/src/hooks/hermes/capture.js
1573
- import { fileURLToPath as fileURLToPath3 } from "node:url";
1574
- import { dirname as dirname7, join as join20 } from "node:path";
1577
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
1578
+ import { dirname as dirname9, join as join22 } from "node:path";
1575
1579
 
1576
1580
  // dist/src/hooks/summary-state.js
1577
- 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, statSync as statSync3 } from "node:fs";
1581
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, writeSync as writeSync2, mkdirSync as mkdirSync7, renameSync as renameSync4, existsSync as existsSync6, unlinkSync as unlinkSync4, openSync as openSync3, closeSync as closeSync3, statSync as statSync3 } from "node:fs";
1578
1582
  import { homedir as homedir9 } from "node:os";
1579
1583
  import { join as join10 } from "node:path";
1580
1584
  var dlog = (msg) => log("summary-state", msg);
@@ -1597,14 +1601,14 @@ function readState(sessionId) {
1597
1601
  }
1598
1602
  }
1599
1603
  function writeState(sessionId, state) {
1600
- mkdirSync6(STATE_DIR, { recursive: true });
1604
+ mkdirSync7(STATE_DIR, { recursive: true });
1601
1605
  const p = statePath(sessionId);
1602
1606
  const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
1603
1607
  writeFileSync5(tmp, JSON.stringify(state));
1604
1608
  renameSync4(tmp, p);
1605
1609
  }
1606
1610
  function withRmwLock(sessionId, fn) {
1607
- mkdirSync6(STATE_DIR, { recursive: true });
1611
+ mkdirSync7(STATE_DIR, { recursive: true });
1608
1612
  const rmwLock = statePath(sessionId) + ".rmw";
1609
1613
  const deadline = Date.now() + 2e3;
1610
1614
  let fd = null;
@@ -1666,7 +1670,7 @@ function shouldTrigger(state, cfg, now = Date.now()) {
1666
1670
  return false;
1667
1671
  }
1668
1672
  function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
1669
- mkdirSync6(STATE_DIR, { recursive: true });
1673
+ mkdirSync7(STATE_DIR, { recursive: true });
1670
1674
  const p = lockPath2(sessionId);
1671
1675
  if (existsSync6(p)) {
1672
1676
  try {
@@ -1710,21 +1714,21 @@ function releaseLock(sessionId) {
1710
1714
  // dist/src/hooks/hermes/spawn-wiki-worker.js
1711
1715
  import { execSync } from "node:child_process";
1712
1716
  import { fileURLToPath } from "node:url";
1713
- import { dirname as dirname4, join as join13 } from "node:path";
1714
- import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync8 } from "node:fs";
1717
+ import { dirname as dirname5, join as join13 } from "node:path";
1718
+ import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync9 } from "node:fs";
1715
1719
  import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
1716
1720
 
1717
1721
  // dist/src/utils/wiki-log.js
1718
- import { mkdirSync as mkdirSync7, appendFileSync as appendFileSync2 } from "node:fs";
1722
+ import { mkdirSync as mkdirSync8, appendFileSync as appendFileSync2 } from "node:fs";
1719
1723
  import { join as join11 } from "node:path";
1720
1724
  function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") {
1721
- const path = join11(hooksDir, filename);
1725
+ const path2 = join11(hooksDir, filename);
1722
1726
  return {
1723
- path,
1727
+ path: path2,
1724
1728
  log(msg) {
1725
1729
  try {
1726
- mkdirSync7(hooksDir, { recursive: true });
1727
- appendFileSync2(path, `[${utcTimestamp()}] ${msg}
1730
+ mkdirSync8(hooksDir, { recursive: true });
1731
+ appendFileSync2(path2, `[${utcTimestamp()}] ${msg}
1728
1732
  `);
1729
1733
  } catch {
1730
1734
  }
@@ -1734,7 +1738,7 @@ function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") {
1734
1738
 
1735
1739
  // dist/src/utils/version-check.js
1736
1740
  import { readFileSync as readFileSync8 } from "node:fs";
1737
- import { dirname as dirname3, join as join12 } from "node:path";
1741
+ import { dirname as dirname4, join as join12 } from "node:path";
1738
1742
  function getInstalledVersion(bundleDir, pluginManifestDir) {
1739
1743
  try {
1740
1744
  const pluginJson = join12(bundleDir, "..", pluginManifestDir, "plugin.json");
@@ -1766,7 +1770,7 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
1766
1770
  return pkg.version;
1767
1771
  } catch {
1768
1772
  }
1769
- const parent = dirname3(dir);
1773
+ const parent = dirname4(dir);
1770
1774
  if (parent === dir)
1771
1775
  break;
1772
1776
  dir = parent;
@@ -1777,10 +1781,10 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
1777
1781
  // dist/src/utils/spawn-detached.js
1778
1782
  import { spawn as nodeSpawn } from "node:child_process";
1779
1783
  function spawnDetachedNodeWorker(workerPath, args = [], deps = {}) {
1780
- const spawn2 = deps.spawn ?? nodeSpawn;
1784
+ const spawn3 = deps.spawn ?? nodeSpawn;
1781
1785
  const execPath = deps.execPath ?? process.execPath;
1782
1786
  try {
1783
- const child = spawn2(execPath, [workerPath, ...args], {
1787
+ const child = spawn3(execPath, [workerPath, ...args], {
1784
1788
  detached: true,
1785
1789
  stdio: ["ignore", "ignore", "ignore"],
1786
1790
  // Suppress the transient console window Windows would otherwise pop for
@@ -1862,7 +1866,7 @@ function spawnHermesWikiWorker(opts) {
1862
1866
  const { config, sessionId, cwd, bundleDir, reason } = opts;
1863
1867
  const projectName = projectNameFromCwd(cwd);
1864
1868
  const tmpDir = join13(tmpdir2(), `deeplake-wiki-${sessionId}-${Date.now()}`);
1865
- mkdirSync8(tmpDir, { recursive: true });
1869
+ mkdirSync9(tmpDir, { recursive: true });
1866
1870
  const pluginVersion = getInstalledVersion(bundleDir, ".claude-plugin") ?? "";
1867
1871
  const configFile = join13(tmpDir, "config.json");
1868
1872
  writeFileSync6(configFile, JSON.stringify({
@@ -1890,13 +1894,13 @@ function spawnHermesWikiWorker(opts) {
1890
1894
  wikiLog(`${reason}: spawned summary worker for ${sessionId}`);
1891
1895
  }
1892
1896
  function bundleDirFromImportMeta(importMetaUrl) {
1893
- return dirname4(fileURLToPath(importMetaUrl));
1897
+ return dirname5(fileURLToPath(importMetaUrl));
1894
1898
  }
1895
1899
 
1896
1900
  // dist/src/skillify/spawn-skillify-worker.js
1897
1901
  import { fileURLToPath as fileURLToPath2 } from "node:url";
1898
- import { dirname as dirname5, join as join15 } from "node:path";
1899
- import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync9, appendFileSync as appendFileSync3, chmodSync } from "node:fs";
1902
+ import { dirname as dirname6, join as join15 } from "node:path";
1903
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync10, appendFileSync as appendFileSync3, chmodSync } from "node:fs";
1900
1904
  import { homedir as homedir12, tmpdir as tmpdir3 } from "node:os";
1901
1905
 
1902
1906
  // dist/src/skillify/gate-runner.js
@@ -1971,7 +1975,7 @@ var HOME2 = homedir12();
1971
1975
  var SKILLIFY_LOG = join15(HOME2, ".claude", "hooks", "skillify.log");
1972
1976
  function skillifyLog(msg) {
1973
1977
  try {
1974
- mkdirSync9(dirname5(SKILLIFY_LOG), { recursive: true });
1978
+ mkdirSync10(dirname6(SKILLIFY_LOG), { recursive: true });
1975
1979
  appendFileSync3(SKILLIFY_LOG, `[${utcTimestamp()}] ${msg}
1976
1980
  `);
1977
1981
  } catch {
@@ -1980,7 +1984,7 @@ function skillifyLog(msg) {
1980
1984
  function spawnSkillifyWorker(opts) {
1981
1985
  const { config, cwd, projectKey, project, bundleDir, agent, scopeConfig, currentSessionId, reason } = opts;
1982
1986
  const tmpDir = join15(tmpdir3(), `deeplake-skillify-${projectKey}-${Date.now()}`);
1983
- mkdirSync9(tmpDir, { recursive: true, mode: 448 });
1987
+ mkdirSync10(tmpDir, { recursive: true, mode: 448 });
1984
1988
  const gateBin = findAgentBin(agent);
1985
1989
  const configFile = join15(tmpDir, "config.json");
1986
1990
  writeFileSync7(configFile, JSON.stringify({
@@ -2019,7 +2023,7 @@ function spawnSkillifyWorker(opts) {
2019
2023
  }
2020
2024
 
2021
2025
  // dist/src/skillify/state.js
2022
- 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";
2026
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, writeSync as writeSync3, mkdirSync as mkdirSync11, renameSync as renameSync6, rmdirSync, existsSync as existsSync9, lstatSync as lstatSync2, unlinkSync as unlinkSync5, openSync as openSync4, closeSync as closeSync4 } from "node:fs";
2023
2027
  import { join as join18 } from "node:path";
2024
2028
 
2025
2029
  // dist/src/utils/repo-identity.js
@@ -2071,7 +2075,7 @@ function deriveProjectKey(cwd) {
2071
2075
 
2072
2076
  // dist/src/skillify/legacy-migration.js
2073
2077
  import { existsSync as existsSync8, renameSync as renameSync5 } from "node:fs";
2074
- import { dirname as dirname6, join as join17 } from "node:path";
2078
+ import { dirname as dirname7, join as join17 } from "node:path";
2075
2079
 
2076
2080
  // dist/src/skillify/state-dir.js
2077
2081
  import { homedir as homedir13 } from "node:os";
@@ -2091,7 +2095,7 @@ function migrateLegacyStateDir() {
2091
2095
  return;
2092
2096
  attempted = true;
2093
2097
  const current = getStateDir();
2094
- const legacy = join17(dirname6(current), "skilify");
2098
+ const legacy = join17(dirname7(current), "skilify");
2095
2099
  if (!existsSync8(legacy))
2096
2100
  return;
2097
2101
  if (existsSync8(current))
@@ -2135,7 +2139,7 @@ function readState2(projectKey) {
2135
2139
  }
2136
2140
  function writeState2(projectKey, state) {
2137
2141
  migrateLegacyStateDir();
2138
- mkdirSync10(getStateDir(), { recursive: true });
2142
+ mkdirSync11(getStateDir(), { recursive: true });
2139
2143
  const p = statePath2(projectKey);
2140
2144
  const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
2141
2145
  writeFileSync8(tmp, JSON.stringify(state, null, 2));
@@ -2143,7 +2147,7 @@ function writeState2(projectKey, state) {
2143
2147
  }
2144
2148
  function withRmwLock2(projectKey, fn) {
2145
2149
  migrateLegacyStateDir();
2146
- mkdirSync10(getStateDir(), { recursive: true });
2150
+ mkdirSync11(getStateDir(), { recursive: true });
2147
2151
  const rmw = lockPath3(projectKey) + ".rmw";
2148
2152
  const deadline = Date.now() + 2e3;
2149
2153
  let fd = null;
@@ -2203,7 +2207,7 @@ function resetCounter(projectKey) {
2203
2207
  }
2204
2208
  function tryAcquireWorkerLock(projectKey, maxAgeMs = 10 * 60 * 1e3) {
2205
2209
  migrateLegacyStateDir();
2206
- mkdirSync10(getStateDir(), { recursive: true });
2210
+ mkdirSync11(getStateDir(), { recursive: true });
2207
2211
  const p = lockPath3(projectKey);
2208
2212
  if (existsSync9(p)) {
2209
2213
  try {
@@ -2255,7 +2259,7 @@ function releaseWorkerLock(projectKey) {
2255
2259
  }
2256
2260
 
2257
2261
  // dist/src/skillify/scope-config.js
2258
- import { existsSync as existsSync10, mkdirSync as mkdirSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "node:fs";
2262
+ import { existsSync as existsSync10, mkdirSync as mkdirSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "node:fs";
2259
2263
  import { join as join19 } from "node:path";
2260
2264
  function configPath() {
2261
2265
  return join19(getStateDir(), "config.json");
@@ -2317,12 +2321,151 @@ function tryStopCounterTrigger(opts) {
2317
2321
  }
2318
2322
  }
2319
2323
 
2324
+ // dist/src/utils/plugin-state.js
2325
+ import { readFileSync as readFileSync11 } from "node:fs";
2326
+ import { join as join20 } from "node:path";
2327
+ import { homedir as homedir14 } from "node:os";
2328
+ var PLUGIN_ID = "hivemind@hivemind";
2329
+ function isHivemindPluginEnabled() {
2330
+ try {
2331
+ const settingsPath = join20(homedir14(), ".claude", "settings.json");
2332
+ const settings = JSON.parse(readFileSync11(settingsPath, "utf-8"));
2333
+ const enabledPlugins = settings?.enabledPlugins;
2334
+ if (enabledPlugins && typeof enabledPlugins === "object" && PLUGIN_ID in enabledPlugins) {
2335
+ return enabledPlugins[PLUGIN_ID] !== false;
2336
+ }
2337
+ return true;
2338
+ } catch {
2339
+ return true;
2340
+ }
2341
+ }
2342
+
2343
+ // dist/src/skillify/skillopt-trigger.js
2344
+ import { spawn as spawn2 } from "node:child_process";
2345
+ import fs from "node:fs";
2346
+ import path from "node:path";
2347
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
2348
+
2349
+ // dist/src/skillify/manifest.js
2350
+ import { existsSync as existsSync11, lstatSync as lstatSync3, mkdirSync as mkdirSync13, readFileSync as readFileSync12, renameSync as renameSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync10 } from "node:fs";
2351
+ import { dirname as dirname8, join as join21 } from "node:path";
2352
+
2353
+ // dist/src/skillify/skillopt-env.js
2354
+ var SKILLOPT_ENV = {
2355
+ /** User-set kill switch: "1" disables the whole trigger. */
2356
+ DISABLED: "HIVEMIND_SKILLOPT_DISABLED",
2357
+ /** Recursion guard the trigger sets on the spawned worker so the worker can't re-arm. */
2358
+ WORKER: "HIVEMIND_SKILLOPT_WORKER",
2359
+ /** Worker inputs, handed trigger → worker via the child env. */
2360
+ SESSION: "HIVEMIND_SKILLOPT_SESSION",
2361
+ SKILL: "HIVEMIND_SKILLOPT_SKILL",
2362
+ REACTION: "HIVEMIND_SKILLOPT_REACTION",
2363
+ TOOL_USE_ID: "HIVEMIND_SKILLOPT_TOOL_USE_ID",
2364
+ /** Which agent's CLI runs the judge/proposer (claude_code/codex/hermes/cursor/pi). */
2365
+ AGENT: "HIVEMIND_SKILLOPT_AGENT",
2366
+ /** K-message judgment-window size override. */
2367
+ JUDGE_WINDOW: "HIVEMIND_SKILLOPT_JUDGE_WINDOW"
2368
+ };
2369
+
2370
+ // dist/src/skillify/skillopt-trigger.js
2371
+ var log5 = (m) => log("skillopt-trigger", m);
2372
+ function defaultHasCreds() {
2373
+ try {
2374
+ return Boolean(loadConfig()?.token);
2375
+ } catch {
2376
+ return false;
2377
+ }
2378
+ }
2379
+ var MAX_REACTION = 8e3;
2380
+ function pendingFile(sessionId) {
2381
+ const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 200);
2382
+ return path.join(getStateDir(), "skillopt", "pending", `${safe}.json`);
2383
+ }
2384
+ var fileStore = {
2385
+ load(sessionId) {
2386
+ try {
2387
+ return JSON.parse(fs.readFileSync(pendingFile(sessionId), "utf8"));
2388
+ } catch {
2389
+ return null;
2390
+ }
2391
+ },
2392
+ save(sessionId, p) {
2393
+ try {
2394
+ const f = pendingFile(sessionId);
2395
+ if (p === null) {
2396
+ try {
2397
+ fs.unlinkSync(f);
2398
+ } catch {
2399
+ }
2400
+ return;
2401
+ }
2402
+ fs.mkdirSync(path.dirname(f), { recursive: true });
2403
+ const tmp = `${f}.${process.pid}.tmp`;
2404
+ fs.writeFileSync(tmp, JSON.stringify(p));
2405
+ fs.renameSync(tmp, f);
2406
+ } catch {
2407
+ }
2408
+ }
2409
+ };
2410
+ function runEventTrigger(sessionId, reaction, opts = {}) {
2411
+ const deps = opts.deps ?? {};
2412
+ const env = deps.env ?? process.env;
2413
+ if (env[SKILLOPT_ENV.DISABLED] === "1")
2414
+ return { fired: false, reason: "disabled" };
2415
+ if (env[SKILLOPT_ENV.WORKER] === "1")
2416
+ return { fired: false, reason: "in-worker" };
2417
+ if (!sessionId)
2418
+ return { fired: false, reason: "no-skill" };
2419
+ const store = deps.store ?? fileStore;
2420
+ const p = store.load(sessionId);
2421
+ if (!p)
2422
+ return { fired: false, reason: "no-skill" };
2423
+ if (!(deps.canFire ?? defaultHasCreds)())
2424
+ return { fired: false, reason: "no-creds" };
2425
+ store.save(sessionId, p.budget - 1 <= 0 ? null : { ...p, budget: p.budget - 1 });
2426
+ (deps.spawnWorker ?? spawnWorker)(sessionId, p.skill, reaction ?? "", p.toolUseId, opts.agent);
2427
+ return { fired: true, reason: "spawned" };
2428
+ }
2429
+ function spawnWorker(sessionId, skill, reaction, toolUseId, agent) {
2430
+ try {
2431
+ const here = path.dirname(fileURLToPath3(import.meta.url));
2432
+ const entry = path.join(here, "skillopt-worker.js");
2433
+ const child = spawn2(process.execPath, [entry], {
2434
+ detached: true,
2435
+ stdio: "ignore",
2436
+ env: {
2437
+ ...process.env,
2438
+ [SKILLOPT_ENV.WORKER]: "1",
2439
+ [SKILLOPT_ENV.SESSION]: sessionId,
2440
+ [SKILLOPT_ENV.SKILL]: skill,
2441
+ [SKILLOPT_ENV.REACTION]: (reaction ?? "").slice(0, MAX_REACTION),
2442
+ ...toolUseId ? { [SKILLOPT_ENV.TOOL_USE_ID]: toolUseId } : {},
2443
+ ...agent ? { [SKILLOPT_ENV.AGENT]: agent } : {}
2444
+ }
2445
+ });
2446
+ child.unref();
2447
+ log5(`spawned skillopt worker for ${skill} in ${sessionId}${agent ? ` (agent=${agent})` : ""}`);
2448
+ } catch (e) {
2449
+ log5(`spawn failed (swallowed): ${e?.message ?? e}`);
2450
+ }
2451
+ }
2452
+
2453
+ // dist/src/hooks/shared/skillopt-hook.js
2454
+ function reactSkillOpt(sessionId, prompt, agent) {
2455
+ try {
2456
+ if (prompt === void 0 || prompt.trim() === "" || process.env.HIVEMIND_WIKI_WORKER === "1")
2457
+ return;
2458
+ runEventTrigger(sessionId, prompt, { agent });
2459
+ } catch {
2460
+ }
2461
+ }
2462
+
2320
2463
  // dist/src/hooks/hermes/capture.js
2321
- var log5 = (msg) => log("hermes-capture", msg);
2464
+ var log6 = (msg) => log("hermes-capture", msg);
2322
2465
  function resolveEmbedDaemonPath() {
2323
- return join20(dirname7(fileURLToPath3(import.meta.url)), "embeddings", "embed-daemon.js");
2466
+ return join22(dirname9(fileURLToPath4(import.meta.url)), "embeddings", "embed-daemon.js");
2324
2467
  }
2325
- var __bundleDir = dirname7(fileURLToPath3(import.meta.url));
2468
+ var __bundleDir = dirname9(fileURLToPath4(import.meta.url));
2326
2469
  var PLUGIN_VERSION = getInstalledVersion(__bundleDir, ".claude-plugin") ?? "";
2327
2470
  if (!embeddingsDisabled()) {
2328
2471
  try {
@@ -2341,10 +2484,14 @@ function pickString(...candidates) {
2341
2484
  async function main() {
2342
2485
  if (!CAPTURE)
2343
2486
  return;
2487
+ if (!isHivemindPluginEnabled()) {
2488
+ log6("plugin disabled, skipping capture");
2489
+ return;
2490
+ }
2344
2491
  const input = await readStdin();
2345
2492
  const config = loadConfig();
2346
2493
  if (!config) {
2347
- log5("no config");
2494
+ log6("no config");
2348
2495
  return;
2349
2496
  }
2350
2497
  const sessionId = input.session_id ?? `hermes-${Date.now()}`;
@@ -2361,17 +2508,19 @@ async function main() {
2361
2508
  timestamp: ts
2362
2509
  };
2363
2510
  let entry = null;
2511
+ let reactPrompt;
2364
2512
  if (event === "pre_llm_call") {
2365
2513
  const prompt = pickString(extra.prompt, extra.user_message, extra.message?.content);
2366
2514
  if (!prompt) {
2367
- log5(`pre_llm_call: no prompt found in extra`);
2515
+ log6(`pre_llm_call: no prompt found in extra`);
2368
2516
  return;
2369
2517
  }
2370
- log5(`user session=${sessionId}`);
2518
+ log6(`user session=${sessionId}`);
2371
2519
  entry = { id: crypto.randomUUID(), ...meta, type: "user_message", content: prompt };
2520
+ reactPrompt = prompt;
2372
2521
  } else if (event === "post_tool_call" && typeof input.tool_name === "string") {
2373
2522
  const toolResponse = extra.tool_result ?? extra.tool_output ?? extra.result ?? extra.output;
2374
- log5(`tool=${input.tool_name} session=${sessionId}`);
2523
+ log6(`tool=${input.tool_name} session=${sessionId}`);
2375
2524
  entry = {
2376
2525
  id: crypto.randomUUID(),
2377
2526
  ...meta,
@@ -2383,18 +2532,18 @@ async function main() {
2383
2532
  } else if (event === "post_llm_call") {
2384
2533
  const text = pickString(extra.response, extra.assistant_message, extra.message?.content);
2385
2534
  if (!text) {
2386
- log5(`post_llm_call: no response found in extra`);
2535
+ log6(`post_llm_call: no response found in extra`);
2387
2536
  return;
2388
2537
  }
2389
- log5(`assistant session=${sessionId}`);
2538
+ log6(`assistant session=${sessionId}`);
2390
2539
  entry = { id: crypto.randomUUID(), ...meta, type: "assistant_message", content: text };
2391
2540
  } else {
2392
- log5(`unknown/unhandled event: ${event}, skipping`);
2541
+ log6(`unknown/unhandled event: ${event}, skipping`);
2393
2542
  return;
2394
2543
  }
2395
2544
  const sessionPath = buildSessionPath(config, sessionId);
2396
2545
  const line = JSON.stringify(entry);
2397
- log5(`writing to ${sessionPath}`);
2546
+ log6(`writing to ${sessionPath}`);
2398
2547
  const projectName = projectNameFromCwd(cwd);
2399
2548
  const filename = sessionPath.split("/").pop() ?? "";
2400
2549
  const jsonForSql = line.replace(/'/g, "''");
@@ -2405,14 +2554,15 @@ async function main() {
2405
2554
  await api.query(insertSql);
2406
2555
  } catch (e) {
2407
2556
  if (e.message?.includes("permission denied") || e.message?.includes("does not exist")) {
2408
- log5("table missing, creating and retrying");
2557
+ log6("table missing, creating and retrying");
2409
2558
  await api.ensureSessionsTable(sessionsTable);
2410
2559
  await api.query(insertSql);
2411
2560
  } else {
2412
2561
  throw e;
2413
2562
  }
2414
2563
  }
2415
- log5("capture ok \u2192 cloud");
2564
+ log6("capture ok \u2192 cloud");
2565
+ reactSkillOpt(sessionId, reactPrompt, "hermes");
2416
2566
  maybeTriggerPeriodicSummary(sessionId, cwd, config);
2417
2567
  if (event === "post_llm_call" && process.env.HIVEMIND_WIKI_WORKER !== "1" && process.env.HIVEMIND_SKILLIFY_WORKER !== "1") {
2418
2568
  tryStopCounterTrigger({
@@ -2433,7 +2583,7 @@ function maybeTriggerPeriodicSummary(sessionId, cwd, config) {
2433
2583
  if (!shouldTrigger(state, cfg))
2434
2584
  return;
2435
2585
  if (!tryAcquireLock(sessionId)) {
2436
- log5(`periodic trigger suppressed (lock held) session=${sessionId}`);
2586
+ log6(`periodic trigger suppressed (lock held) session=${sessionId}`);
2437
2587
  return;
2438
2588
  }
2439
2589
  wikiLog(`Periodic: threshold hit (total=${state.totalCount}, since=${state.totalCount - state.lastSummaryCount}, N=${cfg.everyNMessages}, hours=${cfg.everyHours})`);
@@ -2446,17 +2596,17 @@ function maybeTriggerPeriodicSummary(sessionId, cwd, config) {
2446
2596
  reason: "Periodic"
2447
2597
  });
2448
2598
  } catch (e) {
2449
- log5(`periodic spawn failed: ${e.message}`);
2599
+ log6(`periodic spawn failed: ${e.message}`);
2450
2600
  try {
2451
2601
  releaseLock(sessionId);
2452
2602
  } catch {
2453
2603
  }
2454
2604
  }
2455
2605
  } catch (e) {
2456
- log5(`periodic trigger error: ${e.message}`);
2606
+ log6(`periodic trigger error: ${e.message}`);
2457
2607
  }
2458
2608
  }
2459
2609
  main().catch((e) => {
2460
- log5(`fatal: ${e.message}`);
2610
+ log6(`fatal: ${e.message}`);
2461
2611
  process.exit(0);
2462
2612
  });