codebakers 2.5.4 → 3.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 (60) hide show
  1. package/README.md +54 -255
  2. package/dist/chunk-HOWR3YTF.js +146 -0
  3. package/dist/index.d.ts +0 -3
  4. package/dist/index.js +10488 -7993
  5. package/dist/terminal-6ZQVP6R7.js +10 -0
  6. package/package.json +26 -41
  7. package/AUDIT_REPORT.md +0 -138
  8. package/dist/advisors-RWRTSJRR.js +0 -7
  9. package/dist/chunk-ASIJIQYC.js +0 -320
  10. package/dist/chunk-D44U3IEA.js +0 -565
  11. package/dist/chunk-LANM5XQW.js +0 -326
  12. package/dist/prd-RYITSL6Q.js +0 -7
  13. package/install.bat +0 -9
  14. package/installers/CodeBakers-Install.bat +0 -207
  15. package/installers/CodeBakers-Install.command +0 -232
  16. package/installers/README.md +0 -157
  17. package/installers/mac/assets/README.txt +0 -31
  18. package/installers/mac/build-mac-installer.sh +0 -240
  19. package/installers/windows/CodeBakers.iss +0 -256
  20. package/installers/windows/assets/README.txt +0 -16
  21. package/installers/windows/scripts/post-install.bat +0 -15
  22. package/src/channels/discord.ts +0 -5
  23. package/src/channels/slack.ts +0 -5
  24. package/src/channels/sms.ts +0 -4
  25. package/src/channels/telegram.ts +0 -5
  26. package/src/channels/whatsapp.ts +0 -7
  27. package/src/commands/advisors.ts +0 -699
  28. package/src/commands/build.ts +0 -1025
  29. package/src/commands/check.ts +0 -365
  30. package/src/commands/code.ts +0 -806
  31. package/src/commands/connect.ts +0 -12
  32. package/src/commands/deploy.ts +0 -448
  33. package/src/commands/design.ts +0 -298
  34. package/src/commands/fix.ts +0 -20
  35. package/src/commands/gateway.ts +0 -604
  36. package/src/commands/generate.ts +0 -178
  37. package/src/commands/init.ts +0 -634
  38. package/src/commands/integrate.ts +0 -884
  39. package/src/commands/learn.ts +0 -36
  40. package/src/commands/migrate.ts +0 -419
  41. package/src/commands/prd-maker.ts +0 -588
  42. package/src/commands/prd.ts +0 -419
  43. package/src/commands/security.ts +0 -102
  44. package/src/commands/setup.ts +0 -600
  45. package/src/commands/status.ts +0 -56
  46. package/src/commands/website.ts +0 -741
  47. package/src/index.ts +0 -627
  48. package/src/patterns/loader.ts +0 -337
  49. package/src/services/github.ts +0 -61
  50. package/src/services/supabase.ts +0 -147
  51. package/src/services/vercel.ts +0 -61
  52. package/src/utils/claude-md.ts +0 -287
  53. package/src/utils/config.ts +0 -375
  54. package/src/utils/display.ts +0 -338
  55. package/src/utils/files.ts +0 -418
  56. package/src/utils/nlp.ts +0 -312
  57. package/src/utils/ui.ts +0 -441
  58. package/src/utils/updates.ts +0 -8
  59. package/src/utils/voice.ts +0 -323
  60. package/tsconfig.json +0 -26
