skill-gen 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/SKILL.md +229 -0
- package/bin/skillify.js +325 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# skillify
|
|
2
|
+
|
|
3
|
+
Generate SKILL.md files for npm packages following [Anthropic's Agent Skills specification](https://agentskills.io/specification).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g skillify
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or use directly:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx skill-gen .
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Current directory
|
|
21
|
+
npx skill-gen .
|
|
22
|
+
|
|
23
|
+
# Specific path
|
|
24
|
+
npx skill-gen ~/projects/my-package
|
|
25
|
+
|
|
26
|
+
# Print to stdout
|
|
27
|
+
npx skill-gen . --stdout
|
|
28
|
+
|
|
29
|
+
# Dry run (preview only)
|
|
30
|
+
npx skill-gen . --dry-run
|
|
31
|
+
|
|
32
|
+
# Custom output path
|
|
33
|
+
npx skill-gen . -o ./docs/SKILL.md
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## What it Does
|
|
37
|
+
|
|
38
|
+
1. Reads `package.json` for name, description, keywords, bin, exports
|
|
39
|
+
2. Analyzes CLI entry point for flags/commands
|
|
40
|
+
3. Extracts exported functions from main module
|
|
41
|
+
4. Generates SKILL.md with:
|
|
42
|
+
- Proper YAML frontmatter (name, description)
|
|
43
|
+
- "When to Use" triggers
|
|
44
|
+
- Quick Start examples
|
|
45
|
+
- CLI Reference (if applicable)
|
|
46
|
+
- API Reference (if applicable)
|
|
47
|
+
|
|
48
|
+
## Output Format
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
---
|
|
52
|
+
name: my-package
|
|
53
|
+
description: Does X and Y. Use when working with Z.
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
# my-package
|
|
57
|
+
|
|
58
|
+
## When to Use
|
|
59
|
+
...
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Why SKILL.md?
|
|
66
|
+
|
|
67
|
+
SKILL.md is the [Agent Skills](https://agentskills.io) standard for AI agent documentation:
|
|
68
|
+
|
|
69
|
+
- **Discoverable**: Agents find skills by name + description
|
|
70
|
+
- **Progressive disclosure**: Metadata loads first, details on-demand
|
|
71
|
+
- **Portable**: Works with Claude Code, Cursor, Copilot, Codex
|
|
72
|
+
|
|
73
|
+
## Best Practices Applied
|
|
74
|
+
|
|
75
|
+
Based on [Anthropic's guidelines](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices):
|
|
76
|
+
|
|
77
|
+
- Third person descriptions ("Builds X" not "I build X")
|
|
78
|
+
- Includes "when to use" triggers
|
|
79
|
+
- Concrete examples over abstract descriptions
|
|
80
|
+
- Under 500 lines for optimal performance
|
|
81
|
+
|
|
82
|
+
## Related
|
|
83
|
+
|
|
84
|
+
- [Agent Skills Specification](https://agentskills.io/specification)
|
|
85
|
+
- [Anthropic Skills Repository](https://github.com/anthropics/skills)
|
|
86
|
+
- [fund-agent](https://npmjs.com/package/fund-agent)
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skillify
|
|
3
|
+
description: Generates SKILL.md files for npm packages following Anthropic's Agent Skills specification. Use when adding agent documentation to an npm package, making a package AI-agent friendly, or creating skills from existing code.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skillify
|
|
7
|
+
|
|
8
|
+
Generate a SKILL.md file for an npm package, making it discoverable and usable by AI agents.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
- Adding agent documentation to an npm package
|
|
13
|
+
- Making a library AI-agent friendly
|
|
14
|
+
- Creating a skill from existing CLI tool
|
|
15
|
+
- Preparing a package for the Agent Skills ecosystem
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
/skillify . # Current directory
|
|
21
|
+
/skillify ~/path/to/package # Local package
|
|
22
|
+
/skillify btctx # npm package name
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Process
|
|
26
|
+
|
|
27
|
+
### Step 1: Gather Package Information
|
|
28
|
+
|
|
29
|
+
Read these files (in order of importance):
|
|
30
|
+
|
|
31
|
+
1. **package.json** (required)
|
|
32
|
+
- `name` → skill name (kebab-case)
|
|
33
|
+
- `description` → base for skill description
|
|
34
|
+
- `bin` → CLI commands available
|
|
35
|
+
- `main`/`exports` → API entry points
|
|
36
|
+
- `keywords` → trigger words
|
|
37
|
+
|
|
38
|
+
2. **README.md** (if exists)
|
|
39
|
+
- Usage examples
|
|
40
|
+
- API documentation
|
|
41
|
+
- Installation instructions
|
|
42
|
+
|
|
43
|
+
3. **CLI entry point** (if `bin` exists)
|
|
44
|
+
- Parse for `--help` output
|
|
45
|
+
- Extract flags and commands
|
|
46
|
+
|
|
47
|
+
4. **Main module** (if `main`/`exports` exists)
|
|
48
|
+
- Exported functions
|
|
49
|
+
- JSDoc comments
|
|
50
|
+
- Type definitions
|
|
51
|
+
|
|
52
|
+
### Step 2: Analyze for Agent Usage
|
|
53
|
+
|
|
54
|
+
Determine:
|
|
55
|
+
- **What it does** - core functionality in one sentence
|
|
56
|
+
- **When to use** - specific triggers/contexts
|
|
57
|
+
- **How to use** - primary usage pattern (CLI or API)
|
|
58
|
+
- **Examples** - concrete input/output pairs
|
|
59
|
+
|
|
60
|
+
### Step 3: Generate SKILL.md
|
|
61
|
+
|
|
62
|
+
Follow this template:
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
---
|
|
66
|
+
name: <package-name-kebab-case>
|
|
67
|
+
description: <What it does>. <When to use - specific triggers>.
|
|
68
|
+
---
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Description rules:**
|
|
72
|
+
- Third person only ("Builds X" not "I build X")
|
|
73
|
+
- Under 1024 characters
|
|
74
|
+
- Include both WHAT and WHEN
|
|
75
|
+
- Use specific keywords for discovery
|
|
76
|
+
|
|
77
|
+
**Body structure:**
|
|
78
|
+
|
|
79
|
+
```markdown
|
|
80
|
+
# <Package Name>
|
|
81
|
+
|
|
82
|
+
## When to Use
|
|
83
|
+
|
|
84
|
+
Invoke when you need to:
|
|
85
|
+
- <specific trigger 1>
|
|
86
|
+
- <specific trigger 2>
|
|
87
|
+
- <specific trigger 3>
|
|
88
|
+
|
|
89
|
+
## Quick Start
|
|
90
|
+
|
|
91
|
+
<primary usage pattern - CLI or code>
|
|
92
|
+
|
|
93
|
+
## Examples
|
|
94
|
+
|
|
95
|
+
**Example 1: <use case>**
|
|
96
|
+
|
|
97
|
+
Input:
|
|
98
|
+
<concrete input>
|
|
99
|
+
|
|
100
|
+
Output:
|
|
101
|
+
<concrete output>
|
|
102
|
+
|
|
103
|
+
## CLI Reference (if applicable)
|
|
104
|
+
|
|
105
|
+
<flags and commands>
|
|
106
|
+
|
|
107
|
+
## API Reference (if applicable)
|
|
108
|
+
|
|
109
|
+
<key exported functions>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Step 4: Write the File
|
|
113
|
+
|
|
114
|
+
Save to: `<package-root>/SKILL.md`
|
|
115
|
+
|
|
116
|
+
## Quality Checklist
|
|
117
|
+
|
|
118
|
+
Before finalizing, verify:
|
|
119
|
+
|
|
120
|
+
- [ ] Description is third person
|
|
121
|
+
- [ ] Description includes WHAT and WHEN
|
|
122
|
+
- [ ] Description under 1024 characters
|
|
123
|
+
- [ ] Name is kebab-case, lowercase
|
|
124
|
+
- [ ] Examples are concrete (not abstract)
|
|
125
|
+
- [ ] Body under 500 lines
|
|
126
|
+
- [ ] No time-sensitive information
|
|
127
|
+
- [ ] Consistent terminology
|
|
128
|
+
|
|
129
|
+
## Description Formula
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
<Verb>s <object> [details]. Use when <trigger1>, <trigger2>, or <trigger3>.
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Good examples:**
|
|
136
|
+
```yaml
|
|
137
|
+
description: Builds Bitcoin Taproot transactions from inputs and outputs. Use when creating P2TR transactions, spending UTXOs, or working with Taproot addresses.
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
description: Broadcasts signed Bitcoin transactions to the network. Use when sending transactions to mempool, publishing to testnet4, or checking broadcast status.
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Bad examples:**
|
|
145
|
+
```yaml
|
|
146
|
+
description: Helps with Bitcoin stuff. # Too vague
|
|
147
|
+
description: I can build transactions. # Wrong POV
|
|
148
|
+
description: A library for transactions. # No "when to use"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Naming Convention
|
|
152
|
+
|
|
153
|
+
Convert package name to kebab-case:
|
|
154
|
+
|
|
155
|
+
| package.json name | SKILL.md name |
|
|
156
|
+
|-------------------|---------------|
|
|
157
|
+
| `btctx` | `btctx` |
|
|
158
|
+
| `sendTx` | `send-tx` |
|
|
159
|
+
| `BitcoinBuilder` | `bitcoin-builder` |
|
|
160
|
+
| `@scope/pkg` | `pkg` (drop scope) |
|
|
161
|
+
|
|
162
|
+
## Example Output
|
|
163
|
+
|
|
164
|
+
For a package like `btctx`:
|
|
165
|
+
|
|
166
|
+
```yaml
|
|
167
|
+
---
|
|
168
|
+
name: btctx
|
|
169
|
+
description: Builds Bitcoin Taproot (P2TR) transactions from UTXOs. Use when creating Bitcoin transactions, spending Taproot outputs, or building raw transaction hex.
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
# btctx
|
|
173
|
+
|
|
174
|
+
## When to Use
|
|
175
|
+
|
|
176
|
+
Invoke when you need to:
|
|
177
|
+
- Build a Bitcoin transaction from UTXOs
|
|
178
|
+
- Create Taproot (P2TR) outputs
|
|
179
|
+
- Generate signed transaction hex for broadcasting
|
|
180
|
+
|
|
181
|
+
## Quick Start
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
import { buildTx } from 'btctx';
|
|
185
|
+
|
|
186
|
+
const { hex, txid } = await buildTx({
|
|
187
|
+
privateKey: '...',
|
|
188
|
+
publicKey: '...',
|
|
189
|
+
txid: '<input-txid>',
|
|
190
|
+
vout: 0,
|
|
191
|
+
inputAmount: 100000,
|
|
192
|
+
outputs: [{ pubkey: '<recipient>', amount: 99000 }]
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Examples
|
|
197
|
+
|
|
198
|
+
**Example: Simple transfer**
|
|
199
|
+
|
|
200
|
+
Input:
|
|
201
|
+
- 100,000 sats from UTXO
|
|
202
|
+
- Send to one recipient
|
|
203
|
+
|
|
204
|
+
Output:
|
|
205
|
+
- Signed transaction hex
|
|
206
|
+
- Transaction ID (txid)
|
|
207
|
+
|
|
208
|
+
## API Reference
|
|
209
|
+
|
|
210
|
+
### `buildTx(options)`
|
|
211
|
+
|
|
212
|
+
Builds and signs a Taproot transaction.
|
|
213
|
+
|
|
214
|
+
Options:
|
|
215
|
+
- `privateKey` - 64-char hex signing key
|
|
216
|
+
- `publicKey` - 64-char hex x-only pubkey
|
|
217
|
+
- `txid` - Input transaction ID
|
|
218
|
+
- `vout` - Output index to spend
|
|
219
|
+
- `inputAmount` - Satoshis in input
|
|
220
|
+
- `outputs` - Array of `{ pubkey, amount }`
|
|
221
|
+
|
|
222
|
+
Returns: `{ hex, txid }`
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## References
|
|
226
|
+
|
|
227
|
+
- [Agent Skills Specification](https://agentskills.io/specification)
|
|
228
|
+
- [Anthropic Best Practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices)
|
|
229
|
+
- [GitHub: anthropics/skills](https://github.com/anthropics/skills)
|
package/bin/skillify.js
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* skillify - Generate SKILL.md for npm packages
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx skill-gen . # Current directory
|
|
8
|
+
* npx skill-gen ~/path/to/pkg # Local package
|
|
9
|
+
* npx skill-gen btctx # npm package (fetches info)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { fileURLToPath } from 'url';
|
|
15
|
+
|
|
16
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
|
|
18
|
+
// CLI args
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
|
|
21
|
+
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
22
|
+
console.log(`
|
|
23
|
+
skillify v0.0.1 - Generate SKILL.md for npm packages
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
npx skill-gen <path> Generate SKILL.md for local package
|
|
27
|
+
npx skill-gen . Current directory
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
-h, --help Show this help
|
|
31
|
+
-v, --version Show version
|
|
32
|
+
-o, --output Output path (default: ./SKILL.md)
|
|
33
|
+
--stdout Print to stdout instead of file
|
|
34
|
+
--dry-run Show what would be generated
|
|
35
|
+
|
|
36
|
+
Examples:
|
|
37
|
+
npx skill-gen .
|
|
38
|
+
npx skill-gen ~/projects/my-package
|
|
39
|
+
npx skill-gen . --stdout
|
|
40
|
+
`);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
45
|
+
console.log('0.0.1');
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Parse flags
|
|
50
|
+
const stdout = args.includes('--stdout');
|
|
51
|
+
const dryRun = args.includes('--dry-run');
|
|
52
|
+
const outputIdx = args.indexOf('-o') !== -1 ? args.indexOf('-o') : args.indexOf('--output');
|
|
53
|
+
const outputPath = outputIdx !== -1 ? args[outputIdx + 1] : null;
|
|
54
|
+
|
|
55
|
+
// Get target path
|
|
56
|
+
const targetArg = args.find(a => !a.startsWith('-') && a !== outputPath);
|
|
57
|
+
const targetPath = path.resolve(targetArg || '.');
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Convert string to kebab-case
|
|
61
|
+
*/
|
|
62
|
+
function toKebabCase(str) {
|
|
63
|
+
return str
|
|
64
|
+
.replace(/^@[^/]+\//, '') // Remove scope
|
|
65
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
66
|
+
.replace(/[_\s]+/g, '-')
|
|
67
|
+
.toLowerCase();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Extract CLI info from a file
|
|
72
|
+
*/
|
|
73
|
+
function extractCliInfo(filePath) {
|
|
74
|
+
try {
|
|
75
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
76
|
+
const flags = [];
|
|
77
|
+
|
|
78
|
+
// Look for common flag patterns
|
|
79
|
+
const flagPatterns = [
|
|
80
|
+
/--(\w[-\w]*)/g,
|
|
81
|
+
/-([a-zA-Z]),\s*--(\w[-\w]*)/g,
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
for (const pattern of flagPatterns) {
|
|
85
|
+
let match;
|
|
86
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
87
|
+
flags.push(match[1] || match[2]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return [...new Set(flags)].filter(f => !['help', 'version'].includes(f));
|
|
92
|
+
} catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Extract exports from main module
|
|
99
|
+
*/
|
|
100
|
+
function extractExports(filePath) {
|
|
101
|
+
try {
|
|
102
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
103
|
+
const exports = [];
|
|
104
|
+
|
|
105
|
+
// Named exports
|
|
106
|
+
const namedExports = content.matchAll(/export\s+(?:async\s+)?(?:function|const|let|var|class)\s+(\w+)/g);
|
|
107
|
+
for (const match of namedExports) {
|
|
108
|
+
exports.push(match[1]);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Export { ... }
|
|
112
|
+
const bracketExports = content.matchAll(/export\s*\{([^}]+)\}/g);
|
|
113
|
+
for (const match of bracketExports) {
|
|
114
|
+
const names = match[1].split(',').map(s => s.trim().split(/\s+as\s+/)[0].trim());
|
|
115
|
+
exports.push(...names);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return [...new Set(exports)];
|
|
119
|
+
} catch {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Generate description from package info
|
|
126
|
+
*/
|
|
127
|
+
function generateDescription(pkg, hasCliCommands, exportedFunctions) {
|
|
128
|
+
let desc = pkg.description || `Provides ${pkg.name} functionality`;
|
|
129
|
+
|
|
130
|
+
// Ensure it ends with a period
|
|
131
|
+
if (!desc.endsWith('.')) desc += '.';
|
|
132
|
+
|
|
133
|
+
// Add "Use when" triggers based on keywords
|
|
134
|
+
const triggers = [];
|
|
135
|
+
|
|
136
|
+
if (pkg.keywords?.length) {
|
|
137
|
+
const keywordTriggers = pkg.keywords.slice(0, 3).map(k => `working with ${k}`);
|
|
138
|
+
triggers.push(...keywordTriggers);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (hasCliCommands) {
|
|
142
|
+
triggers.push(`using the ${pkg.name} CLI`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (triggers.length) {
|
|
146
|
+
desc += ` Use when ${triggers.slice(0, 2).join(' or ')}.`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Truncate to 1024 chars
|
|
150
|
+
if (desc.length > 1024) {
|
|
151
|
+
desc = desc.slice(0, 1020) + '...';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return desc;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Generate SKILL.md content
|
|
159
|
+
*/
|
|
160
|
+
function generateSkillMd(pkg, options = {}) {
|
|
161
|
+
const { cliFlags = [], exports = [], readme = '' } = options;
|
|
162
|
+
|
|
163
|
+
const name = toKebabCase(pkg.name);
|
|
164
|
+
const description = generateDescription(pkg, cliFlags.length > 0, exports);
|
|
165
|
+
|
|
166
|
+
let content = `---
|
|
167
|
+
name: ${name}
|
|
168
|
+
description: ${description}
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
# ${pkg.name}
|
|
172
|
+
|
|
173
|
+
`;
|
|
174
|
+
|
|
175
|
+
// When to Use
|
|
176
|
+
content += `## When to Use
|
|
177
|
+
|
|
178
|
+
Invoke when you need to:
|
|
179
|
+
`;
|
|
180
|
+
|
|
181
|
+
if (pkg.keywords?.length) {
|
|
182
|
+
pkg.keywords.slice(0, 4).forEach(kw => {
|
|
183
|
+
content += `- Work with ${kw}\n`;
|
|
184
|
+
});
|
|
185
|
+
} else {
|
|
186
|
+
content += `- Use ${pkg.name} functionality\n`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
content += '\n';
|
|
190
|
+
|
|
191
|
+
// Quick Start
|
|
192
|
+
content += `## Quick Start
|
|
193
|
+
|
|
194
|
+
`;
|
|
195
|
+
|
|
196
|
+
if (pkg.bin) {
|
|
197
|
+
const binName = typeof pkg.bin === 'string' ? pkg.name : Object.keys(pkg.bin)[0];
|
|
198
|
+
content += `\`\`\`bash
|
|
199
|
+
npx ${binName} --help
|
|
200
|
+
\`\`\`
|
|
201
|
+
|
|
202
|
+
`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (exports.length) {
|
|
206
|
+
content += `\`\`\`javascript
|
|
207
|
+
import { ${exports.slice(0, 3).join(', ')} } from '${pkg.name}';
|
|
208
|
+
\`\`\`
|
|
209
|
+
|
|
210
|
+
`;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// CLI Reference
|
|
214
|
+
if (pkg.bin && cliFlags.length) {
|
|
215
|
+
content += `## CLI Reference
|
|
216
|
+
|
|
217
|
+
\`\`\`
|
|
218
|
+
npx ${Object.keys(pkg.bin)[0]} [options]
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
**Options:**
|
|
222
|
+
`;
|
|
223
|
+
cliFlags.slice(0, 10).forEach(flag => {
|
|
224
|
+
content += `- \`--${flag}\`\n`;
|
|
225
|
+
});
|
|
226
|
+
content += '\n';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// API Reference
|
|
230
|
+
if (exports.length) {
|
|
231
|
+
content += `## API Reference
|
|
232
|
+
|
|
233
|
+
**Exported functions:**
|
|
234
|
+
`;
|
|
235
|
+
exports.slice(0, 10).forEach(exp => {
|
|
236
|
+
content += `- \`${exp}\`\n`;
|
|
237
|
+
});
|
|
238
|
+
content += '\n';
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// References
|
|
242
|
+
content += `## References
|
|
243
|
+
|
|
244
|
+
`;
|
|
245
|
+
if (pkg.homepage) {
|
|
246
|
+
content += `- [Documentation](${pkg.homepage})\n`;
|
|
247
|
+
}
|
|
248
|
+
if (pkg.repository?.url) {
|
|
249
|
+
const repoUrl = pkg.repository.url.replace(/^git\+/, '').replace(/\.git$/, '');
|
|
250
|
+
content += `- [GitHub](${repoUrl})\n`;
|
|
251
|
+
}
|
|
252
|
+
content += `- [npm](https://www.npmjs.com/package/${pkg.name})\n`;
|
|
253
|
+
|
|
254
|
+
return content;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Main
|
|
258
|
+
async function main() {
|
|
259
|
+
console.log('skillify v0.0.1\n');
|
|
260
|
+
|
|
261
|
+
// Check if path exists
|
|
262
|
+
if (!fs.existsSync(targetPath)) {
|
|
263
|
+
console.error(`Error: Path not found: ${targetPath}`);
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Read package.json
|
|
268
|
+
const pkgPath = path.join(targetPath, 'package.json');
|
|
269
|
+
if (!fs.existsSync(pkgPath)) {
|
|
270
|
+
console.error(`Error: No package.json found at ${targetPath}`);
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
275
|
+
console.log(`Package: ${pkg.name}@${pkg.version}`);
|
|
276
|
+
|
|
277
|
+
// Extract CLI info
|
|
278
|
+
let cliFlags = [];
|
|
279
|
+
if (pkg.bin) {
|
|
280
|
+
const binPath = typeof pkg.bin === 'string'
|
|
281
|
+
? path.join(targetPath, pkg.bin)
|
|
282
|
+
: path.join(targetPath, Object.values(pkg.bin)[0]);
|
|
283
|
+
|
|
284
|
+
if (fs.existsSync(binPath)) {
|
|
285
|
+
cliFlags = extractCliInfo(binPath);
|
|
286
|
+
console.log(`CLI flags found: ${cliFlags.length}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Extract exports
|
|
291
|
+
let exports = [];
|
|
292
|
+
const mainPath = path.join(targetPath, pkg.main || 'index.js');
|
|
293
|
+
if (fs.existsSync(mainPath)) {
|
|
294
|
+
exports = extractExports(mainPath);
|
|
295
|
+
console.log(`Exports found: ${exports.length}`);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Read README
|
|
299
|
+
let readme = '';
|
|
300
|
+
const readmePath = path.join(targetPath, 'README.md');
|
|
301
|
+
if (fs.existsSync(readmePath)) {
|
|
302
|
+
readme = fs.readFileSync(readmePath, 'utf8');
|
|
303
|
+
console.log(`README.md: ${readme.length} chars`);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Generate SKILL.md
|
|
307
|
+
const skillMd = generateSkillMd(pkg, { cliFlags, exports, readme });
|
|
308
|
+
|
|
309
|
+
if (dryRun || stdout) {
|
|
310
|
+
console.log('\n--- Generated SKILL.md ---\n');
|
|
311
|
+
console.log(skillMd);
|
|
312
|
+
if (dryRun) {
|
|
313
|
+
console.log('--- dry-run: not written ---');
|
|
314
|
+
}
|
|
315
|
+
} else {
|
|
316
|
+
const outPath = outputPath || path.join(targetPath, 'SKILL.md');
|
|
317
|
+
fs.writeFileSync(outPath, skillMd);
|
|
318
|
+
console.log(`\nWritten: ${outPath}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
main().catch(err => {
|
|
323
|
+
console.error(`Error: ${err.message}`);
|
|
324
|
+
process.exit(1);
|
|
325
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "skill-gen",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Generate SKILL.md files for npm packages following Anthropic's Agent Skills specification",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"skill-gen": "./bin/skillify.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"agent",
|
|
12
|
+
"skills",
|
|
13
|
+
"anthropic",
|
|
14
|
+
"claude",
|
|
15
|
+
"ai",
|
|
16
|
+
"documentation",
|
|
17
|
+
"npm"
|
|
18
|
+
],
|
|
19
|
+
"author": "Melvin Carvalho",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/melvincarvalho/skillify"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
}
|
|
28
|
+
}
|