wogiflow 1.0.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 (221) hide show
  1. package/.workflow/agents/reviewer.md +81 -0
  2. package/.workflow/agents/security.md +94 -0
  3. package/.workflow/agents/story-writer.md +58 -0
  4. package/.workflow/bridges/base-bridge.js +395 -0
  5. package/.workflow/bridges/claude-bridge.js +434 -0
  6. package/.workflow/bridges/index.js +130 -0
  7. package/.workflow/lib/assumption-detector.js +481 -0
  8. package/.workflow/lib/config-substitution.js +371 -0
  9. package/.workflow/lib/failure-categories.js +478 -0
  10. package/.workflow/state/app-map.md.template +15 -0
  11. package/.workflow/state/architecture.md.template +24 -0
  12. package/.workflow/state/component-index.json.template +5 -0
  13. package/.workflow/state/decisions.md.template +15 -0
  14. package/.workflow/state/feedback-patterns.md.template +9 -0
  15. package/.workflow/state/knowledge-sync.json.template +6 -0
  16. package/.workflow/state/progress.md.template +14 -0
  17. package/.workflow/state/ready.json.template +7 -0
  18. package/.workflow/state/request-log.md.template +14 -0
  19. package/.workflow/state/session-state.json.template +11 -0
  20. package/.workflow/state/stack.md.template +33 -0
  21. package/.workflow/state/testing.md.template +36 -0
  22. package/.workflow/templates/claude-md.hbs +257 -0
  23. package/.workflow/templates/correction-report.md +67 -0
  24. package/.workflow/templates/gemini-md.hbs +52 -0
  25. package/README.md +1802 -0
  26. package/bin/flow +205 -0
  27. package/lib/index.js +33 -0
  28. package/lib/installer.js +467 -0
  29. package/lib/release-channel.js +269 -0
  30. package/lib/skill-registry.js +526 -0
  31. package/lib/upgrader.js +401 -0
  32. package/lib/utils.js +305 -0
  33. package/package.json +64 -0
  34. package/scripts/flow +985 -0
  35. package/scripts/flow-adaptive-learning.js +1259 -0
  36. package/scripts/flow-aggregate.js +488 -0
  37. package/scripts/flow-archive +133 -0
  38. package/scripts/flow-auto-context.js +1015 -0
  39. package/scripts/flow-auto-learn.js +615 -0
  40. package/scripts/flow-bridge.js +223 -0
  41. package/scripts/flow-browser-suggest.js +316 -0
  42. package/scripts/flow-bug.js +247 -0
  43. package/scripts/flow-cascade.js +711 -0
  44. package/scripts/flow-changelog +85 -0
  45. package/scripts/flow-checkpoint.js +483 -0
  46. package/scripts/flow-cli.js +403 -0
  47. package/scripts/flow-code-intelligence.js +760 -0
  48. package/scripts/flow-complexity.js +502 -0
  49. package/scripts/flow-config-set.js +152 -0
  50. package/scripts/flow-constants.js +157 -0
  51. package/scripts/flow-context +152 -0
  52. package/scripts/flow-context-init.js +482 -0
  53. package/scripts/flow-context-monitor.js +384 -0
  54. package/scripts/flow-context-scoring.js +886 -0
  55. package/scripts/flow-correct.js +458 -0
  56. package/scripts/flow-damage-control.js +985 -0
  57. package/scripts/flow-deps +101 -0
  58. package/scripts/flow-diff.js +700 -0
  59. package/scripts/flow-done +151 -0
  60. package/scripts/flow-done.js +489 -0
  61. package/scripts/flow-durable-session.js +1541 -0
  62. package/scripts/flow-entropy-monitor.js +345 -0
  63. package/scripts/flow-export-profile +349 -0
  64. package/scripts/flow-export-scanner.js +1046 -0
  65. package/scripts/flow-figma-confirm.js +400 -0
  66. package/scripts/flow-figma-extract.js +496 -0
  67. package/scripts/flow-figma-generate.js +683 -0
  68. package/scripts/flow-figma-index.js +909 -0
  69. package/scripts/flow-figma-match.js +617 -0
  70. package/scripts/flow-figma-mcp-server.js +518 -0
  71. package/scripts/flow-figma-pipeline.js +414 -0
  72. package/scripts/flow-file-ops.js +301 -0
  73. package/scripts/flow-gate-confidence.js +825 -0
  74. package/scripts/flow-guided-edit.js +659 -0
  75. package/scripts/flow-health +185 -0
  76. package/scripts/flow-health.js +413 -0
  77. package/scripts/flow-hooks.js +556 -0
  78. package/scripts/flow-http-client.js +249 -0
  79. package/scripts/flow-hybrid-detect.js +167 -0
  80. package/scripts/flow-hybrid-interactive.js +591 -0
  81. package/scripts/flow-hybrid-test.js +152 -0
  82. package/scripts/flow-import-profile +439 -0
  83. package/scripts/flow-init +253 -0
  84. package/scripts/flow-instruction-richness.js +827 -0
  85. package/scripts/flow-jira-integration.js +579 -0
  86. package/scripts/flow-knowledge-router.js +522 -0
  87. package/scripts/flow-knowledge-sync.js +589 -0
  88. package/scripts/flow-linear-integration.js +631 -0
  89. package/scripts/flow-links.js +774 -0
  90. package/scripts/flow-log-manager.js +559 -0
  91. package/scripts/flow-loop-enforcer.js +1246 -0
  92. package/scripts/flow-loop-retry-learning.js +630 -0
  93. package/scripts/flow-lsp.js +923 -0
  94. package/scripts/flow-map-index +348 -0
  95. package/scripts/flow-map-sync +201 -0
  96. package/scripts/flow-memory-blocks.js +668 -0
  97. package/scripts/flow-memory-compactor.js +350 -0
  98. package/scripts/flow-memory-db.js +1110 -0
  99. package/scripts/flow-memory-sync.js +484 -0
  100. package/scripts/flow-metrics.js +353 -0
  101. package/scripts/flow-migrate-ids.js +370 -0
  102. package/scripts/flow-model-adapter.js +802 -0
  103. package/scripts/flow-model-router.js +884 -0
  104. package/scripts/flow-models.js +1231 -0
  105. package/scripts/flow-morning.js +517 -0
  106. package/scripts/flow-multi-approach.js +660 -0
  107. package/scripts/flow-new-feature +86 -0
  108. package/scripts/flow-onboard +1042 -0
  109. package/scripts/flow-orchestrate-llm.js +459 -0
  110. package/scripts/flow-orchestrate.js +3592 -0
  111. package/scripts/flow-output.js +123 -0
  112. package/scripts/flow-parallel-detector.js +399 -0
  113. package/scripts/flow-parallel-dispatch.js +987 -0
  114. package/scripts/flow-parallel.js +428 -0
  115. package/scripts/flow-pattern-enforcer.js +600 -0
  116. package/scripts/flow-prd-manager.js +282 -0
  117. package/scripts/flow-progress.js +323 -0
  118. package/scripts/flow-project-analyzer.js +975 -0
  119. package/scripts/flow-prompt-composer.js +487 -0
  120. package/scripts/flow-providers.js +1381 -0
  121. package/scripts/flow-queue.js +308 -0
  122. package/scripts/flow-ready +82 -0
  123. package/scripts/flow-ready.js +189 -0
  124. package/scripts/flow-regression.js +396 -0
  125. package/scripts/flow-response-parser.js +450 -0
  126. package/scripts/flow-resume.js +284 -0
  127. package/scripts/flow-rules-sync.js +439 -0
  128. package/scripts/flow-run-trace.js +718 -0
  129. package/scripts/flow-safety.js +587 -0
  130. package/scripts/flow-search +104 -0
  131. package/scripts/flow-security.js +481 -0
  132. package/scripts/flow-session-end +106 -0
  133. package/scripts/flow-session-end.js +437 -0
  134. package/scripts/flow-session-state.js +671 -0
  135. package/scripts/flow-setup-hooks +216 -0
  136. package/scripts/flow-setup-hooks.js +377 -0
  137. package/scripts/flow-skill-create.js +329 -0
  138. package/scripts/flow-skill-creator.js +572 -0
  139. package/scripts/flow-skill-generator.js +1046 -0
  140. package/scripts/flow-skill-learn.js +880 -0
  141. package/scripts/flow-skill-matcher.js +578 -0
  142. package/scripts/flow-spec-generator.js +820 -0
  143. package/scripts/flow-stack-wizard.js +895 -0
  144. package/scripts/flow-standup +162 -0
  145. package/scripts/flow-start +74 -0
  146. package/scripts/flow-start.js +235 -0
  147. package/scripts/flow-status +110 -0
  148. package/scripts/flow-status.js +301 -0
  149. package/scripts/flow-step-browser.js +83 -0
  150. package/scripts/flow-step-changelog.js +217 -0
  151. package/scripts/flow-step-comments.js +306 -0
  152. package/scripts/flow-step-complexity.js +234 -0
  153. package/scripts/flow-step-coverage.js +218 -0
  154. package/scripts/flow-step-knowledge.js +193 -0
  155. package/scripts/flow-step-pr-tests.js +364 -0
  156. package/scripts/flow-step-regression.js +89 -0
  157. package/scripts/flow-step-review.js +516 -0
  158. package/scripts/flow-step-security.js +162 -0
  159. package/scripts/flow-step-silent-failures.js +290 -0
  160. package/scripts/flow-step-simplifier.js +346 -0
  161. package/scripts/flow-story +105 -0
  162. package/scripts/flow-story.js +500 -0
  163. package/scripts/flow-suspend.js +252 -0
  164. package/scripts/flow-sync-daemon.js +654 -0
  165. package/scripts/flow-task-analyzer.js +606 -0
  166. package/scripts/flow-team-dashboard.js +748 -0
  167. package/scripts/flow-team-sync.js +752 -0
  168. package/scripts/flow-team.js +977 -0
  169. package/scripts/flow-tech-options.js +528 -0
  170. package/scripts/flow-templates.js +812 -0
  171. package/scripts/flow-tiered-learning.js +728 -0
  172. package/scripts/flow-trace +204 -0
  173. package/scripts/flow-transcript-chunking.js +1106 -0
  174. package/scripts/flow-transcript-digest.js +7918 -0
  175. package/scripts/flow-transcript-language.js +465 -0
  176. package/scripts/flow-transcript-parsing.js +1085 -0
  177. package/scripts/flow-transcript-stories.js +2194 -0
  178. package/scripts/flow-update-map +224 -0
  179. package/scripts/flow-utils.js +2242 -0
  180. package/scripts/flow-verification.js +644 -0
  181. package/scripts/flow-verify.js +1177 -0
  182. package/scripts/flow-voice-input.js +638 -0
  183. package/scripts/flow-watch +168 -0
  184. package/scripts/flow-workflow-steps.js +521 -0
  185. package/scripts/flow-workflow.js +1029 -0
  186. package/scripts/flow-worktree.js +489 -0
  187. package/scripts/hooks/adapters/base-adapter.js +102 -0
  188. package/scripts/hooks/adapters/claude-code.js +359 -0
  189. package/scripts/hooks/adapters/index.js +79 -0
  190. package/scripts/hooks/core/component-check.js +341 -0
  191. package/scripts/hooks/core/index.js +35 -0
  192. package/scripts/hooks/core/loop-check.js +241 -0
  193. package/scripts/hooks/core/session-context.js +294 -0
  194. package/scripts/hooks/core/task-gate.js +177 -0
  195. package/scripts/hooks/core/validation.js +230 -0
  196. package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
  197. package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
  198. package/scripts/hooks/entry/claude-code/session-end.js +87 -0
  199. package/scripts/hooks/entry/claude-code/session-start.js +46 -0
  200. package/scripts/hooks/entry/claude-code/stop.js +43 -0
  201. package/scripts/postinstall.js +139 -0
  202. package/templates/browser-test-flow.json +56 -0
  203. package/templates/bug-report.md +43 -0
  204. package/templates/component-detail.md +42 -0
  205. package/templates/component.stories.tsx +49 -0
  206. package/templates/context/constraints.md +83 -0
  207. package/templates/context/conventions.md +177 -0
  208. package/templates/context/stack.md +60 -0
  209. package/templates/correction-report.md +90 -0
  210. package/templates/feature-proposal.md +35 -0
  211. package/templates/hybrid/_base.md +254 -0
  212. package/templates/hybrid/_patterns.md +45 -0
  213. package/templates/hybrid/create-component.md +127 -0
  214. package/templates/hybrid/create-file.md +56 -0
  215. package/templates/hybrid/create-hook.md +145 -0
  216. package/templates/hybrid/create-service.md +70 -0
  217. package/templates/hybrid/fix-bug.md +33 -0
  218. package/templates/hybrid/modify-file.md +55 -0
  219. package/templates/story.md +68 -0
  220. package/templates/task.json +56 -0
  221. package/templates/trace.md +69 -0
