@codebakers/cli 3.8.2 → 3.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,8 +10,8 @@ const fs_1 = require("fs");
10
10
  const path_1 = require("path");
11
11
  const config_js_1 = require("../config.js");
12
12
  const api_js_1 = require("../lib/api.js");
13
- // v6.0 Bootstrap files - patterns come from server via MCP
14
- const V6_CLAUDE_MD = `# CodeBakers v6.0
13
+ // Bootstrap files - patterns come from server via MCP
14
+ const CLAUDE_MD_BOOTSTRAP = `# CodeBakers
15
15
 
16
16
  **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
17
17
 
@@ -25,7 +25,7 @@ The server will return:
25
25
 
26
26
  **You cannot write code without calling this tool first. The server tracks compliance.**
27
27
  `;
28
- const V6_CURSORRULES = `# CodeBakers v6.0
28
+ const CURSORRULES_BOOTSTRAP = `# CodeBakers
29
29
 
30
30
  **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
31
31
 
@@ -40,26 +40,26 @@ The server will return:
40
40
  **You cannot write code without calling this tool first. The server tracks compliance.**
41
41
  `;
42
42
  async function install() {
43
- console.log(chalk_1.default.blue('\n CodeBakers Install (v6.0)\n'));
43
+ console.log(chalk_1.default.blue('\n CodeBakers Install\n'));
44
44
  const apiKey = (0, config_js_1.getApiKey)();
45
45
  if (!apiKey) {
46
46
  console.log(chalk_1.default.red(' Not logged in. Run `codebakers login` first.\n'));
47
47
  process.exit(1);
48
48
  }
49
- const spinner = (0, ora_1.default)('Installing CodeBakers v6.0...').start();
49
+ const spinner = (0, ora_1.default)('Installing CodeBakers...').start();
50
50
  try {
51
51
  const cwd = process.cwd();
52
52
  const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
53
53
  const cursorRulesPath = (0, path_1.join)(cwd, '.cursorrules');
54
54
  const claudeDir = (0, path_1.join)(cwd, '.claude');
55
- // Check for existing v5 installation and migrate
55
+ // Remove old .claude folder if it exists (patterns now server-side)
56
56
  if ((0, fs_1.existsSync)(claudeDir)) {
57
- spinner.text = 'Migrating from v5 to v6...';
57
+ spinner.text = 'Removing old pattern files...';
58
58
  (0, fs_1.rmSync)(claudeDir, { recursive: true, force: true });
59
59
  }
60
- // Write v6 bootstrap files
61
- (0, fs_1.writeFileSync)(claudeMdPath, V6_CLAUDE_MD);
62
- (0, fs_1.writeFileSync)(cursorRulesPath, V6_CURSORRULES);
60
+ // Write bootstrap files
61
+ (0, fs_1.writeFileSync)(claudeMdPath, CLAUDE_MD_BOOTSTRAP);
62
+ (0, fs_1.writeFileSync)(cursorRulesPath, CURSORRULES_BOOTSTRAP);
63
63
  // Add .cursorrules to .gitignore if not present
64
64
  const gitignorePath = (0, path_1.join)(cwd, '.gitignore');
65
65
  if ((0, fs_1.existsSync)(gitignorePath)) {
@@ -69,15 +69,14 @@ async function install() {
69
69
  (0, fs_1.writeFileSync)(gitignorePath, gitignore + additions);
70
70
  }
71
71
  }
72
- spinner.succeed('CodeBakers v6.0 installed!');
72
+ spinner.succeed('CodeBakers installed!');
73
73
  console.log(chalk_1.default.gray('\n Files created:'));
74
74
  console.log(chalk_1.default.gray(' - CLAUDE.md (Claude Code gateway)'));
75
75
  console.log(chalk_1.default.gray(' - .cursorrules (Cursor IDE gateway)'));
76
- console.log(chalk_1.default.cyan('\n What\'s new in v6.0:'));
77
- console.log(chalk_1.default.gray(' - Patterns are now server-side'));
76
+ console.log(chalk_1.default.cyan('\n How it works:'));
77
+ console.log(chalk_1.default.gray(' - Patterns are fetched from server in real-time'));
78
78
  console.log(chalk_1.default.gray(' - AI calls discover_patterns before coding'));
79
- console.log(chalk_1.default.gray(' - Real-time pattern updates'));
80
- console.log(chalk_1.default.gray(' - Usage tracking & compliance'));
79
+ console.log(chalk_1.default.gray(' - Always up-to-date, no manual updates needed'));
81
80
  console.log(chalk_1.default.gray(`\n CLI version: ${(0, api_js_1.getCliVersion)()}`));
82
81
  console.log(chalk_1.default.blue('\n Start building! AI will fetch patterns via MCP.\n'));
83
82
  }
@@ -1,4 +1,4 @@
1
1
  /**
2
- * Upgrade CodeBakers patterns to the latest version
2
+ * Upgrade CodeBakers - checks for CLI updates and ensures server-enforced setup
3
3
  */
4
4
  export declare function upgrade(): Promise<void>;
@@ -10,75 +10,8 @@ const fs_1 = require("fs");
10
10
  const path_1 = require("path");
11
11
  const config_js_1 = require("../config.js");
12
12
  const api_js_1 = require("../lib/api.js");
13
- // Pre-commit hook script for session enforcement
14
- const PRE_COMMIT_SCRIPT = `#!/bin/sh
15
- # CodeBakers Pre-Commit Hook - Session Enforcement
16
- # Blocks commits unless AI called discover_patterns and validate_complete
17
- node "$(dirname "$0")/validate-session.js"
18
- exit $?
19
- `;
20
- const VALIDATE_SESSION_SCRIPT = `#!/usr/bin/env node
21
- const fs = require('fs');
22
- const path = require('path');
23
- const RED = '\\x1b[31m', GREEN = '\\x1b[32m', YELLOW = '\\x1b[33m', CYAN = '\\x1b[36m', RESET = '\\x1b[0m';
24
- function log(c, m) { console.log(c + m + RESET); }
25
-
26
- async function validate() {
27
- const stateFile = path.join(process.cwd(), '.codebakers.json');
28
- if (!fs.existsSync(stateFile)) return { valid: true, reason: 'not-codebakers' };
29
-
30
- let state;
31
- try { state = JSON.parse(fs.readFileSync(stateFile, 'utf-8')); }
32
- catch { return { valid: false, reason: 'invalid-state' }; }
33
-
34
- if (!state.serverEnforced) return { valid: true, reason: 'legacy' };
35
-
36
- const v = state.lastValidation;
37
- if (!v) return { valid: false, reason: 'no-validation', msg: 'AI must call validate_complete before commit' };
38
- if (!v.passed) return { valid: false, reason: 'failed', msg: 'Validation failed - fix issues first' };
39
-
40
- const age = Date.now() - new Date(v.timestamp).getTime();
41
- if (age > 30 * 60 * 1000) return { valid: false, reason: 'stale', msg: 'Validation expired - call validate_complete again' };
42
-
43
- return { valid: true, reason: 'ok' };
44
- }
45
-
46
- async function main() {
47
- console.log(''); log(CYAN, ' 🍪 CodeBakers Pre-Commit');
48
- const r = await validate();
49
- if (r.valid) { log(GREEN, ' ✓ Commit allowed'); console.log(''); process.exit(0); }
50
- else { log(RED, ' ✗ Blocked: ' + r.reason); if (r.msg) log(YELLOW, ' ' + r.msg);
51
- console.log(''); log(YELLOW, ' Bypass: git commit --no-verify'); console.log(''); process.exit(1); }
52
- }
53
- main().catch(e => { log(RED, ' Error: ' + e.message); process.exit(1); });
54
- `;
55
- /**
56
- * Install pre-commit hook for session enforcement
57
- */
58
- function installPrecommitHook(cwd) {
59
- const gitDir = (0, path_1.join)(cwd, '.git');
60
- if (!(0, fs_1.existsSync)(gitDir)) {
61
- console.log(chalk_1.default.gray(' ⏭️ Skipping pre-commit hook (not a git repo)'));
62
- return;
63
- }
64
- const hooksDir = (0, path_1.join)(gitDir, 'hooks');
65
- if (!(0, fs_1.existsSync)(hooksDir)) {
66
- (0, fs_1.mkdirSync)(hooksDir, { recursive: true });
67
- }
68
- // Write pre-commit hook
69
- const preCommitPath = (0, path_1.join)(hooksDir, 'pre-commit');
70
- (0, fs_1.writeFileSync)(preCommitPath, PRE_COMMIT_SCRIPT);
71
- try {
72
- (0, fs_1.chmodSync)(preCommitPath, '755');
73
- }
74
- catch { /* Windows */ }
75
- // Write validation script
76
- const validatePath = (0, path_1.join)(hooksDir, 'validate-session.js');
77
- (0, fs_1.writeFileSync)(validatePath, VALIDATE_SESSION_SCRIPT);
78
- console.log(chalk_1.default.green(' ✓ Installed pre-commit hook (blocks commits without validation)'));
79
- }
80
- // Ultra-minimal CLAUDE.md for v6.0 - ALL instructions come from server
81
- const MINIMAL_CLAUDE_MD = `# CodeBakers v6.0
13
+ // Bootstrap files - patterns come from server via MCP
14
+ const CLAUDE_MD_BOOTSTRAP = `# CodeBakers
82
15
 
83
16
  **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
84
17
 
@@ -93,12 +26,8 @@ The server will return:
93
26
  - Validation instructions
94
27
 
95
28
  **You cannot write code without calling this tool first. The server tracks compliance.**
96
-
97
- ---
98
- *CodeBakers v6.0 - Server-Enforced*
99
29
  `;
100
- // Ultra-minimal .cursorrules for v6.0 - ALL instructions come from server
101
- const MINIMAL_CURSORRULES = `# CodeBakers v6.0
30
+ const CURSORRULES_BOOTSTRAP = `# CodeBakers
102
31
 
103
32
  MANDATORY: Before writing ANY code, call the discover_patterns MCP tool.
104
33
 
@@ -109,128 +38,46 @@ The server returns all patterns, rules, and test requirements.
109
38
  You cannot write code without calling this tool first.
110
39
  `;
111
40
  /**
112
- * Compare semantic versions (returns true if v1 < v2)
113
- */
114
- function isVersionLessThan(v1, v2) {
115
- const parts1 = v1.split('.').map(Number);
116
- const parts2 = v2.split('.').map(Number);
117
- for (let i = 0; i < 3; i++) {
118
- const p1 = parts1[i] || 0;
119
- const p2 = parts2[i] || 0;
120
- if (p1 < p2)
121
- return true;
122
- if (p1 > p2)
123
- return false;
124
- }
125
- return false;
126
- }
127
- /**
128
- * Confirm download to server (non-blocking, fire-and-forget)
129
- */
130
- async function confirmDownload(apiUrl, apiKey, data) {
131
- try {
132
- await fetch(`${apiUrl}/api/content/confirm`, {
133
- method: 'POST',
134
- headers: {
135
- 'Content-Type': 'application/json',
136
- 'Authorization': `Bearer ${apiKey}`,
137
- },
138
- body: JSON.stringify(data),
139
- });
140
- }
141
- catch {
142
- // Silently ignore - this is just for analytics
143
- }
144
- }
145
- /**
146
- * Get current installed version from .claude/.version.json
41
+ * Check if project is using server-enforced mode
147
42
  */
148
- function getCurrentVersion(cwd) {
149
- const versionFile = (0, path_1.join)(cwd, '.claude', '.version.json');
150
- const codebakersFile = (0, path_1.join)(cwd, '.codebakers.json');
151
- try {
152
- if ((0, fs_1.existsSync)(versionFile)) {
153
- const data = JSON.parse((0, fs_1.readFileSync)(versionFile, 'utf-8'));
154
- return data.version || null;
155
- }
156
- if ((0, fs_1.existsSync)(codebakersFile)) {
157
- const data = JSON.parse((0, fs_1.readFileSync)(codebakersFile, 'utf-8'));
158
- return data.version || null;
43
+ function isServerEnforced(cwd) {
44
+ const stateFile = (0, path_1.join)(cwd, '.codebakers.json');
45
+ if ((0, fs_1.existsSync)(stateFile)) {
46
+ try {
47
+ const state = JSON.parse((0, fs_1.readFileSync)(stateFile, 'utf-8'));
48
+ return state.serverEnforced === true;
159
49
  }
160
- }
161
- catch {
162
- // Ignore errors
163
- }
164
- return null;
165
- }
166
- /**
167
- * Backup old files before migration
168
- */
169
- function backupOldFiles(cwd) {
170
- const backupDir = (0, path_1.join)(cwd, '.codebakers', 'backup', new Date().toISOString().replace(/[:.]/g, '-'));
171
- (0, fs_1.mkdirSync)(backupDir, { recursive: true });
172
- // Backup CLAUDE.md
173
- const claudeMd = (0, path_1.join)(cwd, 'CLAUDE.md');
174
- if ((0, fs_1.existsSync)(claudeMd)) {
175
- (0, fs_1.copyFileSync)(claudeMd, (0, path_1.join)(backupDir, 'CLAUDE.md'));
176
- }
177
- // Backup .cursorrules
178
- const cursorrules = (0, path_1.join)(cwd, '.cursorrules');
179
- if ((0, fs_1.existsSync)(cursorrules)) {
180
- (0, fs_1.copyFileSync)(cursorrules, (0, path_1.join)(backupDir, '.cursorrules'));
181
- }
182
- // Backup .claude folder
183
- const claudeDir = (0, path_1.join)(cwd, '.claude');
184
- if ((0, fs_1.existsSync)(claudeDir)) {
185
- const claudeBackup = (0, path_1.join)(backupDir, '.claude');
186
- (0, fs_1.mkdirSync)(claudeBackup, { recursive: true });
187
- const files = (0, fs_1.readdirSync)(claudeDir);
188
- for (const file of files) {
189
- const src = (0, path_1.join)(claudeDir, file);
190
- const dest = (0, path_1.join)(claudeBackup, file);
191
- try {
192
- (0, fs_1.copyFileSync)(src, dest);
193
- }
194
- catch {
195
- // Ignore copy errors
196
- }
50
+ catch {
51
+ // Ignore parse errors
197
52
  }
198
53
  }
199
- console.log(chalk_1.default.gray(` Backup saved to: ${backupDir}`));
54
+ return false;
200
55
  }
201
56
  /**
202
- * Migrate to v6.0 server-enforced patterns
57
+ * Migrate project to server-enforced mode
203
58
  */
204
- function migrateToV6(cwd) {
205
- console.log(chalk_1.default.yellow('\n 📦 Migrating to v6.0 Server-Enforced Patterns...\n'));
206
- // Backup old files
207
- console.log(chalk_1.default.gray(' Backing up old files...'));
208
- backupOldFiles(cwd);
209
- // Replace CLAUDE.md with minimal version
210
- const claudeMd = (0, path_1.join)(cwd, 'CLAUDE.md');
211
- (0, fs_1.writeFileSync)(claudeMd, MINIMAL_CLAUDE_MD);
212
- console.log(chalk_1.default.green(' ✓ Updated CLAUDE.md (minimal server-enforced version)'));
213
- // Replace .cursorrules with minimal version
59
+ function migrateToServerEnforced(cwd) {
60
+ console.log(chalk_1.default.yellow('\n 📦 Upgrading to server-enforced patterns...\n'));
61
+ // Update CLAUDE.md
62
+ const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
63
+ (0, fs_1.writeFileSync)(claudeMdPath, CLAUDE_MD_BOOTSTRAP);
64
+ console.log(chalk_1.default.green(' ✓ Updated CLAUDE.md'));
65
+ // Update .cursorrules
214
66
  const cursorrules = (0, path_1.join)(cwd, '.cursorrules');
215
- (0, fs_1.writeFileSync)(cursorrules, MINIMAL_CURSORRULES);
216
- console.log(chalk_1.default.green(' ✓ Updated .cursorrules (minimal server-enforced version)'));
217
- // Delete .claude folder (patterns now come from server)
67
+ (0, fs_1.writeFileSync)(cursorrules, CURSORRULES_BOOTSTRAP);
68
+ console.log(chalk_1.default.green(' ✓ Updated .cursorrules'));
69
+ // Remove old .claude folder if it exists (patterns now come from server)
218
70
  const claudeDir = (0, path_1.join)(cwd, '.claude');
219
71
  if ((0, fs_1.existsSync)(claudeDir)) {
220
72
  try {
221
73
  (0, fs_1.rmSync)(claudeDir, { recursive: true, force: true });
222
74
  console.log(chalk_1.default.green(' ✓ Removed .claude/ folder (patterns now server-side)'));
223
75
  }
224
- catch (error) {
76
+ catch {
225
77
  console.log(chalk_1.default.yellow(' ⚠️ Could not remove .claude/ folder - please delete manually'));
226
78
  }
227
79
  }
228
- // Create .codebakers directory if it doesn't exist
229
- const codebakersDir = (0, path_1.join)(cwd, '.codebakers');
230
- if (!(0, fs_1.existsSync)(codebakersDir)) {
231
- (0, fs_1.mkdirSync)(codebakersDir, { recursive: true });
232
- }
233
- // Update version in .codebakers.json
80
+ // Update .codebakers.json
234
81
  const stateFile = (0, path_1.join)(cwd, '.codebakers.json');
235
82
  let state = {};
236
83
  if ((0, fs_1.existsSync)(stateFile)) {
@@ -241,164 +88,61 @@ function migrateToV6(cwd) {
241
88
  // Ignore errors
242
89
  }
243
90
  }
244
- state.version = '6.0';
245
91
  state.migratedAt = new Date().toISOString();
246
92
  state.serverEnforced = true;
247
93
  (0, fs_1.writeFileSync)(stateFile, JSON.stringify(state, null, 2));
248
- // Auto-install pre-commit hook for enforcement
249
- installPrecommitHook(cwd);
250
- console.log(chalk_1.default.green('\n ✅ Migration to v6.0 complete!\n'));
94
+ console.log(chalk_1.default.green('\n ✅ Upgrade complete!\n'));
251
95
  console.log(chalk_1.default.cyan(' What changed:'));
252
96
  console.log(chalk_1.default.gray(' - Patterns are now fetched from server in real-time'));
253
- console.log(chalk_1.default.gray(' - discover_patterns creates a server-tracked session'));
254
- console.log(chalk_1.default.gray(' - validate_complete verifies with server before completion'));
255
- console.log(chalk_1.default.gray(' - Pre-commit hook blocks commits without validation'));
256
- console.log(chalk_1.default.gray(' - No local pattern files needed\n'));
97
+ console.log(chalk_1.default.gray(' - AI calls discover_patterns before coding'));
98
+ console.log(chalk_1.default.gray(' - No local pattern files needed'));
99
+ console.log(chalk_1.default.gray(' - Always up-to-date patterns\n'));
257
100
  }
258
101
  /**
259
- * Upgrade CodeBakers patterns to the latest version
102
+ * Upgrade CodeBakers - checks for CLI updates and ensures server-enforced setup
260
103
  */
261
104
  async function upgrade() {
262
105
  console.log(chalk_1.default.blue('\n CodeBakers Upgrade\n'));
263
106
  const cwd = process.cwd();
264
107
  const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
265
- const claudeDir = (0, path_1.join)(cwd, '.claude');
266
108
  const codebakersJson = (0, path_1.join)(cwd, '.codebakers.json');
267
109
  // Check if this is a CodeBakers project
268
- if (!(0, fs_1.existsSync)(claudeMdPath) && !(0, fs_1.existsSync)(claudeDir) && !(0, fs_1.existsSync)(codebakersJson)) {
110
+ if (!(0, fs_1.existsSync)(claudeMdPath) && !(0, fs_1.existsSync)(codebakersJson)) {
269
111
  console.log(chalk_1.default.yellow(' No CodeBakers installation found in this directory.\n'));
270
- console.log(chalk_1.default.gray(' Run `codebakers install` to set up patterns first.\n'));
112
+ console.log(chalk_1.default.gray(' Run `codebakers init` to set up CodeBakers first.\n'));
271
113
  return;
272
114
  }
273
115
  // Check for CLI updates
274
- console.log(chalk_1.default.gray(' Checking for CLI updates...\n'));
275
- const updateInfo = await (0, api_js_1.checkForUpdates)();
276
- if (updateInfo?.updateAvailable) {
277
- console.log(chalk_1.default.yellow(` ⚠️ CLI update available: ${updateInfo.currentVersion} → ${updateInfo.latestVersion}`));
278
- console.log(chalk_1.default.gray(' Run: npm install -g @codebakers/cli@latest\n'));
116
+ const spinner = (0, ora_1.default)('Checking for CLI updates...').start();
117
+ try {
118
+ const updateInfo = await (0, api_js_1.checkForUpdates)();
119
+ if (updateInfo?.updateAvailable) {
120
+ spinner.succeed('CLI update available!');
121
+ console.log(chalk_1.default.yellow(`\n ⚠️ New CLI version: ${updateInfo.currentVersion} → ${updateInfo.latestVersion}`));
122
+ console.log(chalk_1.default.cyan(' Run: npm install -g @codebakers/cli@latest\n'));
123
+ }
124
+ else {
125
+ spinner.succeed(`CLI is up to date (v${(0, api_js_1.getCliVersion)()})`);
126
+ }
279
127
  }
280
- else {
281
- console.log(chalk_1.default.green(` ✓ CLI is up to date (v${(0, api_js_1.getCliVersion)()})\n`));
128
+ catch {
129
+ spinner.warn('Could not check for CLI updates');
282
130
  }
283
131
  // Check API key
284
132
  const apiKey = (0, config_js_1.getApiKey)();
285
133
  if (!apiKey) {
286
- console.log(chalk_1.default.yellow(' Not logged in. Run `codebakers setup` first.\n'));
287
- return;
134
+ console.log(chalk_1.default.yellow('\n Not logged in. Run `codebakers login` to authenticate.\n'));
288
135
  }
289
- // Check current version and determine if migration is needed
290
- const currentVersion = getCurrentVersion(cwd);
291
- const spinner = (0, ora_1.default)('Checking server for latest version...').start();
292
- try {
293
- const apiUrl = (0, config_js_1.getApiUrl)();
294
- // Check latest version from server
295
- const versionResponse = await fetch(`${apiUrl}/api/content/version`, {
296
- method: 'GET',
297
- headers: {
298
- 'Authorization': `Bearer ${apiKey}`,
299
- },
300
- });
301
- if (!versionResponse.ok) {
302
- throw new Error('Failed to check version');
303
- }
304
- const versionData = await versionResponse.json();
305
- const latestVersion = versionData.version;
306
- spinner.succeed(`Latest version: v${latestVersion}`);
307
- // Check if we need to migrate to v6.0
308
- const needsV6Migration = currentVersion && isVersionLessThan(currentVersion, '6.0') &&
309
- !isVersionLessThan(latestVersion, '6.0');
310
- if (needsV6Migration || (!currentVersion && !isVersionLessThan(latestVersion, '6.0'))) {
311
- // Need to migrate to v6.0 server-enforced patterns
312
- migrateToV6(cwd);
313
- // Confirm migration to server
314
- confirmDownload(apiUrl, apiKey, {
315
- version: '6.0',
316
- moduleCount: 0, // No local modules in v6
317
- cliVersion: (0, api_js_1.getCliVersion)(),
318
- command: 'upgrade-v6-migration',
319
- }).catch(() => { });
320
- return;
321
- }
322
- // For v6.0+, just confirm the installation is up to date
323
- const stateFile = (0, path_1.join)(cwd, '.codebakers.json');
324
- let state = {};
325
- if ((0, fs_1.existsSync)(stateFile)) {
326
- try {
327
- state = JSON.parse((0, fs_1.readFileSync)(stateFile, 'utf-8'));
328
- }
329
- catch {
330
- // Ignore
331
- }
332
- }
333
- if (state.serverEnforced) {
334
- // Already on v6.0+ server-enforced mode
335
- console.log(chalk_1.default.green('\n ✅ Already using v6.0 server-enforced patterns!\n'));
336
- console.log(chalk_1.default.gray(' Patterns are fetched from server in real-time.'));
337
- console.log(chalk_1.default.gray(' No local updates needed.\n'));
338
- return;
339
- }
340
- // Legacy upgrade for pre-6.0 versions (fetch full content)
341
- const contentSpinner = (0, ora_1.default)('Fetching latest patterns...').start();
342
- const response = await fetch(`${apiUrl}/api/content`, {
343
- method: 'GET',
344
- headers: {
345
- 'Authorization': `Bearer ${apiKey}`,
346
- },
347
- });
348
- if (!response.ok) {
349
- const error = await response.json().catch(() => ({}));
350
- throw new Error(error.error || 'Failed to fetch patterns');
351
- }
352
- const content = await response.json();
353
- contentSpinner.succeed(`Patterns v${content.version} downloaded`);
354
- // Count what we're updating
355
- const moduleCount = Object.keys(content.modules).length;
356
- console.log(chalk_1.default.gray(` Updating ${moduleCount} modules...\n`));
357
- // Update CLAUDE.md
358
- if (content.router) {
359
- (0, fs_1.writeFileSync)(claudeMdPath, content.router);
360
- console.log(chalk_1.default.green(' ✓ Updated CLAUDE.md'));
361
- }
362
- // Update pattern modules
363
- if (content.modules && Object.keys(content.modules).length > 0) {
364
- if (!(0, fs_1.existsSync)(claudeDir)) {
365
- (0, fs_1.mkdirSync)(claudeDir, { recursive: true });
366
- }
367
- for (const [name, data] of Object.entries(content.modules)) {
368
- (0, fs_1.writeFileSync)((0, path_1.join)(claudeDir, name), data);
369
- }
370
- console.log(chalk_1.default.green(` ✓ Updated ${moduleCount} modules in .claude/`));
371
- }
372
- // Write version file for tracking
373
- const versionInfo = {
374
- version: content.version,
375
- moduleCount,
376
- updatedAt: new Date().toISOString(),
377
- cliVersion: (0, api_js_1.getCliVersion)(),
378
- };
379
- if (!(0, fs_1.existsSync)(claudeDir)) {
380
- (0, fs_1.mkdirSync)(claudeDir, { recursive: true });
381
- }
382
- (0, fs_1.writeFileSync)((0, path_1.join)(claudeDir, '.version.json'), JSON.stringify(versionInfo, null, 2));
383
- console.log(chalk_1.default.green(' ✓ Version info saved'));
384
- // Confirm download to server (non-blocking)
385
- confirmDownload(apiUrl, apiKey, {
386
- version: content.version,
387
- moduleCount,
388
- cliVersion: (0, api_js_1.getCliVersion)(),
389
- command: 'upgrade',
390
- }).catch(() => { }); // Silently ignore confirmation failures
391
- console.log(chalk_1.default.green(`\n ✅ Upgraded to patterns v${content.version}!\n`));
392
- // Show what's new if available
393
- console.log(chalk_1.default.gray(' Changes take effect in your next AI session.\n'));
136
+ else {
137
+ console.log(chalk_1.default.green(' ✓ Logged in\n'));
394
138
  }
395
- catch (error) {
396
- spinner.fail('Upgrade failed');
397
- const message = error instanceof Error ? error.message : 'Unknown error';
398
- console.log(chalk_1.default.red(`\n Error: ${message}\n`));
399
- if (message.includes('401') || message.includes('Invalid')) {
400
- console.log(chalk_1.default.gray(' Your API key may have expired. Run `codebakers setup` to reconfigure.\n'));
401
- }
402
- process.exit(1);
139
+ // Check if already using server-enforced patterns
140
+ if (isServerEnforced(cwd)) {
141
+ console.log(chalk_1.default.green(' ✅ Already using server-enforced patterns!\n'));
142
+ console.log(chalk_1.default.gray(' Patterns are fetched from server in real-time.'));
143
+ console.log(chalk_1.default.gray(' AI calls discover_patterns before coding - always up to date.\n'));
144
+ return;
403
145
  }
146
+ // Migrate to server-enforced mode
147
+ migrateToServerEnforced(cwd);
404
148
  }