@vibe-agent-toolkit/agent-skills 0.1.4
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 +593 -0
- package/dist/builder.d.ts +41 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +526 -0
- package/dist/builder.js.map +1 -0
- package/dist/import.d.ts +33 -0
- package/dist/import.d.ts.map +1 -0
- package/dist/import.js +124 -0
- package/dist/import.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/frontmatter-parser.d.ts +27 -0
- package/dist/parsers/frontmatter-parser.d.ts.map +1 -0
- package/dist/parsers/frontmatter-parser.js +60 -0
- package/dist/parsers/frontmatter-parser.js.map +1 -0
- package/dist/schemas/claude-skill-frontmatter.d.ts +75 -0
- package/dist/schemas/claude-skill-frontmatter.d.ts.map +1 -0
- package/dist/schemas/claude-skill-frontmatter.js +48 -0
- package/dist/schemas/claude-skill-frontmatter.js.map +1 -0
- package/dist/schemas/index.d.ts +9 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +9 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/installed-plugins-registry.d.ts +97 -0
- package/dist/schemas/installed-plugins-registry.d.ts.map +1 -0
- package/dist/schemas/installed-plugins-registry.js +54 -0
- package/dist/schemas/installed-plugins-registry.js.map +1 -0
- package/dist/schemas/known-marketplaces-registry.d.ts +129 -0
- package/dist/schemas/known-marketplaces-registry.d.ts.map +1 -0
- package/dist/schemas/known-marketplaces-registry.js +52 -0
- package/dist/schemas/known-marketplaces-registry.js.map +1 -0
- package/dist/schemas/marketplace.d.ts +342 -0
- package/dist/schemas/marketplace.d.ts.map +1 -0
- package/dist/schemas/marketplace.js +88 -0
- package/dist/schemas/marketplace.js.map +1 -0
- package/dist/schemas/plugin.d.ts +61 -0
- package/dist/schemas/plugin.d.ts.map +1 -0
- package/dist/schemas/plugin.js +51 -0
- package/dist/schemas/plugin.js.map +1 -0
- package/dist/validators/format-detection.d.ts +26 -0
- package/dist/validators/format-detection.d.ts.map +1 -0
- package/dist/validators/format-detection.js +178 -0
- package/dist/validators/format-detection.js.map +1 -0
- package/dist/validators/index.d.ts +8 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/index.js +7 -0
- package/dist/validators/index.js.map +1 -0
- package/dist/validators/marketplace-validator.d.ts +9 -0
- package/dist/validators/marketplace-validator.d.ts.map +1 -0
- package/dist/validators/marketplace-validator.js +89 -0
- package/dist/validators/marketplace-validator.js.map +1 -0
- package/dist/validators/plugin-validator.d.ts +9 -0
- package/dist/validators/plugin-validator.d.ts.map +1 -0
- package/dist/validators/plugin-validator.js +84 -0
- package/dist/validators/plugin-validator.js.map +1 -0
- package/dist/validators/registry-validator.d.ts +16 -0
- package/dist/validators/registry-validator.d.ts.map +1 -0
- package/dist/validators/registry-validator.js +92 -0
- package/dist/validators/registry-validator.js.map +1 -0
- package/dist/validators/skill-validator.d.ts +9 -0
- package/dist/validators/skill-validator.d.ts.map +1 -0
- package/dist/validators/skill-validator.js +582 -0
- package/dist/validators/skill-validator.js.map +1 -0
- package/dist/validators/types.d.ts +73 -0
- package/dist/validators/types.d.ts.map +1 -0
- package/dist/validators/types.js +2 -0
- package/dist/validators/types.js.map +1 -0
- package/dist/validators/unified-validator.d.ts +22 -0
- package/dist/validators/unified-validator.d.ts.map +1 -0
- package/dist/validators/unified-validator.js +81 -0
- package/dist/validators/unified-validator.js.map +1 -0
- package/dist/validators/validation-utils.d.ts +17 -0
- package/dist/validators/validation-utils.d.ts.map +1 -0
- package/dist/validators/validation-utils.js +35 -0
- package/dist/validators/validation-utils.js.map +1 -0
- package/package.json +61 -0
- package/schemas/skill-frontmatter.json +49 -0
- package/schemas/vat-skill-frontmatter.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
# @vibe-agent-toolkit/agent-skills
|
|
2
|
+
|
|
3
|
+
Build, validate, and import Claude Skills for Claude Desktop, Claude Code, and VAT agents.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides runtime support for Claude Skills including:
|
|
8
|
+
- **Validation** - Audit Claude Skills for quality and compatibility
|
|
9
|
+
- **Import/Export** - Convert between SKILL.md and agent.yaml formats
|
|
10
|
+
- **Building** - Package VAT agents as Claude Skills
|
|
11
|
+
- **Frontmatter Parsing** - Extract and validate Claude Skills frontmatter
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- **Skill Validation** - Comprehensive validation against Agent Skills specification
|
|
16
|
+
- **Format Conversion** - Import SKILL.md to agent.yaml (and vice versa)
|
|
17
|
+
- **Build Pipeline** - Generate SKILL.md from agent manifests
|
|
18
|
+
- **Schema Validation** - Zod-based frontmatter validation with TypeScript types
|
|
19
|
+
- **Link Integrity** - Validate all markdown links and references
|
|
20
|
+
- **Console Compatibility** - Detect tool usage incompatible with console mode
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @vibe-agent-toolkit/agent-skills
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### Validate a Claude Skill
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { validateSkill } from '@vibe-agent-toolkit/agent-skills';
|
|
34
|
+
|
|
35
|
+
const result = await validateSkill({
|
|
36
|
+
skillPath: './my-skill/SKILL.md',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (result.status === 'error') {
|
|
40
|
+
console.error('Validation failed:');
|
|
41
|
+
for (const issue of result.issues) {
|
|
42
|
+
console.error(` [${issue.code}] ${issue.message}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Import SKILL.md to agent.yaml
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { importSkillToAgent } from '@vibe-agent-toolkit/agent-skills';
|
|
51
|
+
|
|
52
|
+
const result = await importSkillToAgent({
|
|
53
|
+
skillPath: './my-skill/SKILL.md',
|
|
54
|
+
outputPath: './my-agent/agent.yaml', // Optional
|
|
55
|
+
force: false, // Optional
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (result.success) {
|
|
59
|
+
console.log(`Imported to: ${result.agentPath}`);
|
|
60
|
+
} else {
|
|
61
|
+
console.error(`Import failed: ${result.error}`);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Build Claude Skill from VAT Agent
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { buildClaudeSkill } from '@vibe-agent-toolkit/agent-skills';
|
|
69
|
+
|
|
70
|
+
await buildClaudeSkill({
|
|
71
|
+
agentPath: './my-agent',
|
|
72
|
+
outputPath: './dist/skills/my-agent',
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## API Reference
|
|
77
|
+
|
|
78
|
+
### validateSkill(options): Promise<ValidationResult>
|
|
79
|
+
|
|
80
|
+
Validate a Claude Skill (SKILL.md) for quality and compatibility.
|
|
81
|
+
|
|
82
|
+
**Options:**
|
|
83
|
+
```typescript
|
|
84
|
+
interface ValidateOptions {
|
|
85
|
+
skillPath: string; // Path to SKILL.md
|
|
86
|
+
rootDir?: string; // Root directory for resolving links
|
|
87
|
+
isVATGenerated?: boolean; // Treat as VAT-generated (stricter validation)
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Returns:**
|
|
92
|
+
```typescript
|
|
93
|
+
interface ValidationResult {
|
|
94
|
+
path: string; // Path to skill file
|
|
95
|
+
type: 'claude-skill' | 'vat-agent'; // Detected type
|
|
96
|
+
status: 'success' | 'warning' | 'error';
|
|
97
|
+
summary: string; // Human-readable summary
|
|
98
|
+
issues: ValidationIssue[]; // All validation issues
|
|
99
|
+
metadata?: { // Extracted metadata
|
|
100
|
+
name?: string;
|
|
101
|
+
description?: string;
|
|
102
|
+
lineCount?: number;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface ValidationIssue {
|
|
107
|
+
severity: 'error' | 'warning' | 'info';
|
|
108
|
+
code: IssueCode; // Machine-readable code
|
|
109
|
+
message: string; // Human-readable message
|
|
110
|
+
location?: string; // File:line location
|
|
111
|
+
fix?: string; // Suggested fix
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Example:**
|
|
116
|
+
```typescript
|
|
117
|
+
const result = await validateSkill({
|
|
118
|
+
skillPath: './my-skill/SKILL.md',
|
|
119
|
+
rootDir: './my-skill',
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
console.log(`Status: ${result.status}`);
|
|
123
|
+
console.log(`Summary: ${result.summary}`);
|
|
124
|
+
|
|
125
|
+
// Check for specific error types
|
|
126
|
+
const nameErrors = result.issues.filter(
|
|
127
|
+
i => i.code === 'SKILL_NAME_INVALID'
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
if (nameErrors.length > 0) {
|
|
131
|
+
console.error('Name validation failed');
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Validation Rules
|
|
136
|
+
|
|
137
|
+
The validator checks for:
|
|
138
|
+
|
|
139
|
+
#### Critical Errors (Blocking)
|
|
140
|
+
|
|
141
|
+
**Frontmatter Errors:**
|
|
142
|
+
- `SKILL_MISSING_FRONTMATTER` - No YAML frontmatter found
|
|
143
|
+
- `SKILL_MISSING_NAME` - Required "name" field missing
|
|
144
|
+
- `SKILL_MISSING_DESCRIPTION` - Required "description" field missing
|
|
145
|
+
- `SKILL_NAME_INVALID` - Name doesn't match pattern: `^[a-z0-9]+(-[a-z0-9]+)*$`
|
|
146
|
+
- `SKILL_NAME_RESERVED_WORD` - Name contains "claude" or "anthropic"
|
|
147
|
+
- `SKILL_NAME_XML_TAGS` - Name contains < or > characters
|
|
148
|
+
- `SKILL_DESCRIPTION_TOO_LONG` - Description exceeds 1024 characters
|
|
149
|
+
- `SKILL_DESCRIPTION_EMPTY` - Description is empty or whitespace-only
|
|
150
|
+
- `SKILL_DESCRIPTION_XML_TAGS` - Description contains < or > characters
|
|
151
|
+
|
|
152
|
+
**Link Errors:**
|
|
153
|
+
- `LINK_INTEGRITY_BROKEN` - Link points to non-existent file
|
|
154
|
+
- `PATH_STYLE_WINDOWS` - Link uses Windows backslashes (\)
|
|
155
|
+
|
|
156
|
+
#### Warnings (Non-Blocking)
|
|
157
|
+
|
|
158
|
+
- `SKILL_TOO_LONG` - Skill exceeds 5000 lines
|
|
159
|
+
- `SKILL_CONSOLE_INCOMPATIBLE` - References Write, Edit, Bash, or NotebookEdit tools
|
|
160
|
+
|
|
161
|
+
See [Best Practices Guide](../../docs/guides/claude-skills-best-practices.md) for detailed guidance.
|
|
162
|
+
|
|
163
|
+
### importSkillToAgent(options): Promise<ImportResult>
|
|
164
|
+
|
|
165
|
+
Convert a Claude Skill (SKILL.md) to VAT agent format (agent.yaml).
|
|
166
|
+
|
|
167
|
+
**Options:**
|
|
168
|
+
```typescript
|
|
169
|
+
interface ImportOptions {
|
|
170
|
+
skillPath: string; // Path to SKILL.md
|
|
171
|
+
outputPath?: string; // Custom output path (default: same dir as SKILL.md)
|
|
172
|
+
force?: boolean; // Overwrite existing agent.yaml (default: false)
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Returns:**
|
|
177
|
+
```typescript
|
|
178
|
+
type ImportResult =
|
|
179
|
+
| { success: true; agentPath: string }
|
|
180
|
+
| { success: false; error: string };
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Example:**
|
|
184
|
+
```typescript
|
|
185
|
+
// Basic import
|
|
186
|
+
const result = await importSkillToAgent({
|
|
187
|
+
skillPath: './my-skill/SKILL.md',
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Custom output path
|
|
191
|
+
const result = await importSkillToAgent({
|
|
192
|
+
skillPath: './my-skill/SKILL.md',
|
|
193
|
+
outputPath: './agents/my-agent/agent.yaml',
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Force overwrite
|
|
197
|
+
const result = await importSkillToAgent({
|
|
198
|
+
skillPath: './my-skill/SKILL.md',
|
|
199
|
+
force: true,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
if (!result.success) {
|
|
203
|
+
console.error(`Import failed: ${result.error}`);
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**What Gets Converted:**
|
|
209
|
+
|
|
210
|
+
| SKILL.md Field | agent.yaml Field | Notes |
|
|
211
|
+
|----------------|------------------|-------|
|
|
212
|
+
| `name` | `metadata.name` | Required |
|
|
213
|
+
| `description` | `metadata.description` | Required |
|
|
214
|
+
| `metadata.version` | `metadata.version` | Defaults to "0.1.0" |
|
|
215
|
+
| `metadata.tags` | `metadata.tags` | Optional |
|
|
216
|
+
| `license` | `metadata.license` | Optional |
|
|
217
|
+
| `compatibility` | `spec.compatibility` | Optional |
|
|
218
|
+
|
|
219
|
+
The generated agent.yaml will have:
|
|
220
|
+
```yaml
|
|
221
|
+
metadata:
|
|
222
|
+
name: skill-name
|
|
223
|
+
description: Skill description
|
|
224
|
+
version: 1.0.0
|
|
225
|
+
spec:
|
|
226
|
+
runtime: claude-skills
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### buildClaudeSkill(options): Promise<BuildResult>
|
|
230
|
+
|
|
231
|
+
Build a Claude Skill from a VAT agent manifest.
|
|
232
|
+
|
|
233
|
+
**Options:**
|
|
234
|
+
```typescript
|
|
235
|
+
interface BuildOptions {
|
|
236
|
+
agentPath: string; // Path to agent directory or manifest
|
|
237
|
+
outputPath: string; // Where to write skill bundle
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Returns:**
|
|
242
|
+
```typescript
|
|
243
|
+
interface BuildResult {
|
|
244
|
+
outputPath: string; // Path to generated SKILL.md
|
|
245
|
+
metadata: {
|
|
246
|
+
name: string;
|
|
247
|
+
description: string;
|
|
248
|
+
version: string;
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**Example:**
|
|
254
|
+
```typescript
|
|
255
|
+
const result = await buildClaudeSkill({
|
|
256
|
+
agentPath: './my-agent',
|
|
257
|
+
outputPath: './dist/skills/my-agent',
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
console.log(`Built skill: ${result.outputPath}`);
|
|
261
|
+
console.log(`Version: ${result.metadata.version}`);
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Frontmatter Schemas
|
|
265
|
+
|
|
266
|
+
#### ClaudeSkillFrontmatterSchema
|
|
267
|
+
|
|
268
|
+
Strict schema for console-compatible Claude Skills:
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { ClaudeSkillFrontmatterSchema } from '@vibe-agent-toolkit/agent-skills';
|
|
272
|
+
import { z } from 'zod';
|
|
273
|
+
|
|
274
|
+
const frontmatter = {
|
|
275
|
+
name: 'my-skill',
|
|
276
|
+
description: 'Does something useful',
|
|
277
|
+
compatibility: 'Requires Node.js 18+',
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const result = ClaudeSkillFrontmatterSchema.safeParse(frontmatter);
|
|
281
|
+
if (result.success) {
|
|
282
|
+
// TypeScript type: ClaudeSkillFrontmatter
|
|
283
|
+
const validated = result.data;
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Required Fields:**
|
|
288
|
+
- `name` - Skill identifier (lowercase, hyphens, max 64 chars)
|
|
289
|
+
- `description` - What skill does (max 1024 chars)
|
|
290
|
+
|
|
291
|
+
**Optional Fields:**
|
|
292
|
+
- `license` - License identifier
|
|
293
|
+
- `compatibility` - Environment requirements (max 500 chars)
|
|
294
|
+
- `metadata` - Additional properties (Record<string, string>)
|
|
295
|
+
- `allowed-tools` - Pre-approved tools (experimental)
|
|
296
|
+
|
|
297
|
+
#### VATClaudeSkillFrontmatterSchema
|
|
298
|
+
|
|
299
|
+
Extended schema for VAT-generated skills:
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
import { VATClaudeSkillFrontmatterSchema } from '@vibe-agent-toolkit/agent-skills';
|
|
303
|
+
|
|
304
|
+
const frontmatter = {
|
|
305
|
+
name: 'my-skill',
|
|
306
|
+
description: 'Does something useful',
|
|
307
|
+
metadata: {
|
|
308
|
+
version: '1.0.0', // Required for VAT skills
|
|
309
|
+
tags: ['utility', 'data'],
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const result = VATClaudeSkillFrontmatterSchema.safeParse(frontmatter);
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Additional Requirements:**
|
|
317
|
+
- `metadata.version` - Semantic version (required for VAT)
|
|
318
|
+
|
|
319
|
+
### parseFrontmatter(content): ParseResult
|
|
320
|
+
|
|
321
|
+
Parse YAML frontmatter from SKILL.md content.
|
|
322
|
+
|
|
323
|
+
**Example:**
|
|
324
|
+
```typescript
|
|
325
|
+
import { parseFrontmatter } from '@vibe-agent-toolkit/agent-skills';
|
|
326
|
+
import * as fs from 'node:fs';
|
|
327
|
+
|
|
328
|
+
const content = fs.readFileSync('./SKILL.md', 'utf-8');
|
|
329
|
+
const result = parseFrontmatter(content);
|
|
330
|
+
|
|
331
|
+
if (result.success) {
|
|
332
|
+
console.log('Frontmatter:', result.frontmatter);
|
|
333
|
+
console.log('Body:', result.body);
|
|
334
|
+
} else {
|
|
335
|
+
console.error('Parse error:', result.error);
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Usage Examples
|
|
340
|
+
|
|
341
|
+
### Validate Before Import
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
import {
|
|
345
|
+
validateSkill,
|
|
346
|
+
importSkillToAgent
|
|
347
|
+
} from '@vibe-agent-toolkit/agent-skills';
|
|
348
|
+
|
|
349
|
+
// Validate first
|
|
350
|
+
const validation = await validateSkill({
|
|
351
|
+
skillPath: './my-skill/SKILL.md',
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
if (validation.status === 'error') {
|
|
355
|
+
console.error('Validation failed, cannot import');
|
|
356
|
+
process.exit(1);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Import if validation passes
|
|
360
|
+
const importResult = await importSkillToAgent({
|
|
361
|
+
skillPath: './my-skill/SKILL.md',
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
if (importResult.success) {
|
|
365
|
+
console.log(`Imported to: ${importResult.agentPath}`);
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Batch Validation
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
import { validateSkill } from '@vibe-agent-toolkit/agent-skills';
|
|
373
|
+
import * as fs from 'node:fs/promises';
|
|
374
|
+
import * as path from 'node:path';
|
|
375
|
+
|
|
376
|
+
async function validateAllSkills(dir: string) {
|
|
377
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
378
|
+
const results = [];
|
|
379
|
+
|
|
380
|
+
for (const entry of entries) {
|
|
381
|
+
if (entry.isDirectory()) {
|
|
382
|
+
const skillPath = path.join(dir, entry.name, 'SKILL.md');
|
|
383
|
+
try {
|
|
384
|
+
const result = await validateSkill({ skillPath });
|
|
385
|
+
results.push({ skill: entry.name, result });
|
|
386
|
+
} catch (error) {
|
|
387
|
+
console.error(`Error validating ${entry.name}:`, error);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return results;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const results = await validateAllSkills('./skills');
|
|
396
|
+
const failed = results.filter(r => r.result.status === 'error');
|
|
397
|
+
|
|
398
|
+
console.log(`Validated ${results.length} skills`);
|
|
399
|
+
console.log(`Failed: ${failed.length}`);
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Custom Validation Logic
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
import { validateSkill } from '@vibe-agent-toolkit/agent-skills';
|
|
406
|
+
|
|
407
|
+
const result = await validateSkill({
|
|
408
|
+
skillPath: './my-skill/SKILL.md',
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
// Filter by severity
|
|
412
|
+
const errors = result.issues.filter(i => i.severity === 'error');
|
|
413
|
+
const warnings = result.issues.filter(i => i.severity === 'warning');
|
|
414
|
+
|
|
415
|
+
// Group by error code
|
|
416
|
+
const byCode = result.issues.reduce((acc, issue) => {
|
|
417
|
+
if (!acc[issue.code]) acc[issue.code] = [];
|
|
418
|
+
acc[issue.code].push(issue);
|
|
419
|
+
return acc;
|
|
420
|
+
}, {} as Record<string, typeof result.issues>);
|
|
421
|
+
|
|
422
|
+
// Check for specific issues
|
|
423
|
+
const hasLinkErrors = result.issues.some(
|
|
424
|
+
i => i.code === 'LINK_INTEGRITY_BROKEN'
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
if (hasLinkErrors) {
|
|
428
|
+
console.error('Fix broken links before proceeding');
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Integration
|
|
433
|
+
|
|
434
|
+
### CLI Integration
|
|
435
|
+
|
|
436
|
+
This package powers these CLI commands:
|
|
437
|
+
- `vat agent audit` - Validates skills using `validateSkill()`
|
|
438
|
+
- `vat agent import` - Imports skills using `importSkillToAgent()`
|
|
439
|
+
|
|
440
|
+
See [CLI Documentation](../../docs/cli/audit.md) for command usage.
|
|
441
|
+
|
|
442
|
+
### CI/CD Integration
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
// ci-validate.ts
|
|
446
|
+
import { validateSkill } from '@vibe-agent-toolkit/agent-skills';
|
|
447
|
+
import * as fs from 'node:fs/promises';
|
|
448
|
+
|
|
449
|
+
async function validateInCI() {
|
|
450
|
+
const files = await fs.readdir('./skills', { recursive: true });
|
|
451
|
+
const skills = files.filter(f => f.endsWith('SKILL.md'));
|
|
452
|
+
|
|
453
|
+
let hasErrors = false;
|
|
454
|
+
|
|
455
|
+
for (const skill of skills) {
|
|
456
|
+
const result = await validateSkill({
|
|
457
|
+
skillPath: `./skills/${skill}`,
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
if (result.status === 'error') {
|
|
461
|
+
console.error(`❌ ${skill}:`);
|
|
462
|
+
for (const issue of result.issues) {
|
|
463
|
+
if (issue.severity === 'error') {
|
|
464
|
+
console.error(` ${issue.message}`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
hasErrors = true;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (hasErrors) {
|
|
472
|
+
process.exit(1);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
console.log('✅ All skills validated successfully');
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
validateInCI();
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## TypeScript Types
|
|
482
|
+
|
|
483
|
+
The package exports all types for TypeScript users:
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
import type {
|
|
487
|
+
ValidateOptions,
|
|
488
|
+
ValidationResult,
|
|
489
|
+
ValidationIssue,
|
|
490
|
+
IssueCode,
|
|
491
|
+
IssueSeverity,
|
|
492
|
+
ClaudeSkillFrontmatter,
|
|
493
|
+
VATClaudeSkillFrontmatter,
|
|
494
|
+
ImportOptions,
|
|
495
|
+
ImportResult,
|
|
496
|
+
BuildOptions,
|
|
497
|
+
BuildResult,
|
|
498
|
+
} from '@vibe-agent-toolkit/agent-skills';
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## Error Handling
|
|
502
|
+
|
|
503
|
+
All async functions use standard Promise rejection for errors:
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
try {
|
|
507
|
+
const result = await validateSkill({
|
|
508
|
+
skillPath: './invalid-path/SKILL.md',
|
|
509
|
+
});
|
|
510
|
+
} catch (error) {
|
|
511
|
+
if (error instanceof Error) {
|
|
512
|
+
console.error(`Validation error: ${error.message}`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Validation errors are returned in the `ValidationResult` object, not thrown:
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
const result = await validateSkill({ skillPath: './skill/SKILL.md' });
|
|
521
|
+
|
|
522
|
+
// result.status will be 'error', not thrown
|
|
523
|
+
if (result.status === 'error') {
|
|
524
|
+
// Handle validation failures
|
|
525
|
+
}
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
## Performance
|
|
529
|
+
|
|
530
|
+
### Validation Performance
|
|
531
|
+
|
|
532
|
+
Validation is optimized for:
|
|
533
|
+
- **Fast parsing** - Efficient YAML frontmatter extraction
|
|
534
|
+
- **Cached git checks** - Gitignore status cached per directory
|
|
535
|
+
- **Parallel validation** - Validate multiple skills concurrently
|
|
536
|
+
|
|
537
|
+
Typical performance:
|
|
538
|
+
- Single skill: ~10-50ms
|
|
539
|
+
- 10 skills: ~100-200ms (parallel)
|
|
540
|
+
- 100 skills: ~1-2s (parallel)
|
|
541
|
+
|
|
542
|
+
### Memory Usage
|
|
543
|
+
|
|
544
|
+
Memory usage is proportional to skill size:
|
|
545
|
+
- Small skill (<100KB): ~2MB
|
|
546
|
+
- Medium skill (500KB): ~5MB
|
|
547
|
+
- Large skill (2MB): ~10MB
|
|
548
|
+
|
|
549
|
+
For large-scale validation, validate in batches to control memory.
|
|
550
|
+
|
|
551
|
+
## Cross-Platform Compatibility
|
|
552
|
+
|
|
553
|
+
The package is fully cross-platform:
|
|
554
|
+
- **Path handling** - Uses `node:path` for Windows/Unix compatibility
|
|
555
|
+
- **Line endings** - Handles CRLF and LF correctly
|
|
556
|
+
- **File system** - Works with case-sensitive and case-insensitive file systems
|
|
557
|
+
|
|
558
|
+
Tested on:
|
|
559
|
+
- Windows 10/11
|
|
560
|
+
- macOS (Apple Silicon and Intel)
|
|
561
|
+
- Linux (Ubuntu, Debian, Alpine)
|
|
562
|
+
|
|
563
|
+
## Related Packages
|
|
564
|
+
|
|
565
|
+
- [`@vibe-agent-toolkit/discovery`](../discovery/README.md) - File discovery for skills
|
|
566
|
+
- [`@vibe-agent-toolkit/cli`](../cli/README.md) - CLI commands using this package
|
|
567
|
+
- [`@vibe-agent-toolkit/utils`](../utils/README.md) - Shared utilities
|
|
568
|
+
|
|
569
|
+
## Related Documentation
|
|
570
|
+
|
|
571
|
+
- [Audit Command](../../docs/cli/audit.md) - CLI validation command
|
|
572
|
+
- [Import Command](../../docs/cli/import.md) - CLI import command
|
|
573
|
+
- [Claude Skills Best Practices](../../docs/guides/claude-skills-best-practices.md) - Comprehensive guide
|
|
574
|
+
- [Agent Skills Specification](https://agentskills.io/specification) - Official spec
|
|
575
|
+
|
|
576
|
+
## Testing
|
|
577
|
+
|
|
578
|
+
The package includes comprehensive tests:
|
|
579
|
+
|
|
580
|
+
```bash
|
|
581
|
+
# Unit tests
|
|
582
|
+
bun run test:unit
|
|
583
|
+
|
|
584
|
+
# Integration tests
|
|
585
|
+
bun run test:integration
|
|
586
|
+
|
|
587
|
+
# Watch mode
|
|
588
|
+
bun run test:watch
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## License
|
|
592
|
+
|
|
593
|
+
MIT
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Skill builder - converts VAT agents to Claude Skills
|
|
3
|
+
*/
|
|
4
|
+
export interface BuildOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Path to agent directory or manifest file
|
|
7
|
+
*/
|
|
8
|
+
agentPath: string;
|
|
9
|
+
/**
|
|
10
|
+
* Output path for skill bundle
|
|
11
|
+
* If not provided, defaults to <agent-package-root>/dist/vat-bundles/skill
|
|
12
|
+
*/
|
|
13
|
+
outputPath?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Build target (skill, langchain, etc.)
|
|
16
|
+
* Used for default output path determination
|
|
17
|
+
*/
|
|
18
|
+
target?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface BuildResult {
|
|
21
|
+
/**
|
|
22
|
+
* Path where skill was written
|
|
23
|
+
*/
|
|
24
|
+
outputPath: string;
|
|
25
|
+
/**
|
|
26
|
+
* Agent metadata
|
|
27
|
+
*/
|
|
28
|
+
agent: {
|
|
29
|
+
name: string;
|
|
30
|
+
version: string | undefined;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Files created
|
|
34
|
+
*/
|
|
35
|
+
files: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build a Claude Skill from a VAT agent
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildClaudeSkill(options: BuildOptions): Promise<BuildResult>;
|
|
41
|
+
//# sourceMappingURL=builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;KAC7B,CAAC;IAEF;;OAEG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA6DlF"}
|