@@ -0,0 +1,518 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Figma Analyzer MCP Server
5
+ *
6
+ * Standalone MCP server that provides component analysis tools.
7
+ * Can be used with any MCP client (Claude Desktop, Cursor, VS Code, etc.)
8
+ *
9
+ * Supports both:
10
+ * - stdio mode (standard MCP protocol for Claude Desktop)
11
+ * - HTTP mode (for testing and web clients)
12
+ *
13
+ * Tools provided:
14
+ * - wogi_figma_analyze: Analyze a Figma screen and match components
15
+ * - wogi_figma_registry: Get the codebase component registry
16
+ * - wogi_figma_match: Match a single component against registry
17
+ * - wogi_figma_generate: Generate code from confirmed decisions
18
+ *
19
+ * Usage:
20
+ * node flow-figma-mcp-server.js # stdio mode (for MCP clients)
21
+ * node flow-figma-mcp-server.js --http # HTTP mode (port 3847)
22
+ * node flow-figma-mcp-server.js --http 8080 # HTTP on custom port
23
+ */
24
+
25
+ const http = require('http');
26
+ const fs = require('fs');
27
+ const path = require('path');
28
+ const readline = require('readline');
29
+
30
+ const { ComponentScanner } = require('./flow-figma-index');
31
+ const { FigmaExtractor } = require('./flow-figma-extract');
32
+ const { SimilarityMatcher, MATCH_CONFIG } = require('./flow-figma-match');
33
+ const { CodeGenerator } = require('./flow-figma-generate');
34
+ const { getProjectRoot } = require('./flow-utils');
35
+
36
+ const PROJECT_ROOT = getProjectRoot();
37
+ const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
38
+ const REGISTRY_PATH = path.join(WORKFLOW_DIR, 'state', 'component-registry.json');
39
+
40
+ // ============================================================
41
+ // Tool Definitions
42
+ // ============================================================
43
+
44
+ const TOOLS = [
45
+ {
46
+ name: 'wogi_figma_analyze',
47
+ description: 'Analyze a Figma screen/component and match against your codebase. Returns components with match suggestions (use existing, add variant, or create new).',
48
+ inputSchema: {
49
+ type: 'object',
50
+ properties: {
51
+ figma_data: {
52
+ type: 'object',
53
+ description: 'The Figma MCP response data (from get_code, get_metadata, or node data)'
54
+ },
55
+ threshold: {
56
+ type: 'number',
57
+ description: 'Minimum match score (0-100) to consider as a match. Default: 60',
58
+ default: 60
59
+ }
60
+ },
61
+ required: ['figma_data']
62
+ }
63
+ },
64
+ {
65
+ name: 'wogi_figma_registry',
66
+ description: 'Get or scan the component registry from the codebase. Shows all existing components that can be reused.',
67
+ inputSchema: {
68
+ type: 'object',
69
+ properties: {
70
+ scan: {
71
+ type: 'boolean',
72
+ description: 'If true, rescan the codebase before returning registry. Default: false',
73
+ default: false
74
+ },
75
+ filter: {
76
+ type: 'string',
77
+ description: 'Filter components by type: "atom", "molecule", or "organism"'
78
+ }
79
+ }
80
+ }
81
+ },
82
+ {
83
+ name: 'wogi_figma_match',
84
+ description: 'Match a single extracted Figma component against the registry.',
85
+ inputSchema: {
86
+ type: 'object',
87
+ properties: {
88
+ component: {
89
+ type: 'object',
90
+ description: 'The extracted Figma component (from wogi_figma_analyze)'
91
+ }
92
+ },
93
+ required: ['component']
94
+ }
95
+ },
96
+ {
97
+ name: 'wogi_figma_generate',
98
+ description: 'Generate code prompts and imports from confirmed component decisions.',
99
+ inputSchema: {
100
+ type: 'object',
101
+ properties: {
102
+ decisions: {
103
+ type: 'array',
104
+ description: 'Array of component decisions with action (use, add-variant, create-new) and details'
105
+ }
106
+ },
107
+ required: ['decisions']
108
+ }
109
+ }
110
+ ];
111
+
112
+ // ============================================================
113
+ // MCP Handler
114
+ // ============================================================
115
+
116
+ class FigmaAnalyzerMCP {
117
+ constructor() {
118
+ this.tools = TOOLS;
119
+ }
120
+
121
+ async handleToolCall(toolName, args) {
122
+ switch (toolName) {
123
+ case 'wogi_figma_analyze':
124
+ return this.analyzeScreen(args.figma_data, args.threshold || 60);
125
+
126
+ case 'wogi_figma_registry':
127
+ return this.getRegistry(args.scan, args.filter);
128
+
129
+ case 'wogi_figma_match':
130
+ return this.matchComponent(args.component);
131
+
132
+ case 'wogi_figma_generate':
133
+ return this.generateCode(args.decisions);
134
+
135
+ default:
136
+ throw new Error(`Unknown tool: ${toolName}`);
137
+ }
138
+ }
139
+
140
+ async analyzeScreen(figmaData, threshold) {
141
+ // Extract components from Figma data
142
+ const extractor = new FigmaExtractor();
143
+ const extracted = extractor.parse(figmaData);
144
+
145
+ // Load registry
146
+ const registry = this.loadRegistry();
147
+ if (!registry) {
148
+ return {
149
+ error: 'Component registry not found. Call wogi_figma_registry with scan=true first.',
150
+ suggestion: 'Run: wogi_figma_registry({ scan: true })'
151
+ };
152
+ }
153
+
154
+ // Match components
155
+ const matcher = new SimilarityMatcher(registry);
156
+ const results = matcher.matchAll(extracted.components);
157
+
158
+ // Format for readable output
159
+ return {
160
+ summary: results.summary,
161
+ thresholds: MATCH_CONFIG.thresholds,
162
+ components: results.matches.map(m => ({
163
+ name: m.figmaComponent.name,
164
+ type: m.figmaComponent.type,
165
+ figmaType: m.figmaComponent.figmaType,
166
+ bestMatch: m.bestMatch ? {
167
+ name: m.bestMatch.registryComponent.name,
168
+ path: m.bestMatch.registryComponent.path,
169
+ score: m.bestMatch.score,
170
+ breakdown: m.bestMatch.breakdown,
171
+ differences: m.bestMatch.differences?.slice(0, 3) // Limit differences
172
+ } : null,
173
+ recommendation: m.suggestion
174
+ })),
175
+ tokens: extracted.tokens
176
+ };
177
+ }
178
+
179
+ async getRegistry(scan = false, filter = null) {
180
+ if (scan) {
181
+ const scanner = new ComponentScanner();
182
+ await scanner.scan();
183
+ }
184
+
185
+ const registry = this.loadRegistry();
186
+ if (!registry) {
187
+ return {
188
+ error: 'Registry not found. Set scan=true to scan the codebase.',
189
+ suggestion: 'Run: wogi_figma_registry({ scan: true })'
190
+ };
191
+ }
192
+
193
+ let components = registry.components;
194
+
195
+ // Apply filter if specified
196
+ if (filter && ['atom', 'molecule', 'organism'].includes(filter)) {
197
+ components = components.filter(c => c.type === filter);
198
+ }
199
+
200
+ return {
201
+ framework: registry.framework,
202
+ scannedAt: registry.scannedAt,
203
+ componentCount: components.length,
204
+ components: components.map(c => ({
205
+ name: c.name,
206
+ path: c.path,
207
+ type: c.type,
208
+ variants: c.variants,
209
+ props: c.props?.map(p => ({ name: p.name, type: p.type }))
210
+ })),
211
+ tokenCount: {
212
+ colors: Object.keys(registry.tokens?.colors || {}).length,
213
+ spacing: Object.keys(registry.tokens?.spacing || {}).length,
214
+ typography: Object.keys(registry.tokens?.typography || {}).length
215
+ }
216
+ };
217
+ }
218
+
219
+ async matchComponent(component) {
220
+ const registry = this.loadRegistry();
221
+ if (!registry) {
222
+ return { error: 'Registry not found' };
223
+ }
224
+
225
+ const matcher = new SimilarityMatcher(registry);
226
+ const result = matcher.matchComponent(component);
227
+
228
+ return {
229
+ figmaComponent: result.figmaComponent,
230
+ matches: result.matches.slice(0, 3).map(m => ({
231
+ name: m.registryComponent.name,
232
+ path: m.registryComponent.path,
233
+ score: m.score,
234
+ suggestion: m.suggestion
235
+ })),
236
+ recommendation: result.suggestion
237
+ };
238
+ }
239
+
240
+ async generateCode(decisions) {
241
+ const generator = new CodeGenerator({ decisions });
242
+ const output = generator.generate();
243
+
244
+ return {
245
+ framework: output.framework,
246
+ imports: output.imports.map(i => ({
247
+ component: i.componentName,
248
+ import: i.importStatement,
249
+ usage: i.usage
250
+ })),
251
+ newComponents: output.newComponents.map(c => ({
252
+ name: c.componentName,
253
+ path: c.suggestedPath,
254
+ prompt: c.prompt
255
+ })),
256
+ variants: output.variants.map(v => ({
257
+ component: v.componentName,
258
+ variant: v.variantName,
259
+ prompt: v.prompt
260
+ }))
261
+ };
262
+ }
263
+
264
+ loadRegistry() {
265
+ if (fs.existsSync(REGISTRY_PATH)) {
266
+ try {
267
+ return JSON.parse(fs.readFileSync(REGISTRY_PATH, 'utf-8'));
268
+ } catch {
269
+ return null;
270
+ }
271
+ }
272
+ return null;
273
+ }
274
+ }
275
+
276
+ // ============================================================
277
+ // stdio Mode (Standard MCP Protocol)
278
+ // ============================================================
279
+
280
+ class StdioServer {
281
+ constructor(handler) {
282
+ this.handler = handler;
283
+ this.rl = readline.createInterface({
284
+ input: process.stdin,
285
+ output: process.stdout,
286
+ terminal: false
287
+ });
288
+ }
289
+
290
+ start() {
291
+ this.rl.on('line', async (line) => {
292
+ if (!line.trim()) return;
293
+
294
+ try {
295
+ const request = JSON.parse(line);
296
+ const response = await this.handleRequest(request);
297
+ console.log(JSON.stringify(response));
298
+ } catch (err) {
299
+ console.log(JSON.stringify({
300
+ jsonrpc: '2.0',
301
+ error: { code: -32700, message: 'Parse error', data: err.message },
302
+ id: null
303
+ }));
304
+ }
305
+ });
306
+
307
+ // Send capabilities on start
308
+ console.error('Wogi Flow Figma Analyzer MCP Server (stdio mode)');
309
+ }
310
+
311
+ async handleRequest(request) {
312
+ const { method, params, id } = request;
313
+
314
+ try {
315
+ let result;
316
+
317
+ switch (method) {
318
+ case 'initialize':
319
+ result = {
320
+ protocolVersion: '2024-11-05',
321
+ capabilities: {
322
+ tools: {}
323
+ },
324
+ serverInfo: {
325
+ name: 'wogi-figma-analyzer',
326
+ version: '1.0.0'
327
+ }
328
+ };
329
+ break;
330
+
331
+ case 'tools/list':
332
+ result = { tools: this.handler.tools };
333
+ break;
334
+
335
+ case 'tools/call':
336
+ const toolResult = await this.handler.handleToolCall(
337
+ params.name,
338
+ params.arguments || {}
339
+ );
340
+ result = {
341
+ content: [{
342
+ type: 'text',
343
+ text: JSON.stringify(toolResult, null, 2)
344
+ }]
345
+ };
346
+ break;
347
+
348
+ case 'ping':
349
+ result = {};
350
+ break;
351
+
352
+ default:
353
+ throw new Error(`Unknown method: ${method}`);
354
+ }
355
+
356
+ return { jsonrpc: '2.0', result, id };
357
+
358
+ } catch (err) {
359
+ return {
360
+ jsonrpc: '2.0',
361
+ error: { code: -32603, message: err.message },
362
+ id
363
+ };
364
+ }
365
+ }
366
+ }
367
+
368
+ // ============================================================
369
+ // HTTP Mode (for testing)
370
+ // ============================================================
371
+
372
+ class HttpServer {
373
+ constructor(handler, port = 3847) {
374
+ this.handler = handler;
375
+ this.port = port;
376
+ }
377
+
378
+ start() {
379
+ const server = http.createServer(async (req, res) => {
380
+ // CORS headers
381
+ res.setHeader('Access-Control-Allow-Origin', '*');
382
+ res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
383
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
384
+
385
+ if (req.method === 'OPTIONS') {
386
+ res.writeHead(200);
387
+ res.end();
388
+ return;
389
+ }
390
+
391
+ // Health check
392
+ if (req.method === 'GET' && req.url === '/health') {
393
+ res.writeHead(200, { 'Content-Type': 'application/json' });
394
+ res.end(JSON.stringify({ status: 'ok', tools: this.handler.tools.length }));
395
+ return;
396
+ }
397
+
398
+ if (req.method !== 'POST') {
399
+ res.writeHead(405);
400
+ res.end('Method not allowed');
401
+ return;
402
+ }
403
+
404
+ let body = '';
405
+ req.on('data', chunk => body += chunk);
406
+ req.on('end', async () => {
407
+ try {
408
+ const request = JSON.parse(body);
409
+ let response;
410
+
411
+ if (request.method === 'tools/list') {
412
+ response = { tools: this.handler.tools };
413
+ } else if (request.method === 'tools/call') {
414
+ const result = await this.handler.handleToolCall(
415
+ request.params.name,
416
+ request.params.arguments || {}
417
+ );
418
+ response = {
419
+ content: [{
420
+ type: 'text',
421
+ text: JSON.stringify(result, null, 2)
422
+ }]
423
+ };
424
+ } else {
425
+ response = { error: 'Unknown method' };
426
+ }
427
+
428
+ res.writeHead(200, { 'Content-Type': 'application/json' });
429
+ res.end(JSON.stringify(response));
430
+
431
+ } catch (err) {
432
+ res.writeHead(500, { 'Content-Type': 'application/json' });
433
+ res.end(JSON.stringify({ error: err.message }));
434
+ }
435
+ });
436
+ });
437
+
438
+ server.listen(this.port, () => {
439
+ console.log(`
440
+ ╔═══════════════════════════════════════════════════════════════════╗
441
+ ║ Wogi Flow - Figma Analyzer MCP Server (HTTP) ║
442
+ ╚═══════════════════════════════════════════════════════════════════╝
443
+
444
+ Server running at http://localhost:${this.port}
445
+
446
+ Endpoints:
447
+ POST / MCP protocol
448
+ GET /health Health check
449
+
450
+ Available tools:
451
+ • wogi_figma_analyze - Analyze Figma screen
452
+ • wogi_figma_registry - Get component registry
453
+ • wogi_figma_match - Match single component
454
+ • wogi_figma_generate - Generate code from decisions
455
+
456
+ Test with:
457
+ curl -X POST http://localhost:${this.port} \\
458
+ -H "Content-Type: application/json" \\
459
+ -d '{"method":"tools/list"}'
460
+ `);
461
+ });
462
+ }
463
+ }
464
+
465
+ // ============================================================
466
+ // CLI
467
+ // ============================================================
468
+
469
+ function main() {
470
+ const args = process.argv.slice(2);
471
+ const handler = new FigmaAnalyzerMCP();
472
+
473
+ if (args.includes('--http')) {
474
+ const portIndex = args.indexOf('--http') + 1;
475
+ const port = parseInt(args[portIndex]) || 3847;
476
+ const server = new HttpServer(handler, port);
477
+ server.start();
478
+ } else if (args.includes('--help') || args.includes('-h')) {
479
+ console.log(`
480
+ Wogi Flow - Figma Analyzer MCP Server
481
+
482
+ Usage:
483
+ node flow-figma-mcp-server.js # stdio mode (for MCP clients)
484
+ node flow-figma-mcp-server.js --http # HTTP mode (port 3847)
485
+ node flow-figma-mcp-server.js --http 8080 # HTTP on custom port
486
+
487
+ Add to Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json):
488
+ {
489
+ "mcpServers": {
490
+ "wogi-figma": {
491
+ "command": "node",
492
+ "args": ["${path.resolve(__dirname, 'flow-figma-mcp-server.js')}"]
493
+ }
494
+ }
495
+ }
496
+
497
+ Add to Cursor MCP config:
498
+ {
499
+ "mcpServers": {
500
+ "wogi-figma": {
501
+ "command": "node",
502
+ "args": ["${path.resolve(__dirname, 'flow-figma-mcp-server.js')}"]
503
+ }
504
+ }
505
+ }
506
+ `);
507
+ } else {
508
+ // Default: stdio mode
509
+ const server = new StdioServer(handler);
510
+ server.start();
511
+ }
512
+ }
513
+
514
+ module.exports = { FigmaAnalyzerMCP, StdioServer, HttpServer };
515
+
516
+ if (require.main === module) {
517
+ main();
518
+ }