@codebakers/cli 3.9.32 → 3.9.33

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.
@@ -0,0 +1,10 @@
1
+ interface CoherenceOptions {
2
+ focus?: string;
3
+ fix?: boolean;
4
+ verbose?: boolean;
5
+ }
6
+ /**
7
+ * CLI coherence command - checks wiring and dependencies
8
+ */
9
+ export declare function coherence(options?: CoherenceOptions): Promise<void>;
10
+ export {};
@@ -0,0 +1,396 @@
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.coherence = coherence;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
11
+ /**
12
+ * CLI coherence command - checks wiring and dependencies
13
+ */
14
+ async function coherence(options = {}) {
15
+ const { focus = 'all', fix = false, verbose = false } = options;
16
+ const cwd = process.cwd();
17
+ console.log(chalk_1.default.blue(`
18
+ ╔═══════════════════════════════════════════════════════════╗
19
+ ║ ║
20
+ ║ ${chalk_1.default.bold.white('🔗 CodeBakers Coherence Audit')} ║
21
+ ║ ║
22
+ ╚═══════════════════════════════════════════════════════════╝
23
+ `));
24
+ const spinner = (0, ora_1.default)('Scanning codebase for coherence issues...').start();
25
+ const issues = [];
26
+ const stats = {
27
+ filesScanned: 0,
28
+ importsChecked: 0,
29
+ exportsFound: 0,
30
+ envVarsFound: 0,
31
+ };
32
+ // Helper to extract imports from a file
33
+ const extractImports = (content) => {
34
+ const imports = [];
35
+ const lines = content.split('\n');
36
+ lines.forEach((line, i) => {
37
+ // Match: import { X, Y } from 'path'
38
+ const namedMatch = line.match(/import\s+(type\s+)?{([^}]+)}\s+from\s+['"]([^'"]+)['"]/);
39
+ if (namedMatch) {
40
+ const names = namedMatch[2].split(',').map(n => n.trim().split(' as ')[0].trim()).filter(Boolean);
41
+ imports.push({ path: namedMatch[3], names, line: i + 1 });
42
+ }
43
+ // Match: import X from 'path'
44
+ const defaultMatch = line.match(/import\s+(type\s+)?(\w+)\s+from\s+['"]([^'"]+)['"]/);
45
+ if (defaultMatch && !namedMatch) {
46
+ imports.push({ path: defaultMatch[3], names: ['default'], line: i + 1 });
47
+ }
48
+ });
49
+ return imports;
50
+ };
51
+ // Helper to extract exports from a file
52
+ const extractExports = (content) => {
53
+ const exports = [];
54
+ // Named exports: export { X, Y }
55
+ const namedExportMatches = content.matchAll(/export\s+{([^}]+)}/g);
56
+ for (const match of namedExportMatches) {
57
+ const names = match[1].split(',').map(n => n.trim().split(' as ').pop()?.trim() || '').filter(Boolean);
58
+ exports.push(...names);
59
+ }
60
+ // Direct exports: export const/function/class/type/interface X
61
+ const directExportMatches = content.matchAll(/export\s+(const|let|var|function|class|type|interface|enum)\s+(\w+)/g);
62
+ for (const match of directExportMatches) {
63
+ exports.push(match[2]);
64
+ }
65
+ // Default export
66
+ if (content.includes('export default')) {
67
+ exports.push('default');
68
+ }
69
+ return exports;
70
+ };
71
+ // Helper to resolve import path to file
72
+ const resolveImportPath = (importPath, fromFile) => {
73
+ if (!importPath.startsWith('.') && !importPath.startsWith('@/') && !importPath.startsWith('~/')) {
74
+ return null;
75
+ }
76
+ let resolvedPath = importPath;
77
+ if (importPath.startsWith('@/')) {
78
+ resolvedPath = (0, path_1.join)(cwd, 'src', importPath.slice(2));
79
+ }
80
+ else if (importPath.startsWith('~/')) {
81
+ resolvedPath = (0, path_1.join)(cwd, importPath.slice(2));
82
+ }
83
+ else {
84
+ resolvedPath = (0, path_1.resolve)((0, path_1.dirname)(fromFile), importPath);
85
+ }
86
+ const extensions = ['', '.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.tsx', '/index.js'];
87
+ for (const ext of extensions) {
88
+ const fullPath = resolvedPath + ext;
89
+ if ((0, fs_1.existsSync)(fullPath) && (0, fs_1.statSync)(fullPath).isFile()) {
90
+ return fullPath;
91
+ }
92
+ }
93
+ return null;
94
+ };
95
+ const searchDirs = ['src', 'app', 'lib', 'components', 'services', 'types', 'utils', 'hooks', 'pages'];
96
+ const fileExtensions = ['.ts', '.tsx', '.js', '.jsx'];
97
+ // Build export map
98
+ const exportMap = new Map();
99
+ const importGraph = new Map();
100
+ const usedExports = new Set();
101
+ // First pass: collect all exports
102
+ const collectExports = (dir) => {
103
+ if (!(0, fs_1.existsSync)(dir))
104
+ return;
105
+ const entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
106
+ for (const entry of entries) {
107
+ const fullPath = (0, path_1.join)(dir, entry.name);
108
+ if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
109
+ collectExports(fullPath);
110
+ }
111
+ else if (entry.isFile() && fileExtensions.some(ext => entry.name.endsWith(ext))) {
112
+ try {
113
+ const content = (0, fs_1.readFileSync)(fullPath, 'utf-8');
114
+ const exports = extractExports(content);
115
+ exportMap.set(fullPath, exports);
116
+ stats.exportsFound += exports.length;
117
+ stats.filesScanned++;
118
+ }
119
+ catch {
120
+ // Skip unreadable files
121
+ }
122
+ }
123
+ }
124
+ };
125
+ spinner.text = 'Collecting exports...';
126
+ for (const dir of searchDirs) {
127
+ collectExports((0, path_1.join)(cwd, dir));
128
+ }
129
+ // Second pass: check imports
130
+ const checkImports = (dir) => {
131
+ if (!(0, fs_1.existsSync)(dir))
132
+ return;
133
+ const entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
134
+ for (const entry of entries) {
135
+ const fullPath = (0, path_1.join)(dir, entry.name);
136
+ if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
137
+ checkImports(fullPath);
138
+ }
139
+ else if (entry.isFile() && fileExtensions.some(ext => entry.name.endsWith(ext))) {
140
+ try {
141
+ const content = (0, fs_1.readFileSync)(fullPath, 'utf-8');
142
+ const imports = extractImports(content);
143
+ const relativePath = (0, path_1.relative)(cwd, fullPath);
144
+ const importedFiles = [];
145
+ for (const imp of imports) {
146
+ stats.importsChecked++;
147
+ const resolvedPath = resolveImportPath(imp.path, fullPath);
148
+ if (resolvedPath === null)
149
+ continue;
150
+ importedFiles.push(resolvedPath);
151
+ if (!(0, fs_1.existsSync)(resolvedPath)) {
152
+ if (focus === 'all' || focus === 'imports') {
153
+ issues.push({
154
+ category: 'import',
155
+ severity: 'error',
156
+ file: relativePath,
157
+ line: imp.line,
158
+ message: `Import target not found: '${imp.path}'`,
159
+ fix: `Create the file or update the import path`,
160
+ autoFixable: false,
161
+ });
162
+ }
163
+ continue;
164
+ }
165
+ const targetExports = exportMap.get(resolvedPath) || [];
166
+ for (const name of imp.names) {
167
+ if (name === '*' || name === 'default') {
168
+ if (name === 'default' && !targetExports.includes('default')) {
169
+ if (focus === 'all' || focus === 'imports') {
170
+ issues.push({
171
+ category: 'import',
172
+ severity: 'error',
173
+ file: relativePath,
174
+ line: imp.line,
175
+ message: `No default export in '${imp.path}'`,
176
+ fix: `Add 'export default' or change to named import`,
177
+ autoFixable: false,
178
+ });
179
+ }
180
+ }
181
+ continue;
182
+ }
183
+ usedExports.add(`${resolvedPath}:${name}`);
184
+ if (!targetExports.includes(name)) {
185
+ if (focus === 'all' || focus === 'imports') {
186
+ issues.push({
187
+ category: 'export',
188
+ severity: 'error',
189
+ file: relativePath,
190
+ line: imp.line,
191
+ message: `'${name}' is not exported from '${imp.path}'`,
192
+ fix: `Add 'export { ${name} }' to ${(0, path_1.basename)(resolvedPath)} or update import`,
193
+ autoFixable: false,
194
+ });
195
+ }
196
+ }
197
+ }
198
+ }
199
+ importGraph.set(fullPath, importedFiles);
200
+ }
201
+ catch {
202
+ // Skip unreadable files
203
+ }
204
+ }
205
+ }
206
+ };
207
+ spinner.text = 'Checking imports...';
208
+ for (const dir of searchDirs) {
209
+ checkImports((0, path_1.join)(cwd, dir));
210
+ }
211
+ // Check for circular dependencies
212
+ if (focus === 'all' || focus === 'circular') {
213
+ spinner.text = 'Detecting circular dependencies...';
214
+ const visited = new Set();
215
+ const recursionStack = new Set();
216
+ const circularPaths = [];
217
+ const detectCircular = (file, pathStack) => {
218
+ if (recursionStack.has(file)) {
219
+ const cycleStart = pathStack.indexOf(file);
220
+ if (cycleStart !== -1) {
221
+ circularPaths.push(pathStack.slice(cycleStart).concat(file));
222
+ }
223
+ return;
224
+ }
225
+ if (visited.has(file))
226
+ return;
227
+ visited.add(file);
228
+ recursionStack.add(file);
229
+ const imports = importGraph.get(file) || [];
230
+ for (const imported of imports) {
231
+ detectCircular(imported, [...pathStack, file]);
232
+ }
233
+ recursionStack.delete(file);
234
+ };
235
+ for (const file of importGraph.keys()) {
236
+ detectCircular(file, []);
237
+ }
238
+ const seenCycles = new Set();
239
+ for (const cycle of circularPaths) {
240
+ const cycleKey = cycle.map(f => (0, path_1.relative)(cwd, f)).sort().join(' -> ');
241
+ if (!seenCycles.has(cycleKey)) {
242
+ seenCycles.add(cycleKey);
243
+ issues.push({
244
+ category: 'circular',
245
+ severity: 'warning',
246
+ file: (0, path_1.relative)(cwd, cycle[0]),
247
+ message: `Circular dependency: ${cycle.map(f => (0, path_1.basename)(f)).join(' → ')}`,
248
+ fix: 'Break the cycle by extracting shared code to a separate module',
249
+ autoFixable: false,
250
+ });
251
+ }
252
+ }
253
+ }
254
+ // Check environment variables
255
+ if (focus === 'all' || focus === 'env') {
256
+ spinner.text = 'Checking environment variables...';
257
+ const envVarsUsed = new Set();
258
+ const envVarsDefined = new Set();
259
+ const scanEnvUsage = (dir) => {
260
+ if (!(0, fs_1.existsSync)(dir))
261
+ return;
262
+ const entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
263
+ for (const entry of entries) {
264
+ const fullPath = (0, path_1.join)(dir, entry.name);
265
+ if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
266
+ scanEnvUsage(fullPath);
267
+ }
268
+ else if (entry.isFile() && fileExtensions.some(ext => entry.name.endsWith(ext))) {
269
+ try {
270
+ const content = (0, fs_1.readFileSync)(fullPath, 'utf-8');
271
+ const envMatches = content.matchAll(/process\.env\.(\w+)|process\.env\[['"](\w+)['"]\]/g);
272
+ for (const match of envMatches) {
273
+ const varName = match[1] || match[2];
274
+ envVarsUsed.add(varName);
275
+ stats.envVarsFound++;
276
+ }
277
+ }
278
+ catch {
279
+ // Skip
280
+ }
281
+ }
282
+ }
283
+ };
284
+ for (const dir of searchDirs) {
285
+ scanEnvUsage((0, path_1.join)(cwd, dir));
286
+ }
287
+ const envFiles = ['.env', '.env.local', '.env.example', '.env.development'];
288
+ for (const envFile of envFiles) {
289
+ const envPath = (0, path_1.join)(cwd, envFile);
290
+ if ((0, fs_1.existsSync)(envPath)) {
291
+ try {
292
+ const content = (0, fs_1.readFileSync)(envPath, 'utf-8');
293
+ const lines = content.split('\n');
294
+ for (const line of lines) {
295
+ const match = line.match(/^([A-Z][A-Z0-9_]*)=/);
296
+ if (match) {
297
+ envVarsDefined.add(match[1]);
298
+ }
299
+ }
300
+ }
301
+ catch {
302
+ // Skip
303
+ }
304
+ }
305
+ }
306
+ for (const varName of envVarsUsed) {
307
+ if (varName.startsWith('NEXT_') || varName === 'NODE_ENV')
308
+ continue;
309
+ if (!envVarsDefined.has(varName)) {
310
+ issues.push({
311
+ category: 'env',
312
+ severity: 'warning',
313
+ file: '.env.example',
314
+ message: `Environment variable '${varName}' is used but not defined in .env files`,
315
+ fix: `Add ${varName}= to .env.example`,
316
+ autoFixable: true,
317
+ });
318
+ }
319
+ }
320
+ }
321
+ spinner.succeed('Coherence audit complete!');
322
+ // Display results
323
+ console.log('');
324
+ console.log(chalk_1.default.white(' 📊 Summary'));
325
+ console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
326
+ console.log(` Files scanned: ${chalk_1.default.cyan(stats.filesScanned)}`);
327
+ console.log(` Imports checked: ${chalk_1.default.cyan(stats.importsChecked)}`);
328
+ console.log(` Exports found: ${chalk_1.default.cyan(stats.exportsFound)}`);
329
+ const errors = issues.filter(i => i.severity === 'error');
330
+ const warnings = issues.filter(i => i.severity === 'warning');
331
+ const infos = issues.filter(i => i.severity === 'info');
332
+ console.log('');
333
+ console.log(` ${chalk_1.default.red('🔴 Errors:')} ${errors.length}`);
334
+ console.log(` ${chalk_1.default.yellow('🟡 Warnings:')} ${warnings.length}`);
335
+ console.log(` ${chalk_1.default.blue('🔵 Info:')} ${infos.length}`);
336
+ console.log('');
337
+ if (issues.length === 0) {
338
+ console.log(chalk_1.default.green(' ✅ No coherence issues found! Your codebase wiring is solid.\n'));
339
+ return;
340
+ }
341
+ // Group issues by category
342
+ const categories = {
343
+ import: [],
344
+ export: [],
345
+ circular: [],
346
+ env: [],
347
+ 'dead-code': [],
348
+ };
349
+ for (const issue of issues) {
350
+ if (categories[issue.category]) {
351
+ categories[issue.category].push(issue);
352
+ }
353
+ }
354
+ const categoryLabels = {
355
+ import: '🔴 Broken Imports',
356
+ export: '🔴 Missing Exports',
357
+ circular: '⚪ Circular Dependencies',
358
+ env: '🟡 Environment Variables',
359
+ 'dead-code': '🔵 Dead Code',
360
+ };
361
+ for (const [category, catIssues] of Object.entries(categories)) {
362
+ if (catIssues.length === 0)
363
+ continue;
364
+ console.log(chalk_1.default.white(` ${categoryLabels[category]} (${catIssues.length})`));
365
+ console.log(chalk_1.default.gray(' ─────────────────────────────────────'));
366
+ const displayIssues = verbose ? catIssues : catIssues.slice(0, 5);
367
+ for (const issue of displayIssues) {
368
+ const severityColor = issue.severity === 'error' ? chalk_1.default.red : issue.severity === 'warning' ? chalk_1.default.yellow : chalk_1.default.blue;
369
+ console.log(` ${severityColor('•')} ${chalk_1.default.gray(issue.file)}${issue.line ? chalk_1.default.gray(`:${issue.line}`) : ''}`);
370
+ console.log(` ${issue.message}`);
371
+ if (issue.fix) {
372
+ console.log(chalk_1.default.gray(` Fix: ${issue.fix}`));
373
+ }
374
+ }
375
+ if (!verbose && catIssues.length > 5) {
376
+ console.log(chalk_1.default.gray(` ... and ${catIssues.length - 5} more (use --verbose to see all)`));
377
+ }
378
+ console.log('');
379
+ }
380
+ // Save state
381
+ const statePath = (0, path_1.join)(cwd, '.codebakers', 'coherence-state.json');
382
+ try {
383
+ (0, fs_1.mkdirSync)((0, path_1.dirname)(statePath), { recursive: true });
384
+ (0, fs_1.writeFileSync)(statePath, JSON.stringify({
385
+ lastAudit: new Date().toISOString(),
386
+ stats,
387
+ issues,
388
+ summary: { errors: errors.length, warnings: warnings.length, info: infos.length },
389
+ }, null, 2));
390
+ }
391
+ catch {
392
+ // Ignore write errors
393
+ }
394
+ console.log(chalk_1.default.gray(' Run ') + chalk_1.default.cyan('npx tsc --noEmit') + chalk_1.default.gray(' to verify TypeScript compiles'));
395
+ console.log(chalk_1.default.gray(' Run ') + chalk_1.default.cyan('codebakers heal') + chalk_1.default.gray(' to auto-fix what\'s possible\n'));
396
+ }
@@ -1356,21 +1356,31 @@ async function showVSCodeClaudeInstructions() {
1356
1356
  console.log(chalk_1.default.gray(' Look for the ') + chalk_1.default.cyan('Claude icon') + chalk_1.default.gray(' in the left sidebar'));
1357
1357
  console.log(chalk_1.default.gray(' Click it to open the Claude Code chat panel\n'));
1358
1358
  console.log(chalk_1.default.gray(' Or press ') + chalk_1.default.cyan('Cmd+Shift+P') + chalk_1.default.gray(' → type ') + chalk_1.default.cyan('"Claude Code: Open Chat"') + chalk_1.default.gray('\n'));
1359
- console.log(chalk_1.default.yellow(' STEP 3: Start building!\n'));
1360
- console.log(chalk_1.default.gray(' Type your request in the Claude chat. For example:\n'));
1361
- console.log(chalk_1.default.white(' "Build me a todo app with authentication"'));
1362
- console.log(chalk_1.default.white(' "Add a login page to my project"'));
1363
- console.log(chalk_1.default.white(' "Review my code and make it production-ready"\n'));
1359
+ console.log(chalk_1.default.yellow(' STEP 3: Type the magic phrase!\n'));
1360
+ console.log(chalk_1.default.gray(' In the chat, type:\n'));
1361
+ console.log(chalk_1.default.cyan.bold(' codebakers go\n'));
1362
+ console.log(chalk_1.default.gray(' This magic phrase unlocks the full CodeBakers feature set:'));
1363
+ console.log(chalk_1.default.gray(' Guided onboarding conversation'));
1364
+ console.log(chalk_1.default.gray(' • Production-ready code patterns'));
1365
+ console.log(chalk_1.default.gray(' • Automatic testing & validation\n'));
1364
1366
  console.log(chalk_1.default.green(' ✅ You are now done with the terminal!\n'));
1365
- console.log(chalk_1.default.gray(' From now on, use the ') + chalk_1.default.cyan('Claude Code Chat') + chalk_1.default.gray(' panel to talk to AI.'));
1366
- console.log(chalk_1.default.gray(' The terminal is only needed for running commands like npm.\n'));
1367
+ console.log(chalk_1.default.gray(' Just type ') + chalk_1.default.cyan('codebakers go') + chalk_1.default.gray(' in chat to get started.'));
1368
+ console.log(chalk_1.default.gray(' The AI will guide you from there.\n'));
1367
1369
  console.log(chalk_1.default.gray(' ─────────────────────────────────────────────────────────\n'));
1368
1370
  console.log(chalk_1.default.gray(' Tip: ') + chalk_1.default.white('Make sure you have the Claude Code extension installed.'));
1369
1371
  console.log(chalk_1.default.gray(' Get it from: ') + chalk_1.default.cyan('https://marketplace.visualstudio.com/items?itemName=anthropics.claude-code\n'));
1370
1372
  console.log(chalk_1.default.gray(' Having issues? Run: ') + chalk_1.default.cyan('codebakers doctor') + chalk_1.default.gray(' to diagnose\n'));
1371
1373
  }
1372
- // v6.15 Bootstrap - SHORT template with rules at START and END for attention
1373
- const V6_CLAUDE_MD = `# CodeBakers v6.15
1374
+ // v6.17 Bootstrap - SHORT template with magic phrase + rules at START and END
1375
+ const V6_CLAUDE_MD = `# CodeBakers v6.17
1376
+
1377
+ ## 🪄 MAGIC PHRASE: "codebakers go"
1378
+ When user says "codebakers go" in chat, start the onboarding conversation:
1379
+ 1. Ask: "Is this an existing project or are you starting fresh?" (1=existing, 2=new)
1380
+ 2. If existing: "Great! What would you like to work on?"
1381
+ 3. If new: "What do you want to build? Describe your project."
1382
+ 4. Then call \`init_project()\` to set up CodeBakers files
1383
+ 5. Continue helping them build
1374
1384
 
1375
1385
  ## 🚨 ALWAYS DO THIS (Critical - Read First)
1376
1386
  1. ALWAYS call \`project_status()\` FIRST → If works show "🍪 CodeBakers is working..." / If fails show "⚠️ Not connected"
@@ -1389,10 +1399,13 @@ const V6_CLAUDE_MD = `# CodeBakers v6.15
1389
1399
  project_status() → Verify connection FIRST
1390
1400
  discover_patterns({ task: "what you're building" }) → Get patterns BEFORE code
1391
1401
  validate_complete({ feature: "name", files: [...] }) → Validate BEFORE done
1402
+ coherence_audit() → Check wiring & dependencies
1392
1403
  \`\`\`
1393
1404
 
1405
+ Commands: /build, /feature, /design, /status, /audit, /coherence, /upgrade
1406
+
1394
1407
  Header (after project_status succeeds): 🍪 CodeBakers is working on this...
1395
- Header (if project_status fails): ⚠️ CodeBakers not connected - run: codebakers go
1408
+ Header (if project_status fails): ⚠️ CodeBakers not connected
1396
1409
  Footer (after code): 🍪 **CodeBakers** | Patterns: X | TSC: ✅ | Tests: ✅
1397
1410
 
1398
1411
  ## 🚨 ALWAYS DO THIS (Critical - Repeated at End)
@@ -1401,7 +1414,10 @@ Footer (after code): 🍪 **CodeBakers** | Patterns: X | TSC: ✅ | Tests: ✅
1401
1414
  3. Call \`validate_complete()\` before done
1402
1415
  4. Show footer after code responses
1403
1416
  `;
1404
- const V6_CURSORRULES = `# CodeBakers v6.15
1417
+ const V6_CURSORRULES = `# CodeBakers v6.17
1418
+
1419
+ ## 🪄 "codebakers go" = Start onboarding conversation
1420
+ Ask existing/new → Ask what to build → Call init_project() → Help them build
1405
1421
 
1406
1422
  ## 🚨 ALWAYS (Read First)
1407
1423
  1. Call project_status() FIRST → 🍪 Working... or ⚠️ Not connected
@@ -1415,6 +1431,9 @@ const V6_CURSORRULES = `# CodeBakers v6.15
1415
1431
  3. Show header without project_status succeeding
1416
1432
  4. Skip writing tests for new features
1417
1433
 
1434
+ Commands: /build, /feature, /design, /status, /audit, /coherence, /upgrade
1435
+ Use coherence_audit() to check wiring & dependencies
1436
+
1418
1437
  ## 🚨 ALWAYS (Repeated at End)
1419
1438
  1. project_status() FIRST
1420
1439
  2. discover_patterns() before code
@@ -1422,7 +1441,7 @@ const V6_CURSORRULES = `# CodeBakers v6.15
1422
1441
  `;
1423
1442
  /**
1424
1443
  * Complete project setup - handles everything:
1425
- * - Detect new vs existing project
1444
+ * - Ask user if existing or new project
1426
1445
  * - Set up all tracking files
1427
1446
  * - Configure Cursor and Claude Code MCP
1428
1447
  * - Run guided questions for new projects
@@ -1430,10 +1449,33 @@ const V6_CURSORRULES = `# CodeBakers v6.15
1430
1449
  */
1431
1450
  async function setupProject(options = {}, auth) {
1432
1451
  const cwd = process.cwd();
1433
- // Detect if this is an existing project
1452
+ // Auto-detect non-interactive mode (e.g., running from Claude Code)
1453
+ const isNonInteractive = !process.stdin.isTTY;
1454
+ // Detect if this looks like an existing project
1434
1455
  const projectInfo = detectExistingProject(cwd);
1435
- if (projectInfo.exists) {
1436
- // Existing project detected
1456
+ let isExistingProject;
1457
+ if (isNonInteractive) {
1458
+ // Non-interactive: use auto-detection
1459
+ isExistingProject = projectInfo.exists;
1460
+ }
1461
+ else {
1462
+ // Interactive: ASK the user
1463
+ console.log(chalk_1.default.cyan('\n ━━━ CodeBakers Setup ━━━\n'));
1464
+ if (projectInfo.exists) {
1465
+ // We detected existing code, but still ask
1466
+ console.log(chalk_1.default.gray(` Detected: ${projectInfo.files} files, ${projectInfo.stack.framework || 'unknown framework'}\n`));
1467
+ }
1468
+ console.log(chalk_1.default.white(' Is this an existing project or are you starting fresh?\n'));
1469
+ console.log(chalk_1.default.gray(' 1. ') + chalk_1.default.cyan('EXISTING PROJECT') + chalk_1.default.gray(' - I already have code here'));
1470
+ console.log(chalk_1.default.gray(' 2. ') + chalk_1.default.cyan('NEW PROJECT') + chalk_1.default.gray(' - Starting from scratch\n'));
1471
+ let projectChoice = '';
1472
+ while (!['1', '2'].includes(projectChoice)) {
1473
+ projectChoice = await prompt(' Enter 1 or 2: ');
1474
+ }
1475
+ isExistingProject = projectChoice === '1';
1476
+ }
1477
+ if (isExistingProject) {
1478
+ // Existing project
1437
1479
  await setupExistingProject(cwd, projectInfo, options, auth);
1438
1480
  }
1439
1481
  else {
@@ -1442,14 +1484,19 @@ async function setupProject(options = {}, auth) {
1442
1484
  }
1443
1485
  }
1444
1486
  async function setupNewProject(cwd, options = {}, auth) {
1445
- console.log(chalk_1.default.cyan('\n ━━━ New Project Setup ━━━\n'));
1446
1487
  // Auto-detect non-interactive mode (e.g., running from Claude Code)
1447
1488
  const isNonInteractive = !process.stdin.isTTY;
1448
- if (isNonInteractive && !options.type) {
1449
- console.log(chalk_1.default.yellow(' Non-interactive mode detected - using defaults\n'));
1450
- options.type = 'personal';
1451
- options.describe = options.describe || 'chat';
1452
- options.skipReview = true;
1489
+ if (isNonInteractive) {
1490
+ console.log(chalk_1.default.cyan('\n ━━━ New Project Setup ━━━\n'));
1491
+ if (!options.type) {
1492
+ console.log(chalk_1.default.yellow(' ⚡ Non-interactive mode detected - using defaults\n'));
1493
+ options.type = 'personal';
1494
+ options.describe = options.describe || 'chat';
1495
+ options.skipReview = true;
1496
+ }
1497
+ }
1498
+ else {
1499
+ console.log(chalk_1.default.green('\n ✓ Setting up as NEW PROJECT\n'));
1453
1500
  }
1454
1501
  let projectType;
1455
1502
  let projectName;
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ const generate_js_1 = require("./commands/generate.js");
22
22
  const upgrade_js_1 = require("./commands/upgrade.js");
23
23
  const config_js_1 = require("./commands/config.js");
24
24
  const audit_js_1 = require("./commands/audit.js");
25
+ const coherence_js_1 = require("./commands/coherence.js");
25
26
  const heal_js_1 = require("./commands/heal.js");
26
27
  const push_patterns_js_1 = require("./commands/push-patterns.js");
27
28
  const go_js_1 = require("./commands/go.js");
@@ -198,11 +199,12 @@ function showWelcome() {
198
199
  console.log(chalk_1.default.gray(' Generate a React component with TypeScript\n'));
199
200
  console.log(chalk_1.default.white(' Quality:\n'));
200
201
  console.log(chalk_1.default.cyan(' codebakers audit') + chalk_1.default.gray(' Run automated code quality checks'));
202
+ console.log(chalk_1.default.cyan(' codebakers coherence') + chalk_1.default.gray(' Check wiring, imports, and dependencies'));
201
203
  console.log(chalk_1.default.cyan(' codebakers heal') + chalk_1.default.gray(' Auto-detect and fix common issues'));
202
204
  console.log(chalk_1.default.cyan(' codebakers doctor') + chalk_1.default.gray(' Check CodeBakers setup\n'));
203
205
  console.log(chalk_1.default.white(' All Commands:\n'));
204
206
  console.log(chalk_1.default.gray(' go, extend, billing, build, build-status, setup, scaffold, init'));
205
- console.log(chalk_1.default.gray(' generate, upgrade, status, audit, heal, doctor, config, login'));
207
+ console.log(chalk_1.default.gray(' generate, upgrade, status, audit, coherence, heal, doctor, config, login'));
206
208
  console.log(chalk_1.default.gray(' serve, mcp-config, mcp-uninstall\n'));
207
209
  console.log(chalk_1.default.gray(' Run ') + chalk_1.default.cyan('codebakers <command> --help') + chalk_1.default.gray(' for more info\n'));
208
210
  }
@@ -316,6 +318,20 @@ program
316
318
  .command('audit')
317
319
  .description('Run automated code quality and security checks')
318
320
  .action(async () => { await (0, audit_js_1.audit)(); });
321
+ program
322
+ .command('coherence')
323
+ .alias('wiring')
324
+ .description('Check codebase wiring, imports, exports, and dependencies')
325
+ .option('-f, --focus <area>', 'Focus area: all, imports, circular, env (default: all)')
326
+ .option('--fix', 'Automatically fix issues that can be auto-fixed')
327
+ .option('-v, --verbose', 'Show all issues (not just first 5 per category)')
328
+ .action(async (options) => {
329
+ await (0, coherence_js_1.coherence)({
330
+ focus: options.focus,
331
+ fix: options.fix,
332
+ verbose: options.verbose,
333
+ });
334
+ });
319
335
  program
320
336
  .command('heal')
321
337
  .description('Auto-detect and fix common issues (TypeScript, deps, security)')