@kurokeita/add-skill 1.11.0 → 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 +1 -0
- package/dist/bin/cli.js +139 -39
- package/package.json +1 -1
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
|
|
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/
|
|
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
|
|
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(
|
|
305
|
+
const match = content.match(frontmatterRegex2);
|
|
207
306
|
if (!match) return "skill";
|
|
208
307
|
try {
|
|
209
|
-
const parsed =
|
|
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 =
|
|
323
|
+
targetPath = path4.join(basePath, entry.name, "SKILL.md");
|
|
225
324
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
226
|
-
targetPath =
|
|
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
|
|
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(
|
|
349
|
+
const match = content.match(frontmatterRegex2);
|
|
251
350
|
if (match) {
|
|
252
|
-
body = content.replace(
|
|
351
|
+
body = content.replace(frontmatterRegex2, "").trim();
|
|
253
352
|
try {
|
|
254
|
-
const parsed =
|
|
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
|
|
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
|
|
296
|
-
const match = content.match(
|
|
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 =
|
|
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(
|
|
415
|
+
body = content.replace(frontmatterRegex3, "").trim();
|
|
317
416
|
} catch (_) {
|
|
318
417
|
}
|
|
319
418
|
}
|
|
320
|
-
const yamlStr =
|
|
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
|
|
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
|
|
386
|
-
const match = content.match(
|
|
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 =
|
|
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(
|
|
524
|
+
body = content.replace(frontmatterRegex3, "").trim();
|
|
426
525
|
} catch (_) {
|
|
427
526
|
}
|
|
428
527
|
}
|
|
429
|
-
const yamlStr =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
758
|
+
path6.parse(item).name
|
|
659
759
|
);
|
|
660
|
-
await fs4.ensureDir(
|
|
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
|
|
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 :
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
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 {
|