@fragments-sdk/cli 0.10.1 → 0.12.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 (223) hide show
  1. package/dist/ai-client-I6MDWNYA.js +21 -0
  2. package/dist/bin.js +292 -367
  3. package/dist/bin.js.map +1 -1
  4. package/dist/{chunk-PW7QTQA6.js → chunk-4OC7FTJB.js} +2 -2
  5. package/dist/{chunk-HRFUSSZI.js → chunk-AM4MRTMN.js} +2 -2
  6. package/dist/{chunk-5G3VZH43.js → chunk-GVDSFQ4E.js} +281 -351
  7. package/dist/chunk-GVDSFQ4E.js.map +1 -0
  8. package/dist/chunk-JJ2VRTBU.js +626 -0
  9. package/dist/chunk-JJ2VRTBU.js.map +1 -0
  10. package/dist/{chunk-D5PYOXEI.js → chunk-LVWFOLUZ.js} +148 -13
  11. package/dist/{chunk-D5PYOXEI.js.map → chunk-LVWFOLUZ.js.map} +1 -1
  12. package/dist/{chunk-WXSR2II7.js → chunk-OQKMEFOS.js} +58 -6
  13. package/dist/chunk-OQKMEFOS.js.map +1 -0
  14. package/dist/chunk-SXTKFDCR.js +104 -0
  15. package/dist/chunk-SXTKFDCR.js.map +1 -0
  16. package/dist/chunk-T5OMVL7E.js +443 -0
  17. package/dist/chunk-T5OMVL7E.js.map +1 -0
  18. package/dist/{chunk-ZM4ZQZWZ.js → chunk-TPWGL2XS.js} +39 -37
  19. package/dist/chunk-TPWGL2XS.js.map +1 -0
  20. package/dist/{chunk-OQO55NKV.js → chunk-WFS63PCW.js} +85 -11
  21. package/dist/chunk-WFS63PCW.js.map +1 -0
  22. package/dist/core/index.js +9 -1
  23. package/dist/{discovery-NEOY4MPN.js → discovery-ZJQSXF56.js} +3 -3
  24. package/dist/{generate-FBHSXR3D.js → generate-RJFS2JWA.js} +4 -4
  25. package/dist/index.js +7 -6
  26. package/dist/index.js.map +1 -1
  27. package/dist/init-ZSX3NRCZ.js +636 -0
  28. package/dist/init-ZSX3NRCZ.js.map +1 -0
  29. package/dist/mcp-bin.js +2 -2
  30. package/dist/{scan-CJF2DOQW.js → scan-3PMCJ4RB.js} +6 -6
  31. package/dist/scan-generate-SYU4PYZD.js +1115 -0
  32. package/dist/scan-generate-SYU4PYZD.js.map +1 -0
  33. package/dist/{service-TQYWY65E.js → service-VMGNJZ42.js} +3 -3
  34. package/dist/snapshot-XOISO2IS.js +139 -0
  35. package/dist/snapshot-XOISO2IS.js.map +1 -0
  36. package/dist/{static-viewer-NUBFPKWH.js → static-viewer-5GXH2MGE.js} +3 -3
  37. package/dist/static-viewer-5GXH2MGE.js.map +1 -0
  38. package/dist/{test-Z5LVO724.js → test-SI4NSHQX.js} +4 -4
  39. package/dist/{tokens-CE46OTMD.js → tokens-T6SIVUT5.js} +5 -5
  40. package/dist/{viewer-DNMNC5VS.js → viewer-7ZEAFBVN.js} +80 -58
  41. package/dist/viewer-7ZEAFBVN.js.map +1 -0
  42. package/package.json +6 -14
  43. package/src/ai-client.ts +156 -0
  44. package/src/bin.ts +74 -2
  45. package/src/build.ts +95 -33
  46. package/src/commands/__tests__/drift-sync.test.ts +252 -0
  47. package/src/commands/__tests__/scan-generate.test.ts +497 -45
  48. package/src/commands/enhance.ts +11 -35
  49. package/src/commands/init.ts +296 -193
  50. package/src/commands/scan-generate.ts +740 -139
  51. package/src/commands/scan.ts +37 -32
  52. package/src/commands/setup.ts +143 -52
  53. package/src/commands/snapshot.ts +197 -0
  54. package/src/commands/sync.ts +357 -0
  55. package/src/commands/validate.ts +43 -1
  56. package/src/core/component-extractor.test.ts +282 -0
  57. package/src/core/component-extractor.ts +1030 -0
  58. package/src/core/discovery.ts +93 -7
  59. package/src/service/enhance/props-extractor.ts +235 -13
  60. package/src/validators.ts +236 -0
  61. package/src/viewer/__tests__/viewer-integration.test.ts +85 -74
  62. package/src/viewer/server.ts +37 -22
  63. package/src/viewer/vite-plugin.ts +25 -9
  64. package/dist/chunk-5G3VZH43.js.map +0 -1
  65. package/dist/chunk-OQO55NKV.js.map +0 -1
  66. package/dist/chunk-WXSR2II7.js.map +0 -1
  67. package/dist/chunk-ZM4ZQZWZ.js.map +0 -1
  68. package/dist/init-NDQXUWDU.js +0 -796
  69. package/dist/init-NDQXUWDU.js.map +0 -1
  70. package/dist/scan-generate-SJAN5MVI.js +0 -691
  71. package/dist/scan-generate-SJAN5MVI.js.map +0 -1
  72. package/dist/viewer-DNMNC5VS.js.map +0 -1
  73. package/src/ai.ts +0 -266
  74. package/src/commands/init-framework.ts +0 -414
  75. package/src/mcp/bin.ts +0 -36
  76. package/src/migrate/bin.ts +0 -114
  77. package/src/theme/index.ts +0 -77
  78. package/src/viewer/__tests__/a11y-fixes.test.ts +0 -358
  79. package/src/viewer/__tests__/jsx-parser.test.ts +0 -502
  80. package/src/viewer/__tests__/render-utils.test.ts +0 -232
  81. package/src/viewer/__tests__/style-utils.test.ts +0 -404
  82. package/src/viewer/assets/fragments-logo.ts +0 -4
  83. package/src/viewer/assets/fragments_logo.png +0 -0
  84. package/src/viewer/bin.ts +0 -86
  85. package/src/viewer/cli/health.ts +0 -256
  86. package/src/viewer/cli/index.ts +0 -33
  87. package/src/viewer/cli/scan.ts +0 -124
  88. package/src/viewer/cli/utils.ts +0 -174
  89. package/src/viewer/components/AccessibilityPanel.tsx +0 -1457
  90. package/src/viewer/components/ActionCapture.tsx +0 -172
  91. package/src/viewer/components/ActionsPanel.tsx +0 -332
  92. package/src/viewer/components/AllVariantsPreview.tsx +0 -78
  93. package/src/viewer/components/App.tsx +0 -582
  94. package/src/viewer/components/BottomPanel.tsx +0 -288
  95. package/src/viewer/components/CodePanel.naming.test.tsx +0 -59
  96. package/src/viewer/components/CodePanel.tsx +0 -118
  97. package/src/viewer/components/CommandPalette.tsx +0 -392
  98. package/src/viewer/components/ComponentDocView.tsx +0 -164
  99. package/src/viewer/components/ComponentGraph.tsx +0 -380
  100. package/src/viewer/components/ComponentHeader.tsx +0 -88
  101. package/src/viewer/components/ContractPanel.tsx +0 -241
  102. package/src/viewer/components/EmptyVariantMessage.tsx +0 -54
  103. package/src/viewer/components/ErrorBoundary.tsx +0 -97
  104. package/src/viewer/components/FigmaEmbed.tsx +0 -238
  105. package/src/viewer/components/FragmentEditor.tsx +0 -525
  106. package/src/viewer/components/FragmentRenderer.tsx +0 -61
  107. package/src/viewer/components/HeaderSearch.tsx +0 -24
  108. package/src/viewer/components/HealthDashboard.tsx +0 -441
  109. package/src/viewer/components/HmrStatusIndicator.tsx +0 -61
  110. package/src/viewer/components/Icons.tsx +0 -479
  111. package/src/viewer/components/InteractionsPanel.tsx +0 -757
  112. package/src/viewer/components/IsolatedPreviewFrame.tsx +0 -346
  113. package/src/viewer/components/IsolatedRender.tsx +0 -113
  114. package/src/viewer/components/KeyboardShortcutsHelp.tsx +0 -53
  115. package/src/viewer/components/LandingPage.tsx +0 -421
  116. package/src/viewer/components/Layout.tsx +0 -27
  117. package/src/viewer/components/LeftSidebar.tsx +0 -472
  118. package/src/viewer/components/LoadErrorMessage.tsx +0 -102
  119. package/src/viewer/components/MultiViewportPreview.tsx +0 -522
  120. package/src/viewer/components/NoVariantsMessage.tsx +0 -59
  121. package/src/viewer/components/PanelShell.tsx +0 -161
  122. package/src/viewer/components/PerformancePanel.tsx +0 -304
  123. package/src/viewer/components/PreviewArea.tsx +0 -472
  124. package/src/viewer/components/PreviewAside.tsx +0 -168
  125. package/src/viewer/components/PreviewFrameHost.tsx +0 -303
  126. package/src/viewer/components/PreviewPane.tsx +0 -149
  127. package/src/viewer/components/PreviewToolbar.tsx +0 -80
  128. package/src/viewer/components/PropsEditor.tsx +0 -506
  129. package/src/viewer/components/PropsTable.tsx +0 -111
  130. package/src/viewer/components/RelationsSection.tsx +0 -88
  131. package/src/viewer/components/ResizablePanel.tsx +0 -271
  132. package/src/viewer/components/RightSidebar.tsx +0 -102
  133. package/src/viewer/components/RuntimeToolsRegistrar.tsx +0 -17
  134. package/src/viewer/components/ScreenshotButton.tsx +0 -90
  135. package/src/viewer/components/Sidebar.tsx +0 -169
  136. package/src/viewer/components/SkeletonLoader.tsx +0 -161
  137. package/src/viewer/components/ThemeProvider.tsx +0 -42
  138. package/src/viewer/components/Toast.tsx +0 -3
  139. package/src/viewer/components/TokenStylePanel.tsx +0 -699
  140. package/src/viewer/components/TopToolbar.tsx +0 -159
  141. package/src/viewer/components/UsageSection.tsx +0 -95
  142. package/src/viewer/components/VariantMatrix.tsx +0 -388
  143. package/src/viewer/components/VariantRenderer.tsx +0 -131
  144. package/src/viewer/components/VariantTabs.tsx +0 -40
  145. package/src/viewer/components/ViewerHeader.tsx +0 -69
  146. package/src/viewer/components/ViewerStateSync.tsx +0 -52
  147. package/src/viewer/components/ViewportSelector.tsx +0 -172
  148. package/src/viewer/components/WebMCPDevTools.tsx +0 -503
  149. package/src/viewer/components/WebMCPIntegration.tsx +0 -47
  150. package/src/viewer/components/WebMCPStatusIndicator.tsx +0 -60
  151. package/src/viewer/components/_future/CreatePage.tsx +0 -836
  152. package/src/viewer/components/viewer-utils.ts +0 -16
  153. package/src/viewer/composition-renderer.ts +0 -381
  154. package/src/viewer/constants/index.ts +0 -1
  155. package/src/viewer/constants/ui.ts +0 -166
  156. package/src/viewer/entry.tsx +0 -335
  157. package/src/viewer/hooks/index.ts +0 -2
  158. package/src/viewer/hooks/useA11yCache.ts +0 -383
  159. package/src/viewer/hooks/useA11yService.ts +0 -364
  160. package/src/viewer/hooks/useActions.ts +0 -138
  161. package/src/viewer/hooks/useAppState.ts +0 -147
  162. package/src/viewer/hooks/useCompiledFragments.ts +0 -42
  163. package/src/viewer/hooks/useFigmaIntegration.ts +0 -132
  164. package/src/viewer/hooks/useHmrStatus.ts +0 -109
  165. package/src/viewer/hooks/useKeyboardShortcuts.ts +0 -270
  166. package/src/viewer/hooks/usePreviewBridge.ts +0 -347
  167. package/src/viewer/hooks/useScrollSpy.ts +0 -78
  168. package/src/viewer/hooks/useUrlState.ts +0 -318
  169. package/src/viewer/hooks/useViewSettings.ts +0 -111
  170. package/src/viewer/index.html +0 -28
  171. package/src/viewer/intelligence/healthReport.ts +0 -505
  172. package/src/viewer/intelligence/styleDrift.ts +0 -340
  173. package/src/viewer/intelligence/usageScanner.ts +0 -309
  174. package/src/viewer/jsx-parser.ts +0 -486
  175. package/src/viewer/preview-frame-entry.tsx +0 -25
  176. package/src/viewer/preview-frame.html +0 -125
  177. package/src/viewer/public/favicon.ico +0 -0
  178. package/src/viewer/render-template.html +0 -68
  179. package/src/viewer/styles/globals.css +0 -278
  180. package/src/viewer/types/a11y.ts +0 -197
  181. package/src/viewer/utils/a11y-fixes.ts +0 -509
  182. package/src/viewer/utils/actionExport.ts +0 -372
  183. package/src/viewer/utils/colorSchemes.ts +0 -201
  184. package/src/viewer/utils/detectRelationships.ts +0 -256
  185. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss +0 -10
  186. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss.d.ts +0 -2
  187. package/src/viewer/vendor/shared/src/ComponentDocContent.tsx +0 -274
  188. package/src/viewer/vendor/shared/src/DocsHeaderBar.tsx +0 -129
  189. package/src/viewer/vendor/shared/src/DocsPageAsideHost.tsx +0 -89
  190. package/src/viewer/vendor/shared/src/DocsPageShell.tsx +0 -124
  191. package/src/viewer/vendor/shared/src/DocsSearchCommand.tsx +0 -99
  192. package/src/viewer/vendor/shared/src/DocsSidebarNav.tsx +0 -66
  193. package/src/viewer/vendor/shared/src/PropsTable.module.scss +0 -68
  194. package/src/viewer/vendor/shared/src/PropsTable.module.scss.d.ts +0 -2
  195. package/src/viewer/vendor/shared/src/PropsTable.tsx +0 -76
  196. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss +0 -114
  197. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss.d.ts +0 -2
  198. package/src/viewer/vendor/shared/src/VariantPreviewCard.tsx +0 -137
  199. package/src/viewer/vendor/shared/src/docs-data/index.ts +0 -32
  200. package/src/viewer/vendor/shared/src/docs-data/mcp-configs.ts +0 -72
  201. package/src/viewer/vendor/shared/src/docs-data/palettes.ts +0 -75
  202. package/src/viewer/vendor/shared/src/docs-data/setup-examples.ts +0 -55
  203. package/src/viewer/vendor/shared/src/docs-layout.scss +0 -28
  204. package/src/viewer/vendor/shared/src/docs-layout.scss.d.ts +0 -2
  205. package/src/viewer/vendor/shared/src/index.ts +0 -34
  206. package/src/viewer/vendor/shared/src/types.ts +0 -53
  207. package/src/viewer/webmcp/__tests__/analytics.test.ts +0 -108
  208. package/src/viewer/webmcp/analytics.ts +0 -165
  209. package/src/viewer/webmcp/index.ts +0 -3
  210. package/src/viewer/webmcp/posthog-bridge.ts +0 -39
  211. package/src/viewer/webmcp/runtime-tools.ts +0 -152
  212. package/src/viewer/webmcp/scan-utils.ts +0 -135
  213. package/src/viewer/webmcp/use-tool-analytics.ts +0 -69
  214. package/src/viewer/webmcp/viewer-state.ts +0 -45
  215. /package/dist/{discovery-NEOY4MPN.js.map → ai-client-I6MDWNYA.js.map} +0 -0
  216. /package/dist/{chunk-PW7QTQA6.js.map → chunk-4OC7FTJB.js.map} +0 -0
  217. /package/dist/{chunk-HRFUSSZI.js.map → chunk-AM4MRTMN.js.map} +0 -0
  218. /package/dist/{scan-CJF2DOQW.js.map → discovery-ZJQSXF56.js.map} +0 -0
  219. /package/dist/{generate-FBHSXR3D.js.map → generate-RJFS2JWA.js.map} +0 -0
  220. /package/dist/{service-TQYWY65E.js.map → scan-3PMCJ4RB.js.map} +0 -0
  221. /package/dist/{static-viewer-NUBFPKWH.js.map → service-VMGNJZ42.js.map} +0 -0
  222. /package/dist/{test-Z5LVO724.js.map → test-SI4NSHQX.js.map} +0 -0
  223. /package/dist/{tokens-CE46OTMD.js.map → tokens-T6SIVUT5.js.map} +0 -0
