skillpkg-mcp-server 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -89,7 +89,7 @@ Installs a skill from multiple sources:
89
89
  "source": "commit-helper", // Registry
90
90
  "source": "github:user/repo", // GitHub repo
91
91
  "source": "gist:abc123", // GitHub Gist
92
- "source": "https://example.com/skill.yaml", // URL
92
+ "source": "https://example.com/SKILL.md", // URL
93
93
  "source": "./my-skill", // Local path
94
94
  "scope": "local" // "local" | "global"
95
95
  }
package/dist/index.d.ts CHANGED
@@ -16,5 +16,5 @@
16
16
  export declare const VERSION = "0.1.0";
17
17
  export * from './types.js';
18
18
  export { SkillpkgMcpServer } from './server.js';
19
- export { createAllToolHandlers, createListSkillsHandler, createLoadSkillHandler, createSearchSkillsHandler, createInstallSkillHandler, createUninstallSkillHandler, createSkillInfoHandler, createRecommendSkillHandler, } from './tools/index.js';
19
+ export { createAllToolHandlers, createListSkillsHandler, createLoadSkillHandler, createSearchSkillsHandler, createInstallSkillHandler, createUninstallSkillHandler, createSyncSkillsHandler, createCreateSkillHandler, createSkillStatusHandler, createSkillInfoHandler, createRecommendSkillHandler, } from './tools/index.js';
20
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,OAAO,UAAU,CAAC;AAG/B,cAAc,YAAY,CAAC;AAG3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,OAAO,UAAU,CAAC;AAG/B,cAAc,YAAY,CAAC;AAG3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -19,5 +19,5 @@ export * from './types.js';
19
19
  // Server
20
20
  export { SkillpkgMcpServer } from './server.js';
21
21
  // Tool handlers
