@jtalk22/slack-mcp 3.0.0 → 3.2.0

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 (59) hide show
  1. package/README.md +63 -28
  2. package/docs/SETUP.md +64 -29
  3. package/docs/TROUBLESHOOTING.md +28 -0
  4. package/lib/handlers.js +156 -0
  5. package/lib/slack-client.js +11 -3
  6. package/lib/token-store.js +6 -5
  7. package/lib/tools.js +131 -0
  8. package/package.json +35 -36
  9. package/public/index.html +10 -6
  10. package/public/share.html +128 -0
  11. package/scripts/setup-wizard.js +1 -1
  12. package/server.json +10 -4
  13. package/src/server-http.js +16 -1
  14. package/src/server.js +31 -7
  15. package/src/web-server.js +119 -4
  16. package/docs/CLOUDFLARE-BROWSER-TOOLKIT.md +0 -67
  17. package/docs/COMMUNICATION-STYLE.md +0 -66
  18. package/docs/COMPATIBILITY.md +0 -19
  19. package/docs/DEPLOYMENT-MODES.md +0 -55
  20. package/docs/HN-LAUNCH.md +0 -72
  21. package/docs/INDEX.md +0 -40
  22. package/docs/INSTALL-PROOF.md +0 -18
  23. package/docs/LAUNCH-COPY-v3.0.0.md +0 -73
  24. package/docs/LAUNCH-MATRIX.md +0 -22
  25. package/docs/LAUNCH-OPS.md +0 -71
  26. package/docs/RELEASE-HEALTH.md +0 -90
  27. package/docs/SUPPORT-BOUNDARIES.md +0 -49
  28. package/docs/USE_CASE_RECIPES.md +0 -69
  29. package/docs/WEB-API.md +0 -303
  30. package/docs/images/demo-channel-messages.png +0 -0
  31. package/docs/images/demo-channels.png +0 -0
  32. package/docs/images/demo-claude-mobile-360x800.png +0 -0
  33. package/docs/images/demo-claude-mobile-390x844.png +0 -0
  34. package/docs/images/demo-main-mobile-360x800.png +0 -0
  35. package/docs/images/demo-main-mobile-390x844.png +0 -0
  36. package/docs/images/demo-main.png +0 -0
  37. package/docs/images/demo-messages.png +0 -0
  38. package/docs/images/demo-poster.png +0 -0
  39. package/docs/images/demo-sidebar.png +0 -0
  40. package/docs/images/diagram-oauth-comparison.svg +0 -80
  41. package/docs/images/diagram-session-flow.svg +0 -105
  42. package/docs/images/web-api-mobile-360x800.png +0 -0
  43. package/docs/images/web-api-mobile-390x844.png +0 -0
  44. package/public/demo-claude.html +0 -1958
  45. package/public/demo-video.html +0 -235
  46. package/public/demo.html +0 -1196
  47. package/scripts/build-release-health-delta.js +0 -201
  48. package/scripts/capture-screenshots.js +0 -146
  49. package/scripts/check-owner-attribution.sh +0 -80
  50. package/scripts/check-public-language.sh +0 -25
  51. package/scripts/check-version-parity.js +0 -176
  52. package/scripts/cloudflare-browser-tool.js +0 -237
  53. package/scripts/collect-release-health.js +0 -150
  54. package/scripts/record-demo.js +0 -162
  55. package/scripts/release-preflight.js +0 -243
  56. package/scripts/setup-git-hooks.sh +0 -15
  57. package/scripts/verify-core.js +0 -159
  58. package/scripts/verify-install-flow.js +0 -193
  59. package/scripts/verify-web.js +0 -269
