add-skill 1.0.20 → 1.0.22

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.
Files changed (3) hide show
  1. package/README.md +44 -28
  2. package/dist/index.js +221 -108
  3. package/package.json +11 -9
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Install agent skills onto your coding agents from any git repository.
4
4
 
5
5
  <!-- agent-list:start -->
6
- Supports **Opencode**, **Claude Code**, **Codex**, **Cursor**, and [10 more](#available-agents).
6
+ Supports **Opencode**, **Claude Code**, **Codex**, **Cursor**, and [12 more](#available-agents).
7
7
  <!-- agent-list:end -->
8
8
 
9
9
  ## Quick Start
@@ -82,22 +82,34 @@ Skills can be installed to any of these supported agents. Use `-g, --global` to
82
82
  <!-- available-agents:start -->
83
83
  | Agent | `--agent` | Project Path | Global Path |
84
84
  |-------|-----------|--------------|-------------|
85
- | OpenCode | `opencode` | `.opencode/skills/` | `~/.config/opencode/skills/` |
85
+ | Amp | `amp` | `.agents/skills/` | `~/.config/agents/skills/` |
86
+ | Antigravity | `antigravity` | `.agent/skills/` | `~/.gemini/antigravity/skills/` |
86
87
  | Claude Code | `claude-code` | `.claude/skills/` | `~/.claude/skills/` |
88
+ | Clawdbot | `clawdbot` | `skills/` | `~/.clawdbot/skills/` |
87
89
  | Codex | `codex` | `.codex/skills/` | `~/.codex/skills/` |
88
90
  | Cursor | `cursor` | `.cursor/skills/` | `~/.cursor/skills/` |
89
- | Amp | `amp` | `.agents/skills/` | `~/.config/agents/skills/` |
90
- | Kilo Code | `kilo` | `.kilocode/skills/` | `~/.kilocode/skills/` |
91
- | Roo Code | `roo` | `.roo/skills/` | `~/.roo/skills/` |
92
- | Goose | `goose` | `.goose/skills/` | `~/.config/goose/skills/` |
91
+ | Droid | `droid` | `.factory/skills/` | `~/.factory/skills/` |
93
92
  | Gemini CLI | `gemini-cli` | `.gemini/skills/` | `~/.gemini/skills/` |
94
- | Antigravity | `antigravity` | `.agent/skills/` | `~/.gemini/antigravity/skills/` |
95
93
  | GitHub Copilot | `github-copilot` | `.github/skills/` | `~/.copilot/skills/` |
96
- | Clawdbot | `clawdbot` | `skills/` | `~/.clawdbot/skills/` |
97
- | Droid | `droid` | `.factory/skills/` | `~/.factory/skills/` |
94
+ | Goose | `goose` | `.goose/skills/` | `~/.config/goose/skills/` |
95
+ | Kilo Code | `kilo` | `.kilocode/skills/` | `~/.kilocode/skills/` |
96
+ | Kiro CLI | `kiro-cli` | `.kiro/skills/` | `~/.kiro/skills/` |
97
+ | OpenCode | `opencode` | `.opencode/skills/` | `~/.config/opencode/skills/` |
98
+ | Roo Code | `roo` | `.roo/skills/` | `~/.roo/skills/` |
99
+ | Trae | `trae` | `.trae/skills/` | `~/.trae/skills/` |
98
100
  | Windsurf | `windsurf` | `.windsurf/skills/` | `~/.codeium/windsurf/skills/` |
99
101
  <!-- available-agents:end -->
100
102
 
103
+ > [!NOTE]
104
+ > **Kiro CLI users:** After installing skills, you need to manually add them to your custom agent's `resources` in `.kiro/agents/<agent>.json`:
105
+ > ```json
106
+ > {
107
+ > "resources": [
108
+ > "skill://.kiro/skills/**/SKILL.md"
109
+ > ]
110
+ > }
111
+ > ```
112
+
101
113
  ## Agent Detection
102
114
 
103
115
  The CLI automatically detects which coding agents you have installed by checking for their configuration directories. If none are detected, you'll be prompted to select which agents to install to.
@@ -141,19 +153,21 @@ The CLI searches for skills in these locations within a repository:
141
153
  - `skills/.curated/`
142
154
  - `skills/.experimental/`
143
155
  - `skills/.system/`
144
- - `.opencode/skills/`
156
+ - `.agents/skills/`
157
+ - `.agent/skills/`
145
158
  - `.claude/skills/`
159
+ - `./skills/`
146
160
  - `.codex/skills/`
147
161
  - `.cursor/skills/`
148
- - `.agents/skills/`
149
- - `.kilocode/skills/`
150
- - `.roo/skills/`
151
- - `.goose/skills/`
162
+ - `.factory/skills/`
152
163
  - `.gemini/skills/`
153
- - `.agent/skills/`
154
164
  - `.github/skills/`
155
- - `./skills/`
156
- - `.factory/skills/`
165
+ - `.goose/skills/`
166
+ - `.kilocode/skills/`
167
+ - `.kiro/skills/`
168
+ - `.opencode/skills/`
169
+ - `.roo/skills/`
170
+ - `.trae/skills/`
157
171
  - `.windsurf/skills/`
158
172
  <!-- skill-discovery:end -->
159
173
 
@@ -163,12 +177,12 @@ If no skills are found in standard locations, a recursive search is performed.
163
177
 
164
178
  Skills are generally compatible across agents since they follow a shared [Agent Skills specification](https://agentskills.io). However, some features may be agent-specific:
165
179
 
166
- | Feature | OpenCode | Claude Code | Codex | Cursor | Antigravity | Roo Code | Github Copilot | Amp | Clawdbot |
167
- |---------|----------|-------------|-------|--------|-------------|----------|----------------|-----|----------|
168
- | Basic skills | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
169
- | `allowed-tools` | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
170
- | `context: fork` | No | Yes | No | No | No | No | No | No | No |
171
- | Hooks | No | Yes | No | No | No | No | No | No | No |
180
+ | Feature | OpenCode | Claude Code | Codex | Kiro CLI | Cursor | Antigravity | Roo Code | Github Copilot | Amp | Clawdbot |
181
+ |---------|----------|-------------|-------|----------|--------|-------------|----------|----------------|-----|----------|
182
+ | Basic skills | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
183
+ | `allowed-tools` | Yes | Yes | Yes | No | Yes | Yes | Yes | Yes | Yes | Yes |
184
+ | `context: fork` | No | Yes | No | No | No | No | No | No | No | No |
185
+ | Hooks | No | Yes | No | No | No | No | No | No | No | No |
172
186
 
173
187
  ## Troubleshooting
174
188
 
@@ -202,18 +216,20 @@ Telemetry is also automatically disabled in CI environments.
202
216
 
203
217
  ## Related Links
204
218
 
205
- - [Vercel Agent Skills Repository](https://github.com/vercel-labs/agent-skills)
206
219
  - [Agent Skills Specification](https://agentskills.io)
207
- - [OpenCode Skills Documentation](https://opencode.ai/docs/skills)
220
+ - [Amp Skills Documentation](https://ampcode.com/manual#agent-skills)
221
+ - [Antigravity Skills Documentation](https://antigravity.google/docs/skills)
208
222
  - [Claude Code Skills Documentation](https://code.claude.com/docs/en/skills)
223
+ - [Clawdbot Skills Documentation](https://docs.clawd.bot/tools/skills)
209
224
  - [Codex Skills Documentation](https://developers.openai.com/codex/skills)
210
225
  - [Cursor Skills Documentation](https://cursor.com/docs/context/skills)
211
226
  - [Gemini CLI Skills Documentation](https://geminicli.com/docs/cli/skills/)
212
- - [Amp Skills Documentation](https://ampcode.com/manual#agent-skills)
213
- - [Antigravity Skills Documentation](https://antigravity.google/docs/skills)
214
227
  - [GitHub Copilot Agent Skills](https://docs.github.com/en/copilot/concepts/agents/about-agent-skills)
228
+ - [Kiro CLI Skills Documentation](https://kiro.dev/docs/cli/custom-agents/configuration-reference/#skill-resources)
229
+ - [OpenCode Skills Documentation](https://opencode.ai/docs/skills)
215
230
  - [Roo Code Skills Documentation](https://docs.roocode.com/features/skills)
216
- - [Clawdbot Skills Documentation](https://docs.clawd.bot/tools/skills)
231
+ - [Trae Skills Documentation](https://docs.trae.ai/ide/skills)
232
+ - [Vercel Agent Skills Repository](https://github.com/vercel-labs/agent-skills)
217
233
 
218
234
  ## License
219
235
 
package/dist/index.js CHANGED
@@ -197,16 +197,18 @@ async function discoverSkills(basePath, subpath) {
197
197
  join2(searchPath, "skills/.curated"),
198
198
  join2(searchPath, "skills/.experimental"),
199
199
  join2(searchPath, "skills/.system"),
200
- join2(searchPath, ".codex/skills"),
200
+ join2(searchPath, ".agent/skills"),
201
+ join2(searchPath, ".agents/skills"),
201
202
  join2(searchPath, ".claude/skills"),
202
- join2(searchPath, ".opencode/skill"),
203
+ join2(searchPath, ".codex/skills"),
203
204
  join2(searchPath, ".cursor/skills"),
204
- join2(searchPath, ".agents/skills"),
205
+ join2(searchPath, ".github/skills"),
206
+ join2(searchPath, ".goose/skills"),
205
207
  join2(searchPath, ".kilocode/skills"),
208
+ join2(searchPath, ".kiro/skills"),
209
+ join2(searchPath, ".opencode/skills"),
206
210
  join2(searchPath, ".roo/skills"),
207
- join2(searchPath, ".goose/skills"),
208
- join2(searchPath, ".agent/skills"),
209
- join2(searchPath, ".github/skills")
211
+ join2(searchPath, ".trae/skills")
210
212
  ];
211
213
  for (const dir of prioritySearchDirs) {
212
214
  try {
@@ -243,8 +245,9 @@ function getSkillDisplayName(skill) {
243
245
  }
244
246
 
245
247
  // src/installer.ts
246
- import { mkdir, cp, access, readdir as readdir2 } from "fs/promises";
247
- import { join as join4, basename as basename2, normalize as normalize2, resolve as resolve3, sep as sep2 } from "path";
248
+ import { mkdir, cp, access, readdir as readdir2, symlink, lstat, rm as rm2, readlink } from "fs/promises";
249
+ import { join as join4, basename as basename2, normalize as normalize2, resolve as resolve3, sep as sep2, relative } from "path";
250
+ import { homedir as homedir2, platform } from "os";
248
251
 
249
252
  // src/agents.ts
250
253
  import { homedir } from "os";
@@ -252,13 +255,22 @@ import { join as join3 } from "path";
252
255
  import { existsSync } from "fs";
253
256
  var home = homedir();
254
257
  var agents = {
255
- opencode: {
256
- name: "opencode",
257
- displayName: "OpenCode",
258
- skillsDir: ".opencode/skills",
259
- globalSkillsDir: join3(home, ".config/opencode/skills"),
258
+ amp: {
259
+ name: "amp",
260
+ displayName: "Amp",
261
+ skillsDir: ".agents/skills",
262
+ globalSkillsDir: join3(home, ".config/agents/skills"),
260
263
  detectInstalled: async () => {
261
- return existsSync(join3(home, ".config/opencode")) || existsSync(join3(home, ".claude/skills"));
264
+ return existsSync(join3(home, ".config/amp"));
265
+ }
266
+ },
267
+ antigravity: {
268
+ name: "antigravity",
269
+ displayName: "Antigravity",
270
+ skillsDir: ".agent/skills",
271
+ globalSkillsDir: join3(home, ".gemini/antigravity/skills"),
272
+ detectInstalled: async () => {
273
+ return existsSync(join3(process.cwd(), ".agent")) || existsSync(join3(home, ".gemini/antigravity"));
262
274
  }
263
275
  },
264
276
  "claude-code": {
@@ -270,6 +282,15 @@ var agents = {
270
282
  return existsSync(join3(home, ".claude"));
271
283
  }
272
284
  },
285
+ clawdbot: {
286
+ name: "clawdbot",
287
+ displayName: "Clawdbot",
288
+ skillsDir: "skills",
289
+ globalSkillsDir: join3(home, ".clawdbot/skills"),
290
+ detectInstalled: async () => {
291
+ return existsSync(join3(home, ".clawdbot"));
292
+ }
293
+ },
273
294
  codex: {
274
295
  name: "codex",
275
296
  displayName: "Codex",
@@ -288,31 +309,31 @@ var agents = {
288
309
  return existsSync(join3(home, ".cursor"));
289
310
  }
290
311
  },
291
- amp: {
292
- name: "amp",
293
- displayName: "Amp",
294
- skillsDir: ".agents/skills",
295
- globalSkillsDir: join3(home, ".config/agents/skills"),
312
+ droid: {
313
+ name: "droid",
314
+ displayName: "Droid",
315
+ skillsDir: ".factory/skills",
316
+ globalSkillsDir: join3(home, ".factory/skills"),
296
317
  detectInstalled: async () => {
297
- return existsSync(join3(home, ".config/amp"));
318
+ return existsSync(join3(home, ".factory/skills"));
298
319
  }
299
320
  },
300
- kilo: {
301
- name: "kilo",
302
- displayName: "Kilo Code",
303
- skillsDir: ".kilocode/skills",
304
- globalSkillsDir: join3(home, ".kilocode/skills"),
321
+ "gemini-cli": {
322
+ name: "gemini-cli",
323
+ displayName: "Gemini CLI",
324
+ skillsDir: ".gemini/skills",
325
+ globalSkillsDir: join3(home, ".gemini/skills"),
305
326
  detectInstalled: async () => {
306
- return existsSync(join3(home, ".kilocode"));
327
+ return existsSync(join3(home, ".gemini"));
307
328
  }
308
329
  },
309
- roo: {
310
- name: "roo",
311
- displayName: "Roo Code",
312
- skillsDir: ".roo/skills",
313
- globalSkillsDir: join3(home, ".roo/skills"),
330
+ "github-copilot": {
331
+ name: "github-copilot",
332
+ displayName: "GitHub Copilot",
333
+ skillsDir: ".github/skills",
334
+ globalSkillsDir: join3(home, ".copilot/skills"),
314
335
  detectInstalled: async () => {
315
- return existsSync(join3(home, ".roo"));
336
+ return existsSync(join3(process.cwd(), ".github")) || existsSync(join3(home, ".copilot"));
316
337
  }
317
338
  },
318
339
  goose: {
@@ -324,49 +345,49 @@ var agents = {
324
345
  return existsSync(join3(home, ".config/goose"));
325
346
  }
326
347
  },
327
- "gemini-cli": {
328
- name: "gemini-cli",
329
- displayName: "Gemini CLI",
330
- skillsDir: ".gemini/skills",
331
- globalSkillsDir: join3(home, ".gemini/skills"),
348
+ kilo: {
349
+ name: "kilo",
350
+ displayName: "Kilo Code",
351
+ skillsDir: ".kilocode/skills",
352
+ globalSkillsDir: join3(home, ".kilocode/skills"),
332
353
  detectInstalled: async () => {
333
- return existsSync(join3(home, ".gemini"));
354
+ return existsSync(join3(home, ".kilocode"));
334
355
  }
335
356
  },
336
- antigravity: {
337
- name: "antigravity",
338
- displayName: "Antigravity",
339
- skillsDir: ".agent/skills",
340
- globalSkillsDir: join3(home, ".gemini/antigravity/skills"),
357
+ "kiro-cli": {
358
+ name: "kiro-cli",
359
+ displayName: "Kiro CLI",
360
+ skillsDir: ".kiro/skills",
361
+ globalSkillsDir: join3(home, ".kiro/skills"),
341
362
  detectInstalled: async () => {
342
- return existsSync(join3(process.cwd(), ".agent")) || existsSync(join3(home, ".gemini/antigravity"));
363
+ return existsSync(join3(home, ".kiro"));
343
364
  }
344
365
  },
345
- "github-copilot": {
346
- name: "github-copilot",
347
- displayName: "GitHub Copilot",
348
- skillsDir: ".github/skills",
349
- globalSkillsDir: join3(home, ".copilot/skills"),
366
+ opencode: {
367
+ name: "opencode",
368
+ displayName: "OpenCode",
369
+ skillsDir: ".opencode/skills",
370
+ globalSkillsDir: join3(home, ".config/opencode/skills"),
350
371
  detectInstalled: async () => {
351
- return existsSync(join3(process.cwd(), ".github")) || existsSync(join3(home, ".copilot"));
372
+ return existsSync(join3(home, ".config/opencode")) || existsSync(join3(home, ".claude/skills"));
352
373
  }
353
374
  },
354
- clawdbot: {
355
- name: "clawdbot",
356
- displayName: "Clawdbot",
357
- skillsDir: "skills",
358
- globalSkillsDir: join3(home, ".clawdbot/skills"),
375
+ roo: {
376
+ name: "roo",
377
+ displayName: "Roo Code",
378
+ skillsDir: ".roo/skills",
379
+ globalSkillsDir: join3(home, ".roo/skills"),
359
380
  detectInstalled: async () => {
360
- return existsSync(join3(home, ".clawdbot"));
381
+ return existsSync(join3(home, ".roo"));
361
382
  }
362
383
  },
363
- droid: {
364
- name: "droid",
365
- displayName: "Droid",
366
- skillsDir: ".factory/skills",
367
- globalSkillsDir: join3(home, ".factory/skills"),
384
+ trae: {
385
+ name: "trae",
386
+ displayName: "Trae",
387
+ skillsDir: ".trae/skills",
388
+ globalSkillsDir: join3(home, ".trae/skills"),
368
389
  detectInstalled: async () => {
369
- return existsSync(join3(home, ".factory/skills"));
390
+ return existsSync(join3(home, ".trae"));
370
391
  }
371
392
  },
372
393
  windsurf: {
@@ -390,6 +411,8 @@ async function detectInstalledAgents() {
390
411
  }
391
412
 
392
413
  // src/installer.ts
414
+ var AGENTS_DIR = ".agents";
415
+ var SKILLS_SUBDIR = "skills";
393
416
  function sanitizeName(name) {
394
417
  let sanitized = name.replace(/[\/\\:\0]/g, "");
395
418
  sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, "");
@@ -407,27 +430,82 @@ function isPathSafe(basePath, targetPath) {
407
430
  const normalizedTarget = normalize2(resolve3(targetPath));
408
431
  return normalizedTarget.startsWith(normalizedBase + sep2) || normalizedTarget === normalizedBase;
409
432
  }
433
+ function getCanonicalSkillsDir(global, cwd) {
434
+ const baseDir = global ? homedir2() : cwd || process.cwd();
435
+ return join4(baseDir, AGENTS_DIR, SKILLS_SUBDIR);
436
+ }
437
+ async function createSymlink(target, linkPath) {
438
+ try {
439
+ try {
440
+ const stats = await lstat(linkPath);
441
+ if (stats.isSymbolicLink()) {
442
+ const existingTarget = await readlink(linkPath);
443
+ if (resolve3(existingTarget) === resolve3(target)) {
444
+ return true;
445
+ }
446
+ await rm2(linkPath);
447
+ } else {
448
+ await rm2(linkPath, { recursive: true });
449
+ }
450
+ } catch {
451
+ }
452
+ const linkDir = join4(linkPath, "..");
453
+ await mkdir(linkDir, { recursive: true });
454
+ const relativePath = relative(linkDir, target);
455
+ const symlinkType = platform() === "win32" ? "junction" : void 0;
456
+ await symlink(relativePath, linkPath, symlinkType);
457
+ return true;
458
+ } catch {
459
+ return false;
460
+ }
461
+ }
410
462
  async function installSkillForAgent(skill, agentType, options = {}) {
411
463
  const agent = agents[agentType];
464
+ const isGlobal = options.global ?? false;
465
+ const cwd = options.cwd || process.cwd();
412
466
  const rawSkillName = skill.name || basename2(skill.path);
413
467
  const skillName = sanitizeName(rawSkillName);
414
- const targetBase = options.global ? agent.globalSkillsDir : join4(options.cwd || process.cwd(), agent.skillsDir);
415
- const targetDir = join4(targetBase, skillName);
416
- if (!isPathSafe(targetBase, targetDir)) {
468
+ const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);
469
+ const canonicalDir = join4(canonicalBase, skillName);
470
+ const agentBase = isGlobal ? agent.globalSkillsDir : join4(cwd, agent.skillsDir);
471
+ const agentDir = join4(agentBase, skillName);
472
+ if (!isPathSafe(canonicalBase, canonicalDir)) {
417
473
  return {
418
474
  success: false,
419
- path: targetDir,
475
+ path: agentDir,
476
+ error: "Invalid skill name: potential path traversal detected"
477
+ };
478
+ }
479
+ if (!isPathSafe(agentBase, agentDir)) {
480
+ return {
481
+ success: false,
482
+ path: agentDir,
420
483
  error: "Invalid skill name: potential path traversal detected"
421
484
  };
422
485
  }
423
486
  try {
424
- await mkdir(targetDir, { recursive: true });
425
- await copyDirectory(skill.path, targetDir);
426
- return { success: true, path: targetDir };
487
+ await mkdir(canonicalDir, { recursive: true });
488
+ await copyDirectory(skill.path, canonicalDir);
489
+ const symlinkCreated = await createSymlink(canonicalDir, agentDir);
490
+ if (!symlinkCreated) {
491
+ await mkdir(agentDir, { recursive: true });
492
+ await copyDirectory(skill.path, agentDir);
493
+ return {
494
+ success: true,
495
+ path: agentDir,
496
+ canonicalPath: canonicalDir,
497
+ symlinkFailed: true
498
+ };
499
+ }
500
+ return {
501
+ success: true,
502
+ path: agentDir,
503
+ canonicalPath: canonicalDir
504
+ };
427
505
  } catch (error) {
428
506
  return {
429
507
  success: false,
430
- path: targetDir,
508
+ path: agentDir,
431
509
  error: error instanceof Error ? error.message : "Unknown error"
432
510
  };
433
511
  }
@@ -472,17 +550,19 @@ async function isSkillInstalled(skillName, agentType, options = {}) {
472
550
  return false;
473
551
  }
474
552
  }
475
- function getInstallPath(skillName, agentType, options = {}) {
476
- const agent = agents[agentType];
553
+ function getCanonicalPath(skillName, options = {}) {
477
554
  const sanitized = sanitizeName(skillName);
478
- const targetBase = options.global ? agent.globalSkillsDir : join4(options.cwd || process.cwd(), agent.skillsDir);
479
- const installPath = join4(targetBase, sanitized);
480
- if (!isPathSafe(targetBase, installPath)) {
555
+ const canonicalBase = getCanonicalSkillsDir(options.global ?? false, options.cwd);
556
+ const canonicalPath = join4(canonicalBase, sanitized);
557
+ if (!isPathSafe(canonicalBase, canonicalPath)) {
481
558
  throw new Error("Invalid skill name: potential path traversal detected");
482
559
  }
483
- return installPath;
560
+ return canonicalPath;
484
561
  }
485
562
 
563
+ // src/index.ts
564
+ import { homedir as homedir3 } from "os";
565
+
486
566
  // src/telemetry.ts
487
567
  var TELEMETRY_URL = "https://add-skill.vercel.sh/t";
488
568
  var cliVersion = null;
@@ -519,7 +599,7 @@ function track(data) {
519
599
  // package.json
520
600
  var package_default = {
521
601
  name: "add-skill",
522
- version: "1.0.20",
602
+ version: "1.0.22",
523
603
  description: "Install agent skills onto coding agents (OpenCode, Claude Code, Codex, Cursor)",
524
604
  type: "module",
525
605
  bin: {
@@ -539,19 +619,21 @@ var package_default = {
539
619
  "agent-skills",
540
620
  "skills",
541
621
  "ai-agents",
542
- "opencode",
622
+ "amp",
623
+ "antigravity",
543
624
  "claude-code",
625
+ "clawdbot",
544
626
  "codex",
545
627
  "cursor",
546
- "amp",
547
- "kilo",
548
- "roo",
549
- "goose",
628
+ "droid",
550
629
  "gemini-cli",
551
- "antigravity",
552
630
  "github-copilot",
553
- "clawdbot",
554
- "droid",
631
+ "goose",
632
+ "kilo",
633
+ "kiro-cli",
634
+ "opencode",
635
+ "roo",
636
+ "trae",
555
637
  "windsurf"
556
638
  ],
557
639
  repository: {
@@ -583,9 +665,27 @@ var package_default = {
583
665
  };
584
666
 
585
667
  // src/index.ts
668
+ function shortenPath(fullPath, cwd) {
669
+ const home2 = homedir3();
670
+ if (fullPath.startsWith(home2)) {
671
+ return fullPath.replace(home2, "~");
672
+ }
673
+ if (fullPath.startsWith(cwd)) {
674
+ return "." + fullPath.slice(cwd.length);
675
+ }
676
+ return fullPath;
677
+ }
678
+ function formatList(items, maxShow = 5) {
679
+ if (items.length <= maxShow) {
680
+ return items.join(", ");
681
+ }
682
+ const shown = items.slice(0, maxShow);
683
+ const remaining = items.length - maxShow;
684
+ return `${shown.join(", ")} +${remaining} more`;
685
+ }
586
686
  var version = package_default.version;
587
687
  setVersion(version);
588
- program.name("add-skill").description("Install skills onto coding agents (OpenCode, Claude Code, Codex, Cursor, Antigravity, Github Copilot, Roo Code)").version(version).argument("<source>", "Git repo URL, GitHub shorthand (owner/repo), local path (./path), or direct path to skill").option("-g, --global", "Install skill globally (user-level) instead of project-level").option("-a, --agent <agents...>", "Specify agents to install to (opencode, claude-code, codex, cursor, antigravity, gitub-copilot, roo)").option("-s, --skill <skills...>", "Specify skill names to install (skip selection prompt)").option("-l, --list", "List available skills in the repository without installing").option("-y, --yes", "Skip confirmation prompts").option("--all", "Install all skills to all agents without any prompts (implies -y -g)").configureOutput({
688
+ program.name("add-skill").description("Install skills onto coding agents (OpenCode, Claude Code, Codex, Kiro CLI, Cursor, Antigravity, Github Copilot, Roo Code)").version(version).argument("<source>", "Git repo URL, GitHub shorthand (owner/repo), local path (./path), or direct path to skill").option("-g, --global", "Install skill globally (user-level) instead of project-level").option("-a, --agent <agents...>", "Specify agents to install to (opencode, claude-code, codex, kiro-cli, cursor, antigravity, github-copilot, roo)").option("-s, --skill <skills...>", "Specify skill names to install (skip selection prompt)").option("-l, --list", "List available skills in the repository without installing").option("-y, --yes", "Skip confirmation prompts").option("--all", "Install all skills to all agents without any prompts (implies -y -g)").configureOutput({
589
689
  outputError: (str, write) => {
590
690
  if (str.includes("missing required argument")) {
591
691
  console.log();
@@ -786,8 +886,8 @@ async function main(source, options) {
786
886
  }
787
887
  installGlobally = scope;
788
888
  }
889
+ const cwd = process.cwd();
789
890
  const summaryLines = [];
790
- const maxAgentLen = Math.max(...targetAgents.map((a) => agents[a].displayName.length));
791
891
  const overwriteStatus = /* @__PURE__ */ new Map();
792
892
  for (const skill of selectedSkills) {
793
893
  const agentStatus = /* @__PURE__ */ new Map();
@@ -796,18 +896,20 @@ async function main(source, options) {
796
896
  }
797
897
  overwriteStatus.set(skill.name, agentStatus);
798
898
  }
899
+ const agentNames = targetAgents.map((a) => agents[a].displayName);
900
+ const hasOverwrites = Array.from(overwriteStatus.values()).some(
901
+ (agentMap) => Array.from(agentMap.values()).some((v) => v)
902
+ );
799
903
  for (const skill of selectedSkills) {
800
904
  if (summaryLines.length > 0) summaryLines.push("");
801
- summaryLines.push(chalk.bold.cyan(getSkillDisplayName(skill)));
802
- summaryLines.push("");
803
- summaryLines.push(` ${chalk.bold("Agent".padEnd(maxAgentLen + 2))}${chalk.bold("Directory")}`);
804
- for (const agent of targetAgents) {
805
- const fullPath = getInstallPath(skill.name, agent, { global: installGlobally });
806
- const basePath = fullPath.replace(/\/[^/]+$/, "/");
807
- const installed = overwriteStatus.get(skill.name)?.get(agent) ?? false;
808
- const status = installed ? chalk.yellow(" (overwrite)") : "";
809
- const agentName = agents[agent].displayName.padEnd(maxAgentLen + 2);
810
- summaryLines.push(` ${agentName}${chalk.dim(basePath)}${status}`);
905
+ const canonicalPath = getCanonicalPath(skill.name, { global: installGlobally });
906
+ const shortCanonical = shortenPath(canonicalPath, cwd);
907
+ summaryLines.push(`${chalk.cyan(shortCanonical)}`);
908
+ const skillOverwrites = overwriteStatus.get(skill.name);
909
+ const overwriteAgents = targetAgents.filter((a) => skillOverwrites?.get(a)).map((a) => agents[a].displayName);
910
+ summaryLines.push(` ${chalk.dim("\u2192")} ${formatList(agentNames)}`);
911
+ if (overwriteAgents.length > 0) {
912
+ summaryLines.push(` ${chalk.yellow("overwrites:")} ${formatList(overwriteAgents)}`);
811
913
  }
812
914
  }
813
915
  console.log();
@@ -862,25 +964,36 @@ async function main(source, options) {
862
964
  if (successful.length > 0) {
863
965
  const bySkill = /* @__PURE__ */ new Map();
864
966
  for (const r of successful) {
865
- const skillAgents = bySkill.get(r.skill) || [];
866
- skillAgents.push(r.agent);
867
- bySkill.set(r.skill, skillAgents);
967
+ const skillResults = bySkill.get(r.skill) || [];
968
+ skillResults.push(r);
969
+ bySkill.set(r.skill, skillResults);
868
970
  }
869
971
  const skillCount = bySkill.size;
870
972
  const agentCount = new Set(successful.map((r) => r.agent)).size;
973
+ const symlinkFailures = successful.filter((r) => r.symlinkFailed);
974
+ const copiedAgents = symlinkFailures.map((r) => r.agent);
871
975
  const resultLines = [];
872
- for (const [skill, skillAgents] of bySkill) {
873
- resultLines.push(`${chalk.green("\u2713")} ${chalk.bold(skill)}`);
874
- for (const agent of skillAgents) {
875
- resultLines.push(` ${chalk.dim(agent)}`);
976
+ for (const [, skillResults] of bySkill) {
977
+ const firstResult = skillResults[0];
978
+ if (firstResult.canonicalPath) {
979
+ const shortPath = shortenPath(firstResult.canonicalPath, cwd);
980
+ resultLines.push(`${chalk.green("\u2713")} ${shortPath}`);
981
+ }
982
+ const symlinked = skillResults.filter((r) => !r.symlinkFailed).map((r) => r.agent);
983
+ const copied = skillResults.filter((r) => r.symlinkFailed).map((r) => r.agent);
984
+ if (symlinked.length > 0) {
985
+ resultLines.push(` ${chalk.dim("\u2192")} ${formatList(symlinked)}`);
986
+ }
987
+ if (copied.length > 0) {
988
+ resultLines.push(` ${chalk.yellow("copied \u2192")} ${formatList(copied)}`);
876
989
  }
877
- resultLines.push("");
878
- }
879
- if (resultLines.length > 0 && resultLines[resultLines.length - 1] === "") {
880
- resultLines.pop();
881
990
  }
882
991
  const title = chalk.green(`Installed ${skillCount} skill${skillCount !== 1 ? "s" : ""} to ${agentCount} agent${agentCount !== 1 ? "s" : ""}`);
883
992
  p.note(resultLines.join("\n"), title);
993
+ if (symlinkFailures.length > 0) {
994
+ p.log.warn(chalk.yellow(`Symlinks failed for: ${formatList(copiedAgents)}`));
995
+ p.log.message(chalk.dim(" Files were copied instead. On Windows, enable Developer Mode for symlink support."));
996
+ }
884
997
  }
885
998
  if (failed.length > 0) {
886
999
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "add-skill",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "Install agent skills onto coding agents (OpenCode, Claude Code, Codex, Cursor)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,19 +20,21 @@
20
20
  "agent-skills",
21
21
  "skills",
22
22
  "ai-agents",
23
- "opencode",
23
+ "amp",
24
+ "antigravity",
24
25
  "claude-code",
26
+ "clawdbot",
25
27
  "codex",
26
28
  "cursor",
27
- "amp",
28
- "kilo",
29
- "roo",
30
- "goose",
29
+ "droid",
31
30
  "gemini-cli",
32
- "antigravity",
33
31
  "github-copilot",
34
- "clawdbot",
35
- "droid",
32
+ "goose",
33
+ "kilo",
34
+ "kiro-cli",
35
+ "opencode",
36
+ "roo",
37
+ "trae",
36
38
  "windsurf"
37
39
  ],
38
40
  "repository": {