22
- export { createAllToolHandlers, createListSkillsHandler, createLoadSkillHandler, createSearchSkillsHandler, createInstallSkillHandler, createUninstallSkillHandler, createSkillInfoHandler, createRecommendSkillHandler, } from './tools/index.js';
22
+ export { createAllToolHandlers, createListSkillsHandler, createLoadSkillHandler, createSearchSkillsHandler, createInstallSkillHandler, createUninstallSkillHandler, createSyncSkillsHandler, createCreateSkillHandler, createSkillStatusHandler, createSkillInfoHandler, createRecommendSkillHandler, } from './tools/index.js';
23
23
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,QAAQ;AACR,cAAc,YAAY,CAAC;AAE3B,SAAS;AACT,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,gBAAgB;AAChB,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,QAAQ;AACR,cAAc,YAAY,CAAC;AAE3B,SAAS;AACT,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,gBAAgB;AAChB,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Tool: create_skill
3
+ *
4
+ * Creates a new skill with SKILL.md format.
5
+ * Useful for AI agents to help users create new skills.
6
+ */
7
+ import type { ToolHandler } from '../types.js';
8
+ export interface CreateSkillInput {
9
+ name: string;
10
+ description?: string;
11
+ instructions?: string;
12
+ }
13
+ export declare function createCreateSkillHandler(): ToolHandler;
14
+ //# sourceMappingURL=create-skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-skill.d.ts","sourceRoot":"","sources":["../../src/tools/create-skill.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,aAAa,CAAC;AAI3D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgCD,wBAAgB,wBAAwB,IAAI,WAAW,CA8EtD"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Tool: create_skill
3
+ *
4
+ * Creates a new skill with SKILL.md format.
5
+ * Useful for AI agents to help users create new skills.
6
+ */
7
+ import { successResult, errorResult, validateString } from './utils.js';
8
+ import { SkillCreator } from 'skillpkg-core';
9
+ /**
10
+ * Convert string to kebab-case
11
+ */
12
+ function toKebabCase(str) {
13
+ return str
14
+ .toLowerCase()
15
+ .replace(/[^a-z0-9]+/g, '-')
16
+ .replace(/^-|-$/g, '');
17
+ }
18
+ /**
19
+ * Validate skill name
20
+ */
21
+ function validateSkillName(name) {
22
+ if (!name) {
23
+ return 'Name is required';
24
+ }
25
+ const normalized = toKebabCase(name);
26
+ if (normalized.length < 2) {
27
+ return 'Name must be at least 2 characters';
28
+ }
29
+ if (normalized.length > 100) {
30
+ return 'Name must be less than 100 characters';
31
+ }
32
+ return null;
33
+ }
34
+ export function createCreateSkillHandler() {
35
+ return {
36
+ name: 'create_skill',
37
+ description: `Create a new skill with SKILL.md format.
38
+
39
+ This tool helps AI agents create new skills for users. It generates:
40
+ - A directory with the skill name
41
+ - A SKILL.md file with frontmatter and instructions
42
+
43
+ Parameters:
44
+ - name (required): Skill name (will be converted to kebab-case)
45
+ - description (optional): Short description of the skill
46
+ - instructions (optional): The skill instructions content
47
+
48
+ Returns the path to the created SKILL.md file.`,
49
+ inputSchema: {
50
+ type: 'object',
51
+ properties: {
52
+ name: {
53
+ type: 'string',
54
+ description: 'Skill name (e.g., "my-helper", "code-reviewer")',
55
+ },
56
+ description: {
57
+ type: 'string',
58
+ description: 'Short description of what the skill does',
59
+ },
60
+ instructions: {
61
+ type: 'string',
62
+ description: 'The full instructions content for the skill (markdown)',
63
+ },
64
+ },
65
+ required: ['name'],
66
+ },
67
+ async execute(args) {
68
+ const input = args;
69
+ try {
70
+ const rawName = validateString(input.name, 'name');
71
+ // Validate name
72
+ const nameError = validateSkillName(rawName);
73
+ if (nameError) {
74
+ return errorResult(nameError);
75
+ }
76
+ const skillName = toKebabCase(rawName);
77
+ const description = input.description || 'A helpful skill';
78
+ const instructions = input.instructions;
79
+ const creator = new SkillCreator();
80
+ // Create the skill
81
+ const skillMdPath = await creator.create({
82
+ name: skillName,
83
+ description,
84
+ instructions,
85
+ createDir: true,
86
+ });
87
+ const lines = [
88
+ `✅ Created skill: ${skillName}`,
89
+ '',
90
+ `📄 File: ${skillMdPath}`,
91
+ '',
92
+ '📋 Next steps:',
93
+ ` • Edit ${skillName}/SKILL.md to customize instructions`,
94
+ ` • Run \`skillpkg install ./${skillName}\` to install locally`,
95
+ ` • Run \`skillpkg sync\` to sync to AI platforms`,
96
+ ];
97
+ return successResult(lines.join('\n'));
98
+ }
99
+ catch (error) {
100
+ const message = error instanceof Error ? error.message : String(error);
101
+ return errorResult(`Failed to create skill: ${message}`);
102
+ }
103
+ },
104
+ };
105
+ }
106
+ //# sourceMappingURL=create-skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-skill.js","sourceRoot":"","sources":["../../src/tools/create-skill.ts"],"names":[],"mappings":"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"}
@@ -12,10 +12,13 @@ import { createInstallSkillHandler } from './install-skill.js';
12
12
  import { createUninstallSkillHandler } from './uninstall-skill.js';
13
13
  import { createSkillInfoHandler } from './skill-info.js';
14
14
  import { createRecommendSkillHandler } from './recommend-skill.js';
15
+ import { createSyncSkillsHandler } from './sync-skills.js';
16
+ import { createCreateSkillHandler } from './create-skill.js';
17
+ import { createSkillStatusHandler } from './skill-status.js';
15
18
  /**
16
19
  * Create all tool handlers
17
20
  */
18
21
  export declare function createAllToolHandlers(): ToolHandler[];
