@codebakers/cli 3.8.2 → 3.8.4

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,363 @@ 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
- }
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
289
  }
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]'}
583
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]'}
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]
459
+
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]
605
480
 
606
- The server returns all patterns, rules, and test requirements.
607
- You cannot write code without calling this tool first.
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
+ async function runGuidedQuestions() {
490
+ console.log(chalk_1.default.cyan('\n ━━━ Let\'s define your project ━━━\n'));
491
+ console.log(chalk_1.default.gray(' Answer these questions (press Enter to skip any)\n'));
492
+ // One-liner
493
+ console.log(chalk_1.default.white(' 1. What are you building?\n'));
494
+ const oneLiner = await prompt(' ') || 'A web application';
495
+ // Problem
496
+ console.log(chalk_1.default.white('\n 2. What problem does this solve?\n'));
497
+ const problem = await prompt(' ') || '';
498
+ // Users
499
+ console.log(chalk_1.default.white('\n 3. Who will use this?\n'));
500
+ console.log(chalk_1.default.gray(' (e.g., "small business owners", "freelancers", "developers")\n'));
501
+ const users = await prompt(' ') || 'General users';
502
+ // Features
503
+ console.log(chalk_1.default.white('\n 4. What are the 3 must-have features?\n'));
504
+ console.log(chalk_1.default.gray(' (Enter each feature, then press Enter. Type "done" when finished)\n'));
505
+ const features = [];
506
+ for (let i = 0; i < 5; i++) {
507
+ const feature = await prompt(` Feature ${i + 1}: `);
508
+ if (!feature || feature.toLowerCase() === 'done')
509
+ break;
510
+ features.push(feature);
511
+ }
512
+ // Auth
513
+ console.log(chalk_1.default.white('\n 5. Do users need to create accounts?\n'));
514
+ const authAnswer = await prompt(' (y/n): ');
515
+ const auth = authAnswer.toLowerCase() === 'y' || authAnswer.toLowerCase() === 'yes';
516
+ // Payments
517
+ console.log(chalk_1.default.white('\n 6. Will you charge money?\n'));
518
+ const paymentsAnswer = await prompt(' (y/n): ');
519
+ const payments = paymentsAnswer.toLowerCase() === 'y' || paymentsAnswer.toLowerCase() === 'yes';
520
+ // Integrations
521
+ console.log(chalk_1.default.white('\n 7. Any specific integrations needed?\n'));
522
+ console.log(chalk_1.default.gray(' (e.g., "Stripe, SendGrid, Twilio" or press Enter to skip)\n'));
523
+ const integrations = await prompt(' ') || '';
524
+ // Deadline
525
+ console.log(chalk_1.default.white('\n 8. When do you need this done?\n'));
526
+ console.log(chalk_1.default.gray(' (e.g., "2 weeks", "end of month", or press Enter to skip)\n'));
527
+ const deadline = await prompt(' ') || '';
528
+ console.log(chalk_1.default.green('\n ✓ Got it! Creating your PRD...\n'));
529
+ return { oneLiner, problem, users, features, auth, payments, integrations, deadline };
530
+ }
531
+ function createPrdFromAnswers(projectName, projectType, answers) {
532
+ const date = new Date().toISOString().split('T')[0];
533
+ const featuresSection = answers.features.length > 0
534
+ ? answers.features.map((f, i) => `${i + 1}. [ ] **${f}**`).join('\n')
535
+ : '1. [ ] **Feature 1:** [To be defined]\n2. [ ] **Feature 2:** [To be defined]';
536
+ const techRequirements = [];
537
+ if (answers.auth)
538
+ techRequirements.push('User authentication (Supabase Auth)');
539
+ if (answers.payments)
540
+ techRequirements.push('Payment processing (Stripe)');
541
+ if (answers.integrations)
542
+ techRequirements.push(answers.integrations);
543
+ return `# Product Requirements Document
544
+ # Project: ${projectName}
545
+ # Created: ${date}
546
+ # Type: ${projectType}
547
+
548
+ ## Overview
549
+ **One-liner:** ${answers.oneLiner}
550
+
551
+ **Problem:** ${answers.problem || '[To be refined]'}
552
+
553
+ **Solution:** ${answers.oneLiner}
554
+
555
+ ## Target Users
556
+ - **Primary:** ${answers.users}
557
+
558
+ ## Core Features (MVP)
559
+ ${featuresSection}
560
+
561
+ ## Technical Requirements
562
+ ${techRequirements.length > 0 ? techRequirements.map(t => `- ${t}`).join('\n') : '- [No specific requirements noted]'}
563
+
564
+ ## Timeline
565
+ ${answers.deadline ? `- **Target:** ${answers.deadline}` : '- [No deadline specified]'}
566
+
567
+ ## Notes
568
+ - Authentication: ${answers.auth ? 'Yes - users need accounts' : 'No - public access'}
569
+ - Payments: ${answers.payments ? 'Yes - will charge users' : 'No - free to use'}
570
+
571
+ ---
572
+ <!-- Generated from guided questions - AI reads this to build your project -->
573
+ `;
574
+ }
575
+ // ============================================================================
576
+ // SHARED SETUP FUNCTIONS
577
+ // ============================================================================
578
+ async function ensureLoggedIn() {
579
+ let apiKey = (0, config_js_1.getApiKey)();
580
+ if (apiKey) {
581
+ console.log(chalk_1.default.green(' ✓ Already logged in\n'));
582
+ const useExisting = await confirm(' Use existing API key?');
583
+ if (useExisting)
584
+ return apiKey;
585
+ apiKey = null;
586
+ }
587
+ console.log(chalk_1.default.white('\n Login to CodeBakers\n'));
588
+ console.log(chalk_1.default.gray(' Go to: ') + chalk_1.default.cyan('https://codebakers.ai/dashboard'));
589
+ console.log(chalk_1.default.gray(' Copy your API key (starts with cb_)\n'));
590
+ apiKey = await prompt(' Paste your API key: ');
591
+ if (!apiKey || !apiKey.startsWith('cb_')) {
592
+ console.log(chalk_1.default.red('\n ✗ Invalid API key. Keys start with "cb_"\n'));
593
+ process.exit(1);
594
+ }
595
+ const spinner = (0, ora_1.default)(' Validating API key...').start();
609
596
  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)
