@codebakers/cli 3.8.9 → 3.9.1

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/index.js CHANGED
@@ -34,7 +34,7 @@ const api_js_1 = require("./lib/api.js");
34
34
  // ============================================
35
35
  // Automatic Update Notification
36
36
  // ============================================
37
- const CURRENT_VERSION = '3.3.7';
37
+ const CURRENT_VERSION = '3.9.1';
38
38
  async function checkForUpdatesInBackground() {
39
39
  // Check if we have a valid cached result first (fast path)
40
40
  const cached = (0, config_js_2.getCachedUpdateInfo)();
@@ -195,7 +195,7 @@ const program = new commander_1.Command();
195
195
  program
196
196
  .name('codebakers')
197
197
  .description('CodeBakers CLI - Production patterns for AI-assisted development')
198
- .version('3.3.0');
198
+ .version('3.9.1');
199
199
  // Zero-friction trial entry (no signup required)
200
200
  program
201
201
  .command('go')
@@ -1440,6 +1440,19 @@ class CodeBakersServer {
1440
1440
  properties: {},
1441
1441
  },
1442
1442
  },
1443
+ {
1444
+ name: 'resume_session',
1445
+ description: 'IMPORTANT: Call this AUTOMATICALLY at the start of any session, especially after conversation compaction/summarization. Returns full project context including: project name, PRD summary, in-progress tasks, completed tasks, blockers, and a suggested next action. This prevents losing context after Claude Code or Cursor compacts the conversation. Use when: (1) starting a new session, (2) conversation was just summarized, (3) you are unsure what you were working on, (4) user says "where was I?" or "what should I do next?".',
1446
+ inputSchema: {
1447
+ type: 'object',
1448
+ properties: {
1449
+ reason: {
1450
+ type: 'string',
1451
+ description: 'Why you are calling this (e.g., "session start", "after compaction", "context lost")',
1452
+ },
1453
+ },
1454
+ },
1455
+ },
1443
1456
  // Engineering workflow tools
1444
1457
  ...engineering_tools_js_1.ENGINEERING_TOOLS,
1445
1458
  ],
@@ -1570,6 +1583,8 @@ class CodeBakersServer {
1570
1583
  return this.handleProjectSync(args);
1571
1584
  case 'project_dashboard_url':
1572
1585
  return this.handleProjectDashboardUrl();
1586
+ case 'resume_session':
1587
+ return this.handleResumeSession(args);
1573
1588
  // Engineering workflow tools
1574
1589
  case 'engineering_start':
1575
1590
  case 'engineering_scope':
@@ -3354,6 +3369,200 @@ Just describe what you want to build! I'll automatically:
3354
3369
  }],
3355
3370
  };
3356
3371
  }
