@codebakers/cli 3.8.6 → 3.8.7

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,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, existsSync, readFileSync } from 'fs';
4
+ import { writeFileSync, existsSync, readFileSync, mkdirSync, readdirSync, statSync, rmSync } from 'fs';
5
5
  import { join } from 'path';
6
6
  import { createInterface } from 'readline';
7
7
  import {
@@ -16,6 +16,8 @@ import {
16
16
  } from '../config.js';
17
17
  import { validateApiKey } from '../lib/api.js';
18
18
  import { getDeviceFingerprint } from '../lib/fingerprint.js';
19
+ import { audit } from './audit.js';
20
+ import { heal } from './heal.js';
19
21
 
20
22
  function prompt(question: string): Promise<string> {
21
23
  const rl = createInterface({
@@ -26,11 +28,747 @@ function prompt(question: string): Promise<string> {
26
28
  return new Promise((resolve) => {
27
29
  rl.question(question, (answer) => {
28
30
  rl.close();
29
- resolve(answer.trim().toLowerCase());
31
+ resolve(answer.trim());
30
32
  });
31
33
  });
32
34
  }
33
35
 
36
+ async function confirm(question: string): Promise<boolean> {
37
+ const answer = await prompt(`${question} (Y/n): `);
38
+ return answer.toLowerCase() !== 'n';
39
+ }
40
+
41
+ // ============================================================================
42
+ // PROJECT DETECTION
43
+ // ============================================================================
44
+
45
+ function countSourceFiles(dir: string): number {
46
+ let count = 0;
47
+ try {
48
+ const items = readdirSync(dir, { withFileTypes: true });
49
+ for (const item of items) {
50
+ if (item.name.startsWith('.') || item.name === 'node_modules') continue;
51
+ const fullPath = join(dir, item.name);
52
+ if (item.isDirectory()) {
53
+ count += countSourceFiles(fullPath);
54
+ } else if (
55
+ item.name.endsWith('.ts') ||
56
+ item.name.endsWith('.tsx') ||
57
+ item.name.endsWith('.js') ||
58
+ item.name.endsWith('.jsx')
59
+ ) {
60
+ count++;
61
+ }
62
+ }
63
+ } catch {
64
+ // Ignore access errors
65
+ }
66
+ return count;
67
+ }
68
+
69
+ interface ProjectInfo {
70
+ exists: boolean;
71
+ files: number;
72
+ details: string[];
73
+ stack: Record<string, string>;
74
+ }
75
+
76
+ function detectExistingProject(cwd: string): ProjectInfo {
77
+ const details: string[] = [];
78
+ const stack: Record<string, string> = {};
79
+ let sourceFileCount = 0;
80
+
81
+ const packageJsonPath = join(cwd, 'package.json');
82
+ if (existsSync(packageJsonPath)) {
83
+ try {
84
+ const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
85
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
86
+ const depCount = Object.keys(pkg.dependencies || {}).length;
87
+
88
+ if (depCount > 0) {
89
+ details.push(`package.json with ${depCount} dependencies`);
90
+ }
91
+
92
+ if (deps['next']) stack.framework = `Next.js ${deps['next']}`;
93
+ else if (deps['react']) stack.framework = `React ${deps['react']}`;
94
+ else if (deps['vue']) stack.framework = `Vue ${deps['vue']}`;
95
+ else if (deps['express']) stack.framework = `Express ${deps['express']}`;
96
+
97
+ if (deps['drizzle-orm']) stack.database = 'Drizzle ORM';
98
+ else if (deps['prisma']) stack.database = 'Prisma';
99
+ else if (deps['mongoose']) stack.database = 'MongoDB/Mongoose';
100
+
101
+ if (deps['@supabase/supabase-js']) stack.auth = 'Supabase Auth';
102
+ else if (deps['next-auth']) stack.auth = 'NextAuth.js';
103
+ else if (deps['@clerk/nextjs']) stack.auth = 'Clerk';
104
+
105
+ if (deps['tailwindcss']) stack.styling = 'Tailwind CSS';
106
+ if (deps['typescript'] || existsSync(join(cwd, 'tsconfig.json'))) {
107
+ stack.language = 'TypeScript';
108
+ } else {
109
+ stack.language = 'JavaScript';
110
+ }
111
+
112
+ if (deps['vitest']) stack.testing = 'Vitest';
113
+ else if (deps['jest']) stack.testing = 'Jest';
114
+ else if (deps['@playwright/test']) stack.testing = 'Playwright';
115
+ } catch {
116
+ // Ignore parse errors
117
+ }
118
+ }
119
+
120
+ const sourceDirs = ['src', 'app', 'pages', 'components', 'lib'];
121
+ for (const dir of sourceDirs) {
122
+ const dirPath = join(cwd, dir);
123
+ if (existsSync(dirPath)) {
124
+ try {
125
+ if (statSync(dirPath).isDirectory()) {
126
+ const files = countSourceFiles(dirPath);
127
+ if (files > 0) {
128
+ sourceFileCount += files;
129
+ details.push(`${dir}/ with ${files} source files`);
130
+ }
131
+ }
132
+ } catch {
133
+ // Ignore access errors
134
+ }
135
+ }
136
+ }
137
+
138
+ const configFiles = ['tsconfig.json', 'next.config.js', 'next.config.mjs', 'vite.config.ts', 'tailwind.config.js'];
139
+ for (const file of configFiles) {
140
+ if (existsSync(join(cwd, file))) {
141
+ details.push(file);
142
+ }
143
+ }
144
+
145
+ return {
146
+ exists: sourceFileCount > 5 || details.length >= 3,
147
+ files: sourceFileCount,
148
+ details,
149
+ stack
150
+ };
151
+ }
152
+
153
+ function buildStructureString(cwd: string): string {
154
+ try {
155
+ const items = readdirSync(cwd);
156
+ const dirs: string[] = [];
157
+ const files: string[] = [];
158
+
159
+ for (const item of items) {
160
+ if (item.startsWith('.') || item === 'node_modules') continue;
161
+ const fullPath = join(cwd, item);
162
+ try {
163
+ if (statSync(fullPath).isDirectory()) {
164
+ dirs.push(item + '/');
165
+ } else {
166
+ files.push(item);
167
+ }
168
+ } catch {
169
+ // Skip inaccessible items
170
+ }
171
+ }
172
+
173
+ return [...dirs.sort(), ...files.sort()].join('\n');
174
+ } catch {
175
+ return '[Could not scan structure]';
176
+ }
177
+ }
178
+
179
+ // ============================================================================
180
+ // GUIDED QUESTIONS FOR NEW PROJECTS
181
+ // ============================================================================
182
+
183
+ interface GuidedAnswers {
184
+ oneLiner: string;
185
+ problem: string;
186
+ users: string;
187
+ features: string[];
188
+ auth: boolean;
189
+ payments: boolean;
190
+ integrations: string;
191
+ deadline: string;
192
+ }
193
+
194
+ async function runGuidedQuestions(): Promise<GuidedAnswers> {
195
+ console.log(chalk.cyan('\n ━━━ Let\'s define your project ━━━\n'));
196
+ console.log(chalk.gray(' Answer these questions (press Enter to skip any)\n'));
197
+
198
+ console.log(chalk.white(' 1. What are you building?\n'));
199
+ const oneLiner = await prompt(' ') || 'A web application';
200
+
201
+ console.log(chalk.white('\n 2. What problem does this solve?\n'));
202
+ const problem = await prompt(' ') || '';
203
+
204
+ console.log(chalk.white('\n 3. Who will use this?\n'));
205
+ console.log(chalk.gray(' (e.g., "small business owners", "freelancers", "developers")\n'));
206
+ const users = await prompt(' ') || 'General users';
207
+
208
+ console.log(chalk.white('\n 4. What are the 3 must-have features?\n'));
209
+ console.log(chalk.gray(' (Enter each feature, then press Enter. Type "done" when finished)\n'));
210
+ const features: string[] = [];
211
+ for (let i = 0; i < 5; i++) {
212
+ const feature = await prompt(` Feature ${i + 1}: `);
213
+ if (!feature || feature.toLowerCase() === 'done') break;
214
+ features.push(feature);
215
+ }
216
+
217
+ console.log(chalk.white('\n 5. Do users need to create accounts?\n'));
218
+ const authAnswer = await prompt(' (y/n): ');
219
+ const auth = authAnswer.toLowerCase() === 'y' || authAnswer.toLowerCase() === 'yes';
220
+
221
+ console.log(chalk.white('\n 6. Will you charge money?\n'));
222
+ const paymentsAnswer = await prompt(' (y/n): ');
223
+ const payments = paymentsAnswer.toLowerCase() === 'y' || paymentsAnswer.toLowerCase() === 'yes';
224
+
225
+ console.log(chalk.white('\n 7. Any specific integrations needed?\n'));
226
+ console.log(chalk.gray(' (e.g., "Stripe, SendGrid, Twilio" or press Enter to skip)\n'));
227
+ const integrations = await prompt(' ') || '';
228
+
229
+ console.log(chalk.white('\n 8. When do you need this done?\n'));
230
+ console.log(chalk.gray(' (e.g., "2 weeks", "end of month", or press Enter to skip)\n'));
231
+ const deadline = await prompt(' ') || '';
232
+
233
+ console.log(chalk.green('\n ✓ Got it! Creating your PRD...\n'));
234
+
235
+ return { oneLiner, problem, users, features, auth, payments, integrations, deadline };
236
+ }
237
+
238
+ function createPrdFromAnswers(projectName: string, projectType: string, answers: GuidedAnswers): string {
239
+ const date = new Date().toISOString().split('T')[0];
240
+
241
+ const featuresSection = answers.features.length > 0
242
+ ? answers.features.map((f, i) => `${i + 1}. [ ] **${f}**`).join('\n')
243
+ : '1. [ ] **Feature 1:** [To be defined]\n2. [ ] **Feature 2:** [To be defined]';
244
+
245
+ const techRequirements: string[] = [];
246
+ if (answers.auth) techRequirements.push('User authentication (Supabase Auth)');
247
+ if (answers.payments) techRequirements.push('Payment processing (Stripe)');
248
+ if (answers.integrations) techRequirements.push(answers.integrations);
249
+
250
+ return `# Product Requirements Document
251
+ # Project: ${projectName}
252
+ # Created: ${date}
253
+ # Type: ${projectType}
254
+
255
+ ## Overview
256
+ **One-liner:** ${answers.oneLiner}
257
+
258
+ **Problem:** ${answers.problem || '[To be refined]'}
259
+
260
+ **Solution:** ${answers.oneLiner}
261
+
262
+ ## Target Users
263
+ - **Primary:** ${answers.users}
264
+
265
+ ## Core Features (MVP)
266
+ ${featuresSection}
267
+
268
+ ## Technical Requirements
269
+ ${techRequirements.length > 0 ? techRequirements.map(t => `- ${t}`).join('\n') : '- [No specific requirements noted]'}
270
+
271
+ ## Timeline
272
+ ${answers.deadline ? `- **Target:** ${answers.deadline}` : '- [No deadline specified]'}
273
+
274
+ ## Notes
275
+ - Authentication: ${answers.auth ? 'Yes - users need accounts' : 'No - public access'}
276
+ - Payments: ${answers.payments ? 'Yes - will charge users' : 'No - free to use'}
277
+
278
+ ---
279
+ <!-- Generated from guided questions - AI reads this to build your project -->
280
+ `;
281
+ }
282
+
283
+ function createPrdTemplate(projectName: string, projectType: string): string {
284
+ const date = new Date().toISOString().split('T')[0];
285
+
286
+ const typeSpecificSections = projectType === 'client'
287
+ ? `
288
+ ## Client Info
289
+ - Client Name: [Who is this for?]
290
+ - Contact: [Primary contact]
291
+ - Deadline: [When is this due?]
292
+ `
293
+ : projectType === 'business'
294
+ ? `
295
+ ## Business Context
296
+ - Target Market: [Who are you selling to?]
297
+ - Revenue Model: [How does this make money?]
298
+ - MVP Deadline: [When do you need to launch?]
299
+ `
300
+ : `
301
+ ## Personal Goals
302
+ - Why am I building this? [Your motivation]
303
+ - Learning goals: [What do you want to learn?]
304
+ `;
305
+
306
+ return `# Product Requirements Document
307
+ # Project: ${projectName}
308
+ # Created: ${date}
309
+ # Type: ${projectType}
310
+
311
+ ## Overview
312
+ **One-liner:** [Describe this project in one sentence]
313
+
314
+ **Problem:** [What problem does this solve?]
315
+
316
+ **Solution:** [How does this solve it?]
317
+ ${typeSpecificSections}
318
+ ## Target Users
319
+ - **Primary:** [Who is the main user?]
320
+ - **Secondary:** [Other users?]
321
+
322
+ ## Core Features (MVP)
323
+ 1. [ ] **Feature 1:** [Description]
324
+ 2. [ ] **Feature 2:** [Description]
325
+ 3. [ ] **Feature 3:** [Description]
326
+
327
+ ## Nice-to-Have Features (Post-MVP)
328
+ 1. [ ] [Feature description]
329
+ 2. [ ] [Feature description]
330
+
331
+ ## Technical Requirements
332
+ - **Must use:** [Required technologies, APIs, etc.]
333
+ - **Must avoid:** [Things you don't want]
334
+
335
+ ## Success Metrics
336
+ - [ ] [How will you measure success?]
337
+ - [ ] [What does "done" look like?]
338
+
339
+ ---
340
+ <!-- AI reads this file to understand what to build -->
341
+ `;
342
+ }
343
+
344
+ // ============================================================================
345
+ // PROJECT FILE CREATION
346
+ // ============================================================================
347
+
348
+ function createProjectContext(projectName: string, stack: Record<string, string>, structure: string, isExisting: boolean): string {
349
+ const date = new Date().toISOString().split('T')[0];
350
+ return `# PROJECT CONTEXT
351
+ # Last Scanned: ${date}
352
+ # Mode: ${isExisting ? 'Existing Project' : 'New Project'}
353
+
354
+ ## Overview
355
+ name: ${projectName}
356
+ description: ${isExisting ? '[Existing project - AI will analyze on first interaction]' : '[AI will fill after first feature]'}
357
+
358
+ ## Tech Stack
359
+ framework: ${stack.framework || '[Not detected]'}
360
+ language: ${stack.language || '[Not detected]'}
361
+ database: ${stack.database || '[Not detected]'}
362
+ auth: ${stack.auth || '[Not detected]'}
363
+ styling: ${stack.styling || '[Not detected]'}
364
+ testing: ${stack.testing || '[Not detected]'}
365
+
366
+ ## Project Structure
367
+ \`\`\`
368
+ ${structure || '[Empty project]'}
369
+ \`\`\`
370
+
371
+ ## Key Files
372
+ <!-- AI: List the most important files for understanding the project -->
373
+ - Entry point: ${stack.framework?.includes('Next') ? 'src/app/page.tsx or pages/index.tsx' : '[AI will identify]'}
374
+ - Config: ${existsSync(join(process.cwd(), 'tsconfig.json')) ? 'tsconfig.json' : '[AI will identify]'}
375
+ - Database schema: [AI will identify]
376
+ - API routes: ${stack.framework?.includes('Next') ? 'src/app/api/ or pages/api/' : '[AI will identify]'}
377
+
378
+ ## Existing Patterns
379
+ <!-- AI: Document patterns you find so you can reuse them -->
380
+
381
+ ### API Route Pattern
382
+ \`\`\`typescript
383
+ [AI: Copy an example API route pattern from this project]
384
+ \`\`\`
385
+
386
+ ### Component Pattern
387
+ \`\`\`typescript
388
+ [AI: Copy an example component pattern from this project]
389
+ \`\`\`
390
+
391
+ ## Environment Variables
392
+ <!-- AI: List required env vars (don't include values!) -->
393
+ ${existsSync(join(process.cwd(), '.env.example')) ? '[Check .env.example]' : '- [ ] [AI will identify required vars]'}
394
+
395
+ ## Notes
396
+ <!-- AI: Any important context about this specific project -->
397
+ `;
398
+ }
399
+
400
+ function createProjectState(projectName: string, isExisting: boolean): string {
401
+ const date = new Date().toISOString().split('T')[0];
402
+ return `# PROJECT STATE
403
+ # Last Updated: ${date}
404
+ # Auto-maintained by AI - update when starting/completing tasks
405
+
406
+ ## Project Info
407
+ name: ${projectName}
408
+ phase: ${isExisting ? 'active' : 'planning'}
409
+ mode: ${isExisting ? 'existing-project' : 'new-project'}
410
+
411
+ ## Current Sprint
412
+ Goal: ${isExisting ? '[AI will identify based on conversation]' : '[Define in first conversation]'}
413
+
414
+ ## In Progress
415
+ <!-- AI: Add tasks here when you START working on them -->
416
+ <!-- Format: - [task] (started: date, agent: cursor/claude) -->
417
+
418
+ ## Completed
419
+ <!-- AI: Move tasks here when DONE -->
420
+ <!-- Format: - [task] (completed: date) -->
421
+ ${isExisting ? `\n- CodeBakers integration (completed: ${date})` : ''}
422
+
423
+ ## Blockers
424
+ <!-- AI: List anything blocking progress -->
425
+
426
+ ## Next Up
427
+ <!-- AI: Queue of upcoming tasks -->
428
+ `;
429
+ }
430
+
431
+ function createDecisionsLog(projectName: string): string {
432
+ const date = new Date().toISOString().split('T')[0];
433
+ return `# ARCHITECTURAL DECISIONS
434
+ # Project: ${projectName}
435
+ # AI: Add entries here when making significant technical choices
436
+
437
+ ## How to Use This File
438
+ When you make a decision that affects architecture, add an entry:
439
+ - Date
440
+ - Decision
441
+ - Reason
442
+ - Alternatives considered
443
+
444
+ ---
445
+
446
+ ## ${date}: CodeBakers Initialized
447
+ **Decision:** Using CodeBakers server-enforced pattern system
448
+ **Reason:** Ensure consistent, production-quality code
449
+ **Pattern:** Server-enforced via discover_patterns MCP tool
450
+
451
+ ---
452
+
453
+ <!-- AI: Add new decisions above this line -->
454
+ `;
455
+ }
456
+
457
+ function createDevlog(projectName: string, isExisting: boolean, auditScore?: number): string {
458
+ const date = new Date().toISOString().split('T')[0];
459
+ const timestamp = new Date().toISOString();
460
+
461
+ return `# Development Log
462
+ # Project: ${projectName}
463
+
464
+ ## ${date} - CodeBakers Integration
465
+ **Session:** ${timestamp}
466
+ **Task Size:** MEDIUM
467
+ **Status:** Completed
468
+
469
+ ### What was done:
470
+ - Integrated CodeBakers into ${isExisting ? 'existing' : 'new'} project
471
+ - Created project tracking files
472
+ - Configured AI assistants (Cursor + Claude Code)
473
+ ${isExisting && auditScore !== undefined ? `- Ran initial code audit (Score: ${auditScore}%)` : ''}
474
+
475
+ ### Files created:
476
+ - \`CLAUDE.md\` - AI bootstrap file
477
+ - \`.cursorrules\` - Cursor IDE rules
478
+ - \`PROJECT-CONTEXT.md\` - Project knowledge base
479
+ - \`PROJECT-STATE.md\` - Task tracking
480
+ - \`DECISIONS.md\` - Architecture log
481
+ - \`.codebakers/DEVLOG.md\` - This file
482
+
483
+ ### Next steps:
484
+ ${isExisting ? '- Start using AI assistance with existing codebase' : '- Define project requirements in first conversation'}
485
+ ${isExisting ? '- AI will analyze existing patterns on first interaction' : '- AI will help scaffold initial features'}
486
+
487
+ ---
488
+ `;
489
+ }
490
+
491
+ // ============================================================================
492
+ // IDE AND MCP SETUP
493
+ // ============================================================================
494
+
495
+ const CURSORRULES_TEMPLATE = `# CODEBAKERS CURSOR RULES
496
+ # Zero-friction AI assistance - everything is automatic
497
+
498
+ ## ON EVERY MESSAGE - AUTOMATIC WORKFLOW
499
+
500
+ ### PHASE 1: CONTEXT LOAD (automatic)
501
+ 1. Read CLAUDE.md → Load router
502
+ 2. Read PROJECT-CONTEXT.md → Understand codebase
503
+ 3. Read PROJECT-STATE.md → Check what's in progress
504
+ 4. Read DECISIONS.md → Know past decisions
505
+
506
+ ### PHASE 2: PRE-FLIGHT CHECK (before writing code)
507
+ Ask yourself silently:
508
+ - [ ] What existing code does this touch? (check PROJECT-CONTEXT.md)
509
+ - [ ] Is similar code already in the codebase? (copy that pattern)
510
+ - [ ] What's the data model involved?
511
+ - [ ] What are the error cases?
512
+
513
+ ### PHASE 3: EXECUTE
514
+ - State: \`📋 CodeBakers | [Type] | Server-Enforced\`
515
+ - Call discover_patterns MCP tool first
516
+ - Follow patterns from server EXACTLY
517
+
518
+ ### PHASE 4: SELF-REVIEW (before saying "done")
519
+ - [ ] TypeScript compiles? (npx tsc --noEmit)
520
+ - [ ] Imports resolve correctly?
521
+ - [ ] Error handling exists?
522
+ - [ ] Matches existing patterns in codebase?
523
+ - [ ] Tests written?
524
+ - [ ] PROJECT-STATE.md updated?
525
+
526
+ If ANY check fails, fix it before responding.
527
+
528
+ ### PHASE 5: UPDATE STATE
529
+ - Update PROJECT-STATE.md with completed work
530
+ - Add to DECISIONS.md if architectural choice was made
531
+ - Update .codebakers/DEVLOG.md with session summary
532
+
533
+ ## REMEMBER
534
+ - You are a full product team, not just a code assistant
535
+ - The modules contain production-tested patterns — USE THEM
536
+ - When in doubt, check existing code first
537
+ `;
538
+
539
+ const CURSORIGNORE_TEMPLATE = `# CodeBakers - Files to ignore in Cursor context
540
+
541
+ # Dependencies
542
+ node_modules/
543
+ .pnpm-store/
544
+
545
+ # Build outputs
546
+ dist/
547
+ build/
548
+ .next/
549
+ .nuxt/
550
+ out/
551
+
552
+ # Cache
553
+ .cache/
554
+ .turbo/
555
+ *.tsbuildinfo
556
+
557
+ # Logs
558
+ logs/
559
+ *.log
560
+
561
+ # Environment files (don't leak secrets)
562
+ .env
563
+ .env.local
564
+ .env.*.local
565
+
566
+ # IDE
567
+ .idea/
568
+ *.swp
569
+
570
+ # OS
571
+ .DS_Store
572
+ Thumbs.db
573
+
574
+ # Test coverage
575
+ coverage/
576
+
577
+ # Package locks
578
+ package-lock.json
579
+ yarn.lock
580
+ pnpm-lock.yaml
581
+
582
+ # Generated files
583
+ *.min.js
584
+ *.min.css
585
+ *.map
586
+ `;
587
+
588
+ const VSCODE_SETTINGS_TEMPLATE = {
589
+ "cursor.chat.defaultContext": [
590
+ "CLAUDE.md",
591
+ "PROJECT-CONTEXT.md",
592
+ "PROJECT-STATE.md",
593
+ "DECISIONS.md"
594
+ ],
595
+ "cursor.chat.alwaysIncludeRules": true,
596
+ "cursor.composer.alwaysIncludeRules": true,
597
+ "cursor.general.enableAutoImport": true
598
+ };
599
+
600
+ function setupCursorIDE(cwd: string): void {
601
+ const spinner = ora(' Setting up Cursor IDE...').start();
602
+
603
+ try {
604
+ // Write .cursorrules and .cursorignore
605
+ writeFileSync(join(cwd, '.cursorrules'), CURSORRULES_TEMPLATE);
606
+ writeFileSync(join(cwd, '.cursorignore'), CURSORIGNORE_TEMPLATE);
607
+
608
+ // Global MCP config for Cursor
609
+ const homeDir = process.env.USERPROFILE || process.env.HOME || '';
610
+ const globalCursorDir = join(homeDir, '.cursor');
611
+ if (!existsSync(globalCursorDir)) {
612
+ mkdirSync(globalCursorDir, { recursive: true });
613
+ }
614
+
615
+ const mcpConfigPath = join(globalCursorDir, 'mcp.json');
616
+ const isWindows = process.platform === 'win32';
617
+ const mcpConfig = {
618
+ mcpServers: {
619
+ codebakers: isWindows
620
+ ? { command: 'cmd', args: ['/c', 'npx', '-y', '@codebakers/cli', 'serve'] }
621
+ : { command: 'npx', args: ['-y', '@codebakers/cli', 'serve'] }
622
+ }
623
+ };
624
+
625
+ if (existsSync(mcpConfigPath)) {
626
+ try {
627
+ const existing = JSON.parse(readFileSync(mcpConfigPath, 'utf-8'));
628
+ existing.mcpServers = { ...existing.mcpServers, ...mcpConfig.mcpServers };
629
+ writeFileSync(mcpConfigPath, JSON.stringify(existing, null, 2));
630
+ } catch {
631
+ writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));
632
+ }
633
+ } else {
634
+ writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));
635
+ }
636
+
637
+ // VSCode settings
638
+ const vscodeDir = join(cwd, '.vscode');
639
+ if (!existsSync(vscodeDir)) {
640
+ mkdirSync(vscodeDir, { recursive: true });
641
+ }
642
+
643
+ const settingsPath = join(vscodeDir, 'settings.json');
644
+ if (existsSync(settingsPath)) {
645
+ try {
646
+ const existing = JSON.parse(readFileSync(settingsPath, 'utf-8'));
647
+ writeFileSync(settingsPath, JSON.stringify({ ...existing, ...VSCODE_SETTINGS_TEMPLATE }, null, 2));
648
+ } catch {
649
+ writeFileSync(settingsPath, JSON.stringify(VSCODE_SETTINGS_TEMPLATE, null, 2));
650
+ }
651
+ } else {
652
+ writeFileSync(settingsPath, JSON.stringify(VSCODE_SETTINGS_TEMPLATE, null, 2));
653
+ }
654
+
655
+ spinner.succeed('Cursor IDE configured!');
656
+ } catch {
657
+ spinner.warn('Could not configure Cursor IDE (continuing anyway)');
658
+ }
659
+ }
660
+
661
+ function setupClaudeCodeMCP(): void {
662
+ const spinner = ora(' Setting up Claude Code MCP...').start();
663
+
664
+ try {
665
+ const homeDir = process.env.USERPROFILE || process.env.HOME || '';
666
+ let configPath: string;
667
+ const isWindows = process.platform === 'win32';
668
+
669
+ if (isWindows) {
670
+ configPath = join(homeDir, 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json');
671
+ } else if (process.platform === 'darwin') {
672
+ configPath = join(homeDir, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
673
+ } else {
674
+ configPath = join(homeDir, '.config', 'claude', 'claude_desktop_config.json');
675
+ }
676
+
677
+ const configDir = join(configPath, '..');
678
+ if (!existsSync(configDir)) {
679
+ mkdirSync(configDir, { recursive: true });
680
+ }
681
+
682
+ const mcpConfig = {
683
+ mcpServers: {
684
+ codebakers: isWindows
685
+ ? { command: 'cmd', args: ['/c', 'npx', '-y', '@codebakers/cli', 'serve'] }
686
+ : { command: 'npx', args: ['-y', '@codebakers/cli', 'serve'] }
687
+ }
688
+ };
689
+
690
+ if (existsSync(configPath)) {
691
+ try {
692
+ const existing = JSON.parse(readFileSync(configPath, 'utf-8'));
693
+ if (!existing.mcpServers) {
694
+ existing.mcpServers = {};
695
+ }
696
+ existing.mcpServers.codebakers = mcpConfig.mcpServers.codebakers;
697
+ writeFileSync(configPath, JSON.stringify(existing, null, 2));
698
+ } catch {
699
+ writeFileSync(configPath, JSON.stringify(mcpConfig, null, 2));
700
+ }
701
+ } else {
702
+ writeFileSync(configPath, JSON.stringify(mcpConfig, null, 2));
703
+ }
704
+
705
+ spinner.succeed('Claude Code MCP configured!');
706
+ } catch {
707
+ spinner.warn('Could not configure Claude Code MCP (continuing anyway)');
708
+ }
709
+ }
710
+
711
+ function createTrackingFiles(cwd: string, projectName: string, stack: Record<string, string>, structure: string, isExisting: boolean, auditScore?: number): void {
712
+ const spinner = ora(' Creating project tracking files...').start();
713
+
714
+ try {
715
+ // Create .codebakers directory
716
+ const codebakersDir = join(cwd, '.codebakers');
717
+ if (!existsSync(codebakersDir)) {
718
+ mkdirSync(codebakersDir, { recursive: true });
719
+ }
720
+
721
+ // Remove old .claude folder if it exists
722
+ const claudeDir = join(cwd, '.claude');
723
+ if (existsSync(claudeDir)) {
724
+ try {
725
+ rmSync(claudeDir, { recursive: true, force: true });
726
+ } catch {
727
+ // Ignore errors
728
+ }
729
+ }
730
+
731
+ // PROJECT-CONTEXT.md
732
+ writeFileSync(join(cwd, 'PROJECT-CONTEXT.md'), createProjectContext(projectName, stack, structure, isExisting));
733
+
734
+ // PROJECT-STATE.md
735
+ writeFileSync(join(cwd, 'PROJECT-STATE.md'), createProjectState(projectName, isExisting));
736
+
737
+ // DECISIONS.md
738
+ writeFileSync(join(cwd, 'DECISIONS.md'), createDecisionsLog(projectName));
739
+
740
+ // .codebakers/DEVLOG.md
741
+ writeFileSync(join(codebakersDir, 'DEVLOG.md'), createDevlog(projectName, isExisting, auditScore));
742
+
743
+ // .codebakers.json state file
744
+ const stateFile = join(cwd, '.codebakers.json');
745
+ const state = {
746
+ version: '1.0',
747
+ serverEnforced: true,
748
+ projectType: isExisting ? 'existing' : 'new',
749
+ projectName,
750
+ createdAt: new Date().toISOString(),
751
+ stack,
752
+ auditScore: auditScore
753
+ };
754
+ writeFileSync(stateFile, JSON.stringify(state, null, 2));
755
+
756
+ spinner.succeed('Project tracking files created!');
757
+ } catch {
758
+ spinner.warn('Some tracking files could not be created');
759
+ }
760
+ }
761
+
762
+ function updateGitignore(cwd: string): void {
763
+ const gitignorePath = join(cwd, '.gitignore');
764
+ if (existsSync(gitignorePath)) {
765
+ const gitignore = readFileSync(gitignorePath, 'utf-8');
766
+ if (!gitignore.includes('.cursorrules')) {
767
+ writeFileSync(gitignorePath, gitignore + '\n# CodeBakers\n.cursorrules\n');
768
+ }
769
+ }
770
+ }
771
+
34
772
  interface GoOptions {
35
773
  verbose?: boolean;
36
774
  }
@@ -116,9 +854,8 @@ export async function go(options: GoOptions = {}): Promise<void> {
116
854
  log(`Found API key: ${existingApiKey.substring(0, 8)}...`, options);
117
855
  console.log(chalk.green(' ✓ You\'re already logged in!\n'));
118
856
 
119
- // Install patterns if not already installed
120
- await installPatternsWithApiKey(existingApiKey, options);
121
- await configureMCP(options);
857
+ // Run complete project setup
858
+ await setupProject(options, { apiKey: existingApiKey });
122
859
  await showSuccessAndRestart();
123
860
  return;
124
861
  }
@@ -136,9 +873,8 @@ export async function go(options: GoOptions = {}): Promise<void> {
136
873
  console.log(chalk.cyan(' codebakers extend\n'));
137
874
  }
138
875
 
139
- // Install patterns if not already installed
140
- await installPatterns(existingTrial.trialId, options);
141
- await configureMCP(options);
876
+ // Run complete project setup
877
+ await setupProject(options, { trialId: existingTrial.trialId });
142
878
  await showSuccessAndRestart();
143
879
  return;
144
880
  }
@@ -263,13 +999,8 @@ async function startTrialWithGitHub(options: GoOptions = {}): Promise<void> {
263
999
  spinner.succeed(`Trial started (${data.daysRemaining} days free)${username}`);
264
1000
  console.log('');
265
1001
 
266
- // Install v6.0 bootstrap files
267
- await installPatterns(data.trialId, options);
268
-
269
- // Configure MCP
270
- await configureMCP(options);
271
-
272
- // Show success and restart
1002
+ // Run complete project setup
1003
+ await setupProject(options, { trialId: data.trialId });
273
1004
  await showSuccessAndRestart();
274
1005
  return;
275
1006
  }
@@ -286,30 +1017,6 @@ async function startTrialWithGitHub(options: GoOptions = {}): Promise<void> {
286
1017
  }
287
1018
  }
