@skillsmith/mcp-server 0.1.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/dist/.tsbuildinfo +1 -0
- package/dist/src/__tests__/get-skill.test.d.ts +6 -0
- package/dist/src/__tests__/get-skill.test.d.ts.map +1 -0
- package/dist/src/__tests__/get-skill.test.js +88 -0
- package/dist/src/__tests__/get-skill.test.js.map +1 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.d.ts +7 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.d.ts.map +1 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.js +304 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.js.map +1 -0
- package/dist/src/__tests__/middleware/license.test.d.ts +7 -0
- package/dist/src/__tests__/middleware/license.test.d.ts.map +1 -0
- package/dist/src/__tests__/middleware/license.test.js +500 -0
- package/dist/src/__tests__/middleware/license.test.js.map +1 -0
- package/dist/src/__tests__/search.test.d.ts +6 -0
- package/dist/src/__tests__/search.test.d.ts.map +1 -0
- package/dist/src/__tests__/search.test.js +86 -0
- package/dist/src/__tests__/search.test.js.map +1 -0
- package/dist/src/__tests__/test-utils.d.ts +19 -0
- package/dist/src/__tests__/test-utils.d.ts.map +1 -0
- package/dist/src/__tests__/test-utils.js +87 -0
- package/dist/src/__tests__/test-utils.js.map +1 -0
- package/dist/src/context/index.d.ts +19 -0
- package/dist/src/context/index.d.ts.map +1 -0
- package/dist/src/context/index.js +25 -0
- package/dist/src/context/index.js.map +1 -0
- package/dist/src/context/project-detector.d.ts +145 -0
- package/dist/src/context/project-detector.d.ts.map +1 -0
- package/dist/src/context/project-detector.js +321 -0
- package/dist/src/context/project-detector.js.map +1 -0
- package/dist/src/context.d.ts +100 -0
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/context.js +157 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/core-shim.d.ts +7 -0
- package/dist/src/core-shim.d.ts.map +1 -0
- package/dist/src/core-shim.js +9 -0
- package/dist/src/core-shim.js.map +1 -0
- package/dist/src/health/healthCheck.d.ts +88 -0
- package/dist/src/health/healthCheck.d.ts.map +1 -0
- package/dist/src/health/healthCheck.js +117 -0
- package/dist/src/health/healthCheck.js.map +1 -0
- package/dist/src/health/index.d.ts +21 -0
- package/dist/src/health/index.d.ts.map +1 -0
- package/dist/src/health/index.js +21 -0
- package/dist/src/health/index.js.map +1 -0
- package/dist/src/health/readinessCheck.d.ts +139 -0
- package/dist/src/health/readinessCheck.d.ts.map +1 -0
- package/dist/src/health/readinessCheck.js +266 -0
- package/dist/src/health/readinessCheck.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +178 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/index.test.d.ts +2 -0
- package/dist/src/index.test.d.ts.map +1 -0
- package/dist/src/index.test.js +43 -0
- package/dist/src/index.test.js.map +1 -0
- package/dist/src/logger.d.ts +26 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +179 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/middleware/__tests__/csp.test.d.ts +2 -0
- package/dist/src/middleware/__tests__/csp.test.d.ts.map +1 -0
- package/dist/src/middleware/__tests__/csp.test.js +389 -0
- package/dist/src/middleware/__tests__/csp.test.js.map +1 -0
- package/dist/src/middleware/csp.d.ts +87 -0
- package/dist/src/middleware/csp.d.ts.map +1 -0
- package/dist/src/middleware/csp.js +273 -0
- package/dist/src/middleware/csp.js.map +1 -0
- package/dist/src/middleware/degradation.d.ts +99 -0
- package/dist/src/middleware/degradation.d.ts.map +1 -0
- package/dist/src/middleware/degradation.js +315 -0
- package/dist/src/middleware/degradation.js.map +1 -0
- package/dist/src/middleware/errorFormatter.d.ts +119 -0
- package/dist/src/middleware/errorFormatter.d.ts.map +1 -0
- package/dist/src/middleware/errorFormatter.js +294 -0
- package/dist/src/middleware/errorFormatter.js.map +1 -0
- package/dist/src/middleware/index.d.ts +10 -0
- package/dist/src/middleware/index.d.ts.map +1 -0
- package/dist/src/middleware/index.js +14 -0
- package/dist/src/middleware/index.js.map +1 -0
- package/dist/src/middleware/license.d.ts +161 -0
- package/dist/src/middleware/license.d.ts.map +1 -0
- package/dist/src/middleware/license.js +281 -0
- package/dist/src/middleware/license.js.map +1 -0
- package/dist/src/middleware/toolFeatureMapping.d.ts +36 -0
- package/dist/src/middleware/toolFeatureMapping.d.ts.map +1 -0
- package/dist/src/middleware/toolFeatureMapping.js +90 -0
- package/dist/src/middleware/toolFeatureMapping.js.map +1 -0
- package/dist/src/onboarding/first-run.d.ts +64 -0
- package/dist/src/onboarding/first-run.d.ts.map +1 -0
- package/dist/src/onboarding/first-run.js +77 -0
- package/dist/src/onboarding/first-run.js.map +1 -0
- package/dist/src/onboarding/index.d.ts +7 -0
- package/dist/src/onboarding/index.d.ts.map +1 -0
- package/dist/src/onboarding/index.js +7 -0
- package/dist/src/onboarding/index.js.map +1 -0
- package/dist/src/suggestions/index.d.ts +21 -0
- package/dist/src/suggestions/index.d.ts.map +1 -0
- package/dist/src/suggestions/index.js +20 -0
- package/dist/src/suggestions/index.js.map +1 -0
- package/dist/src/suggestions/suggestion-engine.d.ts +185 -0
- package/dist/src/suggestions/suggestion-engine.d.ts.map +1 -0
- package/dist/src/suggestions/suggestion-engine.js +352 -0
- package/dist/src/suggestions/suggestion-engine.js.map +1 -0
- package/dist/src/suggestions/types.d.ts +88 -0
- package/dist/src/suggestions/types.d.ts.map +1 -0
- package/dist/src/suggestions/types.js +21 -0
- package/dist/src/suggestions/types.js.map +1 -0
- package/dist/src/tools/analyze.d.ts +151 -0
- package/dist/src/tools/analyze.d.ts.map +1 -0
- package/dist/src/tools/analyze.js +205 -0
- package/dist/src/tools/analyze.js.map +1 -0
- package/dist/src/tools/compare.d.ts +149 -0
- package/dist/src/tools/compare.d.ts.map +1 -0
- package/dist/src/tools/compare.js +464 -0
- package/dist/src/tools/compare.js.map +1 -0
- package/dist/src/tools/get-skill.d.ts +116 -0
- package/dist/src/tools/get-skill.d.ts.map +1 -0
- package/dist/src/tools/get-skill.js +224 -0
- package/dist/src/tools/get-skill.js.map +1 -0
- package/dist/src/tools/index.d.ts +20 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +20 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/install.d.ts +122 -0
- package/dist/src/tools/install.d.ts.map +1 -0
- package/dist/src/tools/install.js +314 -0
- package/dist/src/tools/install.js.map +1 -0
- package/dist/src/tools/recommend.d.ts +171 -0
- package/dist/src/tools/recommend.d.ts.map +1 -0
- package/dist/src/tools/recommend.js +325 -0
- package/dist/src/tools/recommend.js.map +1 -0
- package/dist/src/tools/search.d.ts +121 -0
- package/dist/src/tools/search.d.ts.map +1 -0
- package/dist/src/tools/search.js +249 -0
- package/dist/src/tools/search.js.map +1 -0
- package/dist/src/tools/suggest.d.ts +181 -0
- package/dist/src/tools/suggest.d.ts.map +1 -0
- package/dist/src/tools/suggest.js +342 -0
- package/dist/src/tools/suggest.js.map +1 -0
- package/dist/src/tools/uninstall.d.ts +123 -0
- package/dist/src/tools/uninstall.d.ts.map +1 -0
- package/dist/src/tools/uninstall.js +250 -0
- package/dist/src/tools/uninstall.js.map +1 -0
- package/dist/src/tools/validate.d.ts +122 -0
- package/dist/src/tools/validate.d.ts.map +1 -0
- package/dist/src/tools/validate.js +497 -0
- package/dist/src/tools/validate.js.map +1 -0
- package/dist/src/utils/installed-skills.d.ts +101 -0
- package/dist/src/utils/installed-skills.d.ts.map +1 -0
- package/dist/src/utils/installed-skills.js +220 -0
- package/dist/src/utils/installed-skills.js.map +1 -0
- package/dist/src/utils/validation.d.ts +76 -0
- package/dist/src/utils/validation.d.ts.map +1 -0
- package/dist/src/utils/validation.js +153 -0
- package/dist/src/utils/validation.js.map +1 -0
- package/dist/src/webhooks/index.d.ts +8 -0
- package/dist/src/webhooks/index.d.ts.map +1 -0
- package/dist/src/webhooks/index.js +9 -0
- package/dist/src/webhooks/index.js.map +1 -0
- package/dist/src/webhooks/webhook-endpoint.d.ts +149 -0
- package/dist/src/webhooks/webhook-endpoint.d.ts.map +1 -0
- package/dist/src/webhooks/webhook-endpoint.js +339 -0
- package/dist/src/webhooks/webhook-endpoint.js.map +1 -0
- package/dist/tests/compare.test.d.ts +6 -0
- package/dist/tests/compare.test.d.ts.map +1 -0
- package/dist/tests/compare.test.js +225 -0
- package/dist/tests/compare.test.js.map +1 -0
- package/dist/tests/context/project-detector.test.d.ts +6 -0
- package/dist/tests/context/project-detector.test.d.ts.map +1 -0
- package/dist/tests/context/project-detector.test.js +719 -0
- package/dist/tests/context/project-detector.test.js.map +1 -0
- package/dist/tests/e2e/compare.e2e.test.d.ts +10 -0
- package/dist/tests/e2e/compare.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/compare.e2e.test.js +286 -0
- package/dist/tests/e2e/compare.e2e.test.js.map +1 -0
- package/dist/tests/e2e/install-flow.e2e.test.d.ts +10 -0
- package/dist/tests/e2e/install-flow.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/install-flow.e2e.test.js +209 -0
- package/dist/tests/e2e/install-flow.e2e.test.js.map +1 -0
- package/dist/tests/e2e/recommend.e2e.test.d.ts +12 -0
- package/dist/tests/e2e/recommend.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/recommend.e2e.test.js +347 -0
- package/dist/tests/e2e/recommend.e2e.test.js.map +1 -0
- package/dist/tests/e2e/skill-flow.e2e.test.d.ts +10 -0
- package/dist/tests/e2e/skill-flow.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/skill-flow.e2e.test.js +280 -0
- package/dist/tests/e2e/skill-flow.e2e.test.js.map +1 -0
- package/dist/tests/e2e/suggest.e2e.test.d.ts +13 -0
- package/dist/tests/e2e/suggest.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/suggest.e2e.test.js +347 -0
- package/dist/tests/e2e/suggest.e2e.test.js.map +1 -0
- package/dist/tests/e2e/utils/baseline-collector.d.ts +107 -0
- package/dist/tests/e2e/utils/baseline-collector.d.ts.map +1 -0
- package/dist/tests/e2e/utils/baseline-collector.js +211 -0
- package/dist/tests/e2e/utils/baseline-collector.js.map +1 -0
- package/dist/tests/e2e/utils/hardcoded-detector.d.ts +46 -0
- package/dist/tests/e2e/utils/hardcoded-detector.d.ts.map +1 -0
- package/dist/tests/e2e/utils/hardcoded-detector.js +255 -0
- package/dist/tests/e2e/utils/hardcoded-detector.js.map +1 -0
- package/dist/tests/e2e/utils/index.d.ts +7 -0
- package/dist/tests/e2e/utils/index.d.ts.map +1 -0
- package/dist/tests/e2e/utils/index.js +7 -0
- package/dist/tests/e2e/utils/index.js.map +1 -0
- package/dist/tests/e2e/utils/linear-reporter.d.ts +60 -0
- package/dist/tests/e2e/utils/linear-reporter.d.ts.map +1 -0
- package/dist/tests/e2e/utils/linear-reporter.js +232 -0
- package/dist/tests/e2e/utils/linear-reporter.js.map +1 -0
- package/dist/tests/health.test.d.ts +9 -0
- package/dist/tests/health.test.d.ts.map +1 -0
- package/dist/tests/health.test.js +308 -0
- package/dist/tests/health.test.js.map +1 -0
- package/dist/tests/integration/analyze.integration.test.d.ts +2 -0
- package/dist/tests/integration/analyze.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/analyze.integration.test.js +244 -0
- package/dist/tests/integration/analyze.integration.test.js.map +1 -0
- package/dist/tests/integration/compare.integration.test.d.ts +2 -0
- package/dist/tests/integration/compare.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/compare.integration.test.js +120 -0
- package/dist/tests/integration/compare.integration.test.js.map +1 -0
- package/dist/tests/integration/fixtures/test-skills.d.ts +62 -0
- package/dist/tests/integration/fixtures/test-skills.d.ts.map +1 -0
- package/dist/tests/integration/fixtures/test-skills.js +644 -0
- package/dist/tests/integration/fixtures/test-skills.js.map +1 -0
- package/dist/tests/integration/get-skill.integration.test.d.ts +6 -0
- package/dist/tests/integration/get-skill.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/get-skill.integration.test.js +203 -0
- package/dist/tests/integration/get-skill.integration.test.js.map +1 -0
- package/dist/tests/integration/github-api.integration.test.d.ts +14 -0
- package/dist/tests/integration/github-api.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/github-api.integration.test.js +190 -0
- package/dist/tests/integration/github-api.integration.test.js.map +1 -0
- package/dist/tests/integration/install.integration.test.d.ts +6 -0
- package/dist/tests/integration/install.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/install.integration.test.js +282 -0
- package/dist/tests/integration/install.integration.test.js.map +1 -0
- package/dist/tests/integration/recommend.integration.test.d.ts +2 -0
- package/dist/tests/integration/recommend.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/recommend.integration.test.js +215 -0
- package/dist/tests/integration/recommend.integration.test.js.map +1 -0
- package/dist/tests/integration/search.integration.test.d.ts +6 -0
- package/dist/tests/integration/search.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/search.integration.test.js +229 -0
- package/dist/tests/integration/search.integration.test.js.map +1 -0
- package/dist/tests/integration/setup.d.ts +71 -0
- package/dist/tests/integration/setup.d.ts.map +1 -0
- package/dist/tests/integration/setup.js +124 -0
- package/dist/tests/integration/setup.js.map +1 -0
- package/dist/tests/integration/uninstall.integration.test.d.ts +6 -0
- package/dist/tests/integration/uninstall.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/uninstall.integration.test.js +296 -0
- package/dist/tests/integration/uninstall.integration.test.js.map +1 -0
- package/dist/tests/integration/validate.integration.test.d.ts +2 -0
- package/dist/tests/integration/validate.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/validate.integration.test.js +181 -0
- package/dist/tests/integration/validate.integration.test.js.map +1 -0
- package/dist/tests/onboarding/first-run.test.d.ts +7 -0
- package/dist/tests/onboarding/first-run.test.d.ts.map +1 -0
- package/dist/tests/onboarding/first-run.test.js +258 -0
- package/dist/tests/onboarding/first-run.test.js.map +1 -0
- package/dist/tests/performance/search-performance.test.d.ts +10 -0
- package/dist/tests/performance/search-performance.test.d.ts.map +1 -0
- package/dist/tests/performance/search-performance.test.js +218 -0
- package/dist/tests/performance/search-performance.test.js.map +1 -0
- package/dist/tests/recommend.test.d.ts +6 -0
- package/dist/tests/recommend.test.d.ts.map +1 -0
- package/dist/tests/recommend.test.js +208 -0
- package/dist/tests/recommend.test.js.map +1 -0
- package/dist/tests/suggestions/suggestion-engine.test.d.ts +6 -0
- package/dist/tests/suggestions/suggestion-engine.test.d.ts.map +1 -0
- package/dist/tests/suggestions/suggestion-engine.test.js +448 -0
- package/dist/tests/suggestions/suggestion-engine.test.js.map +1 -0
- package/dist/tests/test-utils.d.ts +74 -0
- package/dist/tests/test-utils.d.ts.map +1 -0
- package/dist/tests/test-utils.js +98 -0
- package/dist/tests/test-utils.js.map +1 -0
- package/dist/tests/tools.test.d.ts +5 -0
- package/dist/tests/tools.test.d.ts.map +1 -0
- package/dist/tests/tools.test.js +138 -0
- package/dist/tests/tools.test.js.map +1 -0
- package/dist/tests/unit/installed-skills.test.d.ts +6 -0
- package/dist/tests/unit/installed-skills.test.d.ts.map +1 -0
- package/dist/tests/unit/installed-skills.test.js +285 -0
- package/dist/tests/unit/installed-skills.test.js.map +1 -0
- package/dist/tests/unit/logger.test.d.ts +6 -0
- package/dist/tests/unit/logger.test.d.ts.map +1 -0
- package/dist/tests/unit/logger.test.js +281 -0
- package/dist/tests/unit/logger.test.js.map +1 -0
- package/dist/tests/validate.test.d.ts +5 -0
- package/dist/tests/validate.test.d.ts.map +1 -0
- package/dist/tests/validate.test.js +303 -0
- package/dist/tests/validate.test.js.map +1 -0
- package/dist/tests/webhooks/proxy-trust.security.test.d.ts +8 -0
- package/dist/tests/webhooks/proxy-trust.security.test.d.ts.map +1 -0
- package/dist/tests/webhooks/proxy-trust.security.test.js +145 -0
- package/dist/tests/webhooks/proxy-trust.security.test.js.map +1 -0
- package/dist/tests/webhooks/rate-limiter.security.test.d.ts +8 -0
- package/dist/tests/webhooks/rate-limiter.security.test.d.ts.map +1 -0
- package/dist/tests/webhooks/rate-limiter.security.test.js +122 -0
- package/dist/tests/webhooks/rate-limiter.security.test.js.map +1 -0
- package/dist/vitest.config.d.ts +6 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +13 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview MCP Install Skill Tool for downloading and installing skills
|
|
3
|
+
* @module @skillsmith/mcp-server/tools/install
|
|
4
|
+
* @see {@link https://github.com/wrsmith108/skillsmith|Skillsmith Repository}
|
|
5
|
+
*
|
|
6
|
+
* Provides skill installation functionality with:
|
|
7
|
+
* - GitHub repository fetching (supports owner/repo and full URLs)
|
|
8
|
+
* - Automatic security scanning before installation
|
|
9
|
+
* - SKILL.md validation
|
|
10
|
+
* - Manifest tracking of installed skills
|
|
11
|
+
* - Optional file fetching (README.md, examples.md, config.json)
|
|
12
|
+
*
|
|
13
|
+
* Skills are installed to ~/.claude/skills/ and tracked in ~/.skillsmith/manifest.json
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Install from owner/repo format
|
|
17
|
+
* const result = await installSkill({ skillId: 'anthropic/commit' });
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Install from GitHub URL
|
|
21
|
+
* const result = await installSkill({
|
|
22
|
+
* skillId: 'https://github.com/user/repo/tree/main/skills/my-skill'
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Force reinstall with security scan skip
|
|
27
|
+
* const result = await installSkill({
|
|
28
|
+
* skillId: 'community/helper',
|
|
29
|
+
* force: true,
|
|
30
|
+
* skipScan: true // Not recommended
|
|
31
|
+
* });
|
|
32
|
+
*/
|
|
33
|
+
import { z } from 'zod';
|
|
34
|
+
import { SecurityScanner } from '@skillsmith/core';
|
|
35
|
+
import * as fs from 'fs/promises';
|
|
36
|
+
import * as path from 'path';
|
|
37
|
+
import * as os from 'os';
|
|
38
|
+
// Input schema
|
|
39
|
+
export const installInputSchema = z.object({
|
|
40
|
+
skillId: z.string().min(1).describe('Skill ID or GitHub URL'),
|
|
41
|
+
force: z.boolean().default(false).describe('Force reinstall if exists'),
|
|
42
|
+
skipScan: z.boolean().default(false).describe('Skip security scan (not recommended)'),
|
|
43
|
+
});
|
|
44
|
+
// Paths
|
|
45
|
+
const CLAUDE_SKILLS_DIR = path.join(os.homedir(), '.claude', 'skills');
|
|
46
|
+
const SKILLSMITH_DIR = path.join(os.homedir(), '.skillsmith');
|
|
47
|
+
const MANIFEST_PATH = path.join(SKILLSMITH_DIR, 'manifest.json');
|
|
48
|
+
/**
|
|
49
|
+
* Load or create manifest
|
|
50
|
+
*/
|
|
51
|
+
async function loadManifest() {
|
|
52
|
+
try {
|
|
53
|
+
const content = await fs.readFile(MANIFEST_PATH, 'utf-8');
|
|
54
|
+
return JSON.parse(content);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return {
|
|
58
|
+
version: '1.0.0',
|
|
59
|
+
installedSkills: {},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Save manifest
|
|
65
|
+
*/
|
|
66
|
+
async function saveManifest(manifest) {
|
|
67
|
+
await fs.mkdir(path.dirname(MANIFEST_PATH), { recursive: true });
|
|
68
|
+
await fs.writeFile(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse skill ID or URL to get components
|
|
72
|
+
*/
|
|
73
|
+
function parseSkillId(input) {
|
|
74
|
+
// Handle full GitHub URLs
|
|
75
|
+
if (input.startsWith('https://github.com/')) {
|
|
76
|
+
const url = new URL(input);
|
|
77
|
+
const parts = url.pathname.split('/').filter(Boolean);
|
|
78
|
+
return {
|
|
79
|
+
owner: parts[0],
|
|
80
|
+
repo: parts[1],
|
|
81
|
+
path: parts.slice(2).join('/') || '',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Handle owner/repo format
|
|
85
|
+
if (input.includes('/')) {
|
|
86
|
+
const [owner, ...rest] = input.split('/');
|
|
87
|
+
const repo = rest[0];
|
|
88
|
+
const skillPath = rest.slice(1).join('/');
|
|
89
|
+
return { owner, repo, path: skillPath };
|
|
90
|
+
}
|
|
91
|
+
// Handle skill ID from registry
|
|
92
|
+
throw new Error('Invalid skill ID format: ' + input + '. Use owner/repo or GitHub URL.');
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Fetch file from GitHub
|
|
96
|
+
*/
|
|
97
|
+
async function fetchFromGitHub(owner, repo, filePath) {
|
|
98
|
+
const url = 'https://raw.githubusercontent.com/' + owner + '/' + repo + '/main/' + filePath;
|
|
99
|
+
const response = await fetch(url);
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
// Try master branch
|
|
102
|
+
const masterUrl = 'https://raw.githubusercontent.com/' + owner + '/' + repo + '/master/' + filePath;
|
|
103
|
+
const masterResponse = await fetch(masterUrl);
|
|
104
|
+
if (!masterResponse.ok) {
|
|
105
|
+
throw new Error('Failed to fetch ' + filePath + ': ' + response.status);
|
|
106
|
+
}
|
|
107
|
+
return masterResponse.text();
|
|
108
|
+
}
|
|
109
|
+
return response.text();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Validate SKILL.md content
|
|
113
|
+
*/
|
|
114
|
+
function validateSkillMd(content) {
|
|
115
|
+
const errors = [];
|
|
116
|
+
// Check for required sections
|
|
117
|
+
if (!content.includes('# ')) {
|
|
118
|
+
errors.push('Missing title (# heading)');
|
|
119
|
+
}
|
|
120
|
+
// Check minimum length
|
|
121
|
+
if (content.length < 100) {
|
|
122
|
+
errors.push('SKILL.md is too short (minimum 100 characters)');
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
valid: errors.length === 0,
|
|
126
|
+
errors,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Generate post-install tips
|
|
131
|
+
*/
|
|
132
|
+
function generateTips(skillName) {
|
|
133
|
+
return [
|
|
134
|
+
'Skill "' + skillName + '" installed successfully!',
|
|
135
|
+
'To use this skill, mention it in Claude Code: "Use the ' + skillName + ' skill to..."',
|
|
136
|
+
'View installed skills: ls ~/.claude/skills/',
|
|
137
|
+
'To uninstall: use the uninstall_skill tool',
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Install a skill from GitHub to the local Claude Code skills directory.
|
|
142
|
+
*
|
|
143
|
+
* This function:
|
|
144
|
+
* 1. Parses the skill ID or GitHub URL
|
|
145
|
+
* 2. Checks if already installed (returns error unless force=true)
|
|
146
|
+
* 3. Fetches SKILL.md from GitHub (required)
|
|
147
|
+
* 4. Validates SKILL.md content
|
|
148
|
+
* 5. Runs security scan (unless skipScan=true)
|
|
149
|
+
* 6. Creates installation directory at ~/.claude/skills/{skillName}
|
|
150
|
+
* 7. Writes skill files
|
|
151
|
+
* 8. Updates manifest at ~/.skillsmith/manifest.json
|
|
152
|
+
*
|
|
153
|
+
* @param input - Installation parameters
|
|
154
|
+
* @param input.skillId - Skill ID (owner/repo) or full GitHub URL
|
|
155
|
+
* @param input.force - Force reinstall if skill already exists (default: false)
|
|
156
|
+
* @param input.skipScan - Skip security scan (default: false, not recommended)
|
|
157
|
+
* @returns Promise resolving to installation result with success status
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* // Successful installation
|
|
161
|
+
* const result = await installSkill({ skillId: 'anthropic/commit' });
|
|
162
|
+
* if (result.success) {
|
|
163
|
+
* console.log(`Installed to ${result.installPath}`);
|
|
164
|
+
* result.tips?.forEach(tip => console.log(tip));
|
|
165
|
+
* }
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* // Handle security scan failure
|
|
169
|
+
* const result = await installSkill({ skillId: 'untrusted/skill' });
|
|
170
|
+
* if (!result.success && result.securityReport) {
|
|
171
|
+
* console.log('Security issues found:');
|
|
172
|
+
* result.securityReport.findings.forEach(f =>
|
|
173
|
+
* console.log(` ${f.severity}: ${f.message}`)
|
|
174
|
+
* );
|
|
175
|
+
* }
|
|
176
|
+
*/
|
|
177
|
+
export async function installSkill(input, _context) {
|
|
178
|
+
const scanner = new SecurityScanner();
|
|
179
|
+
try {
|
|
180
|
+
// Parse skill ID
|
|
181
|
+
const { owner, repo, path: skillPath } = parseSkillId(input.skillId);
|
|
182
|
+
const skillName = skillPath ? path.basename(skillPath) : repo;
|
|
183
|
+
const installPath = path.join(CLAUDE_SKILLS_DIR, skillName);
|
|
184
|
+
// Check if already installed
|
|
185
|
+
const manifest = await loadManifest();
|
|
186
|
+
if (manifest.installedSkills[skillName] && !input.force) {
|
|
187
|
+
return {
|
|
188
|
+
success: false,
|
|
189
|
+
skillId: input.skillId,
|
|
190
|
+
installPath,
|
|
191
|
+
error: 'Skill "' + skillName + '" is already installed. Use force=true to reinstall.',
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// Determine files to fetch
|
|
195
|
+
const basePath = skillPath ? skillPath + '/' : '';
|
|
196
|
+
const skillMdPath = basePath + 'SKILL.md';
|
|
197
|
+
// Fetch SKILL.md (required)
|
|
198
|
+
let skillMdContent;
|
|
199
|
+
try {
|
|
200
|
+
skillMdContent = await fetchFromGitHub(owner, repo, skillMdPath);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return {
|
|
204
|
+
success: false,
|
|
205
|
+
skillId: input.skillId,
|
|
206
|
+
installPath,
|
|
207
|
+
error: 'Could not find SKILL.md at ' + skillMdPath + '. Skills must have a SKILL.md file.',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
// Validate SKILL.md
|
|
211
|
+
const validation = validateSkillMd(skillMdContent);
|
|
212
|
+
if (!validation.valid) {
|
|
213
|
+
return {
|
|
214
|
+
success: false,
|
|
215
|
+
skillId: input.skillId,
|
|
216
|
+
installPath,
|
|
217
|
+
error: 'Invalid SKILL.md: ' + validation.errors.join(', '),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
// Security scan
|
|
221
|
+
let securityReport;
|
|
222
|
+
if (!input.skipScan) {
|
|
223
|
+
securityReport = scanner.scan(input.skillId, skillMdContent);
|
|
224
|
+
if (!securityReport.passed) {
|
|
225
|
+
const criticalFindings = securityReport.findings.filter((f) => f.severity === 'critical' || f.severity === 'high');
|
|
226
|
+
return {
|
|
227
|
+
success: false,
|
|
228
|
+
skillId: input.skillId,
|
|
229
|
+
installPath,
|
|
230
|
+
securityReport,
|
|
231
|
+
error: 'Security scan failed with ' +
|
|
232
|
+
criticalFindings.length +
|
|
233
|
+
' critical/high findings. Use skipScan=true to override (not recommended).',
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Create installation directory
|
|
238
|
+
await fs.mkdir(installPath, { recursive: true });
|
|
239
|
+
// Write SKILL.md
|
|
240
|
+
await fs.writeFile(path.join(installPath, 'SKILL.md'), skillMdContent);
|
|
241
|
+
// Try to fetch optional files
|
|
242
|
+
const optionalFiles = ['README.md', 'examples.md', 'config.json'];
|
|
243
|
+
for (const file of optionalFiles) {
|
|
244
|
+
try {
|
|
245
|
+
const content = await fetchFromGitHub(owner, repo, basePath + file);
|
|
246
|
+
// Scan optional files too
|
|
247
|
+
if (!input.skipScan) {
|
|
248
|
+
const fileScan = scanner.scan(input.skillId + '/' + file, content);
|
|
249
|
+
if (!fileScan.passed) {
|
|
250
|
+
console.warn('Skipping ' + file + ' due to security findings');
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
await fs.writeFile(path.join(installPath, file), content);
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
// Optional files are fine to skip
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Update manifest
|
|
261
|
+
manifest.installedSkills[skillName] = {
|
|
262
|
+
id: input.skillId,
|
|
263
|
+
name: skillName,
|
|
264
|
+
version: '1.0.0',
|
|
265
|
+
source: 'github:' + owner + '/' + repo,
|
|
266
|
+
installPath,
|
|
267
|
+
installedAt: new Date().toISOString(),
|
|
268
|
+
lastUpdated: new Date().toISOString(),
|
|
269
|
+
};
|
|
270
|
+
await saveManifest(manifest);
|
|
271
|
+
return {
|
|
272
|
+
success: true,
|
|
273
|
+
skillId: input.skillId,
|
|
274
|
+
installPath,
|
|
275
|
+
securityReport,
|
|
276
|
+
tips: generateTips(skillName),
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
return {
|
|
281
|
+
success: false,
|
|
282
|
+
skillId: input.skillId,
|
|
283
|
+
installPath: '',
|
|
284
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* MCP tool definition
|
|
290
|
+
*/
|
|
291
|
+
export const installTool = {
|
|
292
|
+
name: 'install_skill',
|
|
293
|
+
description: 'Install a Claude Code skill from GitHub. Performs security scan before installation.',
|
|
294
|
+
inputSchema: {
|
|
295
|
+
type: 'object',
|
|
296
|
+
properties: {
|
|
297
|
+
skillId: {
|
|
298
|
+
type: 'string',
|
|
299
|
+
description: 'Skill ID (owner/repo/skill) or GitHub URL',
|
|
300
|
+
},
|
|
301
|
+
force: {
|
|
302
|
+
type: 'boolean',
|
|
303
|
+
description: 'Force reinstall if skill already exists',
|
|
304
|
+
},
|
|
305
|
+
skipScan: {
|
|
306
|
+
type: 'boolean',
|
|
307
|
+
description: 'Skip security scan (not recommended)',
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
required: ['skillId'],
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
export default installTool;
|
|
314
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/tools/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview MCP Skill Recommend Tool for suggesting relevant skills
|
|
3
|
+
* @module @skillsmith/mcp-server/tools/recommend
|
|
4
|
+
* @see SMI-741: Add MCP Tool skill_recommend
|
|
5
|
+
* @see SMI-602: Integrate semantic matching with EmbeddingService
|
|
6
|
+
* @see SMI-604: Add trigger phrase overlap detection
|
|
7
|
+
*
|
|
8
|
+
* Provides skill recommendations based on:
|
|
9
|
+
* - Currently installed skills (semantic similarity)
|
|
10
|
+
* - Optional project context (semantic matching)
|
|
11
|
+
* - Codebase analysis (framework detection)
|
|
12
|
+
* - Overlap detection (avoid similar skills)
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Basic recommendation
|
|
16
|
+
* const results = await executeRecommend({
|
|
17
|
+
* installed_skills: ['anthropic/commit'],
|
|
18
|
+
* limit: 5
|
|
19
|
+
* }, toolContext);
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Recommendation with project context
|
|
23
|
+
* const results = await executeRecommend({
|
|
24
|
+
* installed_skills: ['anthropic/commit'],
|
|
25
|
+
* project_context: 'React frontend with Jest testing',
|
|
26
|
+
* limit: 10
|
|
27
|
+
* }, toolContext);
|
|
28
|
+
*/
|
|
29
|
+
import { z } from 'zod';
|
|
30
|
+
import { type MCPTrustTier as TrustTier } from '@skillsmith/core';
|
|
31
|
+
import type { ToolContext } from '../context.js';
|
|
32
|
+
/**
|
|
33
|
+
* Zod schema for recommend tool input validation
|
|
34
|
+
*/
|
|
35
|
+
export declare const recommendInputSchema: z.ZodObject<{
|
|
36
|
+
/** Currently installed skill IDs */
|
|
37
|
+
installed_skills: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
38
|
+
/** Optional project description for context-aware recommendations */
|
|
39
|
+
project_context: z.ZodOptional<z.ZodString>;
|
|
40
|
+
/** Maximum recommendations to return (default 5) */
|
|
41
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
42
|
+
/** Enable overlap detection (default true) */
|
|
43
|
+
detect_overlap: z.ZodDefault<z.ZodBoolean>;
|
|
44
|
+
/** Minimum similarity threshold (0-1, default 0.3) */
|
|
45
|
+
min_similarity: z.ZodDefault<z.ZodNumber>;
|
|
46
|
+
}, "strip", z.ZodTypeAny, {
|
|
47
|
+
installed_skills: string[];
|
|
48
|
+
limit: number;
|
|
49
|
+
detect_overlap: boolean;
|
|
50
|
+
min_similarity: number;
|
|
51
|
+
project_context?: string | undefined;
|
|
52
|
+
}, {
|
|
53
|
+
installed_skills?: string[] | undefined;
|
|
54
|
+
project_context?: string | undefined;
|
|
55
|
+
limit?: number | undefined;
|
|
56
|
+
detect_overlap?: boolean | undefined;
|
|
57
|
+
min_similarity?: number | undefined;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* Input type (before parsing, allows optional fields)
|
|
61
|
+
*/
|
|
62
|
+
export type RecommendInput = z.input<typeof recommendInputSchema>;
|
|
63
|
+
/**
|
|
64
|
+
* Individual skill recommendation with reasoning
|
|
65
|
+
*/
|
|
66
|
+
export interface SkillRecommendation {
|
|
67
|
+
/** Skill identifier */
|
|
68
|
+
skill_id: string;
|
|
69
|
+
/** Skill name */
|
|
70
|
+
name: string;
|
|
71
|
+
/** Why this skill is recommended */
|
|
72
|
+
reason: string;
|
|
73
|
+
/** Semantic similarity score (0-1) */
|
|
74
|
+
similarity_score: number;
|
|
75
|
+
/** Trust tier for user confidence */
|
|
76
|
+
trust_tier: TrustTier;
|
|
77
|
+
/** Overall quality score */
|
|
78
|
+
quality_score: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Recommendation response with timing info
|
|
82
|
+
*/
|
|
83
|
+
export interface RecommendResponse {
|
|
84
|
+
/** List of recommended skills */
|
|
85
|
+
recommendations: SkillRecommendation[];
|
|
86
|
+
/** Total candidates considered */
|
|
87
|
+
candidates_considered: number;
|
|
88
|
+
/** Skills filtered due to overlap */
|
|
89
|
+
overlap_filtered: number;
|
|
90
|
+
/** Query context used for matching */
|
|
91
|
+
context: {
|
|
92
|
+
installed_count: number;
|
|
93
|
+
has_project_context: boolean;
|
|
94
|
+
using_semantic_matching: boolean;
|
|
95
|
+
/** SMI-906: Whether installed skills were auto-detected from ~/.claude/skills/ */
|
|
96
|
+
auto_detected: boolean;
|
|
97
|
+
};
|
|
98
|
+
/** Performance timing */
|
|
99
|
+
timing: {
|
|
100
|
+
totalMs: number;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* MCP tool schema definition for skill_recommend
|
|
105
|
+
*/
|
|
106
|
+
export declare const recommendToolSchema: {
|
|
107
|
+
name: string;
|
|
108
|
+
description: string;
|
|
109
|
+
inputSchema: {
|
|
110
|
+
type: "object";
|
|
111
|
+
properties: {
|
|
112
|
+
installed_skills: {
|
|
113
|
+
type: string;
|
|
114
|
+
items: {
|
|
115
|
+
type: string;
|
|
116
|
+
};
|
|
117
|
+
description: string;
|
|
118
|
+
};
|
|
119
|
+
project_context: {
|
|
120
|
+
type: string;
|
|
121
|
+
description: string;
|
|
122
|
+
};
|
|
123
|
+
limit: {
|
|
124
|
+
type: string;
|
|
125
|
+
description: string;
|
|
126
|
+
minimum: number;
|
|
127
|
+
maximum: number;
|
|
128
|
+
default: number;
|
|
129
|
+
};
|
|
130
|
+
detect_overlap: {
|
|
131
|
+
type: string;
|
|
132
|
+
description: string;
|
|
133
|
+
default: boolean;
|
|
134
|
+
};
|
|
135
|
+
min_similarity: {
|
|
136
|
+
type: string;
|
|
137
|
+
description: string;
|
|
138
|
+
minimum: number;
|
|
139
|
+
maximum: number;
|
|
140
|
+
default: number;
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
required: never[];
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Execute skill recommendation based on installed skills and context.
|
|
148
|
+
*
|
|
149
|
+
* Uses semantic similarity to find skills that complement the user's
|
|
150
|
+
* current installation. When project context is provided, it's used
|
|
151
|
+
* to improve recommendation relevance. Overlap detection prevents
|
|
152
|
+
* recommending skills that are too similar to installed ones.
|
|
153
|
+
*
|
|
154
|
+
* @param input - Recommendation parameters
|
|
155
|
+
* @returns Promise resolving to recommendation response
|
|
156
|
+
* @throws {SkillsmithError} When validation fails
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* const response = await executeRecommend({
|
|
160
|
+
* installed_skills: ['anthropic/commit'],
|
|
161
|
+
* project_context: 'React TypeScript frontend',
|
|
162
|
+
* limit: 5
|
|
163
|
+
* }, toolContext);
|
|
164
|
+
* console.log(response.recommendations[0].reason);
|
|
165
|
+
*/
|
|
166
|
+
export declare function executeRecommend(input: RecommendInput, context: ToolContext): Promise<RecommendResponse>;
|
|
167
|
+
/**
|
|
168
|
+
* Format recommendations for terminal display
|
|
169
|
+
*/
|
|
170
|
+
export declare function formatRecommendations(response: RecommendResponse): string;
|
|
171
|
+
//# sourceMappingURL=recommend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recommend.d.ts","sourceRoot":"","sources":["../../../src/tools/recommend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,KAAK,YAAY,IAAI,SAAS,EAAiC,MAAM,kBAAkB,CAAA;AAChG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAGhD;;GAEG;AACH,eAAO,MAAM,oBAAoB;IAC/B,oCAAoC;;IAEpC,qEAAqE;;IAErE,oDAAoD;;IAEpD,8CAA8C;;IAE9C,sDAAsD;;;;;;;;;;;;;;EAEtD,CAAA;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAEjE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,sCAAsC;IACtC,gBAAgB,EAAE,MAAM,CAAA;IACxB,qCAAqC;IACrC,UAAU,EAAE,SAAS,CAAA;IACrB,4BAA4B;IAC5B,aAAa,EAAE,MAAM,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,eAAe,EAAE,mBAAmB,EAAE,CAAA;IACtC,kCAAkC;IAClC,qBAAqB,EAAE,MAAM,CAAA;IAC7B,qCAAqC;IACrC,gBAAgB,EAAE,MAAM,CAAA;IACxB,sCAAsC;IACtC,OAAO,EAAE;QACP,eAAe,EAAE,MAAM,CAAA;QACvB,mBAAmB,EAAE,OAAO,CAAA;QAC5B,uBAAuB,EAAE,OAAO,CAAA;QAChC,kFAAkF;QAClF,aAAa,EAAE,OAAO,CAAA;KACvB,CAAA;IACD,yBAAyB;IACzB,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;CACF;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwC/B,CAAA;AAkFD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,iBAAiB,CAAC,CA4I5B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CA4CzE"}
|