597
+ const apiUrl = (0, config_js_1.getApiUrl)();
598
+ const response = await fetch(`${apiUrl}/api/content`, {
599
+ method: 'GET',
600
+ headers: { Authorization: `Bearer ${apiKey}` },
601
+ });
602
+ if (!response.ok) {
603
+ throw new Error('Invalid API key');
604
+ }
605
+ (0, config_js_1.setApiKey)(apiKey);
606
+ spinner.succeed('API key valid!');
607
+ return apiKey;
608
+ }
609
+ catch (error) {
610
+ spinner.fail('Invalid API key');
611
+ process.exit(1);
612
+ }
613
+ }
614
+ function installBootstrapFiles(cwd) {
615
+ const spinner = (0, ora_1.default)(' Installing bootstrap files...').start();
616
+ try {
617
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'CLAUDE.md'), CLAUDE_MD_BOOTSTRAP);
618
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.cursorrules'), CURSORRULES_TEMPLATE);
619
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.cursorignore'), CURSORIGNORE_TEMPLATE);
620
+ // Remove old .claude folder if it exists
614
621
  const claudeDir = (0, path_1.join)(cwd, '.claude');
615
622
  if ((0, fs_1.existsSync)(claudeDir)) {
616
- const { rmSync } = await import('fs');
617
623
  try {
618
- rmSync(claudeDir, { recursive: true, force: true });
624
+ (0, fs_1.rmSync)(claudeDir, { recursive: true, force: true });
619
625
  }
620
626
  catch {
621
627
  // Ignore errors
622
628
  }
623
629
  }
