@deeplake/hivemind 0.7.21 → 0.7.23
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 +1 -1
- package/bundle/cli.js +66 -15
- package/codex/bundle/capture.js +60 -12
- package/codex/bundle/commands/auth-login.js +4 -2
- package/codex/bundle/pre-tool-use.js +4 -2
- package/codex/bundle/session-start-setup.js +52 -5
- package/codex/bundle/session-start.js +62 -11
- package/codex/bundle/shell/deeplake-shell.js +4 -2
- package/codex/bundle/skillify-worker.js +118 -29
- package/codex/bundle/stop.js +100 -52
- package/codex/bundle/wiki-worker.js +7 -3
- package/cursor/bundle/capture.js +87 -39
- package/cursor/bundle/commands/auth-login.js +4 -2
- package/cursor/bundle/pre-tool-use.js +4 -2
- package/cursor/bundle/session-end.js +78 -34
- package/cursor/bundle/session-start.js +67 -15
- package/cursor/bundle/shell/deeplake-shell.js +4 -2
- package/cursor/bundle/skillify-worker.js +118 -29
- package/cursor/bundle/wiki-worker.js +7 -3
- package/hermes/bundle/capture.js +87 -39
- package/hermes/bundle/commands/auth-login.js +4 -2
- package/hermes/bundle/pre-tool-use.js +4 -2
- package/hermes/bundle/session-end.js +78 -34
- package/hermes/bundle/session-start.js +67 -15
- package/hermes/bundle/shell/deeplake-shell.js +4 -2
- package/hermes/bundle/skillify-worker.js +118 -29
- package/hermes/bundle/wiki-worker.js +7 -3
- package/mcp/bundle/server.js +4 -2
- package/openclaw/dist/index.js +8 -6
- package/openclaw/dist/skillify-worker.js +118 -29
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/openclaw/skills/SKILL.md +1 -1
- package/package.json +1 -1
- package/pi/extension-source/hivemind.ts +18 -3
|
@@ -112,7 +112,7 @@ function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
|
|
|
112
112
|
// dist/src/hooks/cursor/spawn-wiki-worker.js
|
|
113
113
|
import { spawn, execSync } from "node:child_process";
|
|
114
114
|
import { fileURLToPath } from "node:url";
|
|
115
|
-
import { dirname, join as
|
|
115
|
+
import { dirname as dirname2, join as join6 } from "node:path";
|
|
116
116
|
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "node:fs";
|
|
117
117
|
import { homedir as homedir4, tmpdir } from "node:os";
|
|
118
118
|
|
|
@@ -134,9 +134,51 @@ function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") {
|
|
|
134
134
|
};
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
// dist/src/utils/version-check.js
|
|
138
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
139
|
+
import { dirname, join as join5 } from "node:path";
|
|
140
|
+
function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
141
|
+
try {
|
|
142
|
+
const pluginJson = join5(bundleDir, "..", pluginManifestDir, "plugin.json");
|
|
143
|
+
const plugin = JSON.parse(readFileSync3(pluginJson, "utf-8"));
|
|
144
|
+
if (plugin.version)
|
|
145
|
+
return plugin.version;
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const stamp = readFileSync3(join5(bundleDir, "..", ".hivemind_version"), "utf-8").trim();
|
|
150
|
+
if (stamp)
|
|
151
|
+
return stamp;
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
const HIVEMIND_PKG_NAMES = /* @__PURE__ */ new Set([
|
|
155
|
+
"hivemind",
|
|
156
|
+
"hivemind-codex",
|
|
157
|
+
"@deeplake/hivemind",
|
|
158
|
+
"@deeplake/hivemind-codex",
|
|
159
|
+
"@activeloop/hivemind",
|
|
160
|
+
"@activeloop/hivemind-codex"
|
|
161
|
+
]);
|
|
162
|
+
let dir = bundleDir;
|
|
163
|
+
for (let i = 0; i < 5; i++) {
|
|
164
|
+
const candidate = join5(dir, "package.json");
|
|
165
|
+
try {
|
|
166
|
+
const pkg = JSON.parse(readFileSync3(candidate, "utf-8"));
|
|
167
|
+
if (HIVEMIND_PKG_NAMES.has(pkg.name) && pkg.version)
|
|
168
|
+
return pkg.version;
|
|
169
|
+
} catch {
|
|
170
|
+
}
|
|
171
|
+
const parent = dirname(dir);
|
|
172
|
+
if (parent === dir)
|
|
173
|
+
break;
|
|
174
|
+
dir = parent;
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
137
179
|
// dist/src/hooks/cursor/spawn-wiki-worker.js
|
|
138
180
|
var HOME = homedir4();
|
|
139
|
-
var wikiLogger = makeWikiLogger(
|
|
181
|
+
var wikiLogger = makeWikiLogger(join6(HOME, ".cursor", "hooks"));
|
|
140
182
|
var WIKI_LOG = wikiLogger.path;
|
|
141
183
|
var WIKI_PROMPT_TEMPLATE = `You are building a personal wiki from a coding session. Your goal is to extract every piece of knowledge \u2014 entities, decisions, relationships, and facts \u2014 into a structured, searchable wiki entry.
|
|
142
184
|
|
|
@@ -198,9 +240,10 @@ function findCursorBin() {
|
|
|
198
240
|
function spawnCursorWikiWorker(opts) {
|
|
199
241
|
const { config, sessionId, cwd, bundleDir, reason } = opts;
|
|
200
242
|
const projectName = cwd.split("/").pop() || "unknown";
|
|
201
|
-
const tmpDir =
|
|
243
|
+
const tmpDir = join6(tmpdir(), `deeplake-wiki-${sessionId}-${Date.now()}`);
|
|
202
244
|
mkdirSync3(tmpDir, { recursive: true });
|
|
203
|
-
const
|
|
245
|
+
const pluginVersion = getInstalledVersion(bundleDir, ".claude-plugin") ?? "";
|
|
246
|
+
const configFile = join6(tmpDir, "config.json");
|
|
204
247
|
writeFileSync2(configFile, JSON.stringify({
|
|
205
248
|
apiUrl: config.apiUrl,
|
|
206
249
|
token: config.token,
|
|
@@ -211,15 +254,16 @@ function spawnCursorWikiWorker(opts) {
|
|
|
211
254
|
sessionId,
|
|
212
255
|
userName: config.userName,
|
|
213
256
|
project: projectName,
|
|
257
|
+
pluginVersion,
|
|
214
258
|
tmpDir,
|
|
215
259
|
cursorBin: findCursorBin(),
|
|
216
260
|
cursorModel: process.env.HIVEMIND_CURSOR_MODEL ?? "auto",
|
|
217
261
|
wikiLog: WIKI_LOG,
|
|
218
|
-
hooksDir:
|
|
262
|
+
hooksDir: join6(HOME, ".cursor", "hooks"),
|
|
219
263
|
promptTemplate: WIKI_PROMPT_TEMPLATE
|
|
220
264
|
}));
|
|
221
265
|
wikiLog(`${reason}: spawning summary worker for ${sessionId}`);
|
|
222
|
-
const workerPath =
|
|
266
|
+
const workerPath = join6(bundleDir, "wiki-worker.js");
|
|
223
267
|
spawn("nohup", ["node", workerPath, configFile], {
|
|
224
268
|
detached: true,
|
|
225
269
|
stdio: ["ignore", "ignore", "ignore"]
|
|
@@ -227,13 +271,13 @@ function spawnCursorWikiWorker(opts) {
|
|
|
227
271
|
wikiLog(`${reason}: spawned summary worker for ${sessionId}`);
|
|
228
272
|
}
|
|
229
273
|
function bundleDirFromImportMeta(importMetaUrl) {
|
|
230
|
-
return
|
|
274
|
+
return dirname2(fileURLToPath(importMetaUrl));
|
|
231
275
|
}
|
|
232
276
|
|
|
233
277
|
// dist/src/skillify/spawn-skillify-worker.js
|
|
234
278
|
import { spawn as spawn2 } from "node:child_process";
|
|
235
279
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
236
|
-
import { dirname as
|
|
280
|
+
import { dirname as dirname3, join as join8 } from "node:path";
|
|
237
281
|
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, appendFileSync as appendFileSync3, chmodSync } from "node:fs";
|
|
238
282
|
import { homedir as homedir6, tmpdir as tmpdir2 } from "node:os";
|
|
239
283
|
|
|
@@ -241,7 +285,7 @@ import { homedir as homedir6, tmpdir as tmpdir2 } from "node:os";
|
|
|
241
285
|
import { execFileSync } from "node:child_process";
|
|
242
286
|
import { existsSync as existsSync3 } from "node:fs";
|
|
243
287
|
import { homedir as homedir5 } from "node:os";
|
|
244
|
-
import { join as
|
|
288
|
+
import { join as join7 } from "node:path";
|
|
245
289
|
function findAgentBin(agent) {
|
|
246
290
|
const which = (name) => {
|
|
247
291
|
try {
|
|
@@ -256,24 +300,24 @@ function findAgentBin(agent) {
|
|
|
256
300
|
};
|
|
257
301
|
switch (agent) {
|
|
258
302
|
case "claude_code":
|
|
259
|
-
return which("claude") ??
|
|
303
|
+
return which("claude") ?? join7(homedir5(), ".claude", "local", "claude");
|
|
260
304
|
case "codex":
|
|
261
305
|
return which("codex") ?? "/usr/local/bin/codex";
|
|
262
306
|
case "cursor":
|
|
263
307
|
return which("cursor-agent") ?? "/usr/local/bin/cursor-agent";
|
|
264
308
|
case "hermes":
|
|
265
|
-
return which("hermes") ??
|
|
309
|
+
return which("hermes") ?? join7(homedir5(), ".local", "bin", "hermes");
|
|
266
310
|
case "pi":
|
|
267
|
-
return which("pi") ??
|
|
311
|
+
return which("pi") ?? join7(homedir5(), ".local", "bin", "pi");
|
|
268
312
|
}
|
|
269
313
|
}
|
|
270
314
|
|
|
271
315
|
// dist/src/skillify/spawn-skillify-worker.js
|
|
272
316
|
var HOME2 = homedir6();
|
|
273
|
-
var SKILLIFY_LOG =
|
|
317
|
+
var SKILLIFY_LOG = join8(HOME2, ".claude", "hooks", "skillify.log");
|
|
274
318
|
function skillifyLog(msg) {
|
|
275
319
|
try {
|
|
276
|
-
mkdirSync4(
|
|
320
|
+
mkdirSync4(dirname3(SKILLIFY_LOG), { recursive: true });
|
|
277
321
|
appendFileSync3(SKILLIFY_LOG, `[${utcTimestamp()}] ${msg}
|
|
278
322
|
`);
|
|
279
323
|
} catch {
|
|
@@ -281,10 +325,10 @@ function skillifyLog(msg) {
|
|
|
281
325
|
}
|
|
282
326
|
function spawnSkillifyWorker(opts) {
|
|
283
327
|
const { config, cwd, projectKey, project, bundleDir, agent, scopeConfig, currentSessionId, reason } = opts;
|
|
284
|
-
const tmpDir =
|
|
328
|
+
const tmpDir = join8(tmpdir2(), `deeplake-skillify-${projectKey}-${Date.now()}`);
|
|
285
329
|
mkdirSync4(tmpDir, { recursive: true, mode: 448 });
|
|
286
330
|
const gateBin = findAgentBin(agent);
|
|
287
|
-
const configFile =
|
|
331
|
+
const configFile = join8(tmpDir, "config.json");
|
|
288
332
|
writeFileSync3(configFile, JSON.stringify({
|
|
289
333
|
apiUrl: config.apiUrl,
|
|
290
334
|
token: config.token,
|
|
@@ -315,7 +359,7 @@ function spawnSkillifyWorker(opts) {
|
|
|
315
359
|
} catch {
|
|
316
360
|
}
|
|
317
361
|
skillifyLog(`${reason}: spawning skillify worker for project=${project} key=${projectKey}`);
|
|
318
|
-
const workerPath =
|
|
362
|
+
const workerPath = join8(bundleDir, "skillify-worker.js");
|
|
319
363
|
spawn2("nohup", ["node", workerPath, configFile], {
|
|
320
364
|
detached: true,
|
|
321
365
|
stdio: ["ignore", "ignore", "ignore"]
|
|
@@ -324,25 +368,25 @@ function spawnSkillifyWorker(opts) {
|
|
|
324
368
|
}
|
|
325
369
|
|
|
326
370
|
// dist/src/skillify/state.js
|
|
327
|
-
import { readFileSync as
|
|
371
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, writeSync as writeSync2, mkdirSync as mkdirSync5, renameSync as renameSync3, existsSync as existsSync5, unlinkSync as unlinkSync2, openSync as openSync2, closeSync as closeSync2 } from "node:fs";
|
|
328
372
|
import { execSync as execSync2 } from "node:child_process";
|
|
329
373
|
import { homedir as homedir8 } from "node:os";
|
|
330
374
|
import { createHash } from "node:crypto";
|
|
331
|
-
import { join as
|
|
375
|
+
import { join as join10, basename } from "node:path";
|
|
332
376
|
|
|
333
377
|
// dist/src/skillify/legacy-migration.js
|
|
334
378
|
import { existsSync as existsSync4, renameSync as renameSync2 } from "node:fs";
|
|
335
379
|
import { homedir as homedir7 } from "node:os";
|
|
336
|
-
import { join as
|
|
380
|
+
import { join as join9 } from "node:path";
|
|
337
381
|
var dlog2 = (msg) => log("skillify-migrate", msg);
|
|
338
382
|
var attempted = false;
|
|
339
383
|
function migrateLegacyStateDir() {
|
|
340
384
|
if (attempted)
|
|
341
385
|
return;
|
|
342
386
|
attempted = true;
|
|
343
|
-
const root =
|
|
344
|
-
const legacy =
|
|
345
|
-
const current =
|
|
387
|
+
const root = join9(homedir7(), ".deeplake", "state");
|
|
388
|
+
const legacy = join9(root, "skilify");
|
|
389
|
+
const current = join9(root, "skillify");
|
|
346
390
|
if (!existsSync4(legacy))
|
|
347
391
|
return;
|
|
348
392
|
if (existsSync4(current))
|
|
@@ -362,17 +406,17 @@ function migrateLegacyStateDir() {
|
|
|
362
406
|
|
|
363
407
|
// dist/src/skillify/state.js
|
|
364
408
|
var dlog3 = (msg) => log("skillify-state", msg);
|
|
365
|
-
var STATE_DIR2 =
|
|
409
|
+
var STATE_DIR2 = join10(homedir8(), ".deeplake", "state", "skillify");
|
|
366
410
|
var YIELD_BUF2 = new Int32Array(new SharedArrayBuffer(4));
|
|
367
411
|
var TRIGGER_THRESHOLD = (() => {
|
|
368
412
|
const n = Number(process.env.HIVEMIND_SKILLIFY_EVERY_N_TURNS ?? "");
|
|
369
413
|
return Number.isInteger(n) && n > 0 ? n : 20;
|
|
370
414
|
})();
|
|
371
415
|
function statePath(projectKey) {
|
|
372
|
-
return
|
|
416
|
+
return join10(STATE_DIR2, `${projectKey}.json`);
|
|
373
417
|
}
|
|
374
418
|
function lockPath2(projectKey) {
|
|
375
|
-
return
|
|
419
|
+
return join10(STATE_DIR2, `${projectKey}.lock`);
|
|
376
420
|
}
|
|
377
421
|
var DEFAULT_PORTS = {
|
|
378
422
|
http: "80",
|
|
@@ -421,7 +465,7 @@ function readState(projectKey) {
|
|
|
421
465
|
if (!existsSync5(p))
|
|
422
466
|
return null;
|
|
423
467
|
try {
|
|
424
|
-
return JSON.parse(
|
|
468
|
+
return JSON.parse(readFileSync4(p, "utf-8"));
|
|
425
469
|
} catch {
|
|
426
470
|
return null;
|
|
427
471
|
}
|
|
@@ -483,7 +527,7 @@ function tryAcquireWorkerLock(projectKey, maxAgeMs = 10 * 60 * 1e3) {
|
|
|
483
527
|
const p = lockPath2(projectKey);
|
|
484
528
|
if (existsSync5(p)) {
|
|
485
529
|
try {
|
|
486
|
-
const ageMs = Date.now() - parseInt(
|
|
530
|
+
const ageMs = Date.now() - parseInt(readFileSync4(p, "utf-8"), 10);
|
|
487
531
|
if (Number.isFinite(ageMs) && ageMs < maxAgeMs)
|
|
488
532
|
return false;
|
|
489
533
|
} catch (readErr) {
|
|
@@ -517,19 +561,19 @@ function releaseWorkerLock(projectKey) {
|
|
|
517
561
|
}
|
|
518
562
|
|
|
519
563
|
// dist/src/skillify/scope-config.js
|
|
520
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as
|
|
564
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
521
565
|
import { homedir as homedir9 } from "node:os";
|
|
522
|
-
import { join as
|
|
523
|
-
var STATE_DIR3 =
|
|
524
|
-
var CONFIG_PATH =
|
|
566
|
+
import { join as join11 } from "node:path";
|
|
567
|
+
var STATE_DIR3 = join11(homedir9(), ".deeplake", "state", "skillify");
|
|
568
|
+
var CONFIG_PATH = join11(STATE_DIR3, "config.json");
|
|
525
569
|
var DEFAULT = { scope: "me", team: [], install: "project" };
|
|
526
570
|
function loadScopeConfig() {
|
|
527
571
|
migrateLegacyStateDir();
|
|
528
572
|
if (!existsSync6(CONFIG_PATH))
|
|
529
573
|
return DEFAULT;
|
|
530
574
|
try {
|
|
531
|
-
const raw = JSON.parse(
|
|
532
|
-
const scope = raw.scope === "team"
|
|
575
|
+
const raw = JSON.parse(readFileSync5(CONFIG_PATH, "utf-8"));
|
|
576
|
+
const scope = raw.scope === "team" ? "team" : raw.scope === "org" ? "team" : "me";
|
|
533
577
|
const team = Array.isArray(raw.team) ? raw.team.filter((s) => typeof s === "string") : [];
|
|
534
578
|
const install = raw.install === "global" ? "global" : "project";
|
|
535
579
|
return { scope, team, install };
|
|
@@ -512,13 +512,14 @@ var DeeplakeApi = class {
|
|
|
512
512
|
const tables = await this.listTables();
|
|
513
513
|
if (!tables.includes(tbl)) {
|
|
514
514
|
log2(`table "${tbl}" not found, creating`);
|
|
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);
|
|
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 '', plugin_version TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, tbl);
|
|
516
516
|
log2(`table "${tbl}" created`);
|
|
517
517
|
if (!tables.includes(tbl))
|
|
518
518
|
this._tablesCache = [...tables, tbl];
|
|
519
519
|
}
|
|
520
520
|
await this.ensureEmbeddingColumn(tbl, SUMMARY_EMBEDDING_COL);
|
|
521
521
|
await this.ensureColumn(tbl, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
522
|
+
await this.ensureColumn(tbl, "plugin_version", "TEXT NOT NULL DEFAULT ''");
|
|
522
523
|
}
|
|
523
524
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
524
525
|
async ensureSessionsTable(name) {
|
|
@@ -526,13 +527,14 @@ var DeeplakeApi = class {
|
|
|
526
527
|
const tables = await this.listTables();
|
|
527
528
|
if (!tables.includes(safe)) {
|
|
528
529
|
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
|
+
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 '', plugin_version TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
|
|
530
531
|
log2(`table "${safe}" created`);
|
|
531
532
|
if (!tables.includes(safe))
|
|
532
533
|
this._tablesCache = [...tables, safe];
|
|
533
534
|
}
|
|
534
535
|
await this.ensureEmbeddingColumn(safe, MESSAGE_EMBEDDING_COL);
|
|
535
536
|
await this.ensureColumn(safe, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
537
|
+
await this.ensureColumn(safe, "plugin_version", "TEXT NOT NULL DEFAULT ''");
|
|
536
538
|
await this.ensureLookupIndex(safe, "path_creation_date", `("path", "creation_date")`);
|
|
537
539
|
}
|
|
538
540
|
/**
|
|
@@ -703,18 +705,25 @@ function parseFrontmatter(text) {
|
|
|
703
705
|
const head = text.slice(4, end).trim();
|
|
704
706
|
const body = text.slice(end + 4).replace(/^\r?\n/, "");
|
|
705
707
|
const fm = { source_sessions: [] };
|
|
706
|
-
let
|
|
708
|
+
let arrayKey = null;
|
|
707
709
|
for (const raw of head.split(/\r?\n/)) {
|
|
708
|
-
if (
|
|
710
|
+
if (arrayKey) {
|
|
709
711
|
const m2 = raw.match(/^\s+-\s+(.+)$/);
|
|
710
712
|
if (m2) {
|
|
711
|
-
fm
|
|
713
|
+
const arr = fm[arrayKey] ?? [];
|
|
714
|
+
arr.push(m2[1].trim());
|
|
715
|
+
fm[arrayKey] = arr;
|
|
712
716
|
continue;
|
|
713
717
|
}
|
|
714
|
-
|
|
718
|
+
arrayKey = null;
|
|
715
719
|
}
|
|
716
720
|
if (raw.startsWith("source_sessions:")) {
|
|
717
|
-
|
|
721
|
+
arrayKey = "source_sessions";
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
if (raw.startsWith("contributors:")) {
|
|
725
|
+
arrayKey = "contributors";
|
|
726
|
+
fm.contributors = [];
|
|
718
727
|
continue;
|
|
719
728
|
}
|
|
720
729
|
const m = raw.match(/^([a-zA-Z_]+):\s*(.*)$/);
|
|
@@ -929,11 +938,19 @@ function buildPullSql(args) {
|
|
|
929
938
|
where.push(`name = '${esc(args.skillName)}'`);
|
|
930
939
|
}
|
|
931
940
|
const whereClause = where.length > 0 ? ` WHERE ${where.join(" AND ")}` : "";
|
|
932
|
-
|
|
941
|
+
const contributorsCol = args.includeContributors === false ? "" : "contributors, ";
|
|
942
|
+
return `SELECT name, project, project_key, body, version, source_agent, scope, author, ${contributorsCol}description, trigger_text, source_sessions, install, created_at, updated_at FROM "${args.tableName}"${whereClause} ORDER BY project_key ASC, name ASC, version DESC`;
|
|
943
|
+
}
|
|
944
|
+
function isMissingContributorsColumnError(message) {
|
|
945
|
+
if (!message)
|
|
946
|
+
return false;
|
|
947
|
+
return /contributors.*(?:does not exist|not found|unknown)/i.test(message) || /(?:does not exist|unknown column).*contributors/i.test(message);
|
|
933
948
|
}
|
|
934
949
|
function isMissingTableError(message) {
|
|
935
950
|
if (!message)
|
|
936
951
|
return false;
|
|
952
|
+
if (/\bcolumn\b/i.test(message))
|
|
953
|
+
return false;
|
|
937
954
|
return /Table does not exist|relation .* does not exist|no such table/i.test(message);
|
|
938
955
|
}
|
|
939
956
|
function resolvePullDestination(install, cwd) {
|
|
@@ -1029,11 +1046,16 @@ function selectLatestPerName(rows) {
|
|
|
1029
1046
|
}
|
|
1030
1047
|
function renderSkillFile(row) {
|
|
1031
1048
|
const sources = parseSourceSessions(row.source_sessions);
|
|
1049
|
+
const author = typeof row.author === "string" && row.author.length > 0 ? row.author : void 0;
|
|
1050
|
+
const contributors = parseContributors(row.contributors);
|
|
1051
|
+
const renderedContributors = contributors.length > 0 ? contributors : author ? [author] : [];
|
|
1032
1052
|
const fm = {
|
|
1033
1053
|
name: String(row.name ?? ""),
|
|
1034
1054
|
description: String(row.description ?? ""),
|
|
1035
1055
|
trigger: typeof row.trigger_text === "string" && row.trigger_text.length > 0 ? String(row.trigger_text) : void 0,
|
|
1056
|
+
author,
|
|
1036
1057
|
source_sessions: sources,
|
|
1058
|
+
contributors: renderedContributors,
|
|
1037
1059
|
version: Number(row.version ?? 1),
|
|
1038
1060
|
created_by_agent: String(row.source_agent ?? "unknown"),
|
|
1039
1061
|
created_at: String(row.created_at ?? (/* @__PURE__ */ new Date()).toISOString()),
|
|
@@ -1058,15 +1080,35 @@ function parseSourceSessions(v) {
|
|
|
1058
1080
|
}
|
|
1059
1081
|
return [];
|
|
1060
1082
|
}
|
|
1083
|
+
function parseContributors(v) {
|
|
1084
|
+
if (Array.isArray(v))
|
|
1085
|
+
return v.map(String);
|
|
1086
|
+
if (typeof v === "string") {
|
|
1087
|
+
try {
|
|
1088
|
+
const parsed = JSON.parse(v);
|
|
1089
|
+
if (Array.isArray(parsed))
|
|
1090
|
+
return parsed.map(String);
|
|
1091
|
+
} catch {
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
return [];
|
|
1095
|
+
}
|
|
1061
1096
|
function renderFrontmatter(fm) {
|
|
1062
1097
|
const lines = ["---"];
|
|
1063
1098
|
lines.push(`name: ${fm.name}`);
|
|
1064
1099
|
lines.push(`description: ${JSON.stringify(fm.description)}`);
|
|
1065
1100
|
if (fm.trigger)
|
|
1066
1101
|
lines.push(`trigger: ${JSON.stringify(fm.trigger)}`);
|
|
1102
|
+
if (fm.author)
|
|
1103
|
+
lines.push(`author: ${fm.author}`);
|
|
1067
1104
|
lines.push(`source_sessions:`);
|
|
1068
1105
|
for (const s of fm.source_sessions)
|
|
1069
1106
|
lines.push(` - ${s}`);
|
|
1107
|
+
if (fm.contributors && fm.contributors.length > 0) {
|
|
1108
|
+
lines.push(`contributors:`);
|
|
1109
|
+
for (const c of fm.contributors)
|
|
1110
|
+
lines.push(` - ${c}`);
|
|
1111
|
+
}
|
|
1070
1112
|
lines.push(`version: ${fm.version}`);
|
|
1071
1113
|
lines.push(`created_by_agent: ${fm.created_by_agent}`);
|
|
1072
1114
|
lines.push(`created_at: ${fm.created_at}`);
|
|
@@ -1106,10 +1148,19 @@ async function runPull(opts) {
|
|
|
1106
1148
|
try {
|
|
1107
1149
|
rows = await opts.query(sql);
|
|
1108
1150
|
} catch (e) {
|
|
1109
|
-
if (isMissingTableError(e?.message))
|
|
1151
|
+
if (isMissingTableError(e?.message)) {
|
|
1110
1152
|
rows = [];
|
|
1111
|
-
else
|
|
1153
|
+
} else if (isMissingContributorsColumnError(e?.message)) {
|
|
1154
|
+
const legacySql = buildPullSql({
|
|
1155
|
+
tableName: opts.tableName,
|
|
1156
|
+
users: opts.users,
|
|
1157
|
+
skillName: opts.skillName,
|
|
1158
|
+
includeContributors: false
|
|
1159
|
+
});
|
|
1160
|
+
rows = await opts.query(legacySql);
|
|
1161
|
+
} else {
|
|
1112
1162
|
throw e;
|
|
1163
|
+
}
|
|
1113
1164
|
}
|
|
1114
1165
|
const latest = selectLatestPerName(rows);
|
|
1115
1166
|
const root = resolvePullDestination(opts.install, opts.cwd);
|
|
@@ -1312,7 +1363,7 @@ SKILLS (skillify) \u2014 mine + share reusable skills across the org:
|
|
|
1312
1363
|
- hivemind skillify unpull --user <email> \u2014 remove only that author's pulls
|
|
1313
1364
|
- hivemind skillify unpull --not-mine \u2014 remove all pulls except your own
|
|
1314
1365
|
- hivemind skillify unpull --dry-run \u2014 preview without touching disk
|
|
1315
|
-
- hivemind skillify scope <me|team
|
|
1366
|
+
- hivemind skillify scope <me|team> \u2014 sharing scope for new skills
|
|
1316
1367
|
- hivemind skillify install <project|global> \u2014 default install location
|
|
1317
1368
|
- hivemind skillify team add|remove|list <name> \u2014 manage team list`;
|
|
1318
1369
|
function resolveSessionId(input) {
|
|
@@ -1325,7 +1376,7 @@ function resolveCwd(input) {
|
|
|
1325
1376
|
}
|
|
1326
1377
|
return process.cwd();
|
|
1327
1378
|
}
|
|
1328
|
-
async function createPlaceholder(api, table, sessionId, cwd, userName, orgName, workspaceId) {
|
|
1379
|
+
async function createPlaceholder(api, table, sessionId, cwd, userName, orgName, workspaceId, pluginVersion) {
|
|
1329
1380
|
const summaryPath = `/summaries/${userName}/${sessionId}.md`;
|
|
1330
1381
|
const existing = await api.query(`SELECT path FROM "${table}" WHERE path = '${sqlStr(summaryPath)}' LIMIT 1`);
|
|
1331
1382
|
if (existing.length > 0)
|
|
@@ -1342,7 +1393,7 @@ async function createPlaceholder(api, table, sessionId, cwd, userName, orgName,
|
|
|
1342
1393
|
""
|
|
1343
1394
|
].join("\n");
|
|
1344
1395
|
const filename = `${sessionId}.md`;
|
|
1345
|
-
await api.query(`INSERT INTO "${table}" (id, path, filename, summary, author, mime_type, size_bytes, project, description, agent, creation_date, last_update_date) VALUES ('${crypto.randomUUID()}', '${sqlStr(summaryPath)}', '${sqlStr(filename)}', E'${sqlStr(content)}', '${sqlStr(userName)}', 'text/markdown', ${Buffer.byteLength(content, "utf-8")}, '${sqlStr(projectName)}', 'in progress', 'cursor', '${now}', '${now}')`);
|
|
1396
|
+
await api.query(`INSERT INTO "${table}" (id, path, filename, summary, author, mime_type, size_bytes, project, description, agent, plugin_version, creation_date, last_update_date) VALUES ('${crypto.randomUUID()}', '${sqlStr(summaryPath)}', '${sqlStr(filename)}', E'${sqlStr(content)}', '${sqlStr(userName)}', 'text/markdown', ${Buffer.byteLength(content, "utf-8")}, '${sqlStr(projectName)}', 'in progress', 'cursor', '${sqlStr(pluginVersion)}', '${now}', '${now}')`);
|
|
1346
1397
|
}
|
|
1347
1398
|
async function main() {
|
|
1348
1399
|
if (process.env.HIVEMIND_WIKI_WORKER === "1")
|
|
@@ -1357,6 +1408,8 @@ async function main() {
|
|
|
1357
1408
|
log5(`credentials loaded: org=${creds.orgName ?? creds.orgId}`);
|
|
1358
1409
|
}
|
|
1359
1410
|
await autoUpdate(creds, { agent: "cursor" });
|
|
1411
|
+
const current = getInstalledVersion(__bundleDir, ".claude-plugin");
|
|
1412
|
+
const pluginVersion = current ?? "";
|
|
1360
1413
|
const captureEnabled = process.env.HIVEMIND_CAPTURE !== "false";
|
|
1361
1414
|
if (creds?.token && captureEnabled) {
|
|
1362
1415
|
try {
|
|
@@ -1367,7 +1420,7 @@ async function main() {
|
|
|
1367
1420
|
const api = new DeeplakeApi(config.token, config.apiUrl, config.orgId, config.workspaceId, table);
|
|
1368
1421
|
await api.ensureTable();
|
|
1369
1422
|
await api.ensureSessionsTable(sessionsTable);
|
|
1370
|
-
await createPlaceholder(api, table, sessionId, cwd, config.userName, config.orgName, config.workspaceId);
|
|
1423
|
+
await createPlaceholder(api, table, sessionId, cwd, config.userName, config.orgName, config.workspaceId, pluginVersion);
|
|
1371
1424
|
log5("placeholder created");
|
|
1372
1425
|
}
|
|
1373
1426
|
} catch (e) {
|
|
@@ -1377,7 +1430,6 @@ async function main() {
|
|
|
1377
1430
|
const pullResult = await autoPullSkills();
|
|
1378
1431
|
log5(`autopull: pulled=${pullResult.pulled} skipped=${pullResult.skipped}`);
|
|
1379
1432
|
let versionNotice = "";
|
|
1380
|
-
const current = getInstalledVersion(__bundleDir, ".claude-plugin");
|
|
1381
1433
|
if (current)
|
|
1382
1434
|
versionNotice = `
|
|
1383
1435
|
Hivemind v${current}`;
|
|
@@ -67201,13 +67201,14 @@ var DeeplakeApi = class {
|
|
|
67201
67201
|
const tables = await this.listTables();
|
|
67202
67202
|
if (!tables.includes(tbl)) {
|
|
67203
67203
|
log2(`table "${tbl}" not found, creating`);
|
|
67204
|
-
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);
|
|
67204
|
+
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 '', plugin_version TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, tbl);
|
|
67205
67205
|
log2(`table "${tbl}" created`);
|
|
67206
67206
|
if (!tables.includes(tbl))
|
|
67207
67207
|
this._tablesCache = [...tables, tbl];
|
|
67208
67208
|
}
|
|
67209
67209
|
await this.ensureEmbeddingColumn(tbl, SUMMARY_EMBEDDING_COL);
|
|
67210
67210
|
await this.ensureColumn(tbl, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
67211
|
+
await this.ensureColumn(tbl, "plugin_version", "TEXT NOT NULL DEFAULT ''");
|
|
67211
67212
|
}
|
|
67212
67213
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
67213
67214
|
async ensureSessionsTable(name) {
|
|
@@ -67215,13 +67216,14 @@ var DeeplakeApi = class {
|
|
|
67215
67216
|
const tables = await this.listTables();
|
|
67216
67217
|
if (!tables.includes(safe)) {
|
|
67217
67218
|
log2(`table "${safe}" not found, creating`);
|
|
67218
|
-
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);
|
|
67219
|
+
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 '', plugin_version TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
|
|
67219
67220
|
log2(`table "${safe}" created`);
|
|
67220
67221
|
if (!tables.includes(safe))
|
|
67221
67222
|
this._tablesCache = [...tables, safe];
|
|
67222
67223
|
}
|
|
67223
67224
|
await this.ensureEmbeddingColumn(safe, MESSAGE_EMBEDDING_COL);
|
|
67224
67225
|
await this.ensureColumn(safe, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
67226
|
+
await this.ensureColumn(safe, "plugin_version", "TEXT NOT NULL DEFAULT ''");
|
|
67225
67227
|
await this.ensureLookupIndex(safe, "path_creation_date", `("path", "creation_date")`);
|
|
67226
67228
|
}
|
|
67227
67229
|
/**
|