3372
+ handleResumeSession(args) {
3373
+ const { reason = 'session start' } = args;
3374
+ const cwd = process.cwd();
3375
+ // Initialize state object
3376
+ const state = {
3377
+ isSetUp: false,
3378
+ projectName: '',
3379
+ projectType: '',
3380
+ hasPrd: false,
3381
+ prdSummary: '',
3382
+ inProgressTasks: [],
3383
+ completedTasks: [],
3384
+ blockers: [],
3385
+ lastSession: '',
3386
+ suggestion: '',
3387
+ status: 'UNKNOWN',
3388
+ };
3389
+ // Check if CodeBakers is set up
3390
+ const codebakersJsonPath = path.join(cwd, '.codebakers.json');
3391
+ if (!fs.existsSync(codebakersJsonPath)) {
3392
+ state.suggestion = 'Project not set up. Run `codebakers go` in the terminal to start.';
3393
+ state.status = 'NOT_INITIALIZED';
3394
+ }
3395
+ else {
3396
+ state.isSetUp = true;
3397
+ // Read .codebakers.json
3398
+ try {
3399
+ const cbState = JSON.parse(fs.readFileSync(codebakersJsonPath, 'utf-8'));
3400
+ state.projectName = cbState.projectName || '';
3401
+ state.projectType = cbState.projectType || '';
3402
+ }
3403
+ catch {
3404
+ // Ignore parse errors
3405
+ }
3406
+ }
3407
+ // Check for PRD.md
3408
+ const prdPath = path.join(cwd, 'PRD.md');
3409
+ if (fs.existsSync(prdPath)) {
3410
+ state.hasPrd = true;
3411
+ try {
3412
+ const prdContent = fs.readFileSync(prdPath, 'utf-8');
3413
+ // Extract one-liner if present
3414
+ const oneLineMatch = prdContent.match(/\*\*One-liner:\*\*\s*(.+)/);
3415
+ if (oneLineMatch) {
3416
+ state.prdSummary = oneLineMatch[1].trim();
3417
+ }
3418
+ else {
3419
+ // Get first non-comment, non-header line
3420
+ const lines = prdContent.split('\n').filter(l => l.trim() && !l.startsWith('#') && !l.startsWith('<!--'));
3421
+ if (lines[0]) {
3422
+ state.prdSummary = lines[0].substring(0, 150);
3423
+ }
3424
+ }
3425
+ }
3426
+ catch {
3427
+ // Ignore read errors
3428
+ }
3429
+ }
3430
+ // Read PROJECT-STATE.md for tasks
3431
+ const projectStatePath = path.join(cwd, 'PROJECT-STATE.md');
3432
+ if (fs.existsSync(projectStatePath)) {
3433
+ try {
3434
+ const content = fs.readFileSync(projectStatePath, 'utf-8');
3435
+ // Extract In Progress section
3436
+ const inProgressMatch = content.match(/## In Progress\n([\s\S]*?)(?=\n##|$)/);
3437
+ if (inProgressMatch) {
3438
+ const lines = inProgressMatch[1].split('\n')
3439
+ .filter(l => l.trim().startsWith('-'))
3440
+ .map(l => l.replace(/^-\s*/, '').trim())
3441
+ .filter(l => l && !l.startsWith('<!--'));
3442
+ state.inProgressTasks = lines;
3443
+ }
3444
+ // Extract Completed section (last 5)
3445
+ const completedMatch = content.match(/## Completed\n([\s\S]*?)(?=\n##|$)/);
3446
+ if (completedMatch) {
3447
+ const lines = completedMatch[1].split('\n')
3448
+ .filter(l => l.trim().startsWith('-'))
3449
+ .map(l => l.replace(/^-\s*/, '').trim())
3450
+ .filter(l => l && !l.startsWith('<!--'));
3451
+ state.completedTasks = lines.slice(-5);
3452
+ }
3453
+ // Extract Blockers section
3454
+ const blockersMatch = content.match(/## Blockers\n([\s\S]*?)(?=\n##|$)/);
3455
+ if (blockersMatch) {
3456
+ const lines = blockersMatch[1].split('\n')
3457
+ .filter(l => l.trim().startsWith('-'))
3458
+ .map(l => l.replace(/^-\s*/, '').trim())
3459
+ .filter(l => l && !l.startsWith('<!--'));
3460
+ state.blockers = lines;
3461
+ }
3462
+ }
3463
+ catch {
3464
+ // Ignore read errors
3465
+ }
3466
+ }
3467
+ // Read DEVLOG for last session
3468
+ const devlogPath = path.join(cwd, '.codebakers', 'DEVLOG.md');
3469
+ if (fs.existsSync(devlogPath)) {
3470
+ try {
3471
+ const content = fs.readFileSync(devlogPath, 'utf-8');
3472
+ // Get first session entry
3473
+ const sessionMatch = content.match(/## .+?\n\*\*Session:\*\*\s*(.+)/);
3474
+ if (sessionMatch) {
3475
+ state.lastSession = sessionMatch[1].trim();
3476
+ }
3477
+ // Get "What was done" from most recent entry
3478
+ const whatDoneMatch = content.match(/### What was done:\n([\s\S]*?)(?=\n###|---|\n\n)/);
3479
+ if (whatDoneMatch && !state.lastSession) {
3480
+ const lines = whatDoneMatch[1].split('\n')
3481
+ .filter(l => l.trim().startsWith('-'))
3482
+ .map(l => l.replace(/^-\s*/, '').trim());
3483
+ if (lines[0]) {
3484
+ state.lastSession = lines[0];
3485
+ }
3486
+ }
3487
+ }
3488
+ catch {
3489
+ // Ignore read errors
3490
+ }
3491
+ }
3492
+ // Determine suggestion and status based on state
3493
+ if (!state.isSetUp) {
3494
+ state.status = 'NOT_INITIALIZED';
3495
+ state.suggestion = 'Run `codebakers go` in the terminal to set up the project.';
3496
+ }
3497
+ else if (state.blockers.length > 0) {
3498
+ state.status = 'BLOCKED';
3499
+ state.suggestion = `BLOCKED: ${state.blockers[0]}. Address this blocker first.`;
3500
+ }
3501
+ else if (state.inProgressTasks.length > 0) {
3502
+ state.status = 'IN_PROGRESS';
3503
+ state.suggestion = `CONTINUE: ${state.inProgressTasks[0]}`;
3504
+ }
3505
+ else if (state.hasPrd && state.completedTasks.length === 0) {
3506
+ state.status = 'READY_TO_BUILD';
3507
+ state.suggestion = 'START BUILDING: PRD exists. Begin implementing features from PRD.md';
3508
+ }
3509
+ else if (!state.hasPrd) {
3510
+ state.status = 'NEEDS_PRD';
3511
+ state.suggestion = 'DEFINE PROJECT: No PRD found. Ask the user what they want to build.';
3512
+ }
3513
+ else {
3514
+ state.status = 'READY';
3515
+ state.suggestion = 'READY: Project set up. Ask the user for the next feature to build.';
3516
+ }
3517
+ // Build response
3518
+ let response = `# 🔄 Session Context Recovered\n\n`;
3519
+ response += `**Reason:** ${reason}\n\n`;
3520
+ response += `## Project\n`;
3521
+ response += `- **Name:** ${state.projectName || 'Unknown'}\n`;
3522
+ response += `- **Type:** ${state.projectType || 'Not set'}\n`;
3523
+ response += `- **Status:** ${state.status}\n`;
3524
+ if (state.prdSummary) {
3525
+ response += `- **Description:** ${state.prdSummary}\n`;
3526
+ }
3527
+ response += `\n`;
3528
+ if (state.blockers.length > 0) {
3529
+ response += `## ⚠️ BLOCKERS (Address First!)\n`;
3530
+ for (const blocker of state.blockers) {
3531
+ response += `- ${blocker}\n`;
3532
+ }
3533
+ response += `\n`;
3534
+ }
3535
+ if (state.inProgressTasks.length > 0) {
3536
+ response += `## 🔄 In Progress\n`;
3537
+ for (const task of state.inProgressTasks) {
3538
+ response += `- ${task}\n`;
3539
+ }
3540
+ response += `\n`;
3541
+ }
3542
+ if (state.completedTasks.length > 0) {
3543
+ response += `## ✅ Recently Completed\n`;
3544
+ for (const task of state.completedTasks) {
3545
+ response += `- ${task}\n`;
3546
+ }
3547
+ response += `\n`;
3548
+ }
3549
+ if (state.lastSession) {
3550
+ response += `## 📅 Last Session\n`;
3551
+ response += `${state.lastSession}\n\n`;
3552
+ }
3553
+ response += `---\n\n`;
3554
+ response += `## 🎯 NEXT ACTION\n\n`;
3555
+ response += `**${state.suggestion}**\n\n`;
3556
+ response += `---\n\n`;
3557
+ response += `*Context recovered via CodeBakers resume_session. `;
3558
+ response += `This tool should be called automatically after conversation compaction.*`;
3559
+ return {
3560
+ content: [{
3561
+ type: 'text',
3562
+ text: response,
3563
+ }],
3564
+ };
3565
+ }
3357
3566
  handleRunTests(args) {
3358
3567
  const { filter, watch = false } = args;
3359
3568
  const cwd = process.cwd();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codebakers/cli",
3
- "version": "3.8.9",
3
+ "version": "3.9.1",
4
4
  "description": "CodeBakers CLI - Production patterns for AI-assisted development",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -34,7 +34,7 @@ import { join } from 'path';
34
34
  // Automatic Update Notification
35
35
  // ============================================
36
36
 
37
- const CURRENT_VERSION = '3.3.7';
37
+ const CURRENT_VERSION = '3.9.1';
38
38
 
39
39
  async function checkForUpdatesInBackground(): Promise<void> {
40
40
  // Check if we have a valid cached result first (fast path)
@@ -216,7 +216,7 @@ const program = new Command();
216
216
  program
217
217
  .name('codebakers')
218
218
  .description('CodeBakers CLI - Production patterns for AI-assisted development')
219
- .version('3.3.0');
219
+ .version('3.9.1');
220
220
 
221
221
  // Zero-friction trial entry (no signup required)
222
222
  program
package/src/mcp/server.ts CHANGED
@@ -1552,6 +1552,20 @@ class CodeBakersServer {
1552
1552
  properties: {},
1553
1553
  },
1554
1554
  },
1555
+ {
1556
+ name: 'resume_session',
1557
+ description:
1558
+ 'IMPORTANT: Call this AUTOMATICALLY at the start of any session, especially after conversation compaction/summarization. Returns full project context including: project name, PRD summary, in-progress tasks, completed tasks, blockers, and a suggested next action. This prevents losing context after Claude Code or Cursor compacts the conversation. Use when: (1) starting a new session, (2) conversation was just summarized, (3) you are unsure what you were working on, (4) user says "where was I?" or "what should I do next?".',
1559
+ inputSchema: {
1560
+ type: 'object' as const,
1561
+ properties: {
1562
+ reason: {
1563
+ type: 'string',
1564
+ description: 'Why you are calling this (e.g., "session start", "after compaction", "context lost")',
1565
+ },
1566
+ },
1567
+ },
1568
+ },
1555
1569
  // Engineering workflow tools
1556
1570
  ...ENGINEERING_TOOLS,
1557
1571
  ],
@@ -1797,6 +1811,9 @@ class CodeBakersServer {
1797
1811
  case 'project_dashboard_url':
1798
1812
  return this.handleProjectDashboardUrl();
1799
1813
 
1814
+ case 'resume_session':
1815
+ return this.handleResumeSession(args as { reason?: string });
1816
+
1800
1817
  // Engineering workflow tools
1801
1818
  case 'engineering_start':
1802
1819
  case 'engineering_scope':
@@ -3784,6 +3801,211 @@ Just describe what you want to build! I'll automatically:
3784
3801
  };
3785
3802
  }
3786
3803
 
3804
+ private handleResumeSession(args: { reason?: string }) {
3805
+ const { reason = 'session start' } = args;
3806
+ const cwd = process.cwd();
3807
+
3808
+ // Initialize state object
3809
+ const state = {
3810
+ isSetUp: false,
3811
+ projectName: '',
3812
+ projectType: '',
3813
+ hasPrd: false,
3814
+ prdSummary: '',
3815
+ inProgressTasks: [] as string[],
3816
+ completedTasks: [] as string[],
3817
+ blockers: [] as string[],
3818
+ lastSession: '',
3819
+ suggestion: '',
3820
+ status: 'UNKNOWN',
3821
+ };
3822
+
3823
+ // Check if CodeBakers is set up
3824
+ const codebakersJsonPath = path.join(cwd, '.codebakers.json');
3825
+ if (!fs.existsSync(codebakersJsonPath)) {
3826
+ state.suggestion = 'Project not set up. Run `codebakers go` in the terminal to start.';
3827
+ state.status = 'NOT_INITIALIZED';
3828
+ } else {
3829
+ state.isSetUp = true;
3830
+
3831
+ // Read .codebakers.json
3832
+ try {
3833
+ const cbState = JSON.parse(fs.readFileSync(codebakersJsonPath, 'utf-8'));
3834
+ state.projectName = cbState.projectName || '';
3835
+ state.projectType = cbState.projectType || '';
3836
+ } catch {
3837
+ // Ignore parse errors
3838
+ }
3839
+ }
3840
+
3841
+ // Check for PRD.md
3842
+ const prdPath = path.join(cwd, 'PRD.md');
3843
+ if (fs.existsSync(prdPath)) {
3844
+ state.hasPrd = true;
3845
+ try {
3846
+ const prdContent = fs.readFileSync(prdPath, 'utf-8');
3847
+ // Extract one-liner if present
3848
+ const oneLineMatch = prdContent.match(/\*\*One-liner:\*\*\s*(.+)/);
3849
+ if (oneLineMatch) {
3850
+ state.prdSummary = oneLineMatch[1].trim();
3851
+ } else {
3852
+ // Get first non-comment, non-header line
3853
+ const lines = prdContent.split('\n').filter(l =>
3854
+ l.trim() && !l.startsWith('#') && !l.startsWith('<!--')
3855
+ );
3856
+ if (lines[0]) {
3857
+ state.prdSummary = lines[0].substring(0, 150);
3858
+ }
3859
+ }
3860
+ } catch {
3861
+ // Ignore read errors
3862
+ }
3863
+ }
3864
+
3865
+ // Read PROJECT-STATE.md for tasks
3866
+ const projectStatePath = path.join(cwd, 'PROJECT-STATE.md');
3867
+ if (fs.existsSync(projectStatePath)) {
3868
+ try {
3869
+ const content = fs.readFileSync(projectStatePath, 'utf-8');
3870
+
3871
+ // Extract In Progress section
3872
+ const inProgressMatch = content.match(/## In Progress\n([\s\S]*?)(?=\n##|$)/);
3873
+ if (inProgressMatch) {
3874
+ const lines = inProgressMatch[1].split('\n')
3875
+ .filter(l => l.trim().startsWith('-'))
3876
+ .map(l => l.replace(/^-\s*/, '').trim())
3877
+ .filter(l => l && !l.startsWith('<!--'));
3878
+ state.inProgressTasks = lines;
3879
+ }
3880
+
3881
+ // Extract Completed section (last 5)
3882
+ const completedMatch = content.match(/## Completed\n([\s\S]*?)(?=\n##|$)/);
3883
+ if (completedMatch) {
3884
+ const lines = completedMatch[1].split('\n')
3885
+ .filter(l => l.trim().startsWith('-'))
3886
+ .map(l => l.replace(/^-\s*/, '').trim())
3887
+ .filter(l => l && !l.startsWith('<!--'));
3888
+ state.completedTasks = lines.slice(-5);
3889
+ }
3890
+
3891
+ // Extract Blockers section
3892
+ const blockersMatch = content.match(/## Blockers\n([\s\S]*?)(?=\n##|$)/);
3893
+ if (blockersMatch) {
3894
+ const lines = blockersMatch[1].split('\n')
3895
+ .filter(l => l.trim().startsWith('-'))
3896
+ .map(l => l.replace(/^-\s*/, '').trim())
3897
+ .filter(l => l && !l.startsWith('<!--'));
3898
+ state.blockers = lines;
3899
+ }
3900
+ } catch {
3901
+ // Ignore read errors
3902
+ }
3903
+ }
3904
+
3905
+ // Read DEVLOG for last session
3906
+ const devlogPath = path.join(cwd, '.codebakers', 'DEVLOG.md');
3907
+ if (fs.existsSync(devlogPath)) {
3908
+ try {
3909
+ const content = fs.readFileSync(devlogPath, 'utf-8');
3910
+ // Get first session entry
3911
+ const sessionMatch = content.match(/## .+?\n\*\*Session:\*\*\s*(.+)/);
3912
+ if (sessionMatch) {
3913
+ state.lastSession = sessionMatch[1].trim();
3914
+ }
3915
+ // Get "What was done" from most recent entry
3916
+ const whatDoneMatch = content.match(/### What was done:\n([\s\S]*?)(?=\n###|---|\n\n)/);
3917
+ if (whatDoneMatch && !state.lastSession) {
3918
+ const lines = whatDoneMatch[1].split('\n')
3919
+ .filter(l => l.trim().startsWith('-'))
3920
+ .map(l => l.replace(/^-\s*/, '').trim());
3921
+ if (lines[0]) {
3922
+ state.lastSession = lines[0];
3923
+ }
3924
+ }
3925
+ } catch {
3926
+ // Ignore read errors
3927
+ }
3928
+ }
3929
+
3930
+ // Determine suggestion and status based on state
3931
+ if (!state.isSetUp) {
3932
+ state.status = 'NOT_INITIALIZED';
3933
+ state.suggestion = 'Run `codebakers go` in the terminal to set up the project.';
3934
+ } else if (state.blockers.length > 0) {
3935
+ state.status = 'BLOCKED';
3936
+ state.suggestion = `BLOCKED: ${state.blockers[0]}. Address this blocker first.`;
3937
+ } else if (state.inProgressTasks.length > 0) {
3938
+ state.status = 'IN_PROGRESS';
3939
+ state.suggestion = `CONTINUE: ${state.inProgressTasks[0]}`;
3940
+ } else if (state.hasPrd && state.completedTasks.length === 0) {
3941
+ state.status = 'READY_TO_BUILD';
3942
+ state.suggestion = 'START BUILDING: PRD exists. Begin implementing features from PRD.md';
3943
+ } else if (!state.hasPrd) {
3944
+ state.status = 'NEEDS_PRD';
3945
+ state.suggestion = 'DEFINE PROJECT: No PRD found. Ask the user what they want to build.';
3946
+ } else {
3947
+ state.status = 'READY';
3948
+ state.suggestion = 'READY: Project set up. Ask the user for the next feature to build.';
3949
+ }
3950
+
3951
+ // Build response
3952
+ let response = `# 🔄 Session Context Recovered\n\n`;
3953
+ response += `**Reason:** ${reason}\n\n`;
3954
+
3955
+ response += `## Project\n`;
3956
+ response += `- **Name:** ${state.projectName || 'Unknown'}\n`;
3957
+ response += `- **Type:** ${state.projectType || 'Not set'}\n`;
3958
+ response += `- **Status:** ${state.status}\n`;
3959
+ if (state.prdSummary) {
3960
+ response += `- **Description:** ${state.prdSummary}\n`;
3961
+ }
3962
+ response += `\n`;
3963
+
3964
+ if (state.blockers.length > 0) {
3965
+ response += `## ⚠️ BLOCKERS (Address First!)\n`;
3966
+ for (const blocker of state.blockers) {
3967
+ response += `- ${blocker}\n`;
3968
+ }
3969
+ response += `\n`;
3970
+ }
3971
+
3972
+ if (state.inProgressTasks.length > 0) {
3973
+ response += `## 🔄 In Progress\n`;
3974
+ for (const task of state.inProgressTasks) {
3975
+ response += `- ${task}\n`;
3976
+ }
3977
+ response += `\n`;
3978
+ }
3979
+
3980
+ if (state.completedTasks.length > 0) {
3981
+ response += `## ✅ Recently Completed\n`;
3982
+ for (const task of state.completedTasks) {
3983
+ response += `- ${task}\n`;
3984
+ }
3985
+ response += `\n`;
3986
+ }
3987
+
3988
+ if (state.lastSession) {
3989
+ response += `## 📅 Last Session\n`;
3990
+ response += `${state.lastSession}\n\n`;
3991
+ }
3992
+
3993
+ response += `---\n\n`;
3994
+ response += `## 🎯 NEXT ACTION\n\n`;
3995
+ response += `**${state.suggestion}**\n\n`;
3996
+
3997
+ response += `---\n\n`;
3998
+ response += `*Context recovered via CodeBakers resume_session. `;
3999
+ response += `This tool should be called automatically after conversation compaction.*`;
4000
+
4001
+ return {
4002
+ content: [{
4003
+ type: 'text' as const,
4004
+ text: response,
4005
+ }],
4006
+ };
4007
+ }
4008
+
3787
4009
  private handleRunTests(args: { filter?: string; watch?: boolean }) {
3788
4010
  const { filter, watch = false } = args;
3789
4011
  const cwd = process.cwd();