624
- spinner.succeed('CodeBakers v6.0 installed!');
625
- console.log(chalk_1.default.gray('\n Patterns are server-enforced via MCP tools'));
630
+ spinner.succeed('Bootstrap files installed!');
626
631
  }
627
632
  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
- }
633
+ spinner.fail('Failed to install bootstrap files');
634
+ throw error;
644
635
  }
645
- else {
646
- scanSpinner.succeed('Project scanned (new project detected)');
647
- }
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();
636
+ }
637
+ function setupCursorIDE(cwd) {
638
+ const spinner = (0, ora_1.default)(' Setting up Cursor IDE...').start();
670
639
  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
640
+ // Global MCP config
677
641
  const homeDir = process.env.USERPROFILE || process.env.HOME || '';
678
642
  const globalCursorDir = (0, path_1.join)(homeDir, '.cursor');
679
643
  if (!(0, fs_1.existsSync)(globalCursorDir)) {
@@ -688,7 +652,6 @@ You cannot write code without calling this tool first.
688
652
  : { command: 'npx', args: ['-y', '@codebakers/cli', 'serve'] }
689
653
  }
690
654
  };
691
- // Merge with existing MCP config if present
692
655
  if ((0, fs_1.existsSync)(mcpConfigPath)) {
693
656
  try {
694
657
  const existing = JSON.parse((0, fs_1.readFileSync)(mcpConfigPath, 'utf-8'));
@@ -702,123 +665,297 @@ You cannot write code without calling this tool first.
702
665
  else {
703
666
  (0, fs_1.writeFileSync)(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));
704
667
  }
705
- // Create/merge .vscode/settings.json
668
+ // VSCode settings
706
669
  const vscodeDir = (0, path_1.join)(cwd, '.vscode');
707
670
  if (!(0, fs_1.existsSync)(vscodeDir)) {
708
671
  (0, fs_1.mkdirSync)(vscodeDir, { recursive: true });
709
672
  }
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));
673
+ const settingsPath = (0, path_1.join)(vscodeDir, 'settings.json');
674
+ if ((0, fs_1.existsSync)(settingsPath)) {
675
+ const existing = JSON.parse((0, fs_1.readFileSync)(settingsPath, 'utf-8'));
676
+ (0, fs_1.writeFileSync)(settingsPath, JSON.stringify({ ...existing, ...VSCODE_SETTINGS_TEMPLATE }, null, 2));
715
677
  }
716
678
  else {
717
- (0, fs_1.writeFileSync)(existingSettingsPath, JSON.stringify(VSCODE_SETTINGS_TEMPLATE, null, 2));
679
+ (0, fs_1.writeFileSync)(settingsPath, JSON.stringify(VSCODE_SETTINGS_TEMPLATE, null, 2));
718
680
  }
719
- cursorSpinner.succeed('Cursor configuration installed!');
720
- console.log(chalk_1.default.green(' ✓ MCP server configured (~/.cursor/mcp.json)'));
681
+ spinner.succeed('Cursor IDE configured!');
721
682
  }
