swift-skills-mcp 0.0.1

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 (247) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +410 -0
  3. package/build/cli/auth.d.ts +3 -0
  4. package/build/cli/auth.d.ts.map +1 -0
  5. package/build/cli/auth.js +44 -0
  6. package/build/cli/auth.js.map +1 -0
  7. package/build/cli/setup.d.ts +2 -0
  8. package/build/cli/setup.d.ts.map +1 -0
  9. package/build/cli/setup.js +150 -0
  10. package/build/cli/setup.js.map +1 -0
  11. package/build/cli/source-manager.d.ts +3 -0
  12. package/build/cli/source-manager.d.ts.map +1 -0
  13. package/build/cli/source-manager.js +117 -0
  14. package/build/cli/source-manager.js.map +1 -0
  15. package/build/config/creators.d.ts +11 -0
  16. package/build/config/creators.d.ts.map +1 -0
  17. package/build/config/creators.js +32 -0
  18. package/build/config/creators.js.map +1 -0
  19. package/build/config/sources.d.ts +91 -0
  20. package/build/config/sources.d.ts.map +1 -0
  21. package/build/config/sources.js +231 -0
  22. package/build/config/sources.js.map +1 -0
  23. package/build/config/sources.test.d.ts +2 -0
  24. package/build/config/sources.test.d.ts.map +1 -0
  25. package/build/config/sources.test.js +199 -0
  26. package/build/config/sources.test.js.map +1 -0
  27. package/build/config/swift-keywords.d.ts +29 -0
  28. package/build/config/swift-keywords.d.ts.map +1 -0
  29. package/build/config/swift-keywords.js +77 -0
  30. package/build/config/swift-keywords.js.map +1 -0
  31. package/build/index.d.ts +3 -0
  32. package/build/index.d.ts.map +1 -0
  33. package/build/index.js +181 -0
  34. package/build/index.js.map +1 -0
  35. package/build/integration/cache-behavior.test.d.ts +2 -0
  36. package/build/integration/cache-behavior.test.d.ts.map +1 -0
  37. package/build/integration/cache-behavior.test.js +521 -0
  38. package/build/integration/cache-behavior.test.js.map +1 -0
  39. package/build/integration/mcp-client.test.d.ts +2 -0
  40. package/build/integration/mcp-client.test.d.ts.map +1 -0
  41. package/build/integration/mcp-client.test.js +82 -0
  42. package/build/integration/mcp-client.test.js.map +1 -0
  43. package/build/integration/response-quality.test.d.ts +2 -0
  44. package/build/integration/response-quality.test.d.ts.map +1 -0
  45. package/build/integration/response-quality.test.js +230 -0
  46. package/build/integration/response-quality.test.js.map +1 -0
  47. package/build/integration/test-client.d.ts +25 -0
  48. package/build/integration/test-client.d.ts.map +1 -0
  49. package/build/integration/test-client.js +93 -0
  50. package/build/integration/test-client.js.map +1 -0
  51. package/build/sources/free/nilcoalescing.d.ts +8 -0
  52. package/build/sources/free/nilcoalescing.d.ts.map +1 -0
  53. package/build/sources/free/nilcoalescing.js +26 -0
  54. package/build/sources/free/nilcoalescing.js.map +1 -0
  55. package/build/sources/free/nilcoalescing.test.d.ts +2 -0
  56. package/build/sources/free/nilcoalescing.test.d.ts.map +1 -0
  57. package/build/sources/free/nilcoalescing.test.js +63 -0
  58. package/build/sources/free/nilcoalescing.test.js.map +1 -0
  59. package/build/sources/free/pointfree.d.ts +15 -0
  60. package/build/sources/free/pointfree.d.ts.map +1 -0
  61. package/build/sources/free/pointfree.js +175 -0
  62. package/build/sources/free/pointfree.js.map +1 -0
  63. package/build/sources/free/pointfree.test.d.ts +2 -0
  64. package/build/sources/free/pointfree.test.d.ts.map +1 -0
  65. package/build/sources/free/pointfree.test.js +86 -0
  66. package/build/sources/free/pointfree.test.js.map +1 -0
  67. package/build/sources/free/rssPatternSource.d.ts +42 -0
  68. package/build/sources/free/rssPatternSource.d.ts.map +1 -0
  69. package/build/sources/free/rssPatternSource.js +109 -0
  70. package/build/sources/free/rssPatternSource.js.map +1 -0
  71. package/build/sources/free/rssPatternSource.test.d.ts +2 -0
  72. package/build/sources/free/rssPatternSource.test.d.ts.map +1 -0
  73. package/build/sources/free/rssPatternSource.test.js +89 -0
  74. package/build/sources/free/rssPatternSource.test.js.map +1 -0
  75. package/build/sources/free/sundell.d.ts +8 -0
  76. package/build/sources/free/sundell.d.ts.map +1 -0
  77. package/build/sources/free/sundell.js +17 -0
  78. package/build/sources/free/sundell.js.map +1 -0
  79. package/build/sources/free/sundell.test.d.ts +2 -0
  80. package/build/sources/free/sundell.test.d.ts.map +1 -0
  81. package/build/sources/free/sundell.test.js +63 -0
  82. package/build/sources/free/sundell.test.js.map +1 -0
  83. package/build/sources/free/vanderlee.d.ts +8 -0
  84. package/build/sources/free/vanderlee.d.ts.map +1 -0
  85. package/build/sources/free/vanderlee.js +63 -0
  86. package/build/sources/free/vanderlee.js.map +1 -0
  87. package/build/sources/free/vanderlee.test.d.ts +2 -0
  88. package/build/sources/free/vanderlee.test.d.ts.map +1 -0
  89. package/build/sources/free/vanderlee.test.js +77 -0
  90. package/build/sources/free/vanderlee.test.js.map +1 -0
  91. package/build/sources/premium/patreon-dl.d.ts +45 -0
  92. package/build/sources/premium/patreon-dl.d.ts.map +1 -0
  93. package/build/sources/premium/patreon-dl.js +189 -0
  94. package/build/sources/premium/patreon-dl.js.map +1 -0
  95. package/build/sources/premium/patreon-fetch.d.ts +3 -0
  96. package/build/sources/premium/patreon-fetch.d.ts.map +1 -0
  97. package/build/sources/premium/patreon-fetch.js +18 -0
  98. package/build/sources/premium/patreon-fetch.js.map +1 -0
  99. package/build/sources/premium/patreon-oauth.d.ts +24 -0
  100. package/build/sources/premium/patreon-oauth.d.ts.map +1 -0
  101. package/build/sources/premium/patreon-oauth.js +208 -0
  102. package/build/sources/premium/patreon-oauth.js.map +1 -0
  103. package/build/sources/premium/patreon-zip.d.ts +17 -0
  104. package/build/sources/premium/patreon-zip.d.ts.map +1 -0
  105. package/build/sources/premium/patreon-zip.js +127 -0
  106. package/build/sources/premium/patreon-zip.js.map +1 -0
  107. package/build/sources/premium/patreon.d.ts +48 -0
  108. package/build/sources/premium/patreon.d.ts.map +1 -0
  109. package/build/sources/premium/patreon.js +221 -0
  110. package/build/sources/premium/patreon.js.map +1 -0
  111. package/build/sources/premium/youtube.d.ts +14 -0
  112. package/build/sources/premium/youtube.d.ts.map +1 -0
  113. package/build/sources/premium/youtube.js +92 -0
  114. package/build/sources/premium/youtube.js.map +1 -0
  115. package/build/tools/extract-cookie.d.ts +2 -0
  116. package/build/tools/extract-cookie.d.ts.map +1 -0
  117. package/build/tools/extract-cookie.js +40 -0
  118. package/build/tools/extract-cookie.js.map +1 -0
  119. package/build/tools/handlers/enableSource.d.ts +3 -0
  120. package/build/tools/handlers/enableSource.d.ts.map +1 -0
  121. package/build/tools/handlers/enableSource.js +25 -0
  122. package/build/tools/handlers/enableSource.js.map +1 -0
  123. package/build/tools/handlers/getPatreonPatterns.d.ts +3 -0
  124. package/build/tools/handlers/getPatreonPatterns.d.ts.map +1 -0
  125. package/build/tools/handlers/getPatreonPatterns.js +43 -0
  126. package/build/tools/handlers/getPatreonPatterns.js.map +1 -0
  127. package/build/tools/handlers/getSwiftPattern.d.ts +3 -0
  128. package/build/tools/handlers/getSwiftPattern.d.ts.map +1 -0
  129. package/build/tools/handlers/getSwiftPattern.js +72 -0
  130. package/build/tools/handlers/getSwiftPattern.js.map +1 -0
  131. package/build/tools/handlers/handlers.test.d.ts +2 -0
  132. package/build/tools/handlers/handlers.test.d.ts.map +1 -0
  133. package/build/tools/handlers/handlers.test.js +359 -0
  134. package/build/tools/handlers/handlers.test.js.map +1 -0
  135. package/build/tools/handlers/listContentSources.d.ts +3 -0
  136. package/build/tools/handlers/listContentSources.d.ts.map +1 -0
  137. package/build/tools/handlers/listContentSources.js +34 -0
  138. package/build/tools/handlers/listContentSources.js.map +1 -0
  139. package/build/tools/handlers/searchSwiftContent.d.ts +3 -0
  140. package/build/tools/handlers/searchSwiftContent.d.ts.map +1 -0
  141. package/build/tools/handlers/searchSwiftContent.js +121 -0
  142. package/build/tools/handlers/searchSwiftContent.js.map +1 -0
  143. package/build/tools/handlers/setupPatreon.d.ts +3 -0
  144. package/build/tools/handlers/setupPatreon.d.ts.map +1 -0
  145. package/build/tools/handlers/setupPatreon.js +40 -0
  146. package/build/tools/handlers/setupPatreon.js.map +1 -0
  147. package/build/tools/index.d.ts +3 -0
  148. package/build/tools/index.d.ts.map +1 -0
  149. package/build/tools/index.js +18 -0
  150. package/build/tools/index.js.map +1 -0
  151. package/build/tools/registry.d.ts +14 -0
  152. package/build/tools/registry.d.ts.map +1 -0
  153. package/build/tools/registry.js +21 -0
  154. package/build/tools/registry.js.map +1 -0
  155. package/build/tools/registry.test.d.ts +2 -0
  156. package/build/tools/registry.test.d.ts.map +1 -0
  157. package/build/tools/registry.test.js +54 -0
  158. package/build/tools/registry.test.js.map +1 -0
  159. package/build/tools/types.d.ts +67 -0
  160. package/build/tools/types.d.ts.map +1 -0
  161. package/build/tools/types.js +3 -0
  162. package/build/tools/types.js.map +1 -0
  163. package/build/utils/cache.d.ts +20 -0
  164. package/build/utils/cache.d.ts.map +1 -0
  165. package/build/utils/cache.js +186 -0
  166. package/build/utils/cache.js.map +1 -0
  167. package/build/utils/concurrency.d.ts +13 -0
  168. package/build/utils/concurrency.d.ts.map +1 -0
  169. package/build/utils/concurrency.js +33 -0
  170. package/build/utils/concurrency.js.map +1 -0
  171. package/build/utils/errors.d.ts +19 -0
  172. package/build/utils/errors.d.ts.map +1 -0
  173. package/build/utils/errors.js +35 -0
  174. package/build/utils/errors.js.map +1 -0
  175. package/build/utils/fetch.d.ts +6 -0
  176. package/build/utils/fetch.d.ts.map +1 -0
  177. package/build/utils/fetch.js +6 -0
  178. package/build/utils/fetch.js.map +1 -0
  179. package/build/utils/http.d.ts +21 -0
  180. package/build/utils/http.d.ts.map +1 -0
  181. package/build/utils/http.js +53 -0
  182. package/build/utils/http.js.map +1 -0
  183. package/build/utils/intent-cache.d.ts +94 -0
  184. package/build/utils/intent-cache.d.ts.map +1 -0
  185. package/build/utils/intent-cache.js +164 -0
  186. package/build/utils/intent-cache.js.map +1 -0
  187. package/build/utils/intent-cache.test.d.ts +2 -0
  188. package/build/utils/intent-cache.test.d.ts.map +1 -0
  189. package/build/utils/intent-cache.test.js +290 -0
  190. package/build/utils/intent-cache.test.js.map +1 -0
  191. package/build/utils/logger.d.ts +4 -0
  192. package/build/utils/logger.d.ts.map +1 -0
  193. package/build/utils/logger.js +9 -0
  194. package/build/utils/logger.js.map +1 -0
  195. package/build/utils/paths.d.ts +27 -0
  196. package/build/utils/paths.d.ts.map +1 -0
  197. package/build/utils/paths.js +43 -0
  198. package/build/utils/paths.js.map +1 -0
  199. package/build/utils/pattern-formatter.d.ts +40 -0
  200. package/build/utils/pattern-formatter.d.ts.map +1 -0
  201. package/build/utils/pattern-formatter.js +124 -0
  202. package/build/utils/pattern-formatter.js.map +1 -0
  203. package/build/utils/response-helpers.d.ts +17 -0
  204. package/build/utils/response-helpers.d.ts.map +1 -0
  205. package/build/utils/response-helpers.js +34 -0
  206. package/build/utils/response-helpers.js.map +1 -0
  207. package/build/utils/search-terms.d.ts +17 -0
  208. package/build/utils/search-terms.d.ts.map +1 -0
  209. package/build/utils/search-terms.js +71 -0
  210. package/build/utils/search-terms.js.map +1 -0
  211. package/build/utils/search-terms.test.d.ts +2 -0
  212. package/build/utils/search-terms.test.d.ts.map +1 -0
  213. package/build/utils/search-terms.test.js +107 -0
  214. package/build/utils/search-terms.test.js.map +1 -0
  215. package/build/utils/search.d.ts +48 -0
  216. package/build/utils/search.d.ts.map +1 -0
  217. package/build/utils/search.js +158 -0
  218. package/build/utils/search.js.map +1 -0
  219. package/build/utils/search.test.d.ts +2 -0
  220. package/build/utils/search.test.d.ts.map +1 -0
  221. package/build/utils/search.test.js +199 -0
  222. package/build/utils/search.test.js.map +1 -0
  223. package/build/utils/semantic-recall.d.ts +38 -0
  224. package/build/utils/semantic-recall.d.ts.map +1 -0
  225. package/build/utils/semantic-recall.js +134 -0
  226. package/build/utils/semantic-recall.js.map +1 -0
  227. package/build/utils/semantic-recall.test.d.ts +2 -0
  228. package/build/utils/semantic-recall.test.d.ts.map +1 -0
  229. package/build/utils/semantic-recall.test.js +326 -0
  230. package/build/utils/semantic-recall.test.js.map +1 -0
  231. package/build/utils/source-registry.d.ts +45 -0
  232. package/build/utils/source-registry.d.ts.map +1 -0
  233. package/build/utils/source-registry.js +113 -0
  234. package/build/utils/source-registry.js.map +1 -0
  235. package/build/utils/source-registry.test.d.ts +2 -0
  236. package/build/utils/source-registry.test.d.ts.map +1 -0
  237. package/build/utils/source-registry.test.js +206 -0
  238. package/build/utils/source-registry.test.js.map +1 -0
  239. package/build/utils/swift-analysis.d.ts +61 -0
  240. package/build/utils/swift-analysis.d.ts.map +1 -0
  241. package/build/utils/swift-analysis.js +339 -0
  242. package/build/utils/swift-analysis.js.map +1 -0
  243. package/build/utils/swift-analysis.test.d.ts +2 -0
  244. package/build/utils/swift-analysis.test.d.ts.map +1 -0
  245. package/build/utils/swift-analysis.test.js +473 -0
  246. package/build/utils/swift-analysis.test.js.map +1 -0
  247. package/package.json +85 -0
