@codemcp/skills 2.0.0 → 2.1.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.
@@ -1,1537 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
- // If the importer is in node compatibility mode or this is not an ESM
20
- // file that has been converted to a CommonJS file using a Babel-
21
- // compatible transform (i.e. "__esModule" has not been set), then set
22
- // "default" to the CommonJS "module.exports" for node compatibility.
23
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
- mod
25
- ));
26
-
27
- // ../core/dist/config-generators.js
28
- var ConfigGeneratorRegistry = class {
29
- generators = /* @__PURE__ */ new Map();
30
- /**
31
- * Register a config generator
32
- */
33
- register(generator) {
34
- for (const agentType of generator.agentTypes) {
35
- this.generators.set(agentType, generator);
36
- }
37
- }
38
- /**
39
- * Get a generator for an agent type
40
- */
41
- getGenerator(agentType) {
42
- return this.generators.get(agentType);
43
- }
44
- /**
45
- * Generate config for an agent
46
- */
47
- async generate(agentType, config, options) {
48
- const generator = this.getGenerator(agentType);
49
- if (!generator)
50
- return null;
51
- return generator.generate(config, options);
52
- }
53
- /**
54
- * List all registered generators
55
- */
56
- listGenerators() {
57
- const seen = /* @__PURE__ */ new Set();
58
- const result = [];
59
- for (const generator of this.generators.values()) {
60
- const name = generator.getMetadata().name;
61
- if (!seen.has(name)) {
62
- result.push(generator.getMetadata());
63
- seen.add(name);
64
- }
65
- }
66
- return result;
67
- }
68
- /**
69
- * Check if any generator supports an agent type
70
- */
71
- supports(agentType) {
72
- return this.generators.has(agentType);
73
- }
74
- /**
75
- * Get all supported agent types
76
- */
77
- getSupportedAgentTypes() {
78
- return Array.from(this.generators.keys());
79
- }
80
- /**
81
- * Clear all generators (mainly for testing)
82
- */
83
- clear() {
84
- this.generators.clear();
85
- }
86
- };
87
-
88
- // ../core/dist/generators/skills-agent-description.js
89
- var SKILLS_AGENT_DESCRIPTION_MARKDOWN = `# Skill Usage
90
-
91
- ## Mandatory Workflow Before Every Response
92
-
93
- Before responding to a message, ALWAYS check:
94
-
95
- 1. List available skills
96
- 2. Ask yourself: "Does ONE skill fit this task?" (at just 1% probability \u2192 call the skill)
97
- 3. If yes \u2192 load and execute skill via \`use_skill\` MCP tool
98
- 4. Announce: "I'm using [Skill-Name] for [Purpose]."
99
- 5. Follow skill instructions exactly
100
-
101
- ## Rules
102
-
103
- - ALWAYS call skills via \`use_skill\` tool, never work from memory
104
- - If a skill contains a checklist \u2192 create EACH point as its own todo
105
- - Never rationalize that a skill is "not needed" or "overkill"
106
- - Answering without skill check = error`;
107
-
108
- // ../core/dist/generators/github-copilot-generator.js
109
- var GitHubCopilotGenerator = class {
110
- agentTypes = [
111
- "github-copilot",
112
- "copilot-cli",
113
- "copilot-coding-agent"
114
- ];
115
- async generate(config, options) {
116
- const yaml = this.generateYamlFrontmatter(config);
117
- const markdown = this.generateMarkdownContent();
118
- return {
119
- filePath: `${options.skillsDir}/.github/agents/skills-mcp.agent.md`,
120
- content: `${yaml}
121
-
122
- ${markdown}`,
123
- format: "markdown"
124
- };
125
- }
126
- supports(agentType) {
127
- return this.agentTypes.includes(agentType);
128
- }
129
- getOutputPath(skillsDir) {
130
- return `${skillsDir}/.github/agents/skills-mcp.agent.md`;
131
- }
132
- getMetadata() {
133
- return {
134
- name: "GitHub Copilot",
135
- description: "Generates Markdown+YAML agent configs for GitHub Copilot CLI and coding agent",
136
- agentTypes: this.agentTypes,
137
- docsUrl: "https://docs.github.com/en/copilot/reference/custom-agents-configuration",
138
- version: "1.0.0"
139
- };
140
- }
141
- generateYamlFrontmatter(config) {
142
- const tools = this.mapToolsToGitHubFormat(config.tools, config.mcp_servers);
143
- const yamlObj = {
144
- name: config.id,
145
- description: config.description
146
- };
147
- if (tools.length > 0) {
148
- yamlObj.tools = tools;
149
- }
150
- if (config.mcp_servers && Object.keys(config.mcp_servers).length > 0) {
151
- yamlObj["mcp-servers"] = this.generateMcpServers(config.mcp_servers);
152
- }
153
- yamlObj["disable-model-invocation"] = false;
154
- yamlObj["user-invocable"] = true;
155
- let yaml = "---\n";
156
- for (const [k, v] of Object.entries(yamlObj)) {
157
- yaml += this.formatYamlEntry(k, v) + "\n";
158
- }
159
- yaml += "---";
160
- return yaml;
161
- }
162
- generateMarkdownContent() {
163
- return SKILLS_AGENT_DESCRIPTION_MARKDOWN;
164
- }
165
- generateMcpServers(servers) {
166
- const result = {};
167
- for (const [name, config] of Object.entries(servers)) {
168
- const serverConfig = config;
169
- const serverEntry = {};
170
- if (serverConfig.type) {
171
- serverEntry.type = serverConfig.type;
172
- }
173
- if (serverConfig.command) {
174
- serverEntry.command = serverConfig.command;
175
- }
176
- if (serverConfig.args) {
177
- serverEntry.args = serverConfig.args;
178
- }
179
- if (serverConfig.url) {
180
- serverEntry.url = serverConfig.url;
181
- }
182
- if (serverConfig.headers) {
183
- serverEntry.headers = serverConfig.headers;
184
- }
185
- if (serverConfig.env) {
186
- serverEntry.env = serverConfig.env;
187
- }
188
- if (serverConfig.tools) {
189
- serverEntry.tools = serverConfig.tools;
190
- }
191
- result[name] = serverEntry;
192
- }
193
- return result;
194
- }
195
- mapToolsToGitHubFormat(tools, servers) {
196
- const result = [];
197
- if (tools?.write)
198
- result.push("edit");
199
- if (tools?.read)
200
- result.push("read");
201
- if (tools?.bash)
202
- result.push("execute");
203
- if (tools?.use_skill)
204
- result.push("use_skill");
205
- if (servers) {
206
- for (const [name, server] of Object.entries(servers)) {
207
- const serverConfig = server;
208
- if (serverConfig.tools && !serverConfig.tools.includes("*")) {
209
- for (const tool of serverConfig.tools) {
210
- result.push(`${name}/${tool}`);
211
- }
212
- } else {
213
- result.push(`${name}/*`);
214
- }
215
- }
216
- }
217
- return result.length > 0 ? result : ["*"];
218
- }
219
- formatYamlEntry(key, value, indent = 0) {
220
- const prefix = " ".repeat(indent);
221
- if (Array.isArray(value)) {
222
- return `${prefix}${key}:
223
- ${value.map((v) => `${prefix} - ${v}`).join("\n")}`;
224
- }
225
- if (typeof value === "object" && value !== null) {
226
- const entries = Object.entries(value);
227
- if (entries.length === 0)
228
- return `${prefix}${key}: {}`;
229
- let result = `${prefix}${key}:
230
- `;
231
- for (const [k, v] of entries) {
232
- const entry = this.formatYamlEntry(k, v, indent + 2);
233
- result += entry + "\n";
234
- }
235
- return result.trimEnd();
236
- }
237
- if (typeof value === "boolean") {
238
- return `${prefix}${key}: ${value}`;
239
- }
240
- return `${prefix}${key}: ${value}`;
241
- }
242
- };
243
-
244
- // ../core/dist/generators/kiro-generator.js
245
- var KiroGenerator = class {
246
- agentTypes = ["kiro", "kiro-cli"];
247
- async generate(config, _options) {
248
- const agentConfig = this.generateAgentConfig(config);
249
- return {
250
- filePath: `${_options.skillsDir}/.kiro/agents/skills-mcp.json`,
251
- content: JSON.stringify(agentConfig, null, 2),
252
- format: "json"
253
- };
254
- }
255
- supports(agentType) {
256
- return this.agentTypes.includes(agentType);
257
- }
258
- getOutputPath(skillsDir) {
259
- return `${skillsDir}/.kiro/agents/skills-mcp.json`;
260
- }
261
- getMetadata() {
262
- return {
263
- name: "Kiro",
264
- description: "Generates JSON agent configs for Kiro CLI",
265
- agentTypes: this.agentTypes,
266
- docsUrl: "https://kiro.dev/docs/cli/custom-agents/",
267
- version: "1.0.0"
268
- };
269
- }
270
- generateAgentConfig(config) {
271
- const agentConfig = {
272
- name: config.id,
273
- prompt: SKILLS_AGENT_DESCRIPTION_MARKDOWN,
274
- mcpServers: this.generateMcpServers(config.mcp_servers),
275
- tools: this.generateTools(config),
276
- allowedTools: this.generateAllowedTools(config)
277
- };
278
- return agentConfig;
279
- }
280
- generateMcpServers(servers) {
281
- const result = {};
282
- if (!servers)
283
- return result;
284
- for (const [name, config] of Object.entries(servers)) {
285
- const serverConfig = config;
286
- const serverEntry = {};
287
- if (serverConfig.command) {
288
- serverEntry.command = serverConfig.command;
289
- }
290
- if (serverConfig.args && Array.isArray(serverConfig.args)) {
291
- serverEntry.args = serverConfig.args;
292
- }
293
- if (serverConfig.env) {
294
- serverEntry.env = serverConfig.env;
295
- }
296
- result[name] = serverEntry;
297
- }
298
- return result;
299
- }
300
- generateTools(config) {
301
- const tools = [
302
- "execute_bash",
303
- "fs_read",
304
- "fs_write",
305
- "report_issue",
306
- "knowledge",
307
- "thinking",
308
- "use_aws"
309
- ];
310
- if (config.mcp_servers && Object.keys(config.mcp_servers).length > 0) {
311
- for (const name of Object.keys(config.mcp_servers)) {
312
- tools.push(`@${name}`);
313
- }
314
- }
315
- return tools;
316
- }
317
- generateAllowedTools(config) {
318
- const allowed = ["fs_read", "use_skill"];
319
- if (config.mcp_servers) {
320
- for (const [name, server] of Object.entries(config.mcp_servers)) {
321
- if (server.tools && !server.tools.includes("*")) {
322
- for (const tool of server.tools) {
323
- allowed.push(`@${name}/${tool}`);
324
- }
325
- } else {
326
- allowed.push(`@${name}/*`);
327
- }
328
- }
329
- }
330
- return allowed;
331
- }
332
- };
333
-
334
- // ../core/dist/generators/opencode-generator.js
335
- var OpenCodeMcpGenerator = class {
336
- agentTypes = ["opencode", "opencode-cli"];
337
- async generate(config, options) {
338
- const opencodeConfig = this.generateOpenCodeConfig(config);
339
- return {
340
- filePath: `${options.skillsDir}/opencode.json`,
341
- content: JSON.stringify(opencodeConfig, null, 2),
342
- format: "json"
343
- };
344
- }
345
- supports(agentType) {
346
- return this.agentTypes.includes(agentType);
347
- }
348
- getOutputPath(skillsDir) {
349
- return `${skillsDir}/opencode.json`;
350
- }
351
- getMetadata() {
352
- return {
353
- name: "OpenCode MCP",
354
- description: "Writes opencode.json with MCP server configurations for OpenCode",
355
- agentTypes: this.agentTypes,
356
- docsUrl: "https://opencode.ai/docs/mcp-servers/",
357
- version: "1.0.0"
358
- };
359
- }
360
- generateOpenCodeConfig(config) {
361
- const opencodeConfig = {
362
- $schema: "https://opencode.ai/config.json",
363
- permission: {
364
- skill: "deny"
365
- // Disable native skill tool to avoid conflicts
366
- },
367
- mcp: {}
368
- };
369
- if (config.mcp_servers) {
370
- const mcp = opencodeConfig.mcp;
371
- for (const [name, serverConfig] of Object.entries(config.mcp_servers)) {
372
- const entry = {
373
- type: "local",
374
- enabled: true,
375
- environment: serverConfig.env || {}
376
- };
377
- if (serverConfig.command) {
378
- entry.command = [serverConfig.command, ...serverConfig.args || []];
379
- }
380
- mcp[name] = entry;
381
- }
382
- }
383
- return opencodeConfig;
384
- }
385
- };
386
- var OpenCodeAgentGenerator = class {
387
- agentTypes = ["opencode", "opencode-cli"];
388
- async generate(config, options) {
389
- const markdown = this.generateMarkdown(config);
390
- return {
391
- filePath: `${options.skillsDir}/.opencode/agents/skills-mcp.md`,
392
- content: markdown,
393
- format: "markdown"
394
- };
395
- }
396
- supports(agentType) {
397
- return this.agentTypes.includes(agentType);
398
- }
399
- getOutputPath(skillsDir) {
400
- return `${skillsDir}/.opencode/agents/skills-mcp.md`;
401
- }
402
- getMetadata() {
403
- return {
404
- name: "OpenCode Agent",
405
- description: "Generates Markdown agent configs for OpenCode",
406
- agentTypes: this.agentTypes,
407
- docsUrl: "https://opencode.ai/docs/agents/",
408
- version: "1.0.0"
409
- };
410
- }
411
- generateMarkdown(config) {
412
- const frontmatter = this.generateFrontmatter(config);
413
- const content = this.generateContent();
414
- return `${frontmatter}
415
-
416
- ${content}`;
417
- }
418
- generateFrontmatter(config) {
419
- const permissions = this.mapPermissions(config.permissions);
420
- const frontmatterObj = {
421
- name: config.id,
422
- description: config.description,
423
- tools: this.mapTools(config.tools),
424
- permission: permissions
425
- };
426
- if (config.mcp_servers && Object.keys(config.mcp_servers).length > 0) {
427
- frontmatterObj.mcp = this.generateMcpServers(config.mcp_servers);
428
- }
429
- let yaml = "---\n";
430
- for (const [key, value] of Object.entries(frontmatterObj)) {
431
- yaml += this.formatYamlValue(key, value);
432
- }
433
- yaml += "---";
434
- return yaml;
435
- }
436
- formatYamlValue(key, value, indent = 0) {
437
- const prefix = " ".repeat(indent);
438
- if (typeof value === "boolean" || typeof value === "number") {
439
- return `${prefix}${key}: ${value}
440
- `;
441
- }
442
- if (Array.isArray(value)) {
443
- let result = `${prefix}${key}:
444
- `;
445
- for (const item of value) {
446
- result += `${prefix} - ${item}
447
- `;
448
- }
449
- return result;
450
- }
451
- if (typeof value === "object" && value !== null) {
452
- let result = `${prefix}${key}:
453
- `;
454
- for (const [k, v] of Object.entries(value)) {
455
- result += this.formatYamlValue(k, v, indent + 2);
456
- }
457
- return result;
458
- }
459
- return `${prefix}${key}: ${value}
460
- `;
461
- }
462
- mapTools(tools) {
463
- const mapped = {
464
- read: true,
465
- write: false,
466
- edit: false,
467
- bash: false,
468
- use_skill: true
469
- };
470
- if (tools) {
471
- Object.assign(mapped, tools);
472
- }
473
- return mapped;
474
- }
475
- mapPermissions(permissions) {
476
- if (!permissions) {
477
- return {
478
- edit: "ask",
479
- bash: "ask",
480
- use_skill: "allow"
481
- };
482
- }
483
- return permissions || {
484
- edit: "ask",
485
- bash: "ask",
486
- use_skill: "allow"
487
- };
488
- }
489
- generateMcpServers(servers) {
490
- const result = {};
491
- for (const [name, config] of Object.entries(servers)) {
492
- const serverConfig = config;
493
- const serverEntry = {};
494
- if (serverConfig.type) {
495
- serverEntry.type = serverConfig.type;
496
- }
497
- if (serverConfig.command) {
498
- serverEntry.command = serverConfig.command;
499
- }
500
- if (serverConfig.args) {
501
- serverEntry.args = serverConfig.args;
502
- }
503
- if (serverConfig.url) {
504
- serverEntry.url = serverConfig.url;
505
- }
506
- if (serverConfig.env) {
507
- serverEntry.env = serverConfig.env;
508
- }
509
- if (serverConfig.tools) {
510
- serverEntry.tools = serverConfig.tools;
511
- }
512
- result[name] = serverEntry;
513
- }
514
- return result;
515
- }
516
- generateContent() {
517
- return SKILLS_AGENT_DESCRIPTION_MARKDOWN;
518
- }
519
- };
520
-
521
- // ../core/dist/generators/vscode-generator.js
522
- var VsCodeGenerator = class {
523
- // github-copilot is the primary agent type; the others are aliases
524
- // that also live inside VS Code and share the same MCP config file.
525
- agentTypes = [
526
- "github-copilot",
527
- "copilot-cli",
528
- "copilot-coding-agent"
529
- ];
530
- async generate(config, options) {
531
- const vscodeConfig = this.generateVsCodeConfig(config);
532
- return {
533
- filePath: `${options.skillsDir}/.vscode/mcp.json`,
534
- content: JSON.stringify(vscodeConfig, null, 2),
535
- format: "json"
536
- };
537
- }
538
- supports(agentType) {
539
- return this.agentTypes.includes(agentType);
540
- }
541
- getOutputPath(skillsDir) {
542
- return `${skillsDir}/.vscode/mcp.json`;
543
- }
544
- getMetadata() {
545
- return {
546
- name: "VS Code",
547
- description: "Writes .vscode/mcp.json (servers format) so MCP servers are available to GitHub Copilot and other VS Code extensions",
548
- agentTypes: this.agentTypes,
549
- docsUrl: "https://code.visualstudio.com/docs/copilot/chat/mcp-servers",
550
- version: "1.0.0"
551
- };
552
- }
553
- generateVsCodeConfig(config) {
554
- const servers = {};
555
- if (config.mcp_servers) {
556
- for (const [name, serverConfig] of Object.entries(config.mcp_servers)) {
557
- const entry = {};
558
- if (serverConfig.url) {
559
- entry.type = serverConfig.type ?? "http";
560
- entry.url = serverConfig.url;
561
- if (serverConfig.headers)
562
- entry.headers = serverConfig.headers;
563
- } else if (serverConfig.command) {
564
- entry.command = serverConfig.command;
565
- if (serverConfig.args?.length)
566
- entry.args = serverConfig.args;
567
- if (serverConfig.env && Object.keys(serverConfig.env).length) {
568
- entry.env = serverConfig.env;
569
- }
570
- }
571
- servers[name] = entry;
572
- }
573
- }
574
- return { servers };
575
- }
576
- };
577
-
578
- // ../core/dist/parser.js
579
- import matter from "gray-matter";
580
- import { promises as fs } from "fs";
581
- var FIELD_MAP = {
582
- name: "name",
583
- description: "description",
584
- license: "license",
585
- compatibility: "compatibility",
586
- metadata: "metadata",
587
- "allowed-tools": "allowedTools",
588
- "disable-model-invocation": "disableModelInvocation",
589
- "user-invocable": "userInvocable",
590
- "argument-hint": "argumentHint",
591
- context: "context",
592
- agent: "agent",
593
- model: "model",
594
- hooks: "hooks",
595
- labels: "labels",
596
- "requires-mcp-servers": "requiresMcpServers"
597
- };
598
- var REQUIRED_FIELDS = ["name", "description"];
599
- function createError(code, message, field) {
600
- return {
601
- success: false,
602
- error: { code, message, ...field && { field } }
603
- };
604
- }
605
- function mapFieldNames(data) {
606
- const metadata = {};
607
- for (const [key, value] of Object.entries(data)) {
608
- const mappedKey = FIELD_MAP[key];
609
- if (mappedKey !== void 0) {
610
- if (mappedKey === "allowedTools" && typeof value === "string") {
611
- metadata[mappedKey] = value.split(/\s+/).filter(Boolean);
612
- } else {
613
- metadata[mappedKey] = value;
614
- }
615
- }
616
- }
617
- return metadata;
618
- }
619
- function parseSkillContent(content) {
620
- if (!content || content.trim().length === 0) {
621
- return createError("EMPTY_FILE", "Skill file is empty");
622
- }
623
- let parsed;
624
- try {
625
- parsed = matter(content);
626
- } catch (error) {
627
- return createError("INVALID_YAML", `Failed to parse YAML frontmatter: ${error.message}`);
628
- }
629
- if (!parsed.data || Object.keys(parsed.data).length === 0) {
630
- return createError("MISSING_FRONTMATTER", "Skill file must contain YAML frontmatter");
631
- }
632
- for (const field of REQUIRED_FIELDS) {
633
- if (!(field in parsed.data)) {
634
- return createError("MISSING_REQUIRED_FIELD", `required field '${field}' is missing from skill metadata`, field);
635
- }
636
- }
637
- const metadata = mapFieldNames(parsed.data);
638
- const skill = Object.freeze({
639
- metadata: Object.freeze(metadata),
640
- body: parsed.content
641
- });
642
- return {
643
- success: true,
644
- skill
645
- };
646
- }
647
- async function parseSkill(filePath) {
648
- try {
649
- const content = await fs.readFile(filePath, "utf-8");
650
- return parseSkillContent(content);
651
- } catch (error) {
652
- const nodeError = error;
653
- if (nodeError.code === "ENOENT") {
654
- return createError("FILE_NOT_FOUND", `File not found: ${filePath}`);
655
- }
656
- if (nodeError.code === "EACCES" || nodeError.code === "EISDIR") {
657
- return createError("FILE_READ_ERROR", `Failed to read file: ${nodeError.message}`);
658
- }
659
- return createError("FILE_READ_ERROR", `Failed to read file: ${nodeError.message}`);
660
- }
661
- }
662
-
663
- // ../core/dist/validator.js
664
- import Ajv from "ajv";
665
-
666
- // ../core/dist/skill-frontmatter.schema.json
667
- var skill_frontmatter_schema_default = {
668
- $schema: "https://json-schema.org/draft-07/schema#",
669
- $id: "https://mrsimpson.github.io/agentskills-mcp/skill-frontmatter-schema.json",
670
- title: "Agent Skill Frontmatter",
671
- description: "YAML frontmatter schema for Agent Skills (SKILL.md files). See https://mrsimpson.github.io/agentskills-mcp/reference/skill-format for full documentation.",
672
- type: "object",
673
- required: ["name", "description"],
674
- additionalProperties: false,
675
- properties: {
676
- name: {
677
- type: "string",
678
- description: "Unique skill identifier. Lowercase letters, numbers, and hyphens only. No leading/trailing/consecutive hyphens.",
679
- minLength: 1,
680
- maxLength: 64,
681
- allOf: [
682
- { pattern: "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$" },
683
- { not: { pattern: "--" } }
684
- ]
685
- },
686
- description: {
687
- type: "string",
688
- description: "Short summary of the skill shown in tool descriptions.",
689
- minLength: 1,
690
- maxLength: 1024
691
- },
692
- license: {
693
- type: "string",
694
- description: "SPDX license identifier (e.g. MIT, Apache-2.0). Recommended for published skills."
695
- },
696
- compatibility: {
697
- type: "string",
698
- description: "Agent compatibility string.",
699
- maxLength: 500
700
- },
701
- metadata: {
702
- type: "object",
703
- description: "Arbitrary key-value metadata.",
704
- additionalProperties: true
705
- },
706
- "allowed-tools": {
707
- type: "string",
708
- description: "Space-delimited list of tools this skill is permitted to use. MCP server tools use the format '@server-name/tool-name'. When specified, only these tools are whitelisted in the generated agent config instead of allowing all tools from each MCP server."
709
- },
710
- "disable-model-invocation": {
711
- type: "boolean",
712
- description: "If true, the skill is excluded from the use_skill tool enum and cannot be invoked via MCP."
713
- },
714
- "user-invocable": {
715
- type: "boolean",
716
- description: "If true, the skill is designed for direct user invocation (e.g. via /skill-name)."
717
- },
718
- "argument-hint": {
719
- type: "string",
720
- description: 'Hint shown to users about expected arguments, e.g. "<pr-url>" or "<target> [options]".'
721
- },
722
- context: {
723
- type: "string",
724
- description: "Execution context hint for the agent."
725
- },
726
- agent: {
727
- type: "string",
728
- description: "Target agent identifier this skill is optimized for."
729
- },
730
- model: {
731
- type: "string",
732
- description: "Preferred model for executing this skill."
733
- },
734
- hooks: {
735
- type: "object",
736
- description: "Lifecycle hook definitions keyed by hook name.",
737
- additionalProperties: {
738
- type: "string"
739
- }
740
- },
741
- labels: {
742
- type: "array",
743
- description: "Optional labels/tags for categorizing skills. Used with the SKILL_LABELS environment variable to filter which skills are loaded by the MCP server.",
744
- items: {
745
- type: "string",
746
- minLength: 1,
747
- maxLength: 64,
748
- pattern: "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$"
749
- },
750
- uniqueItems: true
751
- },
752
- "requires-mcp-servers": {
753
- type: "array",
754
- description: "MCP servers that must be configured for this skill to work. Used by 'agentskills install --agent' for validation and auto-configuration.",
755
- items: {
756
- $ref: "#/$defs/McpServerDependency"
757
- }
758
- }
759
- },
760
- $defs: {
761
- McpServerDependency: {
762
- type: "object",
763
- description: "An MCP server that this skill depends on.",
764
- required: ["name", "description", "command"],
765
- additionalProperties: false,
766
- properties: {
767
- name: {
768
- type: "string",
769
- description: "Server identifier. Lowercase letters, numbers, and hyphens. Must start and end with alphanumeric.",
770
- allOf: [
771
- { pattern: "^[a-z0-9][a-z0-9-]*[a-z0-9]$" },
772
- { not: { pattern: "--" } }
773
- ]
774
- },
775
- package: {
776
- type: "string",
777
- description: 'npm package name used for auto-installation (e.g. "@modelcontextprotocol/server-filesystem").'
778
- },
779
- description: {
780
- type: "string",
781
- description: "Why this MCP server is needed by the skill."
782
- },
783
- command: {
784
- type: "string",
785
- description: 'Executable to run (e.g. "npx", "node", "/usr/local/bin/my-server").'
786
- },
787
- args: {
788
- type: "array",
789
- description: "Arguments passed to the command. May contain {{PARAM_NAME}} placeholders resolved at install time.",
790
- items: {
791
- type: "string"
792
- }
793
- },
794
- env: {
795
- type: "object",
796
- description: "Environment variables to set when running the server.",
797
- additionalProperties: {
798
- type: "string"
799
- }
800
- },
801
- cwd: {
802
- type: "string",
803
- description: "Working directory for the server process."
804
- },
805
- parameters: {
806
- type: "object",
807
- description: "Parameter definitions for {{PARAM}} placeholders used in args or env.",
808
- propertyNames: {
809
- allOf: [
810
- { pattern: "^[a-z0-9][a-z0-9-]*[a-z0-9]$" },
811
- { not: { pattern: "--" } }
812
- ]
813
- },
814
- additionalProperties: {
815
- $ref: "#/$defs/McpParameterSpec"
816
- }
817
- }
818
- }
819
- },
820
- McpParameterSpec: {
821
- type: "object",
822
- description: "Definition of a parameter placeholder used in an MCP server dependency.",
823
- required: ["description", "required"],
824
- additionalProperties: false,
825
- properties: {
826
- description: {
827
- type: "string",
828
- description: "What this parameter configures."
829
- },
830
- required: {
831
- type: "boolean",
832
- description: "Whether the user must supply this parameter."
833
- },
834
- sensitive: {
835
- type: "boolean",
836
- description: "If true, treat as a secret or credential (mask in output, do not log)."
837
- },
838
- default: {
839
- type: "string",
840
- description: "Default value used when the parameter is not supplied."
841
- },
842
- example: {
843
- type: "string",
844
- description: "Example value shown to guide users."
845
- }
846
- }
847
- }
848
- }
849
- };
850
-
851
- // ../core/dist/validator.js
852
- var ajv = new Ajv({ validateSchema: false });
853
- var validateFrontmatter = ajv.compile(skill_frontmatter_schema_default);
854
- var CAMEL_TO_KEBAB = {
855
- allowedTools: "allowed-tools",
856
- disableModelInvocation: "disable-model-invocation",
857
- userInvocable: "user-invocable",
858
- argumentHint: "argument-hint",
859
- requiresMcpServers: "requires-mcp-servers"
860
- };
861
- function toRawYamlKeys(metadata) {
862
- const result = {};
863
- for (const [key, value] of Object.entries(metadata)) {
864
- const yamlKey = CAMEL_TO_KEBAB[key] ?? key;
865
- if (key === "allowedTools" && Array.isArray(value)) {
866
- result[yamlKey] = value.join(" ");
867
- } else {
868
- result[yamlKey] = value;
869
- }
870
- }
871
- return result;
872
- }
873
- function validateSkill(skill) {
874
- const rawData = toRawYamlKeys(skill.metadata);
875
- const valid = validateFrontmatter(rawData);
876
- return {
877
- valid,
878
- errors: valid ? [] : (validateFrontmatter.errors ?? []).map((e) => ({
879
- message: e.message ?? "Validation error"
880
- })),
881
- warnings: []
882
- };
883
- }
884
-
885
- // ../core/dist/registry.js
886
- import { promises as fs2 } from "fs";
887
- import { join, basename } from "path";
888
- function makeInvalidSkillPlaceholder(dirName, sourcePath, errors) {
889
- return Object.freeze({
890
- metadata: Object.freeze({
891
- name: dirName,
892
- description: "[INVALID] This skill failed validation and cannot be applied"
893
- }),
894
- body: `This skill is invalid and cannot be applied.
895
-
896
- Validation errors:
897
- ${errors}
898
-
899
- Please inform the user that the skill at \`${sourcePath}\` is invalid and needs to be fixed before it can be used.`
900
- });
901
- }
902
- var SkillRegistry = class {
903
- skills = /* @__PURE__ */ new Map();
904
- skillsDir = "";
905
- skillsDirs = [];
906
- lastLoaded;
907
- /**
908
- * Load skills from multiple directories with optional filtering
909
- *
910
- * Loads skills from each directory in order, with later directories
911
- * overriding skills from earlier ones. Supports optional filtering
912
- * to only include skills specified in an allow list.
913
- *
914
- * Expected structure: <skillsDir>/<skill-name>/SKILL.md (exactly 2 levels deep)
915
- * - Throws on first required directory error (fail fast)
916
- * - Skips non-existent optional directories (2nd onwards)
917
- * - Ignores hidden directories (.git/, etc.)
918
- * - Ignores non-directory files
919
- * - Validates directory name matches skill name in SKILL.md
920
- *
921
- * @param skillsDirs - Array of directories containing skill subdirectories
922
- * @param allowedSkills - Optional set of skill names to include. If provided, only these skills are loaded.
923
- * @param requiredLabels - Optional set of labels. If provided, only skills that have at least one matching label are loaded.
924
- * @returns Load result with count, directories, and timestamp
925
- * @throws Error if first directory is invalid or any skill is invalid
926
- */
927
- async loadSkillsFromMultiple(skillsDirs, allowedSkills, requiredLabels) {
928
- this.skills.clear();
929
- this.skillsDir = "";
930
- this.skillsDirs = [];
931
- let totalLoaded = 0;
932
- for (let i = 0; i < skillsDirs.length; i++) {
933
- const skillsDir = skillsDirs[i];
934
- const isRequired = i === 0;
935
- totalLoaded += await this.loadSkillsFromDirectory(skillsDir, allowedSkills, isRequired, requiredLabels);
936
- }
937
- this.skillsDirs = skillsDirs;
938
- this.skillsDir = skillsDirs[0] || "";
939
- this.lastLoaded = /* @__PURE__ */ new Date();
940
- return {
941
- loaded: totalLoaded,
942
- skillsDir: this.skillsDirs.join(":"),
943
- timestamp: this.lastLoaded
944
- };
945
- }
946
- /**
947
- * Load skills from a single directory (internal helper)
948
- *
949
- * @param skillsDir - Directory containing skill subdirectories
950
- * @param allowedSkills - Optional set of skill names to include
951
- * @param isRequired - Whether this directory is required (first directory always is)
952
- * @param requiredLabels - Optional set of labels. If provided, only skills with at least one matching label are loaded.
953
- * @returns Number of skills loaded from this directory
954
- * @throws Error if directory is invalid and required
955
- */
956
- async loadSkillsFromDirectory(skillsDir, allowedSkills, isRequired = true, requiredLabels) {
957
- let stat;
958
- try {
959
- stat = await fs2.stat(skillsDir);
960
- } catch {
961
- if (isRequired) {
962
- throw new Error(`Skills directory does not exist: ${skillsDir}`);
963
- }
964
- return 0;
965
- }
966
- if (!stat.isDirectory()) {
967
- throw new Error(`Skills directory is not a directory: ${skillsDir}`);
968
- }
969
- const entries = await fs2.readdir(skillsDir, { withFileTypes: true });
970
- let loadedCount = 0;
971
- for (const entry of entries) {
972
- if (!entry.isDirectory()) {
973
- continue;
974
- }
975
- if (entry.name.startsWith(".")) {
976
- continue;
977
- }
978
- if (allowedSkills && !allowedSkills.has(entry.name)) {
979
- continue;
980
- }
981
- const skillDir = join(skillsDir, entry.name);
982
- const skillPath = join(skillDir, "SKILL.md");
983
- let skillStat;
984
- try {
985
- skillStat = await fs2.stat(skillPath);
986
- } catch {
987
- throw new Error(`Missing SKILL.md in: ${skillDir}`);
988
- }
989
- if (!skillStat.isFile()) {
990
- throw new Error(`Missing SKILL.md in: ${skillDir}`);
991
- }
992
- const parseResult = await parseSkill(skillPath);
993
- if (!parseResult.success) {
994
- throw new Error(`Failed to parse SKILL.md in ${skillDir}: ${parseResult.error.message}`);
995
- }
996
- const { skill } = parseResult;
997
- const validationResult = validateSkill(skill);
998
- if (!validationResult.valid) {
999
- const errorMessages = validationResult.errors.map((e) => e.message).join(", ");
1000
- const dirName2 = basename(skillDir);
1001
- const placeholder = makeInvalidSkillPlaceholder(dirName2, skillPath, errorMessages);
1002
- this.skills.set(dirName2, { skill: placeholder, sourcePath: skillPath });
1003
- loadedCount++;
1004
- continue;
1005
- }
1006
- const dirName = basename(skillDir);
1007
- if (skill.metadata.name !== dirName) {
1008
- throw new Error(`Directory name '${dirName}' does not match skill name '${skill.metadata.name}' in ${skillPath}`);
1009
- }
1010
- if (requiredLabels && requiredLabels.size > 0) {
1011
- const skillLabels = skill.metadata.labels;
1012
- if (!skillLabels || !skillLabels.some((label) => requiredLabels.has(label))) {
1013
- continue;
1014
- }
1015
- }
1016
- this.skills.set(skill.metadata.name, { skill, sourcePath: skillPath });
1017
- loadedCount++;
1018
- }
1019
- return loadedCount;
1020
- }
1021
- /**
1022
- * Load skills from a single directory with strict error handling
1023
- *
1024
- * Expected structure: <skillsDir>/<skill-name>/SKILL.md (exactly 2 levels deep)
1025
- * - Throws on any error (fail fast)
1026
- * - Ignores hidden directories (.git/, etc.)
1027
- * - Ignores non-directory files
1028
- * - Validates directory name matches skill name in SKILL.md
1029
- *
1030
- * @param skillsDir - Directory containing skill subdirectories
1031
- * @returns Load result with count, directory, and timestamp
1032
- * @throws Error if directory doesn't exist, isn't a directory, or any skill is invalid
1033
- */
1034
- async loadSkills(skillsDir) {
1035
- this.skills.clear();
1036
- this.skillsDir = "";
1037
- this.skillsDirs = [];
1038
- let stat;
1039
- try {
1040
- stat = await fs2.stat(skillsDir);
1041
- } catch {
1042
- throw new Error(`Skills directory does not exist: ${skillsDir}`);
1043
- }
1044
- if (!stat.isDirectory()) {
1045
- throw new Error(`Skills directory is not a directory: ${skillsDir}`);
1046
- }
1047
- const entries = await fs2.readdir(skillsDir, { withFileTypes: true });
1048
- let loadedCount = 0;
1049
- for (const entry of entries) {
1050
- if (!entry.isDirectory()) {
1051
- continue;
1052
- }
1053
- if (entry.name.startsWith(".")) {
1054
- continue;
1055
- }
1056
- const skillDir = join(skillsDir, entry.name);
1057
- const skillPath = join(skillDir, "SKILL.md");
1058
- let skillStat;
1059
- try {
1060
- skillStat = await fs2.stat(skillPath);
1061
- } catch {
1062
- throw new Error(`Missing SKILL.md in: ${skillDir}`);
1063
- }
1064
- if (!skillStat.isFile()) {
1065
- throw new Error(`Missing SKILL.md in: ${skillDir}`);
1066
- }
1067
- const parseResult = await parseSkill(skillPath);
1068
- if (!parseResult.success) {
1069
- throw new Error(`Failed to parse SKILL.md in ${skillDir}: ${parseResult.error.message}`);
1070
- }
1071
- const { skill } = parseResult;
1072
- const validationResult = validateSkill(skill);
1073
- if (!validationResult.valid) {
1074
- const errorMessages = validationResult.errors.map((e) => e.message).join(", ");
1075
- const dirName2 = basename(skillDir);
1076
- const placeholder = makeInvalidSkillPlaceholder(dirName2, skillPath, errorMessages);
1077
- this.skills.set(dirName2, { skill: placeholder, sourcePath: skillPath });
1078
- loadedCount++;
1079
- continue;
1080
- }
1081
- const dirName = basename(skillDir);
1082
- if (skill.metadata.name !== dirName) {
1083
- throw new Error(`Directory name '${dirName}' does not match skill name '${skill.metadata.name}' in ${skillPath}`);
1084
- }
1085
- this.skills.set(skill.metadata.name, { skill, sourcePath: skillPath });
1086
- loadedCount++;
1087
- }
1088
- this.skillsDir = skillsDir;
1089
- this.skillsDirs = [skillsDir];
1090
- this.lastLoaded = /* @__PURE__ */ new Date();
1091
- return {
1092
- loaded: loadedCount,
1093
- skillsDir,
1094
- timestamp: this.lastLoaded
1095
- };
1096
- }
1097
- /**
1098
- * Get a skill by name
1099
- *
1100
- * @param name - The skill name
1101
- * @returns The skill or undefined if not found
1102
- */
1103
- getSkill(name) {
1104
- const entry = this.skills.get(name);
1105
- if (!entry) {
1106
- return void 0;
1107
- }
1108
- return {
1109
- metadata: { ...entry.skill.metadata },
1110
- body: entry.skill.body
1111
- };
1112
- }
1113
- /**
1114
- * Get all loaded skills
1115
- *
1116
- * @returns Array of all skills
1117
- */
1118
- getAllSkills() {
1119
- return Array.from(this.skills.values()).map((entry) => ({
1120
- metadata: { ...entry.skill.metadata },
1121
- body: entry.skill.body
1122
- }));
1123
- }
1124
- /**
1125
- * Get skill metadata without body content
1126
- *
1127
- * @param name - The skill name
1128
- * @returns The skill metadata or undefined if not found
1129
- */
1130
- getSkillMetadata(name) {
1131
- const entry = this.skills.get(name);
1132
- if (!entry) {
1133
- return void 0;
1134
- }
1135
- return { ...entry.skill.metadata };
1136
- }
1137
- /**
1138
- * Get all skill metadata without body content
1139
- *
1140
- * @returns Array of all skill metadata
1141
- */
1142
- getAllMetadata() {
1143
- return Array.from(this.skills.values()).map((entry) => ({
1144
- ...entry.skill.metadata
1145
- }));
1146
- }
1147
- /**
1148
- * Get current registry state
1149
- *
1150
- * @returns Current state with counts and source info
1151
- */
1152
- getState() {
1153
- return {
1154
- skillCount: this.skills.size,
1155
- skillsDir: this.skillsDir,
1156
- lastLoaded: this.lastLoaded
1157
- };
1158
- }
1159
- /**
1160
- * Get the skills directory (base path for resolving relative references)
1161
- *
1162
- * @returns Absolute path to the skills directory, or empty string if no skills loaded
1163
- */
1164
- getSkillsDirectory() {
1165
- return this.skillsDir;
1166
- }
1167
- };
1168
-
1169
- // ../core/dist/package-config.js
1170
- import { promises as fs3 } from "fs";
1171
- import { join as join2 } from "path";
1172
- var PackageConfigManager = class {
1173
- projectRoot;
1174
- packageJsonPath;
1175
- constructor(projectRoot) {
1176
- if (!projectRoot) {
1177
- throw new Error("Project root directory is required");
1178
- }
1179
- this.projectRoot = projectRoot;
1180
- this.packageJsonPath = join2(projectRoot, "package.json");
1181
- }
1182
- /**
1183
- * Get default configuration with empty skills and standard defaults
1184
- */
1185
- getDefaultConfig() {
1186
- return {
1187
- skills: {},
1188
- config: {
1189
- skillsDirectory: ".agentskills/skills",
1190
- autoDiscover: [".claude/skills"],
1191
- maxSkillSize: 5e3,
1192
- logLevel: "info"
1193
- },
1194
- source: {
1195
- type: "defaults"
1196
- }
1197
- };
1198
- }
1199
- /**
1200
- * Load configuration from package.json
1201
- * Returns defaults if package.json doesn't exist
1202
- */
1203
- async loadConfig() {
1204
- try {
1205
- const content = await fs3.readFile(this.packageJsonPath, "utf-8");
1206
- let packageJson;
1207
- try {
1208
- packageJson = JSON.parse(content);
1209
- } catch (error) {
1210
- throw new Error(`Failed to parse package.json: ${error instanceof Error ? error.message : String(error)}`);
1211
- }
1212
- const skills = this.validateAndExtractSkills(packageJson);
1213
- const config = this.validateAndExtractConfig(packageJson);
1214
- return {
1215
- skills,
1216
- config,
1217
- source: {
1218
- type: "file",
1219
- path: this.packageJsonPath
1220
- }
1221
- };
1222
- } catch (error) {
1223
- if (error.code === "ENOENT") {
1224
- return this.getDefaultConfig();
1225
- }
1226
- if (error.code === "EACCES") {
1227
- throw new Error(`Permission denied reading package.json at ${this.packageJsonPath}`);
1228
- }
1229
- throw error;
1230
- }
1231
- }
1232
- /**
1233
- * Validate and extract skills from package.json
1234
- */
1235
- validateAndExtractSkills(packageJson) {
1236
- if (!packageJson.agentskills) {
1237
- return {};
1238
- }
1239
- const agentskills = packageJson.agentskills;
1240
- if (typeof agentskills !== "object" || agentskills === null || Array.isArray(agentskills)) {
1241
- throw new Error("agentskills must be an object");
1242
- }
1243
- for (const value of Object.values(agentskills)) {
1244
- if (typeof value !== "string") {
1245
- throw new Error("agentskills values must be strings");
1246
- }
1247
- }
1248
- return agentskills;
1249
- }
1250
- /**
1251
- * Validate and extract config from package.json
1252
- */
1253
- validateAndExtractConfig(packageJson) {
1254
- const defaultConfig = this.getDefaultConfig().config;
1255
- if (!packageJson.agentskillsConfig) {
1256
- return defaultConfig;
1257
- }
1258
- const agentskillsConfig = packageJson.agentskillsConfig;
1259
- if (typeof agentskillsConfig !== "object" || agentskillsConfig === null || Array.isArray(agentskillsConfig)) {
1260
- throw new Error("agentskillsConfig must be an object");
1261
- }
1262
- const configObj = agentskillsConfig;
1263
- const config = { ...defaultConfig };
1264
- if (configObj.skillsDirectory !== void 0) {
1265
- if (typeof configObj.skillsDirectory !== "string") {
1266
- throw new Error("skillsDirectory must be a string");
1267
- }
1268
- if (configObj.skillsDirectory === "") {
1269
- throw new Error("skillsDirectory cannot be empty");
1270
- }
1271
- config.skillsDirectory = configObj.skillsDirectory;
1272
- }
1273
- if (configObj.autoDiscover !== void 0) {
1274
- if (!Array.isArray(configObj.autoDiscover)) {
1275
- throw new Error("autoDiscover must be an array");
1276
- }
1277
- for (const item of configObj.autoDiscover) {
1278
- if (typeof item !== "string") {
1279
- throw new Error("autoDiscover must contain only strings");
1280
- }
1281
- }
1282
- config.autoDiscover = configObj.autoDiscover;
1283
- }
1284
- if (configObj.maxSkillSize !== void 0) {
1285
- if (typeof configObj.maxSkillSize !== "number") {
1286
- throw new Error("maxSkillSize must be a number");
1287
- }
1288
- if (configObj.maxSkillSize <= 0) {
1289
- throw new Error("maxSkillSize must be a positive number");
1290
- }
1291
- config.maxSkillSize = configObj.maxSkillSize;
1292
- }
1293
- if (configObj.logLevel !== void 0) {
1294
- if (typeof configObj.logLevel !== "string") {
1295
- throw new Error("logLevel must be a string");
1296
- }
1297
- const validLogLevels = ["error", "warn", "info", "debug"];
1298
- if (!validLogLevels.includes(configObj.logLevel)) {
1299
- throw new Error(`Invalid logLevel '${configObj.logLevel}'. Must be one of: error, warn, info, debug`);
1300
- }
1301
- config.logLevel = configObj.logLevel;
1302
- }
1303
- return config;
1304
- }
1305
- /**
1306
- * Save skills to package.json
1307
- * Creates package.json if it doesn't exist
1308
- * Preserves other fields
1309
- */
1310
- async saveSkills(skills) {
1311
- let packageJson;
1312
- try {
1313
- const content = await fs3.readFile(this.packageJsonPath, "utf-8");
1314
- packageJson = JSON.parse(content);
1315
- } catch (error) {
1316
- if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
1317
- packageJson = {
1318
- name: "agentskills-project"
1319
- };
1320
- } else {
1321
- throw error;
1322
- }
1323
- }
1324
- packageJson.agentskills = skills;
1325
- await fs3.writeFile(this.packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
1326
- }
1327
- /**
1328
- * Add a single skill to package.json
1329
- * Updates existing skill if name already exists
1330
- */
1331
- async addSkill(name, spec) {
1332
- if (!name) {
1333
- throw new Error("Skill name cannot be empty");
1334
- }
1335
- if (!spec) {
1336
- throw new Error("Skill spec cannot be empty");
1337
- }
1338
- let packageJson;
1339
- try {
1340
- const content = await fs3.readFile(this.packageJsonPath, "utf-8");
1341
- packageJson = JSON.parse(content);
1342
- } catch (error) {
1343
- if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
1344
- packageJson = {
1345
- name: "agentskills-project"
1346
- };
1347
- } else {
1348
- throw error;
1349
- }
1350
- }
1351
- if (!packageJson.agentskills) {
1352
- packageJson.agentskills = {};
1353
- }
1354
- const agentskills = packageJson.agentskills;
1355
- agentskills[name] = spec;
1356
- await fs3.writeFile(this.packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
1357
- }
1358
- /**
1359
- * Remove a skill from package.json
1360
- * Does not error if skill doesn't exist or file doesn't exist
1361
- */
1362
- async removeSkill(name) {
1363
- if (!name) {
1364
- throw new Error("Skill name cannot be empty");
1365
- }
1366
- try {
1367
- const content = await fs3.readFile(this.packageJsonPath, "utf-8");
1368
- const packageJson = JSON.parse(content);
1369
- if (!packageJson.agentskills) {
1370
- return;
1371
- }
1372
- delete packageJson.agentskills[name];
1373
- await fs3.writeFile(this.packageJsonPath, JSON.stringify(packageJson, null, 2), "utf-8");
1374
- } catch (error) {
1375
- if (error.code === "ENOENT") {
1376
- return;
1377
- }
1378
- throw error;
1379
- }
1380
- }
1381
- };
1382
-
1383
- // ../core/dist/skills-lock.js
1384
- import { promises as fs4 } from "fs";
1385
- import { join as join3 } from "path";
1386
- async function loadSkillsLock(lockFilePath) {
1387
- try {
1388
- const content = await fs4.readFile(lockFilePath, "utf-8");
1389
- const lock = JSON.parse(content);
1390
- return lock;
1391
- } catch (error) {
1392
- if (error.code === "ENOENT") {
1393
- return null;
1394
- }
1395
- throw error;
1396
- }
1397
- }
1398
- async function getAllowedSkills(lockFilePath) {
1399
- const lock = await loadSkillsLock(lockFilePath);
1400
- if (!lock) {
1401
- return void 0;
1402
- }
1403
- return new Set(Object.keys(lock.skills));
1404
- }
1405
- async function getAllowedSkillsFromProject(projectDir) {
1406
- const lockFilePath = join3(projectDir, "skills-lock.json");
1407
- return getAllowedSkills(lockFilePath);
1408
- }
1409
- async function getAllowedSkillsFromAgentskills(projectDir) {
1410
- const lockFilePath = join3(projectDir, "skills-lock.json");
1411
- return getAllowedSkills(lockFilePath);
1412
- }
1413
-
1414
- // ../core/dist/mcp-config-adapters.js
1415
- var StandardMcpConfigAdapter = class {
1416
- toStandard(clientConfig) {
1417
- const config = clientConfig;
1418
- if (!config.mcpServers) {
1419
- config.mcpServers = {};
1420
- }
1421
- return config;
1422
- }
1423
- toClient(mcpConfig) {
1424
- return mcpConfig;
1425
- }
1426
- };
1427
- var OpenCodeConfigAdapter = class {
1428
- toStandard(clientConfig) {
1429
- const config = clientConfig;
1430
- const mcpServers = {};
1431
- if (config.mcp) {
1432
- for (const [name, serverConfig] of Object.entries(config.mcp)) {
1433
- const server = serverConfig;
1434
- if (server.type === "local" && server.command) {
1435
- const [command, ...args] = server.command;
1436
- mcpServers[name] = {
1437
- command,
1438
- args,
1439
- env: server.environment || {}
1440
- };
1441
- }
1442
- }
1443
- }
1444
- return { mcpServers };
1445
- }
1446
- toClient(mcpConfig, existingConfig) {
1447
- const openCodeConfig = existingConfig || {
1448
- $schema: "https://opencode.ai/config.json"
1449
- };
1450
- openCodeConfig.permission = {
1451
- ...openCodeConfig.permission || {},
1452
- skill: "deny"
1453
- };
1454
- openCodeConfig.mcp = {};
1455
- for (const [name, serverConfig] of Object.entries(mcpConfig.mcpServers)) {
1456
- openCodeConfig.mcp[name] = {
1457
- type: "local",
1458
- command: [serverConfig.command, ...serverConfig.args || []],
1459
- enabled: true,
1460
- environment: serverConfig.env || {}
1461
- };
1462
- }
1463
- delete openCodeConfig.mcpServers;
1464
- return openCodeConfig;
1465
- }
1466
- };
1467
- var VsCodeConfigAdapter = class {
1468
- toStandard(clientConfig) {
1469
- const config = clientConfig;
1470
- const mcpServers = config.servers || {};
1471
- return { mcpServers };
1472
- }
1473
- toClient(mcpConfig, existingConfig) {
1474
- const vsCodeConfig = existingConfig || {
1475
- $schema: "https://opencode.ai/config.json"
1476
- };
1477
- return {
1478
- ...vsCodeConfig,
1479
- servers: mcpConfig.mcpServers
1480
- };
1481
- }
1482
- };
1483
- var McpConfigAdapterRegistry = class {
1484
- static adapters = /* @__PURE__ */ new Map();
1485
- static standardAdapter = new StandardMcpConfigAdapter();
1486
- /**
1487
- * Initialize the registry with default adapters
1488
- */
1489
- static initialize() {
1490
- this.register("opencode", new OpenCodeConfigAdapter());
1491
- this.register("github-copilot", new VsCodeConfigAdapter());
1492
- }
1493
- /**
1494
- * Register a custom adapter for a client type
1495
- */
1496
- static register(clientType, adapter) {
1497
- this.adapters.set(clientType, adapter);
1498
- }
1499
- /**
1500
- * Get the adapter for a client type
1501
- * Returns standard adapter if no custom adapter is registered
1502
- */
1503
- static getAdapter(clientType) {
1504
- return this.adapters.get(clientType) || this.standardAdapter;
1505
- }
1506
- /**
1507
- * Check if a client has a custom adapter
1508
- */
1509
- static hasCustomAdapter(clientType) {
1510
- return this.adapters.has(clientType);
1511
- }
1512
- };
1513
- McpConfigAdapterRegistry.initialize();
1514
-
1515
- export {
1516
- __commonJS,
1517
- __toESM,
1518
- ConfigGeneratorRegistry,
1519
- GitHubCopilotGenerator,
1520
- KiroGenerator,
1521
- OpenCodeMcpGenerator,
1522
- OpenCodeAgentGenerator,
1523
- VsCodeGenerator,
1524
- parseSkillContent,
1525
- parseSkill,
1526
- validateSkill,
1527
- SkillRegistry,
1528
- PackageConfigManager,
1529
- loadSkillsLock,
1530
- getAllowedSkills,
1531
- getAllowedSkillsFromProject,
1532
- getAllowedSkillsFromAgentskills,
1533
- StandardMcpConfigAdapter,
1534
- OpenCodeConfigAdapter,
1535
- VsCodeConfigAdapter,
1536
- McpConfigAdapterRegistry
1537
- };