popeye-cli 1.0.1 → 1.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 (216) hide show
  1. package/.env.example +24 -1
  2. package/CONTRIBUTING.md +275 -0
  3. package/OPEN_SOURCE_MANIFESTO.md +172 -0
  4. package/README.md +832 -123
  5. package/dist/adapters/claude.d.ts +19 -4
  6. package/dist/adapters/claude.d.ts.map +1 -1
  7. package/dist/adapters/claude.js +908 -42
  8. package/dist/adapters/claude.js.map +1 -1
  9. package/dist/adapters/gemini.d.ts +55 -0
  10. package/dist/adapters/gemini.d.ts.map +1 -0
  11. package/dist/adapters/gemini.js +318 -0
  12. package/dist/adapters/gemini.js.map +1 -0
  13. package/dist/adapters/grok.d.ts +73 -0
  14. package/dist/adapters/grok.d.ts.map +1 -0
  15. package/dist/adapters/grok.js +430 -0
  16. package/dist/adapters/grok.js.map +1 -0
  17. package/dist/adapters/openai.d.ts +1 -1
  18. package/dist/adapters/openai.d.ts.map +1 -1
  19. package/dist/adapters/openai.js +47 -8
  20. package/dist/adapters/openai.js.map +1 -1
  21. package/dist/auth/claude.d.ts +11 -9
  22. package/dist/auth/claude.d.ts.map +1 -1
  23. package/dist/auth/claude.js +107 -71
  24. package/dist/auth/claude.js.map +1 -1
  25. package/dist/auth/gemini.d.ts +58 -0
  26. package/dist/auth/gemini.d.ts.map +1 -0
  27. package/dist/auth/gemini.js +172 -0
  28. package/dist/auth/gemini.js.map +1 -0
  29. package/dist/auth/grok.d.ts +73 -0
  30. package/dist/auth/grok.d.ts.map +1 -0
  31. package/dist/auth/grok.js +211 -0
  32. package/dist/auth/grok.js.map +1 -0
  33. package/dist/auth/index.d.ts +14 -7
  34. package/dist/auth/index.d.ts.map +1 -1
  35. package/dist/auth/index.js +41 -6
  36. package/dist/auth/index.js.map +1 -1
  37. package/dist/auth/keychain.d.ts +20 -7
  38. package/dist/auth/keychain.d.ts.map +1 -1
  39. package/dist/auth/keychain.js +85 -29
  40. package/dist/auth/keychain.js.map +1 -1
  41. package/dist/auth/openai.d.ts +2 -2
  42. package/dist/auth/openai.d.ts.map +1 -1
  43. package/dist/auth/openai.js +30 -32
  44. package/dist/auth/openai.js.map +1 -1
  45. package/dist/cli/commands/auth.d.ts +1 -1
  46. package/dist/cli/commands/auth.d.ts.map +1 -1
  47. package/dist/cli/commands/auth.js +79 -8
  48. package/dist/cli/commands/auth.js.map +1 -1
  49. package/dist/cli/commands/create.d.ts.map +1 -1
  50. package/dist/cli/commands/create.js +15 -4
  51. package/dist/cli/commands/create.js.map +1 -1
  52. package/dist/cli/interactive.d.ts.map +1 -1
  53. package/dist/cli/interactive.js +1494 -114
  54. package/dist/cli/interactive.js.map +1 -1
  55. package/dist/config/defaults.d.ts +9 -1
  56. package/dist/config/defaults.d.ts.map +1 -1
  57. package/dist/config/defaults.js +19 -2
  58. package/dist/config/defaults.js.map +1 -1
  59. package/dist/config/index.d.ts +19 -0
  60. package/dist/config/index.d.ts.map +1 -1
  61. package/dist/config/index.js +33 -1
  62. package/dist/config/index.js.map +1 -1
  63. package/dist/config/schema.d.ts +47 -0
  64. package/dist/config/schema.d.ts.map +1 -1
  65. package/dist/config/schema.js +29 -1
  66. package/dist/config/schema.js.map +1 -1
  67. package/dist/generators/fullstack.d.ts +32 -0
  68. package/dist/generators/fullstack.d.ts.map +1 -0
  69. package/dist/generators/fullstack.js +497 -0
  70. package/dist/generators/fullstack.js.map +1 -0
  71. package/dist/generators/index.d.ts +4 -3
  72. package/dist/generators/index.d.ts.map +1 -1
  73. package/dist/generators/index.js +15 -1
  74. package/dist/generators/index.js.map +1 -1
  75. package/dist/generators/python.d.ts +17 -1
  76. package/dist/generators/python.d.ts.map +1 -1
  77. package/dist/generators/python.js +34 -20
  78. package/dist/generators/python.js.map +1 -1
  79. package/dist/generators/templates/fullstack.d.ts +113 -0
  80. package/dist/generators/templates/fullstack.d.ts.map +1 -0
  81. package/dist/generators/templates/fullstack.js +1004 -0
  82. package/dist/generators/templates/fullstack.js.map +1 -0
  83. package/dist/generators/typescript.d.ts +19 -1
  84. package/dist/generators/typescript.d.ts.map +1 -1
  85. package/dist/generators/typescript.js +37 -20
  86. package/dist/generators/typescript.js.map +1 -1
  87. package/dist/state/index.d.ts +108 -0
  88. package/dist/state/index.d.ts.map +1 -1
  89. package/dist/state/index.js +551 -4
  90. package/dist/state/index.js.map +1 -1
  91. package/dist/state/registry.d.ts +52 -0
  92. package/dist/state/registry.d.ts.map +1 -0
  93. package/dist/state/registry.js +215 -0
  94. package/dist/state/registry.js.map +1 -0
  95. package/dist/types/cli.d.ts +8 -0
  96. package/dist/types/cli.d.ts.map +1 -1
  97. package/dist/types/cli.js.map +1 -1
  98. package/dist/types/consensus.d.ts +186 -4
  99. package/dist/types/consensus.d.ts.map +1 -1
  100. package/dist/types/consensus.js +35 -3
  101. package/dist/types/consensus.js.map +1 -1
  102. package/dist/types/project.d.ts +76 -0
  103. package/dist/types/project.d.ts.map +1 -1
  104. package/dist/types/project.js +1 -1
  105. package/dist/types/project.js.map +1 -1
  106. package/dist/types/workflow.d.ts +217 -16
  107. package/dist/types/workflow.d.ts.map +1 -1
  108. package/dist/types/workflow.js +40 -1
  109. package/dist/types/workflow.js.map +1 -1
  110. package/dist/workflow/auto-fix.d.ts +45 -0
  111. package/dist/workflow/auto-fix.d.ts.map +1 -0
  112. package/dist/workflow/auto-fix.js +274 -0
  113. package/dist/workflow/auto-fix.js.map +1 -0
  114. package/dist/workflow/consensus.d.ts +70 -2
  115. package/dist/workflow/consensus.d.ts.map +1 -1
  116. package/dist/workflow/consensus.js +872 -17
  117. package/dist/workflow/consensus.js.map +1 -1
  118. package/dist/workflow/execution-mode.d.ts +10 -4
  119. package/dist/workflow/execution-mode.d.ts.map +1 -1
  120. package/dist/workflow/execution-mode.js +547 -58
  121. package/dist/workflow/execution-mode.js.map +1 -1
  122. package/dist/workflow/index.d.ts +14 -2
  123. package/dist/workflow/index.d.ts.map +1 -1
  124. package/dist/workflow/index.js +69 -6
  125. package/dist/workflow/index.js.map +1 -1
  126. package/dist/workflow/milestone-workflow.d.ts +34 -0
  127. package/dist/workflow/milestone-workflow.d.ts.map +1 -0
  128. package/dist/workflow/milestone-workflow.js +414 -0
  129. package/dist/workflow/milestone-workflow.js.map +1 -0
  130. package/dist/workflow/plan-mode.d.ts +80 -3
  131. package/dist/workflow/plan-mode.d.ts.map +1 -1
  132. package/dist/workflow/plan-mode.js +767 -49
  133. package/dist/workflow/plan-mode.js.map +1 -1
  134. package/dist/workflow/plan-storage.d.ts +386 -0
  135. package/dist/workflow/plan-storage.d.ts.map +1 -0
  136. package/dist/workflow/plan-storage.js +878 -0
  137. package/dist/workflow/plan-storage.js.map +1 -0
  138. package/dist/workflow/project-verification.d.ts +37 -0
  139. package/dist/workflow/project-verification.d.ts.map +1 -0
  140. package/dist/workflow/project-verification.js +381 -0
  141. package/dist/workflow/project-verification.js.map +1 -0
  142. package/dist/workflow/task-workflow.d.ts +37 -0
  143. package/dist/workflow/task-workflow.d.ts.map +1 -0
  144. package/dist/workflow/task-workflow.js +386 -0
  145. package/dist/workflow/task-workflow.js.map +1 -0
  146. package/dist/workflow/test-runner.d.ts +9 -0
  147. package/dist/workflow/test-runner.d.ts.map +1 -1
  148. package/dist/workflow/test-runner.js +101 -5
  149. package/dist/workflow/test-runner.js.map +1 -1
  150. package/dist/workflow/ui-designer.d.ts +82 -0
  151. package/dist/workflow/ui-designer.d.ts.map +1 -0
  152. package/dist/workflow/ui-designer.js +234 -0
  153. package/dist/workflow/ui-designer.js.map +1 -0
  154. package/dist/workflow/ui-setup.d.ts +58 -0
  155. package/dist/workflow/ui-setup.d.ts.map +1 -0
  156. package/dist/workflow/ui-setup.js +685 -0
  157. package/dist/workflow/ui-setup.js.map +1 -0
  158. package/dist/workflow/ui-verification.d.ts +114 -0
  159. package/dist/workflow/ui-verification.d.ts.map +1 -0
  160. package/dist/workflow/ui-verification.js +258 -0
  161. package/dist/workflow/ui-verification.js.map +1 -0
  162. package/dist/workflow/workflow-logger.d.ts +110 -0
  163. package/dist/workflow/workflow-logger.d.ts.map +1 -0
  164. package/dist/workflow/workflow-logger.js +267 -0
  165. package/dist/workflow/workflow-logger.js.map +1 -0
  166. package/dist/workflow/workspace-manager.d.ts +342 -0
  167. package/dist/workflow/workspace-manager.d.ts.map +1 -0
  168. package/dist/workflow/workspace-manager.js +733 -0
  169. package/dist/workflow/workspace-manager.js.map +1 -0
  170. package/package.json +2 -2
  171. package/src/adapters/claude.ts +1067 -47
  172. package/src/adapters/gemini.ts +373 -0
  173. package/src/adapters/grok.ts +492 -0
  174. package/src/adapters/openai.ts +48 -9
  175. package/src/auth/claude.ts +120 -78
  176. package/src/auth/gemini.ts +207 -0
  177. package/src/auth/grok.ts +255 -0
  178. package/src/auth/index.ts +47 -9
  179. package/src/auth/keychain.ts +95 -28
  180. package/src/auth/openai.ts +29 -36
  181. package/src/cli/commands/auth.ts +89 -10
  182. package/src/cli/commands/create.ts +13 -4
  183. package/src/cli/interactive.ts +1774 -142
  184. package/src/config/defaults.ts +19 -2
  185. package/src/config/index.ts +36 -1
  186. package/src/config/schema.ts +30 -1
  187. package/src/generators/fullstack.ts +551 -0
  188. package/src/generators/index.ts +25 -1
  189. package/src/generators/python.ts +65 -20
  190. package/src/generators/templates/fullstack.ts +1047 -0
  191. package/src/generators/typescript.ts +69 -20
  192. package/src/state/index.ts +713 -4
  193. package/src/state/registry.ts +278 -0
  194. package/src/types/cli.ts +8 -0
  195. package/src/types/consensus.ts +197 -6
  196. package/src/types/project.ts +82 -1
  197. package/src/types/workflow.ts +90 -1
  198. package/src/workflow/auto-fix.ts +340 -0
  199. package/src/workflow/consensus.ts +1180 -16
  200. package/src/workflow/execution-mode.ts +673 -74
  201. package/src/workflow/index.ts +95 -6
  202. package/src/workflow/milestone-workflow.ts +576 -0
  203. package/src/workflow/plan-mode.ts +924 -50
  204. package/src/workflow/plan-storage.ts +1282 -0
  205. package/src/workflow/project-verification.ts +471 -0
  206. package/src/workflow/task-workflow.ts +528 -0
  207. package/src/workflow/test-runner.ts +120 -5
  208. package/src/workflow/ui-designer.ts +337 -0
  209. package/src/workflow/ui-setup.ts +797 -0
  210. package/src/workflow/ui-verification.ts +357 -0
  211. package/src/workflow/workflow-logger.ts +353 -0
  212. package/src/workflow/workspace-manager.ts +912 -0
  213. package/tests/config/config.test.ts +1 -1
  214. package/tests/types/consensus.test.ts +3 -3
  215. package/tests/workflow/plan-mode.test.ts +213 -0
  216. package/tests/workflow/test-runner.test.ts +5 -3
