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.
- package/dist/{advisors-GGUCFS4E.js → advisors-3PWAN6UL.js} +1 -1
- package/dist/{chunk-YUSDTJD6.js → chunk-URNRSXPU.js} +2 -2
- package/dist/{chunk-ND6T4UDY.js → chunk-WZQNFV7Q.js} +3 -3
- package/dist/index.js +762 -441
- package/dist/{prd-AIEY63YY.js → prd-YAUSAL5V.js} +1 -1
- package/package.json +1 -1
- package/src/commands/advisors.ts +2 -2
- package/src/commands/build.ts +12 -7
- package/src/commands/code.ts +2 -2
- package/src/commands/deploy.ts +3 -3
- package/src/commands/init.ts +81 -38
- package/src/commands/prd-maker.ts +1 -1
- package/src/commands/prd.ts +3 -3
- package/src/commands/website.ts +139 -64
- package/src/index.ts +1 -1
- package/src/utils/display.ts +325 -0
- package/src/utils/updates.ts +2 -21
|
@@ -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
|
+
};
|
package/src/utils/updates.ts
CHANGED
|
@@ -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
|
-
|
|
7
|
-
|
|
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
|
}
|