@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.
Files changed (306) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/src/__tests__/get-skill.test.d.ts +6 -0
  3. package/dist/src/__tests__/get-skill.test.d.ts.map +1 -0
  4. package/dist/src/__tests__/get-skill.test.js +88 -0
  5. package/dist/src/__tests__/get-skill.test.js.map +1 -0
  6. package/dist/src/__tests__/middleware/errorFormatter.test.d.ts +7 -0
  7. package/dist/src/__tests__/middleware/errorFormatter.test.d.ts.map +1 -0
  8. package/dist/src/__tests__/middleware/errorFormatter.test.js +304 -0
  9. package/dist/src/__tests__/middleware/errorFormatter.test.js.map +1 -0
  10. package/dist/src/__tests__/middleware/license.test.d.ts +7 -0
  11. package/dist/src/__tests__/middleware/license.test.d.ts.map +1 -0
  12. package/dist/src/__tests__/middleware/license.test.js +500 -0
  13. package/dist/src/__tests__/middleware/license.test.js.map +1 -0
  14. package/dist/src/__tests__/search.test.d.ts +6 -0
  15. package/dist/src/__tests__/search.test.d.ts.map +1 -0
  16. package/dist/src/__tests__/search.test.js +86 -0
  17. package/dist/src/__tests__/search.test.js.map +1 -0
  18. package/dist/src/__tests__/test-utils.d.ts +19 -0
  19. package/dist/src/__tests__/test-utils.d.ts.map +1 -0
  20. package/dist/src/__tests__/test-utils.js +87 -0
  21. package/dist/src/__tests__/test-utils.js.map +1 -0
  22. package/dist/src/context/index.d.ts +19 -0
  23. package/dist/src/context/index.d.ts.map +1 -0
  24. package/dist/src/context/index.js +25 -0
  25. package/dist/src/context/index.js.map +1 -0
  26. package/dist/src/context/project-detector.d.ts +145 -0
  27. package/dist/src/context/project-detector.d.ts.map +1 -0
  28. package/dist/src/context/project-detector.js +321 -0
  29. package/dist/src/context/project-detector.js.map +1 -0
  30. package/dist/src/context.d.ts +100 -0
  31. package/dist/src/context.d.ts.map +1 -0
  32. package/dist/src/context.js +157 -0
  33. package/dist/src/context.js.map +1 -0
  34. package/dist/src/core-shim.d.ts +7 -0
  35. package/dist/src/core-shim.d.ts.map +1 -0
  36. package/dist/src/core-shim.js +9 -0
  37. package/dist/src/core-shim.js.map +1 -0
  38. package/dist/src/health/healthCheck.d.ts +88 -0
  39. package/dist/src/health/healthCheck.d.ts.map +1 -0
  40. package/dist/src/health/healthCheck.js +117 -0
  41. package/dist/src/health/healthCheck.js.map +1 -0
  42. package/dist/src/health/index.d.ts +21 -0
  43. package/dist/src/health/index.d.ts.map +1 -0
  44. package/dist/src/health/index.js +21 -0
  45. package/dist/src/health/index.js.map +1 -0
  46. package/dist/src/health/readinessCheck.d.ts +139 -0
  47. package/dist/src/health/readinessCheck.d.ts.map +1 -0
  48. package/dist/src/health/readinessCheck.js +266 -0
  49. package/dist/src/health/readinessCheck.js.map +1 -0
  50. package/dist/src/index.d.ts +8 -0
  51. package/dist/src/index.d.ts.map +1 -0
  52. package/dist/src/index.js +178 -0
  53. package/dist/src/index.js.map +1 -0
  54. package/dist/src/index.test.d.ts +2 -0
  55. package/dist/src/index.test.d.ts.map +1 -0
  56. package/dist/src/index.test.js +43 -0
  57. package/dist/src/index.test.js.map +1 -0
  58. package/dist/src/logger.d.ts +26 -0
  59. package/dist/src/logger.d.ts.map +1 -0
  60. package/dist/src/logger.js +179 -0
  61. package/dist/src/logger.js.map +1 -0
  62. package/dist/src/middleware/__tests__/csp.test.d.ts +2 -0
  63. package/dist/src/middleware/__tests__/csp.test.d.ts.map +1 -0
  64. package/dist/src/middleware/__tests__/csp.test.js +389 -0
  65. package/dist/src/middleware/__tests__/csp.test.js.map +1 -0
  66. package/dist/src/middleware/csp.d.ts +87 -0
  67. package/dist/src/middleware/csp.d.ts.map +1 -0
  68. package/dist/src/middleware/csp.js +273 -0
  69. package/dist/src/middleware/csp.js.map +1 -0
  70. package/dist/src/middleware/degradation.d.ts +99 -0
  71. package/dist/src/middleware/degradation.d.ts.map +1 -0
  72. package/dist/src/middleware/degradation.js +315 -0
  73. package/dist/src/middleware/degradation.js.map +1 -0
  74. package/dist/src/middleware/errorFormatter.d.ts +119 -0
  75. package/dist/src/middleware/errorFormatter.d.ts.map +1 -0
  76. package/dist/src/middleware/errorFormatter.js +294 -0
  77. package/dist/src/middleware/errorFormatter.js.map +1 -0
  78. package/dist/src/middleware/index.d.ts +10 -0
  79. package/dist/src/middleware/index.d.ts.map +1 -0
  80. package/dist/src/middleware/index.js +14 -0
  81. package/dist/src/middleware/index.js.map +1 -0
  82. package/dist/src/middleware/license.d.ts +161 -0
  83. package/dist/src/middleware/license.d.ts.map +1 -0
  84. package/dist/src/middleware/license.js +281 -0
  85. package/dist/src/middleware/license.js.map +1 -0
  86. package/dist/src/middleware/toolFeatureMapping.d.ts +36 -0
  87. package/dist/src/middleware/toolFeatureMapping.d.ts.map +1 -0
  88. package/dist/src/middleware/toolFeatureMapping.js +90 -0
  89. package/dist/src/middleware/toolFeatureMapping.js.map +1 -0
  90. package/dist/src/onboarding/first-run.d.ts +64 -0
  91. package/dist/src/onboarding/first-run.d.ts.map +1 -0
  92. package/dist/src/onboarding/first-run.js +77 -0
  93. package/dist/src/onboarding/first-run.js.map +1 -0
  94. package/dist/src/onboarding/index.d.ts +7 -0
  95. package/dist/src/onboarding/index.d.ts.map +1 -0
  96. package/dist/src/onboarding/index.js +7 -0
  97. package/dist/src/onboarding/index.js.map +1 -0
  98. package/dist/src/suggestions/index.d.ts +21 -0
  99. package/dist/src/suggestions/index.d.ts.map +1 -0
  100. package/dist/src/suggestions/index.js +20 -0
  101. package/dist/src/suggestions/index.js.map +1 -0
  102. package/dist/src/suggestions/suggestion-engine.d.ts +185 -0
  103. package/dist/src/suggestions/suggestion-engine.d.ts.map +1 -0
  104. package/dist/src/suggestions/suggestion-engine.js +352 -0
  105. package/dist/src/suggestions/suggestion-engine.js.map +1 -0
  106. package/dist/src/suggestions/types.d.ts +88 -0
  107. package/dist/src/suggestions/types.d.ts.map +1 -0
  108. package/dist/src/suggestions/types.js +21 -0
  109. package/dist/src/suggestions/types.js.map +1 -0
  110. package/dist/src/tools/analyze.d.ts +151 -0
  111. package/dist/src/tools/analyze.d.ts.map +1 -0
  112. package/dist/src/tools/analyze.js +205 -0
  113. package/dist/src/tools/analyze.js.map +1 -0
  114. package/dist/src/tools/compare.d.ts +149 -0
  115. package/dist/src/tools/compare.d.ts.map +1 -0
  116. package/dist/src/tools/compare.js +464 -0
  117. package/dist/src/tools/compare.js.map +1 -0
  118. package/dist/src/tools/get-skill.d.ts +116 -0
  119. package/dist/src/tools/get-skill.d.ts.map +1 -0
  120. package/dist/src/tools/get-skill.js +224 -0
  121. package/dist/src/tools/get-skill.js.map +1 -0
  122. package/dist/src/tools/index.d.ts +20 -0
  123. package/dist/src/tools/index.d.ts.map +1 -0
  124. package/dist/src/tools/index.js +20 -0
  125. package/dist/src/tools/index.js.map +1 -0
  126. package/dist/src/tools/install.d.ts +122 -0
  127. package/dist/src/tools/install.d.ts.map +1 -0
  128. package/dist/src/tools/install.js +314 -0
  129. package/dist/src/tools/install.js.map +1 -0
  130. package/dist/src/tools/recommend.d.ts +171 -0
  131. package/dist/src/tools/recommend.d.ts.map +1 -0
  132. package/dist/src/tools/recommend.js +325 -0
  133. package/dist/src/tools/recommend.js.map +1 -0
  134. package/dist/src/tools/search.d.ts +121 -0
  135. package/dist/src/tools/search.d.ts.map +1 -0
  136. package/dist/src/tools/search.js +249 -0
  137. package/dist/src/tools/search.js.map +1 -0
  138. package/dist/src/tools/suggest.d.ts +181 -0
  139. package/dist/src/tools/suggest.d.ts.map +1 -0
  140. package/dist/src/tools/suggest.js +342 -0
  141. package/dist/src/tools/suggest.js.map +1 -0
  142. package/dist/src/tools/uninstall.d.ts +123 -0
  143. package/dist/src/tools/uninstall.d.ts.map +1 -0
  144. package/dist/src/tools/uninstall.js +250 -0
  145. package/dist/src/tools/uninstall.js.map +1 -0
  146. package/dist/src/tools/validate.d.ts +122 -0
  147. package/dist/src/tools/validate.d.ts.map +1 -0
  148. package/dist/src/tools/validate.js +497 -0
  149. package/dist/src/tools/validate.js.map +1 -0
  150. package/dist/src/utils/installed-skills.d.ts +101 -0
  151. package/dist/src/utils/installed-skills.d.ts.map +1 -0
  152. package/dist/src/utils/installed-skills.js +220 -0
  153. package/dist/src/utils/installed-skills.js.map +1 -0
  154. package/dist/src/utils/validation.d.ts +76 -0
  155. package/dist/src/utils/validation.d.ts.map +1 -0
  156. package/dist/src/utils/validation.js +153 -0
  157. package/dist/src/utils/validation.js.map +1 -0
  158. package/dist/src/webhooks/index.d.ts +8 -0
  159. package/dist/src/webhooks/index.d.ts.map +1 -0
  160. package/dist/src/webhooks/index.js +9 -0
  161. package/dist/src/webhooks/index.js.map +1 -0
  162. package/dist/src/webhooks/webhook-endpoint.d.ts +149 -0
  163. package/dist/src/webhooks/webhook-endpoint.d.ts.map +1 -0
  164. package/dist/src/webhooks/webhook-endpoint.js +339 -0
  165. package/dist/src/webhooks/webhook-endpoint.js.map +1 -0
  166. package/dist/tests/compare.test.d.ts +6 -0
  167. package/dist/tests/compare.test.d.ts.map +1 -0
  168. package/dist/tests/compare.test.js +225 -0
  169. package/dist/tests/compare.test.js.map +1 -0
  170. package/dist/tests/context/project-detector.test.d.ts +6 -0
  171. package/dist/tests/context/project-detector.test.d.ts.map +1 -0
  172. package/dist/tests/context/project-detector.test.js +719 -0
  173. package/dist/tests/context/project-detector.test.js.map +1 -0
  174. package/dist/tests/e2e/compare.e2e.test.d.ts +10 -0
  175. package/dist/tests/e2e/compare.e2e.test.d.ts.map +1 -0
  176. package/dist/tests/e2e/compare.e2e.test.js +286 -0
  177. package/dist/tests/e2e/compare.e2e.test.js.map +1 -0
  178. package/dist/tests/e2e/install-flow.e2e.test.d.ts +10 -0
  179. package/dist/tests/e2e/install-flow.e2e.test.d.ts.map +1 -0
  180. package/dist/tests/e2e/install-flow.e2e.test.js +209 -0
  181. package/dist/tests/e2e/install-flow.e2e.test.js.map +1 -0
  182. package/dist/tests/e2e/recommend.e2e.test.d.ts +12 -0
  183. package/dist/tests/e2e/recommend.e2e.test.d.ts.map +1 -0
  184. package/dist/tests/e2e/recommend.e2e.test.js +347 -0
  185. package/dist/tests/e2e/recommend.e2e.test.js.map +1 -0
  186. package/dist/tests/e2e/skill-flow.e2e.test.d.ts +10 -0
  187. package/dist/tests/e2e/skill-flow.e2e.test.d.ts.map +1 -0
  188. package/dist/tests/e2e/skill-flow.e2e.test.js +280 -0
  189. package/dist/tests/e2e/skill-flow.e2e.test.js.map +1 -0
  190. package/dist/tests/e2e/suggest.e2e.test.d.ts +13 -0
  191. package/dist/tests/e2e/suggest.e2e.test.d.ts.map +1 -0
  192. package/dist/tests/e2e/suggest.e2e.test.js +347 -0
  193. package/dist/tests/e2e/suggest.e2e.test.js.map +1 -0
  194. package/dist/tests/e2e/utils/baseline-collector.d.ts +107 -0
  195. package/dist/tests/e2e/utils/baseline-collector.d.ts.map +1 -0
  196. package/dist/tests/e2e/utils/baseline-collector.js +211 -0
  197. package/dist/tests/e2e/utils/baseline-collector.js.map +1 -0
  198. package/dist/tests/e2e/utils/hardcoded-detector.d.ts +46 -0
  199. package/dist/tests/e2e/utils/hardcoded-detector.d.ts.map +1 -0
  200. package/dist/tests/e2e/utils/hardcoded-detector.js +255 -0
  201. package/dist/tests/e2e/utils/hardcoded-detector.js.map +1 -0
  202. package/dist/tests/e2e/utils/index.d.ts +7 -0
  203. package/dist/tests/e2e/utils/index.d.ts.map +1 -0
  204. package/dist/tests/e2e/utils/index.js +7 -0
  205. package/dist/tests/e2e/utils/index.js.map +1 -0
  206. package/dist/tests/e2e/utils/linear-reporter.d.ts +60 -0
  207. package/dist/tests/e2e/utils/linear-reporter.d.ts.map +1 -0
  208. package/dist/tests/e2e/utils/linear-reporter.js +232 -0
  209. package/dist/tests/e2e/utils/linear-reporter.js.map +1 -0
  210. package/dist/tests/health.test.d.ts +9 -0
  211. package/dist/tests/health.test.d.ts.map +1 -0
  212. package/dist/tests/health.test.js +308 -0
  213. package/dist/tests/health.test.js.map +1 -0
  214. package/dist/tests/integration/analyze.integration.test.d.ts +2 -0
  215. package/dist/tests/integration/analyze.integration.test.d.ts.map +1 -0
  216. package/dist/tests/integration/analyze.integration.test.js +244 -0
  217. package/dist/tests/integration/analyze.integration.test.js.map +1 -0
  218. package/dist/tests/integration/compare.integration.test.d.ts +2 -0
  219. package/dist/tests/integration/compare.integration.test.d.ts.map +1 -0
  220. package/dist/tests/integration/compare.integration.test.js +120 -0
  221. package/dist/tests/integration/compare.integration.test.js.map +1 -0
  222. package/dist/tests/integration/fixtures/test-skills.d.ts +62 -0
  223. package/dist/tests/integration/fixtures/test-skills.d.ts.map +1 -0
  224. package/dist/tests/integration/fixtures/test-skills.js +644 -0
  225. package/dist/tests/integration/fixtures/test-skills.js.map +1 -0
  226. package/dist/tests/integration/get-skill.integration.test.d.ts +6 -0
  227. package/dist/tests/integration/get-skill.integration.test.d.ts.map +1 -0
  228. package/dist/tests/integration/get-skill.integration.test.js +203 -0
  229. package/dist/tests/integration/get-skill.integration.test.js.map +1 -0
  230. package/dist/tests/integration/github-api.integration.test.d.ts +14 -0
  231. package/dist/tests/integration/github-api.integration.test.d.ts.map +1 -0
  232. package/dist/tests/integration/github-api.integration.test.js +190 -0
  233. package/dist/tests/integration/github-api.integration.test.js.map +1 -0
  234. package/dist/tests/integration/install.integration.test.d.ts +6 -0
  235. package/dist/tests/integration/install.integration.test.d.ts.map +1 -0
  236. package/dist/tests/integration/install.integration.test.js +282 -0
  237. package/dist/tests/integration/install.integration.test.js.map +1 -0
  238. package/dist/tests/integration/recommend.integration.test.d.ts +2 -0
  239. package/dist/tests/integration/recommend.integration.test.d.ts.map +1 -0
  240. package/dist/tests/integration/recommend.integration.test.js +215 -0
  241. package/dist/tests/integration/recommend.integration.test.js.map +1 -0
  242. package/dist/tests/integration/search.integration.test.d.ts +6 -0
  243. package/dist/tests/integration/search.integration.test.d.ts.map +1 -0
  244. package/dist/tests/integration/search.integration.test.js +229 -0
  245. package/dist/tests/integration/search.integration.test.js.map +1 -0
  246. package/dist/tests/integration/setup.d.ts +71 -0
  247. package/dist/tests/integration/setup.d.ts.map +1 -0
  248. package/dist/tests/integration/setup.js +124 -0
  249. package/dist/tests/integration/setup.js.map +1 -0
  250. package/dist/tests/integration/uninstall.integration.test.d.ts +6 -0
  251. package/dist/tests/integration/uninstall.integration.test.d.ts.map +1 -0
  252. package/dist/tests/integration/uninstall.integration.test.js +296 -0
  253. package/dist/tests/integration/uninstall.integration.test.js.map +1 -0
  254. package/dist/tests/integration/validate.integration.test.d.ts +2 -0
  255. package/dist/tests/integration/validate.integration.test.d.ts.map +1 -0
  256. package/dist/tests/integration/validate.integration.test.js +181 -0
  257. package/dist/tests/integration/validate.integration.test.js.map +1 -0
  258. package/dist/tests/onboarding/first-run.test.d.ts +7 -0
  259. package/dist/tests/onboarding/first-run.test.d.ts.map +1 -0
  260. package/dist/tests/onboarding/first-run.test.js +258 -0
  261. package/dist/tests/onboarding/first-run.test.js.map +1 -0
  262. package/dist/tests/performance/search-performance.test.d.ts +10 -0
  263. package/dist/tests/performance/search-performance.test.d.ts.map +1 -0
  264. package/dist/tests/performance/search-performance.test.js +218 -0
  265. package/dist/tests/performance/search-performance.test.js.map +1 -0
  266. package/dist/tests/recommend.test.d.ts +6 -0
  267. package/dist/tests/recommend.test.d.ts.map +1 -0
  268. package/dist/tests/recommend.test.js +208 -0
  269. package/dist/tests/recommend.test.js.map +1 -0
  270. package/dist/tests/suggestions/suggestion-engine.test.d.ts +6 -0
  271. package/dist/tests/suggestions/suggestion-engine.test.d.ts.map +1 -0
  272. package/dist/tests/suggestions/suggestion-engine.test.js +448 -0
  273. package/dist/tests/suggestions/suggestion-engine.test.js.map +1 -0
  274. package/dist/tests/test-utils.d.ts +74 -0
  275. package/dist/tests/test-utils.d.ts.map +1 -0
  276. package/dist/tests/test-utils.js +98 -0
  277. package/dist/tests/test-utils.js.map +1 -0
  278. package/dist/tests/tools.test.d.ts +5 -0
  279. package/dist/tests/tools.test.d.ts.map +1 -0
  280. package/dist/tests/tools.test.js +138 -0
  281. package/dist/tests/tools.test.js.map +1 -0
  282. package/dist/tests/unit/installed-skills.test.d.ts +6 -0
  283. package/dist/tests/unit/installed-skills.test.d.ts.map +1 -0
  284. package/dist/tests/unit/installed-skills.test.js +285 -0
  285. package/dist/tests/unit/installed-skills.test.js.map +1 -0
  286. package/dist/tests/unit/logger.test.d.ts +6 -0
  287. package/dist/tests/unit/logger.test.d.ts.map +1 -0
  288. package/dist/tests/unit/logger.test.js +281 -0
  289. package/dist/tests/unit/logger.test.js.map +1 -0
  290. package/dist/tests/validate.test.d.ts +5 -0
  291. package/dist/tests/validate.test.d.ts.map +1 -0
  292. package/dist/tests/validate.test.js +303 -0
  293. package/dist/tests/validate.test.js.map +1 -0
  294. package/dist/tests/webhooks/proxy-trust.security.test.d.ts +8 -0
  295. package/dist/tests/webhooks/proxy-trust.security.test.d.ts.map +1 -0
  296. package/dist/tests/webhooks/proxy-trust.security.test.js +145 -0
  297. package/dist/tests/webhooks/proxy-trust.security.test.js.map +1 -0
  298. package/dist/tests/webhooks/rate-limiter.security.test.d.ts +8 -0
  299. package/dist/tests/webhooks/rate-limiter.security.test.d.ts.map +1 -0
  300. package/dist/tests/webhooks/rate-limiter.security.test.js +122 -0
  301. package/dist/tests/webhooks/rate-limiter.security.test.js.map +1 -0
  302. package/dist/vitest.config.d.ts +6 -0
  303. package/dist/vitest.config.d.ts.map +1 -0
  304. package/dist/vitest.config.js +13 -0
  305. package/dist/vitest.config.js.map +1 -0
  306. 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"}