package/src/ai.ts DELETED
@@ -1,266 +0,0 @@
1
- import type { CompiledFragment, CompiledFragmentsFile } from "./core/index.js";
2
- import { generateContext } from "./core/index.js";
3
-
4
- export interface AiSuggestOptions {
5
- /** The user's prompt describing what they want to build */
6
- prompt: string;
7
- /** Optional additional context */
8
- context?: string;
9
- /** Compiled fragments to use */
10
- fragments: CompiledFragment[];
11
- /** Whether to stream output */
12
- stream?: boolean;
13
- }
14
-
15
- export interface AiSuggestResult {
16
- success: boolean;
17
- response?: string;
18
- error?: string;
19
- tokensUsed?: number;
20
- }
21
-
22
- /**
23
- * Call AI API to get component suggestions based on design system context.
24
- * Supports both Anthropic and OpenAI APIs via environment variables.
25
- */
26
- export async function aiSuggest(options: AiSuggestOptions): Promise<AiSuggestResult> {
27
- const { prompt, context, fragments, stream = true } = options;
28
-
29
- // Check for API keys
30
- const anthropicKey = process.env.ANTHROPIC_API_KEY;
31
- const openaiKey = process.env.OPENAI_API_KEY;
32
-
33
- if (!anthropicKey && !openaiKey) {
34
- return {
35
- success: false,
36
- error: "No API key found. Set ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable.",
37
- };
38
- }
39
-
40
- // Generate design system context
41
- const { content: systemContext } = generateContext(fragments, {
42
- format: "markdown",
43
- compact: false,
44
- include: {
45
- props: true,
46
- variants: true,
47
- usage: true,
48
- code: true,
49
- },
50
- });
51
-
52
- // Build the system prompt
53
- const systemPrompt = `You are a UI developer assistant helping to build interfaces using a specific design system.
54
-
55
- You have access to the following design system components:
56
-
57
- ${systemContext}
58
-
59
- When suggesting components:
60
- 1. ONLY use components from this design system - never suggest generic HTML or components not listed above
61
- 2. Explain WHY each component is appropriate for the use case
62
- 3. Show complete, ready-to-use code examples with correct props
63
- 4. Follow the "when to use" and "when NOT to use" guidelines for each component
64
- 5. Consider accessibility and best practices
65
- 6. If multiple approaches are valid, recommend the simplest one first
66
-
67
- Format your response as:
68
- 1. A brief explanation of the approach
69
- 2. Code example(s) with comments
70
- 3. Any important notes about props or customization`;
71
-
72
- // Build the user prompt
73
- const userPrompt = context
74
- ? `${prompt}\n\nAdditional context: ${context}`
75
- : prompt;
76
-
77
- // Prefer Anthropic, fallback to OpenAI
78
- if (anthropicKey) {
79
- return callAnthropic(anthropicKey, systemPrompt, userPrompt, stream);
80
- } else {
81
- return callOpenAI(openaiKey!, systemPrompt, userPrompt, stream);
82
- }
83
- }
84
-
85
- /**
86
- * Call Anthropic's Claude API
87
- */
88
- async function callAnthropic(
89
- apiKey: string,
90
- systemPrompt: string,
91
- userPrompt: string,
92
- stream: boolean
93
- ): Promise<AiSuggestResult> {
94
- try {
95
- const response = await fetch("https://api.anthropic.com/v1/messages", {
96
- method: "POST",
97
- headers: {
98
- "Content-Type": "application/json",
99
- "x-api-key": apiKey,
100
- "anthropic-version": "2023-06-01",
101
- },
102
- body: JSON.stringify({
103
- model: "claude-sonnet-4-20250514",
104
- max_tokens: 4096,
105
- system: systemPrompt,
106
- messages: [
107
- {
108
- role: "user",
109
- content: userPrompt,
110
- },
111
- ],
112
- stream: stream,
113
- }),
114
- });
115
-
116
- if (!response.ok) {
117
- const error = await response.text();
118
- return {
119
- success: false,
120
- error: `Anthropic API error: ${response.status} - ${error}`,
121
- };
122
- }
123
-
124
- if (stream && response.body) {
125
- // Stream the response
126
- const reader = response.body.getReader();
127
- const decoder = new TextDecoder();
128
- let fullResponse = "";
129
-
130
- while (true) {
131
- const { done, value } = await reader.read();
132
- if (done) break;
133
-
134
- const chunk = decoder.decode(value, { stream: true });
135
- const lines = chunk.split("\n");
136
-
137
- for (const line of lines) {
138
- if (line.startsWith("data: ")) {
139
- const data = line.slice(6);
140
- if (data === "[DONE]") continue;
141
-
142
- try {
143
- const parsed = JSON.parse(data);
144
- if (parsed.type === "content_block_delta" && parsed.delta?.text) {
145
- process.stdout.write(parsed.delta.text);
146
- fullResponse += parsed.delta.text;
147
- }
148
- } catch {
149
- // Skip malformed JSON
150
- }
151
- }
152
- }
153
- }
154
-
155
- console.log(); // Final newline
156
- return {
157
- success: true,
158
- response: fullResponse,
159
- };
160
- } else {
161
- const data = await response.json();
162
- const text = data.content?.[0]?.text ?? "";
163
-
164
- return {
165
- success: true,
166
- response: text,
167
- tokensUsed: data.usage?.input_tokens + data.usage?.output_tokens,
168
- };
169
- }
170
- } catch (error) {
171
- return {
172
- success: false,
173
- error: `Failed to call Anthropic API: ${error instanceof Error ? error.message : error}`,
174
- };
175
- }
176
- }
177
-
178
- /**
179
- * Call OpenAI's API
180
- */
181
- async function callOpenAI(
182
- apiKey: string,
183
- systemPrompt: string,
184
- userPrompt: string,
185
- stream: boolean
186
- ): Promise<AiSuggestResult> {
187
- try {
188
- const response = await fetch("https://api.openai.com/v1/chat/completions", {
189
- method: "POST",
190
- headers: {
191
- "Content-Type": "application/json",
192
- Authorization: `Bearer ${apiKey}`,
193
- },
194
- body: JSON.stringify({
195
- model: "gpt-4o",
196
- messages: [
197
- { role: "system", content: systemPrompt },
198
- { role: "user", content: userPrompt },
199
- ],
200
- max_tokens: 4096,
201
- stream: stream,
202
- }),
203
- });
204
-
205
- if (!response.ok) {
206
- const error = await response.text();
207
- return {
208
- success: false,
209
- error: `OpenAI API error: ${response.status} - ${error}`,
210
- };
211
- }
212
-
213
- if (stream && response.body) {
214
- // Stream the response
215
- const reader = response.body.getReader();
216
- const decoder = new TextDecoder();
217
- let fullResponse = "";
218
-
219
- while (true) {
220
- const { done, value } = await reader.read();
221
- if (done) break;
222
-
223
- const chunk = decoder.decode(value, { stream: true });
224
- const lines = chunk.split("\n");
225
-
226
- for (const line of lines) {
227
- if (line.startsWith("data: ")) {
228
- const data = line.slice(6);
229
- if (data === "[DONE]") continue;
230
-
231
- try {
232
- const parsed = JSON.parse(data);
233
- const content = parsed.choices?.[0]?.delta?.content;
234
- if (content) {
235
- process.stdout.write(content);
236
- fullResponse += content;
237
- }
238
- } catch {
239
- // Skip malformed JSON
240
- }
241
- }
242
- }
243
- }
244
-
245
- console.log(); // Final newline
246
- return {
247
- success: true,
248
- response: fullResponse,
249
- };
250
- } else {
251
- const data = await response.json();
252
- const text = data.choices?.[0]?.message?.content ?? "";
253
-
254
- return {
255
- success: true,
256
- response: text,
257
- tokensUsed: data.usage?.total_tokens,
258
- };
259
- }
260
- } catch (error) {
261
- return {
262
- success: false,
263
- error: `Failed to call OpenAI API: ${error instanceof Error ? error.message : error}`,
264
- };
265
- }
266
- }
@@ -1,414 +0,0 @@
1
- /**
2
- * Framework detection and auto-configuration for fragments init.
3
- *
4
- * Detects the consumer's framework (Next.js, Vite, Remix, Astro)
5
- * and generates appropriate configuration files.
6
- */
7
-
8
- import { readFile, writeFile, access } from "node:fs/promises";
9
- import { join } from "node:path";
10
- import pc from "picocolors";
11
-
12
- // ============================================
13
- // Types
14
- // ============================================
15
-
16
- export type Framework = "nextjs" | "vite" | "remix" | "astro" | "unknown";
17
-
18
- export interface FrameworkDetection {
19
- framework: Framework;
20
- /** Package that triggered the detection */
21
- detectedBy: string | null;
22
- }
23
-
24
- export interface FrameworkSetupOptions {
25
- /** Project root directory */
26
- projectRoot: string;
27
- /** Override auto-detected framework */
28
- framework?: Framework;
29
- /** Seed overrides for globals.scss generation */
30
- seeds?: {
31
- brand?: string;
32
- neutral?: string;
33
- density?: string;
34
- radiusStyle?: string;
35
- };
36
- }
37
-
38
- export interface FrameworkSetupResult {
39
- framework: Framework;
40
- filesCreated: string[];
41
- packagesToInstall: string[];
42
- configModified: string[];
43
- warnings: string[];
44
- }
45
-
46
- // ============================================
47
- // Framework Detection
48
- // ============================================
49
-
50
- /**
51
- * Detect framework from package.json dependencies
52
- */
53
- export async function detectFramework(
54
- projectRoot: string
55
- ): Promise<FrameworkDetection> {
56
- try {
57
- const pkgPath = join(projectRoot, "package.json");
58
- const pkgContent = await readFile(pkgPath, "utf-8");
59
- const pkg = JSON.parse(pkgContent);
60
-
61
- const allDeps = {
62
- ...pkg.dependencies,
63
- ...pkg.devDependencies,
64
- };
65
-
66
- // Check in order of specificity
67
- if (allDeps["next"]) {
68
- return { framework: "nextjs", detectedBy: "next" };
69
- }
70
- if (allDeps["@remix-run/react"]) {
71
- return { framework: "remix", detectedBy: "@remix-run/react" };
72
- }
73
- if (allDeps["astro"]) {
74
- return { framework: "astro", detectedBy: "astro" };
75
- }
76
- if (allDeps["vite"]) {
77
- return { framework: "vite", detectedBy: "vite" };
78
- }
79
-
80
- return { framework: "unknown", detectedBy: null };
81
- } catch {
82
- return { framework: "unknown", detectedBy: null };
83
- }
84
- }
85
-
86
- // ============================================
87
- // Globals SCSS Generation
88
- // ============================================
89
-
90
- function generateGlobalsSCSS(seeds?: FrameworkSetupOptions["seeds"]): string {
91
- const withClauses: string[] = [];
92
-
93
- if (seeds?.brand) {
94
- withClauses.push(` $fui-brand: ${seeds.brand}`);
95
- }
96
- if (seeds?.neutral) {
97
- withClauses.push(` $fui-neutral: "${seeds.neutral}"`);
98
- }
99
- if (seeds?.density) {
100
- withClauses.push(` $fui-density: "${seeds.density}"`);
101
- }
102
- if (seeds?.radiusStyle) {
103
- withClauses.push(` $fui-radius-style: "${seeds.radiusStyle}"`);
104
- }
105
-
106
- const useStatement =
107
- withClauses.length > 0
108
- ? `@use '@fragments-sdk/ui/styles' with (\n${withClauses.join(",\n")}\n);`
109
- : `@use '@fragments-sdk/ui/styles';`;
110
-
111
- return `// Fragments SDK Global Styles
112
- // Customize seed values to theme the entire design system.
113
- // See: https://usefragments.com/docs/theming
114
- ${useStatement}
115
- `;
116
- }
117
-
118
- // ============================================
119
- // Providers Component Generation
120
- // ============================================
121
-
122
- function generateProviders(): string {
123
- return `'use client';
124
-
125
- import { ThemeProvider } from '@fragments-sdk/ui';
126
-
127
- export function Providers({ children }: { children: React.ReactNode }) {
128
- return (
129
- <ThemeProvider defaultMode="system" attribute="data-theme">
130
- {children}
131
- </ThemeProvider>
132
- );
133
- }
134
- `;
135
- }
136
-
137
- // ============================================
138
- // Per-Framework Configuration
139
- // ============================================
140
-
141
- async function setupNextJS(
142
- projectRoot: string,
143
- options: FrameworkSetupOptions
144
- ): Promise<FrameworkSetupResult> {
145
- const result: FrameworkSetupResult = {
146
- framework: "nextjs",
147
- filesCreated: [],
148
- packagesToInstall: [],
149
- configModified: [],
150
- warnings: [],
151
- };
152
-
153
- // Check if sass is installed
154
- try {
155
- const pkgContent = await readFile(
156
- join(projectRoot, "package.json"),
157
- "utf-8"
158
- );
159
- const pkg = JSON.parse(pkgContent);
160
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
161
- if (!allDeps["sass"]) {
162
- result.packagesToInstall.push("sass");
163
- }
164
- } catch {
165
- // Proceed without checking
166
- }
167
-
168
- // Update next.config if transpilePackages is needed
169
- const nextConfigPaths = [
170
- "next.config.ts",
171
- "next.config.mjs",
172
- "next.config.js",
173
- ];
174
-
175
- for (const configName of nextConfigPaths) {
176
- const configPath = join(projectRoot, configName);
177
- try {
178
- await access(configPath);
179
- const content = await readFile(configPath, "utf-8");
180
-
181
- if (!content.includes("transpilePackages")) {
182
- // Add transpilePackages to the config
183
- if (content.includes("const nextConfig")) {
184
- const updated = content.replace(
185
- /const nextConfig\s*=\s*\{/,
186
- `const nextConfig = {\n transpilePackages: ['@fragments-sdk/ui'],`
187
- );
188
- await writeFile(configPath, updated, "utf-8");
189
- result.configModified.push(configName);
190
- } else {
191
- result.warnings.push(
192
- `Could not auto-modify ${configName}. Add transpilePackages: ['@fragments-sdk/ui'] manually.`
193
- );
194
- }
195
- }
196
- break;
197
- } catch {
198
- continue;
199
- }
200
- }
201
-
202
- // Generate globals.scss
203
- const globalsPath = join(projectRoot, "src", "styles", "globals.scss");
204
- try {
205
- await access(globalsPath);
206
- result.warnings.push(
207
- "src/styles/globals.scss already exists. Skipped generation."
208
- );
209
- } catch {
210
- await writeFile(globalsPath, generateGlobalsSCSS(options.seeds), "utf-8");
211
- result.filesCreated.push("src/styles/globals.scss");
212
- }
213
-
214
- // Generate providers.tsx
215
- const providersPath = join(projectRoot, "src", "providers.tsx");
216
- try {
217
- await access(providersPath);
218
- result.warnings.push("src/providers.tsx already exists. Skipped.");
219
- } catch {
220
- await writeFile(providersPath, generateProviders(), "utf-8");
221
- result.filesCreated.push("src/providers.tsx");
222
- }
223
-
224
- return result;
225
- }
226
-
227
- async function setupVite(
228
- projectRoot: string,
229
- options: FrameworkSetupOptions
230
- ): Promise<FrameworkSetupResult> {
231
- const result: FrameworkSetupResult = {
232
- framework: "vite",
233
- filesCreated: [],
234
- packagesToInstall: [],
235
- configModified: [],
236
- warnings: [],
237
- };
238
-
239
- // Check if sass is installed
240
- try {
241
- const pkgContent = await readFile(
242
- join(projectRoot, "package.json"),
243
- "utf-8"
244
- );
245
- const pkg = JSON.parse(pkgContent);
246
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
247
- if (!allDeps["sass"]) {
248
- result.packagesToInstall.push("sass");
249
- }
250
- } catch {
251
- // Proceed
252
- }
253
-
254
- // Generate globals.scss
255
- const globalsPath = join(projectRoot, "src", "styles", "globals.scss");
256
- try {
257
- await access(globalsPath);
258
- result.warnings.push(
259
- "src/styles/globals.scss already exists. Skipped generation."
260
- );
261
- } catch {
262
- await writeFile(globalsPath, generateGlobalsSCSS(options.seeds), "utf-8");
263
- result.filesCreated.push("src/styles/globals.scss");
264
- }
265
-
266
- // Generate providers.tsx
267
- const providersPath = join(projectRoot, "src", "providers.tsx");
268
- try {
269
- await access(providersPath);
270
- result.warnings.push("src/providers.tsx already exists. Skipped.");
271
- } catch {
272
- await writeFile(providersPath, generateProviders(), "utf-8");
273
- result.filesCreated.push("src/providers.tsx");
274
- }
275
-
276
- return result;
277
- }
278
-
279
- async function setupRemix(
280
- projectRoot: string,
281
- options: FrameworkSetupOptions
282
- ): Promise<FrameworkSetupResult> {
283
- const result: FrameworkSetupResult = {
284
- framework: "remix",
285
- filesCreated: [],
286
- packagesToInstall: [],
287
- configModified: [],
288
- warnings: [],
289
- };
290
-
291
- result.packagesToInstall.push("sass");
292
-
293
- // Generate globals.scss in app/styles
294
- const globalsPath = join(projectRoot, "app", "styles", "globals.scss");
295
- try {
296
- await access(globalsPath);
297
- result.warnings.push(
298
- "app/styles/globals.scss already exists. Skipped generation."
299
- );
300
- } catch {
301
- await writeFile(globalsPath, generateGlobalsSCSS(options.seeds), "utf-8");
302
- result.filesCreated.push("app/styles/globals.scss");
303
- }
304
-
305
- // Generate providers.tsx
306
- const providersPath = join(projectRoot, "app", "providers.tsx");
307
- try {
308
- await access(providersPath);
309
- result.warnings.push("app/providers.tsx already exists. Skipped.");
310
- } catch {
311
- await writeFile(providersPath, generateProviders(), "utf-8");
312
- result.filesCreated.push("app/providers.tsx");
313
- }
314
-
315
- result.warnings.push(
316
- 'Add @fragments-sdk/ui to serverDependenciesToBundle in remix.config if using source imports.'
317
- );
318
-
319
- return result;
320
- }
321
-
322
- async function setupAstro(
323
- projectRoot: string,
324
- options: FrameworkSetupOptions
325
- ): Promise<FrameworkSetupResult> {
326
- const result: FrameworkSetupResult = {
327
- framework: "astro",
328
- filesCreated: [],
329
- packagesToInstall: [],
330
- configModified: [],
331
- warnings: [],
332
- };
333
-
334
- result.packagesToInstall.push("sass");
335
-
336
- // Generate globals.scss
337
- const globalsPath = join(projectRoot, "src", "styles", "globals.scss");
338
- try {
339
- await access(globalsPath);
340
- result.warnings.push(
341
- "src/styles/globals.scss already exists. Skipped generation."
342
- );
343
- } catch {
344
- await writeFile(globalsPath, generateGlobalsSCSS(options.seeds), "utf-8");
345
- result.filesCreated.push("src/styles/globals.scss");
346
- }
347
-
348
- return result;
349
- }
350
-
351
- // ============================================
352
- // Main Setup Function
353
- // ============================================
354
-
355
- /**
356
- * Set up framework-specific configuration for @fragments-sdk/ui
357
- */
358
- export async function setupFramework(
359
- options: FrameworkSetupOptions
360
- ): Promise<FrameworkSetupResult> {
361
- const { projectRoot } = options;
362
-
363
- // Detect or use provided framework
364
- let framework = options.framework;
365
- if (!framework || framework === "unknown") {
366
- const detection = await detectFramework(projectRoot);
367
- framework = detection.framework;
368
-
369
- if (detection.detectedBy) {
370
- console.log(
371
- pc.green(` Detected ${frameworkLabel(framework)}`) +
372
- pc.dim(` (via ${detection.detectedBy})`)
373
- );
374
- }
375
- } else {
376
- console.log(pc.green(` Framework: ${frameworkLabel(framework)}`));
377
- }
378
-
379
- switch (framework) {
380
- case "nextjs":
381
- return setupNextJS(projectRoot, options);
382
- case "vite":
383
- return setupVite(projectRoot, options);
384
- case "remix":
385
- return setupRemix(projectRoot, options);
386
- case "astro":
387
- return setupAstro(projectRoot, options);
388
- default:
389
- return {
390
- framework: "unknown",
391
- filesCreated: [],
392
- packagesToInstall: ["sass"],
393
- configModified: [],
394
- warnings: [
395
- "Could not detect framework. Install sass and import @fragments-sdk/ui/styles manually.",
396
- ],
397
- };
398
- }
399
- }
400
-
401
- function frameworkLabel(framework: Framework): string {
402
- switch (framework) {
403
- case "nextjs":
404
- return "Next.js";
405
- case "vite":
406
- return "Vite";
407
- case "remix":
408
- return "Remix";
409
- case "astro":
410
- return "Astro";
411
- default:
412
- return "Unknown";
413
- }
414
- }
package/src/mcp/bin.ts DELETED
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env node
2
- import { startMcpServer } from './server.js';
3
-
4
- // Parse command line arguments
5
- const args = process.argv.slice(2);
6
- let projectRoot = process.cwd();
7
- let viewerUrl: string | undefined;
8
-
9
- for (let i = 0; i < args.length; i++) {
10
- const arg = args[i];
11
-
12
- if (arg === '--project-root' || arg === '-p') {
13
- projectRoot = args[++i] ?? projectRoot;
14
- } else if (arg === '--viewer-url' || arg === '-u') {
15
- viewerUrl = args[++i];
16
- } else if (arg === '--help' || arg === '-h') {
17
- console.log(`
18
- Usage: fragments-mcp [options]
19
-
20
- Options:
21
- -p, --project-root <path> Project root directory (default: cwd)
22
- -u, --viewer-url <url> Viewer URL (default: http://localhost:6006)
23
- -h, --help Show this help message
24
- `);
25
- process.exit(0);
26
- }
27
- }
28
-
29
- // Start server
30
- startMcpServer({
31
- projectRoot,
32
- viewerUrl,
33
- }).catch((error) => {
34
- console.error('Failed to start MCP server:', error);
35
- process.exit(1);
36
- });