@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
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// dist/src/hooks/hermes/wiki-worker.js
|
|
4
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, appendFileSync as appendFileSync2, mkdirSync as
|
|
4
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, appendFileSync as appendFileSync2, mkdirSync as mkdirSync4, rmSync } from "node:fs";
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
|
-
import { dirname as
|
|
6
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
|
|
9
9
|
// dist/src/hooks/summary-state.js
|
|
10
|
-
import { readFileSync, writeFileSync, writeSync, mkdirSync, renameSync, existsSync, unlinkSync, openSync, closeSync, statSync } from "node:fs";
|
|
10
|
+
import { readFileSync, writeFileSync, writeSync, mkdirSync as mkdirSync2, renameSync, existsSync, unlinkSync, openSync, closeSync, statSync } from "node:fs";
|
|
11
11
|
import { homedir as homedir2 } from "node:os";
|
|
12
12
|
import { join as join2 } from "node:path";
|
|
13
13
|
|
|
14
14
|
// dist/src/utils/debug.js
|
|
15
|
-
import { appendFileSync } from "node:fs";
|
|
16
|
-
import { join } from "node:path";
|
|
15
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
16
|
+
import { dirname, join } from "node:path";
|
|
17
17
|
import { homedir } from "node:os";
|
|
18
18
|
var LOG = join(homedir(), ".deeplake", "hook-debug.log");
|
|
19
19
|
function isDebug() {
|
|
@@ -22,8 +22,12 @@ function isDebug() {
|
|
|
22
22
|
function log(tag, msg) {
|
|
23
23
|
if (!isDebug())
|
|
24
24
|
return;
|
|
25
|
-
|
|
25
|
+
try {
|
|
26
|
+
mkdirSync(dirname(LOG), { recursive: true });
|
|
27
|
+
appendFileSync(LOG, `${(/* @__PURE__ */ new Date()).toISOString()} [${tag}] ${msg}
|
|
26
28
|
`);
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
// dist/src/hooks/summary-state.js
|
|
@@ -47,14 +51,14 @@ function readState(sessionId) {
|
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
53
|
function writeState(sessionId, state) {
|
|
50
|
-
|
|
54
|
+
mkdirSync2(STATE_DIR, { recursive: true });
|
|
51
55
|
const p = statePath(sessionId);
|
|
52
56
|
const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
|
|
53
57
|
writeFileSync(tmp, JSON.stringify(state));
|
|
54
58
|
renameSync(tmp, p);
|
|
55
59
|
}
|
|
56
60
|
function withRmwLock(sessionId, fn) {
|
|
57
|
-
|
|
61
|
+
mkdirSync2(STATE_DIR, { recursive: true });
|
|
58
62
|
const rmwLock = statePath(sessionId) + ".rmw";
|
|
59
63
|
const deadline = Date.now() + 2e3;
|
|
60
64
|
let fd = null;
|
|
@@ -543,9 +547,9 @@ import { join as join5 } from "node:path";
|
|
|
543
547
|
import { pathToFileURL } from "node:url";
|
|
544
548
|
|
|
545
549
|
// dist/src/user-config.js
|
|
546
|
-
import { existsSync as existsSync3, mkdirSync as
|
|
550
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
547
551
|
import { homedir as homedir4 } from "node:os";
|
|
548
|
-
import { dirname, join as join4 } from "node:path";
|
|
552
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
549
553
|
var _configPath = () => process.env.HIVEMIND_CONFIG_PATH ?? join4(homedir4(), ".deeplake", "config.json");
|
|
550
554
|
var _cache = null;
|
|
551
555
|
var _migrated = false;
|
|
@@ -570,9 +574,9 @@ function writeUserConfig(patch) {
|
|
|
570
574
|
const current = readUserConfig();
|
|
571
575
|
const merged = deepMerge(current, patch);
|
|
572
576
|
const path = _configPath();
|
|
573
|
-
const dir =
|
|
577
|
+
const dir = dirname2(path);
|
|
574
578
|
if (!existsSync3(dir))
|
|
575
|
-
|
|
579
|
+
mkdirSync3(dir, { recursive: true });
|
|
576
580
|
const tmp = `${path}.tmp.${process.pid}`;
|
|
577
581
|
writeFileSync2(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
578
582
|
renameSync2(tmp, path);
|
|
@@ -671,7 +675,7 @@ var tmpJsonl = join6(tmpDir, "session.jsonl");
|
|
|
671
675
|
var tmpSummary = join6(tmpDir, "summary.md");
|
|
672
676
|
function wlog(msg) {
|
|
673
677
|
try {
|
|
674
|
-
|
|
678
|
+
mkdirSync4(cfg.hooksDir, { recursive: true });
|
|
675
679
|
appendFileSync2(cfg.wikiLog, `[${(/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)}] wiki-worker(${cfg.sessionId}): ${msg}
|
|
676
680
|
`);
|
|
677
681
|
} catch {
|
|
@@ -773,7 +777,7 @@ async function main() {
|
|
|
773
777
|
let embedding = null;
|
|
774
778
|
if (!embeddingsDisabled()) {
|
|
775
779
|
try {
|
|
776
|
-
const daemonEntry = join6(
|
|
780
|
+
const daemonEntry = join6(dirname3(fileURLToPath(import.meta.url)), "embeddings", "embed-daemon.js");
|
|
777
781
|
embedding = await new EmbedClient({ daemonEntry }).embed(text, "document");
|
|
778
782
|
} catch (e) {
|
|
779
783
|
wlog(`summary embedding failed, writing NULL: ${e.message}`);
|
package/mcp/bundle/server.js
CHANGED
|
@@ -6809,7 +6809,7 @@ __export(index_marker_store_exports, {
|
|
|
6809
6809
|
hasFreshIndexMarker: () => hasFreshIndexMarker,
|
|
6810
6810
|
writeIndexMarker: () => writeIndexMarker
|
|
6811
6811
|
});
|
|
6812
|
-
import { existsSync as existsSync2, mkdirSync as
|
|
6812
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
6813
6813
|
import { join as join6 } from "node:path";
|
|
6814
6814
|
import { tmpdir } from "node:os";
|
|
6815
6815
|
function getIndexMarkerDir() {
|
|
@@ -6833,7 +6833,7 @@ function hasFreshIndexMarker(markerPath) {
|
|
|
6833
6833
|
}
|
|
6834
6834
|
}
|
|
6835
6835
|
function writeIndexMarker(markerPath) {
|
|
6836
|
-
|
|
6836
|
+
mkdirSync5(getIndexMarkerDir(), { recursive: true });
|
|
6837
6837
|
writeFileSync4(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
6838
6838
|
}
|
|
6839
6839
|
var INDEX_MARKER_TTL_MS;
|
|
@@ -23352,8 +23352,8 @@ function loadConfig() {
|
|
|
23352
23352
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
23353
23353
|
|
|
23354
23354
|
// dist/src/utils/debug.js
|
|
23355
|
-
import { appendFileSync } from "node:fs";
|
|
23356
|
-
import { join as join4 } from "node:path";
|
|
23355
|
+
import { appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
|
|
23356
|
+
import { dirname, join as join4 } from "node:path";
|
|
23357
23357
|
import { homedir as homedir4 } from "node:os";
|
|
23358
23358
|
var LOG = join4(homedir4(), ".deeplake", "hook-debug.log");
|
|
23359
23359
|
function isDebug() {
|
|
@@ -23362,8 +23362,12 @@ function isDebug() {
|
|
|
23362
23362
|
function log(tag, msg) {
|
|
23363
23363
|
if (!isDebug())
|
|
23364
23364
|
return;
|
|
23365
|
-
|
|
23365
|
+
try {
|
|
23366
|
+
mkdirSync3(dirname(LOG), { recursive: true });
|
|
23367
|
+
appendFileSync(LOG, `${(/* @__PURE__ */ new Date()).toISOString()} [${tag}] ${msg}
|
|
23366
23368
|
`);
|
|
23369
|
+
} catch {
|
|
23370
|
+
}
|
|
23367
23371
|
}
|
|
23368
23372
|
|
|
23369
23373
|
// dist/src/utils/sql.js
|
|
@@ -23563,7 +23567,7 @@ async function healMissingColumns(args) {
|
|
|
23563
23567
|
}
|
|
23564
23568
|
|
|
23565
23569
|
// dist/src/notifications/queue.js
|
|
23566
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync, mkdirSync as
|
|
23570
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync, mkdirSync as mkdirSync4, openSync, closeSync, unlinkSync as unlinkSync2, statSync } from "node:fs";
|
|
23567
23571
|
import { join as join5, resolve } from "node:path";
|
|
23568
23572
|
import { homedir as homedir5 } from "node:os";
|
|
23569
23573
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
@@ -23601,14 +23605,14 @@ function writeQueue(q) {
|
|
|
23601
23605
|
if (!_isQueuePathInsideHome(path, home)) {
|
|
23602
23606
|
throw new Error(`notifications-queue write blocked: ${path} is outside ${home}`);
|
|
23603
23607
|
}
|
|
23604
|
-
|
|
23608
|
+
mkdirSync4(join5(home, ".deeplake"), { recursive: true, mode: 448 });
|
|
23605
23609
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
23606
23610
|
writeFileSync3(tmp, JSON.stringify(q, null, 2), { mode: 384 });
|
|
23607
23611
|
renameSync(tmp, path);
|
|
23608
23612
|
}
|
|
23609
23613
|
async function withQueueLock(fn) {
|
|
23610
23614
|
const path = lockPath();
|
|
23611
|
-
|
|
23615
|
+
mkdirSync4(join5(homedir5(), ".deeplake"), { recursive: true, mode: 448 });
|
|
23612
23616
|
let fd = null;
|
|
23613
23617
|
for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
|
|
23614
23618
|
try {
|
|
@@ -24561,8 +24565,8 @@ import { readFileSync as readFileSync7 } from "node:fs";
|
|
|
24561
24565
|
import { join as join8 } from "node:path";
|
|
24562
24566
|
|
|
24563
24567
|
// dist/src/cli/util.js
|
|
24564
|
-
import { existsSync as existsSync3, mkdirSync as
|
|
24565
|
-
import { join as join7, dirname } from "node:path";
|
|
24568
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5, cpSync, symlinkSync, unlinkSync as unlinkSync3, lstatSync } from "node:fs";
|
|
24569
|
+
import { join as join7, dirname as dirname2 } from "node:path";
|
|
24566
24570
|
import { homedir as homedir6 } from "node:os";
|
|
24567
24571
|
import { fileURLToPath } from "node:url";
|
|
24568
24572
|
import { createInterface } from "node:readline";
|
|
@@ -24576,7 +24580,7 @@ function pkgRoot() {
|
|
|
24576
24580
|
return dir;
|
|
24577
24581
|
} catch {
|
|
24578
24582
|
}
|
|
24579
|
-
const parent =
|
|
24583
|
+
const parent = dirname2(dir);
|
|
24580
24584
|
if (parent === dir)
|
|
24581
24585
|
break;
|
|
24582
24586
|
dir = parent;
|
package/openclaw/dist/index.js
CHANGED
|
@@ -198,8 +198,8 @@ async function switchWorkspace(workspaceId) {
|
|
|
198
198
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
199
199
|
|
|
200
200
|
// src/utils/debug.ts
|
|
201
|
-
import { appendFileSync } from "node:fs";
|
|
202
|
-
import { join as join2 } from "node:path";
|
|
201
|
+
import { appendFileSync, mkdirSync as mkdirSync2 } from "node:fs";
|
|
202
|
+
import { dirname, join as join2 } from "node:path";
|
|
203
203
|
import { homedir as homedir2 } from "node:os";
|
|
204
204
|
var LOG = join2(homedir2(), ".deeplake", "hook-debug.log");
|
|
205
205
|
function isDebug() {
|
|
@@ -207,8 +207,12 @@ function isDebug() {
|
|
|
207
207
|
}
|
|
208
208
|
function log(tag, msg) {
|
|
209
209
|
if (!isDebug()) return;
|
|
210
|
-
|
|
210
|
+
try {
|
|
211
|
+
mkdirSync2(dirname(LOG), { recursive: true });
|
|
212
|
+
appendFileSync(LOG, `${(/* @__PURE__ */ new Date()).toISOString()} [${tag}] ${msg}
|
|
211
213
|
`);
|
|
214
|
+
} catch {
|
|
215
|
+
}
|
|
212
216
|
}
|
|
213
217
|
|
|
214
218
|
// src/utils/sql.ts
|
|
@@ -406,7 +410,7 @@ async function healMissingColumns(args) {
|
|
|
406
410
|
}
|
|
407
411
|
|
|
408
412
|
// src/notifications/queue.ts
|
|
409
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync, mkdirSync as
|
|
413
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync, mkdirSync as mkdirSync3, openSync, closeSync, unlinkSync, statSync } from "node:fs";
|
|
410
414
|
import { join as join3, resolve } from "node:path";
|
|
411
415
|
import { homedir as homedir3 } from "node:os";
|
|
412
416
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
@@ -444,14 +448,14 @@ function writeQueue(q) {
|
|
|
444
448
|
if (!_isQueuePathInsideHome(path, home)) {
|
|
445
449
|
throw new Error(`notifications-queue write blocked: ${path} is outside ${home}`);
|
|
446
450
|
}
|
|
447
|
-
|
|
451
|
+
mkdirSync3(join3(home, ".deeplake"), { recursive: true, mode: 448 });
|
|
448
452
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
449
453
|
writeFileSync2(tmp, JSON.stringify(q, null, 2), { mode: 384 });
|
|
450
454
|
renameSync(tmp, path);
|
|
451
455
|
}
|
|
452
456
|
async function withQueueLock(fn) {
|
|
453
457
|
const path = lockPath();
|
|
454
|
-
|
|
458
|
+
mkdirSync3(join3(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
|
|
455
459
|
let fd = null;
|
|
456
460
|
for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
|
|
457
461
|
try {
|
|
@@ -1828,7 +1832,7 @@ function extractLatestVersion(body) {
|
|
|
1828
1832
|
return typeof v === "string" && v.length > 0 ? v : null;
|
|
1829
1833
|
}
|
|
1830
1834
|
function getInstalledVersion() {
|
|
1831
|
-
return "0.7.
|
|
1835
|
+
return "0.7.81".length > 0 ? "0.7.81" : null;
|
|
1832
1836
|
}
|
|
1833
1837
|
function isNewer(latest, current) {
|
|
1834
1838
|
const parse = (v) => v.replace(/-.*$/, "").split(".").map(Number);
|
|
@@ -6,8 +6,8 @@ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsS
|
|
|
6
6
|
import { join as join7 } from "node:path";
|
|
7
7
|
|
|
8
8
|
// dist/src/utils/debug.js
|
|
9
|
-
import { appendFileSync } from "node:fs";
|
|
10
|
-
import { join } from "node:path";
|
|
9
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
var LOG = join(homedir(), ".deeplake", "hook-debug.log");
|
|
13
13
|
function isDebug() {
|
|
@@ -19,8 +19,12 @@ function utcTimestamp(d = /* @__PURE__ */ new Date()) {
|
|
|
19
19
|
function log(tag, msg) {
|
|
20
20
|
if (!isDebug())
|
|
21
21
|
return;
|
|
22
|
-
|
|
22
|
+
try {
|
|
23
|
+
mkdirSync(dirname(LOG), { recursive: true });
|
|
24
|
+
appendFileSync(LOG, `${(/* @__PURE__ */ new Date()).toISOString()} [${tag}] ${msg}
|
|
23
25
|
`);
|
|
26
|
+
} catch {
|
|
27
|
+
}
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
// dist/src/utils/client-header.js
|
|
@@ -64,7 +68,7 @@ function extractPairs(rows) {
|
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
// dist/src/skillify/skill-writer.js
|
|
67
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
71
|
+
import { existsSync, mkdirSync as mkdirSync2, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
68
72
|
import { homedir as homedir2 } from "node:os";
|
|
69
73
|
import { join as join2 } from "node:path";
|
|
70
74
|
function assertValidSkillName(name) {
|
|
@@ -166,7 +170,7 @@ function writeNewSkill(args) {
|
|
|
166
170
|
if (existsSync(path)) {
|
|
167
171
|
throw new Error(`skill already exists at ${path}; use mergeSkill`);
|
|
168
172
|
}
|
|
169
|
-
|
|
173
|
+
mkdirSync2(dir, { recursive: true });
|
|
170
174
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
171
175
|
const author = args.author && args.author.length > 0 ? args.author : void 0;
|
|
172
176
|
const contributors = author ? [author] : [];
|
|
@@ -755,7 +759,7 @@ function resolveRecordScope(args) {
|
|
|
755
759
|
}
|
|
756
760
|
|
|
757
761
|
// dist/src/skillify/state.js
|
|
758
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, writeSync, mkdirSync as
|
|
762
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, writeSync, mkdirSync as mkdirSync3, renameSync as renameSync2, rmdirSync, existsSync as existsSync4, lstatSync, unlinkSync, openSync, closeSync } from "node:fs";
|
|
759
763
|
import { join as join6 } from "node:path";
|
|
760
764
|
|
|
761
765
|
// dist/src/utils/repo-identity.js
|
|
@@ -765,7 +769,7 @@ import { basename, resolve } from "node:path";
|
|
|
765
769
|
|
|
766
770
|
// dist/src/skillify/legacy-migration.js
|
|
767
771
|
import { existsSync as existsSync3, renameSync } from "node:fs";
|
|
768
|
-
import { dirname, join as join5 } from "node:path";
|
|
772
|
+
import { dirname as dirname2, join as join5 } from "node:path";
|
|
769
773
|
|
|
770
774
|
// dist/src/skillify/state-dir.js
|
|
771
775
|
import { homedir as homedir4 } from "node:os";
|
|
@@ -785,7 +789,7 @@ function migrateLegacyStateDir() {
|
|
|
785
789
|
return;
|
|
786
790
|
attempted = true;
|
|
787
791
|
const current = getStateDir();
|
|
788
|
-
const legacy = join5(
|
|
792
|
+
const legacy = join5(dirname2(current), "skilify");
|
|
789
793
|
if (!existsSync3(legacy))
|
|
790
794
|
return;
|
|
791
795
|
if (existsSync3(current))
|
|
@@ -829,7 +833,7 @@ function readState(projectKey) {
|
|
|
829
833
|
}
|
|
830
834
|
function writeState(projectKey, state) {
|
|
831
835
|
migrateLegacyStateDir();
|
|
832
|
-
|
|
836
|
+
mkdirSync3(getStateDir(), { recursive: true });
|
|
833
837
|
const p = statePath(projectKey);
|
|
834
838
|
const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
|
|
835
839
|
writeFileSync2(tmp, JSON.stringify(state, null, 2));
|
|
@@ -837,7 +841,7 @@ function writeState(projectKey, state) {
|
|
|
837
841
|
}
|
|
838
842
|
function withRmwLock(projectKey, fn) {
|
|
839
843
|
migrateLegacyStateDir();
|
|
840
|
-
|
|
844
|
+
mkdirSync3(getStateDir(), { recursive: true });
|
|
841
845
|
const rmw = lockPath(projectKey) + ".rmw";
|
|
842
846
|
const deadline = Date.now() + 2e3;
|
|
843
847
|
let fd = null;
|
package/openclaw/package.json
CHANGED
package/package.json
CHANGED
|
@@ -466,6 +466,94 @@ function runAutopullWorker(): void {
|
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
+
// ---------- SkillOpt: arm on org-skill use, react on the next user message ------------
|
|
470
|
+
// Mirrors the CC PreToolUse/UserPromptSubmit wiring, inlined because this extension is raw
|
|
471
|
+
// .ts with zero non-builtin deps (it can't import the skillify trigger). pi has no first-class
|
|
472
|
+
// `Skill` tool — it USES a skill by READING its SKILL.md — so we arm on a tool_result whose
|
|
473
|
+
// path is .../skills/<name--author>/SKILL.md, then on the next user prompt (the reaction) spawn
|
|
474
|
+
// the bundled skillopt-worker to judge + improve. Env-var names are the cross-process contract
|
|
475
|
+
// with the worker (SKILLOPT_ENV in src/skillify/skillopt-env.ts) — kept as literals here since
|
|
476
|
+
// the extension can't import. Fully swallowed; never blocks pi. Both call sites sit AFTER the
|
|
477
|
+
// handler's captureEnabled check, so the worker's own pi-judge subprocess (HIVEMIND_CAPTURE=false)
|
|
478
|
+
// can't re-arm/re-react — that's the recursion guard.
|
|
479
|
+
const PI_SKILLOPT_WORKER_PATH = join(homedir(), ".pi", "agent", "hivemind", "skillopt-worker.js");
|
|
480
|
+
// Mirror getStateDir()'s contract: a non-empty (trimmed) HIVEMIND_STATE_DIR overrides the default
|
|
481
|
+
// ~/.deeplake/state/skillify root, so pi's pending state co-locates with the rest of Skillify
|
|
482
|
+
// (and test-isolation overrides apply here too, not just in the shared trigger).
|
|
483
|
+
const SKILLOPT_STATE_ROOT = (typeof process.env.HIVEMIND_STATE_DIR === "string" && process.env.HIVEMIND_STATE_DIR.trim())
|
|
484
|
+
? process.env.HIVEMIND_STATE_DIR.trim()
|
|
485
|
+
: join(homedir(), ".deeplake", "state", "skillify");
|
|
486
|
+
const SKILLOPT_PENDING_DIR = join(SKILLOPT_STATE_ROOT, "skillopt", "pending");
|
|
487
|
+
const SKILLOPT_JUDGE_WINDOW = 3; // K reactions to keep judging after a skill use (DEFAULT_JUDGE_WINDOW)
|
|
488
|
+
|
|
489
|
+
/** Recover an org-skill ref (name--author) from a path that loads a skill's SKILL.md, else null. */
|
|
490
|
+
function skilloptRefFromPath(p: unknown): string | null {
|
|
491
|
+
if (typeof p !== "string") return null;
|
|
492
|
+
const m = p.match(/\/skills\/([^/]+)\/SKILL\.md$/);
|
|
493
|
+
if (!m) return null;
|
|
494
|
+
const ref = m[1];
|
|
495
|
+
// org shape only: name--author, no plugin namespace / path separators / traversal.
|
|
496
|
+
if (ref.includes(":") || ref.includes("/") || ref.includes("\\") || ref.includes("..")) return null;
|
|
497
|
+
const i = ref.lastIndexOf("--");
|
|
498
|
+
return i > 0 && i + 2 < ref.length ? ref : null;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function skilloptPendingFile(sessionId: string): string {
|
|
502
|
+
const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 200);
|
|
503
|
+
return join(SKILLOPT_PENDING_DIR, `${safe}.json`);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** tool_result: pi read an org skill's SKILL.md → open a K-message judgment window. */
|
|
507
|
+
function skilloptArm(sessionId: string, toolName: unknown, toolInput: any, toolCallId: unknown): void {
|
|
508
|
+
try {
|
|
509
|
+
if (process.env.HIVEMIND_SKILLOPT_DISABLED === "1") return;
|
|
510
|
+
// Arm only on a READ of the SKILL.md — USING a skill is reading it. An edit/write of a
|
|
511
|
+
// SKILL.md (even one whose input carries a matching path) must NOT open a judgment window.
|
|
512
|
+
if (!/^read/i.test(String(toolName ?? ""))) return;
|
|
513
|
+
const ref = skilloptRefFromPath(toolInput?.path ?? toolInput?.file ?? toolInput?.filePath);
|
|
514
|
+
if (!ref) return;
|
|
515
|
+
mkdirSync(SKILLOPT_PENDING_DIR, { recursive: true });
|
|
516
|
+
const f = skilloptPendingFile(sessionId);
|
|
517
|
+
const tmp = `${f}.${process.pid}.tmp`;
|
|
518
|
+
writeFileSync(tmp, JSON.stringify({ skill: ref, budget: SKILLOPT_JUDGE_WINDOW, toolUseId: typeof toolCallId === "string" ? toolCallId : undefined }));
|
|
519
|
+
renameSync(tmp, f);
|
|
520
|
+
logHm(`skillopt: armed ${ref} for ${sessionId}`);
|
|
521
|
+
} catch (e: any) { logHm(`skillopt arm swallowed: ${e?.message ?? e}`); }
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/** input: the user's reaction → spawn the detached worker to judge the pending skill; spend budget. */
|
|
525
|
+
function skilloptReact(sessionId: string, reaction: string): void {
|
|
526
|
+
try {
|
|
527
|
+
if (process.env.HIVEMIND_SKILLOPT_DISABLED === "1" || process.env.HIVEMIND_WIKI_WORKER === "1") return;
|
|
528
|
+
if (!reaction.trim()) return;
|
|
529
|
+
const f = skilloptPendingFile(sessionId);
|
|
530
|
+
let p: { skill?: string; budget?: number; toolUseId?: string };
|
|
531
|
+
try { p = JSON.parse(readFileSync(f, "utf8")); } catch { return; } // no window open → no-op
|
|
532
|
+
if (!p?.skill || typeof p.budget !== "number") return;
|
|
533
|
+
if (!existsSync(PI_SKILLOPT_WORKER_PATH)) { logHm(`skillopt: worker bundle missing at ${PI_SKILLOPT_WORKER_PATH} — run 'hivemind pi install'`); return; }
|
|
534
|
+
// Spend one message of the budget; close the window when exhausted.
|
|
535
|
+
try {
|
|
536
|
+
if (p.budget - 1 <= 0) { unlinkSync(f); }
|
|
537
|
+
else { const tmp = `${f}.${process.pid}.tmp`; writeFileSync(tmp, JSON.stringify({ ...p, budget: p.budget - 1 })); renameSync(tmp, f); }
|
|
538
|
+
} catch { /* best-effort */ }
|
|
539
|
+
const child = spawn(process.execPath, [PI_SKILLOPT_WORKER_PATH], {
|
|
540
|
+
detached: true,
|
|
541
|
+
stdio: "ignore",
|
|
542
|
+
env: {
|
|
543
|
+
...process.env,
|
|
544
|
+
HIVEMIND_SKILLOPT_WORKER: "1", // recursion guard (worker won't re-fire the trigger)
|
|
545
|
+
HIVEMIND_SKILLOPT_SESSION: sessionId,
|
|
546
|
+
HIVEMIND_SKILLOPT_SKILL: p.skill,
|
|
547
|
+
HIVEMIND_SKILLOPT_REACTION: reaction.slice(0, 8000),
|
|
548
|
+
HIVEMIND_SKILLOPT_AGENT: "pi", // judge/proposer run on pi (the user's own agent)
|
|
549
|
+
...(p.toolUseId ? { HIVEMIND_SKILLOPT_TOOL_USE_ID: p.toolUseId } : {}),
|
|
550
|
+
},
|
|
551
|
+
});
|
|
552
|
+
child.unref();
|
|
553
|
+
logHm(`skillopt: spawned worker for ${p.skill} in ${sessionId} (agent=pi)`);
|
|
554
|
+
} catch (e: any) { logHm(`skillopt react swallowed: ${e?.message ?? e}`); }
|
|
555
|
+
}
|
|
556
|
+
|
|
469
557
|
interface SummaryState {
|
|
470
558
|
lastSummaryAt: number;
|
|
471
559
|
lastSummaryCount: number;
|
|
@@ -1255,6 +1343,8 @@ export default function hivemindExtension(pi: ExtensionAPI): void {
|
|
|
1255
1343
|
} catch (e: any) {
|
|
1256
1344
|
logHm(`input: writeSessionRow swallowed: ${e?.message ?? e}`);
|
|
1257
1345
|
}
|
|
1346
|
+
// SkillOpt: this prompt is the user's reaction to a recently-used org skill. Swallowed.
|
|
1347
|
+
skilloptReact(sessionId, text);
|
|
1258
1348
|
maybeTriggerPeriodicSummary(creds, sessionId, cwd);
|
|
1259
1349
|
});
|
|
1260
1350
|
|
|
@@ -1286,6 +1376,9 @@ export default function hivemindExtension(pi: ExtensionAPI): void {
|
|
|
1286
1376
|
} catch (e: any) {
|
|
1287
1377
|
logHm(`tool_result: writeSessionRow swallowed: ${e?.message ?? e}`);
|
|
1288
1378
|
}
|
|
1379
|
+
// SkillOpt: pi USES an org skill by reading its SKILL.md — arm the judgment window on
|
|
1380
|
+
// a successful such read (skip errored reads). Swallowed.
|
|
1381
|
+
if (event.isError !== true) skilloptArm(sessionId, event.toolName, event.input, event.toolCallId);
|
|
1289
1382
|
maybeTriggerPeriodicSummary(creds, sessionId, cwd);
|
|
1290
1383
|
});
|
|
1291
1384
|
|