19
- export { createListSkillsHandler, createLoadSkillHandler, createSearchSkillsHandler, createInstallSkillHandler, createUninstallSkillHandler, createSkillInfoHandler, createRecommendSkillHandler, };
22
+ export { createListSkillsHandler, createLoadSkillHandler, createSearchSkillsHandler, createInstallSkillHandler, createUninstallSkillHandler, createSyncSkillsHandler, createCreateSkillHandler, createSkillStatusHandler, createSkillInfoHandler, createRecommendSkillHandler, };
20
23
  export * from './utils.js';
21
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAEnE;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,WAAW,EAAE,CAarD;AAGD,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,GAC5B,CAAC;AAGF,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAE7D;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,WAAW,EAAE,CAgBrD;AAGD,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,2BAA2B,GAC5B,CAAC;AAGF,cAAc,YAAY,CAAC"}
@@ -12,6 +12,9 @@ import { createInstallSkillHandler } from './install-skill.js';
12
12
  import { createUninstallSkillHandler } from './uninstall-skill.js';
13
13
  import { createSkillInfoHandler } from './skill-info.js';
14
14
  import { createRecommendSkillHandler } from './recommend-skill.js';
15
+ import { createSyncSkillsHandler } from './sync-skills.js';
16
+ import { createCreateSkillHandler } from './create-skill.js';
17
+ import { createSkillStatusHandler } from './skill-status.js';
15
18
  /**
16
19
  * Create all tool handlers
17
20
  */
@@ -22,6 +25,9 @@ export function createAllToolHandlers() {
22
25
  createLoadSkillHandler(),
23
26
  createInstallSkillHandler(),
24
27
  createUninstallSkillHandler(),
28
+ createSyncSkillsHandler(),
29
+ createCreateSkillHandler(),
30
+ createSkillStatusHandler(),
25
31
  // Search & Discovery
26
32
  createSearchSkillsHandler(),
27
33
  createSkillInfoHandler(),
@@ -29,7 +35,7 @@ export function createAllToolHandlers() {
29
35
  ];
30
36
  }
31
37
  // Export individual handlers for selective use
32
- export { createListSkillsHandler, createLoadSkillHandler, createSearchSkillsHandler, createInstallSkillHandler, createUninstallSkillHandler, createSkillInfoHandler, createRecommendSkillHandler, };
38
+ export { createListSkillsHandler, createLoadSkillHandler, createSearchSkillsHandler, createInstallSkillHandler, createUninstallSkillHandler, createSyncSkillsHandler, createCreateSkillHandler, createSkillStatusHandler, createSkillInfoHandler, createRecommendSkillHandler, };
33
39
  // Re-export utilities
34
40
  export * from './utils.js';
35
41
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,2BAA2B;AAC3B,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAEnE;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,wBAAwB;QACxB,uBAAuB,EAAE;QACzB,sBAAsB,EAAE;QACxB,yBAAyB,EAAE;QAC3B,2BAA2B,EAAE;QAE7B,qBAAqB;QACrB,yBAAyB,EAAE;QAC3B,sBAAsB,EAAE;QACxB,2BAA2B,EAAE;KAC9B,CAAC;AACJ,CAAC;AAED,+CAA+C;AAC/C,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,GAC5B,CAAC;AAEF,sBAAsB;AACtB,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,2BAA2B;AAC3B,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAE7D;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO;QACL,wBAAwB;QACxB,uBAAuB,EAAE;QACzB,sBAAsB,EAAE;QACxB,yBAAyB,EAAE;QAC3B,2BAA2B,EAAE;QAC7B,uBAAuB,EAAE;QACzB,wBAAwB,EAAE;QAC1B,wBAAwB,EAAE;QAE1B,qBAAqB;QACrB,yBAAyB,EAAE;QAC3B,sBAAsB,EAAE;QACxB,2BAA2B,EAAE;KAC9B,CAAC;AACJ,CAAC;AAED,+CAA+C;AAC/C,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,2BAA2B,GAC5B,CAAC;AAEF,sBAAsB;AACtB,cAAc,YAAY,CAAC"}
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Tool: install_skill
3
3
  *
4
- * Installs a skill from GitHub, Gist, URL, or local path.
5
- * Supports SKILL.md format (industry standard for Claude Code and OpenAI Codex).
4
+ * v2.0: Uses new Installer module with dependency resolution.
5
+ * Returns dependency info and MCP requirements.
6
6
  */