722
- catch (error) {
723
- cursorSpinner.warn('Could not install Cursor files (continuing anyway)');
683
+ catch {
684
+ spinner.warn('Could not configure Cursor IDE (continuing anyway)');
724
685
  }
725
- // Step 8: Add to .gitignore if not present
686
+ }
687
+ function updateGitignore(cwd) {
726
688
  const gitignorePath = (0, path_1.join)(cwd, '.gitignore');
727
689
  if ((0, fs_1.existsSync)(gitignorePath)) {
728
690
  const gitignore = (0, fs_1.readFileSync)(gitignorePath, 'utf-8');
729
691
  if (!gitignore.includes('.cursorrules')) {
730
- const additions = '\n# CodeBakers\n.cursorrules\n';
731
- (0, fs_1.writeFileSync)(gitignorePath, gitignore + additions);
692
+ (0, fs_1.writeFileSync)(gitignorePath, gitignore + '\n# CodeBakers\n.cursorrules\n');
693
+ }
694
+ }
695
+ }
696
+ function createTrackingFiles(cwd, projectName, stack, structure, isExisting, auditScore) {
697
+ const spinner = (0, ora_1.default)(' Creating project tracking files...').start();
698
+ try {
699
+ // Create .codebakers directory
700
+ const codebakersDir = (0, path_1.join)(cwd, '.codebakers');
701
+ if (!(0, fs_1.existsSync)(codebakersDir)) {
702
+ (0, fs_1.mkdirSync)(codebakersDir, { recursive: true });
732
703
  }
704
+ // PROJECT-CONTEXT.md
705
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PROJECT-CONTEXT.md'), createProjectContext(projectName, stack, structure, isExisting));
706
+ // PROJECT-STATE.md
707
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PROJECT-STATE.md'), createProjectState(projectName, isExisting));
708
+ // DECISIONS.md
709
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'DECISIONS.md'), createDecisionsLog(projectName));
710
+ // .codebakers/DEVLOG.md
711
+ (0, fs_1.writeFileSync)((0, path_1.join)(codebakersDir, 'DEVLOG.md'), createDevlog(projectName, isExisting, auditScore));
712
+ // .codebakers.json state file
713
+ const stateFile = (0, path_1.join)(cwd, '.codebakers.json');
714
+ const state = {
715
+ version: '1.0',
716
+ serverEnforced: true,
717
+ projectType: isExisting ? 'existing' : 'new',
718
+ projectName,
719
+ createdAt: new Date().toISOString(),
720
+ stack,
721
+ auditScore: auditScore
722
+ };
723
+ (0, fs_1.writeFileSync)(stateFile, JSON.stringify(state, null, 2));
724
+ spinner.succeed('Project tracking files created!');
725
+ }
726
+ catch (error) {
727
+ spinner.warn('Some tracking files could not be created');
728
+ }
729
+ }
730
+ // ============================================================================
731
+ // MODE: NEW PROJECT
732
+ // ============================================================================
733
+ async function initNewProject(cwd) {
734
+ console.log(chalk_1.default.cyan('\n ━━━ New Project Setup ━━━\n'));
735
+ // Get project info
736
+ console.log(chalk_1.default.white(' What kind of project is this?\n'));
737
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('PERSONAL') + chalk_1.default.gray(' - Just building for myself'));
738
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('CLIENT') + chalk_1.default.gray(' - Building for someone else'));
739
+ console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('BUSINESS') + chalk_1.default.gray(' - My own product/startup\n'));
740
+ let typeChoice = '';
741
+ while (!['1', '2', '3'].includes(typeChoice)) {
742
+ typeChoice = await prompt(' Enter 1, 2, or 3: ');
743
+ }
744
+ const typeMap = { '1': 'personal', '2': 'client', '3': 'business' };
745
+ const projectType = typeMap[typeChoice];
746
+ const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
747
+ const projectName = await prompt(` Project name (${defaultName}): `) || defaultName;
748
+ console.log(chalk_1.default.green(`\n ✓ Setting up "${projectName}" as ${projectType.toUpperCase()} project\n`));
749
+ // Login
750
+ await ensureLoggedIn();
751
+ // Install files
752
+ console.log(chalk_1.default.white('\n Installing CodeBakers...\n'));
753
+ installBootstrapFiles(cwd);
754
+ // Create tracking files
755
+ const structure = buildStructureString(cwd);
756
+ createTrackingFiles(cwd, projectName, {}, structure, false);
757
+ // Setup Cursor
758
+ console.log('');
759
+ setupCursorIDE(cwd);
760
+ // Update .gitignore
761
+ updateGitignore(cwd);
762
+ // How to describe project
763
+ console.log(chalk_1.default.white('\n 📝 How would you like to describe your project?\n'));
764
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('GUIDED QUESTIONS') + chalk_1.default.gray(' - I\'ll ask you step by step'));
765
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('WRITE A PRD') + chalk_1.default.gray(' - Create a requirements doc to fill out'));
766
+ console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('DESCRIBE IN CHAT') + chalk_1.default.gray(' - Just tell the AI what you want'));
767
+ console.log(chalk_1.default.gray(' 4. ') + chalk_1.default.cyan('I HAVE SPECS') + chalk_1.default.gray(' - I\'ll share existing docs/mockups\n'));
768
+ let describeChoice = '';
769
+ while (!['1', '2', '3', '4'].includes(describeChoice)) {
770
+ describeChoice = await prompt(' Enter 1, 2, 3, or 4: ');
733
771
  }
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
772
  let prdCreated = false;
