@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.
package/src/mcp/server.ts CHANGED
@@ -1158,13 +1158,13 @@ class CodeBakersServer {
1158
1158
  {
1159
1159
  name: 'update_patterns',
1160
1160
  description:
1161
- '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.',
1161
+ '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.',
1162
1162
  inputSchema: {
1163
1163
  type: 'object' as const,
1164
1164
  properties: {
1165
1165
  force: {
1166
1166
  type: 'boolean',
1167
- description: 'Force update even if already at latest version (default: false)',
1167
+ description: 'Force reinstall even if already on v6.0 (default: false)',
1168
1168
  },
1169
1169
  },
1170
1170
  },
@@ -2705,41 +2705,71 @@ Or if user declines, call without fullDeploy:
2705
2705
  // Use default
2706
2706
  }
2707
2707
 
2708
- results.push(`# 🎨 Adding CodeBakers to: ${projectName}\n`);
2708
+ results.push(`# 🎨 Adding CodeBakers v6.0 to: ${projectName}\n`);
2709
2709
 
2710
- // Check if already initialized
2711
- if (fs.existsSync(path.join(cwd, 'CLAUDE.md'))) {
2712
- results.push('⚠️ CLAUDE.md already exists. Updating patterns...\n');
2713
- }
2710
+ // v6.0 bootstrap content - minimal files, patterns from server
2711
+ const V6_CLAUDE_MD = `# CodeBakers v6.0
2714
2712
 
2715
- try {
2716
- const response = await fetch(`${this.apiUrl}/api/content`, {
2717
- method: 'GET',
2718
- headers: this.getAuthHeaders(),
2719
- });
2713
+ **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
2720
2714
 
2721
- if (!response.ok) {
2722
- throw new Error('Failed to fetch patterns from API');
2723
- }
2715
+ \`\`\`
2716
+ Tool: discover_patterns
2717
+ Args: { task: "description of what you're building" }
2718
+ \`\`\`
2719
+
2720
+ The server will return:
2721
+ - All coding patterns and rules you must follow
2722
+ - Test requirements
2723
+ - Validation instructions
2724
2724
 
2725
- const content = await response.json();
2725
+ **You cannot write code without calling this tool first. The server tracks compliance.**
2726
2726
 
2727
- // Write CLAUDE.md
2728
- if (content.router) {
2729
- fs.writeFileSync(path.join(cwd, 'CLAUDE.md'), content.router);
2730
- results.push('✓ Created/Updated CLAUDE.md');
2727
+ ---
2728
+ *CodeBakers v6.0 - Server-Enforced*
2729
+ `;
2730
+
2731
+ const V6_CURSORRULES = `# CodeBakers v6.0
2732
+
2733
+ MANDATORY: Before writing ANY code, call the discover_patterns MCP tool.
2734
+
2735
+ Tool: discover_patterns
2736
+ Args: { task: "description of what you're building" }
2737
+
2738
+ The server returns all patterns, rules, and test requirements.
2739
+ You cannot write code without calling this tool first.
2740
+ `;
2741
+
2742
+ // Check if already v6
2743
+ const claudeMdPath = path.join(cwd, 'CLAUDE.md');
2744
+ if (fs.existsSync(claudeMdPath)) {
2745
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
2746
+ if (content.includes('v6.0') && content.includes('discover_patterns')) {
2747
+ results.push('✓ CodeBakers v6.0 already installed\n');
2748
+ results.push('Patterns are server-enforced. Just call `discover_patterns` before coding!');
2749
+ return {
2750
+ content: [{ type: 'text' as const, text: results.join('\n') }],
2751
+ };
2731
2752
  }
2753
+ results.push('⚠️ Upgrading to v6.0 (server-enforced patterns)...\n');
2754
+ }
2732
2755
 
2733
- // Write pattern modules
2734
- if (content.modules && Object.keys(content.modules).length > 0) {
2735
- const modulesDir = path.join(cwd, '.claude');
2736
- if (!fs.existsSync(modulesDir)) {
2737
- fs.mkdirSync(modulesDir, { recursive: true });
2738
- }
2739
- for (const [name, data] of Object.entries(content.modules)) {
2740
- fs.writeFileSync(path.join(modulesDir, name), data as string);
2756
+ try {
2757
+ // Write v6.0 bootstrap files
2758
+ fs.writeFileSync(claudeMdPath, V6_CLAUDE_MD);
2759
+ results.push('✓ Created CLAUDE.md (v6.0 bootstrap)');
2760
+
2761
+ fs.writeFileSync(path.join(cwd, '.cursorrules'), V6_CURSORRULES);
2762
+ results.push('✓ Created .cursorrules (v6.0 bootstrap)');
2763
+
2764
+ // Remove old .claude folder if it exists (v5 → v6 migration)
2765
+ const claudeDir = path.join(cwd, '.claude');
2766
+ if (fs.existsSync(claudeDir)) {
2767
+ try {
2768
+ fs.rmSync(claudeDir, { recursive: true, force: true });
2769
+ results.push('✓ Removed .claude/ folder (patterns now server-side)');
2770
+ } catch {
2771
+ results.push('⚠️ Could not remove .claude/ folder - please delete manually');
2741
2772
  }
2742
- results.push(`✓ Installed ${Object.keys(content.modules).length} pattern modules (v${content.version})`);
2743
2773
  }
2744
2774
 
2745
2775
  // Create PRD if doesn't exist
@@ -2760,41 +2790,29 @@ Or if user declines, call without fullDeploy:
2760
2790
  results.push('✓ Created PRD.md template');
2761
2791
  }
2762
2792
 
2763
- // Create PROJECT-STATE if doesn't exist
2764
- const statePath = path.join(cwd, 'PROJECT-STATE.md');
2765
- if (!fs.existsSync(statePath)) {
2766
- fs.writeFileSync(statePath, `# PROJECT STATE
2767
- # Last Updated: ${date}
2768
-
2769
- ## Project Info
2770
- name: ${projectName}
2771
- phase: development
2772
-
2773
- ## In Progress
2774
- ## Completed
2775
- ## Next Up
2776
- `);
2777
- results.push('✓ Created PROJECT-STATE.md');
2778
- }
2779
-
2780
- // Update .gitignore
2781
- const gitignorePath = path.join(cwd, '.gitignore');
2782
- if (fs.existsSync(gitignorePath)) {
2783
- const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
2784
- if (!gitignore.includes('.claude/')) {
2785
- fs.writeFileSync(gitignorePath, gitignore + '\n# CodeBakers\n.claude/\n');
2786
- results.push('✓ Updated .gitignore');
2793
+ // Update .codebakers.json
2794
+ const stateFile = path.join(cwd, '.codebakers.json');
2795
+ let state: Record<string, unknown> = {};
2796
+ if (fs.existsSync(stateFile)) {
2797
+ try {
2798
+ state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
2799
+ } catch {
2800
+ // Ignore errors
2787
2801
  }
2788
2802
  }
2803
+ state.version = '6.0';
2804
+ state.serverEnforced = true;
2805
+ state.updatedAt = new Date().toISOString();
2806
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2));
2789
2807
 
2790
2808
  results.push('\n---\n');
2791
- results.push('## ✅ CodeBakers Patterns Installed!\n');
2792
- results.push('The AI now has access to production patterns for:');
2793
- results.push('- Authentication, Database, API design');
2794
- results.push('- Frontend components, Forms, Validation');
2795
- results.push('- Payments, Email, Real-time features');
2796
- results.push('- And 30+ more specialized patterns\n');
2797
- results.push('Just describe what you want to build!');
2809
+ results.push('## ✅ CodeBakers v6.0 Installed!\n');
2810
+ results.push('**How it works now:**');
2811
+ results.push('1. Call `discover_patterns` before writing code');
2812
+ results.push('2. Server returns all patterns and rules');
2813
+ results.push('3. Call `validate_complete` before marking done');
2814
+ results.push('4. Server verifies compliance\n');
2815
+ results.push('No local pattern files needed - everything is server-side!');
2798
2816
 
2799
2817
  } catch (error) {
2800
2818
  const message = error instanceof Error ? error.message : 'Unknown error';
@@ -3835,6 +3853,16 @@ Just describe what you want to build! I'll automatically:
3835
3853
  let typescriptPass = false;
3836
3854
  const testsWritten: string[] = [];
3837
3855
 
3856
+ // v6.1: Code analysis for compliance scoring
3857
+ const codeAnalysis: {
3858
+ hasErrorHandling?: boolean;
3859
+ hasLoadingStates?: boolean;
3860
+ hasTypeAnnotations?: boolean;
3861
+ hasConsoleLog?: boolean;
3862
+ hasAnyType?: boolean;
3863
+ linesOfCode?: number;
3864
+ } = {};
3865
+
3838
3866
  // Step 1: Get session token (from memory or state file)
3839
3867
  let sessionToken = this.currentSessionToken;
3840
3868
  if (!sessionToken) {
@@ -3885,6 +3913,81 @@ Just describe what you want to build! I'll automatically:
3885
3913
  // Ignore errors
3886
3914
  }
3887
3915
 
3916
+ // Step 2.5: v6.1 - Analyze code for compliance scoring
3917
+ try {
3918
+ let totalLines = 0;
3919
+ let hasErrorHandling = false;
3920
+ let hasLoadingStates = false;
3921
+ let hasConsoleLog = false;
3922
+ let hasAnyType = false;
3923
+
3924
+ // Analyze provided files
3925
+ const filesToAnalyze = files.length > 0 ? files : [];
3926
+
3927
+ // Also scan for recently modified .ts/.tsx files if no files provided
3928
+ if (filesToAnalyze.length === 0) {
3929
+ const srcDir = path.join(cwd, 'src');
3930
+ if (fs.existsSync(srcDir)) {
3931
+ const recentFiles = fs.readdirSync(srcDir, { recursive: true })
3932
+ .filter((f: string | Buffer) => {
3933
+ const name = String(f);
3934
+ return (name.endsWith('.ts') || name.endsWith('.tsx')) &&
3935
+ !name.includes('.test.') && !name.includes('.spec.');
3936
+ })
3937
+ .slice(0, 20) // Limit to 20 files for performance
3938
+ .map(f => path.join('src', String(f)));
3939
+ filesToAnalyze.push(...recentFiles);
3940
+ }
3941
+ }
3942
+
3943
+ for (const file of filesToAnalyze) {
3944
+ try {
3945
+ const filePath = path.isAbsolute(file) ? file : path.join(cwd, file);
3946
+ if (!fs.existsSync(filePath)) continue;
3947
+
3948
+ const content = fs.readFileSync(filePath, 'utf-8');
3949
+ const lines = content.split('\n').length;
3950
+ totalLines += lines;
3951
+
3952
+ // Check for error handling patterns
3953
+ if (content.includes('try {') || content.includes('catch (') ||
3954
+ content.includes('.catch(') || content.includes('onError') ||
3955
+ content.includes('error:') || content.includes('handleError')) {
3956
+ hasErrorHandling = true;
3957
+ }
3958
+
3959
+ // Check for loading states
3960
+ if (content.includes('isLoading') || content.includes('loading:') ||
3961
+ content.includes('isPending') || content.includes('Skeleton') ||
3962
+ content.includes('Spinner') || content.includes('Loading')) {
3963
+ hasLoadingStates = true;
3964
+ }
3965
+
3966
+ // Check for console.log (bad in production)
3967
+ if (content.includes('console.log') || content.includes('console.warn') ||
3968
+ content.includes('console.error')) {
3969
+ hasConsoleLog = true;
3970
+ }
3971
+
3972
+ // Check for any type (should be avoided)
3973
+ if (content.includes(': any') || content.includes(':any') ||
3974
+ content.includes('as any') || content.includes('<any>')) {
3975
+ hasAnyType = true;
3976
+ }
3977
+ } catch {
3978
+ // Skip files that can't be read
3979
+ }
3980
+ }
3981
+
3982
+ codeAnalysis.linesOfCode = totalLines;
3983
+ codeAnalysis.hasErrorHandling = hasErrorHandling;
3984
+ codeAnalysis.hasLoadingStates = hasLoadingStates;
3985
+ codeAnalysis.hasConsoleLog = hasConsoleLog;
3986
+ codeAnalysis.hasAnyType = hasAnyType;
3987
+ } catch {
3988
+ // Ignore code analysis errors
3989
+ }
3990
+
3888
3991
  // Step 3: Run tests locally
3889
3992
  if (testsExist) {
3890
3993
  try {
@@ -3941,6 +4044,7 @@ Just describe what you want to build! I'll automatically:
3941
4044
  testsRun: testsExist,
3942
4045
  testsPassed: testsPass,
3943
4046
  typescriptPassed: typescriptPass,
4047
+ codeAnalysis, // v6.1: Send code analysis for compliance scoring
3944
4048
  }),
3945
4049
  });
3946
4050
 
@@ -3983,6 +4087,58 @@ Just describe what you want to build! I'll automatically:
3983
4087
  responseText += `## Server Validation Result\n\n`;
3984
4088
  responseText += `**Status:** ${result.passed ? '✅ PASSED' : '❌ FAILED'}\n\n`;
3985
4089
 
4090
+ // v6.1: Show compliance score
4091
+ if (result.compliance) {
4092
+ const score = result.compliance.score || 0;
4093
+ const scoreEmoji = score >= 90 ? '🏆' : score >= 70 ? '👍' : score >= 50 ? '⚠️' : '❌';
4094
+ responseText += `## ${scoreEmoji} Compliance Score: ${score}/100\n\n`;
4095
+
4096
+ if (result.compliance.patternScores) {
4097
+ responseText += `### Pattern Scores:\n`;
4098
+ responseText += `| Pattern | Score |\n|---------|-------|\n`;
4099
+ for (const [pattern, patternScore] of Object.entries(result.compliance.patternScores)) {
4100
+ const emoji = (patternScore as number) >= 80 ? '✅' : (patternScore as number) >= 50 ? '⚠️' : '❌';
4101
+ responseText += `| ${pattern} | ${emoji} ${patternScore}/100 |\n`;
4102
+ }
4103
+ responseText += `\n`;
4104
+ }
4105
+
4106
+ if (result.compliance.deductions && result.compliance.deductions.length > 0) {
4107
+ responseText += `### Deductions:\n`;
4108
+ for (const deduction of result.compliance.deductions) {
4109
+ responseText += `- ❌ **${deduction.rule}**: ${deduction.issue} (-${deduction.points} pts)\n`;
4110
+ }
4111
+ responseText += `\n`;
4112
+ }
4113
+ }
4114
+
4115
+ // v6.1: Show test quality metrics
4116
+ if (result.testQuality) {
4117
+ const tq = result.testQuality;
4118
+ responseText += `## 🧪 Test Quality Score: ${tq.overallScore}/100\n\n`;
4119
+ responseText += `| Metric | Status |\n|--------|--------|\n`;
4120
+ responseText += `| Coverage | ${tq.coverage || 0}% |\n`;
4121
+ responseText += `| Happy Path Tests | ${tq.hasHappyPath ? '✅' : '❌'} |\n`;
4122
+ responseText += `| Error Case Tests | ${tq.hasErrorCases ? '✅' : '❌'} |\n`;
4123
+ responseText += `| Boundary Cases | ${tq.hasBoundaryCases ? '✅' : '❌'} |\n\n`;
4124
+
4125
+ if (tq.missingTests && tq.missingTests.length > 0) {
4126
+ responseText += `### Missing Tests:\n`;
4127
+ for (const missing of tq.missingTests) {
4128
+ responseText += `- ⚠️ ${missing}\n`;
4129
+ }
4130
+ responseText += `\n`;
4131
+ }
4132
+
4133
+ if (tq.recommendations && tq.recommendations.length > 0) {
4134
+ responseText += `### Recommendations:\n`;
4135
+ for (const rec of tq.recommendations) {
4136
+ responseText += `- 💡 ${rec}\n`;
4137
+ }
4138
+ responseText += `\n`;
4139
+ }
4140
+ }
4141
+
3986
4142
  if (result.issues && result.issues.length > 0) {
3987
4143
  responseText += `### Issues:\n\n`;
3988
4144
  for (const issue of result.issues) {
@@ -3999,7 +4155,10 @@ Just describe what you want to build! I'll automatically:
3999
4155
 
4000
4156
  if (result.passed) {
4001
4157
  responseText += `## ✅ Feature is COMPLETE\n\n`;
4002
- responseText += `Server has recorded this completion. You may now mark this feature as done.\n`;
4158
+ const completionMsg = result.compliance && result.compliance.score >= 90
4159
+ ? 'Excellent work! High compliance score achieved.'
4160
+ : 'Server has recorded this completion. You may now mark this feature as done.';
4161
+ responseText += `${completionMsg}\n`;
4003
4162
  } else {
4004
4163
  responseText += `## ❌ Feature is NOT COMPLETE\n\n`;
4005
4164
  responseText += `**${result.nextSteps || 'Fix the issues above and try again.'}**\n`;
@@ -4070,11 +4229,68 @@ Just describe what you want to build! I'll automatically:
4070
4229
  // Generate project hash for context
4071
4230
  let projectHash: string | undefined;
4072
4231
  let projectName: string | undefined;
4232
+ let detectedStack: Record<string, string | string[]> = {};
4233
+
4073
4234
  try {
4074
4235
  const pkgPath = path.join(cwd, 'package.json');
4075
4236
  if (fs.existsSync(pkgPath)) {
4076
4237
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
4077
4238
  projectName = pkg.name || path.basename(cwd);
4239
+
4240
+ // v6.1: Extract detected stack from dependencies for conflict detection
4241
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
4242
+ const depNames = Object.keys(allDeps);
4243
+
4244
+ // Detect framework
4245
+ if (depNames.includes('next')) detectedStack.framework = 'nextjs';
4246
+ else if (depNames.includes('remix')) detectedStack.framework = 'remix';
4247
+ else if (depNames.includes('gatsby')) detectedStack.framework = 'gatsby';
4248
+ else if (depNames.includes('react')) detectedStack.framework = 'react';
4249
+ else if (depNames.includes('vue')) detectedStack.framework = 'vue';
4250
+
4251
+ // Detect ORM/database
4252
+ const orms: string[] = [];
4253
+ if (depNames.includes('drizzle-orm')) orms.push('drizzle');
4254
+ if (depNames.includes('prisma') || depNames.includes('@prisma/client')) orms.push('prisma');
4255
+ if (depNames.includes('typeorm')) orms.push('typeorm');
4256
+ if (depNames.includes('mongoose')) orms.push('mongoose');
4257
+ if (depNames.includes('sequelize')) orms.push('sequelize');
4258
+ if (orms.length > 0) detectedStack.orm = orms.length === 1 ? orms[0] : orms;
4259
+
4260
+ // Detect state management
4261
+ const stateLibs: string[] = [];
4262
+ if (depNames.includes('@reduxjs/toolkit') || depNames.includes('redux')) stateLibs.push('redux');
4263
+ if (depNames.includes('zustand')) stateLibs.push('zustand');
4264
+ if (depNames.includes('jotai')) stateLibs.push('jotai');
4265
+ if (depNames.includes('recoil')) stateLibs.push('recoil');
4266
+ if (depNames.includes('mobx')) stateLibs.push('mobx');
4267
+ if (stateLibs.length > 0) detectedStack.stateManagement = stateLibs.length === 1 ? stateLibs[0] : stateLibs;
4268
+
4269
+ // Detect styling
4270
+ const styleLibs: string[] = [];
4271
+ if (depNames.includes('tailwindcss')) styleLibs.push('tailwind');
4272
+ if (depNames.includes('@emotion/react') || depNames.includes('@emotion/styled')) styleLibs.push('emotion');
4273
+ if (depNames.includes('styled-components')) styleLibs.push('styled-components');
4274
+ if (depNames.includes('@mui/material')) styleLibs.push('mui');
4275
+ if (depNames.includes('@chakra-ui/react')) styleLibs.push('chakra');
4276
+ if (styleLibs.length > 0) detectedStack.styling = styleLibs.length === 1 ? styleLibs[0] : styleLibs;
4277
+
4278
+ // Detect form libraries
4279
+ const formLibs: string[] = [];
4280
+ if (depNames.includes('react-hook-form')) formLibs.push('react-hook-form');
4281
+ if (depNames.includes('formik')) formLibs.push('formik');
4282
+ if (depNames.includes('react-final-form')) formLibs.push('react-final-form');
4283
+ if (formLibs.length > 0) detectedStack.forms = formLibs.length === 1 ? formLibs[0] : formLibs;
4284
+
4285
+ // Detect auth
4286
+ if (depNames.includes('@supabase/supabase-js')) detectedStack.auth = 'supabase';
4287
+ else if (depNames.includes('next-auth') || depNames.includes('@auth/core')) detectedStack.auth = 'next-auth';
4288
+ else if (depNames.includes('@clerk/nextjs')) detectedStack.auth = 'clerk';
4289
+ else if (depNames.includes('firebase')) detectedStack.auth = 'firebase';
4290
+
4291
+ // Detect payments
4292
+ if (depNames.includes('stripe')) detectedStack.payments = 'stripe';
4293
+ else if (depNames.includes('@paypal/react-paypal-js')) detectedStack.payments = 'paypal';
4078
4294
  } else {
4079
4295
  projectName = path.basename(cwd);
4080
4296
  }
@@ -4098,6 +4314,7 @@ Just describe what you want to build! I'll automatically:
4098
4314
  keywords,
4099
4315
  projectHash,
4100
4316
  projectName,
4317
+ detectedStack, // v6.1: Send stack for conflict detection
4101
4318
  }),
4102
4319
  });
4103
4320
 
@@ -4134,6 +4351,67 @@ Just describe what you want to build! I'll automatically:
4134
4351
  let responseText = `# 🔍 Pattern Discovery: ${task}\n\n`;
4135
4352
  responseText += `## ⛔ SERVER-ENFORCED SESSION ACTIVE\n\n`;
4136
4353
  responseText += `**Session Token:** \`${result.sessionToken}\`\n\n`;
4354
+
4355
+ // v6.1: Show detected conflicts (high priority warning)
4356
+ if (result.detectedConflicts && result.detectedConflicts.length > 0) {
4357
+ responseText += `---\n\n`;
4358
+ responseText += `## ⚠️ ARCHITECTURE CONFLICTS DETECTED\n\n`;
4359
+ responseText += `The following conflicts were found in your project:\n\n`;
4360
+ for (const conflict of result.detectedConflicts) {
4361
+ responseText += `### ${conflict.type}\n`;
4362
+ responseText += `**Conflicting:** ${conflict.items.join(' + ')}\n`;
4363
+ responseText += `**Recommendation:** ${conflict.recommendation}\n`;
4364
+ responseText += `**Reason:** ${conflict.reason}\n\n`;
4365
+ }
4366
+ responseText += `**Please resolve these conflicts before proceeding.**\n\n`;
4367
+ }
4368
+
4369
+ // v6.1: Show team profile settings if configured
4370
+ if (result.teamProfile) {
4371
+ responseText += `---\n\n`;
4372
+ responseText += `## 🏢 TEAM PROFILE\n\n`;
4373
+ responseText += `| Setting | Value |\n|---------|-------|\n`;
4374
+ responseText += `| Industry | ${result.teamProfile.industryProfile || 'general'} |\n`;
4375
+ responseText += `| Strictness | ${result.teamProfile.strictnessLevel || 'standard'} |\n`;
4376
+ if (result.teamProfile.requireHipaa) responseText += `| HIPAA | ✅ Required |\n`;
4377
+ if (result.teamProfile.requirePci) responseText += `| PCI-DSS | ✅ Required |\n`;
4378
+ if (result.teamProfile.requireSoc2) responseText += `| SOC2 | ✅ Required |\n`;
4379
+ if (result.teamProfile.requireGdpr) responseText += `| GDPR | ✅ Required |\n`;
4380
+ responseText += `\n`;
4381
+ }
4382
+
4383
+ // v6.1: Show project memory if available
4384
+ if (result.projectMemory) {
4385
+ responseText += `---\n\n`;
4386
+ responseText += `## 🧠 PROJECT MEMORY\n\n`;
4387
+ responseText += `Server has remembered your project's architectural decisions:\n\n`;
4388
+
4389
+ const memory = result.projectMemory;
4390
+ if (memory.stackDecisions) {
4391
+ const stack = typeof memory.stackDecisions === 'string'
4392
+ ? JSON.parse(memory.stackDecisions)
4393
+ : memory.stackDecisions;
4394
+ if (Object.keys(stack).length > 0) {
4395
+ responseText += `### Stack Decisions\n`;
4396
+ responseText += `| Category | Choice |\n|----------|--------|\n`;
4397
+ for (const [key, value] of Object.entries(stack)) {
4398
+ responseText += `| ${key} | ${value} |\n`;
4399
+ }
4400
+ responseText += `\n`;
4401
+ }
4402
+ }
4403
+
4404
+ if (memory.namingConventions) {
4405
+ responseText += `### Naming Conventions\n\`\`\`\n${memory.namingConventions}\n\`\`\`\n\n`;
4406
+ }
4407
+
4408
+ if (memory.projectRules) {
4409
+ responseText += `### Project Rules\n${memory.projectRules}\n\n`;
4410
+ }
4411
+
4412
+ responseText += `**Follow these established patterns for consistency.**\n\n`;
4413
+ }
4414
+
4137
4415
  responseText += `---\n\n`;
4138
4416
 
4139
4417
  // Section 1: Patterns from server
@@ -6242,7 +6520,7 @@ ${handlers.join('\n')}
6242
6520
  }