@@ -1,741 +0,0 @@
1
- import * as p from '@clack/prompts';
2
- import chalk from 'chalk';
3
- import fs from 'fs-extra';
4
- import * as path from 'path';
5
- import Anthropic from '@anthropic-ai/sdk';
6
- import { execa } from 'execa';
7
- import { Config } from '../utils/config.js';
8
- import { textWithVoice } from '../utils/voice.js';
9
- import { StepTracker, showError, showSuccess, showFileList, ERRORS } from '../utils/display.js';
10
- import {
11
- showMiniLogo,
12
- box,
13
- doubleBox,
14
- sectionHeader,
15
- showSuccessScreen,
16
- showErrorScreen,
17
- showFileTree,
18
- colors
19
- } from '../utils/ui.js';
20
-
21
- // ============================================================================
22
- // WEBSITE TEMPLATES
23
- // ============================================================================
24
-
25
- interface WebsiteTemplate {
26
- id: string;
27
- name: string;
28
- description: string;
29
- icon: string;
30
- sections: string[];
31
- style: 'minimal' | 'bold' | 'elegant' | 'playful' | 'corporate';
32
- }
33
-
34
- const TEMPLATES: WebsiteTemplate[] = [
35
- {
36
- id: 'landing',
37
- name: 'Landing Page',
38
- description: 'Convert visitors into customers',
39
- icon: '🚀',
40
- sections: ['hero', 'features', 'testimonials', 'pricing', 'cta', 'footer'],
41
- style: 'bold',
42
- },
43
- {
44
- id: 'saas',
45
- name: 'SaaS Website',
46
- description: 'Software product marketing site',
47
- icon: '💻',
48
- sections: ['hero', 'features', 'how-it-works', 'pricing', 'faq', 'testimonials', 'cta', 'footer'],
49
- style: 'minimal',
50
- },
51
- {
52
- id: 'portfolio',
53
- name: 'Portfolio',
54
- description: 'Showcase your work',
55
- icon: '🎨',
56
- sections: ['hero', 'about', 'projects', 'skills', 'contact', 'footer'],
57
- style: 'elegant',
58
- },
59
- {
60
- id: 'agency',
61
- name: 'Agency Website',
62
- description: 'Professional services company',
63
- icon: '🏢',
64
- sections: ['hero', 'services', 'portfolio', 'team', 'testimonials', 'contact', 'footer'],
65
- style: 'corporate',
66
- },
67
- {
68
- id: 'startup',
69
- name: 'Startup Page',
70
- description: 'Early stage company',
71
- icon: '⚡',
72
- sections: ['hero', 'problem', 'solution', 'features', 'team', 'waitlist', 'footer'],
73
- style: 'bold',
74
- },
75
- {
76
- id: 'restaurant',
77
- name: 'Restaurant',
78
- description: 'Food & dining establishment',
79
- icon: '🍽️',
80
- sections: ['hero', 'menu', 'about', 'gallery', 'reservations', 'location', 'footer'],
81
- style: 'elegant',
82
- },
83
- {
84
- id: 'ecommerce',
85
- name: 'E-commerce',
86
- description: 'Online store',
87
- icon: '🛒',
88
- sections: ['hero', 'featured-products', 'categories', 'bestsellers', 'newsletter', 'footer'],
89
- style: 'minimal',
90
- },
91
- {
92
- id: 'blog',
93
- name: 'Blog',
94
- description: 'Content & articles',
95
- icon: '📝',
96
- sections: ['hero', 'featured-posts', 'categories', 'newsletter', 'about', 'footer'],
97
- style: 'minimal',
98
- },
99
- {
100
- id: 'event',
101
- name: 'Event Page',
102
- description: 'Conference or meetup',
103
- icon: '🎉',
104
- sections: ['hero', 'speakers', 'schedule', 'venue', 'sponsors', 'tickets', 'footer'],
105
- style: 'bold',
106
- },
107
- {
108
- id: 'nonprofit',
109
- name: 'Nonprofit',
110
- description: 'Charity or cause',
111
- icon: '💚',
112
- sections: ['hero', 'mission', 'impact', 'programs', 'donate', 'volunteer', 'footer'],
113
- style: 'elegant',
114
- },
115
- {
116
- id: 'personal',
117
- name: 'Personal Website',
118
- description: 'Your online presence',
119
- icon: '👤',
120
- sections: ['hero', 'about', 'experience', 'projects', 'blog', 'contact', 'footer'],
121
- style: 'minimal',
122
- },
123
- {
124
- id: 'coming-soon',
125
- name: 'Coming Soon',
126
- description: 'Pre-launch teaser',
127
- icon: '⏳',
128
- sections: ['hero', 'countdown', 'features-preview', 'waitlist', 'footer'],
129
- style: 'bold',
130
- },
131
- {
132
- id: 'custom',
133
- name: 'Custom',
134
- description: 'Build from scratch with AI',
135
- icon: '✨',
136
- sections: [],
137
- style: 'minimal',
138
- },
139
- ];
140
-
141
- // ============================================================================
142
- // MAIN COMMAND
143
- // ============================================================================
144
-
145
- export async function websiteCommand(): Promise<void> {
146
- const config = new Config();
147
-
148
- if (!config.isConfigured()) {
149
- showErrorScreen({
150
- title: 'CodeBakers not configured',
151
- message: 'Run setup first to connect your API keys.',
152
- command: 'codebakers setup',
153
- });
154
- return;
155
- }
156
-
157
- const anthropicCreds = config.getCredentials('anthropic');
158
- if (!anthropicCreds?.apiKey) {
159
- showErrorScreen({
160
- title: 'Anthropic API key not configured',
161
- message: 'The website builder needs Claude AI to generate code.',
162
- fixes: [
163
- 'Run: codebakers setup',
164
- 'Get an API key at: console.anthropic.com',
165
- ],
166
- command: 'codebakers setup',
167
- });
168
- return;
169
- }
170
-
171
- console.clear();
172
- showMiniLogo();
173
-
174
- doubleBox([
175
- colors.primary('🌐 WEBSITE BUILDER'),
176
- '',
177
- colors.white('Describe your website in plain English.'),
178
- colors.muted('AI builds it in minutes.'),
179
- ]);
180
-
181
- // Step 1: Choose approach
182
- const approach = await p.select({
183
- message: 'How would you like to build your website?',
184
- options: [
185
- { value: 'describe', label: '💬 Describe it', hint: 'Tell me what you want in plain English' },
186
- { value: 'template', label: '📋 Start from template', hint: 'Choose a pre-made structure' },
187
- { value: 'url', label: '🔗 Clone a design', hint: 'Describe a site you like' },
188
- ],
189
- });
190
-
191
- if (p.isCancel(approach)) return;
192
-
193
- const anthropic = new Anthropic({ apiKey: anthropicCreds.apiKey });
194
- let websiteSpec: WebsiteSpec;
195
-
196
- if (approach === 'describe') {
197
- websiteSpec = await describeWebsite(anthropic);
198
- } else if (approach === 'template') {
199
- websiteSpec = await templateWebsite(anthropic);
200
- } else {
201
- websiteSpec = await cloneDesign(anthropic);
202
- }
203
-
204
- if (!websiteSpec) return;
205
-
206
- // Step 2: Confirm spec
207
- console.log(chalk.cyan(`\n 📋 Website Plan:\n`));
208
- console.log(chalk.bold(` ${websiteSpec.name}`));
209
- console.log(chalk.dim(` ${websiteSpec.description}\n`));
210
- console.log(chalk.dim(` Style: ${websiteSpec.style}`));
211
- console.log(chalk.dim(` Sections: ${websiteSpec.sections.join(', ')}\n`));
212
-
213
- const confirm = await p.confirm({
214
- message: 'Build this website?',
215
- initialValue: true,
216
- });
217
-
218
- if (!confirm || p.isCancel(confirm)) return;
219
-
220
- // Step 3: Build it
221
- await buildWebsite(anthropic, websiteSpec, config);
222
- }
223
-
224
- // ============================================================================
225
- // TYPES
226
- // ============================================================================
227
-
228
- interface WebsiteSpec {
229
- name: string;
230
- description: string;
231
- style: string;
232
- colorScheme: {
233
- primary: string;
234
- secondary: string;
235
- accent: string;
236
- background: string;
237
- text: string;
238
- };
239
- sections: string[];
240
- content: Record<string, any>;
241
- features: string[];
242
- }
243
-
244
- // ============================================================================
245
- // DESCRIBE WEBSITE
246
- // ============================================================================
247
-
248
- async function describeWebsite(anthropic: Anthropic): Promise<WebsiteSpec | null> {
249
- console.log(chalk.dim('\n Describe your website. Be as detailed as you want.\n'));
250
- console.log(chalk.dim(' Examples:'));
251
- console.log(chalk.dim(' • "A landing page for my AI writing tool called WriteBot"'));
252
- console.log(chalk.dim(' • "Portfolio site for a photographer, dark theme, minimal"'));
253
- console.log(chalk.dim(' • "Coffee shop website with menu, location, and online ordering"\n'));
254
-
255
- const description = await textWithVoice({
256
- message: 'Describe your website:',
257
- placeholder: 'A landing page for...',
258
- });
259
-
260
- if (p.isCancel(description)) return null;
261
-
262
- const spinner = p.spinner();
263
- spinner.start('Understanding your vision...');
264
-
265
- const response = await anthropic.messages.create({
266
- model: 'claude-sonnet-4-5-20250929',
267
- max_tokens: 2048,
268
- messages: [{
269
- role: 'user',
270
- content: `Based on this website description, create a detailed specification.
271
-
272
- Description: "${description}"
273
-
274
- Return JSON only:
275
- {
276
- "name": "Project name (kebab-case)",
277
- "description": "One line description",
278
- "style": "minimal | bold | elegant | playful | corporate",
279
- "colorScheme": {
280
- "primary": "#hex",
281
- "secondary": "#hex",
282
- "accent": "#hex",
283
- "background": "#hex",
284
- "text": "#hex"
285
- },
286
- "sections": ["hero", "features", ...],
287
- "content": {
288
- "hero": {
289
- "headline": "...",
290
- "subheadline": "...",
291
- "cta": "..."
292
- },
293
- "features": [
294
- { "title": "...", "description": "...", "icon": "..." }
295
- ]
296
- // etc for each section
297
- },
298
- "features": ["responsive", "dark-mode", "animations", etc]
299
- }
300
-
301
- Make the content compelling and professional. Use appropriate sections for the type of website.`
302
- }],
303
- });
304
-
305
- spinner.stop('Got it!');
306
-
307
- const text = response.content[0].type === 'text' ? response.content[0].text : '';
308
- const jsonMatch = text.match(/\{[\s\S]*\}/);
309
-
310
- if (!jsonMatch) {
311
- p.log.error('Failed to understand website description');
312
- return null;
313
- }
314
-
315
- return JSON.parse(jsonMatch[0]);
316
- }
317
-
318
- // ============================================================================
319
- // TEMPLATE WEBSITE
320
- // ============================================================================
321
-
322
- async function templateWebsite(anthropic: Anthropic): Promise<WebsiteSpec | null> {
323
- const template = await p.select({
324
- message: 'Choose a template:',
325
- options: TEMPLATES.map(t => ({
326
- value: t.id,
327
- label: `${t.icon} ${t.name}`,
328
- hint: t.description,
329
- })),
330
- });
331
-
332
- if (p.isCancel(template)) return null;
333
-
334
- const selectedTemplate = TEMPLATES.find(t => t.id === template)!;
335
-
336
- // Get customization details
337
- const name = await p.text({
338
- message: 'What is your business/project name?',
339
- placeholder: 'My Awesome Project',
340
- });
341
-
342
- if (p.isCancel(name)) return null;
343
-
344
- const tagline = await p.text({
345
- message: 'Tagline or one-line description:',
346
- placeholder: 'The best solution for...',
347
- });
348
-
349
- if (p.isCancel(tagline)) return null;
350
-
351
- const details = await textWithVoice({
352
- message: 'Any other details? (or press enter to skip)',
353
- placeholder: 'We help startups with..., Our colors are blue and white...',
354
- });
355
-
356
- if (p.isCancel(details)) return null;
357
-
358
- const spinner = p.spinner();
359
- spinner.start('Customizing template...');
360
-
361
- const response = await anthropic.messages.create({
362
- model: 'claude-sonnet-4-5-20250929',
363
- max_tokens: 2048,
364
- messages: [{
365
- role: 'user',
366
- content: `Create a website spec based on this template and customization.
367
-
368
- Template: ${selectedTemplate.name}
369
- Sections: ${selectedTemplate.sections.join(', ')}
370
- Default Style: ${selectedTemplate.style}
371
-
372
- Business Name: ${name}
373
- Tagline: ${tagline}
374
- Additional Details: ${details || 'None provided'}
375
-
376
- Return JSON only:
377
- {
378
- "name": "project-name-kebab",
379
- "description": "${tagline}",
380
- "style": "${selectedTemplate.style}",
381
- "colorScheme": {
382
- "primary": "#hex",
383
- "secondary": "#hex",
384
- "accent": "#hex",
385
- "background": "#hex",
386
- "text": "#hex"
387
- },
388
- "sections": ${JSON.stringify(selectedTemplate.sections)},
389
- "content": {
390
- // Content for each section, tailored to the business
391
- },
392
- "features": ["responsive", "dark-mode", etc]
393
- }
394
-
395
- Make the content specific and compelling for this business.`
396
- }],
397
- });
398
-
399
- spinner.stop('Template customized!');
400
-
401
- const text = response.content[0].type === 'text' ? response.content[0].text : '';
402
- const jsonMatch = text.match(/\{[\s\S]*\}/);
403
-
404
- if (!jsonMatch) {
405
- p.log.error('Failed to customize template');
406
- return null;
407
- }
408
-
409
- return JSON.parse(jsonMatch[0]);
410
- }
411
-
412
- // ============================================================================
413
- // CLONE DESIGN
414
- // ============================================================================
415
-
416
- async function cloneDesign(anthropic: Anthropic): Promise<WebsiteSpec | null> {
417
- console.log(chalk.dim('\n Describe a website design you like.\n'));
418
- console.log(chalk.dim(' Examples:'));
419
- console.log(chalk.dim(' • "Like Linear.app - minimal, clean, dark mode"'));
420
- console.log(chalk.dim(' • "Like Stripe - professional, lots of gradients"'));
421
- console.log(chalk.dim(' • "Like Notion - simple, friendly, illustrated"\n'));
422
-
423
- const inspiration = await textWithVoice({
424
- message: 'What site do you want to be inspired by?',
425
- placeholder: 'Like Linear.app but for...',
426
- });
427
-
428
- if (p.isCancel(inspiration)) return null;
429
-
430
- const purpose = await p.text({
431
- message: 'What is YOUR website for?',
432
- placeholder: 'A project management tool for designers',
433
- });
434
-
435
- if (p.isCancel(purpose)) return null;
436
-
437
- const spinner = p.spinner();
438
- spinner.start('Analyzing design inspiration...');
439
-
440
- const response = await anthropic.messages.create({
441
- model: 'claude-sonnet-4-5-20250929',
442
- max_tokens: 2048,
443
- messages: [{
444
- role: 'user',
445
- content: `Create a website spec inspired by another site's design.
446
-
447
- Inspiration: "${inspiration}"
448
- Purpose: "${purpose}"
449
-
450
- Analyze the design style of the inspiration (based on your knowledge of popular websites) and create a spec that captures that aesthetic for this new purpose.
451
-
452
- Return JSON only:
453
- {
454
- "name": "project-name-kebab",
455
- "description": "One line description",
456
- "style": "minimal | bold | elegant | playful | corporate",
457
- "colorScheme": {
458
- "primary": "#hex - inspired by the reference",
459
- "secondary": "#hex",
460
- "accent": "#hex",
461
- "background": "#hex",
462
- "text": "#hex"
463
- },
464
- "sections": ["appropriate sections for the purpose"],
465
- "content": {
466
- // Compelling content for each section
467
- },
468
- "features": ["responsive", "dark-mode", "animations", "gradients", etc - based on inspiration]
469
- }
470
-
471
- Capture the FEEL of the inspiration but make it original.`
472
- }],
473
- });
474
-
475
- spinner.stop('Design analyzed!');
476
-
477
- const text = response.content[0].type === 'text' ? response.content[0].text : '';
478
- const jsonMatch = text.match(/\{[\s\S]*\}/);
479
-
480
- if (!jsonMatch) {
481
- p.log.error('Failed to analyze design');
482
- return null;
483
- }
484
-
485
- return JSON.parse(jsonMatch[0]);
486
- }
487
-
488
- // ============================================================================
489
- // BUILD WEBSITE
490
- // ============================================================================
491
-
492
- async function buildWebsite(
493
- anthropic: Anthropic,
494
- spec: WebsiteSpec,
495
- config: Config
496
- ): Promise<void> {
497
- const projectPath = path.join(process.cwd(), spec.name);
498
-
499
- // Check if exists
500
- if (await fs.pathExists(projectPath)) {
501
- const overwrite = await p.confirm({
502
- message: `${spec.name} already exists. Overwrite?`,
503
- initialValue: false,
504
- });
505
- if (!overwrite || p.isCancel(overwrite)) return;
506
- await fs.remove(projectPath);
507
- }
508
-
509
- console.log(chalk.cyan(`\n 🏗️ Building ${chalk.bold(spec.name)}\n`));
510
-
511
- // Initialize step tracker
512
- const steps = new StepTracker([
513
- 'Create project structure',
514
- 'Install dependencies',
515
- 'Set up UI components',
516
- 'Generate website code',
517
- 'Create additional pages',
518
- 'Initialize git repository',
519
- ]);
520
-
521
- const createdFiles: string[] = [];
522
-
523
- // Step 1: Create project
524
- steps.start();
525
-
526
- try {
527
- await execa('npx', [
528
- 'create-next-app@latest',
529
- spec.name,
530
- '--typescript',
531
- '--tailwind',
532
- '--eslint',
533
- '--app',
534
- '--src-dir',
535
- '--import-alias', '@/*',
536
- '--no-git',
537
- '--yes',
538
- ], {
539
- cwd: process.cwd(),
540
- stdio: 'pipe', // Hide output for cleaner display
541
- });
542
- steps.complete();
543
- } catch (error) {
544
- steps.error();
545
- showError({
546
- title: 'Project creation failed',
547
- message: 'create-next-app could not complete',
548
- fixes: [
549
- 'Make sure Node.js 18+ is installed',
550
- 'Check your internet connection',
551
- 'Try running manually: npx create-next-app@latest ' + spec.name,
552
- ],
553
- command: 'npx create-next-app@latest ' + spec.name,
554
- });
555
- return;
556
- }
557
-
558
- // Verify project was created
559
- if (!(await fs.pathExists(projectPath))) {
560
- steps.error();
561
- showError({
562
- title: 'Project folder not created',
563
- message: 'The project directory was not found after creation',
564
- fixes: [
565
- 'Check if you have write permissions in this folder',
566
- 'Try creating the project in a different location',
567
- ],
568
- });
569
- return;
570
- }
571
-
572
- // Step 2: Install dependencies
573
- steps.start();
574
-
575
- try {
576
- await execa('npm', ['install', 'lucide-react'], {
577
- cwd: projectPath,
578
- stdio: 'pipe',
579
- });
580
- steps.complete();
581
- } catch (error) {
582
- steps.error();
583
- showError({
584
- ...ERRORS.npmFailed,
585
- command: `cd ${spec.name} && npm install`,
586
- });
587
- return;
588
- }
589
-
590
- // Step 3: Install shadcn
591
- steps.start();
592
-
593
- try {
594
- await execa('npx', ['shadcn@latest', 'init', '-y', '-d'], {
595
- cwd: projectPath,
596
- stdio: 'pipe',
597
- });
598
-
599
- await execa('npx', ['shadcn@latest', 'add', 'button', 'card', 'input', 'badge', '-y'], {
600
- cwd: projectPath,
601
- stdio: 'pipe',
602
- });
603
- steps.complete();
604
- } catch (error) {
605
- steps.skip(); // Not critical, continue anyway
606
- }
607
-
608
- // Step 4: Generate pages
609
- steps.start();
610
-
611
- const response = await anthropic.messages.create({
612
- model: 'claude-sonnet-4-5-20250929',
613
- max_tokens: 16000,
614
- messages: [{
615
- role: 'user',
616
- content: `Generate a complete Next.js website based on this specification.
617
-
618
- Website Spec:
619
- ${JSON.stringify(spec, null, 2)}
620
-
621
- Generate these files:
622
-
623
- 1. src/app/page.tsx - Main landing page with ALL sections
624
- 2. src/app/layout.tsx - Root layout with fonts, metadata
625
- 3. src/app/globals.css - Tailwind config with custom colors
626
- 4. src/components/sections/Hero.tsx
627
- 5. src/components/sections/[OtherSections].tsx - One for each section
628
- 6. src/components/ui/Navbar.tsx
629
- 7. src/components/ui/Footer.tsx
630
- 8. tailwind.config.ts - With custom colors from colorScheme
631
-
632
- Requirements:
633
- - Use TypeScript
634
- - Use Tailwind CSS for styling
635
- - Use shadcn/ui components (Button, Card, Input, Badge)
636
- - Make it responsive (mobile-first)
637
- - Add smooth scroll behavior
638
- - Use modern design patterns
639
- - Include hover effects and transitions
640
- - Use Lucide icons where appropriate
641
-
642
- Color scheme to use:
643
- - Primary: ${spec.colorScheme.primary}
644
- - Secondary: ${spec.colorScheme.secondary}
645
- - Accent: ${spec.colorScheme.accent}
646
- - Background: ${spec.colorScheme.background}
647
- - Text: ${spec.colorScheme.text}
648
-
649
- Style: ${spec.style}
650
- ${spec.style === 'minimal' ? 'Clean, lots of whitespace, simple' : ''}
651
- ${spec.style === 'bold' ? 'Strong colors, big typography, impactful' : ''}
652
- ${spec.style === 'elegant' ? 'Refined, sophisticated, subtle animations' : ''}
653
- ${spec.style === 'playful' ? 'Fun, colorful, friendly illustrations' : ''}
654
- ${spec.style === 'corporate' ? 'Professional, trustworthy, structured' : ''}
655
-
656
- Output format:
657
- <<<FILE: path/to/file.tsx>>>
658
- content
659
- <<<END_FILE>>>
660
-
661
- Make it production-quality and visually impressive.`
662
- }],
663
- });
664
-
665
- const text = response.content[0].type === 'text' ? response.content[0].text : '';
666
-
667
- // Write files
668
- const fileRegex = /<<<FILE:\s*(.+?)>>>([\s\S]*?)<<<END_FILE>>>/g;
669
- let match;
670
-
671
- while ((match = fileRegex.exec(text)) !== null) {
672
- const filePath = path.join(projectPath, match[1].trim());
673
- const content = match[2].trim();
674
-
675
- await fs.ensureDir(path.dirname(filePath));
676
- await fs.writeFile(filePath, content);
677
- createdFiles.push(match[1].trim());
678
- }
679
-
680
- steps.complete();
681
-
682
- // Step 5: Additional pages (placeholder for now)
683
- steps.start();
684
- steps.complete();
685
-
686
- // Step 6: Git init
687
- steps.start();
688
-
689
- try {
690
- await execa('git', ['init'], { cwd: projectPath, stdio: 'pipe' });
691
- await execa('git', ['add', '.'], { cwd: projectPath, stdio: 'pipe' });
692
- await execa('git', ['commit', '-m', 'Initial website build by CodeBakers'], { cwd: projectPath, stdio: 'pipe' });
693
- steps.complete();
694
- } catch (error) {
695
- steps.skip();
696
- }
697
-
698
- // Show created files
699
- if (createdFiles.length > 0) {
700
- showFileTree('Files created', createdFiles.slice(0, 10));
701
- if (createdFiles.length > 10) {
702
- console.log(colors.muted(` ... and ${createdFiles.length - 10} more files`));
703
- }
704
- }
705
-
706
- // Success message with beautiful screen
707
- showSuccessScreen({
708
- title: 'Website built successfully!',
709
- message: spec.description,
710
- stats: [
711
- { label: 'Project', value: spec.name },
712
- { label: 'Files', value: createdFiles.length.toString() + ' created' },
713
- { label: 'Sections', value: spec.sections.length.toString() },
714
- { label: 'Time', value: steps.getElapsedTime() },
715
- ],
716
- nextSteps: [
717
- `cd ${spec.name}`,
718
- 'npm run dev',
719
- ],
720
- command: `cd ${spec.name} && npm run dev`,
721
- });
722
-
723
- // Offer to open in browser
724
- const openDev = await p.confirm({
725
- message: 'Start development server now?',
726
- initialValue: true,
727
- });
728
-
729
- if (openDev && !p.isCancel(openDev)) {
730
- console.log(colors.muted('\n Starting dev server...\n'));
731
-
732
- // Change to project directory and run dev
733
- process.chdir(projectPath);
734
- await execa('npm', ['run', 'dev'], {
735
- stdio: 'inherit',
736
- reject: false,
737
- });
738
- }
739
- }
740
-
741
- export { TEMPLATES };