288
1019
 
289
- async function configureMCP(options: GoOptions = {}): Promise<void> {
290
- log('Configuring MCP integration...', options);
291
- const spinner = ora('Configuring Claude Code integration...').start();
292
- const isWindows = process.platform === 'win32';
293
-
294
- const mcpCmd = isWindows
295
- ? 'claude mcp add --transport stdio codebakers -- cmd /c npx -y @codebakers/cli serve'
296
- : 'claude mcp add --transport stdio codebakers -- npx -y @codebakers/cli serve';
297
-
298
- try {
299
- execSync(mcpCmd, { stdio: 'pipe' });
300
- spinner.succeed('CodeBakers connected to Claude Code');
301
- } catch (error) {
302
- const errorMessage = error instanceof Error ? error.message : String(error);
303
- if (errorMessage.includes('already exists') || errorMessage.includes('already registered')) {
304
- spinner.succeed('CodeBakers already connected to Claude Code');
305
- } else {
306
- spinner.warn('Could not auto-configure Claude Code');
307
- console.log(chalk.gray('\n Run this command manually:\n'));
308
- console.log(chalk.cyan(` ${mcpCmd}\n`));
309
- }
310
- }
311
- }
312
-
313
1020
  /**
314
1021
  * Handle API key login flow (for paid users)
315
1022
  */
