@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.
@@ -17,21 +17,21 @@ __export(index_marker_store_exports, {
17
17
  hasFreshIndexMarker: () => hasFreshIndexMarker,
18
18
  writeIndexMarker: () => writeIndexMarker
19
19
  });
20
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
21
- import { join as join5 } from "node:path";
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 ?? join5(tmpdir(), "hivemind-deeplake-indexes");
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 join5(getIndexMarkerDir(), `${markerKey}.json`);
28
+ return join7(getIndexMarkerDir(), `${markerKey}.json`);
29
29
  }
30
30
  function hasFreshIndexMarker(markerPath) {
31
- if (!existsSync2(markerPath))
31
+ if (!existsSync4(markerPath))
32
32
  return false;
33
33
  try {
34
- const raw = JSON.parse(readFileSync4(markerPath, "utf-8"));
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
- mkdirSync2(getIndexMarkerDir(), { recursive: true });
45
- writeFileSync2(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
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 dirname4, join as join11 } from "node:path";
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 join2 } from "node:path";
110
- import { homedir as homedir2 } from "node:os";
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 = join2(homedir2(), ".deeplake", "hook-debug.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 readFileSync2 } from "node:fs";
122
- import { dirname, join as join3 } from "node:path";
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 = join3(bundleDir, "..", pluginManifestDir, "plugin.json");
126
- const plugin = JSON.parse(readFileSync2(pluginJson, "utf-8"));
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 = readFileSync2(join3(bundleDir, "..", ".hivemind_version"), "utf-8").trim();
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 = join3(dir, "package.json");
274
+ const candidate = join5(dir, "package.json");
148
275
  try {
149
- const pkg = JSON.parse(readFileSync2(candidate, "utf-8"));
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 = dirname(dir);
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 readFileSync3, existsSync } from "node:fs";
164
- import { join as join4 } from "node:path";
165
- import { homedir as homedir3, userInfo } from "node:os";
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 = homedir3();
168
- const credPath = join4(home, ".deeplake", "credentials.json");
294
+ const home = homedir5();
295
+ const credPath = join6(home, ".deeplake", "credentials.json");
169
296
  let creds = null;
170
- if (existsSync(credPath)) {
297
+ if (existsSync3(credPath)) {
171
298
  try {
172
- creds = JSON.parse(readFileSync3(credPath, "utf-8"));
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 ?? join4(home, ".deeplake", "memory")
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 existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, renameSync as renameSync3, lstatSync as lstatSync2, readlinkSync, symlinkSync, unlinkSync as unlinkSync3 } from "node:fs";
626
- import { homedir as homedir8 } from "node:os";
627
- import { dirname as dirname3, join as join10 } from "node:path";
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 existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync, statSync, writeFileSync as writeFileSync3 } from "node:fs";
631
- import { homedir as homedir4 } from "node:os";
632
- import { join as join6 } from "node:path";
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 existsSync5, lstatSync, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
699
- import { homedir as homedir6 } from "node:os";
700
- import { dirname as dirname2, join as join8 } from "node:path";
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 existsSync4, renameSync } from "node:fs";
704
- import { homedir as homedir5 } from "node:os";
705
- import { join as join7 } from "node:path";
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 = join7(homedir5(), ".deeplake", "state");
713
- const legacy = join7(root, "skilify");
714
- const current = join7(root, "skillify");
715
- if (!existsSync4(legacy))
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 (existsSync4(current))
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 join8(homedir6(), ".deeplake", "state", "skillify", "pulled.json");
864
+ return join10(homedir8(), ".deeplake", "state", "skillify", "pulled.json");
738
865
  }
739
866
  function loadManifest(path = manifestPath()) {
740
867
  migrateLegacyStateDir();
741
- if (!existsSync5(path))
868
+ if (!existsSync7(path))
742
869
  return emptyManifest();
743
870
  let raw;
744
871
  try {
745
- raw = readFileSync6(path, "utf-8");
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
- mkdirSync4(dirname2(path), { recursive: true });
919
+ mkdirSync6(dirname4(path), { recursive: true });
793
920
  const tmp = `${path}.tmp`;
794
- writeFileSync4(tmp, JSON.stringify(m, null, 2) + "\n", { mode: 384 });
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
- unlinkSync2(path);
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 (existsSync5(join8(e.installRoot, e.dirName))) {
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 existsSync6 } from "node:fs";
844
- import { homedir as homedir7 } from "node:os";
845
- import { join as join9 } from "node:path";
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 = existsSync6(join9(home, ".codex"));
849
- const piInstalled = existsSync6(join9(home, ".pi", "agent"));
850
- const hermesInstalled = existsSync6(join9(home, ".hermes"));
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(join9(home, ".agents", "skills"));
979
+ out.push(join11(home, ".agents", "skills"));
853
980
  }
854
981
  if (hermesInstalled) {
855
- out.push(join9(home, ".hermes", "skills"));
982
+ out.push(join11(home, ".hermes", "skills"));
856
983
  }
857
984
  if (piInstalled) {
858
- out.push(join9(home, ".pi", "agent", "skills"));
985
+ out.push(join11(home, ".pi", "agent", "skills"));
859
986
  }
860
987
  return out;
861
988
  }
862
- function detectAgentSkillsRoots(canonicalRoot, home = homedir7()) {
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 join10(homedir8(), ".claude", "skills");
1033
+ return join12(homedir10(), ".claude", "skills");
907
1034
  if (!cwd)
908
1035
  throw new Error("install=project requires a cwd");
909
- return join10(cwd, ".claude", "skills");
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 = join10(root, dirName);
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
- unlinkSync3(link);
1063
+ unlinkSync4(link);
937
1064
  } catch {
938
1065
  continue;
939
1066
  }
940
1067
  }
941
1068
  try {
942
- mkdirSync5(dirname3(link), { recursive: true });
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 = join10(entry.installRoot, entry.dirName);
958
- if (!existsSync7(canonical))
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 (!existsSync7(path))
1195
+ if (!existsSync9(path))
1069
1196
  return null;
1070
1197
  try {
1071
- const text = readFileSync7(path, "utf-8");
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 = join10(root, dirName);
1167
- const skillFile = join10(skillDir, "SKILL.md");
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
- mkdirSync5(skillDir, { recursive: true });
1179
- if (existsSync7(skillFile)) {
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
- writeFileSync5(skillFile, renderSkillFile(row));
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 = dirname4(fileURLToPath(import.meta.url));
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 = join11(__bundleDir, "session-start-setup.js");
1340
- const child = spawn("node", [setupScript], {
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 additionalContext = creds?.token ? `${context}
1359
- Logged in to Deeplake as org: ${creds.orgName ?? creds.orgId} (workspace: ${creds.workspaceId ?? "default"})${versionNotice}` : `${context}
1360
- Not logged in to Deeplake. Run: hivemind login${versionNotice}`;
1361
- console.log(additionalContext);
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'`).