@deeplake/hivemind 0.6.47 → 0.7.4

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 (41) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +158 -51
  4. package/bundle/cli.js +4103 -282
  5. package/codex/bundle/capture.js +510 -90
  6. package/codex/bundle/commands/auth-login.js +219 -72
  7. package/codex/bundle/embeddings/embed-daemon.js +243 -0
  8. package/codex/bundle/pre-tool-use.js +713 -108
  9. package/codex/bundle/session-start-setup.js +209 -58
  10. package/codex/bundle/session-start.js +40 -11
  11. package/codex/bundle/shell/deeplake-shell.js +679 -112
  12. package/codex/bundle/stop.js +477 -59
  13. package/codex/bundle/wiki-worker.js +312 -11
  14. package/cursor/bundle/capture.js +768 -57
  15. package/cursor/bundle/commands/auth-login.js +219 -72
  16. package/cursor/bundle/embeddings/embed-daemon.js +243 -0
  17. package/cursor/bundle/pre-tool-use.js +1684 -0
  18. package/cursor/bundle/session-end.js +223 -2
  19. package/cursor/bundle/session-start.js +209 -57
  20. package/cursor/bundle/shell/deeplake-shell.js +679 -112
  21. package/cursor/bundle/wiki-worker.js +571 -0
  22. package/hermes/bundle/capture.js +1194 -0
  23. package/hermes/bundle/commands/auth-login.js +1009 -0
  24. package/hermes/bundle/embeddings/embed-daemon.js +243 -0
  25. package/hermes/bundle/package.json +1 -0
  26. package/hermes/bundle/pre-tool-use.js +1681 -0
  27. package/hermes/bundle/session-end.js +265 -0
  28. package/hermes/bundle/session-start.js +655 -0
  29. package/hermes/bundle/shell/deeplake-shell.js +69905 -0
  30. package/hermes/bundle/wiki-worker.js +572 -0
  31. package/mcp/bundle/server.js +289 -69
  32. package/openclaw/dist/chunks/auth-creds-AEKS6D3P.js +14 -0
  33. package/openclaw/dist/chunks/chunk-SRCBBT4H.js +37 -0
  34. package/openclaw/dist/chunks/config-G23NI5TV.js +33 -0
  35. package/openclaw/dist/chunks/index-marker-store-PGT5CW6T.js +33 -0
  36. package/openclaw/dist/chunks/setup-config-C35UK4LP.js +114 -0
  37. package/openclaw/dist/index.js +752 -702
  38. package/openclaw/openclaw.plugin.json +1 -1
  39. package/openclaw/package.json +1 -1
  40. package/package.json +7 -3
  41. package/pi/extension-source/hivemind.ts +807 -0
