@codebakers/cli 3.5.0 → 3.6.0

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.
@@ -1062,13 +1062,13 @@ class CodeBakersServer {
1062
1062
  },
1063
1063
  {
1064
1064
  name: 'update_patterns',
1065
- description: 'Download and update CodeBakers pattern files from the server. Use when user says "upgrade codebakers", "update patterns", "download latest patterns", "sync codebakers", or when patterns are missing or outdated. This tool fetches the latest CLAUDE.md router and all .claude/ module files from the server and writes them to disk.',
1065
+ description: 'Update to CodeBakers v6.0 server-enforced patterns. Use when user says "upgrade codebakers", "update patterns", or "sync codebakers". In v6.0, patterns are server-side - this tool installs minimal bootstrap files (CLAUDE.md and .cursorrules) and removes old .claude/ folder if present.',
1066
1066
  inputSchema: {
1067
1067
  type: 'object',
1068
1068
  properties: {
1069
1069
  force: {
1070
1070
  type: 'boolean',
1071
- description: 'Force update even if already at latest version (default: false)',
1071
+ description: 'Force reinstall even if already on v6.0 (default: false)',
1072
1072
  },
1073
1073
  },
1074
1074
  },
@@ -2372,35 +2372,66 @@ Or if user declines, call without fullDeploy:
2372
2372
  catch {
2373
2373
  // Use default
2374
2374
  }
2375
- results.push(`# 🎨 Adding CodeBakers to: ${projectName}\n`);
2376
- // Check if already initialized
2377
- if (fs.existsSync(path.join(cwd, 'CLAUDE.md'))) {
2378
- results.push('⚠️ CLAUDE.md already exists. Updating patterns...\n');
2375
+ results.push(`# 🎨 Adding CodeBakers v6.0 to: ${projectName}\n`);
2376
+ // v6.0 bootstrap content - minimal files, patterns from server
2377
+ const V6_CLAUDE_MD = `# CodeBakers v6.0
2378
+
2379
+ **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
2380
+
2381
+ \`\`\`
2382
+ Tool: discover_patterns
2383
+ Args: { task: "description of what you're building" }
2384
+ \`\`\`
2385
+
2386
+ The server will return:
2387
+ - All coding patterns and rules you must follow
2388
+ - Test requirements
2389
+ - Validation instructions
2390
+
2391
+ **You cannot write code without calling this tool first. The server tracks compliance.**
2392
+
2393
+ ---
2394
+ *CodeBakers v6.0 - Server-Enforced*
2395
+ `;
2396
+ const V6_CURSORRULES = `# CodeBakers v6.0
2397
+
2398
+ MANDATORY: Before writing ANY code, call the discover_patterns MCP tool.
2399
+
2400
+ Tool: discover_patterns
2401
+ Args: { task: "description of what you're building" }
2402
+
2403
+ The server returns all patterns, rules, and test requirements.
2404
+ You cannot write code without calling this tool first.
2405
+ `;
2406
+ // Check if already v6
2407
+ const claudeMdPath = path.join(cwd, 'CLAUDE.md');
2408
+ if (fs.existsSync(claudeMdPath)) {
2409
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
2410
+ if (content.includes('v6.0') && content.includes('discover_patterns')) {
2411
+ results.push('✓ CodeBakers v6.0 already installed\n');
2412
+ results.push('Patterns are server-enforced. Just call `discover_patterns` before coding!');
2413
+ return {
2414
+ content: [{ type: 'text', text: results.join('\n') }],
2415
+ };
2416
+ }
2417
+ results.push('⚠️ Upgrading to v6.0 (server-enforced patterns)...\n');
2379
2418
  }
2380
2419
  try {
2381
- const response = await fetch(`${this.apiUrl}/api/content`, {
2382
- method: 'GET',
2383
- headers: this.getAuthHeaders(),
2384
- });
2385
- if (!response.ok) {
2386
- throw new Error('Failed to fetch patterns from API');
2387
- }
2388
- const content = await response.json();
2389
- // Write CLAUDE.md
2390
- if (content.router) {
2391
- fs.writeFileSync(path.join(cwd, 'CLAUDE.md'), content.router);
2392
- results.push('✓ Created/Updated CLAUDE.md');
2393
- }
2394
- // Write pattern modules
2395
- if (content.modules && Object.keys(content.modules).length > 0) {
2396
- const modulesDir = path.join(cwd, '.claude');
2397
- if (!fs.existsSync(modulesDir)) {
2398
- fs.mkdirSync(modulesDir, { recursive: true });
2420
+ // Write v6.0 bootstrap files
2421
+ fs.writeFileSync(claudeMdPath, V6_CLAUDE_MD);
2422
+ results.push('✓ Created CLAUDE.md (v6.0 bootstrap)');
2423
+ fs.writeFileSync(path.join(cwd, '.cursorrules'), V6_CURSORRULES);
2424
+ results.push('✓ Created .cursorrules (v6.0 bootstrap)');
2425
+ // Remove old .claude folder if it exists (v5 → v6 migration)
2426
+ const claudeDir = path.join(cwd, '.claude');
2427
+ if (fs.existsSync(claudeDir)) {
2428
+ try {
2429
+ fs.rmSync(claudeDir, { recursive: true, force: true });
2430
+ results.push('✓ Removed .claude/ folder (patterns now server-side)');
2399
2431
  }
2400
- for (const [name, data] of Object.entries(content.modules)) {
2401
- fs.writeFileSync(path.join(modulesDir, name), data);
2432
+ catch {
2433
+ results.push('⚠️ Could not remove .claude/ folder - please delete manually');
2402
2434
  }
2403
- results.push(`✓ Installed ${Object.keys(content.modules).length} pattern modules (v${content.version})`);
2404
2435
  }
2405
2436
  // Create PRD if doesn't exist
2406
2437
  const date = new Date().toISOString().split('T')[0];
@@ -2419,39 +2450,29 @@ Or if user declines, call without fullDeploy:
2419
2450
  `);
2420
2451
  results.push('✓ Created PRD.md template');
2421
2452
  }
2422
- // Create PROJECT-STATE if doesn't exist
2423
- const statePath = path.join(cwd, 'PROJECT-STATE.md');
2424
- if (!fs.existsSync(statePath)) {
2425
- fs.writeFileSync(statePath, `# PROJECT STATE
2426
- # Last Updated: ${date}
2427
-
2428
- ## Project Info
2429
- name: ${projectName}
2430
- phase: development
2431
-
2432
- ## In Progress
2433
- ## Completed
2434
- ## Next Up
2435
- `);
2436
- results.push('✓ Created PROJECT-STATE.md');
2437
- }
2438
- // Update .gitignore
2439
- const gitignorePath = path.join(cwd, '.gitignore');
2440
- if (fs.existsSync(gitignorePath)) {
2441
- const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
2442
- if (!gitignore.includes('.claude/')) {
2443
- fs.writeFileSync(gitignorePath, gitignore + '\n# CodeBakers\n.claude/\n');
2444
- results.push('✓ Updated .gitignore');
2453
+ // Update .codebakers.json
2454
+ const stateFile = path.join(cwd, '.codebakers.json');
2455
+ let state = {};
2456
+ if (fs.existsSync(stateFile)) {
2457
+ try {
2458
+ state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
2459
+ }
2460
+ catch {
2461
+ // Ignore errors
2445
2462
  }
2446
2463
  }
2464
+ state.version = '6.0';
2465
+ state.serverEnforced = true;
2466
+ state.updatedAt = new Date().toISOString();
2467
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2));
2447
2468
  results.push('\n---\n');
2448
- results.push('## ✅ CodeBakers Patterns Installed!\n');
2449
- results.push('The AI now has access to production patterns for:');
2450
- results.push('- Authentication, Database, API design');
2451
- results.push('- Frontend components, Forms, Validation');
2452
- results.push('- Payments, Email, Real-time features');
2453
- results.push('- And 30+ more specialized patterns\n');
2454
- results.push('Just describe what you want to build!');
2469
+ results.push('## ✅ CodeBakers v6.0 Installed!\n');
2470
+ results.push('**How it works now:**');
2471
+ results.push('1. Call `discover_patterns` before writing code');
2472
+ results.push('2. Server returns all patterns and rules');
2473
+ results.push('3. Call `validate_complete` before marking done');
2474
+ results.push('4. Server verifies compliance\n');
2475
+ results.push('No local pattern files needed - everything is server-side!');
2455
2476
  }
2456
2477
  catch (error) {
2457
2478
  const message = error instanceof Error ? error.message : 'Unknown error';
@@ -3395,6 +3416,8 @@ Just describe what you want to build! I'll automatically:
3395
3416
  let testsPass = false;
3396
3417
  let typescriptPass = false;
3397
3418
  const testsWritten = [];
3419
+ // v6.1: Code analysis for compliance scoring
3420
+ const codeAnalysis = {};
3398
3421
  // Step 1: Get session token (from memory or state file)
3399
3422
  let sessionToken = this.currentSessionToken;
3400
3423
  if (!sessionToken) {
@@ -3443,6 +3466,74 @@ Just describe what you want to build! I'll automatically:
3443
3466
  catch {
3444
3467
  // Ignore errors
3445
3468
  }
3469
+ // Step 2.5: v6.1 - Analyze code for compliance scoring
3470
+ try {
3471
+ let totalLines = 0;
3472
+ let hasErrorHandling = false;
3473
+ let hasLoadingStates = false;
3474
+ let hasConsoleLog = false;
3475
+ let hasAnyType = false;
3476
+ // Analyze provided files
3477
+ const filesToAnalyze = files.length > 0 ? files : [];
3478
+ // Also scan for recently modified .ts/.tsx files if no files provided
3479
+ if (filesToAnalyze.length === 0) {
3480
+ const srcDir = path.join(cwd, 'src');
3481
+ if (fs.existsSync(srcDir)) {
3482
+ const recentFiles = fs.readdirSync(srcDir, { recursive: true })
3483
+ .filter((f) => {
3484
+ const name = String(f);
3485
+ return (name.endsWith('.ts') || name.endsWith('.tsx')) &&
3486
+ !name.includes('.test.') && !name.includes('.spec.');
3487
+ })
3488
+ .slice(0, 20) // Limit to 20 files for performance
3489
+ .map(f => path.join('src', String(f)));
3490
+ filesToAnalyze.push(...recentFiles);
3491
+ }
3492
+ }
3493
+ for (const file of filesToAnalyze) {
3494
+ try {
3495
+ const filePath = path.isAbsolute(file) ? file : path.join(cwd, file);
3496
+ if (!fs.existsSync(filePath))
3497
+ continue;
3498
+ const content = fs.readFileSync(filePath, 'utf-8');
3499
+ const lines = content.split('\n').length;
3500
+ totalLines += lines;
3501
+ // Check for error handling patterns
3502
+ if (content.includes('try {') || content.includes('catch (') ||
3503
+ content.includes('.catch(') || content.includes('onError') ||
3504
+ content.includes('error:') || content.includes('handleError')) {
3505
+ hasErrorHandling = true;
3506
+ }
3507
+ // Check for loading states
3508
+ if (content.includes('isLoading') || content.includes('loading:') ||
3509
+ content.includes('isPending') || content.includes('Skeleton') ||
3510
+ content.includes('Spinner') || content.includes('Loading')) {
3511
+ hasLoadingStates = true;
3512
+ }
3513
+ // Check for console.log (bad in production)
3514
+ if (content.includes('console.log') || content.includes('console.warn') ||
3515
+ content.includes('console.error')) {
3516
+ hasConsoleLog = true;
3517
+ }
3518
+ // Check for any type (should be avoided)
3519
+ if (content.includes(': any') || content.includes(':any') ||
3520
+ content.includes('as any') || content.includes('<any>')) {
3521
+ hasAnyType = true;
3522
+ }
3523
+ }
3524
+ catch {
3525
+ // Skip files that can't be read
3526
+ }
3527
+ }
3528
+ codeAnalysis.linesOfCode = totalLines;
3529
+ codeAnalysis.hasErrorHandling = hasErrorHandling;
3530
+ codeAnalysis.hasLoadingStates = hasLoadingStates;
3531
+ codeAnalysis.hasConsoleLog = hasConsoleLog;
3532
+ codeAnalysis.hasAnyType = hasAnyType;
3533
+ }
3534
+ catch {
3535
+ // Ignore code analysis errors
3536
+ }
3446
3537
  // Step 3: Run tests locally
3447
3538
  if (testsExist) {
3448
3539
  try {
@@ -3501,6 +3592,7 @@ Just describe what you want to build! I'll automatically:
3501
3592
  testsRun: testsExist,
3502
3593
  testsPassed: testsPass,
3503
3594
  typescriptPassed: typescriptPass,
3595
+ codeAnalysis, // v6.1: Send code analysis for compliance scoring
3504
3596
  }),
3505
3597
  });
3506
3598
  const result = await response.json();
@@ -3537,6 +3629,52 @@ Just describe what you want to build! I'll automatically:
3537
3629
  let responseText = `# ✅ Feature Validation: ${feature}\n\n`;
3538
3630
  responseText += `## Server Validation Result\n\n`;
3539
3631
  responseText += `**Status:** ${result.passed ? '✅ PASSED' : '❌ FAILED'}\n\n`;
3632
+ // v6.1: Show compliance score
3633
+ if (result.compliance) {
3634
+ const score = result.compliance.score || 0;
3635
+ const scoreEmoji = score >= 90 ? '🏆' : score >= 70 ? '👍' : score >= 50 ? '⚠️' : '❌';
3636
+ responseText += `## ${scoreEmoji} Compliance Score: ${score}/100\n\n`;
3637
+ if (result.compliance.patternScores) {
3638
+ responseText += `### Pattern Scores:\n`;
3639
+ responseText += `| Pattern | Score |\n|---------|-------|\n`;
3640
+ for (const [pattern, patternScore] of Object.entries(result.compliance.patternScores)) {
3641
+ const emoji = patternScore >= 80 ? '✅' : patternScore >= 50 ? '⚠️' : '❌';
3642
+ responseText += `| ${pattern} | ${emoji} ${patternScore}/100 |\n`;
3643
+ }
3644
+ responseText += `\n`;
3645
+ }
3646
+ if (result.compliance.deductions && result.compliance.deductions.length > 0) {
3647
+ responseText += `### Deductions:\n`;
3648
+ for (const deduction of result.compliance.deductions) {
3649
+ responseText += `- ❌ **${deduction.rule}**: ${deduction.issue} (-${deduction.points} pts)\n`;
3650
+ }
3651
+ responseText += `\n`;
3652
+ }
3653
+ }
3654
+ // v6.1: Show test quality metrics
3655
+ if (result.testQuality) {
3656
+ const tq = result.testQuality;
3657
+ responseText += `## 🧪 Test Quality Score: ${tq.overallScore}/100\n\n`;
3658
+ responseText += `| Metric | Status |\n|--------|--------|\n`;
3659
+ responseText += `| Coverage | ${tq.coverage || 0}% |\n`;
3660
+ responseText += `| Happy Path Tests | ${tq.hasHappyPath ? '✅' : '❌'} |\n`;
3661
+ responseText += `| Error Case Tests | ${tq.hasErrorCases ? '✅' : '❌'} |\n`;
3662
+ responseText += `| Boundary Cases | ${tq.hasBoundaryCases ? '✅' : '❌'} |\n\n`;
3663
+ if (tq.missingTests && tq.missingTests.length > 0) {
3664
+ responseText += `### Missing Tests:\n`;
3665
+ for (const missing of tq.missingTests) {
3666
+ responseText += `- ⚠️ ${missing}\n`;
3667
+ }
3668
+ responseText += `\n`;
3669
+ }
3670
+ if (tq.recommendations && tq.recommendations.length > 0) {
3671
+ responseText += `### Recommendations:\n`;
3672
+ for (const rec of tq.recommendations) {
3673
+ responseText += `- 💡 ${rec}\n`;
3674
+ }
3675
+ responseText += `\n`;
3676
+ }
3677
+ }
3540
3678
  if (result.issues && result.issues.length > 0) {
3541
3679
  responseText += `### Issues:\n\n`;
3542
3680
  for (const issue of result.issues) {
@@ -3551,7 +3689,10 @@ Just describe what you want to build! I'll automatically:
3551
3689
  responseText += `| TypeScript compiles | ${typescriptPass ? '✅ PASS' : '❌ FAIL'} |\n\n`;
3552
3690
  if (result.passed) {
3553
3691
  responseText += `## ✅ Feature is COMPLETE\n\n`;
3554
- responseText += `Server has recorded this completion. You may now mark this feature as done.\n`;
3692
+ const completionMsg = result.compliance && result.compliance.score >= 90
3693
+ ? 'Excellent work! High compliance score achieved.'
3694
+ : 'Server has recorded this completion. You may now mark this feature as done.';
3695
+ responseText += `${completionMsg}\n`;
3555
3696
  }
3556
3697
  else {
3557
3698
  responseText += `## ❌ Feature is NOT COMPLETE\n\n`;
@@ -3619,11 +3760,92 @@ Just describe what you want to build! I'll automatically:
3619
3760
  // Generate project hash for context
3620
3761
  let projectHash;
3621
3762
  let projectName;
3763
+ let detectedStack = {};
3622
3764
  try {
3623
3765
  const pkgPath = path.join(cwd, 'package.json');
3624
3766
  if (fs.existsSync(pkgPath)) {
3625
3767
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
3626
3768
  projectName = pkg.name || path.basename(cwd);
3769
+ // v6.1: Extract detected stack from dependencies for conflict detection
3770
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
3771
+ const depNames = Object.keys(allDeps);
3772
+ // Detect framework
3773
+ if (depNames.includes('next'))
3774
+ detectedStack.framework = 'nextjs';
3775
+ else if (depNames.includes('remix'))
3776
+ detectedStack.framework = 'remix';
3777
+ else if (depNames.includes('gatsby'))
3778
+ detectedStack.framework = 'gatsby';
3779
+ else if (depNames.includes('react'))
3780
+ detectedStack.framework = 'react';
3781
+ else if (depNames.includes('vue'))
3782
+ detectedStack.framework = 'vue';
3783
+ // Detect ORM/database
3784
+ const orms = [];
3785
+ if (depNames.includes('drizzle-orm'))
3786
+ orms.push('drizzle');
3787
+ if (depNames.includes('prisma') || depNames.includes('@prisma/client'))
3788
+ orms.push('prisma');
3789
+ if (depNames.includes('typeorm'))
3790
+ orms.push('typeorm');
3791
+ if (depNames.includes('mongoose'))
3792
+ orms.push('mongoose');
3793
+ if (depNames.includes('sequelize'))
3794
+ orms.push('sequelize');
3795
+ if (orms.length > 0)
3796
+ detectedStack.orm = orms.length === 1 ? orms[0] : orms;
3797
+ // Detect state management
3798
+ const stateLibs = [];
3799
+ if (depNames.includes('@reduxjs/toolkit') || depNames.includes('redux'))
3800
+ stateLibs.push('redux');
3801
+ if (depNames.includes('zustand'))
3802
+ stateLibs.push('zustand');
3803
+ if (depNames.includes('jotai'))
3804
+ stateLibs.push('jotai');
3805
+ if (depNames.includes('recoil'))
3806
+ stateLibs.push('recoil');
3807
+ if (depNames.includes('mobx'))
3808
+ stateLibs.push('mobx');
3809
+ if (stateLibs.length > 0)
3810
+ detectedStack.stateManagement = stateLibs.length === 1 ? stateLibs[0] : stateLibs;
3811
+ // Detect styling
3812
+ const styleLibs = [];
3813
+ if (depNames.includes('tailwindcss'))
3814
+ styleLibs.push('tailwind');
3815
+ if (depNames.includes('@emotion/react') || depNames.includes('@emotion/styled'))
3816
+ styleLibs.push('emotion');
3817
+ if (depNames.includes('styled-components'))
3818
+ styleLibs.push('styled-components');
3819
+ if (depNames.includes('@mui/material'))
3820
+ styleLibs.push('mui');
3821
+ if (depNames.includes('@chakra-ui/react'))
3822
+ styleLibs.push('chakra');
3823
+ if (styleLibs.length > 0)
3824
+ detectedStack.styling = styleLibs.length === 1 ? styleLibs[0] : styleLibs;
3825
+ // Detect form libraries
3826
+ const formLibs = [];
3827
+ if (depNames.includes('react-hook-form'))
3828
+ formLibs.push('react-hook-form');
3829
+ if (depNames.includes('formik'))
3830
+ formLibs.push('formik');
3831
+ if (depNames.includes('react-final-form'))
3832
+ formLibs.push('react-final-form');
3833
+ if (formLibs.length > 0)
3834
+ detectedStack.forms = formLibs.length === 1 ? formLibs[0] : formLibs;
3835
+ // Detect auth
3836
+ if (depNames.includes('@supabase/supabase-js'))
3837
+ detectedStack.auth = 'supabase';
3838
+ else if (depNames.includes('next-auth') || depNames.includes('@auth/core'))
3839
+ detectedStack.auth = 'next-auth';
3840
+ else if (depNames.includes('@clerk/nextjs'))
3841
+ detectedStack.auth = 'clerk';
3842
+ else if (depNames.includes('firebase'))
3843
+ detectedStack.auth = 'firebase';
3844
+ // Detect payments
3845
+ if (depNames.includes('stripe'))
3846
+ detectedStack.payments = 'stripe';
3847
+ else if (depNames.includes('@paypal/react-paypal-js'))
3848
+ detectedStack.payments = 'paypal';
3627
3849
  }
3628
3850
  else {
3629
3851
  projectName = path.basename(cwd);
@@ -3648,6 +3870,7 @@ Just describe what you want to build! I'll automatically:
3648
3870
  keywords,
3649
3871
  projectHash,
3650
3872
  projectName,
3873
+ detectedStack, // v6.1: Send stack for conflict detection
3651
3874
  }),
3652
3875
  });
3653
3876
  if (!response.ok) {
@@ -3680,6 +3903,63 @@ Just describe what you want to build! I'll automatically:
3680
3903
  let responseText = `# 🔍 Pattern Discovery: ${task}\n\n`;
3681
3904
  responseText += `## ⛔ SERVER-ENFORCED SESSION ACTIVE\n\n`;
3682
3905
  responseText += `**Session Token:** \`${result.sessionToken}\`\n\n`;
3906
+ // v6.1: Show detected conflicts (high priority warning)
3907
+ if (result.detectedConflicts && result.detectedConflicts.length > 0) {
3908
+ responseText += `---\n\n`;
3909
+ responseText += `## ⚠️ ARCHITECTURE CONFLICTS DETECTED\n\n`;
3910
+ responseText += `The following conflicts were found in your project:\n\n`;
3911
+ for (const conflict of result.detectedConflicts) {
3912
+ responseText += `### ${conflict.type}\n`;
3913
+ responseText += `**Conflicting:** ${conflict.items.join(' + ')}\n`;
3914
+ responseText += `**Recommendation:** ${conflict.recommendation}\n`;
3915
+ responseText += `**Reason:** ${conflict.reason}\n\n`;
3916
+ }
3917
+ responseText += `**Please resolve these conflicts before proceeding.**\n\n`;
3918
+ }
3919
+ // v6.1: Show team profile settings if configured
3920
+ if (result.teamProfile) {
3921
+ responseText += `---\n\n`;
3922
+ responseText += `## 🏢 TEAM PROFILE\n\n`;
3923
+ responseText += `| Setting | Value |\n|---------|-------|\n`;
3924
+ responseText += `| Industry | ${result.teamProfile.industryProfile || 'general'} |\n`;
3925
+ responseText += `| Strictness | ${result.teamProfile.strictnessLevel || 'standard'} |\n`;
3926
+ if (result.teamProfile.requireHipaa)
3927
+ responseText += `| HIPAA | ✅ Required |\n`;
3928
+ if (result.teamProfile.requirePci)
3929
+ responseText += `| PCI-DSS | ✅ Required |\n`;
3930
+ if (result.teamProfile.requireSoc2)
3931
+ responseText += `| SOC2 | ✅ Required |\n`;
3932
+ if (result.teamProfile.requireGdpr)
3933
+ responseText += `| GDPR | ✅ Required |\n`;
3934
+ responseText += `\n`;
3935
+ }
3936
+ // v6.1: Show project memory if available
3937
+ if (result.projectMemory) {
3938
+ responseText += `---\n\n`;
3939
+ responseText += `## 🧠 PROJECT MEMORY\n\n`;
3940
+ responseText += `Server has remembered your project's architectural decisions:\n\n`;
3941
+ const memory = result.projectMemory;
3942
+ if (memory.stackDecisions) {
3943
+ const stack = typeof memory.stackDecisions === 'string'
3944
+ ? JSON.parse(memory.stackDecisions)
3945
+ : memory.stackDecisions;
3946
+ if (Object.keys(stack).length > 0) {
3947
+ responseText += `### Stack Decisions\n`;
3948
+ responseText += `| Category | Choice |\n|----------|--------|\n`;
3949
+ for (const [key, value] of Object.entries(stack)) {
3950
+ responseText += `| ${key} | ${value} |\n`;
3951
+ }
3952
+ responseText += `\n`;
3953
+ }
3954
+ }
3955
+ if (memory.namingConventions) {
3956
+ responseText += `### Naming Conventions\n\`\`\`\n${memory.namingConventions}\n\`\`\`\n\n`;
3957
+ }
3958
+ if (memory.projectRules) {
3959
+ responseText += `### Project Rules\n${memory.projectRules}\n\n`;
3960
+ }
3961
+ responseText += `**Follow these established patterns for consistency.**\n\n`;
3962
+ }
3683
3963
  responseText += `---\n\n`;
3684
3964
  // Section 1: Patterns from server
3685
3965
  if (result.patterns && result.patterns.length > 0) {
@@ -5517,7 +5797,7 @@ ${handlers.join('\n')}
5517
5797
  `;
5518
5798
  }
5519
5799
  /**
5520
- * Download and update CodeBakers patterns from server
5800
+ * Update to CodeBakers v6.0 - server-enforced patterns
5521
5801
  * This is the MCP equivalent of the `codebakers upgrade` CLI command
5522
5802
  */
5523
5803
  async handleUpdatePatterns(args) {
@@ -5525,54 +5805,63 @@ ${handlers.join('\n')}
5525
5805
  const cwd = process.cwd();
5526
5806
  const claudeMdPath = path.join(cwd, 'CLAUDE.md');
5527
5807
  const claudeDir = path.join(cwd, '.claude');
5528
- const versionPath = path.join(claudeDir, '.version.json');
5529
- let response = `# 🔄 CodeBakers Pattern Update\n\n`;
5808
+ const codebakersJson = path.join(cwd, '.codebakers.json');
5809
+ let response = `# 🔄 CodeBakers v6.0 Update\n\n`;
5810
+ // v6.0 bootstrap content
5811
+ const V6_CLAUDE_MD = `# CodeBakers v6.0
5812
+
5813
+ **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
5814
+
5815
+ \`\`\`
5816
+ Tool: discover_patterns
5817
+ Args: { task: "description of what you're building" }
5818
+ \`\`\`
5819
+
5820
+ The server will return:
5821
+ - All coding patterns and rules you must follow
5822
+ - Test requirements
5823
+ - Validation instructions
5824
+
5825
+ **You cannot write code without calling this tool first. The server tracks compliance.**
5826
+
5827
+ ---
5828
+ *CodeBakers v6.0 - Server-Enforced*
5829
+ `;
5830
+ const V6_CURSORRULES = `# CodeBakers v6.0
5831
+
5832
+ MANDATORY: Before writing ANY code, call the discover_patterns MCP tool.
5833
+
5834
+ Tool: discover_patterns
5835
+ Args: { task: "description of what you're building" }
5836
+
5837
+ The server returns all patterns, rules, and test requirements.
5838
+ You cannot write code without calling this tool first.
5839
+ `;
5530
5840
  try {
5531
5841
  // Check current version
5532
5842
  let currentVersion = null;
5533
- let currentModuleCount = 0;
5534
- if (fs.existsSync(versionPath)) {
5535
- try {
5536
- const versionInfo = JSON.parse(fs.readFileSync(versionPath, 'utf-8'));
5537
- currentVersion = versionInfo.version;
5538
- currentModuleCount = versionInfo.moduleCount || 0;
5539
- }
5540
- catch {
5541
- // Ignore parse errors
5542
- }
5843
+ let isV6 = false;
5844
+ if (fs.existsSync(claudeMdPath)) {
5845
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
5846
+ isV6 = content.includes('v6.0') && content.includes('discover_patterns');
5543
5847
  }
5544
- // Count current modules
5545
- if (fs.existsSync(claudeDir)) {
5848
+ if (fs.existsSync(codebakersJson)) {
5546
5849
  try {
5547
- const files = fs.readdirSync(claudeDir).filter(f => f.endsWith('.md'));
5548
- currentModuleCount = files.length;
5850
+ const state = JSON.parse(fs.readFileSync(codebakersJson, 'utf-8'));
5851
+ currentVersion = state.version || null;
5549
5852
  }
5550
5853
  catch {
5551
- // Ignore read errors
5854
+ // Ignore parse errors
5552
5855
  }
5553
5856
  }
5554
5857
  response += `## Current Status\n`;
5555
5858
  response += `- Version: ${currentVersion || 'Unknown'}\n`;
5556
- response += `- Modules: ${currentModuleCount}\n\n`;
5557
- // Fetch latest version info first
5558
- const versionResponse = await fetch(`${this.apiUrl}/api/content/version`, {
5559
- headers: this.getAuthHeaders(),
5560
- });
5561
- if (!versionResponse.ok) {
5562
- throw new Error('Failed to check version from server');
5563
- }
5564
- const latestInfo = await versionResponse.json();
5565
- const latestVersion = latestInfo.version;
5566
- const latestModuleCount = latestInfo.moduleCount || 0;
5567
- response += `## Server Status\n`;
5568
- response += `- Latest Version: ${latestVersion}\n`;
5569
- response += `- Available Modules: ${latestModuleCount}\n\n`;
5570
- // Check if update needed
5571
- const needsUpdate = force || !currentVersion || currentVersion !== latestVersion || currentModuleCount < latestModuleCount;
5572
- if (!needsUpdate) {
5573
- response += `✅ **Already up to date!**\n\n`;
5574
- response += `Your patterns are current (v${latestVersion} with ${latestModuleCount} modules).\n`;
5575
- response += `Use \`force: true\` to re-download anyway.\n`;
5859
+ response += `- v6.0 (Server-Enforced): ${isV6 ? 'Yes ✓' : 'No'}\n\n`;
5860
+ // Check if already on v6
5861
+ if (isV6 && !force) {
5862
+ response += `✅ **Already on v6.0!**\n\n`;
5863
+ response += `Your patterns are server-enforced. Just use \`discover_patterns\` before coding.\n`;
5864
+ response += `Use \`force: true\` to reinstall bootstrap files.\n`;
5576
5865
  response += this.getUpdateNotice();
5577
5866
  return {
5578
5867
  content: [{
@@ -5581,65 +5870,54 @@ ${handlers.join('\n')}
5581
5870
  }],
5582
5871
  };
5583
5872
  }
5584
- response += `## Downloading Updates...\n\n`;
5585
- // Fetch full content
5586
- const contentResponse = await fetch(`${this.apiUrl}/api/content`, {
5587
- headers: this.getAuthHeaders(),
5588
- });
5589
- if (!contentResponse.ok) {
5590
- const error = await contentResponse.json().catch(() => ({}));
5591
- throw new Error(error.error || error.message || 'Failed to fetch patterns');
5592
- }
5593
- const content = await contentResponse.json();
5594
- const moduleCount = content.modules ? Object.keys(content.modules).length : 0;
5595
- // Create .claude directory if needed
5596
- if (!fs.existsSync(claudeDir)) {
5597
- fs.mkdirSync(claudeDir, { recursive: true });
5598
- response += `✓ Created .claude/ directory\n`;
5599
- }
5600
- // Update CLAUDE.md router
5601
- if (content.router) {
5602
- fs.writeFileSync(claudeMdPath, content.router);
5603
- response += `✓ Updated CLAUDE.md (router)\n`;
5873
+ response += `## Upgrading to v6.0...\n\n`;
5874
+ // Write v6.0 bootstrap files
5875
+ fs.writeFileSync(claudeMdPath, V6_CLAUDE_MD);
5876
+ response += `✓ Updated CLAUDE.md (v6.0 bootstrap)\n`;
5877
+ fs.writeFileSync(path.join(cwd, '.cursorrules'), V6_CURSORRULES);
5878
+ response += `✓ Updated .cursorrules (v6.0 bootstrap)\n`;
5879
+ // Remove old .claude folder (v5 v6 migration)
5880
+ if (fs.existsSync(claudeDir)) {
5881
+ try {
5882
+ fs.rmSync(claudeDir, { recursive: true, force: true });
5883
+ response += `✓ Removed .claude/ folder (patterns now server-side)\n`;
5884
+ }
5885
+ catch {
5886
+ response += `⚠️ Could not remove .claude/ folder - please delete manually\n`;
5887
+ }
5604
5888
  }
5605
- // Update all modules
5606
- if (content.modules && moduleCount > 0) {
5607
- for (const [name, data] of Object.entries(content.modules)) {
5608
- fs.writeFileSync(path.join(claudeDir, name), data);
5889
+ // Update .codebakers.json
5890
+ let state = {};
5891
+ if (fs.existsSync(codebakersJson)) {
5892
+ try {
5893
+ state = JSON.parse(fs.readFileSync(codebakersJson, 'utf-8'));
5894
+ }
5895
+ catch {
5896
+ // Ignore errors
5609
5897
  }
5610
- response += `✓ Updated ${moduleCount} modules in .claude/\n`;
5611
5898
  }
5612
- // Save version info
5613
- const newVersionInfo = {
5614
- version: content.version || latestVersion,
5615
- moduleCount,
5616
- installedAt: currentVersion ? undefined : new Date().toISOString(),
5617
- updatedAt: new Date().toISOString(),
5618
- cliVersion: (0, api_js_1.getCliVersion)(),
5619
- };
5620
- fs.writeFileSync(versionPath, JSON.stringify(newVersionInfo, null, 2));
5621
- response += `✓ Saved version info\n`;
5622
- // Confirm download to server (non-blocking analytics)
5623
- this.confirmDownload(content.version || latestVersion, moduleCount).catch(() => { });
5624
- response += `\n## Update Complete!\n\n`;
5625
- response += `- **From:** v${currentVersion || 'none'} (${currentModuleCount} modules)\n`;
5626
- response += `- **To:** v${content.version || latestVersion} (${moduleCount} modules)\n\n`;
5627
- if (moduleCount > currentModuleCount) {
5628
- response += `🆕 **${moduleCount - currentModuleCount} new modules added!**\n\n`;
5629
- }
5630
- response += `Your patterns are now up to date. The new patterns will be used in your next response.\n`;
5899
+ state.version = '6.0';
5900
+ state.serverEnforced = true;
5901
+ state.updatedAt = new Date().toISOString();
5902
+ fs.writeFileSync(codebakersJson, JSON.stringify(state, null, 2));
5903
+ response += `✓ Updated .codebakers.json\n`;
5904
+ // Confirm to server (non-blocking analytics)
5905
+ this.confirmDownload('6.0', 0).catch(() => { });
5906
+ response += `\n## ✅ Upgrade Complete!\n\n`;
5907
+ response += `**What changed in v6.0:**\n`;
5908
+ response += `- No local pattern files (.claude/ folder removed)\n`;
5909
+ response += `- All patterns fetched from server in real-time\n`;
5910
+ response += `- Server tracks compliance via discover_patterns/validate_complete\n\n`;
5911
+ response += `**How to use:**\n`;
5912
+ response += `1. Call \`discover_patterns\` before writing any code\n`;
5913
+ response += `2. Follow the patterns returned by server\n`;
5914
+ response += `3. Call \`validate_complete\` before marking done\n`;
5631
5915
  }
5632
5916
  catch (error) {
5633
5917
  const message = error instanceof Error ? error.message : 'Unknown error';
5634
5918
  response += `\n## ❌ Update Failed\n\n`;
5635
5919
  response += `Error: ${message}\n\n`;
5636
- if (message.includes('401') || message.includes('Invalid') || message.includes('expired')) {
5637
- response += `Your API key may be invalid or expired.\n`;
5638
- response += `Run \`codebakers setup\` in terminal to reconfigure.\n`;
5639
- }
5640
- else {
5641
- response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
5642
- }
5920
+ response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
5643
5921
  }
5644
5922
  // Add CLI update notice if available
5645
5923
  response += this.getUpdateNotice();