@codebakers/cli 3.3.12 โ†’ 3.3.13

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/src/mcp/server.ts CHANGED
@@ -1385,6 +1385,126 @@ class CodeBakersServer {
1385
1385
  properties: {},
1386
1386
  },
1387
1387
  },
1388
+ // ============================================
1389
+ // PROJECT TRACKING - Server-Side Dashboard
1390
+ // ============================================
1391
+ {
1392
+ name: 'project_sync',
1393
+ description:
1394
+ 'Sync project progress to the CodeBakers server for dashboard visualization. Call this after completing builds, features, tests, or other significant milestones. Data appears on the web dashboard at codebakers.ai/projects.',
1395
+ inputSchema: {
1396
+ type: 'object' as const,
1397
+ properties: {
1398
+ projectStatus: {
1399
+ type: 'string',
1400
+ enum: ['discovery', 'planning', 'building', 'testing', 'completed', 'paused', 'failed'],
1401
+ description: 'Current project status',
1402
+ },
1403
+ overallProgress: {
1404
+ type: 'number',
1405
+ description: 'Overall progress percentage (0-100)',
1406
+ },
1407
+ phases: {
1408
+ type: 'array',
1409
+ items: {
1410
+ type: 'object',
1411
+ properties: {
1412
+ phaseNumber: { type: 'number' },
1413
+ phaseName: { type: 'string' },
1414
+ phaseDescription: { type: 'string' },
1415
+ status: { type: 'string', enum: ['pending', 'in_progress', 'completed', 'skipped', 'failed'] },
1416
+ progress: { type: 'number' },
1417
+ aiConfidence: { type: 'number' },
1418
+ },
1419
+ },
1420
+ description: 'Build phases to sync',
1421
+ },
1422
+ events: {
1423
+ type: 'array',
1424
+ items: {
1425
+ type: 'object',
1426
+ properties: {
1427
+ eventType: { type: 'string' },
1428
+ eventTitle: { type: 'string' },
1429
+ eventDescription: { type: 'string' },
1430
+ filePath: { type: 'string' },
1431
+ fileAction: { type: 'string' },
1432
+ linesChanged: { type: 'number' },
1433
+ riskLevel: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
1434
+ },
1435
+ },
1436
+ description: 'Timeline events to record',
1437
+ },
1438
+ testRuns: {
1439
+ type: 'array',
1440
+ items: {
1441
+ type: 'object',
1442
+ properties: {
1443
+ testType: { type: 'string' },
1444
+ testCommand: { type: 'string' },
1445
+ passed: { type: 'boolean' },
1446
+ totalTests: { type: 'number' },
1447
+ passedTests: { type: 'number' },
1448
+ failedTests: { type: 'number' },
1449
+ skippedTests: { type: 'number' },
1450
+ durationMs: { type: 'number' },
1451
+ },
1452
+ },
1453
+ description: 'Test run results to sync',
1454
+ },
1455
+ riskFlags: {
1456
+ type: 'array',
1457
+ items: {
1458
+ type: 'object',
1459
+ properties: {
1460
+ riskLevel: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },
1461
+ riskCategory: { type: 'string' },
1462
+ riskTitle: { type: 'string' },
1463
+ riskDescription: { type: 'string' },
1464
+ triggerFile: { type: 'string' },
1465
+ aiRecommendation: { type: 'string' },
1466
+ },
1467
+ },
1468
+ description: 'Risk flags to create',
1469
+ },
1470
+ resources: {
1471
+ type: 'array',
1472
+ items: {
1473
+ type: 'object',
1474
+ properties: {
1475
+ resourceType: { type: 'string' },
1476
+ inputTokens: { type: 'number' },
1477
+ outputTokens: { type: 'number' },
1478
+ totalTokens: { type: 'number' },
1479
+ durationMs: { type: 'number' },
1480
+ estimatedCostMillicents: { type: 'number' },
1481
+ },
1482
+ },
1483
+ description: 'Resource usage to track (API calls, tokens, etc.)',
1484
+ },
1485
+ createSnapshot: {
1486
+ type: 'object',
1487
+ properties: {
1488
+ snapshotName: { type: 'string' },
1489
+ snapshotDescription: { type: 'string' },
1490
+ isAutomatic: { type: 'boolean' },
1491
+ gitCommitHash: { type: 'string' },
1492
+ gitBranch: { type: 'string' },
1493
+ },
1494
+ description: 'Create a rollback snapshot',
1495
+ },
1496
+ },
1497
+ },
1498
+ },
1499
+ {
1500
+ name: 'project_dashboard_url',
1501
+ description:
1502
+ 'Get the URL to view the project dashboard on codebakers.ai. Use when user says "show dashboard", "view progress online", or "open project page".',
1503
+ inputSchema: {
1504
+ type: 'object' as const,
1505
+ properties: {},
1506
+ },
1507
+ },
1388
1508
  ],
