@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 +2 -2
- package/dist/mcp/server.js +209 -0
- package/package.json +1 -1
- package/src/index.ts +2 -2
- package/src/mcp/server.ts +222 -0
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.
|
|
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.
|
|
198
|
+
.version('3.9.1');
|
|
199
199
|
// Zero-friction trial entry (no signup required)
|
|
200
200
|
program
|
|
201
201
|
.command('go')
|
package/dist/mcp/server.js
CHANGED
|
@@ -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
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.
|
|
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.
|
|
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();
|