@codebakers/cli 3.3.0 → 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/doctor.js +4 -3
- package/dist/commands/go.js +54 -6
- package/dist/commands/install.js +2 -1
- package/dist/commands/upgrade.js +25 -0
- package/dist/index.js +36 -18
- package/dist/lib/api.d.ts +10 -0
- package/dist/lib/api.js +73 -4
- package/dist/lib/stats.d.ts +9 -0
- package/dist/lib/stats.js +12 -0
- package/dist/mcp/server.js +227 -0
- package/nul +1 -0
- package/package.json +3 -2
- package/scripts/register-version.js +79 -0
- package/src/commands/doctor.ts +4 -3
- package/src/commands/go.ts +75 -6
- package/src/commands/install.ts +2 -1
- package/src/commands/upgrade.ts +34 -0
- package/src/index.ts +36 -19
- package/src/lib/api.ts +83 -4
- package/src/lib/stats.ts +10 -0
- package/src/mcp/server.ts +262 -0
package/src/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { go } from './commands/go.js';
|
|
|
23
23
|
import { extend } from './commands/extend.js';
|
|
24
24
|
import { billing } from './commands/billing.js';
|
|
25
25
|
import { getCachedUpdateInfo, setCachedUpdateInfo, getCliVersion, getCachedPatternInfo, setCachedPatternInfo, getApiKey, getApiUrl, getTrialState, hasValidAccess } from './config.js';
|
|
26
|
+
import { checkForUpdates } from './lib/api.js';
|
|
26
27
|
import { existsSync, writeFileSync, readFileSync, mkdirSync } from 'fs';
|
|
27
28
|
import { join } from 'path';
|
|
28
29
|
|
|
@@ -30,37 +31,37 @@ import { join } from 'path';
|
|
|
30
31
|
// Automatic Update Notification
|
|
31
32
|
// ============================================
|
|
32
33
|
|
|
33
|
-
const CURRENT_VERSION = '3.3.
|
|
34
|
+
const CURRENT_VERSION = '3.3.1';
|
|
34
35
|
|
|
35
36
|
async function checkForUpdatesInBackground(): Promise<void> {
|
|
36
37
|
// Check if we have a valid cached result first (fast path)
|
|
37
38
|
const cached = getCachedUpdateInfo();
|
|
38
39
|
if (cached) {
|
|
39
40
|
if (cached.latestVersion !== CURRENT_VERSION) {
|
|
40
|
-
showUpdateBanner(CURRENT_VERSION, cached.latestVersion);
|
|
41
|
+
showUpdateBanner(CURRENT_VERSION, cached.latestVersion, false);
|
|
41
42
|
}
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
//
|
|
46
|
+
// Use the API-based version check (with controlled rollout support)
|
|
46
47
|
try {
|
|
47
|
-
const
|
|
48
|
-
const timeout = setTimeout(() => controller.abort(), 3000);
|
|
49
|
-
|
|
50
|
-
const response = await fetch('https://registry.npmjs.org/@codebakers/cli/latest', {
|
|
51
|
-
headers: { 'Accept': 'application/json' },
|
|
52
|
-
signal: controller.signal,
|
|
53
|
-
});
|
|
48
|
+
const updateInfo = await checkForUpdates();
|
|
54
49
|
|
|
55
|
-
|
|
50
|
+
if (updateInfo) {
|
|
51
|
+
setCachedUpdateInfo(updateInfo.latestVersion);
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
// Show blocked version warning first (critical)
|
|
54
|
+
if (updateInfo.isBlocked) {
|
|
55
|
+
showBlockedVersionWarning(updateInfo.currentVersion, updateInfo.latestVersion);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
61
58
|
|
|
62
|
-
if
|
|
63
|
-
|
|
59
|
+
// Only show update banner if auto-update is enabled for this version
|
|
60
|
+
if (updateInfo.autoUpdateEnabled && updateInfo.autoUpdateVersion) {
|
|
61
|
+
showUpdateBanner(updateInfo.currentVersion, updateInfo.autoUpdateVersion, true);
|
|
62
|
+
} else if (updateInfo.updateAvailable) {
|
|
63
|
+
// Update available but not auto-update enabled - show regular banner
|
|
64
|
+
showUpdateBanner(updateInfo.currentVersion, updateInfo.latestVersion, false);
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
} catch {
|
|
@@ -68,11 +69,27 @@ async function checkForUpdatesInBackground(): Promise<void> {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
function
|
|
72
|
+
function showBlockedVersionWarning(currentVersion: string, recommendedVersion: string): void {
|
|
73
|
+
console.log(chalk.red(`
|
|
74
|
+
╭─────────────────────────────────────────────────────────╮
|
|
75
|
+
│ │
|
|
76
|
+
│ ${chalk.bold('⚠️ VERSION BLOCKED')} │
|
|
77
|
+
│ │
|
|
78
|
+
│ Your CLI version ${chalk.gray(currentVersion)} has critical issues. │
|
|
79
|
+
│ Please update immediately to ${chalk.green(recommendedVersion)} │
|
|
80
|
+
│ │
|
|
81
|
+
│ Run ${chalk.cyan('npm i -g @codebakers/cli@latest')} to update │
|
|
82
|
+
│ │
|
|
83
|
+
╰─────────────────────────────────────────────────────────╯
|
|
84
|
+
`));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function showUpdateBanner(currentVersion: string, latestVersion: string, isRecommended: boolean): void {
|
|
88
|
+
const updateType = isRecommended ? chalk.green('Recommended update') : chalk.bold('Update available!');
|
|
72
89
|
console.log(chalk.yellow(`
|
|
73
90
|
╭─────────────────────────────────────────────────────────╮
|
|
74
91
|
│ │
|
|
75
|
-
│ ${
|
|
92
|
+
│ ${updateType} ${chalk.gray(currentVersion)} → ${chalk.green(latestVersion)} │
|
|
76
93
|
│ │
|
|
77
94
|
│ Run ${chalk.cyan('npm i -g @codebakers/cli@latest')} to update │
|
|
78
95
|
│ │
|
package/src/lib/api.ts
CHANGED
|
@@ -155,29 +155,108 @@ export function getCliVersion(): string {
|
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
157
|
* Check if there's a newer version of the CLI available
|
|
158
|
+
* Uses the CodeBakers API for controlled rollouts (only recommends stable, tested versions)
|
|
159
|
+
* Falls back to npm registry if API is unavailable
|
|
158
160
|
*/
|
|
159
161
|
export async function checkForUpdates(): Promise<{
|
|
160
162
|
currentVersion: string;
|
|
161
163
|
latestVersion: string;
|
|
162
164
|
updateAvailable: boolean;
|
|
165
|
+
autoUpdateEnabled: boolean;
|
|
166
|
+
autoUpdateVersion: string | null;
|
|
167
|
+
isBlocked: boolean;
|
|
163
168
|
} | null> {
|
|
164
169
|
try {
|
|
165
170
|
const currentVersion = getCliVersion();
|
|
166
|
-
const
|
|
171
|
+
const apiUrl = getApiUrl();
|
|
172
|
+
|
|
173
|
+
// First, try the CodeBakers API for controlled rollout info
|
|
174
|
+
try {
|
|
175
|
+
const response = await fetch(`${apiUrl}/api/cli/version`, {
|
|
176
|
+
headers: {
|
|
177
|
+
'Accept': 'application/json',
|
|
178
|
+
'X-CLI-Version': currentVersion,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (response.ok) {
|
|
183
|
+
const data = await response.json();
|
|
184
|
+
const latestVersion = data.stableVersion || data.latestVersion;
|
|
185
|
+
const autoUpdateVersion = data.autoUpdateVersion;
|
|
186
|
+
const isBlocked = data.isBlocked === true;
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
currentVersion,
|
|
190
|
+
latestVersion,
|
|
191
|
+
updateAvailable: latestVersion !== currentVersion,
|
|
192
|
+
autoUpdateEnabled: data.autoUpdateEnabled === true,
|
|
193
|
+
autoUpdateVersion: autoUpdateVersion || null,
|
|
194
|
+
isBlocked,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
// API unavailable, fall through to npm
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Fallback: check npm registry directly
|
|
202
|
+
const npmResponse = await fetch('https://registry.npmjs.org/@codebakers/cli/latest', {
|
|
167
203
|
headers: { 'Accept': 'application/json' },
|
|
168
204
|
});
|
|
169
205
|
|
|
170
|
-
if (!
|
|
206
|
+
if (!npmResponse.ok) return null;
|
|
171
207
|
|
|
172
|
-
const
|
|
173
|
-
const latestVersion =
|
|
208
|
+
const npmData = await npmResponse.json();
|
|
209
|
+
const latestVersion = npmData.version;
|
|
174
210
|
|
|
175
211
|
return {
|
|
176
212
|
currentVersion,
|
|
177
213
|
latestVersion,
|
|
178
214
|
updateAvailable: currentVersion !== latestVersion,
|
|
215
|
+
autoUpdateEnabled: false, // npm fallback doesn't have controlled rollout
|
|
216
|
+
autoUpdateVersion: null,
|
|
217
|
+
isBlocked: false,
|
|
179
218
|
};
|
|
180
219
|
} catch {
|
|
181
220
|
return null;
|
|
182
221
|
}
|
|
183
222
|
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Report a CLI error to the server for tracking
|
|
226
|
+
* This helps identify problematic versions for blocking
|
|
227
|
+
*/
|
|
228
|
+
export async function reportCliError(
|
|
229
|
+
errorType: string,
|
|
230
|
+
errorMessage: string,
|
|
231
|
+
context?: Record<string, unknown>
|
|
232
|
+
): Promise<void> {
|
|
233
|
+
try {
|
|
234
|
+
const apiUrl = getApiUrl();
|
|
235
|
+
const cliVersion = getCliVersion();
|
|
236
|
+
|
|
237
|
+
// Fire and forget - don't block on error reporting
|
|
238
|
+
fetch(`${apiUrl}/api/cli/error-report`, {
|
|
239
|
+
method: 'POST',
|
|
240
|
+
headers: {
|
|
241
|
+
'Content-Type': 'application/json',
|
|
242
|
+
'X-CLI-Version': cliVersion,
|
|
243
|
+
},
|
|
244
|
+
body: JSON.stringify({
|
|
245
|
+
cliVersion,
|
|
246
|
+
errorType,
|
|
247
|
+
errorMessage,
|
|
248
|
+
stackTrace: context?.stack,
|
|
249
|
+
context: JSON.stringify({
|
|
250
|
+
...context,
|
|
251
|
+
nodeVersion: process.version,
|
|
252
|
+
platform: process.platform,
|
|
253
|
+
arch: process.arch,
|
|
254
|
+
}),
|
|
255
|
+
}),
|
|
256
|
+
}).catch(() => {
|
|
257
|
+
// Ignore reporting failures
|
|
258
|
+
});
|
|
259
|
+
} catch {
|
|
260
|
+
// Never fail on error reporting
|
|
261
|
+
}
|
|
262
|
+
}
|
package/src/lib/stats.ts
ADDED
package/src/mcp/server.ts
CHANGED
|
@@ -108,6 +108,31 @@ class CodeBakersServer {
|
|
|
108
108
|
return {};
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Confirm download to server (non-blocking analytics)
|
|
113
|
+
*/
|
|
114
|
+
private async confirmDownload(version: string, moduleCount: number): Promise<void> {
|
|
115
|
+
try {
|
|
116
|
+
const headers: Record<string, string> = {
|
|
117
|
+
'Content-Type': 'application/json',
|
|
118
|
+
...this.getAuthHeaders(),
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
await fetch(`${this.apiUrl}/api/content/confirm`, {
|
|
122
|
+
method: 'POST',
|
|
123
|
+
headers,
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
version,
|
|
126
|
+
moduleCount,
|
|
127
|
+
cliVersion: getCliVersion(),
|
|
128
|
+
command: 'auto-update',
|
|
129
|
+
}),
|
|
130
|
+
});
|
|
131
|
+
} catch {
|
|
132
|
+
// Silently ignore - this is just for analytics
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
111
136
|
/**
|
|
112
137
|
* Automatically check for and apply pattern updates
|
|
113
138
|
* Runs silently in background - no user intervention needed
|
|
@@ -213,6 +238,21 @@ class CodeBakersServer {
|
|
|
213
238
|
};
|
|
214
239
|
fs.writeFileSync(versionPath, JSON.stringify(versionInfo, null, 2));
|
|
215
240
|
|
|
241
|
+
// Write notification file for AI to read and show to user
|
|
242
|
+
const notificationPath = path.join(claudeDir, '.update-notification.json');
|
|
243
|
+
const notification = {
|
|
244
|
+
type: 'patterns_updated',
|
|
245
|
+
previousVersion: installed?.version || 'unknown',
|
|
246
|
+
newVersion: content.version,
|
|
247
|
+
moduleCount,
|
|
248
|
+
updatedAt: new Date().toISOString(),
|
|
249
|
+
message: `CodeBakers patterns have been automatically updated from v${installed?.version || 'unknown'} to v${content.version} (${moduleCount} modules). Your AI tools now have the latest production patterns.`,
|
|
250
|
+
};
|
|
251
|
+
fs.writeFileSync(notificationPath, JSON.stringify(notification, null, 2));
|
|
252
|
+
|
|
253
|
+
// Confirm to server (non-blocking, fire-and-forget)
|
|
254
|
+
this.confirmDownload(content.version, moduleCount).catch(() => {});
|
|
255
|
+
|
|
216
256
|
this.autoUpdateChecked = true;
|
|
217
257
|
this.autoUpdateInProgress = false;
|
|
218
258
|
|
|
@@ -984,6 +1024,29 @@ class CodeBakersServer {
|
|
|
984
1024
|
required: ['request'],
|
|
985
1025
|
},
|
|
986
1026
|
},
|
|
1027
|
+
{
|
|
1028
|
+
name: 'check_update_notification',
|
|
1029
|
+
description:
|
|
1030
|
+
'ALWAYS CALL THIS AT THE START OF EACH SESSION. Checks if CodeBakers patterns were recently auto-updated and returns a notification message to show the user. If an update occurred, tell the user about it with the returned message. After showing, the notification is cleared.',
|
|
1031
|
+
inputSchema: {
|
|
1032
|
+
type: 'object' as const,
|
|
1033
|
+
properties: {},
|
|
1034
|
+
},
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
name: 'update_patterns',
|
|
1038
|
+
description:
|
|
1039
|
+
'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.',
|
|
1040
|
+
inputSchema: {
|
|
1041
|
+
type: 'object' as const,
|
|
1042
|
+
properties: {
|
|
1043
|
+
force: {
|
|
1044
|
+
type: 'boolean',
|
|
1045
|
+
description: 'Force update even if already at latest version (default: false)',
|
|
1046
|
+
},
|
|
1047
|
+
},
|
|
1048
|
+
},
|
|
1049
|
+
},
|
|
987
1050
|
],
|
|
988
1051
|
}));
|
|
989
1052
|
|
|
@@ -1111,6 +1174,12 @@ class CodeBakersServer {
|
|
|
1111
1174
|
case 'add_api_route':
|
|
1112
1175
|
return this.handleAddApiRoute(args as { request: string });
|
|
1113
1176
|
|
|
1177
|
+
case 'check_update_notification':
|
|
1178
|
+
return this.handleCheckUpdateNotification();
|
|
1179
|
+
|
|
1180
|
+
case 'update_patterns':
|
|
1181
|
+
return this.handleUpdatePatterns(args as { force?: boolean });
|
|
1182
|
+
|
|
1114
1183
|
default:
|
|
1115
1184
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
1116
1185
|
}
|
|
@@ -4839,6 +4908,44 @@ export default ${asyncKeyword}function ${pageName}Page() {${authCheck}
|
|
|
4839
4908
|
};
|
|
4840
4909
|
}
|
|
4841
4910
|
|
|
4911
|
+
/**
|
|
4912
|
+
* Check for update notifications and return message to show user
|
|
4913
|
+
*/
|
|
4914
|
+
private async handleCheckUpdateNotification() {
|
|
4915
|
+
const cwd = process.cwd();
|
|
4916
|
+
const notificationPath = path.join(cwd, '.claude', '.update-notification.json');
|
|
4917
|
+
|
|
4918
|
+
try {
|
|
4919
|
+
if (!fs.existsSync(notificationPath)) {
|
|
4920
|
+
return {
|
|
4921
|
+
content: [{
|
|
4922
|
+
type: 'text' as const,
|
|
4923
|
+
text: 'No update notification.',
|
|
4924
|
+
}],
|
|
4925
|
+
};
|
|
4926
|
+
}
|
|
4927
|
+
|
|
4928
|
+
const notification = JSON.parse(fs.readFileSync(notificationPath, 'utf-8'));
|
|
4929
|
+
|
|
4930
|
+
// Delete the notification file after reading (so it only shows once)
|
|
4931
|
+
fs.unlinkSync(notificationPath);
|
|
4932
|
+
|
|
4933
|
+
return {
|
|
4934
|
+
content: [{
|
|
4935
|
+
type: 'text' as const,
|
|
4936
|
+
text: `🍪 **CodeBakers Update**\n\n${notification.message}\n\n**Previous version:** ${notification.previousVersion}\n**New version:** ${notification.newVersion}\n**Modules:** ${notification.moduleCount}\n**Updated:** ${new Date(notification.updatedAt).toLocaleString()}`,
|
|
4937
|
+
}],
|
|
4938
|
+
};
|
|
4939
|
+
} catch {
|
|
4940
|
+
return {
|
|
4941
|
+
content: [{
|
|
4942
|
+
type: 'text' as const,
|
|
4943
|
+
text: 'No update notification.',
|
|
4944
|
+
}],
|
|
4945
|
+
};
|
|
4946
|
+
}
|
|
4947
|
+
}
|
|
4948
|
+
|
|
4842
4949
|
private parseApiRouteRequest(request: string): {
|
|
4843
4950
|
success: boolean;
|
|
4844
4951
|
routeName?: string;
|
|
@@ -5041,6 +5148,161 @@ ${handlers.join('\n')}
|
|
|
5041
5148
|
`;
|
|
5042
5149
|
}
|
|
5043
5150
|
|
|
5151
|
+
/**
|
|
5152
|
+
* Download and update CodeBakers patterns from server
|
|
5153
|
+
* This is the MCP equivalent of the `codebakers upgrade` CLI command
|
|
5154
|
+
*/
|
|
5155
|
+
private async handleUpdatePatterns(args: { force?: boolean }) {
|
|
5156
|
+
const { force = false } = args;
|
|
5157
|
+
const cwd = process.cwd();
|
|
5158
|
+
const claudeMdPath = path.join(cwd, 'CLAUDE.md');
|
|
5159
|
+
const claudeDir = path.join(cwd, '.claude');
|
|
5160
|
+
const versionPath = path.join(claudeDir, '.version.json');
|
|
5161
|
+
|
|
5162
|
+
let response = `# 🔄 CodeBakers Pattern Update\n\n`;
|
|
5163
|
+
|
|
5164
|
+
try {
|
|
5165
|
+
// Check current version
|
|
5166
|
+
let currentVersion: string | null = null;
|
|
5167
|
+
let currentModuleCount = 0;
|
|
5168
|
+
|
|
5169
|
+
if (fs.existsSync(versionPath)) {
|
|
5170
|
+
try {
|
|
5171
|
+
const versionInfo = JSON.parse(fs.readFileSync(versionPath, 'utf-8'));
|
|
5172
|
+
currentVersion = versionInfo.version;
|
|
5173
|
+
currentModuleCount = versionInfo.moduleCount || 0;
|
|
5174
|
+
} catch {
|
|
5175
|
+
// Ignore parse errors
|
|
5176
|
+
}
|
|
5177
|
+
}
|
|
5178
|
+
|
|
5179
|
+
// Count current modules
|
|
5180
|
+
if (fs.existsSync(claudeDir)) {
|
|
5181
|
+
try {
|
|
5182
|
+
const files = fs.readdirSync(claudeDir).filter(f => f.endsWith('.md'));
|
|
5183
|
+
currentModuleCount = files.length;
|
|
5184
|
+
} catch {
|
|
5185
|
+
// Ignore read errors
|
|
5186
|
+
}
|
|
5187
|
+
}
|
|
5188
|
+
|
|
5189
|
+
response += `## Current Status\n`;
|
|
5190
|
+
response += `- Version: ${currentVersion || 'Unknown'}\n`;
|
|
5191
|
+
response += `- Modules: ${currentModuleCount}\n\n`;
|
|
5192
|
+
|
|
5193
|
+
// Fetch latest version info first
|
|
5194
|
+
const versionResponse = await fetch(`${this.apiUrl}/api/content/version`, {
|
|
5195
|
+
headers: this.getAuthHeaders(),
|
|
5196
|
+
});
|
|
5197
|
+
|
|
5198
|
+
if (!versionResponse.ok) {
|
|
5199
|
+
throw new Error('Failed to check version from server');
|
|
5200
|
+
}
|
|
5201
|
+
|
|
5202
|
+
const latestInfo = await versionResponse.json();
|
|
5203
|
+
const latestVersion = latestInfo.version;
|
|
5204
|
+
const latestModuleCount = latestInfo.moduleCount || 0;
|
|
5205
|
+
|
|
5206
|
+
response += `## Server Status\n`;
|
|
5207
|
+
response += `- Latest Version: ${latestVersion}\n`;
|
|
5208
|
+
response += `- Available Modules: ${latestModuleCount}\n\n`;
|
|
5209
|
+
|
|
5210
|
+
// Check if update needed
|
|
5211
|
+
const needsUpdate = force || !currentVersion || currentVersion !== latestVersion || currentModuleCount < latestModuleCount;
|
|
5212
|
+
|
|
5213
|
+
if (!needsUpdate) {
|
|
5214
|
+
response += `✅ **Already up to date!**\n\n`;
|
|
5215
|
+
response += `Your patterns are current (v${latestVersion} with ${latestModuleCount} modules).\n`;
|
|
5216
|
+
response += `Use \`force: true\` to re-download anyway.\n`;
|
|
5217
|
+
|
|
5218
|
+
return {
|
|
5219
|
+
content: [{
|
|
5220
|
+
type: 'text' as const,
|
|
5221
|
+
text: response,
|
|
5222
|
+
}],
|
|
5223
|
+
};
|
|
5224
|
+
}
|
|
5225
|
+
|
|
5226
|
+
response += `## Downloading Updates...\n\n`;
|
|
5227
|
+
|
|
5228
|
+
// Fetch full content
|
|
5229
|
+
const contentResponse = await fetch(`${this.apiUrl}/api/content`, {
|
|
5230
|
+
headers: this.getAuthHeaders(),
|
|
5231
|
+
});
|
|
5232
|
+
|
|
5233
|
+
if (!contentResponse.ok) {
|
|
5234
|
+
const error = await contentResponse.json().catch(() => ({}));
|
|
5235
|
+
throw new Error(error.error || error.message || 'Failed to fetch patterns');
|
|
5236
|
+
}
|
|
5237
|
+
|
|
5238
|
+
const content = await contentResponse.json();
|
|
5239
|
+
const moduleCount = content.modules ? Object.keys(content.modules).length : 0;
|
|
5240
|
+
|
|
5241
|
+
// Create .claude directory if needed
|
|
5242
|
+
if (!fs.existsSync(claudeDir)) {
|
|
5243
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
5244
|
+
response += `✓ Created .claude/ directory\n`;
|
|
5245
|
+
}
|
|
5246
|
+
|
|
5247
|
+
// Update CLAUDE.md router
|
|
5248
|
+
if (content.router) {
|
|
5249
|
+
fs.writeFileSync(claudeMdPath, content.router);
|
|
5250
|
+
response += `✓ Updated CLAUDE.md (router)\n`;
|
|
5251
|
+
}
|
|
5252
|
+
|
|
5253
|
+
// Update all modules
|
|
5254
|
+
if (content.modules && moduleCount > 0) {
|
|
5255
|
+
for (const [name, data] of Object.entries(content.modules)) {
|
|
5256
|
+
fs.writeFileSync(path.join(claudeDir, name), data as string);
|
|
5257
|
+
}
|
|
5258
|
+
response += `✓ Updated ${moduleCount} modules in .claude/\n`;
|
|
5259
|
+
}
|
|
5260
|
+
|
|
5261
|
+
// Save version info
|
|
5262
|
+
const newVersionInfo = {
|
|
5263
|
+
version: content.version || latestVersion,
|
|
5264
|
+
moduleCount,
|
|
5265
|
+
installedAt: currentVersion ? undefined : new Date().toISOString(),
|
|
5266
|
+
updatedAt: new Date().toISOString(),
|
|
5267
|
+
cliVersion: getCliVersion(),
|
|
5268
|
+
};
|
|
5269
|
+
fs.writeFileSync(versionPath, JSON.stringify(newVersionInfo, null, 2));
|
|
5270
|
+
response += `✓ Saved version info\n`;
|
|
5271
|
+
|
|
5272
|
+
// Confirm download to server (non-blocking analytics)
|
|
5273
|
+
this.confirmDownload(content.version || latestVersion, moduleCount).catch(() => {});
|
|
5274
|
+
|
|
5275
|
+
response += `\n## ✅ Update Complete!\n\n`;
|
|
5276
|
+
response += `- **From:** v${currentVersion || 'none'} (${currentModuleCount} modules)\n`;
|
|
5277
|
+
response += `- **To:** v${content.version || latestVersion} (${moduleCount} modules)\n\n`;
|
|
5278
|
+
|
|
5279
|
+
if (moduleCount > currentModuleCount) {
|
|
5280
|
+
response += `🆕 **${moduleCount - currentModuleCount} new modules added!**\n\n`;
|
|
5281
|
+
}
|
|
5282
|
+
|
|
5283
|
+
response += `Your patterns are now up to date. The new patterns will be used in your next response.\n`;
|
|
5284
|
+
|
|
5285
|
+
} catch (error) {
|
|
5286
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
5287
|
+
response += `\n## ❌ Update Failed\n\n`;
|
|
5288
|
+
response += `Error: ${message}\n\n`;
|
|
5289
|
+
|
|
5290
|
+
if (message.includes('401') || message.includes('Invalid') || message.includes('expired')) {
|
|
5291
|
+
response += `Your API key may be invalid or expired.\n`;
|
|
5292
|
+
response += `Run \`codebakers setup\` in terminal to reconfigure.\n`;
|
|
5293
|
+
} else {
|
|
5294
|
+
response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
|
|
5295
|
+
}
|
|
5296
|
+
}
|
|
5297
|
+
|
|
5298
|
+
return {
|
|
5299
|
+
content: [{
|
|
5300
|
+
type: 'text' as const,
|
|
5301
|
+
text: response,
|
|
5302
|
+
}],
|
|
5303
|
+
};
|
|
5304
|
+
}
|
|
5305
|
+
|
|
5044
5306
|
async run(): Promise<void> {
|
|
5045
5307
|
const transport = new StdioServerTransport();
|
|
5046
5308
|
await this.server.connect(transport);
|