@@ -0,0 +1,359 @@
1
+ // src/tools/handlers/handlers.test.ts
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
+ import { getSwiftPatternHandler } from './getSwiftPattern.js';
4
+ import { searchSwiftContentHandler } from './searchSwiftContent.js';
5
+ import { listContentSourcesHandler } from './listContentSources.js';
6
+ import { enableSourceHandler } from './enableSource.js';
7
+ // Test fixtures - known patterns with specific properties for testing
8
+ const MOCK_PATTERNS = {
9
+ sundell: [
10
+ {
11
+ id: 'sundell-1',
12
+ title: 'Advanced SwiftUI Patterns',
13
+ url: 'https://swiftbysundell.com/swiftui',
14
+ excerpt: 'Learn advanced SwiftUI patterns for production apps',
15
+ content: 'Full content about SwiftUI state management and views',
16
+ topics: ['swiftui', 'architecture'],
17
+ relevanceScore: 85,
18
+ hasCode: true,
19
+ publishDate: '2024-01-15T00:00:00Z',
20
+ },
21
+ {
22
+ id: 'sundell-2',
23
+ title: 'Basic Swift Tips',
24
+ url: 'https://swiftbysundell.com/tips',
25
+ excerpt: 'Simple tips for Swift developers',
26
+ content: 'Basic content without code examples',
27
+ topics: ['swift'],
28
+ relevanceScore: 55, // Below default minQuality of 65
29
+ hasCode: false,
30
+ publishDate: '2024-01-10T00:00:00Z',
31
+ },
32
+ ],
33
+ vanderlee: [
34
+ {
35
+ id: 'vanderlee-1',
36
+ title: 'iOS Performance Optimization',
37
+ url: 'https://avanderlee.com/performance',
38
+ excerpt: 'Optimize your iOS app performance',
39
+ content: 'Detailed performance optimization techniques',
40
+ topics: ['performance', 'optimization'],
41
+ relevanceScore: 78,
42
+ hasCode: true,
43
+ publishDate: '2024-01-12T00:00:00Z',
44
+ },
45
+ {
46
+ id: 'vanderlee-2',
47
+ title: 'Debugging Tips',
48
+ url: 'https://avanderlee.com/debugging',
49
+ excerpt: 'Debug your iOS apps effectively',
50
+ content: 'Debugging techniques without code',
51
+ topics: ['debugging'],
52
+ relevanceScore: 65,
53
+ hasCode: false,
54
+ publishDate: '2024-01-08T00:00:00Z',
55
+ },
56
+ ],
57
+ nilcoalescing: [
58
+ {
59
+ id: 'nilcoalescing-1',
60
+ title: 'SwiftUI Navigation Deep Dive',
61
+ url: 'https://nilcoalescing.com/navigation',
62
+ excerpt: 'Master SwiftUI navigation patterns',
63
+ content: 'Navigation code examples and patterns',
64
+ topics: ['swiftui', 'navigation'],
65
+ relevanceScore: 72,
66
+ hasCode: true,
67
+ publishDate: '2024-01-14T00:00:00Z',
68
+ },
69
+ ],
70
+ pointfree: [
71
+ {
72
+ id: 'pointfree-1',
73
+ title: 'Composable Architecture Case Study',
74
+ url: 'https://github.com/pointfreeco/pointfreeco/blob/main/Sources/Models/Episodes/0001-functions.md',
75
+ excerpt: 'Build apps with TCA',
76
+ content: 'TCA reducer and store patterns',
77
+ topics: ['architecture', 'tca'],
78
+ relevanceScore: 90,
79
+ hasCode: true,
80
+ publishDate: '2024-01-16T00:00:00Z',
81
+ },
82
+ ],
83
+ };
84
+ // Mock sources to return our test fixtures
85
+ vi.mock('../../sources/free/sundell.js', () => ({
86
+ default: vi.fn().mockImplementation(() => ({
87
+ searchPatterns: vi.fn().mockResolvedValue(MOCK_PATTERNS.sundell),
88
+ })),
89
+ }));
90
+ vi.mock('../../sources/free/vanderlee.js', () => ({
91
+ default: vi.fn().mockImplementation(() => ({
92
+ searchPatterns: vi.fn().mockResolvedValue(MOCK_PATTERNS.vanderlee),
93
+ })),
94
+ }));
95
+ vi.mock('../../sources/free/nilcoalescing.js', () => ({
96
+ default: vi.fn().mockImplementation(() => ({
97
+ searchPatterns: vi.fn().mockResolvedValue(MOCK_PATTERNS.nilcoalescing),
98
+ })),
99
+ }));
100
+ vi.mock('../../sources/free/pointfree.js', () => ({
101
+ default: vi.fn().mockImplementation(() => ({
102
+ searchPatterns: vi.fn().mockResolvedValue(MOCK_PATTERNS.pointfree),
103
+ })),
104
+ }));
105
+ // Mock SourceManager to ensure semantic recall is disabled in tests
106
+ vi.mock('../../config/sources.js', () => ({
107
+ default: vi.fn().mockImplementation(() => ({
108
+ getSemanticRecallConfig: vi.fn().mockReturnValue({
109
+ enabled: false,
110
+ minLexicalScore: 0.35,
111
+ minRelevanceScore: 70,
112
+ }),
113
+ isSemanticRecallEnabled: vi.fn().mockReturnValue(false),
114
+ })),
115
+ }));
116
+ // Create mock SourceManager
117
+ function createMockSourceManager() {
118
+ const sources = [
119
+ { id: 'sundell', name: 'Swift by Sundell', type: 'free', requiresAuth: false, isEnabled: true, isConfigured: true, description: 'Swift articles' },
120
+ { id: 'vanderlee', name: 'Antoine van der Lee', type: 'free', requiresAuth: false, isEnabled: true, isConfigured: true, description: 'iOS tips' },
121
+ { id: 'nilcoalescing', name: 'Nil Coalescing', type: 'free', requiresAuth: false, isEnabled: true, isConfigured: true, description: 'SwiftUI tips' },
122
+ { id: 'pointfree', name: 'Point-Free', type: 'free', requiresAuth: false, isEnabled: true, isConfigured: true, description: 'Open source patterns' },
123
+ { id: 'patreon', name: 'Patreon', type: 'premium', requiresAuth: true, isEnabled: false, isConfigured: false, description: 'Premium content' },
124
+ ];
125
+ return {
126
+ getAllSources: vi.fn().mockReturnValue(sources),
127
+ getSource: vi.fn((id) => sources.find(s => s.id === id)),
128
+ isSourceConfigured: vi.fn((id) => {
129
+ const source = sources.find(s => s.id === id);
130
+ return source?.isConfigured ?? false;
131
+ }),
132
+ enableSource: vi.fn(),
133
+ disableSource: vi.fn(),
134
+ getEnabledSources: vi.fn().mockReturnValue(sources.filter(s => s.isEnabled)),
135
+ };
136
+ }
137
+ describe('getSwiftPatternHandler', () => {
138
+ let context;
139
+ beforeEach(() => {
140
+ context = {
141
+ sourceManager: createMockSourceManager(),
142
+ patreonSource: null,
143
+ };
144
+ });
145
+ it('should return error when topic is missing', async () => {
146
+ const result = await getSwiftPatternHandler({}, context);
147
+ expect(result.content[0].text).toContain('Missing required argument');
148
+ expect(result.content[0].text).toContain('topic');
149
+ });
150
+ it('should return patterns matching the topic', async () => {
151
+ const result = await getSwiftPatternHandler({ topic: 'swiftui' }, context);
152
+ const text = result.content[0].text;
153
+ // Should include SwiftUI-related patterns
154
+ expect(text).toContain('Advanced SwiftUI Patterns');
155
+ expect(text).toContain('SwiftUI Navigation Deep Dive');
156
+ });
157
+ it('should filter out patterns below minQuality threshold', async () => {
158
+ const result = await getSwiftPatternHandler({
159
+ topic: 'swift',
160
+ minQuality: 70,
161
+ }, context);
162
+ const text = result.content[0].text;
163
+ // sundell-1 (85), vanderlee-1 (78), nilcoalescing-1 (72), pointfree-1 (90) should be included
164
+ expect(text).toContain('Advanced SwiftUI Patterns'); // score 85
165
+ expect(text).toContain('iOS Performance Optimization'); // score 78
166
+ // sundell-2 (55) and vanderlee-2 (65) should be EXCLUDED
167
+ expect(text).not.toContain('Basic Swift Tips'); // score 55
168
+ expect(text).not.toContain('Debugging Tips'); // score 65
169
+ });
170
+ it('should use default minQuality of 65 when not specified', async () => {
171
+ const result = await getSwiftPatternHandler({ topic: 'swift' }, context);
172
+ const text = result.content[0].text;
173
+ // sundell-2 has score 55, below default minQuality of 65
174
+ expect(text).not.toContain('Basic Swift Tips');
175
+ // vanderlee-2 has score 65, meets minQuality threshold
176
+ // Note: Due to maxResults=4 default, only top 4 patterns are shown
177
+ // So vanderlee-2 (score 65, ranked 5th) won't appear in output
178
+ expect(text).toContain('Found 5 results'); // 5 patterns pass the threshold
179
+ expect(text).toContain('Showing top 4 of 5 results'); // But only 4 are displayed
180
+ });
181
+ it('should filter by specific source when provided', async () => {
182
+ const result = await getSwiftPatternHandler({
183
+ topic: 'swift',
184
+ source: 'sundell',
185
+ }, context);
186
+ const text = result.content[0].text;
187
+ // Should only contain sundell patterns
188
+ expect(text).toContain('Advanced SwiftUI Patterns');
189
+ // Should NOT contain patterns from other sources
190
+ expect(text).not.toContain('iOS Performance Optimization'); // vanderlee
191
+ expect(text).not.toContain('SwiftUI Navigation Deep Dive'); // nilcoalescing
192
+ expect(text).not.toContain('Composable Architecture'); // pointfree
193
+ });
194
+ it('should sort results by relevance score (highest first)', async () => {
195
+ const result = await getSwiftPatternHandler({
196
+ topic: 'swift',
197
+ minQuality: 0, // Include all
198
+ }, context);
199
+ const text = result.content[0].text;
200
+ // pointfree-1 (90) should appear before sundell-1 (85)
201
+ const pointfreeIndex = text.indexOf('Composable Architecture');
202
+ const sundellIndex = text.indexOf('Advanced SwiftUI Patterns');
203
+ expect(pointfreeIndex).toBeLessThan(sundellIndex);
204
+ });
205
+ it('should include quality scores in output', async () => {
206
+ const result = await getSwiftPatternHandler({ topic: 'swiftui' }, context);
207
+ const text = result.content[0].text;
208
+ // Should show quality scores
209
+ expect(text).toMatch(/Quality.*\d+\/100/i);
210
+ });
211
+ it('should include source attribution in output', async () => {
212
+ const result = await getSwiftPatternHandler({ topic: 'swiftui' }, context);
213
+ const text = result.content[0].text;
214
+ expect(text).toMatch(/Source.*:/i);
215
+ });
216
+ it('should include clickable URLs in output', async () => {
217
+ const result = await getSwiftPatternHandler({ topic: 'swiftui' }, context);
218
+ const text = result.content[0].text;
219
+ // Should have markdown links
220
+ expect(text).toMatch(/\[.+\]\(https?:\/\/.+\)/);
221
+ });
222
+ it('should return helpful message when no patterns found', async () => {
223
+ const result = await getSwiftPatternHandler({
224
+ topic: 'nonexistent_topic',
225
+ minQuality: 100, // Filter out everything
226
+ }, context);
227
+ const text = result.content[0].text;
228
+ expect(text).toContain('No patterns found');
229
+ expect(text).toMatch(/[Tt]ry/); // Should suggest trying something else
230
+ });
231
+ });
232
+ describe('searchSwiftContentHandler', () => {
233
+ let context;
234
+ beforeEach(() => {
235
+ context = {
236
+ sourceManager: createMockSourceManager(),
237
+ patreonSource: null,
238
+ };
239
+ });
240
+ it('should return error when query is missing', async () => {
241
+ const result = await searchSwiftContentHandler({}, context);
242
+ expect(result.content[0].text).toContain('Missing required argument');
243
+ expect(result.content[0].text).toContain('query');
244
+ });
245
+ it('should return results from all sources', async () => {
246
+ const result = await searchSwiftContentHandler({ query: 'swift' }, context);
247
+ const text = result.content[0].text;
248
+ // Should include results from multiple sources
249
+ expect(text).toContain('Advanced SwiftUI Patterns'); // sundell
250
+ expect(text).toContain('iOS Performance Optimization'); // vanderlee
251
+ });
252
+ it('should filter by requireCode when true', async () => {
253
+ const result = await searchSwiftContentHandler({
254
+ query: 'swift',
255
+ requireCode: true,
256
+ }, context);
257
+ const text = result.content[0].text;
258
+ // Should include patterns with code
259
+ expect(text).toContain('Advanced SwiftUI Patterns'); // hasCode: true
260
+ expect(text).toContain('iOS Performance Optimization'); // hasCode: true
261
+ // Should EXCLUDE patterns without code
262
+ expect(text).not.toContain('Basic Swift Tips'); // hasCode: false
263
+ expect(text).not.toContain('Debugging Tips'); // hasCode: false
264
+ });
265
+ it('should include all patterns when requireCode is false', async () => {
266
+ const result = await searchSwiftContentHandler({
267
+ query: 'swift',
268
+ requireCode: false,
269
+ }, context);
270
+ const text = result.content[0].text;
271
+ // Should include patterns both with and without code
272
+ expect(text).toContain('Advanced SwiftUI Patterns'); // hasCode: true
273
+ expect(text).toContain('Basic Swift Tips'); // hasCode: false
274
+ });
275
+ it('should have search results header', async () => {
276
+ const result = await searchSwiftContentHandler({ query: 'swift' }, context);
277
+ const text = result.content[0].text;
278
+ expect(text).toMatch(/# Search Results/);
279
+ });
280
+ });
281
+ describe('listContentSourcesHandler', () => {
282
+ let context;
283
+ beforeEach(() => {
284
+ context = {
285
+ sourceManager: createMockSourceManager(),
286
+ patreonSource: null,
287
+ };
288
+ });
289
+ it('should list all sources with categories', async () => {
290
+ const result = await listContentSourcesHandler({}, context);
291
+ const text = result.content[0].text;
292
+ expect(text).toContain('Content Sources');
293
+ expect(text).toContain('Free Sources');
294
+ expect(text).toContain('Premium Sources');
295
+ });
296
+ it('should list all source names', async () => {
297
+ const result = await listContentSourcesHandler({}, context);
298
+ const text = result.content[0].text;
299
+ expect(text).toContain('Swift by Sundell');
300
+ expect(text).toContain('Antoine van der Lee');
301
+ expect(text).toContain('Nil Coalescing');
302
+ expect(text).toContain('Point-Free');
303
+ expect(text).toContain('Patreon');
304
+ });
305
+ it('should show status indicators', async () => {
306
+ const result = await listContentSourcesHandler({}, context);
307
+ const text = result.content[0].text;
308
+ // Should have status indicators (enabled/disabled/needs setup)
309
+ expect(text).toMatch(/✅|⚙️|⬜/);
310
+ });
311
+ it('should show setup instructions for premium sources', async () => {
312
+ const result = await listContentSourcesHandler({}, context);
313
+ const text = result.content[0].text;
314
+ expect(text).toContain('swift-patterns-mcp setup');
315
+ });
316
+ });
317
+ describe('enableSourceHandler', () => {
318
+ let context;
319
+ beforeEach(() => {
320
+ context = {
321
+ sourceManager: createMockSourceManager(),
322
+ patreonSource: null,
323
+ };
324
+ });
325
+ it('should return error for unknown source', async () => {
326
+ const result = await enableSourceHandler({ source: 'unknown_source' }, context);
327
+ const text = result.content[0].text;
328
+ expect(text).toContain('Unknown source');
329
+ expect(text).toContain('unknown_source');
330
+ });
331
+ it('should list available sources when source is unknown', async () => {
332
+ const result = await enableSourceHandler({ source: 'invalid' }, context);
333
+ const text = result.content[0].text;
334
+ expect(text).toContain('Available sources');
335
+ expect(text).toContain('sundell');
336
+ expect(text).toContain('vanderlee');
337
+ expect(text).toContain('nilcoalescing');
338
+ expect(text).toContain('pointfree');
339
+ });
340
+ it('should require setup for unconfigured premium sources', async () => {
341
+ const result = await enableSourceHandler({ source: 'patreon' }, context);
342
+ const text = result.content[0].text;
343
+ expect(text).toContain('requires setup');
344
+ expect(text).toContain('swift-patterns-mcp setup');
345
+ expect(text).toContain('--patreon');
346
+ });
347
+ it('should enable configured free sources', async () => {
348
+ const result = await enableSourceHandler({ source: 'sundell' }, context);
349
+ const text = result.content[0].text;
350
+ expect(text).toContain('enabled');
351
+ expect(text).toContain('Swift by Sundell');
352
+ expect(context.sourceManager.enableSource).toHaveBeenCalledWith('sundell');
353
+ });
354
+ it('should not call enableSource for unknown sources', async () => {
355
+ await enableSourceHandler({ source: 'unknown' }, context);
356
+ expect(context.sourceManager.enableSource).not.toHaveBeenCalled();
357
+ });
358
+ });
359
+ //# sourceMappingURL=handlers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.test.js","sourceRoot":"","sources":["../../../src/tools/handlers/handlers.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolHandler } from '../types.js';
2
+ export declare const listContentSourcesHandler: ToolHandler;
3
+ //# sourceMappingURL=listContentSources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listContentSources.d.ts","sourceRoot":"","sources":["../../../src/tools/handlers/listContentSources.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,eAAO,MAAM,yBAAyB,EAAE,WAiCvC,CAAC"}
@@ -0,0 +1,34 @@
1
+ // src/tools/handlers/listContentSources.ts
2
+ import { createTextResponse } from '../../utils/response-helpers.js';
3
+ export const listContentSourcesHandler = async (_args, context) => {
4
+ const allSources = context.sourceManager.getAllSources();
5
+ const freeList = allSources
6
+ .filter(s => s.type === 'free')
7
+ .map(s => `- ✅ **${s.name}** - ${s.description}`)
8
+ .join('\n');
9
+ const premiumList = allSources
10
+ .filter(s => s.type === 'premium')
11
+ .map(s => {
12
+ const status = s.isConfigured && s.isEnabled ? '✅' :
13
+ s.isConfigured ? '⚙️' : '⬜';
14
+ return `- ${status} **${s.name}** - ${s.description}${s.isConfigured ? '' : ' (Setup required)'}`;
15
+ })
16
+ .join('\n');
17
+ return createTextResponse(`# Content Sources
18
+
19
+ ## Free Sources (Always Available)
20
+ ${freeList}
21
+
22
+ ## Premium Sources (Optional)
23
+ ${premiumList}
24
+
25
+ ## Legend
26
+ ✅ Enabled | ⚙️ Configured but disabled | ⬜ Not configured
27
+
28
+ To enable premium sources:
29
+ \`\`\`
30
+ swift-patterns-mcp setup --patreon
31
+ \`\`\`
32
+ `);
33
+ };
34
+ //# sourceMappingURL=listContentSources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listContentSources.js","sourceRoot":"","sources":["../../../src/tools/handlers/listContentSources.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAG3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAErE,MAAM,CAAC,MAAM,yBAAyB,GAAgB,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAC7E,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,aAAa,EAAE,CAAC;IAEzD,MAAM,QAAQ,GAAG,UAAU;SACxB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;SAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;SAChD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,WAAW,GAAG,UAAU;SAC3B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;SACjC,GAAG,CAAC,CAAC,CAAC,EAAE;QACP,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACtC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;QAC1C,OAAO,KAAK,MAAM,MAAM,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC;IACpG,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,kBAAkB,CAAC;;;EAG1B,QAAQ;;;EAGR,WAAW;;;;;;;;;CASZ,CAAC,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ToolHandler } from '../types.js';
2
+ export declare const searchSwiftContentHandler: ToolHandler;
3
+ //# sourceMappingURL=searchSwiftContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchSwiftContent.d.ts","sourceRoot":"","sources":["../../../src/tools/handlers/searchSwiftContent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkE/C,eAAO,MAAM,yBAAyB,EAAE,WAsFvC,CAAC"}
@@ -0,0 +1,121 @@
1
+ // src/tools/handlers/searchSwiftContent.ts
2
+ import { searchMultipleSources, getSourceNames, fetchAllPatterns } from '../../utils/source-registry.js';
3
+ import { formatSearchPatterns, COMMON_FORMAT_OPTIONS, detectCodeIntent } from '../../utils/pattern-formatter.js';
4
+ import { createTextResponse } from '../../utils/response-helpers.js';
5
+ import { intentCache } from '../../utils/intent-cache.js';
6
+ import { SemanticRecallIndex } from '../../utils/semantic-recall.js';
7
+ import SourceManager from '../../config/sources.js';
8
+ // Module-level singleton for semantic recall index
9
+ let semanticIndex = null;
10
+ function getSemanticIndex(config) {
11
+ if (!semanticIndex) {
12
+ semanticIndex = new SemanticRecallIndex(config);
13
+ }
14
+ return semanticIndex;
15
+ }
16
+ /**
17
+ * Attempt semantic recall to supplement lexical results.
18
+ * Returns additional patterns not in lexicalResults, or empty array on failure.
19
+ * Handles all errors internally - never throws.
20
+ */
21
+ async function trySemanticRecall(options) {
22
+ const { query, lexicalResults, config, sourceManager, requireCode } = options;
23
+ try {
24
+ // Check if semantic recall should activate
25
+ const maxScore = lexicalResults.length > 0
26
+ ? Math.max(...lexicalResults.map(p => p.relevanceScore)) / 100
27
+ : 0;
28
+ const shouldActivate = lexicalResults.length === 0 || maxScore < config.minLexicalScore;
29
+ if (!shouldActivate)
30
+ return [];
31
+ // Get/create index and fetch patterns from enabled sources
32
+ const index = getSemanticIndex(config);
33
+ const enabledSourceIds = sourceManager.getEnabledSources().map(s => s.id);
34
+ const allPatterns = await fetchAllPatterns(enabledSourceIds);
35
+ await index.index(allPatterns);
36
+ // Search and filter
37
+ const semanticResults = await index.search(query, 5);
38
+ const existingIds = new Set(lexicalResults.map(p => p.id));
39
+ return semanticResults.filter(p => !existingIds.has(p.id) &&
40
+ (!requireCode || p.hasCode) &&
41
+ p.relevanceScore >= config.minRelevanceScore);
42
+ }
43
+ catch {
44
+ // Semantic recall is best-effort; return empty on any failure
45
+ return [];
46
+ }
47
+ }
48
+ export const searchSwiftContentHandler = async (args) => {
49
+ const query = args?.query;
50
+ const requireCode = args?.requireCode;
51
+ const wantsCode = detectCodeIntent(args, query);
52
+ if (!query) {
53
+ return createTextResponse(`Missing required argument: query
54
+
55
+ Usage: search_swift_content({ query: "async await" })`);
56
+ }
57
+ // Build intent key for caching
58
+ // This handler always uses 'all' sources and default minQuality of 0
59
+ const intentKey = {
60
+ tool: 'search_swift_content',
61
+ query,
62
+ minQuality: 0,
63
+ sources: getSourceNames('all'),
64
+ requireCode: requireCode || false,
65
+ };
66
+ // Try to get cached result
67
+ const cached = await intentCache.get(intentKey);
68
+ let filtered;
69
+ // Track whether this was a cache hit (to avoid re-caching)
70
+ let wasCacheHit = false;
71
+ if (cached) {
72
+ // Cache hit - use cached patterns (includes any semantic results from prior search)
73
+ filtered = cached.patterns || [];
74
+ wasCacheHit = true;
75
+ }
76
+ else {
77
+ // Cache miss - fetch from sources
78
+ const results = await searchMultipleSources(query);
79
+ // Filter by code if requested
80
+ filtered = requireCode
81
+ ? results.filter(r => r.hasCode)
82
+ : results;
83
+ }
84
+ // Semantic recall: supplement lexical results when enabled and not cached
85
+ const sourceManager = new SourceManager();
86
+ const semanticConfig = sourceManager.getSemanticRecallConfig();
87
+ let finalResults = filtered;
88
+ if (!wasCacheHit && semanticConfig.enabled) {
89
+ const semanticResults = await trySemanticRecall({
90
+ query,
91
+ lexicalResults: filtered,
92
+ config: semanticConfig,
93
+ sourceManager,
94
+ requireCode: requireCode || false,
95
+ });
96
+ if (semanticResults.length > 0) {
97
+ finalResults = [...filtered, ...semanticResults]
98
+ .sort((a, b) => b.relevanceScore - a.relevanceScore);
99
+ }
100
+ }
101
+ // Cache final results (after semantic merge) if this was a cache miss
102
+ if (!wasCacheHit && finalResults.length > 0) {
103
+ const cacheData = {
104
+ patternIds: finalResults.map(p => p.id),
105
+ scores: Object.fromEntries(finalResults.map(p => [p.id, p.relevanceScore])),
106
+ totalCount: finalResults.length,
107
+ patterns: finalResults,
108
+ };
109
+ await intentCache.set(intentKey, cacheData);
110
+ }
111
+ if (finalResults.length === 0) {
112
+ return createTextResponse(`No results found for "${query}"${requireCode ? ' with code examples' : ''}.`);
113
+ }
114
+ // Format using shared utility
115
+ const formatted = formatSearchPatterns(finalResults, query, {
116
+ ...COMMON_FORMAT_OPTIONS,
117
+ includeCode: wantsCode,
118
+ });
119
+ return createTextResponse(formatted);
120
+ };
121
+ //# sourceMappingURL=searchSwiftContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchSwiftContent.js","sourceRoot":"","sources":["../../../src/tools/handlers/searchSwiftContent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolHandler } from '../types.js';
2
+ export declare const setupPatreonHandler: ToolHandler;
3
+ //# sourceMappingURL=setupPatreon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setupPatreon.d.ts","sourceRoot":"","sources":["../../../src/tools/handlers/setupPatreon.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,eAAO,MAAM,mBAAmB,EAAE,WAuCjC,CAAC"}
@@ -0,0 +1,40 @@
1
+ // src/tools/handlers/setupPatreon.ts
2
+ import { createTextResponse } from '../../utils/response-helpers.js';
3
+ export const setupPatreonHandler = async (args, context) => {
4
+ if (!context.patreonSource) {
5
+ return createTextResponse(`Patreon integration not available.
6
+
7
+ Please ensure:
8
+ 1. PATREON_CLIENT_ID is set in environment
9
+ 2. PATREON_CLIENT_SECRET is set in environment
10
+
11
+ Get credentials at: https://www.patreon.com/portal/registration/register-clients`);
12
+ }
13
+ const action = args?.action || 'start';
14
+ if (action === 'status') {
15
+ const isConfigured = context.sourceManager.isSourceConfigured('patreon');
16
+ return createTextResponse(isConfigured
17
+ ? `Patreon is configured and ready to use!`
18
+ : `Patreon is not yet configured.
19
+
20
+ Run: swift-patterns-mcp setup --patreon`);
21
+ }
22
+ return createTextResponse(`Patreon Setup
23
+
24
+ To set up Patreon integration, run:
25
+ \`\`\`bash
26
+ swift-patterns-mcp setup --patreon
27
+ \`\`\`
28
+
29
+ This will:
30
+ 1. Open your browser for Patreon OAuth
31
+ 2. Connect your subscriptions
32
+ 3. Analyze your content
33
+ 4. Enable premium patterns
34
+
35
+ After setup, you'll have access to:
36
+ - High-quality patterns from creators you support
37
+ - Automatic code extraction from zips
38
+ - Advanced filtering and search`);
39
+ };
40
+ //# sourceMappingURL=setupPatreon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setupPatreon.js","sourceRoot":"","sources":["../../../src/tools/handlers/setupPatreon.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAGrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAErE,MAAM,CAAC,MAAM,mBAAmB,GAAgB,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;IACtE,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;QAC3B,OAAO,kBAAkB,CAAC;;;;;;iFAMmD,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,MAAM,GAAI,IAAI,EAAE,MAAiB,IAAI,OAAO,CAAC;IAEnD,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACzE,OAAO,kBAAkB,CAAC,YAAY;YACpC,CAAC,CAAC,yCAAyC;YAC3C,CAAC,CAAC;;wCAEgC,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,kBAAkB,CAAC;;;;;;;;;;;;;;;;gCAgBI,CAAC,CAAC;AAClC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export * from './registry.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}