@codebakers/cli 2.2.0 → 2.3.0
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/mcp/server.js +370 -1
- package/package.json +1 -1
- package/src/mcp/server.ts +412 -1
package/dist/mcp/server.js
CHANGED
|
@@ -453,6 +453,55 @@ class CodeBakersServer {
|
|
|
453
453
|
},
|
|
454
454
|
},
|
|
455
455
|
},
|
|
456
|
+
{
|
|
457
|
+
name: 'design',
|
|
458
|
+
description: 'Clone and implement designs from mockups, screenshots, or website references. Analyzes visual designs and generates pixel-perfect matching code with extracted design tokens (colors, typography, spacing). Use when user says "clone this design", "make it look like...", or "copy this UI".',
|
|
459
|
+
inputSchema: {
|
|
460
|
+
type: 'object',
|
|
461
|
+
properties: {
|
|
462
|
+
source: {
|
|
463
|
+
type: 'string',
|
|
464
|
+
description: 'Path to mockup image, folder of images, URL to clone, or reference style (e.g., "./mockups", "https://linear.app", "like Notion")',
|
|
465
|
+
},
|
|
466
|
+
outputDir: {
|
|
467
|
+
type: 'string',
|
|
468
|
+
description: 'Directory to output generated components (default: src/components)',
|
|
469
|
+
},
|
|
470
|
+
},
|
|
471
|
+
required: ['source'],
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
name: 'upgrade',
|
|
476
|
+
description: 'Upgrade an existing project to CodeBakers patterns WITHOUT changing the user\'s tech stack. Preserves their existing ORM (Prisma/Drizzle), auth (NextAuth/Clerk), UI library (Chakra/MUI), etc. Only upgrades code quality patterns like error handling, validation, tests, and security. Use when user says "upgrade this project", "improve my code", or "make this production ready".',
|
|
477
|
+
inputSchema: {
|
|
478
|
+
type: 'object',
|
|
479
|
+
properties: {
|
|
480
|
+
areas: {
|
|
481
|
+
type: 'array',
|
|
482
|
+
items: { type: 'string' },
|
|
483
|
+
description: 'Specific areas to upgrade: "api", "components", "testing", "security", "all" (default: all)',
|
|
484
|
+
},
|
|
485
|
+
severity: {
|
|
486
|
+
type: 'string',
|
|
487
|
+
enum: ['critical', 'high', 'medium', 'low', 'all'],
|
|
488
|
+
description: 'Filter upgrades by severity (default: all)',
|
|
489
|
+
},
|
|
490
|
+
dryRun: {
|
|
491
|
+
type: 'boolean',
|
|
492
|
+
description: 'Show what would be upgraded without making changes (default: false)',
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
name: 'project_status',
|
|
499
|
+
description: 'Show project build progress, completed features, and what\'s next. Different from get_status which shows CodeBakers connection status. Use when user asks "where am I?", "what\'s built?", "show progress", or "what\'s next?".',
|
|
500
|
+
inputSchema: {
|
|
501
|
+
type: 'object',
|
|
502
|
+
properties: {},
|
|
503
|
+
},
|
|
504
|
+
},
|
|
456
505
|
],
|
|
457
506
|
}));
|
|
458
507
|
// Handle tool calls
|
|
@@ -488,6 +537,12 @@ class CodeBakersServer {
|
|
|
488
537
|
return this.handleRunAudit();
|
|
489
538
|
case 'heal':
|
|
490
539
|
return this.handleHeal(args);
|
|
540
|
+
case 'design':
|
|
541
|
+
return this.handleDesign(args);
|
|
542
|
+
case 'upgrade':
|
|
543
|
+
return this.handleUpgrade(args);
|
|
544
|
+
case 'project_status':
|
|
545
|
+
return this.handleProjectStatus();
|
|
491
546
|
default:
|
|
492
547
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
493
548
|
}
|
|
@@ -1277,7 +1332,7 @@ phase: development
|
|
|
1277
1332
|
## Connection Status
|
|
1278
1333
|
- **MCP Server:** Running
|
|
1279
1334
|
- **API Connected:** Yes
|
|
1280
|
-
- **Version:**
|
|
1335
|
+
- **Version:** 2.2.0
|
|
1281
1336
|
|
|
1282
1337
|
## Current Settings
|
|
1283
1338
|
- **Experience Level:** ${level.charAt(0).toUpperCase() + level.slice(1)}
|
|
@@ -1289,6 +1344,9 @@ phase: development
|
|
|
1289
1344
|
- 🔍 **search_patterns** - Search for specific guidance
|
|
1290
1345
|
- 🏗️ **scaffold_project** - Create new projects
|
|
1291
1346
|
- ⚙️ **init_project** - Add patterns to existing projects
|
|
1347
|
+
- 🎨 **design** - Clone designs from mockups/websites
|
|
1348
|
+
- ⬆️ **upgrade** - Upgrade project patterns (preserves your stack)
|
|
1349
|
+
- 📊 **project_status** - Show build progress
|
|
1292
1350
|
|
|
1293
1351
|
## How to Use
|
|
1294
1352
|
Just describe what you want to build! I'll automatically:
|
|
@@ -1307,6 +1365,317 @@ Just describe what you want to build! I'll automatically:
|
|
|
1307
1365
|
}],
|
|
1308
1366
|
};
|
|
1309
1367
|
}
|
|
1368
|
+
async handleDesign(args) {
|
|
1369
|
+
const { source, outputDir = 'src/components' } = args;
|
|
1370
|
+
const cwd = process.cwd();
|
|
1371
|
+
// Detect source type
|
|
1372
|
+
let sourceType = 'reference';
|
|
1373
|
+
if (source.startsWith('http://') || source.startsWith('https://')) {
|
|
1374
|
+
sourceType = 'url';
|
|
1375
|
+
}
|
|
1376
|
+
else if (source.startsWith('./') || source.startsWith('/') || source.includes('\\')) {
|
|
1377
|
+
const fullPath = path.join(cwd, source);
|
|
1378
|
+
if (fs.existsSync(fullPath)) {
|
|
1379
|
+
const stat = fs.statSync(fullPath);
|
|
1380
|
+
sourceType = stat.isDirectory() ? 'folder' : 'file';
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
else if (source.toLowerCase().startsWith('like ')) {
|
|
1384
|
+
sourceType = 'reference';
|
|
1385
|
+
}
|
|
1386
|
+
// Fetch design pattern from API
|
|
1387
|
+
const patternResult = await this.fetchPatterns(['33-design-clone', '09-design']);
|
|
1388
|
+
let response = `# 🎨 Design Clone Tool\n\n`;
|
|
1389
|
+
response += `**Source:** ${source}\n`;
|
|
1390
|
+
response += `**Type:** ${sourceType}\n`;
|
|
1391
|
+
response += `**Output:** ${outputDir}\n\n`;
|
|
1392
|
+
switch (sourceType) {
|
|
1393
|
+
case 'folder':
|
|
1394
|
+
const folderPath = path.join(cwd, source);
|
|
1395
|
+
const images = fs.readdirSync(folderPath).filter(f => /\.(png|jpg|jpeg|webp|svg|gif)$/i.test(f));
|
|
1396
|
+
response += `## Found ${images.length} Design Files\n\n`;
|
|
1397
|
+
images.forEach(img => {
|
|
1398
|
+
response += `- ${img}\n`;
|
|
1399
|
+
});
|
|
1400
|
+
response += `\n## Next Steps\n\n`;
|
|
1401
|
+
response += `1. I'll analyze each image for design tokens\n`;
|
|
1402
|
+
response += `2. Extract colors, typography, spacing\n`;
|
|
1403
|
+
response += `3. Generate Tailwind config with your design system\n`;
|
|
1404
|
+
response += `4. Create matching components\n\n`;
|
|
1405
|
+
response += `**Note:** For best results, provide screenshots of:\n`;
|
|
1406
|
+
response += `- Color palette / brand guidelines\n`;
|
|
1407
|
+
response += `- Typography samples\n`;
|
|
1408
|
+
response += `- Key UI components (buttons, cards, forms)\n`;
|
|
1409
|
+
break;
|
|
1410
|
+
case 'file':
|
|
1411
|
+
response += `## Analyzing Single Design\n\n`;
|
|
1412
|
+
response += `I'll extract design tokens from this image and generate matching components.\n\n`;
|
|
1413
|
+
response += `**Tip:** For a complete design system, provide a folder with multiple mockups.\n`;
|
|
1414
|
+
break;
|
|
1415
|
+
case 'url':
|
|
1416
|
+
response += `## Cloning Website Design\n\n`;
|
|
1417
|
+
response += `I'll analyze the visual design at ${source} and extract:\n`;
|
|
1418
|
+
response += `- Color palette\n`;
|
|
1419
|
+
response += `- Typography (fonts, sizes, weights)\n`;
|
|
1420
|
+
response += `- Spacing system\n`;
|
|
1421
|
+
response += `- Component patterns\n\n`;
|
|
1422
|
+
response += `**Note:** This creates inspired-by components, not exact copies.\n`;
|
|
1423
|
+
break;
|
|
1424
|
+
case 'reference':
|
|
1425
|
+
const refStyle = source.replace(/^like\s+/i, '').toLowerCase();
|
|
1426
|
+
const knownStyles = {
|
|
1427
|
+
'linear': 'Dark theme, purple accents, minimal, clean',
|
|
1428
|
+
'notion': 'Light theme, black/white, content-focused, lots of whitespace',
|
|
1429
|
+
'stripe': 'Professional, purple gradients, polished shadows',
|
|
1430
|
+
'vercel': 'Black/white, developer-focused, geometric',
|
|
1431
|
+
'github': 'Blue accents, familiar, dev-tool aesthetic',
|
|
1432
|
+
'figma': 'Purple accents, collaborative, modern',
|
|
1433
|
+
};
|
|
1434
|
+
const matchedStyle = Object.entries(knownStyles).find(([key]) => refStyle.includes(key));
|
|
1435
|
+
if (matchedStyle) {
|
|
1436
|
+
response += `## Reference Style: ${matchedStyle[0]}\n\n`;
|
|
1437
|
+
response += `**Characteristics:** ${matchedStyle[1]}\n\n`;
|
|
1438
|
+
}
|
|
1439
|
+
else {
|
|
1440
|
+
response += `## Reference Style: "${source}"\n\n`;
|
|
1441
|
+
response += `I'll apply a design language inspired by this reference.\n\n`;
|
|
1442
|
+
}
|
|
1443
|
+
response += `I'll generate components matching this aesthetic.\n`;
|
|
1444
|
+
break;
|
|
1445
|
+
}
|
|
1446
|
+
response += `\n---\n\n`;
|
|
1447
|
+
response += `## Design Pattern Loaded\n\n`;
|
|
1448
|
+
response += `The design-clone pattern (33-design-clone) is now active.\n`;
|
|
1449
|
+
response += `Proceed with specific component requests like:\n`;
|
|
1450
|
+
response += `- "Create the navigation bar"\n`;
|
|
1451
|
+
response += `- "Build the hero section"\n`;
|
|
1452
|
+
response += `- "Generate the card components"\n`;
|
|
1453
|
+
return {
|
|
1454
|
+
content: [{
|
|
1455
|
+
type: 'text',
|
|
1456
|
+
text: response,
|
|
1457
|
+
}],
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
async handleUpgrade(args) {
|
|
1461
|
+
const { areas = ['all'], severity = 'all', dryRun = false } = args;
|
|
1462
|
+
const context = this.gatherProjectContext();
|
|
1463
|
+
let response = `# ⬆️ Project Upgrade Analysis\n\n`;
|
|
1464
|
+
// Stack detection
|
|
1465
|
+
response += `## Your Stack (Preserving As-Is)\n\n`;
|
|
1466
|
+
response += `| Layer | Detected | Status |\n`;
|
|
1467
|
+
response += `|-------|----------|--------|\n`;
|
|
1468
|
+
// ORM detection
|
|
1469
|
+
let orm = 'None';
|
|
1470
|
+
if (context.dependencies.includes('drizzle-orm'))
|
|
1471
|
+
orm = 'Drizzle';
|
|
1472
|
+
else if (context.dependencies.includes('@prisma/client'))
|
|
1473
|
+
orm = 'Prisma';
|
|
1474
|
+
else if (context.dependencies.includes('typeorm'))
|
|
1475
|
+
orm = 'TypeORM';
|
|
1476
|
+
else if (context.dependencies.includes('mongoose'))
|
|
1477
|
+
orm = 'Mongoose';
|
|
1478
|
+
response += `| ORM | ${orm} | ✓ Keeping |\n`;
|
|
1479
|
+
// Auth detection
|
|
1480
|
+
let auth = 'None';
|
|
1481
|
+
if (context.dependencies.includes('@supabase/supabase-js'))
|
|
1482
|
+
auth = 'Supabase';
|
|
1483
|
+
else if (context.dependencies.includes('next-auth'))
|
|
1484
|
+
auth = 'NextAuth';
|
|
1485
|
+
else if (context.dependencies.includes('@clerk/nextjs'))
|
|
1486
|
+
auth = 'Clerk';
|
|
1487
|
+
else if (context.dependencies.includes('firebase'))
|
|
1488
|
+
auth = 'Firebase';
|
|
1489
|
+
response += `| Auth | ${auth} | ✓ Keeping |\n`;
|
|
1490
|
+
// UI detection
|
|
1491
|
+
response += `| UI | ${context.uiLibrary || 'Tailwind'} | ✓ Keeping |\n`;
|
|
1492
|
+
// Framework (always Next.js for now)
|
|
1493
|
+
const hasNext = context.dependencies.includes('next');
|
|
1494
|
+
response += `| Framework | ${hasNext ? 'Next.js' : 'Unknown'} | ✓ Keeping |\n`;
|
|
1495
|
+
response += `\n---\n\n`;
|
|
1496
|
+
// Scan for upgrade opportunities
|
|
1497
|
+
response += `## Upgrade Opportunities\n\n`;
|
|
1498
|
+
const upgrades = [];
|
|
1499
|
+
// Check API routes
|
|
1500
|
+
if (context.existingApiRoutes.length > 0) {
|
|
1501
|
+
upgrades.push({
|
|
1502
|
+
area: 'API Routes',
|
|
1503
|
+
issue: 'Add error handling, validation, rate limiting',
|
|
1504
|
+
severity: 'HIGH',
|
|
1505
|
+
count: context.existingApiRoutes.length,
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
// Check components
|
|
1509
|
+
if (context.existingComponents.length > 0) {
|
|
1510
|
+
upgrades.push({
|
|
1511
|
+
area: 'Components',
|
|
1512
|
+
issue: 'Add loading states, error boundaries, accessibility',
|
|
1513
|
+
severity: 'MEDIUM',
|
|
1514
|
+
count: context.existingComponents.length,
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
// Check for tests
|
|
1518
|
+
const hasTests = context.dependencies.includes('@playwright/test') ||
|
|
1519
|
+
context.dependencies.includes('jest') ||
|
|
1520
|
+
context.dependencies.includes('vitest');
|
|
1521
|
+
if (!hasTests) {
|
|
1522
|
+
upgrades.push({
|
|
1523
|
+
area: 'Testing',
|
|
1524
|
+
issue: 'No test framework detected',
|
|
1525
|
+
severity: 'HIGH',
|
|
1526
|
+
count: 0,
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
// Check for Zod
|
|
1530
|
+
const hasZod = context.dependencies.includes('zod');
|
|
1531
|
+
if (!hasZod && context.existingApiRoutes.length > 0) {
|
|
1532
|
+
upgrades.push({
|
|
1533
|
+
area: 'Validation',
|
|
1534
|
+
issue: 'No Zod validation detected for API routes',
|
|
1535
|
+
severity: 'HIGH',
|
|
1536
|
+
count: context.existingApiRoutes.length,
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
// Display upgrades
|
|
1540
|
+
for (const upgrade of upgrades) {
|
|
1541
|
+
const icon = upgrade.severity === 'HIGH' ? '🔴' :
|
|
1542
|
+
upgrade.severity === 'MEDIUM' ? '🟡' : '🟢';
|
|
1543
|
+
response += `### ${icon} ${upgrade.area}\n`;
|
|
1544
|
+
response += `- **Issue:** ${upgrade.issue}\n`;
|
|
1545
|
+
if (upgrade.count > 0) {
|
|
1546
|
+
response += `- **Affected:** ${upgrade.count} files\n`;
|
|
1547
|
+
}
|
|
1548
|
+
response += `- **Severity:** ${upgrade.severity}\n\n`;
|
|
1549
|
+
}
|
|
1550
|
+
if (upgrades.length === 0) {
|
|
1551
|
+
response += `✅ No major upgrade opportunities detected!\n\n`;
|
|
1552
|
+
}
|
|
1553
|
+
// Recommendations
|
|
1554
|
+
response += `---\n\n`;
|
|
1555
|
+
response += `## Recommended Actions\n\n`;
|
|
1556
|
+
if (dryRun) {
|
|
1557
|
+
response += `**(Dry Run Mode - No changes will be made)**\n\n`;
|
|
1558
|
+
}
|
|
1559
|
+
response += `1. Run \`run_audit\` for detailed code quality check\n`;
|
|
1560
|
+
response += `2. Use \`heal\` to auto-fix common issues\n`;
|
|
1561
|
+
response += `3. Request specific upgrades like:\n`;
|
|
1562
|
+
response += ` - "Add Zod validation to my API routes"\n`;
|
|
1563
|
+
response += ` - "Add error boundaries to components"\n`;
|
|
1564
|
+
response += ` - "Set up Playwright testing"\n\n`;
|
|
1565
|
+
response += `---\n\n`;
|
|
1566
|
+
response += `**Key Principle:** Your stack stays the same. Only code quality patterns are upgraded.\n`;
|
|
1567
|
+
return {
|
|
1568
|
+
content: [{
|
|
1569
|
+
type: 'text',
|
|
1570
|
+
text: response,
|
|
1571
|
+
}],
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
handleProjectStatus() {
|
|
1575
|
+
const cwd = process.cwd();
|
|
1576
|
+
const context = this.gatherProjectContext();
|
|
1577
|
+
let response = `# 📊 Project Status\n\n`;
|
|
1578
|
+
response += `**Project:** ${context.projectName}\n\n`;
|
|
1579
|
+
// Check for .codebakers.json state
|
|
1580
|
+
let state = null;
|
|
1581
|
+
try {
|
|
1582
|
+
const statePath = path.join(cwd, '.codebakers.json');
|
|
1583
|
+
if (fs.existsSync(statePath)) {
|
|
1584
|
+
state = JSON.parse(fs.readFileSync(statePath, 'utf-8'));
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
catch {
|
|
1588
|
+
// No state file
|
|
1589
|
+
}
|
|
1590
|
+
// Check for PRD
|
|
1591
|
+
const prdPath = path.join(cwd, 'PRD.md');
|
|
1592
|
+
const hasPrd = fs.existsSync(prdPath);
|
|
1593
|
+
// Check for PROJECT-STATE.md
|
|
1594
|
+
const projectStatePath = path.join(cwd, 'PROJECT-STATE.md');
|
|
1595
|
+
const hasProjectState = fs.existsSync(projectStatePath);
|
|
1596
|
+
if (state && typeof state === 'object') {
|
|
1597
|
+
const s = state;
|
|
1598
|
+
// Build progress
|
|
1599
|
+
if (s.build && typeof s.build === 'object') {
|
|
1600
|
+
const build = s.build;
|
|
1601
|
+
response += `## Build Progress\n\n`;
|
|
1602
|
+
const currentPhase = build.currentPhase || 0;
|
|
1603
|
+
const totalPhases = build.totalPhases || 1;
|
|
1604
|
+
const percent = Math.round((currentPhase / totalPhases) * 100);
|
|
1605
|
+
response += `**Phase ${currentPhase}/${totalPhases}** (${percent}%)\n\n`;
|
|
1606
|
+
// Progress bar
|
|
1607
|
+
const filled = Math.round(percent / 10);
|
|
1608
|
+
const empty = 10 - filled;
|
|
1609
|
+
response += `[${'█'.repeat(filled)}${'░'.repeat(empty)}] ${percent}%\n\n`;
|
|
1610
|
+
if (build.status) {
|
|
1611
|
+
response += `**Status:** ${build.status}\n\n`;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
// Current work
|
|
1615
|
+
if (s.currentWork && typeof s.currentWork === 'object') {
|
|
1616
|
+
const work = s.currentWork;
|
|
1617
|
+
response += `## Current Work\n\n`;
|
|
1618
|
+
if (work.activeFeature) {
|
|
1619
|
+
response += `**In Progress:** ${work.activeFeature}\n`;
|
|
1620
|
+
}
|
|
1621
|
+
if (work.summary) {
|
|
1622
|
+
response += `**Summary:** ${work.summary}\n`;
|
|
1623
|
+
}
|
|
1624
|
+
if (work.lastUpdated) {
|
|
1625
|
+
response += `**Last Updated:** ${work.lastUpdated}\n`;
|
|
1626
|
+
}
|
|
1627
|
+
response += `\n`;
|
|
1628
|
+
}
|
|
1629
|
+
// Stack
|
|
1630
|
+
if (s.stack && typeof s.stack === 'object') {
|
|
1631
|
+
const stack = s.stack;
|
|
1632
|
+
response += `## Stack\n\n`;
|
|
1633
|
+
for (const [key, value] of Object.entries(stack)) {
|
|
1634
|
+
if (value) {
|
|
1635
|
+
response += `- **${key}:** ${value}\n`;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
response += `\n`;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
else {
|
|
1642
|
+
response += `## Project Overview\n\n`;
|
|
1643
|
+
response += `- **PRD:** ${hasPrd ? '✅ Found' : '❌ Not found'}\n`;
|
|
1644
|
+
response += `- **State Tracking:** ${hasProjectState ? '✅ Found' : '❌ Not found'}\n`;
|
|
1645
|
+
response += `- **CodeBakers State:** ${state ? '✅ Found' : '❌ Not initialized'}\n\n`;
|
|
1646
|
+
}
|
|
1647
|
+
// What's built
|
|
1648
|
+
response += `## What's Built\n\n`;
|
|
1649
|
+
response += `- **Components:** ${context.existingComponents.length}\n`;
|
|
1650
|
+
response += `- **API Routes:** ${context.existingApiRoutes.length}\n`;
|
|
1651
|
+
response += `- **Services:** ${context.existingServices.length}\n`;
|
|
1652
|
+
if (context.hasAuth)
|
|
1653
|
+
response += `- ✅ Authentication\n`;
|
|
1654
|
+
if (context.hasDatabase)
|
|
1655
|
+
response += `- ✅ Database\n`;
|
|
1656
|
+
if (context.hasPayments)
|
|
1657
|
+
response += `- ✅ Payments\n`;
|
|
1658
|
+
response += `\n`;
|
|
1659
|
+
// Recent components
|
|
1660
|
+
if (context.existingComponents.length > 0) {
|
|
1661
|
+
response += `### Recent Components\n`;
|
|
1662
|
+
context.existingComponents.slice(0, 10).forEach(comp => {
|
|
1663
|
+
response += `- ${comp}\n`;
|
|
1664
|
+
});
|
|
1665
|
+
if (context.existingComponents.length > 10) {
|
|
1666
|
+
response += `- ... and ${context.existingComponents.length - 10} more\n`;
|
|
1667
|
+
}
|
|
1668
|
+
response += `\n`;
|
|
1669
|
+
}
|
|
1670
|
+
response += `---\n\n`;
|
|
1671
|
+
response += `*Run \`upgrade\` to improve code quality or \`run_audit\` for detailed analysis.*`;
|
|
1672
|
+
return {
|
|
1673
|
+
content: [{
|
|
1674
|
+
type: 'text',
|
|
1675
|
+
text: response,
|
|
1676
|
+
}],
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1310
1679
|
async run() {
|
|
1311
1680
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
1312
1681
|
await this.server.connect(transport);
|
package/package.json
CHANGED
package/src/mcp/server.ts
CHANGED
|
@@ -480,6 +480,58 @@ class CodeBakersServer {
|
|
|
480
480
|
},
|
|
481
481
|
},
|
|
482
482
|
},
|
|
483
|
+
{
|
|
484
|
+
name: 'design',
|
|
485
|
+
description:
|
|
486
|
+
'Clone and implement designs from mockups, screenshots, or website references. Analyzes visual designs and generates pixel-perfect matching code with extracted design tokens (colors, typography, spacing). Use when user says "clone this design", "make it look like...", or "copy this UI".',
|
|
487
|
+
inputSchema: {
|
|
488
|
+
type: 'object' as const,
|
|
489
|
+
properties: {
|
|
490
|
+
source: {
|
|
491
|
+
type: 'string',
|
|
492
|
+
description: 'Path to mockup image, folder of images, URL to clone, or reference style (e.g., "./mockups", "https://linear.app", "like Notion")',
|
|
493
|
+
},
|
|
494
|
+
outputDir: {
|
|
495
|
+
type: 'string',
|
|
496
|
+
description: 'Directory to output generated components (default: src/components)',
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
required: ['source'],
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
name: 'upgrade',
|
|
504
|
+
description:
|
|
505
|
+
'Upgrade an existing project to CodeBakers patterns WITHOUT changing the user\'s tech stack. Preserves their existing ORM (Prisma/Drizzle), auth (NextAuth/Clerk), UI library (Chakra/MUI), etc. Only upgrades code quality patterns like error handling, validation, tests, and security. Use when user says "upgrade this project", "improve my code", or "make this production ready".',
|
|
506
|
+
inputSchema: {
|
|
507
|
+
type: 'object' as const,
|
|
508
|
+
properties: {
|
|
509
|
+
areas: {
|
|
510
|
+
type: 'array',
|
|
511
|
+
items: { type: 'string' },
|
|
512
|
+
description: 'Specific areas to upgrade: "api", "components", "testing", "security", "all" (default: all)',
|
|
513
|
+
},
|
|
514
|
+
severity: {
|
|
515
|
+
type: 'string',
|
|
516
|
+
enum: ['critical', 'high', 'medium', 'low', 'all'],
|
|
517
|
+
description: 'Filter upgrades by severity (default: all)',
|
|
518
|
+
},
|
|
519
|
+
dryRun: {
|
|
520
|
+
type: 'boolean',
|
|
521
|
+
description: 'Show what would be upgraded without making changes (default: false)',
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
name: 'project_status',
|
|
528
|
+
description:
|
|
529
|
+
'Show project build progress, completed features, and what\'s next. Different from get_status which shows CodeBakers connection status. Use when user asks "where am I?", "what\'s built?", "show progress", or "what\'s next?".',
|
|
530
|
+
inputSchema: {
|
|
531
|
+
type: 'object' as const,
|
|
532
|
+
properties: {},
|
|
533
|
+
},
|
|
534
|
+
},
|
|
483
535
|
],
|
|
484
536
|
}));
|
|
485
537
|
|
|
@@ -534,6 +586,15 @@ class CodeBakersServer {
|
|
|
534
586
|
case 'heal':
|
|
535
587
|
return this.handleHeal(args as { auto?: boolean; dryRun?: boolean; severity?: string });
|
|
536
588
|
|
|
589
|
+
case 'design':
|
|
590
|
+
return this.handleDesign(args as { source: string; outputDir?: string });
|
|
591
|
+
|
|
592
|
+
case 'upgrade':
|
|
593
|
+
return this.handleUpgrade(args as { areas?: string[]; severity?: string; dryRun?: boolean });
|
|
594
|
+
|
|
595
|
+
case 'project_status':
|
|
596
|
+
return this.handleProjectStatus();
|
|
597
|
+
|
|
537
598
|
default:
|
|
538
599
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
539
600
|
}
|
|
@@ -1445,7 +1506,7 @@ phase: development
|
|
|
1445
1506
|
## Connection Status
|
|
1446
1507
|
- **MCP Server:** Running
|
|
1447
1508
|
- **API Connected:** Yes
|
|
1448
|
-
- **Version:**
|
|
1509
|
+
- **Version:** 2.2.0
|
|
1449
1510
|
|
|
1450
1511
|
## Current Settings
|
|
1451
1512
|
- **Experience Level:** ${level.charAt(0).toUpperCase() + level.slice(1)}
|
|
@@ -1457,6 +1518,9 @@ phase: development
|
|
|
1457
1518
|
- 🔍 **search_patterns** - Search for specific guidance
|
|
1458
1519
|
- 🏗️ **scaffold_project** - Create new projects
|
|
1459
1520
|
- ⚙️ **init_project** - Add patterns to existing projects
|
|
1521
|
+
- 🎨 **design** - Clone designs from mockups/websites
|
|
1522
|
+
- ⬆️ **upgrade** - Upgrade project patterns (preserves your stack)
|
|
1523
|
+
- 📊 **project_status** - Show build progress
|
|
1460
1524
|
|
|
1461
1525
|
## How to Use
|
|
1462
1526
|
Just describe what you want to build! I'll automatically:
|
|
@@ -1477,6 +1541,353 @@ Just describe what you want to build! I'll automatically:
|
|
|
1477
1541
|
};
|
|
1478
1542
|
}
|
|
1479
1543
|
|
|
1544
|
+
private async handleDesign(args: { source: string; outputDir?: string }) {
|
|
1545
|
+
const { source, outputDir = 'src/components' } = args;
|
|
1546
|
+
const cwd = process.cwd();
|
|
1547
|
+
|
|
1548
|
+
// Detect source type
|
|
1549
|
+
let sourceType: 'folder' | 'file' | 'url' | 'reference' = 'reference';
|
|
1550
|
+
if (source.startsWith('http://') || source.startsWith('https://')) {
|
|
1551
|
+
sourceType = 'url';
|
|
1552
|
+
} else if (source.startsWith('./') || source.startsWith('/') || source.includes('\\')) {
|
|
1553
|
+
const fullPath = path.join(cwd, source);
|
|
1554
|
+
if (fs.existsSync(fullPath)) {
|
|
1555
|
+
const stat = fs.statSync(fullPath);
|
|
1556
|
+
sourceType = stat.isDirectory() ? 'folder' : 'file';
|
|
1557
|
+
}
|
|
1558
|
+
} else if (source.toLowerCase().startsWith('like ')) {
|
|
1559
|
+
sourceType = 'reference';
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// Fetch design pattern from API
|
|
1563
|
+
const patternResult = await this.fetchPatterns(['33-design-clone', '09-design']);
|
|
1564
|
+
|
|
1565
|
+
let response = `# 🎨 Design Clone Tool\n\n`;
|
|
1566
|
+
response += `**Source:** ${source}\n`;
|
|
1567
|
+
response += `**Type:** ${sourceType}\n`;
|
|
1568
|
+
response += `**Output:** ${outputDir}\n\n`;
|
|
1569
|
+
|
|
1570
|
+
switch (sourceType) {
|
|
1571
|
+
case 'folder':
|
|
1572
|
+
const folderPath = path.join(cwd, source);
|
|
1573
|
+
const images = fs.readdirSync(folderPath).filter(f =>
|
|
1574
|
+
/\.(png|jpg|jpeg|webp|svg|gif)$/i.test(f)
|
|
1575
|
+
);
|
|
1576
|
+
response += `## Found ${images.length} Design Files\n\n`;
|
|
1577
|
+
images.forEach(img => {
|
|
1578
|
+
response += `- ${img}\n`;
|
|
1579
|
+
});
|
|
1580
|
+
response += `\n## Next Steps\n\n`;
|
|
1581
|
+
response += `1. I'll analyze each image for design tokens\n`;
|
|
1582
|
+
response += `2. Extract colors, typography, spacing\n`;
|
|
1583
|
+
response += `3. Generate Tailwind config with your design system\n`;
|
|
1584
|
+
response += `4. Create matching components\n\n`;
|
|
1585
|
+
response += `**Note:** For best results, provide screenshots of:\n`;
|
|
1586
|
+
response += `- Color palette / brand guidelines\n`;
|
|
1587
|
+
response += `- Typography samples\n`;
|
|
1588
|
+
response += `- Key UI components (buttons, cards, forms)\n`;
|
|
1589
|
+
break;
|
|
1590
|
+
|
|
1591
|
+
case 'file':
|
|
1592
|
+
response += `## Analyzing Single Design\n\n`;
|
|
1593
|
+
response += `I'll extract design tokens from this image and generate matching components.\n\n`;
|
|
1594
|
+
response += `**Tip:** For a complete design system, provide a folder with multiple mockups.\n`;
|
|
1595
|
+
break;
|
|
1596
|
+
|
|
1597
|
+
case 'url':
|
|
1598
|
+
response += `## Cloning Website Design\n\n`;
|
|
1599
|
+
response += `I'll analyze the visual design at ${source} and extract:\n`;
|
|
1600
|
+
response += `- Color palette\n`;
|
|
1601
|
+
response += `- Typography (fonts, sizes, weights)\n`;
|
|
1602
|
+
response += `- Spacing system\n`;
|
|
1603
|
+
response += `- Component patterns\n\n`;
|
|
1604
|
+
response += `**Note:** This creates inspired-by components, not exact copies.\n`;
|
|
1605
|
+
break;
|
|
1606
|
+
|
|
1607
|
+
case 'reference':
|
|
1608
|
+
const refStyle = source.replace(/^like\s+/i, '').toLowerCase();
|
|
1609
|
+
const knownStyles: Record<string, string> = {
|
|
1610
|
+
'linear': 'Dark theme, purple accents, minimal, clean',
|
|
1611
|
+
'notion': 'Light theme, black/white, content-focused, lots of whitespace',
|
|
1612
|
+
'stripe': 'Professional, purple gradients, polished shadows',
|
|
1613
|
+
'vercel': 'Black/white, developer-focused, geometric',
|
|
1614
|
+
'github': 'Blue accents, familiar, dev-tool aesthetic',
|
|
1615
|
+
'figma': 'Purple accents, collaborative, modern',
|
|
1616
|
+
};
|
|
1617
|
+
const matchedStyle = Object.entries(knownStyles).find(([key]) =>
|
|
1618
|
+
refStyle.includes(key)
|
|
1619
|
+
);
|
|
1620
|
+
if (matchedStyle) {
|
|
1621
|
+
response += `## Reference Style: ${matchedStyle[0]}\n\n`;
|
|
1622
|
+
response += `**Characteristics:** ${matchedStyle[1]}\n\n`;
|
|
1623
|
+
} else {
|
|
1624
|
+
response += `## Reference Style: "${source}"\n\n`;
|
|
1625
|
+
response += `I'll apply a design language inspired by this reference.\n\n`;
|
|
1626
|
+
}
|
|
1627
|
+
response += `I'll generate components matching this aesthetic.\n`;
|
|
1628
|
+
break;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
response += `\n---\n\n`;
|
|
1632
|
+
response += `## Design Pattern Loaded\n\n`;
|
|
1633
|
+
response += `The design-clone pattern (33-design-clone) is now active.\n`;
|
|
1634
|
+
response += `Proceed with specific component requests like:\n`;
|
|
1635
|
+
response += `- "Create the navigation bar"\n`;
|
|
1636
|
+
response += `- "Build the hero section"\n`;
|
|
1637
|
+
response += `- "Generate the card components"\n`;
|
|
1638
|
+
|
|
1639
|
+
return {
|
|
1640
|
+
content: [{
|
|
1641
|
+
type: 'text' as const,
|
|
1642
|
+
text: response,
|
|
1643
|
+
}],
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
private async handleUpgrade(args: { areas?: string[]; severity?: string; dryRun?: boolean }) {
|
|
1648
|
+
const { areas = ['all'], severity = 'all', dryRun = false } = args;
|
|
1649
|
+
const context = this.gatherProjectContext();
|
|
1650
|
+
|
|
1651
|
+
let response = `# ⬆️ Project Upgrade Analysis\n\n`;
|
|
1652
|
+
|
|
1653
|
+
// Stack detection
|
|
1654
|
+
response += `## Your Stack (Preserving As-Is)\n\n`;
|
|
1655
|
+
response += `| Layer | Detected | Status |\n`;
|
|
1656
|
+
response += `|-------|----------|--------|\n`;
|
|
1657
|
+
|
|
1658
|
+
// ORM detection
|
|
1659
|
+
let orm = 'None';
|
|
1660
|
+
if (context.dependencies.includes('drizzle-orm')) orm = 'Drizzle';
|
|
1661
|
+
else if (context.dependencies.includes('@prisma/client')) orm = 'Prisma';
|
|
1662
|
+
else if (context.dependencies.includes('typeorm')) orm = 'TypeORM';
|
|
1663
|
+
else if (context.dependencies.includes('mongoose')) orm = 'Mongoose';
|
|
1664
|
+
response += `| ORM | ${orm} | ✓ Keeping |\n`;
|
|
1665
|
+
|
|
1666
|
+
// Auth detection
|
|
1667
|
+
let auth = 'None';
|
|
1668
|
+
if (context.dependencies.includes('@supabase/supabase-js')) auth = 'Supabase';
|
|
1669
|
+
else if (context.dependencies.includes('next-auth')) auth = 'NextAuth';
|
|
1670
|
+
else if (context.dependencies.includes('@clerk/nextjs')) auth = 'Clerk';
|
|
1671
|
+
else if (context.dependencies.includes('firebase')) auth = 'Firebase';
|
|
1672
|
+
response += `| Auth | ${auth} | ✓ Keeping |\n`;
|
|
1673
|
+
|
|
1674
|
+
// UI detection
|
|
1675
|
+
response += `| UI | ${context.uiLibrary || 'Tailwind'} | ✓ Keeping |\n`;
|
|
1676
|
+
|
|
1677
|
+
// Framework (always Next.js for now)
|
|
1678
|
+
const hasNext = context.dependencies.includes('next');
|
|
1679
|
+
response += `| Framework | ${hasNext ? 'Next.js' : 'Unknown'} | ✓ Keeping |\n`;
|
|
1680
|
+
|
|
1681
|
+
response += `\n---\n\n`;
|
|
1682
|
+
|
|
1683
|
+
// Scan for upgrade opportunities
|
|
1684
|
+
response += `## Upgrade Opportunities\n\n`;
|
|
1685
|
+
|
|
1686
|
+
const upgrades: Array<{ area: string; issue: string; severity: string; count: number }> = [];
|
|
1687
|
+
|
|
1688
|
+
// Check API routes
|
|
1689
|
+
if (context.existingApiRoutes.length > 0) {
|
|
1690
|
+
upgrades.push({
|
|
1691
|
+
area: 'API Routes',
|
|
1692
|
+
issue: 'Add error handling, validation, rate limiting',
|
|
1693
|
+
severity: 'HIGH',
|
|
1694
|
+
count: context.existingApiRoutes.length,
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
// Check components
|
|
1699
|
+
if (context.existingComponents.length > 0) {
|
|
1700
|
+
upgrades.push({
|
|
1701
|
+
area: 'Components',
|
|
1702
|
+
issue: 'Add loading states, error boundaries, accessibility',
|
|
1703
|
+
severity: 'MEDIUM',
|
|
1704
|
+
count: context.existingComponents.length,
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
// Check for tests
|
|
1709
|
+
const hasTests = context.dependencies.includes('@playwright/test') ||
|
|
1710
|
+
context.dependencies.includes('jest') ||
|
|
1711
|
+
context.dependencies.includes('vitest');
|
|
1712
|
+
if (!hasTests) {
|
|
1713
|
+
upgrades.push({
|
|
1714
|
+
area: 'Testing',
|
|
1715
|
+
issue: 'No test framework detected',
|
|
1716
|
+
severity: 'HIGH',
|
|
1717
|
+
count: 0,
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
// Check for Zod
|
|
1722
|
+
const hasZod = context.dependencies.includes('zod');
|
|
1723
|
+
if (!hasZod && context.existingApiRoutes.length > 0) {
|
|
1724
|
+
upgrades.push({
|
|
1725
|
+
area: 'Validation',
|
|
1726
|
+
issue: 'No Zod validation detected for API routes',
|
|
1727
|
+
severity: 'HIGH',
|
|
1728
|
+
count: context.existingApiRoutes.length,
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
// Display upgrades
|
|
1733
|
+
for (const upgrade of upgrades) {
|
|
1734
|
+
const icon = upgrade.severity === 'HIGH' ? '🔴' :
|
|
1735
|
+
upgrade.severity === 'MEDIUM' ? '🟡' : '🟢';
|
|
1736
|
+
response += `### ${icon} ${upgrade.area}\n`;
|
|
1737
|
+
response += `- **Issue:** ${upgrade.issue}\n`;
|
|
1738
|
+
if (upgrade.count > 0) {
|
|
1739
|
+
response += `- **Affected:** ${upgrade.count} files\n`;
|
|
1740
|
+
}
|
|
1741
|
+
response += `- **Severity:** ${upgrade.severity}\n\n`;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
if (upgrades.length === 0) {
|
|
1745
|
+
response += `✅ No major upgrade opportunities detected!\n\n`;
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
// Recommendations
|
|
1749
|
+
response += `---\n\n`;
|
|
1750
|
+
response += `## Recommended Actions\n\n`;
|
|
1751
|
+
|
|
1752
|
+
if (dryRun) {
|
|
1753
|
+
response += `**(Dry Run Mode - No changes will be made)**\n\n`;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
response += `1. Run \`run_audit\` for detailed code quality check\n`;
|
|
1757
|
+
response += `2. Use \`heal\` to auto-fix common issues\n`;
|
|
1758
|
+
response += `3. Request specific upgrades like:\n`;
|
|
1759
|
+
response += ` - "Add Zod validation to my API routes"\n`;
|
|
1760
|
+
response += ` - "Add error boundaries to components"\n`;
|
|
1761
|
+
response += ` - "Set up Playwright testing"\n\n`;
|
|
1762
|
+
|
|
1763
|
+
response += `---\n\n`;
|
|
1764
|
+
response += `**Key Principle:** Your stack stays the same. Only code quality patterns are upgraded.\n`;
|
|
1765
|
+
|
|
1766
|
+
return {
|
|
1767
|
+
content: [{
|
|
1768
|
+
type: 'text' as const,
|
|
1769
|
+
text: response,
|
|
1770
|
+
}],
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
private handleProjectStatus() {
|
|
1775
|
+
const cwd = process.cwd();
|
|
1776
|
+
const context = this.gatherProjectContext();
|
|
1777
|
+
|
|
1778
|
+
let response = `# 📊 Project Status\n\n`;
|
|
1779
|
+
response += `**Project:** ${context.projectName}\n\n`;
|
|
1780
|
+
|
|
1781
|
+
// Check for .codebakers.json state
|
|
1782
|
+
let state: Record<string, unknown> | null = null;
|
|
1783
|
+
try {
|
|
1784
|
+
const statePath = path.join(cwd, '.codebakers.json');
|
|
1785
|
+
if (fs.existsSync(statePath)) {
|
|
1786
|
+
state = JSON.parse(fs.readFileSync(statePath, 'utf-8'));
|
|
1787
|
+
}
|
|
1788
|
+
} catch {
|
|
1789
|
+
// No state file
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
// Check for PRD
|
|
1793
|
+
const prdPath = path.join(cwd, 'PRD.md');
|
|
1794
|
+
const hasPrd = fs.existsSync(prdPath);
|
|
1795
|
+
|
|
1796
|
+
// Check for PROJECT-STATE.md
|
|
1797
|
+
const projectStatePath = path.join(cwd, 'PROJECT-STATE.md');
|
|
1798
|
+
const hasProjectState = fs.existsSync(projectStatePath);
|
|
1799
|
+
|
|
1800
|
+
if (state && typeof state === 'object') {
|
|
1801
|
+
const s = state as Record<string, unknown>;
|
|
1802
|
+
|
|
1803
|
+
// Build progress
|
|
1804
|
+
if (s.build && typeof s.build === 'object') {
|
|
1805
|
+
const build = s.build as Record<string, unknown>;
|
|
1806
|
+
response += `## Build Progress\n\n`;
|
|
1807
|
+
const currentPhase = build.currentPhase as number || 0;
|
|
1808
|
+
const totalPhases = build.totalPhases as number || 1;
|
|
1809
|
+
const percent = Math.round((currentPhase / totalPhases) * 100);
|
|
1810
|
+
response += `**Phase ${currentPhase}/${totalPhases}** (${percent}%)\n\n`;
|
|
1811
|
+
|
|
1812
|
+
// Progress bar
|
|
1813
|
+
const filled = Math.round(percent / 10);
|
|
1814
|
+
const empty = 10 - filled;
|
|
1815
|
+
response += `[${'█'.repeat(filled)}${'░'.repeat(empty)}] ${percent}%\n\n`;
|
|
1816
|
+
|
|
1817
|
+
if (build.status) {
|
|
1818
|
+
response += `**Status:** ${build.status}\n\n`;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
// Current work
|
|
1823
|
+
if (s.currentWork && typeof s.currentWork === 'object') {
|
|
1824
|
+
const work = s.currentWork as Record<string, unknown>;
|
|
1825
|
+
response += `## Current Work\n\n`;
|
|
1826
|
+
if (work.activeFeature) {
|
|
1827
|
+
response += `**In Progress:** ${work.activeFeature}\n`;
|
|
1828
|
+
}
|
|
1829
|
+
if (work.summary) {
|
|
1830
|
+
response += `**Summary:** ${work.summary}\n`;
|
|
1831
|
+
}
|
|
1832
|
+
if (work.lastUpdated) {
|
|
1833
|
+
response += `**Last Updated:** ${work.lastUpdated}\n`;
|
|
1834
|
+
}
|
|
1835
|
+
response += `\n`;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
// Stack
|
|
1839
|
+
if (s.stack && typeof s.stack === 'object') {
|
|
1840
|
+
const stack = s.stack as Record<string, unknown>;
|
|
1841
|
+
response += `## Stack\n\n`;
|
|
1842
|
+
for (const [key, value] of Object.entries(stack)) {
|
|
1843
|
+
if (value) {
|
|
1844
|
+
response += `- **${key}:** ${value}\n`;
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
response += `\n`;
|
|
1848
|
+
}
|
|
1849
|
+
} else {
|
|
1850
|
+
response += `## Project Overview\n\n`;
|
|
1851
|
+
response += `- **PRD:** ${hasPrd ? '✅ Found' : '❌ Not found'}\n`;
|
|
1852
|
+
response += `- **State Tracking:** ${hasProjectState ? '✅ Found' : '❌ Not found'}\n`;
|
|
1853
|
+
response += `- **CodeBakers State:** ${state ? '✅ Found' : '❌ Not initialized'}\n\n`;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
// What's built
|
|
1857
|
+
response += `## What's Built\n\n`;
|
|
1858
|
+
response += `- **Components:** ${context.existingComponents.length}\n`;
|
|
1859
|
+
response += `- **API Routes:** ${context.existingApiRoutes.length}\n`;
|
|
1860
|
+
response += `- **Services:** ${context.existingServices.length}\n`;
|
|
1861
|
+
|
|
1862
|
+
if (context.hasAuth) response += `- ✅ Authentication\n`;
|
|
1863
|
+
if (context.hasDatabase) response += `- ✅ Database\n`;
|
|
1864
|
+
if (context.hasPayments) response += `- ✅ Payments\n`;
|
|
1865
|
+
|
|
1866
|
+
response += `\n`;
|
|
1867
|
+
|
|
1868
|
+
// Recent components
|
|
1869
|
+
if (context.existingComponents.length > 0) {
|
|
1870
|
+
response += `### Recent Components\n`;
|
|
1871
|
+
context.existingComponents.slice(0, 10).forEach(comp => {
|
|
1872
|
+
response += `- ${comp}\n`;
|
|
1873
|
+
});
|
|
1874
|
+
if (context.existingComponents.length > 10) {
|
|
1875
|
+
response += `- ... and ${context.existingComponents.length - 10} more\n`;
|
|
1876
|
+
}
|
|
1877
|
+
response += `\n`;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
response += `---\n\n`;
|
|
1881
|
+
response += `*Run \`upgrade\` to improve code quality or \`run_audit\` for detailed analysis.*`;
|
|
1882
|
+
|
|
1883
|
+
return {
|
|
1884
|
+
content: [{
|
|
1885
|
+
type: 'text' as const,
|
|
1886
|
+
text: response,
|
|
1887
|
+
}],
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1480
1891
|
async run(): Promise<void> {
|
|
1481
1892
|
const transport = new StdioServerTransport();
|
|
1482
1893
|
await this.server.connect(transport);
|