@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.
- package/dist/commands/init.d.ts +0 -3
- package/dist/commands/init.js +685 -548
- package/dist/commands/install.js +14 -15
- package/dist/commands/upgrade.d.ts +1 -1
- package/dist/commands/upgrade.js +57 -313
- package/dist/index.js +7 -151
- package/package.json +1 -1
- package/src/commands/init.ts +730 -545
- package/src/commands/install.ts +14 -15
- package/src/commands/upgrade.ts +60 -369
- package/src/index.ts +7 -185
package/dist/commands/init.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
22
|
-
3. Read PROJECT-
|
|
23
|
-
4. Read
|
|
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] |
|
|
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
|
|
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
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
400
|
-
*/
|
|
401
|
-
function scanProject(cwd) {
|
|
176
|
+
function detectExistingProject(cwd) {
|
|
177
|
+
const details = [];
|
|
402
178
|
const stack = {};
|
|
403
|
-
let
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
284
|
+
return [...dirs.sort(), ...files.sort()].join('\n');
|
|
481
285
|
}
|
|
482
286
|
catch {
|
|
483
|
-
|
|
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
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
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
|
-
|
|
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
|
-
|
|
586
|
-
Args: { task: "description of what you're building" }
|
|
313
|
+
${structure || '[Empty project]'}
|
|
587
314
|
\`\`\`
|
|
588
315
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
-
|
|
592
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
604
|
-
|
|
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
|
-
|
|
607
|
-
|
|
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
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
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('
|
|
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('
|
|
629
|
-
|
|
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
|
-
|
|
646
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
711
|
-
if ((0, fs_1.existsSync)(
|
|
712
|
-
const existing = JSON.parse((0, fs_1.readFileSync)(
|
|
713
|
-
|
|
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)(
|
|
679
|
+
(0, fs_1.writeFileSync)(settingsPath, JSON.stringify(VSCODE_SETTINGS_TEMPLATE, null, 2));
|
|
718
680
|
}
|
|
719
|
-
|
|
720
|
-
console.log(chalk_1.default.green(' ✓ MCP server configured (~/.cursor/mcp.json)'));
|
|
681
|
+
spinner.succeed('Cursor IDE configured!');
|
|
721
682
|
}
|
|
722
|
-
catch
|
|
723
|
-
|
|
683
|
+
catch {
|
|
684
|
+
spinner.warn('Could not configure Cursor IDE (continuing anyway)');
|
|
724
685
|
}
|
|
725
|
-
|
|
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
|
-
|
|
731
|
-
|
|
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 (
|
|
739
|
-
|
|
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
|
-
|
|
744
|
-
console.log(chalk_1.default.
|
|
745
|
-
console.log(chalk_1.default.gray('
|
|
746
|
-
console.log(chalk_1.default.gray('
|
|
747
|
-
console.log(chalk_1.default.gray('
|
|
748
|
-
console.log(chalk_1.default.
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
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
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
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 (
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
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
|
|
857
|
+
console.log(chalk_1.default.gray('\n Run `codebakers heal --auto` later to fix issues.\n'));
|
|
793
858
|
}
|
|
794
859
|
}
|
|
795
|
-
//
|
|
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
|
|
805
|
-
console.log(chalk_1.default.cyan(' .cursorrules
|
|
806
|
-
if (prdCreated) {
|
|
807
|
-
console.log(chalk_1.default.cyan(' PRD.md
|
|
808
|
-
}
|
|
809
|
-
console.log(chalk_1.default.cyan(' PROJECT-CONTEXT.md
|
|
810
|
-
console.log(chalk_1.default.cyan(' PROJECT-STATE.md
|
|
811
|
-
console.log(chalk_1.default.cyan(' DECISIONS.md
|
|
812
|
-
console.log(chalk_1.default.cyan(' .
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
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
|
}
|