738
- if ((0, fs_1.existsSync)(prdPath)) {
739
- console.log(chalk_1.default.green(' ✓ PRD.md already exists\n'));
773
+ if (describeChoice === '1') {
774
+ // Guided questions
775
+ const answers = await runGuidedQuestions();
776
+ const prdSpinner = (0, ora_1.default)(' Creating PRD from your answers...').start();
777
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PRD.md'), createPrdFromAnswers(projectName, projectType, answers));
778
+ prdSpinner.succeed('PRD created from your answers!');
779
+ console.log(chalk_1.default.yellow('\n → Review PRD.md, then start building with the AI\n'));
780
+ prdCreated = true;
781
+ }
782
+ else if (describeChoice === '2') {
783
+ // Write PRD template
784
+ const prdSpinner = (0, ora_1.default)(' Creating PRD template...').start();
785
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PRD.md'), createPrdTemplate(projectName, projectType));
786
+ prdSpinner.succeed('PRD template created!');
787
+ console.log(chalk_1.default.yellow('\n → Open PRD.md and fill in your requirements\n'));
740
788
  prdCreated = true;
741
789
  }
790
+ else if (describeChoice === '3') {
791
+ // Describe in chat
792
+ console.log(chalk_1.default.gray('\n Perfect! Just describe your project to the AI when you\'re ready.\n'));
793
+ console.log(chalk_1.default.gray(' Example: "Build me a SaaS for invoice management with Stripe payments"\n'));
794
+ }
742
795
  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';
796
+ // I have specs
797
+ console.log(chalk_1.default.gray('\n Great! When chatting with the AI:\n'));
798
+ console.log(chalk_1.default.gray(' Share your docs, mockups, or screenshots'));
799
+ console.log(chalk_1.default.gray(' Paste your existing requirements'));
800
+ console.log(chalk_1.default.gray(' Reference URLs to designs you want to clone\n'));
801
+ console.log(chalk_1.default.cyan(' The AI will analyze them and start building.\n'));
802
+ }
803
+ // Success
804
+ showSuccessMessage(projectName, false, prdCreated);
805
+ }
806
+ // ============================================================================
807
+ // MODE: EXISTING PROJECT
808
+ // ============================================================================
809
+ async function initExistingProject(cwd, projectInfo) {
810
+ console.log(chalk_1.default.cyan('\n ━━━ Existing Project Setup ━━━\n'));
811
+ // Show what was detected
812
+ console.log(chalk_1.default.gray(' Detected:'));
813
+ for (const detail of projectInfo.details.slice(0, 5)) {
814
+ console.log(chalk_1.default.gray(` • ${detail}`));
815
+ }
816
+ const stackItems = Object.entries(projectInfo.stack).filter(([_, v]) => v);
817
+ if (stackItems.length > 0) {
818
+ console.log(chalk_1.default.gray('\n Tech Stack:'));
819
+ for (const [key, value] of stackItems) {
820
+ console.log(chalk_1.default.gray(` • ${key}: ${value}`));
757
821
  }
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;
822
+ }
823
+ // Get project name
824
+ const defaultName = cwd.split(/[\\/]/).pop() || 'my-project';
825
+ const projectName = await prompt(`\n Project name (${defaultName}): `) || defaultName;
826
+ // Code review offer
827
+ console.log(chalk_1.default.white('\n Want me to review your code and bring it up to CodeBakers standards?\n'));
828
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('YES, REVIEW & FIX') + chalk_1.default.gray(' - Run audit, then auto-fix issues'));
829
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('REVIEW ONLY') + chalk_1.default.gray(' - Just show me the issues'));
830
+ console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('SKIP') + chalk_1.default.gray(' - Just install CodeBakers\n'));
831
+ let reviewChoice = '';
832
+ while (!['1', '2', '3'].includes(reviewChoice)) {
833
+ reviewChoice = await prompt(' Enter 1, 2, or 3: ');
834
+ }
835
+ let auditScore;
836
+ if (reviewChoice !== '3') {
837
+ console.log(chalk_1.default.blue('\n Running code audit...\n'));
838
+ const auditResult = await (0, audit_js_1.audit)();
839
+ auditScore = auditResult.score;
840
+ if (auditResult.score >= 90) {
841
+ console.log(chalk_1.default.green('\n 🎉 Your code is already in great shape!\n'));
767
842
  }
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'));
843
+ else if (reviewChoice === '1') {
844
+ const fixableCount = auditResult.checks.filter(c => !c.passed && c.severity !== 'info').length;
845
+ if (fixableCount > 0) {
846
+ console.log(chalk_1.default.blue('\n 🔧 Attempting to auto-fix issues...\n'));
847
+ const healResult = await (0, heal_js_1.heal)({ auto: true });
848
+ if (healResult.fixed > 0) {
849
+ console.log(chalk_1.default.green(`\n ✓ Fixed ${healResult.fixed} issue(s)!`));
850
+ if (healResult.remaining > 0) {
851
+ console.log(chalk_1.default.yellow(` ⚠ ${healResult.remaining} issue(s) need manual attention.`));
852
+ }
853
+ }
789
854
  }
790
855
  }
791
856
  else {
792
- console.log(chalk_1.default.gray('\n You can add PRD.md anytime. The AI will use it automatically.\n'));
857
+ console.log(chalk_1.default.gray('\n Run `codebakers heal --auto` later to fix issues.\n'));
793
858
  }
794
859
  }
