@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.
@@ -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:** 1.5.0
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codebakers/cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "CodeBakers CLI - Production patterns for AI-assisted development",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
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:** 1.5.0
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);