@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,277 @@
1
+ /**
2
+ * Tests for SMI-1837: Include Local Skills in Recommendations
3
+ * Verifies that local skills are searched in parallel with the API,
4
+ * not just as a fallback.
5
+ */
6
+ import { describe, it, expect, beforeAll, afterAll, vi, beforeEach, afterEach } from 'vitest';
7
+ import { executeRecommend, formatRecommendations } from '../tools/recommend.js';
8
+ import { createSeededTestContext } from './test-utils.js';
9
+ import * as LocalSkillSearchModule from '../tools/LocalSkillSearch.js';
10
+ let context;
11
+ beforeAll(() => {
12
+ context = createSeededTestContext();
13
+ });
14
+ afterAll(() => {
15
+ context.db.close();
16
+ });
17
+ describe('Recommend Tool', () => {
18
+ describe('executeRecommend - basic functionality', () => {
19
+ it('should return recommendations for project context', async () => {
20
+ const result = await executeRecommend({
21
+ project_context: 'React frontend with testing',
22
+ limit: 5,
23
+ }, context);
24
+ expect(result.recommendations).toBeDefined();
25
+ expect(Array.isArray(result.recommendations)).toBe(true);
26
+ expect(result.context.has_project_context).toBe(true);
27
+ expect(result.timing.totalMs).toBeGreaterThanOrEqual(0);
28
+ });
29
+ it('should return recommendations with installed skills', async () => {
30
+ const result = await executeRecommend({
31
+ installed_skills: ['anthropic/commit'],
32
+ limit: 5,
33
+ }, context);
34
+ expect(result.recommendations).toBeDefined();
35
+ expect(result.context.installed_count).toBe(1);
36
+ // Should not recommend the already installed skill
37
+ const hasInstalledSkill = result.recommendations.some((r) => r.skill_id === 'anthropic/commit');
38
+ expect(hasInstalledSkill).toBe(false);
39
+ });
40
+ });
41
+ describe('formatRecommendations', () => {
42
+ it('should format results for terminal display', async () => {
43
+ const result = await executeRecommend({
44
+ project_context: 'testing',
45
+ limit: 3,
46
+ }, context);
47
+ const formatted = formatRecommendations(result);
48
+ expect(formatted).toContain('Skill Recommendations');
49
+ });
50
+ it('should show helpful message when no results', async () => {
51
+ const emptyResult = {
52
+ recommendations: [],
53
+ candidates_considered: 0,
54
+ overlap_filtered: 0,
55
+ role_filtered: 0,
56
+ context: {
57
+ installed_count: 0,
58
+ has_project_context: false,
59
+ using_semantic_matching: true,
60
+ auto_detected: false,
61
+ },
62
+ timing: { totalMs: 10 },
63
+ };
64
+ const formatted = formatRecommendations(emptyResult);
65
+ expect(formatted).toContain('No recommendations found');
66
+ expect(formatted).toContain('Suggestions:');
67
+ });
68
+ });
69
+ });
70
+ /**
71
+ * SMI-1837: Tests for parallel local skill search integration
72
+ */
73
+ describe('Recommend Tool - Local Skill Integration (SMI-1837)', () => {
74
+ let branchContext;
75
+ // Mock local skills for testing
76
+ const mockLocalSkills = [
77
+ {
78
+ id: 'local/my-commit-helper',
79
+ name: 'my-commit-helper',
80
+ description: 'Personal commit message helper',
81
+ author: 'local',
82
+ tags: ['git', 'commit', 'personal'],
83
+ qualityScore: 75,
84
+ trustTier: 'local',
85
+ source: 'local',
86
+ path: '/home/user/.claude/skills/my-commit-helper',
87
+ hasSkillMd: true,
88
+ lastModified: new Date().toISOString(),
89
+ },
90
+ {
91
+ id: 'local/react-patterns',
92
+ name: 'react-patterns',
93
+ description: 'React component patterns and best practices',
94
+ author: 'local',
95
+ tags: ['react', 'patterns', 'components'],
96
+ qualityScore: 80,
97
+ trustTier: 'local',
98
+ source: 'local',
99
+ path: '/home/user/.claude/skills/react-patterns',
100
+ hasSkillMd: true,
101
+ lastModified: new Date().toISOString(),
102
+ },
103
+ {
104
+ id: 'local/testing-utils',
105
+ name: 'testing-utils',
106
+ description: 'Testing utilities and helpers',
107
+ author: 'local',
108
+ tags: ['testing', 'jest', 'vitest'],
109
+ qualityScore: 70,
110
+ trustTier: 'local',
111
+ source: 'local',
112
+ path: '/home/user/.claude/skills/testing-utils',
113
+ hasSkillMd: true,
114
+ lastModified: new Date().toISOString(),
115
+ },
116
+ ];
117
+ beforeAll(() => {
118
+ branchContext = createSeededTestContext();
119
+ });
120
+ afterAll(() => {
121
+ branchContext.db.close();
122
+ });
123
+ beforeEach(() => {
124
+ // Mock the local indexer to return controlled test data
125
+ vi.spyOn(LocalSkillSearchModule, 'getLocalIndexer').mockReturnValue({
126
+ index: vi.fn().mockResolvedValue(mockLocalSkills),
127
+ indexSync: vi.fn().mockReturnValue(mockLocalSkills),
128
+ search: vi.fn((query, skills) => {
129
+ const lowerQuery = query.toLowerCase();
130
+ return skills.filter((s) => s.name.toLowerCase().includes(lowerQuery) ||
131
+ s.description?.toLowerCase().includes(lowerQuery) ||
132
+ s.tags.some((t) => t.toLowerCase().includes(lowerQuery)));
133
+ }),
134
+ clearCache: vi.fn(),
135
+ getSkillsDir: vi.fn().mockReturnValue('/home/user/.claude/skills'),
136
+ calculateQualityScore: vi.fn().mockReturnValue(75),
137
+ indexSkillDir: vi.fn(),
138
+ });
139
+ });
140
+ afterEach(() => {
141
+ vi.restoreAllMocks();
142
+ });
143
+ describe('parallel local search', () => {
144
+ it('should include local skills in recommendations when API is offline', async () => {
145
+ // Context is created with offline mode, so it will use local matching
146
+ const result = await executeRecommend({
147
+ project_context: 'React testing project',
148
+ limit: 10,
149
+ }, branchContext);
150
+ expect(result.recommendations).toBeDefined();
151
+ expect(result.timing.totalMs).toBeGreaterThanOrEqual(0);
152
+ expect(result.timing.totalMs).toBeLessThan(500); // Performance requirement
153
+ });
154
+ it('should not have duplicate skills in results', async () => {
155
+ const result = await executeRecommend({
156
+ project_context: 'commit automation',
157
+ limit: 10,
158
+ }, branchContext);
159
+ // Check for duplicate skill_ids
160
+ const skillIds = result.recommendations.map((r) => r.skill_id);
161
+ const uniqueIds = new Set(skillIds);
162
+ expect(skillIds.length).toBe(uniqueIds.size);
163
+ });
164
+ it('should complete within performance target (<500ms)', async () => {
165
+ const startTime = performance.now();
166
+ await executeRecommend({
167
+ project_context: 'JavaScript development',
168
+ installed_skills: ['anthropic/commit'],
169
+ limit: 10,
170
+ }, branchContext);
171
+ const endTime = performance.now();
172
+ const duration = endTime - startTime;
173
+ expect(duration).toBeLessThan(500);
174
+ });
175
+ it('should handle empty local skills gracefully', async () => {
176
+ // Mock empty local skills
177
+ vi.spyOn(LocalSkillSearchModule, 'getLocalIndexer').mockReturnValue({
178
+ index: vi.fn().mockResolvedValue([]),
179
+ indexSync: vi.fn().mockReturnValue([]),
180
+ search: vi.fn().mockReturnValue([]),
181
+ clearCache: vi.fn(),
182
+ getSkillsDir: vi.fn().mockReturnValue('/home/user/.claude/skills'),
183
+ calculateQualityScore: vi.fn().mockReturnValue(0),
184
+ indexSkillDir: vi.fn(),
185
+ });
186
+ const result = await executeRecommend({
187
+ project_context: 'testing',
188
+ limit: 5,
189
+ }, branchContext);
190
+ // Should still return database results
191
+ expect(result.recommendations).toBeDefined();
192
+ expect(Array.isArray(result.recommendations)).toBe(true);
193
+ });
194
+ it('should handle local indexer errors gracefully', async () => {
195
+ // Mock indexer that throws an error
196
+ vi.spyOn(LocalSkillSearchModule, 'getLocalIndexer').mockReturnValue({
197
+ index: vi.fn().mockRejectedValue(new Error('Indexer failed')),
198
+ indexSync: vi.fn().mockImplementation(() => {
199
+ throw new Error('Indexer failed');
200
+ }),
201
+ search: vi.fn().mockReturnValue([]),
202
+ clearCache: vi.fn(),
203
+ getSkillsDir: vi.fn().mockReturnValue('/home/user/.claude/skills'),
204
+ calculateQualityScore: vi.fn().mockReturnValue(0),
205
+ indexSkillDir: vi.fn(),
206
+ });
207
+ // Should not throw, should fall back gracefully
208
+ const result = await executeRecommend({
209
+ project_context: 'testing',
210
+ limit: 5,
211
+ }, branchContext);
212
+ expect(result.recommendations).toBeDefined();
213
+ });
214
+ });
215
+ describe('deduplication logic', () => {
216
+ it('should prefer registry skills over local skills with same name', async () => {
217
+ // Create a local skill with same name as registry skill
218
+ const duplicateMockSkills = [
219
+ {
220
+ id: 'local/commit',
221
+ name: 'commit',
222
+ description: 'Local commit helper (duplicate of anthropic/commit)',
223
+ author: 'local',
224
+ tags: ['git', 'commit'],
225
+ qualityScore: 60,
226
+ trustTier: 'local',
227
+ source: 'local',
228
+ path: '/home/user/.claude/skills/commit',
229
+ hasSkillMd: true,
230
+ lastModified: new Date().toISOString(),
231
+ },
232
+ ];
233
+ vi.spyOn(LocalSkillSearchModule, 'getLocalIndexer').mockReturnValue({
234
+ index: vi.fn().mockResolvedValue(duplicateMockSkills),
235
+ indexSync: vi.fn().mockReturnValue(duplicateMockSkills),
236
+ search: vi.fn().mockReturnValue(duplicateMockSkills),
237
+ clearCache: vi.fn(),
238
+ getSkillsDir: vi.fn().mockReturnValue('/home/user/.claude/skills'),
239
+ calculateQualityScore: vi.fn().mockReturnValue(60),
240
+ indexSkillDir: vi.fn(),
241
+ });
242
+ const result = await executeRecommend({
243
+ project_context: 'git workflow',
244
+ limit: 10,
245
+ }, branchContext);
246
+ // Should not have both 'anthropic/commit' and 'local/commit'
247
+ const commitSkills = result.recommendations.filter((r) => r.name === 'commit' || r.skill_id.includes('commit'));
248
+ // If there's a commit skill, registry should take precedence
249
+ if (commitSkills.length > 0) {
250
+ const hasRegistryCommit = commitSkills.some((s) => s.skill_id === 'anthropic/commit');
251
+ const hasLocalCommit = commitSkills.some((s) => s.skill_id === 'local/commit');
252
+ // Should not have local duplicate if registry version exists
253
+ if (hasRegistryCommit) {
254
+ expect(hasLocalCommit).toBe(false);
255
+ }
256
+ }
257
+ });
258
+ });
259
+ describe('role filtering with local skills', () => {
260
+ it('should apply role filter to local skills', async () => {
261
+ const result = await executeRecommend({
262
+ project_context: 'testing project',
263
+ role: 'testing',
264
+ limit: 10,
265
+ }, branchContext);
266
+ // All results should have testing role if role filter is applied
267
+ if (result.recommendations.length > 0 && result.context.role_filter) {
268
+ result.recommendations.forEach((rec) => {
269
+ if (rec.roles) {
270
+ expect(rec.roles).toContain('testing');
271
+ }
272
+ });
273
+ }
274
+ });
275
+ });
276
+ });
277
+ //# sourceMappingURL=recommend.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recommend.test.js","sourceRoot":"","sources":["../../../src/__tests__/recommend.test.ts"],"names":[],"mappings":"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"}
@@ -61,8 +61,9 @@ describe('Search Tool', () => {
61
61
  it('should throw error for empty query', async () => {
62
62
  await expect(executeSearch({ query: '' }, context)).rejects.toThrow(SkillsmithError);
63
63
  });
64
- it('should throw error for query less than 2 characters', async () => {
64
+ it('should throw error for query less than 3 characters', async () => {
65
65
  await expect(executeSearch({ query: 'a' }, context)).rejects.toThrow(SkillsmithError);
66
+ await expect(executeSearch({ query: 'ab' }, context)).rejects.toThrow(SkillsmithError);
66
67
  });
67
68
  it('should throw error for invalid min_score', async () => {
68
69
  await expect(executeSearch({ query: 'test', min_score: 150 }, context)).rejects.toThrow(SkillsmithError);
@@ -83,4 +84,142 @@ describe('Search Tool', () => {
83
84
  });
84
85
  });
85
86
  });
87
+ /**
88
+ * SMI-1785: Additional tests for search.ts branch coverage
89
+ * Covers validation errors, filter combinations, and edge cases
90
+ */
91
+ describe('Search Tool branch coverage', () => {
92
+ let branchContext;
93
+ beforeAll(() => {
94
+ branchContext = createSeededTestContext();
95
+ });
96
+ afterAll(() => {
97
+ branchContext.db.close();
98
+ });
99
+ describe('validation errors', () => {
100
+ it('should throw error for negative min_score', async () => {
101
+ await expect(executeSearch({ query: 'test', min_score: -10 }, branchContext)).rejects.toThrow(SkillsmithError);
102
+ });
103
+ it('should throw error for invalid trust_tier', async () => {
104
+ try {
105
+ await executeSearch({ query: 'test', trust_tier: 'invalid_tier' }, branchContext);
106
+ expect.fail('Should have thrown an error');
107
+ }
108
+ catch (error) {
109
+ expect(error).toBeInstanceOf(SkillsmithError);
110
+ expect(error.message).toContain('Invalid trust_tier');
111
+ expect(error.message).toContain('invalid_tier');
112
+ }
113
+ });
114
+ it('should throw error for negative max_risk', async () => {
115
+ try {
116
+ await executeSearch({ query: 'test', max_risk: -5 }, branchContext);
117
+ expect.fail('Should have thrown an error');
118
+ }
119
+ catch (error) {
120
+ expect(error).toBeInstanceOf(SkillsmithError);
121
+ expect(error.message).toContain('max_risk must be between 0 and 100');
122
+ }
123
+ });
124
+ it('should throw error for max_risk over 100', async () => {
125
+ try {
126
+ await executeSearch({ query: 'test', max_risk: 150 }, branchContext);
127
+ expect.fail('Should have thrown an error');
128
+ }
129
+ catch (error) {
130
+ expect(error).toBeInstanceOf(SkillsmithError);
131
+ expect(error.message).toContain('max_risk must be between 0 and 100');
132
+ }
133
+ });
134
+ });
135
+ describe('security filters', () => {
136
+ it('should accept safe_only filter', async () => {
137
+ const result = await executeSearch({
138
+ query: 'commit',
139
+ safe_only: true,
140
+ }, branchContext);
141
+ expect(result.results).toBeDefined();
142
+ expect(result.filters.safeOnly).toBe(true);
143
+ });
144
+ it('should accept max_risk filter', async () => {
145
+ const result = await executeSearch({
146
+ query: 'commit',
147
+ max_risk: 50,
148
+ }, branchContext);
149
+ expect(result.results).toBeDefined();
150
+ expect(result.filters.maxRiskScore).toBe(50);
151
+ });
152
+ });
153
+ describe('filter-only search (no query)', () => {
154
+ it('should allow search with only category filter', async () => {
155
+ const result = await executeSearch({
156
+ category: 'testing',
157
+ }, branchContext);
158
+ expect(result.results).toBeDefined();
159
+ expect(result.query).toBe('');
160
+ expect(result.filters.category).toBe('testing');
161
+ });
162
+ it('should allow search with only trust_tier filter', async () => {
163
+ const result = await executeSearch({
164
+ trust_tier: 'verified',
165
+ }, branchContext);
166
+ expect(result.results).toBeDefined();
167
+ expect(result.query).toBe('');
168
+ expect(result.filters.trustTier).toBe('verified');
169
+ });
170
+ it('should allow search with only min_score filter', async () => {
171
+ const result = await executeSearch({
172
+ min_score: 90,
173
+ }, branchContext);
174
+ expect(result.results).toBeDefined();
175
+ expect(result.query).toBe('');
176
+ });
177
+ it('should allow search with only safe_only filter', async () => {
178
+ const result = await executeSearch({
179
+ safe_only: true,
180
+ }, branchContext);
181
+ expect(result.results).toBeDefined();
182
+ expect(result.query).toBe('');
183
+ expect(result.filters.safeOnly).toBe(true);
184
+ });
185
+ it('should allow search with only max_risk filter', async () => {
186
+ const result = await executeSearch({
187
+ max_risk: 30,
188
+ }, branchContext);
189
+ expect(result.results).toBeDefined();
190
+ expect(result.query).toBe('');
191
+ expect(result.filters.maxRiskScore).toBe(30);
192
+ });
193
+ it('should allow search with multiple filters (no query)', async () => {
194
+ const result = await executeSearch({
195
+ category: 'testing',
196
+ trust_tier: 'community',
197
+ min_score: 70,
198
+ safe_only: true,
199
+ }, branchContext);
200
+ expect(result.results).toBeDefined();
201
+ expect(result.query).toBe('');
202
+ expect(result.filters.category).toBe('testing');
203
+ expect(result.filters.trustTier).toBe('community');
204
+ expect(result.filters.safeOnly).toBe(true);
205
+ });
206
+ });
207
+ describe('combined query and filters', () => {
208
+ it('should accept all filters together', async () => {
209
+ const result = await executeSearch({
210
+ query: 'test',
211
+ category: 'testing',
212
+ trust_tier: 'community',
213
+ min_score: 70,
214
+ safe_only: true,
215
+ max_risk: 40,
216
+ }, branchContext);
217
+ expect(result.results).toBeDefined();
218
+ expect(result.filters.category).toBe('testing');
219
+ expect(result.filters.trustTier).toBe('community');
220
+ expect(result.filters.safeOnly).toBe(true);
221
+ expect(result.filters.maxRiskScore).toBe(40);
222
+ });
223
+ });
224
+ });
86
225
  //# sourceMappingURL=search.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.test.js","sourceRoot":"","sources":["../../../src/__tests__/search.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search.test.js","sourceRoot":"","sources":["../../../src/__tests__/search.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * SMI-1602: Validation utility tests
3
+ *
4
+ * Tests for validation functions to increase branch coverage.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=validation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/utils/validation.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * SMI-1602: Validation utility tests
3
+ *
4
+ * Tests for validation functions to increase branch coverage.
5
+ */
6
+ import { describe, it, expect } from 'vitest';
7
+ import { parseSkillId, mapTrustTierToDb, mapTrustTierFromDb, extractCategoryFromTags, } from '../../utils/validation.js';
8
+ describe('Validation Utilities', () => {
9
+ describe('parseSkillId', () => {
10
+ it('should parse 2-part skill ID (author/name)', () => {
11
+ const result = parseSkillId('anthropic/commit');
12
+ expect(result).toEqual({ author: 'anthropic', name: 'commit' });
13
+ });
14
+ it('should parse 3-part skill ID (source/author/name)', () => {
15
+ const result = parseSkillId('github/cyanheads/git-mcp-server');
16
+ expect(result).toEqual({
17
+ source: 'github',
18
+ author: 'cyanheads',
19
+ name: 'git-mcp-server',
20
+ });
21
+ });
22
+ it('should return null for invalid skill ID', () => {
23
+ expect(parseSkillId('invalid')).toBeNull();
24
+ expect(parseSkillId('')).toBeNull();
25
+ expect(parseSkillId('too/many/parts/here')).toBeNull();
26
+ });
27
+ });
28
+ describe('mapTrustTierToDb', () => {
29
+ it('should map verified tier', () => {
30
+ expect(mapTrustTierToDb('verified')).toBe('verified');
31
+ });
32
+ it('should map community tier', () => {
33
+ expect(mapTrustTierToDb('community')).toBe('community');
34
+ });
35
+ it('should map experimental tier', () => {
36
+ expect(mapTrustTierToDb('experimental')).toBe('experimental');
37
+ });
38
+ it('should map unknown tier', () => {
39
+ expect(mapTrustTierToDb('unknown')).toBe('unknown');
40
+ });
41
+ });
42
+ describe('mapTrustTierFromDb', () => {
43
+ it('should map verified tier', () => {
44
+ expect(mapTrustTierFromDb('verified')).toBe('verified');
45
+ });
46
+ it('should map community tier', () => {
47
+ expect(mapTrustTierFromDb('community')).toBe('community');
48
+ });
49
+ it('should map experimental tier', () => {
50
+ expect(mapTrustTierFromDb('experimental')).toBe('experimental');
51
+ });
52
+ it('should map unknown tier', () => {
53
+ expect(mapTrustTierFromDb('unknown')).toBe('unknown');
54
+ });
55
+ it('should return unknown for unrecognized string', () => {
56
+ // The function accepts string input and handles invalid values gracefully
57
+ const invalidValue = 'invalid';
58
+ expect(mapTrustTierFromDb(invalidValue)).toBe('unknown');
59
+ });
60
+ });
61
+ describe('extractCategoryFromTags', () => {
62
+ it('should return "other" for null tags', () => {
63
+ expect(extractCategoryFromTags(null)).toBe('other');
64
+ });
65
+ it('should return "other" for undefined tags', () => {
66
+ expect(extractCategoryFromTags(undefined)).toBe('other');
67
+ });
68
+ it('should return "other" for empty tags array', () => {
69
+ expect(extractCategoryFromTags([])).toBe('other');
70
+ });
71
+ it('should extract testing category', () => {
72
+ expect(extractCategoryFromTags(['testing', 'jest'])).toBe('testing');
73
+ });
74
+ it('should extract development category', () => {
75
+ expect(extractCategoryFromTags(['development', 'react'])).toBe('development');
76
+ });
77
+ it('should return "other" for unrecognized tags', () => {
78
+ expect(extractCategoryFromTags(['random', 'tags'])).toBe('other');
79
+ });
80
+ });
81
+ });
82
+ //# sourceMappingURL=validation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.test.js","sourceRoot":"","sources":["../../../../src/__tests__/utils/validation.test.ts"],"names":[],"mappings":"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"}
@@ -19,10 +19,12 @@
19
19
  */
20
20
  import type { Database as DatabaseType } from 'better-sqlite3';
21
21
  import { SearchService, SkillRepository, SkillsmithApiClient, BackgroundSyncService, type ApiClientConfig } from '@skillsmith/core';
22
+ import { LLMFailoverChain, type LLMFailoverConfig } from './llm/failover.js';
22
23
  /**
23
24
  * Shared context for MCP tool handlers
24
25
  * SMI-1183: Added apiClient for live API access with local fallback
25
26
  * SMI-1184: Added distinctId for telemetry tracking
27
+ * SMI-1524: Added llmFailover for multi-LLM support with circuit breaker
26
28
  */
27
29
  export interface ToolContext {
28
30
  /** SQLite database connection */
@@ -37,6 +39,13 @@ export interface ToolContext {
37
39
  distinctId?: string;
38
40
  /** Background sync service (if enabled) */
39
41
  backgroundSync?: BackgroundSyncService;
42
+ /** LLM failover chain for multi-provider support (SMI-1524) */
43
+ llmFailover?: LLMFailoverChain;
44
+ /** Internal: Signal handlers for cleanup (prevents memory leaks) */
45
+ _signalHandlers?: Array<{
46
+ signal: NodeJS.Signals;
47
+ handler: () => void;
48
+ }>;
40
49
  }
41
50
  /**
42
51
  * Telemetry configuration for PostHog (SMI-1184)
@@ -83,6 +92,12 @@ export interface ToolContextOptions {
83
92
  searchCacheTtl?: number;
84
93
  /** API client configuration (SMI-1183) */
85
94
  apiClientConfig?: ApiClientConfig;
95
+ /**
96
+ * API key for authenticated requests
97
+ * Can also be set via SKILLSMITH_API_KEY env var
98
+ * SMI-XXXX: API Key Authentication
99
+ */
100
+ apiKey?: string;
86
101
  /**
87
102
  * Telemetry configuration (SMI-1184)
88
103
  * Privacy-first: telemetry is OPT-IN and disabled by default
@@ -93,6 +108,12 @@ export interface ToolContextOptions {
93
108
  * Enables automatic registry sync during MCP server sessions
94
109
  */
95
110
  backgroundSyncConfig?: BackgroundSyncConfig;
111
+ /**
112
+ * LLM failover chain configuration (SMI-1524)
113
+ * Enables multi-provider LLM support with automatic failover
114
+ * Disabled by default - set enabled: true to activate
115
+ */
116
+ llmFailoverConfig?: LLMFailoverConfig;
96
117
  }
97
118
  /**
98
119
  * Get the default database path
@@ -134,6 +155,7 @@ export declare function createToolContext(options?: ToolContextOptions): ToolCon
134
155
  /**
135
156
  * Close the tool context and release resources
136
157
  * SMI-1184: Also shuts down PostHog telemetry if initialized
158
+ * SMI-1524: Also closes LLM failover chain
137
159
  *
138
160
  * @param context - Tool context to close
139
161
  */
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAEL,aAAa,EACb,eAAe,EAEf,mBAAmB,EAOnB,qBAAqB,EACrB,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAA;AAEzB;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,EAAE,EAAE,YAAY,CAAA;IAChB,+CAA+C;IAC/C,aAAa,EAAE,aAAa,CAAA;IAC5B,sDAAsD;IACtD,eAAe,EAAE,eAAe,CAAA;IAChC,iDAAiD;IACjD,SAAS,EAAE,mBAAmB,CAAA;IAC9B,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,cAAc,CAAC,EAAE,qBAAqB,CAAA;CACvC;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,0CAA0C;IAC1C,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC;;;OAGG;IACH,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC;;;OAGG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;CAC5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAqBzC;AAYD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CA0H/E;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAa1E;AAKD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,WAAW,CAUxE;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAKtD"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAGL,aAAa,EACb,eAAe,EAEf,mBAAmB,EAOnB,qBAAqB,EAErB,KAAK,eAAe,EAErB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE5E;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,EAAE,EAAE,YAAY,CAAA;IAChB,+CAA+C;IAC/C,aAAa,EAAE,aAAa,CAAA;IAC5B,sDAAsD;IACtD,eAAe,EAAE,eAAe,CAAA;IAChC,iDAAiD;IACjD,SAAS,EAAE,mBAAmB,CAAA;IAC9B,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,cAAc,CAAC,EAAE,qBAAqB,CAAA;IACtC,+DAA+D;IAC/D,WAAW,CAAC,EAAE,gBAAgB,CAAA;IAC9B,oEAAoE;IACpE,eAAe,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC,CAAA;CACzE;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,0CAA0C;IAC1C,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC;;;OAGG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;CACtC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAqBzC;AAeD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CA+K/E;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB1E;AAKD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,WAAW,CAUxE;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAKtD"}