@@ -0,0 +1,797 @@
1
+ /**
2
+ * UI Setup Module
3
+ * Automatically sets up component libraries, design systems, and styling
4
+ * for a polished, professional UI without manual configuration
5
+ */
6
+
7
+ import { promises as fs } from 'node:fs';
8
+ import path from 'node:path';
9
+ import { exec } from 'node:child_process';
10
+ import { promisify } from 'node:util';
11
+
12
+ const execAsync = promisify(exec);
13
+
14
+ /**
15
+ * Design theme configuration
16
+ */
17
+ export interface DesignTheme {
18
+ name: string;
19
+ colors: {
20
+ primary: string;
21
+ primaryForeground: string;
22
+ secondary: string;
23
+ secondaryForeground: string;
24
+ accent: string;
25
+ accentForeground: string;
26
+ background: string;
27
+ foreground: string;
28
+ card: string;
29
+ cardForeground: string;
30
+ muted: string;
31
+ mutedForeground: string;
32
+ destructive: string;
33
+ destructiveForeground: string;
34
+ border: string;
35
+ input: string;
36
+ ring: string;
37
+ };
38
+ borderRadius: string;
39
+ fontFamily: string;
40
+ }
41
+
42
+ /**
43
+ * Pre-defined professional themes
44
+ */
45
+ export const THEMES: Record<string, DesignTheme> = {
46
+ modern: {
47
+ name: 'Modern Blue',
48
+ colors: {
49
+ primary: '221.2 83.2% 53.3%',
50
+ primaryForeground: '210 40% 98%',
51
+ secondary: '210 40% 96.1%',
52
+ secondaryForeground: '222.2 47.4% 11.2%',
53
+ accent: '210 40% 96.1%',
54
+ accentForeground: '222.2 47.4% 11.2%',
55
+ background: '0 0% 100%',
56
+ foreground: '222.2 84% 4.9%',
57
+ card: '0 0% 100%',
58
+ cardForeground: '222.2 84% 4.9%',
59
+ muted: '210 40% 96.1%',
60
+ mutedForeground: '215.4 16.3% 46.9%',
61
+ destructive: '0 84.2% 60.2%',
62
+ destructiveForeground: '210 40% 98%',
63
+ border: '214.3 31.8% 91.4%',
64
+ input: '214.3 31.8% 91.4%',
65
+ ring: '221.2 83.2% 53.3%',
66
+ },
67
+ borderRadius: '0.5rem',
68
+ fontFamily: 'Inter, system-ui, sans-serif',
69
+ },
70
+ elegant: {
71
+ name: 'Elegant Dark',
72
+ colors: {
73
+ primary: '262.1 83.3% 57.8%',
74
+ primaryForeground: '210 20% 98%',
75
+ secondary: '220 14.3% 95.9%',
76
+ secondaryForeground: '220.9 39.3% 11%',
77
+ accent: '220 14.3% 95.9%',
78
+ accentForeground: '220.9 39.3% 11%',
79
+ background: '0 0% 100%',
80
+ foreground: '224 71.4% 4.1%',
81
+ card: '0 0% 100%',
82
+ cardForeground: '224 71.4% 4.1%',
83
+ muted: '220 14.3% 95.9%',
84
+ mutedForeground: '220 8.9% 46.1%',
85
+ destructive: '0 84.2% 60.2%',
86
+ destructiveForeground: '210 20% 98%',
87
+ border: '220 13% 91%',
88
+ input: '220 13% 91%',
89
+ ring: '262.1 83.3% 57.8%',
90
+ },
91
+ borderRadius: '0.75rem',
92
+ fontFamily: 'Plus Jakarta Sans, system-ui, sans-serif',
93
+ },
94
+ minimal: {
95
+ name: 'Minimal Clean',
96
+ colors: {
97
+ primary: '240 5.9% 10%',
98
+ primaryForeground: '0 0% 98%',
99
+ secondary: '240 4.8% 95.9%',
100
+ secondaryForeground: '240 5.9% 10%',
101
+ accent: '240 4.8% 95.9%',
102
+ accentForeground: '240 5.9% 10%',
103
+ background: '0 0% 100%',
104
+ foreground: '240 10% 3.9%',
105
+ card: '0 0% 100%',
106
+ cardForeground: '240 10% 3.9%',
107
+ muted: '240 4.8% 95.9%',
108
+ mutedForeground: '240 3.8% 46.1%',
109
+ destructive: '0 84.2% 60.2%',
110
+ destructiveForeground: '0 0% 98%',
111
+ border: '240 5.9% 90%',
112
+ input: '240 5.9% 90%',
113
+ ring: '240 5.9% 10%',
114
+ },
115
+ borderRadius: '0.375rem',
116
+ fontFamily: 'system-ui, sans-serif',
117
+ },
118
+ vibrant: {
119
+ name: 'Vibrant Gradient',
120
+ colors: {
121
+ primary: '339 89.6% 51%',
122
+ primaryForeground: '0 0% 100%',
123
+ secondary: '217.2 91.2% 59.8%',
124
+ secondaryForeground: '0 0% 100%',
125
+ accent: '47.9 95.8% 53.1%',
126
+ accentForeground: '0 0% 9%',
127
+ background: '0 0% 100%',
128
+ foreground: '222.2 84% 4.9%',
129
+ card: '0 0% 100%',
130
+ cardForeground: '222.2 84% 4.9%',
131
+ muted: '210 40% 96.1%',
132
+ mutedForeground: '215.4 16.3% 46.9%',
133
+ destructive: '0 84.2% 60.2%',
134
+ destructiveForeground: '0 0% 100%',
135
+ border: '214.3 31.8% 91.4%',
136
+ input: '214.3 31.8% 91.4%',
137
+ ring: '339 89.6% 51%',
138
+ },
139
+ borderRadius: '1rem',
140
+ fontFamily: 'Poppins, system-ui, sans-serif',
141
+ },
142
+ };
143
+
144
+ /**
145
+ * UI Setup result
146
+ */
147
+ export interface UISetupResult {
148
+ success: boolean;
149
+ theme: string;
150
+ componentsInstalled: string[];
151
+ error?: string;
152
+ }
153
+
154
+ /**
155
+ * Generate globals.css with theme
156
+ */
157
+ function generateGlobalsCss(theme: DesignTheme): string {
158
+ return `@tailwind base;
159
+ @tailwind components;
160
+ @tailwind utilities;
161
+
162
+ @layer base {
163
+ :root {
164
+ --background: ${theme.colors.background};
165
+ --foreground: ${theme.colors.foreground};
166
+ --card: ${theme.colors.card};
167
+ --card-foreground: ${theme.colors.cardForeground};
168
+ --popover: ${theme.colors.card};
169
+ --popover-foreground: ${theme.colors.cardForeground};
170
+ --primary: ${theme.colors.primary};
171
+ --primary-foreground: ${theme.colors.primaryForeground};
172
+ --secondary: ${theme.colors.secondary};
173
+ --secondary-foreground: ${theme.colors.secondaryForeground};
174
+ --muted: ${theme.colors.muted};
175
+ --muted-foreground: ${theme.colors.mutedForeground};
176
+ --accent: ${theme.colors.accent};
177
+ --accent-foreground: ${theme.colors.accentForeground};
178
+ --destructive: ${theme.colors.destructive};
179
+ --destructive-foreground: ${theme.colors.destructiveForeground};
180
+ --border: ${theme.colors.border};
181
+ --input: ${theme.colors.input};
182
+ --ring: ${theme.colors.ring};
183
+ --radius: ${theme.borderRadius};
184
+ }
185
+
186
+ .dark {
187
+ --background: 222.2 84% 4.9%;
188
+ --foreground: 210 40% 98%;
189
+ --card: 222.2 84% 4.9%;
190
+ --card-foreground: 210 40% 98%;
191
+ --popover: 222.2 84% 4.9%;
192
+ --popover-foreground: 210 40% 98%;
193
+ --primary: ${theme.colors.primary};
194
+ --primary-foreground: ${theme.colors.primaryForeground};
195
+ --secondary: 217.2 32.6% 17.5%;
196
+ --secondary-foreground: 210 40% 98%;
197
+ --muted: 217.2 32.6% 17.5%;
198
+ --muted-foreground: 215 20.2% 65.1%;
199
+ --accent: 217.2 32.6% 17.5%;
200
+ --accent-foreground: 210 40% 98%;
201
+ --destructive: 0 62.8% 30.6%;
202
+ --destructive-foreground: 210 40% 98%;
203
+ --border: 217.2 32.6% 17.5%;
204
+ --input: 217.2 32.6% 17.5%;
205
+ --ring: ${theme.colors.ring};
206
+ }
207
+ }
208
+
209
+ @layer base {
210
+ * {
211
+ @apply border-border;
212
+ }
213
+
214
+ body {
215
+ @apply bg-background text-foreground;
216
+ font-family: ${theme.fontFamily};
217
+ }
218
+ }
219
+
220
+ /* Custom utility classes */
221
+ @layer utilities {
222
+ .text-balance {
223
+ text-wrap: balance;
224
+ }
225
+
226
+ .glass {
227
+ @apply bg-white/80 backdrop-blur-lg border border-white/20;
228
+ }
229
+
230
+ .glass-dark {
231
+ @apply bg-black/40 backdrop-blur-lg border border-white/10;
232
+ }
233
+ }
234
+
235
+ /* Animation utilities */
236
+ @layer utilities {
237
+ .animate-in {
238
+ animation: animateIn 0.3s ease-out;
239
+ }
240
+
241
+ .animate-out {
242
+ animation: animateOut 0.2s ease-in;
243
+ }
244
+
245
+ @keyframes animateIn {
246
+ from {
247
+ opacity: 0;
248
+ transform: translateY(-10px);
249
+ }
250
+ to {
251
+ opacity: 1;
252
+ transform: translateY(0);
253
+ }
254
+ }
255
+
256
+ @keyframes animateOut {
257
+ from {
258
+ opacity: 1;
259
+ transform: translateY(0);
260
+ }
261
+ to {
262
+ opacity: 0;
263
+ transform: translateY(-10px);
264
+ }
265
+ }
266
+ }
267
+ `;
268
+ }
269
+
270
+ /**
271
+ * Generate Tailwind config for shadcn
272
+ */
273
+ function generateTailwindConfig(theme: DesignTheme): string {
274
+ return `import type { Config } from "tailwindcss";
275
+
276
+ const config: Config = {
277
+ darkMode: ["class"],
278
+ content: [
279
+ "./index.html",
280
+ "./src/**/*.{js,ts,jsx,tsx}",
281
+ ],
282
+ theme: {
283
+ container: {
284
+ center: true,
285
+ padding: "2rem",
286
+ screens: {
287
+ "2xl": "1400px",
288
+ },
289
+ },
290
+ extend: {
291
+ fontFamily: {
292
+ sans: ["${theme.fontFamily.split(',')[0]}", "system-ui", "sans-serif"],
293
+ },
294
+ colors: {
295
+ border: "hsl(var(--border))",
296
+ input: "hsl(var(--input))",
297
+ ring: "hsl(var(--ring))",
298
+ background: "hsl(var(--background))",
299
+ foreground: "hsl(var(--foreground))",
300
+ primary: {
301
+ DEFAULT: "hsl(var(--primary))",
302
+ foreground: "hsl(var(--primary-foreground))",
303
+ },
304
+ secondary: {
305
+ DEFAULT: "hsl(var(--secondary))",
306
+ foreground: "hsl(var(--secondary-foreground))",
307
+ },
308
+ destructive: {
309
+ DEFAULT: "hsl(var(--destructive))",
310
+ foreground: "hsl(var(--destructive-foreground))",
311
+ },
312
+ muted: {
313
+ DEFAULT: "hsl(var(--muted))",
314
+ foreground: "hsl(var(--muted-foreground))",
315
+ },
316
+ accent: {
317
+ DEFAULT: "hsl(var(--accent))",
318
+ foreground: "hsl(var(--accent-foreground))",
319
+ },
320
+ popover: {
321
+ DEFAULT: "hsl(var(--popover))",
322
+ foreground: "hsl(var(--popover-foreground))",
323
+ },
324
+ card: {
325
+ DEFAULT: "hsl(var(--card))",
326
+ foreground: "hsl(var(--card-foreground))",
327
+ },
328
+ },
329
+ borderRadius: {
330
+ lg: "var(--radius)",
331
+ md: "calc(var(--radius) - 2px)",
332
+ sm: "calc(var(--radius) - 4px)",
333
+ },
334
+ keyframes: {
335
+ "accordion-down": {
336
+ from: { height: "0" },
337
+ to: { height: "var(--radix-accordion-content-height)" },
338
+ },
339
+ "accordion-up": {
340
+ from: { height: "var(--radix-accordion-content-height)" },
341
+ to: { height: "0" },
342
+ },
343
+ },
344
+ animation: {
345
+ "accordion-down": "accordion-down 0.2s ease-out",
346
+ "accordion-up": "accordion-up 0.2s ease-out",
347
+ },
348
+ },
349
+ },
350
+ plugins: [require("tailwindcss-animate")],
351
+ };
352
+
353
+ export default config;
354
+ `;
355
+ }
356
+
357
+ /**
358
+ * Components to install based on project type
359
+ */
360
+ const COMPONENT_SETS: Record<string, string[]> = {
361
+ dashboard: [
362
+ 'button', 'card', 'input', 'label', 'select', 'table', 'tabs',
363
+ 'dialog', 'dropdown-menu', 'avatar', 'badge', 'skeleton',
364
+ 'tooltip', 'separator', 'scroll-area', 'sheet', 'toast',
365
+ ],
366
+ kanban: [
367
+ 'button', 'card', 'input', 'label', 'select', 'dialog',
368
+ 'dropdown-menu', 'avatar', 'badge', 'skeleton', 'tooltip',
369
+ 'separator', 'scroll-area', 'sheet', 'toast', 'popover',
370
+ 'context-menu', 'command',
371
+ ],
372
+ ecommerce: [
373
+ 'button', 'card', 'input', 'label', 'select', 'dialog',
374
+ 'carousel', 'avatar', 'badge', 'skeleton', 'tooltip',
375
+ 'separator', 'scroll-area', 'sheet', 'toast', 'accordion',
376
+ 'tabs', 'slider',
377
+ ],
378
+ blog: [
379
+ 'button', 'card', 'input', 'label', 'textarea', 'dialog',
380
+ 'avatar', 'badge', 'skeleton', 'separator', 'scroll-area',
381
+ 'toast', 'navigation-menu',
382
+ ],
383
+ default: [
384
+ 'button', 'card', 'input', 'label', 'select', 'dialog',
385
+ 'dropdown-menu', 'avatar', 'badge', 'skeleton', 'tooltip',
386
+ 'separator', 'toast',
387
+ ],
388
+ };
389
+
390
+ /**
391
+ * Detect project type from idea/specification
392
+ */
393
+ export function detectProjectType(idea: string): string {
394
+ const lowerIdea = idea.toLowerCase();
395
+
396
+ if (lowerIdea.includes('kanban') || lowerIdea.includes('project manage') || lowerIdea.includes('task')) {
397
+ return 'kanban';
398
+ }
399
+ if (lowerIdea.includes('dashboard') || lowerIdea.includes('analytics') || lowerIdea.includes('admin')) {
400
+ return 'dashboard';
401
+ }
402
+ if (lowerIdea.includes('shop') || lowerIdea.includes('store') || lowerIdea.includes('ecommerce') || lowerIdea.includes('product')) {
403
+ return 'ecommerce';
404
+ }
405
+ if (lowerIdea.includes('blog') || lowerIdea.includes('article') || lowerIdea.includes('content')) {
406
+ return 'blog';
407
+ }
408
+
409
+ return 'default';
410
+ }
411
+
412
+ /**
413
+ * Setup complete UI system for a project
414
+ */
415
+ export async function setupUI(
416
+ projectDir: string,
417
+ options: {
418
+ theme?: string;
419
+ projectType?: string;
420
+ idea?: string;
421
+ } = {},
422
+ onProgress?: (message: string) => void
423
+ ): Promise<UISetupResult> {
424
+ const frontendDir = path.join(projectDir, 'packages', 'frontend');
425
+ const componentsInstalled: string[] = [];
426
+
427
+ try {
428
+ // Determine theme
429
+ const themeName = options.theme || 'modern';
430
+ const theme = THEMES[themeName] || THEMES.modern;
431
+ onProgress?.(`Using theme: ${theme.name}`);
432
+
433
+ // Determine project type
434
+ const projectType = options.projectType || (options.idea ? detectProjectType(options.idea) : 'default');
435
+ onProgress?.(`Detected project type: ${projectType}`);
436
+
437
+ // Check if frontend exists
438
+ const frontendExists = await fs.access(frontendDir).then(() => true).catch(() => false);
439
+ if (!frontendExists) {
440
+ return {
441
+ success: false,
442
+ theme: themeName,
443
+ componentsInstalled: [],
444
+ error: 'Frontend directory not found',
445
+ };
446
+ }
447
+
448
+ // Step 1: Install Tailwind and dependencies
449
+ onProgress?.('Installing Tailwind CSS and dependencies...');
450
+ await execAsync(
451
+ 'npm install -D tailwindcss postcss autoprefixer tailwindcss-animate @tailwindcss/postcss',
452
+ { cwd: frontendDir, timeout: 120000 }
453
+ );
454
+
455
+ // Step 2: Install shadcn/ui dependencies
456
+ onProgress?.('Installing UI component dependencies...');
457
+ await execAsync(
458
+ 'npm install class-variance-authority clsx tailwind-merge lucide-react @radix-ui/react-slot',
459
+ { cwd: frontendDir, timeout: 120000 }
460
+ );
461
+
462
+ // Step 3: Create lib/utils.ts
463
+ onProgress?.('Creating utility functions...');
464
+ const libDir = path.join(frontendDir, 'src', 'lib');
465
+ await fs.mkdir(libDir, { recursive: true });
466
+ await fs.writeFile(
467
+ path.join(libDir, 'utils.ts'),
468
+ `import { type ClassValue, clsx } from "clsx";
469
+ import { twMerge } from "tailwind-merge";
470
+
471
+ export function cn(...inputs: ClassValue[]) {
472
+ return twMerge(clsx(inputs));
473
+ }
474
+ `
475
+ );
476
+
477
+ // Step 4: Create Tailwind config
478
+ onProgress?.('Configuring Tailwind CSS...');
479
+ await fs.writeFile(
480
+ path.join(frontendDir, 'tailwind.config.ts'),
481
+ generateTailwindConfig(theme)
482
+ );
483
+
484
+ // Step 5: Create PostCSS config
485
+ await fs.writeFile(
486
+ path.join(frontendDir, 'postcss.config.js'),
487
+ `export default {
488
+ plugins: {
489
+ tailwindcss: {},
490
+ autoprefixer: {},
491
+ },
492
+ };
493
+ `
494
+ );
495
+
496
+ // Step 6: Create globals.css
497
+ onProgress?.('Setting up theme and styles...');
498
+ await fs.writeFile(
499
+ path.join(frontendDir, 'src', 'index.css'),
500
+ generateGlobalsCss(theme)
501
+ );
502
+
503
+ // Step 7: Create components directory structure
504
+ const componentsDir = path.join(frontendDir, 'src', 'components', 'ui');
505
+ await fs.mkdir(componentsDir, { recursive: true });
506
+
507
+ // Step 8: Install base components
508
+ const components = COMPONENT_SETS[projectType] || COMPONENT_SETS.default;
509
+ onProgress?.(`Installing ${components.length} UI components...`);
510
+
511
+ // Create button component (always needed)
512
+ await fs.writeFile(
513
+ path.join(componentsDir, 'button.tsx'),
514
+ generateButtonComponent()
515
+ );
516
+ componentsInstalled.push('button');
517
+
518
+ // Create card component
519
+ await fs.writeFile(
520
+ path.join(componentsDir, 'card.tsx'),
521
+ generateCardComponent()
522
+ );
523
+ componentsInstalled.push('card');
524
+
525
+ // Create input component
526
+ await fs.writeFile(
527
+ path.join(componentsDir, 'input.tsx'),
528
+ generateInputComponent()
529
+ );
530
+ componentsInstalled.push('input');
531
+
532
+ // Create badge component
533
+ await fs.writeFile(
534
+ path.join(componentsDir, 'badge.tsx'),
535
+ generateBadgeComponent()
536
+ );
537
+ componentsInstalled.push('badge');
538
+
539
+ // Create skeleton component
540
+ await fs.writeFile(
541
+ path.join(componentsDir, 'skeleton.tsx'),
542
+ generateSkeletonComponent()
543
+ );
544
+ componentsInstalled.push('skeleton');
545
+
546
+ // Step 9: Update main.tsx to import CSS
547
+ onProgress?.('Updating application entry point...');
548
+ const mainTsxPath = path.join(frontendDir, 'src', 'main.tsx');
549
+ let mainTsx = await fs.readFile(mainTsxPath, 'utf-8');
550
+
551
+ if (!mainTsx.includes("import './index.css'")) {
552
+ // Add CSS import at the top
553
+ mainTsx = `import './index.css';\n${mainTsx}`;
554
+ await fs.writeFile(mainTsxPath, mainTsx);
555
+ }
556
+
557
+ onProgress?.(`UI setup complete! Theme: ${theme.name}, Components: ${componentsInstalled.length}`);
558
+
559
+ return {
560
+ success: true,
561
+ theme: themeName,
562
+ componentsInstalled,
563
+ };
564
+ } catch (error) {
565
+ return {
566
+ success: false,
567
+ theme: options.theme || 'modern',
568
+ componentsInstalled,
569
+ error: error instanceof Error ? error.message : 'Unknown error',
570
+ };
571
+ }
572
+ }
573
+
574
+ // Component generators
575
+ function generateButtonComponent(): string {
576
+ return `import * as React from "react";
577
+ import { Slot } from "@radix-ui/react-slot";
578
+ import { cva, type VariantProps } from "class-variance-authority";
579
+ import { cn } from "@/lib/utils";
580
+
581
+ const buttonVariants = cva(
582
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
583
+ {
584
+ variants: {
585
+ variant: {
586
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
587
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
588
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
589
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
590
+ ghost: "hover:bg-accent hover:text-accent-foreground",
591
+ link: "text-primary underline-offset-4 hover:underline",
592
+ },
593
+ size: {
594
+ default: "h-10 px-4 py-2",
595
+ sm: "h-9 rounded-md px-3",
596
+ lg: "h-11 rounded-md px-8",
597
+ icon: "h-10 w-10",
598
+ },
599
+ },
600
+ defaultVariants: {
601
+ variant: "default",
602
+ size: "default",
603
+ },
604
+ }
605
+ );
606
+
607
+ export interface ButtonProps
608
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
609
+ VariantProps<typeof buttonVariants> {
610
+ asChild?: boolean;
611
+ }
612
+
613
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
614
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
615
+ const Comp = asChild ? Slot : "button";
616
+ return (
617
+ <Comp
618
+ className={cn(buttonVariants({ variant, size, className }))}
619
+ ref={ref}
620
+ {...props}
621
+ />
622
+ );
623
+ }
624
+ );
625
+ Button.displayName = "Button";
626
+
627
+ export { Button, buttonVariants };
628
+ `;
629
+ }
630
+
631
+ function generateCardComponent(): string {
632
+ return `import * as React from "react";
633
+ import { cn } from "@/lib/utils";
634
+
635
+ const Card = React.forwardRef<
636
+ HTMLDivElement,
637
+ React.HTMLAttributes<HTMLDivElement>
638
+ >(({ className, ...props }, ref) => (
639
+ <div
640
+ ref={ref}
641
+ className={cn(
642
+ "rounded-lg border bg-card text-card-foreground shadow-sm",
643
+ className
644
+ )}
645
+ {...props}
646
+ />
647
+ ));
648
+ Card.displayName = "Card";
649
+
650
+ const CardHeader = React.forwardRef<
651
+ HTMLDivElement,
652
+ React.HTMLAttributes<HTMLDivElement>
653
+ >(({ className, ...props }, ref) => (
654
+ <div
655
+ ref={ref}
656
+ className={cn("flex flex-col space-y-1.5 p-6", className)}
657
+ {...props}
658
+ />
659
+ ));
660
+ CardHeader.displayName = "CardHeader";
661
+
662
+ const CardTitle = React.forwardRef<
663
+ HTMLParagraphElement,
664
+ React.HTMLAttributes<HTMLHeadingElement>
665
+ >(({ className, ...props }, ref) => (
666
+ <h3
667
+ ref={ref}
668
+ className={cn(
669
+ "text-2xl font-semibold leading-none tracking-tight",
670
+ className
671
+ )}
672
+ {...props}
673
+ />
674
+ ));
675
+ CardTitle.displayName = "CardTitle";
676
+
677
+ const CardDescription = React.forwardRef<
678
+ HTMLParagraphElement,
679
+ React.HTMLAttributes<HTMLParagraphElement>
680
+ >(({ className, ...props }, ref) => (
681
+ <p
682
+ ref={ref}
683
+ className={cn("text-sm text-muted-foreground", className)}
684
+ {...props}
685
+ />
686
+ ));
687
+ CardDescription.displayName = "CardDescription";
688
+
689
+ const CardContent = React.forwardRef<
690
+ HTMLDivElement,
691
+ React.HTMLAttributes<HTMLDivElement>
692
+ >(({ className, ...props }, ref) => (
693
+ <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
694
+ ));
695
+ CardContent.displayName = "CardContent";
696
+
697
+ const CardFooter = React.forwardRef<
698
+ HTMLDivElement,
699
+ React.HTMLAttributes<HTMLDivElement>
700
+ >(({ className, ...props }, ref) => (
701
+ <div
702
+ ref={ref}
703
+ className={cn("flex items-center p-6 pt-0", className)}
704
+ {...props}
705
+ />
706
+ ));
707
+ CardFooter.displayName = "CardFooter";
708
+
709
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
710
+ `;
711
+ }
712
+
713
+ function generateInputComponent(): string {
714
+ return `import * as React from "react";
715
+ import { cn } from "@/lib/utils";
716
+
717
+ export interface InputProps
718
+ extends React.InputHTMLAttributes<HTMLInputElement> {}
719
+
720
+ const Input = React.forwardRef<HTMLInputElement, InputProps>(
721
+ ({ className, type, ...props }, ref) => {
722
+ return (
723
+ <input
724
+ type={type}
725
+ className={cn(
726
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
727
+ className
728
+ )}
729
+ ref={ref}
730
+ {...props}
731
+ />
732
+ );
733
+ }
734
+ );
735
+ Input.displayName = "Input";
736
+
737
+ export { Input };
738
+ `;
739
+ }
740
+
741
+ function generateBadgeComponent(): string {
742
+ return `import * as React from "react";
743
+ import { cva, type VariantProps } from "class-variance-authority";
744
+ import { cn } from "@/lib/utils";
745
+
746
+ const badgeVariants = cva(
747
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
748
+ {
749
+ variants: {
750
+ variant: {
751
+ default:
752
+ "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
753
+ secondary:
754
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
755
+ destructive:
756
+ "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
757
+ outline: "text-foreground",
758
+ },
759
+ },
760
+ defaultVariants: {
761
+ variant: "default",
762
+ },
763
+ }
764
+ );
765
+
766
+ export interface BadgeProps
767
+ extends React.HTMLAttributes<HTMLDivElement>,
768
+ VariantProps<typeof badgeVariants> {}
769
+
770
+ function Badge({ className, variant, ...props }: BadgeProps) {
771
+ return (
772
+ <div className={cn(badgeVariants({ variant }), className)} {...props} />
773
+ );
774
+ }
775
+
776
+ export { Badge, badgeVariants };
777
+ `;
778
+ }
779
+
780
+ function generateSkeletonComponent(): string {
781
+ return `import { cn } from "@/lib/utils";
782
+
783
+ function Skeleton({
784
+ className,
785
+ ...props
786
+ }: React.HTMLAttributes<HTMLDivElement>) {
787
+ return (
788
+ <div
789
+ className={cn("animate-pulse rounded-md bg-muted", className)}
790
+ {...props}
791
+ />
792
+ );
793
+ }
794
+
795
+ export { Skeleton };
796
+ `;
797
+ }