@kurokeita/add-skill 1.9.0 → 1.10.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,11 +87,14 @@ 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
+ | Codex | `~/.codex/skills` | `~/.codex/skills` | `~/.codex/skills` |
90
91
  | Gemini CLI | `~/.gemini/agents` | `~/.gemini/skills` | `~/.gemini/commands` |
91
92
  | GitHub Copilot | `~/.copilot/agents` | `~/.copilot/skills` | `~/.copilot/prompts` |
92
93
  | Windsurf | *Not Supported* | `~/.codeium/windsurf/skills` | `~/.codeium/windsurf/global_workflows` |
93
94
  <!-- SUPPORTED_AGENTS_END -->
94
95
 
96
+ For Codex, this package installs skills directly and converts agents and workflows into Codex skill packages under `~/.codex/skills`.
97
+
95
98
  ## Development
96
99
 
97
100
  1. **Clone the repository:**
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 path4 from "node:path";
10
+ import path5 from "node:path";
11
11
  import {
12
12
  cancel,
13
13
  confirm,
@@ -19,7 +19,7 @@ import {
19
19
  select,
20
20
  spinner
21
21
  } from "@clack/prompts";
22
- import fs2 from "fs-extra";
22
+ import fs3 from "fs-extra";
23
23
  import pc from "picocolors";
24
24
 
25
25
  // src/utils/github.ts
@@ -106,22 +106,26 @@ var __dirname = path2.dirname(__filename);
106
106
  var PROJECT_ROOT = path2.resolve(__dirname, "../..");
107
107
  var PLATFORM_LABELS = {
108
108
  antigravity: "Antigravity",
109
+ codex: "Codex",
109
110
  gemini: "Gemini CLI",
110
111
  copilot: "GitHub Copilot",
111
112
  windsurf: "Windsurf"
112
113
  };
113
114
  var PLATFORM_PATHS_SKILLS = {
114
115
  antigravity: path2.join(os2.homedir(), ".gemini/antigravity/global_skills"),
116
+ codex: path2.join(os2.homedir(), ".codex/skills"),
115
117
  copilot: path2.join(os2.homedir(), ".copilot/skills"),
116
118
  gemini: path2.join(os2.homedir(), ".gemini/skills"),
117
119
  windsurf: path2.join(os2.homedir(), ".codeium/windsurf/skills")
118
120
  };
119
121
  var PLATFORM_PATHS_AGENTS = {
122
+ codex: path2.join(os2.homedir(), ".codex/skills"),
120
123
  copilot: path2.join(os2.homedir(), ".copilot/agents"),
121
124
  gemini: path2.join(os2.homedir(), ".gemini/agents")
122
125
  };
123
126
  var PLATFORM_PATHS_WORKFLOWS = {
124
127
  antigravity: path2.join(os2.homedir(), ".gemini/antigravity/global_workflows"),
128
+ codex: path2.join(os2.homedir(), ".codex/skills"),
125
129
  copilot: path2.join(os2.homedir(), ".copilot/prompts"),
126
130
  gemini: path2.join(os2.homedir(), ".gemini/commands"),
127
131
  windsurf: path2.join(os2.homedir(), ".codeium/windsurf/global_workflows")
@@ -153,8 +157,118 @@ var AntigravityHandler = class {
153
157
  }
154
158
  };
155
159
 
156
- // src/utils/platforms/copilot.ts
160
+ // src/utils/platforms/codex.ts
161
+ import path3 from "node:path";
162
+ import fs2 from "fs-extra";
157
163
  import yaml from "js-yaml";
164
+ var frontmatterRegex = /^---\n([\s\S]*?)\n---/;
165
+ var CODEX_TYPE_FIELD = "x-ai-agents-type";
166
+ function extractTitle(body) {
167
+ const match = body.match(/^#\s+(.+)$/m);
168
+ return match?.[1]?.trim();
169
+ }
170
+ function buildDescription(type, itemName, title) {
171
+ const subject = title || itemName;
172
+ if (type === "agent") {
173
+ return `This skill should be used when Codex needs to follow the ${subject} agent instructions.`;
174
+ }
175
+ if (type === "workflow") {
176
+ return `This skill should be used when Codex needs to follow the ${subject} workflow instructions.`;
177
+ }
178
+ return `This skill should be used when Codex needs the ${subject} skill.`;
179
+ }
180
+ function toYamlFrontmatter(name, description, extraFields = {}) {
181
+ const normalizedName = name.replace(/\n+/g, " ").trim();
182
+ const normalizedDescription = description.replace(/\n+/g, " ").trim();
183
+ return yaml.dump(
184
+ {
185
+ name: normalizedName,
186
+ description: normalizedDescription,
187
+ ...extraFields
188
+ },
189
+ { lineWidth: -1 }
190
+ ).trimEnd();
191
+ }
192
+ function parseCodexType(content) {
193
+ const match = content.match(frontmatterRegex);
194
+ if (!match) return "skill";
195
+ try {
196
+ const parsed = yaml.load(match[1]);
197
+ if (parsed && typeof parsed === "object") {
198
+ const type = parsed[CODEX_TYPE_FIELD];
199
+ if (type === "agent" || type === "workflow" || type === "skill") {
200
+ return type;
201
+ }
202
+ }
203
+ } catch {
204
+ return "skill";
205
+ }
206
+ return "skill";
207
+ }
208
+ async function codexEntryMatchesType(basePath, entry, requestedType) {
209
+ let targetPath = null;
210
+ if (entry.isDirectory()) {
211
+ targetPath = path3.join(basePath, entry.name, "SKILL.md");
212
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
213
+ targetPath = path3.join(basePath, entry.name);
214
+ }
215
+ if (!targetPath) return false;
216
+ try {
217
+ const content = await fs2.readFile(targetPath, "utf-8");
218
+ return parseCodexType(content) === requestedType;
219
+ } catch {
220
+ return false;
221
+ }
222
+ }
223
+ var CodexHandler = class {
224
+ platform = "codex";
225
+ getTargetFileName(itemName, type) {
226
+ if (type === "agent" || type === "workflow") {
227
+ return path3.join(path3.parse(itemName).name, "SKILL.md");
228
+ }
229
+ return itemName;
230
+ }
231
+ transform(content, type, itemName) {
232
+ if (type === "skill") return content;
233
+ if (type !== "agent" && type !== "workflow") return content;
234
+ let name = itemName;
235
+ let description = "";
236
+ let body = content.trim();
237
+ const match = content.match(frontmatterRegex);
238
+ if (match) {
239
+ body = content.replace(frontmatterRegex, "").trim();
240
+ try {
241
+ const parsed = yaml.load(match[1]);
242
+ if (parsed && typeof parsed === "object") {
243
+ const frontmatter = parsed;
244
+ if (typeof frontmatter.name === "string" && frontmatter.name.trim()) {
245
+ name = frontmatter.name.trim();
246
+ }
247
+ if (typeof frontmatter.description === "string" && frontmatter.description.trim()) {
248
+ description = frontmatter.description.trim();
249
+ }
250
+ }
251
+ } catch {
252
+ name = itemName;
253
+ description = "";
254
+ }
255
+ }
256
+ if (!description) {
257
+ description = buildDescription(type, itemName, extractTitle(body));
258
+ }
259
+ const yamlStr = toYamlFrontmatter(name, description, {
260
+ [CODEX_TYPE_FIELD]: type
261
+ });
262
+ return `---
263
+ ${yamlStr}
264
+ ---
265
+
266
+ ${body}`;
267
+ }
268
+ };
269
+
270
+ // src/utils/platforms/copilot.ts
271
+ import yaml2 from "js-yaml";
158
272
  var CopilotHandler = class {
159
273
  platform = "copilot";
160
274
  getTargetFileName(itemName, type) {
@@ -165,8 +279,8 @@ var CopilotHandler = class {
165
279
  }
166
280
  transform(content, type, itemName) {
167
281
  if (type !== "agent") return content;
168
- const frontmatterRegex = /^---\n([\s\S]*?)\n---/;
169
- const match = content.match(frontmatterRegex);
282
+ const frontmatterRegex2 = /^---\n([\s\S]*?)\n---/;
283
+ const match = content.match(frontmatterRegex2);
170
284
  let frontmatter = {
171
285
  name: itemName,
172
286
  description: "",
@@ -176,7 +290,7 @@ var CopilotHandler = class {
176
290
  let body = content;
177
291
  if (match) {
178
292
  try {
179
- const parsed = yaml.load(match[1]);
293
+ const parsed = yaml2.load(match[1]);
180
294
  frontmatter = { ...frontmatter, ...parsed };
181
295
  frontmatter.target = "github-copilot";
182
296
  frontmatter.tools = [
@@ -186,11 +300,11 @@ var CopilotHandler = class {
186
300
  "grep_search",
187
301
  "githubRepo"
188
302
  ];
189
- body = content.replace(frontmatterRegex, "").trim();
303
+ body = content.replace(frontmatterRegex2, "").trim();
190
304
  } catch (_) {
191
305
  }
192
306
  }
193
- const yamlStr = yaml.dump(frontmatter);
307
+ const yamlStr = yaml2.dump(frontmatter);
194
308
  return `---
195
309
  ${yamlStr}---
196
310
 
@@ -212,7 +326,7 @@ var DefaultHandler = class {
212
326
  };
213
327
 
214
328
  // src/utils/platforms/gemini.ts
215
- import yaml2 from "js-yaml";
329
+ import yaml3 from "js-yaml";
216
330
 
217
331
  // src/utils/toml.ts
218
332
  function convertToGeminiCommandTOML(markdownContent) {
@@ -255,8 +369,8 @@ var GeminiHandler = class {
255
369
  return convertToGeminiCommandTOML(content);
256
370
  }
257
371
  if (type === "agent") {
258
- const frontmatterRegex = /^---\n([\s\S]*?)\n---/;
259
- const match = content.match(frontmatterRegex);
372
+ const frontmatterRegex2 = /^---\n([\s\S]*?)\n---/;
373
+ const match = content.match(frontmatterRegex2);
260
374
  let frontmatter = {
261
375
  name: itemName,
262
376
  description: "",
@@ -278,7 +392,7 @@ var GeminiHandler = class {
278
392
  let body = content;
279
393
  if (match) {
280
394
  try {
281
- const parsed = yaml2.load(match[1]);
395
+ const parsed = yaml3.load(match[1]);
282
396
  frontmatter = { ...frontmatter, ...parsed };
283
397
  frontmatter.tools = [
284
398
  "list_directory",
@@ -295,11 +409,11 @@ var GeminiHandler = class {
295
409
  "activate_skill"
296
410
  ];
297
411
  delete frontmatter.skills;
298
- body = content.replace(frontmatterRegex, "").trim();
412
+ body = content.replace(frontmatterRegex2, "").trim();
299
413
  } catch (_) {
300
414
  }
301
415
  }
302
- const yamlStr = yaml2.dump(frontmatter);
416
+ const yamlStr = yaml3.dump(frontmatter);
303
417
  return `---
304
418
  ${yamlStr}---
305
419
 
@@ -310,12 +424,12 @@ ${body}`;
310
424
  };
311
425
 
312
426
  // src/utils/platforms/windsurf.ts
313
- import path3 from "node:path";
427
+ import path4 from "node:path";
314
428
  var WindsurfHandler = class {
315
429
  platform = "windsurf";
316
430
  getTargetFileName(itemName, type) {
317
431
  if (type === "agent") {
318
- return path3.join(path3.parse(itemName).name, "AGENTS.md");
432
+ return path4.join(path4.parse(itemName).name, "AGENTS.md");
319
433
  }
320
434
  return itemName;
321
435
  }
@@ -330,6 +444,7 @@ function registerHandler(handler) {
330
444
  handlers.set(handler.platform, handler);
331
445
  }
332
446
  registerHandler(new AntigravityHandler());
447
+ registerHandler(new CodexHandler());
333
448
  registerHandler(new CopilotHandler());
334
449
  registerHandler(new GeminiHandler());
335
450
  registerHandler(new WindsurfHandler());
@@ -347,15 +462,15 @@ function getPlatformOptions(type) {
347
462
  }));
348
463
  }
349
464
  async function installItem(itemName, overwrite, sourcePath, targetBaseDir) {
350
- const targetPath = path4.join(targetBaseDir, itemName);
351
- if (!await fs2.pathExists(sourcePath)) {
465
+ const targetPath = path5.join(targetBaseDir, itemName);
466
+ if (!await fs3.pathExists(sourcePath)) {
352
467
  throw new Error(`Item '${itemName}' not found at ${sourcePath}`);
353
468
  }
354
- if (!overwrite && await fs2.pathExists(targetPath)) {
469
+ if (!overwrite && await fs3.pathExists(targetPath)) {
355
470
  return false;
356
471
  }
357
- await fs2.ensureDir(targetBaseDir);
358
- await fs2.copy(sourcePath, targetPath, { overwrite });
472
+ await fs3.ensureDir(targetBaseDir);
473
+ await fs3.copy(sourcePath, targetPath, { overwrite });
359
474
  return true;
360
475
  }
361
476
  async function add(type, url, options) {
@@ -403,12 +518,12 @@ async function add(type, url, options) {
403
518
  }
404
519
  } else {
405
520
  const sourceDir = TYPE_DIRS[normalizedType];
406
- if (!await fs2.pathExists(sourceDir)) {
521
+ if (!await fs3.pathExists(sourceDir)) {
407
522
  cancel(`${normalizedType} directory not found!`);
408
523
  process.exit(1);
409
524
  return;
410
525
  }
411
- const entries = await fs2.readdir(sourceDir, { withFileTypes: true });
526
+ const entries = await fs3.readdir(sourceDir, { withFileTypes: true });
412
527
  const availableItems = entries.filter(
413
528
  (entry) => entry.isDirectory() || (normalizedType === "workflow" || normalizedType === "agent") && entry.isFile() && entry.name.endsWith(".md")
414
529
  ).map((entry) => ({ label: entry.name, value: entry.name })).sort((a, b) => a.label.localeCompare(b.label));
@@ -443,7 +558,7 @@ async function add(type, url, options) {
443
558
  required: true
444
559
  });
445
560
  if (isCancel(platforms)) {
446
- if (tempDir) await fs2.remove(tempDir);
561
+ if (tempDir) await fs3.remove(tempDir);
447
562
  if (isSingleShot) break;
448
563
  currentType = void 0;
449
564
  continue;
@@ -453,9 +568,11 @@ async function add(type, url, options) {
453
568
  for (const platform of selectedPlatforms) {
454
569
  const targetBase = supportedPaths[platform];
455
570
  if (!targetBase) continue;
571
+ const handler = getHandler(platform);
456
572
  for (const item of selectedItems) {
457
- const targetPath = path4.join(targetBase, item);
458
- if (await fs2.pathExists(targetPath)) {
573
+ const targetItemName = handler.getTargetFileName(item, normalizedType);
574
+ const targetPath = path5.join(targetBase, targetItemName);
575
+ if (await fs3.pathExists(targetPath)) {
459
576
  existingItems.push({ item, platform });
460
577
  }
461
578
  }
@@ -472,7 +589,7 @@ async function add(type, url, options) {
472
589
  initialValue: false
473
590
  });
474
591
  if (isCancel(shouldOverwrite)) {
475
- if (tempDir) await fs2.remove(tempDir);
592
+ if (tempDir) await fs3.remove(tempDir);
476
593
  if (isSingleShot) break;
477
594
  currentType = void 0;
478
595
  continue;
@@ -497,15 +614,15 @@ async function add(type, url, options) {
497
614
  try {
498
615
  let currentSourcePath;
499
616
  if (url && tempDir) {
500
- const potentialFile = path4.join(tempDir, item);
501
- if (await fs2.pathExists(potentialFile) && (await fs2.stat(potentialFile)).isFile()) {
617
+ const potentialFile = path5.join(tempDir, item);
618
+ if (await fs3.pathExists(potentialFile) && (await fs3.stat(potentialFile)).isFile()) {
502
619
  currentSourcePath = potentialFile;
503
620
  } else {
504
621
  currentSourcePath = tempDir;
505
622
  }
506
623
  } else {
507
- const src = path4.join(TYPE_DIRS[normalizedType], item);
508
- if ((await fs2.stat(src)).isFile()) {
624
+ const src = path5.join(TYPE_DIRS[normalizedType], item);
625
+ if ((await fs3.stat(src)).isFile()) {
509
626
  currentSourcePath = src;
510
627
  } else {
511
628
  currentSourcePath = src;
@@ -517,18 +634,18 @@ async function add(type, url, options) {
517
634
  normalizedType
518
635
  );
519
636
  if ((normalizedType === "agent" || normalizedType === "workflow") && currentSourcePath.endsWith(".md")) {
520
- const targetPath = path4.join(targetBase, targetItemName);
521
- if (!overwrite && await fs2.pathExists(targetPath)) {
637
+ const targetPath = path5.join(targetBase, targetItemName);
638
+ if (!overwrite && await fs3.pathExists(targetPath)) {
522
639
  skippedCount++;
523
640
  } else {
524
- let content = await fs2.readFile(currentSourcePath, "utf-8");
641
+ let content = await fs3.readFile(currentSourcePath, "utf-8");
525
642
  content = handler.transform(
526
643
  content,
527
644
  normalizedType,
528
- path4.parse(item).name
645
+ path5.parse(item).name
529
646
  );
530
- await fs2.ensureDir(path4.dirname(targetPath));
531
- await fs2.writeFile(targetPath, content);
647
+ await fs3.ensureDir(path5.dirname(targetPath));
648
+ await fs3.writeFile(targetPath, content);
532
649
  installedCount++;
533
650
  }
534
651
  continue;
@@ -551,7 +668,7 @@ async function add(type, url, options) {
551
668
  }
552
669
  }
553
670
  if (tempDir) {
554
- await fs2.remove(tempDir);
671
+ await fs3.remove(tempDir);
555
672
  }
556
673
  if (errors.length > 0) {
557
674
  s.stop(
@@ -571,7 +688,7 @@ async function add(type, url, options) {
571
688
  );
572
689
  }
573
690
  } catch (error) {
574
- if (tempDir) await fs2.remove(tempDir);
691
+ if (tempDir) await fs3.remove(tempDir);
575
692
  cancel(`An error occurred: ${error}`);
576
693
  process.exit(1);
577
694
  return;
@@ -585,7 +702,7 @@ async function add(type, url, options) {
585
702
  }
586
703
 
587
704
  // src/commands/import.ts
588
- import path5 from "node:path";
705
+ import path6 from "node:path";
589
706
  import {
590
707
  cancel as cancel2,
591
708
  confirm as confirm2,
@@ -596,7 +713,7 @@ import {
596
713
  spinner as spinner2,
597
714
  text
598
715
  } from "@clack/prompts";
599
- import fs3 from "fs-extra";
716
+ import fs4 from "fs-extra";
600
717
  import pc2 from "picocolors";
601
718
  async function importItem(type, url, options) {
602
719
  if (!options?.skipIntro) {
@@ -654,12 +771,12 @@ async function importItem(type, url, options) {
654
771
  throw e;
655
772
  }
656
773
  const shouldFlatten = (normalizedType === "agent" || normalizedType === "workflow") && !isFile;
657
- const targetPath = shouldFlatten ? targetBaseDir : path5.join(targetBaseDir, itemName);
774
+ const targetPath = shouldFlatten ? targetBaseDir : path6.join(targetBaseDir, itemName);
658
775
  if (shouldFlatten) {
659
- const srcFiles = await fs3.readdir(tempDir);
776
+ const srcFiles = await fs4.readdir(tempDir);
660
777
  const conflicts = [];
661
778
  for (const file of srcFiles) {
662
- if (await fs3.pathExists(path5.join(targetBaseDir, file))) {
779
+ if (await fs4.pathExists(path6.join(targetBaseDir, file))) {
663
780
  conflicts.push(file);
664
781
  }
665
782
  }
@@ -673,40 +790,40 @@ async function importItem(type, url, options) {
673
790
  initialValue: false
674
791
  });
675
792
  if (isCancel2(shouldOverwrite) || !shouldOverwrite) {
676
- await fs3.remove(tempDir);
793
+ await fs4.remove(tempDir);
677
794
  return;
678
795
  }
679
796
  }
680
- } else if (await fs3.pathExists(targetPath)) {
797
+ } else if (await fs4.pathExists(targetPath)) {
681
798
  const shouldOverwrite = await confirm2({
682
799
  message: `${normalizedType} '${itemName}' already exists in the repo. Overwrite?`,
683
800
  initialValue: false
684
801
  });
685
802
  if (isCancel2(shouldOverwrite) || !shouldOverwrite) {
686
- await fs3.remove(tempDir);
803
+ await fs4.remove(tempDir);
687
804
  return;
688
805
  }
689
806
  }
690
807
  s.start(`Importing ${itemName} to ${targetBaseDir}...`);
691
- await fs3.ensureDir(targetBaseDir);
808
+ await fs4.ensureDir(targetBaseDir);
692
809
  if (isFile) {
693
- await fs3.copy(path5.join(tempDir, itemName), targetPath, {
810
+ await fs4.copy(path6.join(tempDir, itemName), targetPath, {
694
811
  overwrite: true
695
812
  });
696
813
  } else {
697
814
  if (shouldFlatten) {
698
- await fs3.copy(tempDir, targetBaseDir, { overwrite: true });
815
+ await fs4.copy(tempDir, targetBaseDir, { overwrite: true });
699
816
  } else {
700
- await fs3.copy(tempDir, targetPath, { overwrite: true });
817
+ await fs4.copy(tempDir, targetPath, { overwrite: true });
701
818
  }
702
819
  }
703
820
  s.stop(pc2.green(`Successfully imported ${itemName}!`));
704
- await fs3.remove(tempDir);
821
+ await fs4.remove(tempDir);
705
822
  if (!options?.skipIntro) {
706
823
  outro2(`${normalizedType} available at: ${targetPath}`);
707
824
  }
708
825
  } catch (error) {
709
- if (tempDir) await fs3.remove(tempDir);
826
+ if (tempDir) await fs4.remove(tempDir);
710
827
  cancel2(`An error occurred: ${error}`);
711
828
  process.exit(1);
712
829
  return;
@@ -715,7 +832,7 @@ async function importItem(type, url, options) {
715
832
 
716
833
  // src/commands/list.ts
717
834
  import { intro as intro3, isCancel as isCancel3, outro as outro3, select as select3 } from "@clack/prompts";
718
- import fs4 from "fs-extra";
835
+ import fs5 from "fs-extra";
719
836
  import pc3 from "picocolors";
720
837
  async function performListing(type, local) {
721
838
  const normalizedType = type.toLowerCase().endsWith("s") ? type.slice(0, -1) : type.toLowerCase();
@@ -725,13 +842,23 @@ async function performListing(type, local) {
725
842
  let foundAny = false;
726
843
  for (const [platform, pathStr] of Object.entries(targetPaths)) {
727
844
  const fullPath = pathStr;
728
- if (await fs4.pathExists(fullPath)) {
729
- const entries = await fs4.readdir(fullPath, {
845
+ if (await fs5.pathExists(fullPath)) {
846
+ const entries = await fs5.readdir(fullPath, {
730
847
  withFileTypes: true
731
848
  });
732
- const items = entries.filter(
733
- (entry) => entry.isDirectory() || entry.isFile() && entry.name.endsWith(".md")
734
- ).map((entry) => entry.name).sort();
849
+ const items = [];
850
+ for (const entry of entries) {
851
+ if (platform === "codex") {
852
+ if (await codexEntryMatchesType(fullPath, entry, normalizedType)) {
853
+ items.push(entry.name);
854
+ }
855
+ continue;
856
+ }
857
+ if (entry.isDirectory() || entry.isFile() && entry.name.endsWith(".md")) {
858
+ items.push(entry.name);
859
+ }
860
+ }
861
+ items.sort();
735
862
  if (items.length > 0) {
736
863
  foundAny = true;
737
864
  console.log(pc3.cyan(` ${platform}:`));
@@ -755,13 +882,13 @@ async function performListing(type, local) {
755
882
  return;
756
883
  }
757
884
  const dirPath = TYPE_DIRS[normalizedType];
758
- if (!await fs4.pathExists(dirPath)) {
885
+ if (!await fs5.pathExists(dirPath)) {
759
886
  console.log(
760
887
  pc3.yellow(`No ${normalizedType} directory found at: ${dirPath}`)
761
888
  );
762
889
  return;
763
890
  }
764
- const entries = await fs4.readdir(dirPath, { withFileTypes: true });
891
+ const entries = await fs5.readdir(dirPath, { withFileTypes: true });
765
892
  const items = entries.filter(
766
893
  (entry) => entry.isDirectory() || normalizedType !== "skill" && entry.isFile() && entry.name.endsWith(".md")
767
894
  ).map((entry) => entry.name).sort();
@@ -825,7 +952,7 @@ async function list(type, options) {
825
952
  }
826
953
 
827
954
  // src/commands/remove.ts
828
- import path6 from "node:path";
955
+ import path7 from "node:path";
829
956
  import {
830
957
  confirm as confirm3,
831
958
  intro as intro4,
@@ -836,7 +963,7 @@ import {
836
963
  select as select4,
837
964
  spinner as spinner3
838
965
  } from "@clack/prompts";
839
- import fs5 from "fs-extra";
966
+ import fs6 from "fs-extra";
840
967
  import pc4 from "picocolors";
841
968
  async function remove(type, options) {
842
969
  if (!options?.skipIntro) {
@@ -865,12 +992,22 @@ async function remove(type, options) {
865
992
  const uniqueItems = /* @__PURE__ */ new Set();
866
993
  const s = spinner3();
867
994
  s.start("Scanning for installed items...");
868
- for (const pathStr of Object.values(targetPaths)) {
869
- if (await fs5.pathExists(pathStr)) {
870
- const entries = await fs5.readdir(pathStr, {
995
+ for (const [platform, pathStr] of Object.entries(targetPaths)) {
996
+ if (await fs6.pathExists(pathStr)) {
997
+ const entries = await fs6.readdir(pathStr, {
871
998
  withFileTypes: true
872
999
  });
873
1000
  for (const entry of entries) {
1001
+ if (platform === "codex") {
1002
+ if (await codexEntryMatchesType(
1003
+ pathStr,
1004
+ entry,
1005
+ normalizedType
1006
+ )) {
1007
+ uniqueItems.add(entry.name);
1008
+ }
1009
+ continue;
1010
+ }
874
1011
  if (entry.isDirectory() || normalizedType === "workflow" && entry.isFile() && entry.name.endsWith(".md") || normalizedType === "agent" && entry.isFile() && entry.name.endsWith(".md")) {
875
1012
  uniqueItems.add(entry.name);
876
1013
  }
@@ -929,11 +1066,11 @@ async function remove(type, options) {
929
1066
  const targetBase = targetPaths[platform];
930
1067
  if (!targetBase) continue;
931
1068
  for (const item of selectedItems) {
932
- const targetPath = path6.join(targetBase, item);
933
- if (await fs5.pathExists(targetPath)) {
1069
+ const targetPath = path7.join(targetBase, item);
1070
+ if (await fs6.pathExists(targetPath)) {
934
1071
  sDel.message(`Removing ${pc4.bold(item)} from ${pc4.cyan(platform)}...`);
935
1072
  try {
936
- await fs5.remove(targetPath);
1073
+ await fs6.remove(targetPath);
937
1074
  removedCount++;
938
1075
  } catch (err) {
939
1076
  const msg = err instanceof Error ? err.message : String(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kurokeita/add-skill",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "CLI to install AI agent skills to various platforms",
5
5
  "type": "module",
6
6
  "bin": {