@codebakers/cli 3.3.1 → 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.
@@ -12,6 +12,7 @@ const os_1 = require("os");
12
12
  const install_hook_js_1 = require("./install-hook.js");
13
13
  const config_js_1 = require("../config.js");
14
14
  const api_js_1 = require("../lib/api.js");
15
+ const stats_js_1 = require("../lib/stats.js");
15
16
  /**
16
17
  * Run all health checks for CodeBakers setup
17
18
  */
@@ -118,20 +119,20 @@ function checkProject() {
118
119
  try {
119
120
  const files = (0, fs_1.readdirSync)(claudeDir).filter(f => f.endsWith('.md'));
120
121
  const moduleCount = files.length;
121
- if (moduleCount >= 40) {
122
+ if (moduleCount >= 50) {
122
123
  results.push({ ok: true, message: `${moduleCount} modules present (full set)` });
123
124
  }
124
125
  else if (moduleCount >= 10) {
125
126
  results.push({
126
127
  ok: true,
127
128
  message: `${moduleCount} modules present (partial set)`,
128
- details: 'Run: codebakers upgrade to get all 47 modules'
129
+ details: `Run: codebakers upgrade to get all ${stats_js_1.CODEBAKERS_STATS.moduleCount} modules`
129
130
  });
130
131
  }
131
132
  else if (moduleCount > 0) {
132
133
  results.push({
133
134
  ok: false,
134
- message: `Only ${moduleCount} modules found (expected 47)`,
135
+ message: `Only ${moduleCount} modules found (expected ${stats_js_1.CODEBAKERS_STATS.moduleCount})`,
135
136
  details: 'Run: codebakers upgrade to get all modules'
136
137
  });
137
138
  }
@@ -10,6 +10,7 @@ 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
+ const stats_js_1 = require("../lib/stats.js");
13
14
  async function install() {
14
15
  console.log(chalk_1.default.blue('\n CodeBakers Install\n'));
15
16
  const apiKey = (0, config_js_1.getApiKey)();
@@ -79,7 +80,7 @@ async function install() {
79
80
  if (moduleCount > 0) {
80
81
  console.log(chalk_1.default.gray(` - .claude/ (${moduleCount} pattern modules)`));
81
82
  }
82
- console.log(chalk_1.default.blue('\n Start building! Your AI now knows 114 production patterns.\n'));
83
+ console.log(chalk_1.default.blue(`\n Start building! Your AI now knows ${stats_js_1.CODEBAKERS_STATS.moduleCount} production modules.\n`));
83
84
  }
84
85
  catch (error) {
85
86
  spinner.fail('Installation failed');
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Central configuration for CodeBakers CLI stats.
3
+ * Keep in sync with server-side src/lib/stats.ts
4
+ */
5
+ export declare const CODEBAKERS_STATS: {
6
+ readonly moduleCount: 59;
7
+ readonly totalLinesDisplay: "50K+";
8
+ readonly patternCount: 150;
9
+ };
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * Central configuration for CodeBakers CLI stats.
4
+ * Keep in sync with server-side src/lib/stats.ts
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.CODEBAKERS_STATS = void 0;
8
+ exports.CODEBAKERS_STATS = {
9
+ moduleCount: 59,
10
+ totalLinesDisplay: '50K+',
11
+ patternCount: 150,
12
+ };
@@ -947,6 +947,19 @@ class CodeBakersServer {
947
947
  properties: {},
948
948
  },
949
949
  },
950
+ {
951
+ name: 'update_patterns',
952
+ description: '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.',
953
+ inputSchema: {
954
+ type: 'object',
955
+ properties: {
956
+ force: {
957
+ type: 'boolean',
958
+ description: 'Force update even if already at latest version (default: false)',
959
+ },
960
+ },
961
+ },
962
+ },
950
963
  ],
951
964
  }));
952
965
  // Handle tool calls
@@ -1034,6 +1047,8 @@ class CodeBakersServer {
1034
1047
  return this.handleAddApiRoute(args);
1035
1048
  case 'check_update_notification':
1036
1049
  return this.handleCheckUpdateNotification();
1050
+ case 'update_patterns':
1051
+ return this.handleUpdatePatterns(args);
1037
1052
  default:
1038
1053
  throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
1039
1054
  }
