swift-skills 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,63 @@
1
+ // src/sources/free/sundell.test.ts
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
+ import SundellSource from './sundell.js';
4
+ vi.mock('rss-parser', () => {
5
+ return {
6
+ default: class Parser {
7
+ async parseURL(_url) {
8
+ return {
9
+ items: [
10
+ {
11
+ guid: '1',
12
+ title: 'How to test Swift code',
13
+ link: 'https://example.com/1',
14
+ pubDate: '2026-01-01',
15
+ contentSnippet: 'A guide to testing in Swift',
16
+ content: '<p>Some content <code>let x = 1</code></p>',
17
+ },
18
+ {
19
+ guid: '2',
20
+ title: 'SwiftUI Patterns',
21
+ link: 'https://example.com/2',
22
+ pubDate: '2026-01-02',
23
+ contentSnippet: 'SwiftUI best practices',
24
+ content: '<p>SwiftUI <pre>struct ContentView: View {}</pre></p>',
25
+ },
26
+ ],
27
+ };
28
+ }
29
+ },
30
+ };
31
+ });
32
+ vi.mock('../../utils/cache.js', () => ({
33
+ rssCache: {
34
+ get: vi.fn(async () => undefined),
35
+ set: vi.fn(async () => undefined),
36
+ },
37
+ }));
38
+ describe('SundellSource', () => {
39
+ let source;
40
+ beforeEach(() => {
41
+ source = new SundellSource();
42
+ });
43
+ it('fetches and parses patterns', async () => {
44
+ const patterns = await source.fetchPatterns();
45
+ expect(patterns).toHaveLength(2);
46
+ expect(patterns[0].title).toBe('How to test Swift code');
47
+ expect(patterns[0].topics).toContain('testing');
48
+ expect(patterns[1].topics).toContain('swiftui');
49
+ expect(patterns[0].hasCode).toBe(true);
50
+ expect(patterns[1].hasCode).toBe(true);
51
+ });
52
+ it('calculates relevance score', async () => {
53
+ const patterns = await source.fetchPatterns();
54
+ expect(patterns[0].relevanceScore).toBeGreaterThanOrEqual(65);
55
+ expect(patterns[1].relevanceScore).toBeGreaterThanOrEqual(66);
56
+ });
57
+ it('searchPatterns returns relevant results', async () => {
58
+ const results = await source.searchPatterns('swiftui');
59
+ expect(results[0].title).toMatch(/swiftui/i);
60
+ expect(results[0].topics).toContain('swiftui');
61
+ });
62
+ });
63
+ //# sourceMappingURL=sundell.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sundell.test.js","sourceRoot":"","sources":["../../../src/sources/free/sundell.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { RssPatternSource, type BasePattern } from './rssPatternSource.js';
2
+ export interface VanderLeePattern extends BasePattern {
3
+ }
4
+ export declare class VanderLeeSource extends RssPatternSource<VanderLeePattern> {
5
+ constructor();
6
+ }
7
+ export default VanderLeeSource;
8
+ //# sourceMappingURL=vanderlee.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vanderlee.d.ts","sourceRoot":"","sources":["../../../src/sources/free/vanderlee.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAI3E,MAAM,WAAW,gBAAiB,SAAQ,WAAW;CAAG;AAsDxD,qBAAa,eAAgB,SAAQ,gBAAgB,CAAC,gBAAgB,CAAC;;CAatE;AAED,eAAe,eAAe,CAAC"}
@@ -0,0 +1,63 @@
1
+ // src/sources/free/vanderlee.ts
2
+ import { parseHTML } from 'linkedom';
3
+ import { stripHtml as stripHtmlLib } from 'string-strip-html';
4
+ import { RssPatternSource } from './rssPatternSource.js';
5
+ import { createSourceConfig } from '../../config/swift-keywords.js';
6
+ const { topicKeywords, qualitySignals } = createSourceConfig({
7
+ 'debugging': ['debug', 'breakpoint', 'lldb', 'xcode'],
8
+ 'combine': ['combine', 'publisher', 'subscriber'],
9
+ 'tooling': ['xcode', 'git', 'ci', 'fastlane'],
10
+ 'performance': ['leak', 'profiling'],
11
+ }, {
12
+ 'fix': 4, 'solve': 4, 'performance': 8, 'memory': 7,
13
+ 'debugging': 7, 'leak': 6, 'optimization': 7, 'profiling': 6,
14
+ 'xcode': 5, 'instruments': 6, 'ci': 4, 'fastlane': 4,
15
+ });
16
+ function extractPostContent(html) {
17
+ const { document } = parseHTML(html);
18
+ // Try multiple selectors in order of preference
19
+ const selectors = [
20
+ '.post-content',
21
+ 'article .entry-content',
22
+ 'article',
23
+ 'main',
24
+ '.content',
25
+ ];
26
+ for (const selector of selectors) {
27
+ const element = document.querySelector(selector);
28
+ if (element) {
29
+ // Remove unwanted elements before extracting text
30
+ const unwantedElements = element.querySelectorAll('script, style, nav, footer, .sidebar, .comments');
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ unwantedElements.forEach((el) => {
33
+ el.parentNode?.removeChild(el);
34
+ });
35
+ return stripHtml(element.innerHTML);
36
+ }
37
+ }
38
+ return '';
39
+ }
40
+ function stripHtml(html) {
41
+ // Use string-strip-html library (more robust than regex)
42
+ // Keep pre/code tags for code detection in swift-analysis.ts
43
+ return stripHtmlLib(html, {
44
+ ignoreTags: ['pre', 'code'],
45
+ stripTogetherWithTheirContents: ['script', 'style', 'nav', 'footer'],
46
+ }).result;
47
+ }
48
+ export class VanderLeeSource extends RssPatternSource {
49
+ constructor() {
50
+ super({
51
+ feedUrl: 'https://www.avanderlee.com/feed/',
52
+ cacheKey: 'vanderlee-patterns',
53
+ rssCacheTtl: 3600,
54
+ articleCacheTtl: 86400,
55
+ topicKeywords,
56
+ qualitySignals,
57
+ fetchFullArticle: true,
58
+ extractContentFn: extractPostContent,
59
+ });
60
+ }
61
+ }
62
+ export default VanderLeeSource;
63
+ //# sourceMappingURL=vanderlee.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vanderlee.js","sourceRoot":"","sources":["../../../src/sources/free/vanderlee.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAEhC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAKpE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,kBAAkB,CAC1D;IACE,WAAW,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC;IACrD,SAAS,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,YAAY,CAAC;IACjD,SAAS,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC;IAC7C,aAAa,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;CACrC,EACD;IACE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnD,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5D,OAAO,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;CACrD,CACF,CAAC;AAEF,SAAS,kBAAkB,CAAC,IAAY;IACtC,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAErC,gDAAgD;IAChD,MAAM,SAAS,GAAG;QAChB,eAAe;QACf,wBAAwB;QACxB,SAAS;QACT,MAAM;QACN,UAAU;KACX,CAAC;IAEF,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,OAAO,EAAE,CAAC;YACZ,kDAAkD;YAClD,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,iDAAiD,CAAC,CAAC;YACrG,8DAA8D;YAC9D,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAO,EAAE,EAAE;gBACnC,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;YAEH,OAAO,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,yDAAyD;IACzD,6DAA6D;IAC7D,OAAO,YAAY,CAAC,IAAI,EAAE;QACxB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;QAC3B,8BAA8B,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC;KACrE,CAAC,CAAC,MAAM,CAAC;AACZ,CAAC;AAED,MAAM,OAAO,eAAgB,SAAQ,gBAAkC;IACrE;QACE,KAAK,CAAC;YACJ,OAAO,EAAE,kCAAkC;YAC3C,QAAQ,EAAE,oBAAoB;YAC9B,WAAW,EAAE,IAAI;YACjB,eAAe,EAAE,KAAK;YACtB,aAAa;YACb,cAAc;YACd,gBAAgB,EAAE,IAAI;YACtB,gBAAgB,EAAE,kBAAkB;SACrC,CAAC,CAAC;IACL,CAAC;CACF;AAED,eAAe,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=vanderlee.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vanderlee.test.d.ts","sourceRoot":"","sources":["../../../src/sources/free/vanderlee.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,77 @@
1
+ // src/sources/free/vanderlee.test.ts
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
+ import VanderLeeSource from './vanderlee.js';
4
+ const mockFetch = vi.hoisted(() => vi.fn());
5
+ vi.mock('../../utils/fetch.js', () => ({
6
+ fetch: (...args) => mockFetch(...args),
7
+ }));
8
+ vi.mock('rss-parser', () => {
9
+ return {
10
+ default: class Parser {
11
+ async parseURL(_url) {
12
+ return {
13
+ items: [
14
+ {
15
+ guid: '1',
16
+ title: 'Debugging with Xcode',
17
+ link: 'https://example.com/1',
18
+ pubDate: '2026-01-01',
19
+ contentSnippet: 'Debugging tips',
20
+ content: '<p>Debugging <code>let x = 1</code></p>',
21
+ },
22
+ {
23
+ guid: '2',
24
+ title: 'SwiftUI Performance',
25
+ link: 'https://example.com/2',
26
+ pubDate: '2026-01-02',
27
+ contentSnippet: 'SwiftUI performance best practices',
28
+ content: '<p>SwiftUI <pre>struct ContentView: View {}</pre></p>',
29
+ },
30
+ ],
31
+ };
32
+ }
33
+ },
34
+ };
35
+ });
36
+ vi.mock('../../utils/cache.js', () => ({
37
+ rssCache: {
38
+ get: vi.fn(async () => undefined),
39
+ set: vi.fn(async () => undefined),
40
+ },
41
+ articleCache: {
42
+ get: vi.fn(async () => undefined),
43
+ set: vi.fn(async () => undefined),
44
+ },
45
+ }));
46
+ describe('VanderLeeSource', () => {
47
+ let source;
48
+ beforeEach(() => {
49
+ mockFetch.mockReset();
50
+ mockFetch.mockResolvedValue({
51
+ ok: true,
52
+ text: async () => '<div class="post-content">Full article <code>let y = 2</code></div><div></div>',
53
+ });
54
+ source = new VanderLeeSource();
55
+ });
56
+ it('fetches and parses patterns with full article', async () => {
57
+ const patterns = await source.fetchPatterns();
58
+ expect(patterns).toHaveLength(2);
59
+ expect(patterns[0].title).toBe('Debugging with Xcode');
60
+ expect(patterns[0].topics).toContain('debugging');
61
+ expect(patterns[1].topics).toContain('swiftui');
62
+ expect(patterns[0].hasCode).toBe(true);
63
+ expect(patterns[1].hasCode).toBe(true);
64
+ expect(patterns[0].content).toMatch(/Full article/);
65
+ });
66
+ it('calculates relevance score', async () => {
67
+ const patterns = await source.fetchPatterns();
68
+ expect(patterns[0].relevanceScore).toBeGreaterThanOrEqual(67);
69
+ expect(patterns[1].relevanceScore).toBeGreaterThanOrEqual(74);
70
+ });
71
+ it('searchPatterns returns relevant results', async () => {
72
+ const results = await source.searchPatterns('swiftui');
73
+ expect(results[0].title).toMatch(/swiftui/i);
74
+ expect(results[0].topics).toContain('swiftui');
75
+ });
76
+ });
77
+ //# sourceMappingURL=vanderlee.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vanderlee.test.js","sourceRoot":"","sources":["../../../src/sources/free/vanderlee.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ export interface DownloadedPost {
2
+ postId: string;
3
+ title: string;
4
+ publishDate: string;
5
+ creator: string;
6
+ files: DownloadedFile[];
7
+ }
8
+ export interface DownloadedFile {
9
+ filename: string;
10
+ filepath: string;
11
+ type: 'swift' | 'zip' | 'markdown' | 'other';
12
+ content?: string;
13
+ }
14
+ /**
15
+ * Check if patreon-dl is available
16
+ */
17
+ export declare function isPatreonDlAvailable(): Promise<boolean>;
18
+ /**
19
+ * Check if cookie is configured
20
+ */
21
+ export declare function isCookieConfigured(): boolean;
22
+ /**
23
+ * Save cookie for patreon-dl
24
+ */
25
+ export declare function saveCookie(cookie: string): void;
26
+ /**
27
+ * Download content for a creator
28
+ */
29
+ export declare function downloadCreatorContent(creatorUrl: string, creatorName: string): Promise<{
30
+ success: boolean;
31
+ error?: string;
32
+ }>;
33
+ /**
34
+ * Download content for all registered creators
35
+ */
36
+ export declare function downloadAllCreators(): Promise<void>;
37
+ /**
38
+ * Scan downloaded content and index files
39
+ */
40
+ export declare function scanDownloadedContent(): DownloadedPost[];
41
+ /**
42
+ * Get download directory path
43
+ */
44
+ export declare function getContentDir(): string;
45
+ //# sourceMappingURL=patreon-dl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patreon-dl.d.ts","sourceRoot":"","sources":["../../../src/sources/premium/patreon-dl.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO7D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAI/C;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAkB/C;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAWzD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,cAAc,EAAE,CAiCxD;AAmFD;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
@@ -0,0 +1,189 @@
1
+ // src/sources/premium/patreon-dl.ts
2
+ // Wrapper for patreon-dl to download and index Patreon content
3
+ import { exec } from 'child_process';
4
+ import { promisify } from 'util';
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import { CREATORS } from '../../config/creators.js';
8
+ import { getPatreonContentDir } from '../../utils/paths.js';
9
+ import logger from '../../utils/logger.js';
10
+ const execAsync = promisify(exec);
11
+ function getCookiePath() {
12
+ // Use .patreon-session in project root (created by extract-cookie.ts)
13
+ return path.join(process.cwd(), '.patreon-session');
14
+ }
15
+ /**
16
+ * Check if patreon-dl is available
17
+ */
18
+ export async function isPatreonDlAvailable() {
19
+ try {
20
+ await execAsync('npx patreon-dl --version');
21
+ return true;
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ }
27
+ /**
28
+ * Check if cookie is configured
29
+ */
30
+ export function isCookieConfigured() {
31
+ return fs.existsSync(getCookiePath());
32
+ }
33
+ /**
34
+ * Save cookie for patreon-dl
35
+ */
36
+ export function saveCookie(cookie) {
37
+ const cookiePath = getCookiePath();
38
+ fs.mkdirSync(path.dirname(cookiePath), { recursive: true });
39
+ fs.writeFileSync(cookiePath, cookie);
40
+ }
41
+ /**
42
+ * Download content for a creator
43
+ */
44
+ export async function downloadCreatorContent(creatorUrl, creatorName) {
45
+ const cookiePath = getCookiePath();
46
+ if (!fs.existsSync(cookiePath)) {
47
+ return { success: false, error: 'Cookie not configured' };
48
+ }
49
+ const cookie = fs.readFileSync(cookiePath, 'utf-8').trim();
50
+ const outDir = path.join(getPatreonContentDir(), creatorName);
51
+ try {
52
+ // Run patreon-dl with session_id cookie format
53
+ const cmd = `npx patreon-dl -c "session_id=${cookie}" -o "${outDir}" "${creatorUrl}"`;
54
+ await execAsync(cmd, { timeout: 300000 }); // 5 min timeout
55
+ return { success: true };
56
+ }
57
+ catch (error) {
58
+ return { success: false, error: String(error) };
59
+ }
60
+ }
61
+ /**
62
+ * Download content for all registered creators
63
+ */
64
+ export async function downloadAllCreators() {
65
+ for (const creator of CREATORS) {
66
+ const patreonUrl = `https://www.patreon.com/c/${creator.id}`;
67
+ const result = await downloadCreatorContent(patreonUrl, creator.name);
68
+ if (result.success) {
69
+ logger.info({ creator: creator.name }, 'Downloaded content for creator');
70
+ }
71
+ else {
72
+ logger.error({ creator: creator.name, error: result.error }, 'Failed to download creator content');
73
+ }
74
+ }
75
+ }
76
+ /**
77
+ * Scan downloaded content and index files
78
+ */
79
+ export function scanDownloadedContent() {
80
+ const downloadDir = getPatreonContentDir();
81
+ const posts = [];
82
+ if (!fs.existsSync(downloadDir)) {
83
+ return posts;
84
+ }
85
+ // Scan each creator directory
86
+ const creatorDirs = fs.readdirSync(downloadDir);
87
+ for (const creatorDir of creatorDirs) {
88
+ const creatorPath = path.join(downloadDir, creatorDir);
89
+ if (!fs.statSync(creatorPath).isDirectory())
90
+ continue;
91
+ // Look for posts directory
92
+ const postsPath = path.join(creatorPath, 'posts');
93
+ if (!fs.existsSync(postsPath))
94
+ continue;
95
+ // Scan each post
96
+ const postDirs = fs.readdirSync(postsPath);
97
+ for (const postDir of postDirs) {
98
+ const postPath = path.join(postsPath, postDir);
99
+ if (!fs.statSync(postPath).isDirectory())
100
+ continue;
101
+ const post = scanPost(postPath, creatorDir);
102
+ if (post) {
103
+ posts.push(post);
104
+ }
105
+ }
106
+ }
107
+ return posts;
108
+ }
109
+ /**
110
+ * Scan a single post directory
111
+ */
112
+ function scanPost(postPath, creatorName) {
113
+ const files = [];
114
+ // Read post metadata if available
115
+ const metadataPath = path.join(postPath, 'post.json');
116
+ let title = path.basename(postPath);
117
+ let publishDate = '';
118
+ let postId = path.basename(postPath);
119
+ if (fs.existsSync(metadataPath)) {
120
+ try {
121
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
122
+ title = metadata.title || title;
123
+ publishDate = metadata.published_at || metadata.publishedAt || '';
124
+ postId = metadata.id || postId;
125
+ }
126
+ catch {
127
+ // Ignore metadata parsing errors
128
+ }
129
+ }
130
+ // Scan for relevant files
131
+ scanDirectory(postPath, files);
132
+ if (files.length === 0) {
133
+ return null;
134
+ }
135
+ return {
136
+ postId,
137
+ title,
138
+ publishDate,
139
+ creator: creatorName,
140
+ files,
141
+ };
142
+ }
143
+ /**
144
+ * Recursively scan directory for relevant files
145
+ */
146
+ function scanDirectory(dir, files) {
147
+ const entries = fs.readdirSync(dir);
148
+ for (const entry of entries) {
149
+ const fullPath = path.join(dir, entry);
150
+ const stat = fs.statSync(fullPath);
151
+ if (stat.isDirectory()) {
152
+ // Skip certain directories
153
+ if (!['node_modules', '.git', '__MACOSX'].includes(entry)) {
154
+ scanDirectory(fullPath, files);
155
+ }
156
+ }
157
+ else {
158
+ const ext = path.extname(entry).toLowerCase();
159
+ let type = 'other';
160
+ let content;
161
+ if (ext === '.swift') {
162
+ type = 'swift';
163
+ content = fs.readFileSync(fullPath, 'utf-8');
164
+ }
165
+ else if (ext === '.zip') {
166
+ type = 'zip';
167
+ }
168
+ else if (ext === '.md' || ext === '.markdown') {
169
+ type = 'markdown';
170
+ content = fs.readFileSync(fullPath, 'utf-8');
171
+ }
172
+ if (type !== 'other') {
173
+ files.push({
174
+ filename: entry,
175
+ filepath: fullPath,
176
+ type,
177
+ content,
178
+ });
179
+ }
180
+ }
181
+ }
182
+ }
183
+ /**
184
+ * Get download directory path
185
+ */
186
+ export function getContentDir() {
187
+ return getPatreonContentDir();
188
+ }
189
+ //# sourceMappingURL=patreon-dl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patreon-dl.js","sourceRoot":"","sources":["../../../src/sources/premium/patreon-dl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=patreon-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patreon-fetch.d.ts","sourceRoot":"","sources":["../../../src/sources/premium/patreon-fetch.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from 'child_process';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ const [, , url, out] = process.argv;
8
+ const cookieFile = '.patreon-session';
9
+ if (!fs.existsSync(cookieFile)) {
10
+ console.log('No session cookie — running browser auth...');
11
+ // extract-cookie.js is in build/tools/ relative to this file in build/sources/premium/
12
+ const extractCookiePath = path.join(__dirname, '..', '..', 'tools', 'extract-cookie.js');
13
+ execSync(`node "${extractCookiePath}"`, { stdio: 'inherit' });
14
+ }
15
+ const session = fs.readFileSync(cookieFile, 'utf8').trim();
16
+ console.log('Downloading with patreon-dl...');
17
+ execSync(`npx patreon-dl -c "session_id=${session}" -o "${out}" "${url}"`, { stdio: 'inherit' });
18
+ //# sourceMappingURL=patreon-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patreon-fetch.js","sourceRoot":"","sources":["../../../src/sources/premium/patreon-fetch.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,MAAM,CAAC,EAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;AACnC,MAAM,UAAU,GAAG,kBAAkB,CAAC;AAEtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;IAC3D,uFAAuF;IACvF,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;IACzF,QAAQ,CAAC,SAAS,iBAAiB,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;AAC3D,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;AAC9C,QAAQ,CAAC,iCAAiC,OAAO,SAAS,GAAG,MAAM,GAAG,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ export declare const PATREON_SCOPES: string;
2
+ export interface PatreonTokens {
3
+ access_token: string;
4
+ refresh_token: string;
5
+ expires_at: number;
6
+ scope: string;
7
+ }
8
+ export interface OAuthResult {
9
+ success: boolean;
10
+ tokens?: PatreonTokens;
11
+ error?: string;
12
+ }
13
+ export declare function saveTokens(tokens: PatreonTokens): Promise<void>;
14
+ export declare function loadTokens(): Promise<PatreonTokens | null>;
15
+ export declare function clearTokens(): Promise<void>;
16
+ export declare function isTokenExpired(tokens: PatreonTokens): boolean;
17
+ export declare function refreshAccessToken(clientId: string, clientSecret: string, refreshToken: string): Promise<PatreonTokens>;
18
+ export declare function startOAuthFlow(clientId: string, clientSecret: string): Promise<OAuthResult>;
19
+ export declare function getValidAccessToken(clientId: string, clientSecret: string): Promise<string | null>;
20
+ /**
21
+ * Clear all Patreon authentication data (keytar + legacy tokens.json)
22
+ */
23
+ export declare function clearPatreonAuth(): Promise<void>;
24
+ //# sourceMappingURL=patreon-oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patreon-oauth.d.ts","sourceRoot":"","sources":["../../../src/sources/premium/patreon-oauth.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,cAAc,QAKhB,CAAC;AAEZ,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrE;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAQhE;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAG7D;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,CAAC,CAgCxB;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC,CAuHtB;AAED,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgBxB;AAMD;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAYtD"}