ai-agent-skills 1.1.1 → 1.2.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 (4) hide show
  1. package/README.md +38 -29
  2. package/cli.js +313 -9
  3. package/package.json +1 -1
  4. package/skills.json +1 -1
package/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
  </h1>
6
6
 
7
7
  <p align="center">
8
- <strong>The universal skill repository for AI agents.</strong><br>
9
- One command. Works everywhere.
8
+ <strong>Homebrew for AI agent skills.</strong><br>
9
+ One command. Ten agents. Skills that follow you.
10
10
  </p>
11
11
 
12
12
  <p align="center">
@@ -29,13 +29,23 @@
29
29
  ## Quick Start
30
30
 
31
31
  ```bash
32
- # Install for Claude Code (default)
32
+ # Browse skills interactively
33
+ npx ai-agent-skills browse
34
+
35
+ # Install from our curated catalog
33
36
  npx ai-agent-skills install frontend-design
34
37
 
35
- # Install for other agents
38
+ # Install for specific agents
36
39
  npx ai-agent-skills install frontend-design --agent cursor
37
- npx ai-agent-skills install frontend-design --agent codex (ps this currently only works if you run codex and --enable skills flag)
40
+ npx ai-agent-skills install frontend-design --agent codex
38
41
  npx ai-agent-skills install frontend-design --agent amp
42
+
43
+ # Install from any GitHub repo
44
+ npx ai-agent-skills install anthropics/skills
45
+ npx ai-agent-skills install anthropics/skills/pdf # specific skill
46
+
47
+ # Install from local path
48
+ npx ai-agent-skills install ./my-custom-skill
39
49
  ```
40
50
 
41
51
  That's it. The skill installs to the right location for your agent automatically.
@@ -114,43 +124,32 @@ Works with **Claude Code**, **Cursor**, **Amp**, **VS Code**, **GitHub Copilot**
114
124
  ## Commands
115
125
 
116
126
  ```bash
127
+ # Interactive browser (TUI)
128
+ npx ai-agent-skills browse
129
+
117
130
  # List all available skills
118
131
  npx ai-agent-skills list
119
-
120
- # Filter by category
121
132
  npx ai-agent-skills list --category development
122
-
123
- # List installed skills for an agent
124
- npx ai-agent-skills list --installed
125
133
  npx ai-agent-skills list --installed --agent cursor
126
134
 
127
- # Install a skill (defaults to Claude Code)
128
- npx ai-agent-skills install <name>
129
-
130
- # Preview what will be installed (dry run)
131
- npx ai-agent-skills install <name> --dry-run
135
+ # Install from catalog, GitHub, or local path
136
+ npx ai-agent-skills install <name> # from catalog
137
+ npx ai-agent-skills install <owner/repo> # from GitHub
138
+ npx ai-agent-skills install <owner/repo/skill> # specific skill from GitHub
139
+ npx ai-agent-skills install ./path # from local path
140
+ npx ai-agent-skills install <name> --agent cursor # for specific agent
141
+ npx ai-agent-skills install <name> --dry-run # preview only
132
142
 
133
- # Install for a specific agent
134
- npx ai-agent-skills install <name> --agent <agent>
135
-
136
- # Uninstall a skill
143
+ # Manage installed skills
137
144
  npx ai-agent-skills uninstall <name>
138
- npx ai-agent-skills uninstall <name> --agent cursor
139
-
140
- # Update a skill to latest version
141
145
  npx ai-agent-skills update <name>
142
-
143
- # Update all installed skills
144
146
  npx ai-agent-skills update --all
145
147
 
146
- # Search skills by name, description, or tags
148
+ # Discovery
147
149
  npx ai-agent-skills search <query>
148
-
149
- # Get skill details
150
150
  npx ai-agent-skills info <name>
151
151
 
152
- # Configure default settings
153
- npx ai-agent-skills config
152
+ # Configuration
154
153
  npx ai-agent-skills config --default-agent cursor
155
154
  ```
156
155
 
