@skillsmith/mcp-server 0.3.3 → 0.3.5

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 (261) hide show
  1. package/README.md +5 -3
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/src/__tests__/LocalIndexer.test.d.ts +5 -0
  4. package/dist/src/__tests__/LocalIndexer.test.d.ts.map +1 -0
  5. package/dist/src/__tests__/LocalIndexer.test.js +396 -0
  6. package/dist/src/__tests__/LocalIndexer.test.js.map +1 -0
  7. package/dist/src/__tests__/context.test.d.ts +10 -0
  8. package/dist/src/__tests__/context.test.d.ts.map +1 -0
  9. package/dist/src/__tests__/context.test.js +345 -0
  10. package/dist/src/__tests__/context.test.js.map +1 -0
  11. package/dist/src/__tests__/get-skill.test.d.ts +1 -0
  12. package/dist/src/__tests__/get-skill.test.d.ts.map +1 -1
  13. package/dist/src/__tests__/get-skill.test.js +279 -0
  14. package/dist/src/__tests__/get-skill.test.js.map +1 -1
  15. package/dist/src/__tests__/index-local.test.d.ts +5 -0
  16. package/dist/src/__tests__/index-local.test.d.ts.map +1 -0
  17. package/dist/src/__tests__/index-local.test.js +203 -0
  18. package/dist/src/__tests__/index-local.test.js.map +1 -0
  19. package/dist/src/__tests__/middleware/license.test.js +180 -78
  20. package/dist/src/__tests__/middleware/license.test.js.map +1 -1
  21. package/dist/src/__tests__/recommend.test.d.ts +7 -0
  22. package/dist/src/__tests__/recommend.test.d.ts.map +1 -0
  23. package/dist/src/__tests__/recommend.test.js +277 -0
  24. package/dist/src/__tests__/recommend.test.js.map +1 -0
  25. package/dist/src/__tests__/search.test.js +140 -1
  26. package/dist/src/__tests__/search.test.js.map +1 -1
  27. package/dist/src/__tests__/utils/validation.test.d.ts +7 -0
  28. package/dist/src/__tests__/utils/validation.test.d.ts.map +1 -0
  29. package/dist/src/__tests__/utils/validation.test.js +82 -0
  30. package/dist/src/__tests__/utils/validation.test.js.map +1 -0
  31. package/dist/src/context.d.ts +22 -0
  32. package/dist/src/context.d.ts.map +1 -1
  33. package/dist/src/context.js +63 -9
  34. package/dist/src/context.js.map +1 -1
  35. package/dist/src/index.js +15 -1
  36. package/dist/src/index.js.map +1 -1
  37. package/dist/src/indexer/FrontmatterParser.d.ts +30 -0
  38. package/dist/src/indexer/FrontmatterParser.d.ts.map +1 -0
  39. package/dist/src/indexer/FrontmatterParser.js +109 -0
  40. package/dist/src/indexer/FrontmatterParser.js.map +1 -0
  41. package/dist/src/indexer/LocalIndexer.d.ts +136 -0
  42. package/dist/src/indexer/LocalIndexer.d.ts.map +1 -0
  43. package/dist/src/indexer/LocalIndexer.js +271 -0
  44. package/dist/src/indexer/LocalIndexer.js.map +1 -0
  45. package/dist/src/indexer/index.d.ts +8 -0
  46. package/dist/src/indexer/index.d.ts.map +1 -0
  47. package/dist/src/indexer/index.js +8 -0
  48. package/dist/src/indexer/index.js.map +1 -0
  49. package/dist/src/llm/failover.d.ts +210 -0
  50. package/dist/src/llm/failover.d.ts.map +1 -0
  51. package/dist/src/llm/failover.js +329 -0
  52. package/dist/src/llm/failover.js.map +1 -0
  53. package/dist/src/middleware/errorFormatter.d.ts +27 -0
  54. package/dist/src/middleware/errorFormatter.d.ts.map +1 -1
  55. package/dist/src/middleware/errorFormatter.js +95 -0
  56. package/dist/src/middleware/errorFormatter.js.map +1 -1
  57. package/dist/src/middleware/index.d.ts +1 -1
  58. package/dist/src/middleware/index.d.ts.map +1 -1
  59. package/dist/src/middleware/index.js.map +1 -1
  60. package/dist/src/middleware/license.d.ts +5 -0
  61. package/dist/src/middleware/license.d.ts.map +1 -1
  62. package/dist/src/middleware/license.js +2 -1
  63. package/dist/src/middleware/license.js.map +1 -1
  64. package/dist/src/middleware/quota-helpers.d.ts +40 -0
  65. package/dist/src/middleware/quota-helpers.d.ts.map +1 -0
  66. package/dist/src/middleware/quota-helpers.js +90 -0
  67. package/dist/src/middleware/quota-helpers.js.map +1 -0
  68. package/dist/src/middleware/quota-types.d.ts +105 -0
  69. package/dist/src/middleware/quota-types.d.ts.map +1 -0
  70. package/dist/src/middleware/quota-types.js +4 -0
  71. package/dist/src/middleware/quota-types.js.map +1 -0
  72. package/dist/src/middleware/quota.d.ts +3 -97
  73. package/dist/src/middleware/quota.d.ts.map +1 -1
  74. package/dist/src/middleware/quota.js +2 -87
  75. package/dist/src/middleware/quota.js.map +1 -1
  76. package/dist/src/tools/LocalSkillSearch.d.ts +32 -0
  77. package/dist/src/tools/LocalSkillSearch.d.ts.map +1 -0
  78. package/dist/src/tools/LocalSkillSearch.js +74 -0
  79. package/dist/src/tools/LocalSkillSearch.js.map +1 -0
  80. package/dist/src/tools/compare.d.ts +3 -102
  81. package/dist/src/tools/compare.d.ts.map +1 -1
  82. package/dist/src/tools/compare.helpers.d.ts +36 -0
  83. package/dist/src/tools/compare.helpers.d.ts.map +1 -0
  84. package/dist/src/tools/compare.helpers.js +252 -0
  85. package/dist/src/tools/compare.helpers.js.map +1 -0
  86. package/dist/src/tools/compare.js +6 -288
  87. package/dist/src/tools/compare.js.map +1 -1
  88. package/dist/src/tools/compare.types.d.ts +134 -0
  89. package/dist/src/tools/compare.types.d.ts.map +1 -0
  90. package/dist/src/tools/compare.types.js +47 -0
  91. package/dist/src/tools/compare.types.js.map +1 -0
  92. package/dist/src/tools/get-skill.d.ts.map +1 -1
  93. package/dist/src/tools/get-skill.js +38 -2
  94. package/dist/src/tools/get-skill.js.map +1 -1
  95. package/dist/src/tools/index-local.d.ts +117 -0
  96. package/dist/src/tools/index-local.d.ts.map +1 -0
  97. package/dist/src/tools/index-local.js +126 -0
  98. package/dist/src/tools/index-local.js.map +1 -0
  99. package/dist/src/tools/index.d.ts +2 -0
  100. package/dist/src/tools/index.d.ts.map +1 -1
  101. package/dist/src/tools/index.js +2 -0
  102. package/dist/src/tools/index.js.map +1 -1
  103. package/dist/src/tools/install.conflict-helpers.d.ts +64 -0
  104. package/dist/src/tools/install.conflict-helpers.d.ts.map +1 -0
  105. package/dist/src/tools/install.conflict-helpers.js +165 -0
  106. package/dist/src/tools/install.conflict-helpers.js.map +1 -0
  107. package/dist/src/tools/install.conflict-helpers.test.d.ts +15 -0
  108. package/dist/src/tools/install.conflict-helpers.test.d.ts.map +1 -0
  109. package/dist/src/tools/install.conflict-helpers.test.js +243 -0
  110. package/dist/src/tools/install.conflict-helpers.test.js.map +1 -0
  111. package/dist/src/tools/install.conflict.d.ts +58 -0
  112. package/dist/src/tools/install.conflict.d.ts.map +1 -0
  113. package/dist/src/tools/install.conflict.js +160 -0
  114. package/dist/src/tools/install.conflict.js.map +1 -0
  115. package/dist/src/tools/install.conflict.test.d.ts +15 -0
  116. package/dist/src/tools/install.conflict.test.d.ts.map +1 -0
  117. package/dist/src/tools/install.conflict.test.js +354 -0
  118. package/dist/src/tools/install.conflict.test.js.map +1 -0
  119. package/dist/src/tools/install.d.ts +11 -60
  120. package/dist/src/tools/install.d.ts.map +1 -1
  121. package/dist/src/tools/install.helpers.d.ts +83 -0
  122. package/dist/src/tools/install.helpers.d.ts.map +1 -0
  123. package/dist/src/tools/install.helpers.js +333 -0
  124. package/dist/src/tools/install.helpers.js.map +1 -0
  125. package/dist/src/tools/install.js +199 -255
  126. package/dist/src/tools/install.js.map +1 -1
  127. package/dist/src/tools/install.types.d.ts +178 -0
  128. package/dist/src/tools/install.types.d.ts.map +1 -0
  129. package/dist/src/tools/install.types.js +105 -0
  130. package/dist/src/tools/install.types.js.map +1 -0
  131. package/dist/src/tools/merge.d.ts +53 -0
  132. package/dist/src/tools/merge.d.ts.map +1 -0
  133. package/dist/src/tools/merge.js +276 -0
  134. package/dist/src/tools/merge.js.map +1 -0
  135. package/dist/src/tools/merge.test.d.ts +11 -0
  136. package/dist/src/tools/merge.test.d.ts.map +1 -0
  137. package/dist/src/tools/merge.test.js +224 -0
  138. package/dist/src/tools/merge.test.js.map +1 -0
  139. package/dist/src/tools/recommend.d.ts +3 -148
  140. package/dist/src/tools/recommend.d.ts.map +1 -1
  141. package/dist/src/tools/recommend.helpers.d.ts +42 -0
  142. package/dist/src/tools/recommend.helpers.d.ts.map +1 -0
  143. package/dist/src/tools/recommend.helpers.js +155 -0
  144. package/dist/src/tools/recommend.helpers.js.map +1 -0
  145. package/dist/src/tools/recommend.js +216 -154
  146. package/dist/src/tools/recommend.js.map +1 -1
  147. package/dist/src/tools/recommend.types.d.ts +164 -0
  148. package/dist/src/tools/recommend.types.d.ts.map +1 -0
  149. package/dist/src/tools/recommend.types.js +87 -0
  150. package/dist/src/tools/recommend.types.js.map +1 -0
  151. package/dist/src/tools/search.d.ts +18 -4
  152. package/dist/src/tools/search.d.ts.map +1 -1
  153. package/dist/src/tools/search.js +91 -16
  154. package/dist/src/tools/search.js.map +1 -1
  155. package/dist/src/tools/validate.d.ts +3 -70
  156. package/dist/src/tools/validate.d.ts.map +1 -1
  157. package/dist/src/tools/validate.helpers.d.ts +22 -0
  158. package/dist/src/tools/validate.helpers.d.ts.map +1 -0
  159. package/dist/src/tools/validate.helpers.js +276 -0
  160. package/dist/src/tools/validate.helpers.js.map +1 -0
  161. package/dist/src/tools/validate.js +4 -337
  162. package/dist/src/tools/validate.js.map +1 -1
  163. package/dist/src/tools/validate.types.d.ts +96 -0
  164. package/dist/src/tools/validate.types.d.ts.map +1 -0
  165. package/dist/src/tools/validate.types.js +71 -0
  166. package/dist/src/tools/validate.types.js.map +1 -0
  167. package/dist/src/utils/validation.d.ts +6 -2
  168. package/dist/src/utils/validation.d.ts.map +1 -1
  169. package/dist/src/utils/validation.js +11 -2
  170. package/dist/src/utils/validation.js.map +1 -1
  171. package/dist/src/webhooks/index.d.ts +1 -0
  172. package/dist/src/webhooks/index.d.ts.map +1 -1
  173. package/dist/src/webhooks/index.js +2 -0
  174. package/dist/src/webhooks/index.js.map +1 -1
  175. package/dist/src/webhooks/stripe-webhook-endpoint.d.ts +68 -0
  176. package/dist/src/webhooks/stripe-webhook-endpoint.d.ts.map +1 -0
  177. package/dist/src/webhooks/stripe-webhook-endpoint.js +213 -0
  178. package/dist/src/webhooks/stripe-webhook-endpoint.js.map +1 -0
  179. package/dist/src/webhooks/webhook-endpoint.d.ts +4 -49
  180. package/dist/src/webhooks/webhook-endpoint.d.ts.map +1 -1
  181. package/dist/src/webhooks/webhook-endpoint.js +3 -125
  182. package/dist/src/webhooks/webhook-endpoint.js.map +1 -1
  183. package/dist/src/webhooks/webhook-helpers.d.ts +69 -0
  184. package/dist/src/webhooks/webhook-helpers.d.ts.map +1 -0
  185. package/dist/src/webhooks/webhook-helpers.js +146 -0
  186. package/dist/src/webhooks/webhook-helpers.js.map +1 -0
  187. package/dist/tests/e2e/conflict-resolution.e2e.test.d.ts +12 -0
  188. package/dist/tests/e2e/conflict-resolution.e2e.test.d.ts.map +1 -0
  189. package/dist/tests/e2e/conflict-resolution.e2e.test.js +343 -0
  190. package/dist/tests/e2e/conflict-resolution.e2e.test.js.map +1 -0
  191. package/dist/tests/integration/fixtures/development-skills.d.ts +22 -0
  192. package/dist/tests/integration/fixtures/development-skills.d.ts.map +1 -0
  193. package/dist/tests/integration/fixtures/development-skills.js +165 -0
  194. package/dist/tests/integration/fixtures/development-skills.js.map +1 -0
  195. package/dist/tests/integration/fixtures/devops-skills.d.ts +10 -0
  196. package/dist/tests/integration/fixtures/devops-skills.d.ts.map +1 -0
  197. package/dist/tests/integration/fixtures/devops-skills.js +70 -0
  198. package/dist/tests/integration/fixtures/devops-skills.js.map +1 -0
  199. package/dist/tests/integration/fixtures/experimental-skills.d.ts +14 -0
  200. package/dist/tests/integration/fixtures/experimental-skills.d.ts.map +1 -0
  201. package/dist/tests/integration/fixtures/experimental-skills.js +255 -0
  202. package/dist/tests/integration/fixtures/experimental-skills.js.map +1 -0
  203. package/dist/tests/integration/fixtures/skill-types.d.ts +18 -0
  204. package/dist/tests/integration/fixtures/skill-types.d.ts.map +1 -0
  205. package/dist/tests/integration/fixtures/skill-types.js +6 -0
  206. package/dist/tests/integration/fixtures/skill-types.js.map +1 -0
  207. package/dist/tests/integration/fixtures/test-skills.d.ts +10 -14
  208. package/dist/tests/integration/fixtures/test-skills.d.ts.map +1 -1
  209. package/dist/tests/integration/fixtures/test-skills.js +23 -590
  210. package/dist/tests/integration/fixtures/test-skills.js.map +1 -1
  211. package/dist/tests/integration/fixtures/testing-skills.d.ts +10 -0
  212. package/dist/tests/integration/fixtures/testing-skills.d.ts.map +1 -0
  213. package/dist/tests/integration/fixtures/testing-skills.js +70 -0
  214. package/dist/tests/integration/fixtures/testing-skills.js.map +1 -0
  215. package/dist/tests/integration/fixtures/verified-skills.d.ts +11 -0
  216. package/dist/tests/integration/fixtures/verified-skills.d.ts.map +1 -0
  217. package/dist/tests/integration/fixtures/verified-skills.js +91 -0
  218. package/dist/tests/integration/fixtures/verified-skills.js.map +1 -0
  219. package/dist/tests/integration/install-conflict.integration.test.d.ts +8 -0
  220. package/dist/tests/integration/install-conflict.integration.test.d.ts.map +1 -0
  221. package/dist/tests/integration/install-conflict.integration.test.js +384 -0
  222. package/dist/tests/integration/install-conflict.integration.test.js.map +1 -0
  223. package/dist/tests/integration/install-trust-parsing.integration.test.d.ts +13 -0
  224. package/dist/tests/integration/install-trust-parsing.integration.test.d.ts.map +1 -0
  225. package/dist/tests/integration/install-trust-parsing.integration.test.js +290 -0
  226. package/dist/tests/integration/install-trust-parsing.integration.test.js.map +1 -0
  227. package/dist/tests/integration/install.integration.test.js +151 -1
  228. package/dist/tests/integration/install.integration.test.js.map +1 -1
  229. package/dist/tests/integration/recommend.integration.test.js +2 -1
  230. package/dist/tests/integration/recommend.integration.test.js.map +1 -1
  231. package/dist/tests/llm/failover.test.d.ts +13 -0
  232. package/dist/tests/llm/failover.test.d.ts.map +1 -0
  233. package/dist/tests/llm/failover.test.js +250 -0
  234. package/dist/tests/llm/failover.test.js.map +1 -0
  235. package/dist/tests/recommend.test.js +133 -1
  236. package/dist/tests/recommend.test.js.map +1 -1
  237. package/dist/tests/tools.test.d.ts +1 -0
  238. package/dist/tests/tools.test.d.ts.map +1 -1
  239. package/dist/tests/tools.test.js +59 -1
  240. package/dist/tests/tools.test.js.map +1 -1
  241. package/dist/tests/unit/compare-helpers.test.d.ts +8 -0
  242. package/dist/tests/unit/compare-helpers.test.d.ts.map +1 -0
  243. package/dist/tests/unit/compare-helpers.test.js +224 -0
  244. package/dist/tests/unit/compare-helpers.test.js.map +1 -0
  245. package/dist/tests/unit/install-helpers.test.d.ts +8 -0
  246. package/dist/tests/unit/install-helpers.test.d.ts.map +1 -0
  247. package/dist/tests/unit/install-helpers.test.js +460 -0
  248. package/dist/tests/unit/install-helpers.test.js.map +1 -0
  249. package/dist/tests/unit/recommend-helpers.test.d.ts +8 -0
  250. package/dist/tests/unit/recommend-helpers.test.d.ts.map +1 -0
  251. package/dist/tests/unit/recommend-helpers.test.js +117 -0
  252. package/dist/tests/unit/recommend-helpers.test.js.map +1 -0
  253. package/dist/tests/unit/validate-helpers.test.d.ts +8 -0
  254. package/dist/tests/unit/validate-helpers.test.d.ts.map +1 -0
  255. package/dist/tests/unit/validate-helpers.test.js +243 -0
  256. package/dist/tests/unit/validate-helpers.test.js.map +1 -0
  257. package/package.json +7 -6
  258. package/src/assets/docs/USER_GUIDE.md +0 -220
  259. package/src/assets/skills/skillsmith/docs/QUOTAS.md +0 -182
  260. package/src/assets/skills/skillsmith/docs/SECURITY.md +0 -174
  261. package/src/assets/skills/skillsmith/docs/TRUST_TIERS.md +0 -142
