codebakers 2.3.7 → 2.5.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.
@@ -0,0 +1,325 @@
1
+ import chalk from 'chalk';
2
+
3
+ // ============================================================================
4
+ // STEP TRACKER - Shows progress through multiple steps
5
+ // ============================================================================
6
+
7
+ export interface Step {
8
+ name: string;
9
+ status: 'pending' | 'running' | 'done' | 'error' | 'skipped';
10
+ }
11
+
12
+ export class StepTracker {
13
+ private steps: Step[];
14
+ private currentIndex: number = -1;
15
+ private startTime: number = Date.now();
16
+
17
+ constructor(stepNames: string[]) {
18
+ this.steps = stepNames.map(name => ({ name, status: 'pending' }));
19
+ }
20
+
21
+ start(index?: number): void {
22
+ if (index !== undefined) {
23
+ this.currentIndex = index;
24
+ } else {
25
+ this.currentIndex++;
26
+ }
27
+
28
+ if (this.currentIndex < this.steps.length) {
29
+ this.steps[this.currentIndex].status = 'running';
30
+ }
31
+ this.render();
32
+ }
33
+
34
+ complete(): void {
35
+ if (this.currentIndex >= 0 && this.currentIndex < this.steps.length) {
36
+ this.steps[this.currentIndex].status = 'done';
37
+ }
38
+ this.render();
39
+ }
40
+
41
+ error(): void {
42
+ if (this.currentIndex >= 0 && this.currentIndex < this.steps.length) {
43
+ this.steps[this.currentIndex].status = 'error';
44
+ }
45
+ this.render();
46
+ }
47
+
48
+ skip(): void {
49
+ if (this.currentIndex >= 0 && this.currentIndex < this.steps.length) {
50
+ this.steps[this.currentIndex].status = 'skipped';
51
+ }
52
+ this.render();
53
+ }
54
+
55
+ private render(): void {
56
+ // Clear previous output (move up and clear lines)
57
+ const output: string[] = [];
58
+
59
+ output.push(''); // Empty line for spacing
60
+
61
+ for (let i = 0; i < this.steps.length; i++) {
62
+ const step = this.steps[i];
63
+ const icon = this.getIcon(step.status);
64
+ const color = this.getColor(step.status);
65
+ const suffix = step.status === 'running' ? chalk.dim(' ...') : '';
66
+
67
+ output.push(` ${icon} ${color(step.name)}${suffix}`);
68
+ }
69
+
70
+ // Progress bar
71
+ const completed = this.steps.filter(s => s.status === 'done').length;
72
+ const total = this.steps.length;
73
+ const percent = Math.round((completed / total) * 100);
74
+ const barWidth = 30;
75
+ const filled = Math.round((completed / total) * barWidth);
76
+ const empty = barWidth - filled;
77
+
78
+ output.push('');
79
+ output.push(` ${chalk.green('█'.repeat(filled))}${chalk.gray('░'.repeat(empty))} ${percent}%`);
80
+ output.push('');
81
+
82
+ console.log(output.join('\n'));
83
+ }
84
+
85
+ private getIcon(status: Step['status']): string {
86
+ switch (status) {
87
+ case 'pending': return chalk.gray('○');
88
+ case 'running': return chalk.blue('●');
89
+ case 'done': return chalk.green('✓');
90
+ case 'error': return chalk.red('✗');
91
+ case 'skipped': return chalk.yellow('⊘');
92
+ }
93
+ }
94
+
95
+ private getColor(status: Step['status']): (s: string) => string {
96
+ switch (status) {
97
+ case 'pending': return chalk.gray;
98
+ case 'running': return chalk.white;
99
+ case 'done': return chalk.green;
100
+ case 'error': return chalk.red;
101
+ case 'skipped': return chalk.yellow;
102
+ }
103
+ }
104
+
105
+ getElapsedTime(): string {
106
+ const elapsed = Math.round((Date.now() - this.startTime) / 1000);
107
+ const minutes = Math.floor(elapsed / 60);
108
+ const seconds = elapsed % 60;
109
+ return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
110
+ }
111
+ }
112
+
113
+ // ============================================================================
114
+ // ERROR DISPLAY - Beautiful error messages
115
+ // ============================================================================
116
+
117
+ export interface ErrorInfo {
118
+ title: string;
119
+ message: string;
120
+ fixes?: string[];
121
+ command?: string;
122
+ docs?: string;
123
+ }
124
+
125
+ export function showError(error: ErrorInfo): void {
126
+ console.log('');
127
+ console.log(chalk.red(` ❌ ${error.title}`));
128
+ console.log('');
129
+ console.log(chalk.white(` What went wrong:`));
130
+ console.log(chalk.gray(` ${error.message}`));
131
+
132
+ if (error.fixes && error.fixes.length > 0) {
133
+ console.log('');
134
+ console.log(chalk.white(` Possible fixes:`));
135
+ error.fixes.forEach((fix, i) => {
136
+ console.log(chalk.gray(` ${i + 1}. ${fix}`));
137
+ });
138
+ }
139
+
140
+ if (error.command) {
141
+ console.log('');
142
+ console.log(chalk.white(` Try running:`));
143
+ console.log(chalk.cyan(` ${error.command}`));
144
+ }
145
+
146
+ if (error.docs) {
147
+ console.log('');
148
+ console.log(chalk.dim(` Docs: ${error.docs}`));
149
+ }
150
+
151
+ console.log('');
152
+ }
153
+
154
+ // ============================================================================
155
+ // SUCCESS DISPLAY - Beautiful success messages
156
+ // ============================================================================
157
+
158
+ export interface SuccessInfo {
159
+ title: string;
160
+ message?: string;
161
+ stats?: { label: string; value: string }[];
162
+ nextSteps?: string[];
163
+ command?: string;
164
+ }
165
+
166
+ export function showSuccess(success: SuccessInfo): void {
167
+ console.log('');
168
+ console.log(chalk.green(` ✅ ${success.title}`));
169
+
170
+ if (success.message) {
171
+ console.log(chalk.gray(` ${success.message}`));
172
+ }
173
+
174
+ if (success.stats && success.stats.length > 0) {
175
+ console.log('');
176
+ console.log(chalk.white(` 📊 Summary:`));
177
+ success.stats.forEach(stat => {
178
+ console.log(chalk.gray(` ${stat.label}: ${chalk.white(stat.value)}`));
179
+ });
180
+ }
181
+
182
+ if (success.nextSteps && success.nextSteps.length > 0) {
183
+ console.log('');
184
+ console.log(chalk.white(` Next steps:`));
185
+ success.nextSteps.forEach(step => {
186
+ console.log(chalk.cyan(` ${step}`));
187
+ });
188
+ }
189
+
190
+ if (success.command) {
191
+ console.log('');
192
+ console.log(chalk.white(` Quick start:`));
193
+ console.log(chalk.cyan(` ${success.command}`));
194
+ }
195
+
196
+ console.log('');
197
+ }
198
+
199
+ // ============================================================================
200
+ // INFO BOX - Boxed information display
201
+ // ============================================================================
202
+
203
+ export function showBox(title: string, content: string[], style: 'info' | 'warning' | 'success' = 'info'): void {
204
+ const colors = {
205
+ info: chalk.cyan,
206
+ warning: chalk.yellow,
207
+ success: chalk.green,
208
+ };
209
+ const color = colors[style];
210
+
211
+ const maxLength = Math.max(title.length, ...content.map(c => c.length));
212
+ const width = maxLength + 4;
213
+
214
+ const top = `╭${'─'.repeat(width)}╮`;
215
+ const bottom = `╰${'─'.repeat(width)}╯`;
216
+ const titleLine = `│ ${color(title.padEnd(maxLength))} │`;
217
+ const separator = `├${'─'.repeat(width)}┤`;
218
+
219
+ console.log('');
220
+ console.log(color(top));
221
+ console.log(color(titleLine));
222
+ console.log(color(separator));
223
+ content.forEach(line => {
224
+ console.log(color(`│ ${line.padEnd(maxLength)} │`));
225
+ });
226
+ console.log(color(bottom));
227
+ console.log('');
228
+ }
229
+
230
+ // ============================================================================
231
+ // FILE LIST - Show created/modified files
232
+ // ============================================================================
233
+
234
+ export function showFileList(title: string, files: string[]): void {
235
+ console.log('');
236
+ console.log(chalk.white(` 📁 ${title}`));
237
+
238
+ files.forEach((file, i) => {
239
+ const isLast = i === files.length - 1;
240
+ const prefix = isLast ? '└──' : '├──';
241
+ const icon = getFileIcon(file);
242
+ console.log(chalk.gray(` ${prefix} ${icon} ${file}`));
243
+ });
244
+
245
+ console.log('');
246
+ }
247
+
248
+ function getFileIcon(filename: string): string {
249
+ const ext = filename.split('.').pop()?.toLowerCase();
250
+ const icons: Record<string, string> = {
251
+ 'tsx': '⚛️',
252
+ 'ts': '📘',
253
+ 'js': '📒',
254
+ 'jsx': '⚛️',
255
+ 'css': '🎨',
256
+ 'json': '📋',
257
+ 'md': '📝',
258
+ 'html': '🌐',
259
+ };
260
+ return icons[ext || ''] || '📄';
261
+ }
262
+
263
+ // ============================================================================
264
+ // COMMON ERROR MESSAGES
265
+ // ============================================================================
266
+
267
+ export const ERRORS = {
268
+ nodeNotInstalled: {
269
+ title: 'Node.js not found',
270
+ message: 'Node.js 18 or higher is required',
271
+ fixes: [
272
+ 'Install Node.js from https://nodejs.org',
273
+ 'Use nvm to install: nvm install 18',
274
+ 'Restart your terminal after installing',
275
+ ],
276
+ docs: 'https://nodejs.org/en/download',
277
+ },
278
+
279
+ npmFailed: {
280
+ title: 'Package installation failed',
281
+ message: 'npm install encountered an error',
282
+ fixes: [
283
+ 'Check your internet connection',
284
+ 'Clear npm cache: npm cache clean --force',
285
+ 'Delete node_modules and try again',
286
+ 'Try using yarn instead: yarn install',
287
+ ],
288
+ },
289
+
290
+ createNextAppFailed: {
291
+ title: 'Project creation failed',
292
+ message: 'create-next-app could not complete',
293
+ fixes: [
294
+ 'Make sure Node.js 18+ is installed',
295
+ 'Check your internet connection',
296
+ 'Try running manually: npx create-next-app@latest',
297
+ ],
298
+ },
299
+
300
+ apiKeyMissing: {
301
+ title: 'API key not configured',
302
+ message: 'Anthropic API key is required for AI features',
303
+ fixes: [
304
+ 'Run: codebakers setup',
305
+ 'Get an API key at: https://console.anthropic.com',
306
+ ],
307
+ command: 'codebakers setup',
308
+ },
309
+
310
+ notConfigured: {
311
+ title: 'CodeBakers not configured',
312
+ message: 'Run setup before using this command',
313
+ command: 'codebakers setup',
314
+ },
315
+
316
+ notInProject: {
317
+ title: 'Not in a project folder',
318
+ message: 'This command must be run inside a project',
319
+ fixes: [
320
+ 'Navigate to your project: cd my-project',
321
+ 'Create a new project: codebakers init',
322
+ 'Or build a website: codebakers website',
323
+ ],
324
+ },
325
+ };
@@ -3,25 +3,6 @@ import chalk from 'chalk';
3
3
  const VERSION = '1.0.0';
4
4
 
5
5
  export async function checkForUpdates(): Promise<void> {
6
- try {
7
- const response = await fetch('https://registry.npmjs.org/codebakers/latest', {
8
- signal: AbortSignal.timeout(3000),
9
- });
10
-
11
- if (!response.ok) return;
12
-
13
- const data = await response.json();
14
- const latestVersion = data.version;
15
-
16
- if (latestVersion && latestVersion !== VERSION) {
17
- console.log(chalk.yellow(`
18
- ╭────────────────────────────────────────────╮
19
- │ Update available: ${VERSION} → ${latestVersion.padEnd(10)} │
20
- │ Run: npm install -g codebakers │
21
- ╰────────────────────────────────────────────╯
22
- `));
23
- }
24
- } catch {
25
- // Silently fail - update check is not critical
26
- }
6
+ // Update check disabled - Studio handles updates automatically
7
+ return;
27
8
  }