@deeplake/hivemind 0.7.25 → 0.7.27
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/bundle/cli.js +1102 -151
- package/codex/bundle/session-start.js +223 -131
- package/codex/skills/deeplake-memory/SKILL.md +33 -0
- package/cursor/bundle/session-start.js +228 -82
- package/hermes/bundle/session-start.js +229 -82
- package/openclaw/dist/index.js +1 -1
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/package.json +1 -1
- package/pi/extension-source/hivemind.ts +157 -19
|
@@ -17,21 +17,21 @@ __export(index_marker_store_exports, {
|
|
|
17
17
|
hasFreshIndexMarker: () => hasFreshIndexMarker,
|
|
18
18
|
writeIndexMarker: () => writeIndexMarker
|
|
19
19
|
});
|
|
20
|
-
import { existsSync as
|
|
21
|
-
import { join as
|
|
20
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
21
|
+
import { join as join7 } from "node:path";
|
|
22
22
|
import { tmpdir } from "node:os";
|
|
23
23
|
function getIndexMarkerDir() {
|
|
24
|
-
return process.env.HIVEMIND_INDEX_MARKER_DIR ??
|
|
24
|
+
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join7(tmpdir(), "hivemind-deeplake-indexes");
|
|
25
25
|
}
|
|
26
26
|
function buildIndexMarkerPath(workspaceId, orgId, table, suffix) {
|
|
27
27
|
const markerKey = [workspaceId, orgId, table, suffix].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
28
|
-
return
|
|
28
|
+
return join7(getIndexMarkerDir(), `${markerKey}.json`);
|
|
29
29
|
}
|
|
30
30
|
function hasFreshIndexMarker(markerPath) {
|
|
31
|
-
if (!
|
|
31
|
+
if (!existsSync4(markerPath))
|
|
32
32
|
return false;
|
|
33
33
|
try {
|
|
34
|
-
const raw = JSON.parse(
|
|
34
|
+
const raw = JSON.parse(readFileSync5(markerPath, "utf-8"));
|
|
35
35
|
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
36
36
|
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
37
37
|
return false;
|
|
@@ -41,8 +41,8 @@ function hasFreshIndexMarker(markerPath) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
function writeIndexMarker(markerPath) {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
mkdirSync4(getIndexMarkerDir(), { recursive: true });
|
|
45
|
+
writeFileSync3(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
46
46
|
}
|
|
47
47
|
var INDEX_MARKER_TTL_MS;
|
|
48
48
|
var init_index_marker_store = __esm({
|
|
@@ -53,9 +53,9 @@ var init_index_marker_store = __esm({
|
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
// dist/src/hooks/codex/session-start.js
|
|
56
|
-
import { spawn } from "node:child_process";
|
|
57
|
-
import { fileURLToPath } from "node:url";
|
|
58
|
-
import { dirname as
|
|
56
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
57
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
58
|
+
import { dirname as dirname6, join as join13 } from "node:path";
|
|
59
59
|
|
|
60
60
|
// dist/src/commands/auth.js
|
|
61
61
|
import { execSync } from "node:child_process";
|
|
@@ -104,12 +104,139 @@ function readStdin() {
|
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
// dist/src/skillify/local-manifest.js
|
|
108
|
+
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
109
|
+
import { homedir as homedir2 } from "node:os";
|
|
110
|
+
import { dirname, join as join2 } from "node:path";
|
|
111
|
+
var LOCAL_MANIFEST_PATH = join2(homedir2(), ".claude", "hivemind", "local-mined.json");
|
|
112
|
+
var LOCAL_MINE_LOCK_PATH = join2(homedir2(), ".claude", "hivemind", "local-mined.lock");
|
|
113
|
+
function readLocalManifest(path = LOCAL_MANIFEST_PATH) {
|
|
114
|
+
if (!existsSync(path))
|
|
115
|
+
return null;
|
|
116
|
+
try {
|
|
117
|
+
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
118
|
+
} catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function countLocalManifestEntries(path = LOCAL_MANIFEST_PATH) {
|
|
123
|
+
const m = readLocalManifest(path);
|
|
124
|
+
return Array.isArray(m?.entries) ? m.entries.length : 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// dist/src/skillify/spawn-mine-local-worker.js
|
|
128
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
129
|
+
import { closeSync, existsSync as existsSync2, mkdirSync as mkdirSync3, openSync, readdirSync, statSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
130
|
+
import { homedir as homedir3 } from "node:os";
|
|
131
|
+
import { dirname as dirname2, join as join3 } from "node:path";
|
|
132
|
+
import { fileURLToPath } from "node:url";
|
|
133
|
+
var HOME = homedir3();
|
|
134
|
+
var HIVEMIND_DIR = join3(HOME, ".claude", "hivemind");
|
|
135
|
+
var LOG_PATH = join3(HOME, ".claude", "hooks", "mine-local.log");
|
|
136
|
+
var CLAUDE_PROJECTS_DIR = join3(HOME, ".claude", "projects");
|
|
137
|
+
var LOCK_STALE_MS = 15 * 60 * 1e3;
|
|
138
|
+
function findBundledCliPath() {
|
|
139
|
+
try {
|
|
140
|
+
const thisDir = dirname2(fileURLToPath(import.meta.url));
|
|
141
|
+
const cliPath = join3(thisDir, "..", "..", "bundle", "cli.js");
|
|
142
|
+
return existsSync2(cliPath) ? cliPath : null;
|
|
143
|
+
} catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function findHivemindLauncher() {
|
|
148
|
+
const bundled = findBundledCliPath();
|
|
149
|
+
if (bundled)
|
|
150
|
+
return { kind: "node-script", path: bundled };
|
|
151
|
+
try {
|
|
152
|
+
const out = execFileSync("which", ["hivemind"], {
|
|
153
|
+
encoding: "utf-8",
|
|
154
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
155
|
+
});
|
|
156
|
+
const bin = out.trim();
|
|
157
|
+
return bin ? { kind: "bin", path: bin } : null;
|
|
158
|
+
} catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function hasLocalClaudeSessions() {
|
|
163
|
+
if (!existsSync2(CLAUDE_PROJECTS_DIR))
|
|
164
|
+
return false;
|
|
165
|
+
let subdirs;
|
|
166
|
+
try {
|
|
167
|
+
subdirs = readdirSync(CLAUDE_PROJECTS_DIR);
|
|
168
|
+
} catch {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
for (const sub of subdirs) {
|
|
172
|
+
let files;
|
|
173
|
+
try {
|
|
174
|
+
files = readdirSync(join3(CLAUDE_PROJECTS_DIR, sub));
|
|
175
|
+
} catch {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (files.some((f) => f.endsWith(".jsonl")))
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
function maybeAutoMineLocal() {
|
|
184
|
+
if (existsSync2(LOCAL_MANIFEST_PATH))
|
|
185
|
+
return { triggered: false, reason: "manifest-exists" };
|
|
186
|
+
if (existsSync2(LOCAL_MINE_LOCK_PATH)) {
|
|
187
|
+
let stale = false;
|
|
188
|
+
try {
|
|
189
|
+
const stats = statSync(LOCAL_MINE_LOCK_PATH);
|
|
190
|
+
stale = Date.now() - stats.mtimeMs > LOCK_STALE_MS;
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
if (!stale)
|
|
194
|
+
return { triggered: false, reason: "lock-exists" };
|
|
195
|
+
try {
|
|
196
|
+
unlinkSync2(LOCAL_MINE_LOCK_PATH);
|
|
197
|
+
} catch {
|
|
198
|
+
return { triggered: false, reason: "lock-exists" };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (!hasLocalClaudeSessions())
|
|
202
|
+
return { triggered: false, reason: "no-claude-sessions" };
|
|
203
|
+
const launcher = findHivemindLauncher();
|
|
204
|
+
if (!launcher)
|
|
205
|
+
return { triggered: false, reason: "no-hivemind-bin" };
|
|
206
|
+
try {
|
|
207
|
+
mkdirSync3(HIVEMIND_DIR, { recursive: true });
|
|
208
|
+
const fd = openSync(LOCAL_MINE_LOCK_PATH, "wx");
|
|
209
|
+
closeSync(fd);
|
|
210
|
+
} catch {
|
|
211
|
+
return { triggered: false, reason: "lock-acquire-failed" };
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
mkdirSync3(join3(HOME, ".claude", "hooks"), { recursive: true });
|
|
215
|
+
const out = openSync(LOG_PATH, "a");
|
|
216
|
+
const [cmd, args] = launcher.kind === "node-script" ? [process.execPath, [launcher.path, "skillify", "mine-local"]] : [launcher.path, ["skillify", "mine-local"]];
|
|
217
|
+
const child = spawn(cmd, args, {
|
|
218
|
+
detached: true,
|
|
219
|
+
stdio: ["ignore", out, out],
|
|
220
|
+
env: process.env
|
|
221
|
+
});
|
|
222
|
+
closeSync(out);
|
|
223
|
+
child.unref();
|
|
224
|
+
return { triggered: true };
|
|
225
|
+
} catch {
|
|
226
|
+
try {
|
|
227
|
+
unlinkSync2(LOCAL_MINE_LOCK_PATH);
|
|
228
|
+
} catch {
|
|
229
|
+
}
|
|
230
|
+
return { triggered: false, reason: "spawn-failed" };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
107
234
|
// dist/src/utils/debug.js
|
|
108
235
|
import { appendFileSync } from "node:fs";
|
|
109
|
-
import { join as
|
|
110
|
-
import { homedir as
|
|
236
|
+
import { join as join4 } from "node:path";
|
|
237
|
+
import { homedir as homedir4 } from "node:os";
|
|
111
238
|
var DEBUG = process.env.HIVEMIND_DEBUG === "1";
|
|
112
|
-
var LOG =
|
|
239
|
+
var LOG = join4(homedir4(), ".deeplake", "hook-debug.log");
|
|
113
240
|
function log(tag, msg) {
|
|
114
241
|
if (!DEBUG)
|
|
115
242
|
return;
|
|
@@ -118,18 +245,18 @@ function log(tag, msg) {
|
|
|
118
245
|
}
|
|
119
246
|
|
|
120
247
|
// dist/src/utils/version-check.js
|
|
121
|
-
import { readFileSync as
|
|
122
|
-
import { dirname, join as
|
|
248
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
249
|
+
import { dirname as dirname3, join as join5 } from "node:path";
|
|
123
250
|
function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
124
251
|
try {
|
|
125
|
-
const pluginJson =
|
|
126
|
-
const plugin = JSON.parse(
|
|
252
|
+
const pluginJson = join5(bundleDir, "..", pluginManifestDir, "plugin.json");
|
|
253
|
+
const plugin = JSON.parse(readFileSync3(pluginJson, "utf-8"));
|
|
127
254
|
if (plugin.version)
|
|
128
255
|
return plugin.version;
|
|
129
256
|
} catch {
|
|
130
257
|
}
|
|
131
258
|
try {
|
|
132
|
-
const stamp =
|
|
259
|
+
const stamp = readFileSync3(join5(bundleDir, "..", ".hivemind_version"), "utf-8").trim();
|
|
133
260
|
if (stamp)
|
|
134
261
|
return stamp;
|
|
135
262
|
} catch {
|
|
@@ -144,14 +271,14 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
|
144
271
|
]);
|
|
145
272
|
let dir = bundleDir;
|
|
146
273
|
for (let i = 0; i < 5; i++) {
|
|
147
|
-
const candidate =
|
|
274
|
+
const candidate = join5(dir, "package.json");
|
|
148
275
|
try {
|
|
149
|
-
const pkg = JSON.parse(
|
|
276
|
+
const pkg = JSON.parse(readFileSync3(candidate, "utf-8"));
|
|
150
277
|
if (HIVEMIND_PKG_NAMES.has(pkg.name) && pkg.version)
|
|
151
278
|
return pkg.version;
|
|
152
279
|
} catch {
|
|
153
280
|
}
|
|
154
|
-
const parent =
|
|
281
|
+
const parent = dirname3(dir);
|
|
155
282
|
if (parent === dir)
|
|
156
283
|
break;
|
|
157
284
|
dir = parent;
|
|
@@ -160,16 +287,16 @@ function getInstalledVersion(bundleDir, pluginManifestDir) {
|
|
|
160
287
|
}
|
|
161
288
|
|
|
162
289
|
// dist/src/config.js
|
|
163
|
-
import { readFileSync as
|
|
164
|
-
import { join as
|
|
165
|
-
import { homedir as
|
|
290
|
+
import { readFileSync as readFileSync4, existsSync as existsSync3 } from "node:fs";
|
|
291
|
+
import { join as join6 } from "node:path";
|
|
292
|
+
import { homedir as homedir5, userInfo } from "node:os";
|
|
166
293
|
function loadConfig() {
|
|
167
|
-
const home =
|
|
168
|
-
const credPath =
|
|
294
|
+
const home = homedir5();
|
|
295
|
+
const credPath = join6(home, ".deeplake", "credentials.json");
|
|
169
296
|
let creds = null;
|
|
170
|
-
if (
|
|
297
|
+
if (existsSync3(credPath)) {
|
|
171
298
|
try {
|
|
172
|
-
creds = JSON.parse(
|
|
299
|
+
creds = JSON.parse(readFileSync4(credPath, "utf-8"));
|
|
173
300
|
} catch {
|
|
174
301
|
return null;
|
|
175
302
|
}
|
|
@@ -188,7 +315,7 @@ function loadConfig() {
|
|
|
188
315
|
tableName: process.env.HIVEMIND_TABLE ?? "memory",
|
|
189
316
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
190
317
|
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
191
|
-
memoryPath: process.env.HIVEMIND_MEMORY_PATH ??
|
|
318
|
+
memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join6(home, ".deeplake", "memory")
|
|
192
319
|
};
|
|
193
320
|
}
|
|
194
321
|
|
|
@@ -622,14 +749,14 @@ var DeeplakeApi = class {
|
|
|
622
749
|
};
|
|
623
750
|
|
|
624
751
|
// dist/src/skillify/pull.js
|
|
625
|
-
import { existsSync as
|
|
626
|
-
import { homedir as
|
|
627
|
-
import { dirname as
|
|
752
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, renameSync as renameSync3, lstatSync as lstatSync2, readlinkSync, symlinkSync, unlinkSync as unlinkSync4 } from "node:fs";
|
|
753
|
+
import { homedir as homedir10 } from "node:os";
|
|
754
|
+
import { dirname as dirname5, join as join12 } from "node:path";
|
|
628
755
|
|
|
629
756
|
// dist/src/skillify/skill-writer.js
|
|
630
|
-
import { existsSync as
|
|
631
|
-
import { homedir as
|
|
632
|
-
import { join as
|
|
757
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
758
|
+
import { homedir as homedir6 } from "node:os";
|
|
759
|
+
import { join as join8 } from "node:path";
|
|
633
760
|
function assertValidSkillName(name) {
|
|
634
761
|
if (typeof name !== "string" || name.length === 0) {
|
|
635
762
|
throw new Error(`invalid skill name: empty or non-string`);
|
|
@@ -695,26 +822,26 @@ function parseFrontmatter(text) {
|
|
|
695
822
|
}
|
|
696
823
|
|
|
697
824
|
// dist/src/skillify/manifest.js
|
|
698
|
-
import { existsSync as
|
|
699
|
-
import { homedir as
|
|
700
|
-
import { dirname as
|
|
825
|
+
import { existsSync as existsSync7, lstatSync, mkdirSync as mkdirSync6, readFileSync as readFileSync7, renameSync as renameSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
826
|
+
import { homedir as homedir8 } from "node:os";
|
|
827
|
+
import { dirname as dirname4, join as join10 } from "node:path";
|
|
701
828
|
|
|
702
829
|
// dist/src/skillify/legacy-migration.js
|
|
703
|
-
import { existsSync as
|
|
704
|
-
import { homedir as
|
|
705
|
-
import { join as
|
|
830
|
+
import { existsSync as existsSync6, renameSync } from "node:fs";
|
|
831
|
+
import { homedir as homedir7 } from "node:os";
|
|
832
|
+
import { join as join9 } from "node:path";
|
|
706
833
|
var dlog = (msg) => log("skillify-migrate", msg);
|
|
707
834
|
var attempted = false;
|
|
708
835
|
function migrateLegacyStateDir() {
|
|
709
836
|
if (attempted)
|
|
710
837
|
return;
|
|
711
838
|
attempted = true;
|
|
712
|
-
const root =
|
|
713
|
-
const legacy =
|
|
714
|
-
const current =
|
|
715
|
-
if (!
|
|
839
|
+
const root = join9(homedir7(), ".deeplake", "state");
|
|
840
|
+
const legacy = join9(root, "skilify");
|
|
841
|
+
const current = join9(root, "skillify");
|
|
842
|
+
if (!existsSync6(legacy))
|
|
716
843
|
return;
|
|
717
|
-
if (
|
|
844
|
+
if (existsSync6(current))
|
|
718
845
|
return;
|
|
719
846
|
try {
|
|
720
847
|
renameSync(legacy, current);
|
|
@@ -734,15 +861,15 @@ function emptyManifest() {
|
|
|
734
861
|
return { version: 1, entries: [] };
|
|
735
862
|
}
|
|
736
863
|
function manifestPath() {
|
|
737
|
-
return
|
|
864
|
+
return join10(homedir8(), ".deeplake", "state", "skillify", "pulled.json");
|
|
738
865
|
}
|
|
739
866
|
function loadManifest(path = manifestPath()) {
|
|
740
867
|
migrateLegacyStateDir();
|
|
741
|
-
if (!
|
|
868
|
+
if (!existsSync7(path))
|
|
742
869
|
return emptyManifest();
|
|
743
870
|
let raw;
|
|
744
871
|
try {
|
|
745
|
-
raw =
|
|
872
|
+
raw = readFileSync7(path, "utf-8");
|
|
746
873
|
} catch {
|
|
747
874
|
return emptyManifest();
|
|
748
875
|
}
|
|
@@ -789,9 +916,9 @@ function loadManifest(path = manifestPath()) {
|
|
|
789
916
|
}
|
|
790
917
|
function saveManifest(m, path = manifestPath()) {
|
|
791
918
|
migrateLegacyStateDir();
|
|
792
|
-
|
|
919
|
+
mkdirSync6(dirname4(path), { recursive: true });
|
|
793
920
|
const tmp = `${path}.tmp`;
|
|
794
|
-
|
|
921
|
+
writeFileSync5(tmp, JSON.stringify(m, null, 2) + "\n", { mode: 384 });
|
|
795
922
|
renameSync2(tmp, path);
|
|
796
923
|
}
|
|
797
924
|
function recordPull(entry, path = manifestPath()) {
|
|
@@ -817,7 +944,7 @@ function unlinkSymlinks(paths) {
|
|
|
817
944
|
if (!st.isSymbolicLink())
|
|
818
945
|
continue;
|
|
819
946
|
try {
|
|
820
|
-
|
|
947
|
+
unlinkSync3(path);
|
|
821
948
|
} catch {
|
|
822
949
|
}
|
|
823
950
|
}
|
|
@@ -827,7 +954,7 @@ function pruneOrphanedEntries(path = manifestPath()) {
|
|
|
827
954
|
const live = [];
|
|
828
955
|
let pruned = 0;
|
|
829
956
|
for (const e of m.entries) {
|
|
830
|
-
if (
|
|
957
|
+
if (existsSync7(join10(e.installRoot, e.dirName))) {
|
|
831
958
|
live.push(e);
|
|
832
959
|
continue;
|
|
833
960
|
}
|
|
@@ -840,26 +967,26 @@ function pruneOrphanedEntries(path = manifestPath()) {
|
|
|
840
967
|
}
|
|
841
968
|
|
|
842
969
|
// dist/src/skillify/agent-roots.js
|
|
843
|
-
import { existsSync as
|
|
844
|
-
import { homedir as
|
|
845
|
-
import { join as
|
|
970
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
971
|
+
import { homedir as homedir9 } from "node:os";
|
|
972
|
+
import { join as join11 } from "node:path";
|
|
846
973
|
function resolveDetected(home) {
|
|
847
974
|
const out = [];
|
|
848
|
-
const codexInstalled =
|
|
849
|
-
const piInstalled =
|
|
850
|
-
const hermesInstalled =
|
|
975
|
+
const codexInstalled = existsSync8(join11(home, ".codex"));
|
|
976
|
+
const piInstalled = existsSync8(join11(home, ".pi", "agent"));
|
|
977
|
+
const hermesInstalled = existsSync8(join11(home, ".hermes"));
|
|
851
978
|
if (codexInstalled || piInstalled) {
|
|
852
|
-
out.push(
|
|
979
|
+
out.push(join11(home, ".agents", "skills"));
|
|
853
980
|
}
|
|
854
981
|
if (hermesInstalled) {
|
|
855
|
-
out.push(
|
|
982
|
+
out.push(join11(home, ".hermes", "skills"));
|
|
856
983
|
}
|
|
857
984
|
if (piInstalled) {
|
|
858
|
-
out.push(
|
|
985
|
+
out.push(join11(home, ".pi", "agent", "skills"));
|
|
859
986
|
}
|
|
860
987
|
return out;
|
|
861
988
|
}
|
|
862
|
-
function detectAgentSkillsRoots(canonicalRoot, home =
|
|
989
|
+
function detectAgentSkillsRoots(canonicalRoot, home = homedir9()) {
|
|
863
990
|
return resolveDetected(home).filter((p) => p !== canonicalRoot);
|
|
864
991
|
}
|
|
865
992
|
|
|
@@ -903,15 +1030,15 @@ function isMissingTableError(message) {
|
|
|
903
1030
|
}
|
|
904
1031
|
function resolvePullDestination(install, cwd) {
|
|
905
1032
|
if (install === "global")
|
|
906
|
-
return
|
|
1033
|
+
return join12(homedir10(), ".claude", "skills");
|
|
907
1034
|
if (!cwd)
|
|
908
1035
|
throw new Error("install=project requires a cwd");
|
|
909
|
-
return
|
|
1036
|
+
return join12(cwd, ".claude", "skills");
|
|
910
1037
|
}
|
|
911
1038
|
function fanOutSymlinks(canonicalDir, dirName, agentRoots) {
|
|
912
1039
|
const out = [];
|
|
913
1040
|
for (const root of agentRoots) {
|
|
914
|
-
const link =
|
|
1041
|
+
const link = join12(root, dirName);
|
|
915
1042
|
let existing;
|
|
916
1043
|
try {
|
|
917
1044
|
existing = lstatSync2(link);
|
|
@@ -933,13 +1060,13 @@ function fanOutSymlinks(canonicalDir, dirName, agentRoots) {
|
|
|
933
1060
|
continue;
|
|
934
1061
|
}
|
|
935
1062
|
try {
|
|
936
|
-
|
|
1063
|
+
unlinkSync4(link);
|
|
937
1064
|
} catch {
|
|
938
1065
|
continue;
|
|
939
1066
|
}
|
|
940
1067
|
}
|
|
941
1068
|
try {
|
|
942
|
-
|
|
1069
|
+
mkdirSync7(dirname5(link), { recursive: true });
|
|
943
1070
|
symlinkSync(canonicalDir, link, "dir");
|
|
944
1071
|
out.push(link);
|
|
945
1072
|
} catch {
|
|
@@ -954,8 +1081,8 @@ function backfillSymlinks(installRoot) {
|
|
|
954
1081
|
return;
|
|
955
1082
|
const detected = detectAgentSkillsRoots(installRoot);
|
|
956
1083
|
for (const entry of entries) {
|
|
957
|
-
const canonical =
|
|
958
|
-
if (!
|
|
1084
|
+
const canonical = join12(entry.installRoot, entry.dirName);
|
|
1085
|
+
if (!existsSync9(canonical))
|
|
959
1086
|
continue;
|
|
960
1087
|
const fresh = fanOutSymlinks(canonical, entry.dirName, detected);
|
|
961
1088
|
if (sameSorted(fresh, entry.symlinks))
|
|
@@ -1065,10 +1192,10 @@ function renderFrontmatter(fm) {
|
|
|
1065
1192
|
return lines.join("\n");
|
|
1066
1193
|
}
|
|
1067
1194
|
function readLocalVersion(path) {
|
|
1068
|
-
if (!
|
|
1195
|
+
if (!existsSync9(path))
|
|
1069
1196
|
return null;
|
|
1070
1197
|
try {
|
|
1071
|
-
const text =
|
|
1198
|
+
const text = readFileSync8(path, "utf-8");
|
|
1072
1199
|
const parsed = parseFrontmatter(text);
|
|
1073
1200
|
if (!parsed)
|
|
1074
1201
|
return null;
|
|
@@ -1163,8 +1290,8 @@ async function runPull(opts) {
|
|
|
1163
1290
|
summary.skipped++;
|
|
1164
1291
|
continue;
|
|
1165
1292
|
}
|
|
1166
|
-
const skillDir =
|
|
1167
|
-
const skillFile =
|
|
1293
|
+
const skillDir = join12(root, dirName);
|
|
1294
|
+
const skillFile = join12(skillDir, "SKILL.md");
|
|
1168
1295
|
const remoteVersion = Number(row.version ?? 1);
|
|
1169
1296
|
const localVersion = readLocalVersion(skillFile);
|
|
1170
1297
|
const action = decideAction({
|
|
@@ -1175,14 +1302,14 @@ async function runPull(opts) {
|
|
|
1175
1302
|
});
|
|
1176
1303
|
let manifestError;
|
|
1177
1304
|
if (action === "wrote") {
|
|
1178
|
-
|
|
1179
|
-
if (
|
|
1305
|
+
mkdirSync7(skillDir, { recursive: true });
|
|
1306
|
+
if (existsSync9(skillFile)) {
|
|
1180
1307
|
try {
|
|
1181
1308
|
renameSync3(skillFile, `${skillFile}.bak`);
|
|
1182
1309
|
} catch {
|
|
1183
1310
|
}
|
|
1184
1311
|
}
|
|
1185
|
-
|
|
1312
|
+
writeFileSync6(skillFile, renderSkillFile(row));
|
|
1186
1313
|
const symlinks = opts.install === "global" ? fanOutSymlinks(skillDir, dirName, detectAgentSkillsRoots(root)) : [];
|
|
1187
1314
|
try {
|
|
1188
1315
|
recordPull({
|
|
@@ -1278,53 +1405,7 @@ async function autoPullSkills(deps = {}) {
|
|
|
1278
1405
|
|
|
1279
1406
|
// dist/src/hooks/codex/session-start.js
|
|
1280
1407
|
var log4 = (msg) => log("codex-session-start", msg);
|
|
1281
|
-
var __bundleDir =
|
|
1282
|
-
var context = `DEEPLAKE MEMORY: Persistent memory at ~/.deeplake/memory/ shared across sessions, users, and agents.
|
|
1283
|
-
|
|
1284
|
-
Deeplake memory has THREE tiers \u2014 pick the right one for the question:
|
|
1285
|
-
1. ~/.deeplake/memory/index.md \u2014 auto-generated index, top 50 most-recently-updated entries with Created + Last Updated + Project + Description columns. ~5 KB. **For "what's recent / who did X this week / since <date>" queries, START HERE** and trust the Last Updated column over any "Started:" line in summary bodies.
|
|
1286
|
-
2. ~/.deeplake/memory/summaries/ \u2014 condensed wiki summaries per session (~3 KB each). For keyword/topic recall, search these.
|
|
1287
|
-
3. ~/.deeplake/memory/sessions/ \u2014 raw full-dialogue JSONL (~5 KB each). FALLBACK only \u2014 use when summaries don't contain the exact quote/turn you need.
|
|
1288
|
-
|
|
1289
|
-
Search workflow:
|
|
1290
|
-
- Time-based ("last week", "today", "since X"): cat ~/.deeplake/memory/index.md and read the most-recent rows.
|
|
1291
|
-
- Keyword/topic recall: grep -r "keyword" ~/.deeplake/memory/summaries/ (the shell hook routes this through hybrid lexical+semantic search \u2014 synonyms match too). Then cat the top-matching summary.
|
|
1292
|
-
- Raw transcript fallback only: grep -r "keyword" ~/.deeplake/memory/sessions/ (use sparingly \u2014 JSONL is verbose).
|
|
1293
|
-
|
|
1294
|
-
\u2705 grep -r "keyword" ~/.deeplake/memory/summaries/
|
|
1295
|
-
\u274C grep without a summaries/ or sessions/ suffix \u2014 too noisy
|
|
1296
|
-
|
|
1297
|
-
IMPORTANT: Only use bash builtins (cat, ls, grep, echo, jq, head, tail, sed, awk, etc.) on ~/.deeplake/memory/. Do NOT use python, python3, node, curl, or other interpreters \u2014 they are not available in the memory filesystem.
|
|
1298
|
-
Do NOT spawn subagents to read deeplake memory.
|
|
1299
|
-
|
|
1300
|
-
Organization management \u2014 each argument is SEPARATE (do NOT quote subcommands together):
|
|
1301
|
-
- hivemind login \u2014 SSO login
|
|
1302
|
-
- hivemind whoami \u2014 show current user/org
|
|
1303
|
-
- hivemind org list \u2014 list organizations
|
|
1304
|
-
- hivemind org switch <name-or-id> \u2014 switch organization
|
|
1305
|
-
- hivemind workspaces \u2014 list workspaces
|
|
1306
|
-
- hivemind workspace <id> \u2014 switch workspace
|
|
1307
|
-
- hivemind invite <email> <ADMIN|WRITE|READ> \u2014 invite member (ALWAYS ask user which role before inviting)
|
|
1308
|
-
- hivemind members \u2014 list members
|
|
1309
|
-
- hivemind remove <user-id> \u2014 remove member
|
|
1310
|
-
|
|
1311
|
-
SKILLS (skillify) \u2014 mine + share reusable skills across the org:
|
|
1312
|
-
- hivemind skillify \u2014 show scope/team/install + per-project state
|
|
1313
|
-
- hivemind skillify pull \u2014 sync project skills from the org table
|
|
1314
|
-
- hivemind skillify pull --user <email> \u2014 only that author's skills
|
|
1315
|
-
- hivemind skillify pull --users a,b,c \u2014 multiple authors (CSV)
|
|
1316
|
-
- hivemind skillify pull --all-users \u2014 explicit "no author filter"
|
|
1317
|
-
- hivemind skillify pull --to project|global \u2014 install location
|
|
1318
|
-
- hivemind skillify pull --dry-run \u2014 preview only
|
|
1319
|
-
- hivemind skillify pull --force \u2014 overwrite local (creates .bak)
|
|
1320
|
-
- hivemind skillify pull <skill-name> \u2014 pull only that skill (combines with --user)
|
|
1321
|
-
- hivemind skillify unpull \u2014 remove every skill previously installed by pull
|
|
1322
|
-
- hivemind skillify unpull --user <email> \u2014 remove only that author's pulls
|
|
1323
|
-
- hivemind skillify unpull --not-mine \u2014 remove all pulls except your own
|
|
1324
|
-
- hivemind skillify unpull --dry-run \u2014 preview without touching disk
|
|
1325
|
-
- hivemind skillify scope <me|team> \u2014 sharing scope for new skills
|
|
1326
|
-
- hivemind skillify install <project|global> \u2014 default install location
|
|
1327
|
-
- hivemind skillify team add|remove|list <name> \u2014 manage team list`;
|
|
1408
|
+
var __bundleDir = dirname6(fileURLToPath2(import.meta.url));
|
|
1328
1409
|
async function main() {
|
|
1329
1410
|
if (process.env.HIVEMIND_WIKI_WORKER === "1")
|
|
1330
1411
|
return;
|
|
@@ -1332,12 +1413,14 @@ async function main() {
|
|
|
1332
1413
|
const creds = loadCredentials();
|
|
1333
1414
|
if (!creds?.token) {
|
|
1334
1415
|
log4("no credentials found \u2014 run auth login to authenticate");
|
|
1416
|
+
const auto = maybeAutoMineLocal();
|
|
1417
|
+
log4(`auto-mine: ${auto.triggered ? "triggered (background)" : `skipped (${auto.reason})`}`);
|
|
1335
1418
|
} else {
|
|
1336
1419
|
log4(`credentials loaded: org=${creds.orgName ?? creds.orgId}`);
|
|
1337
1420
|
}
|
|
1338
1421
|
if (creds?.token) {
|
|
1339
|
-
const setupScript =
|
|
1340
|
-
const child =
|
|
1422
|
+
const setupScript = join13(__bundleDir, "session-start-setup.js");
|
|
1423
|
+
const child = spawn2("node", [setupScript], {
|
|
1341
1424
|
detached: true,
|
|
1342
1425
|
stdio: ["pipe", "ignore", "ignore"],
|
|
1343
1426
|
env: { ...process.env }
|
|
@@ -1355,10 +1438,19 @@ async function main() {
|
|
|
1355
1438
|
versionNotice = `
|
|
1356
1439
|
Hivemind v${current}`;
|
|
1357
1440
|
}
|
|
1358
|
-
const
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1441
|
+
const localMined = countLocalManifestEntries();
|
|
1442
|
+
const skillNoun = localMined === 1 ? "skill" : "skills";
|
|
1443
|
+
const additionalContext = creds?.token ? `Hivemind: logged in as org ${creds.orgName ?? creds.orgId} (workspace: ${creds.workspaceId ?? "default"}).${versionNotice}` : `Hivemind: not logged in. Run \`hivemind login\` to enable shared memory + skill sharing.${versionNotice}`;
|
|
1444
|
+
const systemMessage = !creds?.token && localMined > 0 ? `\u{1F4A1} ${localMined} ${skillNoun} mined from your local sessions live in ~/.claude/skills/. Run 'hivemind login' to share them with your team.` : void 0;
|
|
1445
|
+
const output = {
|
|
1446
|
+
hookSpecificOutput: {
|
|
1447
|
+
hookEventName: "SessionStart",
|
|
1448
|
+
additionalContext
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
if (systemMessage)
|
|
1452
|
+
output.systemMessage = systemMessage;
|
|
1453
|
+
console.log(JSON.stringify(output));
|
|
1362
1454
|
}
|
|
1363
1455
|
main().catch((e) => {
|
|
1364
1456
|
log4(`fatal: ${e.message}`);
|
|
@@ -45,6 +45,39 @@ Each argument is separate — do NOT quote subcommands together. The auth comman
|
|
|
45
45
|
- `node "<path>/auth-login.js" remove <user-id>` — remove member
|
|
46
46
|
- `node "<path>/auth-login.js" --help` — show all commands
|
|
47
47
|
|
|
48
|
+
## Skill Management (skillify)
|
|
49
|
+
|
|
50
|
+
Hivemind can mine reusable skills from agent session logs and share them across your team. Each argument is separate — do NOT quote subcommands together.
|
|
51
|
+
|
|
52
|
+
- `hivemind skillify` — show current scope, team, install location, per-project state
|
|
53
|
+
- `hivemind skillify pull` — sync project skills from the org table to local FS
|
|
54
|
+
- `hivemind skillify pull --user <email>` — only skills authored by that user
|
|
55
|
+
- `hivemind skillify pull --users <a,b,c>` — multiple authors (CSV)
|
|
56
|
+
- `hivemind skillify pull --all-users` — explicit "no author filter" (default)
|
|
57
|
+
- `hivemind skillify pull --to <project|global>` — install location (project=cwd/.claude/skills, global=~/.claude/skills)
|
|
58
|
+
- `hivemind skillify pull --dry-run` — preview without touching disk
|
|
59
|
+
- `hivemind skillify pull --force` — overwrite local files even if up-to-date (creates .bak)
|
|
60
|
+
- `hivemind skillify pull <skill-name>` — pull only that one skill (combines with --user)
|
|
61
|
+
- `hivemind skillify unpull` — remove every skill previously installed by pull
|
|
62
|
+
- `hivemind skillify unpull --user <email>` — remove only that author's pulls
|
|
63
|
+
- `hivemind skillify unpull --not-mine` — remove all pulls except your own
|
|
64
|
+
- `hivemind skillify unpull --dry-run` — preview without touching disk
|
|
65
|
+
- `hivemind skillify scope <me|team>` — sharing scope for newly mined skills
|
|
66
|
+
- `hivemind skillify install <project|global>` — default install location for new skills
|
|
67
|
+
- `hivemind skillify promote <skill-name>` — move a project skill to the global location
|
|
68
|
+
- `hivemind skillify team add|remove|list <username>` — manage team member list
|
|
69
|
+
- `hivemind skillify mine-local` — one-shot: mine skills from local sessions, no auth needed
|
|
70
|
+
|
|
71
|
+
## Embeddings (semantic memory search)
|
|
72
|
+
|
|
73
|
+
Opt-in, persisted in `~/.deeplake/config.json`.
|
|
74
|
+
|
|
75
|
+
- `hivemind embeddings install` — download deps (~600MB), symlink agents, set enabled:true
|
|
76
|
+
- `hivemind embeddings enable` — flip enabled:true (run install first if deps missing)
|
|
77
|
+
- `hivemind embeddings disable` — flip enabled:false + SIGTERM daemon (deps stay on disk)
|
|
78
|
+
- `hivemind embeddings uninstall [--prune]` — remove agent symlinks + disable; --prune wipes deps too
|
|
79
|
+
- `hivemind embeddings status` — show config + deps + per-agent link state
|
|
80
|
+
|
|
48
81
|
## Important: Bash Only
|
|
49
82
|
|
|
50
83
|
Only use bash commands (cat, ls, grep, echo, jq, head, tail, sed, awk, etc.) to interact with `~/.deeplake/memory/`. Do NOT use python, python3, node, curl, or other interpreters — they are not available in the memory filesystem. If a task seems to require Python, rewrite it using bash tools (e.g., `cat file.json | jq 'keys | length'`).
|