@deeplake/hivemind 0.7.16 → 0.7.18

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.
@@ -54,7 +54,7 @@ var init_index_marker_store = __esm({
54
54
 
55
55
  // dist/src/hooks/cursor/session-start.js
56
56
  import { fileURLToPath } from "node:url";
57
- import { dirname as dirname2 } from "node:path";
57
+ import { dirname as dirname4 } from "node:path";
58
58
 
59
59
  // dist/src/commands/auth.js
60
60
  import { execSync } from "node:child_process";
@@ -671,9 +671,615 @@ async function autoUpdate(creds, opts) {
671
671
  log3(`agent=${opts.agent} dispatched (pid=${pid ?? "?"}) (${Date.now() - t0}ms total)`);
672
672
  }
673
673
 
674
+ // dist/src/skillify/pull.js
675
+ import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, renameSync as renameSync3, lstatSync as lstatSync2, readlinkSync, symlinkSync, unlinkSync as unlinkSync3 } from "node:fs";
676
+ import { homedir as homedir8 } from "node:os";
677
+ import { dirname as dirname3, join as join11 } from "node:path";
678
+
679
+ // dist/src/skillify/skill-writer.js
680
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync, statSync, writeFileSync as writeFileSync3 } from "node:fs";
681
+ import { homedir as homedir4 } from "node:os";
682
+ import { join as join7 } from "node:path";
683
+ function assertValidSkillName(name) {
684
+ if (typeof name !== "string" || name.length === 0) {
685
+ throw new Error(`invalid skill name: empty or non-string`);
686
+ }
687
+ if (name.length > 100) {
688
+ throw new Error(`invalid skill name: too long (${name.length} chars)`);
689
+ }
690
+ if (name.includes("/") || name.includes("\\") || name.includes("..")) {
691
+ throw new Error(`invalid skill name: contains path separator or '..': ${name}`);
692
+ }
693
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) {
694
+ throw new Error(`invalid skill name: must be kebab-case (lowercase a-z, 0-9, hyphen): ${name}`);
695
+ }
696
+ }
697
+ function parseFrontmatter(text) {
698
+ if (!text.startsWith("---\n") && !text.startsWith("---\r\n"))
699
+ return null;
700
+ const end = text.indexOf("\n---", 4);
701
+ if (end < 0)
702
+ return null;
703
+ const head = text.slice(4, end).trim();
704
+ const body = text.slice(end + 4).replace(/^\r?\n/, "");
705
+ const fm = { source_sessions: [] };
706
+ let mode = "kv";
707
+ for (const raw of head.split(/\r?\n/)) {
708
+ if (mode === "sources") {
709
+ const m2 = raw.match(/^\s+-\s+(.+)$/);
710
+ if (m2) {
711
+ fm.source_sessions.push(m2[1].trim());
712
+ continue;
713
+ }
714
+ mode = "kv";
715
+ }
716
+ if (raw.startsWith("source_sessions:")) {
717
+ mode = "sources";
718
+ continue;
719
+ }
720
+ const m = raw.match(/^([a-zA-Z_]+):\s*(.*)$/);
721
+ if (!m)
722
+ continue;
723
+ const [, k, v] = m;
724
+ let val = v;
725
+ if (v.startsWith('"') && v.endsWith('"')) {
726
+ try {
727
+ val = JSON.parse(v);
728
+ } catch {
729
+ }
730
+ } else if (k === "version") {
731
+ const n = parseInt(v, 10);
732
+ if (Number.isFinite(n))
733
+ val = n;
734
+ }
735
+ fm[k] = val;
736
+ }
737
+ return { fm, body };
738
+ }
739
+
740
+ // dist/src/skillify/manifest.js
741
+ import { existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
742
+ import { homedir as homedir6 } from "node:os";
743
+ import { dirname as dirname2, join as join9 } from "node:path";
744
+
745
+ // dist/src/skillify/legacy-migration.js
746
+ import { existsSync as existsSync5, renameSync } from "node:fs";
747
+ import { homedir as homedir5 } from "node:os";
748
+ import { join as join8 } from "node:path";
749
+ var dlog = (msg) => log("skillify-migrate", msg);
750
+ var attempted = false;
751
+ function migrateLegacyStateDir() {
752
+ if (attempted)
753
+ return;
754
+ attempted = true;
755
+ const root = join8(homedir5(), ".deeplake", "state");
756
+ const legacy = join8(root, "skilify");
757
+ const current = join8(root, "skillify");
758
+ if (!existsSync5(legacy))
759
+ return;
760
+ if (existsSync5(current))
761
+ return;
762
+ try {
763
+ renameSync(legacy, current);
764
+ dlog(`migrated ${legacy} -> ${current}`);
765
+ } catch (err) {
766
+ const code = err.code;
767
+ if (code === "EXDEV" || code === "EPERM") {
768
+ dlog(`migration failed (${code}); leaving legacy dir in place`);
769
+ return;
770
+ }
771
+ throw err;
772
+ }
773
+ }
774
+
775
+ // dist/src/skillify/manifest.js
776
+ function emptyManifest() {
777
+ return { version: 1, entries: [] };
778
+ }
779
+ function manifestPath() {
780
+ return join9(homedir6(), ".deeplake", "state", "skillify", "pulled.json");
781
+ }
782
+ function loadManifest(path = manifestPath()) {
783
+ migrateLegacyStateDir();
784
+ if (!existsSync6(path))
785
+ return emptyManifest();
786
+ let raw;
787
+ try {
788
+ raw = readFileSync6(path, "utf-8");
789
+ } catch {
790
+ return emptyManifest();
791
+ }
792
+ try {
793
+ const parsed = JSON.parse(raw);
794
+ if (!parsed || typeof parsed !== "object")
795
+ return emptyManifest();
796
+ if (parsed.version !== 1 || !Array.isArray(parsed.entries))
797
+ return emptyManifest();
798
+ const entries = [];
799
+ for (const e of parsed.entries) {
800
+ if (!e || typeof e !== "object")
801
+ continue;
802
+ if (typeof e.dirName !== "string" || !e.dirName)
803
+ continue;
804
+ if (e.dirName.includes("/") || e.dirName.includes("\\") || e.dirName.includes(".."))
805
+ continue;
806
+ if (typeof e.name !== "string" || !e.name)
807
+ continue;
808
+ if (typeof e.author !== "string")
809
+ continue;
810
+ if (typeof e.installRoot !== "string" || !e.installRoot)
811
+ continue;
812
+ if (e.install !== "global" && e.install !== "project")
813
+ continue;
814
+ const symlinks = Array.isArray(e.symlinks) ? e.symlinks.filter((p) => typeof p === "string" && p.length > 0 && (p.startsWith("/") || /^[A-Za-z]:[\\/]/.test(p)) && // absolute (POSIX or Windows)
815
+ !p.includes("..")) : [];
816
+ entries.push({
817
+ dirName: e.dirName,
818
+ name: e.name,
819
+ author: e.author,
820
+ projectKey: typeof e.projectKey === "string" ? e.projectKey : "",
821
+ remoteVersion: typeof e.remoteVersion === "number" ? e.remoteVersion : 1,
822
+ install: e.install,
823
+ installRoot: e.installRoot,
824
+ pulledAt: typeof e.pulledAt === "string" ? e.pulledAt : (/* @__PURE__ */ new Date()).toISOString(),
825
+ symlinks
826
+ });
827
+ }
828
+ return { version: 1, entries };
829
+ } catch {
830
+ return emptyManifest();
831
+ }
832
+ }
833
+ function saveManifest(m, path = manifestPath()) {
834
+ migrateLegacyStateDir();
835
+ mkdirSync4(dirname2(path), { recursive: true });
836
+ const tmp = `${path}.tmp`;
837
+ writeFileSync4(tmp, JSON.stringify(m, null, 2) + "\n", { mode: 384 });
838
+ renameSync2(tmp, path);
839
+ }
840
+ function recordPull(entry, path = manifestPath()) {
841
+ const m = loadManifest(path);
842
+ const idx = m.entries.findIndex((e) => e.install === entry.install && e.installRoot === entry.installRoot && e.dirName === entry.dirName);
843
+ if (idx >= 0)
844
+ m.entries[idx] = entry;
845
+ else
846
+ m.entries.push(entry);
847
+ saveManifest(m, path);
848
+ }
849
+ function entriesForRoot(m, install, installRoot) {
850
+ return m.entries.filter((e) => e.install === install && e.installRoot === installRoot);
851
+ }
852
+ function unlinkSymlinks(paths) {
853
+ for (const path of paths) {
854
+ let st;
855
+ try {
856
+ st = lstatSync(path);
857
+ } catch {
858
+ continue;
859
+ }
860
+ if (!st.isSymbolicLink())
861
+ continue;
862
+ try {
863
+ unlinkSync2(path);
864
+ } catch {
865
+ }
866
+ }
867
+ }
868
+ function pruneOrphanedEntries(path = manifestPath()) {
869
+ const m = loadManifest(path);
870
+ const live = [];
871
+ let pruned = 0;
872
+ for (const e of m.entries) {
873
+ if (existsSync6(join9(e.installRoot, e.dirName))) {
874
+ live.push(e);
875
+ continue;
876
+ }
877
+ unlinkSymlinks(e.symlinks);
878
+ pruned++;
879
+ }
880
+ if (pruned > 0)
881
+ saveManifest({ version: 1, entries: live }, path);
882
+ return pruned;
883
+ }
884
+
885
+ // dist/src/skillify/agent-roots.js
886
+ import { existsSync as existsSync7 } from "node:fs";
887
+ import { homedir as homedir7 } from "node:os";
888
+ import { join as join10 } from "node:path";
889
+ function resolveDetected(home) {
890
+ const out = [];
891
+ const codexInstalled = existsSync7(join10(home, ".codex"));
892
+ const piInstalled = existsSync7(join10(home, ".pi", "agent"));
893
+ const hermesInstalled = existsSync7(join10(home, ".hermes"));
894
+ if (codexInstalled || piInstalled) {
895
+ out.push(join10(home, ".agents", "skills"));
896
+ }
897
+ if (hermesInstalled) {
898
+ out.push(join10(home, ".hermes", "skills"));
899
+ }
900
+ if (piInstalled) {
901
+ out.push(join10(home, ".pi", "agent", "skills"));
902
+ }
903
+ return out;
904
+ }
905
+ function detectAgentSkillsRoots(canonicalRoot, home = homedir7()) {
906
+ return resolveDetected(home).filter((p) => p !== canonicalRoot);
907
+ }
908
+
909
+ // dist/src/skillify/pull.js
910
+ function assertValidAuthor(author) {
911
+ if (!author)
912
+ throw new Error("author is empty");
913
+ if (author.length > 64)
914
+ throw new Error(`author too long (${author.length}): ${author.slice(0, 32)}\u2026`);
915
+ if (!/^[A-Za-z0-9_.\-@]+$/.test(author)) {
916
+ throw new Error(`author contains invalid characters: ${author}`);
917
+ }
918
+ }
919
+ function esc(s) {
920
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
921
+ }
922
+ function buildPullSql(args) {
923
+ const where = [];
924
+ if (args.users.length > 0) {
925
+ const list = args.users.map((u) => `'${esc(u)}'`).join(", ");
926
+ where.push(`author IN (${list})`);
927
+ }
928
+ if (args.skillName) {
929
+ where.push(`name = '${esc(args.skillName)}'`);
930
+ }
931
+ const whereClause = where.length > 0 ? ` WHERE ${where.join(" AND ")}` : "";
932
+ 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`;
933
+ }
934
+ function isMissingTableError(message) {
935
+ if (!message)
936
+ return false;
937
+ return /Table does not exist|relation .* does not exist|no such table/i.test(message);
938
+ }
939
+ function resolvePullDestination(install, cwd) {
940
+ if (install === "global")
941
+ return join11(homedir8(), ".claude", "skills");
942
+ if (!cwd)
943
+ throw new Error("install=project requires a cwd");
944
+ return join11(cwd, ".claude", "skills");
945
+ }
946
+ function fanOutSymlinks(canonicalDir, dirName, agentRoots) {
947
+ const out = [];
948
+ for (const root of agentRoots) {
949
+ const link = join11(root, dirName);
950
+ let existing;
951
+ try {
952
+ existing = lstatSync2(link);
953
+ } catch {
954
+ existing = null;
955
+ }
956
+ if (existing) {
957
+ if (!existing.isSymbolicLink()) {
958
+ continue;
959
+ }
960
+ let current;
961
+ try {
962
+ current = readlinkSync(link);
963
+ } catch {
964
+ current = null;
965
+ }
966
+ if (current === canonicalDir) {
967
+ out.push(link);
968
+ continue;
969
+ }
970
+ try {
971
+ unlinkSync3(link);
972
+ } catch {
973
+ continue;
974
+ }
975
+ }
976
+ try {
977
+ mkdirSync5(dirname3(link), { recursive: true });
978
+ symlinkSync(canonicalDir, link, "dir");
979
+ out.push(link);
980
+ } catch {
981
+ }
982
+ }
983
+ return out;
984
+ }
985
+ function backfillSymlinks(installRoot) {
986
+ const manifest = loadManifest();
987
+ const entries = entriesForRoot(manifest, "global", installRoot);
988
+ if (entries.length === 0)
989
+ return;
990
+ const detected = detectAgentSkillsRoots(installRoot);
991
+ for (const entry of entries) {
992
+ const canonical = join11(entry.installRoot, entry.dirName);
993
+ if (!existsSync8(canonical))
994
+ continue;
995
+ const fresh = fanOutSymlinks(canonical, entry.dirName, detected);
996
+ if (sameSorted(fresh, entry.symlinks))
997
+ continue;
998
+ try {
999
+ recordPull({ ...entry, symlinks: fresh });
1000
+ } catch {
1001
+ }
1002
+ }
1003
+ }
1004
+ function sameSorted(a, b) {
1005
+ if (a.length !== b.length)
1006
+ return false;
1007
+ const sa = [...a].sort();
1008
+ const sb = [...b].sort();
1009
+ for (let i = 0; i < sa.length; i++)
1010
+ if (sa[i] !== sb[i])
1011
+ return false;
1012
+ return true;
1013
+ }
1014
+ function selectLatestPerName(rows) {
1015
+ const seen = /* @__PURE__ */ new Set();
1016
+ const out = [];
1017
+ for (const r of rows) {
1018
+ const name = String(r.name ?? "");
1019
+ const projectKey = String(r.project_key ?? "");
1020
+ if (!name)
1021
+ continue;
1022
+ const key = `${projectKey}\0${name}`;
1023
+ if (seen.has(key))
1024
+ continue;
1025
+ seen.add(key);
1026
+ out.push(r);
1027
+ }
1028
+ return out;
1029
+ }
1030
+ function renderSkillFile(row) {
1031
+ const sources = parseSourceSessions(row.source_sessions);
1032
+ const fm = {
1033
+ name: String(row.name ?? ""),
1034
+ description: String(row.description ?? ""),
1035
+ trigger: typeof row.trigger_text === "string" && row.trigger_text.length > 0 ? String(row.trigger_text) : void 0,
1036
+ source_sessions: sources,
1037
+ version: Number(row.version ?? 1),
1038
+ created_by_agent: String(row.source_agent ?? "unknown"),
1039
+ created_at: String(row.created_at ?? (/* @__PURE__ */ new Date()).toISOString()),
1040
+ updated_at: String(row.updated_at ?? (/* @__PURE__ */ new Date()).toISOString())
1041
+ };
1042
+ const body = String(row.body ?? "").trim();
1043
+ return `${renderFrontmatter(fm)}
1044
+
1045
+ ${body}
1046
+ `;
1047
+ }
1048
+ function parseSourceSessions(v) {
1049
+ if (Array.isArray(v))
1050
+ return v.map(String);
1051
+ if (typeof v === "string") {
1052
+ try {
1053
+ const parsed = JSON.parse(v);
1054
+ if (Array.isArray(parsed))
1055
+ return parsed.map(String);
1056
+ } catch {
1057
+ }
1058
+ }
1059
+ return [];
1060
+ }
1061
+ function renderFrontmatter(fm) {
1062
+ const lines = ["---"];
1063
+ lines.push(`name: ${fm.name}`);
1064
+ lines.push(`description: ${JSON.stringify(fm.description)}`);
1065
+ if (fm.trigger)
1066
+ lines.push(`trigger: ${JSON.stringify(fm.trigger)}`);
1067
+ lines.push(`source_sessions:`);
1068
+ for (const s of fm.source_sessions)
1069
+ lines.push(` - ${s}`);
1070
+ lines.push(`version: ${fm.version}`);
1071
+ lines.push(`created_by_agent: ${fm.created_by_agent}`);
1072
+ lines.push(`created_at: ${fm.created_at}`);
1073
+ lines.push(`updated_at: ${fm.updated_at}`);
1074
+ lines.push("---");
1075
+ return lines.join("\n");
1076
+ }
1077
+ function readLocalVersion(path) {
1078
+ if (!existsSync8(path))
1079
+ return null;
1080
+ try {
1081
+ const text = readFileSync7(path, "utf-8");
1082
+ const parsed = parseFrontmatter(text);
1083
+ if (!parsed)
1084
+ return null;
1085
+ const v = parsed.fm.version;
1086
+ return typeof v === "number" ? v : null;
1087
+ } catch {
1088
+ return null;
1089
+ }
1090
+ }
1091
+ function decideAction(args) {
1092
+ const shouldWrite = args.localVersion === null || args.remoteVersion > args.localVersion || args.force;
1093
+ if (!shouldWrite)
1094
+ return "skipped";
1095
+ return args.dryRun ? "dryrun" : "wrote";
1096
+ }
1097
+ async function runPull(opts) {
1098
+ if (!opts.dryRun)
1099
+ pruneOrphanedEntries();
1100
+ const sql = buildPullSql({
1101
+ tableName: opts.tableName,
1102
+ users: opts.users,
1103
+ skillName: opts.skillName
1104
+ });
1105
+ let rows = [];
1106
+ try {
1107
+ rows = await opts.query(sql);
1108
+ } catch (e) {
1109
+ if (isMissingTableError(e?.message))
1110
+ rows = [];
1111
+ else
1112
+ throw e;
1113
+ }
1114
+ const latest = selectLatestPerName(rows);
1115
+ const root = resolvePullDestination(opts.install, opts.cwd);
1116
+ const summary = { scanned: latest.length, wrote: 0, skipped: 0, dryrun: 0, entries: [] };
1117
+ for (const row of latest) {
1118
+ const name = String(row.name ?? "");
1119
+ if (!name)
1120
+ continue;
1121
+ try {
1122
+ assertValidSkillName(name);
1123
+ } catch (e) {
1124
+ summary.entries.push({
1125
+ name,
1126
+ remoteVersion: Number(row.version ?? 1),
1127
+ localVersion: null,
1128
+ action: "skipped",
1129
+ destination: "(invalid name \u2014 skipped)",
1130
+ author: String(row.author ?? ""),
1131
+ sourceAgent: String(row.source_agent ?? "")
1132
+ });
1133
+ summary.skipped++;
1134
+ continue;
1135
+ }
1136
+ const author = String(row.author ?? "");
1137
+ if (!author) {
1138
+ summary.entries.push({
1139
+ name,
1140
+ remoteVersion: Number(row.version ?? 1),
1141
+ localVersion: null,
1142
+ action: "skipped",
1143
+ destination: "(empty author \u2014 skipped)",
1144
+ author: "",
1145
+ sourceAgent: String(row.source_agent ?? "")
1146
+ });
1147
+ summary.skipped++;
1148
+ continue;
1149
+ }
1150
+ let dirName;
1151
+ try {
1152
+ assertValidAuthor(author);
1153
+ dirName = `${name}--${author}`;
1154
+ } catch (e) {
1155
+ summary.entries.push({
1156
+ name,
1157
+ remoteVersion: Number(row.version ?? 1),
1158
+ localVersion: null,
1159
+ action: "skipped",
1160
+ destination: `(invalid author '${author}' \u2014 skipped)`,
1161
+ author,
1162
+ sourceAgent: String(row.source_agent ?? "")
1163
+ });
1164
+ summary.skipped++;
1165
+ continue;
1166
+ }
1167
+ const skillDir = join11(root, dirName);
1168
+ const skillFile = join11(skillDir, "SKILL.md");
1169
+ const remoteVersion = Number(row.version ?? 1);
1170
+ const localVersion = readLocalVersion(skillFile);
1171
+ const action = decideAction({
1172
+ remoteVersion,
1173
+ localVersion,
1174
+ force: opts.force ?? false,
1175
+ dryRun: opts.dryRun ?? false
1176
+ });
1177
+ let manifestError;
1178
+ if (action === "wrote") {
1179
+ mkdirSync5(skillDir, { recursive: true });
1180
+ if (existsSync8(skillFile)) {
1181
+ try {
1182
+ renameSync3(skillFile, `${skillFile}.bak`);
1183
+ } catch {
1184
+ }
1185
+ }
1186
+ writeFileSync5(skillFile, renderSkillFile(row));
1187
+ const symlinks = opts.install === "global" ? fanOutSymlinks(skillDir, dirName, detectAgentSkillsRoots(root)) : [];
1188
+ try {
1189
+ recordPull({
1190
+ dirName,
1191
+ name,
1192
+ author,
1193
+ projectKey: String(row.project_key ?? ""),
1194
+ remoteVersion,
1195
+ install: opts.install,
1196
+ installRoot: root,
1197
+ pulledAt: (/* @__PURE__ */ new Date()).toISOString(),
1198
+ symlinks
1199
+ });
1200
+ } catch (e) {
1201
+ manifestError = e?.message ?? String(e);
1202
+ }
1203
+ }
1204
+ summary.entries.push({
1205
+ name,
1206
+ remoteVersion,
1207
+ localVersion,
1208
+ action,
1209
+ destination: skillFile,
1210
+ author: String(row.author ?? ""),
1211
+ sourceAgent: String(row.source_agent ?? ""),
1212
+ manifestError
1213
+ });
1214
+ if (action === "wrote")
1215
+ summary.wrote++;
1216
+ else if (action === "dryrun")
1217
+ summary.dryrun++;
1218
+ else
1219
+ summary.skipped++;
1220
+ }
1221
+ if (!opts.dryRun && opts.install === "global") {
1222
+ backfillSymlinks(root);
1223
+ }
1224
+ return summary;
1225
+ }
1226
+
1227
+ // dist/src/skillify/auto-pull.js
1228
+ var log4 = (msg) => log("skillify-autopull", msg);
1229
+ var DEFAULT_TIMEOUT_MS = 5e3;
1230
+ function withTimeout(p, ms) {
1231
+ let timer = null;
1232
+ const timeout = new Promise((_, reject) => {
1233
+ timer = setTimeout(() => reject(new Error(`autopull timeout after ${ms}ms`)), ms);
1234
+ if (typeof timer.unref === "function")
1235
+ timer.unref();
1236
+ });
1237
+ return Promise.race([p, timeout]).finally(() => {
1238
+ if (timer)
1239
+ clearTimeout(timer);
1240
+ });
1241
+ }
1242
+ async function autoPullSkills(deps = {}) {
1243
+ if (process.env.HIVEMIND_AUTOPULL_DISABLED === "1") {
1244
+ log4("disabled via HIVEMIND_AUTOPULL_DISABLED=1");
1245
+ return { pulled: 0, skipped: true, reason: "disabled" };
1246
+ }
1247
+ const loadFn = deps.loadConfigFn ?? loadConfig;
1248
+ const config = loadFn();
1249
+ if (!config) {
1250
+ log4("skipped: not logged in");
1251
+ return { pulled: 0, skipped: true, reason: "not-logged-in" };
1252
+ }
1253
+ let query;
1254
+ if (deps.queryFn) {
1255
+ query = deps.queryFn;
1256
+ } else {
1257
+ const api = new DeeplakeApi(config.token, config.apiUrl, config.orgId, config.workspaceId, config.skillsTableName);
1258
+ query = (sql) => api.query(sql);
1259
+ }
1260
+ const install = deps.install ?? "global";
1261
+ const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1262
+ try {
1263
+ const summary = await withTimeout(runPull({
1264
+ query,
1265
+ tableName: config.skillsTableName,
1266
+ install,
1267
+ cwd: install === "project" ? deps.cwd ?? process.cwd() : void 0,
1268
+ users: [],
1269
+ dryRun: false,
1270
+ force: false
1271
+ }), timeoutMs);
1272
+ log4(`pulled scanned=${summary.scanned} wrote=${summary.wrote} skipped=${summary.skipped}`);
1273
+ return { pulled: summary.wrote, skipped: false };
1274
+ } catch (e) {
1275
+ log4(`pull failed (swallowed): ${e?.message ?? e}`);
1276
+ return { pulled: 0, skipped: true, reason: "error" };
1277
+ }
1278
+ }
1279
+
674
1280
  // dist/src/hooks/cursor/session-start.js
675
- var log4 = (msg) => log("cursor-session-start", msg);
676
- var __bundleDir = dirname2(fileURLToPath(import.meta.url));
1281
+ var log5 = (msg) => log("cursor-session-start", msg);
1282
+ var __bundleDir = dirname4(fileURLToPath(import.meta.url));
677
1283
  var context = `DEEPLAKE MEMORY: Persistent memory at ~/.deeplake/memory/ shared across sessions, users, and agents.
678
1284
 
679
1285
  Structure: index.md (start here) \u2192 summaries/*.md \u2192 sessions/*.jsonl (last resort). Do NOT jump straight to JSONL.
@@ -692,23 +1298,23 @@ Organization management \u2014 each argument is SEPARATE (do NOT quote subcomman
692
1298
  - hivemind members \u2014 list members
693
1299
  - hivemind remove <user-id> \u2014 remove member
694
1300
 
695
- SKILLS (skilify) \u2014 mine + share reusable skills across the org:
696
- - hivemind skilify \u2014 show scope/team/install + per-project state
697
- - hivemind skilify pull \u2014 sync project skills from the org table
698
- - hivemind skilify pull --user <email> \u2014 only that author's skills
699
- - hivemind skilify pull --users a,b,c \u2014 multiple authors (CSV)
700
- - hivemind skilify pull --all-users \u2014 explicit "no author filter"
701
- - hivemind skilify pull --to project|global \u2014 install location
702
- - hivemind skilify pull --dry-run \u2014 preview only
703
- - hivemind skilify pull --force \u2014 overwrite local (creates .bak)
704
- - hivemind skilify pull <skill-name> \u2014 pull only that skill (combines with --user)
705
- - hivemind skilify unpull \u2014 remove every skill previously installed by pull
706
- - hivemind skilify unpull --user <email> \u2014 remove only that author's pulls
707
- - hivemind skilify unpull --not-mine \u2014 remove all pulls except your own
708
- - hivemind skilify unpull --dry-run \u2014 preview without touching disk
709
- - hivemind skilify scope <me|team|org> \u2014 sharing scope for new skills
710
- - hivemind skilify install <project|global> \u2014 default install location
711
- - hivemind skilify team add|remove|list <name> \u2014 manage team list`;
1301
+ SKILLS (skillify) \u2014 mine + share reusable skills across the org:
1302
+ - hivemind skillify \u2014 show scope/team/install + per-project state
1303
+ - hivemind skillify pull \u2014 sync project skills from the org table
1304
+ - hivemind skillify pull --user <email> \u2014 only that author's skills
1305
+ - hivemind skillify pull --users a,b,c \u2014 multiple authors (CSV)
1306
+ - hivemind skillify pull --all-users \u2014 explicit "no author filter"
1307
+ - hivemind skillify pull --to project|global \u2014 install location
1308
+ - hivemind skillify pull --dry-run \u2014 preview only
1309
+ - hivemind skillify pull --force \u2014 overwrite local (creates .bak)
1310
+ - hivemind skillify pull <skill-name> \u2014 pull only that skill (combines with --user)
1311
+ - hivemind skillify unpull \u2014 remove every skill previously installed by pull
1312
+ - hivemind skillify unpull --user <email> \u2014 remove only that author's pulls
1313
+ - hivemind skillify unpull --not-mine \u2014 remove all pulls except your own
1314
+ - hivemind skillify unpull --dry-run \u2014 preview without touching disk
1315
+ - hivemind skillify scope <me|team|org> \u2014 sharing scope for new skills
1316
+ - hivemind skillify install <project|global> \u2014 default install location
1317
+ - hivemind skillify team add|remove|list <name> \u2014 manage team list`;
712
1318
  function resolveSessionId(input) {
713
1319
  return input.session_id ?? input.conversation_id ?? `cursor-${Date.now()}`;
714
1320
  }
@@ -746,9 +1352,9 @@ async function main() {
746
1352
  const cwd = resolveCwd(input);
747
1353
  const creds = loadCredentials();
748
1354
  if (!creds?.token) {
749
- log4("no credentials found");
1355
+ log5("no credentials found");
750
1356
  } else {
751
- log4(`credentials loaded: org=${creds.orgName ?? creds.orgId}`);
1357
+ log5(`credentials loaded: org=${creds.orgName ?? creds.orgId}`);
752
1358
  }
753
1359
  await autoUpdate(creds, { agent: "cursor" });
754
1360
  const captureEnabled = process.env.HIVEMIND_CAPTURE !== "false";
@@ -762,12 +1368,14 @@ async function main() {
762
1368
  await api.ensureTable();
763
1369
  await api.ensureSessionsTable(sessionsTable);
764
1370
  await createPlaceholder(api, table, sessionId, cwd, config.userName, config.orgName, config.workspaceId);
765
- log4("placeholder created");
1371
+ log5("placeholder created");
766
1372
  }
767
1373
  } catch (e) {
768
- log4(`placeholder failed: ${e.message}`);
1374
+ log5(`placeholder failed: ${e.message}`);
769
1375
  }
770
1376
  }
1377
+ const pullResult = await autoPullSkills();
1378
+ log5(`autopull: pulled=${pullResult.pulled} skipped=${pullResult.skipped}`);
771
1379
  let versionNotice = "";
772
1380
  const current = getInstalledVersion(__bundleDir, ".claude-plugin");
773
1381
  if (current)
@@ -779,6 +1387,6 @@ Not logged in to Deeplake. Run: hivemind login${versionNotice}`;
779
1387
  console.log(JSON.stringify({ additional_context: additionalContext }));
780
1388
  }
781
1389
  main().catch((e) => {
782
- log4(`fatal: ${e.message}`);
1390
+ log5(`fatal: ${e.message}`);
783
1391
  process.exit(0);
784
1392
  });