@deeplake/hivemind 0.7.79 → 0.7.80
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 +9 -0
- package/codex/bundle/capture.js +176 -43
- package/codex/bundle/pre-tool-use.js +316 -93
- package/codex/bundle/skillopt-worker.js +2057 -0
- package/hermes/bundle/capture.js +168 -45
- package/hermes/bundle/pre-tool-use.js +272 -52
- package/hermes/bundle/skillopt-worker.js +2057 -0
- package/openclaw/dist/index.js +1 -1
- 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
|
@@ -6,18 +6,18 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Cloud-backed persistent shared memory for AI agents powered by Deeplake",
|
|
9
|
-
"version": "0.7.
|
|
9
|
+
"version": "0.7.80"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "hivemind",
|
|
14
14
|
"description": "Persistent shared memory powered by Deeplake — captures all session activity and provides cross-session, cross-agent memory search",
|
|
15
|
-
"version": "0.7.
|
|
15
|
+
"version": "0.7.80",
|
|
16
16
|
"source": {
|
|
17
17
|
"source": "git-subdir",
|
|
18
18
|
"url": "https://github.com/activeloopai/hivemind.git",
|
|
19
19
|
"path": "claude-code",
|
|
20
|
-
"sha": "
|
|
20
|
+
"sha": "491ff3fe01c8ffe102dd4ed88dc67b645870c8af"
|
|
21
21
|
},
|
|
22
22
|
"homepage": "https://github.com/activeloopai/hivemind"
|
|
23
23
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hivemind",
|
|
3
3
|
"description": "Cloud-backed persistent memory powered by Deeplake — read, write, and share memory across Claude Code sessions and agents",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.80",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Activeloop",
|
|
7
7
|
"url": "https://deeplake.ai"
|
package/bundle/cli.js
CHANGED
|
@@ -3622,6 +3622,7 @@ var WIKI_WORKER_DIR = join10(PI_AGENT_DIR, "hivemind");
|
|
|
3622
3622
|
var WIKI_WORKER_PATH = join10(WIKI_WORKER_DIR, "wiki-worker.js");
|
|
3623
3623
|
var SKILLIFY_WORKER_PATH = join10(WIKI_WORKER_DIR, "skillify-worker.js");
|
|
3624
3624
|
var AUTOPULL_WORKER_PATH = join10(WIKI_WORKER_DIR, "autopull-worker.js");
|
|
3625
|
+
var SKILLOPT_WORKER_PATH = join10(WIKI_WORKER_DIR, "skillopt-worker.js");
|
|
3625
3626
|
var HIVEMIND_BLOCK_START = "<!-- BEGIN hivemind-memory -->";
|
|
3626
3627
|
var HIVEMIND_BLOCK_END = "<!-- END hivemind-memory -->";
|
|
3627
3628
|
var HIVEMIND_BLOCK_BODY = `${HIVEMIND_BLOCK_START}
|
|
@@ -3716,6 +3717,11 @@ function installPi() {
|
|
|
3716
3717
|
ensureDir(WIKI_WORKER_DIR);
|
|
3717
3718
|
copyFileSync2(srcAutopullWorker, AUTOPULL_WORKER_PATH);
|
|
3718
3719
|
}
|
|
3720
|
+
const srcSkilloptWorker = join10(pkgRoot(), "pi", "bundle", "skillopt-worker.js");
|
|
3721
|
+
if (existsSync9(srcSkilloptWorker)) {
|
|
3722
|
+
ensureDir(WIKI_WORKER_DIR);
|
|
3723
|
+
copyFileSync2(srcSkilloptWorker, SKILLOPT_WORKER_PATH);
|
|
3724
|
+
}
|
|
3719
3725
|
ensureDir(VERSION_DIR);
|
|
3720
3726
|
writeVersionStamp(VERSION_DIR, getVersion());
|
|
3721
3727
|
log(` pi AGENTS.md updated -> ${AGENTS_MD}`);
|
|
@@ -3729,6 +3735,9 @@ function installPi() {
|
|
|
3729
3735
|
if (existsSync9(AUTOPULL_WORKER_PATH)) {
|
|
3730
3736
|
log(` pi autopull-worker installed -> ${AUTOPULL_WORKER_PATH}`);
|
|
3731
3737
|
}
|
|
3738
|
+
if (existsSync9(SKILLOPT_WORKER_PATH)) {
|
|
3739
|
+
log(` pi skillopt-worker installed -> ${SKILLOPT_WORKER_PATH}`);
|
|
3740
|
+
}
|
|
3732
3741
|
}
|
|
3733
3742
|
function uninstallPi() {
|
|
3734
3743
|
if (existsSync9(LEGACY_SKILL_DIR)) {
|
package/codex/bundle/capture.js
CHANGED
|
@@ -367,38 +367,38 @@ function readQueue() {
|
|
|
367
367
|
return { queue: [] };
|
|
368
368
|
}
|
|
369
369
|
}
|
|
370
|
-
function _isQueuePathInsideHome(
|
|
371
|
-
const r = resolve(
|
|
370
|
+
function _isQueuePathInsideHome(path2, home) {
|
|
371
|
+
const r = resolve(path2);
|
|
372
372
|
const h = resolve(home);
|
|
373
373
|
return r.startsWith(h + "/") || r === h;
|
|
374
374
|
}
|
|
375
375
|
function writeQueue(q) {
|
|
376
|
-
const
|
|
376
|
+
const path2 = queuePath();
|
|
377
377
|
const home = resolve(homedir3());
|
|
378
|
-
if (!_isQueuePathInsideHome(
|
|
379
|
-
throw new Error(`notifications-queue write blocked: ${
|
|
378
|
+
if (!_isQueuePathInsideHome(path2, home)) {
|
|
379
|
+
throw new Error(`notifications-queue write blocked: ${path2} is outside ${home}`);
|
|
380
380
|
}
|
|
381
381
|
mkdirSync(join3(home, ".deeplake"), { recursive: true, mode: 448 });
|
|
382
|
-
const tmp = `${
|
|
382
|
+
const tmp = `${path2}.${process.pid}.tmp`;
|
|
383
383
|
writeFileSync(tmp, JSON.stringify(q, null, 2), { mode: 384 });
|
|
384
|
-
renameSync(tmp,
|
|
384
|
+
renameSync(tmp, path2);
|
|
385
385
|
}
|
|
386
386
|
async function withQueueLock(fn) {
|
|
387
|
-
const
|
|
387
|
+
const path2 = lockPath();
|
|
388
388
|
mkdirSync(join3(homedir3(), ".deeplake"), { recursive: true, mode: 448 });
|
|
389
389
|
let fd = null;
|
|
390
390
|
for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
|
|
391
391
|
try {
|
|
392
|
-
fd = openSync(
|
|
392
|
+
fd = openSync(path2, "wx", 384);
|
|
393
393
|
break;
|
|
394
394
|
} catch (e) {
|
|
395
395
|
const code = e.code;
|
|
396
396
|
if (code !== "EEXIST")
|
|
397
397
|
throw e;
|
|
398
398
|
try {
|
|
399
|
-
const age = Date.now() - statSync(
|
|
399
|
+
const age = Date.now() - statSync(path2).mtimeMs;
|
|
400
400
|
if (age > LOCK_STALE_MS) {
|
|
401
|
-
unlinkSync(
|
|
401
|
+
unlinkSync(path2);
|
|
402
402
|
continue;
|
|
403
403
|
}
|
|
404
404
|
} catch {
|
|
@@ -419,7 +419,7 @@ async function withQueueLock(fn) {
|
|
|
419
419
|
} catch {
|
|
420
420
|
}
|
|
421
421
|
try {
|
|
422
|
-
unlinkSync(
|
|
422
|
+
unlinkSync(path2);
|
|
423
423
|
} catch {
|
|
424
424
|
}
|
|
425
425
|
}
|
|
@@ -695,9 +695,9 @@ var DeeplakeApi = class {
|
|
|
695
695
|
}
|
|
696
696
|
}
|
|
697
697
|
/** Update specific columns on a row by path. */
|
|
698
|
-
async updateColumns(
|
|
698
|
+
async updateColumns(path2, columns) {
|
|
699
699
|
const setClauses = Object.entries(columns).map(([col, val]) => typeof val === "number" ? `${col} = ${val}` : `${col} = '${sqlStr(String(val))}'`).join(", ");
|
|
700
|
-
await this.query(`UPDATE "${this.tableName}" SET ${setClauses} WHERE path = '${sqlStr(
|
|
700
|
+
await this.query(`UPDATE "${this.tableName}" SET ${setClauses} WHERE path = '${sqlStr(path2)}'`);
|
|
701
701
|
}
|
|
702
702
|
// ── Convenience ─────────────────────────────────────────────────────────────
|
|
703
703
|
/** Create a BM25 search index on a column. */
|
|
@@ -1403,13 +1403,13 @@ var _migrated = false;
|
|
|
1403
1403
|
function readUserConfig() {
|
|
1404
1404
|
if (_cache !== null)
|
|
1405
1405
|
return _cache;
|
|
1406
|
-
const
|
|
1407
|
-
if (!existsSync4(
|
|
1406
|
+
const path2 = _configPath();
|
|
1407
|
+
if (!existsSync4(path2)) {
|
|
1408
1408
|
_cache = {};
|
|
1409
1409
|
return _cache;
|
|
1410
1410
|
}
|
|
1411
1411
|
try {
|
|
1412
|
-
const raw = readFileSync6(
|
|
1412
|
+
const raw = readFileSync6(path2, "utf-8");
|
|
1413
1413
|
const parsed = JSON.parse(raw);
|
|
1414
1414
|
_cache = isPlainObject(parsed) ? parsed : {};
|
|
1415
1415
|
} catch {
|
|
@@ -1420,13 +1420,13 @@ function readUserConfig() {
|
|
|
1420
1420
|
function writeUserConfig(patch) {
|
|
1421
1421
|
const current = readUserConfig();
|
|
1422
1422
|
const merged = deepMerge(current, patch);
|
|
1423
|
-
const
|
|
1424
|
-
const dir = dirname(
|
|
1423
|
+
const path2 = _configPath();
|
|
1424
|
+
const dir = dirname(path2);
|
|
1425
1425
|
if (!existsSync4(dir))
|
|
1426
1426
|
mkdirSync4(dir, { recursive: true });
|
|
1427
|
-
const tmp = `${
|
|
1427
|
+
const tmp = `${path2}.tmp.${process.pid}`;
|
|
1428
1428
|
writeFileSync4(tmp, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
1429
|
-
renameSync2(tmp,
|
|
1429
|
+
renameSync2(tmp, path2);
|
|
1430
1430
|
_cache = merged;
|
|
1431
1431
|
return merged;
|
|
1432
1432
|
}
|
|
@@ -1571,8 +1571,8 @@ function createSymlinkAtomic(target, link) {
|
|
|
1571
1571
|
}
|
|
1572
1572
|
|
|
1573
1573
|
// dist/src/hooks/codex/capture.js
|
|
1574
|
-
import { fileURLToPath as
|
|
1575
|
-
import { dirname as
|
|
1574
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1575
|
+
import { dirname as dirname7, join as join17 } from "node:path";
|
|
1576
1576
|
|
|
1577
1577
|
// dist/src/hooks/summary-state.js
|
|
1578
1578
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, writeSync as writeSync2, mkdirSync as mkdirSync6, renameSync as renameSync4, existsSync as existsSync6, unlinkSync as unlinkSync4, openSync as openSync3, closeSync as closeSync3, statSync as statSync3 } from "node:fs";
|
|
@@ -1719,13 +1719,13 @@ import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
|
|
|
1719
1719
|
import { mkdirSync as mkdirSync7, appendFileSync as appendFileSync2 } from "node:fs";
|
|
1720
1720
|
import { join as join11 } from "node:path";
|
|
1721
1721
|
function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") {
|
|
1722
|
-
const
|
|
1722
|
+
const path2 = join11(hooksDir, filename);
|
|
1723
1723
|
return {
|
|
1724
|
-
path,
|
|
1724
|
+
path: path2,
|
|
1725
1725
|
log(msg) {
|
|
1726
1726
|
try {
|
|
1727
1727
|
mkdirSync7(hooksDir, { recursive: true });
|
|
1728
|
-
appendFileSync2(
|
|
1728
|
+
appendFileSync2(path2, `[${utcTimestamp()}] ${msg}
|
|
1729
1729
|
`);
|
|
1730
1730
|
} catch {
|
|
1731
1731
|
}
|
|
@@ -1778,10 +1778,10 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
|
1778
1778
|
// dist/src/utils/spawn-detached.js
|
|
1779
1779
|
import { spawn as nodeSpawn } from "node:child_process";
|
|
1780
1780
|
function spawnDetachedNodeWorker(workerPath, args = [], deps = {}) {
|
|
1781
|
-
const
|
|
1781
|
+
const spawn3 = deps.spawn ?? nodeSpawn;
|
|
1782
1782
|
const execPath = deps.execPath ?? process.execPath;
|
|
1783
1783
|
try {
|
|
1784
|
-
const child =
|
|
1784
|
+
const child = spawn3(execPath, [workerPath, ...args], {
|
|
1785
1785
|
detached: true,
|
|
1786
1786
|
stdio: ["ignore", "ignore", "ignore"],
|
|
1787
1787
|
// Suppress the transient console window Windows would otherwise pop for
|
|
@@ -1892,12 +1892,144 @@ function bundleDirFromImportMeta(importMetaUrl) {
|
|
|
1892
1892
|
return dirname4(fileURLToPath(importMetaUrl));
|
|
1893
1893
|
}
|
|
1894
1894
|
|
|
1895
|
+
// dist/src/skillify/skillopt-trigger.js
|
|
1896
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
1897
|
+
import fs from "node:fs";
|
|
1898
|
+
import path from "node:path";
|
|
1899
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1900
|
+
|
|
1901
|
+
// dist/src/skillify/state-dir.js
|
|
1902
|
+
import { homedir as homedir11 } from "node:os";
|
|
1903
|
+
import { join as join14 } from "node:path";
|
|
1904
|
+
function getStateDir() {
|
|
1905
|
+
const override = process.env.HIVEMIND_STATE_DIR?.trim();
|
|
1906
|
+
return override && override.length > 0 ? override : join14(homedir11(), ".deeplake", "state", "skillify");
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
// dist/src/skillify/manifest.js
|
|
1910
|
+
import { existsSync as existsSync8, lstatSync as lstatSync2, mkdirSync as mkdirSync9, readFileSync as readFileSync9, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync7 } from "node:fs";
|
|
1911
|
+
import { dirname as dirname6, join as join16 } from "node:path";
|
|
1912
|
+
|
|
1913
|
+
// dist/src/skillify/legacy-migration.js
|
|
1914
|
+
import { existsSync as existsSync7, renameSync as renameSync5 } from "node:fs";
|
|
1915
|
+
import { dirname as dirname5, join as join15 } from "node:path";
|
|
1916
|
+
|
|
1917
|
+
// dist/src/skillify/skillopt-env.js
|
|
1918
|
+
var SKILLOPT_ENV = {
|
|
1919
|
+
/** User-set kill switch: "1" disables the whole trigger. */
|
|
1920
|
+
DISABLED: "HIVEMIND_SKILLOPT_DISABLED",
|
|
1921
|
+
/** Recursion guard the trigger sets on the spawned worker so the worker can't re-arm. */
|
|
1922
|
+
WORKER: "HIVEMIND_SKILLOPT_WORKER",
|
|
1923
|
+
/** Worker inputs, handed trigger → worker via the child env. */
|
|
1924
|
+
SESSION: "HIVEMIND_SKILLOPT_SESSION",
|
|
1925
|
+
SKILL: "HIVEMIND_SKILLOPT_SKILL",
|
|
1926
|
+
REACTION: "HIVEMIND_SKILLOPT_REACTION",
|
|
1927
|
+
TOOL_USE_ID: "HIVEMIND_SKILLOPT_TOOL_USE_ID",
|
|
1928
|
+
/** Which agent's CLI runs the judge/proposer (claude_code/codex/hermes/cursor/pi). */
|
|
1929
|
+
AGENT: "HIVEMIND_SKILLOPT_AGENT",
|
|
1930
|
+
/** K-message judgment-window size override. */
|
|
1931
|
+
JUDGE_WINDOW: "HIVEMIND_SKILLOPT_JUDGE_WINDOW"
|
|
1932
|
+
};
|
|
1933
|
+
|
|
1934
|
+
// dist/src/skillify/skillopt-trigger.js
|
|
1935
|
+
var log5 = (m) => log("skillopt-trigger", m);
|
|
1936
|
+
function defaultHasCreds() {
|
|
1937
|
+
try {
|
|
1938
|
+
return Boolean(loadConfig()?.token);
|
|
1939
|
+
} catch {
|
|
1940
|
+
return false;
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
var MAX_REACTION = 8e3;
|
|
1944
|
+
function pendingFile(sessionId) {
|
|
1945
|
+
const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 200);
|
|
1946
|
+
return path.join(getStateDir(), "skillopt", "pending", `${safe}.json`);
|
|
1947
|
+
}
|
|
1948
|
+
var fileStore = {
|
|
1949
|
+
load(sessionId) {
|
|
1950
|
+
try {
|
|
1951
|
+
return JSON.parse(fs.readFileSync(pendingFile(sessionId), "utf8"));
|
|
1952
|
+
} catch {
|
|
1953
|
+
return null;
|
|
1954
|
+
}
|
|
1955
|
+
},
|
|
1956
|
+
save(sessionId, p) {
|
|
1957
|
+
try {
|
|
1958
|
+
const f = pendingFile(sessionId);
|
|
1959
|
+
if (p === null) {
|
|
1960
|
+
try {
|
|
1961
|
+
fs.unlinkSync(f);
|
|
1962
|
+
} catch {
|
|
1963
|
+
}
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
fs.mkdirSync(path.dirname(f), { recursive: true });
|
|
1967
|
+
const tmp = `${f}.${process.pid}.tmp`;
|
|
1968
|
+
fs.writeFileSync(tmp, JSON.stringify(p));
|
|
1969
|
+
fs.renameSync(tmp, f);
|
|
1970
|
+
} catch {
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
};
|
|
1974
|
+
function runEventTrigger(sessionId, reaction, opts = {}) {
|
|
1975
|
+
const deps = opts.deps ?? {};
|
|
1976
|
+
const env = deps.env ?? process.env;
|
|
1977
|
+
if (env[SKILLOPT_ENV.DISABLED] === "1")
|
|
1978
|
+
return { fired: false, reason: "disabled" };
|
|
1979
|
+
if (env[SKILLOPT_ENV.WORKER] === "1")
|
|
1980
|
+
return { fired: false, reason: "in-worker" };
|
|
1981
|
+
if (!sessionId)
|
|
1982
|
+
return { fired: false, reason: "no-skill" };
|
|
1983
|
+
const store = deps.store ?? fileStore;
|
|
1984
|
+
const p = store.load(sessionId);
|
|
1985
|
+
if (!p)
|
|
1986
|
+
return { fired: false, reason: "no-skill" };
|
|
1987
|
+
if (!(deps.canFire ?? defaultHasCreds)())
|
|
1988
|
+
return { fired: false, reason: "no-creds" };
|
|
1989
|
+
store.save(sessionId, p.budget - 1 <= 0 ? null : { ...p, budget: p.budget - 1 });
|
|
1990
|
+
(deps.spawnWorker ?? spawnWorker)(sessionId, p.skill, reaction ?? "", p.toolUseId, opts.agent);
|
|
1991
|
+
return { fired: true, reason: "spawned" };
|
|
1992
|
+
}
|
|
1993
|
+
function spawnWorker(sessionId, skill, reaction, toolUseId, agent) {
|
|
1994
|
+
try {
|
|
1995
|
+
const here = path.dirname(fileURLToPath2(import.meta.url));
|
|
1996
|
+
const entry = path.join(here, "skillopt-worker.js");
|
|
1997
|
+
const child = spawn2(process.execPath, [entry], {
|
|
1998
|
+
detached: true,
|
|
1999
|
+
stdio: "ignore",
|
|
2000
|
+
env: {
|
|
2001
|
+
...process.env,
|
|
2002
|
+
[SKILLOPT_ENV.WORKER]: "1",
|
|
2003
|
+
[SKILLOPT_ENV.SESSION]: sessionId,
|
|
2004
|
+
[SKILLOPT_ENV.SKILL]: skill,
|
|
2005
|
+
[SKILLOPT_ENV.REACTION]: (reaction ?? "").slice(0, MAX_REACTION),
|
|
2006
|
+
...toolUseId ? { [SKILLOPT_ENV.TOOL_USE_ID]: toolUseId } : {},
|
|
2007
|
+
...agent ? { [SKILLOPT_ENV.AGENT]: agent } : {}
|
|
2008
|
+
}
|
|
2009
|
+
});
|
|
2010
|
+
child.unref();
|
|
2011
|
+
log5(`spawned skillopt worker for ${skill} in ${sessionId}${agent ? ` (agent=${agent})` : ""}`);
|
|
2012
|
+
} catch (e) {
|
|
2013
|
+
log5(`spawn failed (swallowed): ${e?.message ?? e}`);
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
// dist/src/hooks/shared/skillopt-hook.js
|
|
2018
|
+
function reactSkillOpt(sessionId, prompt, agent) {
|
|
2019
|
+
try {
|
|
2020
|
+
if (prompt === void 0 || prompt.trim() === "" || process.env.HIVEMIND_WIKI_WORKER === "1")
|
|
2021
|
+
return;
|
|
2022
|
+
runEventTrigger(sessionId, prompt, { agent });
|
|
2023
|
+
} catch {
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
|
|
1895
2027
|
// dist/src/hooks/codex/capture.js
|
|
1896
|
-
var
|
|
2028
|
+
var log6 = (msg) => log("codex-capture", msg);
|
|
1897
2029
|
function resolveEmbedDaemonPath() {
|
|
1898
|
-
return
|
|
2030
|
+
return join17(dirname7(fileURLToPath3(import.meta.url)), "embeddings", "embed-daemon.js");
|
|
1899
2031
|
}
|
|
1900
|
-
var __bundleDir =
|
|
2032
|
+
var __bundleDir = dirname7(fileURLToPath3(import.meta.url));
|
|
1901
2033
|
var PLUGIN_VERSION = getInstalledVersion(__bundleDir, ".codex-plugin") ?? "";
|
|
1902
2034
|
if (!embeddingsDisabled()) {
|
|
1903
2035
|
try {
|
|
@@ -1912,7 +2044,7 @@ async function main() {
|
|
|
1912
2044
|
const input = await readStdin();
|
|
1913
2045
|
const config = loadConfig();
|
|
1914
2046
|
if (!config) {
|
|
1915
|
-
|
|
2047
|
+
log6("no config");
|
|
1916
2048
|
return;
|
|
1917
2049
|
}
|
|
1918
2050
|
const sessionsTable = config.sessionsTableName;
|
|
@@ -1929,7 +2061,7 @@ async function main() {
|
|
|
1929
2061
|
};
|
|
1930
2062
|
let entry;
|
|
1931
2063
|
if (input.hook_event_name === "UserPromptSubmit" && input.prompt !== void 0) {
|
|
1932
|
-
|
|
2064
|
+
log6(`user session=${input.session_id}`);
|
|
1933
2065
|
entry = {
|
|
1934
2066
|
id: crypto.randomUUID(),
|
|
1935
2067
|
...meta,
|
|
@@ -1937,7 +2069,7 @@ async function main() {
|
|
|
1937
2069
|
content: input.prompt
|
|
1938
2070
|
};
|
|
1939
2071
|
} else if (input.hook_event_name === "PostToolUse" && input.tool_name !== void 0) {
|
|
1940
|
-
|
|
2072
|
+
log6(`tool=${input.tool_name} session=${input.session_id}`);
|
|
1941
2073
|
entry = {
|
|
1942
2074
|
id: crypto.randomUUID(),
|
|
1943
2075
|
...meta,
|
|
@@ -1948,12 +2080,12 @@ async function main() {
|
|
|
1948
2080
|
tool_response: JSON.stringify(input.tool_response)
|
|
1949
2081
|
};
|
|
1950
2082
|
} else {
|
|
1951
|
-
|
|
2083
|
+
log6(`unknown event: ${input.hook_event_name}, skipping`);
|
|
1952
2084
|
return;
|
|
1953
2085
|
}
|
|
1954
2086
|
const sessionPath = buildSessionPath(config, input.session_id);
|
|
1955
2087
|
const line = JSON.stringify(entry);
|
|
1956
|
-
|
|
2088
|
+
log6(`writing to ${sessionPath}`);
|
|
1957
2089
|
const projectName = projectNameFromCwd(input.cwd);
|
|
1958
2090
|
const filename = sessionPath.split("/").pop() ?? "";
|
|
1959
2091
|
const jsonForSql = line.replace(/'/g, "''");
|
|
@@ -1964,14 +2096,15 @@ async function main() {
|
|
|
1964
2096
|
await api.query(insertSql);
|
|
1965
2097
|
} catch (e) {
|
|
1966
2098
|
if (e.message?.includes("permission denied") || e.message?.includes("does not exist")) {
|
|
1967
|
-
|
|
2099
|
+
log6("table missing, creating and retrying");
|
|
1968
2100
|
await api.ensureSessionsTable(sessionsTable);
|
|
1969
2101
|
await api.query(insertSql);
|
|
1970
2102
|
} else {
|
|
1971
2103
|
throw e;
|
|
1972
2104
|
}
|
|
1973
2105
|
}
|
|
1974
|
-
|
|
2106
|
+
log6("capture ok");
|
|
2107
|
+
reactSkillOpt(input.session_id, input.prompt, "codex");
|
|
1975
2108
|
maybeTriggerPeriodicSummary(input.session_id, input.cwd ?? "", config);
|
|
1976
2109
|
}
|
|
1977
2110
|
function maybeTriggerPeriodicSummary(sessionId, cwd, config) {
|
|
@@ -1983,7 +2116,7 @@ function maybeTriggerPeriodicSummary(sessionId, cwd, config) {
|
|
|
1983
2116
|
if (!shouldTrigger(state, cfg))
|
|
1984
2117
|
return;
|
|
1985
2118
|
if (!tryAcquireLock(sessionId)) {
|
|
1986
|
-
|
|
2119
|
+
log6(`periodic trigger suppressed (lock held) session=${sessionId}`);
|
|
1987
2120
|
return;
|
|
1988
2121
|
}
|
|
1989
2122
|
wikiLog(`Periodic: threshold hit (total=${state.totalCount}, since=${state.totalCount - state.lastSummaryCount}, N=${cfg.everyNMessages}, hours=${cfg.everyHours})`);
|
|
@@ -1996,19 +2129,19 @@ function maybeTriggerPeriodicSummary(sessionId, cwd, config) {
|
|
|
1996
2129
|
reason: "Periodic"
|
|
1997
2130
|
});
|
|
1998
2131
|
} catch (e) {
|
|
1999
|
-
|
|
2132
|
+
log6(`periodic spawn failed: ${e.message}`);
|
|
2000
2133
|
try {
|
|
2001
2134
|
releaseLock(sessionId);
|
|
2002
2135
|
} catch (releaseErr) {
|
|
2003
|
-
|
|
2136
|
+
log6(`releaseLock after periodic spawn failure also failed: ${releaseErr.message}`);
|
|
2004
2137
|
}
|
|
2005
2138
|
throw e;
|
|
2006
2139
|
}
|
|
2007
2140
|
} catch (e) {
|
|
2008
|
-
|
|
2141
|
+
log6(`periodic trigger error: ${e.message}`);
|
|
2009
2142
|
}
|
|
2010
2143
|
}
|
|
2011
2144
|
main().catch((e) => {
|
|
2012
|
-
|
|
2145
|
+
log6(`fatal: ${e.message}`);
|
|
2013
2146
|
process.exit(0);
|
|
2014
2147
|
});
|