@@ -4532,6 +4547,137 @@ export async function POST(request: NextRequest) {
4532
4547
  ${handlers.join('\n')}
4533
4548
  `;
4534
4549
  }
4550
+ /**
4551
+ * Download and update CodeBakers patterns from server
4552
+ * This is the MCP equivalent of the `codebakers upgrade` CLI command
4553
+ */
4554
+ async handleUpdatePatterns(args) {
4555
+ const { force = false } = args;
4556
+ const cwd = process.cwd();
4557
+ const claudeMdPath = path.join(cwd, 'CLAUDE.md');
4558
+ const claudeDir = path.join(cwd, '.claude');
4559
+ const versionPath = path.join(claudeDir, '.version.json');
4560
+ let response = `# 🔄 CodeBakers Pattern Update\n\n`;
4561
+ try {
4562
+ // Check current version
4563
+ let currentVersion = null;
4564
+ let currentModuleCount = 0;
4565
+ if (fs.existsSync(versionPath)) {
4566
+ try {
4567
+ const versionInfo = JSON.parse(fs.readFileSync(versionPath, 'utf-8'));
4568
+ currentVersion = versionInfo.version;
4569
+ currentModuleCount = versionInfo.moduleCount || 0;
4570
+ }
4571
+ catch {
4572
+ // Ignore parse errors
4573
+ }
4574
+ }
4575
+ // Count current modules
4576
+ if (fs.existsSync(claudeDir)) {
4577
+ try {
4578
+ const files = fs.readdirSync(claudeDir).filter(f => f.endsWith('.md'));
4579
+ currentModuleCount = files.length;
4580
+ }
4581
+ catch {
4582
+ // Ignore read errors
4583
+ }
4584
+ }
4585
+ response += `## Current Status\n`;
4586
+ response += `- Version: ${currentVersion || 'Unknown'}\n`;
4587
+ response += `- Modules: ${currentModuleCount}\n\n`;
4588
+ // Fetch latest version info first
4589
+ const versionResponse = await fetch(`${this.apiUrl}/api/content/version`, {
4590
+ headers: this.getAuthHeaders(),
4591
+ });
4592
+ if (!versionResponse.ok) {
4593
+ throw new Error('Failed to check version from server');
4594
+ }
4595
+ const latestInfo = await versionResponse.json();
4596
+ const latestVersion = latestInfo.version;
4597
+ const latestModuleCount = latestInfo.moduleCount || 0;
4598
+ response += `## Server Status\n`;
4599
+ response += `- Latest Version: ${latestVersion}\n`;
4600
+ response += `- Available Modules: ${latestModuleCount}\n\n`;
4601
+ // Check if update needed
4602
+ const needsUpdate = force || !currentVersion || currentVersion !== latestVersion || currentModuleCount < latestModuleCount;
4603
+ if (!needsUpdate) {
4604
+ response += `✅ **Already up to date!**\n\n`;
4605
+ response += `Your patterns are current (v${latestVersion} with ${latestModuleCount} modules).\n`;
4606
+ response += `Use \`force: true\` to re-download anyway.\n`;
4607
+ return {
4608
+ content: [{
4609
+ type: 'text',
4610
+ text: response,
4611
+ }],
4612
+ };
4613
+ }
4614
+ response += `## Downloading Updates...\n\n`;
4615
+ // Fetch full content
4616
+ const contentResponse = await fetch(`${this.apiUrl}/api/content`, {
4617
+ headers: this.getAuthHeaders(),
4618
+ });
4619
+ if (!contentResponse.ok) {
4620
+ const error = await contentResponse.json().catch(() => ({}));
4621
+ throw new Error(error.error || error.message || 'Failed to fetch patterns');
4622
+ }
4623
+ const content = await contentResponse.json();
4624
+ const moduleCount = content.modules ? Object.keys(content.modules).length : 0;
4625
+ // Create .claude directory if needed
4626
+ if (!fs.existsSync(claudeDir)) {
4627
+ fs.mkdirSync(claudeDir, { recursive: true });
4628
+ response += `✓ Created .claude/ directory\n`;
4629
+ }
4630
+ // Update CLAUDE.md router
4631
+ if (content.router) {
4632
+ fs.writeFileSync(claudeMdPath, content.router);
4633
+ response += `✓ Updated CLAUDE.md (router)\n`;
4634
+ }
4635
+ // Update all modules
4636
+ if (content.modules && moduleCount > 0) {
4637
+ for (const [name, data] of Object.entries(content.modules)) {
4638
+ fs.writeFileSync(path.join(claudeDir, name), data);
4639
+ }
4640
+ response += `✓ Updated ${moduleCount} modules in .claude/\n`;
4641
+ }
4642
+ // Save version info
4643
+ const newVersionInfo = {
4644
+ version: content.version || latestVersion,
4645
+ moduleCount,
4646
+ installedAt: currentVersion ? undefined : new Date().toISOString(),
4647
+ updatedAt: new Date().toISOString(),
4648
+ cliVersion: (0, api_js_1.getCliVersion)(),
4649
+ };
4650
+ fs.writeFileSync(versionPath, JSON.stringify(newVersionInfo, null, 2));
4651
+ response += `✓ Saved version info\n`;
4652
+ // Confirm download to server (non-blocking analytics)
4653
+ this.confirmDownload(content.version || latestVersion, moduleCount).catch(() => { });
4654
+ response += `\n## ✅ Update Complete!\n\n`;
4655
+ response += `- **From:** v${currentVersion || 'none'} (${currentModuleCount} modules)\n`;
4656
+ response += `- **To:** v${content.version || latestVersion} (${moduleCount} modules)\n\n`;
4657
+ if (moduleCount > currentModuleCount) {
4658
+ response += `🆕 **${moduleCount - currentModuleCount} new modules added!**\n\n`;
4659
+ }
4660
+ response += `Your patterns are now up to date. The new patterns will be used in your next response.\n`;
4661
+ }
4662
+ catch (error) {
4663
+ const message = error instanceof Error ? error.message : 'Unknown error';
4664
+ response += `\n## ❌ Update Failed\n\n`;
4665
+ response += `Error: ${message}\n\n`;
4666
+ if (message.includes('401') || message.includes('Invalid') || message.includes('expired')) {
4667
+ response += `Your API key may be invalid or expired.\n`;
4668
+ response += `Run \`codebakers setup\` in terminal to reconfigure.\n`;
4669
+ }
4670
+ else {
4671
+ response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
4672
+ }
4673
+ }
4674
+ return {
4675
+ content: [{
4676
+ type: 'text',
4677
+ text: response,
4678
+ }],
4679
+ };
4680
+ }
4535
4681
  async run() {
4536
4682
  const transport = new stdio_js_1.StdioServerTransport();
4537
4683
  await this.server.connect(transport);
package/nul ADDED
@@ -0,0 +1 @@
1
+ vitest.config.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codebakers/cli",
3
- "version": "3.3.1",
3
+ "version": "3.3.2",
4
4
  "description": "CodeBakers CLI - Production patterns for AI-assisted development",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -5,6 +5,7 @@ import { homedir } from 'os';
5
5
  import { isHookInstalled } from './install-hook.js';
6
6
  import { getApiKey } from '../config.js';
7
7
  import { checkApiKeyValidity, checkForUpdates, getCliVersion } from '../lib/api.js';
8
+ import { CODEBAKERS_STATS } from '../lib/stats.js';
8
9
 
9
10
  interface CheckResult {
10
11
  ok: boolean;
@@ -134,18 +135,18 @@ function checkProject(): CheckResult[] {
134
135
  const files = readdirSync(claudeDir).filter(f => f.endsWith('.md'));
135
136
  const moduleCount = files.length;
136
137
 
137
- if (moduleCount >= 40) {
138
+ if (moduleCount >= 50) {
138
139
  results.push({ ok: true, message: `${moduleCount} modules present (full set)` });
139
140
  } else if (moduleCount >= 10) {
140
141
  results.push({
141
142
  ok: true,
142
143
  message: `${moduleCount} modules present (partial set)`,
143
- details: 'Run: codebakers upgrade to get all 47 modules'
144
+ details: `Run: codebakers upgrade to get all ${CODEBAKERS_STATS.moduleCount} modules`
144
145
  });
145
146
  } else if (moduleCount > 0) {
146
147
  results.push({
147
148
  ok: false,
148
- message: `Only ${moduleCount} modules found (expected 47)`,
149
+ message: `Only ${moduleCount} modules found (expected ${CODEBAKERS_STATS.moduleCount})`,
149
150
  details: 'Run: codebakers upgrade to get all modules'
150
151
  });
151
152
  } else {
@@ -4,6 +4,7 @@ import { writeFileSync, mkdirSync, existsSync } from 'fs';
4
4
  import { join } from 'path';
5
5
  import { getApiKey, getApiUrl } from '../config.js';
6
6
  import { getCliVersion } from '../lib/api.js';
7
+ import { CODEBAKERS_STATS } from '../lib/stats.js';
7
8
 
8
9
  interface ContentResponse {
9
10
  version: string;
@@ -94,7 +95,7 @@ export async function install(): Promise<void> {
94
95
  if (moduleCount > 0) {
95
96
  console.log(chalk.gray(` - .claude/ (${moduleCount} pattern modules)`));
96
97
  }
97
- console.log(chalk.blue('\n Start building! Your AI now knows 114 production patterns.\n'));
98
+ console.log(chalk.blue(`\n Start building! Your AI now knows ${CODEBAKERS_STATS.moduleCount} production modules.\n`));
98
99
  } catch (error) {
99
100
  spinner.fail('Installation failed');
100
101
  const message = error instanceof Error ? error.message : 'Unknown error';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Central configuration for CodeBakers CLI stats.
3
+ * Keep in sync with server-side src/lib/stats.ts
4
+ */
5
+
6
+ export const CODEBAKERS_STATS = {
7
+ moduleCount: 59,
8
+ totalLinesDisplay: '50K+',
9
+ patternCount: 150,
10
+ } as const;
package/src/mcp/server.ts CHANGED
@@ -1033,6 +1033,20 @@ class CodeBakersServer {
1033
1033
  properties: {},
1034
1034
  },
1035
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
+ },
1036
1050
  ],
1037
1051
  }));
1038
1052
 
@@ -1163,6 +1177,9 @@ class CodeBakersServer {
1163
1177
  case 'check_update_notification':
1164
1178
  return this.handleCheckUpdateNotification();
1165
1179
 
1180
+ case 'update_patterns':
1181
+ return this.handleUpdatePatterns(args as { force?: boolean });
1182
+
1166
1183
  default:
1167
1184
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
1168
1185
  }
@@ -5131,6 +5148,161 @@ ${handlers.join('\n')}
5131
5148
  `;
5132
5149
  }
5133
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
+
5134
5306
  async run(): Promise<void> {
5135
5307
  const transport = new StdioServerTransport();
5136
5308
  await this.server.connect(transport);