@codebakers/cli 3.2.0 → 3.3.1
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/go.js +54 -6
- package/dist/commands/upgrade.js +25 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.js +47 -2
- package/dist/index.js +182 -20
- package/dist/lib/api.d.ts +10 -0
- package/dist/lib/api.js +73 -4
- package/dist/mcp/server.js +81 -0
- package/package.json +3 -2
- package/scripts/register-version.js +79 -0
- package/src/commands/go.ts +75 -6
- package/src/commands/upgrade.ts +34 -0
- package/src/config.ts +54 -3
- package/src/index.ts +220 -22
- package/src/lib/api.ts +83 -4
- package/src/mcp/server.ts +90 -0
package/src/index.ts
CHANGED
|
@@ -22,43 +22,46 @@ import { pushPatterns, pushPatternsInteractive } from './commands/push-patterns.
|
|
|
22
22
|
import { go } from './commands/go.js';
|
|
23
23
|
import { extend } from './commands/extend.js';
|
|
24
24
|
import { billing } from './commands/billing.js';
|
|
25
|
-
import { getCachedUpdateInfo, setCachedUpdateInfo, getCliVersion } from './config.js';
|
|
25
|
+
import { getCachedUpdateInfo, setCachedUpdateInfo, getCliVersion, getCachedPatternInfo, setCachedPatternInfo, getApiKey, getApiUrl, getTrialState, hasValidAccess } from './config.js';
|
|
26
|
+
import { checkForUpdates } from './lib/api.js';
|
|
27
|
+
import { existsSync, writeFileSync, readFileSync, mkdirSync } from 'fs';
|
|
28
|
+
import { join } from 'path';
|
|
26
29
|
|
|
27
30
|
// ============================================
|
|
28
31
|
// Automatic Update Notification
|
|
29
32
|
// ============================================
|
|
30
33
|
|
|
31
|
-
const CURRENT_VERSION = '3.
|
|
34
|
+
const CURRENT_VERSION = '3.3.1';
|
|
32
35
|
|
|
33
36
|
async function checkForUpdatesInBackground(): Promise<void> {
|
|
34
37
|
// Check if we have a valid cached result first (fast path)
|
|
35
38
|
const cached = getCachedUpdateInfo();
|
|
36
39
|
if (cached) {
|
|
37
40
|
if (cached.latestVersion !== CURRENT_VERSION) {
|
|
38
|
-
showUpdateBanner(CURRENT_VERSION, cached.latestVersion);
|
|
41
|
+
showUpdateBanner(CURRENT_VERSION, cached.latestVersion, false);
|
|
39
42
|
}
|
|
40
43
|
return;
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
//
|
|
46
|
+
// Use the API-based version check (with controlled rollout support)
|
|
44
47
|
try {
|
|
45
|
-
const
|
|
46
|
-
const timeout = setTimeout(() => controller.abort(), 3000);
|
|
47
|
-
|
|
48
|
-
const response = await fetch('https://registry.npmjs.org/@codebakers/cli/latest', {
|
|
49
|
-
headers: { 'Accept': 'application/json' },
|
|
50
|
-
signal: controller.signal,
|
|
51
|
-
});
|
|
48
|
+
const updateInfo = await checkForUpdates();
|
|
52
49
|
|
|
53
|
-
|
|
50
|
+
if (updateInfo) {
|
|
51
|
+
setCachedUpdateInfo(updateInfo.latestVersion);
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
// Show blocked version warning first (critical)
|
|
54
|
+
if (updateInfo.isBlocked) {
|
|
55
|
+
showBlockedVersionWarning(updateInfo.currentVersion, updateInfo.latestVersion);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
59
58
|
|
|
60
|
-
if
|
|
61
|
-
|
|
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);
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
67
|
} catch {
|
|
@@ -66,11 +69,27 @@ async function checkForUpdatesInBackground(): Promise<void> {
|
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
|
|
69
|
-
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!');
|
|
70
89
|
console.log(chalk.yellow(`
|
|
71
90
|
╭─────────────────────────────────────────────────────────╮
|
|
72
91
|
│ │
|
|
73
|
-
│ ${
|
|
92
|
+
│ ${updateType} ${chalk.gray(currentVersion)} → ${chalk.green(latestVersion)} │
|
|
74
93
|
│ │
|
|
75
94
|
│ Run ${chalk.cyan('npm i -g @codebakers/cli@latest')} to update │
|
|
76
95
|
│ │
|
|
@@ -78,6 +97,181 @@ function showUpdateBanner(currentVersion: string, latestVersion: string): void {
|
|
|
78
97
|
`));
|
|
79
98
|
}
|
|
80
99
|
|
|
100
|
+
// ============================================
|
|
101
|
+
// Automatic Pattern Updates
|
|
102
|
+
// ============================================
|
|
103
|
+
|
|
104
|
+
interface PatternVersionInfo {
|
|
105
|
+
version: string;
|
|
106
|
+
moduleCount: number;
|
|
107
|
+
updatedAt: string;
|
|
108
|
+
cliVersion: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface ContentResponse {
|
|
112
|
+
version: string;
|
|
113
|
+
router: string;
|
|
114
|
+
modules: Record<string, string>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function getLocalPatternVersion(): string | null {
|
|
118
|
+
const cwd = process.cwd();
|
|
119
|
+
const versionFile = join(cwd, '.claude', '.version.json');
|
|
120
|
+
|
|
121
|
+
if (!existsSync(versionFile)) return null;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const content = readFileSync(versionFile, 'utf-8');
|
|
125
|
+
const info: PatternVersionInfo = JSON.parse(content);
|
|
126
|
+
return info.version;
|
|
127
|
+
} catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function isCodeBakersProject(): boolean {
|
|
133
|
+
const cwd = process.cwd();
|
|
134
|
+
return existsSync(join(cwd, 'CLAUDE.md')) || existsSync(join(cwd, '.claude'));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function autoUpdatePatterns(): Promise<void> {
|
|
138
|
+
// Only auto-update if this is a CodeBakers project
|
|
139
|
+
if (!isCodeBakersProject()) return;
|
|
140
|
+
|
|
141
|
+
// Only auto-update if user has valid access
|
|
142
|
+
if (!hasValidAccess()) return;
|
|
143
|
+
|
|
144
|
+
const localVersion = getLocalPatternVersion();
|
|
145
|
+
|
|
146
|
+
// Check if we have a valid cached result first (fast path)
|
|
147
|
+
const cached = getCachedPatternInfo();
|
|
148
|
+
if (cached) {
|
|
149
|
+
// If local matches latest, nothing to do
|
|
150
|
+
if (localVersion === cached.latestVersion) return;
|
|
151
|
+
// If we know there's an update but haven't updated yet, do it now
|
|
152
|
+
if (localVersion !== cached.latestVersion) {
|
|
153
|
+
await performPatternUpdate(cached.latestVersion);
|
|
154
|
+
}
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Fetch from server to check for updates (with timeout)
|
|
159
|
+
try {
|
|
160
|
+
const controller = new AbortController();
|
|
161
|
+
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
162
|
+
|
|
163
|
+
const apiUrl = getApiUrl();
|
|
164
|
+
const apiKey = getApiKey();
|
|
165
|
+
const trial = getTrialState();
|
|
166
|
+
|
|
167
|
+
// Build authorization header
|
|
168
|
+
let authHeader = '';
|
|
169
|
+
if (apiKey) {
|
|
170
|
+
authHeader = `Bearer ${apiKey}`;
|
|
171
|
+
} else if (trial?.trialId) {
|
|
172
|
+
authHeader = `Trial ${trial.trialId}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!authHeader) return;
|
|
176
|
+
|
|
177
|
+
// First, check the version endpoint (lightweight)
|
|
178
|
+
const versionResponse = await fetch(`${apiUrl}/api/content/version`, {
|
|
179
|
+
method: 'GET',
|
|
180
|
+
headers: {
|
|
181
|
+
'Authorization': authHeader,
|
|
182
|
+
},
|
|
183
|
+
signal: controller.signal,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
clearTimeout(timeout);
|
|
187
|
+
|
|
188
|
+
if (versionResponse.ok) {
|
|
189
|
+
const versionData = await versionResponse.json();
|
|
190
|
+
const serverVersion = versionData.version;
|
|
191
|
+
|
|
192
|
+
// Cache the version info
|
|
193
|
+
setCachedPatternInfo(serverVersion);
|
|
194
|
+
|
|
195
|
+
// If local version is different, update
|
|
196
|
+
if (localVersion !== serverVersion) {
|
|
197
|
+
await performPatternUpdate(serverVersion);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} catch {
|
|
201
|
+
// Silently fail - don't block CLI for pattern check
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function performPatternUpdate(targetVersion: string): Promise<void> {
|
|
206
|
+
const cwd = process.cwd();
|
|
207
|
+
const claudeMdPath = join(cwd, 'CLAUDE.md');
|
|
208
|
+
const claudeDir = join(cwd, '.claude');
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const apiUrl = getApiUrl();
|
|
212
|
+
const apiKey = getApiKey();
|
|
213
|
+
const trial = getTrialState();
|
|
214
|
+
|
|
215
|
+
let authHeader = '';
|
|
216
|
+
if (apiKey) {
|
|
217
|
+
authHeader = `Bearer ${apiKey}`;
|
|
218
|
+
} else if (trial?.trialId) {
|
|
219
|
+
authHeader = `Trial ${trial.trialId}`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!authHeader) return;
|
|
223
|
+
|
|
224
|
+
const controller = new AbortController();
|
|
225
|
+
const timeout = setTimeout(() => controller.abort(), 10000);
|
|
226
|
+
|
|
227
|
+
const response = await fetch(`${apiUrl}/api/content`, {
|
|
228
|
+
method: 'GET',
|
|
229
|
+
headers: {
|
|
230
|
+
'Authorization': authHeader,
|
|
231
|
+
},
|
|
232
|
+
signal: controller.signal,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
clearTimeout(timeout);
|
|
236
|
+
|
|
237
|
+
if (!response.ok) return;
|
|
238
|
+
|
|
239
|
+
const content: ContentResponse = await response.json();
|
|
240
|
+
|
|
241
|
+
// Update CLAUDE.md
|
|
242
|
+
if (content.router) {
|
|
243
|
+
writeFileSync(claudeMdPath, content.router);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Update pattern modules
|
|
247
|
+
if (content.modules && Object.keys(content.modules).length > 0) {
|
|
248
|
+
if (!existsSync(claudeDir)) {
|
|
249
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
for (const [name, data] of Object.entries(content.modules)) {
|
|
253
|
+
writeFileSync(join(claudeDir, name), data);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Write version file
|
|
258
|
+
const moduleCount = Object.keys(content.modules || {}).length;
|
|
259
|
+
const versionInfo: PatternVersionInfo = {
|
|
260
|
+
version: content.version,
|
|
261
|
+
moduleCount,
|
|
262
|
+
updatedAt: new Date().toISOString(),
|
|
263
|
+
cliVersion: getCliVersion(),
|
|
264
|
+
};
|
|
265
|
+
writeFileSync(join(claudeDir, '.version.json'), JSON.stringify(versionInfo, null, 2));
|
|
266
|
+
|
|
267
|
+
// Show subtle notification
|
|
268
|
+
console.log(chalk.green(` ✓ Patterns auto-updated to v${content.version} (${moduleCount} modules)\n`));
|
|
269
|
+
|
|
270
|
+
} catch {
|
|
271
|
+
// Silently fail - don't block the user
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
81
275
|
// Show welcome message when no command is provided
|
|
82
276
|
function showWelcome(): void {
|
|
83
277
|
console.log(chalk.blue(`
|
|
@@ -127,7 +321,7 @@ const program = new Command();
|
|
|
127
321
|
program
|
|
128
322
|
.name('codebakers')
|
|
129
323
|
.description('CodeBakers CLI - Production patterns for AI-assisted development')
|
|
130
|
-
.version('3.
|
|
324
|
+
.version('3.3.0');
|
|
131
325
|
|
|
132
326
|
// Zero-friction trial entry (no signup required)
|
|
133
327
|
program
|
|
@@ -282,7 +476,11 @@ program
|
|
|
282
476
|
|
|
283
477
|
// Add update check hook (runs before every command)
|
|
284
478
|
program.hook('preAction', async () => {
|
|
285
|
-
|
|
479
|
+
// Run CLI update check and pattern auto-update in parallel
|
|
480
|
+
await Promise.all([
|
|
481
|
+
checkForUpdatesInBackground(),
|
|
482
|
+
autoUpdatePatterns(),
|
|
483
|
+
]);
|
|
286
484
|
});
|
|
287
485
|
|
|
288
486
|
// Show welcome if no command provided
|
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/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,15 @@ 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
|
+
},
|
|
987
1036
|
],
|
|
988
1037
|
}));
|
|
989
1038
|
|
|
@@ -1111,6 +1160,9 @@ class CodeBakersServer {
|
|
|
1111
1160
|
case 'add_api_route':
|
|
1112
1161
|
return this.handleAddApiRoute(args as { request: string });
|
|
1113
1162
|
|
|
1163
|
+
case 'check_update_notification':
|
|
1164
|
+
return this.handleCheckUpdateNotification();
|
|
1165
|
+
|
|
1114
1166
|
default:
|
|
1115
1167
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
1116
1168
|
}
|
|
@@ -4839,6 +4891,44 @@ export default ${asyncKeyword}function ${pageName}Page() {${authCheck}
|
|
|
4839
4891
|
};
|
|
4840
4892
|
}
|
|
4841
4893
|
|
|
4894
|
+
/**
|
|
4895
|
+
* Check for update notifications and return message to show user
|
|
4896
|
+
*/
|
|
4897
|
+
private async handleCheckUpdateNotification() {
|
|
4898
|
+
const cwd = process.cwd();
|
|
4899
|
+
const notificationPath = path.join(cwd, '.claude', '.update-notification.json');
|
|
4900
|
+
|
|
4901
|
+
try {
|
|
4902
|
+
if (!fs.existsSync(notificationPath)) {
|
|
4903
|
+
return {
|
|
4904
|
+
content: [{
|
|
4905
|
+
type: 'text' as const,
|
|
4906
|
+
text: 'No update notification.',
|
|
4907
|
+
}],
|
|
4908
|
+
};
|
|
4909
|
+
}
|
|
4910
|
+
|
|
4911
|
+
const notification = JSON.parse(fs.readFileSync(notificationPath, 'utf-8'));
|
|
4912
|
+
|
|
4913
|
+
// Delete the notification file after reading (so it only shows once)
|
|
4914
|
+
fs.unlinkSync(notificationPath);
|
|
4915
|
+
|
|
4916
|
+
return {
|
|
4917
|
+
content: [{
|
|
4918
|
+
type: 'text' as const,
|
|
4919
|
+
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()}`,
|
|
4920
|
+
}],
|
|
4921
|
+
};
|
|
4922
|
+
} catch {
|
|
4923
|
+
return {
|
|
4924
|
+
content: [{
|
|
4925
|
+
type: 'text' as const,
|
|
4926
|
+
text: 'No update notification.',
|
|
4927
|
+
}],
|
|
4928
|
+
};
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4931
|
+
|
|
4842
4932
|
private parseApiRouteRequest(request: string): {
|
|
4843
4933
|
success: boolean;
|
|
4844
4934
|
routeName?: string;
|