@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/dist/commands/go.js
CHANGED
|
@@ -24,6 +24,43 @@ function prompt(question) {
|
|
|
24
24
|
});
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Get CLI version from package.json
|
|
29
|
+
*/
|
|
30
|
+
function getCliVersion() {
|
|
31
|
+
try {
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
33
|
+
const pkg = require('../../package.json');
|
|
34
|
+
return pkg.version || '0.0.0';
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return '0.0.0';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Confirm download to server (non-blocking, fire-and-forget)
|
|
42
|
+
*/
|
|
43
|
+
async function confirmDownload(apiUrl, auth, data) {
|
|
44
|
+
try {
|
|
45
|
+
const headers = {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
};
|
|
48
|
+
if (auth.apiKey) {
|
|
49
|
+
headers['Authorization'] = `Bearer ${auth.apiKey}`;
|
|
50
|
+
}
|
|
51
|
+
if (auth.trialId) {
|
|
52
|
+
headers['X-Trial-ID'] = auth.trialId;
|
|
53
|
+
}
|
|
54
|
+
await fetch(`${apiUrl}/api/content/confirm`, {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers,
|
|
57
|
+
body: JSON.stringify(data),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Silently ignore - this is just for analytics
|
|
62
|
+
}
|
|
63
|
+
}
|
|
27
64
|
function log(message, options) {
|
|
28
65
|
if (options?.verbose) {
|
|
29
66
|
console.log(chalk_1.default.gray(` [verbose] ${message}`));
|
|
@@ -264,7 +301,7 @@ async function installPatternsWithApiKey(apiKey, options = {}) {
|
|
|
264
301
|
log('Response OK, parsing JSON...', options);
|
|
265
302
|
const content = await response.json();
|
|
266
303
|
log(`Received version: ${content.version}, modules: ${Object.keys(content.modules || {}).length}`, options);
|
|
267
|
-
await writePatternFiles(cwd, content, spinner, options);
|
|
304
|
+
await writePatternFiles(cwd, content, spinner, options, { apiKey });
|
|
268
305
|
}
|
|
269
306
|
catch (error) {
|
|
270
307
|
log(`Error: ${error instanceof Error ? error.message : String(error)}`, options);
|
|
@@ -305,12 +342,12 @@ async function installPatterns(trialId, options = {}) {
|
|
|
305
342
|
}
|
|
306
343
|
const content = await publicResponse.json();
|
|
307
344
|
log(`Received version: ${content.version}, modules: ${Object.keys(content.modules || {}).length}`, options);
|
|
308
|
-
await writePatternFiles(cwd, content, spinner, options);
|
|
345
|
+
await writePatternFiles(cwd, content, spinner, options, { trialId });
|
|
309
346
|
return;
|
|
310
347
|
}
|
|
311
348
|
const content = await response.json();
|
|
312
349
|
log(`Received version: ${content.version}, modules: ${Object.keys(content.modules || {}).length}`, options);
|
|
313
|
-
await writePatternFiles(cwd, content, spinner, options);
|
|
350
|
+
await writePatternFiles(cwd, content, spinner, options, { trialId });
|
|
314
351
|
}
|
|
315
352
|
catch (error) {
|
|
316
353
|
log(`Error: ${error instanceof Error ? error.message : String(error)}`, options);
|
|
@@ -318,7 +355,7 @@ async function installPatterns(trialId, options = {}) {
|
|
|
318
355
|
console.log(chalk_1.default.gray(' Patterns will be available via MCP tools.\n'));
|
|
319
356
|
}
|
|
320
357
|
}
|
|
321
|
-
async function writePatternFiles(cwd, content, spinner, options = {}) {
|
|
358
|
+
async function writePatternFiles(cwd, content, spinner, options = {}, auth) {
|
|
322
359
|
log(`Writing pattern files to ${cwd}...`, options);
|
|
323
360
|
// Check if patterns already exist
|
|
324
361
|
const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
|
|
@@ -331,7 +368,8 @@ async function writePatternFiles(cwd, content, spinner, options = {}) {
|
|
|
331
368
|
(0, fs_1.writeFileSync)(claudeMdPath, content.router);
|
|
332
369
|
}
|
|
333
370
|
// Write pattern modules to .claude/
|
|
334
|
-
|
|
371
|
+
const moduleCount = Object.keys(content.modules || {}).length;
|
|
372
|
+
if (content.modules && moduleCount > 0) {
|
|
335
373
|
const modulesDir = (0, path_1.join)(cwd, '.claude');
|
|
336
374
|
if (!(0, fs_1.existsSync)(modulesDir)) {
|
|
337
375
|
(0, fs_1.mkdirSync)(modulesDir, { recursive: true });
|
|
@@ -350,5 +388,15 @@ async function writePatternFiles(cwd, content, spinner, options = {}) {
|
|
|
350
388
|
}
|
|
351
389
|
}
|
|
352
390
|
spinner.succeed(`CodeBakers patterns installed (v${content.version})`);
|
|
353
|
-
console.log(chalk_1.default.gray(` ${
|
|
391
|
+
console.log(chalk_1.default.gray(` ${moduleCount} pattern modules ready\n`));
|
|
392
|
+
// Confirm download to server (non-blocking)
|
|
393
|
+
if (auth) {
|
|
394
|
+
const apiUrl = (0, config_js_1.getApiUrl)();
|
|
395
|
+
confirmDownload(apiUrl, auth, {
|
|
396
|
+
version: content.version,
|
|
397
|
+
moduleCount,
|
|
398
|
+
cliVersion: getCliVersion(),
|
|
399
|
+
command: 'go',
|
|
400
|
+
}).catch(() => { }); // Silently ignore
|
|
401
|
+
}
|
|
354
402
|
}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -10,6 +10,24 @@ 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
|
+
/**
|
|
14
|
+
* Confirm download to server (non-blocking, fire-and-forget)
|
|
15
|
+
*/
|
|
16
|
+
async function confirmDownload(apiUrl, apiKey, data) {
|
|
17
|
+
try {
|
|
18
|
+
await fetch(`${apiUrl}/api/content/confirm`, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify(data),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Silently ignore - this is just for analytics
|
|
29
|
+
}
|
|
30
|
+
}
|
|
13
31
|
/**
|
|
14
32
|
* Upgrade CodeBakers patterns to the latest version
|
|
15
33
|
*/
|
|
@@ -83,6 +101,13 @@ async function upgrade() {
|
|
|
83
101
|
};
|
|
84
102
|
(0, fs_1.writeFileSync)((0, path_1.join)(claudeDir, '.version.json'), JSON.stringify(versionInfo, null, 2));
|
|
85
103
|
console.log(chalk_1.default.green(' ✓ Version info saved'));
|
|
104
|
+
// Confirm download to server (non-blocking)
|
|
105
|
+
confirmDownload(apiUrl, apiKey, {
|
|
106
|
+
version: content.version,
|
|
107
|
+
moduleCount,
|
|
108
|
+
cliVersion: (0, api_js_1.getCliVersion)(),
|
|
109
|
+
command: 'upgrade',
|
|
110
|
+
}).catch(() => { }); // Silently ignore confirmation failures
|
|
86
111
|
console.log(chalk_1.default.green(`\n ✅ Upgraded to patterns v${content.version}!\n`));
|
|
87
112
|
// Show what's new if available
|
|
88
113
|
console.log(chalk_1.default.gray(' Changes take effect in your next AI session.\n'));
|
package/dist/config.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ interface ConfigSchema {
|
|
|
45
45
|
trial: TrialState | null;
|
|
46
46
|
lastUpdateCheck: string | null;
|
|
47
47
|
latestKnownVersion: string | null;
|
|
48
|
+
lastPatternCheck: string | null;
|
|
49
|
+
latestPatternVersion: string | null;
|
|
48
50
|
}
|
|
49
51
|
export declare function getApiKey(): string | null;
|
|
50
52
|
export declare function setApiKey(key: string): void;
|
|
@@ -122,4 +124,19 @@ export declare function setCachedUpdateInfo(latestVersion: string): void;
|
|
|
122
124
|
* Get the current CLI version from package.json
|
|
123
125
|
*/
|
|
124
126
|
export declare function getCliVersion(): string;
|
|
127
|
+
/**
|
|
128
|
+
* Get cached pattern version info if still valid (within 6 hours)
|
|
129
|
+
*/
|
|
130
|
+
export declare function getCachedPatternInfo(): {
|
|
131
|
+
latestVersion: string;
|
|
132
|
+
checkedAt: string;
|
|
133
|
+
} | null;
|
|
134
|
+
/**
|
|
135
|
+
* Cache the latest pattern version from server
|
|
136
|
+
*/
|
|
137
|
+
export declare function setCachedPatternInfo(latestVersion: string): void;
|
|
138
|
+
/**
|
|
139
|
+
* Clear pattern cache to force a fresh check
|
|
140
|
+
*/
|
|
141
|
+
export declare function clearPatternCache(): void;
|
|
125
142
|
export {};
|
package/dist/config.js
CHANGED
|
@@ -35,6 +35,9 @@ exports.getAuthMode = getAuthMode;
|
|
|
35
35
|
exports.getCachedUpdateInfo = getCachedUpdateInfo;
|
|
36
36
|
exports.setCachedUpdateInfo = setCachedUpdateInfo;
|
|
37
37
|
exports.getCliVersion = getCliVersion;
|
|
38
|
+
exports.getCachedPatternInfo = getCachedPatternInfo;
|
|
39
|
+
exports.setCachedPatternInfo = setCachedPatternInfo;
|
|
40
|
+
exports.clearPatternCache = clearPatternCache;
|
|
38
41
|
const conf_1 = __importDefault(require("conf"));
|
|
39
42
|
const fs_1 = require("fs");
|
|
40
43
|
const path_1 = require("path");
|
|
@@ -121,7 +124,7 @@ exports.PROVISIONABLE_KEYS = ['github', 'supabase', 'vercel'];
|
|
|
121
124
|
const defaultServiceKeys = Object.fromEntries(exports.SERVICE_KEYS.map(key => [key, null]));
|
|
122
125
|
const config = new conf_1.default({
|
|
123
126
|
projectName: 'codebakers',
|
|
124
|
-
projectVersion: '1.
|
|
127
|
+
projectVersion: '1.9.0',
|
|
125
128
|
defaults: {
|
|
126
129
|
apiKey: null,
|
|
127
130
|
apiUrl: 'https://codebakers.ai',
|
|
@@ -131,6 +134,8 @@ const config = new conf_1.default({
|
|
|
131
134
|
trial: null,
|
|
132
135
|
lastUpdateCheck: null,
|
|
133
136
|
latestKnownVersion: null,
|
|
137
|
+
lastPatternCheck: null,
|
|
138
|
+
latestPatternVersion: null,
|
|
134
139
|
},
|
|
135
140
|
// Migration to add new keys when upgrading from old version
|
|
136
141
|
migrations: {
|
|
@@ -151,6 +156,15 @@ const config = new conf_1.default({
|
|
|
151
156
|
store.set('trial', null);
|
|
152
157
|
}
|
|
153
158
|
},
|
|
159
|
+
'1.9.0': (store) => {
|
|
160
|
+
// Add pattern auto-update fields if not present
|
|
161
|
+
if (!store.has('lastPatternCheck')) {
|
|
162
|
+
store.set('lastPatternCheck', null);
|
|
163
|
+
}
|
|
164
|
+
if (!store.has('latestPatternVersion')) {
|
|
165
|
+
store.set('latestPatternVersion', null);
|
|
166
|
+
}
|
|
167
|
+
},
|
|
154
168
|
},
|
|
155
169
|
});
|
|
156
170
|
// ============================================================
|
|
@@ -444,5 +458,36 @@ function setCachedUpdateInfo(latestVersion) {
|
|
|
444
458
|
* Get the current CLI version from package.json
|
|
445
459
|
*/
|
|
446
460
|
function getCliVersion() {
|
|
447
|
-
return '3.
|
|
461
|
+
return '3.3.0'; // Keep in sync with package.json
|
|
462
|
+
}
|
|
463
|
+
// ============================================
|
|
464
|
+
// Pattern Auto-Update Cache
|
|
465
|
+
// ============================================
|
|
466
|
+
const PATTERN_CHECK_INTERVAL_HOURS = 6; // Check more frequently than CLI
|
|
467
|
+
/**
|
|
468
|
+
* Get cached pattern version info if still valid (within 6 hours)
|
|
469
|
+
*/
|
|
470
|
+
function getCachedPatternInfo() {
|
|
471
|
+
const lastCheck = config.get('lastPatternCheck');
|
|
472
|
+
const latestVersion = config.get('latestPatternVersion');
|
|
473
|
+
if (!lastCheck || !latestVersion)
|
|
474
|
+
return null;
|
|
475
|
+
const hoursSinceCheck = (Date.now() - new Date(lastCheck).getTime()) / (1000 * 60 * 60);
|
|
476
|
+
if (hoursSinceCheck > PATTERN_CHECK_INTERVAL_HOURS)
|
|
477
|
+
return null;
|
|
478
|
+
return { latestVersion, checkedAt: lastCheck };
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Cache the latest pattern version from server
|
|
482
|
+
*/
|
|
483
|
+
function setCachedPatternInfo(latestVersion) {
|
|
484
|
+
config.set('lastPatternCheck', new Date().toISOString());
|
|
485
|
+
config.set('latestPatternVersion', latestVersion);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Clear pattern cache to force a fresh check
|
|
489
|
+
*/
|
|
490
|
+
function clearPatternCache() {
|
|
491
|
+
config.set('lastPatternCheck', null);
|
|
492
|
+
config.set('latestPatternVersion', null);
|
|
448
493
|
}
|
package/dist/index.js
CHANGED
|
@@ -27,34 +27,39 @@ const go_js_1 = require("./commands/go.js");
|
|
|
27
27
|
const extend_js_1 = require("./commands/extend.js");
|
|
28
28
|
const billing_js_1 = require("./commands/billing.js");
|
|
29
29
|
const config_js_2 = require("./config.js");
|
|
30
|
+
const api_js_1 = require("./lib/api.js");
|
|
31
|
+
const fs_1 = require("fs");
|
|
32
|
+
const path_1 = require("path");
|
|
30
33
|
// ============================================
|
|
31
34
|
// Automatic Update Notification
|
|
32
35
|
// ============================================
|
|
33
|
-
const CURRENT_VERSION = '3.
|
|
36
|
+
const CURRENT_VERSION = '3.3.1';
|
|
34
37
|
async function checkForUpdatesInBackground() {
|
|
35
38
|
// Check if we have a valid cached result first (fast path)
|
|
36
39
|
const cached = (0, config_js_2.getCachedUpdateInfo)();
|
|
37
40
|
if (cached) {
|
|
38
41
|
if (cached.latestVersion !== CURRENT_VERSION) {
|
|
39
|
-
showUpdateBanner(CURRENT_VERSION, cached.latestVersion);
|
|
42
|
+
showUpdateBanner(CURRENT_VERSION, cached.latestVersion, false);
|
|
40
43
|
}
|
|
41
44
|
return;
|
|
42
45
|
}
|
|
43
|
-
//
|
|
46
|
+
// Use the API-based version check (with controlled rollout support)
|
|
44
47
|
try {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
const updateInfo = await (0, api_js_1.checkForUpdates)();
|
|
49
|
+
if (updateInfo) {
|
|
50
|
+
(0, config_js_2.setCachedUpdateInfo)(updateInfo.latestVersion);
|
|
51
|
+
// Show blocked version warning first (critical)
|
|
52
|
+
if (updateInfo.isBlocked) {
|
|
53
|
+
showBlockedVersionWarning(updateInfo.currentVersion, updateInfo.latestVersion);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Only show update banner if auto-update is enabled for this version
|
|
57
|
+
if (updateInfo.autoUpdateEnabled && updateInfo.autoUpdateVersion) {
|
|
58
|
+
showUpdateBanner(updateInfo.currentVersion, updateInfo.autoUpdateVersion, true);
|
|
59
|
+
}
|
|
60
|
+
else if (updateInfo.updateAvailable) {
|
|
61
|
+
// Update available but not auto-update enabled - show regular banner
|
|
62
|
+
showUpdateBanner(updateInfo.currentVersion, updateInfo.latestVersion, false);
|
|
58
63
|
}
|
|
59
64
|
}
|
|
60
65
|
}
|
|
@@ -62,17 +67,170 @@ async function checkForUpdatesInBackground() {
|
|
|
62
67
|
// Silently fail - don't block CLI for update check
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
|
-
function
|
|
70
|
+
function showBlockedVersionWarning(currentVersion, recommendedVersion) {
|
|
71
|
+
console.log(chalk_1.default.red(`
|
|
72
|
+
╭─────────────────────────────────────────────────────────╮
|
|
73
|
+
│ │
|
|
74
|
+
│ ${chalk_1.default.bold('⚠️ VERSION BLOCKED')} │
|
|
75
|
+
│ │
|
|
76
|
+
│ Your CLI version ${chalk_1.default.gray(currentVersion)} has critical issues. │
|
|
77
|
+
│ Please update immediately to ${chalk_1.default.green(recommendedVersion)} │
|
|
78
|
+
│ │
|
|
79
|
+
│ Run ${chalk_1.default.cyan('npm i -g @codebakers/cli@latest')} to update │
|
|
80
|
+
│ │
|
|
81
|
+
╰─────────────────────────────────────────────────────────╯
|
|
82
|
+
`));
|
|
83
|
+
}
|
|
84
|
+
function showUpdateBanner(currentVersion, latestVersion, isRecommended) {
|
|
85
|
+
const updateType = isRecommended ? chalk_1.default.green('Recommended update') : chalk_1.default.bold('Update available!');
|
|
66
86
|
console.log(chalk_1.default.yellow(`
|
|
67
87
|
╭─────────────────────────────────────────────────────────╮
|
|
68
88
|
│ │
|
|
69
|
-
│ ${
|
|
89
|
+
│ ${updateType} ${chalk_1.default.gray(currentVersion)} → ${chalk_1.default.green(latestVersion)} │
|
|
70
90
|
│ │
|
|
71
91
|
│ Run ${chalk_1.default.cyan('npm i -g @codebakers/cli@latest')} to update │
|
|
72
92
|
│ │
|
|
73
93
|
╰─────────────────────────────────────────────────────────╯
|
|
74
94
|
`));
|
|
75
95
|
}
|
|
96
|
+
function getLocalPatternVersion() {
|
|
97
|
+
const cwd = process.cwd();
|
|
98
|
+
const versionFile = (0, path_1.join)(cwd, '.claude', '.version.json');
|
|
99
|
+
if (!(0, fs_1.existsSync)(versionFile))
|
|
100
|
+
return null;
|
|
101
|
+
try {
|
|
102
|
+
const content = (0, fs_1.readFileSync)(versionFile, 'utf-8');
|
|
103
|
+
const info = JSON.parse(content);
|
|
104
|
+
return info.version;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function isCodeBakersProject() {
|
|
111
|
+
const cwd = process.cwd();
|
|
112
|
+
return (0, fs_1.existsSync)((0, path_1.join)(cwd, 'CLAUDE.md')) || (0, fs_1.existsSync)((0, path_1.join)(cwd, '.claude'));
|
|
113
|
+
}
|
|
114
|
+
async function autoUpdatePatterns() {
|
|
115
|
+
// Only auto-update if this is a CodeBakers project
|
|
116
|
+
if (!isCodeBakersProject())
|
|
117
|
+
return;
|
|
118
|
+
// Only auto-update if user has valid access
|
|
119
|
+
if (!(0, config_js_2.hasValidAccess)())
|
|
120
|
+
return;
|
|
121
|
+
const localVersion = getLocalPatternVersion();
|
|
122
|
+
// Check if we have a valid cached result first (fast path)
|
|
123
|
+
const cached = (0, config_js_2.getCachedPatternInfo)();
|
|
124
|
+
if (cached) {
|
|
125
|
+
// If local matches latest, nothing to do
|
|
126
|
+
if (localVersion === cached.latestVersion)
|
|
127
|
+
return;
|
|
128
|
+
// If we know there's an update but haven't updated yet, do it now
|
|
129
|
+
if (localVersion !== cached.latestVersion) {
|
|
130
|
+
await performPatternUpdate(cached.latestVersion);
|
|
131
|
+
}
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// Fetch from server to check for updates (with timeout)
|
|
135
|
+
try {
|
|
136
|
+
const controller = new AbortController();
|
|
137
|
+
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
138
|
+
const apiUrl = (0, config_js_2.getApiUrl)();
|
|
139
|
+
const apiKey = (0, config_js_2.getApiKey)();
|
|
140
|
+
const trial = (0, config_js_2.getTrialState)();
|
|
141
|
+
// Build authorization header
|
|
142
|
+
let authHeader = '';
|
|
143
|
+
if (apiKey) {
|
|
144
|
+
authHeader = `Bearer ${apiKey}`;
|
|
145
|
+
}
|
|
146
|
+
else if (trial?.trialId) {
|
|
147
|
+
authHeader = `Trial ${trial.trialId}`;
|
|
148
|
+
}
|
|
149
|
+
if (!authHeader)
|
|
150
|
+
return;
|
|
151
|
+
// First, check the version endpoint (lightweight)
|
|
152
|
+
const versionResponse = await fetch(`${apiUrl}/api/content/version`, {
|
|
153
|
+
method: 'GET',
|
|
154
|
+
headers: {
|
|
155
|
+
'Authorization': authHeader,
|
|
156
|
+
},
|
|
157
|
+
signal: controller.signal,
|
|
158
|
+
});
|
|
159
|
+
clearTimeout(timeout);
|
|
160
|
+
if (versionResponse.ok) {
|
|
161
|
+
const versionData = await versionResponse.json();
|
|
162
|
+
const serverVersion = versionData.version;
|
|
163
|
+
// Cache the version info
|
|
164
|
+
(0, config_js_2.setCachedPatternInfo)(serverVersion);
|
|
165
|
+
// If local version is different, update
|
|
166
|
+
if (localVersion !== serverVersion) {
|
|
167
|
+
await performPatternUpdate(serverVersion);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// Silently fail - don't block CLI for pattern check
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async function performPatternUpdate(targetVersion) {
|
|
176
|
+
const cwd = process.cwd();
|
|
177
|
+
const claudeMdPath = (0, path_1.join)(cwd, 'CLAUDE.md');
|
|
178
|
+
const claudeDir = (0, path_1.join)(cwd, '.claude');
|
|
179
|
+
try {
|
|
180
|
+
const apiUrl = (0, config_js_2.getApiUrl)();
|
|
181
|
+
const apiKey = (0, config_js_2.getApiKey)();
|
|
182
|
+
const trial = (0, config_js_2.getTrialState)();
|
|
183
|
+
let authHeader = '';
|
|
184
|
+
if (apiKey) {
|
|
185
|
+
authHeader = `Bearer ${apiKey}`;
|
|
186
|
+
}
|
|
187
|
+
else if (trial?.trialId) {
|
|
188
|
+
authHeader = `Trial ${trial.trialId}`;
|
|
189
|
+
}
|
|
190
|
+
if (!authHeader)
|
|
191
|
+
return;
|
|
192
|
+
const controller = new AbortController();
|
|
193
|
+
const timeout = setTimeout(() => controller.abort(), 10000);
|
|
194
|
+
const response = await fetch(`${apiUrl}/api/content`, {
|
|
195
|
+
method: 'GET',
|
|
196
|
+
headers: {
|
|
197
|
+
'Authorization': authHeader,
|
|
198
|
+
},
|
|
199
|
+
signal: controller.signal,
|
|
200
|
+
});
|
|
201
|
+
clearTimeout(timeout);
|
|
202
|
+
if (!response.ok)
|
|
203
|
+
return;
|
|
204
|
+
const content = await response.json();
|
|
205
|
+
// Update CLAUDE.md
|
|
206
|
+
if (content.router) {
|
|
207
|
+
(0, fs_1.writeFileSync)(claudeMdPath, content.router);
|
|
208
|
+
}
|
|
209
|
+
// Update pattern modules
|
|
210
|
+
if (content.modules && Object.keys(content.modules).length > 0) {
|
|
211
|
+
if (!(0, fs_1.existsSync)(claudeDir)) {
|
|
212
|
+
(0, fs_1.mkdirSync)(claudeDir, { recursive: true });
|
|
213
|
+
}
|
|
214
|
+
for (const [name, data] of Object.entries(content.modules)) {
|
|
215
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(claudeDir, name), data);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Write version file
|
|
219
|
+
const moduleCount = Object.keys(content.modules || {}).length;
|
|
220
|
+
const versionInfo = {
|
|
221
|
+
version: content.version,
|
|
222
|
+
moduleCount,
|
|
223
|
+
updatedAt: new Date().toISOString(),
|
|
224
|
+
cliVersion: (0, config_js_2.getCliVersion)(),
|
|
225
|
+
};
|
|
226
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(claudeDir, '.version.json'), JSON.stringify(versionInfo, null, 2));
|
|
227
|
+
// Show subtle notification
|
|
228
|
+
console.log(chalk_1.default.green(` ✓ Patterns auto-updated to v${content.version} (${moduleCount} modules)\n`));
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// Silently fail - don't block the user
|
|
232
|
+
}
|
|
233
|
+
}
|
|
76
234
|
// Show welcome message when no command is provided
|
|
77
235
|
function showWelcome() {
|
|
78
236
|
console.log(chalk_1.default.blue(`
|
|
@@ -114,7 +272,7 @@ const program = new commander_1.Command();
|
|
|
114
272
|
program
|
|
115
273
|
.name('codebakers')
|
|
116
274
|
.description('CodeBakers CLI - Production patterns for AI-assisted development')
|
|
117
|
-
.version('3.
|
|
275
|
+
.version('3.3.0');
|
|
118
276
|
// Zero-friction trial entry (no signup required)
|
|
119
277
|
program
|
|
120
278
|
.command('go')
|
|
@@ -248,7 +406,11 @@ program
|
|
|
248
406
|
.action(mcp_config_js_1.mcpUninstall);
|
|
249
407
|
// Add update check hook (runs before every command)
|
|
250
408
|
program.hook('preAction', async () => {
|
|
251
|
-
|
|
409
|
+
// Run CLI update check and pattern auto-update in parallel
|
|
410
|
+
await Promise.all([
|
|
411
|
+
checkForUpdatesInBackground(),
|
|
412
|
+
autoUpdatePatterns(),
|
|
413
|
+
]);
|
|
252
414
|
});
|
|
253
415
|
// Show welcome if no command provided
|
|
254
416
|
if (process.argv.length <= 2) {
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -37,9 +37,19 @@ export declare function checkApiKeyValidity(): Promise<{
|
|
|
37
37
|
export declare function getCliVersion(): string;
|
|
38
38
|
/**
|
|
39
39
|
* Check if there's a newer version of the CLI available
|
|
40
|
+
* Uses the CodeBakers API for controlled rollouts (only recommends stable, tested versions)
|
|
41
|
+
* Falls back to npm registry if API is unavailable
|
|
40
42
|
*/
|
|
41
43
|
export declare function checkForUpdates(): Promise<{
|
|
42
44
|
currentVersion: string;
|
|
43
45
|
latestVersion: string;
|
|
44
46
|
updateAvailable: boolean;
|
|
47
|
+
autoUpdateEnabled: boolean;
|
|
48
|
+
autoUpdateVersion: string | null;
|
|
49
|
+
isBlocked: boolean;
|
|
45
50
|
} | null>;
|
|
51
|
+
/**
|
|
52
|
+
* Report a CLI error to the server for tracking
|
|
53
|
+
* This helps identify problematic versions for blocking
|
|
54
|
+
*/
|
|
55
|
+
export declare function reportCliError(errorType: string, errorMessage: string, context?: Record<string, unknown>): Promise<void>;
|
package/dist/lib/api.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.formatApiError = formatApiError;
|
|
|
7
7
|
exports.checkApiKeyValidity = checkApiKeyValidity;
|
|
8
8
|
exports.getCliVersion = getCliVersion;
|
|
9
9
|
exports.checkForUpdates = checkForUpdates;
|
|
10
|
+
exports.reportCliError = reportCliError;
|
|
10
11
|
const config_js_1 = require("../config.js");
|
|
11
12
|
/**
|
|
12
13
|
* Validate an API key format
|
|
@@ -136,24 +137,92 @@ function getCliVersion() {
|
|
|
136
137
|
}
|
|
137
138
|
/**
|
|
138
139
|
* Check if there's a newer version of the CLI available
|
|
140
|
+
* Uses the CodeBakers API for controlled rollouts (only recommends stable, tested versions)
|
|
141
|
+
* Falls back to npm registry if API is unavailable
|
|
139
142
|
*/
|
|
140
143
|
async function checkForUpdates() {
|
|
141
144
|
try {
|
|
142
145
|
const currentVersion = getCliVersion();
|
|
143
|
-
const
|
|
146
|
+
const apiUrl = (0, config_js_1.getApiUrl)();
|
|
147
|
+
// First, try the CodeBakers API for controlled rollout info
|
|
148
|
+
try {
|
|
149
|
+
const response = await fetch(`${apiUrl}/api/cli/version`, {
|
|
150
|
+
headers: {
|
|
151
|
+
'Accept': 'application/json',
|
|
152
|
+
'X-CLI-Version': currentVersion,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
if (response.ok) {
|
|
156
|
+
const data = await response.json();
|
|
157
|
+
const latestVersion = data.stableVersion || data.latestVersion;
|
|
158
|
+
const autoUpdateVersion = data.autoUpdateVersion;
|
|
159
|
+
const isBlocked = data.isBlocked === true;
|
|
160
|
+
return {
|
|
161
|
+
currentVersion,
|
|
162
|
+
latestVersion,
|
|
163
|
+
updateAvailable: latestVersion !== currentVersion,
|
|
164
|
+
autoUpdateEnabled: data.autoUpdateEnabled === true,
|
|
165
|
+
autoUpdateVersion: autoUpdateVersion || null,
|
|
166
|
+
isBlocked,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// API unavailable, fall through to npm
|
|
172
|
+
}
|
|
173
|
+
// Fallback: check npm registry directly
|
|
174
|
+
const npmResponse = await fetch('https://registry.npmjs.org/@codebakers/cli/latest', {
|
|
144
175
|
headers: { 'Accept': 'application/json' },
|
|
145
176
|
});
|
|
146
|
-
if (!
|
|
177
|
+
if (!npmResponse.ok)
|
|
147
178
|
return null;
|
|
148
|
-
const
|
|
149
|
-
const latestVersion =
|
|
179
|
+
const npmData = await npmResponse.json();
|
|
180
|
+
const latestVersion = npmData.version;
|
|
150
181
|
return {
|
|
151
182
|
currentVersion,
|
|
152
183
|
latestVersion,
|
|
153
184
|
updateAvailable: currentVersion !== latestVersion,
|
|
185
|
+
autoUpdateEnabled: false, // npm fallback doesn't have controlled rollout
|
|
186
|
+
autoUpdateVersion: null,
|
|
187
|
+
isBlocked: false,
|
|
154
188
|
};
|
|
155
189
|
}
|
|
156
190
|
catch {
|
|
157
191
|
return null;
|
|
158
192
|
}
|
|
159
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Report a CLI error to the server for tracking
|
|
196
|
+
* This helps identify problematic versions for blocking
|
|
197
|
+
*/
|
|
198
|
+
async function reportCliError(errorType, errorMessage, context) {
|
|
199
|
+
try {
|
|
200
|
+
const apiUrl = (0, config_js_1.getApiUrl)();
|
|
201
|
+
const cliVersion = getCliVersion();
|
|
202
|
+
// Fire and forget - don't block on error reporting
|
|
203
|
+
fetch(`${apiUrl}/api/cli/error-report`, {
|
|
204
|
+
method: 'POST',
|
|
205
|
+
headers: {
|
|
206
|
+
'Content-Type': 'application/json',
|
|
207
|
+
'X-CLI-Version': cliVersion,
|
|
208
|
+
},
|
|
209
|
+
body: JSON.stringify({
|
|
210
|
+
cliVersion,
|
|
211
|
+
errorType,
|
|
212
|
+
errorMessage,
|
|
213
|
+
stackTrace: context?.stack,
|
|
214
|
+
context: JSON.stringify({
|
|
215
|
+
...context,
|
|
216
|
+
nodeVersion: process.version,
|
|
217
|
+
platform: process.platform,
|
|
218
|
+
arch: process.arch,
|
|
219
|
+
}),
|
|
220
|
+
}),
|
|
221
|
+
}).catch(() => {
|
|
222
|
+
// Ignore reporting failures
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// Never fail on error reporting
|
|
227
|
+
}
|
|
228
|
+
}
|