@@ -334,13 +1041,8 @@ async function handleApiKeyLogin(options: GoOptions = {}): Promise<void> {
334
1041
  setApiKey(apiKey);
335
1042
  console.log(chalk.green(' ✓ Logged in successfully!\n'));
336
1043
 
337
- // Install patterns
338
- await installPatternsWithApiKey(apiKey, options);
339
-
340
- // Configure MCP
341
- await configureMCP(options);
342
-
343
- // Show success
1044
+ // Run complete project setup
1045
+ await setupProject(options, { apiKey });
344
1046
  await showSuccessAndRestart();
345
1047
 
346
1048
  } catch (error) {
@@ -513,69 +1215,264 @@ CodeBakers v6.0 - Server-Enforced Patterns
513
1215
  `;
514
1216
 
515
1217
  /**
516
- * Install v6.0 bootstrap files for API key users (paid users)
517
- * Only installs minimal CLAUDE.md and .cursorrules - no .claude/ folder
1218
+ * Complete project setup - handles everything:
1219
+ * - Detect new vs existing project
1220
+ * - Set up all tracking files
1221
+ * - Configure Cursor and Claude Code MCP
1222
+ * - Run guided questions for new projects
1223
+ * - Run code review for existing projects
518
1224
  */
519
- async function installPatternsWithApiKey(apiKey: string, options: GoOptions = {}): Promise<void> {
520
- log('Installing v6.0 bootstrap files (API key user)...', options);
521
- await installBootstrapFiles(options, { apiKey });
1225
+ async function setupProject(options: GoOptions = {}, auth?: AuthInfo): Promise<void> {
1226
+ const cwd = process.cwd();
1227
+
1228
+ // Detect if this is an existing project
1229
+ const projectInfo = detectExistingProject(cwd);
1230
+
1231
+ if (projectInfo.exists) {
1232
+ // Existing project detected
1233
+ await setupExistingProject(cwd, projectInfo, options, auth);
1234
+ } else {
1235
+ // New project
1236
+ await setupNewProject(cwd, options, auth);
1237
+ }
522
1238
  }
523
1239
 
524
- /**
525
- * Install v6.0 bootstrap files for trial users
526
- * Only installs minimal CLAUDE.md and .cursorrules - no .claude/ folder
527
- */
528
- async function installPatterns(trialId: string, options: GoOptions = {}): Promise<void> {
529
- log(`Installing v6.0 bootstrap files (trial: ${trialId.substring(0, 8)}...)`, options);
530
- await installBootstrapFiles(options, { trialId });
1240
+ async function setupNewProject(cwd: string, options: GoOptions = {}, auth?: AuthInfo): Promise<void> {
1241
+ console.log(chalk.cyan('\n ━━━ New Project Setup ━━━\n'));
1242
+
1243
+ // Get project info
1244
+ console.log(chalk.white(' What kind of project is this?\n'));
1245
+ console.log(chalk.gray(' 1. ') + chalk.cyan('PERSONAL') + chalk.gray(' - Just building for myself'));
1246
+ console.log(chalk.gray(' 2. ') + chalk.cyan('CLIENT') + chalk.gray(' - Building for someone else'));
1247
+ console.log(chalk.gray(' 3. ') + chalk.cyan('BUSINESS') + chalk.gray(' - My own product/startup\n'));
1248
+
1249
+ let typeChoice = '';
1250
+ while (!['1', '2', '3'].includes(typeChoice)) {
1251
+ typeChoice = await prompt(' Enter 1, 2, or 3: ');
1252
+ }
1253
+
1254
+ const typeMap: Record<string, string> = { '1': 'personal', '2': 'client', '3': 'business' };
1255
+ const projectType = typeMap[typeChoice];
1256
+
1257
+ const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
1258
+ const projectName = await prompt(` Project name (${defaultName}): `) || defaultName;
1259
+
1260
+ console.log(chalk.green(`\n ✓ Setting up "${projectName}" as ${projectType.toUpperCase()} project\n`));
1261
+
1262
+ // Install bootstrap files
1263
+ console.log(chalk.white(' Installing CodeBakers...\n'));
1264
+ installBootstrapFilesSync(cwd);
1265
+
1266
+ // Create tracking files
1267
+ const structure = buildStructureString(cwd);
1268
+ createTrackingFiles(cwd, projectName, {}, structure, false);
1269
+
1270
+ // Setup IDEs and MCP
1271
+ console.log('');
1272
+ setupCursorIDE(cwd);
1273
+ setupClaudeCodeMCP();
1274
+
1275
+ // Update .gitignore
1276
+ updateGitignore(cwd);
1277
+
1278
+ // How to describe project
1279
+ console.log(chalk.white('\n 📝 How would you like to describe your project?\n'));
1280
+ console.log(chalk.gray(' 1. ') + chalk.cyan('GUIDED QUESTIONS') + chalk.gray(' - I\'ll ask you step by step'));
1281
+ console.log(chalk.gray(' 2. ') + chalk.cyan('WRITE A PRD') + chalk.gray(' - Create a blank template to fill out'));
1282
+ console.log(chalk.gray(' 3. ') + chalk.cyan('PASTE/UPLOAD PRD') + chalk.gray(' - I already have requirements written'));
1283
+ console.log(chalk.gray(' 4. ') + chalk.cyan('DESCRIBE IN CHAT') + chalk.gray(' - Just tell the AI what you want'));
1284
+ console.log(chalk.gray(' 5. ') + chalk.cyan('SHARE FILES') + chalk.gray(' - I\'ll share docs/mockups/screenshots\n'));
1285
+
1286
+ let describeChoice = '';
1287
+ while (!['1', '2', '3', '4', '5'].includes(describeChoice)) {
1288
+ describeChoice = await prompt(' Enter 1-5: ');
1289
+ }
1290
+
1291
+ let prdCreated = false;
1292
+
1293
+ if (describeChoice === '1') {
1294
+ // Guided questions
1295
+ const answers = await runGuidedQuestions();
1296
+ const prdSpinner = ora(' Creating PRD from your answers...').start();
1297
+ writeFileSync(join(cwd, 'PRD.md'), createPrdFromAnswers(projectName, projectType, answers));
1298
+ prdSpinner.succeed('PRD created from your answers!');
1299
+ console.log(chalk.yellow('\n → Review PRD.md, then start building with the AI\n'));
1300
+ prdCreated = true;
1301
+ } else if (describeChoice === '2') {
1302
+ // Write PRD template
1303
+ const prdSpinner = ora(' Creating PRD template...').start();
1304
+ writeFileSync(join(cwd, 'PRD.md'), createPrdTemplate(projectName, projectType));
1305
+ prdSpinner.succeed('PRD template created!');
1306
+ console.log(chalk.yellow('\n → Open PRD.md and fill in your requirements\n'));
1307
+ prdCreated = true;
1308
+ } else if (describeChoice === '3') {
1309
+ // Paste/upload existing PRD
1310
+ console.log(chalk.cyan('\n ━━━ Paste Your Requirements ━━━\n'));
1311
+ console.log(chalk.gray(' Paste your PRD, requirements, or spec below.'));
1312
+ console.log(chalk.gray(' When done, type ') + chalk.cyan('END') + chalk.gray(' on a new line and press Enter.\n'));
1313
+
1314
+ const lines: string[] = [];
1315
+ let line = '';
1316
+ while (true) {
1317
+ line = await prompt(' ');
1318
+ if (line.toUpperCase() === 'END') break;
1319
+ lines.push(line);
1320
+ }
1321
+
1322
+ if (lines.length > 0) {
1323
+ const content = lines.join('\n');
1324
+ const prdContent = `# Product Requirements Document
1325
+ # Project: ${projectName}
1326
+ # Created: ${new Date().toISOString().split('T')[0]}
1327
+ # Type: ${projectType}
1328
+ # Source: Pasted by user
1329
+
1330
+ ${content}
1331
+
1332
+ ---
1333
+ <!-- User-provided requirements - AI reads this to build your project -->
1334
+ `;
1335
+ writeFileSync(join(cwd, 'PRD.md'), prdContent);
1336
+ console.log(chalk.green('\n ✓ Saved to PRD.md'));
1337
+ console.log(chalk.yellow(' → The AI will read this when you start building\n'));
1338
+ prdCreated = true;
1339
+ } else {
1340
+ console.log(chalk.gray('\n No content pasted. You can add PRD.md manually later.\n'));
1341
+ }
1342
+ } else if (describeChoice === '4') {
1343
+ // Describe in chat
1344
+ console.log(chalk.gray('\n Perfect! Just describe your project to the AI when you\'re ready.\n'));
1345
+ console.log(chalk.gray(' Example: "Build me a SaaS for invoice management with Stripe payments"\n'));
1346
+ } else {
1347
+ // Share files (option 5)
1348
+ console.log(chalk.gray('\n Great! When chatting with the AI:\n'));
1349
+ console.log(chalk.gray(' • Drag and drop your mockups or screenshots'));
1350
+ console.log(chalk.gray(' • Share links to Figma, design files, or websites'));
1351
+ console.log(chalk.gray(' • Reference existing apps: "Make it look like Linear"\n'));
1352
+ console.log(chalk.cyan(' The AI will analyze them and start building.\n'));
1353
+ }
1354
+
1355
+ // Confirm to server
1356
+ if (auth) {
1357
+ const apiUrl = getApiUrl();
1358
+ confirmDownload(apiUrl, auth, {
1359
+ version: '6.0',
1360
+ moduleCount: 0,
1361
+ cliVersion: getCliVersion(),
1362
+ command: 'go',
1363
+ projectName,
1364
+ }).catch(() => {});
1365
+ }
531
1366
  }
532
1367
 
533
- /**
534
- * Install v6.0 minimal bootstrap files
535
- * - CLAUDE.md: Instructions for Claude Code
536
- * - .cursorrules: Instructions for Cursor
537
- * - NO .claude/ folder - all patterns are server-side
538
- */
539
- async function installBootstrapFiles(options: GoOptions = {}, auth?: AuthInfo): Promise<void> {
540
- const spinner = ora('Installing CodeBakers v6.0...').start();
541
- const cwd = process.cwd();
1368
+ async function setupExistingProject(cwd: string, projectInfo: ProjectInfo, options: GoOptions = {}, auth?: AuthInfo): Promise<void> {
1369
+ console.log(chalk.cyan('\n ━━━ Existing Project Detected ━━━\n'));
542
1370
 
543
- try {
544
- const claudeMdPath = join(cwd, 'CLAUDE.md');
545
- const cursorRulesPath = join(cwd, '.cursorrules');
546
-
547
- // Check if already installed with v6
548
- if (existsSync(claudeMdPath)) {
549
- const content = readFileSync(claudeMdPath, 'utf-8');
550
- if (content.includes('v6.0') && content.includes('discover_patterns')) {
551
- spinner.succeed('CodeBakers v6.0 already installed');
552
- return;
1371
+ // Show what was detected
1372
+ console.log(chalk.gray(' Found:'));
1373
+ for (const detail of projectInfo.details.slice(0, 5)) {
1374
+ console.log(chalk.gray(` • ${detail}`));
1375
+ }
1376
+
1377
+ const stackItems = Object.entries(projectInfo.stack).filter(([_, v]) => v);
1378
+ if (stackItems.length > 0) {
1379
+ console.log(chalk.gray('\n Tech Stack:'));
1380
+ for (const [key, value] of stackItems) {
1381
+ console.log(chalk.gray(` • ${key}: ${value}`));
1382
+ }
1383
+ }
1384
+
1385
+ // Get project name
1386
+ const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
1387
+ const projectName = await prompt(`\n Project name (${defaultName}): `) || defaultName;
1388
+
1389
+ // Code review offer
1390
+ console.log(chalk.white('\n Want me to review your code and bring it up to CodeBakers standards?\n'));
1391
+ console.log(chalk.gray(' 1. ') + chalk.cyan('YES, REVIEW & FIX') + chalk.gray(' - Run audit, then auto-fix issues'));
1392
+ console.log(chalk.gray(' 2. ') + chalk.cyan('REVIEW ONLY') + chalk.gray(' - Just show me the issues'));
1393
+ console.log(chalk.gray(' 3. ') + chalk.cyan('SKIP') + chalk.gray(' - Just install CodeBakers\n'));
1394
+
1395
+ let reviewChoice = '';
1396
+ while (!['1', '2', '3'].includes(reviewChoice)) {
1397
+ reviewChoice = await prompt(' Enter 1, 2, or 3: ');
1398
+ }
1399
+
1400
+ let auditScore: number | undefined;
1401
+
1402
+ if (reviewChoice !== '3') {
1403
+ console.log(chalk.blue('\n Running code audit...\n'));
1404
+ const auditResult = await audit();
1405
+ auditScore = auditResult.score;
1406
+
1407
+ if (auditResult.score >= 90) {
1408
+ console.log(chalk.green('\n 🎉 Your code is already in great shape!\n'));
1409
+ } else if (reviewChoice === '1') {
1410
+ const fixableCount = auditResult.checks.filter(c => !c.passed && c.severity !== 'info').length;
1411
+ if (fixableCount > 0) {
1412
+ console.log(chalk.blue('\n 🔧 Attempting to auto-fix issues...\n'));
1413
+ const healResult = await heal({ auto: true });
1414
+
1415
+ if (healResult.fixed > 0) {
1416
+ console.log(chalk.green(`\n ✓ Fixed ${healResult.fixed} issue(s)!`));
1417
+ if (healResult.remaining > 0) {
1418
+ console.log(chalk.yellow(` ⚠ ${healResult.remaining} issue(s) need manual attention.`));
1419
+ }
1420
+ }
553
1421
  }
554
- // Upgrade from v5
555
- log('Upgrading from v5 to v6...', options);
1422
+ } else {
1423
+ console.log(chalk.gray('\n Run `codebakers heal --auto` later to fix issues.\n'));
556
1424
  }
1425
+ }
1426
+
1427
+ // Install files
1428
+ console.log(chalk.white('\n Installing CodeBakers...\n'));
1429
+ installBootstrapFilesSync(cwd);
1430
+
1431
+ // Create tracking files with detected stack
1432
+ const structure = buildStructureString(cwd);
1433
+ createTrackingFiles(cwd, projectName, projectInfo.stack, structure, true, auditScore);
1434
+
1435
+ // Setup IDEs and MCP
1436
+ console.log('');
1437
+ setupCursorIDE(cwd);
1438
+ setupClaudeCodeMCP();
1439
+
1440
+ // Update .gitignore
1441
+ updateGitignore(cwd);
1442
+
1443
+ // Confirm to server
1444
+ if (auth) {
1445
+ const apiUrl = getApiUrl();
1446
+ confirmDownload(apiUrl, auth, {
1447
+ version: '6.0',
1448
+ moduleCount: 0,
1449
+ cliVersion: getCliVersion(),
1450
+ command: 'go',
1451
+ projectName,
1452
+ }).catch(() => {});
1453
+ }
1454
+ }
1455
+
1456
+ function installBootstrapFilesSync(cwd: string): void {
1457
+ const spinner = ora(' Installing bootstrap files...').start();
557
1458
 
558
- // Write v6.0 bootstrap files
559
- writeFileSync(claudeMdPath, V6_CLAUDE_MD);
560
- writeFileSync(cursorRulesPath, V6_CURSORRULES);
561
-
562
- spinner.succeed('CodeBakers v6.0 installed');
563
- console.log(chalk.gray(' Patterns are server-enforced via MCP tools\n'));
564
-
565
- // Confirm install to server (non-blocking)
566
- if (auth) {
567
- const apiUrl = getApiUrl();
568
- confirmDownload(apiUrl, auth, {
569
- version: '6.0',
570
- moduleCount: 0, // No local modules in v6
571
- cliVersion: getCliVersion(),
572
- command: 'go',
573
- }).catch(() => {}); // Silently ignore
1459
+ try {
1460
+ writeFileSync(join(cwd, 'CLAUDE.md'), V6_CLAUDE_MD);
1461
+ // .cursorrules is written by setupCursorIDE
1462
+
1463
+ // Remove old .claude folder if it exists
1464
+ const claudeDir = join(cwd, '.claude');
1465
+ if (existsSync(claudeDir)) {
1466
+ try {
1467
+ rmSync(claudeDir, { recursive: true, force: true });
1468
+ } catch {
1469
+ // Ignore errors
1470
+ }
574
1471
  }
575
1472
 
1473
+ spinner.succeed('Bootstrap files installed!');
576
1474
  } catch (error) {
577
- log(`Error: ${error instanceof Error ? error.message : String(error)}`, options);
578
- spinner.warn('Could not install bootstrap files');
579
- console.log(chalk.gray(' MCP tools will still work without local files.\n'));
1475
+ spinner.fail('Failed to install bootstrap files');
1476
+ throw error;
580
1477
  }
581
1478
  }