@codebakers/cli 3.8.1 → 3.8.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.
package/src/index.ts CHANGED
@@ -23,6 +23,7 @@ import { pushPatterns, pushPatternsInteractive } from './commands/push-patterns.
23
23
  import { go } from './commands/go.js';
24
24
  import { extend } from './commands/extend.js';
25
25
  import { billing } from './commands/billing.js';
26
+ import { build, buildStatus } from './commands/build.js';
26
27
  import { getCachedUpdateInfo, setCachedUpdateInfo, getCliVersion, getCachedPatternInfo, setCachedPatternInfo, getApiKey, getApiUrl, getTrialState, hasValidAccess, shouldAttemptCliUpdate, setCliUpdateAttempt, isCliAutoUpdateDisabled } from './config.js';
27
28
  import { execSync } from 'child_process';
28
29
  import { checkForUpdates } from './lib/api.js';
@@ -164,180 +165,6 @@ async function autoUpdateCli(): Promise<void> {
164
165
  }
165
166
  }
166
167
 
167
- // ============================================
168
- // Automatic Pattern Updates
169
- // ============================================
170
-
171
- interface PatternVersionInfo {
172
- version: string;
173
- moduleCount: number;
174
- updatedAt: string;
175
- cliVersion: string;
176
- }
177
-
178
- interface ContentResponse {
179
- version: string;
180
- router: string;
181
- modules: Record<string, string>;
182
- }
183
-
184
- function getLocalPatternVersion(): string | null {
185
- const cwd = process.cwd();
186
- const versionFile = join(cwd, '.claude', '.version.json');
187
-
188
- if (!existsSync(versionFile)) return null;
189
-
190
- try {
191
- const content = readFileSync(versionFile, 'utf-8');
192
- const info: PatternVersionInfo = JSON.parse(content);
193
- return info.version;
194
- } catch {
195
- return null;
196
- }
197
- }
198
-
199
- function isCodeBakersProject(): boolean {
200
- const cwd = process.cwd();
201
- return existsSync(join(cwd, 'CLAUDE.md')) || existsSync(join(cwd, '.claude'));
202
- }
203
-
204
- async function autoUpdatePatterns(): Promise<void> {
205
- // Only auto-update if this is a CodeBakers project
206
- if (!isCodeBakersProject()) return;
207
-
208
- // Only auto-update if user has valid access
209
- if (!hasValidAccess()) return;
210
-
211
- const localVersion = getLocalPatternVersion();
212
-
213
- // Check if we have a valid cached result first (fast path)
214
- const cached = getCachedPatternInfo();
215
- if (cached) {
216
- // If local matches latest, nothing to do
217
- if (localVersion === cached.latestVersion) return;
218
- // If we know there's an update but haven't updated yet, do it now
219
- if (localVersion !== cached.latestVersion) {
220
- await performPatternUpdate(cached.latestVersion);
221
- }
222
- return;
223
- }
224
-
225
- // Fetch from server to check for updates (with timeout)
226
- try {
227
- const controller = new AbortController();
228
- const timeout = setTimeout(() => controller.abort(), 5000);
229
-
230
- const apiUrl = getApiUrl();
231
- const apiKey = getApiKey();
232
- const trial = getTrialState();
233
-
234
- // Build authorization header
235
- let authHeader = '';
236
- if (apiKey) {
237
- authHeader = `Bearer ${apiKey}`;
238
- } else if (trial?.trialId) {
239
- authHeader = `Trial ${trial.trialId}`;
240
- }
241
-
242
- if (!authHeader) return;
243
-
244
- // First, check the version endpoint (lightweight)
245
- const versionResponse = await fetch(`${apiUrl}/api/content/version`, {
246
- method: 'GET',
247
- headers: {
248
- 'Authorization': authHeader,
249
- },
250
- signal: controller.signal,
251
- });
252
-
253
- clearTimeout(timeout);
254
-
255
- if (versionResponse.ok) {
256
- const versionData = await versionResponse.json();
257
- const serverVersion = versionData.version;
258
-
259
- // Cache the version info
260
- setCachedPatternInfo(serverVersion);
261
-
262
- // If local version is different, update
263
- if (localVersion !== serverVersion) {
264
- await performPatternUpdate(serverVersion);
265
- }
266
- }
267
- } catch {
268
- // Silently fail - don't block CLI for pattern check
269
- }
270
- }
271
-
272
- async function performPatternUpdate(targetVersion: string): Promise<void> {
273
- const cwd = process.cwd();
274
- const claudeMdPath = join(cwd, 'CLAUDE.md');
275
- const claudeDir = join(cwd, '.claude');
276
-
277
- try {
278
- const apiUrl = getApiUrl();
279
- const apiKey = getApiKey();
280
- const trial = getTrialState();
281
-
282
- let authHeader = '';
283
- if (apiKey) {
284
- authHeader = `Bearer ${apiKey}`;
285
- } else if (trial?.trialId) {
286
- authHeader = `Trial ${trial.trialId}`;
287
- }
288
-
289
- if (!authHeader) return;
290
-
291
- const controller = new AbortController();
292
- const timeout = setTimeout(() => controller.abort(), 10000);
293
-
294
- const response = await fetch(`${apiUrl}/api/content`, {
295
- method: 'GET',
296
- headers: {
297
- 'Authorization': authHeader,
298
- },
299
- signal: controller.signal,
300
- });
301
-
302
- clearTimeout(timeout);
303
-
304
- if (!response.ok) return;
305
-
306
- const content: ContentResponse = await response.json();
307
-
308
- // Update CLAUDE.md
309
- if (content.router) {
310
- writeFileSync(claudeMdPath, content.router);
311
- }
312
-
313
- // Update pattern modules
314
- if (content.modules && Object.keys(content.modules).length > 0) {
315
- if (!existsSync(claudeDir)) {
316
- mkdirSync(claudeDir, { recursive: true });
317
- }
318
-
319
- for (const [name, data] of Object.entries(content.modules)) {
320
- writeFileSync(join(claudeDir, name), data);
321
- }
322
- }
323
-
324
- // Write version file
325
- const moduleCount = Object.keys(content.modules || {}).length;
326
- const versionInfo: PatternVersionInfo = {
327
- version: content.version,
328
- moduleCount,
329
- updatedAt: new Date().toISOString(),
330
- cliVersion: getCliVersion(),
331
- };
332
- writeFileSync(join(claudeDir, '.version.json'), JSON.stringify(versionInfo, null, 2));
333
-
334
- // Show subtle notification
335
- console.log(chalk.green(` ✓ Patterns auto-updated to v${content.version} (${moduleCount} modules)\n`));
336
-
337
- } catch {
338
- // Silently fail - don't block the user
339
- }
340
- }
341
168
 
