openskill-ai 1.0.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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +230 -0
  3. package/dist/chunk-63EFN7CX.js +450 -0
  4. package/dist/cli.d.ts +1 -0
  5. package/dist/cli.js +286 -0
  6. package/dist/index.d.ts +158 -0
  7. package/dist/index.js +391 -0
  8. package/package.json +70 -0
  9. package/skills/backend-best-practices/SKILL.md +116 -0
  10. package/skills/backend-best-practices/rules/api-consistent-responses.md +127 -0
  11. package/skills/backend-best-practices/rules/api-pagination.md +83 -0
  12. package/skills/backend-best-practices/rules/api-rate-limiting.md +94 -0
  13. package/skills/backend-best-practices/rules/api-restful-conventions.md +67 -0
  14. package/skills/backend-best-practices/rules/api-versioning.md +69 -0
  15. package/skills/backend-best-practices/rules/arch-dependency-injection.md +55 -0
  16. package/skills/backend-best-practices/rules/arch-dto-pattern.md +64 -0
  17. package/skills/backend-best-practices/rules/arch-repository-pattern.md +74 -0
  18. package/skills/backend-best-practices/rules/arch-separation-concerns.md +80 -0
  19. package/skills/backend-best-practices/rules/arch-service-layer.md +48 -0
  20. package/skills/backend-best-practices/rules/code-documentation.md +77 -0
  21. package/skills/backend-best-practices/rules/code-dry-principle.md +49 -0
  22. package/skills/backend-best-practices/rules/code-naming-conventions.md +47 -0
  23. package/skills/backend-best-practices/rules/code-single-responsibility.md +78 -0
  24. package/skills/backend-best-practices/rules/code-type-safety.md +64 -0
  25. package/skills/backend-best-practices/rules/db-connection-pooling.md +136 -0
  26. package/skills/backend-best-practices/rules/db-indexing.md +88 -0
  27. package/skills/backend-best-practices/rules/db-migrations.md +189 -0
  28. package/skills/backend-best-practices/rules/db-n-plus-one.md +118 -0
  29. package/skills/backend-best-practices/rules/db-transactions.md +178 -0
  30. package/skills/backend-best-practices/rules/deploy-environment-variables.md +63 -0
  31. package/skills/backend-best-practices/rules/deploy-graceful-shutdown.md +77 -0
  32. package/skills/backend-best-practices/rules/deploy-health-checks.md +70 -0
  33. package/skills/backend-best-practices/rules/deploy-monitoring.md +87 -0
  34. package/skills/backend-best-practices/rules/deploy-zero-downtime.md +85 -0
  35. package/skills/backend-best-practices/rules/error-global-handler.md +94 -0
  36. package/skills/backend-best-practices/rules/error-graceful-degradation.md +70 -0
  37. package/skills/backend-best-practices/rules/error-http-status-codes.md +77 -0
  38. package/skills/backend-best-practices/rules/error-logging.md +71 -0
  39. package/skills/backend-best-practices/rules/error-meaningful-messages.md +61 -0
  40. package/skills/backend-best-practices/rules/perf-async-operations.md +55 -0
  41. package/skills/backend-best-practices/rules/perf-caching.md +81 -0
  42. package/skills/backend-best-practices/rules/perf-compression.md +33 -0
  43. package/skills/backend-best-practices/rules/perf-database-queries.md +54 -0
  44. package/skills/backend-best-practices/rules/perf-lazy-loading.md +47 -0
  45. package/skills/backend-best-practices/rules/security-https-only.md +116 -0
  46. package/skills/backend-best-practices/rules/security-input-validation.md +96 -0
  47. package/skills/backend-best-practices/rules/security-jwt-best-practices.md +140 -0
  48. package/skills/backend-best-practices/rules/security-sql-injection.md +77 -0
  49. package/skills/clean-code-skills/references/solid.md +304 -0
  50. package/skills/clean-code-skills/skills.md +263 -0
  51. package/skills/flutter-skills/AGENTS.md +1265 -0
  52. package/skills/flutter-skills/SKILL.md +116 -0
  53. package/skills/flutter-skills/rules/advanced-custom-painter.md +117 -0
  54. package/skills/flutter-skills/rules/advanced-layer-link.md +103 -0
  55. package/skills/flutter-skills/rules/advanced-render-object.md +105 -0
  56. package/skills/flutter-skills/rules/advanced-sliver-persistent.md +111 -0
  57. package/skills/flutter-skills/rules/animation-animated-builder.md +118 -0
  58. package/skills/flutter-skills/rules/animation-cached-images.md +112 -0
  59. package/skills/flutter-skills/rules/animation-physics.md +105 -0
  60. package/skills/flutter-skills/rules/animation-reduce-overdraw.md +111 -0
  61. package/skills/flutter-skills/rules/animation-tween-sequence.md +112 -0
  62. package/skills/flutter-skills/rules/async-cancel-subscriptions.md +112 -0
  63. package/skills/flutter-skills/rules/async-compute.md +78 -0
  64. package/skills/flutter-skills/rules/async-debounce-throttle.md +104 -0
  65. package/skills/flutter-skills/rules/async-future-builder.md +106 -0
  66. package/skills/flutter-skills/rules/async-parallel.md +75 -0
  67. package/skills/flutter-skills/rules/build-avoid-rebuild.md +80 -0
  68. package/skills/flutter-skills/rules/build-const-constructors.md +56 -0
  69. package/skills/flutter-skills/rules/build-itemextent.md +73 -0
  70. package/skills/flutter-skills/rules/build-keys.md +74 -0
  71. package/skills/flutter-skills/rules/build-split-widgets.md +99 -0
  72. package/skills/flutter-skills/rules/dart-avoid-dynamic.md +86 -0
  73. package/skills/flutter-skills/rules/dart-cascade-notation.md +89 -0
  74. package/skills/flutter-skills/rules/dart-collection-if.md +92 -0
  75. package/skills/flutter-skills/rules/dart-final-const.md +70 -0
  76. package/skills/flutter-skills/rules/dart-spread-operator.md +90 -0
  77. package/skills/flutter-skills/rules/dart-string-buffer.md +77 -0
  78. package/skills/flutter-skills/rules/layout-avoid-opacity.md +110 -0
  79. package/skills/flutter-skills/rules/layout-clip-behavior.md +94 -0
  80. package/skills/flutter-skills/rules/layout-intrinsic-dimensions.md +89 -0
  81. package/skills/flutter-skills/rules/layout-repaint-boundary.md +117 -0
  82. package/skills/flutter-skills/rules/layout-slivers.md +94 -0
  83. package/skills/flutter-skills/rules/memory-dispose.md +90 -0
  84. package/skills/flutter-skills/rules/memory-image-cache.md +86 -0
  85. package/skills/flutter-skills/rules/memory-isolate.md +91 -0
  86. package/skills/flutter-skills/rules/memory-precache.md +114 -0
  87. package/skills/flutter-skills/rules/memory-weak-references.md +79 -0
  88. package/skills/flutter-skills/rules/state-late-final.md +90 -0
  89. package/skills/flutter-skills/rules/state-lift-state-up.md +84 -0
  90. package/skills/flutter-skills/rules/state-minimize-rebuilds.md +95 -0
  91. package/skills/flutter-skills/rules/state-selector.md +87 -0
  92. package/skills/flutter-skills/rules/state-valuenotifier.md +85 -0
  93. package/skills/frontend-design/SKILL.md +42 -0
  94. package/skills/skill-writer-skills/AGENTS.md +637 -0
  95. package/skills/skill-writer-skills/README.md +49 -0
  96. package/skills/skill-writer-skills/SKILL.md +97 -0
  97. package/skills/skill-writer-skills/metadata.json +17 -0
  98. package/skills/skill-writer-skills/references/common-pitfalls.md +291 -0
  99. package/skills/skill-writer-skills/references/core-principles.md +147 -0
  100. package/skills/skill-writer-skills/references/creation-process.md +250 -0
  101. package/skills/skill-writer-skills/references/design-patterns.md +300 -0
  102. package/skills/skill-writer-skills/references/skill-anatomy.md +174 -0
  103. package/skills/skill-writer-skills/references/validation-checklist.md +194 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Agent Skills Community
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # agent-skills
2
+
3
+ > Install AI agent skills from any Git repository
4
+
5
+ A powerful CLI tool to install and manage AI coding agent skills from GitHub, GitLab, or any Git repository. Supports 15+ popular AI agents with auto-detection and interactive prompts.
6
+
7
+ ## Features
8
+
9
+ ✨ **Remote Repository Support** - Install skills from any Git repository
10
+ 🤖 **15+ AI Agents** - Antigravity, Cursor, Claude Code, OpenCode, GitHub Copilot, and more
11
+ 💬 **Interactive CLI** - Beautiful prompts with multi-select workflows
12
+ 🔍 **Auto-Detection** - Automatically finds installed agents on your system
13
+ 🌐 **Global/Project Installs** - Choose your installation scope
14
+ 🔒 **Security** - Path sanitization and traversal protection
15
+
16
+ ## Quick Start
17
+
18
+ ```bash
19
+ # Install skills from a repository
20
+ npx agent-skills vercel-labs/agent-skills
21
+
22
+ # List available skills first
23
+ npx agent-skills vercel-labs/agent-skills --list
24
+
25
+ # Install specific skill to Antigravity
26
+ npx agent-skills vercel-labs/agent-skills \
27
+ --skill frontend-design \
28
+ --agent antigravity
29
+ ```
30
+
31
+ ## Installation
32
+
33
+ ### As a CLI Tool (Recommended)
34
+
35
+ Use with `npx` without installing:
36
+ ```bash
37
+ npx agent-skills <source>
38
+ ```
39
+
40
+ Or install globally:
41
+ ```bash
42
+ npm install -g agent-skills
43
+ agent-skills <source>
44
+ ```
45
+
46
+ ### As a Library
47
+
48
+ ```bash
49
+ npm install agent-skills
50
+ ```
51
+
52
+ ```javascript
53
+ import { installSkillForAgent, discoverSkills } from 'agent-skills';
54
+ ```
55
+
56
+ ## Usage
57
+
58
+ ### Source Formats
59
+
60
+ The CLI accepts multiple source formats:
61
+
62
+ ```bash
63
+ # GitHub shorthand
64
+ agent-skills vercel-labs/agent-skills
65
+
66
+ # GitHub URL
67
+ agent-skills https://github.com/owner/repo
68
+
69
+ # GitHub tree path (specific directory)
70
+ agent-skills https://github.com/owner/repo/tree/main/skills/frontend
71
+
72
+ # GitLab
73
+ agent-skills https://gitlab.com/owner/repo
74
+
75
+ # Direct Git URL
76
+ agent-skills git@github.com:owner/repo.git
77
+ ```
78
+
79
+ ### CLI Options
80
+
81
+ | Option | Description |
82
+ |--------|-------------|
83
+ | `-g, --global` | Install globally (user-level) instead of project-level |
84
+ | `-a, --agent <agents...>` | Target specific agents |
85
+ | `-s, --skill <skills...>` | Select specific skills to install |
86
+ | `-l, --list` | List available skills without installing |
87
+ | `-y, --yes` | Skip all confirmation prompts |
88
+ | `-h, --help` | Show help |
89
+
90
+ ### Examples
91
+
92
+ **Interactive Installation** (recommended for first-time users):
93
+ ```bash
94
+ agent-skills vercel-labs/agent-skills
95
+ ```
96
+
97
+ **List Skills Before Installing:**
98
+ ```bash
99
+ agent-skills vercel-labs/agent-skills --list
100
+ ```
101
+
102
+ **Install Specific Skill:**
103
+ ```bash
104
+ agent-skills vercel-labs/agent-skills --skill frontend-design
105
+ ```
106
+
107
+ **Install to Multiple Agents:**
108
+ ```bash
109
+ agent-skills vercel-labs/agent-skills \
110
+ --skill frontend-design \
111
+ --agent antigravity \
112
+ --agent cursor \
113
+ --agent claude-code
114
+ ```
115
+
116
+ **Global Installation (Non-Interactive):**
117
+ ```bash
118
+ agent-skills vercel-labs/agent-skills \
119
+ --skill frontend-design \
120
+ --global \
121
+ --yes
122
+ ```
123
+
124
+ **List All Supported Agents:**
125
+ ```bash
126
+ agent-skills list-agents
127
+ ```
128
+
129
+ ## Supported AI Agents
130
+
131
+ The tool supports 15 AI coding agents with auto-detection:
132
+
133
+ - **Antigravity** - `.agent/skills` (project) or `~/.gemini/antigravity/skills` (global)
134
+ - **Cursor** - `.cursor/skills` or `~/.cursor/skills`
135
+ - **Claude Code** - `.claude/skills` or `~/.claude/skills`
136
+ - **OpenCode** - `.opencode/skill` or `~/.config/opencode/skill`
137
+ - **GitHub Copilot** - `.github/skills` or `~/.copilot/skills`
138
+ - **Codex** - `.codex/skills` or `~/.codex/skills`
139
+ - **Windsurf** - `.windsurf/skills` or `~/.codeium/windsurf/skills`
140
+ - **Roo Code** - `.roo/skills` or `~/.roo/skills`
141
+ - **Goose** - `.goose/skills` or `~/.config/goose/skills`
142
+ - **Gemini CLI** - `.gemini/skills` or `~/.gemini/skills`
143
+ - **Amp** - `.agents/skills` or `~/.config/agents/skills`
144
+ - **Kilo Code** - `.kilocode/skills` or `~/.kilocode/skills`
145
+ - **Clawdbot** - `skills/` or `~/.clawdbot/skills`
146
+ - **Droid** - `.factory/skills` or `~/.factory/skills`
147
+
148
+ ## Creating Skills
149
+
150
+ Skills are defined using `SKILL.md` files with YAML frontmatter:
151
+
152
+ ```markdown
153
+ ---
154
+ name: my-skill
155
+ description: What this skill does and when to use it
156
+ ---
157
+
158
+ # My Skill
159
+
160
+ Instructions for the AI agent to follow when this skill is activated.
161
+
162
+ ## When to Use
163
+
164
+ Describe scenarios where this skill should be applied.
165
+
166
+ ## Guidelines
167
+
168
+ 1. First guideline
169
+ 2. Second guideline
170
+ ```
171
+
172
+ ### Skill Discovery
173
+
174
+ The CLI searches for skills in these locations:
175
+ - Root directory (if it contains `SKILL.md`)
176
+ - `skills/`, `skills/.curated/`, `skills/.experimental/`
177
+ - `.agent/skills/`, `.claude/skills/`, `.cursor/skills/`
178
+ - All other agent-specific directories
179
+ - Recursive search as fallback (max depth 5)
180
+
181
+ ## Security
182
+
183
+ The tool implements several security measures:
184
+
185
+ - **Path Sanitization** - Removes dangerous characters from skill names
186
+ - **Traversal Protection** - Validates all paths to prevent directory traversal
187
+ - **Safe Cloning** - Uses temporary directories for Git operations
188
+ - **File Exclusions** - Skips `README.md`, `metadata.json`, and files starting with `_`
189
+
190
+ ## Programmatic API
191
+
192
+ ```javascript
193
+ import {
194
+ installSkillForAgent,
195
+ discoverSkills,
196
+ detectInstalledAgents,
197
+ parseSource,
198
+ cloneRepo
199
+ } from 'agent-skills';
200
+
201
+ // Clone and discover skills
202
+ const parsed = parseSource('vercel-labs/agent-skills');
203
+ const tempDir = await cloneRepo(parsed.url);
204
+ const skills = await discoverSkills(tempDir);
205
+
206
+ // Detect installed agents
207
+ const agents = await detectInstalledAgents();
208
+
209
+ // Install skill
210
+ await installSkillForAgent(skills[0], 'antigravity', { global: false });
211
+ ```
212
+
213
+ ## Requirements
214
+
215
+ - Node.js >= 18.0.0
216
+ - Git installed on your system
217
+
218
+ ## Contributing
219
+
220
+ Contributions are welcome! Please feel free to submit a Pull Request.
221
+
222
+ ## License
223
+
224
+ MIT © Agent Skills Community
225
+
226
+ ## Links
227
+
228
+ - [GitHub Repository](https://github.com/yourusername/agent-skills)
229
+ - [Report Issues](https://github.com/yourusername/agent-skills/issues)
230
+ - [npm Package](https://www.npmjs.com/package/agent-skills)
@@ -0,0 +1,450 @@
1
+ // src/utils/git.ts
2
+ import simpleGit from "simple-git";
3
+ import { join, normalize, resolve, sep } from "path";
4
+ import { mkdtemp, rm } from "fs/promises";
5
+ import { tmpdir } from "os";
6
+ function parseSource(input) {
7
+ const githubTreeMatch = input.match(
8
+ /github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)/
9
+ );
10
+ if (githubTreeMatch) {
11
+ const [, owner, repo, , subpath] = githubTreeMatch;
12
+ return {
13
+ type: "github",
14
+ url: `https://github.com/${owner}/${repo}.git`,
15
+ subpath
16
+ };
17
+ }
18
+ const githubRepoMatch = input.match(/github\.com\/([^/]+)\/([^/]+)/);
19
+ if (githubRepoMatch) {
20
+ const [, owner, repo] = githubRepoMatch;
21
+ const cleanRepo = repo.replace(/\.git$/, "");
22
+ return {
23
+ type: "github",
24
+ url: `https://github.com/${owner}/${cleanRepo}.git`
25
+ };
26
+ }
27
+ const gitlabTreeMatch = input.match(
28
+ /gitlab\.com\/([^/]+)\/([^/]+)\/-\/tree\/([^/]+)\/(.+)/
29
+ );
30
+ if (gitlabTreeMatch) {
31
+ const [, owner, repo, , subpath] = gitlabTreeMatch;
32
+ return {
33
+ type: "gitlab",
34
+ url: `https://gitlab.com/${owner}/${repo}.git`,
35
+ subpath
36
+ };
37
+ }
38
+ const gitlabRepoMatch = input.match(/gitlab\.com\/([^/]+)\/([^/]+)/);
39
+ if (gitlabRepoMatch) {
40
+ const [, owner, repo] = gitlabRepoMatch;
41
+ const cleanRepo = repo.replace(/\.git$/, "");
42
+ return {
43
+ type: "gitlab",
44
+ url: `https://gitlab.com/${owner}/${cleanRepo}.git`
45
+ };
46
+ }
47
+ const shorthandMatch = input.match(/^([^/]+)\/([^/]+)(?:\/(.+))?$/);
48
+ if (shorthandMatch && !input.includes(":")) {
49
+ const [, owner, repo, subpath] = shorthandMatch;
50
+ return {
51
+ type: "github",
52
+ url: `https://github.com/${owner}/${repo}.git`,
53
+ subpath
54
+ };
55
+ }
56
+ return {
57
+ type: "git",
58
+ url: input
59
+ };
60
+ }
61
+ async function cloneRepo(url) {
62
+ const tempDir = await mkdtemp(join(tmpdir(), "agent-skills-"));
63
+ const git = simpleGit();
64
+ await git.clone(url, tempDir, ["--depth", "1"]);
65
+ return tempDir;
66
+ }
67
+ async function cleanupTempDir(dir) {
68
+ const normalizedDir = normalize(resolve(dir));
69
+ const normalizedTmpDir = normalize(resolve(tmpdir()));
70
+ if (!normalizedDir.startsWith(normalizedTmpDir + sep) && normalizedDir !== normalizedTmpDir) {
71
+ throw new Error("Attempted to clean up directory outside of temp directory");
72
+ }
73
+ await rm(dir, { recursive: true, force: true });
74
+ }
75
+
76
+ // src/utils/skills.ts
77
+ import { readdir, readFile, stat } from "fs/promises";
78
+ import { join as join2, basename, dirname } from "path";
79
+ import matter from "gray-matter";
80
+ var SKIP_DIRS = ["node_modules", ".git", "dist", "build", "__pycache__"];
81
+ async function hasSkillMd(dir) {
82
+ try {
83
+ const skillPath = join2(dir, "SKILL.md");
84
+ const stats = await stat(skillPath);
85
+ return stats.isFile();
86
+ } catch {
87
+ return false;
88
+ }
89
+ }
90
+ async function parseSkillMd(skillMdPath) {
91
+ try {
92
+ const content = await readFile(skillMdPath, "utf-8");
93
+ const { data } = matter(content);
94
+ if (!data.name || !data.description) {
95
+ return null;
96
+ }
97
+ return {
98
+ name: data.name,
99
+ description: data.description,
100
+ path: dirname(skillMdPath),
101
+ metadata: data.metadata
102
+ };
103
+ } catch {
104
+ return null;
105
+ }
106
+ }
107
+ async function findSkillDirs(dir, depth = 0, maxDepth = 5) {
108
+ const skillDirs = [];
109
+ if (depth > maxDepth) return skillDirs;
110
+ try {
111
+ if (await hasSkillMd(dir)) {
112
+ skillDirs.push(dir);
113
+ }
114
+ const entries = await readdir(dir, { withFileTypes: true });
115
+ for (const entry of entries) {
116
+ if (entry.isDirectory() && !SKIP_DIRS.includes(entry.name)) {
117
+ const subDirs = await findSkillDirs(join2(dir, entry.name), depth + 1, maxDepth);
118
+ skillDirs.push(...subDirs);
119
+ }
120
+ }
121
+ } catch {
122
+ }
123
+ return skillDirs;
124
+ }
125
+ async function discoverSkills(basePath, subpath) {
126
+ const skills = [];
127
+ const seenNames = /* @__PURE__ */ new Set();
128
+ const searchPath = subpath ? join2(basePath, subpath) : basePath;
129
+ if (await hasSkillMd(searchPath)) {
130
+ const skill = await parseSkillMd(join2(searchPath, "SKILL.md"));
131
+ if (skill) {
132
+ skills.push(skill);
133
+ return skills;
134
+ }
135
+ }
136
+ const prioritySearchDirs = [
137
+ searchPath,
138
+ join2(searchPath, "skills"),
139
+ join2(searchPath, "skills/.curated"),
140
+ join2(searchPath, "skills/.experimental"),
141
+ join2(searchPath, "skills/.system"),
142
+ join2(searchPath, ".codex/skills"),
143
+ join2(searchPath, ".claude/skills"),
144
+ join2(searchPath, ".opencode/skill"),
145
+ join2(searchPath, ".cursor/skills"),
146
+ join2(searchPath, ".agents/skills"),
147
+ join2(searchPath, ".kilocode/skills"),
148
+ join2(searchPath, ".roo/skills"),
149
+ join2(searchPath, ".goose/skills"),
150
+ join2(searchPath, ".agent/skills"),
151
+ join2(searchPath, ".github/skills")
152
+ ];
153
+ for (const dir of prioritySearchDirs) {
154
+ try {
155
+ const entries = await readdir(dir, { withFileTypes: true });
156
+ for (const entry of entries) {
157
+ if (entry.isDirectory()) {
158
+ const skillDir = join2(dir, entry.name);
159
+ if (await hasSkillMd(skillDir)) {
160
+ const skill = await parseSkillMd(join2(skillDir, "SKILL.md"));
161
+ if (skill && !seenNames.has(skill.name)) {
162
+ skills.push(skill);
163
+ seenNames.add(skill.name);
164
+ }
165
+ }
166
+ }
167
+ }
168
+ } catch {
169
+ }
170
+ }
171
+ if (skills.length === 0) {
172
+ const allSkillDirs = await findSkillDirs(searchPath);
173
+ for (const skillDir of allSkillDirs) {
174
+ const skill = await parseSkillMd(join2(skillDir, "SKILL.md"));
175
+ if (skill && !seenNames.has(skill.name)) {
176
+ skills.push(skill);
177
+ seenNames.add(skill.name);
178
+ }
179
+ }
180
+ }
181
+ return skills;
182
+ }
183
+ function getSkillDisplayName(skill) {
184
+ return skill.name || basename(skill.path);
185
+ }
186
+
187
+ // src/utils/agents.ts
188
+ import { homedir } from "os";
189
+ import { join as join3 } from "path";
190
+ import { existsSync } from "fs";
191
+ var home = homedir();
192
+ var agents = {
193
+ opencode: {
194
+ name: "opencode",
195
+ displayName: "OpenCode",
196
+ skillsDir: ".opencode/skill",
197
+ globalSkillsDir: join3(home, ".config/opencode/skill"),
198
+ detectInstalled: async () => {
199
+ return existsSync(join3(home, ".config/opencode")) || existsSync(join3(home, ".claude/skills"));
200
+ }
201
+ },
202
+ "claude-code": {
203
+ name: "claude-code",
204
+ displayName: "Claude Code",
205
+ skillsDir: ".claude/skills",
206
+ globalSkillsDir: join3(home, ".claude/skills"),
207
+ detectInstalled: async () => {
208
+ return existsSync(join3(home, ".claude"));
209
+ }
210
+ },
211
+ codex: {
212
+ name: "codex",
213
+ displayName: "Codex",
214
+ skillsDir: ".codex/skills",
215
+ globalSkillsDir: join3(home, ".codex/skills"),
216
+ detectInstalled: async () => {
217
+ return existsSync(join3(home, ".codex"));
218
+ }
219
+ },
220
+ cursor: {
221
+ name: "cursor",
222
+ displayName: "Cursor",
223
+ skillsDir: ".cursor/skills",
224
+ globalSkillsDir: join3(home, ".cursor/skills"),
225
+ detectInstalled: async () => {
226
+ return existsSync(join3(home, ".cursor"));
227
+ }
228
+ },
229
+ amp: {
230
+ name: "amp",
231
+ displayName: "Amp",
232
+ skillsDir: ".agents/skills",
233
+ globalSkillsDir: join3(home, ".config/agents/skills"),
234
+ detectInstalled: async () => {
235
+ return existsSync(join3(home, ".config/amp"));
236
+ }
237
+ },
238
+ kilo: {
239
+ name: "kilo",
240
+ displayName: "Kilo Code",
241
+ skillsDir: ".kilocode/skills",
242
+ globalSkillsDir: join3(home, ".kilocode/skills"),
243
+ detectInstalled: async () => {
244
+ return existsSync(join3(home, ".kilocode"));
245
+ }
246
+ },
247
+ roo: {
248
+ name: "roo",
249
+ displayName: "Roo Code",
250
+ skillsDir: ".roo/skills",
251
+ globalSkillsDir: join3(home, ".roo/skills"),
252
+ detectInstalled: async () => {
253
+ return existsSync(join3(home, ".roo"));
254
+ }
255
+ },
256
+ goose: {
257
+ name: "goose",
258
+ displayName: "Goose",
259
+ skillsDir: ".goose/skills",
260
+ globalSkillsDir: join3(home, ".config/goose/skills"),
261
+ detectInstalled: async () => {
262
+ return existsSync(join3(home, ".config/goose"));
263
+ }
264
+ },
265
+ "gemini-cli": {
266
+ name: "gemini-cli",
267
+ displayName: "Gemini CLI",
268
+ skillsDir: ".gemini/skills",
269
+ globalSkillsDir: join3(home, ".gemini/skills"),
270
+ detectInstalled: async () => {
271
+ return existsSync(join3(home, ".gemini"));
272
+ }
273
+ },
274
+ antigravity: {
275
+ name: "antigravity",
276
+ displayName: "Antigravity",
277
+ skillsDir: ".agent/skills",
278
+ globalSkillsDir: join3(home, ".gemini/antigravity/skills"),
279
+ detectInstalled: async () => {
280
+ return existsSync(join3(process.cwd(), ".agent")) || existsSync(join3(home, ".gemini/antigravity"));
281
+ }
282
+ },
283
+ "github-copilot": {
284
+ name: "github-copilot",
285
+ displayName: "GitHub Copilot",
286
+ skillsDir: ".github/skills",
287
+ globalSkillsDir: join3(home, ".copilot/skills"),
288
+ detectInstalled: async () => {
289
+ return existsSync(join3(process.cwd(), ".github")) || existsSync(join3(home, ".copilot"));
290
+ }
291
+ },
292
+ clawdbot: {
293
+ name: "clawdbot",
294
+ displayName: "Clawdbot",
295
+ skillsDir: "skills",
296
+ globalSkillsDir: join3(home, ".clawdbot/skills"),
297
+ detectInstalled: async () => {
298
+ return existsSync(join3(home, ".clawdbot"));
299
+ }
300
+ },
301
+ droid: {
302
+ name: "droid",
303
+ displayName: "Droid",
304
+ skillsDir: ".factory/skills",
305
+ globalSkillsDir: join3(home, ".factory/skills"),
306
+ detectInstalled: async () => {
307
+ return existsSync(join3(home, ".factory/skills"));
308
+ }
309
+ },
310
+ gemini: {
311
+ name: "gemini",
312
+ displayName: "Gemini CLI",
313
+ skillsDir: ".gemini/skills",
314
+ globalSkillsDir: join3(home, ".gemini/skills"),
315
+ detectInstalled: async () => {
316
+ return existsSync(join3(home, ".gemini"));
317
+ }
318
+ },
319
+ windsurf: {
320
+ name: "windsurf",
321
+ displayName: "Windsurf",
322
+ skillsDir: ".windsurf/skills",
323
+ globalSkillsDir: join3(home, ".codeium/windsurf/skills"),
324
+ detectInstalled: async () => {
325
+ return existsSync(join3(home, ".codeium/windsurf"));
326
+ }
327
+ }
328
+ };
329
+ async function detectInstalledAgents() {
330
+ const installed = [];
331
+ for (const [type, config] of Object.entries(agents)) {
332
+ if (await config.detectInstalled()) {
333
+ installed.push(type);
334
+ }
335
+ }
336
+ return installed;
337
+ }
338
+ function getAgentConfig(type) {
339
+ return agents[type];
340
+ }
341
+
342
+ // src/utils/installer.ts
343
+ import { mkdir, cp, access, readdir as readdir2 } from "fs/promises";
344
+ import { join as join4, basename as basename2, normalize as normalize2, resolve as resolve2, sep as sep2 } from "path";
345
+ function sanitizeName(name) {
346
+ let sanitized = name.replace(/[\/\\:\0]/g, "");
347
+ sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, "");
348
+ sanitized = sanitized.replace(/^\.+/, "");
349
+ if (!sanitized || sanitized.length === 0) {
350
+ sanitized = "unnamed-skill";
351
+ }
352
+ if (sanitized.length > 255) {
353
+ sanitized = sanitized.substring(0, 255);
354
+ }
355
+ return sanitized;
356
+ }
357
+ function isPathSafe(basePath, targetPath) {
358
+ const normalizedBase = normalize2(resolve2(basePath));
359
+ const normalizedTarget = normalize2(resolve2(targetPath));
360
+ return normalizedTarget.startsWith(normalizedBase + sep2) || normalizedTarget === normalizedBase;
361
+ }
362
+ async function installSkillForAgent(skill, agentType, options = {}) {
363
+ const agent = agents[agentType];
364
+ const rawSkillName = skill.name || basename2(skill.path);
365
+ const skillName = sanitizeName(rawSkillName);
366
+ const targetBase = options.global ? agent.globalSkillsDir : join4(options.cwd || process.cwd(), agent.skillsDir);
367
+ const targetDir = join4(targetBase, skillName);
368
+ if (!isPathSafe(targetBase, targetDir)) {
369
+ return {
370
+ success: false,
371
+ path: targetDir,
372
+ error: "Invalid skill name: potential path traversal detected"
373
+ };
374
+ }
375
+ try {
376
+ await mkdir(targetDir, { recursive: true });
377
+ await copyDirectory(skill.path, targetDir);
378
+ return { success: true, path: targetDir };
379
+ } catch (error) {
380
+ return {
381
+ success: false,
382
+ path: targetDir,
383
+ error: error instanceof Error ? error.message : "Unknown error"
384
+ };
385
+ }
386
+ }
387
+ var EXCLUDE_FILES = /* @__PURE__ */ new Set([
388
+ "README.md",
389
+ "metadata.json"
390
+ ]);
391
+ var isExcluded = (name) => {
392
+ if (EXCLUDE_FILES.has(name)) return true;
393
+ if (name.startsWith("_")) return true;
394
+ return false;
395
+ };
396
+ async function copyDirectory(src, dest) {
397
+ await mkdir(dest, { recursive: true });
398
+ const entries = await readdir2(src, { withFileTypes: true });
399
+ for (const entry of entries) {
400
+ if (isExcluded(entry.name)) {
401
+ continue;
402
+ }
403
+ const srcPath = join4(src, entry.name);
404
+ const destPath = join4(dest, entry.name);
405
+ if (entry.isDirectory()) {
406
+ await copyDirectory(srcPath, destPath);
407
+ } else {
408
+ await cp(srcPath, destPath);
409
+ }
410
+ }
411
+ }
412
+ async function isSkillInstalled(skillName, agentType, options = {}) {
413
+ const agent = agents[agentType];
414
+ const sanitized = sanitizeName(skillName);
415
+ const targetBase = options.global ? agent.globalSkillsDir : join4(options.cwd || process.cwd(), agent.skillsDir);
416
+ const skillDir = join4(targetBase, sanitized);
417
+ if (!isPathSafe(targetBase, skillDir)) {
418
+ return false;
419
+ }
420
+ try {
421
+ await access(skillDir);
422
+ return true;
423
+ } catch {
424
+ return false;
425
+ }
426
+ }
427
+ function getInstallPath(skillName, agentType, options = {}) {
428
+ const agent = agents[agentType];
429
+ const sanitized = sanitizeName(skillName);
430
+ const targetBase = options.global ? agent.globalSkillsDir : join4(options.cwd || process.cwd(), agent.skillsDir);
431
+ const installPath = join4(targetBase, sanitized);
432
+ if (!isPathSafe(targetBase, installPath)) {
433
+ throw new Error("Invalid skill name: potential path traversal detected");
434
+ }
435
+ return installPath;
436
+ }
437
+
438
+ export {
439
+ parseSource,
440
+ cloneRepo,
441
+ cleanupTempDir,
442
+ discoverSkills,
443
+ getSkillDisplayName,
444
+ agents,
445
+ detectInstalledAgents,
446
+ getAgentConfig,
447
+ installSkillForAgent,
448
+ isSkillInstalled,
449
+ getInstallPath
450
+ };
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node