@codebakers/cli 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/commands/doctor.d.ts +8 -0
  2. package/dist/commands/doctor.js +218 -0
  3. package/dist/commands/init.d.ts +4 -0
  4. package/dist/commands/init.js +772 -0
  5. package/dist/commands/install-hook.d.ts +12 -0
  6. package/dist/commands/install-hook.js +193 -0
  7. package/dist/commands/install.d.ts +1 -0
  8. package/dist/commands/install.js +81 -0
  9. package/dist/commands/login.d.ts +1 -0
  10. package/dist/commands/login.js +54 -0
  11. package/dist/commands/mcp-config.d.ts +6 -0
  12. package/dist/commands/mcp-config.js +209 -0
  13. package/dist/commands/serve.d.ts +1 -0
  14. package/dist/commands/serve.js +26 -0
  15. package/dist/commands/setup.d.ts +1 -0
  16. package/dist/commands/setup.js +92 -0
  17. package/dist/commands/status.d.ts +1 -0
  18. package/dist/commands/status.js +49 -0
  19. package/dist/commands/uninstall.d.ts +1 -0
  20. package/dist/commands/uninstall.js +50 -0
  21. package/dist/config.d.ts +5 -0
  22. package/dist/config.js +33 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +71 -1075
  25. package/dist/mcp/server.d.ts +2 -0
  26. package/dist/mcp/server.js +544 -0
  27. package/package.json +17 -38
  28. package/src/commands/doctor.ts +231 -0
  29. package/src/commands/init.ts +827 -0
  30. package/src/commands/install-hook.ts +207 -0
  31. package/src/commands/install.ts +94 -0
  32. package/src/commands/login.ts +56 -0
  33. package/src/commands/mcp-config.ts +235 -0
  34. package/src/commands/serve.ts +23 -0
  35. package/src/commands/setup.ts +104 -0
  36. package/src/commands/status.ts +48 -0
  37. package/src/commands/uninstall.ts +49 -0
  38. package/src/config.ts +34 -0
  39. package/src/index.ts +87 -0
  40. package/src/mcp/server.ts +617 -0
  41. package/tsconfig.json +16 -0
  42. package/README.md +0 -89
  43. package/dist/chunk-7CKLRE2H.js +0 -36
  44. package/dist/config-R2H6JKGW.js +0 -16
