@kurokeita/add-skill 1.10.1 → 1.12.0

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/README.md CHANGED
@@ -87,6 +87,7 @@ pnpm dev import https://github.com/owner/repo/tree/main/skills/skill-name
87
87
  | Platform | Agents Path | Skills Path | Workflows Path |
88
88
  | :--- | :--- | :--- | :--- |
89
89
  | Antigravity | *Not Supported* | `~/.gemini/antigravity/global_skills` | `~/.gemini/antigravity/global_workflows` |
90
+ | Claude Code | `~/.claude/agents` | `~/.claude/skills` | `~/.claude/skills` |
90
91
  | Codex | `~/.codex/skills` | `~/.codex/skills` | `~/.codex/skills` |
91
92
  | Gemini CLI | `~/.gemini/agents` | `~/.gemini/skills` | `~/.gemini/commands` |
92
93
  | GitHub Copilot | `~/.copilot/agents` | `~/.copilot/skills` | `~/.copilot/prompts` |
package/dist/bin/cli.js CHANGED
@@ -7,7 +7,7 @@ import pc5 from "picocolors";
7
7
 
8
8
  // src/commands/add.ts
9
9
  import os3 from "node:os";
10
- import path5 from "node:path";
10
+ import path6 from "node:path";
11
11
  import {
12
12
  cancel,
13
13
  confirm,
@@ -119,6 +119,7 @@ function resolveProjectRoot(moduleDir) {
119
119
  var PROJECT_ROOT = resolveProjectRoot(__dirname);
120
120
  var PLATFORM_LABELS = {
121
121
  antigravity: "Antigravity",
122
+ "claude-code": "Claude Code",
122
123
  codex: "Codex",
123
124
  gemini: "Gemini CLI",
124
125
  copilot: "GitHub Copilot",
@@ -126,18 +127,21 @@ var PLATFORM_LABELS = {
126
127
  };
127
128
  var PLATFORM_PATHS_SKILLS = {
128
129
  antigravity: path2.join(os2.homedir(), ".gemini/antigravity/global_skills"),
130
+ "claude-code": path2.join(os2.homedir(), ".claude/skills"),
129
131
  codex: path2.join(os2.homedir(), ".codex/skills"),
130
132
  copilot: path2.join(os2.homedir(), ".copilot/skills"),
131
133
  gemini: path2.join(os2.homedir(), ".gemini/skills"),
132
134
  windsurf: path2.join(os2.homedir(), ".codeium/windsurf/skills")
133
135
  };
134
136
  var PLATFORM_PATHS_AGENTS = {
137
+ "claude-code": path2.join(os2.homedir(), ".claude/agents"),
135
138
  codex: path2.join(os2.homedir(), ".codex/skills"),
136
139
  copilot: path2.join(os2.homedir(), ".copilot/agents"),
137
140
  gemini: path2.join(os2.homedir(), ".gemini/agents")
138
141
  };
139
142
  var PLATFORM_PATHS_WORKFLOWS = {
140
143
  antigravity: path2.join(os2.homedir(), ".gemini/antigravity/global_workflows"),
144
+ "claude-code": path2.join(os2.homedir(), ".claude/skills"),
141
145
  codex: path2.join(os2.homedir(), ".codex/skills"),
142
146
  copilot: path2.join(os2.homedir(), ".copilot/prompts"),
143
147
  gemini: path2.join(os2.homedir(), ".gemini/commands"),
@@ -170,11 +174,106 @@ var AntigravityHandler = class {
170
174
  }
171
175
  };
172
176
 
173
- // src/utils/platforms/codex.ts
177
+ // src/utils/platforms/claude-code.ts
174
178
  import path3 from "node:path";
175
- import fs3 from "fs-extra";
176
179
  import yaml from "js-yaml";
177
180
  var frontmatterRegex = /^---\n([\s\S]*?)\n---/;
181
+ var CLAUDE_CODE_TOOLS = [
182
+ "Read",
183
+ "Edit",
184
+ "Write",
185
+ "Bash",
186
+ "Glob",
187
+ "Grep",
188
+ "WebFetch",
189
+ "WebSearch"
190
+ ];
191
+ var ClaudeCodeHandler = class {
192
+ platform = "claude-code";
193
+ getTargetFileName(itemName, type) {
194
+ if (type === "agent") {
195
+ const name = itemName.replace(/\.md$/, "");
196
+ return path3.join(name, `${name}.md`);
197
+ }
198
+ if (type === "workflow") {
199
+ const name = itemName.replace(/\.md$/, "");
200
+ return path3.join(name, "SKILL.md");
201
+ }
202
+ return itemName;
203
+ }
204
+ transform(content, type, itemName) {
205
+ if (type === "skill") return content;
206
+ if (type === "agent") {
207
+ return this.transformAgent(content, itemName);
208
+ }
209
+ if (type === "workflow") {
210
+ return this.transformWorkflow(content, itemName);
211
+ }
212
+ return content;
213
+ }
214
+ transformAgent(content, itemName) {
215
+ const match = content.match(frontmatterRegex);
216
+ let frontmatter = {
217
+ name: itemName.replace(/\.md$/, ""),
218
+ description: "",
219
+ tools: CLAUDE_CODE_TOOLS
220
+ };
221
+ let body = content;
222
+ if (match) {
223
+ try {
224
+ const parsed = yaml.load(match[1]);
225
+ frontmatter = { ...frontmatter, ...parsed };
226
+ frontmatter.tools = CLAUDE_CODE_TOOLS;
227
+ delete frontmatter.target;
228
+ body = content.replace(frontmatterRegex, "").trim();
229
+ } catch (_) {
230
+ }
231
+ }
232
+ const yamlStr = yaml.dump(frontmatter);
233
+ return `---
234
+ ${yamlStr}---
235
+
236
+ ${body}`;
237
+ }
238
+ transformWorkflow(content, itemName) {
239
+ const name = itemName.replace(/\.md$/, "");
240
+ const match = content.match(frontmatterRegex);
241
+ let description = "";
242
+ let body = content.trim();
243
+ if (match) {
244
+ try {
245
+ const parsed = yaml.load(match[1]);
246
+ if (typeof parsed.description === "string" && parsed.description.trim()) {
247
+ description = parsed.description.trim();
248
+ }
249
+ if (typeof parsed.name === "string" && parsed.name.trim()) {
250
+ }
251
+ } catch (_) {
252
+ }
253
+ body = content.replace(frontmatterRegex, "").trim();
254
+ }
255
+ if (!description) {
256
+ const titleMatch = body.match(/^#\s+(.+)$/m);
257
+ const title = titleMatch?.[1]?.trim() || name;
258
+ description = `Workflow: ${title}`;
259
+ }
260
+ const frontmatter = yaml.dump({
261
+ name,
262
+ description,
263
+ "user-invocable": true
264
+ });
265
+ return `---
266
+ ${frontmatter}---
267
+
268
+ ${body}`;
269
+ }
270
+ };
271
+
272
+ // src/utils/platforms/codex.ts
273
+ import path4 from "node:path";
274
+ import fs3 from "fs-extra";
275
+ import yaml2 from "js-yaml";
276
+ var frontmatterRegex2 = /^---\n([\s\S]*?)\n---/;
178
277
  var CODEX_TYPE_FIELD = "x-ai-agents-type";
179
278
  function extractTitle(body) {
180
279
  const match = body.match(/^#\s+(.+)$/m);
@@ -193,7 +292,7 @@ function buildDescription(type, itemName, title) {
193
292
  function toYamlFrontmatter(name, description, extraFields = {}) {
194
293
  const normalizedName = name.replace(/\n+/g, " ").trim();
195
294
  const normalizedDescription = description.replace(/\n+/g, " ").trim();
196
- return yaml.dump(
295
+ return yaml2.dump(
197
296
  {
198
297
  name: normalizedName,
199
298
  description: normalizedDescription,
@@ -203,10 +302,10 @@ function toYamlFrontmatter(name, description, extraFields = {}) {
203
302
  ).trimEnd();
204
303
  }
205
304
  function parseCodexType(content) {
206
- const match = content.match(frontmatterRegex);
305
+ const match = content.match(frontmatterRegex2);
207
306
  if (!match) return "skill";
208
307
  try {
209
- const parsed = yaml.load(match[1]);
308
+ const parsed = yaml2.load(match[1]);
210
309
  if (parsed && typeof parsed === "object") {
211
310
  const type = parsed[CODEX_TYPE_FIELD];
212
311
  if (type === "agent" || type === "workflow" || type === "skill") {
@@ -221,9 +320,9 @@ function parseCodexType(content) {
221
320
  async function codexEntryMatchesType(basePath, entry, requestedType) {
222
321
  let targetPath = null;
223
322
  if (entry.isDirectory()) {
224
- targetPath = path3.join(basePath, entry.name, "SKILL.md");
323
+ targetPath = path4.join(basePath, entry.name, "SKILL.md");
225
324
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
226
- targetPath = path3.join(basePath, entry.name);
325
+ targetPath = path4.join(basePath, entry.name);
227
326
  }
228
327
  if (!targetPath) return false;
229
328
  try {
@@ -237,7 +336,7 @@ var CodexHandler = class {
237
336
  platform = "codex";
238
337
  getTargetFileName(itemName, type) {
239
338
  if (type === "agent" || type === "workflow") {
240
- return path3.join(path3.parse(itemName).name, "SKILL.md");
339
+ return path4.join(path4.parse(itemName).name, "SKILL.md");
241
340
  }
242
341
  return itemName;
243
342
  }
@@ -247,11 +346,11 @@ var CodexHandler = class {
247
346
  let name = itemName;
248
347
  let description = "";
249
348
  let body = content.trim();
250
- const match = content.match(frontmatterRegex);
349
+ const match = content.match(frontmatterRegex2);
251
350
  if (match) {
252
- body = content.replace(frontmatterRegex, "").trim();
351
+ body = content.replace(frontmatterRegex2, "").trim();
253
352
  try {
254
- const parsed = yaml.load(match[1]);
353
+ const parsed = yaml2.load(match[1]);
255
354
  if (parsed && typeof parsed === "object") {
256
355
  const frontmatter = parsed;
257
356
  if (typeof frontmatter.name === "string" && frontmatter.name.trim()) {
@@ -281,7 +380,7 @@ ${body}`;
281
380
  };
282
381
 
283
382
  // src/utils/platforms/copilot.ts
284
- import yaml2 from "js-yaml";
383
+ import yaml3 from "js-yaml";
285
384
  var CopilotHandler = class {
286
385
  platform = "copilot";
287
386
  getTargetFileName(itemName, type) {
@@ -292,8 +391,8 @@ var CopilotHandler = class {
292
391
  }
293
392
  transform(content, type, itemName) {
294
393
  if (type !== "agent") return content;
295
- const frontmatterRegex2 = /^---\n([\s\S]*?)\n---/;
296
- const match = content.match(frontmatterRegex2);
394
+ const frontmatterRegex3 = /^---\n([\s\S]*?)\n---/;
395
+ const match = content.match(frontmatterRegex3);
297
396
  let frontmatter = {
298
397
  name: itemName,
299
398
  description: "",
@@ -303,7 +402,7 @@ var CopilotHandler = class {
303
402
  let body = content;
304
403
  if (match) {
305
404
  try {
306
- const parsed = yaml2.load(match[1]);
405
+ const parsed = yaml3.load(match[1]);
307
406
  frontmatter = { ...frontmatter, ...parsed };
308
407
  frontmatter.target = "github-copilot";
309
408
  frontmatter.tools = [
@@ -313,11 +412,11 @@ var CopilotHandler = class {
313
412
  "grep_search",
314
413
  "githubRepo"
315
414
  ];
316
- body = content.replace(frontmatterRegex2, "").trim();
415
+ body = content.replace(frontmatterRegex3, "").trim();
317
416
  } catch (_) {
318
417
  }
319
418
  }
320
- const yamlStr = yaml2.dump(frontmatter);
419
+ const yamlStr = yaml3.dump(frontmatter);
321
420
  return `---
322
421
  ${yamlStr}---
323
422
 
@@ -339,7 +438,7 @@ var DefaultHandler = class {
339
438
  };
340
439
 
341
440
  // src/utils/platforms/gemini.ts
342
- import yaml3 from "js-yaml";
441
+ import yaml4 from "js-yaml";
343
442
 
344
443
  // src/utils/toml.ts
345
444
  function convertToGeminiCommandTOML(markdownContent) {
@@ -382,8 +481,8 @@ var GeminiHandler = class {
382
481
  return convertToGeminiCommandTOML(content);
383
482
  }
384
483
  if (type === "agent") {
385
- const frontmatterRegex2 = /^---\n([\s\S]*?)\n---/;
386
- const match = content.match(frontmatterRegex2);
484
+ const frontmatterRegex3 = /^---\n([\s\S]*?)\n---/;
485
+ const match = content.match(frontmatterRegex3);
387
486
  let frontmatter = {
388
487
  name: itemName,
389
488
  description: "",
@@ -405,7 +504,7 @@ var GeminiHandler = class {
405
504
  let body = content;
406
505
  if (match) {
407
506
  try {
408
- const parsed = yaml3.load(match[1]);
507
+ const parsed = yaml4.load(match[1]);
409
508
  frontmatter = { ...frontmatter, ...parsed };
410
509
  frontmatter.tools = [
411
510
  "list_directory",
@@ -422,11 +521,11 @@ var GeminiHandler = class {
422
521
  "activate_skill"
423
522
  ];
424
523
  delete frontmatter.skills;
425
- body = content.replace(frontmatterRegex2, "").trim();
524
+ body = content.replace(frontmatterRegex3, "").trim();
426
525
  } catch (_) {
427
526
  }
428
527
  }
429
- const yamlStr = yaml3.dump(frontmatter);
528
+ const yamlStr = yaml4.dump(frontmatter);
430
529
  return `---
431
530
  ${yamlStr}---
432
531
 
@@ -437,12 +536,12 @@ ${body}`;
437
536
  };
438
537
 
439
538
  // src/utils/platforms/windsurf.ts
440
- import path4 from "node:path";
539
+ import path5 from "node:path";
441
540
  var WindsurfHandler = class {
442
541
  platform = "windsurf";
443
542
  getTargetFileName(itemName, type) {
444
543
  if (type === "agent") {
445
- return path4.join(path4.parse(itemName).name, "AGENTS.md");
544
+ return path5.join(path5.parse(itemName).name, "AGENTS.md");
446
545
  }
447
546
  return itemName;
448
547
  }
@@ -457,6 +556,7 @@ function registerHandler(handler) {
457
556
  handlers.set(handler.platform, handler);
458
557
  }
459
558
  registerHandler(new AntigravityHandler());
559
+ registerHandler(new ClaudeCodeHandler());
460
560
  registerHandler(new CodexHandler());
461
561
  registerHandler(new CopilotHandler());
462
562
  registerHandler(new GeminiHandler());
@@ -475,7 +575,7 @@ function getPlatformOptions(type) {
475
575
  }));
476
576
  }
477
577
  async function installItem(itemName, overwrite, sourcePath, targetBaseDir) {
478
- const targetPath = path5.join(targetBaseDir, itemName);
578
+ const targetPath = path6.join(targetBaseDir, itemName);
479
579
  if (!await fs4.pathExists(sourcePath)) {
480
580
  throw new Error(`Item '${itemName}' not found at ${sourcePath}`);
481
581
  }
@@ -584,7 +684,7 @@ async function add(type, url, options) {
584
684
  const handler = getHandler(platform);
585
685
  for (const item of selectedItems) {
586
686
  const targetItemName = handler.getTargetFileName(item, normalizedType);
587
- const targetPath = path5.join(targetBase, targetItemName);
687
+ const targetPath = path6.join(targetBase, targetItemName);
588
688
  if (await fs4.pathExists(targetPath)) {
589
689
  existingItems.push({ item, platform });
590
690
  }
@@ -627,14 +727,14 @@ async function add(type, url, options) {
627
727
  try {
628
728
  let currentSourcePath;
629
729
  if (url && tempDir) {
630
- const potentialFile = path5.join(tempDir, item);
730
+ const potentialFile = path6.join(tempDir, item);
631
731
  if (await fs4.pathExists(potentialFile) && (await fs4.stat(potentialFile)).isFile()) {
632
732
  currentSourcePath = potentialFile;
633
733
  } else {
634
734
  currentSourcePath = tempDir;
635
735
  }
636
736
  } else {
637
- const src = path5.join(TYPE_DIRS[normalizedType], item);
737
+ const src = path6.join(TYPE_DIRS[normalizedType], item);
638
738
  if ((await fs4.stat(src)).isFile()) {
639
739
  currentSourcePath = src;
640
740
  } else {
@@ -647,7 +747,7 @@ async function add(type, url, options) {
647
747
  normalizedType
648
748
  );
649
749
  if ((normalizedType === "agent" || normalizedType === "workflow") && currentSourcePath.endsWith(".md")) {
650
- const targetPath = path5.join(targetBase, targetItemName);
750
+ const targetPath = path6.join(targetBase, targetItemName);
651
751
  if (!overwrite && await fs4.pathExists(targetPath)) {
652
752
  skippedCount++;
653
753
  } else {
@@ -655,9 +755,9 @@ async function add(type, url, options) {
655
755
  content = handler.transform(
656
756
  content,
657
757
  normalizedType,
658
- path5.parse(item).name
758
+ path6.parse(item).name
659
759
  );
660
- await fs4.ensureDir(path5.dirname(targetPath));
760
+ await fs4.ensureDir(path6.dirname(targetPath));
661
761
  await fs4.writeFile(targetPath, content);
662
762
  installedCount++;
663
763
  }
@@ -715,7 +815,7 @@ async function add(type, url, options) {
715
815
  }
716
816
 
717
817
  // src/commands/import.ts
718
- import path6 from "node:path";
818
+ import path7 from "node:path";
719
819
  import {
720
820
  cancel as cancel2,
721
821
  confirm as confirm2,
@@ -784,12 +884,12 @@ async function importItem(type, url, options) {
784
884
  throw e;
785
885
  }
786
886
  const shouldFlatten = (normalizedType === "agent" || normalizedType === "workflow") && !isFile;
787
- const targetPath = shouldFlatten ? targetBaseDir : path6.join(targetBaseDir, itemName);
887
+ const targetPath = shouldFlatten ? targetBaseDir : path7.join(targetBaseDir, itemName);
788
888
  if (shouldFlatten) {
789
889
  const srcFiles = await fs5.readdir(tempDir);
790
890
  const conflicts = [];
791
891
  for (const file of srcFiles) {
792
- if (await fs5.pathExists(path6.join(targetBaseDir, file))) {
892
+ if (await fs5.pathExists(path7.join(targetBaseDir, file))) {
793
893
  conflicts.push(file);
794
894
  }
795
895
  }
@@ -820,7 +920,7 @@ async function importItem(type, url, options) {
820
920
  s.start(`Importing ${itemName} to ${targetBaseDir}...`);
821
921
  await fs5.ensureDir(targetBaseDir);
822
922
  if (isFile) {
823
- await fs5.copy(path6.join(tempDir, itemName), targetPath, {
923
+ await fs5.copy(path7.join(tempDir, itemName), targetPath, {
824
924
  overwrite: true
825
925
  });
826
926
  } else {
@@ -965,7 +1065,7 @@ async function list(type, options) {
965
1065
  }
966
1066
 
967
1067
  // src/commands/remove.ts
968
- import path7 from "node:path";
1068
+ import path8 from "node:path";
969
1069
  import {
970
1070
  confirm as confirm3,
971
1071
  intro as intro4,
@@ -1079,7 +1179,7 @@ async function remove(type, options) {
1079
1179
  const targetBase = targetPaths[platform];
1080
1180
  if (!targetBase) continue;
1081
1181
  for (const item of selectedItems) {
1082
- const targetPath = path7.join(targetBase, item);
1182
+ const targetPath = path8.join(targetBase, item);
1083
1183
  if (await fs7.pathExists(targetPath)) {
1084
1184
  sDel.message(`Removing ${pc4.bold(item)} from ${pc4.cyan(platform)}...`);
1085
1185
  try {
@@ -0,0 +1,134 @@
1
+ ---
2
+ description: Create a GitHub Pull Request for the current branch following project standards. Use when preparing a PR, generating PR title/body, validating branch state, and running the project's configured lint and type-check commands before `gh pr create`.
3
+ ---
4
+
5
+ # /pr - GitHub Pull Request
6
+
7
+ $ARGUMENTS
8
+
9
+ ---
10
+
11
+ ## Purpose
12
+
13
+ This command prepares and creates a GitHub Pull Request for the current branch.
14
+
15
+ It must validate the branch state, run the project's configured quality checks, generate a professional PR title/body, and only then create the PR.
16
+
17
+ ---
18
+
19
+ ## Critical Rules
20
+
21
+ 1. **Never create a PR from `main`**
22
+ 2. **Never create a PR with no commits relative to `main`**
23
+ 3. **Always run the project's configured lint command before creating the PR**
24
+ 4. **Always run the project's configured type-check command before creating the PR**
25
+ 5. **Stop and report the failure if linting or type checking fails**
26
+
27
+ ---
28
+
29
+ ## Validation Order
30
+
31
+ 1. **Confirm branch state**
32
+ - Run `git branch --show-current`
33
+ - Refuse to continue if the current branch is `main`
34
+
35
+ 2. **Confirm there is work to merge**
36
+ - Run `git log main..HEAD --oneline`
37
+ - Refuse to continue if there are no commits
38
+
39
+ 3. **Discover project validation commands**
40
+ - Inspect project scripts and config first, such as `package.json`, `Makefile`, `justfile`, `cargo`, or other repo-standard task runners
41
+ - Prefer explicit project commands over guessed generic commands
42
+
43
+ 4. **Run linting**
44
+ - Use the project's configured lint command
45
+ - Example for this repository: `pnpm run lint`
46
+
47
+ 5. **Run type checking**
48
+ - Use the project's configured type-check command if one exists
49
+ - If no dedicated script exists but the project is TypeScript-based, run the established repo equivalent that performs type checking
50
+ - Example for this repository: `pnpm exec tsc --noEmit`
51
+
52
+ 6. **Push branch**
53
+ - Run `git push -u origin $(git branch --show-current)` after validations pass
54
+
55
+ 7. **Create PR**
56
+ - Run `gh pr create --base main --title "<title>" --body "<body>" {{args}}`
57
+ - Include `--draft` when the work is incomplete or requested in `$ARGUMENTS`
58
+
59
+ ---
60
+
61
+ ## PR Content Requirements
62
+
63
+ ### Title
64
+
65
+ - Use a semantic title such as `feat: ...`, `fix: ...`, `chore: ...`, or `docs: ...`
66
+ - Match the actual change scope
67
+
68
+ ### Body
69
+
70
+ Include these sections:
71
+
72
+ 1. **Summary**
73
+ - Concise explanation of the purpose of the PR
74
+
75
+ 2. **Key Changes**
76
+ - Bulleted list of the most important code changes
77
+
78
+ 3. **Verification**
79
+ - Automated: list the lint and type-check commands that were run and whether they passed
80
+ - Manual: briefly describe any manual verification performed
81
+
82
+ 4. **Related Tracks**
83
+ - Reference relevant track information from `conductor/tracks.md` when applicable
84
+
85
+ ---
86
+
87
+ ## Command Context
88
+
89
+ Gather this context before writing the PR:
90
+
91
+ - Current branch: `git branch --show-current`
92
+ - Commits relative to `main`: `git log main..HEAD --oneline`
93
+ - Diff summary: `git diff main..HEAD --stat`
94
+
95
+ Use that information to write a PR description that reflects the actual technical changes.
96
+
97
+ ---
98
+
99
+ ## Output Format
100
+
101
+ ```markdown
102
+ ## PR Ready
103
+
104
+ ### Title
105
+ feat: short, accurate summary
106
+
107
+ ### Body
108
+ ## Summary
109
+ ...
110
+
111
+ ## Key Changes
112
+ - ...
113
+
114
+ ## Verification
115
+ - Automated: `pnpm run lint` ✅
116
+ - Automated: `pnpm exec tsc --noEmit` ✅
117
+ - Manual: ...
118
+
119
+ ## Related Tracks
120
+ - ...
121
+ ```
122
+
123
+ If validation fails, report the failing command and do not create the PR.
124
+
125
+ ---
126
+
127
+ ## Usage Examples
128
+
129
+ ```text
130
+ /pr
131
+ /pr --draft
132
+ /pr --draft --assignee @me
133
+ /pr --label bug
134
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kurokeita/add-skill",
3
- "version": "1.10.1",
3
+ "version": "1.12.0",
4
4
  "description": "CLI to install AI agent skills to various platforms",
5
5
  "type": "module",
6
6
  "bin": {