@@ -0,0 +1,354 @@
1
+ /**
2
+ * @fileoverview Unit Tests for Conflict Detection and Resolution
3
+ * @module @skillsmith/mcp-server/tools/install.conflict.test
4
+ * @see SMI-1868, SMI-1879
5
+ *
6
+ * Tests cover:
7
+ * - checkForConflicts: Detect local modifications before update
8
+ * - handleMergeAction: Three-way merge with conflict resolution
9
+ *
10
+ * Related test files:
11
+ * - install.conflict-helpers.test.ts: hashContent, detectModifications, backups
12
+ * - merge.test.ts: computeDiff, threeWayMerge
13
+ */
14
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
15
+ import * as fs from 'fs/promises';
16
+ // Import functions under test
17
+ import { hashContent } from './install.conflict-helpers.js';
18
+ import { checkForConflicts, handleMergeAction } from './install.conflict.js';
19
+ // Mock fs module
20
+ vi.mock('fs/promises');
21
+ const mockedFs = vi.mocked(fs);
22
+ // Import the mocked helpers for configuration in tests
23
+ import * as helpersModule from './install.helpers.js';
24
+ // Mock install.helpers for updateManifestSafely
25
+ vi.mock('./install.helpers.js', async (importOriginal) => {
26
+ const actual = await importOriginal();
27
+ return {
28
+ ...actual,
29
+ detectModifications: vi.fn(),
30
+ createSkillBackup: vi.fn().mockResolvedValue('/backup/path'),
31
+ storeOriginal: vi.fn().mockResolvedValue(undefined),
32
+ loadOriginal: vi.fn(),
33
+ cleanupOldBackups: vi.fn().mockResolvedValue(undefined),
34
+ updateManifestSafely: vi.fn().mockResolvedValue(undefined),
35
+ };
36
+ });
37
+ const mockedHelpers = vi.mocked(helpersModule);
38
+ // ============================================================================
39
+ // Tests for checkForConflicts
40
+ // ============================================================================
41
+ describe('checkForConflicts', () => {
42
+ beforeEach(() => {
43
+ vi.clearAllMocks();
44
+ });
45
+ it('should proceed when skill has no originalContentHash', async () => {
46
+ const manifest = {
47
+ version: '1.0.0',
48
+ installedSkills: {
49
+ 'test-skill': {
50
+ id: 'owner/test-skill',
51
+ name: 'test-skill',
52
+ version: '1.0.0',
53
+ source: 'github:owner/test-skill',
54
+ installPath: '/path/to/skill',
55
+ installedAt: '2025-01-01',
56
+ lastUpdated: '2025-01-01',
57
+ // No originalContentHash
58
+ },
59
+ },
60
+ };
61
+ const result = await checkForConflicts('test-skill', '/path/to/skill', manifest, undefined, 'owner/test-skill');
62
+ expect(result.shouldProceed).toBe(true);
63
+ });
64
+ it('should proceed when skill is not modified', async () => {
65
+ const content = 'Original content';
66
+ const originalHash = hashContent(content);
67
+ const manifest = {
68
+ version: '1.0.0',
69
+ installedSkills: {
70
+ 'test-skill': {
71
+ id: 'owner/test-skill',
72
+ name: 'test-skill',
73
+ version: '1.0.0',
74
+ source: 'github:owner/test-skill',
75
+ installPath: '/path/to/skill',
76
+ installedAt: '2025-01-01',
77
+ lastUpdated: '2025-01-01',
78
+ originalContentHash: originalHash,
79
+ },
80
+ },
81
+ };
82
+ // Configure mock to return no modification
83
+ mockedHelpers.detectModifications.mockResolvedValue({
84
+ modified: false,
85
+ currentHash: originalHash,
86
+ originalHash: originalHash,
87
+ });
88
+ const result = await checkForConflicts('test-skill', '/path/to/skill', manifest, undefined, 'owner/test-skill');
89
+ expect(result.shouldProceed).toBe(true);
90
+ });
91
+ it('should return conflict info when modified and no action specified', async () => {
92
+ const originalContent = 'Original content';
93
+ const modifiedContent = 'Modified content';
94
+ const originalHash = hashContent(originalContent);
95
+ const modifiedHash = hashContent(modifiedContent);
96
+ const manifest = {
97
+ version: '1.0.0',
98
+ installedSkills: {
99
+ 'test-skill': {
100
+ id: 'owner/test-skill',
101
+ name: 'test-skill',
102
+ version: '1.0.0',
103
+ source: 'github:owner/test-skill',
104
+ installPath: '/path/to/skill',
105
+ installedAt: '2025-01-01',
106
+ lastUpdated: '2025-01-01',
107
+ originalContentHash: originalHash,
108
+ },
109
+ },
110
+ };
111
+ // Configure mock to return modified
112
+ mockedHelpers.detectModifications.mockResolvedValue({
113
+ modified: true,
114
+ currentHash: modifiedHash,
115
+ originalHash: originalHash,
116
+ });
117
+ const result = await checkForConflicts('test-skill', '/path/to/skill', manifest, undefined, 'owner/test-skill');
118
+ expect(result.shouldProceed).toBe(false);
119
+ expect(result.earlyReturn).toBeDefined();
120
+ expect(result.earlyReturn.conflict).toBeDefined();
121
+ expect(result.earlyReturn.conflict.hasLocalModifications).toBe(true);
122
+ expect(result.earlyReturn.requiresAction).toContain('overwrite');
123
+ expect(result.earlyReturn.requiresAction).toContain('merge');
124
+ expect(result.earlyReturn.requiresAction).toContain('cancel');
125
+ });
126
+ it('should cancel when action is cancel', async () => {
127
+ const originalContent = 'Original content';
128
+ const modifiedContent = 'Modified content';
129
+ const originalHash = hashContent(originalContent);
130
+ const modifiedHash = hashContent(modifiedContent);
131
+ const manifest = {
132
+ version: '1.0.0',
133
+ installedSkills: {
134
+ 'test-skill': {
135
+ id: 'owner/test-skill',
136
+ name: 'test-skill',
137
+ version: '1.0.0',
138
+ source: 'github:owner/test-skill',
139
+ installPath: '/path/to/skill',
140
+ installedAt: '2025-01-01',
141
+ lastUpdated: '2025-01-01',
142
+ originalContentHash: originalHash,
143
+ },
144
+ },
145
+ };
146
+ // Configure mock to return modified
147
+ mockedHelpers.detectModifications.mockResolvedValue({
148
+ modified: true,
149
+ currentHash: modifiedHash,
150
+ originalHash: originalHash,
151
+ });
152
+ const result = await checkForConflicts('test-skill', '/path/to/skill', manifest, 'cancel', 'owner/test-skill');
153
+ expect(result.shouldProceed).toBe(false);
154
+ expect(result.earlyReturn).toBeDefined();
155
+ expect(result.earlyReturn.error).toContain('cancelled');
156
+ });
157
+ it('should create backup when action is overwrite', async () => {
158
+ const originalContent = 'Original content';
159
+ const modifiedContent = 'Modified content';
160
+ const originalHash = hashContent(originalContent);
161
+ const modifiedHash = hashContent(modifiedContent);
162
+ const manifest = {
163
+ version: '1.0.0',
164
+ installedSkills: {
165
+ 'test-skill': {
166
+ id: 'owner/test-skill',
167
+ name: 'test-skill',
168
+ version: '1.0.0',
169
+ source: 'github:owner/test-skill',
170
+ installPath: '/path/to/skill',
171
+ installedAt: '2025-01-01',
172
+ lastUpdated: '2025-01-01',
173
+ originalContentHash: originalHash,
174
+ },
175
+ },
176
+ };
177
+ // Configure mocks
178
+ mockedHelpers.detectModifications.mockResolvedValue({
179
+ modified: true,
180
+ currentHash: modifiedHash,
181
+ originalHash: originalHash,
182
+ });
183
+ mockedHelpers.createSkillBackup.mockResolvedValue('/backup/path/test-skill');
184
+ const result = await checkForConflicts('test-skill', '/path/to/skill', manifest, 'overwrite', 'owner/test-skill');
185
+ expect(result.shouldProceed).toBe(true);
186
+ expect(result.backupPath).toBeDefined();
187
+ });
188
+ it('should proceed for merge action', async () => {
189
+ const originalContent = 'Original content';
190
+ const modifiedContent = 'Modified content';
191
+ const originalHash = hashContent(originalContent);
192
+ const modifiedHash = hashContent(modifiedContent);
193
+ const manifest = {
194
+ version: '1.0.0',
195
+ installedSkills: {
196
+ 'test-skill': {
197
+ id: 'owner/test-skill',
198
+ name: 'test-skill',
199
+ version: '1.0.0',
200
+ source: 'github:owner/test-skill',
201
+ installPath: '/path/to/skill',
202
+ installedAt: '2025-01-01',
203
+ lastUpdated: '2025-01-01',
204
+ originalContentHash: originalHash,
205
+ },
206
+ },
207
+ };
208
+ // Configure mock to return modified
209
+ mockedHelpers.detectModifications.mockResolvedValue({
210
+ modified: true,
211
+ currentHash: modifiedHash,
212
+ originalHash: originalHash,
213
+ });
214
+ const result = await checkForConflicts('test-skill', '/path/to/skill', manifest, 'merge', 'owner/test-skill');
215
+ expect(result.shouldProceed).toBe(true);
216
+ });
217
+ });
218
+ // ============================================================================
219
+ // Tests for handleMergeAction
220
+ // ============================================================================
221
+ describe('handleMergeAction', () => {
222
+ beforeEach(() => {
223
+ vi.clearAllMocks();
224
+ });
225
+ it('should fallback to overwrite when no original content found', async () => {
226
+ const manifest = {
227
+ version: '1.0.0',
228
+ installedSkills: {
229
+ 'test-skill': {
230
+ id: 'owner/test-skill',
231
+ name: 'test-skill',
232
+ version: '1.0.0',
233
+ source: 'github:owner/test-skill',
234
+ installPath: '/path/to/skill',
235
+ installedAt: '2025-01-01',
236
+ lastUpdated: '2025-01-01',
237
+ },
238
+ },
239
+ };
240
+ // loadOriginal returns null
241
+ mockedHelpers.loadOriginal.mockResolvedValue(null);
242
+ mockedFs.readFile.mockResolvedValue('Current content'); // current content
243
+ const result = await handleMergeAction('test-skill', '/path/to/skill', 'Upstream content', manifest, 'owner', 'repo', 'owner/test-skill');
244
+ expect(result.shouldProceed).toBe(true);
245
+ });
246
+ it('should return merged content on clean merge', async () => {
247
+ const originalContent = `Line 1
248
+ Line 2
249
+ Line 3`;
250
+ const currentContent = `Line 1
251
+ Local Line 2
252
+ Line 3`;
253
+ const upstreamContent = `Line 1
254
+ Line 2
255
+ Upstream Line 3`;
256
+ const manifest = {
257
+ version: '1.0.0',
258
+ installedSkills: {
259
+ 'test-skill': {
260
+ id: 'owner/test-skill',
261
+ name: 'test-skill',
262
+ version: '1.0.0',
263
+ source: 'github:owner/test-skill',
264
+ installPath: '/path/to/skill',
265
+ installedAt: '2025-01-01',
266
+ lastUpdated: '2025-01-01',
267
+ },
268
+ },
269
+ };
270
+ // loadOriginal returns original content
271
+ mockedHelpers.loadOriginal.mockResolvedValue(originalContent);
272
+ // current content read from fs
273
+ mockedFs.readFile.mockResolvedValue(currentContent);
274
+ const result = await handleMergeAction('test-skill', '/path/to/skill', upstreamContent, manifest, 'owner', 'repo', 'owner/test-skill');
275
+ expect(result.shouldProceed).toBe(true);
276
+ expect(result.mergedContent).toBeDefined();
277
+ expect(result.mergedContent).toContain('Local Line 2');
278
+ expect(result.mergedContent).toContain('Upstream Line 3');
279
+ });
280
+ it('should handle deleted local file as a conflict', async () => {
281
+ const originalContent = 'Original content';
282
+ const upstreamContent = 'Upstream content';
283
+ const manifest = {
284
+ version: '1.0.0',
285
+ installedSkills: {
286
+ 'test-skill': {
287
+ id: 'owner/test-skill',
288
+ name: 'test-skill',
289
+ version: '1.0.0',
290
+ source: 'github:owner/test-skill',
291
+ installPath: '/path/to/skill',
292
+ installedAt: '2025-01-01',
293
+ lastUpdated: '2025-01-01',
294
+ },
295
+ },
296
+ };
297
+ // loadOriginal returns original content
298
+ mockedHelpers.loadOriginal.mockResolvedValue(originalContent);
299
+ // current content - file deleted (throws ENOENT, treated as empty)
300
+ const error = new Error('ENOENT');
301
+ error.code = 'ENOENT';
302
+ mockedFs.readFile.mockRejectedValue(error);
303
+ // createSkillBackup mock
304
+ mockedHelpers.createSkillBackup.mockResolvedValue('/backup/path/test-skill');
305
+ // fs operations for writing conflict file
306
+ mockedFs.mkdir.mockResolvedValue(undefined);
307
+ mockedFs.writeFile.mockResolvedValue(undefined);
308
+ const result = await handleMergeAction('test-skill', '/path/to/skill', upstreamContent, manifest, 'owner', 'repo', 'owner/test-skill');
309
+ // When local is deleted (empty) and upstream differs from original,
310
+ // this is a conflict since both sides modified the content differently
311
+ expect(result.shouldProceed).toBe(false);
312
+ expect(result.backupPath).toBeDefined();
313
+ expect(result.earlyReturn).toBeDefined();
314
+ expect(result.earlyReturn.mergeResult).toBeDefined();
315
+ expect(result.earlyReturn.mergeResult.conflicts).toBeDefined();
316
+ });
317
+ it('should create backup and write conflict markers on merge conflict', async () => {
318
+ const originalContent = 'Original content';
319
+ const currentContent = 'Local version';
320
+ const upstreamContent = 'Upstream version';
321
+ const manifest = {
322
+ version: '1.0.0',
323
+ installedSkills: {
324
+ 'test-skill': {
325
+ id: 'owner/test-skill',
326
+ name: 'test-skill',
327
+ version: '1.0.0',
328
+ source: 'github:owner/test-skill',
329
+ installPath: '/path/to/skill',
330
+ installedAt: '2025-01-01',
331
+ lastUpdated: '2025-01-01',
332
+ },
333
+ },
334
+ };
335
+ // loadOriginal returns original content
336
+ mockedHelpers.loadOriginal.mockResolvedValue(originalContent);
337
+ // current content read from fs
338
+ mockedFs.readFile.mockResolvedValue(currentContent);
339
+ // createSkillBackup mock
340
+ mockedHelpers.createSkillBackup.mockResolvedValue('/backup/path/test-skill');
341
+ // fs operations for writing conflict file
342
+ mockedFs.mkdir.mockResolvedValue(undefined);
343
+ mockedFs.writeFile.mockResolvedValue(undefined);
344
+ const result = await handleMergeAction('test-skill', '/path/to/skill', upstreamContent, manifest, 'owner', 'repo', 'owner/test-skill');
345
+ expect(result.shouldProceed).toBe(false);
346
+ expect(result.backupPath).toBeDefined();
347
+ expect(result.earlyReturn).toBeDefined();
348
+ expect(result.earlyReturn.mergeResult).toBeDefined();
349
+ expect(result.earlyReturn.mergeResult.conflicts.length).toBeGreaterThan(0);
350
+ expect(result.earlyReturn.tips).toBeDefined();
351
+ expect(result.earlyReturn.tips).toContainEqual(expect.stringContaining('conflict'));
352
+ });
353
+ });
354
+ //# sourceMappingURL=install.conflict.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.conflict.test.js","sourceRoot":"","sources":["../../../src/tools/install.conflict.test.ts"],"names":[],"mappings":"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"}
@@ -11,50 +11,10 @@
11
11
  * - Optional file fetching (README.md, examples.md, config.json)
