@codebakers/cli 3.8.1 → 3.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,27 @@ const readline_1 = require("readline");
10
10
  const fs_1 = require("fs");
11
11
  const path_1 = require("path");
12
12
  const config_js_1 = require("../config.js");
13
- // Enhanced .cursorrules with pre-flight and self-review automation
13
+ const audit_js_1 = require("./audit.js");
14
+ const heal_js_1 = require("./heal.js");
15
+ // ============================================================================
16
+ // TEMPLATES
17
+ // ============================================================================
18
+ const CLAUDE_MD_BOOTSTRAP = `# CodeBakers
19
+
20
+ **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
21
+
22
+ \`\`\`
23
+ Tool: discover_patterns
24
+ Args: { task: "description of what you're building" }
25
+ \`\`\`
26
+
27
+ The server will return:
28
+ - All coding patterns and rules you must follow
29
+ - Test requirements
30
+ - Validation instructions
31
+
32
+ **You cannot write code without calling this tool first. The server tracks compliance.**
33
+ `;
14
34
  const CURSORRULES_TEMPLATE = `# CODEBAKERS CURSOR RULES
15
35
  # Zero-friction AI assistance - everything is automatic
16
36
 
@@ -18,10 +38,9 @@ const CURSORRULES_TEMPLATE = `# CODEBAKERS CURSOR RULES
18
38
 
19
39
  ### PHASE 1: CONTEXT LOAD (automatic)
20
40
  1. Read CLAUDE.md → Load router
21
- 2. Read PRD.md → Understand what we're building
22
- 3. Read PROJECT-CONTEXT.md → Understand codebase
23
- 4. Read PROJECT-STATE.md → Check what's in progress
24
- 5. Read DECISIONS.md → Know past decisions
41
+ 2. Read PROJECT-CONTEXT.md → Understand codebase
42
+ 3. Read PROJECT-STATE.md → Check what's in progress
43
+ 4. Read DECISIONS.md → Know past decisions
25
44
 
26
45
  ### PHASE 2: PRE-FLIGHT CHECK (before writing code)
27
46
  Ask yourself silently:
@@ -29,16 +48,9 @@ Ask yourself silently:
29
48
  - [ ] Is similar code already in the codebase? (copy that pattern)
30
49
  - [ ] What's the data model involved?
31
50
  - [ ] What are the error cases?
32
- - [ ] Is someone else working on this? (check PROJECT-STATE.md)
33
-
34
- If PROJECT-CONTEXT.md is empty or stale (>7 days), SCAN THE PROJECT FIRST:
35
- - Read package.json for dependencies
36
- - Check src/ structure
37
- - Note existing patterns
38
- - Update PROJECT-CONTEXT.md
39
51
 
40
52
  ### PHASE 3: EXECUTE
41
- - State: \`📋 CodeBakers | [Type] | v6.0 Server-Enforced\`
53
+ - State: \`📋 CodeBakers | [Type] | Server-Enforced\`
42
54
  - Call discover_patterns MCP tool first
43
55
  - Follow patterns from server EXACTLY
44
56
 
@@ -55,11 +67,7 @@ If ANY check fails, fix it before responding.
55
67
  ### PHASE 5: UPDATE STATE
56
68
  - Update PROJECT-STATE.md with completed work
57
69
  - Add to DECISIONS.md if architectural choice was made
58
-
59
- ## MULTI-AGENT AWARENESS
60
- - ALWAYS check PROJECT-STATE.md "In Progress" section
61
- - Do NOT duplicate work another agent is doing
62
- - If conflict detected, STOP and ask user
70
+ - Update .codebakers/DEVLOG.md with session summary
63
71
 
64
72
  ## REMEMBER
65
73
  - You are a full product team, not just a code assistant
@@ -71,40 +79,31 @@ const CURSORIGNORE_TEMPLATE = `# CodeBakers - Files to ignore in Cursor context
71
79
  # Dependencies
72
80
  node_modules/
73
81
  .pnpm-store/
74
- bower_components/
75
82
 
76
83
  # Build outputs
77
84
  dist/
78
85
  build/
79
86
  .next/
80
87
  .nuxt/
81
- .output/
82
88
  out/
83
89
 
84
90
  # Cache
85
91
  .cache/
86
92
  .turbo/
87
- .eslintcache
88
- .prettiercache
89
93
  *.tsbuildinfo
90
94
 
91
95
  # Logs
92
96
  logs/
93
97
  *.log
94
- npm-debug.log*
95
- yarn-debug.log*
96
- yarn-error.log*
97
98
 
98
99
  # Environment files (don't leak secrets)
99
100
  .env
100
101
  .env.local
101
102
  .env.*.local
102
- .env.production
103
103
 
104
104
  # IDE
105
105
  .idea/
106
106
  *.swp
107
- *.swo
108
107
 
109
108
  # OS
110
109
  .DS_Store
@@ -112,9 +111,8 @@ Thumbs.db
112
111
 
113
112
  # Test coverage
114
113
  coverage/
115
- .nyc_output/
116
114
 
117
- # Package locks (large files, not needed for context)
115
+ # Package locks
118
116
  package-lock.json
119
117
  yarn.lock
120
118
  pnpm-lock.yaml