342
169
  // Show welcome message when no command is provided
343
170
  function showWelcome(): void {
@@ -353,22 +180,23 @@ function showWelcome(): void {
353
180
 
354
181
  console.log(chalk.white(' Getting Started:\n'));
355
182
  console.log(chalk.cyan(' codebakers go') + chalk.gray(' Start free trial instantly (no signup!)'));
183
+ console.log(chalk.cyan(' codebakers build') + chalk.gray(' Describe your project → Get working code'));
356
184
  console.log(chalk.cyan(' codebakers scaffold') + chalk.gray(' Create a new project from scratch'));
357
- console.log(chalk.cyan(' codebakers init') + chalk.gray(' Add patterns to existing project\n'));
185
+ console.log(chalk.cyan(' codebakers init') + chalk.gray(' Set up CodeBakers in existing project\n'));
358
186
 
359
187
  console.log(chalk.white(' Development:\n'));
360
188
  console.log(chalk.cyan(' codebakers generate') + chalk.gray(' Generate components, APIs, services'));
361
- console.log(chalk.cyan(' codebakers upgrade') + chalk.gray(' Update patterns to latest version'));
362
- console.log(chalk.cyan(' codebakers status') + chalk.gray(' Check what\'s installed'));
189
+ console.log(chalk.cyan(' codebakers upgrade') + chalk.gray(' Check for CLI updates'));
190
+ console.log(chalk.cyan(' codebakers status') + chalk.gray(' Check project status'));
363
191
  console.log(chalk.cyan(' codebakers config') + chalk.gray(' View or modify configuration\n'));
364
192
 
365
193
  console.log(chalk.white(' Examples:\n'));
194
+ console.log(chalk.gray(' $ ') + chalk.cyan('codebakers build "SaaS for invoicing"'));
195
+ console.log(chalk.gray(' AI generates full project with auth, payments, dashboard\n'));
366
196
  console.log(chalk.gray(' $ ') + chalk.cyan('codebakers scaffold'));
367
197
  console.log(chalk.gray(' Create a new Next.js + Supabase + Drizzle project\n'));
368
198
  console.log(chalk.gray(' $ ') + chalk.cyan('codebakers generate component Button'));
369
199
  console.log(chalk.gray(' Generate a React component with TypeScript\n'));
370
- console.log(chalk.gray(' $ ') + chalk.cyan('codebakers g api users'));
371
- console.log(chalk.gray(' Generate a Next.js API route with validation\n'));
372
200
 
373
201
  console.log(chalk.white(' Quality:\n'));
374
202
  console.log(chalk.cyan(' codebakers audit') + chalk.gray(' Run automated code quality checks'));
@@ -376,9 +204,9 @@ function showWelcome(): void {
376
204
  console.log(chalk.cyan(' codebakers doctor') + chalk.gray(' Check CodeBakers setup\n'));
377
205
 
378
206
  console.log(chalk.white(' All Commands:\n'));
379
- console.log(chalk.gray(' go, extend, billing, setup, scaffold, init, generate, upgrade, status'));
380
- console.log(chalk.gray(' audit, heal, doctor, config, login, install, uninstall'));
381
- console.log(chalk.gray(' install-hook, uninstall-hook, serve, mcp-config, mcp-uninstall\n'));
207
+ console.log(chalk.gray(' go, extend, billing, build, build-status, setup, scaffold, init'));
208
+ console.log(chalk.gray(' generate, upgrade, status, audit, heal, doctor, config, login'));
209
+ console.log(chalk.gray(' serve, mcp-config, mcp-uninstall\n'));
382
210
 
383
211
  console.log(chalk.gray(' Run ') + chalk.cyan('codebakers <command> --help') + chalk.gray(' for more info\n'));
384
212
  }
@@ -409,6 +237,23 @@ program
409
237
  .description('Manage subscription or upgrade to paid plan')
410
238
  .action(billing);
411
239
 
240
+ // AI Build command - describe what you want, get working code
241
+ program
242
+ .command('build [description]')
243
+ .description('Build a project from description - AI generates actual files')
244
+ .option('-o, --output <dir>', 'Output directory (default: current directory)')
245
+ .option('-v, --verbose', 'Show detailed progress')
246
+ .action((description, options) => build({
247
+ description,
248
+ output: options.output,
249
+ verbose: options.verbose,
250
+ }));
251
+
252
+ program
253
+ .command('build-status')
254
+ .description('Check status of recent builds')
255
+ .action(buildStatus);
256
+
412
257
  // Primary command - one-time setup (for paid users)
413
258
  program
414
259
  .command('setup')
@@ -549,14 +394,10 @@ program
549
394
  // Add update check hook (runs before every command)
550
395
  program.hook('preAction', async () => {
551
396
  // Run CLI auto-update first (if enabled and conditions met)
552
- // Then run pattern auto-update in parallel with update banner check
553
397
  await autoUpdateCli();
554
398
 
555
- // Run pattern auto-update and update banner check in parallel
556
- await Promise.all([
557
- checkForUpdatesInBackground(),
558
- autoUpdatePatterns(),
559
- ]);
399
+ // Check for CLI updates in background
400
+ await checkForUpdatesInBackground();
560
401
  });
561
402
 
562
403
  // Show welcome if no command provided