12
12
  *
13
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
14
  */
33
- import { z } from 'zod';
34
- import { type ScanReport } from '@skillsmith/core';
35
15
  import type { ToolContext } from '../context.js';
36
- export declare const installInputSchema: z.ZodObject<{
37
- skillId: z.ZodString;
38
- force: z.ZodDefault<z.ZodBoolean>;
39
- skipScan: z.ZodDefault<z.ZodBoolean>;
40
- }, "strip", z.ZodTypeAny, {
41
- skillId: string;
42
- force: boolean;
43
- skipScan: boolean;
44
- }, {
45
- skillId: string;
46
- force?: boolean | undefined;
47
- skipScan?: boolean | undefined;
48
- }>;
49
- export type InstallInput = z.infer<typeof installInputSchema>;
50
- export interface InstallResult {
51
- success: boolean;
52
- skillId: string;
53
- installPath: string;
54
- securityReport?: ScanReport;
55
- tips?: string[];
56
- error?: string;
57
- }
16
+ import { type InstallInput, type InstallResult } from './install.types.js';
17
+ export { installInputSchema, type InstallInput, type InstallResult } from './install.types.js';
58
18
  /**
59
19
  * Install a skill from GitHub to the local Claude Code skills directory.
60
20
  *
@@ -73,24 +33,6 @@ export interface InstallResult {
73
33
  * @param input.force - Force reinstall if skill already exists (default: false)
74
34
  * @param input.skipScan - Skip security scan (default: false, not recommended)
75
35
  * @returns Promise resolving to installation result with success status
76
- *
77
- * @example
78
- * // Successful installation
79
- * const result = await installSkill({ skillId: 'anthropic/commit' });
80
- * if (result.success) {
81
- * console.log(`Installed to ${result.installPath}`);
82
- * result.tips?.forEach(tip => console.log(tip));
83
- * }
84
- *
85
- * @example
86
- * // Handle security scan failure
87
- * const result = await installSkill({ skillId: 'untrusted/skill' });
88
- * if (!result.success && result.securityReport) {
89
- * console.log('Security issues found:');
90
- * result.securityReport.findings.forEach(f =>
91
- * console.log(` ${f.severity}: ${f.message}`)
92
- * );
93
- * }
94
36
  */
