@codebakers/cli 3.3.1 → 3.3.3
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/install.js +2 -1
- package/dist/lib/stats.d.ts +9 -0
- package/dist/lib/stats.js +12 -0
- package/dist/mcp/server.js +299 -0
- package/nul +1 -0
- package/package.json +1 -1
- package/src/commands/doctor.ts +4 -3
- package/src/commands/install.ts +2 -1
- package/src/lib/stats.ts +10 -0
- package/src/mcp/server.ts +335 -0
package/dist/commands/doctor.js
CHANGED
|
@@ -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 >=
|
|
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:
|
|
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
|
|
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
|
}
|
package/dist/commands/install.js
CHANGED
|
@@ -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(
|
|
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,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
|
+
};
|
package/dist/mcp/server.js
CHANGED
|
@@ -947,6 +947,33 @@ 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
|
+
},
|
|
963
|
+
{
|
|
964
|
+
name: 'detect_intent',
|
|
965
|
+
description: 'CALL THIS FIRST when user request is ambiguous or could match multiple MCP tools. Analyzes user input and returns which MCP tool(s) would be appropriate, with explanations. Show the result to the user and ask for confirmation before executing. This prevents accidental destructive actions.',
|
|
966
|
+
inputSchema: {
|
|
967
|
+
type: 'object',
|
|
968
|
+
properties: {
|
|
969
|
+
userMessage: {
|
|
970
|
+
type: 'string',
|
|
971
|
+
description: 'The user\'s message or request to analyze',
|
|
972
|
+
},
|
|
973
|
+
},
|
|
974
|
+
required: ['userMessage'],
|
|
975
|
+
},
|
|
976
|
+
},
|
|
950
977
|
],
|
|
951
978
|
}));
|
|
952
979
|
// Handle tool calls
|
|
@@ -1034,6 +1061,10 @@ class CodeBakersServer {
|
|
|
1034
1061
|
return this.handleAddApiRoute(args);
|
|
1035
1062
|
case 'check_update_notification':
|
|
1036
1063
|
return this.handleCheckUpdateNotification();
|
|
1064
|
+
case 'update_patterns':
|
|
1065
|
+
return this.handleUpdatePatterns(args);
|
|
1066
|
+
case 'detect_intent':
|
|
1067
|
+
return this.handleDetectIntent(args);
|
|
1037
1068
|
default:
|
|
1038
1069
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
1039
1070
|
}
|
|
@@ -4532,6 +4563,274 @@ export async function POST(request: NextRequest) {
|
|
|
4532
4563
|
${handlers.join('\n')}
|
|
4533
4564
|
`;
|
|
4534
4565
|
}
|
|
4566
|
+
/**
|
|
4567
|
+
* Download and update CodeBakers patterns from server
|
|
4568
|
+
* This is the MCP equivalent of the `codebakers upgrade` CLI command
|
|
4569
|
+
*/
|
|
4570
|
+
async handleUpdatePatterns(args) {
|
|
4571
|
+
const { force = false } = args;
|
|
4572
|
+
const cwd = process.cwd();
|
|
4573
|
+
const claudeMdPath = path.join(cwd, 'CLAUDE.md');
|
|
4574
|
+
const claudeDir = path.join(cwd, '.claude');
|
|
4575
|
+
const versionPath = path.join(claudeDir, '.version.json');
|
|
4576
|
+
let response = `# 🔄 CodeBakers Pattern Update\n\n`;
|
|
4577
|
+
try {
|
|
4578
|
+
// Check current version
|
|
4579
|
+
let currentVersion = null;
|
|
4580
|
+
let currentModuleCount = 0;
|
|
4581
|
+
if (fs.existsSync(versionPath)) {
|
|
4582
|
+
try {
|
|
4583
|
+
const versionInfo = JSON.parse(fs.readFileSync(versionPath, 'utf-8'));
|
|
4584
|
+
currentVersion = versionInfo.version;
|
|
4585
|
+
currentModuleCount = versionInfo.moduleCount || 0;
|
|
4586
|
+
}
|
|
4587
|
+
catch {
|
|
4588
|
+
// Ignore parse errors
|
|
4589
|
+
}
|
|
4590
|
+
}
|
|
4591
|
+
// Count current modules
|
|
4592
|
+
if (fs.existsSync(claudeDir)) {
|
|
4593
|
+
try {
|
|
4594
|
+
const files = fs.readdirSync(claudeDir).filter(f => f.endsWith('.md'));
|
|
4595
|
+
currentModuleCount = files.length;
|
|
4596
|
+
}
|
|
4597
|
+
catch {
|
|
4598
|
+
// Ignore read errors
|
|
4599
|
+
}
|
|
4600
|
+
}
|
|
4601
|
+
response += `## Current Status\n`;
|
|
4602
|
+
response += `- Version: ${currentVersion || 'Unknown'}\n`;
|
|
4603
|
+
response += `- Modules: ${currentModuleCount}\n\n`;
|
|
4604
|
+
// Fetch latest version info first
|
|
4605
|
+
const versionResponse = await fetch(`${this.apiUrl}/api/content/version`, {
|
|
4606
|
+
headers: this.getAuthHeaders(),
|
|
4607
|
+
});
|
|
4608
|
+
if (!versionResponse.ok) {
|
|
4609
|
+
throw new Error('Failed to check version from server');
|
|
4610
|
+
}
|
|
4611
|
+
const latestInfo = await versionResponse.json();
|
|
4612
|
+
const latestVersion = latestInfo.version;
|
|
4613
|
+
const latestModuleCount = latestInfo.moduleCount || 0;
|
|
4614
|
+
response += `## Server Status\n`;
|
|
4615
|
+
response += `- Latest Version: ${latestVersion}\n`;
|
|
4616
|
+
response += `- Available Modules: ${latestModuleCount}\n\n`;
|
|
4617
|
+
// Check if update needed
|
|
4618
|
+
const needsUpdate = force || !currentVersion || currentVersion !== latestVersion || currentModuleCount < latestModuleCount;
|
|
4619
|
+
if (!needsUpdate) {
|
|
4620
|
+
response += `✅ **Already up to date!**\n\n`;
|
|
4621
|
+
response += `Your patterns are current (v${latestVersion} with ${latestModuleCount} modules).\n`;
|
|
4622
|
+
response += `Use \`force: true\` to re-download anyway.\n`;
|
|
4623
|
+
return {
|
|
4624
|
+
content: [{
|
|
4625
|
+
type: 'text',
|
|
4626
|
+
text: response,
|
|
4627
|
+
}],
|
|
4628
|
+
};
|
|
4629
|
+
}
|
|
4630
|
+
response += `## Downloading Updates...\n\n`;
|
|
4631
|
+
// Fetch full content
|
|
4632
|
+
const contentResponse = await fetch(`${this.apiUrl}/api/content`, {
|
|
4633
|
+
headers: this.getAuthHeaders(),
|
|
4634
|
+
});
|
|
4635
|
+
if (!contentResponse.ok) {
|
|
4636
|
+
const error = await contentResponse.json().catch(() => ({}));
|
|
4637
|
+
throw new Error(error.error || error.message || 'Failed to fetch patterns');
|
|
4638
|
+
}
|
|
4639
|
+
const content = await contentResponse.json();
|
|
4640
|
+
const moduleCount = content.modules ? Object.keys(content.modules).length : 0;
|
|
4641
|
+
// Create .claude directory if needed
|
|
4642
|
+
if (!fs.existsSync(claudeDir)) {
|
|
4643
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
4644
|
+
response += `✓ Created .claude/ directory\n`;
|
|
4645
|
+
}
|
|
4646
|
+
// Update CLAUDE.md router
|
|
4647
|
+
if (content.router) {
|
|
4648
|
+
fs.writeFileSync(claudeMdPath, content.router);
|
|
4649
|
+
response += `✓ Updated CLAUDE.md (router)\n`;
|
|
4650
|
+
}
|
|
4651
|
+
// Update all modules
|
|
4652
|
+
if (content.modules && moduleCount > 0) {
|
|
4653
|
+
for (const [name, data] of Object.entries(content.modules)) {
|
|
4654
|
+
fs.writeFileSync(path.join(claudeDir, name), data);
|
|
4655
|
+
}
|
|
4656
|
+
response += `✓ Updated ${moduleCount} modules in .claude/\n`;
|
|
4657
|
+
}
|
|
4658
|
+
// Save version info
|
|
4659
|
+
const newVersionInfo = {
|
|
4660
|
+
version: content.version || latestVersion,
|
|
4661
|
+
moduleCount,
|
|
4662
|
+
installedAt: currentVersion ? undefined : new Date().toISOString(),
|
|
4663
|
+
updatedAt: new Date().toISOString(),
|
|
4664
|
+
cliVersion: (0, api_js_1.getCliVersion)(),
|
|
4665
|
+
};
|
|
4666
|
+
fs.writeFileSync(versionPath, JSON.stringify(newVersionInfo, null, 2));
|
|
4667
|
+
response += `✓ Saved version info\n`;
|
|
4668
|
+
// Confirm download to server (non-blocking analytics)
|
|
4669
|
+
this.confirmDownload(content.version || latestVersion, moduleCount).catch(() => { });
|
|
4670
|
+
response += `\n## ✅ Update Complete!\n\n`;
|
|
4671
|
+
response += `- **From:** v${currentVersion || 'none'} (${currentModuleCount} modules)\n`;
|
|
4672
|
+
response += `- **To:** v${content.version || latestVersion} (${moduleCount} modules)\n\n`;
|
|
4673
|
+
if (moduleCount > currentModuleCount) {
|
|
4674
|
+
response += `🆕 **${moduleCount - currentModuleCount} new modules added!**\n\n`;
|
|
4675
|
+
}
|
|
4676
|
+
response += `Your patterns are now up to date. The new patterns will be used in your next response.\n`;
|
|
4677
|
+
}
|
|
4678
|
+
catch (error) {
|
|
4679
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
4680
|
+
response += `\n## ❌ Update Failed\n\n`;
|
|
4681
|
+
response += `Error: ${message}\n\n`;
|
|
4682
|
+
if (message.includes('401') || message.includes('Invalid') || message.includes('expired')) {
|
|
4683
|
+
response += `Your API key may be invalid or expired.\n`;
|
|
4684
|
+
response += `Run \`codebakers setup\` in terminal to reconfigure.\n`;
|
|
4685
|
+
}
|
|
4686
|
+
else {
|
|
4687
|
+
response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
return {
|
|
4691
|
+
content: [{
|
|
4692
|
+
type: 'text',
|
|
4693
|
+
text: response,
|
|
4694
|
+
}],
|
|
4695
|
+
};
|
|
4696
|
+
}
|
|
4697
|
+
/**
|
|
4698
|
+
* Detect intent from user message and suggest appropriate MCP tools
|
|
4699
|
+
* Shows what would happen before executing, for user confirmation
|
|
4700
|
+
*/
|
|
4701
|
+
handleDetectIntent(args) {
|
|
4702
|
+
const { userMessage } = args;
|
|
4703
|
+
const msg = userMessage.toLowerCase();
|
|
4704
|
+
// Define intent patterns with their MCP tools
|
|
4705
|
+
const intentPatterns = [
|
|
4706
|
+
{
|
|
4707
|
+
keywords: ['upgrade codebakers', 'update patterns', 'sync patterns', 'download patterns', 'get latest patterns'],
|
|
4708
|
+
tool: 'update_patterns',
|
|
4709
|
+
description: 'Download latest CLAUDE.md and all .claude/ modules from the CodeBakers server',
|
|
4710
|
+
action: 'WRITE - Will overwrite local pattern files with server versions',
|
|
4711
|
+
isDestructive: true,
|
|
4712
|
+
},
|
|
4713
|
+
{
|
|
4714
|
+
keywords: ['upgrade', 'improve code', 'make production ready', 'code quality'],
|
|
4715
|
+
tool: 'upgrade',
|
|
4716
|
+
description: 'Analyze your code for quality improvements (does NOT download patterns)',
|
|
4717
|
+
action: 'READ-ONLY - Analyzes code and suggests improvements',
|
|
4718
|
+
isDestructive: false,
|
|
4719
|
+
},
|
|
4720
|
+
{
|
|
4721
|
+
keywords: ['build', 'create project', 'new project', 'scaffold', 'start fresh'],
|
|
4722
|
+
tool: 'scaffold_project',
|
|
4723
|
+
description: 'Create a new project from scratch with CodeBakers patterns',
|
|
4724
|
+
action: 'WRITE - Will create new files and folders',
|
|
4725
|
+
isDestructive: true,
|
|
4726
|
+
},
|
|
4727
|
+
{
|
|
4728
|
+
keywords: ['add feature', 'implement', 'build feature', 'create feature'],
|
|
4729
|
+
tool: 'optimize_and_build',
|
|
4730
|
+
description: 'Optimize your feature request with AI and fetch relevant patterns',
|
|
4731
|
+
action: 'READ + ASSIST - Fetches patterns and guides implementation',
|
|
4732
|
+
isDestructive: false,
|
|
4733
|
+
},
|
|
4734
|
+
{
|
|
4735
|
+
keywords: ['audit', 'review code', 'check code', 'code review'],
|
|
4736
|
+
tool: 'run_audit',
|
|
4737
|
+
description: 'Run comprehensive code quality audit',
|
|
4738
|
+
action: 'READ-ONLY - Analyzes code and reports issues',
|
|
4739
|
+
isDestructive: false,
|
|
4740
|
+
},
|
|
4741
|
+
{
|
|
4742
|
+
keywords: ['heal', 'fix errors', 'auto-fix', 'fix bugs'],
|
|
4743
|
+
tool: 'heal',
|
|
4744
|
+
description: 'AI-powered error detection and automatic fixing',
|
|
4745
|
+
action: 'WRITE - May modify files to fix errors',
|
|
4746
|
+
isDestructive: true,
|
|
4747
|
+
},
|
|
4748
|
+
{
|
|
4749
|
+
keywords: ['design', 'clone design', 'copy design', 'match design'],
|
|
4750
|
+
tool: 'design',
|
|
4751
|
+
description: 'Clone a design from mockups, screenshots, or websites',
|
|
4752
|
+
action: 'WRITE - Will generate component files',
|
|
4753
|
+
isDestructive: true,
|
|
4754
|
+
},
|
|
4755
|
+
{
|
|
4756
|
+
keywords: ['status', 'progress', "what's built", 'where am i'],
|
|
4757
|
+
tool: 'project_status',
|
|
4758
|
+
description: 'Show current project build progress and stats',
|
|
4759
|
+
action: 'READ-ONLY - Shows project state',
|
|
4760
|
+
isDestructive: false,
|
|
4761
|
+
},
|
|
4762
|
+
{
|
|
4763
|
+
keywords: ['run tests', 'test', 'check tests'],
|
|
4764
|
+
tool: 'run_tests',
|
|
4765
|
+
description: 'Execute the project test suite',
|
|
4766
|
+
action: 'READ-ONLY - Runs tests and reports results',
|
|
4767
|
+
isDestructive: false,
|
|
4768
|
+
},
|
|
4769
|
+
{
|
|
4770
|
+
keywords: ['list patterns', 'show patterns', 'what patterns'],
|
|
4771
|
+
tool: 'list_patterns',
|
|
4772
|
+
description: 'List all available CodeBakers patterns',
|
|
4773
|
+
action: 'READ-ONLY - Shows available patterns',
|
|
4774
|
+
isDestructive: false,
|
|
4775
|
+
},
|
|
4776
|
+
{
|
|
4777
|
+
keywords: ['init', 'initialize', 'add patterns to existing'],
|
|
4778
|
+
tool: 'init_project',
|
|
4779
|
+
description: 'Add CodeBakers patterns to an existing project',
|
|
4780
|
+
action: 'WRITE - Will add CLAUDE.md and .claude/ folder',
|
|
4781
|
+
isDestructive: true,
|
|
4782
|
+
},
|
|
4783
|
+
];
|
|
4784
|
+
// Find matching intents
|
|
4785
|
+
const matches = intentPatterns.filter(pattern => pattern.keywords.some(keyword => msg.includes(keyword)));
|
|
4786
|
+
let response = `# 🔍 Intent Detection\n\n`;
|
|
4787
|
+
response += `**Your message:** "${userMessage}"\n\n`;
|
|
4788
|
+
if (matches.length === 0) {
|
|
4789
|
+
response += `## No specific MCP tool detected\n\n`;
|
|
4790
|
+
response += `Your request doesn't clearly match any MCP tool. I'll proceed with general assistance.\n\n`;
|
|
4791
|
+
response += `**Available tools you might want:**\n`;
|
|
4792
|
+
response += `- \`update_patterns\` - Download latest patterns from server\n`;
|
|
4793
|
+
response += `- \`optimize_and_build\` - Get AI help building a feature\n`;
|
|
4794
|
+
response += `- \`run_audit\` - Review your code quality\n`;
|
|
4795
|
+
response += `- \`project_status\` - Check build progress\n`;
|
|
4796
|
+
}
|
|
4797
|
+
else if (matches.length === 1) {
|
|
4798
|
+
const match = matches[0];
|
|
4799
|
+
response += `## Detected Intent\n\n`;
|
|
4800
|
+
response += `| Property | Value |\n`;
|
|
4801
|
+
response += `|----------|-------|\n`;
|
|
4802
|
+
response += `| **Tool** | \`${match.tool}\` |\n`;
|
|
4803
|
+
response += `| **Description** | ${match.description} |\n`;
|
|
4804
|
+
response += `| **Action Type** | ${match.action} |\n`;
|
|
4805
|
+
response += `| **Destructive?** | ${match.isDestructive ? '⚠️ YES - modifies files' : '✅ NO - read-only'} |\n\n`;
|
|
4806
|
+
if (match.isDestructive) {
|
|
4807
|
+
response += `### ⚠️ Confirmation Required\n\n`;
|
|
4808
|
+
response += `This action will modify files. Do you want to proceed?\n\n`;
|
|
4809
|
+
response += `**Reply "yes" or "proceed" to execute, or describe what you actually want.**\n`;
|
|
4810
|
+
}
|
|
4811
|
+
else {
|
|
4812
|
+
response += `This is a read-only operation. Safe to proceed.\n\n`;
|
|
4813
|
+
response += `**Reply "yes" to execute, or clarify your request.**\n`;
|
|
4814
|
+
}
|
|
4815
|
+
}
|
|
4816
|
+
else {
|
|
4817
|
+
response += `## Multiple Possible Intents\n\n`;
|
|
4818
|
+
response += `Your request could match several tools:\n\n`;
|
|
4819
|
+
matches.forEach((match, i) => {
|
|
4820
|
+
response += `### Option ${i + 1}: \`${match.tool}\`\n`;
|
|
4821
|
+
response += `- **What it does:** ${match.description}\n`;
|
|
4822
|
+
response += `- **Action:** ${match.action}\n`;
|
|
4823
|
+
response += `- **Destructive:** ${match.isDestructive ? '⚠️ Yes' : '✅ No'}\n\n`;
|
|
4824
|
+
});
|
|
4825
|
+
response += `**Which option do you want?** Reply with the tool name or option number.\n`;
|
|
4826
|
+
}
|
|
4827
|
+
return {
|
|
4828
|
+
content: [{
|
|
4829
|
+
type: 'text',
|
|
4830
|
+
text: response,
|
|
4831
|
+
}],
|
|
4832
|
+
};
|
|
4833
|
+
}
|
|
4535
4834
|
async run() {
|
|
4536
4835
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
4537
4836
|
await this.server.connect(transport);
|
package/nul
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vitest.config.ts
|
package/package.json
CHANGED
package/src/commands/doctor.ts
CHANGED
|
@@ -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 >=
|
|
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:
|
|
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
|
|
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 {
|
package/src/commands/install.ts
CHANGED
|
@@ -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(
|
|
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';
|
package/src/lib/stats.ts
ADDED
package/src/mcp/server.ts
CHANGED
|
@@ -1033,6 +1033,35 @@ 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
|
+
},
|
|
1050
|
+
{
|
|
1051
|
+
name: 'detect_intent',
|
|
1052
|
+
description:
|
|
1053
|
+
'CALL THIS FIRST when user request is ambiguous or could match multiple MCP tools. Analyzes user input and returns which MCP tool(s) would be appropriate, with explanations. Show the result to the user and ask for confirmation before executing. This prevents accidental destructive actions.',
|
|
1054
|
+
inputSchema: {
|
|
1055
|
+
type: 'object' as const,
|
|
1056
|
+
properties: {
|
|
1057
|
+
userMessage: {
|
|
1058
|
+
type: 'string',
|
|
1059
|
+
description: 'The user\'s message or request to analyze',
|
|
1060
|
+
},
|
|
1061
|
+
},
|
|
1062
|
+
required: ['userMessage'],
|
|
1063
|
+
},
|
|
1064
|
+
},
|
|
1036
1065
|
],
|
|
1037
1066
|
}));
|
|
1038
1067
|
|
|
@@ -1163,6 +1192,12 @@ class CodeBakersServer {
|
|
|
1163
1192
|
case 'check_update_notification':
|
|
1164
1193
|
return this.handleCheckUpdateNotification();
|
|
1165
1194
|
|
|
1195
|
+
case 'update_patterns':
|
|
1196
|
+
return this.handleUpdatePatterns(args as { force?: boolean });
|
|
1197
|
+
|
|
1198
|
+
case 'detect_intent':
|
|
1199
|
+
return this.handleDetectIntent(args as { userMessage: string });
|
|
1200
|
+
|
|
1166
1201
|
default:
|
|
1167
1202
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
1168
1203
|
}
|
|
@@ -5131,6 +5166,306 @@ ${handlers.join('\n')}
|
|
|
5131
5166
|
`;
|
|
5132
5167
|
}
|
|
5133
5168
|
|
|
5169
|
+
/**
|
|
5170
|
+
* Download and update CodeBakers patterns from server
|
|
5171
|
+
* This is the MCP equivalent of the `codebakers upgrade` CLI command
|
|
5172
|
+
*/
|
|
5173
|
+
private async handleUpdatePatterns(args: { force?: boolean }) {
|
|
5174
|
+
const { force = false } = args;
|
|
5175
|
+
const cwd = process.cwd();
|
|
5176
|
+
const claudeMdPath = path.join(cwd, 'CLAUDE.md');
|
|
5177
|
+
const claudeDir = path.join(cwd, '.claude');
|
|
5178
|
+
const versionPath = path.join(claudeDir, '.version.json');
|
|
5179
|
+
|
|
5180
|
+
let response = `# 🔄 CodeBakers Pattern Update\n\n`;
|
|
5181
|
+
|
|
5182
|
+
try {
|
|
5183
|
+
// Check current version
|
|
5184
|
+
let currentVersion: string | null = null;
|
|
5185
|
+
let currentModuleCount = 0;
|
|
5186
|
+
|
|
5187
|
+
if (fs.existsSync(versionPath)) {
|
|
5188
|
+
try {
|
|
5189
|
+
const versionInfo = JSON.parse(fs.readFileSync(versionPath, 'utf-8'));
|
|
5190
|
+
currentVersion = versionInfo.version;
|
|
5191
|
+
currentModuleCount = versionInfo.moduleCount || 0;
|
|
5192
|
+
} catch {
|
|
5193
|
+
// Ignore parse errors
|
|
5194
|
+
}
|
|
5195
|
+
}
|
|
5196
|
+
|
|
5197
|
+
// Count current modules
|
|
5198
|
+
if (fs.existsSync(claudeDir)) {
|
|
5199
|
+
try {
|
|
5200
|
+
const files = fs.readdirSync(claudeDir).filter(f => f.endsWith('.md'));
|
|
5201
|
+
currentModuleCount = files.length;
|
|
5202
|
+
} catch {
|
|
5203
|
+
// Ignore read errors
|
|
5204
|
+
}
|
|
5205
|
+
}
|
|
5206
|
+
|
|
5207
|
+
response += `## Current Status\n`;
|
|
5208
|
+
response += `- Version: ${currentVersion || 'Unknown'}\n`;
|
|
5209
|
+
response += `- Modules: ${currentModuleCount}\n\n`;
|
|
5210
|
+
|
|
5211
|
+
// Fetch latest version info first
|
|
5212
|
+
const versionResponse = await fetch(`${this.apiUrl}/api/content/version`, {
|
|
5213
|
+
headers: this.getAuthHeaders(),
|
|
5214
|
+
});
|
|
5215
|
+
|
|
5216
|
+
if (!versionResponse.ok) {
|
|
5217
|
+
throw new Error('Failed to check version from server');
|
|
5218
|
+
}
|
|
5219
|
+
|
|
5220
|
+
const latestInfo = await versionResponse.json();
|
|
5221
|
+
const latestVersion = latestInfo.version;
|
|
5222
|
+
const latestModuleCount = latestInfo.moduleCount || 0;
|
|
5223
|
+
|
|
5224
|
+
response += `## Server Status\n`;
|
|
5225
|
+
response += `- Latest Version: ${latestVersion}\n`;
|
|
5226
|
+
response += `- Available Modules: ${latestModuleCount}\n\n`;
|
|
5227
|
+
|
|
5228
|
+
// Check if update needed
|
|
5229
|
+
const needsUpdate = force || !currentVersion || currentVersion !== latestVersion || currentModuleCount < latestModuleCount;
|
|
5230
|
+
|
|
5231
|
+
if (!needsUpdate) {
|
|
5232
|
+
response += `✅ **Already up to date!**\n\n`;
|
|
5233
|
+
response += `Your patterns are current (v${latestVersion} with ${latestModuleCount} modules).\n`;
|
|
5234
|
+
response += `Use \`force: true\` to re-download anyway.\n`;
|
|
5235
|
+
|
|
5236
|
+
return {
|
|
5237
|
+
content: [{
|
|
5238
|
+
type: 'text' as const,
|
|
5239
|
+
text: response,
|
|
5240
|
+
}],
|
|
5241
|
+
};
|
|
5242
|
+
}
|
|
5243
|
+
|
|
5244
|
+
response += `## Downloading Updates...\n\n`;
|
|
5245
|
+
|
|
5246
|
+
// Fetch full content
|
|
5247
|
+
const contentResponse = await fetch(`${this.apiUrl}/api/content`, {
|
|
5248
|
+
headers: this.getAuthHeaders(),
|
|
5249
|
+
});
|
|
5250
|
+
|
|
5251
|
+
if (!contentResponse.ok) {
|
|
5252
|
+
const error = await contentResponse.json().catch(() => ({}));
|
|
5253
|
+
throw new Error(error.error || error.message || 'Failed to fetch patterns');
|
|
5254
|
+
}
|
|
5255
|
+
|
|
5256
|
+
const content = await contentResponse.json();
|
|
5257
|
+
const moduleCount = content.modules ? Object.keys(content.modules).length : 0;
|
|
5258
|
+
|
|
5259
|
+
// Create .claude directory if needed
|
|
5260
|
+
if (!fs.existsSync(claudeDir)) {
|
|
5261
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
5262
|
+
response += `✓ Created .claude/ directory\n`;
|
|
5263
|
+
}
|
|
5264
|
+
|
|
5265
|
+
// Update CLAUDE.md router
|
|
5266
|
+
if (content.router) {
|
|
5267
|
+
fs.writeFileSync(claudeMdPath, content.router);
|
|
5268
|
+
response += `✓ Updated CLAUDE.md (router)\n`;
|
|
5269
|
+
}
|
|
5270
|
+
|
|
5271
|
+
// Update all modules
|
|
5272
|
+
if (content.modules && moduleCount > 0) {
|
|
5273
|
+
for (const [name, data] of Object.entries(content.modules)) {
|
|
5274
|
+
fs.writeFileSync(path.join(claudeDir, name), data as string);
|
|
5275
|
+
}
|
|
5276
|
+
response += `✓ Updated ${moduleCount} modules in .claude/\n`;
|
|
5277
|
+
}
|
|
5278
|
+
|
|
5279
|
+
// Save version info
|
|
5280
|
+
const newVersionInfo = {
|
|
5281
|
+
version: content.version || latestVersion,
|
|
5282
|
+
moduleCount,
|
|
5283
|
+
installedAt: currentVersion ? undefined : new Date().toISOString(),
|
|
5284
|
+
updatedAt: new Date().toISOString(),
|
|
5285
|
+
cliVersion: getCliVersion(),
|
|
5286
|
+
};
|
|
5287
|
+
fs.writeFileSync(versionPath, JSON.stringify(newVersionInfo, null, 2));
|
|
5288
|
+
response += `✓ Saved version info\n`;
|
|
5289
|
+
|
|
5290
|
+
// Confirm download to server (non-blocking analytics)
|
|
5291
|
+
this.confirmDownload(content.version || latestVersion, moduleCount).catch(() => {});
|
|
5292
|
+
|
|
5293
|
+
response += `\n## ✅ Update Complete!\n\n`;
|
|
5294
|
+
response += `- **From:** v${currentVersion || 'none'} (${currentModuleCount} modules)\n`;
|
|
5295
|
+
response += `- **To:** v${content.version || latestVersion} (${moduleCount} modules)\n\n`;
|
|
5296
|
+
|
|
5297
|
+
if (moduleCount > currentModuleCount) {
|
|
5298
|
+
response += `🆕 **${moduleCount - currentModuleCount} new modules added!**\n\n`;
|
|
5299
|
+
}
|
|
5300
|
+
|
|
5301
|
+
response += `Your patterns are now up to date. The new patterns will be used in your next response.\n`;
|
|
5302
|
+
|
|
5303
|
+
} catch (error) {
|
|
5304
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
5305
|
+
response += `\n## ❌ Update Failed\n\n`;
|
|
5306
|
+
response += `Error: ${message}\n\n`;
|
|
5307
|
+
|
|
5308
|
+
if (message.includes('401') || message.includes('Invalid') || message.includes('expired')) {
|
|
5309
|
+
response += `Your API key may be invalid or expired.\n`;
|
|
5310
|
+
response += `Run \`codebakers setup\` in terminal to reconfigure.\n`;
|
|
5311
|
+
} else {
|
|
5312
|
+
response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
5315
|
+
|
|
5316
|
+
return {
|
|
5317
|
+
content: [{
|
|
5318
|
+
type: 'text' as const,
|
|
5319
|
+
text: response,
|
|
5320
|
+
}],
|
|
5321
|
+
};
|
|
5322
|
+
}
|
|
5323
|
+
|
|
5324
|
+
/**
|
|
5325
|
+
* Detect intent from user message and suggest appropriate MCP tools
|
|
5326
|
+
* Shows what would happen before executing, for user confirmation
|
|
5327
|
+
*/
|
|
5328
|
+
private handleDetectIntent(args: { userMessage: string }) {
|
|
5329
|
+
const { userMessage } = args;
|
|
5330
|
+
const msg = userMessage.toLowerCase();
|
|
5331
|
+
|
|
5332
|
+
// Define intent patterns with their MCP tools
|
|
5333
|
+
const intentPatterns = [
|
|
5334
|
+
{
|
|
5335
|
+
keywords: ['upgrade codebakers', 'update patterns', 'sync patterns', 'download patterns', 'get latest patterns'],
|
|
5336
|
+
tool: 'update_patterns',
|
|
5337
|
+
description: 'Download latest CLAUDE.md and all .claude/ modules from the CodeBakers server',
|
|
5338
|
+
action: 'WRITE - Will overwrite local pattern files with server versions',
|
|
5339
|
+
isDestructive: true,
|
|
5340
|
+
},
|
|
5341
|
+
{
|
|
5342
|
+
keywords: ['upgrade', 'improve code', 'make production ready', 'code quality'],
|
|
5343
|
+
tool: 'upgrade',
|
|
5344
|
+
description: 'Analyze your code for quality improvements (does NOT download patterns)',
|
|
5345
|
+
action: 'READ-ONLY - Analyzes code and suggests improvements',
|
|
5346
|
+
isDestructive: false,
|
|
5347
|
+
},
|
|
5348
|
+
{
|
|
5349
|
+
keywords: ['build', 'create project', 'new project', 'scaffold', 'start fresh'],
|
|
5350
|
+
tool: 'scaffold_project',
|
|
5351
|
+
description: 'Create a new project from scratch with CodeBakers patterns',
|
|
5352
|
+
action: 'WRITE - Will create new files and folders',
|
|
5353
|
+
isDestructive: true,
|
|
5354
|
+
},
|
|
5355
|
+
{
|
|
5356
|
+
keywords: ['add feature', 'implement', 'build feature', 'create feature'],
|
|
5357
|
+
tool: 'optimize_and_build',
|
|
5358
|
+
description: 'Optimize your feature request with AI and fetch relevant patterns',
|
|
5359
|
+
action: 'READ + ASSIST - Fetches patterns and guides implementation',
|
|
5360
|
+
isDestructive: false,
|
|
5361
|
+
},
|
|
5362
|
+
{
|
|
5363
|
+
keywords: ['audit', 'review code', 'check code', 'code review'],
|
|
5364
|
+
tool: 'run_audit',
|
|
5365
|
+
description: 'Run comprehensive code quality audit',
|
|
5366
|
+
action: 'READ-ONLY - Analyzes code and reports issues',
|
|
5367
|
+
isDestructive: false,
|
|
5368
|
+
},
|
|
5369
|
+
{
|
|
5370
|
+
keywords: ['heal', 'fix errors', 'auto-fix', 'fix bugs'],
|
|
5371
|
+
tool: 'heal',
|
|
5372
|
+
description: 'AI-powered error detection and automatic fixing',
|
|
5373
|
+
action: 'WRITE - May modify files to fix errors',
|
|
5374
|
+
isDestructive: true,
|
|
5375
|
+
},
|
|
5376
|
+
{
|
|
5377
|
+
keywords: ['design', 'clone design', 'copy design', 'match design'],
|
|
5378
|
+
tool: 'design',
|
|
5379
|
+
description: 'Clone a design from mockups, screenshots, or websites',
|
|
5380
|
+
action: 'WRITE - Will generate component files',
|
|
5381
|
+
isDestructive: true,
|
|
5382
|
+
},
|
|
5383
|
+
{
|
|
5384
|
+
keywords: ['status', 'progress', "what's built", 'where am i'],
|
|
5385
|
+
tool: 'project_status',
|
|
5386
|
+
description: 'Show current project build progress and stats',
|
|
5387
|
+
action: 'READ-ONLY - Shows project state',
|
|
5388
|
+
isDestructive: false,
|
|
5389
|
+
},
|
|
5390
|
+
{
|
|
5391
|
+
keywords: ['run tests', 'test', 'check tests'],
|
|
5392
|
+
tool: 'run_tests',
|
|
5393
|
+
description: 'Execute the project test suite',
|
|
5394
|
+
action: 'READ-ONLY - Runs tests and reports results',
|
|
5395
|
+
isDestructive: false,
|
|
5396
|
+
},
|
|
5397
|
+
{
|
|
5398
|
+
keywords: ['list patterns', 'show patterns', 'what patterns'],
|
|
5399
|
+
tool: 'list_patterns',
|
|
5400
|
+
description: 'List all available CodeBakers patterns',
|
|
5401
|
+
action: 'READ-ONLY - Shows available patterns',
|
|
5402
|
+
isDestructive: false,
|
|
5403
|
+
},
|
|
5404
|
+
{
|
|
5405
|
+
keywords: ['init', 'initialize', 'add patterns to existing'],
|
|
5406
|
+
tool: 'init_project',
|
|
5407
|
+
description: 'Add CodeBakers patterns to an existing project',
|
|
5408
|
+
action: 'WRITE - Will add CLAUDE.md and .claude/ folder',
|
|
5409
|
+
isDestructive: true,
|
|
5410
|
+
},
|
|
5411
|
+
];
|
|
5412
|
+
|
|
5413
|
+
// Find matching intents
|
|
5414
|
+
const matches = intentPatterns.filter(pattern =>
|
|
5415
|
+
pattern.keywords.some(keyword => msg.includes(keyword))
|
|
5416
|
+
);
|
|
5417
|
+
|
|
5418
|
+
let response = `# 🔍 Intent Detection\n\n`;
|
|
5419
|
+
response += `**Your message:** "${userMessage}"\n\n`;
|
|
5420
|
+
|
|
5421
|
+
if (matches.length === 0) {
|
|
5422
|
+
response += `## No specific MCP tool detected\n\n`;
|
|
5423
|
+
response += `Your request doesn't clearly match any MCP tool. I'll proceed with general assistance.\n\n`;
|
|
5424
|
+
response += `**Available tools you might want:**\n`;
|
|
5425
|
+
response += `- \`update_patterns\` - Download latest patterns from server\n`;
|
|
5426
|
+
response += `- \`optimize_and_build\` - Get AI help building a feature\n`;
|
|
5427
|
+
response += `- \`run_audit\` - Review your code quality\n`;
|
|
5428
|
+
response += `- \`project_status\` - Check build progress\n`;
|
|
5429
|
+
} else if (matches.length === 1) {
|
|
5430
|
+
const match = matches[0];
|
|
5431
|
+
response += `## Detected Intent\n\n`;
|
|
5432
|
+
response += `| Property | Value |\n`;
|
|
5433
|
+
response += `|----------|-------|\n`;
|
|
5434
|
+
response += `| **Tool** | \`${match.tool}\` |\n`;
|
|
5435
|
+
response += `| **Description** | ${match.description} |\n`;
|
|
5436
|
+
response += `| **Action Type** | ${match.action} |\n`;
|
|
5437
|
+
response += `| **Destructive?** | ${match.isDestructive ? '⚠️ YES - modifies files' : '✅ NO - read-only'} |\n\n`;
|
|
5438
|
+
|
|
5439
|
+
if (match.isDestructive) {
|
|
5440
|
+
response += `### ⚠️ Confirmation Required\n\n`;
|
|
5441
|
+
response += `This action will modify files. Do you want to proceed?\n\n`;
|
|
5442
|
+
response += `**Reply "yes" or "proceed" to execute, or describe what you actually want.**\n`;
|
|
5443
|
+
} else {
|
|
5444
|
+
response += `This is a read-only operation. Safe to proceed.\n\n`;
|
|
5445
|
+
response += `**Reply "yes" to execute, or clarify your request.**\n`;
|
|
5446
|
+
}
|
|
5447
|
+
} else {
|
|
5448
|
+
response += `## Multiple Possible Intents\n\n`;
|
|
5449
|
+
response += `Your request could match several tools:\n\n`;
|
|
5450
|
+
|
|
5451
|
+
matches.forEach((match, i) => {
|
|
5452
|
+
response += `### Option ${i + 1}: \`${match.tool}\`\n`;
|
|
5453
|
+
response += `- **What it does:** ${match.description}\n`;
|
|
5454
|
+
response += `- **Action:** ${match.action}\n`;
|
|
5455
|
+
response += `- **Destructive:** ${match.isDestructive ? '⚠️ Yes' : '✅ No'}\n\n`;
|
|
5456
|
+
});
|
|
5457
|
+
|
|
5458
|
+
response += `**Which option do you want?** Reply with the tool name or option number.\n`;
|
|
5459
|
+
}
|
|
5460
|
+
|
|
5461
|
+
return {
|
|
5462
|
+
content: [{
|
|
5463
|
+
type: 'text' as const,
|
|
5464
|
+
text: response,
|
|
5465
|
+
}],
|
|
5466
|
+
};
|
|
5467
|
+
}
|
|
5468
|
+
|
|
5134
5469
|
async run(): Promise<void> {
|
|
5135
5470
|
const transport = new StdioServerTransport();
|
|
5136
5471
|
await this.server.connect(transport);
|