1389
1509
  }));
1390
1510
 
@@ -1562,6 +1682,66 @@ class CodeBakersServer {
1562
1682
  case 'guardian_status':
1563
1683
  return this.handleGuardianStatus();
1564
1684
 
1685
+ // Project Tracking - Server-Side Dashboard
1686
+ case 'project_sync':
1687
+ return this.handleProjectSync(args as {
1688
+ projectStatus?: string;
1689
+ overallProgress?: number;
1690
+ phases?: Array<{
1691
+ phaseNumber: number;
1692
+ phaseName: string;
1693
+ phaseDescription?: string;
1694
+ status?: string;
1695
+ progress?: number;
1696
+ aiConfidence?: number;
1697
+ }>;
1698
+ events?: Array<{
1699
+ eventType: string;
1700
+ eventTitle: string;
1701
+ eventDescription?: string;
1702
+ filePath?: string;
1703
+ fileAction?: string;
1704
+ linesChanged?: number;
1705
+ riskLevel?: string;
1706
+ }>;
1707
+ testRuns?: Array<{
1708
+ testType: string;
1709
+ testCommand?: string;
1710
+ passed: boolean;
1711
+ totalTests: number;
1712
+ passedTests: number;
1713
+ failedTests: number;
1714
+ skippedTests: number;
1715
+ durationMs?: number;
1716
+ }>;
1717
+ riskFlags?: Array<{
1718
+ riskLevel: string;
1719
+ riskCategory: string;
1720
+ riskTitle: string;
1721
+ riskDescription?: string;
1722
+ triggerFile?: string;
1723
+ aiRecommendation?: string;
1724
+ }>;
1725
+ resources?: Array<{
1726
+ resourceType: string;
1727
+ inputTokens?: number;
1728
+ outputTokens?: number;
1729
+ totalTokens?: number;
1730
+ durationMs?: number;
1731
+ estimatedCostMillicents?: number;
1732
+ }>;
1733
+ createSnapshot?: {
1734
+ snapshotName: string;
1735
+ snapshotDescription?: string;
1736
+ isAutomatic?: boolean;
1737
+ gitCommitHash?: string;
1738
+ gitBranch?: string;
1739
+ };
1740
+ });
1741
+
1742
+ case 'project_dashboard_url':
1743
+ return this.handleProjectDashboardUrl();
1744
+
1565
1745
  default:
1566
1746
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
1567
1747
  }