@@ -0,0 +1,772 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.init = init;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const readline_1 = require("readline");
10
+ const fs_1 = require("fs");
11
+ const path_1 = require("path");
12
+ const config_js_1 = require("../config.js");
13
+ // Enhanced .cursorrules with pre-flight and self-review automation
14
+ const CURSORRULES_TEMPLATE = `# CODEBAKERS CURSOR RULES
15
+ # Zero-friction AI assistance - everything is automatic
16
+
17
+ ## ON EVERY MESSAGE - AUTOMATIC WORKFLOW
18
+
19
+ ### PHASE 1: CONTEXT LOAD (automatic)
20
+ 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
25
+
26
+ ### PHASE 2: PRE-FLIGHT CHECK (before writing code)
27
+ Ask yourself silently:
28
+ - [ ] What existing code does this touch? (check PROJECT-CONTEXT.md)
29
+ - [ ] Is similar code already in the codebase? (copy that pattern)
30
+ - [ ] What's the data model involved?
31
+ - [ ] 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
+
40
+ ### PHASE 3: EXECUTE
41
+ - State: \`📋 CodeBakers | [Type] | Modules: [list]\`
42
+ - Load required modules from .claude/
43
+ - Follow patterns EXACTLY
44
+
45
+ ### PHASE 4: SELF-REVIEW (before saying "done")
46
+ - [ ] TypeScript compiles? (npx tsc --noEmit)
47
+ - [ ] Imports resolve correctly?
48
+ - [ ] Error handling exists?
49
+ - [ ] Matches existing patterns in codebase?
50
+ - [ ] Tests written?
51
+ - [ ] PROJECT-STATE.md updated?
52
+
53
+ If ANY check fails, fix it before responding.
54
+
55
+ ### PHASE 5: UPDATE STATE
56
+ - Update PROJECT-STATE.md with completed work
57
+ - 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
63
+
64
+ ## REMEMBER
65
+ - You are a full product team, not just a code assistant
66
+ - The modules contain production-tested patterns — USE THEM
67
+ - When in doubt, check existing code first
68
+ `;
69
+ const CURSORIGNORE_TEMPLATE = `# CodeBakers - Files to ignore in Cursor context
70
+
71
+ # Dependencies
72
+ node_modules/
73
+ .pnpm-store/
74
+ bower_components/
75
+
76
+ # Build outputs
77
+ dist/
78
+ build/
79
+ .next/
80
+ .nuxt/
81
+ .output/
82
+ out/
83
+
84
+ # Cache
85
+ .cache/
86
+ .turbo/
87
+ .eslintcache
88
+ .prettiercache
89
+ *.tsbuildinfo
90
+
91
+ # Logs
92
+ logs/
93
+ *.log
94
+ npm-debug.log*
95
+ yarn-debug.log*
96
+ yarn-error.log*
97
+
98
+ # Environment files (don't leak secrets)
99
+ .env
100
+ .env.local
101
+ .env.*.local
102
+ .env.production
103
+
104
+ # IDE
105
+ .idea/
106
+ *.swp
107
+ *.swo
108
+
109
+ # OS
110
+ .DS_Store
111
+ Thumbs.db
112
+
113
+ # Test coverage
114
+ coverage/
115
+ .nyc_output/
116
+
117
+ # Package locks (large files, not needed for context)
118
+ package-lock.json
119
+ yarn.lock
120
+ pnpm-lock.yaml
121
+
122
+ # Generated files
123
+ *.min.js
124
+ *.min.css
125
+ *.map
126
+ `;
127
+ const VSCODE_SETTINGS_TEMPLATE = {
128
+ "cursor.chat.defaultContext": [
129
+ "CLAUDE.md",
130
+ "PRD.md",
131
+ "PROJECT-CONTEXT.md",
132
+ "PROJECT-STATE.md",
133
+ "DECISIONS.md"
134
+ ],
135
+ "cursor.chat.alwaysIncludeRules": true,
136
+ "cursor.composer.alwaysIncludeRules": true,
137
+ "cursor.general.enableAutoImport": true
138
+ };
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
+ async function prompt(question) {
245
+ const rl = (0, readline_1.createInterface)({
246
+ input: process.stdin,
247
+ output: process.stdout,
248
+ });
249
+ return new Promise((resolve) => {
250
+ rl.question(question, (answer) => {
251
+ rl.close();
252
+ resolve(answer);
253
+ });
254
+ });
255
+ }
256
+ async function confirm(question) {
257
+ const answer = await prompt(`${question} (Y/n): `);
258
+ return answer.toLowerCase() !== 'n';
259
+ }
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: ');
268
+ }
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 pattern system
390
+ **Reason:** Ensure consistent, production-quality code
391
+ **Pattern:** See .claude/ folder for all patterns
392
+
393
+ ---
394
+
395
+ <!-- AI: Add new decisions above this line -->
396
+ `;
397
+ }
398
+ /**
399
+ * Auto-scan project to detect tech stack
400
+ */
401
+ function scanProject(cwd) {
402
+ const stack = {};
403
+ let structure = '';
404
+ // Check package.json
405
+ const packageJsonPath = (0, path_1.join)(cwd, 'package.json');
406
+ if ((0, fs_1.existsSync)(packageJsonPath)) {
407
+ try {
408
+ const pkg = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, 'utf-8'));
409
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
410
+ // Detect framework
411
+ if (deps['next'])
412
+ stack.framework = `Next.js ${deps['next']}`;
413
+ else if (deps['react'])
414
+ stack.framework = `React ${deps['react']}`;
415
+ else if (deps['vue'])
416
+ stack.framework = `Vue ${deps['vue']}`;
417
+ else if (deps['express'])
418
+ stack.framework = `Express ${deps['express']}`;
419
+ // Detect database
420
+ if (deps['drizzle-orm'])
421
+ stack.database = 'Drizzle ORM';
422
+ else if (deps['prisma'])
423
+ stack.database = 'Prisma';
424
+ else if (deps['mongoose'])
425
+ stack.database = 'MongoDB/Mongoose';
426
+ else if (deps['pg'])
427
+ stack.database = 'PostgreSQL';
428
+ // Detect auth
429
+ if (deps['@supabase/supabase-js'])
430
+ stack.auth = 'Supabase Auth';
431
+ else if (deps['next-auth'])
432
+ stack.auth = 'NextAuth.js';
433
+ else if (deps['@clerk/nextjs'])
434
+ stack.auth = 'Clerk';
435
+ // Detect styling
436
+ if (deps['tailwindcss'])
437
+ 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
+ if (deps['typescript'] || (0, fs_1.existsSync)((0, path_1.join)(cwd, 'tsconfig.json'))) {
449
+ stack.language = 'TypeScript';
450
+ }
451
+ else {
452
+ stack.language = 'JavaScript';
453
+ }
454
+ }
455
+ catch {
456
+ // Ignore parse errors
457
+ }
458
+ }
459
+ // Build simple structure
460
+ try {
461
+ const items = (0, fs_1.readdirSync)(cwd);
462
+ const dirs = [];
463
+ const files = [];
464
+ for (const item of items) {
465
+ if (item.startsWith('.') || item === 'node_modules')
466
+ continue;
467
+ const fullPath = (0, path_1.join)(cwd, item);
468
+ try {
469
+ if ((0, fs_1.statSync)(fullPath).isDirectory()) {
470
+ dirs.push(item + '/');
471
+ }
472
+ else {
473
+ files.push(item);
474
+ }
475
+ }
476
+ catch {
477
+ // Skip inaccessible items
478
+ }
479
+ }
480
+ structure = [...dirs.sort(), ...files.sort()].join('\n');
481
+ }
482
+ catch {
483
+ structure = '[Could not scan structure]';
484
+ }
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
+ }
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 patterns from API
577
+ console.log(chalk_1.default.white('\n Step 2: Installing patterns\n'));
578
+ const spinner = (0, ora_1.default)(' Downloading patterns...').start();
579
+ try {
580
+ const apiUrl = (0, config_js_1.getApiUrl)();
581
+ const response = await fetch(`${apiUrl}/api/content`, {
582
+ method: 'GET',
583
+ headers: {
584
+ Authorization: `Bearer ${apiKey}`,
585
+ },
586
+ });
587
+ if (!response.ok) {
588
+ const error = await response.json().catch(() => ({}));
589
+ throw new Error(error.error || 'Failed to fetch content');
590
+ }
591
+ const content = await response.json();
592
+ spinner.text = ' Installing patterns...';
593
+ // Write router file (CLAUDE.md)
594
+ if (content.router) {
595
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'CLAUDE.md'), content.router);
596
+ }
597
+ // Write modules to .claude/
598
+ if (content.modules && Object.keys(content.modules).length > 0) {
599
+ const modulesDir = (0, path_1.join)(cwd, '.claude');
600
+ if (!(0, fs_1.existsSync)(modulesDir)) {
601
+ (0, fs_1.mkdirSync)(modulesDir, { recursive: true });
602
+ }
603
+ for (const [name, data] of Object.entries(content.modules)) {
604
+ (0, fs_1.writeFileSync)((0, path_1.join)(modulesDir, name), data);
605
+ }
606
+ }
607
+ spinner.succeed('Patterns installed!');
608
+ console.log(chalk_1.default.gray(`\n Version: ${content.version}`));
609
+ console.log(chalk_1.default.gray(` Modules: ${Object.keys(content.modules || {}).length} pattern files`));
610
+ }
611
+ catch (error) {
612
+ spinner.fail('Pattern installation failed');
613
+ const message = error instanceof Error ? error.message : 'Unknown error';
614
+ console.log(chalk_1.default.red(`\n Error: ${message}\n`));
615
+ process.exit(1);
616
+ }
617
+ // Step 5: Auto-scan project
618
+ console.log(chalk_1.default.white('\n Step 3: Scanning project\n'));
619
+ const scanSpinner = (0, ora_1.default)(' Analyzing project structure...').start();
620
+ const { stack, structure } = scanProject(cwd);
621
+ const detectedItems = Object.entries(stack).filter(([_, v]) => v).map(([k, v]) => `${k}: ${v}`);
622
+ if (detectedItems.length > 0) {
623
+ scanSpinner.succeed('Project analyzed!');
624
+ console.log(chalk_1.default.gray('\n Detected:'));
625
+ for (const item of detectedItems) {
626
+ console.log(chalk_1.default.gray(` ${item}`));
627
+ }
628
+ }
629
+ else {
630
+ scanSpinner.succeed('Project scanned (new project detected)');
631
+ }
632
+ // Step 6: Create PROJECT-CONTEXT.md with scan results
633
+ console.log(chalk_1.default.white('\n Step 4: Setting up project files\n'));
634
+ const filesSpinner = (0, ora_1.default)(' Creating project files...').start();
635
+ try {
636
+ // PROJECT-CONTEXT.md
637
+ let contextContent = createProjectContext(projectName, projectType);
638
+ contextContent = updateProjectContextWithScan(contextContent, stack, structure);
639
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PROJECT-CONTEXT.md'), contextContent);
640
+ // PROJECT-STATE.md
641
+ const stateContent = createProjectState(projectName, projectType);
642
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'PROJECT-STATE.md'), stateContent);
643
+ // DECISIONS.md
644
+ const decisionsContent = createDecisionsLog(projectName);
645
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, 'DECISIONS.md'), decisionsContent);
646
+ filesSpinner.succeed('Project files created!');
647
+ }
648
+ catch (error) {
649
+ filesSpinner.warn('Some project files could not be created');
650
+ }
651
+ // Step 7: Install Cursor files
652
+ console.log(chalk_1.default.white('\n Step 5: Setting up Cursor IDE\n'));
653
+ const cursorSpinner = (0, ora_1.default)(' Installing Cursor configuration...').start();
654
+ try {
655
+ // Write .cursorrules
656
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.cursorrules'), CURSORRULES_TEMPLATE);
657
+ // Write .cursorignore
658
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, '.cursorignore'), CURSORIGNORE_TEMPLATE);
659
+ // Create/merge .vscode/settings.json
660
+ const vscodeDir = (0, path_1.join)(cwd, '.vscode');
661
+ if (!(0, fs_1.existsSync)(vscodeDir)) {
662
+ (0, fs_1.mkdirSync)(vscodeDir, { recursive: true });
663
+ }
664
+ const existingSettingsPath = (0, path_1.join)(vscodeDir, 'settings.json');
665
+ if ((0, fs_1.existsSync)(existingSettingsPath)) {
666
+ const existing = JSON.parse((0, fs_1.readFileSync)(existingSettingsPath, 'utf-8'));
667
+ const merged = { ...existing, ...VSCODE_SETTINGS_TEMPLATE };
668
+ (0, fs_1.writeFileSync)(existingSettingsPath, JSON.stringify(merged, null, 2));
669
+ }
670
+ else {
671
+ (0, fs_1.writeFileSync)(existingSettingsPath, JSON.stringify(VSCODE_SETTINGS_TEMPLATE, null, 2));
672
+ }
673
+ cursorSpinner.succeed('Cursor configuration installed!');
674
+ }
675
+ catch (error) {
676
+ cursorSpinner.warn('Could not install Cursor files (continuing anyway)');
677
+ }
678
+ // Step 8: Add to .gitignore if not present
679
+ const gitignorePath = (0, path_1.join)(cwd, '.gitignore');
680
+ if ((0, fs_1.existsSync)(gitignorePath)) {
681
+ const gitignore = (0, fs_1.readFileSync)(gitignorePath, 'utf-8');
682
+ if (!gitignore.includes('.cursorrules')) {
683
+ const additions = '\n# CodeBakers (encoded patterns)\n.cursorrules\n.claude/\n';
684
+ (0, fs_1.writeFileSync)(gitignorePath, gitignore + additions);
685
+ }
686
+ }
687
+ // Step 9: PRD Setup
688
+ console.log(chalk_1.default.white('\n Step 6: Product Requirements\n'));
689
+ const prdPath = (0, path_1.join)(cwd, 'PRD.md');
690
+ let prdCreated = false;
691
+ if ((0, fs_1.existsSync)(prdPath)) {
692
+ console.log(chalk_1.default.green(' ✓ PRD.md already exists\n'));
693
+ prdCreated = true;
694
+ }
695
+ else {
696
+ console.log(chalk_1.default.gray(' A PRD helps the AI understand what you\'re building.\n'));
697
+ console.log(chalk_1.default.white(' How would you like to set up your PRD?\n'));
698
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('CREATE TEMPLATE') + chalk_1.default.gray(' - I\'ll fill it out'));
699
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('PASTE CONTENT') + chalk_1.default.gray(' - I have requirements ready'));
700
+ console.log(chalk_1.default.gray(' 3. ') + chalk_1.default.cyan('SKIP FOR NOW') + chalk_1.default.gray(' - I\'ll add it later\n'));
701
+ let prdChoice = '';
702
+ while (!['1', '2', '3'].includes(prdChoice)) {
703
+ prdChoice = await prompt(' Enter 1, 2, or 3: ');
704
+ }
705
+ if (prdChoice === '1') {
706
+ // Create template
707
+ const prdSpinner = (0, ora_1.default)(' Creating PRD template...').start();
708
+ const prdContent = createPrdTemplate(projectName, projectType);
709
+ (0, fs_1.writeFileSync)(prdPath, prdContent);
710
+ prdSpinner.succeed('PRD template created!');
711
+ console.log(chalk_1.default.yellow('\n → Open PRD.md and fill in your requirements'));
712
+ console.log(chalk_1.default.gray(' The AI will use this to understand what to build.\n'));
713
+ prdCreated = true;
714
+ }
715
+ else if (prdChoice === '2') {
716
+ // Paste content
717
+ console.log(chalk_1.default.gray('\n Paste your PRD content below.'));
718
+ 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'));
719
+ const lines = [];
720
+ let line = '';
721
+ while (true) {
722
+ line = await prompt(' ');
723
+ if (line.trim().toUpperCase() === 'END')
724
+ break;
725
+ lines.push(line);
726
+ }
727
+ if (lines.length > 0) {
728
+ const prdSpinner = (0, ora_1.default)(' Saving PRD...').start();
729
+ const header = `# Product Requirements Document\n# Project: ${projectName}\n# Created: ${new Date().toISOString().split('T')[0]}\n\n`;
730
+ (0, fs_1.writeFileSync)(prdPath, header + lines.join('\n'));
731
+ prdSpinner.succeed('PRD saved!');
732
+ prdCreated = true;
733
+ }
734
+ else {
735
+ console.log(chalk_1.default.yellow(' No content provided, skipping PRD.\n'));
736
+ }
737
+ }
738
+ else {
739
+ console.log(chalk_1.default.gray('\n You can add PRD.md anytime. The AI will use it automatically.\n'));
740
+ }
741
+ }
742
+ // Success message
743
+ console.log(chalk_1.default.green(`
744
+ ╔═══════════════════════════════════════════════════════════╗
745
+ ║ ║
746
+ ║ ${chalk_1.default.bold('✓ Setup Complete!')} ║
747
+ ║ ║
748
+ ╚═══════════════════════════════════════════════════════════╝
749
+ `));
750
+ console.log(chalk_1.default.white(' Files created:\n'));
751
+ console.log(chalk_1.default.cyan(' CLAUDE.md ') + chalk_1.default.gray('→ AI router'));
752
+ if (prdCreated) {
753
+ console.log(chalk_1.default.cyan(' PRD.md ') + chalk_1.default.gray('→ Product requirements (AI reads this!)'));
754
+ }
755
+ console.log(chalk_1.default.cyan(' PROJECT-CONTEXT.md ') + chalk_1.default.gray('→ Codebase knowledge (auto-updated)'));
756
+ console.log(chalk_1.default.cyan(' PROJECT-STATE.md ') + chalk_1.default.gray('→ Task tracking (auto-updated)'));
757
+ console.log(chalk_1.default.cyan(' DECISIONS.md ') + chalk_1.default.gray('→ Architecture log (auto-updated)'));
758
+ console.log(chalk_1.default.cyan(' .cursorrules ') + chalk_1.default.gray('→ Cursor AI instructions'));
759
+ console.log(chalk_1.default.cyan(' .cursorignore ') + chalk_1.default.gray('→ Context optimization'));
760
+ console.log(chalk_1.default.cyan(' .claude/ ') + chalk_1.default.gray('→ Pattern modules\n'));
761
+ console.log(chalk_1.default.white(' What happens automatically:\n'));
762
+ console.log(chalk_1.default.gray(' ✓ AI loads context before every response'));
763
+ console.log(chalk_1.default.gray(' ✓ AI checks for existing patterns to copy'));
764
+ console.log(chalk_1.default.gray(' ✓ AI validates code before outputting'));
765
+ console.log(chalk_1.default.gray(' ✓ AI updates project state after completing tasks'));
766
+ console.log(chalk_1.default.gray(' ✓ AI logs architectural decisions\n'));
767
+ console.log(chalk_1.default.white(' For Cursor users:\n'));
768
+ console.log(chalk_1.default.gray(' Just open the project and start chatting!\n'));
769
+ console.log(chalk_1.default.white(' For Claude Code users:\n'));
770
+ console.log(chalk_1.default.cyan(' codebakers install-hook') + chalk_1.default.gray(' (one-time setup)\n'));
771
+ console.log(chalk_1.default.blue(' Zero friction. Just build.\n'));
772
+ }