795
- // Success message
860
+ // Login
861
+ console.log('');
862
+ await ensureLoggedIn();
863
+ // Install files
864
+ console.log(chalk_1.default.white('\n Installing CodeBakers...\n'));
865
+ installBootstrapFiles(cwd);
866
+ // Create tracking files with detected stack
867
+ const structure = buildStructureString(cwd);
868
+ createTrackingFiles(cwd, projectName, projectInfo.stack, structure, true, auditScore);
869
+ // Setup Cursor
870
+ console.log('');
871
+ setupCursorIDE(cwd);
872
+ // Update .gitignore
873
+ updateGitignore(cwd);
874
+ // Success
875
+ showSuccessMessage(projectName, true);
876
+ }
877
+ // ============================================================================
878
+ // SUCCESS MESSAGE
879
+ // ============================================================================
880
+ function showSuccessMessage(projectName, isExisting, prdCreated) {
796
881
  console.log(chalk_1.default.green(`
797
882
  ╔═══════════════════════════════════════════════════════════╗
798
883
  ║ ║
799
- ║ ${chalk_1.default.bold('✓ Setup Complete!')}
884
+ ║ ${chalk_1.default.bold('✓ CodeBakers Setup Complete!')}
800
885
  ║ ║
801
886
  ╚═══════════════════════════════════════════════════════════╝
802
887
  `));
803
888
  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'));
889
+ console.log(chalk_1.default.cyan(' CLAUDE.md ') + chalk_1.default.gray('→ AI bootstrap (patterns via MCP)'));
890
+ console.log(chalk_1.default.cyan(' .cursorrules ') + chalk_1.default.gray('→ Cursor IDE rules'));
891
+ if (!isExisting && prdCreated) {
892
+ console.log(chalk_1.default.cyan(' PRD.md ') + chalk_1.default.gray('→ Product requirements'));
893
+ }
894
+ console.log(chalk_1.default.cyan(' PROJECT-CONTEXT.md ') + chalk_1.default.gray('→ Codebase knowledge'));
895
+ console.log(chalk_1.default.cyan(' PROJECT-STATE.md ') + chalk_1.default.gray('→ Task tracking'));
896
+ console.log(chalk_1.default.cyan(' DECISIONS.md ') + chalk_1.default.gray('→ Architecture log'));
897
+ console.log(chalk_1.default.cyan(' .codebakers/DEVLOG.md') + chalk_1.default.gray('→ Development log\n'));
898
+ if (isExisting) {
899
+ console.log(chalk_1.default.white(' What happens next:\n'));
900
+ console.log(chalk_1.default.gray(' ✓ AI will analyze your existing code patterns'));
901
+ console.log(chalk_1.default.gray(' ✓ AI follows your existing conventions'));
902
+ console.log(chalk_1.default.gray(' ✓ AI updates tracking files as you work\n'));
903
+ }
904
+ else {
905
+ console.log(chalk_1.default.white(' What happens next:\n'));
906
+ console.log(chalk_1.default.gray(' Describe what you want to build'));
907
+ console.log(chalk_1.default.gray(' AI fetches patterns and generates code'));
908
+ console.log(chalk_1.default.gray(' AI updates tracking files as you work\n'));
909
+ }
910
+ console.log(chalk_1.default.white(' Getting started:\n'));
911
+ console.log(chalk_1.default.gray(' For Cursor: Just open the project and start chatting'));
912
+ console.log(chalk_1.default.gray(' For Claude Code: Run ') + chalk_1.default.cyan('codebakers install-hook') + chalk_1.default.gray(' first\n'));
913
+ console.log(chalk_1.default.blue(' Ready to build! 🚀\n'));
914
+ }
915
+ // ============================================================================
916
+ // MAIN INIT FUNCTION
917
+ // ============================================================================
918
+ async function init() {
919
+ console.log(chalk_1.default.blue(`
920
+ ╔═══════════════════════════════════════════════════════════╗
921
+ ║ ║
922
+ ║ ${chalk_1.default.bold('Welcome to CodeBakers!')} ║
923
+ ║ ║
924
+ ║ Production-grade patterns for AI-assisted development ║
925
+ ║ ║
926
+ ╚═══════════════════════════════════════════════════════════╝
927
+ `));
928
+ const cwd = process.cwd();
929
+ // Check if already initialized
930
+ const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
931
+ if ((0, fs_1.existsSync)(claudeMdPath)) {
932
+ const reinitialize = await confirm(' CLAUDE.md already exists. Reinitialize?');
933
+ if (!reinitialize) {
934
+ console.log(chalk_1.default.yellow('\n Skipping. Run with a fresh project or delete CLAUDE.md first.\n'));
935
+ return;
936
+ }
937
+ }
938
+ // Detect existing project
939
+ const projectInfo = detectExistingProject(cwd);
940
+ if (projectInfo.exists) {
941
+ // Existing project detected - ask what they want to do
942
+ console.log(chalk_1.default.yellow('\n 📁 Existing project detected!\n'));
943
+ console.log(chalk_1.default.white(' How would you like to proceed?\n'));
944
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('EXISTING PROJECT') + chalk_1.default.gray(' - Add CodeBakers to this codebase'));
945
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('NEW PROJECT') + chalk_1.default.gray(' - Start fresh (ignore existing code)\n'));
946
+ let modeChoice = '';
947
+ while (!['1', '2'].includes(modeChoice)) {
948
+ modeChoice = await prompt(' Enter 1 or 2: ');
949
+ }
950
+ if (modeChoice === '1') {
951
+ await initExistingProject(cwd, projectInfo);
952
+ }
953
+ else {
954
+ await initNewProject(cwd);
955
+ }
956
+ }
957
+ else {
958
+ // No existing project - go straight to new project flow
959
+ await initNewProject(cwd);
960
+ }
824
961
  }