95
37
  export declare function installSkill(input: InstallInput, _context?: ToolContext): Promise<InstallResult>;
96
38
  /**
@@ -114,6 +56,15 @@ export declare const installTool: {
114
56
  type: string;
115
57
  description: string;
116
58
  };
59
+ skipOptimize: {
60
+ type: string;
61
+ description: string;
62
+ };
63
+ conflictAction: {
64
+ type: string;
65
+ enum: string[];
66
+ description: string;
67
+ };
117
68
  };
118
69
  required: string[];
119
70
  };
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/tools/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAInE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAIhD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAI7B,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAG7D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,UAAU,CAAA;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AA2PD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,YAAY,EACnB,QAAQ,CAAC,EAAE,WAAW,GACrB,OAAO,CAAC,aAAa,CAAC,CAgMxB;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;CAsBvB,CAAA;AAED,eAAe,WAAW,CAAA"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/tools/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAIhD,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,aAAa,EAEnB,MAAM,oBAAoB,CAAA;AAoB3B,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAE9F;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,YAAY,EACnB,QAAQ,CAAC,EAAE,WAAW,GACrB,OAAO,CAAC,aAAa,CAAC,CAsYxB;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCvB,CAAA;AAED,eAAe,WAAW,CAAA"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @fileoverview Install Tool Helper Functions
3
+ * @module @skillsmith/mcp-server/tools/install.helpers
4
+ */
5
+ import type { ToolContext } from '../context.js';
6
+ import { type SkillManifest, type ParsedSkillId, type ParsedRepoUrl, type RegistrySkillInfo } from './install.types.js';
7
+ /**
8
+ * Acquire a file lock for manifest operations
9
+ * SMI-1533: Prevents race conditions during concurrent installs
10
+ */
11
+ export declare function acquireManifestLock(): Promise<void>;
12
+ /**
13
+ * Release the manifest lock
14
+ */
15
+ export declare function releaseManifestLock(): Promise<void>;
16
+ /**
17
+ * Load or create manifest
18
+ */
19
+ export declare function loadManifest(): Promise<SkillManifest>;
20
+ /**
21
+ * Save manifest
22
+ * SMI-1533: Uses atomic write pattern with lock
23
+ */
24
+ export declare function saveManifest(manifest: SkillManifest): Promise<void>;
25
+ /**
26
+ * SMI-1533: Safely update manifest with locking
27
+ * Prevents race conditions during concurrent install operations
28
+ */
29
+ export declare function updateManifestSafely(updateFn: (manifest: SkillManifest) => SkillManifest): Promise<void>;
30
+ /**
31
+ * Parse skill ID or URL to get components
32
+ * SMI-1491: Added isRegistryId flag to detect registry skill IDs vs direct GitHub URLs
33
+ */
34
+ export declare function parseSkillId(input: string): ParsedSkillId;
35
+ /**
36
+ * Parse repo_url from registry to extract GitHub components
37
+ * SMI-1491: Handles various GitHub URL formats stored in registry
38
+ */
39
+ export declare function parseRepoUrl(repoUrl: string): ParsedRepoUrl;
40
+ /**
41
+ * Look up skill in registry to get repo_url
42
+ * SMI-1491: Enables install to work with registry IDs like "author/skill-name"
43
+ *
44
+ * Follows API-first pattern: tries live API, falls back to local DB
45
+ */
46
+ export declare function lookupSkillFromRegistry(skillId: string, context: ToolContext): Promise<RegistrySkillInfo | null>;
47
+ /**
48
+ * Fetch file from GitHub
49
+ * SMI-1491: Added optional branch parameter to use branch from repo_url
50
+ */
51
+ export declare function fetchFromGitHub(owner: string, repo: string, filePath: string, branch?: string): Promise<string>;
52
+ /** Validation result for SKILL.md */
53
+ export interface SkillMdValidation {
54
+ valid: boolean;
55
+ errors: string[];
56
+ }
57
+ /**
58
+ * Validate SKILL.md content
59
+ */
60
+ export declare function validateSkillMd(content: string): SkillMdValidation;
61
+ /**
62
+ * Generate post-install tips
63
+ */
64
+ export declare function generateTips(skillName: string): string[];
65
+ /**
66
+ * SMI-1788: Optimization info type for tips generation
67
+ * SMI-1803: Exported for external use
68
+ */
69
+ export interface OptimizationInfoForTips {
70
+ optimized: boolean;
71
+ subSkills?: string[];
72
+ subagentGenerated?: boolean;
73
+ subagentPath?: string;
74
+ tokenReductionPercent?: number;
75
+ originalLines?: number;
76
+ optimizedLines?: number;
77
+ }
78
+ /**
79
+ * SMI-1788: Generate post-install tips with optimization info
80
+ */
81
+ export declare function generateOptimizedTips(skillName: string, optimizationInfo: OptimizationInfoForTips, claudeMdSnippet?: string): string[];
82
+ export { hashContent, type ModificationResult, detectModifications, createSkillBackup, storeOriginal, loadOriginal, cleanupOldBackups, getBackupsDir, } from './install.conflict-helpers.js';
83
+ //# sourceMappingURL=install.helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.helpers.d.ts","sourceRoot":"","sources":["../../../src/tools/install.helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAA;AAa3B;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAoCzD;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMzD;AAMD;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAU3D;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAMzE;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,aAAa,GACnD,OAAO,CAAC,IAAI,CAAC,CASf;AAMD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAsCzD;AAQD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAiC3D;AAMD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAgCnC;AAMD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAe,GACtB,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAMD,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAiBlE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAOxD;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,uBAAuB,EACzC,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,EAAE,CAmDV;AAQD,OAAO,EACL,WAAW,EACX,KAAK,kBAAkB,EACvB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,aAAa,GACd,MAAM,+BAA+B,CAAA"}