@@ -0,0 +1,265 @@
1
+ // dist/src/utils/stdin.js
2
+ function readStdin() {
3
+ return new Promise((resolve, reject) => {
4
+ let data = "";
5
+ process.stdin.setEncoding("utf-8");
6
+ process.stdin.on("data", (chunk) => data += chunk);
7
+ process.stdin.on("end", () => {
8
+ try {
9
+ resolve(JSON.parse(data));
10
+ } catch (err) {
11
+ reject(new Error(`Failed to parse hook input: ${err}`));
12
+ }
13
+ });
14
+ process.stdin.on("error", reject);
15
+ });
16
+ }
17
+
18
+ // dist/src/utils/debug.js
19
+ import { appendFileSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import { homedir } from "node:os";
22
+ var DEBUG = process.env.HIVEMIND_DEBUG === "1";
23
+ var LOG = join(homedir(), ".deeplake", "hook-debug.log");
24
+ function utcTimestamp(d = /* @__PURE__ */ new Date()) {
25
+ return d.toISOString().replace("T", " ").slice(0, 19) + " UTC";
26
+ }
27
+ function log(tag, msg) {
28
+ if (!DEBUG)
29
+ return;
30
+ appendFileSync(LOG, `${(/* @__PURE__ */ new Date()).toISOString()} [${tag}] ${msg}
31
+ `);
32
+ }
33
+
34
+ // dist/src/config.js
35
+ import { readFileSync, existsSync } from "node:fs";
36
+ import { join as join2 } from "node:path";
37
+ import { homedir as homedir2, userInfo } from "node:os";
38
+ function loadConfig() {
39
+ const home = homedir2();
40
+ const credPath = join2(home, ".deeplake", "credentials.json");
41
+ let creds = null;
42
+ if (existsSync(credPath)) {
43
+ try {
44
+ creds = JSON.parse(readFileSync(credPath, "utf-8"));
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+ const token = process.env.HIVEMIND_TOKEN ?? creds?.token;
50
+ const orgId = process.env.HIVEMIND_ORG_ID ?? creds?.orgId;
51
+ if (!token || !orgId)
52
+ return null;
53
+ return {
54
+ token,
55
+ orgId,
56
+ orgName: creds?.orgName ?? orgId,
57
+ userName: creds?.userName || userInfo().username || "unknown",
58
+ workspaceId: process.env.HIVEMIND_WORKSPACE_ID ?? creds?.workspaceId ?? "default",
59
+ apiUrl: process.env.HIVEMIND_API_URL ?? creds?.apiUrl ?? "https://api.deeplake.ai",
60
+ tableName: process.env.HIVEMIND_TABLE ?? "memory",
61
+ sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
62
+ memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join2(home, ".deeplake", "memory")
63
+ };
64
+ }
65
+
66
+ // dist/src/hooks/summary-state.js
67
+ import { readFileSync as readFileSync2, writeFileSync, writeSync, mkdirSync, renameSync, existsSync as existsSync2, unlinkSync, openSync, closeSync } from "node:fs";
68
+ import { homedir as homedir3 } from "node:os";
69
+ import { join as join3 } from "node:path";
70
+ var dlog = (msg) => log("summary-state", msg);
71
+ var STATE_DIR = join3(homedir3(), ".claude", "hooks", "summary-state");
72
+ var YIELD_BUF = new Int32Array(new SharedArrayBuffer(4));
73
+ function lockPath(sessionId) {
74
+ return join3(STATE_DIR, `${sessionId}.lock`);
75
+ }
76
+ function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
77
+ mkdirSync(STATE_DIR, { recursive: true });
78
+ const p = lockPath(sessionId);
79
+ if (existsSync2(p)) {
80
+ try {
81
+ const ageMs = Date.now() - parseInt(readFileSync2(p, "utf-8"), 10);
82
+ if (Number.isFinite(ageMs) && ageMs < maxAgeMs)
83
+ return false;
84
+ } catch (readErr) {
85
+ dlog(`lock file unreadable for ${sessionId}, treating as stale: ${readErr.message}`);
86
+ }
87
+ try {
88
+ unlinkSync(p);
89
+ } catch (unlinkErr) {
90
+ dlog(`could not unlink stale lock for ${sessionId}: ${unlinkErr.message}`);
91
+ return false;
92
+ }
93
+ }
94
+ try {
95
+ const fd = openSync(p, "wx");
96
+ try {
97
+ writeSync(fd, String(Date.now()));
98
+ } finally {
99
+ closeSync(fd);
100
+ }
101
+ return true;
102
+ } catch (e) {
103
+ if (e.code === "EEXIST")
104
+ return false;
105
+ throw e;
106
+ }
107
+ }
108
+
109
+ // dist/src/hooks/hermes/spawn-wiki-worker.js
110
+ import { spawn, execSync } from "node:child_process";
111
+ import { fileURLToPath } from "node:url";
112
+ import { dirname, join as join5 } from "node:path";
113
+ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "node:fs";
114
+ import { homedir as homedir4, tmpdir } from "node:os";
115
+
116
+ // dist/src/utils/wiki-log.js
117
+ import { mkdirSync as mkdirSync2, appendFileSync as appendFileSync2 } from "node:fs";
118
+ import { join as join4 } from "node:path";
119
+ function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") {
120
+ const path = join4(hooksDir, filename);
121
+ return {
122
+ path,
123
+ log(msg) {
124
+ try {
125
+ mkdirSync2(hooksDir, { recursive: true });
126
+ appendFileSync2(path, `[${utcTimestamp()}] ${msg}
127
+ `);
128
+ } catch {
129
+ }
130
+ }
131
+ };
132
+ }
133
+
134
+ // dist/src/hooks/hermes/spawn-wiki-worker.js
135
+ var HOME = homedir4();
136
+ var wikiLogger = makeWikiLogger(join5(HOME, ".hermes", "hooks"));
137
+ var WIKI_LOG = wikiLogger.path;
138
+ var WIKI_PROMPT_TEMPLATE = `You are building a personal wiki from a coding session. Your goal is to extract every piece of knowledge \u2014 entities, decisions, relationships, and facts \u2014 into a structured, searchable wiki entry.
139
+
140
+ SESSION JSONL path: __JSONL__
141
+ SUMMARY FILE to write: __SUMMARY__
142
+ SESSION ID: __SESSION_ID__
143
+ PROJECT: __PROJECT__
144
+ PREVIOUS JSONL OFFSET (lines already processed): __PREV_OFFSET__
145
+ CURRENT JSONL LINES: __JSONL_LINES__
146
+
147
+ Steps:
148
+ 1. Read the session JSONL at the path above.
149
+ - If PREVIOUS JSONL OFFSET > 0, this is a resumed session. Read the existing summary file first,
150
+ then focus on lines AFTER the offset for new content. Merge new facts into the existing summary.
151
+ - If offset is 0, generate from scratch.
152
+
153
+ 2. Write the summary file at the path above with this EXACT format:
154
+
155
+ # Session __SESSION_ID__
156
+ - **Source**: __JSONL_SERVER_PATH__
157
+ - **Started**: <extract from JSONL>
158
+ - **Ended**: <now>
159
+ - **Project**: __PROJECT__
160
+ - **JSONL offset**: __JSONL_LINES__
161
+
162
+ ## What Happened
163
+ <2-3 dense sentences. What was the goal, what was accomplished, what's left.>
164
+
165
+ ## People
166
+ <For each person mentioned: name, role, what they did/said. Format: **Name** \u2014 role \u2014 action>
167
+
168
+ ## Entities
169
+ <Every named thing: repos, branches, files, APIs, tools, services, tables, features, bugs.
170
+ Format: **entity** (type) \u2014 what was done with it, its current state>
171
+
172
+ ## Decisions & Reasoning
173
+ <Every decision made and WHY.>
174
+
175
+ ## Key Facts
176
+ <Bullet list of atomic facts that could answer future questions.>
177
+
178
+ ## Files Modified
179
+ <bullet list: path (new/modified/deleted) \u2014 what changed>
180
+
181
+ ## Open Questions / TODO
182
+ <Anything unresolved, blocked, or explicitly deferred>
183
+
184
+ IMPORTANT: Be exhaustive. Extract EVERY entity, decision, and fact.
185
+ PRIVACY: Never include absolute filesystem paths in the summary.
186
+ LENGTH LIMIT: Keep the total summary under 4000 characters.`;
187
+ var wikiLog = wikiLogger.log;
188
+ function findHermesBin() {
189
+ try {
190
+ return execSync("which hermes 2>/dev/null", { encoding: "utf-8" }).trim() || "hermes";
191
+ } catch {
192
+ return "hermes";
193
+ }
194
+ }
195
+ function spawnHermesWikiWorker(opts) {
196
+ const { config, sessionId, cwd, bundleDir, reason } = opts;
197
+ const projectName = cwd.split("/").pop() || "unknown";
198
+ const tmpDir = join5(tmpdir(), `deeplake-wiki-${sessionId}-${Date.now()}`);
199
+ mkdirSync3(tmpDir, { recursive: true });
200
+ const configFile = join5(tmpDir, "config.json");
201
+ writeFileSync2(configFile, JSON.stringify({
202
+ apiUrl: config.apiUrl,
203
+ token: config.token,
204
+ orgId: config.orgId,
205
+ workspaceId: config.workspaceId,
206
+ memoryTable: config.tableName,
207
+ sessionsTable: config.sessionsTableName,
208
+ sessionId,
209
+ userName: config.userName,
210
+ project: projectName,
211
+ tmpDir,
212
+ hermesBin: findHermesBin(),
213
+ hermesProvider: process.env.HIVEMIND_HERMES_PROVIDER ?? "openrouter",
214
+ hermesModel: process.env.HIVEMIND_HERMES_MODEL ?? "anthropic/claude-haiku-4-5",
215
+ wikiLog: WIKI_LOG,
216
+ hooksDir: join5(HOME, ".hermes", "hooks"),
217
+ promptTemplate: WIKI_PROMPT_TEMPLATE
218
+ }));
219
+ wikiLog(`${reason}: spawning summary worker for ${sessionId}`);
220
+ const workerPath = join5(bundleDir, "wiki-worker.js");
221
+ spawn("nohup", ["node", workerPath, configFile], {
222
+ detached: true,
223
+ stdio: ["ignore", "ignore", "ignore"]
224
+ }).unref();
225
+ wikiLog(`${reason}: spawned summary worker for ${sessionId}`);
226
+ }
227
+ function bundleDirFromImportMeta(importMetaUrl) {
228
+ return dirname(fileURLToPath(importMetaUrl));
229
+ }
230
+
231
+ // dist/src/hooks/hermes/session-end.js
232
+ var log2 = (msg) => log("hermes-session-end", msg);
233
+ async function main() {
234
+ if (process.env.HIVEMIND_WIKI_WORKER === "1")
235
+ return;
236
+ const input = await readStdin();
237
+ const sessionId = input.session_id ?? "";
238
+ log2(`session=${sessionId || "?"} cwd=${input.cwd ?? "?"}`);
239
+ if (!sessionId)
240
+ return;
241
+ if (!tryAcquireLock(sessionId)) {
242
+ wikiLog(`SessionEnd: periodic worker already running for ${sessionId}, skipping final`);
243
+ return;
244
+ }
245
+ try {
246
+ const config = loadConfig();
247
+ if (!config) {
248
+ wikiLog(`SessionEnd: no config, skipping summary`);
249
+ return;
250
+ }
251
+ spawnHermesWikiWorker({
252
+ config,
253
+ sessionId,
254
+ cwd: input.cwd ?? process.cwd(),
255
+ bundleDir: bundleDirFromImportMeta(import.meta.url),
256
+ reason: "SessionEnd"
257
+ });
258
+ } catch (e) {
259
+ wikiLog(`SessionEnd: spawn failed: ${e?.message ?? e}`);
260
+ }
261
+ }
262
+ main().catch((e) => {
263
+ log2(`fatal: ${e.message}`);
264
+ process.exit(0);
265
+ });