swift-patterns-mcp 1.0.17 → 1.0.18
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.
- package/README.md +48 -2
- package/build/__tests__/fixtures/patterns.d.ts +72 -0
- package/build/__tests__/fixtures/patterns.d.ts.map +1 -0
- package/build/__tests__/fixtures/patterns.js +105 -0
- package/build/__tests__/fixtures/patterns.js.map +1 -0
- package/build/__tests__/fixtures/tool-context.d.ts +53 -0
- package/build/__tests__/fixtures/tool-context.d.ts.map +1 -0
- package/build/__tests__/fixtures/tool-context.js +41 -0
- package/build/__tests__/fixtures/tool-context.js.map +1 -0
- package/build/__tests__/server.test.d.ts +2 -0
- package/build/__tests__/server.test.d.ts.map +1 -0
- package/build/__tests__/server.test.js +167 -0
- package/build/__tests__/server.test.js.map +1 -0
- package/build/cli/__tests__/setup.test.d.ts +2 -0
- package/build/cli/__tests__/setup.test.d.ts.map +1 -0
- package/build/cli/__tests__/setup.test.js +85 -0
- package/build/cli/__tests__/setup.test.js.map +1 -0
- package/build/cli/patreon.js +3 -11
- package/build/cli/patreon.js.map +1 -1
- package/build/cli/router.d.ts +6 -0
- package/build/cli/router.d.ts.map +1 -0
- package/build/cli/router.js +42 -0
- package/build/cli/router.js.map +1 -0
- package/build/cli/setup-utils.d.ts +17 -0
- package/build/cli/setup-utils.d.ts.map +1 -0
- package/build/cli/setup-utils.js +86 -0
- package/build/cli/setup-utils.js.map +1 -0
- package/build/cli/setup.d.ts +3 -0
- package/build/cli/setup.d.ts.map +1 -0
- package/build/cli/setup.js +141 -0
- package/build/cli/setup.js.map +1 -0
- package/build/config/__tests__/sources.test.js +0 -16
- package/build/config/__tests__/sources.test.js.map +1 -1
- package/build/config/creators.d.ts +1 -2
- package/build/config/creators.d.ts.map +1 -1
- package/build/config/sources.d.ts +0 -16
- package/build/config/sources.d.ts.map +1 -1
- package/build/config/sources.js +1 -26
- package/build/config/sources.js.map +1 -1
- package/build/index.js +9 -206
- package/build/index.js.map +1 -1
- package/build/integration/__tests__/mcp-client.test.js +21 -7
- package/build/integration/__tests__/mcp-client.test.js.map +1 -1
- package/build/{sources/premium/__tests__ → integration/__tests__/slow}/patreon-integration.test.d.ts +1 -1
- package/build/integration/__tests__/slow/patreon-integration.test.d.ts.map +1 -0
- package/build/{sources/premium/__tests__ → integration/__tests__/slow}/patreon-integration.test.js +9 -19
- package/build/integration/__tests__/slow/patreon-integration.test.js.map +1 -0
- package/build/integration/__tests__/slow/response-quality.test.d.ts.map +1 -0
- package/build/integration/__tests__/{response-quality.test.js → slow/response-quality.test.js} +105 -19
- package/build/integration/__tests__/slow/response-quality.test.js.map +1 -0
- package/build/integration/test-client.d.ts +2 -0
- package/build/integration/test-client.d.ts.map +1 -1
- package/build/integration/test-client.js +48 -8
- package/build/integration/test-client.js.map +1 -1
- package/build/server.d.ts +5 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +93 -0
- package/build/server.js.map +1 -0
- package/build/sources/free/__tests__/nilcoalescing.test.js +49 -20
- package/build/sources/free/__tests__/nilcoalescing.test.js.map +1 -1
- package/build/sources/free/__tests__/pointfree.test.js +73 -0
- package/build/sources/free/__tests__/pointfree.test.js.map +1 -1
- package/build/sources/free/__tests__/rssPatternSource.test.js +87 -20
- package/build/sources/free/__tests__/rssPatternSource.test.js.map +1 -1
- package/build/sources/free/__tests__/sundell.test.js +49 -20
- package/build/sources/free/__tests__/sundell.test.js.map +1 -1
- package/build/sources/free/__tests__/vanderlee.test.js +60 -20
- package/build/sources/free/__tests__/vanderlee.test.js.map +1 -1
- package/build/sources/free/nilcoalescing.d.ts +1 -3
- package/build/sources/free/nilcoalescing.d.ts.map +1 -1
- package/build/sources/free/nilcoalescing.js.map +1 -1
- package/build/sources/free/sundell.d.ts +1 -3
- package/build/sources/free/sundell.d.ts.map +1 -1
- package/build/sources/free/sundell.js.map +1 -1
- package/build/sources/free/vanderlee.d.ts +1 -3
- package/build/sources/free/vanderlee.d.ts.map +1 -1
- package/build/sources/free/vanderlee.js.map +1 -1
- package/build/sources/premium/__tests__/patreon-dedup.test.d.ts +2 -0
- package/build/sources/premium/__tests__/patreon-dedup.test.d.ts.map +1 -0
- package/build/sources/premium/__tests__/patreon-dedup.test.js +78 -0
- package/build/sources/premium/__tests__/patreon-dedup.test.js.map +1 -0
- package/build/sources/premium/__tests__/patreon-dl.test.d.ts +2 -0
- package/build/sources/premium/__tests__/patreon-dl.test.d.ts.map +1 -0
- package/build/sources/premium/__tests__/patreon-dl.test.js +170 -0
- package/build/sources/premium/__tests__/patreon-dl.test.js.map +1 -0
- package/build/sources/premium/__tests__/patreon-oauth.test.d.ts +2 -0
- package/build/sources/premium/__tests__/patreon-oauth.test.d.ts.map +1 -0
- package/build/sources/premium/__tests__/patreon-oauth.test.js +220 -0
- package/build/sources/premium/__tests__/patreon-oauth.test.js.map +1 -0
- package/build/sources/premium/__tests__/patreon-scoring.test.d.ts +2 -0
- package/build/sources/premium/__tests__/patreon-scoring.test.d.ts.map +1 -0
- package/build/sources/premium/__tests__/patreon-scoring.test.js +103 -0
- package/build/sources/premium/__tests__/patreon-scoring.test.js.map +1 -0
- package/build/sources/premium/__tests__/youtube.test.d.ts +2 -0
- package/build/sources/premium/__tests__/youtube.test.d.ts.map +1 -0
- package/build/sources/premium/__tests__/youtube.test.js +107 -0
- package/build/sources/premium/__tests__/youtube.test.js.map +1 -0
- package/build/sources/premium/patreon-dedup.d.ts +8 -0
- package/build/sources/premium/patreon-dedup.d.ts.map +1 -0
- package/build/sources/premium/patreon-dedup.js +61 -0
- package/build/sources/premium/patreon-dedup.js.map +1 -0
- package/build/sources/premium/patreon-enrichment.d.ts +30 -0
- package/build/sources/premium/patreon-enrichment.d.ts.map +1 -0
- package/build/sources/premium/patreon-enrichment.js +154 -0
- package/build/sources/premium/patreon-enrichment.js.map +1 -0
- package/build/sources/premium/patreon-oauth.d.ts.map +1 -1
- package/build/sources/premium/patreon-oauth.js +62 -21
- package/build/sources/premium/patreon-oauth.js.map +1 -1
- package/build/sources/premium/patreon-scoring.d.ts +9 -0
- package/build/sources/premium/patreon-scoring.d.ts.map +1 -0
- package/build/sources/premium/patreon-scoring.js +43 -0
- package/build/sources/premium/patreon-scoring.js.map +1 -0
- package/build/sources/premium/patreon.d.ts +9 -40
- package/build/sources/premium/patreon.d.ts.map +1 -1
- package/build/sources/premium/patreon.js +168 -139
- package/build/sources/premium/patreon.js.map +1 -1
- package/build/sources/premium/youtube.d.ts +3 -6
- package/build/sources/premium/youtube.d.ts.map +1 -1
- package/build/sources/premium/youtube.js +31 -53
- package/build/sources/premium/youtube.js.map +1 -1
- package/build/tools/handlers/__tests__/getPatreonPatterns.test.js +29 -96
- package/build/tools/handlers/__tests__/getPatreonPatterns.test.js.map +1 -1
- package/build/tools/handlers/__tests__/handlers.test.js +26 -125
- package/build/tools/handlers/__tests__/handlers.test.js.map +1 -1
- package/build/tools/handlers/__tests__/harness.d.ts +8 -0
- package/build/tools/handlers/__tests__/harness.d.ts.map +1 -0
- package/build/tools/handlers/__tests__/harness.js +36 -0
- package/build/tools/handlers/__tests__/harness.js.map +1 -0
- package/build/tools/handlers/cached-search.d.ts +22 -0
- package/build/tools/handlers/cached-search.d.ts.map +1 -0
- package/build/tools/handlers/cached-search.js +59 -0
- package/build/tools/handlers/cached-search.js.map +1 -0
- package/build/tools/handlers/enableSource.d.ts.map +1 -1
- package/build/tools/handlers/enableSource.js +5 -2
- package/build/tools/handlers/enableSource.js.map +1 -1
- package/build/tools/handlers/getPatreonPatterns.d.ts.map +1 -1
- package/build/tools/handlers/getPatreonPatterns.js +40 -31
- package/build/tools/handlers/getPatreonPatterns.js.map +1 -1
- package/build/tools/handlers/getSwiftPattern.d.ts.map +1 -1
- package/build/tools/handlers/getSwiftPattern.js +111 -68
- package/build/tools/handlers/getSwiftPattern.js.map +1 -1
- package/build/tools/handlers/listContentSources.js +1 -1
- package/build/tools/handlers/searchSwiftContent.d.ts.map +1 -1
- package/build/tools/handlers/searchSwiftContent.js +93 -95
- package/build/tools/handlers/searchSwiftContent.js.map +1 -1
- package/build/tools/handlers/setupPatreon.d.ts.map +1 -1
- package/build/tools/handlers/setupPatreon.js +44 -27
- package/build/tools/handlers/setupPatreon.js.map +1 -1
- package/build/tools/registration.d.ts +10 -0
- package/build/tools/registration.d.ts.map +1 -0
- package/build/tools/registration.js +117 -0
- package/build/tools/registration.js.map +1 -0
- package/build/tools/types.d.ts +3 -1
- package/build/tools/types.d.ts.map +1 -1
- package/build/tools/validation.d.ts +26 -0
- package/build/tools/validation.d.ts.map +1 -0
- package/build/tools/validation.js +60 -0
- package/build/tools/validation.js.map +1 -0
- package/build/utils/__tests__/cache.test.js +96 -1
- package/build/utils/__tests__/cache.test.js.map +1 -1
- package/build/utils/__tests__/http.test.d.ts +2 -0
- package/build/utils/__tests__/http.test.d.ts.map +1 -0
- package/build/utils/__tests__/http.test.js +108 -0
- package/build/utils/__tests__/http.test.js.map +1 -0
- package/build/utils/__tests__/inflight-dedup.test.d.ts +2 -0
- package/build/utils/__tests__/inflight-dedup.test.d.ts.map +1 -0
- package/build/utils/__tests__/inflight-dedup.test.js +124 -0
- package/build/utils/__tests__/inflight-dedup.test.js.map +1 -0
- package/build/utils/__tests__/intent-cache.test.js +81 -4
- package/build/utils/__tests__/intent-cache.test.js.map +1 -1
- package/build/utils/__tests__/query-analysis.test.d.ts +2 -0
- package/build/utils/__tests__/query-analysis.test.d.ts.map +1 -0
- package/build/utils/__tests__/query-analysis.test.js +52 -0
- package/build/utils/__tests__/query-analysis.test.js.map +1 -0
- package/build/utils/__tests__/response-helpers.test.js +11 -1
- package/build/utils/__tests__/response-helpers.test.js.map +1 -1
- package/build/utils/__tests__/search.test.js +1 -60
- package/build/utils/__tests__/search.test.js.map +1 -1
- package/build/utils/cache.d.ts +11 -0
- package/build/utils/cache.d.ts.map +1 -1
- package/build/utils/cache.js +23 -0
- package/build/utils/cache.js.map +1 -1
- package/build/utils/fetch.d.ts +2 -3
- package/build/utils/fetch.d.ts.map +1 -1
- package/build/utils/fetch.js +2 -3
- package/build/utils/fetch.js.map +1 -1
- package/build/utils/patreon-env.d.ts +5 -0
- package/build/utils/patreon-env.d.ts.map +1 -0
- package/build/utils/patreon-env.js +17 -0
- package/build/utils/patreon-env.js.map +1 -0
- package/build/utils/query-analysis.d.ts +25 -0
- package/build/utils/query-analysis.d.ts.map +1 -0
- package/build/utils/query-analysis.js +110 -0
- package/build/utils/query-analysis.js.map +1 -0
- package/build/utils/response-helpers.d.ts +16 -0
- package/build/utils/response-helpers.d.ts.map +1 -1
- package/build/utils/response-helpers.js +43 -0
- package/build/utils/response-helpers.js.map +1 -1
- package/build/utils/search.d.ts +0 -3
- package/build/utils/search.d.ts.map +1 -1
- package/build/utils/search.js +2 -41
- package/build/utils/search.js.map +1 -1
- package/package.json +19 -12
- package/build/integration/__tests__/response-quality.test.d.ts.map +0 -1
- package/build/integration/__tests__/response-quality.test.js.map +0 -1
- package/build/sources/premium/__tests__/patreon-integration.test.d.ts.map +0 -1
- package/build/sources/premium/__tests__/patreon-integration.test.js.map +0 -1
- /package/build/integration/__tests__/{response-quality.test.d.ts → slow/response-quality.test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -72,12 +72,55 @@ Access exclusive content from top iOS educators: **Kavsoft**, **SwiftUI Codes**,
|
|
|
72
72
|
|
|
73
73
|
## 🚀 Quick Start
|
|
74
74
|
|
|
75
|
-
###
|
|
75
|
+
### Run Setup
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
78
|
npx -y swift-patterns-mcp@latest
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
+
In an interactive terminal, this opens the setup wizard.
|
|
82
|
+
When launched by an MCP client (non-interactive stdio), it runs as the MCP server automatically.
|
|
83
|
+
|
|
84
|
+
### Interactive Setup Wizard
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx -y swift-patterns-mcp@latest setup
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If installed globally, you can also run:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
swift-patterns-mcp setup
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The wizard helps you choose:
|
|
97
|
+
- Config scope (local project vs global)
|
|
98
|
+
- MCP client (Cursor, Claude Code, Windsurf, VS Code)
|
|
99
|
+
- Optional Patreon setup prompt
|
|
100
|
+
|
|
101
|
+
### Non-interactive Setup (CI/Scripts)
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Cursor
|
|
105
|
+
npx -y swift-patterns-mcp@latest setup --cursor --global
|
|
106
|
+
npx -y swift-patterns-mcp@latest setup --cursor --local
|
|
107
|
+
|
|
108
|
+
# Claude Code
|
|
109
|
+
npx -y swift-patterns-mcp@latest setup --claude --global
|
|
110
|
+
|
|
111
|
+
# Windsurf
|
|
112
|
+
npx -y swift-patterns-mcp@latest setup --windsurf --global
|
|
113
|
+
|
|
114
|
+
# VS Code
|
|
115
|
+
npx -y swift-patterns-mcp@latest setup --vscode --local
|
|
116
|
+
|
|
117
|
+
# All clients
|
|
118
|
+
npx -y swift-patterns-mcp@latest setup --all --global
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Use `--global` (`-g`) or `--local` (`-l`) to skip the location prompt.
|
|
122
|
+
Use `--cursor`, `--claude`, `--windsurf`, `--vscode`, or `--all` to skip the client prompt.
|
|
123
|
+
|
|
81
124
|
### Configure Your AI Assistant
|
|
82
125
|
|
|
83
126
|
#### Cursor
|
|
@@ -359,6 +402,9 @@ Patreon requires OAuth apps to be registered by creators. You don't need to laun
|
|
|
359
402
|
# List all content sources and status
|
|
360
403
|
swift-patterns-mcp sources
|
|
361
404
|
|
|
405
|
+
# Interactive onboarding/configuration wizard
|
|
406
|
+
swift-patterns-mcp setup
|
|
407
|
+
|
|
362
408
|
# Patreon integration
|
|
363
409
|
swift-patterns-mcp patreon setup # Connect your Patreon account
|
|
364
410
|
swift-patterns-mcp patreon status # Check connection status
|
|
@@ -450,4 +496,4 @@ MIT License - Copyright (c) 2026 Lasha Efremidze
|
|
|
450
496
|
|
|
451
497
|
**Made with ❤️ for the Swift community**
|
|
452
498
|
|
|
453
|
-
[⭐ Star this repo](https://github.com/efremidze/swift-patterns-mcp) • [🐛 Report Bug](
|
|
499
|
+
[⭐ Star this repo](https://github.com/efremidze/swift-patterns-mcp) • [🐛 Report Bug](https://github.com/efremidze/swift-patterns-mcp/issues) • [✨ Request Feature](https://github.com/efremidze/swift-patterns-mcp/issues)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { PatreonPattern } from '../../tools/types.js';
|
|
2
|
+
export declare const FREE_SOURCE_PATTERNS: {
|
|
3
|
+
readonly sundell: readonly [{
|
|
4
|
+
readonly id: "sundell-1";
|
|
5
|
+
readonly title: "Advanced SwiftUI Patterns";
|
|
6
|
+
readonly url: "https://swiftbysundell.com/swiftui";
|
|
7
|
+
readonly excerpt: "Learn advanced SwiftUI patterns for production apps";
|
|
8
|
+
readonly content: "Full content about SwiftUI state management and views";
|
|
9
|
+
readonly topics: readonly ["swiftui", "architecture"];
|
|
10
|
+
readonly relevanceScore: 85;
|
|
11
|
+
readonly hasCode: true;
|
|
12
|
+
readonly publishDate: "2024-01-15T00:00:00Z";
|
|
13
|
+
}, {
|
|
14
|
+
readonly id: "sundell-2";
|
|
15
|
+
readonly title: "Basic Swift Tips";
|
|
16
|
+
readonly url: "https://swiftbysundell.com/tips";
|
|
17
|
+
readonly excerpt: "Simple tips for Swift developers";
|
|
18
|
+
readonly content: "Basic content without code examples";
|
|
19
|
+
readonly topics: readonly ["swift"];
|
|
20
|
+
readonly relevanceScore: 55;
|
|
21
|
+
readonly hasCode: false;
|
|
22
|
+
readonly publishDate: "2024-01-10T00:00:00Z";
|
|
23
|
+
}];
|
|
24
|
+
readonly vanderlee: readonly [{
|
|
25
|
+
readonly id: "vanderlee-1";
|
|
26
|
+
readonly title: "iOS Performance Optimization";
|
|
27
|
+
readonly url: "https://avanderlee.com/performance";
|
|
28
|
+
readonly excerpt: "Optimize your iOS app performance";
|
|
29
|
+
readonly content: "Detailed performance optimization techniques";
|
|
30
|
+
readonly topics: readonly ["performance", "optimization"];
|
|
31
|
+
readonly relevanceScore: 78;
|
|
32
|
+
readonly hasCode: true;
|
|
33
|
+
readonly publishDate: "2024-01-12T00:00:00Z";
|
|
34
|
+
}, {
|
|
35
|
+
readonly id: "vanderlee-2";
|
|
36
|
+
readonly title: "Debugging Tips";
|
|
37
|
+
readonly url: "https://avanderlee.com/debugging";
|
|
38
|
+
readonly excerpt: "Debug your iOS apps effectively";
|
|
39
|
+
readonly content: "Debugging techniques without code";
|
|
40
|
+
readonly topics: readonly ["debugging"];
|
|
41
|
+
readonly relevanceScore: 65;
|
|
42
|
+
readonly hasCode: false;
|
|
43
|
+
readonly publishDate: "2024-01-08T00:00:00Z";
|
|
44
|
+
}];
|
|
45
|
+
readonly nilcoalescing: readonly [{
|
|
46
|
+
readonly id: "nilcoalescing-1";
|
|
47
|
+
readonly title: "SwiftUI Navigation Deep Dive";
|
|
48
|
+
readonly url: "https://nilcoalescing.com/navigation";
|
|
49
|
+
readonly excerpt: "Master SwiftUI navigation patterns";
|
|
50
|
+
readonly content: "Navigation code examples and patterns";
|
|
51
|
+
readonly topics: readonly ["swiftui", "navigation"];
|
|
52
|
+
readonly relevanceScore: 72;
|
|
53
|
+
readonly hasCode: true;
|
|
54
|
+
readonly publishDate: "2024-01-14T00:00:00Z";
|
|
55
|
+
}];
|
|
56
|
+
readonly pointfree: readonly [{
|
|
57
|
+
readonly id: "pointfree-1";
|
|
58
|
+
readonly title: "Composable Architecture Case Study";
|
|
59
|
+
readonly url: "https://github.com/pointfreeco/pointfreeco/blob/main/Sources/Models/Episodes/0001-functions.md";
|
|
60
|
+
readonly excerpt: "Build apps with TCA";
|
|
61
|
+
readonly content: "TCA reducer and store patterns";
|
|
62
|
+
readonly topics: readonly ["architecture", "tca"];
|
|
63
|
+
readonly relevanceScore: 90;
|
|
64
|
+
readonly hasCode: true;
|
|
65
|
+
readonly publishDate: "2024-01-16T00:00:00Z";
|
|
66
|
+
}];
|
|
67
|
+
};
|
|
68
|
+
export declare function createPatreonPattern(overrides?: Partial<PatreonPattern>): PatreonPattern;
|
|
69
|
+
export declare const PATREON_PATTERNS_WITH_CODE: PatreonPattern[];
|
|
70
|
+
export declare const PATREON_PATTERNS_MIXED: PatreonPattern[];
|
|
71
|
+
export declare const PATREON_PATTERNS_TWELVE: PatreonPattern[];
|
|
72
|
+
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../src/__tests__/fixtures/patterns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2EvB,CAAC;AAEX,wBAAgB,oBAAoB,CAAC,SAAS,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG,cAAc,CAc5F;AAED,eAAO,MAAM,0BAA0B,kBAGtC,CAAC;AAEF,eAAO,MAAM,sBAAsB,kBAGlC,CAAC;AAEF,eAAO,MAAM,uBAAuB,kBAMnC,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export const FREE_SOURCE_PATTERNS = {
|
|
2
|
+
sundell: [
|
|
3
|
+
{
|
|
4
|
+
id: 'sundell-1',
|
|
5
|
+
title: 'Advanced SwiftUI Patterns',
|
|
6
|
+
url: 'https://swiftbysundell.com/swiftui',
|
|
7
|
+
excerpt: 'Learn advanced SwiftUI patterns for production apps',
|
|
8
|
+
content: 'Full content about SwiftUI state management and views',
|
|
9
|
+
topics: ['swiftui', 'architecture'],
|
|
10
|
+
relevanceScore: 85,
|
|
11
|
+
hasCode: true,
|
|
12
|
+
publishDate: '2024-01-15T00:00:00Z',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 'sundell-2',
|
|
16
|
+
title: 'Basic Swift Tips',
|
|
17
|
+
url: 'https://swiftbysundell.com/tips',
|
|
18
|
+
excerpt: 'Simple tips for Swift developers',
|
|
19
|
+
content: 'Basic content without code examples',
|
|
20
|
+
topics: ['swift'],
|
|
21
|
+
relevanceScore: 55,
|
|
22
|
+
hasCode: false,
|
|
23
|
+
publishDate: '2024-01-10T00:00:00Z',
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
vanderlee: [
|
|
27
|
+
{
|
|
28
|
+
id: 'vanderlee-1',
|
|
29
|
+
title: 'iOS Performance Optimization',
|
|
30
|
+
url: 'https://avanderlee.com/performance',
|
|
31
|
+
excerpt: 'Optimize your iOS app performance',
|
|
32
|
+
content: 'Detailed performance optimization techniques',
|
|
33
|
+
topics: ['performance', 'optimization'],
|
|
34
|
+
relevanceScore: 78,
|
|
35
|
+
hasCode: true,
|
|
36
|
+
publishDate: '2024-01-12T00:00:00Z',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'vanderlee-2',
|
|
40
|
+
title: 'Debugging Tips',
|
|
41
|
+
url: 'https://avanderlee.com/debugging',
|
|
42
|
+
excerpt: 'Debug your iOS apps effectively',
|
|
43
|
+
content: 'Debugging techniques without code',
|
|
44
|
+
topics: ['debugging'],
|
|
45
|
+
relevanceScore: 65,
|
|
46
|
+
hasCode: false,
|
|
47
|
+
publishDate: '2024-01-08T00:00:00Z',
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
nilcoalescing: [
|
|
51
|
+
{
|
|
52
|
+
id: 'nilcoalescing-1',
|
|
53
|
+
title: 'SwiftUI Navigation Deep Dive',
|
|
54
|
+
url: 'https://nilcoalescing.com/navigation',
|
|
55
|
+
excerpt: 'Master SwiftUI navigation patterns',
|
|
56
|
+
content: 'Navigation code examples and patterns',
|
|
57
|
+
topics: ['swiftui', 'navigation'],
|
|
58
|
+
relevanceScore: 72,
|
|
59
|
+
hasCode: true,
|
|
60
|
+
publishDate: '2024-01-14T00:00:00Z',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
pointfree: [
|
|
64
|
+
{
|
|
65
|
+
id: 'pointfree-1',
|
|
66
|
+
title: 'Composable Architecture Case Study',
|
|
67
|
+
url: 'https://github.com/pointfreeco/pointfreeco/blob/main/Sources/Models/Episodes/0001-functions.md',
|
|
68
|
+
excerpt: 'Build apps with TCA',
|
|
69
|
+
content: 'TCA reducer and store patterns',
|
|
70
|
+
topics: ['architecture', 'tca'],
|
|
71
|
+
relevanceScore: 90,
|
|
72
|
+
hasCode: true,
|
|
73
|
+
publishDate: '2024-01-16T00:00:00Z',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
export function createPatreonPattern(overrides = {}) {
|
|
78
|
+
return {
|
|
79
|
+
id: 'pat-001',
|
|
80
|
+
title: 'Test Pattern',
|
|
81
|
+
url: 'https://patreon.com/posts/test-123',
|
|
82
|
+
publishDate: '2024-06-15T00:00:00Z',
|
|
83
|
+
excerpt: 'A test excerpt about SwiftUI',
|
|
84
|
+
content: 'Full test content',
|
|
85
|
+
creator: 'TestCreator',
|
|
86
|
+
topics: ['swiftui'],
|
|
87
|
+
relevanceScore: 80,
|
|
88
|
+
hasCode: true,
|
|
89
|
+
...overrides,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export const PATREON_PATTERNS_WITH_CODE = [
|
|
93
|
+
createPatreonPattern({ id: 'pat-101', title: 'Pattern A', hasCode: true }),
|
|
94
|
+
createPatreonPattern({ id: 'pat-102', title: 'Pattern B', hasCode: true }),
|
|
95
|
+
];
|
|
96
|
+
export const PATREON_PATTERNS_MIXED = [
|
|
97
|
+
createPatreonPattern({ id: 'pat-201', title: 'With Code', hasCode: true }),
|
|
98
|
+
createPatreonPattern({ id: 'pat-202', title: 'No Code', hasCode: false }),
|
|
99
|
+
];
|
|
100
|
+
export const PATREON_PATTERNS_TWELVE = Array.from({ length: 12 }, (_, index) => createPatreonPattern({
|
|
101
|
+
id: `pat-${String(index + 1).padStart(3, '0')}`,
|
|
102
|
+
title: `Pattern ${index + 1}`,
|
|
103
|
+
creator: `Creator ${index + 1}`,
|
|
104
|
+
}));
|
|
105
|
+
//# sourceMappingURL=patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../../src/__tests__/fixtures/patterns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ToolContext } from '../../tools/types.js';
|
|
2
|
+
export declare function createMockSourceManager(): {
|
|
3
|
+
getAllSources: import("vitest").Mock<(...args: any[]) => any>;
|
|
4
|
+
getSource: import("vitest").Mock<(id: string) => {
|
|
5
|
+
id: "sundell";
|
|
6
|
+
name: "Swift by Sundell";
|
|
7
|
+
type: "free";
|
|
8
|
+
requiresAuth: false;
|
|
9
|
+
isEnabled: true;
|
|
10
|
+
isConfigured: true;
|
|
11
|
+
description: "Swift articles";
|
|
12
|
+
} | {
|
|
13
|
+
id: "vanderlee";
|
|
14
|
+
name: "Antoine van der Lee";
|
|
15
|
+
type: "free";
|
|
16
|
+
requiresAuth: false;
|
|
17
|
+
isEnabled: true;
|
|
18
|
+
isConfigured: true;
|
|
19
|
+
description: "iOS tips";
|
|
20
|
+
} | {
|
|
21
|
+
id: "nilcoalescing";
|
|
22
|
+
name: "Nil Coalescing";
|
|
23
|
+
type: "free";
|
|
24
|
+
requiresAuth: false;
|
|
25
|
+
isEnabled: true;
|
|
26
|
+
isConfigured: true;
|
|
27
|
+
description: "SwiftUI tips";
|
|
28
|
+
} | {
|
|
29
|
+
id: "pointfree";
|
|
30
|
+
name: "Point-Free";
|
|
31
|
+
type: "free";
|
|
32
|
+
requiresAuth: false;
|
|
33
|
+
isEnabled: true;
|
|
34
|
+
isConfigured: true;
|
|
35
|
+
description: "Open source patterns";
|
|
36
|
+
} | {
|
|
37
|
+
id: "patreon";
|
|
38
|
+
name: "Patreon";
|
|
39
|
+
type: "premium";
|
|
40
|
+
requiresAuth: true;
|
|
41
|
+
isEnabled: false;
|
|
42
|
+
isConfigured: false;
|
|
43
|
+
description: "Premium content";
|
|
44
|
+
} | undefined>;
|
|
45
|
+
isSourceConfigured: import("vitest").Mock<(id: string) => boolean>;
|
|
46
|
+
getSemanticRecallConfig: import("vitest").Mock<(...args: any[]) => any>;
|
|
47
|
+
getMemvidConfig: import("vitest").Mock<(...args: any[]) => any>;
|
|
48
|
+
enableSource: import("vitest").Mock<(...args: any[]) => any>;
|
|
49
|
+
disableSource: import("vitest").Mock<(...args: any[]) => any>;
|
|
50
|
+
getEnabledSources: import("vitest").Mock<(...args: any[]) => any>;
|
|
51
|
+
};
|
|
52
|
+
export declare function createToolContext(overrides?: Partial<ToolContext>): ToolContext;
|
|
53
|
+
//# sourceMappingURL=tool-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-context.d.ts","sourceRoot":"","sources":["../../../src/__tests__/fixtures/tool-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAUxD,wBAAgB,uBAAuB;;0CAKb,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDACG,MAAM;;;;;;EAmBxC;AAED,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,CAMnF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
const DEFAULT_SOURCES = [
|
|
3
|
+
{ id: 'sundell', name: 'Swift by Sundell', type: 'free', requiresAuth: false, isEnabled: true, isConfigured: true, description: 'Swift articles' },
|
|
4
|
+
{ id: 'vanderlee', name: 'Antoine van der Lee', type: 'free', requiresAuth: false, isEnabled: true, isConfigured: true, description: 'iOS tips' },
|
|
5
|
+
{ id: 'nilcoalescing', name: 'Nil Coalescing', type: 'free', requiresAuth: false, isEnabled: true, isConfigured: true, description: 'SwiftUI tips' },
|
|
6
|
+
{ id: 'pointfree', name: 'Point-Free', type: 'free', requiresAuth: false, isEnabled: true, isConfigured: true, description: 'Open source patterns' },
|
|
7
|
+
{ id: 'patreon', name: 'Patreon', type: 'premium', requiresAuth: true, isEnabled: false, isConfigured: false, description: 'Premium content' },
|
|
8
|
+
];
|
|
9
|
+
export function createMockSourceManager() {
|
|
10
|
+
const sources = DEFAULT_SOURCES.map((source) => ({ ...source }));
|
|
11
|
+
return {
|
|
12
|
+
getAllSources: vi.fn().mockReturnValue(sources),
|
|
13
|
+
getSource: vi.fn((id) => sources.find((source) => source.id === id)),
|
|
14
|
+
isSourceConfigured: vi.fn((id) => {
|
|
15
|
+
const source = sources.find((item) => item.id === id);
|
|
16
|
+
return source?.isConfigured ?? false;
|
|
17
|
+
}),
|
|
18
|
+
getSemanticRecallConfig: vi.fn().mockReturnValue({
|
|
19
|
+
enabled: false,
|
|
20
|
+
minLexicalScore: 0.35,
|
|
21
|
+
minRelevanceScore: 70,
|
|
22
|
+
}),
|
|
23
|
+
getMemvidConfig: vi.fn().mockReturnValue({
|
|
24
|
+
enabled: false,
|
|
25
|
+
autoStore: false,
|
|
26
|
+
useEmbeddings: false,
|
|
27
|
+
embeddingModel: 'bge-small',
|
|
28
|
+
}),
|
|
29
|
+
enableSource: vi.fn(),
|
|
30
|
+
disableSource: vi.fn(),
|
|
31
|
+
getEnabledSources: vi.fn().mockReturnValue(sources.filter((source) => source.isEnabled)),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function createToolContext(overrides = {}) {
|
|
35
|
+
return {
|
|
36
|
+
sourceManager: createMockSourceManager(),
|
|
37
|
+
patreonSource: null,
|
|
38
|
+
...overrides,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=tool-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-context.js","sourceRoot":"","sources":["../../../src/__tests__/fixtures/tool-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAG5B,MAAM,eAAe,GAAG;IACtB,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,gBAAgB,EAAE;IAClJ,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE;IACjJ,EAAE,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE;IACpJ,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,sBAAsB,EAAE;IACpJ,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE;CACtI,CAAC;AAEX,MAAM,UAAU,uBAAuB;IACrC,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;IAEjE,OAAO;QACL,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC;QAC/C,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5E,kBAAkB,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAU,EAAE,EAAE;YACvC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,OAAO,MAAM,EAAE,YAAY,IAAI,KAAK,CAAC;QACvC,CAAC,CAAC;QACF,uBAAuB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;YAC/C,OAAO,EAAE,KAAK;YACd,eAAe,EAAE,IAAI;YACrB,iBAAiB,EAAE,EAAE;SACtB,CAAC;QACF,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;YACvC,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,KAAK;YAChB,aAAa,EAAE,KAAK;YACpB,cAAc,EAAE,WAAW;SAC5B,CAAC;QACF,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE;QACrB,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE;QACtB,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;KACzF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,YAAkC,EAAE;IACpE,OAAO;QACL,aAAa,EAAE,uBAAuB,EAA6C;QACnF,aAAa,EAAE,IAAI;QACnB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/server.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
const mockGetToolList = vi.hoisted(() => vi.fn());
|
|
3
|
+
const mockGetHandler = vi.hoisted(() => vi.fn());
|
|
4
|
+
const mockCreateErrorResponseFromError = vi.hoisted(() => vi.fn());
|
|
5
|
+
const mockPrefetchAllSources = vi.hoisted(() => vi.fn());
|
|
6
|
+
const mockPrefetchEmbeddingModel = vi.hoisted(() => vi.fn());
|
|
7
|
+
const mockLoggerInfo = vi.hoisted(() => vi.fn());
|
|
8
|
+
const mockLoggerWarn = vi.hoisted(() => vi.fn());
|
|
9
|
+
const mockLoggerError = vi.hoisted(() => vi.fn());
|
|
10
|
+
const mockConnect = vi.hoisted(() => vi.fn());
|
|
11
|
+
const handlerMap = vi.hoisted(() => new Map());
|
|
12
|
+
const sourceManagerState = vi.hoisted(() => ({
|
|
13
|
+
enabledSources: [{ id: 'sundell' }],
|
|
14
|
+
patreonConfigured: false,
|
|
15
|
+
prefetchEnabled: false,
|
|
16
|
+
semanticEnabled: false,
|
|
17
|
+
}));
|
|
18
|
+
const sourceManagerInstances = vi.hoisted(() => []);
|
|
19
|
+
const listToolsSchema = vi.hoisted(() => Symbol('ListToolsRequestSchema'));
|
|
20
|
+
const callToolSchema = vi.hoisted(() => Symbol('CallToolRequestSchema'));
|
|
21
|
+
const MockServer = vi.hoisted(() => {
|
|
22
|
+
return class {
|
|
23
|
+
setRequestHandler = vi.fn((schema, handler) => {
|
|
24
|
+
handlerMap.set(schema, handler);
|
|
25
|
+
});
|
|
26
|
+
connect = mockConnect;
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
const MockSourceManager = vi.hoisted(() => {
|
|
30
|
+
return class {
|
|
31
|
+
getEnabledSources = vi.fn(() => sourceManagerState.enabledSources);
|
|
32
|
+
isSourceConfigured = vi.fn((id) => (id === 'patreon' ? sourceManagerState.patreonConfigured : true));
|
|
33
|
+
markSourceConfigured = vi.fn();
|
|
34
|
+
isPrefetchEnabled = vi.fn(() => sourceManagerState.prefetchEnabled);
|
|
35
|
+
getSemanticRecallConfig = vi.fn(() => ({ enabled: sourceManagerState.semanticEnabled }));
|
|
36
|
+
constructor() {
|
|
37
|
+
sourceManagerInstances.push(this);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
vi.mock('@modelcontextprotocol/sdk/server/index.js', () => ({
|
|
42
|
+
Server: MockServer,
|
|
43
|
+
}));
|
|
44
|
+
vi.mock('@modelcontextprotocol/sdk/server/stdio.js', () => ({
|
|
45
|
+
StdioServerTransport: class MockStdioServerTransport {
|
|
46
|
+
},
|
|
47
|
+
}));
|
|
48
|
+
vi.mock('@modelcontextprotocol/sdk/types.js', () => ({
|
|
49
|
+
ListToolsRequestSchema: listToolsSchema,
|
|
50
|
+
CallToolRequestSchema: callToolSchema,
|
|
51
|
+
}));
|
|
52
|
+
vi.mock('../config/sources.js', () => ({
|
|
53
|
+
default: MockSourceManager,
|
|
54
|
+
}));
|
|
55
|
+
vi.mock('../tools/index.js', () => ({
|
|
56
|
+
getHandler: mockGetHandler,
|
|
57
|
+
}));
|
|
58
|
+
vi.mock('../tools/registration.js', () => ({
|
|
59
|
+
getToolList: mockGetToolList,
|
|
60
|
+
}));
|
|
61
|
+
vi.mock('../utils/response-helpers.js', () => ({
|
|
62
|
+
createErrorResponseFromError: mockCreateErrorResponseFromError,
|
|
63
|
+
}));
|
|
64
|
+
vi.mock('../utils/source-registry.js', () => ({
|
|
65
|
+
prefetchAllSources: mockPrefetchAllSources,
|
|
66
|
+
}));
|
|
67
|
+
vi.mock('../utils/semantic-recall.js', () => ({
|
|
68
|
+
prefetchEmbeddingModel: mockPrefetchEmbeddingModel,
|
|
69
|
+
}));
|
|
70
|
+
vi.mock('../sources/premium/patreon.js', () => ({
|
|
71
|
+
PatreonSource: class PatreonSource {
|
|
72
|
+
},
|
|
73
|
+
}));
|
|
74
|
+
vi.mock('../utils/logger.js', () => ({
|
|
75
|
+
default: {
|
|
76
|
+
info: mockLoggerInfo,
|
|
77
|
+
warn: mockLoggerWarn,
|
|
78
|
+
error: mockLoggerError,
|
|
79
|
+
},
|
|
80
|
+
}));
|
|
81
|
+
import { startServer } from '../server.js';
|
|
82
|
+
function getLatestSourceManager() {
|
|
83
|
+
const instance = sourceManagerInstances[sourceManagerInstances.length - 1];
|
|
84
|
+
if (!instance)
|
|
85
|
+
throw new Error('Expected SourceManager instance');
|
|
86
|
+
return instance;
|
|
87
|
+
}
|
|
88
|
+
describe('startServer', () => {
|
|
89
|
+
beforeEach(() => {
|
|
90
|
+
vi.clearAllMocks();
|
|
91
|
+
handlerMap.clear();
|
|
92
|
+
sourceManagerInstances.length = 0;
|
|
93
|
+
sourceManagerState.enabledSources = [{ id: 'sundell' }];
|
|
94
|
+
sourceManagerState.patreonConfigured = false;
|
|
95
|
+
sourceManagerState.prefetchEnabled = false;
|
|
96
|
+
sourceManagerState.semanticEnabled = false;
|
|
97
|
+
mockConnect.mockResolvedValue(undefined);
|
|
98
|
+
mockGetToolList.mockReturnValue([{ name: 'get_swift_pattern' }]);
|
|
99
|
+
mockGetHandler.mockReturnValue(undefined);
|
|
100
|
+
mockCreateErrorResponseFromError.mockReturnValue({
|
|
101
|
+
content: [{ type: 'text', text: 'Error: mocked' }],
|
|
102
|
+
isError: true,
|
|
103
|
+
});
|
|
104
|
+
mockPrefetchAllSources.mockResolvedValue([{ status: 'fulfilled', value: [] }]);
|
|
105
|
+
mockPrefetchEmbeddingModel.mockResolvedValue(undefined);
|
|
106
|
+
});
|
|
107
|
+
afterEach(() => {
|
|
108
|
+
vi.restoreAllMocks();
|
|
109
|
+
});
|
|
110
|
+
it('registers ListTools handler and returns tools from getToolList', async () => {
|
|
111
|
+
const tools = [{ name: 'tool-one' }, { name: 'tool-two' }];
|
|
112
|
+
mockGetToolList.mockReturnValue(tools);
|
|
113
|
+
await startServer();
|
|
114
|
+
const sourceManager = getLatestSourceManager();
|
|
115
|
+
const listToolsHandler = handlerMap.get(listToolsSchema);
|
|
116
|
+
expect(listToolsHandler).toBeDefined();
|
|
117
|
+
const response = await listToolsHandler?.();
|
|
118
|
+
expect(response).toEqual({ tools });
|
|
119
|
+
expect(mockGetToolList).toHaveBeenCalledWith(sourceManager, expect.any(Function));
|
|
120
|
+
});
|
|
121
|
+
it('routes CallTool requests to a registered handler', async () => {
|
|
122
|
+
const handlerResponse = { content: [{ type: 'text', text: 'ok' }] };
|
|
123
|
+
const handler = vi.fn().mockResolvedValue(handlerResponse);
|
|
124
|
+
mockGetHandler.mockReturnValue(handler);
|
|
125
|
+
await startServer();
|
|
126
|
+
const callToolHandler = handlerMap.get(callToolSchema);
|
|
127
|
+
const request = { params: { name: 'get_swift_pattern', arguments: { topic: 'swiftui' } } };
|
|
128
|
+
const response = await callToolHandler?.(request);
|
|
129
|
+
expect(handler).toHaveBeenCalledWith({ topic: 'swiftui' }, expect.objectContaining({ sourceManager: expect.any(Object), patreonSource: expect.any(Function) }));
|
|
130
|
+
expect(response).toEqual(handlerResponse);
|
|
131
|
+
});
|
|
132
|
+
it('returns standardized error response for unknown tools', async () => {
|
|
133
|
+
const errorResponse = { content: [{ type: 'text', text: 'Error: Unknown tool' }], isError: true };
|
|
134
|
+
mockCreateErrorResponseFromError.mockReturnValue(errorResponse);
|
|
135
|
+
await startServer();
|
|
136
|
+
const callToolHandler = handlerMap.get(callToolSchema);
|
|
137
|
+
const response = await callToolHandler?.({ params: { name: 'missing_tool', arguments: {} } });
|
|
138
|
+
expect(mockCreateErrorResponseFromError).toHaveBeenCalledWith(expect.any(Error));
|
|
139
|
+
expect(response).toEqual(errorResponse);
|
|
140
|
+
});
|
|
141
|
+
it('auto-enables Patreon when credentials are detected', async () => {
|
|
142
|
+
sourceManagerState.patreonConfigured = true;
|
|
143
|
+
sourceManagerState.enabledSources = [{ id: 'sundell' }];
|
|
144
|
+
await startServer();
|
|
145
|
+
const sourceManager = getLatestSourceManager();
|
|
146
|
+
expect(sourceManager.markSourceConfigured).toHaveBeenCalledWith('patreon');
|
|
147
|
+
expect(mockLoggerInfo).toHaveBeenCalledWith('Patreon auto-enabled (credentials detected)');
|
|
148
|
+
});
|
|
149
|
+
it('runs source and embedding prefetch hooks when enabled', async () => {
|
|
150
|
+
sourceManagerState.prefetchEnabled = true;
|
|
151
|
+
sourceManagerState.semanticEnabled = true;
|
|
152
|
+
await startServer();
|
|
153
|
+
await Promise.resolve();
|
|
154
|
+
expect(mockPrefetchAllSources).toHaveBeenCalledTimes(1);
|
|
155
|
+
expect(mockPrefetchEmbeddingModel).toHaveBeenCalledTimes(1);
|
|
156
|
+
});
|
|
157
|
+
it('logs fatal error and exits when connect fails', async () => {
|
|
158
|
+
mockConnect.mockRejectedValueOnce(new Error('connect failed'));
|
|
159
|
+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code) => {
|
|
160
|
+
throw new Error(`process.exit called with ${code}`);
|
|
161
|
+
}));
|
|
162
|
+
await expect(startServer()).rejects.toThrow('process.exit called with 1');
|
|
163
|
+
expect(mockLoggerError).toHaveBeenCalled();
|
|
164
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
//# sourceMappingURL=server.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.test.js","sourceRoot":"","sources":["../../src/__tests__/server.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.test.d.ts","sourceRoot":"","sources":["../../../src/cli/__tests__/setup.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { buildSnippet, getConfigPath, getServerCommand, parseOptions, shouldRunNonInteractive, } from '../setup-utils.js';
|
|
3
|
+
describe('setup-utils', () => {
|
|
4
|
+
it('returns npx latest command for on-demand install mode', () => {
|
|
5
|
+
expect(getServerCommand('npx')).toEqual({
|
|
6
|
+
command: 'npx',
|
|
7
|
+
args: ['-y', 'swift-patterns-mcp@latest'],
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
it('returns local install command and hint', () => {
|
|
11
|
+
expect(getServerCommand('local')).toEqual({
|
|
12
|
+
command: 'npx',
|
|
13
|
+
args: ['swift-patterns-mcp'],
|
|
14
|
+
installHint: 'npm install -D swift-patterns-mcp',
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
it('returns global install command and hint', () => {
|
|
18
|
+
expect(getServerCommand('global')).toEqual({
|
|
19
|
+
command: 'swift-patterns-mcp',
|
|
20
|
+
args: [],
|
|
21
|
+
installHint: 'npm install -g swift-patterns-mcp',
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it('resolves client config paths for local and global scopes', () => {
|
|
25
|
+
expect(getConfigPath('cursor', 'local')).toBe('.cursor/mcp.json');
|
|
26
|
+
expect(getConfigPath('claude', 'local')).toBe('.mcp.json');
|
|
27
|
+
expect(getConfigPath('windsurf', 'local')).toBe('.windsurf/mcp.json');
|
|
28
|
+
expect(getConfigPath('vscode', 'local')).toBe('.vscode/mcp.json');
|
|
29
|
+
expect(getConfigPath('cursor', 'global')).toBe('~/.cursor/mcp.json');
|
|
30
|
+
expect(getConfigPath('claude', 'global')).toContain('claude mcp add');
|
|
31
|
+
expect(getConfigPath('windsurf', 'global')).toContain('Windsurf');
|
|
32
|
+
expect(getConfigPath('vscode', 'global')).toContain('VS Code');
|
|
33
|
+
});
|
|
34
|
+
it('builds VS Code snippet with mcp.servers shape', () => {
|
|
35
|
+
const snippet = JSON.parse(buildSnippet('vscode', 'npx', ['-y', 'swift-patterns-mcp@latest']));
|
|
36
|
+
expect(snippet).toEqual({
|
|
37
|
+
mcp: {
|
|
38
|
+
servers: {
|
|
39
|
+
'swift-patterns': {
|
|
40
|
+
command: 'npx',
|
|
41
|
+
args: ['-y', 'swift-patterns-mcp@latest'],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
it('builds non-VS Code snippet with mcpServers shape', () => {
|
|
48
|
+
const snippet = JSON.parse(buildSnippet('cursor', 'npx', ['-y', 'swift-patterns-mcp@latest']));
|
|
49
|
+
expect(snippet).toEqual({
|
|
50
|
+
mcpServers: {
|
|
51
|
+
'swift-patterns': {
|
|
52
|
+
command: 'npx',
|
|
53
|
+
args: ['-y', 'swift-patterns-mcp@latest'],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
it('parses --all and scope flags correctly', () => {
|
|
59
|
+
expect(parseOptions(['--all', '--global'])).toEqual({
|
|
60
|
+
clients: ['cursor', 'claude', 'windsurf', 'vscode'],
|
|
61
|
+
scope: 'global',
|
|
62
|
+
});
|
|
63
|
+
expect(parseOptions(['--all', '-l'])).toEqual({
|
|
64
|
+
clients: ['cursor', 'claude', 'windsurf', 'vscode'],
|
|
65
|
+
scope: 'local',
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
it('parses selected client flags without --all', () => {
|
|
69
|
+
expect(parseOptions(['--cursor', '--vscode'])).toEqual({
|
|
70
|
+
clients: ['cursor', 'vscode'],
|
|
71
|
+
scope: undefined,
|
|
72
|
+
});
|
|
73
|
+
expect(parseOptions(['--claude', '--windsurf', '-g'])).toEqual({
|
|
74
|
+
clients: ['claude', 'windsurf'],
|
|
75
|
+
scope: 'global',
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
it('detects non-interactive mode when clients or scope are provided', () => {
|
|
79
|
+
expect(shouldRunNonInteractive({ clients: ['cursor'] })).toBe(true);
|
|
80
|
+
expect(shouldRunNonInteractive({ scope: 'global' })).toBe(true);
|
|
81
|
+
expect(shouldRunNonInteractive({ clients: ['cursor'], scope: 'local' })).toBe(true);
|
|
82
|
+
expect(shouldRunNonInteractive({})).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=setup.test.js.map
|