@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
|
@@ -1,35 +1,100 @@
|
|
|
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 existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
21
|
+
import { join as join4 } from "node:path";
|
|
22
|
+
import { tmpdir } from "node:os";
|
|
23
|
+
function getIndexMarkerDir() {
|
|
24
|
+
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join4(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 join4(getIndexMarkerDir(), `${markerKey}.json`);
|
|
29
|
+
}
|
|
30
|
+
function hasFreshIndexMarker(markerPath) {
|
|
31
|
+
if (!existsSync2(markerPath))
|
|
32
|
+
return false;
|
|
33
|
+
try {
|
|
34
|
+
const raw = JSON.parse(readFileSync3(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
|
+
mkdirSync2(getIndexMarkerDir(), { recursive: true });
|
|
45
|
+
writeFileSync2(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/hooks/cursor/session-start.js
|
|
4
56
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { dirname as dirname2
|
|
57
|
+
import { dirname as dirname2 } from "node:path";
|
|
6
58
|
|
|
7
59
|
// dist/src/commands/auth.js
|
|
8
|
-
import {
|
|
60
|
+
import { execSync } from "node:child_process";
|
|
61
|
+
|
|
62
|
+
// dist/src/utils/client-header.js
|
|
63
|
+
var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client";
|
|
64
|
+
function deeplakeClientValue() {
|
|
65
|
+
return "hivemind";
|
|
66
|
+
}
|
|
67
|
+
function deeplakeClientHeader() {
|
|
68
|
+
return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// dist/src/commands/auth-creds.js
|
|
72
|
+
import { readFileSync, writeFileSync, mkdirSync, unlinkSync } from "node:fs";
|
|
9
73
|
import { join } from "node:path";
|
|
10
74
|
import { homedir } from "node:os";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
75
|
+
function configDir() {
|
|
76
|
+
return join(homedir(), ".deeplake");
|
|
77
|
+
}
|
|
78
|
+
function credsPath() {
|
|
79
|
+
return join(configDir(), "credentials.json");
|
|
80
|
+
}
|
|
14
81
|
function loadCredentials() {
|
|
15
|
-
if (!existsSync(CREDS_PATH))
|
|
16
|
-
return null;
|
|
17
82
|
try {
|
|
18
|
-
return JSON.parse(readFileSync(
|
|
83
|
+
return JSON.parse(readFileSync(credsPath(), "utf-8"));
|
|
19
84
|
} catch {
|
|
20
85
|
return null;
|
|
21
86
|
}
|
|
22
87
|
}
|
|
23
88
|
|
|
24
89
|
// dist/src/config.js
|
|
25
|
-
import { readFileSync as readFileSync2, existsSync
|
|
90
|
+
import { readFileSync as readFileSync2, existsSync } from "node:fs";
|
|
26
91
|
import { join as join2 } from "node:path";
|
|
27
92
|
import { homedir as homedir2, userInfo } from "node:os";
|
|
28
93
|
function loadConfig() {
|
|
29
94
|
const home = homedir2();
|
|
30
95
|
const credPath = join2(home, ".deeplake", "credentials.json");
|
|
31
96
|
let creds = null;
|
|
32
|
-
if (
|
|
97
|
+
if (existsSync(credPath)) {
|
|
33
98
|
try {
|
|
34
99
|
creds = JSON.parse(readFileSync2(credPath, "utf-8"));
|
|
35
100
|
} catch {
|
|
@@ -49,15 +114,13 @@ function loadConfig() {
|
|
|
49
114
|
apiUrl: process.env.HIVEMIND_API_URL ?? creds?.apiUrl ?? "https://api.deeplake.ai",
|
|
50
115
|
tableName: process.env.HIVEMIND_TABLE ?? "memory",
|
|
51
116
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
117
|
+
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
52
118
|
memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join2(home, ".deeplake", "memory")
|
|
53
119
|
};
|
|
54
120
|
}
|
|
55
121
|
|
|
56
122
|
// dist/src/deeplake-api.js
|
|
57
123
|
import { randomUUID } from "node:crypto";
|
|
58
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
59
|
-
import { join as join4 } from "node:path";
|
|
60
|
-
import { tmpdir } from "node:os";
|
|
61
124
|
|
|
62
125
|
// dist/src/utils/debug.js
|
|
63
126
|
import { appendFileSync } from "node:fs";
|
|
@@ -76,8 +139,24 @@ function log(tag, msg) {
|
|
|
76
139
|
function sqlStr(value) {
|
|
77
140
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
78
141
|
}
|
|
142
|
+
function sqlIdent(name) {
|
|
143
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
|
|
144
|
+
throw new Error(`Invalid SQL identifier: ${JSON.stringify(name)}`);
|
|
145
|
+
}
|
|
146
|
+
return name;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// dist/src/embeddings/columns.js
|
|
150
|
+
var SUMMARY_EMBEDDING_COL = "summary_embedding";
|
|
151
|
+
var MESSAGE_EMBEDDING_COL = "message_embedding";
|
|
79
152
|
|
|
80
153
|
// dist/src/deeplake-api.js
|
|
154
|
+
var indexMarkerStorePromise = null;
|
|
155
|
+
function getIndexMarkerStore() {
|
|
156
|
+
if (!indexMarkerStorePromise)
|
|
157
|
+
indexMarkerStorePromise = Promise.resolve().then(() => (init_index_marker_store(), index_marker_store_exports));
|
|
158
|
+
return indexMarkerStorePromise;
|
|
159
|
+
}
|
|
81
160
|
var log2 = (msg) => log("sdk", msg);
|
|
82
161
|
function summarizeSql(sql, maxLen = 220) {
|
|
83
162
|
const compact = sql.replace(/\s+/g, " ").trim();
|
|
@@ -97,7 +176,6 @@ var MAX_RETRIES = 3;
|
|
|
97
176
|
var BASE_DELAY_MS = 500;
|
|
98
177
|
var MAX_CONCURRENCY = 5;
|
|
99
178
|
var QUERY_TIMEOUT_MS = Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
|
|
100
|
-
var INDEX_MARKER_TTL_MS = Number(process.env.HIVEMIND_INDEX_MARKER_TTL_MS ?? 6 * 60 * 6e4);
|
|
101
179
|
function sleep(ms) {
|
|
102
180
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
103
181
|
}
|
|
@@ -117,9 +195,6 @@ function isTransientHtml403(text) {
|
|
|
117
195
|
const body = text.toLowerCase();
|
|
118
196
|
return body.includes("<html") || body.includes("403 forbidden") || body.includes("cloudflare") || body.includes("nginx");
|
|
119
197
|
}
|
|
120
|
-
function getIndexMarkerDir() {
|
|
121
|
-
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join4(tmpdir(), "hivemind-deeplake-indexes");
|
|
122
|
-
}
|
|
123
198
|
var Semaphore = class {
|
|
124
199
|
max;
|
|
125
200
|
waiting = [];
|
|
@@ -188,7 +263,8 @@ var DeeplakeApi = class {
|
|
|
188
263
|
headers: {
|
|
189
264
|
Authorization: `Bearer ${this.token}`,
|
|
190
265
|
"Content-Type": "application/json",
|
|
191
|
-
"X-Activeloop-Org-Id": this.orgId
|
|
266
|
+
"X-Activeloop-Org-Id": this.orgId,
|
|
267
|
+
...deeplakeClientHeader()
|
|
192
268
|
},
|
|
193
269
|
signal,
|
|
194
270
|
body: JSON.stringify({ query: sql })
|
|
@@ -215,7 +291,8 @@ var DeeplakeApi = class {
|
|
|
215
291
|
}
|
|
216
292
|
const text = await resp.text().catch(() => "");
|
|
217
293
|
const retryable403 = isSessionInsertQuery(sql) && (resp.status === 401 || resp.status === 403 && (text.length === 0 || isTransientHtml403(text)));
|
|
218
|
-
|
|
294
|
+
const alreadyExists = resp.status === 500 && isDuplicateIndexError(text);
|
|
295
|
+
if (!alreadyExists && attempt < MAX_RETRIES && (RETRYABLE_CODES.has(resp.status) || retryable403)) {
|
|
219
296
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
220
297
|
log2(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
|
|
221
298
|
await sleep(delay);
|
|
@@ -249,7 +326,7 @@ var DeeplakeApi = class {
|
|
|
249
326
|
const lud = row.lastUpdateDate ?? ts;
|
|
250
327
|
const exists = await this.query(`SELECT path FROM "${this.tableName}" WHERE path = '${sqlStr(row.path)}' LIMIT 1`);
|
|
251
328
|
if (exists.length > 0) {
|
|
252
|
-
let setClauses = `summary = E'${sqlStr(row.contentText)}', mime_type = '${sqlStr(row.mimeType)}', size_bytes = ${row.sizeBytes}, last_update_date = '${lud}'`;
|
|
329
|
+
let setClauses = `summary = E'${sqlStr(row.contentText)}', ${SUMMARY_EMBEDDING_COL} = NULL, mime_type = '${sqlStr(row.mimeType)}', size_bytes = ${row.sizeBytes}, last_update_date = '${lud}'`;
|
|
253
330
|
if (row.project !== void 0)
|
|
254
331
|
setClauses += `, project = '${sqlStr(row.project)}'`;
|
|
255
332
|
if (row.description !== void 0)
|
|
@@ -257,8 +334,8 @@ var DeeplakeApi = class {
|
|
|
257
334
|
await this.query(`UPDATE "${this.tableName}" SET ${setClauses} WHERE path = '${sqlStr(row.path)}'`);
|
|
258
335
|
} else {
|
|
259
336
|
const id = randomUUID();
|
|
260
|
-
let cols =
|
|
261
|
-
let vals = `'${id}', '${sqlStr(row.path)}', '${sqlStr(row.filename)}', E'${sqlStr(row.contentText)}', '${sqlStr(row.mimeType)}', ${row.sizeBytes}, '${cd}', '${lud}'`;
|
|
337
|
+
let cols = `id, path, filename, summary, ${SUMMARY_EMBEDDING_COL}, mime_type, size_bytes, creation_date, last_update_date`;
|
|
338
|
+
let vals = `'${id}', '${sqlStr(row.path)}', '${sqlStr(row.filename)}', E'${sqlStr(row.contentText)}', NULL, '${sqlStr(row.mimeType)}', ${row.sizeBytes}, '${cd}', '${lud}'`;
|
|
262
339
|
if (row.project !== void 0) {
|
|
263
340
|
cols += ", project";
|
|
264
341
|
vals += `, '${sqlStr(row.project)}'`;
|
|
@@ -283,48 +360,83 @@ var DeeplakeApi = class {
|
|
|
283
360
|
buildLookupIndexName(table, suffix) {
|
|
284
361
|
return `idx_${table}_${suffix}`.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
285
362
|
}
|
|
286
|
-
getLookupIndexMarkerPath(table, suffix) {
|
|
287
|
-
const markerKey = [
|
|
288
|
-
this.workspaceId,
|
|
289
|
-
this.orgId,
|
|
290
|
-
table,
|
|
291
|
-
suffix
|
|
292
|
-
].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
293
|
-
return join4(getIndexMarkerDir(), `${markerKey}.json`);
|
|
294
|
-
}
|
|
295
|
-
hasFreshLookupIndexMarker(table, suffix) {
|
|
296
|
-
const markerPath = this.getLookupIndexMarkerPath(table, suffix);
|
|
297
|
-
if (!existsSync3(markerPath))
|
|
298
|
-
return false;
|
|
299
|
-
try {
|
|
300
|
-
const raw = JSON.parse(readFileSync3(markerPath, "utf-8"));
|
|
301
|
-
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
302
|
-
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
303
|
-
return false;
|
|
304
|
-
return true;
|
|
305
|
-
} catch {
|
|
306
|
-
return false;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
markLookupIndexReady(table, suffix) {
|
|
310
|
-
mkdirSync2(getIndexMarkerDir(), { recursive: true });
|
|
311
|
-
writeFileSync2(this.getLookupIndexMarkerPath(table, suffix), JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
312
|
-
}
|
|
313
363
|
async ensureLookupIndex(table, suffix, columnsSql) {
|
|
314
|
-
|
|
364
|
+
const markers = await getIndexMarkerStore();
|
|
365
|
+
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, suffix);
|
|
366
|
+
if (markers.hasFreshIndexMarker(markerPath))
|
|
315
367
|
return;
|
|
316
368
|
const indexName = this.buildLookupIndexName(table, suffix);
|
|
317
369
|
try {
|
|
318
370
|
await this.query(`CREATE INDEX IF NOT EXISTS "${indexName}" ON "${table}" ${columnsSql}`);
|
|
319
|
-
|
|
371
|
+
markers.writeIndexMarker(markerPath);
|
|
320
372
|
} catch (e) {
|
|
321
373
|
if (isDuplicateIndexError(e)) {
|
|
322
|
-
|
|
374
|
+
markers.writeIndexMarker(markerPath);
|
|
323
375
|
return;
|
|
324
376
|
}
|
|
325
377
|
log2(`index "${indexName}" skipped: ${e.message}`);
|
|
326
378
|
}
|
|
327
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* Ensure a vector column exists on the given table.
|
|
382
|
+
*
|
|
383
|
+
* The previous implementation always issued `ALTER TABLE ADD COLUMN IF NOT
|
|
384
|
+
* EXISTS …` on every SessionStart. On a long-running workspace that's
|
|
385
|
+
* already migrated, every call returns 500 "Column already exists" — noisy
|
|
386
|
+
* in the log and a wasted round-trip. Worse, the very first call after the
|
|
387
|
+
* column is genuinely added triggers Deeplake's post-ALTER `vector::at`
|
|
388
|
+
* window (~30s) during which subsequent INSERTs fail; minimising the
|
|
389
|
+
* number of ALTER calls minimises exposure to that window.
|
|
390
|
+
*
|
|
391
|
+
* New flow:
|
|
392
|
+
* 1. Check the local marker file (mirrors ensureLookupIndex). If fresh,
|
|
393
|
+
* return — zero network calls.
|
|
394
|
+
* 2. SELECT 1 FROM information_schema.columns WHERE table_name = T AND
|
|
395
|
+
* column_name = C. Read-only, idempotent, can't tickle the post-ALTER
|
|
396
|
+
* bug. If the column is present → mark + return.
|
|
397
|
+
* 3. Only if step 2 says the column is missing, fall back to ALTER ADD
|
|
398
|
+
* COLUMN IF NOT EXISTS. Mark on success, also mark if Deeplake reports
|
|
399
|
+
* "already exists" (race: another client added it between our SELECT
|
|
400
|
+
* and ALTER).
|
|
401
|
+
*
|
|
402
|
+
* Marker uses the same dir / TTL as ensureLookupIndex so both schema
|
|
403
|
+
* caches share an opt-out (HIVEMIND_INDEX_MARKER_DIR) and a TTL knob.
|
|
404
|
+
*/
|
|
405
|
+
async ensureEmbeddingColumn(table, column) {
|
|
406
|
+
await this.ensureColumn(table, column, "FLOAT4[]");
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Generic marker-gated column migration. Same SELECT-then-ALTER flow as
|
|
410
|
+
* ensureEmbeddingColumn, parameterized by SQL type so it can patch up any
|
|
411
|
+
* column that was added to the schema after the table was originally
|
|
412
|
+
* created. Used today for `summary_embedding`, `message_embedding`, and
|
|
413
|
+
* the `agent` column (added 2026-04-11) — the latter has no fallback if
|
|
414
|
+
* a user upgraded over a pre-2026-04-11 table, so every INSERT fails
|
|
415
|
+
* with `column "agent" does not exist`.
|
|
416
|
+
*/
|
|
417
|
+
async ensureColumn(table, column, sqlType) {
|
|
418
|
+
const markers = await getIndexMarkerStore();
|
|
419
|
+
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, `col_${column}`);
|
|
420
|
+
if (markers.hasFreshIndexMarker(markerPath))
|
|
421
|
+
return;
|
|
422
|
+
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`;
|
|
423
|
+
const rows = await this.query(colCheck);
|
|
424
|
+
if (rows.length > 0) {
|
|
425
|
+
markers.writeIndexMarker(markerPath);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
await this.query(`ALTER TABLE "${table}" ADD COLUMN ${column} ${sqlType}`);
|
|
430
|
+
} catch (e) {
|
|
431
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
432
|
+
if (!/already exists/i.test(msg))
|
|
433
|
+
throw e;
|
|
434
|
+
const recheck = await this.query(colCheck);
|
|
435
|
+
if (recheck.length === 0)
|
|
436
|
+
throw e;
|
|
437
|
+
}
|
|
438
|
+
markers.writeIndexMarker(markerPath);
|
|
439
|
+
}
|
|
328
440
|
/** List all tables in the workspace (with retry). */
|
|
329
441
|
async listTables(forceRefresh = false) {
|
|
330
442
|
if (!forceRefresh && this._tablesCache)
|
|
@@ -340,7 +452,8 @@ var DeeplakeApi = class {
|
|
|
340
452
|
const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, {
|
|
341
453
|
headers: {
|
|
342
454
|
Authorization: `Bearer ${this.token}`,
|
|
343
|
-
"X-Activeloop-Org-Id": this.orgId
|
|
455
|
+
"X-Activeloop-Org-Id": this.orgId,
|
|
456
|
+
...deeplakeClientHeader()
|
|
344
457
|
}
|
|
345
458
|
});
|
|
346
459
|
if (resp.ok) {
|
|
@@ -365,29 +478,84 @@ var DeeplakeApi = class {
|
|
|
365
478
|
}
|
|
366
479
|
return { tables: [], cacheable: false };
|
|
367
480
|
}
|
|
481
|
+
/**
|
|
482
|
+
* Run a `CREATE TABLE` with an extra outer retry budget. The base
|
|
483
|
+
* `query()` already retries 3 times on fetch errors (~3.5s total), but a
|
|
484
|
+
* failed CREATE is permanent corruption — every subsequent SELECT against
|
|
485
|
+
* the missing table fails. Wrapping in an outer loop with longer backoff
|
|
486
|
+
* (2s, 5s, then 10s) gives us ~17s of reach across transient network
|
|
487
|
+
* blips before giving up. Failures still propagate; getApi() resets its
|
|
488
|
+
* cache on init failure (openclaw plugin) so the next call retries the
|
|
489
|
+
* whole init flow.
|
|
490
|
+
*/
|
|
491
|
+
async createTableWithRetry(sql, label) {
|
|
492
|
+
const OUTER_BACKOFFS_MS = [2e3, 5e3, 1e4];
|
|
493
|
+
let lastErr = null;
|
|
494
|
+
for (let attempt = 0; attempt <= OUTER_BACKOFFS_MS.length; attempt++) {
|
|
495
|
+
try {
|
|
496
|
+
await this.query(sql);
|
|
497
|
+
return;
|
|
498
|
+
} catch (err) {
|
|
499
|
+
lastErr = err;
|
|
500
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
501
|
+
log2(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
|
|
502
|
+
if (attempt < OUTER_BACKOFFS_MS.length) {
|
|
503
|
+
await sleep(OUTER_BACKOFFS_MS[attempt]);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
throw lastErr;
|
|
508
|
+
}
|
|
368
509
|
/** Create the memory table if it doesn't already exist. Migrate columns on existing tables. */
|
|
369
510
|
async ensureTable(name) {
|
|
370
|
-
const tbl = name ?? this.tableName;
|
|
511
|
+
const tbl = sqlIdent(name ?? this.tableName);
|
|
371
512
|
const tables = await this.listTables();
|
|
372
513
|
if (!tables.includes(tbl)) {
|
|
373
514
|
log2(`table "${tbl}" not found, creating`);
|
|
374
|
-
await this.
|
|
515
|
+
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);
|
|
375
516
|
log2(`table "${tbl}" created`);
|
|
376
517
|
if (!tables.includes(tbl))
|
|
377
518
|
this._tablesCache = [...tables, tbl];
|
|
378
519
|
}
|
|
520
|
+
await this.ensureEmbeddingColumn(tbl, SUMMARY_EMBEDDING_COL);
|
|
521
|
+
await this.ensureColumn(tbl, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
379
522
|
}
|
|
380
523
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
381
524
|
async ensureSessionsTable(name) {
|
|
525
|
+
const safe = sqlIdent(name);
|
|
382
526
|
const tables = await this.listTables();
|
|
383
|
-
if (!tables.includes(
|
|
384
|
-
log2(`table "${
|
|
385
|
-
await this.
|
|
386
|
-
log2(`table "${
|
|
387
|
-
if (!tables.includes(
|
|
388
|
-
this._tablesCache = [...tables,
|
|
527
|
+
if (!tables.includes(safe)) {
|
|
528
|
+
log2(`table "${safe}" not found, creating`);
|
|
529
|
+
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);
|
|
530
|
+
log2(`table "${safe}" created`);
|
|
531
|
+
if (!tables.includes(safe))
|
|
532
|
+
this._tablesCache = [...tables, safe];
|
|
389
533
|
}
|
|
390
|
-
await this.
|
|
534
|
+
await this.ensureEmbeddingColumn(safe, MESSAGE_EMBEDDING_COL);
|
|
535
|
+
await this.ensureColumn(safe, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
536
|
+
await this.ensureLookupIndex(safe, "path_creation_date", `("path", "creation_date")`);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Create the skills table.
|
|
540
|
+
*
|
|
541
|
+
* One row per skill version. Workers INSERT a fresh row on every KEEP /
|
|
542
|
+
* MERGE rather than UPDATE-ing in place, so the full version history is
|
|
543
|
+
* recoverable. Uniqueness in the *current* state is by (project_key, name)
|
|
544
|
+
* — newer rows shadow older ones at read time (ORDER BY version DESC).
|
|
545
|
+
* This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
|
|
546
|
+
* worker.
|
|
547
|
+
*/
|
|
548
|
+
async ensureSkillsTable(name) {
|
|
549
|
+
const safe = sqlIdent(name);
|
|
550
|
+
const tables = await this.listTables();
|
|
551
|
+
if (!tables.includes(safe)) {
|
|
552
|
+
log2(`table "${safe}" not found, creating`);
|
|
553
|
+
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);
|
|
554
|
+
log2(`table "${safe}" created`);
|
|
555
|
+
if (!tables.includes(safe))
|
|
556
|
+
this._tablesCache = [...tables, safe];
|
|
557
|
+
}
|
|
558
|
+
await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
|
|
391
559
|
}
|
|
392
560
|
};
|
|
393
561
|
|
|
@@ -453,13 +621,37 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
|
453
621
|
// dist/src/hooks/cursor/session-start.js
|
|
454
622
|
var log3 = (msg) => log("cursor-session-start", msg);
|
|
455
623
|
var __bundleDir = dirname2(fileURLToPath(import.meta.url));
|
|
456
|
-
var AUTH_CMD = join6(__bundleDir, "commands", "auth-login.js");
|
|
457
624
|
var context = `DEEPLAKE MEMORY: Persistent memory at ~/.deeplake/memory/ shared across sessions, users, and agents.
|
|
458
625
|
|
|
459
626
|
Structure: index.md (start here) \u2192 summaries/*.md \u2192 sessions/*.jsonl (last resort). Do NOT jump straight to JSONL.
|
|
460
627
|
Search: use \`grep\` (NOT \`rg\`/ripgrep). Example: grep -ri "keyword" ~/.deeplake/memory/
|
|
461
628
|
IMPORTANT: Only use these bash builtins to interact with ~/.deeplake/memory/: cat, ls, grep, echo, jq, head, tail, sed, awk, wc, sort, find. Do NOT use rg/ripgrep, python, python3, node, curl, or other interpreters \u2014 they may not be installed and the memory filesystem only supports the listed builtins.
|
|
462
|
-
Do NOT spawn subagents to read deeplake memory
|
|
629
|
+
Do NOT spawn subagents to read deeplake memory.
|
|
630
|
+
|
|
631
|
+
Organization management \u2014 each argument is SEPARATE (do NOT quote subcommands together):
|
|
632
|
+
- hivemind login \u2014 SSO login
|
|
633
|
+
- hivemind whoami \u2014 show current user/org
|
|
634
|
+
- hivemind org list \u2014 list organizations
|
|
635
|
+
- hivemind org switch <name-or-id> \u2014 switch organization
|
|
636
|
+
- hivemind workspaces \u2014 list workspaces
|
|
637
|
+
- hivemind workspace <id> \u2014 switch workspace
|
|
638
|
+
- hivemind invite <email> <ADMIN|WRITE|READ> \u2014 invite member (ALWAYS ask user which role before inviting)
|
|
639
|
+
- hivemind members \u2014 list members
|
|
640
|
+
- hivemind remove <user-id> \u2014 remove member
|
|
641
|
+
|
|
642
|
+
SKILLS (skilify) \u2014 mine + share reusable skills across the org:
|
|
643
|
+
- hivemind skilify \u2014 show scope/team/install + per-project state
|
|
644
|
+
- hivemind skilify pull \u2014 sync project skills from the org table
|
|
645
|
+
- hivemind skilify pull --user <email> \u2014 only that author's skills
|
|
646
|
+
- hivemind skilify pull --users a,b,c \u2014 multiple authors (CSV)
|
|
647
|
+
- hivemind skilify pull --all-users \u2014 explicit "no author filter"
|
|
648
|
+
- hivemind skilify pull --to project|global \u2014 install location
|
|
649
|
+
- hivemind skilify pull --dry-run \u2014 preview only
|
|
650
|
+
- hivemind skilify pull --force \u2014 overwrite local (creates .bak)
|
|
651
|
+
- hivemind skilify pull <skill-name> \u2014 pull only that skill (combines with --user)
|
|
652
|
+
- hivemind skilify scope <me|team|org> \u2014 sharing scope for new skills
|
|
653
|
+
- hivemind skilify install <project|global> \u2014 default install location
|
|
654
|
+
- hivemind skilify team add|remove|list <name> \u2014 manage team list`;
|
|
463
655
|
function resolveSessionId(input) {
|
|
464
656
|
return input.session_id ?? input.conversation_id ?? `cursor-${Date.now()}`;
|
|
465
657
|
}
|
|
@@ -525,7 +717,7 @@ async function main() {
|
|
|
525
717
|
Hivemind v${current}`;
|
|
526
718
|
const additionalContext = creds?.token ? `${context}
|
|
527
719
|
Logged in to Deeplake as org: ${creds.orgName ?? creds.orgId} (workspace: ${creds.workspaceId ?? "default"})${versionNotice}` : `${context}
|
|
528
|
-
Not logged in to Deeplake. Run:
|
|
720
|
+
Not logged in to Deeplake. Run: hivemind login${versionNotice}`;
|
|
529
721
|
console.log(JSON.stringify({ additional_context: additionalContext }));
|
|
530
722
|
}
|
|
531
723
|
main().catch((e) => {
|