@deeplake/hivemind 0.6.48 → 0.7.9
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 +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +244 -20
- package/bundle/cli.js +1369 -112
- package/codex/bundle/capture.js +546 -96
- package/codex/bundle/commands/auth-login.js +290 -81
- package/codex/bundle/embeddings/embed-daemon.js +243 -0
- package/codex/bundle/pre-tool-use.js +666 -111
- package/codex/bundle/session-start-setup.js +231 -64
- package/codex/bundle/session-start.js +52 -13
- package/codex/bundle/shell/deeplake-shell.js +716 -119
- package/codex/bundle/skilify-worker.js +907 -0
- package/codex/bundle/stop.js +819 -79
- package/codex/bundle/wiki-worker.js +312 -11
- package/cursor/bundle/capture.js +1116 -64
- package/cursor/bundle/commands/auth-login.js +290 -81
- package/cursor/bundle/embeddings/embed-daemon.js +243 -0
- package/cursor/bundle/pre-tool-use.js +598 -77
- package/cursor/bundle/session-end.js +520 -2
- package/cursor/bundle/session-start.js +257 -65
- package/cursor/bundle/shell/deeplake-shell.js +716 -119
- package/cursor/bundle/skilify-worker.js +907 -0
- package/cursor/bundle/wiki-worker.js +571 -0
- package/hermes/bundle/capture.js +1119 -65
- package/hermes/bundle/commands/auth-login.js +290 -81
- package/hermes/bundle/embeddings/embed-daemon.js +243 -0
- package/hermes/bundle/pre-tool-use.js +597 -76
- package/hermes/bundle/session-end.js +522 -1
- package/hermes/bundle/session-start.js +260 -65
- package/hermes/bundle/shell/deeplake-shell.js +716 -119
- package/hermes/bundle/skilify-worker.js +907 -0
- package/hermes/bundle/wiki-worker.js +572 -0
- package/mcp/bundle/server.js +290 -75
- package/openclaw/dist/chunks/auth-creds-AEKS6D3P.js +14 -0
- package/openclaw/dist/chunks/chunk-SRCBBT4H.js +37 -0
- package/openclaw/dist/chunks/config-ZLH6JFJS.js +34 -0
- package/openclaw/dist/chunks/index-marker-store-PGT5CW6T.js +33 -0
- package/openclaw/dist/chunks/setup-config-C35UK4LP.js +114 -0
- package/openclaw/dist/index.js +929 -710
- package/openclaw/dist/skilify-worker.js +907 -0
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/openclaw/skills/SKILL.md +19 -0
- package/package.json +7 -1
- package/pi/extension-source/hivemind.ts +603 -22
package/bundle/cli.js
CHANGED
|
@@ -1,4 +1,56 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// dist/src/index-marker-store.js
|
|
13
|
+
var index_marker_store_exports = {};
|
|
14
|
+
__export(index_marker_store_exports, {
|
|
15
|
+
buildIndexMarkerPath: () => buildIndexMarkerPath,
|
|
16
|
+
getIndexMarkerDir: () => getIndexMarkerDir,
|
|
17
|
+
hasFreshIndexMarker: () => hasFreshIndexMarker,
|
|
18
|
+
writeIndexMarker: () => writeIndexMarker
|
|
19
|
+
});
|
|
20
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
21
|
+
import { join as join14 } from "node:path";
|
|
22
|
+
import { tmpdir } from "node:os";
|
|
23
|
+
function getIndexMarkerDir() {
|
|
24
|
+
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join14(tmpdir(), "hivemind-deeplake-indexes");
|
|
25
|
+
}
|
|
26
|
+
function buildIndexMarkerPath(workspaceId, orgId, table, suffix) {
|
|
27
|
+
const markerKey = [workspaceId, orgId, table, suffix].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
28
|
+
return join14(getIndexMarkerDir(), `${markerKey}.json`);
|
|
29
|
+
}
|
|
30
|
+
function hasFreshIndexMarker(markerPath) {
|
|
31
|
+
if (!existsSync11(markerPath))
|
|
32
|
+
return false;
|
|
33
|
+
try {
|
|
34
|
+
const raw = JSON.parse(readFileSync8(markerPath, "utf-8"));
|
|
35
|
+
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
36
|
+
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
37
|
+
return false;
|
|
38
|
+
return true;
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function writeIndexMarker(markerPath) {
|
|
44
|
+
mkdirSync3(getIndexMarkerDir(), { recursive: true });
|
|
45
|
+
writeFileSync5(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
46
|
+
}
|
|
47
|
+
var INDEX_MARKER_TTL_MS;
|
|
48
|
+
var init_index_marker_store = __esm({
|
|
49
|
+
"dist/src/index-marker-store.js"() {
|
|
50
|
+
"use strict";
|
|
51
|
+
INDEX_MARKER_TTL_MS = Number(process.env.HIVEMIND_INDEX_MARKER_TTL_MS ?? 6 * 60 * 6e4);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
2
54
|
|
|
3
55
|
// dist/src/cli/install-claude.js
|
|
4
56
|
import { execFileSync } from "node:child_process";
|
|
@@ -10,6 +62,19 @@ import { homedir } from "node:os";
|
|
|
10
62
|
import { fileURLToPath } from "node:url";
|
|
11
63
|
var HOME = homedir();
|
|
12
64
|
function pkgRoot() {
|
|
65
|
+
let dir = fileURLToPath(new URL(".", import.meta.url));
|
|
66
|
+
for (let i = 0; i < 8; i++) {
|
|
67
|
+
try {
|
|
68
|
+
const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8"));
|
|
69
|
+
if (pkg.name === "@deeplake/hivemind" || pkg.name === "hivemind")
|
|
70
|
+
return dir;
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
const parent = dirname(dir);
|
|
74
|
+
if (parent === dir)
|
|
75
|
+
break;
|
|
76
|
+
dir = parent;
|
|
77
|
+
}
|
|
13
78
|
return fileURLToPath(new URL("..", import.meta.url));
|
|
14
79
|
}
|
|
15
80
|
function ensureDir(path, mode = 493) {
|
|
@@ -112,6 +177,7 @@ function pluginAlreadyInstalled() {
|
|
|
112
177
|
return false;
|
|
113
178
|
return r.stdout.includes(PLUGIN_KEY);
|
|
114
179
|
}
|
|
180
|
+
var PLUGIN_SCOPES = ["user", "project", "local", "managed"];
|
|
115
181
|
function installClaude() {
|
|
116
182
|
requireClaudeCli();
|
|
117
183
|
if (!marketplaceAlreadyAdded()) {
|
|
@@ -125,9 +191,15 @@ function installClaude() {
|
|
|
125
191
|
if (!inst.ok) {
|
|
126
192
|
throw new Error(`Failed to install hivemind plugin: ${inst.stderr.slice(0, 200)}`);
|
|
127
193
|
}
|
|
194
|
+
log(` Claude Code installed via marketplace ${MARKETPLACE_SOURCE}`);
|
|
195
|
+
} else {
|
|
196
|
+
runClaude(["plugin", "marketplace", "update", MARKETPLACE_NAME]);
|
|
197
|
+
for (const scope of PLUGIN_SCOPES) {
|
|
198
|
+
runClaude(["plugin", "update", PLUGIN_KEY, "--scope", scope]);
|
|
199
|
+
}
|
|
200
|
+
log(` Claude Code refreshed via marketplace ${MARKETPLACE_SOURCE}`);
|
|
128
201
|
}
|
|
129
202
|
runClaude(["plugin", "enable", PLUGIN_KEY]);
|
|
130
|
-
log(` Claude Code installed via marketplace ${MARKETPLACE_SOURCE}`);
|
|
131
203
|
}
|
|
132
204
|
function uninstallClaude() {
|
|
133
205
|
try {
|
|
@@ -187,7 +259,15 @@ function buildHooksJson() {
|
|
|
187
259
|
}
|
|
188
260
|
};
|
|
189
261
|
}
|
|
190
|
-
|
|
262
|
+
var HIVEMIND_BUNDLE_FILES = [
|
|
263
|
+
"session-start.js",
|
|
264
|
+
"session-start-setup.js",
|
|
265
|
+
"capture.js",
|
|
266
|
+
"pre-tool-use.js",
|
|
267
|
+
"stop.js",
|
|
268
|
+
"wiki-worker.js"
|
|
269
|
+
];
|
|
270
|
+
function isHivemindHookEntry(entry, pluginDir = PLUGIN_DIR) {
|
|
191
271
|
if (!entry || typeof entry !== "object")
|
|
192
272
|
return false;
|
|
193
273
|
const e = entry;
|
|
@@ -196,9 +276,41 @@ function isHivemindHookEntry(entry) {
|
|
|
196
276
|
if (!h || typeof h !== "object")
|
|
197
277
|
return false;
|
|
198
278
|
const cmd = h.command;
|
|
199
|
-
|
|
279
|
+
if (typeof cmd !== "string")
|
|
280
|
+
return false;
|
|
281
|
+
if (cmd.includes(`${pluginDir}/bundle/`))
|
|
282
|
+
return true;
|
|
283
|
+
return HIVEMIND_BUNDLE_FILES.some((f) => cmd.includes(`/bundle/${f}`));
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
function isForeignHivemindHookEntry(entry, pluginDir = PLUGIN_DIR) {
|
|
287
|
+
if (!isHivemindHookEntry(entry, pluginDir))
|
|
288
|
+
return false;
|
|
289
|
+
const e = entry;
|
|
290
|
+
const hooks = Array.isArray(e.hooks) ? e.hooks : [];
|
|
291
|
+
return hooks.every((h) => {
|
|
292
|
+
if (!h || typeof h !== "object")
|
|
293
|
+
return false;
|
|
294
|
+
const cmd = h.command;
|
|
295
|
+
if (typeof cmd !== "string")
|
|
296
|
+
return false;
|
|
297
|
+
return !cmd.includes(`${pluginDir}/bundle/`);
|
|
200
298
|
});
|
|
201
299
|
}
|
|
300
|
+
function mergeHooks(existing, ours, pluginDir = PLUGIN_DIR) {
|
|
301
|
+
const existingHooks = existing.hooks && typeof existing.hooks === "object" ? existing.hooks : {};
|
|
302
|
+
const ourHooks = ours.hooks;
|
|
303
|
+
const merged = {};
|
|
304
|
+
for (const [event, entries] of Object.entries(existingHooks)) {
|
|
305
|
+
const surviving = (entries ?? []).filter((e) => !isHivemindHookEntry(e, pluginDir));
|
|
306
|
+
if (surviving.length)
|
|
307
|
+
merged[event] = surviving;
|
|
308
|
+
}
|
|
309
|
+
for (const [event, entries] of Object.entries(ourHooks)) {
|
|
310
|
+
merged[event] = [...merged[event] ?? [], ...entries ?? []];
|
|
311
|
+
}
|
|
312
|
+
return { ...existing, hooks: merged };
|
|
313
|
+
}
|
|
202
314
|
function mergeHooksJson(ours) {
|
|
203
315
|
let existing = {};
|
|
204
316
|
try {
|
|
@@ -210,18 +322,30 @@ function mergeHooksJson(ours) {
|
|
|
210
322
|
} catch {
|
|
211
323
|
warn(` Codex ${HOOKS_PATH} unparseable \u2014 ignoring prior content`);
|
|
212
324
|
}
|
|
325
|
+
reportForeignHivemindHooks(existing);
|
|
326
|
+
return mergeHooks(existing, ours);
|
|
327
|
+
}
|
|
328
|
+
function reportForeignHivemindHooks(existing) {
|
|
213
329
|
const existingHooks = existing.hooks && typeof existing.hooks === "object" ? existing.hooks : {};
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
330
|
+
const foreign = /* @__PURE__ */ new Set();
|
|
331
|
+
for (const entries of Object.values(existingHooks)) {
|
|
332
|
+
for (const e of entries ?? []) {
|
|
333
|
+
if (!isForeignHivemindHookEntry(e))
|
|
334
|
+
continue;
|
|
335
|
+
const hooks = Array.isArray(e.hooks) ? e.hooks : [];
|
|
336
|
+
for (const h of hooks) {
|
|
337
|
+
const cmd = h?.command;
|
|
338
|
+
if (typeof cmd === "string")
|
|
339
|
+
foreign.add(cmd);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
223
342
|
}
|
|
224
|
-
|
|
343
|
+
if (foreign.size === 0)
|
|
344
|
+
return;
|
|
345
|
+
warn(` Codex stripping ${foreign.size} hivemind hook(s) from a non-canonical path:`);
|
|
346
|
+
for (const cmd of foreign)
|
|
347
|
+
warn(` ${cmd}`);
|
|
348
|
+
warn(` (these were probably leftover from a local dev clone \u2014 re-add them manually if intentional)`);
|
|
225
349
|
}
|
|
226
350
|
function tryEnableCodexHooks() {
|
|
227
351
|
try {
|
|
@@ -253,8 +377,28 @@ function installCodex() {
|
|
|
253
377
|
}
|
|
254
378
|
function uninstallCodex() {
|
|
255
379
|
if (existsSync2(HOOKS_PATH)) {
|
|
256
|
-
|
|
257
|
-
|
|
380
|
+
let existing = {};
|
|
381
|
+
try {
|
|
382
|
+
const raw = JSON.parse(readFileSync3(HOOKS_PATH, "utf-8"));
|
|
383
|
+
if (raw && typeof raw === "object")
|
|
384
|
+
existing = raw;
|
|
385
|
+
} catch {
|
|
386
|
+
unlinkSync2(HOOKS_PATH);
|
|
387
|
+
log(` Codex removed unparseable ${HOOKS_PATH}`);
|
|
388
|
+
existing = {};
|
|
389
|
+
}
|
|
390
|
+
if (Object.keys(existing).length > 0) {
|
|
391
|
+
const stripped = mergeHooks(existing, { hooks: {} });
|
|
392
|
+
const survivingHooks = stripped.hooks ?? {};
|
|
393
|
+
const otherTopLevelKeys = Object.keys(stripped).filter((k) => k !== "hooks");
|
|
394
|
+
if (Object.keys(survivingHooks).length === 0 && otherTopLevelKeys.length === 0) {
|
|
395
|
+
unlinkSync2(HOOKS_PATH);
|
|
396
|
+
log(` Codex removed ${HOOKS_PATH}`);
|
|
397
|
+
} else {
|
|
398
|
+
writeJson(HOOKS_PATH, stripped);
|
|
399
|
+
log(` Codex stripped hivemind hooks from ${HOOKS_PATH}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
258
402
|
}
|
|
259
403
|
if (existsSync2(SKILL_LINK)) {
|
|
260
404
|
unlinkSync2(SKILL_LINK);
|
|
@@ -336,7 +480,7 @@ function isHivemindEntry(entry) {
|
|
|
336
480
|
const cmd = entry.command;
|
|
337
481
|
return typeof cmd === "string" && cmd.includes("/.cursor/hivemind/bundle/");
|
|
338
482
|
}
|
|
339
|
-
function
|
|
483
|
+
function mergeHooks2(existing) {
|
|
340
484
|
const root = existing ?? { version: 1, hooks: {} };
|
|
341
485
|
if (!root.version)
|
|
342
486
|
root.version = 1;
|
|
@@ -375,7 +519,7 @@ function installCursor() {
|
|
|
375
519
|
ensureDir(PLUGIN_DIR3);
|
|
376
520
|
copyDir(srcBundle, join5(PLUGIN_DIR3, "bundle"));
|
|
377
521
|
const existing = readJson(HOOKS_PATH2);
|
|
378
|
-
const merged =
|
|
522
|
+
const merged = mergeHooks2(existing);
|
|
379
523
|
writeJson(HOOKS_PATH2, merged);
|
|
380
524
|
writeVersionStamp(PLUGIN_DIR3, getVersion());
|
|
381
525
|
log(` Cursor installed -> ${PLUGIN_DIR3}`);
|
|
@@ -3090,7 +3234,7 @@ function buildHooksBlock() {
|
|
|
3090
3234
|
on_session_end: [buildHookEntry("session-end.js", 30)]
|
|
3091
3235
|
};
|
|
3092
3236
|
}
|
|
3093
|
-
function
|
|
3237
|
+
function mergeHooks3(existing) {
|
|
3094
3238
|
const merged = { ...existing ?? {} };
|
|
3095
3239
|
const ours = buildHooksBlock();
|
|
3096
3240
|
for (const [event, entries] of Object.entries(ours)) {
|
|
@@ -3151,7 +3295,7 @@ function installHermes() {
|
|
|
3151
3295
|
command: "node",
|
|
3152
3296
|
args: [MCP_SERVER_PATH]
|
|
3153
3297
|
};
|
|
3154
|
-
cfg.hooks =
|
|
3298
|
+
cfg.hooks = mergeHooks3(cfg.hooks);
|
|
3155
3299
|
cfg.hooks_auto_accept = true;
|
|
3156
3300
|
writeConfig(cfg);
|
|
3157
3301
|
log(` Hermes config updated -> ${CONFIG_PATH} (mcp_servers + hooks + hooks_auto_accept)`);
|
|
@@ -3182,6 +3326,10 @@ function uninstallHermes() {
|
|
|
3182
3326
|
delete cfg.hooks;
|
|
3183
3327
|
touched = true;
|
|
3184
3328
|
}
|
|
3329
|
+
if ("hooks_auto_accept" in cfg) {
|
|
3330
|
+
delete cfg.hooks_auto_accept;
|
|
3331
|
+
touched = true;
|
|
3332
|
+
}
|
|
3185
3333
|
if (touched) {
|
|
3186
3334
|
if (Object.keys(cfg).length === 0) {
|
|
3187
3335
|
unlinkSync4(CONFIG_PATH);
|
|
@@ -3202,6 +3350,9 @@ var LEGACY_SKILL_DIR = join8(PI_AGENT_DIR, "skills", "hivemind-memory");
|
|
|
3202
3350
|
var EXTENSIONS_DIR = join8(PI_AGENT_DIR, "extensions");
|
|
3203
3351
|
var EXTENSION_PATH = join8(EXTENSIONS_DIR, "hivemind.ts");
|
|
3204
3352
|
var VERSION_DIR = join8(PI_AGENT_DIR, ".hivemind");
|
|
3353
|
+
var WIKI_WORKER_DIR = join8(PI_AGENT_DIR, "hivemind");
|
|
3354
|
+
var WIKI_WORKER_PATH = join8(WIKI_WORKER_DIR, "wiki-worker.js");
|
|
3355
|
+
var SKILIFY_WORKER_PATH = join8(WIKI_WORKER_DIR, "skilify-worker.js");
|
|
3205
3356
|
var HIVEMIND_BLOCK_START = "<!-- BEGIN hivemind-memory -->";
|
|
3206
3357
|
var HIVEMIND_BLOCK_END = "<!-- END hivemind-memory -->";
|
|
3207
3358
|
var HIVEMIND_BLOCK_BODY = `${HIVEMIND_BLOCK_START}
|
|
@@ -3281,10 +3432,26 @@ function installPi() {
|
|
|
3281
3432
|
}
|
|
3282
3433
|
ensureDir(EXTENSIONS_DIR);
|
|
3283
3434
|
copyFileSync2(srcExtension, EXTENSION_PATH);
|
|
3435
|
+
const srcWorker = join8(pkgRoot(), "pi", "bundle", "wiki-worker.js");
|
|
3436
|
+
if (existsSync7(srcWorker)) {
|
|
3437
|
+
ensureDir(WIKI_WORKER_DIR);
|
|
3438
|
+
copyFileSync2(srcWorker, WIKI_WORKER_PATH);
|
|
3439
|
+
}
|
|
3440
|
+
const srcSkilifyWorker = join8(pkgRoot(), "pi", "bundle", "skilify-worker.js");
|
|
3441
|
+
if (existsSync7(srcSkilifyWorker)) {
|
|
3442
|
+
ensureDir(WIKI_WORKER_DIR);
|
|
3443
|
+
copyFileSync2(srcSkilifyWorker, SKILIFY_WORKER_PATH);
|
|
3444
|
+
}
|
|
3284
3445
|
ensureDir(VERSION_DIR);
|
|
3285
3446
|
writeVersionStamp(VERSION_DIR, getVersion());
|
|
3286
3447
|
log(` pi AGENTS.md updated -> ${AGENTS_MD}`);
|
|
3287
3448
|
log(` pi extension installed -> ${EXTENSION_PATH}`);
|
|
3449
|
+
if (existsSync7(WIKI_WORKER_PATH)) {
|
|
3450
|
+
log(` pi wiki-worker installed -> ${WIKI_WORKER_PATH}`);
|
|
3451
|
+
}
|
|
3452
|
+
if (existsSync7(SKILIFY_WORKER_PATH)) {
|
|
3453
|
+
log(` pi skilify-worker installed -> ${SKILIFY_WORKER_PATH}`);
|
|
3454
|
+
}
|
|
3288
3455
|
}
|
|
3289
3456
|
function uninstallPi() {
|
|
3290
3457
|
if (existsSync7(LEGACY_SKILL_DIR)) {
|
|
@@ -3295,6 +3462,10 @@ function uninstallPi() {
|
|
|
3295
3462
|
rmSync3(EXTENSION_PATH, { force: true });
|
|
3296
3463
|
log(` pi removed extension ${EXTENSION_PATH}`);
|
|
3297
3464
|
}
|
|
3465
|
+
if (existsSync7(WIKI_WORKER_DIR)) {
|
|
3466
|
+
rmSync3(WIKI_WORKER_DIR, { recursive: true, force: true });
|
|
3467
|
+
log(` pi removed wiki-worker dir ${WIKI_WORKER_DIR}`);
|
|
3468
|
+
}
|
|
3298
3469
|
if (existsSync7(AGENTS_MD)) {
|
|
3299
3470
|
const prior = readFileSync5(AGENTS_MD, "utf-8");
|
|
3300
3471
|
const stripped = stripHivemindBlock(prior);
|
|
@@ -3311,43 +3482,228 @@ function uninstallPi() {
|
|
|
3311
3482
|
}
|
|
3312
3483
|
}
|
|
3313
3484
|
|
|
3485
|
+
// dist/src/cli/embeddings.js
|
|
3486
|
+
import { copyFileSync as copyFileSync3, chmodSync, existsSync as existsSync8, lstatSync as lstatSync2, readdirSync, readlinkSync, rmSync as rmSync4, statSync, unlinkSync as unlinkSync5 } from "node:fs";
|
|
3487
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3488
|
+
import { join as join9 } from "node:path";
|
|
3489
|
+
var SHARED_DIR = join9(HOME, ".hivemind", "embed-deps");
|
|
3490
|
+
var SHARED_NODE_MODULES = join9(SHARED_DIR, "node_modules");
|
|
3491
|
+
var SHARED_DAEMON_PATH = join9(SHARED_DIR, "embed-daemon.js");
|
|
3492
|
+
var TRANSFORMERS_PKG = "@huggingface/transformers";
|
|
3493
|
+
var TRANSFORMERS_RANGE = "^3.0.0";
|
|
3494
|
+
function findHivemindInstalls(home = HOME) {
|
|
3495
|
+
const out = [];
|
|
3496
|
+
const fixed = [
|
|
3497
|
+
{ id: "codex", pluginDir: join9(home, ".codex", "hivemind") },
|
|
3498
|
+
{ id: "cursor", pluginDir: join9(home, ".cursor", "hivemind") },
|
|
3499
|
+
{ id: "hermes", pluginDir: join9(home, ".hermes", "hivemind") }
|
|
3500
|
+
];
|
|
3501
|
+
for (const inst of fixed) {
|
|
3502
|
+
if (existsSync8(join9(inst.pluginDir, "bundle")))
|
|
3503
|
+
out.push(inst);
|
|
3504
|
+
}
|
|
3505
|
+
const ccCache = join9(home, ".claude", "plugins", "cache", "hivemind", "hivemind");
|
|
3506
|
+
if (existsSync8(ccCache)) {
|
|
3507
|
+
let entries = [];
|
|
3508
|
+
try {
|
|
3509
|
+
entries = readdirSync(ccCache);
|
|
3510
|
+
} catch {
|
|
3511
|
+
}
|
|
3512
|
+
for (const ver of entries) {
|
|
3513
|
+
const dir = join9(ccCache, ver);
|
|
3514
|
+
try {
|
|
3515
|
+
if (!statSync(dir).isDirectory())
|
|
3516
|
+
continue;
|
|
3517
|
+
} catch {
|
|
3518
|
+
continue;
|
|
3519
|
+
}
|
|
3520
|
+
const candidates = [join9(dir, "bundle"), join9(dir, "claude-code", "bundle")];
|
|
3521
|
+
if (candidates.some((p) => existsSync8(p))) {
|
|
3522
|
+
out.push({ id: `claude (${ver})`, pluginDir: dir });
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
return out;
|
|
3527
|
+
}
|
|
3528
|
+
function isSharedDepsInstalled(sharedNodeModules = SHARED_NODE_MODULES) {
|
|
3529
|
+
return existsSync8(join9(sharedNodeModules, TRANSFORMERS_PKG));
|
|
3530
|
+
}
|
|
3531
|
+
function isSymlinkToSharedDeps(linkPath, sharedNodeModules) {
|
|
3532
|
+
if (!existsSync8(linkPath))
|
|
3533
|
+
return false;
|
|
3534
|
+
try {
|
|
3535
|
+
if (!lstatSync2(linkPath).isSymbolicLink())
|
|
3536
|
+
return false;
|
|
3537
|
+
return readlinkSync(linkPath) === sharedNodeModules;
|
|
3538
|
+
} catch {
|
|
3539
|
+
return false;
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
function linkStateFor(install, sharedNodeModules = SHARED_NODE_MODULES) {
|
|
3543
|
+
const link = join9(install.pluginDir, "node_modules");
|
|
3544
|
+
if (!existsSync8(link) && !isSymbolicLink(link))
|
|
3545
|
+
return { kind: "no-node-modules" };
|
|
3546
|
+
try {
|
|
3547
|
+
if (lstatSync2(link).isSymbolicLink()) {
|
|
3548
|
+
const target = readlinkSync(link);
|
|
3549
|
+
return target === sharedNodeModules ? { kind: "linked-to-shared" } : { kind: "linked-elsewhere", target };
|
|
3550
|
+
}
|
|
3551
|
+
} catch {
|
|
3552
|
+
return { kind: "no-node-modules" };
|
|
3553
|
+
}
|
|
3554
|
+
return { kind: "owns-own-node-modules" };
|
|
3555
|
+
}
|
|
3556
|
+
function isSymbolicLink(path) {
|
|
3557
|
+
try {
|
|
3558
|
+
return lstatSync2(path).isSymbolicLink();
|
|
3559
|
+
} catch {
|
|
3560
|
+
return false;
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
function ensureSharedDeps() {
|
|
3564
|
+
if (!isSharedDepsInstalled()) {
|
|
3565
|
+
log(` Embeddings installing ${TRANSFORMERS_PKG}@${TRANSFORMERS_RANGE} into ${SHARED_DIR}`);
|
|
3566
|
+
log(` (~600 MB; first install only \u2014 every agent will share this)`);
|
|
3567
|
+
ensureDir(SHARED_DIR);
|
|
3568
|
+
writeJson(join9(SHARED_DIR, "package.json"), {
|
|
3569
|
+
name: "hivemind-embed-deps",
|
|
3570
|
+
version: "1.0.0",
|
|
3571
|
+
private: true,
|
|
3572
|
+
dependencies: { [TRANSFORMERS_PKG]: TRANSFORMERS_RANGE }
|
|
3573
|
+
});
|
|
3574
|
+
execFileSync3("npm", ["install", "--omit=dev", "--no-package-lock", "--no-audit", "--no-fund"], {
|
|
3575
|
+
cwd: SHARED_DIR,
|
|
3576
|
+
stdio: "inherit"
|
|
3577
|
+
});
|
|
3578
|
+
} else {
|
|
3579
|
+
log(` Embeddings shared deps already present at ${SHARED_DIR}`);
|
|
3580
|
+
}
|
|
3581
|
+
ensureDir(SHARED_DIR);
|
|
3582
|
+
const src = join9(pkgRoot(), "embeddings", "embed-daemon.js");
|
|
3583
|
+
if (existsSync8(src)) {
|
|
3584
|
+
copyFileSync3(src, SHARED_DAEMON_PATH);
|
|
3585
|
+
chmodSync(SHARED_DAEMON_PATH, 493);
|
|
3586
|
+
} else {
|
|
3587
|
+
warn(` Embeddings standalone daemon bundle missing at ${src} (run 'npm run build' first)`);
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
3590
|
+
function linkAgent(install) {
|
|
3591
|
+
const link = join9(install.pluginDir, "node_modules");
|
|
3592
|
+
symlinkForce(SHARED_NODE_MODULES, link);
|
|
3593
|
+
log(` Embeddings linked ${install.id.padEnd(20)} -> shared deps`);
|
|
3594
|
+
}
|
|
3595
|
+
function enableEmbeddings() {
|
|
3596
|
+
ensureSharedDeps();
|
|
3597
|
+
const installs = findHivemindInstalls();
|
|
3598
|
+
if (installs.length === 0) {
|
|
3599
|
+
warn(" Embeddings no hivemind installs detected \u2014 run `hivemind install` first");
|
|
3600
|
+
warn(" (the shared deps are in place; subsequent agent installs will pick them up if you re-run `hivemind embeddings install`)");
|
|
3601
|
+
return;
|
|
3602
|
+
}
|
|
3603
|
+
for (const inst of installs)
|
|
3604
|
+
linkAgent(inst);
|
|
3605
|
+
log(` Embeddings enabled. Restart your agents to pick up.`);
|
|
3606
|
+
}
|
|
3607
|
+
function disableEmbeddings(opts) {
|
|
3608
|
+
const installs = findHivemindInstalls();
|
|
3609
|
+
for (const inst of installs) {
|
|
3610
|
+
const link = join9(inst.pluginDir, "node_modules");
|
|
3611
|
+
if (isSymlinkToSharedDeps(link, SHARED_NODE_MODULES)) {
|
|
3612
|
+
unlinkSync5(link);
|
|
3613
|
+
log(` Embeddings unlinked ${inst.id}`);
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
if (opts?.prune && existsSync8(SHARED_DIR)) {
|
|
3617
|
+
rmSync4(SHARED_DIR, { recursive: true, force: true });
|
|
3618
|
+
log(` Embeddings pruned ${SHARED_DIR}`);
|
|
3619
|
+
}
|
|
3620
|
+
}
|
|
3621
|
+
function statusEmbeddings() {
|
|
3622
|
+
log(`Shared deps: ${SHARED_DIR}`);
|
|
3623
|
+
log(`Installed: ${isSharedDepsInstalled() ? "yes" : "no"}`);
|
|
3624
|
+
log(`Daemon: ${existsSync8(SHARED_DAEMON_PATH) ? SHARED_DAEMON_PATH : "(not present)"}`);
|
|
3625
|
+
log("");
|
|
3626
|
+
log(`Agent installs:`);
|
|
3627
|
+
const installs = findHivemindInstalls();
|
|
3628
|
+
if (installs.length === 0) {
|
|
3629
|
+
log(` (none detected)`);
|
|
3630
|
+
return;
|
|
3631
|
+
}
|
|
3632
|
+
for (const inst of installs) {
|
|
3633
|
+
const state = linkStateFor(inst);
|
|
3634
|
+
let label;
|
|
3635
|
+
switch (state.kind) {
|
|
3636
|
+
case "linked-to-shared":
|
|
3637
|
+
label = "\u2713 linked \u2192 shared";
|
|
3638
|
+
break;
|
|
3639
|
+
case "no-node-modules":
|
|
3640
|
+
label = "\u2717 not linked (embeddings disabled)";
|
|
3641
|
+
break;
|
|
3642
|
+
case "owns-own-node-modules":
|
|
3643
|
+
label = "\u25B3 has its own node_modules (not shared)";
|
|
3644
|
+
break;
|
|
3645
|
+
case "linked-elsewhere":
|
|
3646
|
+
label = `\u25B3 linked \u2192 ${state.target}`;
|
|
3647
|
+
break;
|
|
3648
|
+
}
|
|
3649
|
+
log(` ${inst.id.padEnd(20)} ${label}`);
|
|
3650
|
+
log(` ${" ".repeat(20)} ${inst.pluginDir}`);
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3314
3654
|
// dist/src/cli/auth.js
|
|
3315
3655
|
import { existsSync as existsSync9 } from "node:fs";
|
|
3316
|
-
import { join as
|
|
3656
|
+
import { join as join11 } from "node:path";
|
|
3317
3657
|
|
|
3318
3658
|
// dist/src/commands/auth.js
|
|
3319
|
-
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync2, unlinkSync as unlinkSync5 } from "node:fs";
|
|
3320
|
-
import { join as join9 } from "node:path";
|
|
3321
|
-
import { homedir as homedir2 } from "node:os";
|
|
3322
3659
|
import { execSync } from "node:child_process";
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
var
|
|
3660
|
+
|
|
3661
|
+
// dist/src/utils/client-header.js
|
|
3662
|
+
var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client";
|
|
3663
|
+
function deeplakeClientValue() {
|
|
3664
|
+
return "hivemind";
|
|
3665
|
+
}
|
|
3666
|
+
function deeplakeClientHeader() {
|
|
3667
|
+
return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3670
|
+
// dist/src/commands/auth-creds.js
|
|
3671
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync2, unlinkSync as unlinkSync6 } from "node:fs";
|
|
3672
|
+
import { join as join10 } from "node:path";
|
|
3673
|
+
import { homedir as homedir2 } from "node:os";
|
|
3674
|
+
function configDir() {
|
|
3675
|
+
return join10(homedir2(), ".deeplake");
|
|
3676
|
+
}
|
|
3677
|
+
function credsPath() {
|
|
3678
|
+
return join10(configDir(), "credentials.json");
|
|
3679
|
+
}
|
|
3326
3680
|
function loadCredentials() {
|
|
3327
|
-
if (!existsSync8(CREDS_PATH))
|
|
3328
|
-
return null;
|
|
3329
3681
|
try {
|
|
3330
|
-
return JSON.parse(readFileSync6(
|
|
3682
|
+
return JSON.parse(readFileSync6(credsPath(), "utf-8"));
|
|
3331
3683
|
} catch {
|
|
3332
3684
|
return null;
|
|
3333
3685
|
}
|
|
3334
3686
|
}
|
|
3335
3687
|
function saveCredentials(creds) {
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
writeFileSync4(CREDS_PATH, JSON.stringify({ ...creds, savedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), { mode: 384 });
|
|
3688
|
+
mkdirSync2(configDir(), { recursive: true, mode: 448 });
|
|
3689
|
+
writeFileSync4(credsPath(), JSON.stringify({ ...creds, savedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), { mode: 384 });
|
|
3339
3690
|
}
|
|
3340
3691
|
function deleteCredentials() {
|
|
3341
|
-
|
|
3342
|
-
|
|
3692
|
+
try {
|
|
3693
|
+
unlinkSync6(credsPath());
|
|
3343
3694
|
return true;
|
|
3695
|
+
} catch {
|
|
3696
|
+
return false;
|
|
3344
3697
|
}
|
|
3345
|
-
return false;
|
|
3346
3698
|
}
|
|
3699
|
+
|
|
3700
|
+
// dist/src/commands/auth.js
|
|
3701
|
+
var DEFAULT_API_URL = "https://api.deeplake.ai";
|
|
3347
3702
|
async function apiGet(path, token, apiUrl, orgId) {
|
|
3348
3703
|
const headers = {
|
|
3349
3704
|
Authorization: `Bearer ${token}`,
|
|
3350
|
-
"Content-Type": "application/json"
|
|
3705
|
+
"Content-Type": "application/json",
|
|
3706
|
+
...deeplakeClientHeader()
|
|
3351
3707
|
};
|
|
3352
3708
|
if (orgId)
|
|
3353
3709
|
headers["X-Activeloop-Org-Id"] = orgId;
|
|
@@ -3359,7 +3715,8 @@ async function apiGet(path, token, apiUrl, orgId) {
|
|
|
3359
3715
|
async function apiPost(path, body, token, apiUrl, orgId) {
|
|
3360
3716
|
const headers = {
|
|
3361
3717
|
Authorization: `Bearer ${token}`,
|
|
3362
|
-
"Content-Type": "application/json"
|
|
3718
|
+
"Content-Type": "application/json",
|
|
3719
|
+
...deeplakeClientHeader()
|
|
3363
3720
|
};
|
|
3364
3721
|
if (orgId)
|
|
3365
3722
|
headers["X-Activeloop-Org-Id"] = orgId;
|
|
@@ -3371,7 +3728,8 @@ async function apiPost(path, body, token, apiUrl, orgId) {
|
|
|
3371
3728
|
async function apiDelete(path, token, apiUrl, orgId) {
|
|
3372
3729
|
const headers = {
|
|
3373
3730
|
Authorization: `Bearer ${token}`,
|
|
3374
|
-
"Content-Type": "application/json"
|
|
3731
|
+
"Content-Type": "application/json",
|
|
3732
|
+
...deeplakeClientHeader()
|
|
3375
3733
|
};
|
|
3376
3734
|
if (orgId)
|
|
3377
3735
|
headers["X-Activeloop-Org-Id"] = orgId;
|
|
@@ -3382,7 +3740,7 @@ async function apiDelete(path, token, apiUrl, orgId) {
|
|
|
3382
3740
|
async function requestDeviceCode(apiUrl = DEFAULT_API_URL) {
|
|
3383
3741
|
const resp = await fetch(`${apiUrl}/auth/device/code`, {
|
|
3384
3742
|
method: "POST",
|
|
3385
|
-
headers: { "Content-Type": "application/json" }
|
|
3743
|
+
headers: { "Content-Type": "application/json", ...deeplakeClientHeader() }
|
|
3386
3744
|
});
|
|
3387
3745
|
if (!resp.ok)
|
|
3388
3746
|
throw new Error(`Device flow unavailable: HTTP ${resp.status}`);
|
|
@@ -3391,7 +3749,7 @@ async function requestDeviceCode(apiUrl = DEFAULT_API_URL) {
|
|
|
3391
3749
|
async function pollForToken(deviceCode, apiUrl = DEFAULT_API_URL) {
|
|
3392
3750
|
const resp = await fetch(`${apiUrl}/auth/device/token`, {
|
|
3393
3751
|
method: "POST",
|
|
3394
|
-
headers: { "Content-Type": "application/json" },
|
|
3752
|
+
headers: { "Content-Type": "application/json", ...deeplakeClientHeader() },
|
|
3395
3753
|
body: JSON.stringify({ device_code: deviceCode })
|
|
3396
3754
|
});
|
|
3397
3755
|
if (resp.ok)
|
|
@@ -3517,9 +3875,9 @@ Using: ${orgName}
|
|
|
3517
3875
|
}
|
|
3518
3876
|
|
|
3519
3877
|
// dist/src/cli/auth.js
|
|
3520
|
-
var
|
|
3878
|
+
var CREDS_PATH = join11(HOME, ".deeplake", "credentials.json");
|
|
3521
3879
|
function isLoggedIn() {
|
|
3522
|
-
return existsSync9(
|
|
3880
|
+
return existsSync9(CREDS_PATH) && loadCredentials() !== null;
|
|
3523
3881
|
}
|
|
3524
3882
|
async function ensureLoggedIn() {
|
|
3525
3883
|
if (isLoggedIn())
|
|
@@ -3553,11 +3911,11 @@ async function maybeShowOrgChoice() {
|
|
|
3553
3911
|
|
|
3554
3912
|
// dist/src/config.js
|
|
3555
3913
|
import { readFileSync as readFileSync7, existsSync as existsSync10 } from "node:fs";
|
|
3556
|
-
import { join as
|
|
3914
|
+
import { join as join12 } from "node:path";
|
|
3557
3915
|
import { homedir as homedir3, userInfo } from "node:os";
|
|
3558
3916
|
function loadConfig() {
|
|
3559
3917
|
const home = homedir3();
|
|
3560
|
-
const credPath =
|
|
3918
|
+
const credPath = join12(home, ".deeplake", "credentials.json");
|
|
3561
3919
|
let creds = null;
|
|
3562
3920
|
if (existsSync10(credPath)) {
|
|
3563
3921
|
try {
|
|
@@ -3579,22 +3937,20 @@ function loadConfig() {
|
|
|
3579
3937
|
apiUrl: process.env.HIVEMIND_API_URL ?? creds?.apiUrl ?? "https://api.deeplake.ai",
|
|
3580
3938
|
tableName: process.env.HIVEMIND_TABLE ?? "memory",
|
|
3581
3939
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
3582
|
-
|
|
3940
|
+
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
3941
|
+
memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join12(home, ".deeplake", "memory")
|
|
3583
3942
|
};
|
|
3584
3943
|
}
|
|
3585
3944
|
|
|
3586
3945
|
// dist/src/deeplake-api.js
|
|
3587
3946
|
import { randomUUID } from "node:crypto";
|
|
3588
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3589
|
-
import { join as join13 } from "node:path";
|
|
3590
|
-
import { tmpdir } from "node:os";
|
|
3591
3947
|
|
|
3592
3948
|
// dist/src/utils/debug.js
|
|
3593
3949
|
import { appendFileSync } from "node:fs";
|
|
3594
|
-
import { join as
|
|
3950
|
+
import { join as join13 } from "node:path";
|
|
3595
3951
|
import { homedir as homedir4 } from "node:os";
|
|
3596
3952
|
var DEBUG = process.env.HIVEMIND_DEBUG === "1";
|
|
3597
|
-
var LOG =
|
|
3953
|
+
var LOG = join13(homedir4(), ".deeplake", "hook-debug.log");
|
|
3598
3954
|
function log2(tag, msg) {
|
|
3599
3955
|
if (!DEBUG)
|
|
3600
3956
|
return;
|
|
@@ -3606,8 +3962,24 @@ function log2(tag, msg) {
|
|
|
3606
3962
|
function sqlStr(value) {
|
|
3607
3963
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
3608
3964
|
}
|
|
3965
|
+
function sqlIdent(name) {
|
|
3966
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
|
|
3967
|
+
throw new Error(`Invalid SQL identifier: ${JSON.stringify(name)}`);
|
|
3968
|
+
}
|
|
3969
|
+
return name;
|
|
3970
|
+
}
|
|
3971
|
+
|
|
3972
|
+
// dist/src/embeddings/columns.js
|
|
3973
|
+
var SUMMARY_EMBEDDING_COL = "summary_embedding";
|
|
3974
|
+
var MESSAGE_EMBEDDING_COL = "message_embedding";
|
|
3609
3975
|
|
|
3610
3976
|
// dist/src/deeplake-api.js
|
|
3977
|
+
var indexMarkerStorePromise = null;
|
|
3978
|
+
function getIndexMarkerStore() {
|
|
3979
|
+
if (!indexMarkerStorePromise)
|
|
3980
|
+
indexMarkerStorePromise = Promise.resolve().then(() => (init_index_marker_store(), index_marker_store_exports));
|
|
3981
|
+
return indexMarkerStorePromise;
|
|
3982
|
+
}
|
|
3611
3983
|
var log3 = (msg) => log2("sdk", msg);
|
|
3612
3984
|
function summarizeSql(sql, maxLen = 220) {
|
|
3613
3985
|
const compact = sql.replace(/\s+/g, " ").trim();
|
|
@@ -3627,7 +3999,6 @@ var MAX_RETRIES = 3;
|
|
|
3627
3999
|
var BASE_DELAY_MS = 500;
|
|
3628
4000
|
var MAX_CONCURRENCY = 5;
|
|
3629
4001
|
var QUERY_TIMEOUT_MS = Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
|
|
3630
|
-
var INDEX_MARKER_TTL_MS = Number(process.env.HIVEMIND_INDEX_MARKER_TTL_MS ?? 6 * 60 * 6e4);
|
|
3631
4002
|
function sleep(ms) {
|
|
3632
4003
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3633
4004
|
}
|
|
@@ -3647,9 +4018,6 @@ function isTransientHtml403(text) {
|
|
|
3647
4018
|
const body = text.toLowerCase();
|
|
3648
4019
|
return body.includes("<html") || body.includes("403 forbidden") || body.includes("cloudflare") || body.includes("nginx");
|
|
3649
4020
|
}
|
|
3650
|
-
function getIndexMarkerDir() {
|
|
3651
|
-
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join13(tmpdir(), "hivemind-deeplake-indexes");
|
|
3652
|
-
}
|
|
3653
4021
|
var Semaphore = class {
|
|
3654
4022
|
max;
|
|
3655
4023
|
waiting = [];
|
|
@@ -3718,7 +4086,8 @@ var DeeplakeApi = class {
|
|
|
3718
4086
|
headers: {
|
|
3719
4087
|
Authorization: `Bearer ${this.token}`,
|
|
3720
4088
|
"Content-Type": "application/json",
|
|
3721
|
-
"X-Activeloop-Org-Id": this.orgId
|
|
4089
|
+
"X-Activeloop-Org-Id": this.orgId,
|
|
4090
|
+
...deeplakeClientHeader()
|
|
3722
4091
|
},
|
|
3723
4092
|
signal,
|
|
3724
4093
|
body: JSON.stringify({ query: sql })
|
|
@@ -3745,7 +4114,8 @@ var DeeplakeApi = class {
|
|
|
3745
4114
|
}
|
|
3746
4115
|
const text = await resp.text().catch(() => "");
|
|
3747
4116
|
const retryable403 = isSessionInsertQuery(sql) && (resp.status === 401 || resp.status === 403 && (text.length === 0 || isTransientHtml403(text)));
|
|
3748
|
-
|
|
4117
|
+
const alreadyExists = resp.status === 500 && isDuplicateIndexError(text);
|
|
4118
|
+
if (!alreadyExists && attempt < MAX_RETRIES && (RETRYABLE_CODES.has(resp.status) || retryable403)) {
|
|
3749
4119
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
3750
4120
|
log3(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
|
|
3751
4121
|
await sleep(delay);
|
|
@@ -3779,7 +4149,7 @@ var DeeplakeApi = class {
|
|
|
3779
4149
|
const lud = row.lastUpdateDate ?? ts;
|
|
3780
4150
|
const exists = await this.query(`SELECT path FROM "${this.tableName}" WHERE path = '${sqlStr(row.path)}' LIMIT 1`);
|
|
3781
4151
|
if (exists.length > 0) {
|
|
3782
|
-
let setClauses = `summary = E'${sqlStr(row.contentText)}', mime_type = '${sqlStr(row.mimeType)}', size_bytes = ${row.sizeBytes}, last_update_date = '${lud}'`;
|
|
4152
|
+
let setClauses = `summary = E'${sqlStr(row.contentText)}', ${SUMMARY_EMBEDDING_COL} = NULL, mime_type = '${sqlStr(row.mimeType)}', size_bytes = ${row.sizeBytes}, last_update_date = '${lud}'`;
|
|
3783
4153
|
if (row.project !== void 0)
|
|
3784
4154
|
setClauses += `, project = '${sqlStr(row.project)}'`;
|
|
3785
4155
|
if (row.description !== void 0)
|
|
@@ -3787,8 +4157,8 @@ var DeeplakeApi = class {
|
|
|
3787
4157
|
await this.query(`UPDATE "${this.tableName}" SET ${setClauses} WHERE path = '${sqlStr(row.path)}'`);
|
|
3788
4158
|
} else {
|
|
3789
4159
|
const id = randomUUID();
|
|
3790
|
-
let cols =
|
|
3791
|
-
let vals = `'${id}', '${sqlStr(row.path)}', '${sqlStr(row.filename)}', E'${sqlStr(row.contentText)}', '${sqlStr(row.mimeType)}', ${row.sizeBytes}, '${cd}', '${lud}'`;
|
|
4160
|
+
let cols = `id, path, filename, summary, ${SUMMARY_EMBEDDING_COL}, mime_type, size_bytes, creation_date, last_update_date`;
|
|
4161
|
+
let vals = `'${id}', '${sqlStr(row.path)}', '${sqlStr(row.filename)}', E'${sqlStr(row.contentText)}', NULL, '${sqlStr(row.mimeType)}', ${row.sizeBytes}, '${cd}', '${lud}'`;
|
|
3792
4162
|
if (row.project !== void 0) {
|
|
3793
4163
|
cols += ", project";
|
|
3794
4164
|
vals += `, '${sqlStr(row.project)}'`;
|
|
@@ -3813,48 +4183,83 @@ var DeeplakeApi = class {
|
|
|
3813
4183
|
buildLookupIndexName(table, suffix) {
|
|
3814
4184
|
return `idx_${table}_${suffix}`.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
3815
4185
|
}
|
|
3816
|
-
getLookupIndexMarkerPath(table, suffix) {
|
|
3817
|
-
const markerKey = [
|
|
3818
|
-
this.workspaceId,
|
|
3819
|
-
this.orgId,
|
|
3820
|
-
table,
|
|
3821
|
-
suffix
|
|
3822
|
-
].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
3823
|
-
return join13(getIndexMarkerDir(), `${markerKey}.json`);
|
|
3824
|
-
}
|
|
3825
|
-
hasFreshLookupIndexMarker(table, suffix) {
|
|
3826
|
-
const markerPath = this.getLookupIndexMarkerPath(table, suffix);
|
|
3827
|
-
if (!existsSync11(markerPath))
|
|
3828
|
-
return false;
|
|
3829
|
-
try {
|
|
3830
|
-
const raw = JSON.parse(readFileSync8(markerPath, "utf-8"));
|
|
3831
|
-
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
3832
|
-
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
3833
|
-
return false;
|
|
3834
|
-
return true;
|
|
3835
|
-
} catch {
|
|
3836
|
-
return false;
|
|
3837
|
-
}
|
|
3838
|
-
}
|
|
3839
|
-
markLookupIndexReady(table, suffix) {
|
|
3840
|
-
mkdirSync3(getIndexMarkerDir(), { recursive: true });
|
|
3841
|
-
writeFileSync5(this.getLookupIndexMarkerPath(table, suffix), JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
3842
|
-
}
|
|
3843
4186
|
async ensureLookupIndex(table, suffix, columnsSql) {
|
|
3844
|
-
|
|
4187
|
+
const markers = await getIndexMarkerStore();
|
|
4188
|
+
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, suffix);
|
|
4189
|
+
if (markers.hasFreshIndexMarker(markerPath))
|
|
3845
4190
|
return;
|
|
3846
4191
|
const indexName = this.buildLookupIndexName(table, suffix);
|
|
3847
4192
|
try {
|
|
3848
4193
|
await this.query(`CREATE INDEX IF NOT EXISTS "${indexName}" ON "${table}" ${columnsSql}`);
|
|
3849
|
-
|
|
4194
|
+
markers.writeIndexMarker(markerPath);
|
|
3850
4195
|
} catch (e) {
|
|
3851
4196
|
if (isDuplicateIndexError(e)) {
|
|
3852
|
-
|
|
4197
|
+
markers.writeIndexMarker(markerPath);
|
|
3853
4198
|
return;
|
|
3854
4199
|
}
|
|
3855
4200
|
log3(`index "${indexName}" skipped: ${e.message}`);
|
|
3856
4201
|
}
|
|
3857
4202
|
}
|
|
4203
|
+
/**
|
|
4204
|
+
* Ensure a vector column exists on the given table.
|
|
4205
|
+
*
|
|
4206
|
+
* The previous implementation always issued `ALTER TABLE ADD COLUMN IF NOT
|
|
4207
|
+
* EXISTS …` on every SessionStart. On a long-running workspace that's
|
|
4208
|
+
* already migrated, every call returns 500 "Column already exists" — noisy
|
|
4209
|
+
* in the log and a wasted round-trip. Worse, the very first call after the
|
|
4210
|
+
* column is genuinely added triggers Deeplake's post-ALTER `vector::at`
|
|
4211
|
+
* window (~30s) during which subsequent INSERTs fail; minimising the
|
|
4212
|
+
* number of ALTER calls minimises exposure to that window.
|
|
4213
|
+
*
|
|
4214
|
+
* New flow:
|
|
4215
|
+
* 1. Check the local marker file (mirrors ensureLookupIndex). If fresh,
|
|
4216
|
+
* return — zero network calls.
|
|
4217
|
+
* 2. SELECT 1 FROM information_schema.columns WHERE table_name = T AND
|
|
4218
|
+
* column_name = C. Read-only, idempotent, can't tickle the post-ALTER
|
|
4219
|
+
* bug. If the column is present → mark + return.
|
|
4220
|
+
* 3. Only if step 2 says the column is missing, fall back to ALTER ADD
|
|
4221
|
+
* COLUMN IF NOT EXISTS. Mark on success, also mark if Deeplake reports
|
|
4222
|
+
* "already exists" (race: another client added it between our SELECT
|
|
4223
|
+
* and ALTER).
|
|
4224
|
+
*
|
|
4225
|
+
* Marker uses the same dir / TTL as ensureLookupIndex so both schema
|
|
4226
|
+
* caches share an opt-out (HIVEMIND_INDEX_MARKER_DIR) and a TTL knob.
|
|
4227
|
+
*/
|
|
4228
|
+
async ensureEmbeddingColumn(table, column) {
|
|
4229
|
+
await this.ensureColumn(table, column, "FLOAT4[]");
|
|
4230
|
+
}
|
|
4231
|
+
/**
|
|
4232
|
+
* Generic marker-gated column migration. Same SELECT-then-ALTER flow as
|
|
4233
|
+
* ensureEmbeddingColumn, parameterized by SQL type so it can patch up any
|
|
4234
|
+
* column that was added to the schema after the table was originally
|
|
4235
|
+
* created. Used today for `summary_embedding`, `message_embedding`, and
|
|
4236
|
+
* the `agent` column (added 2026-04-11) — the latter has no fallback if
|
|
4237
|
+
* a user upgraded over a pre-2026-04-11 table, so every INSERT fails
|
|
4238
|
+
* with `column "agent" does not exist`.
|
|
4239
|
+
*/
|
|
4240
|
+
async ensureColumn(table, column, sqlType) {
|
|
4241
|
+
const markers = await getIndexMarkerStore();
|
|
4242
|
+
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, `col_${column}`);
|
|
4243
|
+
if (markers.hasFreshIndexMarker(markerPath))
|
|
4244
|
+
return;
|
|
4245
|
+
const colCheck = `SELECT 1 FROM information_schema.columns WHERE table_name = '${sqlStr(table)}' AND column_name = '${sqlStr(column)}' AND table_schema = '${sqlStr(this.workspaceId)}' LIMIT 1`;
|
|
4246
|
+
const rows = await this.query(colCheck);
|
|
4247
|
+
if (rows.length > 0) {
|
|
4248
|
+
markers.writeIndexMarker(markerPath);
|
|
4249
|
+
return;
|
|
4250
|
+
}
|
|
4251
|
+
try {
|
|
4252
|
+
await this.query(`ALTER TABLE "${table}" ADD COLUMN ${column} ${sqlType}`);
|
|
4253
|
+
} catch (e) {
|
|
4254
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
4255
|
+
if (!/already exists/i.test(msg))
|
|
4256
|
+
throw e;
|
|
4257
|
+
const recheck = await this.query(colCheck);
|
|
4258
|
+
if (recheck.length === 0)
|
|
4259
|
+
throw e;
|
|
4260
|
+
}
|
|
4261
|
+
markers.writeIndexMarker(markerPath);
|
|
4262
|
+
}
|
|
3858
4263
|
/** List all tables in the workspace (with retry). */
|
|
3859
4264
|
async listTables(forceRefresh = false) {
|
|
3860
4265
|
if (!forceRefresh && this._tablesCache)
|
|
@@ -3870,7 +4275,8 @@ var DeeplakeApi = class {
|
|
|
3870
4275
|
const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, {
|
|
3871
4276
|
headers: {
|
|
3872
4277
|
Authorization: `Bearer ${this.token}`,
|
|
3873
|
-
"X-Activeloop-Org-Id": this.orgId
|
|
4278
|
+
"X-Activeloop-Org-Id": this.orgId,
|
|
4279
|
+
...deeplakeClientHeader()
|
|
3874
4280
|
}
|
|
3875
4281
|
});
|
|
3876
4282
|
if (resp.ok) {
|
|
@@ -3895,29 +4301,84 @@ var DeeplakeApi = class {
|
|
|
3895
4301
|
}
|
|
3896
4302
|
return { tables: [], cacheable: false };
|
|
3897
4303
|
}
|
|
4304
|
+
/**
|
|
4305
|
+
* Run a `CREATE TABLE` with an extra outer retry budget. The base
|
|
4306
|
+
* `query()` already retries 3 times on fetch errors (~3.5s total), but a
|
|
4307
|
+
* failed CREATE is permanent corruption — every subsequent SELECT against
|
|
4308
|
+
* the missing table fails. Wrapping in an outer loop with longer backoff
|
|
4309
|
+
* (2s, 5s, then 10s) gives us ~17s of reach across transient network
|
|
4310
|
+
* blips before giving up. Failures still propagate; getApi() resets its
|
|
4311
|
+
* cache on init failure (openclaw plugin) so the next call retries the
|
|
4312
|
+
* whole init flow.
|
|
4313
|
+
*/
|
|
4314
|
+
async createTableWithRetry(sql, label) {
|
|
4315
|
+
const OUTER_BACKOFFS_MS = [2e3, 5e3, 1e4];
|
|
4316
|
+
let lastErr = null;
|
|
4317
|
+
for (let attempt = 0; attempt <= OUTER_BACKOFFS_MS.length; attempt++) {
|
|
4318
|
+
try {
|
|
4319
|
+
await this.query(sql);
|
|
4320
|
+
return;
|
|
4321
|
+
} catch (err) {
|
|
4322
|
+
lastErr = err;
|
|
4323
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4324
|
+
log3(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
|
|
4325
|
+
if (attempt < OUTER_BACKOFFS_MS.length) {
|
|
4326
|
+
await sleep(OUTER_BACKOFFS_MS[attempt]);
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
}
|
|
4330
|
+
throw lastErr;
|
|
4331
|
+
}
|
|
3898
4332
|
/** Create the memory table if it doesn't already exist. Migrate columns on existing tables. */
|
|
3899
4333
|
async ensureTable(name) {
|
|
3900
|
-
const tbl = name ?? this.tableName;
|
|
4334
|
+
const tbl = sqlIdent(name ?? this.tableName);
|
|
3901
4335
|
const tables = await this.listTables();
|
|
3902
4336
|
if (!tables.includes(tbl)) {
|
|
3903
4337
|
log3(`table "${tbl}" not found, creating`);
|
|
3904
|
-
await this.
|
|
4338
|
+
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${tbl}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', summary TEXT NOT NULL DEFAULT '', summary_embedding FLOAT4[], author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'text/plain', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, tbl);
|
|
3905
4339
|
log3(`table "${tbl}" created`);
|
|
3906
4340
|
if (!tables.includes(tbl))
|
|
3907
4341
|
this._tablesCache = [...tables, tbl];
|
|
3908
4342
|
}
|
|
4343
|
+
await this.ensureEmbeddingColumn(tbl, SUMMARY_EMBEDDING_COL);
|
|
4344
|
+
await this.ensureColumn(tbl, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
3909
4345
|
}
|
|
3910
4346
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
3911
4347
|
async ensureSessionsTable(name) {
|
|
4348
|
+
const safe = sqlIdent(name);
|
|
4349
|
+
const tables = await this.listTables();
|
|
4350
|
+
if (!tables.includes(safe)) {
|
|
4351
|
+
log3(`table "${safe}" not found, creating`);
|
|
4352
|
+
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${safe}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', message JSONB, message_embedding FLOAT4[], author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'application/json', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
|
|
4353
|
+
log3(`table "${safe}" created`);
|
|
4354
|
+
if (!tables.includes(safe))
|
|
4355
|
+
this._tablesCache = [...tables, safe];
|
|
4356
|
+
}
|
|
4357
|
+
await this.ensureEmbeddingColumn(safe, MESSAGE_EMBEDDING_COL);
|
|
4358
|
+
await this.ensureColumn(safe, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
4359
|
+
await this.ensureLookupIndex(safe, "path_creation_date", `("path", "creation_date")`);
|
|
4360
|
+
}
|
|
4361
|
+
/**
|
|
4362
|
+
* Create the skills table.
|
|
4363
|
+
*
|
|
4364
|
+
* One row per skill version. Workers INSERT a fresh row on every KEEP /
|
|
4365
|
+
* MERGE rather than UPDATE-ing in place, so the full version history is
|
|
4366
|
+
* recoverable. Uniqueness in the *current* state is by (project_key, name)
|
|
4367
|
+
* — newer rows shadow older ones at read time (ORDER BY version DESC).
|
|
4368
|
+
* This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
|
|
4369
|
+
* worker.
|
|
4370
|
+
*/
|
|
4371
|
+
async ensureSkillsTable(name) {
|
|
4372
|
+
const safe = sqlIdent(name);
|
|
3912
4373
|
const tables = await this.listTables();
|
|
3913
|
-
if (!tables.includes(
|
|
3914
|
-
log3(`table "${
|
|
3915
|
-
await this.
|
|
3916
|
-
log3(`table "${
|
|
3917
|
-
if (!tables.includes(
|
|
3918
|
-
this._tablesCache = [...tables,
|
|
4374
|
+
if (!tables.includes(safe)) {
|
|
4375
|
+
log3(`table "${safe}" not found, creating`);
|
|
4376
|
+
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${safe}" (id TEXT NOT NULL DEFAULT '', name TEXT NOT NULL DEFAULT '', project TEXT NOT NULL DEFAULT '', project_key TEXT NOT NULL DEFAULT '', local_path TEXT NOT NULL DEFAULT '', install TEXT NOT NULL DEFAULT 'project', source_sessions TEXT NOT NULL DEFAULT '[]', source_agent TEXT NOT NULL DEFAULT '', scope TEXT NOT NULL DEFAULT 'me', author TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', trigger_text TEXT NOT NULL DEFAULT '', body TEXT NOT NULL DEFAULT '', version BIGINT NOT NULL DEFAULT 1, created_at TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
|
|
4377
|
+
log3(`table "${safe}" created`);
|
|
4378
|
+
if (!tables.includes(safe))
|
|
4379
|
+
this._tablesCache = [...tables, safe];
|
|
3919
4380
|
}
|
|
3920
|
-
await this.ensureLookupIndex(
|
|
4381
|
+
await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
|
|
3921
4382
|
}
|
|
3922
4383
|
};
|
|
3923
4384
|
|
|
@@ -4097,8 +4558,24 @@ async function runAuthCommand(args) {
|
|
|
4097
4558
|
console.log(`Org not found: ${target}`);
|
|
4098
4559
|
process.exit(1);
|
|
4099
4560
|
}
|
|
4561
|
+
const prevWs = creds.workspaceId ?? "default";
|
|
4562
|
+
const lcPrev = prevWs.toLowerCase();
|
|
4563
|
+
const wsList = await listWorkspaces(creds.token, apiUrl, match.id);
|
|
4564
|
+
const matchedWs = wsList.find((w) => w.id === prevWs || w.name && w.name.toLowerCase() === lcPrev);
|
|
4100
4565
|
await switchOrg(match.id, match.name);
|
|
4101
4566
|
console.log(`Switched to org: ${match.name}`);
|
|
4567
|
+
if (!matchedWs) {
|
|
4568
|
+
if (prevWs !== "default") {
|
|
4569
|
+
await switchWorkspace("default");
|
|
4570
|
+
console.log(`Workspace '${prevWs}' is not in org '${match.name}'. Reset workspace to 'default'.`);
|
|
4571
|
+
if (wsList.length > 0) {
|
|
4572
|
+
console.log(`Available workspaces: ${wsList.map((w) => w.name || w.id).join(", ")}`);
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4575
|
+
} else if (matchedWs.id !== prevWs) {
|
|
4576
|
+
await switchWorkspace(matchedWs.id);
|
|
4577
|
+
console.log(`Workspace name '${prevWs}' resolved to id '${matchedWs.id}' in org '${match.name}'.`);
|
|
4578
|
+
}
|
|
4102
4579
|
} else {
|
|
4103
4580
|
console.log("Usage: org list | org switch <name-or-id>");
|
|
4104
4581
|
}
|
|
@@ -4110,7 +4587,7 @@ async function runAuthCommand(args) {
|
|
|
4110
4587
|
process.exit(1);
|
|
4111
4588
|
}
|
|
4112
4589
|
const ws = await listWorkspaces(creds.token, apiUrl, creds.orgId);
|
|
4113
|
-
ws.forEach((w) => console.log(
|
|
4590
|
+
ws.forEach((w) => console.log(w.name || w.id));
|
|
4114
4591
|
break;
|
|
4115
4592
|
}
|
|
4116
4593
|
case "workspace": {
|
|
@@ -4118,14 +4595,34 @@ async function runAuthCommand(args) {
|
|
|
4118
4595
|
console.log("Not logged in.");
|
|
4119
4596
|
process.exit(1);
|
|
4120
4597
|
}
|
|
4121
|
-
const
|
|
4122
|
-
if (
|
|
4123
|
-
|
|
4124
|
-
|
|
4598
|
+
const sub = args[1];
|
|
4599
|
+
if (sub === "list") {
|
|
4600
|
+
const wsList = await listWorkspaces(creds.token, apiUrl, creds.orgId);
|
|
4601
|
+
wsList.forEach((w) => console.log(w.name || w.id));
|
|
4602
|
+
break;
|
|
4125
4603
|
}
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4604
|
+
if (sub === "switch") {
|
|
4605
|
+
const target = args[2];
|
|
4606
|
+
if (!target) {
|
|
4607
|
+
console.log("Usage: workspace switch <name-or-id>");
|
|
4608
|
+
process.exit(1);
|
|
4609
|
+
}
|
|
4610
|
+
const wsList = await listWorkspaces(creds.token, apiUrl, creds.orgId);
|
|
4611
|
+
const lcTarget = target.toLowerCase();
|
|
4612
|
+
const match = wsList.find((w) => w.id === target || w.name && w.name.toLowerCase() === lcTarget);
|
|
4613
|
+
if (!match) {
|
|
4614
|
+
console.log(`Workspace not found: ${target}`);
|
|
4615
|
+
if (wsList.length > 0) {
|
|
4616
|
+
console.log(`Available workspaces: ${wsList.map((w) => w.name || w.id).join(", ")}`);
|
|
4617
|
+
}
|
|
4618
|
+
process.exit(1);
|
|
4619
|
+
}
|
|
4620
|
+
await switchWorkspace(match.id);
|
|
4621
|
+
console.log(`Switched to workspace: ${match.name || match.id}`);
|
|
4622
|
+
break;
|
|
4623
|
+
}
|
|
4624
|
+
console.log("Usage: workspace list | workspace switch <name-or-id>");
|
|
4625
|
+
process.exit(1);
|
|
4129
4626
|
}
|
|
4130
4627
|
case "invite": {
|
|
4131
4628
|
if (!creds) {
|
|
@@ -4212,6 +4709,699 @@ if (process.argv[1] && process.argv[1].endsWith("auth-login.js")) {
|
|
|
4212
4709
|
});
|
|
4213
4710
|
}
|
|
4214
4711
|
|
|
4712
|
+
// dist/src/commands/skilify.js
|
|
4713
|
+
import { readdirSync as readdirSync3, existsSync as existsSync15, readFileSync as readFileSync12, mkdirSync as mkdirSync7, renameSync as renameSync2 } from "node:fs";
|
|
4714
|
+
import { homedir as homedir8 } from "node:os";
|
|
4715
|
+
import { dirname as dirname2, join as join18 } from "node:path";
|
|
4716
|
+
|
|
4717
|
+
// dist/src/skilify/scope-config.js
|
|
4718
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
4719
|
+
import { homedir as homedir5 } from "node:os";
|
|
4720
|
+
import { join as join15 } from "node:path";
|
|
4721
|
+
var STATE_DIR = join15(homedir5(), ".deeplake", "state", "skilify");
|
|
4722
|
+
var CONFIG_PATH2 = join15(STATE_DIR, "config.json");
|
|
4723
|
+
var DEFAULT = { scope: "me", team: [], install: "project" };
|
|
4724
|
+
function loadScopeConfig() {
|
|
4725
|
+
if (!existsSync12(CONFIG_PATH2))
|
|
4726
|
+
return DEFAULT;
|
|
4727
|
+
try {
|
|
4728
|
+
const raw = JSON.parse(readFileSync9(CONFIG_PATH2, "utf-8"));
|
|
4729
|
+
const scope = raw.scope === "team" || raw.scope === "org" ? raw.scope : "me";
|
|
4730
|
+
const team = Array.isArray(raw.team) ? raw.team.filter((s) => typeof s === "string") : [];
|
|
4731
|
+
const install = raw.install === "global" ? "global" : "project";
|
|
4732
|
+
return { scope, team, install };
|
|
4733
|
+
} catch {
|
|
4734
|
+
return DEFAULT;
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
function saveScopeConfig(cfg) {
|
|
4738
|
+
mkdirSync4(STATE_DIR, { recursive: true });
|
|
4739
|
+
writeFileSync6(CONFIG_PATH2, JSON.stringify(cfg, null, 2));
|
|
4740
|
+
}
|
|
4741
|
+
|
|
4742
|
+
// dist/src/skilify/pull.js
|
|
4743
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, renameSync } from "node:fs";
|
|
4744
|
+
import { homedir as homedir7 } from "node:os";
|
|
4745
|
+
import { join as join17 } from "node:path";
|
|
4746
|
+
|
|
4747
|
+
// dist/src/skilify/skill-writer.js
|
|
4748
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync5, readFileSync as readFileSync10, readdirSync as readdirSync2, statSync as statSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
4749
|
+
import { homedir as homedir6 } from "node:os";
|
|
4750
|
+
import { join as join16 } from "node:path";
|
|
4751
|
+
function assertValidSkillName(name) {
|
|
4752
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
4753
|
+
throw new Error(`invalid skill name: empty or non-string`);
|
|
4754
|
+
}
|
|
4755
|
+
if (name.length > 100) {
|
|
4756
|
+
throw new Error(`invalid skill name: too long (${name.length} chars)`);
|
|
4757
|
+
}
|
|
4758
|
+
if (name.includes("/") || name.includes("\\") || name.includes("..")) {
|
|
4759
|
+
throw new Error(`invalid skill name: contains path separator or '..': ${name}`);
|
|
4760
|
+
}
|
|
4761
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) {
|
|
4762
|
+
throw new Error(`invalid skill name: must be kebab-case (lowercase a-z, 0-9, hyphen): ${name}`);
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
function parseFrontmatter(text) {
|
|
4766
|
+
if (!text.startsWith("---\n") && !text.startsWith("---\r\n"))
|
|
4767
|
+
return null;
|
|
4768
|
+
const end = text.indexOf("\n---", 4);
|
|
4769
|
+
if (end < 0)
|
|
4770
|
+
return null;
|
|
4771
|
+
const head = text.slice(4, end).trim();
|
|
4772
|
+
const body = text.slice(end + 4).replace(/^\r?\n/, "");
|
|
4773
|
+
const fm = { source_sessions: [] };
|
|
4774
|
+
let mode = "kv";
|
|
4775
|
+
for (const raw of head.split(/\r?\n/)) {
|
|
4776
|
+
if (mode === "sources") {
|
|
4777
|
+
const m2 = raw.match(/^\s+-\s+(.+)$/);
|
|
4778
|
+
if (m2) {
|
|
4779
|
+
fm.source_sessions.push(m2[1].trim());
|
|
4780
|
+
continue;
|
|
4781
|
+
}
|
|
4782
|
+
mode = "kv";
|
|
4783
|
+
}
|
|
4784
|
+
if (raw.startsWith("source_sessions:")) {
|
|
4785
|
+
mode = "sources";
|
|
4786
|
+
continue;
|
|
4787
|
+
}
|
|
4788
|
+
const m = raw.match(/^([a-zA-Z_]+):\s*(.*)$/);
|
|
4789
|
+
if (!m)
|
|
4790
|
+
continue;
|
|
4791
|
+
const [, k, v] = m;
|
|
4792
|
+
let val = v;
|
|
4793
|
+
if (v.startsWith('"') && v.endsWith('"')) {
|
|
4794
|
+
try {
|
|
4795
|
+
val = JSON.parse(v);
|
|
4796
|
+
} catch {
|
|
4797
|
+
}
|
|
4798
|
+
} else if (k === "version") {
|
|
4799
|
+
const n = parseInt(v, 10);
|
|
4800
|
+
if (Number.isFinite(n))
|
|
4801
|
+
val = n;
|
|
4802
|
+
}
|
|
4803
|
+
fm[k] = val;
|
|
4804
|
+
}
|
|
4805
|
+
return { fm, body };
|
|
4806
|
+
}
|
|
4807
|
+
|
|
4808
|
+
// dist/src/skilify/pull.js
|
|
4809
|
+
function esc(s) {
|
|
4810
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
4811
|
+
}
|
|
4812
|
+
function buildPullSql(args) {
|
|
4813
|
+
const where = [];
|
|
4814
|
+
if (args.users.length > 0) {
|
|
4815
|
+
const list = args.users.map((u) => `'${esc(u)}'`).join(", ");
|
|
4816
|
+
where.push(`author IN (${list})`);
|
|
4817
|
+
}
|
|
4818
|
+
if (args.skillName) {
|
|
4819
|
+
where.push(`name = '${esc(args.skillName)}'`);
|
|
4820
|
+
}
|
|
4821
|
+
const whereClause = where.length > 0 ? ` WHERE ${where.join(" AND ")}` : "";
|
|
4822
|
+
return `SELECT name, project, project_key, body, version, source_agent, scope, author, description, trigger_text, source_sessions, install, created_at, updated_at FROM "${args.tableName}"${whereClause} ORDER BY project_key ASC, name ASC, version DESC`;
|
|
4823
|
+
}
|
|
4824
|
+
function isMissingTableError(message) {
|
|
4825
|
+
if (!message)
|
|
4826
|
+
return false;
|
|
4827
|
+
return /Table does not exist|relation .* does not exist|no such table/i.test(message);
|
|
4828
|
+
}
|
|
4829
|
+
function resolvePullDestination(install, cwd) {
|
|
4830
|
+
if (install === "global")
|
|
4831
|
+
return join17(homedir7(), ".claude", "skills");
|
|
4832
|
+
if (!cwd)
|
|
4833
|
+
throw new Error("install=project requires a cwd");
|
|
4834
|
+
return join17(cwd, ".claude", "skills");
|
|
4835
|
+
}
|
|
4836
|
+
function selectLatestPerName(rows) {
|
|
4837
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4838
|
+
const out = [];
|
|
4839
|
+
for (const r of rows) {
|
|
4840
|
+
const name = String(r.name ?? "");
|
|
4841
|
+
const projectKey = String(r.project_key ?? "");
|
|
4842
|
+
if (!name)
|
|
4843
|
+
continue;
|
|
4844
|
+
const key = `${projectKey}\0${name}`;
|
|
4845
|
+
if (seen.has(key))
|
|
4846
|
+
continue;
|
|
4847
|
+
seen.add(key);
|
|
4848
|
+
out.push(r);
|
|
4849
|
+
}
|
|
4850
|
+
return out;
|
|
4851
|
+
}
|
|
4852
|
+
function renderSkillFile(row) {
|
|
4853
|
+
const sources = parseSourceSessions(row.source_sessions);
|
|
4854
|
+
const fm = {
|
|
4855
|
+
name: String(row.name ?? ""),
|
|
4856
|
+
description: String(row.description ?? ""),
|
|
4857
|
+
trigger: typeof row.trigger_text === "string" && row.trigger_text.length > 0 ? String(row.trigger_text) : void 0,
|
|
4858
|
+
source_sessions: sources,
|
|
4859
|
+
version: Number(row.version ?? 1),
|
|
4860
|
+
created_by_agent: String(row.source_agent ?? "unknown"),
|
|
4861
|
+
created_at: String(row.created_at ?? (/* @__PURE__ */ new Date()).toISOString()),
|
|
4862
|
+
updated_at: String(row.updated_at ?? (/* @__PURE__ */ new Date()).toISOString())
|
|
4863
|
+
};
|
|
4864
|
+
const body = String(row.body ?? "").trim();
|
|
4865
|
+
return `${renderFrontmatter(fm)}
|
|
4866
|
+
|
|
4867
|
+
${body}
|
|
4868
|
+
`;
|
|
4869
|
+
}
|
|
4870
|
+
function parseSourceSessions(v) {
|
|
4871
|
+
if (Array.isArray(v))
|
|
4872
|
+
return v.map(String);
|
|
4873
|
+
if (typeof v === "string") {
|
|
4874
|
+
try {
|
|
4875
|
+
const parsed = JSON.parse(v);
|
|
4876
|
+
if (Array.isArray(parsed))
|
|
4877
|
+
return parsed.map(String);
|
|
4878
|
+
} catch {
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4881
|
+
return [];
|
|
4882
|
+
}
|
|
4883
|
+
function renderFrontmatter(fm) {
|
|
4884
|
+
const lines = ["---"];
|
|
4885
|
+
lines.push(`name: ${fm.name}`);
|
|
4886
|
+
lines.push(`description: ${JSON.stringify(fm.description)}`);
|
|
4887
|
+
if (fm.trigger)
|
|
4888
|
+
lines.push(`trigger: ${JSON.stringify(fm.trigger)}`);
|
|
4889
|
+
lines.push(`source_sessions:`);
|
|
4890
|
+
for (const s of fm.source_sessions)
|
|
4891
|
+
lines.push(` - ${s}`);
|
|
4892
|
+
lines.push(`version: ${fm.version}`);
|
|
4893
|
+
lines.push(`created_by_agent: ${fm.created_by_agent}`);
|
|
4894
|
+
lines.push(`created_at: ${fm.created_at}`);
|
|
4895
|
+
lines.push(`updated_at: ${fm.updated_at}`);
|
|
4896
|
+
lines.push("---");
|
|
4897
|
+
return lines.join("\n");
|
|
4898
|
+
}
|
|
4899
|
+
function readLocalVersion(path) {
|
|
4900
|
+
if (!existsSync14(path))
|
|
4901
|
+
return null;
|
|
4902
|
+
try {
|
|
4903
|
+
const text = readFileSync11(path, "utf-8");
|
|
4904
|
+
const parsed = parseFrontmatter(text);
|
|
4905
|
+
if (!parsed)
|
|
4906
|
+
return null;
|
|
4907
|
+
const v = parsed.fm.version;
|
|
4908
|
+
return typeof v === "number" ? v : null;
|
|
4909
|
+
} catch {
|
|
4910
|
+
return null;
|
|
4911
|
+
}
|
|
4912
|
+
}
|
|
4913
|
+
function decideAction(args) {
|
|
4914
|
+
const shouldWrite = args.localVersion === null || args.remoteVersion > args.localVersion || args.force;
|
|
4915
|
+
if (!shouldWrite)
|
|
4916
|
+
return "skipped";
|
|
4917
|
+
return args.dryRun ? "dryrun" : "wrote";
|
|
4918
|
+
}
|
|
4919
|
+
async function runPull(opts) {
|
|
4920
|
+
const sql = buildPullSql({
|
|
4921
|
+
tableName: opts.tableName,
|
|
4922
|
+
users: opts.users,
|
|
4923
|
+
skillName: opts.skillName
|
|
4924
|
+
});
|
|
4925
|
+
let rows = [];
|
|
4926
|
+
try {
|
|
4927
|
+
rows = await opts.query(sql);
|
|
4928
|
+
} catch (e) {
|
|
4929
|
+
if (isMissingTableError(e?.message))
|
|
4930
|
+
rows = [];
|
|
4931
|
+
else
|
|
4932
|
+
throw e;
|
|
4933
|
+
}
|
|
4934
|
+
const latest = selectLatestPerName(rows);
|
|
4935
|
+
const root = resolvePullDestination(opts.install, opts.cwd);
|
|
4936
|
+
const summary = { scanned: latest.length, wrote: 0, skipped: 0, dryrun: 0, entries: [] };
|
|
4937
|
+
for (const row of latest) {
|
|
4938
|
+
const name = String(row.name ?? "");
|
|
4939
|
+
if (!name)
|
|
4940
|
+
continue;
|
|
4941
|
+
try {
|
|
4942
|
+
assertValidSkillName(name);
|
|
4943
|
+
} catch (e) {
|
|
4944
|
+
summary.entries.push({
|
|
4945
|
+
name,
|
|
4946
|
+
remoteVersion: Number(row.version ?? 1),
|
|
4947
|
+
localVersion: null,
|
|
4948
|
+
action: "skipped",
|
|
4949
|
+
destination: "(invalid name \u2014 skipped)",
|
|
4950
|
+
author: String(row.author ?? ""),
|
|
4951
|
+
sourceAgent: String(row.source_agent ?? "")
|
|
4952
|
+
});
|
|
4953
|
+
summary.skipped++;
|
|
4954
|
+
continue;
|
|
4955
|
+
}
|
|
4956
|
+
const projectKey = String(row.project_key ?? "");
|
|
4957
|
+
const skillDir = projectKey ? join17(root, projectKey, name) : join17(root, name);
|
|
4958
|
+
const skillFile = join17(skillDir, "SKILL.md");
|
|
4959
|
+
const remoteVersion = Number(row.version ?? 1);
|
|
4960
|
+
const localVersion = readLocalVersion(skillFile);
|
|
4961
|
+
const action = decideAction({
|
|
4962
|
+
remoteVersion,
|
|
4963
|
+
localVersion,
|
|
4964
|
+
force: opts.force ?? false,
|
|
4965
|
+
dryRun: opts.dryRun ?? false
|
|
4966
|
+
});
|
|
4967
|
+
if (action === "wrote") {
|
|
4968
|
+
mkdirSync6(skillDir, { recursive: true });
|
|
4969
|
+
if (existsSync14(skillFile)) {
|
|
4970
|
+
try {
|
|
4971
|
+
renameSync(skillFile, `${skillFile}.bak`);
|
|
4972
|
+
} catch {
|
|
4973
|
+
}
|
|
4974
|
+
}
|
|
4975
|
+
writeFileSync8(skillFile, renderSkillFile(row));
|
|
4976
|
+
}
|
|
4977
|
+
summary.entries.push({
|
|
4978
|
+
name,
|
|
4979
|
+
remoteVersion,
|
|
4980
|
+
localVersion,
|
|
4981
|
+
action,
|
|
4982
|
+
destination: skillFile,
|
|
4983
|
+
author: String(row.author ?? ""),
|
|
4984
|
+
sourceAgent: String(row.source_agent ?? "")
|
|
4985
|
+
});
|
|
4986
|
+
if (action === "wrote")
|
|
4987
|
+
summary.wrote++;
|
|
4988
|
+
else if (action === "dryrun")
|
|
4989
|
+
summary.dryrun++;
|
|
4990
|
+
else
|
|
4991
|
+
summary.skipped++;
|
|
4992
|
+
}
|
|
4993
|
+
return summary;
|
|
4994
|
+
}
|
|
4995
|
+
|
|
4996
|
+
// dist/src/commands/skilify.js
|
|
4997
|
+
var STATE_DIR2 = join18(homedir8(), ".deeplake", "state", "skilify");
|
|
4998
|
+
function showStatus() {
|
|
4999
|
+
const cfg = loadScopeConfig();
|
|
5000
|
+
console.log(`scope: ${cfg.scope}`);
|
|
5001
|
+
console.log(`team: ${cfg.team.length === 0 ? "(empty)" : cfg.team.join(", ")}`);
|
|
5002
|
+
console.log(`install: ${cfg.install} (${cfg.install === "global" ? "~/.claude/skills/" : "<project>/.claude/skills/"})`);
|
|
5003
|
+
if (!existsSync15(STATE_DIR2)) {
|
|
5004
|
+
console.log(`state: (no projects tracked yet)`);
|
|
5005
|
+
return;
|
|
5006
|
+
}
|
|
5007
|
+
const files = readdirSync3(STATE_DIR2).filter((f) => f.endsWith(".json") && f !== "config.json");
|
|
5008
|
+
if (files.length === 0) {
|
|
5009
|
+
console.log(`state: (no projects tracked yet)`);
|
|
5010
|
+
return;
|
|
5011
|
+
}
|
|
5012
|
+
console.log(`state: ${files.length} project(s) tracked`);
|
|
5013
|
+
for (const f of files) {
|
|
5014
|
+
try {
|
|
5015
|
+
const s = JSON.parse(readFileSync12(join18(STATE_DIR2, f), "utf-8"));
|
|
5016
|
+
const skills = s.skillsGenerated.length === 0 ? "none" : s.skillsGenerated.join(", ");
|
|
5017
|
+
console.log(` - ${s.project} (counter=${s.counter}, last=${s.lastDate ?? "never"}, skills=${skills})`);
|
|
5018
|
+
} catch {
|
|
5019
|
+
}
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
5022
|
+
function setScope(scope) {
|
|
5023
|
+
if (scope !== "me" && scope !== "team" && scope !== "org") {
|
|
5024
|
+
console.error(`Invalid scope '${scope}'. Use one of: me, team, org`);
|
|
5025
|
+
process.exit(1);
|
|
5026
|
+
}
|
|
5027
|
+
const cfg = loadScopeConfig();
|
|
5028
|
+
saveScopeConfig({ ...cfg, scope });
|
|
5029
|
+
console.log(`Scope set to '${scope}'.`);
|
|
5030
|
+
if (scope === "team" && cfg.team.length === 0) {
|
|
5031
|
+
console.log(`Note: team list is empty. Use 'hivemind skilify team add <username>' to populate it.`);
|
|
5032
|
+
}
|
|
5033
|
+
}
|
|
5034
|
+
function setInstall(loc) {
|
|
5035
|
+
if (loc !== "project" && loc !== "global") {
|
|
5036
|
+
console.error(`Invalid install location '${loc}'. Use one of: project, global`);
|
|
5037
|
+
process.exit(1);
|
|
5038
|
+
}
|
|
5039
|
+
const cfg = loadScopeConfig();
|
|
5040
|
+
saveScopeConfig({ ...cfg, install: loc });
|
|
5041
|
+
const path = loc === "global" ? join18(homedir8(), ".claude", "skills") : "<cwd>/.claude/skills";
|
|
5042
|
+
console.log(`Install location set to '${loc}'. New skills will be written to ${path}/<name>/SKILL.md.`);
|
|
5043
|
+
}
|
|
5044
|
+
function promoteSkill(name, cwd) {
|
|
5045
|
+
if (!name) {
|
|
5046
|
+
console.error("Usage: hivemind skilify promote <skill-name>");
|
|
5047
|
+
process.exit(1);
|
|
5048
|
+
}
|
|
5049
|
+
const projectPath = join18(cwd, ".claude", "skills", name);
|
|
5050
|
+
const globalPath = join18(homedir8(), ".claude", "skills", name);
|
|
5051
|
+
if (!existsSync15(join18(projectPath, "SKILL.md"))) {
|
|
5052
|
+
console.error(`Skill '${name}' not found at ${projectPath}/SKILL.md`);
|
|
5053
|
+
process.exit(1);
|
|
5054
|
+
}
|
|
5055
|
+
if (existsSync15(join18(globalPath, "SKILL.md"))) {
|
|
5056
|
+
console.error(`Skill '${name}' already exists at ${globalPath}/SKILL.md \u2014 refusing to overwrite. Remove it first or rename the project skill.`);
|
|
5057
|
+
process.exit(1);
|
|
5058
|
+
}
|
|
5059
|
+
mkdirSync7(dirname2(globalPath), { recursive: true });
|
|
5060
|
+
renameSync2(projectPath, globalPath);
|
|
5061
|
+
console.log(`Promoted '${name}' from ${projectPath} \u2192 ${globalPath}.`);
|
|
5062
|
+
}
|
|
5063
|
+
function teamAdd(name) {
|
|
5064
|
+
if (!name) {
|
|
5065
|
+
console.error("Usage: hivemind skilify team add <username>");
|
|
5066
|
+
process.exit(1);
|
|
5067
|
+
}
|
|
5068
|
+
const cfg = loadScopeConfig();
|
|
5069
|
+
if (cfg.team.includes(name)) {
|
|
5070
|
+
console.log(`'${name}' is already in the team list.`);
|
|
5071
|
+
return;
|
|
5072
|
+
}
|
|
5073
|
+
const next = [...cfg.team, name].sort();
|
|
5074
|
+
saveScopeConfig({ ...cfg, team: next });
|
|
5075
|
+
console.log(`Added '${name}' to team. Team is now: ${next.join(", ")}`);
|
|
5076
|
+
}
|
|
5077
|
+
function teamRemove(name) {
|
|
5078
|
+
if (!name) {
|
|
5079
|
+
console.error("Usage: hivemind skilify team remove <username>");
|
|
5080
|
+
process.exit(1);
|
|
5081
|
+
}
|
|
5082
|
+
const cfg = loadScopeConfig();
|
|
5083
|
+
if (!cfg.team.includes(name)) {
|
|
5084
|
+
console.log(`'${name}' is not in the team list.`);
|
|
5085
|
+
return;
|
|
5086
|
+
}
|
|
5087
|
+
const next = cfg.team.filter((n) => n !== name);
|
|
5088
|
+
saveScopeConfig({ ...cfg, team: next });
|
|
5089
|
+
console.log(`Removed '${name}' from team. Team is now: ${next.length === 0 ? "(empty)" : next.join(", ")}`);
|
|
5090
|
+
}
|
|
5091
|
+
function teamList() {
|
|
5092
|
+
const cfg = loadScopeConfig();
|
|
5093
|
+
if (cfg.team.length === 0) {
|
|
5094
|
+
console.log(`(team list is empty)`);
|
|
5095
|
+
return;
|
|
5096
|
+
}
|
|
5097
|
+
for (const n of cfg.team)
|
|
5098
|
+
console.log(n);
|
|
5099
|
+
}
|
|
5100
|
+
function usage() {
|
|
5101
|
+
console.log("Usage:");
|
|
5102
|
+
console.log(" hivemind skilify show current scope, team, install, and per-project state");
|
|
5103
|
+
console.log(" hivemind skilify scope <me|team|org> set the mining scope");
|
|
5104
|
+
console.log(" hivemind skilify install <project|global> set where new skills are written");
|
|
5105
|
+
console.log(" hivemind skilify promote <skill-name> move a project skill to the global location");
|
|
5106
|
+
console.log(" hivemind skilify team add <username> add a username to the team list");
|
|
5107
|
+
console.log(" hivemind skilify team remove <username> remove a username from the team list");
|
|
5108
|
+
console.log(" hivemind skilify team list list current team members");
|
|
5109
|
+
console.log(" hivemind skilify pull [skill-name] [opts] fetch skills from Deeplake to local FS");
|
|
5110
|
+
console.log(" Options for pull:");
|
|
5111
|
+
console.log(" --to <project|global> destination (default: global)");
|
|
5112
|
+
console.log(" --user <name> only skills authored by this user");
|
|
5113
|
+
console.log(" --users <a,b,c> only skills authored by these users");
|
|
5114
|
+
console.log(" --all-users all authors (default \u2014 equivalent to no filter)");
|
|
5115
|
+
console.log(" --dry-run show what would be written, don't touch disk");
|
|
5116
|
+
console.log(" --force overwrite even when local version >= remote");
|
|
5117
|
+
console.log(" hivemind skilify status show per-project state");
|
|
5118
|
+
}
|
|
5119
|
+
function takeFlagValue(args, flag) {
|
|
5120
|
+
const idx = args.indexOf(flag);
|
|
5121
|
+
if (idx < 0)
|
|
5122
|
+
return null;
|
|
5123
|
+
const value = args[idx + 1];
|
|
5124
|
+
if (value === void 0 || value.startsWith("--")) {
|
|
5125
|
+
console.error(`${flag} requires a value`);
|
|
5126
|
+
process.exit(1);
|
|
5127
|
+
}
|
|
5128
|
+
args.splice(idx, 2);
|
|
5129
|
+
return value;
|
|
5130
|
+
}
|
|
5131
|
+
function takeBooleanFlag(args, flag) {
|
|
5132
|
+
const idx = args.indexOf(flag);
|
|
5133
|
+
if (idx < 0)
|
|
5134
|
+
return false;
|
|
5135
|
+
args.splice(idx, 1);
|
|
5136
|
+
return true;
|
|
5137
|
+
}
|
|
5138
|
+
async function pullSkills(args) {
|
|
5139
|
+
const work = [...args];
|
|
5140
|
+
const toRaw = takeFlagValue(work, "--to") ?? "global";
|
|
5141
|
+
const userOne = takeFlagValue(work, "--user");
|
|
5142
|
+
const usersMany = takeFlagValue(work, "--users");
|
|
5143
|
+
const allUsers = takeBooleanFlag(work, "--all-users");
|
|
5144
|
+
const dryRun = takeBooleanFlag(work, "--dry-run");
|
|
5145
|
+
const force = takeBooleanFlag(work, "--force");
|
|
5146
|
+
const skillName = work[0];
|
|
5147
|
+
if (toRaw !== "project" && toRaw !== "global") {
|
|
5148
|
+
console.error(`Invalid --to '${toRaw}'. Use 'project' or 'global'.`);
|
|
5149
|
+
process.exit(1);
|
|
5150
|
+
}
|
|
5151
|
+
let users = [];
|
|
5152
|
+
if (allUsers)
|
|
5153
|
+
users = [];
|
|
5154
|
+
else if (userOne)
|
|
5155
|
+
users = [userOne];
|
|
5156
|
+
else if (usersMany)
|
|
5157
|
+
users = usersMany.split(",").map((s) => s.trim()).filter(Boolean);
|
|
5158
|
+
const config = loadConfig();
|
|
5159
|
+
if (!config) {
|
|
5160
|
+
console.error("Not logged in. Run: hivemind login");
|
|
5161
|
+
process.exit(1);
|
|
5162
|
+
}
|
|
5163
|
+
const api = new DeeplakeApi(config.token, config.apiUrl, config.orgId, config.workspaceId, config.skillsTableName);
|
|
5164
|
+
const query = (sql) => api.query(sql);
|
|
5165
|
+
let summary;
|
|
5166
|
+
try {
|
|
5167
|
+
summary = await runPull({
|
|
5168
|
+
query,
|
|
5169
|
+
tableName: config.skillsTableName,
|
|
5170
|
+
install: toRaw,
|
|
5171
|
+
cwd: toRaw === "project" ? process.cwd() : void 0,
|
|
5172
|
+
users,
|
|
5173
|
+
skillName,
|
|
5174
|
+
dryRun,
|
|
5175
|
+
force
|
|
5176
|
+
});
|
|
5177
|
+
} catch (e) {
|
|
5178
|
+
console.error(`pull failed: ${e?.message ?? e}`);
|
|
5179
|
+
process.exit(1);
|
|
5180
|
+
}
|
|
5181
|
+
const dest = toRaw === "global" ? join18(homedir8(), ".claude", "skills") : `${process.cwd()}/.claude/skills`;
|
|
5182
|
+
const filterDesc = users.length === 0 ? "all users" : users.join(", ");
|
|
5183
|
+
console.log(`Destination: ${dest}`);
|
|
5184
|
+
console.log(`Filter: ${filterDesc}${skillName ? ` \xB7 skill='${skillName}'` : ""}${dryRun ? " \xB7 dry-run" : ""}${force ? " \xB7 force" : ""}`);
|
|
5185
|
+
console.log(`Scanned ${summary.scanned} remote skill(s).`);
|
|
5186
|
+
for (const e of summary.entries) {
|
|
5187
|
+
const tag = e.action === "wrote" ? "\u2713 wrote" : e.action === "dryrun" ? "\u2192 would write" : "\xB7 skipped";
|
|
5188
|
+
const ver = e.localVersion === null ? `v${e.remoteVersion} (new)` : `v${e.localVersion} \u2192 v${e.remoteVersion}`;
|
|
5189
|
+
console.log(` ${tag.padEnd(15)} ${e.name.padEnd(40)} ${ver.padEnd(20)} (${e.author}/${e.sourceAgent})`);
|
|
5190
|
+
}
|
|
5191
|
+
console.log(`Result: ${summary.wrote} written, ${summary.dryrun} dry-run, ${summary.skipped} skipped.`);
|
|
5192
|
+
}
|
|
5193
|
+
function runSkilifyCommand(args) {
|
|
5194
|
+
const sub = args[0];
|
|
5195
|
+
if (!sub || sub === "status") {
|
|
5196
|
+
showStatus();
|
|
5197
|
+
return;
|
|
5198
|
+
}
|
|
5199
|
+
if (sub === "scope") {
|
|
5200
|
+
setScope(args[1] ?? "");
|
|
5201
|
+
return;
|
|
5202
|
+
}
|
|
5203
|
+
if (sub === "install") {
|
|
5204
|
+
setInstall(args[1] ?? "");
|
|
5205
|
+
return;
|
|
5206
|
+
}
|
|
5207
|
+
if (sub === "promote") {
|
|
5208
|
+
promoteSkill(args[1] ?? "", process.cwd());
|
|
5209
|
+
return;
|
|
5210
|
+
}
|
|
5211
|
+
if (sub === "pull") {
|
|
5212
|
+
pullSkills(args.slice(1)).catch((e) => {
|
|
5213
|
+
console.error(`pull error: ${e?.message ?? e}`);
|
|
5214
|
+
process.exit(1);
|
|
5215
|
+
});
|
|
5216
|
+
return;
|
|
5217
|
+
}
|
|
5218
|
+
if (sub === "team") {
|
|
5219
|
+
const action = args[1];
|
|
5220
|
+
if (action === "add") {
|
|
5221
|
+
teamAdd(args[2] ?? "");
|
|
5222
|
+
return;
|
|
5223
|
+
}
|
|
5224
|
+
if (action === "remove") {
|
|
5225
|
+
teamRemove(args[2] ?? "");
|
|
5226
|
+
return;
|
|
5227
|
+
}
|
|
5228
|
+
if (action === "list") {
|
|
5229
|
+
teamList();
|
|
5230
|
+
return;
|
|
5231
|
+
}
|
|
5232
|
+
console.error("Usage: hivemind skilify team <add|remove|list> [name]");
|
|
5233
|
+
process.exit(1);
|
|
5234
|
+
}
|
|
5235
|
+
if (sub === "--help" || sub === "-h" || sub === "help") {
|
|
5236
|
+
usage();
|
|
5237
|
+
return;
|
|
5238
|
+
}
|
|
5239
|
+
console.error(`Unknown skilify subcommand: ${sub}`);
|
|
5240
|
+
usage();
|
|
5241
|
+
process.exit(1);
|
|
5242
|
+
}
|
|
5243
|
+
if (process.argv[1] && process.argv[1].endsWith("skilify.js")) {
|
|
5244
|
+
runSkilifyCommand(process.argv.slice(2));
|
|
5245
|
+
}
|
|
5246
|
+
|
|
5247
|
+
// dist/src/cli/update.js
|
|
5248
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
5249
|
+
import { existsSync as existsSync16, readFileSync as readFileSync14, realpathSync } from "node:fs";
|
|
5250
|
+
import { dirname as dirname4, sep } from "node:path";
|
|
5251
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5252
|
+
|
|
5253
|
+
// dist/src/utils/version-check.js
|
|
5254
|
+
import { readFileSync as readFileSync13 } from "node:fs";
|
|
5255
|
+
import { dirname as dirname3, join as join19 } from "node:path";
|
|
5256
|
+
function isNewer(latest, current) {
|
|
5257
|
+
const parse = (v) => v.split(".").map(Number);
|
|
5258
|
+
const [la, lb, lc] = parse(latest);
|
|
5259
|
+
const [ca, cb, cc] = parse(current);
|
|
5260
|
+
return la > ca || la === ca && lb > cb || la === ca && lb === cb && lc > cc;
|
|
5261
|
+
}
|
|
5262
|
+
|
|
5263
|
+
// dist/src/cli/update.js
|
|
5264
|
+
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@deeplake/hivemind/latest";
|
|
5265
|
+
var PKG_NAME = "@deeplake/hivemind";
|
|
5266
|
+
function detectInstallKind(argv1) {
|
|
5267
|
+
const realArgv1 = (() => {
|
|
5268
|
+
try {
|
|
5269
|
+
return realpathSync(argv1 ?? process.argv[1] ?? fileURLToPath2(import.meta.url));
|
|
5270
|
+
} catch {
|
|
5271
|
+
return argv1 ?? process.argv[1] ?? fileURLToPath2(import.meta.url);
|
|
5272
|
+
}
|
|
5273
|
+
})();
|
|
5274
|
+
let dir = dirname4(realArgv1);
|
|
5275
|
+
let installDir = null;
|
|
5276
|
+
for (let i = 0; i < 10; i++) {
|
|
5277
|
+
const pkgPath = `${dir}${sep}package.json`;
|
|
5278
|
+
try {
|
|
5279
|
+
const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
5280
|
+
if (pkg.name === PKG_NAME || pkg.name === "hivemind") {
|
|
5281
|
+
installDir = dir;
|
|
5282
|
+
break;
|
|
5283
|
+
}
|
|
5284
|
+
} catch {
|
|
5285
|
+
}
|
|
5286
|
+
const parent = dirname4(dir);
|
|
5287
|
+
if (parent === dir)
|
|
5288
|
+
break;
|
|
5289
|
+
dir = parent;
|
|
5290
|
+
}
|
|
5291
|
+
installDir ??= dirname4(realArgv1);
|
|
5292
|
+
if (realArgv1.includes(`${sep}_npx${sep}`) || realArgv1.includes(`${sep}.npx${sep}`)) {
|
|
5293
|
+
return { kind: "npx", installDir };
|
|
5294
|
+
}
|
|
5295
|
+
if (realArgv1.includes(`${sep}node_modules${sep}@deeplake${sep}hivemind`) || realArgv1.includes(`${sep}node_modules${sep}hivemind`)) {
|
|
5296
|
+
return { kind: "npm-global", installDir };
|
|
5297
|
+
}
|
|
5298
|
+
let gitDir = installDir;
|
|
5299
|
+
for (let i = 0; i < 6; i++) {
|
|
5300
|
+
if (existsSync16(`${gitDir}${sep}.git`)) {
|
|
5301
|
+
return { kind: "local-dev", installDir };
|
|
5302
|
+
}
|
|
5303
|
+
const parent = dirname4(gitDir);
|
|
5304
|
+
if (parent === gitDir)
|
|
5305
|
+
break;
|
|
5306
|
+
gitDir = parent;
|
|
5307
|
+
}
|
|
5308
|
+
return { kind: "unknown", installDir };
|
|
5309
|
+
}
|
|
5310
|
+
async function getLatestNpmVersion(timeoutMs = 5e3) {
|
|
5311
|
+
try {
|
|
5312
|
+
const res = await fetch(NPM_REGISTRY_URL, { signal: AbortSignal.timeout(timeoutMs) });
|
|
5313
|
+
if (!res.ok)
|
|
5314
|
+
return null;
|
|
5315
|
+
const meta = await res.json();
|
|
5316
|
+
return meta.version ?? null;
|
|
5317
|
+
} catch {
|
|
5318
|
+
return null;
|
|
5319
|
+
}
|
|
5320
|
+
}
|
|
5321
|
+
var defaultSpawn = (cmd, args) => {
|
|
5322
|
+
execFileSync4(cmd, args, { stdio: "inherit" });
|
|
5323
|
+
};
|
|
5324
|
+
async function runUpdate(opts = {}) {
|
|
5325
|
+
const current = opts.currentVersionOverride ?? getVersion();
|
|
5326
|
+
const latest = opts.latestVersionOverride !== void 0 ? opts.latestVersionOverride : await getLatestNpmVersion();
|
|
5327
|
+
if (!latest) {
|
|
5328
|
+
warn(`Could not reach npm registry to check for updates.`);
|
|
5329
|
+
warn(`Current version: ${current}`);
|
|
5330
|
+
return 1;
|
|
5331
|
+
}
|
|
5332
|
+
if (!isNewer(latest, current)) {
|
|
5333
|
+
log(`hivemind ${current} is up to date (npm latest: ${latest}).`);
|
|
5334
|
+
return 0;
|
|
5335
|
+
}
|
|
5336
|
+
log(`Update available: ${current} \u2192 ${latest}`);
|
|
5337
|
+
const detected = opts.installKindOverride ?? detectInstallKind();
|
|
5338
|
+
const spawn = opts.spawn ?? defaultSpawn;
|
|
5339
|
+
switch (detected.kind) {
|
|
5340
|
+
case "npm-global": {
|
|
5341
|
+
if (opts.dryRun) {
|
|
5342
|
+
log(`(dry-run) Would run: npm install -g ${PKG_NAME}@latest`);
|
|
5343
|
+
log(`(dry-run) Would re-run: hivemind install --skip-auth`);
|
|
5344
|
+
return 0;
|
|
5345
|
+
}
|
|
5346
|
+
log(`Upgrading via npm\u2026`);
|
|
5347
|
+
try {
|
|
5348
|
+
spawn("npm", ["install", "-g", `${PKG_NAME}@latest`]);
|
|
5349
|
+
} catch (e) {
|
|
5350
|
+
warn(`npm install failed: ${e.message}`);
|
|
5351
|
+
warn(`Try running it manually: npm install -g ${PKG_NAME}@latest`);
|
|
5352
|
+
return 1;
|
|
5353
|
+
}
|
|
5354
|
+
log(``);
|
|
5355
|
+
log(`Refreshing agent bundles\u2026`);
|
|
5356
|
+
try {
|
|
5357
|
+
spawn("hivemind", ["install", "--skip-auth"]);
|
|
5358
|
+
} catch (e) {
|
|
5359
|
+
warn(`Agent refresh failed: ${e.message}`);
|
|
5360
|
+
warn(`Run manually: hivemind install`);
|
|
5361
|
+
return 1;
|
|
5362
|
+
}
|
|
5363
|
+
log(``);
|
|
5364
|
+
log(`Updated to ${latest}.`);
|
|
5365
|
+
return 0;
|
|
5366
|
+
}
|
|
5367
|
+
case "npx": {
|
|
5368
|
+
if (opts.dryRun) {
|
|
5369
|
+
log(`(dry-run) Would print npx-pin instructions (no persistent install to upgrade).`);
|
|
5370
|
+
return 0;
|
|
5371
|
+
}
|
|
5372
|
+
log(`You ran hivemind via npx, which does not have a persistent global install.`);
|
|
5373
|
+
log(`To use the new version, re-run with the explicit version pin:`);
|
|
5374
|
+
log(``);
|
|
5375
|
+
log(` npx ${PKG_NAME}@${latest} install`);
|
|
5376
|
+
log(``);
|
|
5377
|
+
log(`Or install globally so future updates are one command:`);
|
|
5378
|
+
log(``);
|
|
5379
|
+
log(` npm install -g ${PKG_NAME}@latest`);
|
|
5380
|
+
return 0;
|
|
5381
|
+
}
|
|
5382
|
+
case "local-dev": {
|
|
5383
|
+
if (opts.dryRun) {
|
|
5384
|
+
log(`(dry-run) Would refuse: running from a local dev checkout (${detected.installDir}).`);
|
|
5385
|
+
return 0;
|
|
5386
|
+
}
|
|
5387
|
+
warn(`hivemind is running from a local development checkout (${detected.installDir}).`);
|
|
5388
|
+
warn(`Update via your dev workflow (git pull + npm install + npm run build),`);
|
|
5389
|
+
warn(`not via 'hivemind update'.`);
|
|
5390
|
+
return 1;
|
|
5391
|
+
}
|
|
5392
|
+
case "unknown":
|
|
5393
|
+
default: {
|
|
5394
|
+
if (opts.dryRun) {
|
|
5395
|
+
log(`(dry-run) Would refuse: install kind unknown (${detected.installDir}).`);
|
|
5396
|
+
return 0;
|
|
5397
|
+
}
|
|
5398
|
+
warn(`Could not determine how hivemind was installed (path: ${detected.installDir}).`);
|
|
5399
|
+
warn(`Update manually: npm install -g ${PKG_NAME}@latest`);
|
|
5400
|
+
return 1;
|
|
5401
|
+
}
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5404
|
+
|
|
4215
5405
|
// dist/src/cli/index.js
|
|
4216
5406
|
var AUTH_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
4217
5407
|
"whoami",
|
|
@@ -4229,10 +5419,14 @@ var USAGE = `
|
|
|
4229
5419
|
hivemind \u2014 one brain for every agent on your team
|
|
4230
5420
|
|
|
4231
5421
|
Usage:
|
|
4232
|
-
hivemind install
|
|
5422
|
+
hivemind install [--only <platforms>] [--skip-auth]
|
|
4233
5423
|
Auto-detect assistants on this machine and install hivemind into each.
|
|
4234
5424
|
--only takes a comma-separated list: ${allPlatformIds().join(",")}
|
|
4235
5425
|
|
|
5426
|
+
hivemind uninstall [--only <platforms>]
|
|
5427
|
+
Auto-detect installed assistants and remove hivemind from each.
|
|
5428
|
+
--only takes the same list to scope the removal.
|
|
5429
|
+
|
|
4236
5430
|
hivemind claude install | uninstall
|
|
4237
5431
|
hivemind codex install | uninstall
|
|
4238
5432
|
hivemind claw install | uninstall
|
|
@@ -4243,6 +5437,34 @@ Usage:
|
|
|
4243
5437
|
|
|
4244
5438
|
hivemind login Run device-flow login (open browser).
|
|
4245
5439
|
hivemind status Show which assistants are wired up.
|
|
5440
|
+
hivemind update [--dry-run]
|
|
5441
|
+
Check npm for a newer @deeplake/hivemind, upgrade the CLI, and refresh
|
|
5442
|
+
every detected agent bundle. Single command for all agents.
|
|
5443
|
+
|
|
5444
|
+
Semantic search (embeddings):
|
|
5445
|
+
hivemind embeddings install Download @huggingface/transformers
|
|
5446
|
+
once (~600 MB) into a shared dir
|
|
5447
|
+
and symlink every detected agent
|
|
5448
|
+
plugin to it. Idempotent.
|
|
5449
|
+
hivemind embeddings uninstall [--prune] Remove the per-agent symlinks.
|
|
5450
|
+
--prune also deletes the shared dir.
|
|
5451
|
+
hivemind embeddings status Show shared-deps + per-agent state.
|
|
5452
|
+
|
|
5453
|
+
Add --with-embeddings to "hivemind install" (or "hivemind <agent> install")
|
|
5454
|
+
to run "embeddings install" automatically after installing the agent(s).
|
|
5455
|
+
|
|
5456
|
+
Skill management (mine + share reusable Claude skills across the org):
|
|
5457
|
+
hivemind skilify Show scope, team, install, and per-project state.
|
|
5458
|
+
hivemind skilify pull [skill-name] Sync skills from the org table to local FS.
|
|
5459
|
+
Options: --user <email>, --users a,b,c,
|
|
5460
|
+
--all-users, --to <project|global>,
|
|
5461
|
+
--dry-run, --force.
|
|
5462
|
+
hivemind skilify scope <me|team|org> Set the sharing scope for newly mined skills.
|
|
5463
|
+
hivemind skilify install <project|global> Set where new skills are written.
|
|
5464
|
+
hivemind skilify promote <name> Move a project skill to the global location.
|
|
5465
|
+
hivemind skilify team add <username> Add a username to the team list.
|
|
5466
|
+
hivemind skilify team remove <username> Remove a username from the team list.
|
|
5467
|
+
hivemind skilify team list List current team members.
|
|
4246
5468
|
|
|
4247
5469
|
Account / org / workspace:
|
|
4248
5470
|
hivemind whoami Show current user, org, workspace.
|
|
@@ -4250,7 +5472,8 @@ Account / org / workspace:
|
|
|
4250
5472
|
hivemind org list List organizations.
|
|
4251
5473
|
hivemind org switch <name-or-id> Switch active organization.
|
|
4252
5474
|
hivemind workspaces List workspaces in current org.
|
|
4253
|
-
hivemind workspace
|
|
5475
|
+
hivemind workspace list List workspaces (alias of 'workspaces').
|
|
5476
|
+
hivemind workspace switch <name-or-id> Switch active workspace.
|
|
4254
5477
|
hivemind members List org members.
|
|
4255
5478
|
hivemind invite <email> <ADMIN|WRITE|READ> Invite a teammate.
|
|
4256
5479
|
hivemind remove <user-id> Remove a member.
|
|
@@ -4284,6 +5507,7 @@ function hasFlag(args, flag) {
|
|
|
4284
5507
|
async function runInstallAll(args) {
|
|
4285
5508
|
const only = parseOnly(args);
|
|
4286
5509
|
const skipAuth = hasFlag(args, "--skip-auth");
|
|
5510
|
+
const withEmbeddings = hasFlag(args, "--with-embeddings");
|
|
4287
5511
|
const targets = only ?? detectPlatforms().map((p) => p.id);
|
|
4288
5512
|
if (targets.length === 0) {
|
|
4289
5513
|
log("No supported assistants detected.");
|
|
@@ -4302,6 +5526,10 @@ async function runInstallAll(args) {
|
|
|
4302
5526
|
}
|
|
4303
5527
|
for (const id of targets)
|
|
4304
5528
|
runSingleInstall(id);
|
|
5529
|
+
if (withEmbeddings) {
|
|
5530
|
+
log("");
|
|
5531
|
+
enableEmbeddings();
|
|
5532
|
+
}
|
|
4305
5533
|
await maybeShowOrgChoice();
|
|
4306
5534
|
log("");
|
|
4307
5535
|
log("Done. Restart each assistant to activate hooks.");
|
|
@@ -4383,6 +5611,31 @@ async function main() {
|
|
|
4383
5611
|
runStatus();
|
|
4384
5612
|
return;
|
|
4385
5613
|
}
|
|
5614
|
+
if (cmd === "update") {
|
|
5615
|
+
const code = await runUpdate({ dryRun: hasFlag(args.slice(1), "--dry-run") });
|
|
5616
|
+
process.exit(code);
|
|
5617
|
+
}
|
|
5618
|
+
if (cmd === "skilify") {
|
|
5619
|
+
runSkilifyCommand(args.slice(1));
|
|
5620
|
+
return;
|
|
5621
|
+
}
|
|
5622
|
+
if (cmd === "embeddings") {
|
|
5623
|
+
const sub = args[1];
|
|
5624
|
+
if (sub === "install" || sub === "enable") {
|
|
5625
|
+
enableEmbeddings();
|
|
5626
|
+
return;
|
|
5627
|
+
}
|
|
5628
|
+
if (sub === "uninstall" || sub === "disable") {
|
|
5629
|
+
disableEmbeddings({ prune: hasFlag(args.slice(2), "--prune") });
|
|
5630
|
+
return;
|
|
5631
|
+
}
|
|
5632
|
+
if (sub === "status") {
|
|
5633
|
+
statusEmbeddings();
|
|
5634
|
+
return;
|
|
5635
|
+
}
|
|
5636
|
+
warn("Usage: hivemind embeddings install | uninstall [--prune] | status");
|
|
5637
|
+
process.exit(1);
|
|
5638
|
+
}
|
|
4386
5639
|
if (AUTH_SUBCOMMANDS.has(cmd)) {
|
|
4387
5640
|
await runAuthCommand(args);
|
|
4388
5641
|
return;
|
|
@@ -4390,12 +5643,16 @@ async function main() {
|
|
|
4390
5643
|
const platformCmds = ["claude", "codex", "claw", "cursor", "hermes", "pi"];
|
|
4391
5644
|
if (platformCmds.includes(cmd)) {
|
|
4392
5645
|
const sub = args[1];
|
|
4393
|
-
if (sub === "install")
|
|
5646
|
+
if (sub === "install") {
|
|
4394
5647
|
runSingleInstall(cmd);
|
|
4395
|
-
|
|
5648
|
+
if (hasFlag(args.slice(2), "--with-embeddings")) {
|
|
5649
|
+
log("");
|
|
5650
|
+
enableEmbeddings();
|
|
5651
|
+
}
|
|
5652
|
+
} else if (sub === "uninstall")
|
|
4396
5653
|
runSingleUninstall(cmd);
|
|
4397
5654
|
else {
|
|
4398
|
-
warn(`Usage: hivemind ${cmd} install|uninstall`);
|
|
5655
|
+
warn(`Usage: hivemind ${cmd} install [--with-embeddings] | uninstall`);
|
|
4399
5656
|
process.exit(1);
|
|
4400
5657
|
}
|
|
4401
5658
|
return;
|