codebakers 2.3.8 → 2.5.3

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.
@@ -1,11 +1,22 @@
1
1
  import * as p from '@clack/prompts';
2
2
  import chalk from 'chalk';
3
- import * as fs from 'fs-extra';
3
+ import fs from 'fs-extra';
4
4
  import * as path from 'path';
5
5
  import Anthropic from '@anthropic-ai/sdk';
6
6
  import { execa } from 'execa';
7
7
  import { Config } from '../utils/config.js';
8
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';
9
20
 
10
21
  // ============================================================================
11
22
  // WEBSITE TEMPLATES
@@ -135,39 +146,37 @@ export async function websiteCommand(): Promise<void> {
135
146
  const config = new Config();
136
147
 
137
148
  if (!config.isConfigured()) {
138
- console.log(chalk.yellow(`
139
- ⚠️ CodeBakers isn't set up yet.
140
-
141
- Run this first:
142
- ${chalk.cyan('codebakers setup')}
143
- `));
149
+ showErrorScreen({
150
+ title: 'CodeBakers not configured',
151
+ message: 'Run setup first to connect your API keys.',
152
+ command: 'codebakers setup',
153
+ });
144
154
  return;
145
155
  }
146
156
 
147
157
  const anthropicCreds = config.getCredentials('anthropic');
148
158
  if (!anthropicCreds?.apiKey) {
149
- console.log(chalk.yellow(`
150
- ⚠️ Anthropic API key not configured.
151
-
152
- The website builder needs Claude AI to generate code.
153
-
154
- Run this to add your API key:
155
- ${chalk.cyan('codebakers setup')}
156
-
157
- Get an API key at:
158
- ${chalk.dim('https://console.anthropic.com/settings/keys')}
159
- `));
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
+ });
160
168
  return;
161
169
  }
162
170
 
