@danieldeusing/seedr 0.1.97 → 0.1.98

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.
@@ -18,7 +18,7 @@ function registryDirName(config) {
18
18
  }
19
19
  return value;
20
20
  }
21
- var ALL_TYPES = ["skill", "plugin", "hook", "agent", "mcp", "settings", "command"];
21
+ var ALL_TYPES = ["skill", "plugin", "hook", "agent", "mcp", "settings", "command", "rule"];
22
22
  var KNOWN_TYPES = new Set(ALL_TYPES);
23
23
  function typeDirName(type) {
24
24
  return type === "settings" || type === "mcp" ? type : `${type}s`;
@@ -46,6 +46,23 @@ function canonicalAgents(values) {
46
46
  const present = new Set(values.map(canonicalAgent).filter((a) => a !== null));
47
47
  return CANONICAL_AGENTS.filter((a) => present.has(a));
48
48
  }
49
+ var AGENT_COMPATIBILITY = {
50
+ skill: ["claude", "copilot", "antigravity", "codex", "opencode"],
51
+ command: ["claude"],
52
+ // Copilot's subagent files carry the same name/description frontmatter.
53
+ // OpenCode's do not — theirs use `mode` and a `tools` map — so porting there
54
+ // needs a frontmatter translation, not a path.
55
+ agent: ["claude", "copilot"],
56
+ hook: ["claude"],
57
+ plugin: ["claude", "copilot", "antigravity", "codex", "opencode"],
58
+ settings: ["claude"],
59
+ mcp: ["claude", "codex", "opencode", "copilot"],
60
+ rule: ["claude", "copilot", "antigravity", "codex", "opencode"]
61
+ };
62
+ function isTypeSupported(type, agent) {
63
+ const canonical = canonicalAgent(agent);
64
+ return canonical !== null && AGENT_COMPATIBILITY[type].includes(canonical);
65
+ }
49
66
 
50
67
  // ../registry-ops/src/sourceTypes.ts
51
68
  var CANONICAL_SOURCE_TYPES = ["official", "seedr", "community"];
@@ -759,14 +776,20 @@ async function fetchItemToDestination(item, destPath) {
759
776
  import { homedir as homedir2 } from "os";
760
777
  import { join as join14 } from "path";
761
778
  var home = homedir2();
779
+ var claudeUserRoot = () => process.env.CLAUDE_CONFIG_DIR || join14(home, ".claude");
762
780
  var SKILL_DIRECTORY = {
763
781
  path: "skills"
764
782
  };
765
783
  var ANTIGRAVITY = {
766
784
  name: "Google Antigravity",
767
785
  shortName: "antigravity",
786
+ // Project content is the agent-neutral `.agents/` tree, which IS Antigravity's
787
+ // own project root. The personal tier is not the same spelling: the shipped
788
+ // CLI reads `~/.gemini/config/skills`, and the vendor documentation states
789
+ // outright that `~/.agents` does not exist for it. `~/.gemini/skills` is the
790
+ // predecessor Gemini CLI location and is not written.
768
791
  projectRoot: ".agents",
769
- userRoot: join14(home, ".agents"),
792
+ userRoot: join14(home, ".gemini", "config"),
770
793
  contentTypes: { skill: SKILL_DIRECTORY }
771
794
  };
772
795
  var CODING_AGENTS = {
@@ -774,7 +797,7 @@ var CODING_AGENTS = {
774
797
  name: "Claude Code",
775
798
  shortName: "claude",
776
799
  projectRoot: ".claude",
777
- userRoot: join14(home, ".claude"),
800
+ userRoot: claudeUserRoot(),
778
801
  contentTypes: {
779
802
  skill: SKILL_DIRECTORY,
780
803
  command: {
@@ -800,9 +823,15 @@ var CODING_AGENTS = {
800
823
  copilot: {
801
824
  name: "GitHub Copilot",
802
825
  shortName: "copilot",
826
+ // Project content is `.github/`, but the personal tier is `~/.copilot/` —
827
+ // the two are not the same spelling. `~/.github/skills` is read by nothing;
828
+ // `~/.copilot/skills` is what the CLI itself populates.
803
829
  projectRoot: ".github",
804
- userRoot: join14(home, ".github"),
805
- contentTypes: { skill: SKILL_DIRECTORY }
830
+ userRoot: join14(home, ".copilot"),
831
+ // Subagents are `<name>.agent.md` under `agents/`, with the same
832
+ // `name` + `description` frontmatter a Claude subagent carries — confirmed
833
+ // from files on a real machine.
834
+ contentTypes: { skill: SKILL_DIRECTORY, agent: { path: "agents" } }
806
835
  },
807
836
  antigravity: ANTIGRAVITY,
808
837
  gemini: ANTIGRAVITY,
@@ -849,7 +878,7 @@ function getSettingsPath(scope, cwd = process.cwd()) {
849
878
  case "project":
850
879
  return join14(cwd, ".claude/settings.json");
851
880
  case "user":
852
- return join14(home, ".claude/settings.json");
881
+ return join14(claudeUserRoot(), "settings.json");
853
882
  case "local":
854
883
  return join14(cwd, ".claude/settings.local.json");
855
884
  }
@@ -858,11 +887,13 @@ function getMcpConfigPath(agent, scope, cwd = process.cwd()) {
858
887
  const isUser = scope === "user";
859
888
  switch (canonicalAgent(agent) ?? agent) {
860
889
  case "claude":
861
- return isUser ? join14(home, ".claude.json") : join14(cwd, ".mcp.json");
890
+ return isUser ? join14(process.env.CLAUDE_CONFIG_DIR || home, ".claude.json") : join14(cwd, ".mcp.json");
862
891
  case "codex":
863
892
  return isUser ? join14(home, ".codex", "config.toml") : join14(cwd, ".codex", "config.toml");
864
893
  case "opencode":
865
894
  return isUser ? join14(home, ".config", "opencode", "opencode.json") : join14(cwd, "opencode.json");
895
+ case "copilot":
896
+ return isUser ? join14(home, ".copilot", "mcp-config.json") : join14(cwd, ".github", "mcp.json");
866
897
  default:
867
898
  throw new Error(`${agent} has no verified MCP configuration format`);
868
899
  }
@@ -1041,18 +1072,94 @@ function error(message) {
1041
1072
  }
1042
1073
 
1043
1074
  // src/handlers/skill.ts
1044
- import { relative as relative5, dirname as dirname7 } from "path";
1075
+ import { relative as relative5, dirname as dirname8, join as join15 } from "path";
1045
1076
  import { homedir as homedir3 } from "os";
1046
1077
  import { readdir as readdir2, symlink as symlink2 } from "fs/promises";
1047
1078
  import chalk2 from "chalk";
1048
1079
  import ora from "ora";
1080
+
1081
+ // src/utils/json.ts
1082
+ import { readFile as readFile4, stat as stat2 } from "fs/promises";
1083
+ import { dirname as dirname7 } from "path";
1084
+ async function readJson(path) {
1085
+ try {
1086
+ const content = await readFile4(path, "utf-8");
1087
+ return JSON.parse(content);
1088
+ } catch (error2) {
1089
+ if (error2.code === "ENOENT") {
1090
+ return {};
1091
+ }
1092
+ if (error2 instanceof SyntaxError) {
1093
+ throw new Error(`${path} is not valid JSON: ${error2.message}`, { cause: error2 });
1094
+ }
1095
+ throw error2;
1096
+ }
1097
+ }
1098
+ async function existingFileMode(path) {
1099
+ try {
1100
+ return (await stat2(path)).mode & 511;
1101
+ } catch (error2) {
1102
+ if (error2.code === "ENOENT") return void 0;
1103
+ throw error2;
1104
+ }
1105
+ }
1106
+ async function writeJson(path, data) {
1107
+ await ensureDir(dirname7(path));
1108
+ const mode = await existingFileMode(path);
1109
+ await writeFileAtomic(path, JSON.stringify(data, null, 2) + "\n", { mode });
1110
+ }
1111
+ function deepMerge(target, source) {
1112
+ const result = { ...target };
1113
+ for (const key of Object.keys(source)) {
1114
+ const sourceValue = source[key];
1115
+ const targetValue = result[key];
1116
+ if (sourceValue !== null && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue !== null && typeof targetValue === "object" && !Array.isArray(targetValue)) {
1117
+ result[key] = deepMerge(
1118
+ targetValue,
1119
+ sourceValue
1120
+ );
1121
+ } else if (sourceValue !== void 0) {
1122
+ result[key] = sourceValue;
1123
+ }
1124
+ }
1125
+ return result;
1126
+ }
1127
+
1128
+ // src/handlers/skill.ts
1049
1129
  var SLUG_LABEL = "skill slug";
1050
- var READS_CENTRAL_DIR = /* @__PURE__ */ new Set(["antigravity", "codex", "opencode"]);
1130
+ function readsCentralDir(agent, scope) {
1131
+ const canonical = canonicalAgent(agent) ?? agent;
1132
+ if (canonical === "antigravity") return scope !== "user";
1133
+ return canonical === "codex" || canonical === "opencode";
1134
+ }
1135
+ var OWNERS_FILE = ".seedr-central-owners.json";
1136
+ async function readOwners(scope, cwd) {
1137
+ return readJson(join15(centralSkillsDir(scope, cwd), OWNERS_FILE));
1138
+ }
1139
+ async function writeOwners(owners, scope, cwd) {
1140
+ await writeJson(join15(centralSkillsDir(scope, cwd), OWNERS_FILE), owners);
1141
+ }
1142
+ async function addOwners(slug, agents, scope, cwd) {
1143
+ if (agents.length === 0) return;
1144
+ const owners = await readOwners(scope, cwd);
1145
+ owners[slug] = [.../* @__PURE__ */ new Set([...owners[slug] ?? [], ...agents])];
1146
+ await writeOwners(owners, scope, cwd);
1147
+ }
1148
+ async function dropOwner(slug, agent, scope, cwd) {
1149
+ const owners = await readOwners(scope, cwd);
1150
+ const recorded = owners[slug];
1151
+ if (!recorded) return [];
1152
+ const remaining = recorded.filter((owner) => owner !== (canonicalAgent(agent) ?? agent));
1153
+ if (remaining.length > 0) owners[slug] = remaining;
1154
+ else delete owners[slug];
1155
+ await writeOwners(owners, scope, cwd);
1156
+ return remaining;
1157
+ }
1051
1158
  function getScopeRoot(scope, cwd) {
1052
1159
  return scope === "user" ? homedir3() : cwd;
1053
1160
  }
1054
1161
  function centralSkillsDir(scope, cwd) {
1055
- return dirname7(getAgentsPath("skill", "any-slug", scope, cwd));
1162
+ return dirname8(getAgentsPath("skill", "any-slug", scope, cwd));
1056
1163
  }
1057
1164
  async function resolveCentralPath(slug, scope, cwd) {
1058
1165
  const scopeRoot = getScopeRoot(scope, cwd);
@@ -1077,9 +1184,9 @@ async function installToCentralLocation(item, sourcePath, scope, force, cwd) {
1077
1184
  return { centralPath, created: !existed };
1078
1185
  }
1079
1186
  async function createAgentSymlink(centralPath, destPath) {
1080
- await ensureDir(dirname7(destPath));
1187
+ await ensureDir(dirname8(destPath));
1081
1188
  await removePathEntry(destPath);
1082
- const relPath = relative5(dirname7(destPath), centralPath);
1189
+ const relPath = relative5(dirname8(destPath), centralPath);
1083
1190
  await symlink2(relPath, destPath);
1084
1191
  }
1085
1192
  async function installSkillForAgent(item, agent, scope, method, force, cwd, centralPath) {
@@ -1121,7 +1228,7 @@ async function installSkill(item, agents, scope, method, force, cwd = process.cw
1121
1228
  central = await installToCentralLocation(item, sourcePath, scope, force, cwd);
1122
1229
  }
1123
1230
  for (const agent of agents) {
1124
- if (READS_CENTRAL_DIR.has(canonicalAgent(agent) ?? agent) && central) {
1231
+ if (readsCentralDir(agent, scope) && central) {
1125
1232
  results.push({ agent, success: true, path: central.centralPath });
1126
1233
  continue;
1127
1234
  }
@@ -1138,15 +1245,30 @@ async function installSkill(item, agents, scope, method, force, cwd = process.cw
1138
1245
  }
1139
1246
  if (central?.created && !results.some((result) => result.success)) {
1140
1247
  await removePathEntry(central.centralPath);
1248
+ return results;
1249
+ }
1250
+ if (central) {
1251
+ const centralReaders = agents.filter(
1252
+ (agent) => readsCentralDir(agent, scope) && results.some((result) => result.agent === agent && result.success)
1253
+ );
1254
+ await addOwners(item.slug, centralReaders, scope, cwd);
1141
1255
  }
1142
1256
  return results;
1143
1257
  }
1144
1258
  async function uninstallSkill(slug, agent, scope, cwd = process.cwd()) {
1145
1259
  assertValidSlug(slug, SLUG_LABEL);
1260
+ const central = await resolveCentralPath(slug, scope, cwd);
1146
1261
  const destPath = await resolveAgentSkillPath(agent, slug, scope, cwd);
1147
- if (destPath && await removePathEntry(destPath)) return true;
1148
- if (READS_CENTRAL_DIR.has(canonicalAgent(agent) ?? agent)) {
1149
- return removePathEntry(await resolveCentralPath(slug, scope, cwd));
1262
+ if (readsCentralDir(agent, scope) || destPath === central) {
1263
+ const remaining = await dropOwner(slug, agent, scope, cwd);
1264
+ if (remaining.length > 0) {
1265
+ return true;
1266
+ }
1267
+ return removePathEntry(central);
1268
+ }
1269
+ if (destPath && await removePathEntry(destPath)) {
1270
+ await dropOwner(slug, agent, scope, cwd);
1271
+ return true;
1150
1272
  }
1151
1273
  return false;
1152
1274
  }
@@ -1154,13 +1276,21 @@ async function getInstalledSkills(agent, scope, cwd = process.cwd()) {
1154
1276
  const dirs = /* @__PURE__ */ new Set();
1155
1277
  const own = getContentPath(agent, "skill", scope, cwd);
1156
1278
  if (own) dirs.add(own);
1157
- if (READS_CENTRAL_DIR.has(canonicalAgent(agent) ?? agent)) dirs.add(centralSkillsDir(scope, cwd));
1279
+ if (readsCentralDir(agent, scope)) dirs.add(centralSkillsDir(scope, cwd));
1280
+ const owners = await readOwners(scope, cwd);
1281
+ const centralDir = centralSkillsDir(scope, cwd);
1282
+ const canonical = canonicalAgent(agent) ?? agent;
1283
+ const isInstalledHere = (entry, dir) => {
1284
+ if (entry.name.startsWith(".")) return false;
1285
+ if (!entry.isDirectory() && !entry.isSymbolicLink()) return false;
1286
+ const recorded = dir === centralDir ? owners[entry.name] : void 0;
1287
+ return !recorded || recorded.includes(canonical);
1288
+ };
1158
1289
  const slugs = /* @__PURE__ */ new Set();
1159
1290
  for (const dir of dirs) {
1160
1291
  if (!await exists(dir)) continue;
1161
- const entries = await readdir2(dir, { withFileTypes: true });
1162
- for (const entry of entries) {
1163
- if ((entry.isDirectory() || entry.isSymbolicLink()) && !entry.name.startsWith(".")) slugs.add(entry.name);
1292
+ for (const entry of await readdir2(dir, { withFileTypes: true })) {
1293
+ if (isInstalledHere(entry, dir)) slugs.add(entry.name);
1164
1294
  }
1165
1295
  }
1166
1296
  return [...slugs];
@@ -1172,7 +1302,7 @@ async function planSkill(item, agents, scope, method, cwd) {
1172
1302
  let centralPath;
1173
1303
  if (method === "symlink") {
1174
1304
  centralPath = await resolveCentralPath(item.slug, scope, cwd);
1175
- const sharedBy = agents.filter((agent) => READS_CENTRAL_DIR.has(canonicalAgent(agent) ?? agent));
1305
+ const sharedBy = agents.filter((agent) => readsCentralDir(agent, scope));
1176
1306
  changes.push({
1177
1307
  agent: "shared",
1178
1308
  kind: await kindFor(centralPath),
@@ -1181,7 +1311,7 @@ async function planSkill(item, agents, scope, method, cwd) {
1181
1311
  });
1182
1312
  }
1183
1313
  for (const agent of agents) {
1184
- if (centralPath && READS_CENTRAL_DIR.has(canonicalAgent(agent) ?? agent)) continue;
1314
+ if (centralPath && readsCentralDir(agent, scope)) continue;
1185
1315
  const destPath = await resolveAgentSkillPath(agent, item.slug, scope, cwd);
1186
1316
  if (!destPath) throw new Error(`${CODING_AGENTS[agent].name} does not support skills`);
1187
1317
  changes.push({
@@ -1208,10 +1338,13 @@ var skillHandler = {
1208
1338
  };
1209
1339
 
1210
1340
  export {
1341
+ ALL_TYPES,
1211
1342
  mainFileName,
1212
1343
  isLegacyAgent,
1213
1344
  canonicalAgent,
1214
1345
  canonicalAgents,
1346
+ AGENT_COMPATIBILITY,
1347
+ isTypeSupported,
1215
1348
  SLUG_PATTERN2 as SLUG_PATTERN,
1216
1349
  MAX_SLUG_LENGTH2 as MAX_SLUG_LENGTH,
1217
1350
  isValidSlug2 as isValidSlug,
@@ -1242,6 +1375,7 @@ export {
1242
1375
  fetchItemFile,
1243
1376
  getItemSourcePath,
1244
1377
  fetchItemToDestination,
1378
+ claudeUserRoot,
1245
1379
  CODING_AGENTS,
1246
1380
  ALL_AGENTS,
1247
1381
  getAgentConfig,
@@ -1269,6 +1403,9 @@ export {
1269
1403
  success,
1270
1404
  warn,
1271
1405
  error,
1406
+ readJson,
1407
+ writeJson,
1408
+ deepMerge,
1272
1409
  installSkill,
1273
1410
  uninstallSkill,
1274
1411
  getInstalledSkills,