@@ -1,269 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Web UI Verification Script
4
- *
5
- * Tests:
6
- * 1. Server starts and prints Magic Link
7
- * 2. /demo.html contains "STATIC PREVIEW" banner
8
- * 3. /?key=... serves the dashboard (index.html)
9
- * 4. /demo-video.html media assets are reachable
10
- * 5. Server shuts down cleanly
11
- */
12
-
13
- import { spawn } from "child_process";
14
- import { dirname, join } from "path";
15
- import { fileURLToPath } from "url";
16
-
17
- const __dirname = dirname(fileURLToPath(import.meta.url));
18
- const SERVER_PATH = join(__dirname, "../src/web-server.js");
19
- const PORT = 3456; // Use non-standard port to avoid conflicts
20
- const TIMEOUT = 15000;
21
-
22
- let serverProc = null;
23
-
24
- function log(msg) {
25
- console.log(` ${msg}`);
26
- }
27
-
28
- function cleanup() {
29
- if (serverProc) {
30
- serverProc.kill("SIGTERM");
31
- serverProc = null;
32
- }
33
- }
34
-
35
- process.on("exit", cleanup);
36
- process.on("SIGINT", () => { cleanup(); process.exit(1); });
37
- process.on("SIGTERM", () => { cleanup(); process.exit(1); });
38
-
39
- async function startServer() {
40
- return new Promise((resolve, reject) => {
41
- let magicLink = null;
42
- let apiKey = null;
43
- let output = "";
44
-
45
- serverProc = spawn("node", [SERVER_PATH], {
46
- env: { ...process.env, PORT: String(PORT) },
47
- stdio: ["pipe", "pipe", "pipe"]
48
- });
49
-
50
- const timeout = setTimeout(() => {
51
- reject(new Error("Server startup timeout - no magic link detected"));
52
- }, TIMEOUT);
53
-
54
- serverProc.stderr.on("data", (data) => {
55
- const text = data.toString();
56
- output += text;
57
-
58
- // Look for magic link pattern
59
- const match = text.match(/Dashboard:\s*(http:\/\/[^\s]+)/);
60
- if (match) {
61
- magicLink = match[1];
62
- // Extract key from URL
63
- const keyMatch = magicLink.match(/[?&]key=([^&\s]+)/);
64
- if (keyMatch) {
65
- apiKey = keyMatch[1];
66
- }
67
- }
68
-
69
- // Server is ready when we see the full banner
70
- if (output.includes("Dashboard:") && output.includes("API Key:")) {
71
- clearTimeout(timeout);
72
- resolve({ magicLink, apiKey });
73
- }
74
- });
75
-
76
- serverProc.on("error", (err) => {
77
- clearTimeout(timeout);
78
- reject(err);
79
- });
80
-
81
- serverProc.on("exit", (code) => {
82
- if (code !== null && code !== 0) {
83
- clearTimeout(timeout);
84
- reject(new Error(`Server exited with code ${code}`));
85
- }
86
- });
87
- });
88
- }
89
-
90
- async function testDemoPage() {
91
- const url = `http://localhost:${PORT}/demo.html`;
92
- const res = await fetch(url);
93
-
94
- if (!res.ok) {
95
- throw new Error(`Failed to fetch demo.html: ${res.status}`);
96
- }
97
-
98
- const html = await res.text();
99
-
100
- if (!html.includes("STATIC PREVIEW")) {
101
- throw new Error("demo.html missing 'STATIC PREVIEW' banner");
102
- }
103
-
104
- if (!html.includes("Who is Alex?")) {
105
- throw new Error("demo.html missing anonymized 'Who is Alex?' scenario");
106
- }
107
-
108
- return true;
109
- }
110
-
111
- async function testDashboard(apiKey) {
112
- const url = `http://localhost:${PORT}/?key=${apiKey}`;
113
- const res = await fetch(url);
114
-
115
- if (!res.ok) {
116
- throw new Error(`Failed to fetch dashboard: ${res.status}`);
117
- }
118
-
119
- const html = await res.text();
120
-
121
- // Should serve index.html (the dashboard)
122
- if (!html.includes("Slack Web API")) {
123
- throw new Error("Dashboard page missing 'Slack Web API' title");
124
- }
125
-
126
- if (!html.includes("authModal")) {
127
- throw new Error("Dashboard missing auth modal");
128
- }
129
-
130
- return true;
131
- }
132
-
133
- async function testApiWithKey(apiKey) {
134
- // Test that API rejects bad key
135
- const badRes = await fetch(`http://localhost:${PORT}/health`, {
136
- headers: { "Authorization": "Bearer bad-key" }
137
- });
138
-
139
- if (badRes.status !== 401) {
140
- throw new Error(`Expected 401 for bad key, got ${badRes.status}`);
141
- }
142
-
143
- return true;
144
- }
145
-
146
- async function testDemoVideoAssets() {
147
- const demoVideoUrl = `http://localhost:${PORT}/demo-video.html`;
148
- const demoVideoRes = await fetch(demoVideoUrl);
149
-
150
- if (!demoVideoRes.ok) {
151
- throw new Error(`Failed to fetch demo-video.html: ${demoVideoRes.status}`);
152
- }
153
-
154
- const demoVideoHtml = await demoVideoRes.text();
155
- const requiredAssetCandidates = [
156
- [
157
- "/docs/images/demo-poster.png",
158
- "https://jtalk22.github.io/slack-mcp-server/docs/images/demo-poster.png",
159
- ],
160
- [
161
- "/docs/videos/demo-claude.webm",
162
- "https://jtalk22.github.io/slack-mcp-server/docs/videos/demo-claude.webm",
163
- ],
164
- ];
165
-
166
- for (const candidates of requiredAssetCandidates) {
167
- const matched = candidates.find((candidate) => demoVideoHtml.includes(candidate));
168
- if (!matched) {
169
- throw new Error(`demo-video.html missing expected media reference: ${candidates.join(" OR ")}`);
170
- }
171
-
172
- const assetUrl = matched.startsWith("http")
173
- ? matched
174
- : `http://localhost:${PORT}${matched}`;
175
-
176
- const assetRes = await fetch(assetUrl);
177
- if (!assetRes.ok) {
178
- throw new Error(`Demo media not reachable: ${assetUrl} (status ${assetRes.status})`);
179
- }
180
- }
181
-
182
- return true;
183
- }
184
-
185
- async function main() {
186
- console.log("╔════════════════════════════════════════╗");
187
- console.log("║ Web UI Verification Tests ║");
188
- console.log("╚════════════════════════════════════════╝");
189
-
190
- const results = [];
191
-
192
- try {
193
- // Test 1: Server starts with magic link
194
- console.log("\n[TEST 1] Server Startup & Magic Link");
195
- console.log("─".repeat(40));
196
-
197
- const { magicLink, apiKey } = await startServer();
198
-
199
- if (!magicLink) {
200
- throw new Error("No magic link found");
201
- }
202
- if (!apiKey) {
203
- throw new Error("No API key found in magic link");
204
- }
205
-
206
- log(`Magic Link: ${magicLink}`);
207
- log(`API Key: ${apiKey.substring(0, 20)}...`);
208
- log("PASS: Server started with magic link");
209
- results.push(true);
210
-
211
- // Test 2: Demo page
212
- console.log("\n[TEST 2] Demo Page (/demo.html)");
213
- console.log("─".repeat(40));
214
-
215
- await testDemoPage();
216
- log("PASS: Demo page serves correctly with STATIC PREVIEW banner");
217
- results.push(true);
218
-
219
- // Test 3: Dashboard
220
- console.log("\n[TEST 3] Dashboard (/?key=...)");
221
- console.log("─".repeat(40));
222
-
223
- await testDashboard(apiKey);
224
- log("PASS: Dashboard serves with auth modal");
225
- results.push(true);
226
-
227
- // Test 4: API auth
228
- console.log("\n[TEST 4] API Authentication");
229
- console.log("─".repeat(40));
230
-
231
- await testApiWithKey(apiKey);
232
- log("PASS: API correctly rejects bad keys");
233
- results.push(true);
234
-
235
- // Test 5: Demo video/media paths
236
- console.log("\n[TEST 5] Demo Video Media Reachability");
237
- console.log("─".repeat(40));
238
-
239
- await testDemoVideoAssets();
240
- log("PASS: demo-video media assets are reachable");
241
- results.push(true);
242
-
243
- } catch (err) {
244
- console.log(` FAIL: ${err.message}`);
245
- results.push(false);
246
- } finally {
247
- cleanup();
248
- }
249
-
250
- // Summary
251
- console.log("\n" + "═".repeat(40));
252
- const passed = results.filter(r => r).length;
253
- const total = results.length;
254
-
255
- if (passed === total) {
256
- console.log(`\n✓ ALL TESTS PASSED (${passed}/${total})`);
257
- console.log("\nWeb UI features verified");
258
- process.exit(0);
259
- } else {
260
- console.log(`\n✗ TESTS FAILED (${passed}/${total})`);
261
- process.exit(1);
262
- }
263
- }
264
-
265
- main().catch(e => {
266
- console.error("Test error:", e);
267
- cleanup();
268
- process.exit(1);
269
- });