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