@toolr/seedr 0.1.2 → 0.1.3

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.
@@ -102,77 +102,159 @@ function getItemSourcePath(item) {
102
102
  import { homedir } from "os";
103
103
  import { join as join2 } from "path";
104
104
  var home = homedir();
105
- var SKILL_FORMAT_MARKDOWN = "markdown";
106
- var SKILL_EXTENSION_MD = ".md";
107
- var COPILOT_PATH = ".github/copilot-instructions";
108
- var OPENCODE_PATH = ".opencode/agents";
109
105
  var AI_TOOLS = {
110
106
  claude: {
111
107
  name: "Claude Code",
112
108
  shortName: "claude",
113
- projectPath: ".claude/commands",
114
- userPath: join2(home, ".claude/commands"),
115
- globalPath: "/Library/Application Support/ClaudeCode/commands",
116
- skillFormat: SKILL_FORMAT_MARKDOWN,
117
- skillExtension: SKILL_EXTENSION_MD,
118
- skillDir: "commands"
109
+ projectRoot: ".claude",
110
+ userRoot: join2(home, ".claude"),
111
+ contentTypes: {
112
+ skill: {
113
+ path: "skills",
114
+ extension: ".md",
115
+ structure: "directory",
116
+ mainFile: "SKILL.md"
117
+ },
118
+ command: {
119
+ path: "commands",
120
+ extension: ".md",
121
+ structure: "directory",
122
+ mainFile: "COMMAND.md"
123
+ },
124
+ agent: {
125
+ path: "agents",
126
+ extension: ".md",
127
+ structure: "file"
128
+ },
129
+ hook: {
130
+ path: "",
131
+ extension: ".json",
132
+ structure: "json-merge",
133
+ mergeTarget: "settings.json",
134
+ mergeField: "hooks"
135
+ },
136
+ plugin: {
137
+ path: "plugins/cache",
138
+ extension: "",
139
+ structure: "plugin"
140
+ },
141
+ settings: {
142
+ path: "",
143
+ extension: ".json",
144
+ structure: "json-merge",
145
+ mergeTarget: "settings.json"
146
+ },
147
+ mcp: {
148
+ path: "",
149
+ extension: ".json",
150
+ structure: "json-merge",
151
+ mergeTarget: ".mcp.json",
152
+ mergeField: "mcpServers"
153
+ }
154
+ }
119
155
  },
120
156
  copilot: {
121
157
  name: "GitHub Copilot",
122
158
  shortName: "copilot",
123
- projectPath: COPILOT_PATH,
124
- userPath: join2(home, COPILOT_PATH),
125
- globalPath: join2(home, COPILOT_PATH),
126
- skillFormat: SKILL_FORMAT_MARKDOWN,
127
- skillExtension: ".instructions.md",
128
- skillDir: "copilot-instructions"
159
+ projectRoot: ".github",
160
+ userRoot: join2(home, ".github"),
161
+ contentTypes: {
162
+ skill: {
163
+ path: "skills",
164
+ extension: ".md",
165
+ structure: "directory",
166
+ mainFile: "SKILL.md"
167
+ }
168
+ }
129
169
  },
130
170
  gemini: {
131
171
  name: "Gemini Code Assist",
132
172
  shortName: "gemini",
133
- projectPath: ".gemini",
134
- userPath: join2(home, ".gemini"),
135
- globalPath: join2(home, ".gemini"),
136
- skillFormat: SKILL_FORMAT_MARKDOWN,
137
- skillExtension: SKILL_EXTENSION_MD,
138
- skillDir: ".gemini"
173
+ projectRoot: ".gemini",
174
+ userRoot: join2(home, ".gemini"),
175
+ contentTypes: {
176
+ skill: {
177
+ path: "skills",
178
+ extension: ".md",
179
+ structure: "directory",
180
+ mainFile: "SKILL.md"
181
+ }
182
+ }
139
183
  },
140
184
  codex: {
141
- name: "OpenAI Codex",
185
+ name: "OpenAI Codex CLI",
142
186
  shortName: "codex",
143
- projectPath: ".codex",
144
- userPath: join2(home, ".codex"),
145
- globalPath: join2(home, ".codex"),
146
- skillFormat: SKILL_FORMAT_MARKDOWN,
147
- skillExtension: SKILL_EXTENSION_MD,
148
- skillDir: ".codex"
187
+ projectRoot: ".codex",
188
+ userRoot: join2(home, ".codex"),
189
+ contentTypes: {
190
+ skill: {
191
+ path: "skills",
192
+ extension: ".md",
193
+ structure: "directory",
194
+ mainFile: "SKILL.md"
195
+ }
196
+ }
149
197
  },
150
198
  opencode: {
151
199
  name: "OpenCode",
152
200
  shortName: "opencode",
153
- projectPath: OPENCODE_PATH,
154
- userPath: join2(home, OPENCODE_PATH),
155
- globalPath: join2(home, OPENCODE_PATH),
156
- skillFormat: SKILL_FORMAT_MARKDOWN,
157
- skillExtension: SKILL_EXTENSION_MD,
158
- skillDir: "agents"
201
+ projectRoot: ".opencode",
202
+ userRoot: join2(home, ".opencode"),
203
+ contentTypes: {
204
+ skill: {
205
+ path: "skills",
206
+ extension: ".md",
207
+ structure: "directory",
208
+ mainFile: "SKILL.md"
209
+ }
210
+ }
159
211
  }
160
212
  };
161
213
  var ALL_TOOLS = Object.keys(AI_TOOLS);
162
214
  function getToolConfig(tool) {
163
215
  return AI_TOOLS[tool];
164
216
  }
165
- function getToolPath(tool, scope, cwd = process.cwd()) {
217
+ function getContentTypeConfig(tool, type) {
218
+ return AI_TOOLS[tool].contentTypes[type];
219
+ }
220
+ function getToolRoot(tool, scope, cwd = process.cwd()) {
166
221
  const config = AI_TOOLS[tool];
167
222
  switch (scope) {
168
223
  case "project":
169
- return join2(cwd, config.projectPath);
224
+ case "local":
225
+ return join2(cwd, config.projectRoot);
170
226
  case "user":
171
- return config.userPath;
172
- case "global":
173
- return config.globalPath;
227
+ return config.userRoot;
174
228
  }
175
229
  }
230
+ function getContentPath(tool, type, scope, cwd = process.cwd()) {
231
+ const typeConfig = getContentTypeConfig(tool, type);
232
+ if (!typeConfig) return void 0;
233
+ const root = getToolRoot(tool, scope, cwd);
234
+ return typeConfig.path ? join2(root, typeConfig.path) : root;
235
+ }
236
+ function getSettingsPath(scope, cwd = process.cwd()) {
237
+ switch (scope) {
238
+ case "project":
239
+ return join2(cwd, ".claude/settings.json");
240
+ case "user":
241
+ return join2(home, ".claude/settings.json");
242
+ case "local":
243
+ return join2(cwd, ".claude/settings.local.json");
244
+ }
245
+ }
246
+ function getMcpPath(scope, cwd = process.cwd()) {
247
+ switch (scope) {
248
+ case "project":
249
+ case "local":
250
+ return join2(cwd, ".mcp.json");
251
+ case "user":
252
+ return join2(home, ".claude.json");
253
+ }
254
+ }
255
+ function getToolPath(tool, scope, cwd = process.cwd()) {
256
+ return getContentPath(tool, "skill", scope, cwd) || "";
257
+ }
176
258
 
177
259
  // src/utils/fs.ts
178
260
  import {
@@ -222,6 +304,26 @@ async function writeTextFile(path, content) {
222
304
  await ensureDir(dirname2(path));
223
305
  await writeFile(path, content, "utf-8");
224
306
  }
307
+ function getAgentsPath(contentType, slug, cwd) {
308
+ return join3(cwd, ".agents", contentType + "s", slug);
309
+ }
310
+ async function copyDirectory(source, destination) {
311
+ const { cp } = await import("fs/promises");
312
+ await cp(source, destination, { recursive: true });
313
+ }
314
+ async function installDirectory(source, destination, method) {
315
+ await ensureDir(dirname2(destination));
316
+ if (await exists(destination)) {
317
+ const { rm } = await import("fs/promises");
318
+ await rm(destination, { recursive: true });
319
+ }
320
+ if (method === "symlink") {
321
+ const relPath = relative(dirname2(destination), source);
322
+ await symlink(relPath, destination);
323
+ } else {
324
+ await copyDirectory(source, destination);
325
+ }
326
+ }
225
327
 
226
328
  // src/utils/detection.ts
227
329
  async function detectInstalledTools(cwd = process.cwd()) {
@@ -249,7 +351,8 @@ async function detectProjectTools(cwd = process.cwd()) {
249
351
  return detected;
250
352
  }
251
353
  async function isToolInstalled(tool, scope, cwd = process.cwd()) {
252
- const path = getToolPath(tool, scope, cwd);
354
+ const effectiveScope = scope === "local" ? "project" : scope;
355
+ const path = getToolPath(tool, effectiveScope, cwd);
253
356
  return exists(path);
254
357
  }
255
358
  function parseToolArg(arg) {
@@ -277,143 +380,47 @@ function parseToolsArg(agents, allTools) {
277
380
  return agents.split(",").map((t) => parseToolArg(t.trim())).filter((t) => t !== null);
278
381
  }
279
382
 
280
- // src/converters/index.ts
281
- import matter from "gray-matter";
282
-
283
- // src/converters/claude.ts
284
- var claudeConverter = {
285
- convert(skill) {
286
- return skill.raw;
287
- }
288
- };
289
-
290
- // src/converters/copilot.ts
291
- var copilotConverter = {
292
- convert(skill) {
293
- const { frontmatter, body } = skill;
294
- const lines = [];
295
- if (frontmatter.name) {
296
- lines.push(`# ${frontmatter.name}`, "");
297
- }
298
- if (frontmatter.description) {
299
- lines.push(frontmatter.description, "");
300
- }
301
- lines.push(body);
302
- return lines.join("\n");
303
- }
304
- };
305
-
306
- // src/converters/gemini.ts
307
- var geminiConverter = {
308
- convert(skill) {
309
- const { frontmatter, body } = skill;
310
- const lines = [];
311
- if (frontmatter.name) {
312
- lines.push(`# ${frontmatter.name}`, "");
313
- }
314
- if (frontmatter.description) {
315
- lines.push(`> ${frontmatter.description}`, "");
316
- }
317
- lines.push("## Instructions", "", body);
318
- return lines.join("\n");
319
- }
320
- };
321
-
322
- // src/converters/codex.ts
323
- var codexConverter = {
324
- convert(skill) {
325
- const { frontmatter, body } = skill;
326
- const lines = [];
327
- lines.push("# Agent Instructions", "");
328
- if (frontmatter.name) {
329
- lines.push(`**Name:** ${frontmatter.name}`);
330
- }
331
- if (frontmatter.description) {
332
- lines.push(`**Description:** ${frontmatter.description}`);
333
- }
334
- if (frontmatter.name || frontmatter.description) {
335
- lines.push("");
336
- }
337
- lines.push("## Behavior", "", body);
338
- return lines.join("\n");
339
- }
340
- };
341
-
342
- // src/converters/opencode.ts
343
- var opencodeConverter = {
344
- convert(skill) {
345
- const { frontmatter, body } = skill;
346
- const lines = [];
347
- if (frontmatter.name) {
348
- lines.push(`# ${frontmatter.name}`, "");
349
- }
350
- if (frontmatter.description) {
351
- lines.push(frontmatter.description, "");
352
- }
353
- lines.push("---", "", body);
354
- return lines.join("\n");
355
- }
356
- };
357
-
358
- // src/converters/index.ts
359
- var converters = {
360
- claude: claudeConverter,
361
- copilot: copilotConverter,
362
- gemini: geminiConverter,
363
- codex: codexConverter,
364
- opencode: opencodeConverter
365
- };
366
- function parseSkillMarkdown(content) {
367
- const { data, content: body } = matter(content);
368
- return {
369
- frontmatter: data,
370
- body: body.trim(),
371
- raw: content
372
- };
373
- }
374
- function convertSkillToTool(content, targetTool) {
375
- const converter = converters[targetTool];
376
- if (!converter) {
377
- return content;
378
- }
379
- const skill = parseSkillMarkdown(content);
380
- return converter.convert(skill);
381
- }
382
-
383
- // src/utils/convert.ts
384
- function getOutputFilename(slug, tool) {
385
- const config = AI_TOOLS[tool];
386
- return `${slug}${config.skillExtension}`;
387
- }
388
-
389
383
  // src/handlers/skill.ts
390
- import { join as join4, dirname as dirname3 } from "path";
384
+ import { join as join4, relative as relative2, dirname as dirname3 } from "path";
385
+ import { readdir as readdir2, symlink as symlink2 } from "fs/promises";
391
386
  import chalk from "chalk";
392
387
  import ora from "ora";
393
- async function getSkillContent(item, tool) {
394
- const canonicalContent = await getItemContent(item);
395
- return convertSkillToTool(canonicalContent, tool);
388
+ async function installToCentralLocation(item, sourcePath, cwd) {
389
+ const centralPath = getAgentsPath("skill", item.slug, cwd);
390
+ if (await exists(centralPath)) {
391
+ const { rm } = await import("fs/promises");
392
+ await rm(centralPath, { recursive: true });
393
+ }
394
+ await copyDirectory(sourcePath, centralPath);
395
+ return centralPath;
396
396
  }
397
- async function writeSkillFile(item, tool, content, destPath, method) {
398
- const canSymlink = tool === "claude" && item.sourceType === "toolr";
399
- const sourcePath = getItemSourcePath(item);
400
- if (method === "symlink" && canSymlink && sourcePath) {
401
- await installFile(sourcePath, destPath, "symlink");
402
- } else {
403
- await ensureDir(dirname3(destPath));
404
- await writeTextFile(destPath, content);
397
+ async function createToolSymlink(centralPath, destPath) {
398
+ await ensureDir(dirname3(destPath));
399
+ if (await exists(destPath)) {
400
+ const { rm } = await import("fs/promises");
401
+ await rm(destPath, { recursive: true });
405
402
  }
403
+ const relPath = relative2(dirname3(destPath), centralPath);
404
+ await symlink2(relPath, destPath);
406
405
  }
407
- async function installSkillForTool(item, tool, scope, method, cwd) {
406
+ async function installSkillForTool(item, tool, scope, method, cwd, centralPath) {
408
407
  const spinner = ora(
409
408
  `Installing ${item.name} for ${AI_TOOLS[tool].name}...`
410
409
  ).start();
411
410
  try {
412
- const content = await getSkillContent(item, tool);
413
- const destDir = getToolPath(tool, scope, cwd);
414
- const filename = getOutputFilename(item.slug, tool);
415
- const destPath = join4(destDir, filename);
416
- await writeSkillFile(item, tool, content, destPath, method);
411
+ const destDir = getContentPath(tool, "skill", scope, cwd);
412
+ if (!destDir) {
413
+ throw new Error(`${AI_TOOLS[tool].name} does not support skills`);
414
+ }
415
+ const destPath = join4(destDir, item.slug);
416
+ const sourcePath = getItemSourcePath(item);
417
+ if (method === "symlink" && centralPath) {
418
+ await createToolSymlink(centralPath, destPath);
419
+ } else if (sourcePath) {
420
+ await installDirectory(sourcePath, destPath, "copy");
421
+ } else {
422
+ throw new Error("External skill installation not yet implemented");
423
+ }
417
424
  spinner.succeed(
418
425
  chalk.green(`Installed ${item.name} for ${AI_TOOLS[tool].name}`)
419
426
  );
@@ -428,31 +435,59 @@ async function installSkillForTool(item, tool, scope, method, cwd) {
428
435
  }
429
436
  async function installSkill(item, tools, scope, method, cwd = process.cwd()) {
430
437
  const results = [];
438
+ const sourcePath = getItemSourcePath(item);
439
+ let centralPath;
440
+ if (method === "symlink" && sourcePath) {
441
+ centralPath = await installToCentralLocation(item, sourcePath, cwd);
442
+ }
431
443
  for (const tool of tools) {
432
- const result = await installSkillForTool(item, tool, scope, method, cwd);
444
+ const result = await installSkillForTool(
445
+ item,
446
+ tool,
447
+ scope,
448
+ method,
449
+ cwd,
450
+ centralPath
451
+ );
433
452
  results.push(result);
434
453
  }
435
454
  return results;
436
455
  }
437
456
  async function uninstallSkill(slug, tool, scope, cwd = process.cwd()) {
438
- const destDir = getToolPath(tool, scope, cwd);
439
- const filename = getOutputFilename(slug, tool);
440
- const destPath = join4(destDir, filename);
457
+ const destDir = getContentPath(tool, "skill", scope, cwd);
458
+ if (!destDir) return false;
459
+ const destPath = join4(destDir, slug);
441
460
  if (!await exists(destPath)) {
442
461
  return false;
443
462
  }
444
- return removeFile(destPath);
463
+ const { rm } = await import("fs/promises");
464
+ try {
465
+ await rm(destPath, { recursive: true });
466
+ return true;
467
+ } catch {
468
+ return false;
469
+ }
445
470
  }
446
471
  async function getInstalledSkills(tool, scope, cwd = process.cwd()) {
447
- const destDir = getToolPath(tool, scope, cwd);
448
- if (!await exists(destDir)) {
472
+ const destDir = getContentPath(tool, "skill", scope, cwd);
473
+ if (!destDir || !await exists(destDir)) {
449
474
  return [];
450
475
  }
451
- const { readdir: readdir2 } = await import("fs/promises");
452
- const files = await readdir2(destDir);
453
- const config = AI_TOOLS[tool];
454
- return files.filter((f) => f.endsWith(config.skillExtension)).map((f) => f.replace(config.skillExtension, ""));
476
+ const entries = await readdir2(destDir, { withFileTypes: true });
477
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name);
455
478
  }
479
+ var skillHandler = {
480
+ type: "skill",
481
+ async install(item, tools, scope, method, cwd) {
482
+ return installSkill(item, tools, scope, method, cwd);
483
+ },
484
+ async uninstall(slug, tool, scope, cwd) {
485
+ return uninstallSkill(slug, tool, scope, cwd);
486
+ },
487
+ async listInstalled(tool, scope, cwd) {
488
+ return getInstalledSkills(tool, scope, cwd);
489
+ }
490
+ };
456
491
 
457
492
  export {
458
493
  loadManifest,
@@ -460,20 +495,27 @@ export {
460
495
  listItems,
461
496
  searchItems,
462
497
  getItemContent,
498
+ getItemSourcePath,
463
499
  exists,
464
500
  ensureDir,
501
+ installFile,
502
+ removeFile,
465
503
  writeTextFile,
504
+ getAgentsPath,
505
+ installDirectory,
466
506
  AI_TOOLS,
467
507
  ALL_TOOLS,
468
508
  getToolConfig,
509
+ getContentPath,
510
+ getSettingsPath,
511
+ getMcpPath,
469
512
  getToolPath,
470
513
  detectInstalledTools,
471
514
  detectProjectTools,
472
515
  isToolInstalled,
473
516
  parseToolsArg,
474
- parseSkillMarkdown,
475
- convertSkillToTool,
476
517
  installSkill,
477
518
  uninstallSkill,
478
- getInstalledSkills
519
+ getInstalledSkills,
520
+ skillHandler
479
521
  };