@@ -7076,6 +7256,312 @@ ${events.includes('call-started') ? ` case 'call-started':
7076
7256
  return { content: [{ type: 'text' as const, text: response }] };
7077
7257
  }
7078
7258
 
7259
+ // ============================================================================
7260
+ // PROJECT TRACKING - Server-Side Dashboard
7261
+ // ============================================================================
7262
+
7263
+ /**
7264
+ * Sync project progress to the CodeBakers server
7265
+ */
7266
+ private async handleProjectSync(args: {
7267
+ projectStatus?: string;
7268
+ overallProgress?: number;
7269
+ phases?: Array<{
7270
+ phaseNumber: number;
7271
+ phaseName: string;
7272
+ phaseDescription?: string;
7273
+ status?: string;
7274
+ progress?: number;
7275
+ aiConfidence?: number;
7276
+ }>;
7277
+ events?: Array<{
7278
+ eventType: string;
7279
+ eventTitle: string;
7280
+ eventDescription?: string;
7281
+ filePath?: string;
7282
+ fileAction?: string;
7283
+ linesChanged?: number;
7284
+ riskLevel?: string;
7285
+ }>;
7286
+ testRuns?: Array<{
7287
+ testType: string;
7288
+ testCommand?: string;
7289
+ passed: boolean;
7290
+ totalTests: number;
7291
+ passedTests: number;
7292
+ failedTests: number;
7293
+ skippedTests: number;
7294
+ durationMs?: number;
7295
+ }>;
7296
+ riskFlags?: Array<{
7297
+ riskLevel: string;
7298
+ riskCategory: string;
7299
+ riskTitle: string;
7300
+ riskDescription?: string;
7301
+ triggerFile?: string;
7302
+ aiRecommendation?: string;
7303
+ }>;
7304
+ resources?: Array<{
7305
+ resourceType: string;
7306
+ inputTokens?: number;
7307
+ outputTokens?: number;
7308
+ totalTokens?: number;
7309
+ durationMs?: number;
7310
+ estimatedCostMillicents?: number;
7311
+ }>;
7312
+ createSnapshot?: {
7313
+ snapshotName: string;
7314
+ snapshotDescription?: string;
7315
+ isAutomatic?: boolean;
7316
+ gitCommitHash?: string;
7317
+ gitBranch?: string;
7318
+ };
7319
+ }) {
7320
+ const cwd = process.cwd();
7321
+
7322
+ try {
7323
+ // Import API functions dynamically
7324
+ const apiModule = await import('../lib/api.js');
7325
+ const { getOrCreateProject, syncProjectData, createProjectHash } = apiModule;
7326
+
7327
+ // Read package.json for project info
7328
+ let projectName = path.basename(cwd);
7329
+ let packageName: string | undefined;
7330
+
7331
+ const packageJsonPath = path.join(cwd, 'package.json');
7332
+ if (fs.existsSync(packageJsonPath)) {
7333
+ try {
7334
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
7335
+ projectName = packageJson.name || projectName;
7336
+ packageName = packageJson.name;
7337
+ } catch {
7338
+ // Ignore parse errors
7339
+ }
7340
+ }
7341
+
7342
+ // Create project hash
7343
+ const projectHash = createProjectHash(cwd, packageName);
7344
+
7345
+ // Read .codebakers.json for detected stack
7346
+ let detectedStack: Record<string, string> | undefined;
7347
+ const codebakersPath = path.join(cwd, '.codebakers.json');
7348
+ if (fs.existsSync(codebakersPath)) {
7349
+ try {
7350
+ const codebakersState = JSON.parse(fs.readFileSync(codebakersPath, 'utf-8'));
7351
+ if (codebakersState.stack) {
7352
+ detectedStack = codebakersState.stack;
7353
+ }
7354
+ } catch {
7355
+ // Ignore parse errors
7356
+ }
7357
+ }
7358
+
7359
+ // Get or create project on server
7360
+ const authHeaders = this.getAuthHeaders();
7361
+ const { projectId, isNew } = await getOrCreateProject(
7362
+ projectHash,
7363
+ projectName,
7364
+ undefined,
7365
+ detectedStack,
7366
+ authHeaders
7367
+ );
7368
+
7369
+ // Build sync data
7370
+ const syncData: Record<string, unknown> = {};
7371
+
7372
+ // Add project status if provided
7373
+ if (args.projectStatus || args.overallProgress !== undefined) {
7374
+ const projectUpdate: Record<string, unknown> = {};
7375
+ if (args.projectStatus) {
7376
+ projectUpdate.status = args.projectStatus;
7377
+ }
7378
+ if (args.overallProgress !== undefined) {
7379
+ projectUpdate.overallProgress = args.overallProgress;
7380
+ }
7381
+ syncData.project = projectUpdate;
7382
+ }
7383
+
7384
+ // Add phases if provided
7385
+ if (args.phases && args.phases.length > 0) {
7386
+ syncData.phases = args.phases.map(p => ({
7387
+ phaseNumber: p.phaseNumber,
7388
+ phaseName: p.phaseName,
7389
+ phaseDescription: p.phaseDescription,
7390
+ status: p.status as 'pending' | 'in_progress' | 'completed' | 'skipped' | 'failed' | undefined,
7391
+ progress: p.progress,
7392
+ aiConfidence: p.aiConfidence,
7393
+ }));
7394
+ }
7395
+
7396
+ // Add events if provided
7397
+ if (args.events && args.events.length > 0) {
7398
+ syncData.events = args.events.map(e => ({
7399
+ eventType: e.eventType,
7400
+ eventTitle: e.eventTitle,
7401
+ eventDescription: e.eventDescription,
7402
+ filePath: e.filePath,
7403
+ fileAction: e.fileAction,
7404
+ linesChanged: e.linesChanged,
7405
+ riskLevel: e.riskLevel as 'low' | 'medium' | 'high' | 'critical' | undefined,
7406
+ }));
7407
+ }
7408
+
7409
+ // Add test runs if provided
7410
+ if (args.testRuns && args.testRuns.length > 0) {
7411
+ syncData.testRuns = args.testRuns;
7412
+ }
7413
+
7414
+ // Add risk flags if provided
7415
+ if (args.riskFlags && args.riskFlags.length > 0) {
7416
+ syncData.riskFlags = args.riskFlags.map(r => ({
7417
+ riskLevel: r.riskLevel as 'low' | 'medium' | 'high' | 'critical',
7418
+ riskCategory: r.riskCategory,
7419
+ riskTitle: r.riskTitle,
7420
+ riskDescription: r.riskDescription,
7421
+ triggerFile: r.triggerFile,
7422
+ aiRecommendation: r.aiRecommendation,
7423
+ }));
7424
+ }
7425
+
7426
+ // Add resources if provided
7427
+ if (args.resources && args.resources.length > 0) {
7428
+ syncData.resources = args.resources;
7429
+ }
7430
+
7431
+ // Add snapshot if provided
7432
+ if (args.createSnapshot) {
7433
+ // Get git info if available
7434
+ let gitCommitHash: string | undefined;
7435
+ let gitBranch: string | undefined;
7436
+
7437
+ try {
7438
+ gitCommitHash = execSync('git rev-parse HEAD', { cwd, encoding: 'utf-8' }).trim();
7439
+ gitBranch = execSync('git rev-parse --abbrev-ref HEAD', { cwd, encoding: 'utf-8' }).trim();
7440
+ } catch {
7441
+ // Git not available or not a repo
7442
+ }
7443
+
7444
+ syncData.createSnapshot = {
7445
+ snapshotName: args.createSnapshot.snapshotName,
7446
+ snapshotDescription: args.createSnapshot.snapshotDescription,
7447
+ isAutomatic: args.createSnapshot.isAutomatic,
7448
+ gitCommitHash: args.createSnapshot.gitCommitHash || gitCommitHash,
7449
+ gitBranch: args.createSnapshot.gitBranch || gitBranch,
7450
+ };
7451
+ }
7452
+
7453
+ // Sync to server
7454
+ const result = await syncProjectData(projectId, syncData, authHeaders);
7455
+
7456
+ // Build response
7457
+ let response = `# ๐Ÿ“Š Project Synced to Dashboard\n\n`;
7458
+
7459
+ if (isNew) {
7460
+ response += `โœจ **New project registered:** ${projectName}\n\n`;
7461
+ }
7462
+
7463
+ response += `**Project ID:** \`${projectId}\`\n\n`;
7464
+
7465
+ response += `## Synced Data\n\n`;
7466
+
7467
+ const synced = result.synced;
7468
+ if (synced.project) response += `- โœ… Project status updated\n`;
7469
+ if (synced.phases > 0) response += `- โœ… ${synced.phases} phase(s) synced\n`;
7470
+ if (synced.events > 0) response += `- โœ… ${synced.events} event(s) recorded\n`;
7471
+ if (synced.testRuns > 0) response += `- โœ… ${synced.testRuns} test run(s) logged\n`;
7472
+ if (synced.riskFlags > 0) response += `- โœ… ${synced.riskFlags} risk flag(s) created\n`;
7473
+ if (synced.resources > 0) response += `- โœ… ${synced.resources} resource record(s) added\n`;
7474
+ if (synced.snapshot) response += `- โœ… Rollback snapshot created\n`;
7475
+
7476
+ response += `\n---\n\n`;
7477
+ response += `๐Ÿ“ˆ **View Dashboard:** https://codebakers.ai/projects/${projectId}\n`;
7478
+
7479
+ // Add update notice if available
7480
+ response += this.getUpdateNotice();
7481
+
7482
+ return { content: [{ type: 'text' as const, text: response }] };
7483
+
7484
+ } catch (error) {
7485
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
7486
+ let response = `# โŒ Sync Failed\n\n`;
7487
+ response += `Could not sync project to server.\n\n`;
7488
+ response += `**Error:** ${errorMessage}\n\n`;
7489
+ response += `This may be due to:\n`;
7490
+ response += `- Network connectivity issues\n`;
7491
+ response += `- Invalid API key or expired trial\n`;
7492
+ response += `- Server maintenance\n\n`;
7493
+ response += `Your local project is unaffected. Try again later.\n`;
7494
+
7495
+ return { content: [{ type: 'text' as const, text: response }] };
7496
+ }
7497
+ }
7498
+
7499
+ /**
7500
+ * Get the URL to view the project dashboard
7501
+ */
7502
+ private async handleProjectDashboardUrl() {
7503
+ const cwd = process.cwd();
7504
+
7505
+ try {
7506
+ const { getOrCreateProject, createProjectHash } = await import('../lib/api.js');
7507
+
7508
+ // Read package.json for project info
7509
+ let projectName = path.basename(cwd);
7510
+ let packageName: string | undefined;
7511
+
7512
+ const packageJsonPath = path.join(cwd, 'package.json');
7513
+ if (fs.existsSync(packageJsonPath)) {
7514
+ try {
7515
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
7516
+ projectName = packageJson.name || projectName;
7517
+ packageName = packageJson.name;
7518
+ } catch {
7519
+ // Ignore parse errors
7520
+ }
7521
+ }
7522
+
7523
+ // Create project hash
7524
+ const projectHash = createProjectHash(cwd, packageName);
7525
+
7526
+ // Get or create project on server (this ensures the project exists)
7527
+ const authHeaders = this.getAuthHeaders();
7528
+ const { projectId } = await getOrCreateProject(
7529
+ projectHash,
7530
+ projectName,
7531
+ undefined,
7532
+ undefined,
7533
+ authHeaders
7534
+ );
7535
+
7536
+ const dashboardUrl = `https://codebakers.ai/projects/${projectId}`;
7537
+
7538
+ let response = `# ๐Ÿ“Š Project Dashboard\n\n`;
7539
+ response += `**Project:** ${projectName}\n\n`;
7540
+ response += `**Dashboard URL:**\n${dashboardUrl}\n\n`;
7541
+ response += `Open this URL in your browser to view:\n`;
7542
+ response += `- ๐Ÿ“ˆ Build progress and phases\n`;
7543
+ response += `- ๐Ÿงช Test run history and results\n`;
7544
+ response += `- ๐Ÿ“ File tree evolution\n`;
7545
+ response += `- ๐Ÿ”— Dependency graph\n`;
7546
+ response += `- โš ๏ธ Risk flags and recommendations\n`;
7547
+ response += `- ๐Ÿ’ฐ Resource usage (tokens, API calls)\n`;
7548
+ response += `- ๐Ÿ“ธ Rollback snapshots\n`;
7549
+
7550
+ // Add update notice if available
7551
+ response += this.getUpdateNotice();
7552
+
7553
+ return { content: [{ type: 'text' as const, text: response }] };
7554
+
7555
+ } catch (error) {
7556
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
7557
+ let response = `# โŒ Could Not Get Dashboard URL\n\n`;
7558
+ response += `**Error:** ${errorMessage}\n\n`;
7559
+ response += `Make sure you are logged in with a valid API key or trial.\n`;
7560
+
7561
+ return { content: [{ type: 'text' as const, text: response }] };
7562
+ }
7563
+ }
7564
+
7079
7565
  /**
7080
7566
  * Ripple Check - Detect all files affected by a change to a type/schema/function
7081
7567
  * Searches the codebase for imports and usages of the entity