6243
6521
 
6244
6522
  /**
6245
- * Download and update CodeBakers patterns from server
6523
+ * Update to CodeBakers v6.0 - server-enforced patterns
6246
6524
  * This is the MCP equivalent of the `codebakers upgrade` CLI command
6247
6525
  */
6248
6526
  private async handleUpdatePatterns(args: { force?: boolean }) {
@@ -6250,63 +6528,70 @@ ${handlers.join('\n')}
6250
6528
  const cwd = process.cwd();
6251
6529
  const claudeMdPath = path.join(cwd, 'CLAUDE.md');
6252
6530
  const claudeDir = path.join(cwd, '.claude');
6253
- const versionPath = path.join(claudeDir, '.version.json');
6531
+ const codebakersJson = path.join(cwd, '.codebakers.json');
6254
6532
 
6255
- let response = `# 🔄 CodeBakers Pattern Update\n\n`;
6533
+ let response = `# 🔄 CodeBakers v6.0 Update\n\n`;
6534
+
6535
+ // v6.0 bootstrap content
6536
+ const V6_CLAUDE_MD = `# CodeBakers v6.0
6537
+
6538
+ **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
6539
+
6540
+ \`\`\`
6541
+ Tool: discover_patterns
6542
+ Args: { task: "description of what you're building" }
6543
+ \`\`\`
6544
+
6545
+ The server will return:
6546
+ - All coding patterns and rules you must follow
6547
+ - Test requirements
6548
+ - Validation instructions
6549
+
6550
+ **You cannot write code without calling this tool first. The server tracks compliance.**
6551
+
6552
+ ---
6553
+ *CodeBakers v6.0 - Server-Enforced*
6554
+ `;
6555
+
6556
+ const V6_CURSORRULES = `# CodeBakers v6.0
6557
+
6558
+ MANDATORY: Before writing ANY code, call the discover_patterns MCP tool.
6559
+
6560
+ Tool: discover_patterns
6561
+ Args: { task: "description of what you're building" }
6562
+
6563
+ The server returns all patterns, rules, and test requirements.
6564
+ You cannot write code without calling this tool first.
6565
+ `;
6256
6566
 
6257
6567
  try {
6258
6568
  // Check current version
6259
6569
  let currentVersion: string | null = null;
6260
- let currentModuleCount = 0;
6570
+ let isV6 = false;
6261
6571
 
6262
- if (fs.existsSync(versionPath)) {
6263
- try {
6264
- const versionInfo = JSON.parse(fs.readFileSync(versionPath, 'utf-8'));
6265
- currentVersion = versionInfo.version;
6266
- currentModuleCount = versionInfo.moduleCount || 0;
6267
- } catch {
6268
- // Ignore parse errors
6269
- }
6572
+ if (fs.existsSync(claudeMdPath)) {
6573
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
6574
+ isV6 = content.includes('v6.0') && content.includes('discover_patterns');
6270
6575
  }
6271
6576
 
6272
- // Count current modules
6273
- if (fs.existsSync(claudeDir)) {
6577
+ if (fs.existsSync(codebakersJson)) {
6274
6578
  try {
6275
- const files = fs.readdirSync(claudeDir).filter(f => f.endsWith('.md'));
6276
- currentModuleCount = files.length;
6579
+ const state = JSON.parse(fs.readFileSync(codebakersJson, 'utf-8'));
6580
+ currentVersion = state.version || null;
6277
6581
  } catch {
6278
- // Ignore read errors
6582
+ // Ignore parse errors
6279
6583
  }
6280
6584
  }
6281
6585
 
6282
6586
  response += `## Current Status\n`;
6283
6587
  response += `- Version: ${currentVersion || 'Unknown'}\n`;
6284
- response += `- Modules: ${currentModuleCount}\n\n`;
6285
-
6286
- // Fetch latest version info first
6287
- const versionResponse = await fetch(`${this.apiUrl}/api/content/version`, {
6288
- headers: this.getAuthHeaders(),
6289
- });
6588
+ response += `- v6.0 (Server-Enforced): ${isV6 ? 'Yes ✓' : 'No'}\n\n`;
6290
6589
 
6291
- if (!versionResponse.ok) {
6292
- throw new Error('Failed to check version from server');
6293
- }
6294
-
6295
- const latestInfo = await versionResponse.json();
6296
- const latestVersion = latestInfo.version;
6297
- const latestModuleCount = latestInfo.moduleCount || 0;
6298
-
6299
- response += `## Server Status\n`;
6300
- response += `- Latest Version: ${latestVersion}\n`;
6301
- response += `- Available Modules: ${latestModuleCount}\n\n`;
6302
-
6303
- // Check if update needed
6304
- const needsUpdate = force || !currentVersion || currentVersion !== latestVersion || currentModuleCount < latestModuleCount;
6305
-
6306
- if (!needsUpdate) {
6307
- response += `✅ **Already up to date!**\n\n`;
6308
- response += `Your patterns are current (v${latestVersion} with ${latestModuleCount} modules).\n`;
6309
- response += `Use \`force: true\` to re-download anyway.\n`;
6590
+ // Check if already on v6
6591
+ if (isV6 && !force) {
6592
+ response += `✅ **Already on v6.0!**\n\n`;
6593
+ response += `Your patterns are server-enforced. Just use \`discover_patterns\` before coding.\n`;
6594
+ response += `Use \`force: true\` to reinstall bootstrap files.\n`;
6310
6595
  response += this.getUpdateNotice();
6311
6596
 
6312
6597
  return {
@@ -6317,76 +6602,58 @@ ${handlers.join('\n')}
6317
6602
  };
6318
6603
  }
6319
6604
 
6320
- response += `## Downloading Updates...\n\n`;
6321
-
6322
- // Fetch full content
6323
- const contentResponse = await fetch(`${this.apiUrl}/api/content`, {
6324
- headers: this.getAuthHeaders(),
6325
- });
6326
-
6327
- if (!contentResponse.ok) {
6328
- const error = await contentResponse.json().catch(() => ({}));
6329
- throw new Error(error.error || error.message || 'Failed to fetch patterns');
6330
- }
6331
-
6332
- const content = await contentResponse.json();
6333
- const moduleCount = content.modules ? Object.keys(content.modules).length : 0;
6605
+ response += `## Upgrading to v6.0...\n\n`;
6334
6606
 
6335
- // Create .claude directory if needed
6336
- if (!fs.existsSync(claudeDir)) {
6337
- fs.mkdirSync(claudeDir, { recursive: true });
6338
- response += `✓ Created .claude/ directory\n`;
6339
- }
6607
+ // Write v6.0 bootstrap files
6608
+ fs.writeFileSync(claudeMdPath, V6_CLAUDE_MD);
6609
+ response += `✓ Updated CLAUDE.md (v6.0 bootstrap)\n`;
6340
6610
 
6341
- // Update CLAUDE.md router
6342
- if (content.router) {
6343
- fs.writeFileSync(claudeMdPath, content.router);
6344
- response += `✓ Updated CLAUDE.md (router)\n`;
6345
- }
6611
+ fs.writeFileSync(path.join(cwd, '.cursorrules'), V6_CURSORRULES);
6612
+ response += `✓ Updated .cursorrules (v6.0 bootstrap)\n`;
6346
6613
 
6347
- // Update all modules
6348
- if (content.modules && moduleCount > 0) {
6349
- for (const [name, data] of Object.entries(content.modules)) {
6350
- fs.writeFileSync(path.join(claudeDir, name), data as string);
6614
+ // Remove old .claude folder (v5 → v6 migration)
6615
+ if (fs.existsSync(claudeDir)) {
6616
+ try {
6617
+ fs.rmSync(claudeDir, { recursive: true, force: true });
6618
+ response += `✓ Removed .claude/ folder (patterns now server-side)\n`;
6619
+ } catch {
6620
+ response += `⚠️ Could not remove .claude/ folder - please delete manually\n`;
6351
6621
  }
6352
- response += `✓ Updated ${moduleCount} modules in .claude/\n`;
6353
6622
  }
6354
6623
 
6355
- // Save version info
6356
- const newVersionInfo = {
6357
- version: content.version || latestVersion,
6358
- moduleCount,
6359
- installedAt: currentVersion ? undefined : new Date().toISOString(),
6360
- updatedAt: new Date().toISOString(),
6361
- cliVersion: getCliVersion(),
6362
- };
6363
- fs.writeFileSync(versionPath, JSON.stringify(newVersionInfo, null, 2));
6364
- response += `✓ Saved version info\n`;
6365
-
6366
- // Confirm download to server (non-blocking analytics)
6367
- this.confirmDownload(content.version || latestVersion, moduleCount).catch(() => {});
6368
-
6369
- response += `\n## ✅ Update Complete!\n\n`;
6370
- response += `- **From:** v${currentVersion || 'none'} (${currentModuleCount} modules)\n`;
6371
- response += `- **To:** v${content.version || latestVersion} (${moduleCount} modules)\n\n`;
6372
-
6373
- if (moduleCount > currentModuleCount) {
6374
- response += `🆕 **${moduleCount - currentModuleCount} new modules added!**\n\n`;
6624
+ // Update .codebakers.json
6625
+ let state: Record<string, unknown> = {};
6626
+ if (fs.existsSync(codebakersJson)) {
6627
+ try {
6628
+ state = JSON.parse(fs.readFileSync(codebakersJson, 'utf-8'));
6629
+ } catch {
6630
+ // Ignore errors
6631
+ }
6375
6632
  }
6376
-
6377
- response += `Your patterns are now up to date. The new patterns will be used in your next response.\n`;
6633
+ state.version = '6.0';
6634
+ state.serverEnforced = true;
6635
+ state.updatedAt = new Date().toISOString();
6636
+ fs.writeFileSync(codebakersJson, JSON.stringify(state, null, 2));
6637
+ response += `✓ Updated .codebakers.json\n`;
6638
+
6639
+ // Confirm to server (non-blocking analytics)
6640
+ this.confirmDownload('6.0', 0).catch(() => {});
6641
+
6642
+ response += `\n## ✅ Upgrade Complete!\n\n`;
6643
+ response += `**What changed in v6.0:**\n`;
6644
+ response += `- No local pattern files (.claude/ folder removed)\n`;
6645
+ response += `- All patterns fetched from server in real-time\n`;
6646
+ response += `- Server tracks compliance via discover_patterns/validate_complete\n\n`;
6647
+ response += `**How to use:**\n`;
6648
+ response += `1. Call \`discover_patterns\` before writing any code\n`;
6649
+ response += `2. Follow the patterns returned by server\n`;
6650
+ response += `3. Call \`validate_complete\` before marking done\n`;
6378
6651
 
6379
6652
  } catch (error) {
6380
6653
  const message = error instanceof Error ? error.message : 'Unknown error';
6381
6654
  response += `\n## ❌ Update Failed\n\n`;
6382
6655
  response += `Error: ${message}\n\n`;
6383
-
6384
- if (message.includes('401') || message.includes('Invalid') || message.includes('expired')) {
6385
- response += `Your API key may be invalid or expired.\n`;
6386
- response += `Run \`codebakers setup\` in terminal to reconfigure.\n`;
6387
- } else {
6388
- response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
6389
- }
6656
+ response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
6390
6657
  }
6391
6658
 
6392
6659
  // Add CLI update notice if available