@codemcp/agentskills-core 0.0.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/LICENSE +19 -0
- package/dist/__tests__/package-config.test.d.ts +2 -0
- package/dist/__tests__/package-config.test.d.ts.map +1 -0
- package/dist/__tests__/package-config.test.js +251 -0
- package/dist/__tests__/package-config.test.js.map +1 -0
- package/dist/__tests__/parser.test.d.ts +2 -0
- package/dist/__tests__/parser.test.d.ts.map +1 -0
- package/dist/__tests__/parser.test.js +613 -0
- package/dist/__tests__/parser.test.js.map +1 -0
- package/dist/__tests__/registry.test.d.ts +2 -0
- package/dist/__tests__/registry.test.d.ts.map +1 -0
- package/dist/__tests__/registry.test.js +415 -0
- package/dist/__tests__/registry.test.js.map +1 -0
- package/dist/__tests__/skill-installer.test.d.ts +2 -0
- package/dist/__tests__/skill-installer.test.d.ts.map +1 -0
- package/dist/__tests__/skill-installer.test.js +229 -0
- package/dist/__tests__/skill-installer.test.js.map +1 -0
- package/dist/__tests__/validator.test.d.ts +2 -0
- package/dist/__tests__/validator.test.d.ts.map +1 -0
- package/dist/__tests__/validator.test.js +284 -0
- package/dist/__tests__/validator.test.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/installer.d.ts +89 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +469 -0
- package/dist/installer.js.map +1 -0
- package/dist/package-config.d.ts +52 -0
- package/dist/package-config.d.ts.map +1 -0
- package/dist/package-config.js +267 -0
- package/dist/package-config.js.map +1 -0
- package/dist/parser.d.ts +59 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +154 -0
- package/dist/parser.js.map +1 -0
- package/dist/registry.d.ts +72 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +180 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +202 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/validator.d.ts +27 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +165 -0
- package/dist/validator.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
/**
|
|
4
|
+
* PackageConfigManager - Manages package.json configuration for agent skills
|
|
5
|
+
*
|
|
6
|
+
* Responsibilities:
|
|
7
|
+
* - Read package.json from a directory
|
|
8
|
+
* - Parse `agentskills` field (skill dependencies)
|
|
9
|
+
* - Parse `agentskillsConfig` field (configuration settings)
|
|
10
|
+
* - Provide defaults when package.json doesn't exist
|
|
11
|
+
* - Provide defaults when fields are missing
|
|
12
|
+
* - Validate configuration structure
|
|
13
|
+
* - Save/update skills in package.json
|
|
14
|
+
*/
|
|
15
|
+
export class PackageConfigManager {
|
|
16
|
+
projectRoot;
|
|
17
|
+
packageJsonPath;
|
|
18
|
+
constructor(projectRoot) {
|
|
19
|
+
if (!projectRoot) {
|
|
20
|
+
throw new Error("Project root directory is required");
|
|
21
|
+
}
|
|
22
|
+
this.projectRoot = projectRoot;
|
|
23
|
+
this.packageJsonPath = join(projectRoot, "package.json");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get default configuration with empty skills and standard defaults
|
|
27
|
+
*/
|
|
28
|
+
getDefaultConfig() {
|
|
29
|
+
return {
|
|
30
|
+
skills: {},
|
|
31
|
+
config: {
|
|
32
|
+
skillsDirectory: ".agentskills/skills",
|
|
33
|
+
autoDiscover: [".claude/skills"],
|
|
34
|
+
maxSkillSize: 5000,
|
|
35
|
+
logLevel: "info"
|
|
36
|
+
},
|
|
37
|
+
source: {
|
|
38
|
+
type: "defaults"
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Load configuration from package.json
|
|
44
|
+
* Returns defaults if package.json doesn't exist
|
|
45
|
+
*/
|
|
46
|
+
async loadConfig() {
|
|
47
|
+
try {
|
|
48
|
+
const content = await fs.readFile(this.packageJsonPath, "utf-8");
|
|
49
|
+
let packageJson;
|
|
50
|
+
try {
|
|
51
|
+
packageJson = JSON.parse(content);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error(`Failed to parse package.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
55
|
+
}
|
|
56
|
+
// Validate and extract agentskills
|
|
57
|
+
const skills = this.validateAndExtractSkills(packageJson);
|
|
58
|
+
// Validate and extract agentskillsConfig
|
|
59
|
+
const config = this.validateAndExtractConfig(packageJson);
|
|
60
|
+
return {
|
|
61
|
+
skills,
|
|
62
|
+
config,
|
|
63
|
+
source: {
|
|
64
|
+
type: "file",
|
|
65
|
+
path: this.packageJsonPath
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
// Return defaults if file doesn't exist
|
|
71
|
+
if (error.code === "ENOENT") {
|
|
72
|
+
return this.getDefaultConfig();
|
|
73
|
+
}
|
|
74
|
+
// Handle permission errors
|
|
75
|
+
if (error.code === "EACCES") {
|
|
76
|
+
throw new Error(`Permission denied reading package.json at ${this.packageJsonPath}`);
|
|
77
|
+
}
|
|
78
|
+
// Re-throw other errors (like parse errors)
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Validate and extract skills from package.json
|
|
84
|
+
*/
|
|
85
|
+
validateAndExtractSkills(packageJson) {
|
|
86
|
+
if (!packageJson.agentskills) {
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
const agentskills = packageJson.agentskills;
|
|
90
|
+
// Validate agentskills is an object
|
|
91
|
+
if (typeof agentskills !== "object" ||
|
|
92
|
+
agentskills === null ||
|
|
93
|
+
Array.isArray(agentskills)) {
|
|
94
|
+
throw new Error("agentskills must be an object");
|
|
95
|
+
}
|
|
96
|
+
// Validate all values are strings
|
|
97
|
+
for (const value of Object.values(agentskills)) {
|
|
98
|
+
if (typeof value !== "string") {
|
|
99
|
+
throw new Error("agentskills values must be strings");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return agentskills;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Validate and extract config from package.json
|
|
106
|
+
*/
|
|
107
|
+
validateAndExtractConfig(packageJson) {
|
|
108
|
+
const defaultConfig = this.getDefaultConfig().config;
|
|
109
|
+
if (!packageJson.agentskillsConfig) {
|
|
110
|
+
return defaultConfig;
|
|
111
|
+
}
|
|
112
|
+
const agentskillsConfig = packageJson.agentskillsConfig;
|
|
113
|
+
// Validate agentskillsConfig is an object
|
|
114
|
+
if (typeof agentskillsConfig !== "object" ||
|
|
115
|
+
agentskillsConfig === null ||
|
|
116
|
+
Array.isArray(agentskillsConfig)) {
|
|
117
|
+
throw new Error("agentskillsConfig must be an object");
|
|
118
|
+
}
|
|
119
|
+
// Type assertion after validation
|
|
120
|
+
const configObj = agentskillsConfig;
|
|
121
|
+
// Start with defaults and merge
|
|
122
|
+
const config = { ...defaultConfig };
|
|
123
|
+
// Validate and merge skillsDirectory
|
|
124
|
+
if (configObj.skillsDirectory !== undefined) {
|
|
125
|
+
if (typeof configObj.skillsDirectory !== "string") {
|
|
126
|
+
throw new Error("skillsDirectory must be a string");
|
|
127
|
+
}
|
|
128
|
+
if (configObj.skillsDirectory === "") {
|
|
129
|
+
throw new Error("skillsDirectory cannot be empty");
|
|
130
|
+
}
|
|
131
|
+
config.skillsDirectory = configObj.skillsDirectory;
|
|
132
|
+
}
|
|
133
|
+
// Validate and merge autoDiscover
|
|
134
|
+
if (configObj.autoDiscover !== undefined) {
|
|
135
|
+
if (!Array.isArray(configObj.autoDiscover)) {
|
|
136
|
+
throw new Error("autoDiscover must be an array");
|
|
137
|
+
}
|
|
138
|
+
for (const item of configObj.autoDiscover) {
|
|
139
|
+
if (typeof item !== "string") {
|
|
140
|
+
throw new Error("autoDiscover must contain only strings");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
config.autoDiscover = configObj.autoDiscover;
|
|
144
|
+
}
|
|
145
|
+
// Validate and merge maxSkillSize
|
|
146
|
+
if (configObj.maxSkillSize !== undefined) {
|
|
147
|
+
if (typeof configObj.maxSkillSize !== "number") {
|
|
148
|
+
throw new Error("maxSkillSize must be a number");
|
|
149
|
+
}
|
|
150
|
+
if (configObj.maxSkillSize <= 0) {
|
|
151
|
+
throw new Error("maxSkillSize must be a positive number");
|
|
152
|
+
}
|
|
153
|
+
config.maxSkillSize = configObj.maxSkillSize;
|
|
154
|
+
}
|
|
155
|
+
// Validate and merge logLevel
|
|
156
|
+
if (configObj.logLevel !== undefined) {
|
|
157
|
+
if (typeof configObj.logLevel !== "string") {
|
|
158
|
+
throw new Error("logLevel must be a string");
|
|
159
|
+
}
|
|
160
|
+
const validLogLevels = ["error", "warn", "info", "debug"];
|
|
161
|
+
if (!validLogLevels.includes(configObj.logLevel)) {
|
|
162
|
+
throw new Error(`Invalid logLevel '${configObj.logLevel}'. Must be one of: error, warn, info, debug`);
|
|
163
|
+
}
|
|
164
|
+
config.logLevel = configObj.logLevel;
|
|
165
|
+
}
|
|
166
|
+
return config;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Save skills to package.json
|
|
170
|
+
* Creates package.json if it doesn't exist
|
|
171
|
+
* Preserves other fields
|
|
172
|
+
*/
|
|
173
|
+
async saveSkills(skills) {
|
|
174
|
+
let packageJson;
|
|
175
|
+
try {
|
|
176
|
+
const content = await fs.readFile(this.packageJsonPath, "utf-8");
|
|
177
|
+
packageJson = JSON.parse(content);
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
if (error &&
|
|
181
|
+
typeof error === "object" &&
|
|
182
|
+
"code" in error &&
|
|
183
|
+
error.code === "ENOENT") {
|
|
184
|
+
// Create minimal package.json
|
|
185
|
+
packageJson = {
|
|
186
|
+
name: "agentskills-project"
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Update agentskills field
|
|
194
|
+
packageJson.agentskills = skills;
|
|
195
|
+
// Write back to file with proper formatting
|
|
196
|
+
await fs.writeFile(this.packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Add a single skill to package.json
|
|
200
|
+
* Updates existing skill if name already exists
|
|
201
|
+
*/
|
|
202
|
+
async addSkill(name, spec) {
|
|
203
|
+
if (!name) {
|
|
204
|
+
throw new Error("Skill name cannot be empty");
|
|
205
|
+
}
|
|
206
|
+
if (!spec) {
|
|
207
|
+
throw new Error("Skill spec cannot be empty");
|
|
208
|
+
}
|
|
209
|
+
let packageJson;
|
|
210
|
+
try {
|
|
211
|
+
const content = await fs.readFile(this.packageJsonPath, "utf-8");
|
|
212
|
+
packageJson = JSON.parse(content);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (error &&
|
|
216
|
+
typeof error === "object" &&
|
|
217
|
+
"code" in error &&
|
|
218
|
+
error.code === "ENOENT") {
|
|
219
|
+
// Create minimal package.json
|
|
220
|
+
packageJson = {
|
|
221
|
+
name: "agentskills-project"
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Initialize agentskills if it doesn't exist
|
|
229
|
+
if (!packageJson.agentskills) {
|
|
230
|
+
packageJson.agentskills = {};
|
|
231
|
+
}
|
|
232
|
+
// Add or update skill - use type assertion after validation
|
|
233
|
+
const agentskills = packageJson.agentskills;
|
|
234
|
+
agentskills[name] = spec;
|
|
235
|
+
// Write back to file with proper formatting
|
|
236
|
+
await fs.writeFile(this.packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Remove a skill from package.json
|
|
240
|
+
* Does not error if skill doesn't exist or file doesn't exist
|
|
241
|
+
*/
|
|
242
|
+
async removeSkill(name) {
|
|
243
|
+
if (!name) {
|
|
244
|
+
throw new Error("Skill name cannot be empty");
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
const content = await fs.readFile(this.packageJsonPath, "utf-8");
|
|
248
|
+
const packageJson = JSON.parse(content);
|
|
249
|
+
// If agentskills doesn't exist, nothing to remove
|
|
250
|
+
if (!packageJson.agentskills) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
// Remove skill
|
|
254
|
+
delete packageJson.agentskills[name];
|
|
255
|
+
// Write back to file with proper formatting
|
|
256
|
+
await fs.writeFile(this.packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
// If file doesn't exist, nothing to remove
|
|
260
|
+
if (error.code === "ENOENT") {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=package-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-config.js","sourceRoot":"","sources":["../src/package-config.ts"],"names":[],"mappings":"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"}
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillParser Component
|
|
3
|
+
*
|
|
4
|
+
* Responsibility: Parse SKILL.md files into structured Skill objects
|
|
5
|
+
* following the Agent Skills standard and Claude Code extensions.
|
|
6
|
+
*
|
|
7
|
+
* This module provides two main functions:
|
|
8
|
+
* - parseSkillContent: Parse skill content string directly
|
|
9
|
+
* - parseSkill: Read and parse a skill file from the filesystem
|
|
10
|
+
*/
|
|
11
|
+
import type { ParseResult } from "./types.js";
|
|
12
|
+
/**
|
|
13
|
+
* Parse skill content from a string
|
|
14
|
+
*
|
|
15
|
+
* Extracts YAML frontmatter and Markdown body, validates required fields,
|
|
16
|
+
* and returns a structured Skill object.
|
|
17
|
+
*
|
|
18
|
+
* @param content - Raw skill file content (YAML frontmatter + Markdown body)
|
|
19
|
+
* @returns ParseResult with either success (Skill) or failure (ParseError)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const content = `---
|
|
24
|
+
* name: example-skill
|
|
25
|
+
* description: An example skill
|
|
26
|
+
* ---
|
|
27
|
+
* # Example Skill
|
|
28
|
+
*
|
|
29
|
+
* This is the skill body.
|
|
30
|
+
* `;
|
|
31
|
+
*
|
|
32
|
+
* const result = parseSkillContent(content);
|
|
33
|
+
* if (result.success) {
|
|
34
|
+
* console.log(result.skill.metadata.name); // "example-skill"
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseSkillContent(content: string): ParseResult;
|
|
39
|
+
/**
|
|
40
|
+
* Read and parse a skill file from the filesystem
|
|
41
|
+
*
|
|
42
|
+
* Reads the file at the given path, then delegates to parseSkillContent
|
|
43
|
+
* for parsing. Handles file system errors gracefully.
|
|
44
|
+
*
|
|
45
|
+
* @param filePath - Absolute path to SKILL.md file
|
|
46
|
+
* @returns ParseResult with either success (Skill) or failure (ParseError)
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const result = await parseSkill('/path/to/SKILL.md');
|
|
51
|
+
* if (result.success) {
|
|
52
|
+
* console.log(result.skill.metadata.name);
|
|
53
|
+
* } else {
|
|
54
|
+
* console.error(result.error.message);
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function parseSkill(filePath: string): Promise<ParseResult>;
|
|
59
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EACV,WAAW,EAKZ,MAAM,YAAY,CAAC;AAsDpB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAiD9D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA0BvE"}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillParser Component
|
|
3
|
+
*
|
|
4
|
+
* Responsibility: Parse SKILL.md files into structured Skill objects
|
|
5
|
+
* following the Agent Skills standard and Claude Code extensions.
|
|
6
|
+
*
|
|
7
|
+
* This module provides two main functions:
|
|
8
|
+
* - parseSkillContent: Parse skill content string directly
|
|
9
|
+
* - parseSkill: Read and parse a skill file from the filesystem
|
|
10
|
+
*/
|
|
11
|
+
import matter from "gray-matter";
|
|
12
|
+
import { promises as fs } from "fs";
|
|
13
|
+
/**
|
|
14
|
+
* Field name mapping from kebab-case (YAML) to camelCase (TypeScript)
|
|
15
|
+
*/
|
|
16
|
+
const FIELD_MAP = {
|
|
17
|
+
name: "name",
|
|
18
|
+
description: "description",
|
|
19
|
+
license: "license",
|
|
20
|
+
compatibility: "compatibility",
|
|
21
|
+
metadata: "metadata",
|
|
22
|
+
"allowed-tools": "allowedTools",
|
|
23
|
+
"disable-model-invocation": "disableModelInvocation",
|
|
24
|
+
"user-invocable": "userInvocable",
|
|
25
|
+
"argument-hint": "argumentHint",
|
|
26
|
+
context: "context",
|
|
27
|
+
agent: "agent",
|
|
28
|
+
model: "model",
|
|
29
|
+
hooks: "hooks"
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Required fields that must be present in skill metadata
|
|
33
|
+
*/
|
|
34
|
+
const REQUIRED_FIELDS = ["name", "description"];
|
|
35
|
+
/**
|
|
36
|
+
* Helper function to create error result
|
|
37
|
+
*/
|
|
38
|
+
function createError(code, message, field) {
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
error: { code, message, ...(field && { field }) }
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Map YAML field names (kebab-case) to TypeScript field names (camelCase)
|
|
46
|
+
*/
|
|
47
|
+
function mapFieldNames(data) {
|
|
48
|
+
const metadata = {};
|
|
49
|
+
for (const [key, value] of Object.entries(data)) {
|
|
50
|
+
const mappedKey = FIELD_MAP[key] || key;
|
|
51
|
+
metadata[mappedKey] = value;
|
|
52
|
+
}
|
|
53
|
+
return metadata;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Parse skill content from a string
|
|
57
|
+
*
|
|
58
|
+
* Extracts YAML frontmatter and Markdown body, validates required fields,
|
|
59
|
+
* and returns a structured Skill object.
|
|
60
|
+
*
|
|
61
|
+
* @param content - Raw skill file content (YAML frontmatter + Markdown body)
|
|
62
|
+
* @returns ParseResult with either success (Skill) or failure (ParseError)
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const content = `---
|
|
67
|
+
* name: example-skill
|
|
68
|
+
* description: An example skill
|
|
69
|
+
* ---
|
|
70
|
+
* # Example Skill
|
|
71
|
+
*
|
|
72
|
+
* This is the skill body.
|
|
73
|
+
* `;
|
|
74
|
+
*
|
|
75
|
+
* const result = parseSkillContent(content);
|
|
76
|
+
* if (result.success) {
|
|
77
|
+
* console.log(result.skill.metadata.name); // "example-skill"
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function parseSkillContent(content) {
|
|
82
|
+
// Check for empty file
|
|
83
|
+
if (!content || content.trim().length === 0) {
|
|
84
|
+
return createError("EMPTY_FILE", "Skill file is empty");
|
|
85
|
+
}
|
|
86
|
+
// Parse frontmatter using gray-matter
|
|
87
|
+
let parsed;
|
|
88
|
+
try {
|
|
89
|
+
parsed = matter(content);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
return createError("INVALID_YAML", `Failed to parse YAML frontmatter: ${error.message}`);
|
|
93
|
+
}
|
|
94
|
+
// Check if frontmatter exists
|
|
95
|
+
if (!parsed.data || Object.keys(parsed.data).length === 0) {
|
|
96
|
+
return createError("MISSING_FRONTMATTER", "Skill file must contain YAML frontmatter");
|
|
97
|
+
}
|
|
98
|
+
// Validate required fields
|
|
99
|
+
for (const field of REQUIRED_FIELDS) {
|
|
100
|
+
if (!(field in parsed.data)) {
|
|
101
|
+
return createError("MISSING_REQUIRED_FIELD", `required field '${field}' is missing from skill metadata`, field);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Map field names from kebab-case to camelCase
|
|
105
|
+
const metadata = mapFieldNames(parsed.data);
|
|
106
|
+
// Create Skill object
|
|
107
|
+
const skill = Object.freeze({
|
|
108
|
+
metadata: Object.freeze(metadata),
|
|
109
|
+
body: parsed.content
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
success: true,
|
|
113
|
+
skill
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Read and parse a skill file from the filesystem
|
|
118
|
+
*
|
|
119
|
+
* Reads the file at the given path, then delegates to parseSkillContent
|
|
120
|
+
* for parsing. Handles file system errors gracefully.
|
|
121
|
+
*
|
|
122
|
+
* @param filePath - Absolute path to SKILL.md file
|
|
123
|
+
* @returns ParseResult with either success (Skill) or failure (ParseError)
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const result = await parseSkill('/path/to/SKILL.md');
|
|
128
|
+
* if (result.success) {
|
|
129
|
+
* console.log(result.skill.metadata.name);
|
|
130
|
+
* } else {
|
|
131
|
+
* console.error(result.error.message);
|
|
132
|
+
* }
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export async function parseSkill(filePath) {
|
|
136
|
+
try {
|
|
137
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
138
|
+
return parseSkillContent(content);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
const nodeError = error;
|
|
142
|
+
// File not found error
|
|
143
|
+
if (nodeError.code === "ENOENT") {
|
|
144
|
+
return createError("FILE_NOT_FOUND", `File not found: ${filePath}`);
|
|
145
|
+
}
|
|
146
|
+
// Permission or other read errors
|
|
147
|
+
if (nodeError.code === "EACCES" || nodeError.code === "EISDIR") {
|
|
148
|
+
return createError("FILE_READ_ERROR", `Failed to read file: ${nodeError.message}`);
|
|
149
|
+
}
|
|
150
|
+
// Other errors
|
|
151
|
+
return createError("FILE_READ_ERROR", `Failed to read file: ${nodeError.message}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillRegistry Component
|
|
3
|
+
*
|
|
4
|
+
* Responsibility: In-memory skill storage with Map-based O(1) lookups.
|
|
5
|
+
* Load skills from a single directory with strict fail-fast behavior.
|
|
6
|
+
*
|
|
7
|
+
* Expected structure: <skillsDir>/<skill-name>/SKILL.md (exactly 2 levels deep)
|
|
8
|
+
* Throws errors on any misconfiguration (no partial failures).
|
|
9
|
+
*/
|
|
10
|
+
import type { Skill, SkillMetadata, LoadResult, RegistryState } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* In-memory registry for managing agent skills
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* - O(1) skill lookups using Map
|
|
16
|
+
* - Load skills from single directory (strict fail-fast)
|
|
17
|
+
* - Expected structure: <skillsDir>/<skill-name>/SKILL.md
|
|
18
|
+
* - Validates directory name matches skill name
|
|
19
|
+
* - Immutable skill objects
|
|
20
|
+
*/
|
|
21
|
+
export declare class SkillRegistry {
|
|
22
|
+
private skills;
|
|
23
|
+
private skillsDir;
|
|
24
|
+
private lastLoaded?;
|
|
25
|
+
/**
|
|
26
|
+
* Load skills from a single directory with strict error handling
|
|
27
|
+
*
|
|
28
|
+
* Expected structure: <skillsDir>/<skill-name>/SKILL.md (exactly 2 levels deep)
|
|
29
|
+
* - Throws on any error (fail fast)
|
|
30
|
+
* - Ignores hidden directories (.git/, etc.)
|
|
31
|
+
* - Ignores non-directory files
|
|
32
|
+
* - Validates directory name matches skill name in SKILL.md
|
|
33
|
+
*
|
|
34
|
+
* @param skillsDir - Directory containing skill subdirectories
|
|
35
|
+
* @returns Load result with count, directory, and timestamp
|
|
36
|
+
* @throws Error if directory doesn't exist, isn't a directory, or any skill is invalid
|
|
37
|
+
*/
|
|
38
|
+
loadSkills(skillsDir: string): Promise<LoadResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Get a skill by name
|
|
41
|
+
*
|
|
42
|
+
* @param name - The skill name
|
|
43
|
+
* @returns The skill or undefined if not found
|
|
44
|
+
*/
|
|
45
|
+
getSkill(name: string): Skill | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Get all loaded skills
|
|
48
|
+
*
|
|
49
|
+
* @returns Array of all skills
|
|
50
|
+
*/
|
|
51
|
+
getAllSkills(): Skill[];
|
|
52
|
+
/**
|
|
53
|
+
* Get skill metadata without body content
|
|
54
|
+
*
|
|
55
|
+
* @param name - The skill name
|
|
56
|
+
* @returns The skill metadata or undefined if not found
|
|
57
|
+
*/
|
|
58
|
+
getSkillMetadata(name: string): SkillMetadata | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Get all skill metadata without body content
|
|
61
|
+
*
|
|
62
|
+
* @returns Array of all skill metadata
|
|
63
|
+
*/
|
|
64
|
+
getAllMetadata(): SkillMetadata[];
|
|
65
|
+
/**
|
|
66
|
+
* Get current registry state
|
|
67
|
+
*
|
|
68
|
+
* @returns Current state with counts and source info
|
|
69
|
+
*/
|
|
70
|
+
getState(): RegistryState;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EACV,KAAK,EACL,aAAa,EACb,UAAU,EACV,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;GASG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAgE;IAC9E,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,UAAU,CAAC,CAAO;IAE1B;;;;;;;;;;;;OAYG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAgGxD;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAazC;;;;OAIG;IACH,YAAY,IAAI,KAAK,EAAE;IAOvB;;;;;OAKG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IASzD;;;;OAIG;IACH,cAAc,IAAI,aAAa,EAAE;IAMjC;;;;OAIG;IACH,QAAQ,IAAI,aAAa;CAO1B"}
|