@deeplake/hivemind 0.7.4 → 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 +97 -0
- package/bundle/cli.js +820 -20
- package/codex/bundle/capture.js +40 -10
- package/codex/bundle/commands/auth-login.js +84 -18
- package/codex/bundle/pre-tool-use.js +41 -11
- package/codex/bundle/session-start-setup.js +40 -10
- package/codex/bundle/session-start.js +27 -3
- package/codex/bundle/shell/deeplake-shell.js +41 -11
- package/codex/bundle/skilify-worker.js +907 -0
- package/codex/bundle/stop.js +373 -51
- package/cursor/bundle/capture.js +354 -13
- package/cursor/bundle/commands/auth-login.js +84 -18
- package/cursor/bundle/pre-tool-use.js +40 -10
- package/cursor/bundle/session-end.js +303 -6
- package/cursor/bundle/session-start.js +68 -14
- package/cursor/bundle/shell/deeplake-shell.js +41 -11
- package/cursor/bundle/skilify-worker.js +907 -0
- package/hermes/bundle/capture.js +354 -13
- package/hermes/bundle/commands/auth-login.js +84 -18
- package/hermes/bundle/pre-tool-use.js +40 -10
- package/hermes/bundle/session-end.js +305 -7
- package/hermes/bundle/session-start.js +68 -14
- package/hermes/bundle/shell/deeplake-shell.js +41 -11
- package/hermes/bundle/skilify-worker.js +907 -0
- package/mcp/bundle/server.js +41 -11
- package/openclaw/dist/chunks/{config-G23NI5TV.js → config-ZLH6JFJS.js} +1 -0
- package/openclaw/dist/index.js +185 -16
- 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 +6 -1
- package/pi/extension-source/hivemind.ts +130 -1
package/bundle/cli.js
CHANGED
|
@@ -177,6 +177,7 @@ function pluginAlreadyInstalled() {
|
|
|
177
177
|
return false;
|
|
178
178
|
return r.stdout.includes(PLUGIN_KEY);
|
|
179
179
|
}
|
|
180
|
+
var PLUGIN_SCOPES = ["user", "project", "local", "managed"];
|
|
180
181
|
function installClaude() {
|
|
181
182
|
requireClaudeCli();
|
|
182
183
|
if (!marketplaceAlreadyAdded()) {
|
|
@@ -190,9 +191,15 @@ function installClaude() {
|
|
|
190
191
|
if (!inst.ok) {
|
|
191
192
|
throw new Error(`Failed to install hivemind plugin: ${inst.stderr.slice(0, 200)}`);
|
|
192
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}`);
|
|
193
201
|
}
|
|
194
202
|
runClaude(["plugin", "enable", PLUGIN_KEY]);
|
|
195
|
-
log(` Claude Code installed via marketplace ${MARKETPLACE_SOURCE}`);
|
|
196
203
|
}
|
|
197
204
|
function uninstallClaude() {
|
|
198
205
|
try {
|
|
@@ -3345,6 +3352,7 @@ var EXTENSION_PATH = join8(EXTENSIONS_DIR, "hivemind.ts");
|
|
|
3345
3352
|
var VERSION_DIR = join8(PI_AGENT_DIR, ".hivemind");
|
|
3346
3353
|
var WIKI_WORKER_DIR = join8(PI_AGENT_DIR, "hivemind");
|
|
3347
3354
|
var WIKI_WORKER_PATH = join8(WIKI_WORKER_DIR, "wiki-worker.js");
|
|
3355
|
+
var SKILIFY_WORKER_PATH = join8(WIKI_WORKER_DIR, "skilify-worker.js");
|
|
3348
3356
|
var HIVEMIND_BLOCK_START = "<!-- BEGIN hivemind-memory -->";
|
|
3349
3357
|
var HIVEMIND_BLOCK_END = "<!-- END hivemind-memory -->";
|
|
3350
3358
|
var HIVEMIND_BLOCK_BODY = `${HIVEMIND_BLOCK_START}
|
|
@@ -3429,6 +3437,11 @@ function installPi() {
|
|
|
3429
3437
|
ensureDir(WIKI_WORKER_DIR);
|
|
3430
3438
|
copyFileSync2(srcWorker, WIKI_WORKER_PATH);
|
|
3431
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
|
+
}
|
|
3432
3445
|
ensureDir(VERSION_DIR);
|
|
3433
3446
|
writeVersionStamp(VERSION_DIR, getVersion());
|
|
3434
3447
|
log(` pi AGENTS.md updated -> ${AGENTS_MD}`);
|
|
@@ -3436,6 +3449,9 @@ function installPi() {
|
|
|
3436
3449
|
if (existsSync7(WIKI_WORKER_PATH)) {
|
|
3437
3450
|
log(` pi wiki-worker installed -> ${WIKI_WORKER_PATH}`);
|
|
3438
3451
|
}
|
|
3452
|
+
if (existsSync7(SKILIFY_WORKER_PATH)) {
|
|
3453
|
+
log(` pi skilify-worker installed -> ${SKILIFY_WORKER_PATH}`);
|
|
3454
|
+
}
|
|
3439
3455
|
}
|
|
3440
3456
|
function uninstallPi() {
|
|
3441
3457
|
if (existsSync7(LEGACY_SKILL_DIR)) {
|
|
@@ -3921,6 +3937,7 @@ function loadConfig() {
|
|
|
3921
3937
|
apiUrl: process.env.HIVEMIND_API_URL ?? creds?.apiUrl ?? "https://api.deeplake.ai",
|
|
3922
3938
|
tableName: process.env.HIVEMIND_TABLE ?? "memory",
|
|
3923
3939
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
3940
|
+
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
3924
3941
|
memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join12(home, ".deeplake", "memory")
|
|
3925
3942
|
};
|
|
3926
3943
|
}
|
|
@@ -3945,6 +3962,12 @@ function log2(tag, msg) {
|
|
|
3945
3962
|
function sqlStr(value) {
|
|
3946
3963
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
3947
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
|
+
}
|
|
3948
3971
|
|
|
3949
3972
|
// dist/src/embeddings/columns.js
|
|
3950
3973
|
var SUMMARY_EMBEDDING_COL = "summary_embedding";
|
|
@@ -4308,7 +4331,7 @@ var DeeplakeApi = class {
|
|
|
4308
4331
|
}
|
|
4309
4332
|
/** Create the memory table if it doesn't already exist. Migrate columns on existing tables. */
|
|
4310
4333
|
async ensureTable(name) {
|
|
4311
|
-
const tbl = name ?? this.tableName;
|
|
4334
|
+
const tbl = sqlIdent(name ?? this.tableName);
|
|
4312
4335
|
const tables = await this.listTables();
|
|
4313
4336
|
if (!tables.includes(tbl)) {
|
|
4314
4337
|
log3(`table "${tbl}" not found, creating`);
|
|
@@ -4322,17 +4345,40 @@ var DeeplakeApi = class {
|
|
|
4322
4345
|
}
|
|
4323
4346
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
4324
4347
|
async ensureSessionsTable(name) {
|
|
4348
|
+
const safe = sqlIdent(name);
|
|
4325
4349
|
const tables = await this.listTables();
|
|
4326
|
-
if (!tables.includes(
|
|
4327
|
-
log3(`table "${
|
|
4328
|
-
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${
|
|
4329
|
-
log3(`table "${
|
|
4330
|
-
if (!tables.includes(
|
|
4331
|
-
this._tablesCache = [...tables,
|
|
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];
|
|
4332
4356
|
}
|
|
4333
|
-
await this.ensureEmbeddingColumn(
|
|
4334
|
-
await this.ensureColumn(
|
|
4335
|
-
await this.ensureLookupIndex(
|
|
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);
|
|
4373
|
+
const tables = await this.listTables();
|
|
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];
|
|
4380
|
+
}
|
|
4381
|
+
await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
|
|
4336
4382
|
}
|
|
4337
4383
|
};
|
|
4338
4384
|
|
|
@@ -4512,8 +4558,24 @@ async function runAuthCommand(args) {
|
|
|
4512
4558
|
console.log(`Org not found: ${target}`);
|
|
4513
4559
|
process.exit(1);
|
|
4514
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);
|
|
4515
4565
|
await switchOrg(match.id, match.name);
|
|
4516
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
|
+
}
|
|
4517
4579
|
} else {
|
|
4518
4580
|
console.log("Usage: org list | org switch <name-or-id>");
|
|
4519
4581
|
}
|
|
@@ -4525,7 +4587,7 @@ async function runAuthCommand(args) {
|
|
|
4525
4587
|
process.exit(1);
|
|
4526
4588
|
}
|
|
4527
4589
|
const ws = await listWorkspaces(creds.token, apiUrl, creds.orgId);
|
|
4528
|
-
ws.forEach((w) => console.log(
|
|
4590
|
+
ws.forEach((w) => console.log(w.name || w.id));
|
|
4529
4591
|
break;
|
|
4530
4592
|
}
|
|
4531
4593
|
case "workspace": {
|
|
@@ -4533,14 +4595,34 @@ async function runAuthCommand(args) {
|
|
|
4533
4595
|
console.log("Not logged in.");
|
|
4534
4596
|
process.exit(1);
|
|
4535
4597
|
}
|
|
4536
|
-
const
|
|
4537
|
-
if (
|
|
4538
|
-
|
|
4539
|
-
|
|
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;
|
|
4540
4603
|
}
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
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);
|
|
4544
4626
|
}
|
|
4545
4627
|
case "invite": {
|
|
4546
4628
|
if (!creds) {
|
|
@@ -4627,6 +4709,699 @@ if (process.argv[1] && process.argv[1].endsWith("auth-login.js")) {
|
|
|
4627
4709
|
});
|
|
4628
4710
|
}
|
|
4629
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
|
+
|
|
4630
5405
|
// dist/src/cli/index.js
|
|
4631
5406
|
var AUTH_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
4632
5407
|
"whoami",
|
|
@@ -4662,6 +5437,9 @@ Usage:
|
|
|
4662
5437
|
|
|
4663
5438
|
hivemind login Run device-flow login (open browser).
|
|
4664
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.
|
|
4665
5443
|
|
|
4666
5444
|
Semantic search (embeddings):
|
|
4667
5445
|
hivemind embeddings install Download @huggingface/transformers
|
|
@@ -4675,13 +5453,27 @@ Semantic search (embeddings):
|
|
|
4675
5453
|
Add --with-embeddings to "hivemind install" (or "hivemind <agent> install")
|
|
4676
5454
|
to run "embeddings install" automatically after installing the agent(s).
|
|
4677
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.
|
|
5468
|
+
|
|
4678
5469
|
Account / org / workspace:
|
|
4679
5470
|
hivemind whoami Show current user, org, workspace.
|
|
4680
5471
|
hivemind logout Remove credentials.
|
|
4681
5472
|
hivemind org list List organizations.
|
|
4682
5473
|
hivemind org switch <name-or-id> Switch active organization.
|
|
4683
5474
|
hivemind workspaces List workspaces in current org.
|
|
4684
|
-
hivemind workspace
|
|
5475
|
+
hivemind workspace list List workspaces (alias of 'workspaces').
|
|
5476
|
+
hivemind workspace switch <name-or-id> Switch active workspace.
|
|
4685
5477
|
hivemind members List org members.
|
|
4686
5478
|
hivemind invite <email> <ADMIN|WRITE|READ> Invite a teammate.
|
|
4687
5479
|
hivemind remove <user-id> Remove a member.
|
|
@@ -4819,6 +5611,14 @@ async function main() {
|
|
|
4819
5611
|
runStatus();
|
|
4820
5612
|
return;
|
|
4821
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
|
+
}
|
|
4822
5622
|
if (cmd === "embeddings") {
|
|
4823
5623
|
const sub = args[1];
|
|
4824
5624
|
if (sub === "install" || sub === "enable") {
|