@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() {
@@ -129,8 +129,12 @@ function isDebug() {
129
129
  function log(tag, msg) {
130
130
  if (!isDebug())
131
131
  return;
132
- appendFileSync(LOG, `${(/* @__PURE__ */ new Date()).toISOString()} [${tag}] ${msg}
132
+ try {
133
+ mkdirSync(dirname(LOG), { recursive: true });
134
+ appendFileSync(LOG, `${(/* @__PURE__ */ new Date()).toISOString()} [${tag}] ${msg}
133
135
  `);
136
+ } catch {
137
+ }
134
138
  }
135
139
 
136
140
  // 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. */
@@ -1128,8 +1132,8 @@ function formatToolCall(obj) {
1128
1132
  input: ${formatToolInput(obj?.tool_input)}
1129
1133
  response: ${formatToolResponse(obj?.tool_response, obj?.tool_input, obj?.tool_name)}`;
1130
1134
  }
1131
- function normalizeContent(path, raw) {
1132
- if (!path.includes("/sessions/"))
1135
+ function normalizeContent(path2, raw) {
1136
+ if (!path2.includes("/sessions/"))
1133
1137
  return raw;
1134
1138
  if (!raw || raw[0] !== "{")
1135
1139
  return raw;
@@ -1847,22 +1851,22 @@ import { join as join8 } from "node:path";
1847
1851
  import { pathToFileURL } from "node:url";
1848
1852
 
1849
1853
  // dist/src/user-config.js
1850
- import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
1854
+ import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
1851
1855
  import { homedir as homedir6 } from "node:os";
1852
- import { dirname, join as join7 } from "node:path";
1856
+ import { dirname as dirname2, join as join7 } from "node:path";
1853
1857
  var _configPath = () => process.env.HIVEMIND_CONFIG_PATH ?? join7(homedir6(), ".deeplake", "config.json");
1854
1858
  var _cache = null;
1855
1859
  var _migrated = false;
1856
1860
  function readUserConfig() {
1857
1861
  if (_cache !== null)
1858
1862
  return _cache;
1859
- const path = _configPath();
1860
- if (!existsSync4(path)) {
1863
+ const path2 = _configPath();
1864
+ if (!existsSync4(path2)) {
1861
1865
  _cache = {};
1862
1866
  return _cache;
1863
1867
  }
1864
1868
  try {
1865
- const raw = readFileSync6(path, "utf-8");
1869
+ const raw = readFileSync6(path2, "utf-8");
1866
1870
  const parsed = JSON.parse(raw);
1867
1871
  _cache = isPlainObject(parsed) ? parsed : {};
1868
1872
  } catch {
@@ -1873,13 +1877,13 @@ function readUserConfig() {
1873
1877
  function writeUserConfig(patch) {
1874
1878
  const current = readUserConfig();
1875
1879
  const merged = deepMerge(current, patch);
1876
- const path = _configPath();
1877
- const dir = dirname(path);
1880
+ const path2 = _configPath();
1881
+ const dir = dirname2(path2);
1878
1882
  if (!existsSync4(dir))
1879
- mkdirSync4(dir, { recursive: true });
1880
- const tmp = `${path}.tmp.${process.pid}`;
1883
+ mkdirSync5(dir, { recursive: true });
1884
+ const tmp = `${path2}.tmp.${process.pid}`;
1881
1885
  writeFileSync4(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
1882
- renameSync2(tmp, path);
1886
+ renameSync2(tmp, path2);
1883
1887
  _cache = merged;
1884
1888
  return merged;
1885
1889
  }
@@ -1960,11 +1964,11 @@ function embeddingsDisabled() {
1960
1964
 
1961
1965
  // dist/src/hooks/grep-direct.js
1962
1966
  import { fileURLToPath } from "node:url";
1963
- import { dirname as dirname2, join as join9 } from "node:path";
1967
+ import { dirname as dirname3, join as join9 } from "node:path";
1964
1968
  var SEMANTIC_ENABLED = process.env.HIVEMIND_SEMANTIC_SEARCH !== "false" && !embeddingsDisabled();
1965
1969
  var SEMANTIC_TIMEOUT_MS = Number(process.env.HIVEMIND_SEMANTIC_EMBED_TIMEOUT_MS ?? "500");
1966
1970
  function resolveDaemonPath() {
1967
- return join9(dirname2(fileURLToPath(import.meta.url)), "..", "embeddings", "embed-daemon.js");
1971
+ return join9(dirname3(fileURLToPath(import.meta.url)), "..", "embeddings", "embed-daemon.js");
1968
1972
  }
1969
1973
  var sharedEmbedClient = null;
1970
1974
  function getEmbedClient() {
@@ -2336,13 +2340,13 @@ function rewritePaths(cmd) {
2336
2340
  }
2337
2341
 
2338
2342
  // dist/src/graph/vfs-handler.js
2339
- import { existsSync as existsSync7, mkdirSync as mkdirSync8, readFileSync as readFileSync9, renameSync as renameSync5, writeFileSync as writeFileSync7 } from "node:fs";
2343
+ import { existsSync as existsSync7, mkdirSync as mkdirSync9, readFileSync as readFileSync9, renameSync as renameSync5, writeFileSync as writeFileSync7 } from "node:fs";
2340
2344
  import { createHash as createHash3 } from "node:crypto";
2341
- import { join as join14, dirname as dirname6 } from "node:path";
2345
+ import { join as join14, dirname as dirname7 } from "node:path";
2342
2346
 
2343
2347
  // dist/src/graph/last-build.js
2344
- import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync7, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "node:fs";
2345
- import { dirname as dirname3, join as join11 } from "node:path";
2348
+ import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync7, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "node:fs";
2349
+ import { dirname as dirname4, join as join11 } from "node:path";
2346
2350
  function lastBuildPath(baseDir, worktreeId) {
2347
2351
  if (worktreeId !== void 0) {
2348
2352
  return join11(baseDir, "worktrees", worktreeId, ".last-build.json");
@@ -2350,18 +2354,18 @@ function lastBuildPath(baseDir, worktreeId) {
2350
2354
  return join11(baseDir, ".last-build.json");
2351
2355
  }
2352
2356
  function readLastBuild(baseDir, worktreeId) {
2353
- let path = lastBuildPath(baseDir, worktreeId);
2354
- if (!existsSync5(path)) {
2357
+ let path2 = lastBuildPath(baseDir, worktreeId);
2358
+ if (!existsSync5(path2)) {
2355
2359
  if (worktreeId === void 0)
2356
2360
  return null;
2357
2361
  const legacy = lastBuildPath(baseDir, void 0);
2358
2362
  if (!existsSync5(legacy))
2359
2363
  return null;
2360
- path = legacy;
2364
+ path2 = legacy;
2361
2365
  }
2362
2366
  let raw;
2363
2367
  try {
2364
- raw = readFileSync7(path, "utf8");
2368
+ raw = readFileSync7(path2, "utf8");
2365
2369
  } catch {
2366
2370
  return null;
2367
2371
  }
@@ -2392,13 +2396,13 @@ function readLastBuild(baseDir, worktreeId) {
2392
2396
 
2393
2397
  // dist/src/graph/snapshot.js
2394
2398
  import { createHash } from "node:crypto";
2395
- import { mkdirSync as mkdirSync7, renameSync as renameSync4, writeFileSync as writeFileSync6 } from "node:fs";
2399
+ import { mkdirSync as mkdirSync8, renameSync as renameSync4, writeFileSync as writeFileSync6 } from "node:fs";
2396
2400
  import { homedir as homedir9 } from "node:os";
2397
- import { dirname as dirname5, join as join13 } from "node:path";
2401
+ import { dirname as dirname6, join as join13 } from "node:path";
2398
2402
 
2399
2403
  // dist/src/graph/history.js
2400
- import { appendFileSync as appendFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "node:fs";
2401
- import { dirname as dirname4, join as join12 } from "node:path";
2404
+ import { appendFileSync as appendFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync8 } from "node:fs";
2405
+ import { dirname as dirname5, join as join12 } from "node:path";
2402
2406
 
2403
2407
  // dist/src/graph/resolve/cross-file.js
2404
2408
  import { posix } from "node:path";
@@ -2970,18 +2974,18 @@ function workTreeIdFor(cwd) {
2970
2974
  return createHash3("sha256").update(cwd).digest("hex").slice(0, 16);
2971
2975
  }
2972
2976
  function handleGraphVfs(subpath, cwd) {
2973
- const path = subpath.replace(/^\/+/, "");
2974
- if (path === "" || path === "/") {
2977
+ const path2 = subpath.replace(/^\/+/, "");
2978
+ if (path2 === "" || path2 === "/") {
2975
2979
  return { kind: "ok", body: dirListing() };
2976
2980
  }
2977
- if (path === "index.md" || path === "index") {
2981
+ if (path2 === "index.md" || path2 === "index") {
2978
2982
  return loadSnapshotOrError(cwd, (snap, baseDir) => ({
2979
2983
  kind: "ok",
2980
2984
  body: renderIndex(snap, baseDir, cwd)
2981
2985
  }));
2982
2986
  }
2983
- if (path.startsWith("find/")) {
2984
- const pattern = path.slice("find/".length);
2987
+ if (path2.startsWith("find/")) {
2988
+ const pattern = path2.slice("find/".length);
2985
2989
  if (pattern === "") {
2986
2990
  return { kind: "not-found", message: "find/ requires a pattern: cat memory/graph/find/<keyword>" };
2987
2991
  }
@@ -2990,8 +2994,8 @@ function handleGraphVfs(subpath, cwd) {
2990
2994
  body: renderFind(snap, pattern, baseDir, workTreeIdFor(cwd))
2991
2995
  }));
2992
2996
  }
2993
- if (path.startsWith("show/")) {
2994
- const key = path.slice("show/".length);
2997
+ if (path2.startsWith("show/")) {
2998
+ const key = path2.slice("show/".length);
2995
2999
  if (key === "") {
2996
3000
  return { kind: "not-found", message: "show/ requires a handle or pattern" };
2997
3001
  }
@@ -3000,8 +3004,8 @@ function handleGraphVfs(subpath, cwd) {
3000
3004
  body: renderShow(snap, key, baseDir, workTreeIdFor(cwd))
3001
3005
  }));
3002
3006
  }
3003
- if (path.startsWith("query/")) {
3004
- const pattern = path.slice("query/".length);
3007
+ if (path2.startsWith("query/")) {
3008
+ const pattern = path2.slice("query/".length);
3005
3009
  if (pattern === "") {
3006
3010
  return { kind: "not-found", message: "query/ requires a pattern: cat memory/graph/query/<keyword>" };
3007
3011
  }
@@ -3010,28 +3014,28 @@ function handleGraphVfs(subpath, cwd) {
3010
3014
  body: renderQuery(snap, pattern, baseDir, workTreeIdFor(cwd))
3011
3015
  }));
3012
3016
  }
3013
- if (path.startsWith("impact/")) {
3014
- const pattern = path.slice("impact/".length);
3017
+ if (path2.startsWith("impact/")) {
3018
+ const pattern = path2.slice("impact/".length);
3015
3019
  if (pattern === "") {
3016
3020
  return { kind: "not-found", message: "impact/ requires a pattern: cat memory/graph/impact/<symbol>" };
3017
3021
  }
3018
3022
  return loadSnapshotOrError(cwd, (snap) => ({ kind: "ok", body: renderImpact(snap, pattern) }));
3019
3023
  }
3020
- if (path.startsWith("neighborhood/")) {
3021
- const file = path.slice("neighborhood/".length);
3024
+ if (path2.startsWith("neighborhood/")) {
3025
+ const file = path2.slice("neighborhood/".length);
3022
3026
  if (file === "") {
3023
3027
  return { kind: "not-found", message: "neighborhood/ requires a file path: cat memory/graph/neighborhood/<file>" };
3024
3028
  }
3025
3029
  return loadSnapshotOrError(cwd, (snap) => ({ kind: "ok", body: renderNeighborhood(snap, file) }));
3026
3030
  }
3027
- if (path === "layers" || path === "layers/" || path === "layers/index.md") {
3031
+ if (path2 === "layers" || path2 === "layers/" || path2 === "layers/index.md") {
3028
3032
  return loadSnapshotOrError(cwd, (snap) => ({ kind: "ok", body: renderLayers(snap) }));
3029
3033
  }
3030
- if (path === "tour" || path === "tour/" || path === "tour/index.md") {
3034
+ if (path2 === "tour" || path2 === "tour/" || path2 === "tour/index.md") {
3031
3035
  return loadSnapshotOrError(cwd, (snap) => ({ kind: "ok", body: renderTour(snap) }));
3032
3036
  }
3033
- if (path.startsWith("path/")) {
3034
- const rest = path.slice("path/".length);
3037
+ if (path2.startsWith("path/")) {
3038
+ const rest = path2.slice("path/".length);
3035
3039
  const slash = rest.indexOf("/");
3036
3040
  if (slash <= 0 || slash === rest.length - 1) {
3037
3041
  return { kind: "not-found", message: "path/ needs two patterns: cat memory/graph/path/<from>/<to> (each a symbol-name substring, no slash)" };
@@ -3042,7 +3046,7 @@ function handleGraphVfs(subpath, cwd) {
3042
3046
  }
3043
3047
  return {
3044
3048
  kind: "not-found",
3045
- message: `Unknown endpoint: graph/${path}
3049
+ message: `Unknown endpoint: graph/${path2}
3046
3050
  Available: index.md, find/<pattern>, query/<pattern>, show/<handle-or-pattern>, impact/<pattern>, neighborhood/<file>, layers, tour, path/<from>/<to>`
3047
3051
  };
3048
3052
  }
@@ -3441,22 +3445,22 @@ function handlesPath(baseDir, worktreeId) {
3441
3445
  return join14(baseDir, "worktrees", worktreeId, ".find-handles.json");
3442
3446
  }
3443
3447
  function saveHandles(baseDir, worktreeId, ids, pattern) {
3444
- const path = handlesPath(baseDir, worktreeId);
3448
+ const path2 = handlesPath(baseDir, worktreeId);
3445
3449
  const payload = { pattern, ts: Date.now(), ids };
3446
3450
  try {
3447
- mkdirSync8(dirname6(path), { recursive: true });
3448
- const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
3451
+ mkdirSync9(dirname7(path2), { recursive: true });
3452
+ const tmp = `${path2}.tmp.${process.pid}.${Date.now()}`;
3449
3453
  writeFileSync7(tmp, JSON.stringify(payload));
3450
- renameSync5(tmp, path);
3454
+ renameSync5(tmp, path2);
3451
3455
  } catch {
3452
3456
  }
3453
3457
  }
3454
3458
  function loadHandles(baseDir, worktreeId) {
3455
- const path = handlesPath(baseDir, worktreeId);
3456
- if (!existsSync7(path))
3459
+ const path2 = handlesPath(baseDir, worktreeId);
3460
+ if (!existsSync7(path2))
3457
3461
  return null;
3458
3462
  try {
3459
- const parsed = JSON.parse(readFileSync9(path, "utf8"));
3463
+ const parsed = JSON.parse(readFileSync9(path2, "utf8"));
3460
3464
  if (parsed === null || typeof parsed !== "object")
3461
3465
  return null;
3462
3466
  const o = parsed;
@@ -3546,10 +3550,230 @@ function tryGraphRead(rewrittenCommand, cwd) {
3546
3550
  return result.kind === "ok" ? result.body : `(${result.kind}) ${result.message}`;
3547
3551
  }
3548
3552
 
3553
+ // dist/src/skillify/skillopt-trigger.js
3554
+ import { spawn as spawn2 } from "node:child_process";
3555
+ import fs from "node:fs";
3556
+ import path from "node:path";
3557
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
3558
+
3559
+ // dist/src/skillify/state-dir.js
3560
+ import { homedir as homedir10 } from "node:os";
3561
+ import { join as join15 } from "node:path";
3562
+ function getStateDir() {
3563
+ const override = process.env.HIVEMIND_STATE_DIR?.trim();
3564
+ return override && override.length > 0 ? override : join15(homedir10(), ".deeplake", "state", "skillify");
3565
+ }
3566
+
3567
+ // dist/src/skillify/skill-invocations.js
3568
+ function pathToSkillRef(s) {
3569
+ if (typeof s !== "string")
3570
+ return null;
3571
+ const m = s.match(/\/skills\/(?:[^/\s"'`]+\/)*([^/\s"'`]+)\/SKILL\.md/);
3572
+ return m ? m[1] : null;
3573
+ }
3574
+ function splitOrgSkill(skill) {
3575
+ if (skill.includes(":"))
3576
+ return null;
3577
+ if (skill.includes("/") || skill.includes("\\") || skill.includes(".."))
3578
+ return null;
3579
+ const i = skill.lastIndexOf("--");
3580
+ if (i <= 0 || i + 2 >= skill.length)
3581
+ return null;
3582
+ return { name: skill.slice(0, i), author: skill.slice(i + 2) };
3583
+ }
3584
+
3585
+ // dist/src/skillify/manifest.js
3586
+ import { existsSync as existsSync9, lstatSync, mkdirSync as mkdirSync10, readFileSync as readFileSync10, renameSync as renameSync7, unlinkSync as unlinkSync4, writeFileSync as writeFileSync8 } from "node:fs";
3587
+ import { dirname as dirname9, join as join17 } from "node:path";
3588
+
3589
+ // dist/src/skillify/legacy-migration.js
3590
+ import { existsSync as existsSync8, renameSync as renameSync6 } from "node:fs";
3591
+ import { dirname as dirname8, join as join16 } from "node:path";
3592
+ var dlog = (msg) => log("skillify-migrate", msg);
3593
+ var attempted = false;
3594
+ function migrateLegacyStateDir() {
3595
+ if (process.env.HIVEMIND_STATE_DIR?.trim())
3596
+ return;
3597
+ if (attempted)
3598
+ return;
3599
+ attempted = true;
3600
+ const current = getStateDir();
3601
+ const legacy = join16(dirname8(current), "skilify");
3602
+ if (!existsSync8(legacy))
3603
+ return;
3604
+ if (existsSync8(current))
3605
+ return;
3606
+ try {
3607
+ renameSync6(legacy, current);
3608
+ dlog(`migrated ${legacy} -> ${current}`);
3609
+ } catch (err) {
3610
+ const code = err.code;
3611
+ if (code === "EXDEV" || code === "EPERM" || code === "ENOENT" || code === "EEXIST" || code === "ENOTEMPTY") {
3612
+ dlog(`migration skipped (${code}); legacy dir left as-is or another process handled it`);
3613
+ return;
3614
+ }
3615
+ throw err;
3616
+ }
3617
+ }
3618
+
3619
+ // dist/src/skillify/manifest.js
3620
+ function emptyManifest() {
3621
+ return { version: 1, entries: [] };
3622
+ }
3623
+ function manifestPath() {
3624
+ return join17(getStateDir(), "pulled.json");
3625
+ }
3626
+ function loadManifest(path2 = manifestPath()) {
3627
+ migrateLegacyStateDir();
3628
+ if (!existsSync9(path2))
3629
+ return emptyManifest();
3630
+ let raw;
3631
+ try {
3632
+ raw = readFileSync10(path2, "utf-8");
3633
+ } catch {
3634
+ return emptyManifest();
3635
+ }
3636
+ try {
3637
+ const parsed = JSON.parse(raw);
3638
+ if (!parsed || typeof parsed !== "object")
3639
+ return emptyManifest();
3640
+ if (parsed.version !== 1 || !Array.isArray(parsed.entries))
3641
+ return emptyManifest();
3642
+ const entries = [];
3643
+ for (const e of parsed.entries) {
3644
+ if (!e || typeof e !== "object")
3645
+ continue;
3646
+ if (typeof e.dirName !== "string" || !e.dirName)
3647
+ continue;
3648
+ if (e.dirName.includes("/") || e.dirName.includes("\\") || e.dirName.includes(".."))
3649
+ continue;
3650
+ if (typeof e.name !== "string" || !e.name)
3651
+ continue;
3652
+ if (typeof e.author !== "string")
3653
+ continue;
3654
+ if (typeof e.installRoot !== "string" || !e.installRoot)
3655
+ continue;
3656
+ if (e.install !== "global" && e.install !== "project")
3657
+ continue;
3658
+ const symlinks = Array.isArray(e.symlinks) ? e.symlinks.filter((p) => typeof p === "string" && p.length > 0 && (p.startsWith("/") || /^[A-Za-z]:[\\/]/.test(p)) && // absolute (POSIX or Windows)
3659
+ !p.includes("..")) : [];
3660
+ entries.push({
3661
+ dirName: e.dirName,
3662
+ name: e.name,
3663
+ author: e.author,
3664
+ projectKey: typeof e.projectKey === "string" ? e.projectKey : "",
3665
+ remoteVersion: typeof e.remoteVersion === "number" ? e.remoteVersion : 1,
3666
+ install: e.install,
3667
+ installRoot: e.installRoot,
3668
+ pulledAt: typeof e.pulledAt === "string" ? e.pulledAt : (/* @__PURE__ */ new Date()).toISOString(),
3669
+ symlinks
3670
+ });
3671
+ }
3672
+ return { version: 1, entries };
3673
+ } catch {
3674
+ return emptyManifest();
3675
+ }
3676
+ }
3677
+
3678
+ // dist/src/skillify/skillopt-env.js
3679
+ var SKILLOPT_ENV = {
3680
+ /** User-set kill switch: "1" disables the whole trigger. */
3681
+ DISABLED: "HIVEMIND_SKILLOPT_DISABLED",
3682
+ /** Recursion guard the trigger sets on the spawned worker so the worker can't re-arm. */
3683
+ WORKER: "HIVEMIND_SKILLOPT_WORKER",
3684
+ /** Worker inputs, handed trigger → worker via the child env. */
3685
+ SESSION: "HIVEMIND_SKILLOPT_SESSION",
3686
+ SKILL: "HIVEMIND_SKILLOPT_SKILL",
3687
+ REACTION: "HIVEMIND_SKILLOPT_REACTION",
3688
+ TOOL_USE_ID: "HIVEMIND_SKILLOPT_TOOL_USE_ID",
3689
+ /** Which agent's CLI runs the judge/proposer (claude_code/codex/hermes/cursor/pi). */
3690
+ AGENT: "HIVEMIND_SKILLOPT_AGENT",
3691
+ /** K-message judgment-window size override. */
3692
+ JUDGE_WINDOW: "HIVEMIND_SKILLOPT_JUDGE_WINDOW"
3693
+ };
3694
+
3695
+ // dist/src/skillify/skillopt-trigger.js
3696
+ var DEFAULT_JUDGE_WINDOW = 3;
3697
+ function judgeWindow(env = process.env) {
3698
+ const n = Number(env[SKILLOPT_ENV.JUDGE_WINDOW]);
3699
+ return Number.isFinite(n) && n > 0 ? Math.floor(n) : DEFAULT_JUDGE_WINDOW;
3700
+ }
3701
+ function defaultIsOrgSkill(skillRef) {
3702
+ try {
3703
+ return loadManifest().entries.some((e) => e.dirName === skillRef);
3704
+ } catch {
3705
+ return false;
3706
+ }
3707
+ }
3708
+ function pendingFile(sessionId) {
3709
+ const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 200);
3710
+ return path.join(getStateDir(), "skillopt", "pending", `${safe}.json`);
3711
+ }
3712
+ var fileStore = {
3713
+ load(sessionId) {
3714
+ try {
3715
+ return JSON.parse(fs.readFileSync(pendingFile(sessionId), "utf8"));
3716
+ } catch {
3717
+ return null;
3718
+ }
3719
+ },
3720
+ save(sessionId, p) {
3721
+ try {
3722
+ const f = pendingFile(sessionId);
3723
+ if (p === null) {
3724
+ try {
3725
+ fs.unlinkSync(f);
3726
+ } catch {
3727
+ }
3728
+ return;
3729
+ }
3730
+ fs.mkdirSync(path.dirname(f), { recursive: true });
3731
+ const tmp = `${f}.${process.pid}.tmp`;
3732
+ fs.writeFileSync(tmp, JSON.stringify(p));
3733
+ fs.renameSync(tmp, f);
3734
+ } catch {
3735
+ }
3736
+ }
3737
+ };
3738
+ function markSkillPending(sessionId, skillRef, toolUseId, deps = {}) {
3739
+ if (!sessionId || !skillRef)
3740
+ return false;
3741
+ if (!splitOrgSkill(skillRef))
3742
+ return false;
3743
+ if (!(deps.isOrgSkill ?? defaultIsOrgSkill)(skillRef))
3744
+ return false;
3745
+ (deps.store ?? fileStore).save(sessionId, { skill: skillRef, budget: judgeWindow(deps.env ?? process.env), toolUseId });
3746
+ return true;
3747
+ }
3748
+
3749
+ // dist/src/hooks/shared/skillopt-hook.js
3750
+ function skillRefFromSkillFileRead(toolName, toolInput) {
3751
+ if (/^read$/i.test(toolName))
3752
+ return pathToSkillRef(toolInput?.path);
3753
+ return pathToSkillRef(toolInput?.command);
3754
+ }
3755
+ function armSkillOptOnSkillUse(sessionId, toolName, toolInput, toolUseId) {
3756
+ try {
3757
+ if (process.env[SKILLOPT_ENV.DISABLED] === "1")
3758
+ return;
3759
+ let ref = null;
3760
+ if (toolName === "Skill") {
3761
+ const s = toolInput?.skill;
3762
+ ref = typeof s === "string" ? s : null;
3763
+ } else {
3764
+ ref = skillRefFromSkillFileRead(toolName, toolInput);
3765
+ }
3766
+ if (ref)
3767
+ markSkillPending(sessionId, ref, toolUseId);
3768
+ } catch {
3769
+ }
3770
+ }
3771
+
3549
3772
  // dist/src/hooks/hermes/pre-tool-use.js
3550
3773
  var log5 = (msg) => log("hermes-pre-tool-use", msg);
3551
3774
  async function main() {
3552
3775
  const input = await readStdin();
3776
+ armSkillOptOnSkillUse(input.session_id ?? "", input.tool_name ?? "", input.tool_input);
3553
3777
  if (input.tool_name !== "terminal")
3554
3778
  return;
3555
3779
  const ti = input.tool_input;