@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.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/bundle/cli.js +140 -94
- package/codex/bundle/capture.js +232 -72
- package/codex/bundle/commands/auth-login.js +14 -10
- package/codex/bundle/embeddings/embed-daemon.js +9 -5
- package/codex/bundle/graph-on-stop.js +32 -28
- package/codex/bundle/graph-pull-worker.js +27 -23
- package/codex/bundle/pre-tool-use.js +366 -123
- package/codex/bundle/session-start-setup.js +18 -14
- package/codex/bundle/session-start.js +26 -22
- package/codex/bundle/shell/deeplake-shell.js +30 -26
- package/codex/bundle/skillify-worker.js +14 -10
- package/codex/bundle/skillopt-worker.js +2061 -0
- package/codex/bundle/stop.js +50 -45
- package/codex/bundle/wiki-worker.js +18 -14
- package/cursor/bundle/capture.js +71 -44
- package/cursor/bundle/commands/auth-login.js +14 -10
- package/cursor/bundle/embeddings/embed-daemon.js +9 -5
- package/cursor/bundle/graph-on-stop.js +32 -28
- package/cursor/bundle/graph-pull-worker.js +27 -23
- package/cursor/bundle/pre-tool-use.js +28 -24
- package/cursor/bundle/session-end.js +40 -36
- package/cursor/bundle/session-start.js +39 -35
- package/cursor/bundle/shell/deeplake-shell.js +30 -26
- package/cursor/bundle/skillify-worker.js +14 -10
- package/cursor/bundle/wiki-worker.js +18 -14
- package/hermes/bundle/capture.js +235 -85
- package/hermes/bundle/commands/auth-login.js +14 -10
- package/hermes/bundle/embeddings/embed-daemon.js +9 -5
- package/hermes/bundle/graph-on-stop.js +32 -28
- package/hermes/bundle/graph-pull-worker.js +27 -23
- package/hermes/bundle/pre-tool-use.js +298 -74
- package/hermes/bundle/session-end.js +40 -36
- package/hermes/bundle/session-start.js +39 -35
- package/hermes/bundle/shell/deeplake-shell.js +30 -26
- package/hermes/bundle/skillify-worker.js +14 -10
- package/hermes/bundle/skillopt-worker.js +2061 -0
- package/hermes/bundle/wiki-worker.js +18 -14
- package/mcp/bundle/server.js +15 -11
- package/openclaw/dist/index.js +11 -7
- package/openclaw/dist/skillify-worker.js +14 -10
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/package.json +1 -1
- package/pi/extension-source/hivemind.ts +93 -0
package/hermes/bundle/capture.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
370
|
-
const r = resolve(
|
|
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
|
|
379
|
+
const path2 = queuePath();
|
|
376
380
|
const home = resolve(homedir3());
|
|
377
|
-
if (!_isQueuePathInsideHome(
|
|
378
|
-
throw new Error(`notifications-queue write blocked: ${
|
|
381
|
+
if (!_isQueuePathInsideHome(path2, home)) {
|
|
382
|
+
throw new Error(`notifications-queue write blocked: ${path2} is outside ${home}`);
|
|
379
383
|
}
|
|
380
|
-
|
|
381
|
-
const 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,
|
|
387
|
+
renameSync(tmp, path2);
|
|
384
388
|
}
|
|
385
389
|
async function withQueueLock(fn) {
|
|
386
|
-
const
|
|
387
|
-
|
|
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(
|
|
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(
|
|
402
|
+
const age = Date.now() - statSync(path2).mtimeMs;
|
|
399
403
|
if (age > LOCK_STALE_MS) {
|
|
400
|
-
unlinkSync(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
1406
|
-
if (!existsSync4(
|
|
1409
|
+
const path2 = _configPath();
|
|
1410
|
+
if (!existsSync4(path2)) {
|
|
1407
1411
|
_cache = {};
|
|
1408
1412
|
return _cache;
|
|
1409
1413
|
}
|
|
1410
1414
|
try {
|
|
1411
|
-
const raw = readFileSync6(
|
|
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
|
|
1423
|
-
const dir =
|
|
1426
|
+
const path2 = _configPath();
|
|
1427
|
+
const dir = dirname2(path2);
|
|
1424
1428
|
if (!existsSync4(dir))
|
|
1425
|
-
|
|
1426
|
-
const tmp = `${
|
|
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,
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
1560
|
+
const parent = dirname3(link);
|
|
1557
1561
|
if (!existsSync5(parent))
|
|
1558
|
-
|
|
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
|
|
1574
|
-
import { dirname as
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1714
|
-
import { writeFileSync as writeFileSync6, mkdirSync as
|
|
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
|
|
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
|
|
1725
|
+
const path2 = join11(hooksDir, filename);
|
|
1722
1726
|
return {
|
|
1723
|
-
path,
|
|
1727
|
+
path: path2,
|
|
1724
1728
|
log(msg) {
|
|
1725
1729
|
try {
|
|
1726
|
-
|
|
1727
|
-
appendFileSync2(
|
|
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
|
|
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 =
|
|
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
|
|
1784
|
+
const spawn3 = deps.spawn ?? nodeSpawn;
|
|
1781
1785
|
const execPath = deps.execPath ?? process.execPath;
|
|
1782
1786
|
try {
|
|
1783
|
-
const child =
|
|
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
|
-
|
|
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
|
|
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
|
|
1899
|
-
import { writeFileSync as writeFileSync7, mkdirSync as
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
2464
|
+
var log6 = (msg) => log("hermes-capture", msg);
|
|
2322
2465
|
function resolveEmbedDaemonPath() {
|
|
2323
|
-
return
|
|
2466
|
+
return join22(dirname9(fileURLToPath4(import.meta.url)), "embeddings", "embed-daemon.js");
|
|
2324
2467
|
}
|
|
2325
|
-
var __bundleDir =
|
|
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
|
-
|
|
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
|
-
|
|
2515
|
+
log6(`pre_llm_call: no prompt found in extra`);
|
|
2368
2516
|
return;
|
|
2369
2517
|
}
|
|
2370
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2535
|
+
log6(`post_llm_call: no response found in extra`);
|
|
2387
2536
|
return;
|
|
2388
2537
|
}
|
|
2389
|
-
|
|
2538
|
+
log6(`assistant session=${sessionId}`);
|
|
2390
2539
|
entry = { id: crypto.randomUUID(), ...meta, type: "assistant_message", content: text };
|
|
2391
2540
|
} else {
|
|
2392
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2606
|
+
log6(`periodic trigger error: ${e.message}`);
|
|
2457
2607
|
}
|
|
2458
2608
|
}
|
|
2459
2609
|
main().catch((e) => {
|
|
2460
|
-
|
|
2610
|
+
log6(`fatal: ${e.message}`);
|
|
2461
2611
|
process.exit(0);
|
|
2462
2612
|
});
|