@@ -216,6 +215,16 @@ We review all contributions for quality and spec compliance.
216
215
  - [Create Skills](https://skillcreator.ai/build) - Generate skills from plain English
217
216
  - [Anthropic Skills](https://github.com/anthropics/skills) - Official example skills
218
217
 
218
+ ## See Also
219
+
220
+ **[openskills](https://github.com/numman-ali/openskills)** - Universal skills loader that inspired parts of this project. openskills focuses on flexibility: install from any GitHub repo, sync to AGENTS.md, works with any agent via CLI calls. Great if you need maximum customization.
221
+
222
+ **We took a different approach**: Homebrew-style simplicity. No global install, no sync step, no AGENTS.md. Just `npx ai-agent-skills install pdf` and it lands in the right folder for your agent. Curated catalog, native paths, zero config.
223
+
224
+ Different tools for different needs.
225
+
226
+ ---
227
+
219
228
  ## Credits & Attribution
220
229
 
221
230
  This repository builds upon and curates skills from the open-source community:
package/cli.js CHANGED
@@ -659,21 +659,310 @@ function levenshteinDistance(a, b) {
659
659
  return matrix[b.length][a.length];
660
660
  }
661
661
 
662
+ // ============ INTERACTIVE BROWSE ============
663
+
664
+ async function browseSkills(agent = 'claude') {
665
+ const readline = require('readline');
666
+ const data = loadSkillsJson();
667
+ const skills = data.skills || [];
668
+
669
+ if (skills.length === 0) {
670
+ warn('No skills available');
671
+ return;
672
+ }
673
+
674
+ // Group by category
675
+ const categories = [...new Set(skills.map(s => s.category))].sort();
676
+ let currentCategory = 0;
677
+ let currentSkill = 0;
678
+ let mode = 'category'; // 'category' or 'skill'
679
+
680
+ const getSkillsInCategory = (cat) => skills.filter(s => s.category === cat);
681
+
682
+ const render = () => {
683
+ console.clear();
684
+ log(`\n${colors.bold}🔧 AI Agent Skills Browser${colors.reset}`);
685
+ log(`${colors.dim}Use ↑↓ to navigate, Enter to select, q to quit${colors.reset}\n`);
686
+
687
+ if (mode === 'category') {
688
+ log(`${colors.bold}Categories:${colors.reset}\n`);
689
+ categories.forEach((cat, i) => {
690
+ const count = getSkillsInCategory(cat).length;
691
+ const prefix = i === currentCategory ? `${colors.cyan}▶ ` : ' ';
692
+ const suffix = i === currentCategory ? colors.reset : '';
693
+ log(`${prefix}${cat.toUpperCase()} (${count})${suffix}`);
694
+ });
695
+ log(`\n${colors.dim}Press Enter to browse skills in this category${colors.reset}`);
696
+ } else {
697
+ const cat = categories[currentCategory];
698
+ const catSkills = getSkillsInCategory(cat);
699
+ log(`${colors.bold}${cat.toUpperCase()}${colors.reset} ${colors.dim}(← Backspace to go back)${colors.reset}\n`);
700
+
701
+ catSkills.forEach((skill, i) => {
702
+ const prefix = i === currentSkill ? `${colors.green}▶ ` : ' ';
703
+ const suffix = i === currentSkill ? colors.reset : '';
704
+ const featured = skill.featured ? ` ${colors.yellow}★${colors.reset}` : '';
705
+ log(`${prefix}${skill.name}${featured}${suffix}`);
706
+ if (i === currentSkill) {
707
+ log(` ${colors.dim}${skill.description.slice(0, 60)}...${colors.reset}`);
708
+ }
709
+ });
710
+ log(`\n${colors.dim}Press Enter to install, i for info${colors.reset}`);
711
+ }
712
+ };
713
+
714
+ return new Promise((resolve) => {
715
+ readline.emitKeypressEvents(process.stdin);
716
+ if (process.stdin.isTTY) {
717
+ process.stdin.setRawMode(true);
718
+ }
719
+
720
+ render();
721
+
722
+ process.stdin.on('keypress', (str, key) => {
723
+ if (key.name === 'q' || (key.ctrl && key.name === 'c')) {
724
+ console.clear();
725
+ log('Goodbye!');
726
+ process.stdin.setRawMode(false);
727
+ process.exit(0);
728
+ }
729
+
730
+ if (mode === 'category') {
731
+ if (key.name === 'up') {
732
+ currentCategory = Math.max(0, currentCategory - 1);
733
+ } else if (key.name === 'down') {
734
+ currentCategory = Math.min(categories.length - 1, currentCategory + 1);
735
+ } else if (key.name === 'return') {
736
+ mode = 'skill';
737
+ currentSkill = 0;
738
+ }
739
+ } else {
740
+ const catSkills = getSkillsInCategory(categories[currentCategory]);
741
+ if (key.name === 'up') {
742
+ currentSkill = Math.max(0, currentSkill - 1);
743
+ } else if (key.name === 'down') {
744
+ currentSkill = Math.min(catSkills.length - 1, currentSkill + 1);
745
+ } else if (key.name === 'backspace' || key.name === 'escape') {
746
+ mode = 'category';
747
+ } else if (key.name === 'return') {
748
+ const skill = catSkills[currentSkill];
749
+ console.clear();
750
+ process.stdin.setRawMode(false);
751
+ installSkill(skill.name, agent, false);
752
+ resolve();
753
+ return;
754
+ } else if (str === 'i') {
755
+ const skill = catSkills[currentSkill];
756
+ console.clear();
757
+ process.stdin.setRawMode(false);
758
+ showInfo(skill.name);
759
+ resolve();
760
+ return;
761
+ }
762
+ }
763
+ render();
764
+ });
765
+ });
766
+ }
767
+
768
+ // ============ EXTERNAL INSTALL (GitHub/Local) ============
769
+
770
+ function isGitHubUrl(source) {
771
+ return source.includes('/') && !source.startsWith('.') && !source.startsWith('/') && !source.startsWith('~');
772
+ }
773
+
774
+ function isLocalPath(source) {
775
+ return source.startsWith('.') || source.startsWith('/') || source.startsWith('~');
776
+ }
777
+
778
+ function expandPath(p) {
779
+ if (p.startsWith('~')) {
780
+ return path.join(os.homedir(), p.slice(1));
781
+ }
782
+ return path.resolve(p);
783
+ }
784
+
785
+ async function installFromGitHub(source, agent = 'claude', dryRun = false) {
786
+ const { execSync } = require('child_process');
787
+
788
+ // Parse owner/repo format
789
+ const parts = source.split('/');
790
+ if (parts.length < 2) {
791
+ error('Invalid GitHub source. Use format: owner/repo or owner/repo/skill-name');
792
+ return false;
793
+ }
794
+
795
+ const owner = parts[0];
796
+ const repo = parts[1];
797
+ const skillName = parts[2]; // Optional specific skill
798
+
799
+ const repoUrl = `https://github.com/${owner}/${repo}.git`;
800
+ const tempDir = path.join(os.tmpdir(), `ai-skills-${Date.now()}`);
801
+
802
+ if (dryRun) {
803
+ log(`\n${colors.bold}Dry Run${colors.reset} (no changes made)\n`);
804
+ info(`Would clone: ${repoUrl}`);
805
+ info(`Would install ${skillName ? `skill: ${skillName}` : 'all skills from repo'}`);
806
+ info(`Agent: ${agent}`);
807
+ return true;
808
+ }
809
+
810
+ try {
811
+ info(`Cloning ${owner}/${repo}...`);
812
+ execSync(`git clone --depth 1 ${repoUrl} ${tempDir}`, { stdio: 'pipe' });
813
+
814
+ // Find skills in the cloned repo
815
+ const skillsDir = fs.existsSync(path.join(tempDir, 'skills'))
816
+ ? path.join(tempDir, 'skills')
817
+ : tempDir;
818
+
819
+ if (skillName) {
820
+ // Install specific skill
821
+ const skillPath = path.join(skillsDir, skillName);
822
+ if (!fs.existsSync(skillPath) || !fs.existsSync(path.join(skillPath, 'SKILL.md'))) {
823
+ error(`Skill "${skillName}" not found in ${owner}/${repo}`);
824
+ fs.rmSync(tempDir, { recursive: true });
825
+ return false;
826
+ }
827
+
828
+ const destDir = AGENT_PATHS[agent] || AGENT_PATHS.claude;
829
+ const destPath = path.join(destDir, skillName);
830
+
831
+ if (!fs.existsSync(destDir)) {
832
+ fs.mkdirSync(destDir, { recursive: true });
833
+ }
834
+
835
+ copyDir(skillPath, destPath);
836
+ success(`\nInstalled: ${skillName} from ${owner}/${repo}`);
837
+ info(`Location: ${destPath}`);
838
+ } else {
839
+ // Install all skills from repo
840
+ const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
841
+ let installed = 0;
842
+
843
+ for (const entry of entries) {
844
+ if (entry.isDirectory()) {
845
+ const skillPath = path.join(skillsDir, entry.name);
846
+ if (fs.existsSync(path.join(skillPath, 'SKILL.md'))) {
847
+ const destDir = AGENT_PATHS[agent] || AGENT_PATHS.claude;
848
+ const destPath = path.join(destDir, entry.name);
849
+
850
+ if (!fs.existsSync(destDir)) {
851
+ fs.mkdirSync(destDir, { recursive: true });
852
+ }
853
+
854
+ copyDir(skillPath, destPath);
855
+ log(` ${colors.green}✓${colors.reset} ${entry.name}`);
856
+ installed++;
857
+ }
858
+ }
859
+ }
860
+
861
+ if (installed > 0) {
862
+ success(`\nInstalled ${installed} skill(s) from ${owner}/${repo}`);
863
+ } else {
864
+ warn('No skills found in repository');
865
+ }
866
+ }
867
+
868
+ // Cleanup
869
+ fs.rmSync(tempDir, { recursive: true });
870
+ return true;
871
+ } catch (e) {
872
+ error(`Failed to install from GitHub: ${e.message}`);
873
+ try { fs.rmSync(tempDir, { recursive: true }); } catch {}
874
+ return false;
875
+ }
876
+ }
877
+
878
+ function installFromLocalPath(source, agent = 'claude', dryRun = false) {
879
+ const sourcePath = expandPath(source);
880
+
881
+ if (!fs.existsSync(sourcePath)) {
882
+ error(`Path not found: ${sourcePath}`);
883
+ return false;
884
+ }
885
+
886
+ const stat = fs.statSync(sourcePath);
887
+ if (!stat.isDirectory()) {
888
+ error('Source must be a directory');
889
+ return false;
890
+ }
891
+
892
+ // Check if it's a single skill or a directory of skills
893
+ const hasSkillMd = fs.existsSync(path.join(sourcePath, 'SKILL.md'));
894
+
895
+ if (dryRun) {
896
+ log(`\n${colors.bold}Dry Run${colors.reset} (no changes made)\n`);
897
+ info(`Would install from: ${sourcePath}`);
898
+ info(`Agent: ${agent}`);
899
+ return true;
900
+ }
901
+
902
+ if (hasSkillMd) {
903
+ // Single skill
904
+ const skillName = path.basename(sourcePath);
905
+ const destDir = AGENT_PATHS[agent] || AGENT_PATHS.claude;
906
+ const destPath = path.join(destDir, skillName);
907
+
908
+ if (!fs.existsSync(destDir)) {
909
+ fs.mkdirSync(destDir, { recursive: true });
910
+ }
911
+
912
+ copyDir(sourcePath, destPath);
913
+ success(`\nInstalled: ${skillName} from local path`);
914
+ info(`Location: ${destPath}`);
915
+ } else {
916
+ // Directory of skills
917
+ const entries = fs.readdirSync(sourcePath, { withFileTypes: true });
918
+ let installed = 0;
919
+
920
+ for (const entry of entries) {
921
+ if (entry.isDirectory()) {
922
+ const skillPath = path.join(sourcePath, entry.name);
923
+ if (fs.existsSync(path.join(skillPath, 'SKILL.md'))) {
924
+ const destDir = AGENT_PATHS[agent] || AGENT_PATHS.claude;
925
+ const destPath = path.join(destDir, entry.name);
926
+
927
+ if (!fs.existsSync(destDir)) {
928
+ fs.mkdirSync(destDir, { recursive: true });
929
+ }
930
+
931
+ copyDir(skillPath, destPath);
932
+ log(` ${colors.green}✓${colors.reset} ${entry.name}`);
933
+ installed++;
934
+ }
935
+ }
936
+ }
937
+
938
+ if (installed > 0) {
939
+ success(`\nInstalled ${installed} skill(s) from local path`);
940
+ } else {
941
+ warn('No skills found in directory');
942
+ }
943
+ }
944
+
945
+ return true;
946
+ }
947
+
662
948
  // ============ INFO AND HELP ============
663
949
 
664
950
  function showHelp() {
665
951
  log(`
666
952
  ${colors.bold}AI Agent Skills${colors.reset}
667
- The universal skill repository for AI agents.
953
+ Homebrew for AI agent skills. One command, every agent.
668
954
 
669
955
  ${colors.bold}Usage:${colors.reset}
670
956
  npx ai-agent-skills <command> [options]
671
957
 
672
958
  ${colors.bold}Commands:${colors.reset}
959
+ ${colors.green}browse${colors.reset} Interactive skill browser (TUI)
673
960
  ${colors.green}list${colors.reset} List all available skills
674
961
  ${colors.green}list --installed${colors.reset} List installed skills for an agent
675
962
  ${colors.green}list --category <cat>${colors.reset} Filter by category
676
- ${colors.green}install <name>${colors.reset} Install a skill
963
+ ${colors.green}install <name>${colors.reset} Install a skill from catalog
964
+ ${colors.green}install <owner/repo>${colors.reset} Install from GitHub repository
965
+ ${colors.green}install ./path${colors.reset} Install from local path
677
966
  ${colors.green}install <name> --dry-run${colors.reset} Preview installation without changes
678
967
  ${colors.green}uninstall <name>${colors.reset} Remove an installed skill
679
968
  ${colors.green}update <name>${colors.reset} Update an installed skill to latest
@@ -706,11 +995,14 @@ ${colors.bold}Categories:${colors.reset}
706
995
  development, document, creative, business, productivity
707
996
 
708
997
  ${colors.bold}Examples:${colors.reset}
709
- npx ai-agent-skills install frontend-design
710
- npx ai-agent-skills install pdf --dry-run
711
- npx ai-agent-skills install frontend-design --cursor
998
+ npx ai-agent-skills browse # Interactive browser
999
+ npx ai-agent-skills install frontend-design # Install from catalog
1000
+ npx ai-agent-skills install anthropics/skills # Install from GitHub
1001
+ npx ai-agent-skills install anthropics/skills/pdf # Install specific skill from GitHub
1002
+ npx ai-agent-skills install ./my-skill # Install from local path
1003
+ npx ai-agent-skills install pdf --agent cursor # Install for Cursor
1004
+ npx ai-agent-skills install pdf --dry-run # Preview install
712
1005
  npx ai-agent-skills list --category development
713
- npx ai-agent-skills list --installed --agent cursor
714
1006
  npx ai-agent-skills search testing
715
1007
  npx ai-agent-skills update --all
716
1008
 
@@ -826,6 +1118,11 @@ if (command === 'config') {
826
1118
  }
827
1119
 
828
1120
  switch (command || 'help') {
1121
+ case 'browse':
1122
+ case 'b':
1123
+ browseSkills(agent);
1124
+ break;
1125
+
829
1126
  case 'list':
830
1127
  case 'ls':
831
1128
  if (installed) {
@@ -839,11 +1136,18 @@ switch (command || 'help') {
839
1136
  case 'i':
840
1137
  case 'add':
841
1138
  if (!param) {
842
- error('Please specify a skill name.');
843
- log('Usage: npx ai-agent-skills install <skill-name> [--agent <agent>] [--dry-run]');
1139
+ error('Please specify a skill name, GitHub repo, or local path.');
1140
+ log('Usage: npx ai-agent-skills install <skill-name|owner/repo|./path> [--agent <agent>] [--dry-run]');
844
1141
  process.exit(1);
845
1142
  }
846
- installSkill(param, agent, dryRun);
1143
+ // Smart detection: GitHub URL, local path, or catalog skill
1144
+ if (isLocalPath(param)) {
1145
+ installFromLocalPath(param, agent, dryRun);
1146
+ } else if (isGitHubUrl(param)) {
1147
+ installFromGitHub(param, agent, dryRun);
1148
+ } else {
1149
+ installSkill(param, agent, dryRun);
1150
+ }
847
1151
  break;
848
1152
 
849
1153
  case 'uninstall':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-agent-skills",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Install curated AI agent skills with one command. Works with Claude Code, Cursor, Amp, VS Code, and all Agent Skills compatible tools.",
5
5
  "main": "cli.js",
6
6
  "bin": {
package/skills.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.1",
2
+ "version": "1.2.0",
3
3
  "updated": "2025-12-20T00:00:00Z",
4
4
  "total": 39,
5
5
  "skills": [