ai-agent-skills 1.6.2 → 1.8.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.
Files changed (3) hide show
  1. package/README.md +5 -4
  2. package/cli.js +238 -14
  3. package/package.json +5 -2
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  <p align="center">
13
13
  <img src="https://img.shields.io/badge/skills-40-blue?style=flat-square" alt="Skills" />
14
- <img src="https://img.shields.io/badge/agents-10+-green?style=flat-square" alt="Compatible Agents" />
14
+ <img src="https://img.shields.io/badge/agents-11+-green?style=flat-square" alt="Compatible Agents" />
15
15
  <img src="https://img.shields.io/badge/license-MIT-brightgreen?style=flat-square" alt="License" />
16
16
  <img src="https://img.shields.io/npm/v/ai-agent-skills?style=flat-square&color=red" alt="npm" />
17
17
  <img src="https://img.shields.io/npm/dt/ai-agent-skills?style=flat-square&color=orange" alt="Downloads" />
@@ -46,17 +46,17 @@ npx ai-agent-skills install anthropics/skills/pdf # specific skill
46
46
  npx ai-agent-skills install ./my-custom-skill
47
47
  ```
48
48
 
49
- **One command. Every agent.** By default, skills install to Claude Code, Cursor, Codex, Amp, VS Code, Copilot, Goose, Letta, and OpenCode simultaneously.
49
+ **One command. Every agent.** By default, skills install to Claude Code, Cursor, Codex, Amp, VS Code, Copilot, Gemini CLI, Goose, Letta, and OpenCode simultaneously.
50
50
 
51
51
  ## Why This Exists
52
52
 
53
53
  Every major AI coding agent now supports skills. But they're scattered everywhere.
54
54
 
55
- This repo curates the best in one place. Quality over quantity. All skills follow the [Agent Skills spec](https://agentskills.io).
55
+ We also created our own repo to cureate the best in one place. Quality over quantity https://www.skillcreator.ai/explore All skills follow the [Agent Skills spec](https://agentskills.io).
56
56
 
57
57
  ## Compatible Agents
58
58
 
59
- Works with **Claude Code**, **Cursor**, **Codex**, **Amp**, **VS Code**, **GitHub Copilot**, **Goose**, **Letta**, and **OpenCode**.
59
+ Works with **Claude Code**, **Cursor**, **Codex**, **Amp**, **VS Code**, **GitHub Copilot**, **Gemini CLI**, **Goose**, **Letta**, and **OpenCode**.
60
60
 
61
61
  ## Available Skills
62
62
 
@@ -162,6 +162,7 @@ By default, `install` targets **all agents**. Use `--agent <name>` to install to
162
162
  | Codex | `--agent codex` | `~/.codex/skills/` |
163
163
  | Amp | `--agent amp` | `~/.amp/skills/` |
164
164
  | VS Code / Copilot | `--agent vscode` | `.github/skills/` |
165
+ | Gemini CLI | `--agent gemini` | `~/.gemini/skills/` |
165
166
  | Goose | `--agent goose` | `~/.config/goose/skills/` |
166
167
  | OpenCode | `--agent opencode` | `~/.opencode/skill/` |
167
168
  | Letta | `--agent letta` | `~/.letta/skills/` |
package/cli.js CHANGED
@@ -24,9 +24,10 @@ const AGENT_PATHS = {
24
24
  copilot: path.join(process.cwd(), '.github', 'skills'),
25
25
  project: path.join(process.cwd(), '.skills'),
26
26
  goose: path.join(os.homedir(), '.config', 'goose', 'skills'),
27
- opencode: path.join(os.homedir(), '.opencode', 'skill'),
27
+ opencode: path.join(os.homedir(), '.config', 'opencode', 'skill'),
28
28
  codex: path.join(os.homedir(), '.codex', 'skills'),
29
29
  letta: path.join(os.homedir(), '.letta', 'skills'),
30
+ gemini: path.join(os.homedir(), '.gemini', 'skills'),
30
31
  };
31
32
 
32
33
  const colors = {
@@ -70,6 +71,41 @@ function saveConfig(config) {
70
71
  }
71
72
  }
72
73
 
74
+ // ============ SKILL METADATA SUPPORT ============
75
+
76
+ const SKILL_META_FILE = '.skill-meta.json';
77
+
78
+ function writeSkillMeta(skillPath, meta) {
79
+ try {
80
+ const metaPath = path.join(skillPath, SKILL_META_FILE);
81
+ const now = new Date().toISOString();
82
+ const metadata = {
83
+ ...meta,
84
+ // Preserve original installedAt if it exists, otherwise set it
85
+ installedAt: meta.installedAt || now,
86
+ // Always update the updatedAt timestamp
87
+ updatedAt: now
88
+ };
89
+ fs.writeFileSync(metaPath, JSON.stringify(metadata, null, 2));
90
+ return true;
91
+ } catch (e) {
92
+ // Non-fatal - skill still works without metadata
93
+ return false;
94
+ }
95
+ }
96
+
97
+ function readSkillMeta(skillPath) {
98
+ try {
99
+ const metaPath = path.join(skillPath, SKILL_META_FILE);
100
+ if (fs.existsSync(metaPath)) {
101
+ return JSON.parse(fs.readFileSync(metaPath, 'utf8'));
102
+ }
103
+ } catch (e) {
104
+ // Ignore - treat as legacy skill
105
+ }
106
+ return null;
107
+ }
108
+
73
109
  // ============ SECURITY VALIDATION ============
74
110
 
75
111
  function validateSkillName(name) {
@@ -367,6 +403,12 @@ function installSkill(skillName, agent = 'claude', dryRun = false) {
367
403
 
368
404
  copyDir(sourcePath, destPath);
369
405
 
406
+ // Write metadata for update tracking
407
+ writeSkillMeta(destPath, {
408
+ source: 'registry',
409
+ name: skillName
410
+ });
411
+
370
412
  success(`\nInstalled: ${skillName}`);
371
413
  info(`Agent: ${agent}`);
372
414
  info(`Location: ${destPath}`);
@@ -393,7 +435,8 @@ function showAgentInstructions(agent, skillName, destPath) {
393
435
  project: `The skill is installed in .skills/ in your current directory.\nThis makes it portable across all compatible agents.`,
394
436
  letta: `The skill is now available in Letta.`,
395
437
  goose: `The skill is now available in Goose.`,
396
- opencode: `The skill is now available in OpenCode.`
438
+ opencode: `The skill is now available in OpenCode.`,
439
+ gemini: `The skill is now available in Gemini CLI.\nMake sure Agent Skills is enabled in your Gemini CLI settings.`
397
440
  };
398
441
 
399
442
  log(`${colors.dim}${instructions[agent] || `The skill is ready to use with ${agent}.`}${colors.reset}`);
@@ -474,32 +517,133 @@ function listInstalledSkills(agent = 'claude') {
474
517
  log(`${colors.dim}Uninstall: npx ai-agent-skills uninstall <name> --agent ${agent}${colors.reset}`);
475
518
  }
476
519
 
477
- function updateSkill(skillName, agent = 'claude', dryRun = false) {
520
+ // Update from bundled registry
521
+ function updateFromRegistry(skillName, agent, destPath, dryRun) {
522
+ const sourcePath = path.join(SKILLS_DIR, skillName);
523
+
524
+ if (!fs.existsSync(sourcePath)) {
525
+ error(`Skill "${skillName}" not found in repository.`);
526
+ return false;
527
+ }
528
+
529
+ if (dryRun) {
530
+ log(`\n${colors.bold}Dry Run${colors.reset} (no changes made)\n`);
531
+ info(`Would update: ${skillName} (from registry)`);
532
+ info(`Agent: ${agent}`);
533
+ info(`Path: ${destPath}`);
534
+ return true;
535
+ }
536
+
478
537
  try {
479
- validateSkillName(skillName);
538
+ fs.rmSync(destPath, { recursive: true });
539
+ copyDir(sourcePath, destPath);
540
+
541
+ // Write metadata
542
+ writeSkillMeta(destPath, {
543
+ source: 'registry',
544
+ name: skillName
545
+ });
546
+
547
+ success(`\nUpdated: ${skillName}`);
548
+ info(`Agent: ${agent}`);
549
+ info(`Location: ${destPath}`);
550
+ return true;
480
551
  } catch (e) {
481
- error(e.message);
552
+ error(`Failed to update skill: ${e.message}`);
482
553
  return false;
483
554
  }
555
+ }
484
556
 
485
- const sourcePath = path.join(SKILLS_DIR, skillName);
486
- const destDir = AGENT_PATHS[agent] || AGENT_PATHS.claude;
487
- const destPath = path.join(destDir, skillName);
557
+ // Update from GitHub repository
558
+ function updateFromGitHub(meta, skillName, agent, destPath, dryRun) {
559
+ const { execFileSync } = require('child_process');
560
+ const repo = meta.repo;
561
+
562
+ // Validate repo format
563
+ if (!repo || typeof repo !== 'string' || !repo.includes('/')) {
564
+ error(`Invalid repository in metadata: ${repo}`);
565
+ error(`Try reinstalling the skill from GitHub.`);
566
+ return false;
567
+ }
568
+
569
+ if (dryRun) {
570
+ log(`\n${colors.bold}Dry Run${colors.reset} (no changes made)\n`);
571
+ info(`Would update: ${skillName} (from github:${repo})`);
572
+ info(`Agent: ${agent}`);
573
+ info(`Path: ${destPath}`);
574
+ return true;
575
+ }
576
+
577
+ const tempDir = path.join(os.tmpdir(), `ai-skills-update-${Date.now()}`);
578
+
579
+ try {
580
+ info(`Updating ${skillName} from ${repo}...`);
581
+ const repoUrl = `https://github.com/${repo}.git`;
582
+ execFileSync('git', ['clone', '--depth', '1', repoUrl, tempDir], { stdio: 'pipe' });
583
+
584
+ // Determine source path in cloned repo
585
+ let sourcePath;
586
+ if (meta.isRootSkill) {
587
+ sourcePath = tempDir;
588
+ } else if (meta.skillPath) {
589
+ // Check if skills/ subdirectory exists
590
+ const skillsSubdir = path.join(tempDir, 'skills', meta.skillPath);
591
+ const directPath = path.join(tempDir, meta.skillPath);
592
+ sourcePath = fs.existsSync(skillsSubdir) ? skillsSubdir : directPath;
593
+ } else {
594
+ sourcePath = tempDir;
595
+ }
596
+
597
+ if (!fs.existsSync(sourcePath) || !fs.existsSync(path.join(sourcePath, 'SKILL.md'))) {
598
+ error(`Skill not found in repository ${repo}`);
599
+ fs.rmSync(tempDir, { recursive: true });
600
+ return false;
601
+ }
602
+
603
+ fs.rmSync(destPath, { recursive: true });
604
+ copyDir(sourcePath, destPath);
605
+
606
+ // Preserve metadata
607
+ writeSkillMeta(destPath, meta);
608
+
609
+ fs.rmSync(tempDir, { recursive: true });
610
+
611
+ success(`\nUpdated: ${skillName}`);
612
+ info(`Source: github:${repo}`);
613
+ info(`Agent: ${agent}`);
614
+ info(`Location: ${destPath}`);
615
+ return true;
616
+ } catch (e) {
617
+ error(`Failed to update from GitHub: ${e.message}`);
618
+ try { fs.rmSync(tempDir, { recursive: true }); } catch {}
619
+ return false;
620
+ }
621
+ }
622
+
623
+ // Update from local path
624
+ function updateFromLocalPath(meta, skillName, agent, destPath, dryRun) {
625
+ const sourcePath = meta.path;
626
+
627
+ if (!sourcePath || typeof sourcePath !== 'string') {
628
+ error(`Invalid path in metadata.`);
629
+ error(`Try reinstalling the skill from the local path.`);
630
+ return false;
631
+ }
488
632
 
489
633
  if (!fs.existsSync(sourcePath)) {
490
- error(`Skill "${skillName}" not found in repository.`);
634
+ error(`Source path no longer exists: ${sourcePath}`);
491
635
  return false;
492
636
  }
493
637
 
494
- if (!fs.existsSync(destPath)) {
495
- error(`Skill "${skillName}" is not installed for ${agent}.`);
496
- log(`\nUse 'install' to add it first.`);
638
+ // Verify it's still a valid skill directory
639
+ if (!fs.existsSync(path.join(sourcePath, 'SKILL.md'))) {
640
+ error(`Source is no longer a valid skill (missing SKILL.md): ${sourcePath}`);
497
641
  return false;
498
642
  }
499
643
 
500
644
  if (dryRun) {
501
645
  log(`\n${colors.bold}Dry Run${colors.reset} (no changes made)\n`);
502
- info(`Would update: ${skillName}`);
646
+ info(`Would update: ${skillName} (from local:${sourcePath})`);
503
647
  info(`Agent: ${agent}`);
504
648
  info(`Path: ${destPath}`);
505
649
  return true;
@@ -509,16 +653,57 @@ function updateSkill(skillName, agent = 'claude', dryRun = false) {
509
653
  fs.rmSync(destPath, { recursive: true });
510
654
  copyDir(sourcePath, destPath);
511
655
 
656
+ // Preserve metadata
657
+ writeSkillMeta(destPath, meta);
658
+
512
659
  success(`\nUpdated: ${skillName}`);
660
+ info(`Source: local:${sourcePath}`);
513
661
  info(`Agent: ${agent}`);
514
662
  info(`Location: ${destPath}`);
515
663
  return true;
516
664
  } catch (e) {
517
- error(`Failed to update skill: ${e.message}`);
665
+ error(`Failed to update from local path: ${e.message}`);
518
666
  return false;
519
667
  }
520
668
  }
521
669
 
670
+ function updateSkill(skillName, agent = 'claude', dryRun = false) {
671
+ try {
672
+ validateSkillName(skillName);
673
+ } catch (e) {
674
+ error(e.message);
675
+ return false;
676
+ }
677
+
678
+ const destDir = AGENT_PATHS[agent] || AGENT_PATHS.claude;
679
+ const destPath = path.join(destDir, skillName);
680
+
681
+ if (!fs.existsSync(destPath)) {
682
+ error(`Skill "${skillName}" is not installed for ${agent}.`);
683
+ log(`\nUse 'install' to add it first.`);
684
+ return false;
685
+ }
686
+
687
+ // Read metadata to determine source
688
+ const meta = readSkillMeta(destPath);
689
+
690
+ if (!meta) {
691
+ // Legacy skill without metadata - try registry
692
+ return updateFromRegistry(skillName, agent, destPath, dryRun);
693
+ }
694
+
695
+ // Route to correct update method based on source
696
+ switch (meta.source) {
697
+ case 'github':
698
+ return updateFromGitHub(meta, skillName, agent, destPath, dryRun);
699
+ case 'local':
700
+ return updateFromLocalPath(meta, skillName, agent, destPath, dryRun);
701
+ case 'registry':
702
+ default:
703
+ return updateFromRegistry(skillName, agent, destPath, dryRun);
704
+ }
705
+ }
706
+
522
707
  function updateAllSkills(agent = 'claude', dryRun = false) {
523
708
  const installed = getInstalledSkills(agent);
524
709
 
@@ -910,6 +1095,14 @@ async function installFromGitHub(source, agent = 'claude', dryRun = false) {
910
1095
  }
911
1096
 
912
1097
  copyDir(skillPath, destPath);
1098
+
1099
+ // Write metadata for update tracking
1100
+ writeSkillMeta(destPath, {
1101
+ source: 'github',
1102
+ repo: `${owner}/${repo}`,
1103
+ skillPath: skillName
1104
+ });
1105
+
913
1106
  success(`\nInstalled: ${skillName} from ${owner}/${repo}`);
914
1107
  info(`Location: ${destPath}`);
915
1108
  } else if (isRootSkill) {
@@ -933,6 +1126,14 @@ async function installFromGitHub(source, agent = 'claude', dryRun = false) {
933
1126
  }
934
1127
 
935
1128
  copyDir(tempDir, destPath);
1129
+
1130
+ // Write metadata for update tracking
1131
+ writeSkillMeta(destPath, {
1132
+ source: 'github',
1133
+ repo: `${owner}/${repo}`,
1134
+ isRootSkill: true
1135
+ });
1136
+
936
1137
  success(`\nInstalled: ${skillName} from ${owner}/${repo}`);
937
1138
  info(`Location: ${destPath}`);
938
1139
  } else {
@@ -952,6 +1153,14 @@ async function installFromGitHub(source, agent = 'claude', dryRun = false) {
952
1153
  }
953
1154
 
954
1155
  copyDir(skillPath, destPath);
1156
+
1157
+ // Write metadata for update tracking
1158
+ writeSkillMeta(destPath, {
1159
+ source: 'github',
1160
+ repo: `${owner}/${repo}`,
1161
+ skillPath: entry.name
1162
+ });
1163
+
955
1164
  log(` ${colors.green}✓${colors.reset} ${entry.name}`);
956
1165
  installed++;
957
1166
  }
@@ -1010,6 +1219,13 @@ function installFromLocalPath(source, agent = 'claude', dryRun = false) {
1010
1219
  }
1011
1220
 
1012
1221
  copyDir(sourcePath, destPath);
1222
+
1223
+ // Write metadata for update tracking
1224
+ writeSkillMeta(destPath, {
1225
+ source: 'local',
1226
+ path: sourcePath
1227
+ });
1228
+
1013
1229
  success(`\nInstalled: ${skillName} from local path`);
1014
1230
  info(`Location: ${destPath}`);
1015
1231
  } else {
@@ -1029,6 +1245,13 @@ function installFromLocalPath(source, agent = 'claude', dryRun = false) {
1029
1245
  }
1030
1246
 
1031
1247
  copyDir(skillPath, destPath);
1248
+
1249
+ // Write metadata for update tracking
1250
+ writeSkillMeta(destPath, {
1251
+ source: 'local',
1252
+ path: skillPath
1253
+ });
1254
+
1032
1255
  log(` ${colors.green}✓${colors.reset} ${entry.name}`);
1033
1256
  installed++;
1034
1257
  }
@@ -1090,6 +1313,7 @@ ${colors.bold}Agents:${colors.reset} (install targets ALL by default)
1090
1313
  ${colors.cyan}amp${colors.reset} ~/.amp/skills/
1091
1314
  ${colors.cyan}vscode${colors.reset} .github/skills/ (project)
1092
1315
  ${colors.cyan}copilot${colors.reset} .github/skills/ (alias for vscode)
1316
+ ${colors.cyan}gemini${colors.reset} ~/.gemini/skills/
1093
1317
  ${colors.cyan}goose${colors.reset} ~/.config/goose/skills/
1094
1318
  ${colors.cyan}opencode${colors.reset} ~/.opencode/skill/
1095
1319
  ${colors.cyan}letta${colors.reset} ~/.letta/skills/
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-agent-skills",
3
- "version": "1.6.2",
4
- "description": "Install curated AI agent skills with one command. Works with Claude Code, Cursor, Amp, VS Code, and all Agent Skills compatible tools.",
3
+ "version": "1.8.0",
4
+ "description": "Install curated AI agent skills with one command. Works with Claude Code, Cursor, Codex, Gemini CLI, VS Code, Copilot, and 11+ agents.",
5
5
  "main": "cli.js",
6
6
  "bin": {
7
7
  "ai-agent-skills": "./cli.js",
@@ -24,6 +24,9 @@
24
24
  "skills",
25
25
  "claude",
26
26
  "cursor",
27
+ "codex",
28
+ "gemini",
29
+ "copilot",
27
30
  "amp",
28
31
  "vscode",
29
32
  "mcp"