@codebakers/cli 3.4.0 → 3.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.
@@ -3,6 +3,7 @@ interface GoOptions {
3
3
  }
4
4
  /**
5
5
  * Zero-friction entry point - start using CodeBakers instantly
6
+ * Single command for both trial and paid users
6
7
  */
7
8
  export declare function go(options?: GoOptions): Promise<void>;
8
9
  export {};
@@ -11,6 +11,7 @@ const fs_1 = require("fs");
11
11
  const path_1 = require("path");
12
12
  const readline_1 = require("readline");
13
13
  const config_js_1 = require("../config.js");
14
+ const api_js_1 = require("../lib/api.js");
14
15
  const fingerprint_js_1 = require("../lib/fingerprint.js");
15
16
  function prompt(question) {
16
17
  const rl = (0, readline_1.createInterface)({
@@ -68,6 +69,7 @@ function log(message, options) {
68
69
  }
69
70
  /**
70
71
  * Zero-friction entry point - start using CodeBakers instantly
72
+ * Single command for both trial and paid users
71
73
  */
72
74
  async function go(options = {}) {
73
75
  log('Starting go command...', options);
@@ -76,19 +78,20 @@ async function go(options = {}) {
76
78
  console.log(chalk_1.default.blue(`
77
79
  ╔═══════════════════════════════════════════════════════════╗
78
80
  ║ ║
79
- ║ ${chalk_1.default.bold.white('CodeBakers - Zero Setup Required')}
81
+ ║ ${chalk_1.default.bold.white('CodeBakers - Get Started')}
80
82
  ║ ║
81
83
  ╚═══════════════════════════════════════════════════════════╝
82
84
  `));
83
85
  // Check if user already has an API key (paid user)
84
86
  log('Checking for existing API key...', options);
85
- const apiKey = (0, config_js_1.getApiKey)();
86
- if (apiKey) {
87
- log(`Found API key: ${apiKey.substring(0, 8)}...`, options);
88
- console.log(chalk_1.default.green(' ✓ You\'re already logged in with an API key!\n'));
89
- // Still install patterns if not already installed
90
- await installPatternsWithApiKey(apiKey, options);
87
+ const existingApiKey = (0, config_js_1.getApiKey)();
88
+ if (existingApiKey) {
89
+ log(`Found API key: ${existingApiKey.substring(0, 8)}...`, options);
90
+ console.log(chalk_1.default.green(' ✓ You\'re already logged in!\n'));
91
+ // Install patterns if not already installed
92
+ await installPatternsWithApiKey(existingApiKey, options);
91
93
  await configureMCP(options);
94
+ await showSuccessAndRestart();
92
95
  return;
93
96
  }
94
97
  log('No API key found, checking trial state...', options);
@@ -104,21 +107,33 @@ async function go(options = {}) {
104
107
  // Install patterns if not already installed
105
108
  await installPatterns(existingTrial.trialId, options);
106
109
  await configureMCP(options);
110
+ await showSuccessAndRestart();
107
111
  return;
108
112
  }
109
113
  // Check if trial expired
110
114
  if (existingTrial && (0, config_js_1.isTrialExpired)()) {
111
115
  console.log(chalk_1.default.yellow(' ⚠️ Your trial has expired.\n'));
112
- if (existingTrial.stage === 'anonymous') {
113
- console.log(chalk_1.default.white(' Extend your trial for 7 more days with GitHub:\n'));
114
- console.log(chalk_1.default.cyan(' codebakers extend\n'));
115
- console.log(chalk_1.default.gray(' Or upgrade to Pro ($49/month):\n'));
116
- console.log(chalk_1.default.cyan(' codebakers upgrade\n'));
116
+ // Offer to login with API key or extend
117
+ console.log(chalk_1.default.white(' Options:\n'));
118
+ console.log(chalk_1.default.cyan(' [1] Login with API key') + chalk_1.default.gray(' (I have an account)'));
119
+ console.log(chalk_1.default.cyan(' [2] Extend trial') + chalk_1.default.gray(' (7 more days with GitHub)\n'));
120
+ const choice = await prompt(chalk_1.default.gray(' Enter 1 or 2: '));
121
+ if (choice === '1') {
122
+ await handleApiKeyLogin(options);
123
+ return;
117
124
  }
118
125
  else {
119
- console.log(chalk_1.default.white(' Ready to upgrade? $49/month for unlimited access:\n'));
120
- console.log(chalk_1.default.cyan(' codebakers upgrade\n'));
126
+ console.log(chalk_1.default.cyan('\n Run: codebakers extend\n'));
127
+ return;
121
128
  }
129
+ }
130
+ // New user - ask how they want to proceed
131
+ console.log(chalk_1.default.white(' How would you like to get started?\n'));
132
+ console.log(chalk_1.default.cyan(' [1] Start free 7-day trial') + chalk_1.default.gray(' (no signup required)'));
133
+ console.log(chalk_1.default.cyan(' [2] Login with API key') + chalk_1.default.gray(' (I have an account)\n'));
134
+ const choice = await prompt(chalk_1.default.gray(' Enter 1 or 2: '));
135
+ if (choice === '2') {
136
+ await handleApiKeyLogin(options);
122
137
  return;
123
138
  }
124
139
  // Start new trial
@@ -179,22 +194,12 @@ async function go(options = {}) {
179
194
  (0, config_js_1.setTrialState)(trialState);
180
195
  spinner.succeed(`Trial started (${data.daysRemaining} days free)`);
181
196
  console.log('');
182
- // Install patterns (CLAUDE.md and .claude/)
197
+ // Install v6.0 bootstrap files (CLAUDE.md and .cursorrules only)
183
198
  await installPatterns(data.trialId, options);
184
199
  // Configure MCP
185
200
  await configureMCP(options);
186
- // Show success message
187
- console.log(chalk_1.default.green(`
188
- ╔═══════════════════════════════════════════════════════════╗
189
- ║ ✅ CodeBakers is ready! ║
190
- ║ ║
191
- ║ ${chalk_1.default.white('Your 7-day free trial has started.')} ║
192
- ║ ║
193
- ║ ${chalk_1.default.gray('Try: "Build me a todo app with authentication"')} ║
194
- ╚═══════════════════════════════════════════════════════════╝
195
- `));
196
- // Attempt auto-restart Claude Code
197
- await attemptAutoRestart();
201
+ // Show success and restart
202
+ await showSuccessAndRestart();
198
203
  }
199
204
  catch (error) {
200
205
  spinner.fail('Failed to start trial');
@@ -235,9 +240,50 @@ async function configureMCP(options = {}) {
235
240
  }
236
241
  }
237
242
  }
238
- async function attemptAutoRestart() {
243
+ /**
244
+ * Handle API key login flow (for paid users)
245
+ */
246
+ async function handleApiKeyLogin(options = {}) {
247
+ console.log(chalk_1.default.white('\n Enter your API key\n'));
248
+ console.log(chalk_1.default.gray(' Find it at: https://codebakers.ai/dashboard\n'));
249
+ const apiKey = await prompt(chalk_1.default.cyan(' API Key: '));
250
+ if (!apiKey) {
251
+ console.log(chalk_1.default.red('\n API key is required.\n'));
252
+ return;
253
+ }
254
+ const spinner = (0, ora_1.default)('Validating API key...').start();
255
+ try {
256
+ await (0, api_js_1.validateApiKey)(apiKey);
257
+ spinner.succeed('API key validated');
258
+ // Save API key
259
+ (0, config_js_1.setApiKey)(apiKey);
260
+ console.log(chalk_1.default.green(' ✓ Logged in successfully!\n'));
261
+ // Install patterns
262
+ await installPatternsWithApiKey(apiKey, options);
263
+ // Configure MCP
264
+ await configureMCP(options);
265
+ // Show success
266
+ await showSuccessAndRestart();
267
+ }
268
+ catch (error) {
269
+ spinner.fail('Invalid API key');
270
+ console.log(chalk_1.default.red('\n Could not validate API key.'));
271
+ console.log(chalk_1.default.gray(' Check your key at: https://codebakers.ai/dashboard\n'));
272
+ }
273
+ }
274
+ /**
275
+ * Show success message and offer to restart
276
+ */
277
+ async function showSuccessAndRestart() {
239
278
  const cwd = process.cwd();
240
- console.log(chalk_1.default.yellow('\n ⚠️ RESTART REQUIRED\n'));
279
+ console.log(chalk_1.default.green(`
280
+ ╔═══════════════════════════════════════════════════════════╗
281
+ ║ ✅ CodeBakers is ready! ║
282
+ ║ ║
283
+ ║ ${chalk_1.default.gray('Try: "Build me a todo app with authentication"')} ║
284
+ ╚═══════════════════════════════════════════════════════════╝
285
+ `));
286
+ console.log(chalk_1.default.yellow(' ⚠️ RESTART REQUIRED\n'));
241
287
  console.log(chalk_1.default.gray(' Claude Code needs to restart to load CodeBakers.\n'));
242
288
  const answer = await prompt(chalk_1.default.cyan(' Restart Claude Code now? (Y/n): '));
243
289
  if (answer === 'n' || answer === 'no') {
@@ -249,7 +295,6 @@ async function attemptAutoRestart() {
249
295
  try {
250
296
  const isWindows = process.platform === 'win32';
251
297
  if (isWindows) {
252
- // On Windows, spawn a new Claude process detached and exit
253
298
  (0, child_process_1.spawn)('cmd', ['/c', 'start', 'claude'], {
254
299
  cwd,
255
300
  detached: true,
@@ -258,7 +303,6 @@ async function attemptAutoRestart() {
258
303
  }).unref();
259
304
  }
260
305
  else {
261
- // On Mac/Linux, spawn claude in new terminal
262
306
  (0, child_process_1.spawn)('claude', [], {
263
307
  cwd,
264
308
  detached: true,
@@ -268,135 +312,173 @@ async function attemptAutoRestart() {
268
312
  }
269
313
  console.log(chalk_1.default.green(' ✓ Claude Code is restarting...\n'));
270
314
  console.log(chalk_1.default.gray(' This terminal will close. Claude Code will open in a new window.\n'));
271
- // Give the spawn a moment to start
272
315
  await new Promise(resolve => setTimeout(resolve, 1000));
273
- // Exit this process
274
316
  process.exit(0);
275
317
  }
276
- catch (error) {
318
+ catch {
277
319
  console.log(chalk_1.default.yellow(' Could not auto-restart. Please restart Claude Code manually.\n'));
278
320
  }
279
321
  }
322
+ // v6.0 Bootstrap content - minimal files that point to MCP tools
323
+ const V6_CLAUDE_MD = `# CodeBakers v6.0 - Server-Enforced Patterns
324
+
325
+ **All patterns are server-side. No local pattern files needed.**
326
+
327
+ ## Required MCP Tools
328
+
329
+ Before writing ANY code, you MUST use these CodeBakers MCP tools:
330
+
331
+ ### 1. discover_patterns (MANDATORY - START GATE)
332
+ Call this BEFORE writing any code:
333
+ \`\`\`
334
+ Tool: discover_patterns
335
+ Args: { task: "what you're about to do", files: ["files to modify"], keywords: ["relevant terms"] }
336
+ \`\`\`
337
+ This returns:
338
+ - Relevant patterns from the server
339
+ - A session token (required for validation)
340
+ - Code examples to follow
341
+
342
+ ### 2. validate_complete (MANDATORY - END GATE)
343
+ Call this BEFORE saying "done" or "complete":
344
+ \`\`\`
345
+ Tool: validate_complete
346
+ Args: { feature: "what you built", files: ["files modified"] }
347
+ \`\`\`
348
+ This checks:
349
+ - You called discover_patterns first (server verifies)
350
+ - Tests exist and pass
351
+ - TypeScript compiles
352
+ - Returns pass/fail from server
353
+
354
+ ## Rules
355
+
356
+ 1. **You CANNOT skip discover_patterns** - Server tracks compliance
357
+ 2. **You CANNOT say "done" without validate_complete** - Server must approve
358
+ 3. **Follow patterns returned by server** - They are mandatory
359
+ 4. **Write tests** - Validation will fail without them
360
+ 5. **Fix TypeScript errors** - Validation will fail with errors
361
+
362
+ ## If Server is Unreachable
363
+
364
+ The tools will show "OFFLINE MODE" if the server can't be reached. In this case:
365
+ - Enforcement is limited to local checks only
366
+ - You should still follow best practices
367
+ - Try again when connection is restored
368
+
369
+ ## Getting Help
370
+
371
+ - Run \`codebakers doctor\` to diagnose issues
372
+ - Run \`codebakers upgrade\` to update patterns
373
+ - Visit https://codebakers.ai/support for help
374
+
375
+ ---
376
+ *CodeBakers v6.0 - Server-Enforced Patterns*
377
+ `;
378
+ const V6_CURSORRULES = `# CodeBakers v6.0 - Server-Enforced Patterns
379
+
380
+ All patterns are server-side. No local pattern files needed.
381
+
382
+ ## Required MCP Tools
383
+
384
+ Before writing ANY code, you MUST use these CodeBakers MCP tools:
385
+
386
+ ### 1. discover_patterns (MANDATORY - START GATE)
387
+ Call this BEFORE writing any code:
388
+ - Tool: discover_patterns
389
+ - Args: { task: "what you're about to do", files: ["files to modify"], keywords: ["relevant terms"] }
390
+
391
+ Returns:
392
+ - Relevant patterns from the server
393
+ - A session token (required for validation)
394
+ - Code examples to follow
395
+
396
+ ### 2. validate_complete (MANDATORY - END GATE)
397
+ Call this BEFORE saying "done" or "complete":
398
+ - Tool: validate_complete
399
+ - Args: { feature: "what you built", files: ["files modified"] }
400
+
401
+ Checks:
402
+ - You called discover_patterns first (server verifies)
403
+ - Tests exist and pass
404
+ - TypeScript compiles
405
+ - Returns pass/fail from server
406
+
407
+ ## Rules
408
+
409
+ 1. You CANNOT skip discover_patterns - Server tracks compliance
410
+ 2. You CANNOT say "done" without validate_complete - Server must approve
411
+ 3. Follow patterns returned by server - They are mandatory
412
+ 4. Write tests - Validation will fail without them
413
+ 5. Fix TypeScript errors - Validation will fail with errors
414
+
415
+ ## If Server is Unreachable
416
+
417
+ The tools will show "OFFLINE MODE" if the server can't be reached. In this case:
418
+ - Enforcement is limited to local checks only
419
+ - You should still follow best practices
420
+ - Try again when connection is restored
421
+
422
+ ---
423
+ CodeBakers v6.0 - Server-Enforced Patterns
424
+ `;
280
425
  /**
281
- * Install pattern files for API key users (paid users)
426
+ * Install v6.0 bootstrap files for API key users (paid users)
427
+ * Only installs minimal CLAUDE.md and .cursorrules - no .claude/ folder
282
428
  */
283
429
  async function installPatternsWithApiKey(apiKey, options = {}) {
284
- log('Installing patterns with API key...', options);
285
- const spinner = (0, ora_1.default)('Installing CodeBakers patterns...').start();
286
- const cwd = process.cwd();
287
- const apiUrl = (0, config_js_1.getApiUrl)();
288
- log(`Fetching from: ${apiUrl}/api/content`, options);
289
- try {
290
- const response = await fetch(`${apiUrl}/api/content`, {
291
- method: 'GET',
292
- headers: {
293
- 'Authorization': `Bearer ${apiKey}`,
294
- },
295
- });
296
- if (!response.ok) {
297
- log(`Response not OK: ${response.status} ${response.statusText}`, options);
298
- spinner.warn('Could not download patterns');
299
- return;
300
- }
301
- log('Response OK, parsing JSON...', options);
302
- const content = await response.json();
303
- log(`Received version: ${content.version}, modules: ${Object.keys(content.modules || {}).length}`, options);
304
- await writePatternFiles(cwd, content, spinner, options, { apiKey });
305
- }
306
- catch (error) {
307
- log(`Error: ${error instanceof Error ? error.message : String(error)}`, options);
308
- spinner.warn('Could not install patterns');
309
- console.log(chalk_1.default.gray(' Check your internet connection.\n'));
310
- }
430
+ log('Installing v6.0 bootstrap files (API key user)...', options);
431
+ await installBootstrapFiles(options, { apiKey });
311
432
  }
312
433
  /**
313
- * Install pattern files (CLAUDE.md and .claude/) for trial users
434
+ * Install v6.0 bootstrap files for trial users
435
+ * Only installs minimal CLAUDE.md and .cursorrules - no .claude/ folder
314
436
  */
315
437
  async function installPatterns(trialId, options = {}) {
316
- log(`Installing patterns with trial ID: ${trialId.substring(0, 8)}...`, options);
317
- const spinner = (0, ora_1.default)('Installing CodeBakers patterns...').start();
438
+ log(`Installing v6.0 bootstrap files (trial: ${trialId.substring(0, 8)}...)`, options);
439
+ await installBootstrapFiles(options, { trialId });
440
+ }
441
+ /**
442
+ * Install v6.0 minimal bootstrap files
443
+ * - CLAUDE.md: Instructions for Claude Code
444
+ * - .cursorrules: Instructions for Cursor
445
+ * - NO .claude/ folder - all patterns are server-side
446
+ */
447
+ async function installBootstrapFiles(options = {}, auth) {
448
+ const spinner = (0, ora_1.default)('Installing CodeBakers v6.0...').start();
318
449
  const cwd = process.cwd();
319
- const apiUrl = (0, config_js_1.getApiUrl)();
320
450
  try {
321
- // Fetch patterns using trial ID
322
- log(`Fetching from: ${apiUrl}/api/content`, options);
323
- const response = await fetch(`${apiUrl}/api/content`, {
324
- method: 'GET',
325
- headers: {
326
- 'X-Trial-ID': trialId,
327
- },
328
- });
329
- if (!response.ok) {
330
- log(`Primary endpoint failed: ${response.status}, trying trial endpoint...`, options);
331
- // Try without auth - some patterns may be available for trial
332
- const publicResponse = await fetch(`${apiUrl}/api/content/trial`, {
333
- method: 'GET',
334
- headers: {
335
- 'X-Trial-ID': trialId,
336
- },
337
- });
338
- if (!publicResponse.ok) {
339
- log(`Trial endpoint also failed: ${publicResponse.status}`, options);
340
- spinner.warn('Could not download patterns (will use MCP tools)');
451
+ const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
452
+ const cursorRulesPath = (0, path_1.join)(cwd, '.cursorrules');
453
+ // Check if already installed with v6
454
+ if ((0, fs_1.existsSync)(claudeMdPath)) {
455
+ const content = (0, fs_1.readFileSync)(claudeMdPath, 'utf-8');
456
+ if (content.includes('v6.0') && content.includes('discover_patterns')) {
457
+ spinner.succeed('CodeBakers v6.0 already installed');
341
458
  return;
342
459
  }
343
- const content = await publicResponse.json();
344
- log(`Received version: ${content.version}, modules: ${Object.keys(content.modules || {}).length}`, options);
345
- await writePatternFiles(cwd, content, spinner, options, { trialId });
346
- return;
460
+ // Upgrade from v5
461
+ log('Upgrading from v5 to v6...', options);
462
+ }
463
+ // Write v6.0 bootstrap files
464
+ (0, fs_1.writeFileSync)(claudeMdPath, V6_CLAUDE_MD);
465
+ (0, fs_1.writeFileSync)(cursorRulesPath, V6_CURSORRULES);
466
+ spinner.succeed('CodeBakers v6.0 installed');
467
+ console.log(chalk_1.default.gray(' Patterns are server-enforced via MCP tools\n'));
468
+ // Confirm install to server (non-blocking)
469
+ if (auth) {
470
+ const apiUrl = (0, config_js_1.getApiUrl)();
471
+ confirmDownload(apiUrl, auth, {
472
+ version: '6.0',
473
+ moduleCount: 0, // No local modules in v6
474
+ cliVersion: getCliVersion(),
475
+ command: 'go',
476
+ }).catch(() => { }); // Silently ignore
347
477
  }
348
- const content = await response.json();
349
- log(`Received version: ${content.version}, modules: ${Object.keys(content.modules || {}).length}`, options);
350
- await writePatternFiles(cwd, content, spinner, options, { trialId });
351
478
  }
352
479
  catch (error) {
353
480
  log(`Error: ${error instanceof Error ? error.message : String(error)}`, options);
354
- spinner.warn('Could not install patterns (will use MCP tools)');
355
- console.log(chalk_1.default.gray(' Patterns will be available via MCP tools.\n'));
356
- }
357
- }
358
- async function writePatternFiles(cwd, content, spinner, options = {}, auth) {
359
- log(`Writing pattern files to ${cwd}...`, options);
360
- // Check if patterns already exist
361
- const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
362
- if ((0, fs_1.existsSync)(claudeMdPath)) {
363
- spinner.succeed('CodeBakers patterns already installed');
364
- return;
365
- }
366
- // Write CLAUDE.md (router file)
367
- if (content.router) {
368
- (0, fs_1.writeFileSync)(claudeMdPath, content.router);
369
- }
370
- // Write pattern modules to .claude/
371
- const moduleCount = Object.keys(content.modules || {}).length;
372
- if (content.modules && moduleCount > 0) {
373
- const modulesDir = (0, path_1.join)(cwd, '.claude');
374
- if (!(0, fs_1.existsSync)(modulesDir)) {
375
- (0, fs_1.mkdirSync)(modulesDir, { recursive: true });
376
- }
377
- for (const [name, data] of Object.entries(content.modules)) {
378
- (0, fs_1.writeFileSync)((0, path_1.join)(modulesDir, name), data);
379
- }
380
- }
381
- // Update .gitignore to exclude encoded patterns
382
- const gitignorePath = (0, path_1.join)(cwd, '.gitignore');
383
- if ((0, fs_1.existsSync)(gitignorePath)) {
384
- const { readFileSync } = await import('fs');
385
- const gitignore = readFileSync(gitignorePath, 'utf-8');
386
- if (!gitignore.includes('.claude/')) {
387
- (0, fs_1.writeFileSync)(gitignorePath, gitignore + '\n# CodeBakers patterns\n.claude/\n');
388
- }
389
- }
390
- spinner.succeed(`CodeBakers patterns installed (v${content.version})`);
391
- console.log(chalk_1.default.gray(` ${moduleCount} pattern modules ready\n`));
392
- // Confirm download to server (non-blocking)
393
- if (auth) {
394
- const apiUrl = (0, config_js_1.getApiUrl)();
395
- confirmDownload(apiUrl, auth, {
396
- version: content.version,
397
- moduleCount,
398
- cliVersion: getCliVersion(),
399
- command: 'go',
400
- }).catch(() => { }); // Silently ignore
481
+ spinner.warn('Could not install bootstrap files');
482
+ console.log(chalk_1.default.gray(' MCP tools will still work without local files.\n'));
401
483
  }
402
484
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codebakers/cli",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "description": "CodeBakers CLI - Production patterns for AI-assisted development",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import ora from 'ora';
3
3
  import { execSync, spawn } from 'child_process';
4
- import { writeFileSync, mkdirSync, existsSync } from 'fs';
4
+ import { writeFileSync, existsSync, readFileSync } from 'fs';
5
5
  import { join } from 'path';
6
6
  import { createInterface } from 'readline';
7
7
  import {
@@ -9,10 +9,12 @@ import {
9
9
  setTrialState,
10
10
  getApiUrl,
11
11
  getApiKey,
12
+ setApiKey,
12
13
  isTrialExpired,
13
14
  getTrialDaysRemaining,
14
15
  type TrialState,
15
16
  } from '../config.js';
17
+ import { validateApiKey } from '../lib/api.js';
16
18
  import { getDeviceFingerprint } from '../lib/fingerprint.js';
17
19
 
18
20
  function prompt(question: string): Promise<string> {
@@ -29,12 +31,6 @@ function prompt(question: string): Promise<string> {
29
31
  });
30
32
  }
31
33
 
32
- interface ContentResponse {
33
- version: string;
34
- router: string;
35
- modules: Record<string, string>;
36
- }
37
-
38
34
  interface GoOptions {
39
35
  verbose?: boolean;
40
36
  }
@@ -98,6 +94,7 @@ function log(message: string, options?: GoOptions): void {
98
94
 
99
95
  /**
100
96
  * Zero-friction entry point - start using CodeBakers instantly
97
+ * Single command for both trial and paid users
101
98
  */
102
99
  export async function go(options: GoOptions = {}): Promise<void> {
103
100
  log('Starting go command...', options);
@@ -107,21 +104,22 @@ export async function go(options: GoOptions = {}): Promise<void> {
107
104
  console.log(chalk.blue(`
108
105
  ╔═══════════════════════════════════════════════════════════╗
109
106
  ║ ║
110
- ║ ${chalk.bold.white('CodeBakers - Zero Setup Required')}
107
+ ║ ${chalk.bold.white('CodeBakers - Get Started')}
111
108
  ║ ║
112
109
  ╚═══════════════════════════════════════════════════════════╝
113
110
  `));
114
111
 
115
112
  // Check if user already has an API key (paid user)
116
113
  log('Checking for existing API key...', options);
117
- const apiKey = getApiKey();
118
- if (apiKey) {
119
- log(`Found API key: ${apiKey.substring(0, 8)}...`, options);
120
- console.log(chalk.green(' ✓ You\'re already logged in with an API key!\n'));
114
+ const existingApiKey = getApiKey();
115
+ if (existingApiKey) {
116
+ log(`Found API key: ${existingApiKey.substring(0, 8)}...`, options);
117
+ console.log(chalk.green(' ✓ You\'re already logged in!\n'));
121
118
 
122
- // Still install patterns if not already installed
123
- await installPatternsWithApiKey(apiKey, options);
119
+ // Install patterns if not already installed
120
+ await installPatternsWithApiKey(existingApiKey, options);
124
121
  await configureMCP(options);
122
+ await showSuccessAndRestart();
125
123
  return;
126
124
  }
127
125
  log('No API key found, checking trial state...', options);
@@ -140,8 +138,8 @@ export async function go(options: GoOptions = {}): Promise<void> {
140
138
 
141
139
  // Install patterns if not already installed
142
140
  await installPatterns(existingTrial.trialId, options);
143
-
144
141
  await configureMCP(options);
142
+ await showSuccessAndRestart();
145
143
  return;
146
144
  }
147
145
 
@@ -149,15 +147,31 @@ export async function go(options: GoOptions = {}): Promise<void> {
149
147
  if (existingTrial && isTrialExpired()) {
150
148
  console.log(chalk.yellow(' ⚠️ Your trial has expired.\n'));
151
149
 
152
- if (existingTrial.stage === 'anonymous') {
153
- console.log(chalk.white(' Extend your trial for 7 more days with GitHub:\n'));
154
- console.log(chalk.cyan(' codebakers extend\n'));
155
- console.log(chalk.gray(' Or upgrade to Pro ($49/month):\n'));
156
- console.log(chalk.cyan(' codebakers upgrade\n'));
150
+ // Offer to login with API key or extend
151
+ console.log(chalk.white(' Options:\n'));
152
+ console.log(chalk.cyan(' [1] Login with API key') + chalk.gray(' (I have an account)'));
153
+ console.log(chalk.cyan(' [2] Extend trial') + chalk.gray(' (7 more days with GitHub)\n'));
154
+
155
+ const choice = await prompt(chalk.gray(' Enter 1 or 2: '));
156
+
157
+ if (choice === '1') {
158
+ await handleApiKeyLogin(options);
159
+ return;
157
160
  } else {
158
- console.log(chalk.white(' Ready to upgrade? $49/month for unlimited access:\n'));
159
- console.log(chalk.cyan(' codebakers upgrade\n'));
161
+ console.log(chalk.cyan('\n Run: codebakers extend\n'));
162
+ return;
160
163
  }
164
+ }
165
+
166
+ // New user - ask how they want to proceed
167
+ console.log(chalk.white(' How would you like to get started?\n'));
168
+ console.log(chalk.cyan(' [1] Start free 7-day trial') + chalk.gray(' (no signup required)'));
169
+ console.log(chalk.cyan(' [2] Login with API key') + chalk.gray(' (I have an account)\n'));
170
+
171
+ const choice = await prompt(chalk.gray(' Enter 1 or 2: '));
172
+
173
+ if (choice === '2') {
174
+ await handleApiKeyLogin(options);
161
175
  return;
162
176
  }
163
177
 
@@ -229,25 +243,14 @@ export async function go(options: GoOptions = {}): Promise<void> {
229
243
  spinner.succeed(`Trial started (${data.daysRemaining} days free)`);
230
244
  console.log('');
231
245
 
232
- // Install patterns (CLAUDE.md and .claude/)
246
+ // Install v6.0 bootstrap files (CLAUDE.md and .cursorrules only)
233
247
  await installPatterns(data.trialId, options);
234
248
 
235
249
  // Configure MCP
236
250
  await configureMCP(options);
237
251
 
238
- // Show success message
239
- console.log(chalk.green(`
240
- ╔═══════════════════════════════════════════════════════════╗
241
- ║ ✅ CodeBakers is ready! ║
242
- ║ ║
243
- ║ ${chalk.white('Your 7-day free trial has started.')} ║
244
- ║ ║
245
- ║ ${chalk.gray('Try: "Build me a todo app with authentication"')} ║
246
- ╚═══════════════════════════════════════════════════════════╝
247
- `));
248
-
249
- // Attempt auto-restart Claude Code
250
- await attemptAutoRestart();
252
+ // Show success and restart
253
+ await showSuccessAndRestart();
251
254
 
252
255
  } catch (error) {
253
256
  spinner.fail('Failed to start trial');
@@ -289,10 +292,61 @@ async function configureMCP(options: GoOptions = {}): Promise<void> {
289
292
  }
290
293
  }
291
294
 
292
- async function attemptAutoRestart(): Promise<void> {
295
+ /**
296
+ * Handle API key login flow (for paid users)
297
+ */
298
+ async function handleApiKeyLogin(options: GoOptions = {}): Promise<void> {
299
+ console.log(chalk.white('\n Enter your API key\n'));
300
+ console.log(chalk.gray(' Find it at: https://codebakers.ai/dashboard\n'));
301
+
302
+ const apiKey = await prompt(chalk.cyan(' API Key: '));
303
+
304
+ if (!apiKey) {
305
+ console.log(chalk.red('\n API key is required.\n'));
306
+ return;
307
+ }
308
+
309
+ const spinner = ora('Validating API key...').start();
310
+
311
+ try {
312
+ await validateApiKey(apiKey);
313
+ spinner.succeed('API key validated');
314
+
315
+ // Save API key
316
+ setApiKey(apiKey);
317
+ console.log(chalk.green(' ✓ Logged in successfully!\n'));
318
+
319
+ // Install patterns
320
+ await installPatternsWithApiKey(apiKey, options);
321
+
322
+ // Configure MCP
323
+ await configureMCP(options);
324
+
325
+ // Show success
326
+ await showSuccessAndRestart();
327
+
328
+ } catch (error) {
329
+ spinner.fail('Invalid API key');
330
+ console.log(chalk.red('\n Could not validate API key.'));
331
+ console.log(chalk.gray(' Check your key at: https://codebakers.ai/dashboard\n'));
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Show success message and offer to restart
337
+ */
338
+ async function showSuccessAndRestart(): Promise<void> {
293
339
  const cwd = process.cwd();
294
340
 
295
- console.log(chalk.yellow('\n ⚠️ RESTART REQUIRED\n'));
341
+ console.log(chalk.green(`
342
+ ╔═══════════════════════════════════════════════════════════╗
343
+ ║ ✅ CodeBakers is ready! ║
344
+ ║ ║
345
+ ║ ${chalk.gray('Try: "Build me a todo app with authentication"')} ║
346
+ ╚═══════════════════════════════════════════════════════════╝
347
+ `));
348
+
349
+ console.log(chalk.yellow(' ⚠️ RESTART REQUIRED\n'));
296
350
  console.log(chalk.gray(' Claude Code needs to restart to load CodeBakers.\n'));
297
351
 
298
352
  const answer = await prompt(chalk.cyan(' Restart Claude Code now? (Y/n): '));
@@ -309,7 +363,6 @@ async function attemptAutoRestart(): Promise<void> {
309
363
  const isWindows = process.platform === 'win32';
310
364
 
311
365
  if (isWindows) {
312
- // On Windows, spawn a new Claude process detached and exit
313
366
  spawn('cmd', ['/c', 'start', 'claude'], {
314
367
  cwd,
315
368
  detached: true,
@@ -317,7 +370,6 @@ async function attemptAutoRestart(): Promise<void> {
317
370
  shell: true,
318
371
  }).unref();
319
372
  } else {
320
- // On Mac/Linux, spawn claude in new terminal
321
373
  spawn('claude', [], {
322
374
  cwd,
323
375
  detached: true,
@@ -329,160 +381,183 @@ async function attemptAutoRestart(): Promise<void> {
329
381
  console.log(chalk.green(' ✓ Claude Code is restarting...\n'));
330
382
  console.log(chalk.gray(' This terminal will close. Claude Code will open in a new window.\n'));
331
383
 
332
- // Give the spawn a moment to start
333
384
  await new Promise(resolve => setTimeout(resolve, 1000));
334
-
335
- // Exit this process
336
385
  process.exit(0);
337
386
 
338
- } catch (error) {
387
+ } catch {
339
388
  console.log(chalk.yellow(' Could not auto-restart. Please restart Claude Code manually.\n'));
340
389
  }
341
390
  }
342
391
 
343
- /**
344
- * Install pattern files for API key users (paid users)
345
- */
346
- async function installPatternsWithApiKey(apiKey: string, options: GoOptions = {}): Promise<void> {
347
- log('Installing patterns with API key...', options);
348
- const spinner = ora('Installing CodeBakers patterns...').start();
349
- const cwd = process.cwd();
350
- const apiUrl = getApiUrl();
392
+ // v6.0 Bootstrap content - minimal files that point to MCP tools
393
+ const V6_CLAUDE_MD = `# CodeBakers v6.0 - Server-Enforced Patterns
351
394
 
352
- log(`Fetching from: ${apiUrl}/api/content`, options);
395
+ **All patterns are server-side. No local pattern files needed.**
353
396
 
354
- try {
355
- const response = await fetch(`${apiUrl}/api/content`, {
356
- method: 'GET',
357
- headers: {
358
- 'Authorization': `Bearer ${apiKey}`,
359
- },
360
- });
397
+ ## Required MCP Tools
361
398
 
362
- if (!response.ok) {
363
- log(`Response not OK: ${response.status} ${response.statusText}`, options);
364
- spinner.warn('Could not download patterns');
365
- return;
366
- }
399
+ Before writing ANY code, you MUST use these CodeBakers MCP tools:
367
400
 
368
- log('Response OK, parsing JSON...', options);
369
- const content: ContentResponse = await response.json();
370
- log(`Received version: ${content.version}, modules: ${Object.keys(content.modules || {}).length}`, options);
371
- await writePatternFiles(cwd, content, spinner, options, { apiKey });
401
+ ### 1. discover_patterns (MANDATORY - START GATE)
402
+ Call this BEFORE writing any code:
403
+ \`\`\`
404
+ Tool: discover_patterns
405
+ Args: { task: "what you're about to do", files: ["files to modify"], keywords: ["relevant terms"] }
406
+ \`\`\`
407
+ This returns:
408
+ - Relevant patterns from the server
409
+ - A session token (required for validation)
410
+ - Code examples to follow
372
411
 
373
- } catch (error) {
374
- log(`Error: ${error instanceof Error ? error.message : String(error)}`, options);
375
- spinner.warn('Could not install patterns');
376
- console.log(chalk.gray(' Check your internet connection.\n'));
377
- }
412
+ ### 2. validate_complete (MANDATORY - END GATE)
413
+ Call this BEFORE saying "done" or "complete":
414
+ \`\`\`
415
+ Tool: validate_complete
416
+ Args: { feature: "what you built", files: ["files modified"] }
417
+ \`\`\`
418
+ This checks:
419
+ - You called discover_patterns first (server verifies)
420
+ - Tests exist and pass
421
+ - TypeScript compiles
422
+ - Returns pass/fail from server
423
+
424
+ ## Rules
425
+
426
+ 1. **You CANNOT skip discover_patterns** - Server tracks compliance
427
+ 2. **You CANNOT say "done" without validate_complete** - Server must approve
428
+ 3. **Follow patterns returned by server** - They are mandatory
429
+ 4. **Write tests** - Validation will fail without them
430
+ 5. **Fix TypeScript errors** - Validation will fail with errors
431
+
432
+ ## If Server is Unreachable
433
+
434
+ The tools will show "OFFLINE MODE" if the server can't be reached. In this case:
435
+ - Enforcement is limited to local checks only
436
+ - You should still follow best practices
437
+ - Try again when connection is restored
438
+
439
+ ## Getting Help
440
+
441
+ - Run \`codebakers doctor\` to diagnose issues
442
+ - Run \`codebakers upgrade\` to update patterns
443
+ - Visit https://codebakers.ai/support for help
444
+
445
+ ---
446
+ *CodeBakers v6.0 - Server-Enforced Patterns*
447
+ `;
448
+
449
+ const V6_CURSORRULES = `# CodeBakers v6.0 - Server-Enforced Patterns
450
+
451
+ All patterns are server-side. No local pattern files needed.
452
+
453
+ ## Required MCP Tools
454
+
455
+ Before writing ANY code, you MUST use these CodeBakers MCP tools:
456
+
457
+ ### 1. discover_patterns (MANDATORY - START GATE)
458
+ Call this BEFORE writing any code:
459
+ - Tool: discover_patterns
460
+ - Args: { task: "what you're about to do", files: ["files to modify"], keywords: ["relevant terms"] }
461
+
462
+ Returns:
463
+ - Relevant patterns from the server
464
+ - A session token (required for validation)
465
+ - Code examples to follow
466
+
467
+ ### 2. validate_complete (MANDATORY - END GATE)
468
+ Call this BEFORE saying "done" or "complete":
469
+ - Tool: validate_complete
470
+ - Args: { feature: "what you built", files: ["files modified"] }
471
+
472
+ Checks:
473
+ - You called discover_patterns first (server verifies)
474
+ - Tests exist and pass
475
+ - TypeScript compiles
476
+ - Returns pass/fail from server
477
+
478
+ ## Rules
479
+
480
+ 1. You CANNOT skip discover_patterns - Server tracks compliance
481
+ 2. You CANNOT say "done" without validate_complete - Server must approve
482
+ 3. Follow patterns returned by server - They are mandatory
483
+ 4. Write tests - Validation will fail without them
484
+ 5. Fix TypeScript errors - Validation will fail with errors
485
+
486
+ ## If Server is Unreachable
487
+
488
+ The tools will show "OFFLINE MODE" if the server can't be reached. In this case:
489
+ - Enforcement is limited to local checks only
490
+ - You should still follow best practices
491
+ - Try again when connection is restored
492
+
493
+ ---
494
+ CodeBakers v6.0 - Server-Enforced Patterns
495
+ `;
496
+
497
+ /**
498
+ * Install v6.0 bootstrap files for API key users (paid users)
499
+ * Only installs minimal CLAUDE.md and .cursorrules - no .claude/ folder
500
+ */
501
+ async function installPatternsWithApiKey(apiKey: string, options: GoOptions = {}): Promise<void> {
502
+ log('Installing v6.0 bootstrap files (API key user)...', options);
503
+ await installBootstrapFiles(options, { apiKey });
378
504
  }
379
505
 
380
506
  /**
381
- * Install pattern files (CLAUDE.md and .claude/) for trial users
507
+ * Install v6.0 bootstrap files for trial users
508
+ * Only installs minimal CLAUDE.md and .cursorrules - no .claude/ folder
382
509
  */
383
510
  async function installPatterns(trialId: string, options: GoOptions = {}): Promise<void> {
384
- log(`Installing patterns with trial ID: ${trialId.substring(0, 8)}...`, options);
385
- const spinner = ora('Installing CodeBakers patterns...').start();
511
+ log(`Installing v6.0 bootstrap files (trial: ${trialId.substring(0, 8)}...)`, options);
512
+ await installBootstrapFiles(options, { trialId });
513
+ }
514
+
515
+ /**
516
+ * Install v6.0 minimal bootstrap files
517
+ * - CLAUDE.md: Instructions for Claude Code
518
+ * - .cursorrules: Instructions for Cursor
519
+ * - NO .claude/ folder - all patterns are server-side
520
+ */
521
+ async function installBootstrapFiles(options: GoOptions = {}, auth?: AuthInfo): Promise<void> {
522
+ const spinner = ora('Installing CodeBakers v6.0...').start();
386
523
  const cwd = process.cwd();
387
- const apiUrl = getApiUrl();
388
524
 
389
525
  try {
390
- // Fetch patterns using trial ID
391
- log(`Fetching from: ${apiUrl}/api/content`, options);
392
- const response = await fetch(`${apiUrl}/api/content`, {
393
- method: 'GET',
394
- headers: {
395
- 'X-Trial-ID': trialId,
396
- },
397
- });
398
-
399
- if (!response.ok) {
400
- log(`Primary endpoint failed: ${response.status}, trying trial endpoint...`, options);
401
- // Try without auth - some patterns may be available for trial
402
- const publicResponse = await fetch(`${apiUrl}/api/content/trial`, {
403
- method: 'GET',
404
- headers: {
405
- 'X-Trial-ID': trialId,
406
- },
407
- });
408
-
409
- if (!publicResponse.ok) {
410
- log(`Trial endpoint also failed: ${publicResponse.status}`, options);
411
- spinner.warn('Could not download patterns (will use MCP tools)');
526
+ const claudeMdPath = join(cwd, 'CLAUDE.md');
527
+ const cursorRulesPath = join(cwd, '.cursorrules');
528
+
529
+ // Check if already installed with v6
530
+ if (existsSync(claudeMdPath)) {
531
+ const content = readFileSync(claudeMdPath, 'utf-8');
532
+ if (content.includes('v6.0') && content.includes('discover_patterns')) {
533
+ spinner.succeed('CodeBakers v6.0 already installed');
412
534
  return;
413
535
  }
414
-
415
- const content: ContentResponse = await publicResponse.json();
416
- log(`Received version: ${content.version}, modules: ${Object.keys(content.modules || {}).length}`, options);
417
- await writePatternFiles(cwd, content, spinner, options, { trialId });
418
- return;
536
+ // Upgrade from v5
537
+ log('Upgrading from v5 to v6...', options);
419
538
  }
420
539
 
421
- const content: ContentResponse = await response.json();
422
- log(`Received version: ${content.version}, modules: ${Object.keys(content.modules || {}).length}`, options);
423
- await writePatternFiles(cwd, content, spinner, options, { trialId });
540
+ // Write v6.0 bootstrap files
541
+ writeFileSync(claudeMdPath, V6_CLAUDE_MD);
542
+ writeFileSync(cursorRulesPath, V6_CURSORRULES);
543
+
544
+ spinner.succeed('CodeBakers v6.0 installed');
545
+ console.log(chalk.gray(' Patterns are server-enforced via MCP tools\n'));
546
+
547
+ // Confirm install to server (non-blocking)
548
+ if (auth) {
549
+ const apiUrl = getApiUrl();
550
+ confirmDownload(apiUrl, auth, {
551
+ version: '6.0',
552
+ moduleCount: 0, // No local modules in v6
553
+ cliVersion: getCliVersion(),
554
+ command: 'go',
555
+ }).catch(() => {}); // Silently ignore
556
+ }
424
557
 
425
558
  } catch (error) {
426
559
  log(`Error: ${error instanceof Error ? error.message : String(error)}`, options);
427
- spinner.warn('Could not install patterns (will use MCP tools)');
428
- console.log(chalk.gray(' Patterns will be available via MCP tools.\n'));
429
- }
430
- }
431
-
432
- async function writePatternFiles(
433
- cwd: string,
434
- content: ContentResponse,
435
- spinner: ReturnType<typeof ora>,
436
- options: GoOptions = {},
437
- auth?: AuthInfo
438
- ): Promise<void> {
439
- log(`Writing pattern files to ${cwd}...`, options);
440
- // Check if patterns already exist
441
- const claudeMdPath = join(cwd, 'CLAUDE.md');
442
- if (existsSync(claudeMdPath)) {
443
- spinner.succeed('CodeBakers patterns already installed');
444
- return;
445
- }
446
-
447
- // Write CLAUDE.md (router file)
448
- if (content.router) {
449
- writeFileSync(claudeMdPath, content.router);
450
- }
451
-
452
- // Write pattern modules to .claude/
453
- const moduleCount = Object.keys(content.modules || {}).length;
454
- if (content.modules && moduleCount > 0) {
455
- const modulesDir = join(cwd, '.claude');
456
- if (!existsSync(modulesDir)) {
457
- mkdirSync(modulesDir, { recursive: true });
458
- }
459
-
460
- for (const [name, data] of Object.entries(content.modules)) {
461
- writeFileSync(join(modulesDir, name), data);
462
- }
463
- }
464
-
465
- // Update .gitignore to exclude encoded patterns
466
- const gitignorePath = join(cwd, '.gitignore');
467
- if (existsSync(gitignorePath)) {
468
- const { readFileSync } = await import('fs');
469
- const gitignore = readFileSync(gitignorePath, 'utf-8');
470
- if (!gitignore.includes('.claude/')) {
471
- writeFileSync(gitignorePath, gitignore + '\n# CodeBakers patterns\n.claude/\n');
472
- }
473
- }
474
-
475
- spinner.succeed(`CodeBakers patterns installed (v${content.version})`);
476
- console.log(chalk.gray(` ${moduleCount} pattern modules ready\n`));
477
-
478
- // Confirm download to server (non-blocking)
479
- if (auth) {
480
- const apiUrl = getApiUrl();
481
- confirmDownload(apiUrl, auth, {
482
- version: content.version,
483
- moduleCount,
484
- cliVersion: getCliVersion(),
485
- command: 'go',
486
- }).catch(() => {}); // Silently ignore
560
+ spinner.warn('Could not install bootstrap files');
561
+ console.log(chalk.gray(' MCP tools will still work without local files.\n'));
487
562
  }
488
563
  }