@deeplake/hivemind 0.6.47
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 +20 -0
- package/.claude-plugin/plugin.json +19 -0
- package/LICENSE +201 -0
- package/README.md +359 -0
- package/bundle/cli.js +1051 -0
- package/codex/bundle/capture.js +759 -0
- package/codex/bundle/commands/auth-login.js +862 -0
- package/codex/bundle/package.json +1 -0
- package/codex/bundle/pre-tool-use.js +2097 -0
- package/codex/bundle/session-start-setup.js +585 -0
- package/codex/bundle/session-start.js +129 -0
- package/codex/bundle/shell/deeplake-shell.js +69338 -0
- package/codex/bundle/stop.js +673 -0
- package/codex/bundle/wiki-worker.js +266 -0
- package/codex/skills/deeplake-memory/SKILL.md +65 -0
- package/cursor/bundle/capture.js +485 -0
- package/cursor/bundle/commands/auth-login.js +862 -0
- package/cursor/bundle/package.json +1 -0
- package/cursor/bundle/session-end.js +45 -0
- package/cursor/bundle/session-start.js +520 -0
- package/cursor/bundle/shell/deeplake-shell.js +69338 -0
- package/mcp/bundle/package.json +1 -0
- package/mcp/bundle/server.js +24068 -0
- package/openclaw/README.md +89 -0
- package/openclaw/dist/index.js +1714 -0
- package/openclaw/dist/package.json +1 -0
- package/openclaw/openclaw.plugin.json +56 -0
- package/openclaw/package.json +29 -0
- package/openclaw/skills/SKILL.md +61 -0
- package/package.json +69 -0
package/bundle/cli.js
ADDED
|
@@ -0,0 +1,1051 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// dist/src/cli/install-claude.js
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
5
|
+
|
|
6
|
+
// dist/src/cli/util.js
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, cpSync, symlinkSync, unlinkSync, lstatSync } from "node:fs";
|
|
8
|
+
import { join, dirname } from "node:path";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
var HOME = homedir();
|
|
12
|
+
function pkgRoot() {
|
|
13
|
+
return fileURLToPath(new URL("..", import.meta.url));
|
|
14
|
+
}
|
|
15
|
+
function ensureDir(path, mode = 493) {
|
|
16
|
+
if (!existsSync(path))
|
|
17
|
+
mkdirSync(path, { recursive: true, mode });
|
|
18
|
+
}
|
|
19
|
+
function copyDir(src, dst) {
|
|
20
|
+
cpSync(src, dst, { recursive: true, force: true, dereference: false });
|
|
21
|
+
}
|
|
22
|
+
function symlinkForce(target, link) {
|
|
23
|
+
ensureDir(dirname(link));
|
|
24
|
+
if (existsSync(link) || isLink(link))
|
|
25
|
+
unlinkSync(link);
|
|
26
|
+
symlinkSync(target, link);
|
|
27
|
+
}
|
|
28
|
+
function isLink(path) {
|
|
29
|
+
try {
|
|
30
|
+
return lstatSync(path).isSymbolicLink();
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function readJson(path) {
|
|
36
|
+
if (!existsSync(path))
|
|
37
|
+
return null;
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function writeJson(path, obj) {
|
|
45
|
+
ensureDir(dirname(path));
|
|
46
|
+
writeFileSync(path, JSON.stringify(obj, null, 2) + "\n");
|
|
47
|
+
}
|
|
48
|
+
function writeVersionStamp(dir, version) {
|
|
49
|
+
ensureDir(dir);
|
|
50
|
+
writeFileSync(join(dir, ".hivemind_version"), version);
|
|
51
|
+
}
|
|
52
|
+
var PLATFORM_MARKERS = [
|
|
53
|
+
{ id: "claude", markerDir: join(HOME, ".claude") },
|
|
54
|
+
{ id: "codex", markerDir: join(HOME, ".codex") },
|
|
55
|
+
{ id: "claw", markerDir: join(HOME, ".openclaw") },
|
|
56
|
+
{ id: "cursor", markerDir: join(HOME, ".cursor") },
|
|
57
|
+
{ id: "hermes", markerDir: join(HOME, ".hermes") },
|
|
58
|
+
// pi (badlogic/pi-mono coding-agent) — config at ~/.pi/agent/
|
|
59
|
+
{ id: "pi", markerDir: join(HOME, ".pi") },
|
|
60
|
+
// Cline (saoudrizwan.claude-dev VS Code extension) — settings under VS Code's globalStorage
|
|
61
|
+
{ id: "cline", markerDir: join(HOME, ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev") },
|
|
62
|
+
// Roo Code (rooveterinaryinc.roo-cline VS Code extension)
|
|
63
|
+
{ id: "roo", markerDir: join(HOME, ".config", "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline") },
|
|
64
|
+
// Kilo Code — config at ~/.kilocode/
|
|
65
|
+
{ id: "kilo", markerDir: join(HOME, ".kilocode") }
|
|
66
|
+
];
|
|
67
|
+
function detectPlatforms() {
|
|
68
|
+
return PLATFORM_MARKERS.filter((p) => existsSync(p.markerDir));
|
|
69
|
+
}
|
|
70
|
+
function allPlatformIds() {
|
|
71
|
+
return PLATFORM_MARKERS.map((p) => p.id);
|
|
72
|
+
}
|
|
73
|
+
function log(msg) {
|
|
74
|
+
process.stdout.write(msg + "\n");
|
|
75
|
+
}
|
|
76
|
+
function warn(msg) {
|
|
77
|
+
process.stderr.write(msg + "\n");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// dist/src/cli/install-claude.js
|
|
81
|
+
var MARKETPLACE_NAME = "hivemind";
|
|
82
|
+
var MARKETPLACE_SOURCE = "activeloopai/hivemind";
|
|
83
|
+
var PLUGIN_KEY = "hivemind@hivemind";
|
|
84
|
+
function runClaude(args) {
|
|
85
|
+
try {
|
|
86
|
+
const stdout = execFileSync("claude", args, {
|
|
87
|
+
encoding: "utf-8",
|
|
88
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
89
|
+
});
|
|
90
|
+
return { ok: true, stdout, stderr: "" };
|
|
91
|
+
} catch (err) {
|
|
92
|
+
const e = err;
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
stdout: e.stdout?.toString() ?? "",
|
|
96
|
+
stderr: e.stderr?.toString() ?? e.message ?? ""
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function requireClaudeCli() {
|
|
101
|
+
try {
|
|
102
|
+
execFileSync("claude", ["--version"], { stdio: "ignore" });
|
|
103
|
+
} catch {
|
|
104
|
+
throw new Error("Claude Code CLI ('claude') not found on PATH. Install Claude Code first: https://claude.com/claude-code");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function marketplaceAlreadyAdded() {
|
|
108
|
+
const r = runClaude(["plugin", "marketplace", "list"]);
|
|
109
|
+
if (!r.ok)
|
|
110
|
+
return false;
|
|
111
|
+
return new RegExp(`(^|\\s)${MARKETPLACE_NAME}(\\s|$)`, "m").test(r.stdout);
|
|
112
|
+
}
|
|
113
|
+
function pluginAlreadyInstalled() {
|
|
114
|
+
const r = runClaude(["plugin", "list"]);
|
|
115
|
+
if (!r.ok)
|
|
116
|
+
return false;
|
|
117
|
+
return r.stdout.includes(PLUGIN_KEY);
|
|
118
|
+
}
|
|
119
|
+
function installClaude() {
|
|
120
|
+
requireClaudeCli();
|
|
121
|
+
if (!marketplaceAlreadyAdded()) {
|
|
122
|
+
const add = runClaude(["plugin", "marketplace", "add", MARKETPLACE_SOURCE]);
|
|
123
|
+
if (!add.ok) {
|
|
124
|
+
throw new Error(`Failed to add marketplace '${MARKETPLACE_SOURCE}': ${add.stderr.slice(0, 200)}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!pluginAlreadyInstalled()) {
|
|
128
|
+
const inst = runClaude(["plugin", "install", "hivemind"]);
|
|
129
|
+
if (!inst.ok) {
|
|
130
|
+
throw new Error(`Failed to install hivemind plugin: ${inst.stderr.slice(0, 200)}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
runClaude(["plugin", "enable", PLUGIN_KEY]);
|
|
134
|
+
log(` Claude Code installed via marketplace ${MARKETPLACE_SOURCE}`);
|
|
135
|
+
}
|
|
136
|
+
function uninstallClaude() {
|
|
137
|
+
try {
|
|
138
|
+
requireClaudeCli();
|
|
139
|
+
} catch {
|
|
140
|
+
log(" Claude Code skip uninstall \u2014 claude CLI not on PATH");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
runClaude(["plugin", "disable", PLUGIN_KEY]);
|
|
144
|
+
runClaude(["plugin", "uninstall", PLUGIN_KEY]);
|
|
145
|
+
log(" Claude Code plugin uninstalled");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// dist/src/cli/install-codex.js
|
|
149
|
+
import { existsSync as existsSync2, unlinkSync as unlinkSync2 } from "node:fs";
|
|
150
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
151
|
+
import { join as join3 } from "node:path";
|
|
152
|
+
|
|
153
|
+
// dist/src/cli/version.js
|
|
154
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
155
|
+
import { join as join2 } from "node:path";
|
|
156
|
+
function getVersion() {
|
|
157
|
+
try {
|
|
158
|
+
const pkg = JSON.parse(readFileSync2(join2(pkgRoot(), "package.json"), "utf-8"));
|
|
159
|
+
return pkg.version ?? "0.0.0";
|
|
160
|
+
} catch {
|
|
161
|
+
return "0.0.0";
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// dist/src/cli/install-codex.js
|
|
166
|
+
var CODEX_HOME = join3(HOME, ".codex");
|
|
167
|
+
var PLUGIN_DIR = join3(CODEX_HOME, "hivemind");
|
|
168
|
+
var HOOKS_PATH = join3(CODEX_HOME, "hooks.json");
|
|
169
|
+
var AGENTS_SKILLS_DIR = join3(HOME, ".agents", "skills");
|
|
170
|
+
var SKILL_LINK = join3(AGENTS_SKILLS_DIR, "hivemind-memory");
|
|
171
|
+
function hookCmd(bundleFile, timeout, matcher) {
|
|
172
|
+
const block = {
|
|
173
|
+
hooks: [{
|
|
174
|
+
type: "command",
|
|
175
|
+
command: `node "${join3(PLUGIN_DIR, "bundle", bundleFile)}"`,
|
|
176
|
+
timeout
|
|
177
|
+
}]
|
|
178
|
+
};
|
|
179
|
+
if (matcher)
|
|
180
|
+
block.matcher = matcher;
|
|
181
|
+
return block;
|
|
182
|
+
}
|
|
183
|
+
function buildHooksJson() {
|
|
184
|
+
return {
|
|
185
|
+
hooks: {
|
|
186
|
+
SessionStart: [hookCmd("session-start.js", 120)],
|
|
187
|
+
UserPromptSubmit: [hookCmd("capture.js", 10)],
|
|
188
|
+
PreToolUse: [hookCmd("pre-tool-use.js", 15, "Bash")],
|
|
189
|
+
PostToolUse: [hookCmd("capture.js", 15)],
|
|
190
|
+
Stop: [hookCmd("stop.js", 30)]
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function tryEnableCodexHooks() {
|
|
195
|
+
try {
|
|
196
|
+
execFileSync2("codex", ["features", "enable", "codex_hooks"], { stdio: "ignore" });
|
|
197
|
+
} catch {
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function installCodex() {
|
|
201
|
+
const srcBundle = join3(pkgRoot(), "codex", "bundle");
|
|
202
|
+
const srcSkills = join3(pkgRoot(), "codex", "skills");
|
|
203
|
+
if (!existsSync2(srcBundle)) {
|
|
204
|
+
throw new Error(`Codex bundle missing at ${srcBundle}. Run 'npm run build' first.`);
|
|
205
|
+
}
|
|
206
|
+
ensureDir(PLUGIN_DIR);
|
|
207
|
+
copyDir(srcBundle, join3(PLUGIN_DIR, "bundle"));
|
|
208
|
+
if (existsSync2(srcSkills))
|
|
209
|
+
copyDir(srcSkills, join3(PLUGIN_DIR, "skills"));
|
|
210
|
+
tryEnableCodexHooks();
|
|
211
|
+
writeJson(HOOKS_PATH, buildHooksJson());
|
|
212
|
+
ensureDir(AGENTS_SKILLS_DIR);
|
|
213
|
+
const skillTarget = join3(PLUGIN_DIR, "skills", "deeplake-memory");
|
|
214
|
+
if (existsSync2(skillTarget)) {
|
|
215
|
+
symlinkForce(skillTarget, SKILL_LINK);
|
|
216
|
+
} else {
|
|
217
|
+
warn(` Codex skill source missing at ${skillTarget}; skipping symlink`);
|
|
218
|
+
}
|
|
219
|
+
writeVersionStamp(PLUGIN_DIR, getVersion());
|
|
220
|
+
log(` Codex installed -> ${PLUGIN_DIR}`);
|
|
221
|
+
}
|
|
222
|
+
function uninstallCodex() {
|
|
223
|
+
if (existsSync2(HOOKS_PATH)) {
|
|
224
|
+
unlinkSync2(HOOKS_PATH);
|
|
225
|
+
log(` Codex removed ${HOOKS_PATH}`);
|
|
226
|
+
}
|
|
227
|
+
if (existsSync2(SKILL_LINK)) {
|
|
228
|
+
unlinkSync2(SKILL_LINK);
|
|
229
|
+
log(` Codex removed ${SKILL_LINK}`);
|
|
230
|
+
}
|
|
231
|
+
log(` Codex plugin files kept at ${PLUGIN_DIR}`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// dist/src/cli/install-openclaw.js
|
|
235
|
+
import { existsSync as existsSync3, rmSync } from "node:fs";
|
|
236
|
+
import { join as join4 } from "node:path";
|
|
237
|
+
var PLUGIN_DIR2 = join4(HOME, ".openclaw", "extensions", "hivemind");
|
|
238
|
+
function installOpenclaw() {
|
|
239
|
+
const srcDist = join4(pkgRoot(), "openclaw", "dist");
|
|
240
|
+
const srcManifest = join4(pkgRoot(), "openclaw", "openclaw.plugin.json");
|
|
241
|
+
const srcPkg = join4(pkgRoot(), "openclaw", "package.json");
|
|
242
|
+
const srcSkills = join4(pkgRoot(), "openclaw", "skills");
|
|
243
|
+
if (!existsSync3(srcDist)) {
|
|
244
|
+
throw new Error(`OpenClaw bundle missing at ${srcDist}. Run 'npm run build' first.`);
|
|
245
|
+
}
|
|
246
|
+
ensureDir(PLUGIN_DIR2);
|
|
247
|
+
copyDir(srcDist, join4(PLUGIN_DIR2, "dist"));
|
|
248
|
+
if (existsSync3(srcManifest))
|
|
249
|
+
copyDir(srcManifest, join4(PLUGIN_DIR2, "openclaw.plugin.json"));
|
|
250
|
+
if (existsSync3(srcPkg))
|
|
251
|
+
copyDir(srcPkg, join4(PLUGIN_DIR2, "package.json"));
|
|
252
|
+
if (existsSync3(srcSkills))
|
|
253
|
+
copyDir(srcSkills, join4(PLUGIN_DIR2, "skills"));
|
|
254
|
+
writeVersionStamp(PLUGIN_DIR2, getVersion());
|
|
255
|
+
log(` OpenClaw installed -> ${PLUGIN_DIR2}`);
|
|
256
|
+
}
|
|
257
|
+
function uninstallOpenclaw() {
|
|
258
|
+
if (existsSync3(PLUGIN_DIR2)) {
|
|
259
|
+
rmSync(PLUGIN_DIR2, { recursive: true, force: true });
|
|
260
|
+
log(` OpenClaw removed ${PLUGIN_DIR2}`);
|
|
261
|
+
} else {
|
|
262
|
+
log(` OpenClaw nothing to remove`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// dist/src/cli/install-cursor.js
|
|
267
|
+
import { existsSync as existsSync4, unlinkSync as unlinkSync3 } from "node:fs";
|
|
268
|
+
import { join as join5 } from "node:path";
|
|
269
|
+
var CURSOR_HOME = join5(HOME, ".cursor");
|
|
270
|
+
var PLUGIN_DIR3 = join5(CURSOR_HOME, "hivemind");
|
|
271
|
+
var HOOKS_PATH2 = join5(CURSOR_HOME, "hooks.json");
|
|
272
|
+
var HIVEMIND_MARKER_KEY = "_hivemindManaged";
|
|
273
|
+
function buildHookCmd(bundleFile, timeout) {
|
|
274
|
+
return {
|
|
275
|
+
type: "command",
|
|
276
|
+
command: `node "${join5(PLUGIN_DIR3, "bundle", bundleFile)}"`,
|
|
277
|
+
timeout
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function buildHookConfig() {
|
|
281
|
+
return {
|
|
282
|
+
sessionStart: [buildHookCmd("session-start.js", 30)],
|
|
283
|
+
beforeSubmitPrompt: [buildHookCmd("capture.js", 10)],
|
|
284
|
+
postToolUse: [buildHookCmd("capture.js", 15)],
|
|
285
|
+
afterAgentResponse: [buildHookCmd("capture.js", 15)],
|
|
286
|
+
stop: [buildHookCmd("capture.js", 15)],
|
|
287
|
+
sessionEnd: [buildHookCmd("session-end.js", 30)]
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function isHivemindEntry(entry) {
|
|
291
|
+
if (!entry || typeof entry !== "object")
|
|
292
|
+
return false;
|
|
293
|
+
const cmd = entry.command;
|
|
294
|
+
return typeof cmd === "string" && cmd.includes("/.cursor/hivemind/bundle/");
|
|
295
|
+
}
|
|
296
|
+
function mergeHooks(existing) {
|
|
297
|
+
const root = existing ?? { version: 1, hooks: {} };
|
|
298
|
+
if (!root.version)
|
|
299
|
+
root.version = 1;
|
|
300
|
+
if (!root.hooks)
|
|
301
|
+
root.hooks = {};
|
|
302
|
+
const ours = buildHookConfig();
|
|
303
|
+
for (const [event, entries] of Object.entries(ours)) {
|
|
304
|
+
const prior = Array.isArray(root.hooks[event]) ? root.hooks[event] : [];
|
|
305
|
+
const stripped = prior.filter((e) => !isHivemindEntry(e));
|
|
306
|
+
root.hooks[event] = [...stripped, ...entries];
|
|
307
|
+
}
|
|
308
|
+
root[HIVEMIND_MARKER_KEY] = { version: getVersion() };
|
|
309
|
+
return root;
|
|
310
|
+
}
|
|
311
|
+
function stripHooksFromConfig(existing) {
|
|
312
|
+
if (!existing)
|
|
313
|
+
return null;
|
|
314
|
+
const root = existing;
|
|
315
|
+
if (root.hooks) {
|
|
316
|
+
for (const event of Object.keys(root.hooks)) {
|
|
317
|
+
root.hooks[event] = (root.hooks[event] ?? []).filter((e) => !isHivemindEntry(e));
|
|
318
|
+
if (root.hooks[event].length === 0)
|
|
319
|
+
delete root.hooks[event];
|
|
320
|
+
}
|
|
321
|
+
if (Object.keys(root.hooks).length === 0)
|
|
322
|
+
delete root.hooks;
|
|
323
|
+
}
|
|
324
|
+
delete existing[HIVEMIND_MARKER_KEY];
|
|
325
|
+
return existing;
|
|
326
|
+
}
|
|
327
|
+
function installCursor() {
|
|
328
|
+
const srcBundle = join5(pkgRoot(), "cursor", "bundle");
|
|
329
|
+
if (!existsSync4(srcBundle)) {
|
|
330
|
+
throw new Error(`Cursor bundle missing at ${srcBundle}. Run 'npm run build' first.`);
|
|
331
|
+
}
|
|
332
|
+
ensureDir(PLUGIN_DIR3);
|
|
333
|
+
copyDir(srcBundle, join5(PLUGIN_DIR3, "bundle"));
|
|
334
|
+
const existing = readJson(HOOKS_PATH2);
|
|
335
|
+
const merged = mergeHooks(existing);
|
|
336
|
+
writeJson(HOOKS_PATH2, merged);
|
|
337
|
+
writeVersionStamp(PLUGIN_DIR3, getVersion());
|
|
338
|
+
log(` Cursor installed -> ${PLUGIN_DIR3}`);
|
|
339
|
+
}
|
|
340
|
+
function uninstallCursor() {
|
|
341
|
+
const existing = readJson(HOOKS_PATH2);
|
|
342
|
+
if (!existing) {
|
|
343
|
+
log(" Cursor no hooks.json to clean");
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const stripped = stripHooksFromConfig(existing);
|
|
347
|
+
if (!stripped || Object.keys(stripped).length === 1 && stripped.version) {
|
|
348
|
+
if (existsSync4(HOOKS_PATH2))
|
|
349
|
+
unlinkSync3(HOOKS_PATH2);
|
|
350
|
+
} else {
|
|
351
|
+
writeJson(HOOKS_PATH2, stripped);
|
|
352
|
+
}
|
|
353
|
+
log(` Cursor hooks removed from ${HOOKS_PATH2} (plugin files kept at ${PLUGIN_DIR3})`);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// dist/src/cli/install-hermes.js
|
|
357
|
+
import { existsSync as existsSync5, writeFileSync as writeFileSync2, rmSync as rmSync2 } from "node:fs";
|
|
358
|
+
import { join as join6 } from "node:path";
|
|
359
|
+
var HERMES_HOME = join6(HOME, ".hermes");
|
|
360
|
+
var SKILLS_DIR = join6(HERMES_HOME, "skills", "hivemind-memory");
|
|
361
|
+
var SKILL_BODY = `---
|
|
362
|
+
name: hivemind-memory
|
|
363
|
+
description: Global team and org memory powered by Activeloop. ALWAYS check BOTH built-in memory AND Hivemind memory when recalling information.
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
# Hivemind Memory
|
|
367
|
+
|
|
368
|
+
You have persistent memory at \`~/.deeplake/memory/\` \u2014 global memory shared across all sessions, users, and agents in the org.
|
|
369
|
+
|
|
370
|
+
## Memory Structure
|
|
371
|
+
|
|
372
|
+
\`\`\`
|
|
373
|
+
~/.deeplake/memory/
|
|
374
|
+
\u251C\u2500\u2500 index.md \u2190 START HERE \u2014 table of all sessions
|
|
375
|
+
\u251C\u2500\u2500 summaries/
|
|
376
|
+
\u2502 \u251C\u2500\u2500 session-abc.md \u2190 AI-generated wiki summary
|
|
377
|
+
\u2502 \u2514\u2500\u2500 session-xyz.md
|
|
378
|
+
\u2514\u2500\u2500 sessions/
|
|
379
|
+
\u2514\u2500\u2500 username/
|
|
380
|
+
\u251C\u2500\u2500 user_org_ws_slug1.jsonl \u2190 raw session data
|
|
381
|
+
\u2514\u2500\u2500 user_org_ws_slug2.jsonl
|
|
382
|
+
\`\`\`
|
|
383
|
+
|
|
384
|
+
## How to Search
|
|
385
|
+
|
|
386
|
+
1. **First**: Read \`~/.deeplake/memory/index.md\` \u2014 quick scan of all sessions with dates, projects, descriptions
|
|
387
|
+
2. **If you need details**: Read the specific summary at \`~/.deeplake/memory/summaries/<session>.md\`
|
|
388
|
+
3. **If you need raw data**: Read the session JSONL at \`~/.deeplake/memory/sessions/<user>/<file>.jsonl\`
|
|
389
|
+
4. **Keyword search**: \`grep -r "keyword" ~/.deeplake/memory/\`
|
|
390
|
+
|
|
391
|
+
Do NOT jump straight to reading raw JSONL files. Always start with index.md and summaries.
|
|
392
|
+
|
|
393
|
+
## Important Constraints
|
|
394
|
+
|
|
395
|
+
- Only use bash builtins (\`cat\`, \`ls\`, \`grep\`, \`echo\`, \`jq\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, \`wc\`, \`sort\`, \`find\`) to interact with \`~/.deeplake/memory/\`. The memory filesystem does NOT support \`python\`, \`python3\`, \`node\`, or \`curl\`.
|
|
396
|
+
- If a file returns empty after 2 attempts, skip it and move on. Report what you found rather than retrying exhaustively.
|
|
397
|
+
`;
|
|
398
|
+
function installHermes() {
|
|
399
|
+
ensureDir(SKILLS_DIR);
|
|
400
|
+
writeFileSync2(join6(SKILLS_DIR, "SKILL.md"), SKILL_BODY);
|
|
401
|
+
writeVersionStamp(SKILLS_DIR, getVersion());
|
|
402
|
+
log(` Hermes skill installed -> ${SKILLS_DIR}`);
|
|
403
|
+
}
|
|
404
|
+
function uninstallHermes() {
|
|
405
|
+
if (existsSync5(SKILLS_DIR)) {
|
|
406
|
+
rmSync2(SKILLS_DIR, { recursive: true, force: true });
|
|
407
|
+
log(` Hermes removed ${SKILLS_DIR}`);
|
|
408
|
+
} else {
|
|
409
|
+
log(" Hermes nothing to remove");
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// dist/src/cli/install-pi.js
|
|
414
|
+
import { existsSync as existsSync6, writeFileSync as writeFileSync3, rmSync as rmSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
415
|
+
import { join as join7 } from "node:path";
|
|
416
|
+
var PI_AGENT_DIR = join7(HOME, ".pi", "agent");
|
|
417
|
+
var AGENTS_MD = join7(PI_AGENT_DIR, "AGENTS.md");
|
|
418
|
+
var SKILL_DIR = join7(PI_AGENT_DIR, "skills", "hivemind-memory");
|
|
419
|
+
var VERSION_DIR = join7(PI_AGENT_DIR, ".hivemind");
|
|
420
|
+
var HIVEMIND_BLOCK_START = "<!-- BEGIN hivemind-memory -->";
|
|
421
|
+
var HIVEMIND_BLOCK_END = "<!-- END hivemind-memory -->";
|
|
422
|
+
var HIVEMIND_BLOCK_BODY = `${HIVEMIND_BLOCK_START}
|
|
423
|
+
## Hivemind Memory
|
|
424
|
+
|
|
425
|
+
You have access to global org memory at \`~/.deeplake/memory/\`. Always check both
|
|
426
|
+
your local context AND Hivemind memory when the user asks you to recall, look up,
|
|
427
|
+
or remember anything.
|
|
428
|
+
|
|
429
|
+
- Start with \`~/.deeplake/memory/index.md\` (table of all sessions)
|
|
430
|
+
- Then read specific summaries at \`~/.deeplake/memory/summaries/<user>/<session>.md\`
|
|
431
|
+
- Only fall back to raw \`~/.deeplake/memory/sessions/<user>/*.jsonl\` if summaries don't have enough detail
|
|
432
|
+
- Search: \`grep -r "keyword" ~/.deeplake/memory/\`
|
|
433
|
+
|
|
434
|
+
Use only bash builtins (cat, ls, grep, jq, head, tail, sed, awk) to read this filesystem \u2014
|
|
435
|
+
node/python/curl are not available there.
|
|
436
|
+
${HIVEMIND_BLOCK_END}`;
|
|
437
|
+
var SKILL_BODY2 = `---
|
|
438
|
+
name: hivemind-memory
|
|
439
|
+
description: Global team and org memory powered by Activeloop. Always check both local context AND Hivemind memory when recalling information.
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
# Hivemind Memory
|
|
443
|
+
|
|
444
|
+
You have persistent memory at \`~/.deeplake/memory/\` \u2014 global memory shared across all sessions, users, and agents in the org.
|
|
445
|
+
|
|
446
|
+
## Memory Structure
|
|
447
|
+
|
|
448
|
+
\`\`\`
|
|
449
|
+
~/.deeplake/memory/
|
|
450
|
+
\u251C\u2500\u2500 index.md \u2190 START HERE \u2014 table of all sessions
|
|
451
|
+
\u251C\u2500\u2500 summaries/
|
|
452
|
+
\u2502 \u251C\u2500\u2500 session-abc.md \u2190 AI-generated wiki summary
|
|
453
|
+
\u2502 \u2514\u2500\u2500 session-xyz.md
|
|
454
|
+
\u2514\u2500\u2500 sessions/
|
|
455
|
+
\u2514\u2500\u2500 username/
|
|
456
|
+
\u251C\u2500\u2500 user_org_ws_slug1.jsonl \u2190 raw session data
|
|
457
|
+
\u2514\u2500\u2500 user_org_ws_slug2.jsonl
|
|
458
|
+
\`\`\`
|
|
459
|
+
|
|
460
|
+
## How to Search
|
|
461
|
+
|
|
462
|
+
1. **First**: Read \`~/.deeplake/memory/index.md\` \u2014 quick scan of all sessions with dates, projects, descriptions
|
|
463
|
+
2. **If you need details**: Read the specific summary at \`~/.deeplake/memory/summaries/<session>.md\`
|
|
464
|
+
3. **If you need raw data**: Read the session JSONL at \`~/.deeplake/memory/sessions/<user>/<file>.jsonl\`
|
|
465
|
+
4. **Keyword search**: \`grep -r "keyword" ~/.deeplake/memory/\`
|
|
466
|
+
|
|
467
|
+
Do NOT jump straight to reading raw JSONL files. Always start with index.md and summaries.
|
|
468
|
+
|
|
469
|
+
## Important Constraints
|
|
470
|
+
|
|
471
|
+
- Only use bash builtins (\`cat\`, \`ls\`, \`grep\`, \`echo\`, \`jq\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, \`wc\`, \`sort\`, \`find\`) to interact with \`~/.deeplake/memory/\`. The memory filesystem does NOT support \`python\`, \`python3\`, \`node\`, or \`curl\`.
|
|
472
|
+
- If a file returns empty after 2 attempts, skip it and move on. Report what you found rather than retrying exhaustively.
|
|
473
|
+
`;
|
|
474
|
+
function upsertHivemindBlock(existing) {
|
|
475
|
+
const block = HIVEMIND_BLOCK_BODY;
|
|
476
|
+
if (!existing)
|
|
477
|
+
return `${block}
|
|
478
|
+
`;
|
|
479
|
+
const startIdx = existing.indexOf(HIVEMIND_BLOCK_START);
|
|
480
|
+
if (startIdx === -1)
|
|
481
|
+
return `${existing.trimEnd()}
|
|
482
|
+
|
|
483
|
+
${block}
|
|
484
|
+
`;
|
|
485
|
+
const endIdx = existing.indexOf(HIVEMIND_BLOCK_END, startIdx);
|
|
486
|
+
if (endIdx === -1) {
|
|
487
|
+
return `${existing.trimEnd()}
|
|
488
|
+
|
|
489
|
+
${block}
|
|
490
|
+
`;
|
|
491
|
+
}
|
|
492
|
+
const before = existing.slice(0, startIdx).trimEnd();
|
|
493
|
+
const after = existing.slice(endIdx + HIVEMIND_BLOCK_END.length).replace(/^\n+/, "");
|
|
494
|
+
const rest = after ? `
|
|
495
|
+
|
|
496
|
+
${after}` : "";
|
|
497
|
+
return `${before ? before + "\n\n" : ""}${block}
|
|
498
|
+
${rest}`;
|
|
499
|
+
}
|
|
500
|
+
function stripHivemindBlock(existing) {
|
|
501
|
+
const startIdx = existing.indexOf(HIVEMIND_BLOCK_START);
|
|
502
|
+
if (startIdx === -1)
|
|
503
|
+
return existing;
|
|
504
|
+
const endIdx = existing.indexOf(HIVEMIND_BLOCK_END, startIdx);
|
|
505
|
+
if (endIdx === -1)
|
|
506
|
+
return existing;
|
|
507
|
+
const before = existing.slice(0, startIdx).trimEnd();
|
|
508
|
+
const after = existing.slice(endIdx + HIVEMIND_BLOCK_END.length).replace(/^\n+/, "");
|
|
509
|
+
if (!before && !after)
|
|
510
|
+
return "";
|
|
511
|
+
if (!before)
|
|
512
|
+
return after;
|
|
513
|
+
if (!after)
|
|
514
|
+
return `${before}
|
|
515
|
+
`;
|
|
516
|
+
return `${before}
|
|
517
|
+
|
|
518
|
+
${after}`;
|
|
519
|
+
}
|
|
520
|
+
function installPi() {
|
|
521
|
+
ensureDir(PI_AGENT_DIR);
|
|
522
|
+
ensureDir(SKILL_DIR);
|
|
523
|
+
writeFileSync3(join7(SKILL_DIR, "SKILL.md"), SKILL_BODY2);
|
|
524
|
+
const prior = existsSync6(AGENTS_MD) ? readFileSync3(AGENTS_MD, "utf-8") : null;
|
|
525
|
+
const next = upsertHivemindBlock(prior);
|
|
526
|
+
writeFileSync3(AGENTS_MD, next);
|
|
527
|
+
ensureDir(VERSION_DIR);
|
|
528
|
+
writeVersionStamp(VERSION_DIR, getVersion());
|
|
529
|
+
log(` pi skill installed -> ${SKILL_DIR}`);
|
|
530
|
+
log(` pi AGENTS.md updated -> ${AGENTS_MD}`);
|
|
531
|
+
}
|
|
532
|
+
function uninstallPi() {
|
|
533
|
+
if (existsSync6(SKILL_DIR)) {
|
|
534
|
+
rmSync3(SKILL_DIR, { recursive: true, force: true });
|
|
535
|
+
log(` pi removed ${SKILL_DIR}`);
|
|
536
|
+
}
|
|
537
|
+
if (existsSync6(AGENTS_MD)) {
|
|
538
|
+
const prior = readFileSync3(AGENTS_MD, "utf-8");
|
|
539
|
+
const stripped = stripHivemindBlock(prior);
|
|
540
|
+
if (stripped.trim().length === 0) {
|
|
541
|
+
rmSync3(AGENTS_MD, { force: true });
|
|
542
|
+
log(` pi removed empty ${AGENTS_MD}`);
|
|
543
|
+
} else {
|
|
544
|
+
writeFileSync3(AGENTS_MD, stripped);
|
|
545
|
+
log(` pi stripped hivemind block from ${AGENTS_MD}`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
if (existsSync6(VERSION_DIR)) {
|
|
549
|
+
rmSync3(VERSION_DIR, { recursive: true, force: true });
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// dist/src/cli/install-cline.js
|
|
554
|
+
import { existsSync as existsSync8, unlinkSync as unlinkSync4 } from "node:fs";
|
|
555
|
+
import { join as join9 } from "node:path";
|
|
556
|
+
|
|
557
|
+
// dist/src/cli/install-mcp-shared.js
|
|
558
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
559
|
+
import { join as join8 } from "node:path";
|
|
560
|
+
var HIVEMIND_DIR = join8(HOME, ".hivemind");
|
|
561
|
+
var MCP_DIR = join8(HIVEMIND_DIR, "mcp");
|
|
562
|
+
var MCP_SERVER_PATH = join8(MCP_DIR, "server.js");
|
|
563
|
+
var MCP_PACKAGE_JSON = join8(MCP_DIR, "package.json");
|
|
564
|
+
function ensureMcpServerInstalled() {
|
|
565
|
+
const srcDir = join8(pkgRoot(), "mcp", "bundle");
|
|
566
|
+
if (!existsSync7(srcDir)) {
|
|
567
|
+
throw new Error(`MCP server bundle missing at ${srcDir}. Run 'npm run build' to produce it before installing Tier B consumers.`);
|
|
568
|
+
}
|
|
569
|
+
ensureDir(MCP_DIR);
|
|
570
|
+
copyDir(srcDir, MCP_DIR);
|
|
571
|
+
writeVersionStamp(HIVEMIND_DIR, getVersion());
|
|
572
|
+
log(` hivemind-mcp server installed -> ${MCP_SERVER_PATH}`);
|
|
573
|
+
}
|
|
574
|
+
function buildMcpServerEntry() {
|
|
575
|
+
return {
|
|
576
|
+
command: "node",
|
|
577
|
+
args: [MCP_SERVER_PATH]
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// dist/src/cli/install-cline.js
|
|
582
|
+
var CONFIG_PATH = join9(HOME, ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json");
|
|
583
|
+
var SERVER_KEY = "hivemind";
|
|
584
|
+
function installCline() {
|
|
585
|
+
ensureMcpServerInstalled();
|
|
586
|
+
const cfg = readJson(CONFIG_PATH) ?? {};
|
|
587
|
+
if (!cfg.mcpServers)
|
|
588
|
+
cfg.mcpServers = {};
|
|
589
|
+
cfg.mcpServers[SERVER_KEY] = buildMcpServerEntry();
|
|
590
|
+
writeJson(CONFIG_PATH, cfg);
|
|
591
|
+
log(` Cline MCP server registered in ${CONFIG_PATH}`);
|
|
592
|
+
}
|
|
593
|
+
function uninstallCline() {
|
|
594
|
+
const cfg = readJson(CONFIG_PATH);
|
|
595
|
+
if (!cfg?.mcpServers || !(SERVER_KEY in cfg.mcpServers)) {
|
|
596
|
+
log(" Cline nothing to remove");
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
delete cfg.mcpServers[SERVER_KEY];
|
|
600
|
+
if (Object.keys(cfg.mcpServers).length === 0) {
|
|
601
|
+
delete cfg.mcpServers;
|
|
602
|
+
}
|
|
603
|
+
if (Object.keys(cfg).length === 0) {
|
|
604
|
+
if (existsSync8(CONFIG_PATH))
|
|
605
|
+
unlinkSync4(CONFIG_PATH);
|
|
606
|
+
} else {
|
|
607
|
+
writeJson(CONFIG_PATH, cfg);
|
|
608
|
+
}
|
|
609
|
+
log(` Cline MCP entry removed from ${CONFIG_PATH}`);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// dist/src/cli/install-roo.js
|
|
613
|
+
import { existsSync as existsSync9, unlinkSync as unlinkSync5 } from "node:fs";
|
|
614
|
+
import { join as join10 } from "node:path";
|
|
615
|
+
var CONFIG_PATH2 = join10(HOME, ".config", "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline", "settings", "mcp_settings.json");
|
|
616
|
+
var SERVER_KEY2 = "hivemind";
|
|
617
|
+
function installRoo() {
|
|
618
|
+
ensureMcpServerInstalled();
|
|
619
|
+
const cfg = readJson(CONFIG_PATH2) ?? {};
|
|
620
|
+
if (!cfg.mcpServers)
|
|
621
|
+
cfg.mcpServers = {};
|
|
622
|
+
cfg.mcpServers[SERVER_KEY2] = buildMcpServerEntry();
|
|
623
|
+
writeJson(CONFIG_PATH2, cfg);
|
|
624
|
+
log(` Roo Code MCP server registered in ${CONFIG_PATH2}`);
|
|
625
|
+
}
|
|
626
|
+
function uninstallRoo() {
|
|
627
|
+
const cfg = readJson(CONFIG_PATH2);
|
|
628
|
+
if (!cfg?.mcpServers || !(SERVER_KEY2 in cfg.mcpServers)) {
|
|
629
|
+
log(" Roo Code nothing to remove");
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
delete cfg.mcpServers[SERVER_KEY2];
|
|
633
|
+
if (Object.keys(cfg.mcpServers).length === 0)
|
|
634
|
+
delete cfg.mcpServers;
|
|
635
|
+
if (Object.keys(cfg).length === 0) {
|
|
636
|
+
if (existsSync9(CONFIG_PATH2))
|
|
637
|
+
unlinkSync5(CONFIG_PATH2);
|
|
638
|
+
} else {
|
|
639
|
+
writeJson(CONFIG_PATH2, cfg);
|
|
640
|
+
}
|
|
641
|
+
log(` Roo Code MCP entry removed from ${CONFIG_PATH2}`);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// dist/src/cli/install-kilo.js
|
|
645
|
+
import { existsSync as existsSync10, unlinkSync as unlinkSync6 } from "node:fs";
|
|
646
|
+
import { join as join11 } from "node:path";
|
|
647
|
+
var CONFIG_PATH3 = join11(HOME, ".kilocode", "mcp.json");
|
|
648
|
+
var SERVER_KEY3 = "hivemind";
|
|
649
|
+
function installKilo() {
|
|
650
|
+
ensureMcpServerInstalled();
|
|
651
|
+
const cfg = readJson(CONFIG_PATH3) ?? {};
|
|
652
|
+
if (!cfg.mcpServers)
|
|
653
|
+
cfg.mcpServers = {};
|
|
654
|
+
cfg.mcpServers[SERVER_KEY3] = buildMcpServerEntry();
|
|
655
|
+
writeJson(CONFIG_PATH3, cfg);
|
|
656
|
+
log(` Kilo Code MCP server registered in ${CONFIG_PATH3}`);
|
|
657
|
+
}
|
|
658
|
+
function uninstallKilo() {
|
|
659
|
+
const cfg = readJson(CONFIG_PATH3);
|
|
660
|
+
if (!cfg?.mcpServers || !(SERVER_KEY3 in cfg.mcpServers)) {
|
|
661
|
+
log(" Kilo Code nothing to remove");
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
delete cfg.mcpServers[SERVER_KEY3];
|
|
665
|
+
if (Object.keys(cfg.mcpServers).length === 0)
|
|
666
|
+
delete cfg.mcpServers;
|
|
667
|
+
if (Object.keys(cfg).length === 0) {
|
|
668
|
+
if (existsSync10(CONFIG_PATH3))
|
|
669
|
+
unlinkSync6(CONFIG_PATH3);
|
|
670
|
+
} else {
|
|
671
|
+
writeJson(CONFIG_PATH3, cfg);
|
|
672
|
+
}
|
|
673
|
+
log(` Kilo Code MCP entry removed from ${CONFIG_PATH3}`);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// dist/src/cli/auth.js
|
|
677
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
678
|
+
import { join as join13 } from "node:path";
|
|
679
|
+
|
|
680
|
+
// dist/src/commands/auth.js
|
|
681
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync11, mkdirSync as mkdirSync2, unlinkSync as unlinkSync7 } from "node:fs";
|
|
682
|
+
import { join as join12 } from "node:path";
|
|
683
|
+
import { homedir as homedir2 } from "node:os";
|
|
684
|
+
import { execSync } from "node:child_process";
|
|
685
|
+
var CONFIG_DIR = join12(homedir2(), ".deeplake");
|
|
686
|
+
var CREDS_PATH = join12(CONFIG_DIR, "credentials.json");
|
|
687
|
+
var DEFAULT_API_URL = "https://api.deeplake.ai";
|
|
688
|
+
function loadCredentials() {
|
|
689
|
+
if (!existsSync11(CREDS_PATH))
|
|
690
|
+
return null;
|
|
691
|
+
try {
|
|
692
|
+
return JSON.parse(readFileSync4(CREDS_PATH, "utf-8"));
|
|
693
|
+
} catch {
|
|
694
|
+
return null;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
function saveCredentials(creds) {
|
|
698
|
+
if (!existsSync11(CONFIG_DIR))
|
|
699
|
+
mkdirSync2(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
700
|
+
writeFileSync4(CREDS_PATH, JSON.stringify({ ...creds, savedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), { mode: 384 });
|
|
701
|
+
}
|
|
702
|
+
async function apiGet(path, token, apiUrl, orgId) {
|
|
703
|
+
const headers = {
|
|
704
|
+
Authorization: `Bearer ${token}`,
|
|
705
|
+
"Content-Type": "application/json"
|
|
706
|
+
};
|
|
707
|
+
if (orgId)
|
|
708
|
+
headers["X-Activeloop-Org-Id"] = orgId;
|
|
709
|
+
const resp = await fetch(`${apiUrl}${path}`, { headers });
|
|
710
|
+
if (!resp.ok)
|
|
711
|
+
throw new Error(`API ${resp.status}: ${await resp.text().catch(() => "")}`);
|
|
712
|
+
return resp.json();
|
|
713
|
+
}
|
|
714
|
+
async function apiPost(path, body, token, apiUrl, orgId) {
|
|
715
|
+
const headers = {
|
|
716
|
+
Authorization: `Bearer ${token}`,
|
|
717
|
+
"Content-Type": "application/json"
|
|
718
|
+
};
|
|
719
|
+
if (orgId)
|
|
720
|
+
headers["X-Activeloop-Org-Id"] = orgId;
|
|
721
|
+
const resp = await fetch(`${apiUrl}${path}`, { method: "POST", headers, body: JSON.stringify(body) });
|
|
722
|
+
if (!resp.ok)
|
|
723
|
+
throw new Error(`API ${resp.status}: ${await resp.text().catch(() => "")}`);
|
|
724
|
+
return resp.json();
|
|
725
|
+
}
|
|
726
|
+
async function requestDeviceCode(apiUrl = DEFAULT_API_URL) {
|
|
727
|
+
const resp = await fetch(`${apiUrl}/auth/device/code`, {
|
|
728
|
+
method: "POST",
|
|
729
|
+
headers: { "Content-Type": "application/json" }
|
|
730
|
+
});
|
|
731
|
+
if (!resp.ok)
|
|
732
|
+
throw new Error(`Device flow unavailable: HTTP ${resp.status}`);
|
|
733
|
+
return resp.json();
|
|
734
|
+
}
|
|
735
|
+
async function pollForToken(deviceCode, apiUrl = DEFAULT_API_URL) {
|
|
736
|
+
const resp = await fetch(`${apiUrl}/auth/device/token`, {
|
|
737
|
+
method: "POST",
|
|
738
|
+
headers: { "Content-Type": "application/json" },
|
|
739
|
+
body: JSON.stringify({ device_code: deviceCode })
|
|
740
|
+
});
|
|
741
|
+
if (resp.ok)
|
|
742
|
+
return resp.json();
|
|
743
|
+
if (resp.status === 400) {
|
|
744
|
+
const err = await resp.json().catch(() => null);
|
|
745
|
+
if (err?.error === "authorization_pending" || err?.error === "slow_down")
|
|
746
|
+
return null;
|
|
747
|
+
if (err?.error === "expired_token")
|
|
748
|
+
throw new Error("Device code expired. Try again.");
|
|
749
|
+
if (err?.error === "access_denied")
|
|
750
|
+
throw new Error("Authorization denied.");
|
|
751
|
+
}
|
|
752
|
+
throw new Error(`Token polling failed: HTTP ${resp.status}`);
|
|
753
|
+
}
|
|
754
|
+
function openBrowser(url) {
|
|
755
|
+
try {
|
|
756
|
+
const cmd = process.platform === "darwin" ? `open "${url}"` : process.platform === "win32" ? `start "${url}"` : `xdg-open "${url}" 2>/dev/null`;
|
|
757
|
+
execSync(cmd, { stdio: "ignore", timeout: 5e3 });
|
|
758
|
+
return true;
|
|
759
|
+
} catch {
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
async function deviceFlowLogin(apiUrl = DEFAULT_API_URL) {
|
|
764
|
+
const code = await requestDeviceCode(apiUrl);
|
|
765
|
+
const opened = openBrowser(code.verification_uri_complete);
|
|
766
|
+
const msg = [
|
|
767
|
+
"\nDeeplake Authentication",
|
|
768
|
+
"\u2500".repeat(40),
|
|
769
|
+
`
|
|
770
|
+
Open this URL: ${code.verification_uri_complete}`,
|
|
771
|
+
`Or visit ${code.verification_uri} and enter code: ${code.user_code}`,
|
|
772
|
+
opened ? "\nBrowser opened. Waiting for sign in..." : "\nWaiting for sign in..."
|
|
773
|
+
].join("\n");
|
|
774
|
+
process.stderr.write(msg + "\n");
|
|
775
|
+
const interval = Math.max(code.interval || 5, 5) * 1e3;
|
|
776
|
+
const deadline = Date.now() + code.expires_in * 1e3;
|
|
777
|
+
while (Date.now() < deadline) {
|
|
778
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
779
|
+
const result = await pollForToken(code.device_code, apiUrl);
|
|
780
|
+
if (result) {
|
|
781
|
+
process.stderr.write("\nAuthentication successful!\n");
|
|
782
|
+
return { token: result.access_token, expiresIn: result.expires_in };
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
throw new Error("Device code expired.");
|
|
786
|
+
}
|
|
787
|
+
async function listOrgs(token, apiUrl = DEFAULT_API_URL) {
|
|
788
|
+
const data = await apiGet("/organizations", token, apiUrl);
|
|
789
|
+
return Array.isArray(data) ? data : [];
|
|
790
|
+
}
|
|
791
|
+
async function login(apiUrl = DEFAULT_API_URL) {
|
|
792
|
+
const { token: authToken } = await deviceFlowLogin(apiUrl);
|
|
793
|
+
const user = await apiGet("/me", authToken, apiUrl);
|
|
794
|
+
const userName = user.name || (user.email ? user.email.split("@")[0] : "unknown");
|
|
795
|
+
process.stderr.write(`
|
|
796
|
+
Logged in as: ${userName}
|
|
797
|
+
`);
|
|
798
|
+
const orgs = await listOrgs(authToken, apiUrl);
|
|
799
|
+
let orgId;
|
|
800
|
+
let orgName;
|
|
801
|
+
if (orgs.length === 1) {
|
|
802
|
+
orgId = orgs[0].id;
|
|
803
|
+
orgName = orgs[0].name;
|
|
804
|
+
process.stderr.write(`Organization: ${orgName}
|
|
805
|
+
`);
|
|
806
|
+
} else {
|
|
807
|
+
process.stderr.write("\nOrganizations:\n");
|
|
808
|
+
orgs.forEach((org, i) => process.stderr.write(` ${i + 1}. ${org.name}
|
|
809
|
+
`));
|
|
810
|
+
orgId = orgs[0].id;
|
|
811
|
+
orgName = orgs[0].name;
|
|
812
|
+
process.stderr.write(`
|
|
813
|
+
Using: ${orgName}
|
|
814
|
+
`);
|
|
815
|
+
}
|
|
816
|
+
const tokenName = `deeplake-plugin-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
817
|
+
const tokenData = await apiPost("/users/me/tokens", {
|
|
818
|
+
name: tokenName,
|
|
819
|
+
duration: 365 * 24 * 3600,
|
|
820
|
+
organization_id: orgId
|
|
821
|
+
}, authToken, apiUrl);
|
|
822
|
+
const apiToken = tokenData.token.token;
|
|
823
|
+
const creds = {
|
|
824
|
+
token: apiToken,
|
|
825
|
+
orgId,
|
|
826
|
+
orgName,
|
|
827
|
+
userName,
|
|
828
|
+
workspaceId: "default",
|
|
829
|
+
apiUrl,
|
|
830
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
831
|
+
};
|
|
832
|
+
saveCredentials(creds);
|
|
833
|
+
return creds;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// dist/src/cli/auth.js
|
|
837
|
+
var CREDS_PATH2 = join13(HOME, ".deeplake", "credentials.json");
|
|
838
|
+
function isLoggedIn() {
|
|
839
|
+
return existsSync12(CREDS_PATH2) && loadCredentials() !== null;
|
|
840
|
+
}
|
|
841
|
+
async function ensureLoggedIn() {
|
|
842
|
+
if (isLoggedIn())
|
|
843
|
+
return true;
|
|
844
|
+
log("");
|
|
845
|
+
log("No Deeplake credentials found. Starting login...");
|
|
846
|
+
try {
|
|
847
|
+
const apiUrl = process.env.HIVEMIND_API_URL ?? process.env.DEEPLAKE_API_URL ?? "https://api.deeplake.ai";
|
|
848
|
+
await login(apiUrl);
|
|
849
|
+
} catch (err) {
|
|
850
|
+
warn(`Login failed: ${err.message}`);
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
return isLoggedIn();
|
|
854
|
+
}
|
|
855
|
+
async function maybeShowOrgChoice() {
|
|
856
|
+
const creds = loadCredentials();
|
|
857
|
+
if (!creds)
|
|
858
|
+
return;
|
|
859
|
+
try {
|
|
860
|
+
const orgs = await listOrgs(creds.token, creds.apiUrl ?? "https://api.deeplake.ai");
|
|
861
|
+
if (orgs.length <= 1)
|
|
862
|
+
return;
|
|
863
|
+
const activeName = creds.orgName ?? creds.orgId;
|
|
864
|
+
log("");
|
|
865
|
+
log(`You belong to ${orgs.length} orgs. Active: ${activeName}`);
|
|
866
|
+
log(` Change with: hivemind org switch <name-or-id>`);
|
|
867
|
+
} catch {
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// dist/src/cli/index.js
|
|
872
|
+
var USAGE = `
|
|
873
|
+
hivemind \u2014 one brain for every agent on your team
|
|
874
|
+
|
|
875
|
+
Usage:
|
|
876
|
+
hivemind install [--only <platforms>] [--skip-auth]
|
|
877
|
+
Auto-detect assistants on this machine and install hivemind into each.
|
|
878
|
+
--only takes a comma-separated list: ${allPlatformIds().join(",")}
|
|
879
|
+
|
|
880
|
+
hivemind claude install | uninstall
|
|
881
|
+
hivemind codex install | uninstall
|
|
882
|
+
hivemind claw install | uninstall
|
|
883
|
+
hivemind cursor install | uninstall
|
|
884
|
+
hivemind hermes install | uninstall
|
|
885
|
+
hivemind pi install | uninstall
|
|
886
|
+
hivemind cline install | uninstall
|
|
887
|
+
hivemind roo install | uninstall
|
|
888
|
+
hivemind kilo install | uninstall
|
|
889
|
+
Install or remove hivemind for a specific assistant.
|
|
890
|
+
|
|
891
|
+
hivemind login Run device-flow login (open browser).
|
|
892
|
+
hivemind status Show which assistants are wired up.
|
|
893
|
+
hivemind --version Print the hivemind version.
|
|
894
|
+
hivemind --help Show this message.
|
|
895
|
+
|
|
896
|
+
Docs: https://github.com/activeloopai/hivemind
|
|
897
|
+
`.trim();
|
|
898
|
+
function parseOnly(args) {
|
|
899
|
+
const idx = args.findIndex((a) => a === "--only" || a.startsWith("--only="));
|
|
900
|
+
if (idx === -1)
|
|
901
|
+
return null;
|
|
902
|
+
const raw = args[idx].includes("=") ? args[idx].split("=", 2)[1] : args[idx + 1];
|
|
903
|
+
if (!raw)
|
|
904
|
+
return null;
|
|
905
|
+
const ids = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
906
|
+
const valid = new Set(allPlatformIds());
|
|
907
|
+
const bad = ids.filter((id) => !valid.has(id));
|
|
908
|
+
if (bad.length > 0) {
|
|
909
|
+
warn(`Unknown platform(s): ${bad.join(", ")}. Valid: ${allPlatformIds().join(", ")}`);
|
|
910
|
+
process.exit(1);
|
|
911
|
+
}
|
|
912
|
+
return ids;
|
|
913
|
+
}
|
|
914
|
+
function hasFlag(args, flag) {
|
|
915
|
+
return args.includes(flag);
|
|
916
|
+
}
|
|
917
|
+
async function runInstallAll(args) {
|
|
918
|
+
const only = parseOnly(args);
|
|
919
|
+
const skipAuth = hasFlag(args, "--skip-auth");
|
|
920
|
+
const targets = only ?? detectPlatforms().map((p) => p.id);
|
|
921
|
+
if (targets.length === 0) {
|
|
922
|
+
log("No supported assistants detected.");
|
|
923
|
+
log("Supported: Claude Code, Codex, OpenClaw, Cursor, Hermes Agent.");
|
|
924
|
+
log("Install one and rerun `hivemind install`, or target a specific assistant: `hivemind cursor install`.");
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
log(`Installing hivemind ${getVersion()} for: ${targets.join(", ")}`);
|
|
928
|
+
log("");
|
|
929
|
+
if (!skipAuth && !isLoggedIn()) {
|
|
930
|
+
const ok = await ensureLoggedIn();
|
|
931
|
+
if (!ok) {
|
|
932
|
+
warn("Skipping install because login did not complete.");
|
|
933
|
+
process.exit(1);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
for (const id of targets)
|
|
937
|
+
runSingleInstall(id);
|
|
938
|
+
await maybeShowOrgChoice();
|
|
939
|
+
log("");
|
|
940
|
+
log("Done. Restart each assistant to activate hooks.");
|
|
941
|
+
}
|
|
942
|
+
function runSingleInstall(id) {
|
|
943
|
+
try {
|
|
944
|
+
if (id === "claude")
|
|
945
|
+
installClaude();
|
|
946
|
+
else if (id === "codex")
|
|
947
|
+
installCodex();
|
|
948
|
+
else if (id === "claw")
|
|
949
|
+
installOpenclaw();
|
|
950
|
+
else if (id === "cursor")
|
|
951
|
+
installCursor();
|
|
952
|
+
else if (id === "hermes")
|
|
953
|
+
installHermes();
|
|
954
|
+
else if (id === "pi")
|
|
955
|
+
installPi();
|
|
956
|
+
else if (id === "cline")
|
|
957
|
+
installCline();
|
|
958
|
+
else if (id === "roo")
|
|
959
|
+
installRoo();
|
|
960
|
+
else if (id === "kilo")
|
|
961
|
+
installKilo();
|
|
962
|
+
} catch (err) {
|
|
963
|
+
warn(` ${id.padEnd(14)} FAILED: ${err.message}`);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
function runSingleUninstall(id) {
|
|
967
|
+
try {
|
|
968
|
+
if (id === "claude")
|
|
969
|
+
uninstallClaude();
|
|
970
|
+
else if (id === "codex")
|
|
971
|
+
uninstallCodex();
|
|
972
|
+
else if (id === "claw")
|
|
973
|
+
uninstallOpenclaw();
|
|
974
|
+
else if (id === "cursor")
|
|
975
|
+
uninstallCursor();
|
|
976
|
+
else if (id === "hermes")
|
|
977
|
+
uninstallHermes();
|
|
978
|
+
else if (id === "pi")
|
|
979
|
+
uninstallPi();
|
|
980
|
+
else if (id === "cline")
|
|
981
|
+
uninstallCline();
|
|
982
|
+
else if (id === "roo")
|
|
983
|
+
uninstallRoo();
|
|
984
|
+
else if (id === "kilo")
|
|
985
|
+
uninstallKilo();
|
|
986
|
+
} catch (err) {
|
|
987
|
+
warn(` ${id.padEnd(14)} FAILED: ${err.message}`);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
function runStatus() {
|
|
991
|
+
const detected = detectPlatforms();
|
|
992
|
+
log(`hivemind ${getVersion()}`);
|
|
993
|
+
log(`logged in: ${isLoggedIn() ? "yes" : "no"}`);
|
|
994
|
+
log("");
|
|
995
|
+
log("Detected assistants:");
|
|
996
|
+
if (detected.length === 0)
|
|
997
|
+
log(" (none)");
|
|
998
|
+
for (const p of detected)
|
|
999
|
+
log(` ${p.id.padEnd(8)} ${p.markerDir}`);
|
|
1000
|
+
}
|
|
1001
|
+
async function main() {
|
|
1002
|
+
const args = process.argv.slice(2);
|
|
1003
|
+
const cmd = args[0];
|
|
1004
|
+
if (!cmd || cmd === "--help" || cmd === "-h" || cmd === "help") {
|
|
1005
|
+
log(USAGE);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
if (cmd === "--version" || cmd === "-v" || cmd === "version") {
|
|
1009
|
+
log(getVersion());
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
if (cmd === "install") {
|
|
1013
|
+
await runInstallAll(args.slice(1));
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
if (cmd === "uninstall") {
|
|
1017
|
+
const only = parseOnly(args.slice(1));
|
|
1018
|
+
const targets = only ?? detectPlatforms().map((p) => p.id);
|
|
1019
|
+
for (const id of targets)
|
|
1020
|
+
runSingleUninstall(id);
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
if (cmd === "login") {
|
|
1024
|
+
await ensureLoggedIn();
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1027
|
+
if (cmd === "status") {
|
|
1028
|
+
runStatus();
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
const platformCmds = ["claude", "codex", "claw", "cursor", "hermes", "pi", "cline", "roo", "kilo"];
|
|
1032
|
+
if (platformCmds.includes(cmd)) {
|
|
1033
|
+
const sub = args[1];
|
|
1034
|
+
if (sub === "install")
|
|
1035
|
+
runSingleInstall(cmd);
|
|
1036
|
+
else if (sub === "uninstall")
|
|
1037
|
+
runSingleUninstall(cmd);
|
|
1038
|
+
else {
|
|
1039
|
+
warn(`Usage: hivemind ${cmd} install|uninstall`);
|
|
1040
|
+
process.exit(1);
|
|
1041
|
+
}
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
warn(`Unknown command: ${cmd}`);
|
|
1045
|
+
log(USAGE);
|
|
1046
|
+
process.exit(1);
|
|
1047
|
+
}
|
|
1048
|
+
main().catch((err) => {
|
|
1049
|
+
warn(`hivemind: ${err.message}`);
|
|
1050
|
+
process.exit(1);
|
|
1051
|
+
});
|