7
7
  import type { ToolHandler } from '../types.js';
8
8
  export declare function createInstallSkillHandler(): ToolHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"install-skill.d.ts","sourceRoot":"","sources":["../../src/tools/install-skill.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAiE,MAAM,aAAa,CAAC;AA4I9G,wBAAgB,yBAAyB,IAAI,WAAW,CAyHvD"}
1
+ {"version":3,"file":"install-skill.d.ts","sourceRoot":"","sources":["../../src/tools/install-skill.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAiC,MAAM,aAAa,CAAC;AAqN9E,wBAAgB,yBAAyB,IAAI,WAAW,CAyHvD"}
@@ -1,37 +1,29 @@
1
1
  /**
2
2
  * Tool: install_skill
3
3
  *
4
- * Installs a skill from GitHub, Gist, URL, or local path.
5
- * Supports SKILL.md format (industry standard for Claude Code and OpenAI Codex).
4
+ * v2.0: Uses new Installer module with dependency resolution.
5
+ * Returns dependency info and MCP requirements.
6
6
  */
7
7
  import { getStore, successResult, errorResult, validateString, validateScope } from './utils.js';
8
8
  import { InvalidSourceError } from '../types.js';
9
- import { parse as parseSkillYaml, detectSkillMd, fetchSkillMdContent } from 'skillpkg-core';
10
- /**
11
- * Parse source string to determine source type
12
- */
9
+ import matter from 'gray-matter';
10
+ import { detectSkillMd, fetchSkillMdContent, createInstaller, createStateManager, createConfigManager, } from 'skillpkg-core';
13
11
  function parseSource(source) {
14
- // GitHub: github:user/repo or user/repo
15
12
  if (source.startsWith('github:')) {
16
13
  return { type: 'github', value: source.slice(7) };
17
14
  }
18
15
  if (/^[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+$/.test(source)) {
19
16
  return { type: 'github', value: source };
20
17
  }
21
- // Gist: gist:id
22
18
  if (source.startsWith('gist:')) {
23
19
  return { type: 'gist', value: source.slice(5) };
24
20
  }
25
- // URL: https:// or http://
26
21
  if (source.startsWith('https://') || source.startsWith('http://')) {
27
22
  return { type: 'url', value: source };
28
23
  }
29
- // Local path: starts with ./ or / or contains path separators
30
24
  if (source.startsWith('./') || source.startsWith('/') || source.startsWith('../')) {
31
25
  return { type: 'local', value: source };
32
26
  }
33
- // Simple skill names are no longer supported (no central registry)
34
- // Suggest using github:owner/repo format instead
35
27
  throw new InvalidSourceError(`Invalid source "${source}". Use one of: github:owner/repo, gist:id, https://url, or ./local/path`);
36
28
  }
37
29
  /**
@@ -45,36 +37,25 @@ async function fetchSkillFromUrl(url) {
45
37
  return response.text();
46
38
  }
47
39
  /**
48
- * Fetch skill from GitHub repo (SKILL.md or skill.yaml)
49
- * Uses shared logic from skillpkg-core
40
+ * Fetch skill from GitHub repo
50
41
  */
51
42
  async function fetchSkillFromGitHub(repo) {
52
43
  const token = process.env.GITHUB_TOKEN;
53
- // Try SKILL.md first using core's detection
54
44
  const detection = await detectSkillMd(repo, token);
55
45
  if (detection.hasSkill && detection.skillFile) {
56
46
  const content = await fetchSkillMdContent(repo, detection.skillFile, token);
57
47
  if (content) {
58
- // Convert to skill.yaml format for compatibility
59
- return `schema: "1.0"\nname: ${content.name}\nversion: ${content.version}\ndescription: ${JSON.stringify(content.description)}\ninstructions: |\n${content.instructions.split('\n').map((l) => ' ' + l).join('\n')}`;
60
- }
61
- }
62
- // Fall back to skill.yaml
63
- const skillYamlPaths = ['skill.yaml', 'skill.yml', '.claude/skill.yaml'];
64
- const branches = ['main', 'master', 'HEAD'];
65
- for (const branch of branches) {
66
- for (const path of skillYamlPaths) {
67
- const url = `https://raw.githubusercontent.com/${repo}/${branch}/${path}`;
68
- try {
69
- const yamlContent = await fetchSkillFromUrl(url);
70
- return yamlContent;
71
- }
72
- catch {
73
- // Try next path/branch
74
- }
48
+ return {
49
+ schema: '1.0',
50
+ name: content.name,
51
+ version: content.version,
52
+ description: content.description,
53
+ instructions: content.instructions,
54
+ };
75
55
  }
76
56
  }
77
- throw new Error(`Could not find SKILL.md or skill.yaml in repository ${repo}`);
57
+ // No SKILL.md found in standard locations
58
+ return null;
78
59
  }
79
60
  /**
80
61
  * Fetch skill from Gist
@@ -86,13 +67,25 @@ async function fetchSkillFromGist(gistId) {
86
67
  throw new Error(`Failed to fetch gist ${gistId}: ${response.status}`);
87
68
  }
88
69
  const gist = (await response.json());
89
- // Look for skill.yaml or skill.yml
70
+ // Look for SKILL.md in Gist files
90
71
  for (const [filename, file] of Object.entries(gist.files)) {
91
- if (filename === 'skill.yaml' || filename === 'skill.yml') {
92
- return file.content;
72
+ if (filename === 'SKILL.md' || filename === 'skill.md') {
73
+ try {
74
+ const { data, content: body } = matter(file.content);
75
+ return {
76
+ schema: '1.0',
77
+ name: data.name || '',
78
+ version: data.version || '1.0.0',
79
+ description: data.description || '',
80
+ instructions: body.trim(),
81
+ };
82
+ }
83
+ catch {
84
+ // Invalid frontmatter
85
+ }
93
86
  }
94
87
  }
95
- throw new Error(`No skill.yaml found in gist ${gistId}`);
88
+ return null;
96
89
  }
97
90
  /**
98
91
  * Fetch skill from local path
@@ -101,40 +94,117 @@ async function fetchSkillFromLocal(path) {
101
94
  const fs = await import('fs/promises');
102
95
  const nodePath = await import('path');
103
96
  let skillPath = path;
104
- const stat = await fs.stat(path);
105
- if (stat.isDirectory()) {
106
- // Look for skill.yaml in directory
107
- const candidates = ['skill.yaml', 'skill.yml'];
108
- for (const candidate of candidates) {
109
- const fullPath = nodePath.join(path, candidate);
110
- try {
111
- await fs.access(fullPath);
112
- skillPath = fullPath;
113
- break;
97
+ try {
98
+ const stat = await fs.stat(path);
99
+ if (stat.isDirectory()) {
100
+ // Only SKILL.md format is supported
101
+ const candidates = ['SKILL.md', 'skill.md'];
102
+ for (const candidate of candidates) {
103
+ const fullPath = nodePath.join(path, candidate);
104
+ try {
105
+ await fs.access(fullPath);
106
+ skillPath = fullPath;
107
+ break;
108
+ }
109
+ catch {
110
+ // Try next
111
+ }
114
112
  }
115
- catch {
116
- // Try next
113
+ }
114
+ // Only process SKILL.md files
115
+ if (!skillPath.toLowerCase().endsWith('.md')) {
116
+ return null;
117
+ }
118
+ const content = await fs.readFile(skillPath, 'utf-8');
119
+ const { data, content: body } = matter(content);
120
+ return {
121
+ schema: '1.0',
122
+ name: data.name || '',
123
+ version: data.version || '1.0.0',
124
+ description: data.description || '',
125
+ instructions: body.trim(),
126
+ };
127
+ }
128
+ catch {
129
+ return null;
130
+ }
131
+ }
132
+ /**
133
+ * Create a SkillFetcherAdapter
134
+ */
135
+ function createFetcher() {
136
+ return {
137
+ async fetchMetadata(source) {
138
+ const skill = await fetchSkillBySource(source);
139
+ if (!skill)
140
+ return null;
141
+ return {
142
+ name: skill.name,
143
+ version: skill.version,
144
+ dependencies: skill.dependencies,
145
+ };
146
+ },
147
+ async fetchSkill(source) {
148
+ return fetchSkillBySource(source);
149
+ },
150
+ };
151
+ }
152
+ async function fetchSkillBySource(source) {
153
+ try {
154
+ const { type, value } = parseSource(source);
155
+ switch (type) {
156
+ case 'github':
157
+ return fetchSkillFromGitHub(value);
158
+ case 'gist':
159
+ return fetchSkillFromGist(value);
160
+ case 'url': {
161
+ const content = await fetchSkillFromUrl(value);
162
+ // Parse as SKILL.md format with gray-matter
163
+ try {
164
+ const { data, content: body } = matter(content);
165
+ return {
166
+ schema: '1.0',
167
+ name: data.name || '',
168
+ version: data.version || '1.0.0',
169
+ description: data.description || '',
170
+ instructions: body.trim(),
171
+ };
172
+ }
173
+ catch {
174
+ return null;
175
+ }
117
176
  }
177
+ case 'local':
178
+ return fetchSkillFromLocal(value);
118
179
  }
119
180
  }
120
- return fs.readFile(skillPath, 'utf-8');
181
+ catch {
182
+ return null;
183
+ }
121
184
  }
122
185
  export function createInstallSkillHandler() {
123
186
  return {
124
187
  name: 'install_skill',
125
- description: `Install a skill from various sources. Supports SKILL.md format (industry standard for Claude Code and OpenAI Codex).
188
+ description: `Install a skill from various sources with dependency resolution.
189
+
190
+ Supports SKILL.md format (industry standard for Claude Code and OpenAI Codex).
126
191
 
127
192
  Supported source formats:
128
193
  • GitHub: github:user/repo or user/repo (e.g., "anthropics/claude-code-skills")
129
194
  • Gist: gist:id (e.g., "gist:abc123")
130
- • URL: https://... (direct link to SKILL.md or skill.yaml)
131
- • Local: ./path or /absolute/path (local file or directory)`,
195
+ • URL: https://... (direct link to SKILL.md)
196
+ • Local: ./path or /absolute/path (local file or directory)
197
+
198
+ Returns:
199
+ • List of installed skills (including dependencies)
200
+ • MCP servers required by the skill
201
+ • Suggestions for next steps`,
132
202
  inputSchema: {
133
203
  type: 'object',
134
204
  properties: {
135
205
  source: {
136
206
  type: 'string',
137
- description: 'Source to install from: skill-name, github:user/repo, gist:id, URL, or local path',
207
+ description: 'Source to install from: github:user/repo, gist:id, URL, or local path',
138
208
  },
139
209
  scope: {
140
210
  type: 'string',
@@ -150,70 +220,63 @@ Supported source formats:
150
220
  try {
151
221
  const sourceStr = validateString(input.source, 'source');
152
222
  const scope = validateScope(input.scope, 'local');
153
- // Parse the source
223
+ // Normalize source
154
224
  const { type, value } = parseSource(sourceStr);
155
- // Fetch skill content based on source type
156
- let skillContent;
157
- switch (type) {
158
- case 'github':
159
- skillContent = await fetchSkillFromGitHub(value);
160
- break;
161
- case 'gist':
162
- skillContent = await fetchSkillFromGist(value);
163
- break;
164
- case 'url':
165
- skillContent = await fetchSkillFromUrl(value);
166
- break;
167
- case 'local':
168
- skillContent = await fetchSkillFromLocal(value);
169
- break;
225
+ const normalizedSource = type === 'github' ? `github:${value}` : sourceStr;
226
+ // Get project path (cwd for MCP server context)
227
+ const cwd = process.cwd();
228
+ // Create installer
229
+ const stateManager = createStateManager();
230
+ const configManager = createConfigManager();
231
+ const storeManager = getStore(scope);
232
+ const fetcher = createFetcher();
233
+ // Initialize store if needed
234
+ if (!(await storeManager.isInitialized())) {
235
+ await storeManager.init();
170
236
  }
171
- // Parse the skill content
172
- const parseResult = parseSkillYaml(skillContent);
173
- if (!parseResult.success || !parseResult.data) {
174
- const errors = parseResult.errors?.map((e) => e.message).join(', ') || 'Unknown parse error';
175
- return errorResult(`Invalid skill.yaml: ${errors}`);
237
+ const installer = createInstaller(stateManager, configManager, storeManager, fetcher);
238
+ // Run installation
239
+ const result = await installer.install(cwd, normalizedSource);
240
+ if (!result.success) {
241
+ const errors = result.errors.join('; ');
242
+ return errorResult(`Installation failed: ${errors}`);
176
243
  }
177
- const skill = parseResult.data;
178
- // Get the store and initialize if needed
179
- const store = getStore(scope);
180
- if (!(await store.isInitialized())) {
181
- await store.init();
244
+ // Build response
245
+ const installed = result.skills.filter((s) => s.action === 'installed');
246
+ const updated = result.skills.filter((s) => s.action === 'updated');
247
+ const skipped = result.skills.filter((s) => s.action === 'skipped');
248
+ const lines = [];
249
+ if (installed.length > 0) {
250
+ lines.push(`✅ Installed ${installed.length} skill(s):`);
251
+ for (const skill of installed) {
252
+ const note = skill.transitive ? ` (dependency of ${skill.requiredBy})` : '';
253
+ lines.push(` • ${skill.name} v${skill.version}${note}`);
254
+ }
182
255
  }
183
- // Check if already installed
184
- if (await store.hasSkill(skill.name)) {
185
- // Update instead of error
186
- await store.updateSkill(skill.name, skill);
187
- const output = {
188
- success: true,
189
- skill: {
190
- id: `${scope}:${skill.name}`,
191
- name: skill.name,
192
- version: skill.version,
193
- source: sourceStr,
194
- installedAt: new Date().toISOString(),
195
- },
196
- message: `Updated "${skill.name}" to v${skill.version} in ${scope} scope.`,
197
- };
198
- return successResult(output.message);
256
+ if (updated.length > 0) {
257
+ lines.push(`🔄 Updated ${updated.length} skill(s):`);
258
+ for (const skill of updated) {
259
+ lines.push(` • ${skill.name} v${skill.version}`);
260
+ }
199
261
  }
200
- // Add the skill
201
- await store.addSkill(skill, {
202
- source: type === 'local' ? 'local' : 'import',
203
- sourceUrl: sourceStr,
204
- });
205
- const output = {
206
- success: true,
207
- skill: {
208
- id: `${scope}:${skill.name}`,
209
- name: skill.name,
210
- version: skill.version,
211
- source: sourceStr,
212
- installedAt: new Date().toISOString(),
213
- },
214
- message: `Successfully installed "${skill.name}" v${skill.version} to ${scope} scope.`,
215
- };
216
- return successResult(output.message);
262
+ if (skipped.length > 0) {
263
+ lines.push(`⏭️ Skipped ${skipped.length} already installed skill(s)`);
264
+ }
265
+ // MCP requirements
266
+ if (result.mcpRequired.length > 0) {
267
+ lines.push('');
268
+ lines.push('⚠️ MCP servers required:');
269
+ for (const mcp of result.mcpRequired) {
270
+ lines.push(` • ${mcp}`);
271
+ }
272
+ lines.push(' Configure these in your skillpkg.json or install manually.');
273
+ }
274
+ // Next steps
275
+ lines.push('');
276
+ lines.push('📋 Next steps:');
277
+ lines.push(' • Run `skillpkg sync` to sync to AI platforms');
278
+ lines.push(' • Run `skillpkg tree` to see dependency tree');
279
+ return successResult(lines.join('\n'));
217
280
  }
218
281
  catch (error) {
219
282
  if (error instanceof InvalidSourceError) {