163
- console.log(chalk.cyan(`
164
- ╔═══════════════════════════════════════════════════════════════╗
165
- 🌐 WEBSITE BUILDER ║
166
- ║ ║
167
- ║ Describe your website in plain English. ║
168
- ║ AI builds it in minutes. ║
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
+ ]);
171
180
 
172
181
  // Step 1: Choose approach
173
182
  const approach = await p.select({
@@ -254,7 +263,7 @@ async function describeWebsite(anthropic: Anthropic): Promise<WebsiteSpec | null
254
263
  spinner.start('Understanding your vision...');
255
264
 
256
265
  const response = await anthropic.messages.create({
257
- model: 'claude-sonnet-4-20250514',
266
+ model: 'claude-sonnet-4-5-20250929',
258
267
  max_tokens: 2048,
259
268
  messages: [{
260
269
  role: 'user',
@@ -350,7 +359,7 @@ async function templateWebsite(anthropic: Anthropic): Promise<WebsiteSpec | null
350
359
  spinner.start('Customizing template...');
351
360
 
352
361
  const response = await anthropic.messages.create({
353
- model: 'claude-sonnet-4-20250514',
362
+ model: 'claude-sonnet-4-5-20250929',
354
363
  max_tokens: 2048,
355
364
  messages: [{
356
365
  role: 'user',
@@ -429,7 +438,7 @@ async function cloneDesign(anthropic: Anthropic): Promise<WebsiteSpec | null> {
429
438
  spinner.start('Analyzing design inspiration...');
430
439
 
431
440
  const response = await anthropic.messages.create({
432
- model: 'claude-sonnet-4-20250514',
441
+ model: 'claude-sonnet-4-5-20250929',
433
442
  max_tokens: 2048,
434
443
  messages: [{
435
444
  role: 'user',
@@ -497,48 +506,110 @@ async function buildWebsite(
497
506
  await fs.remove(projectPath);
498
507
  }
499
508
 
500
- console.log(chalk.cyan(`\n 🏗️ Building ${spec.name}...\n`));
509
+ console.log(chalk.cyan(`\n 🏗️ Building ${chalk.bold(spec.name)}\n`));
501
510
 
502
- const spinner = p.spinner();
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[] = [];
503
522
 
504
523
  // Step 1: Create project
505
- spinner.start('Creating Next.js project...');
524
+ steps.start();
506
525
 
507
- await execa('npx', [
508
- 'create-next-app@latest',
509
- spec.name,
510
- '--typescript',
511
- '--tailwind',
512
- '--eslint',
513
- '--app',
514
- '--src-dir',
515
- '--import-alias', '@/*',
516
- '--no-git',
517
- ], { cwd: process.cwd(), reject: false });
518
-
519
- spinner.stop('Project created');
520
-
521
- // Step 2: Install shadcn
522
- spinner.start('Setting up shadcn/ui...');
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();
523
574
 
524
- await execa('npx', ['shadcn@latest', 'init', '-y', '-d'], {
525
- cwd: projectPath,
526
- reject: false,
527
- });
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
+ }
528
589
 
529
- // Install common components
530
- await execa('npx', ['shadcn@latest', 'add', 'button', 'card', 'input', 'badge', '-y'], {
531
- cwd: projectPath,
532
- reject: false,
533
- });
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
+ });
534
598
 
535
- spinner.stop('UI components ready');
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
+ }
536
607
 
537
- // Step 3: Generate pages
538
- spinner.start('Generating website code...');
608
+ // Step 4: Generate pages
609
+ steps.start();
539
610
 
540
611
  const response = await anthropic.messages.create({
541
- model: 'claude-sonnet-4-20250514',
612
+ model: 'claude-sonnet-4-5-20250929',
542
613
  max_tokens: 16000,
543
614
  messages: [{
544
615
  role: 'user',
@@ -596,7 +667,6 @@ Make it production-quality and visually impressive.`
596
667
  // Write files
597
668
  const fileRegex = /<<<FILE:\s*(.+?)>>>([\s\S]*?)<<<END_FILE>>>/g;
598
669
  let match;
599
- let fileCount = 0;
600
670
 
601
671
  while ((match = fileRegex.exec(text)) !== null) {
602
672
  const filePath = path.join(projectPath, match[1].trim());
@@ -604,38 +674,51 @@ Make it production-quality and visually impressive.`
604
674
 
605
675
  await fs.ensureDir(path.dirname(filePath));
606
676
  await fs.writeFile(filePath, content);
607
- fileCount++;
677
+ createdFiles.push(match[1].trim());
608
678
  }
609
679
 
610
- spinner.stop(`Generated ${fileCount} files`);
611
-
612
- // Step 4: Git init
613
- spinner.start('Initializing git...');
614
- await execa('git', ['init'], { cwd: projectPath, reject: false });
615
- await execa('git', ['add', '.'], { cwd: projectPath, reject: false });
616
- await execa('git', ['commit', '-m', 'Initial website build by CodeBakers'], { cwd: projectPath, reject: false });
617
- spinner.stop('Git initialized');
618
-
619
- // Done!
620
- console.log(chalk.green(`
621
- ╔═══════════════════════════════════════════════════════════════╗
622
- ║ ✅ Website built successfully! ║
623
- ╠═══════════════════════════════════════════════════════════════╣
624
- ║ ║
625
- ║ ${spec.name.padEnd(55)}║
626
- ${spec.description.substring(0, 55).padEnd(55)}
627
- ║ ║
628
- Next steps: ║
629
- ║ cd ${spec.name.padEnd(52)}║
630
- npm run dev ║
631
- ║ ║
632
- ║ Then open http://localhost:3000 ║
633
- ║ ║
634
- Ready to deploy? ║
635
- ║ codebakers deploy ║
636
- ║ ║
637
- ╚═══════════════════════════════════════════════════════════════╝
638
- `));
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
+ });
639
722
 
640
723
  // Offer to open in browser
641
724
  const openDev = await p.confirm({
@@ -644,7 +727,7 @@ Make it production-quality and visually impressive.`
644
727
  });
645
728
 
646
729
  if (openDev && !p.isCancel(openDev)) {
647
- console.log(chalk.dim('\n Starting dev server...\n'));
730
+ console.log(colors.muted('\n Starting dev server...\n'));
648
731
 
649
732
  // Change to project directory and run dev
650
733
  process.chdir(projectPath);
package/src/index.ts CHANGED
@@ -29,18 +29,21 @@ import { buildCommand } from './commands/build.js';
29
29
  import { integrateCommand, INTEGRATIONS } from './commands/integrate.js';
30
30
  import { websiteCommand } from './commands/website.js';
31
31
  import { parseNaturalLanguage } from './utils/nlp.js';
32
-
33
- const VERSION = '2.3.8';
34
-
35
- // ASCII art logo
36
- const logo = `
37
- ██████╗ ██████╗ ██████╗ ███████╗██████╗ █████╗ ██╗ ██╗███████╗██████╗ ███████╗
38
- ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗██╔══██╗██║ ██╔╝██╔════╝██╔══██╗██╔════╝
39
- ██║ ██║ ██║██║ ██║█████╗ ██████╔╝███████║█████╔╝ █████╗ ██████╔╝███████╗
40
- ██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗██╔══██║██╔═██╗ ██╔══╝ ██╔══██╗╚════██║
41
- ╚██████╗╚██████╔╝██████╔╝███████╗██████╔╝██║ ██║██║ ██╗███████╗██║ ██║███████║
42
- ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝
43
- `;
32
+ import {
33
+ showLogo,
34
+ showMiniLogo,
35
+ showMenuCards,
36
+ showSuccessScreen,
37
+ showErrorScreen,
38
+ box,
39
+ doubleBox,
40
+ divider,
41
+ sectionHeader,
42
+ colors,
43
+ headerGradient
44
+ } from './utils/ui.js';
45
+
46
+ const VERSION = '2.5.3';
44
47
 
45
48
  // ============================================================================
46
49
  // MAIN MENU
@@ -49,21 +52,23 @@ const logo = `
49
52
  async function showMainMenu(): Promise<void> {
50
53
  const config = new Config();
51
54
 
52
- // Show logo
53
- console.log(gradient.pastel.multiline(logo));
54
- console.log(chalk.dim(` v${VERSION} — AI dev team that follows the rules\n`));
55
+ // Clear screen and show beautiful logo
56
+ console.clear();
57
+ showLogo();
58
+ console.log(colors.muted(` v${VERSION}`));
59
+ console.log('');
55
60
 
56
61
  // Check setup status
57
62
  const hasAnthropic = !!config.getCredentials('anthropic')?.apiKey;
58
63
 
59
64
  // STEP 1: First time? Run setup
60
65
  if (!hasAnthropic) {
61
- console.log(boxen(
62
- chalk.yellow('Welcome to CodeBakers!\n\n') +
63
- chalk.white('Let\'s connect your Anthropic API key so the AI can work.\n') +
64
- chalk.dim('(Takes about 1 minute)'),
65
- { padding: 1, borderColor: 'yellow', borderStyle: 'round' }
66
- ));
66
+ doubleBox([
67
+ colors.warning('👋 Welcome to CodeBakers!'),
68
+ '',
69
+ colors.white("Let's connect your Anthropic API key so the AI can work."),
70
+ colors.muted('(Takes about 1 minute)'),
71
+ ], 'default');
67
72
 
68
73
  await setupCommand();
69
74
 
@@ -81,14 +86,18 @@ async function showMainMenu(): Promise<void> {
81
86
  // Show context
82
87
  if (inProject && projectConfig) {
83
88
  const framework = projectConfig.framework || 'detected';
84
- console.log(chalk.cyan(` 📁 Working in: ${chalk.bold(folderName)}`));
85
- console.log(chalk.dim(` ${framework} project\n`));
89
+ box([
90
+ colors.secondary('📁 ') + colors.white(folderName),
91
+ colors.muted(` ${framework} project`),
92
+ ]);
86
93
 
87
94
  // SHOW PROJECT MENU
88
95
  await showProjectMenu(config);
89
96
  } else {
90
- console.log(chalk.cyan(` 📁 Current folder: ${chalk.bold(cwd)}`));
91
- console.log(chalk.dim(` Not a project folder\n`));
97
+ box([
98
+ colors.secondary('📁 ') + colors.white(cwd),
99
+ colors.muted(' Not a project folder'),
100
+ ]);
92
101
 
93
102
  // SHOW START MENU
94
103
  await showStartMenu(config);
@@ -100,25 +109,28 @@ async function showMainMenu(): Promise<void> {
100
109
  // ============================================================================
101
110
 
102
111
  async function showStartMenu(config: Config): Promise<void> {
103
- console.log(chalk.cyan('\n ℹ️ This folder doesn\'t have a project yet.\n'));
112
+ console.log(colors.muted(' This folder doesn\'t have a project yet.'));
113
+ console.log('');
104
114
 
105
115
  let keepRunning = true;
106
116
 
107
117
  while (keepRunning) {
108
- console.log(chalk.white(' What would you like to do?\n'));
109
- console.log(chalk.green(' 1.') + ' 🌐 Build a website ' + chalk.dim('- Describe it, AI builds it'));
110
- console.log(chalk.green(' 2.') + ' 🆕 Create new project ' + chalk.dim('- Start with Next.js, React, etc.'));
111
- console.log(chalk.green(' 3.') + ' ✏️ Plan my project ' + chalk.dim('- Create a detailed plan first'));
112
- console.log(chalk.green(' 4.') + ' 🏗️ Build from plan ' + chalk.dim('- I already have a PRD file'));
113
- console.log(chalk.green(' 5.') + ' 🌟 Get expert advice ' + chalk.dim('- AI consultants help you decide'));
114
- console.log(chalk.green(' 6.') + ' 🔌 Add a service ' + chalk.dim('- Stripe, Supabase, Auth, etc.'));
115
- console.log(chalk.green(' 7.') + ' ⚙️ Settings ' + chalk.dim('- API keys & preferences'));
116
- console.log(chalk.green(' 8.') + ' Help ' + chalk.dim('- Learn how CodeBakers works'));
117
- console.log(chalk.green(' 0.') + ' 🚪 Return to terminal ' + chalk.dim('- Go back to command line'));
118
- console.log('');
118
+ sectionHeader('What would you like to do?');
119
+
120
+ showMenuCards([
121
+ { key: '1', icon: '🌐', label: 'Build a Website', description: 'Describe it, AI builds it' },
122
+ { key: '2', icon: '🆕', label: 'Create New Project', description: 'Start with Next.js, React' },
123
+ { key: '3', icon: '✏️', label: 'Plan My Project', description: 'Create a detailed plan' },
124
+ { key: '4', icon: '🏗️', label: 'Build from Plan', description: 'I have a PRD file' },
125
+ { key: '5', icon: '🌟', label: 'Get Expert Advice', description: 'AI consultants help' },
126
+ { key: '6', icon: '🔌', label: 'Add a Service', description: 'Stripe, Supabase, Auth' },
127
+ { key: '7', icon: '⚙️', label: 'Settings', description: 'API keys & preferences' },
128
+ { key: '8', icon: '❓', label: 'Help', description: 'Learn how it works' },
129
+ { key: '0', icon: '🚪', label: 'Exit', description: 'Return to terminal' },
130
+ ]);
119
131
 
120
132
  const choice = await p.text({
121
- message: 'Enter a number (0-8):',
133
+ message: colors.primary('Enter a number (0-8):'),
122
134
  placeholder: '1',
123
135
  validate: (value) => {
124
136
  if (!/^[0-8]$/.test(value) && value !== '') return 'Please enter a number 0-8';
@@ -172,11 +184,11 @@ async function showStartMenu(config: Config): Promise<void> {
172
184
 
173
185
  function showExitMessage(): void {
174
186
  console.log('');
175
- console.log(chalk.cyan(' ─────────────────────────────────────────────────'));
176
- console.log(chalk.white(' You\'re back in the terminal.'));
187
+ divider();
188
+ console.log(colors.white(' You\'re back in the terminal.'));
177
189
  console.log('');
178
- console.log(chalk.dim(' To start CodeBakers again, type:'));
179
- console.log(chalk.green(' codebakers'));
190
+ console.log(colors.muted(' To start CodeBakers again, type:'));
191
+ console.log(colors.success(' codebakers'));
180
192
  console.log('');
181
193
  console.log(chalk.dim(' Quick commands you can run directly:'));
182
194
  console.log(chalk.dim(' codebakers website') + chalk.gray(' - Build a website'));