@@ -127,7 +125,6 @@ pnpm-lock.yaml
127
125
  const VSCODE_SETTINGS_TEMPLATE = {
128
126
  "cursor.chat.defaultContext": [
129
127
  "CLAUDE.md",
130
- "PRD.md",
131
128
  "PROJECT-CONTEXT.md",
132
129
  "PROJECT-STATE.md",
133
130
  "DECISIONS.md"
@@ -136,111 +133,6 @@ const VSCODE_SETTINGS_TEMPLATE = {
136
133
  "cursor.composer.alwaysIncludeRules": true,
137
134
  "cursor.general.enableAutoImport": true
138
135
  };
139
- function createPrdTemplate(projectName, projectType) {
140
- const date = new Date().toISOString().split('T')[0];
141
- const typeSpecificSections = projectType === 'client'
142
- ? `
143
- ## Client Info
144
- - Client Name: [Who is this for?]
145
- - Contact: [Primary contact]
146
- - Deadline: [When is this due?]
147
- - Budget: [If relevant]
148
- `
149
- : projectType === 'business'
150
- ? `
151
- ## Business Context
152
- - Target Market: [Who are you selling to?]
153
- - Revenue Model: [How does this make money?]
154
- - Competition: [Who are you competing with?]
155
- - MVP Deadline: [When do you need to launch?]
156
- `
157
- : `
158
- ## Personal Goals
159
- - Why am I building this? [Your motivation]
160
- - Learning goals: [What do you want to learn?]
161
- - Time commitment: [Hours per week?]
162
- `;
163
- return `# Product Requirements Document
164
- # Project: ${projectName}
165
- # Created: ${date}
166
- # Type: ${projectType}
167
-
168
- ## Overview
169
- **One-liner:** [Describe this project in one sentence]
170
-
171
- **Problem:** [What problem does this solve?]
172
-
173
- **Solution:** [How does this solve it?]
174
- ${typeSpecificSections}
175
- ## Target Users
176
- - **Primary:** [Who is the main user?]
177
- - **Secondary:** [Other users?]
178
-
179
- ## Core Features (MVP)
180
- <!-- List the MINIMUM features needed to launch -->
181
- <!-- AI will build these first -->
182
-
183
- 1. [ ] **Feature 1:** [Description]
184
- - Acceptance criteria: [How do we know it's done?]
185
-
186
- 2. [ ] **Feature 2:** [Description]
187
- - Acceptance criteria: [How do we know it's done?]
188
-
189
- 3. [ ] **Feature 3:** [Description]
190
- - Acceptance criteria: [How do we know it's done?]
191
-
192
- ## Nice-to-Have Features (Post-MVP)
193
- <!-- Features to add after MVP is working -->
194
-
195
- 1. [ ] [Feature description]
196
- 2. [ ] [Feature description]
197
-
198
- ## Technical Requirements
199
- <!-- AI will use these to make architecture decisions -->
200
-
201
- - **Must use:** [Required technologies, APIs, etc.]
202
- - **Must avoid:** [Things you don't want]
203
- - **Performance:** [Any speed/scale requirements?]
204
- - **Security:** [Auth requirements, data sensitivity?]
205
-
206
- ## User Flows
207
- <!-- Describe the main user journeys -->
208
-
209
- ### Flow 1: [Name]
210
- 1. User does X
211
- 2. System responds with Y
212
- 3. User sees Z
213
-
214
- ### Flow 2: [Name]
215
- 1. User does X
216
- 2. System responds with Y
217
- 3. User sees Z
218
-
219
- ## Data Model (if known)
220
- <!-- Rough idea of main entities -->
221
-
222
- - **User:** [fields]
223
- - **[Entity 2]:** [fields]
224
- - **[Entity 3]:** [fields]
225
-
226
- ## Success Metrics
227
- - [ ] [How will you measure success?]
228
- - [ ] [What does "done" look like?]
229
-
230
- ## Open Questions
231
- <!-- Things you're unsure about - AI can help clarify -->
232
-
233
- 1. [Question?]
234
- 2. [Question?]
235
-
236
- ---
237
- <!-- AI INSTRUCTIONS -->
238
- <!-- When building features, reference this PRD -->
239
- <!-- Check off features as they're completed -->
240
- <!-- Add new questions to Open Questions -->
241
- <!-- Update this doc as requirements change -->
242
- `;
243
- }
244
136
  async function prompt(question) {
245
137
  const rl = (0, readline_1.createInterface)({
246
138
  input: process.stdin,
@@ -257,157 +149,45 @@ async function confirm(question) {
257
149
  const answer = await prompt(`${question} (Y/n): `);
258
150
  return answer.toLowerCase() !== 'n';
259
151
  }
260
- async function selectProjectType() {
261
- console.log(chalk_1.default.white('\n What kind of project is this?\n'));
262
- console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('PERSONAL') + chalk_1.default.gray(' - Just building for myself'));
263
- console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('CLIENT') + chalk_1.default.gray(' - Building for someone else'));
264
- console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('BUSINESS') + chalk_1.default.gray(' - My own product/startup\n'));
265
- let typeChoice = '';
266
- while (!['1', '2', '3'].includes(typeChoice)) {
267
- typeChoice = await prompt(' Enter 1, 2, or 3: ');
152
+ function countSourceFiles(dir) {
153
+ let count = 0;
154
+ try {
155
+ const items = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
156
+ for (const item of items) {
157
+ if (item.name.startsWith('.') || item.name === 'node_modules')
158
+ continue;
159
+ const fullPath = (0, path_1.join)(dir, item.name);
160
+ if (item.isDirectory()) {
161
+ count += countSourceFiles(fullPath);
162
+ }
163
+ else if (item.name.endsWith('.ts') ||
164
+ item.name.endsWith('.tsx') ||
165
+ item.name.endsWith('.js') ||
166
+ item.name.endsWith('.jsx')) {
167
+ count++;
168
+ }
169
+ }
268
170
  }
269
- const typeMap = {
270
- '1': 'personal',
271
- '2': 'client',
272
- '3': 'business'
273
- };
274
- const cwd = process.cwd();
275
- const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
276
- const name = await prompt(` Project name (${defaultName}): `) || defaultName;
277
- return {
278
- type: typeMap[typeChoice],
279
- name
280
- };
281
- }
282
- function createProjectState(projectName, projectType) {
283
- const date = new Date().toISOString().split('T')[0];
284
- return `# PROJECT STATE
285
- # Last Updated: ${date}
286
- # Auto-maintained by AI - update when starting/completing tasks
287
-
288
- ## Project Info
289
- name: ${projectName}
290
- type: ${projectType}
291
- phase: planning
292
-
293
- ## Current Sprint
294
- Goal: [AI will fill this based on conversation]
295
-
296
- ## In Progress
297
- <!-- AI: Add tasks here when you START working on them -->
298
- <!-- Format: - [task] (started: date, agent: cursor/claude) -->
299
-
300
- ## Completed
301
- <!-- AI: Move tasks here when DONE -->
302
- <!-- Format: - [task] (completed: date) -->
303
-
304
- ## Blockers
305
- <!-- AI: List anything blocking progress -->
306
-
307
- ## Next Up
308
- <!-- AI: Queue of upcoming tasks -->
309
- `;
310
- }
311
- function createProjectContext(projectName, projectType) {
312
- const date = new Date().toISOString().split('T')[0];
313
- return `# PROJECT CONTEXT
314
- # Last Scanned: ${date}
315
- # AI: Update this when you first analyze the project or when structure changes significantly
316
-
317
- ## Overview
318
- name: ${projectName}
319
- type: ${projectType}
320
- description: [AI will fill after scanning]
321
-
322
- ## Tech Stack
323
- <!-- AI: Fill this by reading package.json and checking file extensions -->
324
- framework:
325
- language:
326
- database:
327
- auth:
328
- styling:
329
- testing:
330
-
331
- ## Project Structure
332
- <!-- AI: Fill this by scanning the directory structure -->
333
- \`\`\`
334
- [AI will map the project structure here]
335
- \`\`\`
336
-
337
- ## Key Files
338
- <!-- AI: List the most important files for understanding the project -->
339
- - Entry point:
340
- - Config:
341
- - Database schema:
342
- - API routes:
343
- - Components:
344
-
345
- ## Existing Patterns
346
- <!-- AI: Document patterns you find so you can reuse them -->
347
-
348
- ### API Route Pattern
349
- \`\`\`typescript
350
- [AI: Copy an example API route pattern from this project]
351
- \`\`\`
352
-
353
- ### Component Pattern
354
- \`\`\`typescript
355
- [AI: Copy an example component pattern from this project]
356
- \`\`\`
357
-
358
- ### Database Query Pattern
359
- \`\`\`typescript
360
- [AI: Copy an example database query pattern from this project]
361
- \`\`\`
362
-
363
- ## Environment Variables
364
- <!-- AI: List required env vars (don't include values!) -->
365
- - [ ] DATABASE_URL
366
- - [ ] [others...]
367
-
368
- ## Notes
369
- <!-- AI: Any important context about this specific project -->
370
- `;
371
- }
372
- function createDecisionsLog(projectName) {
373
- const date = new Date().toISOString().split('T')[0];
374
- return `# ARCHITECTURAL DECISIONS
375
- # Project: ${projectName}
376
- # AI: Add entries here when making significant technical choices
377
-
378
- ## How to Use This File
379
- When you make a decision that affects architecture, add an entry:
380
- - Date
381
- - Decision
382
- - Reason
383
- - Alternatives considered
384
- - Pattern location (if applicable)
385
-
386
- ---
387
-
388
- ## ${date}: Project Initialized
389
- **Decision:** Using CodeBakers v6.0 pattern system
390
- **Reason:** Ensure consistent, production-quality code
391
- **Pattern:** Server-enforced via discover_patterns MCP tool
392
-
393
- ---
394
-
395
- <!-- AI: Add new decisions above this line -->
396
- `;
171
+ catch {
172
+ // Ignore access errors
173
+ }
174
+ return count;
397
175
  }
398
- /**
399
- * Auto-scan project to detect tech stack
400
- */
401
- function scanProject(cwd) {
176
+ function detectExistingProject(cwd) {
177
+ const details = [];
402
178
  const stack = {};
403
- let structure = '';
404
- // Check package.json
179
+ let sourceFileCount = 0;
180
+ // Check for package.json with dependencies
405
181
  const packageJsonPath = (0, path_1.join)(cwd, 'package.json');
406
182
  if ((0, fs_1.existsSync)(packageJsonPath)) {
407
183
  try {
408
184
  const pkg = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, 'utf-8'));
409
185
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
410
- // Detect framework
186
+ const depCount = Object.keys(pkg.dependencies || {}).length;
187
+ if (depCount > 0) {
188
+ details.push(`package.json with ${depCount} dependencies`);
189
+ }
190
+ // Detect stack
411
191
  if (deps['next'])
412
192
  stack.framework = `Next.js ${deps['next']}`;
413
193
  else if (deps['react'])
@@ -416,47 +196,71 @@ function scanProject(cwd) {
416
196
  stack.framework = `Vue ${deps['vue']}`;
417
197
  else if (deps['express'])
418
198
  stack.framework = `Express ${deps['express']}`;
419
- // Detect database
420
199
  if (deps['drizzle-orm'])
421
200
  stack.database = 'Drizzle ORM';
422
201
  else if (deps['prisma'])
423
202
  stack.database = 'Prisma';
424
203
  else if (deps['mongoose'])
425
204
  stack.database = 'MongoDB/Mongoose';
426
- else if (deps['pg'])
427
- stack.database = 'PostgreSQL';
428
- // Detect auth
429
205
  if (deps['@supabase/supabase-js'])
430
206
  stack.auth = 'Supabase Auth';
431
207
  else if (deps['next-auth'])
432
208
  stack.auth = 'NextAuth.js';
433
209
  else if (deps['@clerk/nextjs'])
434
210
  stack.auth = 'Clerk';
435
- // Detect styling
436
211
  if (deps['tailwindcss'])
437
212
  stack.styling = 'Tailwind CSS';
438
- else if (deps['styled-components'])
439
- stack.styling = 'Styled Components';
440
- // Detect testing
441
- if (deps['vitest'])
442
- stack.testing = 'Vitest';
443
- else if (deps['jest'])
444
- stack.testing = 'Jest';
445
- else if (deps['@playwright/test'])
446
- stack.testing = 'Playwright';
447
- // Detect language
448
213
  if (deps['typescript'] || (0, fs_1.existsSync)((0, path_1.join)(cwd, 'tsconfig.json'))) {
449
214
  stack.language = 'TypeScript';
450
215
  }
451
216
  else {
452
217
  stack.language = 'JavaScript';
453
218
  }
219
+ if (deps['vitest'])
220
+ stack.testing = 'Vitest';
221
+ else if (deps['jest'])
222
+ stack.testing = 'Jest';
223
+ else if (deps['@playwright/test'])
224
+ stack.testing = 'Playwright';
454
225
  }
455
226
  catch {
456
227
  // Ignore parse errors
457
228
  }
458
229
  }
459
- // Build simple structure
230
+ // Check for source directories
231
+ const sourceDirs = ['src', 'app', 'pages', 'components', 'lib'];
232
+ for (const dir of sourceDirs) {
233
+ const dirPath = (0, path_1.join)(cwd, dir);
234
+ if ((0, fs_1.existsSync)(dirPath)) {
235
+ try {
236
+ if ((0, fs_1.statSync)(dirPath).isDirectory()) {
237
+ const files = countSourceFiles(dirPath);
238
+ if (files > 0) {
239
+ sourceFileCount += files;
240
+ details.push(`${dir}/ with ${files} source files`);
241
+ }
242
+ }
243
+ }
244
+ catch {
245
+ // Ignore access errors
246
+ }
247
+ }
248
+ }
249
+ // Check for common config files
250
+ const configFiles = ['tsconfig.json', 'next.config.js', 'next.config.mjs', 'vite.config.ts', 'tailwind.config.js'];
251
+ for (const file of configFiles) {
252
+ if ((0, fs_1.existsSync)((0, path_1.join)(cwd, file))) {
253
+ details.push(file);
254
+ }
255
+ }
256
+ return {
257
+ exists: sourceFileCount > 5 || details.length >= 3,
258
+ files: sourceFileCount,
259
+ details,
260
+ stack
261
+ };
262
+ }
263
+ function buildStructureString(cwd) {
460
264
  try {
461
265
  const items = (0, fs_1.readdirSync)(cwd);
462
266
  const dirs = [];
@@ -477,203 +281,277 @@ function scanProject(cwd) {
477
281
  // Skip inaccessible items
478
282
  }
479
283
  }
480
- structure = [...dirs.sort(), ...files.sort()].join('\n');
284
+ return [...dirs.sort(), ...files.sort()].join('\n');
481
285
  }
482
286
  catch {
483
- structure = '[Could not scan structure]';
287
+ return '[Could not scan structure]';
484
288
  }
485
- return { stack, structure };
486
289
  }
487
- function updateProjectContextWithScan(contextContent, stack, structure) {
488
- let updated = contextContent;
489
- // Update tech stack
490
- if (stack.framework)
491
- updated = updated.replace('framework: ', `framework: ${stack.framework}`);
492
- if (stack.language)
493
- updated = updated.replace('language: ', `language: ${stack.language}`);
494
- if (stack.database)
495
- updated = updated.replace('database: ', `database: ${stack.database}`);
496
- if (stack.auth)
497
- updated = updated.replace('auth: ', `auth: ${stack.auth}`);
498
- if (stack.styling)
499
- updated = updated.replace('styling: ', `styling: ${stack.styling}`);
500
- if (stack.testing)
501
- updated = updated.replace('testing: ', `testing: ${stack.testing}`);
502
- // Update structure
503
- updated = updated.replace('[AI will map the project structure here]', structure || '[Empty project]');
504
- return updated;
505
- }
506
- /**
507
- * Interactive init command - walks users through complete setup
508
- */
509
- async function init() {
510
- console.log(chalk_1.default.blue(`
511
- ╔═══════════════════════════════════════════════════════════╗
512
- ║ ║
513
- ║ ${chalk_1.default.bold('Welcome to CodeBakers!')} ║
514
- ║ ║
515
- ║ Production-grade patterns for AI-assisted development ║
516
- ║ ║
517
- ╚═══════════════════════════════════════════════════════════╝
518
- `));
519
- console.log(chalk_1.default.gray(' This wizard will set up CodeBakers in your project.\n'));
520
- const cwd = process.cwd();
521
- // Check if already initialized
522
- const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
523
- if ((0, fs_1.existsSync)(claudeMdPath)) {
524
- const reinitialize = await confirm(' CLAUDE.md already exists. Reinitialize?');
525
- if (!reinitialize) {
526
- console.log(chalk_1.default.yellow('\n Skipping. Run with a fresh project or delete CLAUDE.md first.\n'));
527
- return;
528
- }
529
- }
530
- // Step 1: Get project type
531
- const { type: projectType, name: projectName } = await selectProjectType();
532
- console.log(chalk_1.default.green(`\n ✓ Setting up ${projectName} as ${projectType.toUpperCase()} project\n`));
533
- // Step 2: Check if already logged in
534
- let apiKey = (0, config_js_1.getApiKey)();
535
- if (apiKey) {
536
- console.log(chalk_1.default.green(' ✓ Already logged in\n'));
537
- const useExisting = await confirm(' Use existing API key?');
538
- if (!useExisting) {
539
- apiKey = null;
540
- }
541
- }
542
- // Step 3: Login if needed
543
- if (!apiKey) {
544
- console.log(chalk_1.default.white('\n Step 1: Get your API key\n'));
545
- console.log(chalk_1.default.gray(' Go to: ') + chalk_1.default.cyan('https://codebakers.ai/dashboard'));
546
- console.log(chalk_1.default.gray(' Copy your API key (starts with cb_)\n'));
547
- apiKey = await prompt(' Paste your API key: ');
548
- if (!apiKey || !apiKey.startsWith('cb_')) {
549
- console.log(chalk_1.default.red('\n ✗ Invalid API key. Keys start with "cb_"\n'));
550
- console.log(chalk_1.default.gray(' Get your key at https://codebakers.ai/dashboard\n'));
551
- process.exit(1);
552
- }
553
- const spinner = (0, ora_1.default)(' Validating API key...').start();
554
- try {
555
- const apiUrl = (0, config_js_1.getApiUrl)();
556
- const response = await fetch(`${apiUrl}/api/content`, {
557
- method: 'GET',
558
- headers: {
559
- Authorization: `Bearer ${apiKey}`,
560
- },
561
- });
562
- if (!response.ok) {
563
- const error = await response.json().catch(() => ({}));
564
- throw new Error(error.error || 'Invalid API key');
565
- }
566
- (0, config_js_1.setApiKey)(apiKey);
567
- spinner.succeed('API key valid!');
568
- }
569
- catch (error) {
570
- spinner.fail('Invalid API key');
571
- const message = error instanceof Error ? error.message : 'Unknown error';
572
- console.log(chalk_1.default.red(`\n Error: ${message}\n`));
573
- process.exit(1);
574
- }
575
- }
576
- // Step 4: Install v6.0 bootstrap files
577
- console.log(chalk_1.default.white('\n Step 2: Installing CodeBakers v6.0\n'));
578
- const spinner = (0, ora_1.default)(' Installing v6.0 bootstrap...').start();
579
- // v6.0 bootstrap content - minimal files, patterns from server
580
- const V6_CLAUDE_MD = `# CodeBakers v6.0
290
+ // ============================================================================
291
+ // FILE CREATION FUNCTIONS
292
+ // ============================================================================
293
+ function createProjectContext(projectName, stack, structure, isExisting) {
294
+ const date = new Date().toISOString().split('T')[0];
295
+ return `# PROJECT CONTEXT
296
+ # Last Scanned: ${date}
297
+ # Mode: ${isExisting ? 'Existing Project' : 'New Project'}
581
298
 
582
- **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
299
+ ## Overview
300
+ name: ${projectName}
301
+ description: ${isExisting ? '[Existing project - AI will analyze on first interaction]' : '[AI will fill after first feature]'}
302
+
303
+ ## Tech Stack
304
+ framework: ${stack.framework || '[Not detected]'}
305
+ language: ${stack.language || '[Not detected]'}
306
+ database: ${stack.database || '[Not detected]'}
307
+ auth: ${stack.auth || '[Not detected]'}
308
+ styling: ${stack.styling || '[Not detected]'}
309
+ testing: ${stack.testing || '[Not detected]'}
583
310
 
311
+ ## Project Structure
584
312
  \`\`\`
585
- Tool: discover_patterns
586
- Args: { task: "description of what you're building" }
313
+ ${structure || '[Empty project]'}
587
314
  \`\`\`
588
315
 
589
- The server will return:
590
- - All coding patterns and rules you must follow
591
- - Test requirements
592
- - Validation instructions
316
+ ## Key Files
317
+ <!-- AI: List the most important files for understanding the project -->
318
+ - Entry point: ${stack.framework?.includes('Next') ? 'src/app/page.tsx or pages/index.tsx' : '[AI will identify]'}
319
+ - Config: ${(0, fs_1.existsSync)((0, path_1.join)(process.cwd(), 'tsconfig.json')) ? 'tsconfig.json' : '[AI will identify]'}
320
+ - Database schema: [AI will identify]
321
+ - API routes: ${stack.framework?.includes('Next') ? 'src/app/api/ or pages/api/' : '[AI will identify]'}
593
322
 
594
- **You cannot write code without calling this tool first. The server tracks compliance.**
323
+ ## Existing Patterns
324
+ <!-- AI: Document patterns you find so you can reuse them -->
325
+
326
+ ### API Route Pattern
327
+ \`\`\`typescript
328
+ [AI: Copy an example API route pattern from this project]
329
+ \`\`\`
330
+
331
+ ### Component Pattern
332
+ \`\`\`typescript
333
+ [AI: Copy an example component pattern from this project]
334
+ \`\`\`
335
+
336
+ ## Environment Variables
337
+ <!-- AI: List required env vars (don't include values!) -->
338
+ ${(0, fs_1.existsSync)((0, path_1.join)(process.cwd(), '.env.example')) ? '[Check .env.example]' : '- [ ] [AI will identify required vars]'}
339
+
340
+ ## Notes
341
+ <!-- AI: Any important context about this specific project -->
342
+ `;
343
+ }
344
+ function createProjectState(projectName, isExisting) {
345
+ const date = new Date().toISOString().split('T')[0];
346
+ return `# PROJECT STATE
347
+ # Last Updated: ${date}
348
+ # Auto-maintained by AI - update when starting/completing tasks
349
+
350
+ ## Project Info
351
+ name: ${projectName}
352
+ phase: ${isExisting ? 'active' : 'planning'}
353
+ mode: ${isExisting ? 'existing-project' : 'new-project'}
354
+
355
+ ## Current Sprint
356
+ Goal: ${isExisting ? '[AI will identify based on conversation]' : '[Define in first conversation]'}
357
+
358
+ ## In Progress
359
+ <!-- AI: Add tasks here when you START working on them -->
360
+ <!-- Format: - [task] (started: date, agent: cursor/claude) -->
361
+
362
+ ## Completed
363
+ <!-- AI: Move tasks here when DONE -->
364
+ <!-- Format: - [task] (completed: date) -->
365
+ ${isExisting ? `\n- CodeBakers integration (completed: ${date})` : ''}
366
+
367
+ ## Blockers
368
+ <!-- AI: List anything blocking progress -->
369
+
370
+ ## Next Up
371
+ <!-- AI: Queue of upcoming tasks -->
372
+ `;
373
+ }
374
+ function createDecisionsLog(projectName) {
375
+ const date = new Date().toISOString().split('T')[0];
376
+ return `# ARCHITECTURAL DECISIONS
377
+ # Project: ${projectName}
378
+ # AI: Add entries here when making significant technical choices
379
+
380
+ ## How to Use This File
381
+ When you make a decision that affects architecture, add an entry:
382
+ - Date
383
+ - Decision
384
+ - Reason
385
+ - Alternatives considered
595
386
 
596
387
  ---
597
- *CodeBakers v6.0 - Server-Enforced*
388
+
389
+ ## ${date}: CodeBakers Initialized
390
+ **Decision:** Using CodeBakers server-enforced pattern system
391
+ **Reason:** Ensure consistent, production-quality code
392
+ **Pattern:** Server-enforced via discover_patterns MCP tool
393
+
394
+ ---
395
+
396
+ <!-- AI: Add new decisions above this line -->
598
397
  `;
599
- const V6_CURSORRULES = `# CodeBakers v6.0
398
+ }
399
+ function createDevlog(projectName, isExisting, auditScore) {
400
+ const date = new Date().toISOString().split('T')[0];
401
+ const timestamp = new Date().toISOString();
402
+ return `# Development Log
403
+ # Project: ${projectName}
600
404
 
601
- MANDATORY: Before writing ANY code, call the discover_patterns MCP tool.
405
+ ## ${date} - CodeBakers Integration
406
+ **Session:** ${timestamp}
407
+ **Task Size:** MEDIUM
408
+ **Status:** Completed
409
+
410
+ ### What was done:
411
+ - Integrated CodeBakers into ${isExisting ? 'existing' : 'new'} project
412
+ - Created project tracking files
413
+ - Set up Cursor IDE configuration
414
+ ${isExisting && auditScore !== undefined ? `- Ran initial code audit (Score: ${auditScore}%)` : ''}
415
+
416
+ ### Files created:
417
+ - \`CLAUDE.md\` - AI bootstrap file
418
+ - \`.cursorrules\` - Cursor IDE rules
419
+ - \`PROJECT-CONTEXT.md\` - Project knowledge base
420
+ - \`PROJECT-STATE.md\` - Task tracking
421
+ - \`DECISIONS.md\` - Architecture log
422
+ - \`.codebakers/DEVLOG.md\` - This file
423
+
424
+ ### Next steps:
425
+ ${isExisting ? '- Start using AI assistance with existing codebase' : '- Define project requirements in first conversation'}
426
+ ${isExisting ? '- AI will analyze existing patterns on first interaction' : '- AI will help scaffold initial features'}
602
427
 
603
- Tool: discover_patterns
604
- Args: { task: "description of what you're building" }
428
+ ---
429
+ `;
430
+ }
431
+ function createPrdTemplate(projectName, projectType) {
432
+ const date = new Date().toISOString().split('T')[0];
433
+ const typeSpecificSections = projectType === 'client'
434
+ ? `
435
+ ## Client Info
436
+ - Client Name: [Who is this for?]
437
+ - Contact: [Primary contact]
438
+ - Deadline: [When is this due?]
439
+ `
440
+ : projectType === 'business'
441
+ ? `
442
+ ## Business Context
443
+ - Target Market: [Who are you selling to?]
444
+ - Revenue Model: [How does this make money?]
445
+ - MVP Deadline: [When do you need to launch?]
446
+ `
447
+ : `
448
+ ## Personal Goals
449
+ - Why am I building this? [Your motivation]
450
+ - Learning goals: [What do you want to learn?]
451
+ `;
452
+ return `# Product Requirements Document
453
+ # Project: ${projectName}
454
+ # Created: ${date}
455
+ # Type: ${projectType}
456
+
457
+ ## Overview
458
+ **One-liner:** [Describe this project in one sentence]
605
459
 
606
- The server returns all patterns, rules, and test requirements.
607
- You cannot write code without calling this tool first.
460
+ **Problem:** [What problem does this solve?]
461
+
462
+ **Solution:** [How does this solve it?]
463
+ ${typeSpecificSections}
464
+ ## Target Users
465
+ - **Primary:** [Who is the main user?]
466
+ - **Secondary:** [Other users?]
467
+
468
+ ## Core Features (MVP)
469
+ 1. [ ] **Feature 1:** [Description]
470
+ 2. [ ] **Feature 2:** [Description]
471
+ 3. [ ] **Feature 3:** [Description]
472
+
473
+ ## Nice-to-Have Features (Post-MVP)
474
+ 1. [ ] [Feature description]
475
+ 2. [ ] [Feature description]
476
+
477
+ ## Technical Requirements
478
+ - **Must use:** [Required technologies, APIs, etc.]
479
+ - **Must avoid:** [Things you don't want]
480
+
481
+ ## Success Metrics
482
+ - [ ] [How will you measure success?]
483
+ - [ ] [What does "done" look like?]
484
+
485
+ ---
486
+ <!-- AI reads this file to understand what to build -->
608
487
  `;
488
+ }
489
+ // ============================================================================
490
+ // SHARED SETUP FUNCTIONS
491
+ // ============================================================================
492
+ async function ensureLoggedIn() {
493
+ let apiKey = (0, config_js_1.getApiKey)();
494
+ if (apiKey) {
495
+ console.log(chalk_1.default.green(' ✓ Already logged in\n'));
496
+ const useExisting = await confirm(' Use existing API key?');
497
+ if (useExisting)
498
+ return apiKey;
499
+ apiKey = null;
500
+ }
501
+ console.log(chalk_1.default.white('\n Login to CodeBakers\n'));
502
+ console.log(chalk_1.default.gray(' Go to: ') + chalk_1.default.cyan('https://codebakers.ai/dashboard'));
503
+ console.log(chalk_1.default.gray(' Copy your API key (starts with cb_)\n'));
504
+ apiKey = await prompt(' Paste your API key: ');
505
+ if (!apiKey || !apiKey.startsWith('cb_')) {
506
+ console.log(chalk_1.default.red('\n ✗ Invalid API key. Keys start with "cb_"\n'));
507
+ process.exit(1);
508
+ }
509
+ const spinner = (0, ora_1.default)(' Validating API key...').start();
609
510
  try {
610
- // Write v6.0 bootstrap files
611
- (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'CLAUDE.md'), V6_CLAUDE_MD);
612
- (0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.cursorrules'), V6_CURSORRULES);
613
- // Remove old .claude folder if it exists (v5 → v6 migration)
511
+ const apiUrl = (0, config_js_1.getApiUrl)();
512
+ const response = await fetch(`${apiUrl}/api/content`, {
513
+ method: 'GET',
514
+ headers: { Authorization: `Bearer ${apiKey}` },
515
+ });
516
+ if (!response.ok) {
517
+ throw new Error('Invalid API key');
518
+ }
519
+ (0, config_js_1.setApiKey)(apiKey);
520
+ spinner.succeed('API key valid!');
521
+ return apiKey;
522
+ }
523
+ catch (error) {
524
+ spinner.fail('Invalid API key');
525
+ process.exit(1);
526
+ }
527
+ }
528
+ function installBootstrapFiles(cwd) {
529
+ const spinner = (0, ora_1.default)(' Installing bootstrap files...').start();
530
+ try {
531
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'CLAUDE.md'), CLAUDE_MD_BOOTSTRAP);
532
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.cursorrules'), CURSORRULES_TEMPLATE);
533
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.cursorignore'), CURSORIGNORE_TEMPLATE);
534
+ // Remove old .claude folder if it exists
614
535
  const claudeDir = (0, path_1.join)(cwd, '.claude');
615
536
  if ((0, fs_1.existsSync)(claudeDir)) {
616
- const { rmSync } = await import('fs');
617
537
  try {
618
- rmSync(claudeDir, { recursive: true, force: true });
538
+ (0, fs_1.rmSync)(claudeDir, { recursive: true, force: true });
619
539
  }
620
540
  catch {
621
541
  // Ignore errors
622
542
  }
623
543
  }
624
- spinner.succeed('CodeBakers v6.0 installed!');
625
- console.log(chalk_1.default.gray('\n Patterns are server-enforced via MCP tools'));
544
+ spinner.succeed('Bootstrap files installed!');
626
545
  }
627
546
  catch (error) {
628
- spinner.fail('Installation failed');
629
- const message = error instanceof Error ? error.message : 'Unknown error';
630
- console.log(chalk_1.default.red(`\n Error: ${message}\n`));
631
- process.exit(1);
632
- }
633
- // Step 5: Auto-scan project
634
- console.log(chalk_1.default.white('\n Step 3: Scanning project\n'));
635
- const scanSpinner = (0, ora_1.default)(' Analyzing project structure...').start();
636
- const { stack, structure } = scanProject(cwd);
637
- const detectedItems = Object.entries(stack).filter(([_, v]) => v).map(([k, v]) => `${k}: ${v}`);
638
- if (detectedItems.length > 0) {
639
- scanSpinner.succeed('Project analyzed!');
640
- console.log(chalk_1.default.gray('\n Detected:'));
641
- for (const item of detectedItems) {
642
- console.log(chalk_1.default.gray(` ${item}`));
643
- }
644
- }
645
- else {
646
- scanSpinner.succeed('Project scanned (new project detected)');
547
+ spinner.fail('Failed to install bootstrap files');
548
+ throw error;
647
549
  }
648
- // Step 6: Create PROJECT-CONTEXT.md with scan results
649
- console.log(chalk_1.default.white('\n Step 4: Setting up project files\n'));
650
- const filesSpinner = (0, ora_1.default)(' Creating project files...').start();
651
- try {
652
- // PROJECT-CONTEXT.md
653
- let contextContent = createProjectContext(projectName, projectType);
654
- contextContent = updateProjectContextWithScan(contextContent, stack, structure);
655
- (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PROJECT-CONTEXT.md'), contextContent);
656
- // PROJECT-STATE.md
657
- const stateContent = createProjectState(projectName, projectType);
658
- (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PROJECT-STATE.md'), stateContent);
659
- // DECISIONS.md
660
- const decisionsContent = createDecisionsLog(projectName);
661
- (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'DECISIONS.md'), decisionsContent);
662
- filesSpinner.succeed('Project files created!');
663
- }
664
- catch (error) {
665
- filesSpinner.warn('Some project files could not be created');
666
- }
667
- // Step 7: Install Cursor files
668
- console.log(chalk_1.default.white('\n Step 5: Setting up Cursor IDE\n'));
669
- const cursorSpinner = (0, ora_1.default)(' Installing Cursor configuration...').start();
550
+ }
551
+ function setupCursorIDE(cwd) {
552
+ const spinner = (0, ora_1.default)(' Setting up Cursor IDE...').start();
670
553
  try {
671
- // Write .cursorrules
672
- (0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.cursorrules'), CURSORRULES_TEMPLATE);
673
- // Write .cursorignore
674
- (0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.cursorignore'), CURSORIGNORE_TEMPLATE);
675
- // Create GLOBAL ~/.cursor/mcp.json for MCP server configuration
676
- // Cursor reads MCP config from global location, not project-local
554
+ // Global MCP config
677
555
  const homeDir = process.env.USERPROFILE || process.env.HOME || '';
678
556
  const globalCursorDir = (0, path_1.join)(homeDir, '.cursor');
679
557
  if (!(0, fs_1.existsSync)(globalCursorDir)) {
@@ -688,7 +566,6 @@ You cannot write code without calling this tool first.
688
566
  : { command: 'npx', args: ['-y', '@codebakers/cli', 'serve'] }
689
567
  }
690
568
  };
691
- // Merge with existing MCP config if present
692
569
  if ((0, fs_1.existsSync)(mcpConfigPath)) {
693
570
  try {
694
571
  const existing = JSON.parse((0, fs_1.readFileSync)(mcpConfigPath, 'utf-8'));
@@ -702,123 +579,274 @@ You cannot write code without calling this tool first.
702
579
  else {
703
580
  (0, fs_1.writeFileSync)(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));
704
581
  }
705
- // Create/merge .vscode/settings.json
582
+ // VSCode settings
706
583
  const vscodeDir = (0, path_1.join)(cwd, '.vscode');
707
584
  if (!(0, fs_1.existsSync)(vscodeDir)) {
708
585
  (0, fs_1.mkdirSync)(vscodeDir, { recursive: true });
709
586
  }
710
- const existingSettingsPath = (0, path_1.join)(vscodeDir, 'settings.json');
711
- if ((0, fs_1.existsSync)(existingSettingsPath)) {
712
- const existing = JSON.parse((0, fs_1.readFileSync)(existingSettingsPath, 'utf-8'));
713
- const merged = { ...existing, ...VSCODE_SETTINGS_TEMPLATE };
714
- (0, fs_1.writeFileSync)(existingSettingsPath, JSON.stringify(merged, null, 2));
587
+ const settingsPath = (0, path_1.join)(vscodeDir, 'settings.json');
588
+ if ((0, fs_1.existsSync)(settingsPath)) {
589
+ const existing = JSON.parse((0, fs_1.readFileSync)(settingsPath, 'utf-8'));
590
+ (0, fs_1.writeFileSync)(settingsPath, JSON.stringify({ ...existing, ...VSCODE_SETTINGS_TEMPLATE }, null, 2));
715
591
  }
716
592
  else {
717
- (0, fs_1.writeFileSync)(existingSettingsPath, JSON.stringify(VSCODE_SETTINGS_TEMPLATE, null, 2));
593
+ (0, fs_1.writeFileSync)(settingsPath, JSON.stringify(VSCODE_SETTINGS_TEMPLATE, null, 2));
718
594
  }
719
- cursorSpinner.succeed('Cursor configuration installed!');
720
- console.log(chalk_1.default.green(' ✓ MCP server configured (~/.cursor/mcp.json)'));
595
+ spinner.succeed('Cursor IDE configured!');
721
596
  }
722
- catch (error) {
723
- cursorSpinner.warn('Could not install Cursor files (continuing anyway)');
597
+ catch {
598
+ spinner.warn('Could not configure Cursor IDE (continuing anyway)');
724
599
  }
725
- // Step 8: Add to .gitignore if not present
600
+ }
601
+ function updateGitignore(cwd) {
726
602
  const gitignorePath = (0, path_1.join)(cwd, '.gitignore');
727
603
  if ((0, fs_1.existsSync)(gitignorePath)) {
728
604
  const gitignore = (0, fs_1.readFileSync)(gitignorePath, 'utf-8');
729
605
  if (!gitignore.includes('.cursorrules')) {
730
- const additions = '\n# CodeBakers\n.cursorrules\n';
731
- (0, fs_1.writeFileSync)(gitignorePath, gitignore + additions);
606
+ (0, fs_1.writeFileSync)(gitignorePath, gitignore + '\n# CodeBakers\n.cursorrules\n');
732
607
  }
733
608
  }
734
- // Step 9: PRD Setup
735
- console.log(chalk_1.default.white('\n Step 6: Product Requirements\n'));
736
- const prdPath = (0, path_1.join)(cwd, 'PRD.md');
737
- let prdCreated = false;
738
- if ((0, fs_1.existsSync)(prdPath)) {
739
- console.log(chalk_1.default.green(' ✓ PRD.md already exists\n'));
740
- prdCreated = true;
609
+ }
610
+ function createTrackingFiles(cwd, projectName, stack, structure, isExisting, auditScore) {
611
+ const spinner = (0, ora_1.default)(' Creating project tracking files...').start();
612
+ try {
613
+ // Create .codebakers directory
614
+ const codebakersDir = (0, path_1.join)(cwd, '.codebakers');
615
+ if (!(0, fs_1.existsSync)(codebakersDir)) {
616
+ (0, fs_1.mkdirSync)(codebakersDir, { recursive: true });
617
+ }
618
+ // PROJECT-CONTEXT.md
619
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PROJECT-CONTEXT.md'), createProjectContext(projectName, stack, structure, isExisting));
620
+ // PROJECT-STATE.md
621
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PROJECT-STATE.md'), createProjectState(projectName, isExisting));
622
+ // DECISIONS.md
623
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'DECISIONS.md'), createDecisionsLog(projectName));
624
+ // .codebakers/DEVLOG.md
625
+ (0, fs_1.writeFileSync)((0, path_1.join)(codebakersDir, 'DEVLOG.md'), createDevlog(projectName, isExisting, auditScore));
626
+ // .codebakers.json state file
627
+ const stateFile = (0, path_1.join)(cwd, '.codebakers.json');
628
+ const state = {
629
+ version: '1.0',
630
+ serverEnforced: true,
631
+ projectType: isExisting ? 'existing' : 'new',
632
+ projectName,
633
+ createdAt: new Date().toISOString(),
634
+ stack,
635
+ auditScore: auditScore
636
+ };
637
+ (0, fs_1.writeFileSync)(stateFile, JSON.stringify(state, null, 2));
638
+ spinner.succeed('Project tracking files created!');
639
+ }
640
+ catch (error) {
641
+ spinner.warn('Some tracking files could not be created');
642
+ }
643
+ }
644
+ // ============================================================================
645
+ // MODE: NEW PROJECT
646
+ // ============================================================================
647
+ async function initNewProject(cwd) {
648
+ console.log(chalk_1.default.cyan('\n ━━━ New Project Setup ━━━\n'));
649
+ // Get project info
650
+ console.log(chalk_1.default.white(' What kind of project is this?\n'));
651
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('PERSONAL') + chalk_1.default.gray(' - Just building for myself'));
652
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('CLIENT') + chalk_1.default.gray(' - Building for someone else'));
653
+ console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('BUSINESS') + chalk_1.default.gray(' - My own product/startup\n'));
654
+ let typeChoice = '';
655
+ while (!['1', '2', '3'].includes(typeChoice)) {
656
+ typeChoice = await prompt(' Enter 1, 2, or 3: ');
657
+ }
658
+ const typeMap = { '1': 'personal', '2': 'client', '3': 'business' };
659
+ const projectType = typeMap[typeChoice];
660
+ const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
661
+ const projectName = await prompt(` Project name (${defaultName}): `) || defaultName;
662
+ console.log(chalk_1.default.green(`\n ✓ Setting up "${projectName}" as ${projectType.toUpperCase()} project\n`));
663
+ // Login
664
+ await ensureLoggedIn();
665
+ // Install files
666
+ console.log(chalk_1.default.white('\n Installing CodeBakers...\n'));
667
+ installBootstrapFiles(cwd);
668
+ // Create tracking files
669
+ const structure = buildStructureString(cwd);
670
+ createTrackingFiles(cwd, projectName, {}, structure, false);
671
+ // Setup Cursor
672
+ console.log('');
673
+ setupCursorIDE(cwd);
674
+ // Update .gitignore
675
+ updateGitignore(cwd);
676
+ // PRD Setup
677
+ console.log(chalk_1.default.white('\n Product Requirements Document\n'));
678
+ console.log(chalk_1.default.gray(' A PRD helps the AI understand what you\'re building.\n'));
679
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('CREATE TEMPLATE') + chalk_1.default.gray(' - I\'ll fill it out'));
680
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('SKIP FOR NOW') + chalk_1.default.gray(' - I\'ll describe it in chat\n'));
681
+ let prdChoice = '';
682
+ while (!['1', '2'].includes(prdChoice)) {
683
+ prdChoice = await prompt(' Enter 1 or 2: ');
684
+ }
685
+ if (prdChoice === '1') {
686
+ const prdSpinner = (0, ora_1.default)(' Creating PRD template...').start();
687
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PRD.md'), createPrdTemplate(projectName, projectType));
688
+ prdSpinner.succeed('PRD template created!');
689
+ console.log(chalk_1.default.yellow('\n → Open PRD.md and fill in your requirements\n'));
741
690
  }
742
691
  else {
743
- console.log(chalk_1.default.gray(' A PRD helps the AI understand what you\'re building.\n'));
744
- console.log(chalk_1.default.white(' How would you like to set up your PRD?\n'));
745
- console.log(chalk_1.default.gray(' 0. ') + chalk_1.default.magenta('You Decide') + chalk_1.default.gray(' - Let AI pick the best option'));
746
- console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('CREATE TEMPLATE') + chalk_1.default.gray(' - I\'ll fill it out'));
747
- console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('PASTE CONTENT') + chalk_1.default.gray(' - I have requirements ready'));
748
- console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('SKIP FOR NOW') + chalk_1.default.gray(' - I\'ll add it later\n'));
749
- let prdChoice = '';
750
- while (!['0', '1', '2', '3'].includes(prdChoice)) {
751
- prdChoice = await prompt(' Enter 0, 1, 2, or 3: ');
752
- }
753
- // "You Decide" defaults to creating a template (most helpful)
754
- if (prdChoice === '0') {
755
- console.log(chalk_1.default.magenta(' → AI chose: Create Template (recommended)\n'));
756
- prdChoice = '1';
692
+ console.log(chalk_1.default.gray('\n No problem! Just describe your project to the AI.\n'));
693
+ }
694
+ // Success
695
+ showSuccessMessage(projectName, false, prdChoice === '1');
696
+ }
697
+ // ============================================================================
698
+ // MODE: EXISTING PROJECT
699
+ // ============================================================================
700
+ async function initExistingProject(cwd, projectInfo) {
701
+ console.log(chalk_1.default.cyan('\n ━━━ Existing Project Setup ━━━\n'));
702
+ // Show what was detected
703
+ console.log(chalk_1.default.gray(' Detected:'));
704
+ for (const detail of projectInfo.details.slice(0, 5)) {
705
+ console.log(chalk_1.default.gray(` • ${detail}`));
706
+ }
707
+ const stackItems = Object.entries(projectInfo.stack).filter(([_, v]) => v);
708
+ if (stackItems.length > 0) {
709
+ console.log(chalk_1.default.gray('\n Tech Stack:'));
710
+ for (const [key, value] of stackItems) {
711
+ console.log(chalk_1.default.gray(` • ${key}: ${value}`));
757
712
  }
758
- if (prdChoice === '1') {
759
- // Create template
760
- const prdSpinner = (0, ora_1.default)(' Creating PRD template...').start();
761
- const prdContent = createPrdTemplate(projectName, projectType);
762
- (0, fs_1.writeFileSync)(prdPath, prdContent);
763
- prdSpinner.succeed('PRD template created!');
764
- console.log(chalk_1.default.yellow('\n → Open PRD.md and fill in your requirements'));
765
- console.log(chalk_1.default.gray(' The AI will use this to understand what to build.\n'));
766
- prdCreated = true;
713
+ }
714
+ // Get project name
715
+ const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
716
+ const projectName = await prompt(`\n Project name (${defaultName}): `) || defaultName;
717
+ // Code review offer
718
+ console.log(chalk_1.default.white('\n Want me to review your code and bring it up to CodeBakers standards?\n'));
719
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('YES, REVIEW & FIX') + chalk_1.default.gray(' - Run audit, then auto-fix issues'));
720
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('REVIEW ONLY') + chalk_1.default.gray(' - Just show me the issues'));
721
+ console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('SKIP') + chalk_1.default.gray(' - Just install CodeBakers\n'));
722
+ let reviewChoice = '';
723
+ while (!['1', '2', '3'].includes(reviewChoice)) {
724
+ reviewChoice = await prompt(' Enter 1, 2, or 3: ');
725
+ }
726
+ let auditScore;
727
+ if (reviewChoice !== '3') {
728
+ console.log(chalk_1.default.blue('\n Running code audit...\n'));
729
+ const auditResult = await (0, audit_js_1.audit)();
730
+ auditScore = auditResult.score;
731
+ if (auditResult.score >= 90) {
732
+ console.log(chalk_1.default.green('\n 🎉 Your code is already in great shape!\n'));
767
733
  }
768
- else if (prdChoice === '2') {
769
- // Paste content
770
- console.log(chalk_1.default.gray('\n Paste your PRD content below.'));
771
- 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'));
772
- const lines = [];
773
- let line = '';
774
- while (true) {
775
- line = await prompt(' ');
776
- if (line.trim().toUpperCase() === 'END')
777
- break;
778
- lines.push(line);
779
- }
780
- if (lines.length > 0) {
781
- const prdSpinner = (0, ora_1.default)(' Saving PRD...').start();
782
- const header = `# Product Requirements Document\n# Project: ${projectName}\n# Created: ${new Date().toISOString().split('T')[0]}\n\n`;
783
- (0, fs_1.writeFileSync)(prdPath, header + lines.join('\n'));
784
- prdSpinner.succeed('PRD saved!');
785
- prdCreated = true;
786
- }
787
- else {
788
- console.log(chalk_1.default.yellow(' No content provided, skipping PRD.\n'));
734
+ else if (reviewChoice === '1') {
735
+ const fixableCount = auditResult.checks.filter(c => !c.passed && c.severity !== 'info').length;
736
+ if (fixableCount > 0) {
737
+ console.log(chalk_1.default.blue('\n 🔧 Attempting to auto-fix issues...\n'));
738
+ const healResult = await (0, heal_js_1.heal)({ auto: true });
739
+ if (healResult.fixed > 0) {
740
+ console.log(chalk_1.default.green(`\n ✓ Fixed ${healResult.fixed} issue(s)!`));
741
+ if (healResult.remaining > 0) {
742
+ console.log(chalk_1.default.yellow(` ⚠ ${healResult.remaining} issue(s) need manual attention.`));
743
+ }
744
+ }
789
745
  }
790
746
  }
791
747
  else {
792
- console.log(chalk_1.default.gray('\n You can add PRD.md anytime. The AI will use it automatically.\n'));
748
+ console.log(chalk_1.default.gray('\n Run `codebakers heal --auto` later to fix issues.\n'));
793
749
  }
794
750
  }
795
- // Success message
751
+ // Login
752
+ console.log('');
753
+ await ensureLoggedIn();
754
+ // Install files
755
+ console.log(chalk_1.default.white('\n Installing CodeBakers...\n'));
756
+ installBootstrapFiles(cwd);
757
+ // Create tracking files with detected stack
758
+ const structure = buildStructureString(cwd);
759
+ createTrackingFiles(cwd, projectName, projectInfo.stack, structure, true, auditScore);
760
+ // Setup Cursor
761
+ console.log('');
762
+ setupCursorIDE(cwd);
763
+ // Update .gitignore
764
+ updateGitignore(cwd);
765
+ // Success
766
+ showSuccessMessage(projectName, true);
767
+ }
768
+ // ============================================================================
769
+ // SUCCESS MESSAGE
770
+ // ============================================================================
771
+ function showSuccessMessage(projectName, isExisting, prdCreated) {
796
772
  console.log(chalk_1.default.green(`
797
773
  ╔═══════════════════════════════════════════════════════════╗
798
774
  ║ ║
799
- ║ ${chalk_1.default.bold('✓ Setup Complete!')}
775
+ ║ ${chalk_1.default.bold('✓ CodeBakers Setup Complete!')}
800
776
  ║ ║
801
777
  ╚═══════════════════════════════════════════════════════════╝
802
778
  `));
803
779
  console.log(chalk_1.default.white(' Files created:\n'));
804
- console.log(chalk_1.default.cyan(' CLAUDE.md ') + chalk_1.default.gray('→ v6.0 bootstrap (patterns via MCP)'));
805
- console.log(chalk_1.default.cyan(' .cursorrules ') + chalk_1.default.gray('→ v6.0 bootstrap (patterns via MCP)'));
806
- if (prdCreated) {
807
- console.log(chalk_1.default.cyan(' PRD.md ') + chalk_1.default.gray('→ Product requirements (AI reads this!)'));
808
- }
809
- console.log(chalk_1.default.cyan(' PROJECT-CONTEXT.md ') + chalk_1.default.gray('→ Codebase knowledge (auto-updated)'));
810
- console.log(chalk_1.default.cyan(' PROJECT-STATE.md ') + chalk_1.default.gray('→ Task tracking (auto-updated)'));
811
- console.log(chalk_1.default.cyan(' DECISIONS.md ') + chalk_1.default.gray('→ Architecture log (auto-updated)'));
812
- console.log(chalk_1.default.cyan(' .cursorignore ') + chalk_1.default.gray('→ Context optimization\n'));
813
- console.log(chalk_1.default.white(' What happens automatically:\n'));
814
- console.log(chalk_1.default.gray(' AI loads context before every response'));
815
- console.log(chalk_1.default.gray(' ✓ AI checks for existing patterns to copy'));
816
- console.log(chalk_1.default.gray(' ✓ AI validates code before outputting'));
817
- console.log(chalk_1.default.gray(' ✓ AI updates project state after completing tasks'));
818
- console.log(chalk_1.default.gray(' ✓ AI logs architectural decisions\n'));
819
- console.log(chalk_1.default.white(' For Cursor users:\n'));
820
- console.log(chalk_1.default.gray(' Just open the project and start chatting!\n'));
821
- console.log(chalk_1.default.white(' For Claude Code users:\n'));
822
- console.log(chalk_1.default.cyan(' codebakers install-hook') + chalk_1.default.gray(' (one-time setup)\n'));
823
- console.log(chalk_1.default.blue(' Zero friction. Just build.\n'));
780
+ console.log(chalk_1.default.cyan(' CLAUDE.md ') + chalk_1.default.gray('→ AI bootstrap (patterns via MCP)'));
781
+ console.log(chalk_1.default.cyan(' .cursorrules ') + chalk_1.default.gray('→ Cursor IDE rules'));
782
+ if (!isExisting && prdCreated) {
783
+ console.log(chalk_1.default.cyan(' PRD.md ') + chalk_1.default.gray('→ Product requirements'));
784
+ }
785
+ console.log(chalk_1.default.cyan(' PROJECT-CONTEXT.md ') + chalk_1.default.gray('→ Codebase knowledge'));
786
+ console.log(chalk_1.default.cyan(' PROJECT-STATE.md ') + chalk_1.default.gray('→ Task tracking'));
787
+ console.log(chalk_1.default.cyan(' DECISIONS.md ') + chalk_1.default.gray('→ Architecture log'));
788
+ console.log(chalk_1.default.cyan(' .codebakers/DEVLOG.md') + chalk_1.default.gray('→ Development log\n'));
789
+ if (isExisting) {
790
+ console.log(chalk_1.default.white(' What happens next:\n'));
791
+ console.log(chalk_1.default.gray(' ✓ AI will analyze your existing code patterns'));
792
+ console.log(chalk_1.default.gray(' ✓ AI follows your existing conventions'));
793
+ console.log(chalk_1.default.gray(' ✓ AI updates tracking files as you work\n'));
794
+ }
795
+ else {
796
+ console.log(chalk_1.default.white(' What happens next:\n'));
797
+ console.log(chalk_1.default.gray(' Describe what you want to build'));
798
+ console.log(chalk_1.default.gray(' AI fetches patterns and generates code'));
799
+ console.log(chalk_1.default.gray(' AI updates tracking files as you work\n'));
800
+ }
801
+ console.log(chalk_1.default.white(' Getting started:\n'));
802
+ console.log(chalk_1.default.gray(' For Cursor: Just open the project and start chatting'));
803
+ console.log(chalk_1.default.gray(' For Claude Code: Run ') + chalk_1.default.cyan('codebakers install-hook') + chalk_1.default.gray(' first\n'));
804
+ console.log(chalk_1.default.blue(' Ready to build! 🚀\n'));
805
+ }
806
+ // ============================================================================
807
+ // MAIN INIT FUNCTION
808
+ // ============================================================================
809
+ async function init() {
810
+ console.log(chalk_1.default.blue(`
811
+ ╔═══════════════════════════════════════════════════════════╗
812
+ ║ ║
813
+ ║ ${chalk_1.default.bold('Welcome to CodeBakers!')} ║
814
+ ║ ║
815
+ ║ Production-grade patterns for AI-assisted development ║
816
+ ║ ║
817
+ ╚═══════════════════════════════════════════════════════════╝
818
+ `));
819
+ const cwd = process.cwd();
820
+ // Check if already initialized
821
+ const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
822
+ if ((0, fs_1.existsSync)(claudeMdPath)) {
823
+ const reinitialize = await confirm(' CLAUDE.md already exists. Reinitialize?');
824
+ if (!reinitialize) {
825
+ console.log(chalk_1.default.yellow('\n Skipping. Run with a fresh project or delete CLAUDE.md first.\n'));
826
+ return;
827
+ }
828
+ }
829
+ // Detect existing project
830
+ const projectInfo = detectExistingProject(cwd);
831
+ if (projectInfo.exists) {
832
+ // Existing project detected - ask what they want to do
833
+ console.log(chalk_1.default.yellow('\n 📁 Existing project detected!\n'));
834
+ console.log(chalk_1.default.white(' How would you like to proceed?\n'));
835
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('EXISTING PROJECT') + chalk_1.default.gray(' - Add CodeBakers to this codebase'));
836
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('NEW PROJECT') + chalk_1.default.gray(' - Start fresh (ignore existing code)\n'));
837
+ let modeChoice = '';
838
+ while (!['1', '2'].includes(modeChoice)) {
839
+ modeChoice = await prompt(' Enter 1 or 2: ');
840
+ }
841
+ if (modeChoice === '1') {
842
+ await initExistingProject(cwd, projectInfo);
843
+ }
844
+ else {
845
+ await initNewProject(cwd);
846
+ }
847
+ }
848
+ else {
849
+ // No existing project - go straight to new project flow
850
+ await initNewProject(cwd);
851
+ }
824
852
  }