UNPKG

@jmkim85/dev-flow-mcp

Version:

MCP-based Dev Flow - AI-powered development workflow management with 13 essential tools for TDD and context management

420 lines (398 loc) โ€ข 15.4 kB
/** * Core Tool Handlers Module * Implements the core MCP tool handlers for Dev Flow */ import { stateManager, tddValidator, mistakeLearner, rewardHackingDetector, unifiedContextManager } from './globals.js'; // Core tool handler implementations export async function getNextTask() { try { const nextTask = await stateManager.getNextTask(); const state = await stateManager.getCurrentState(); if (!nextTask) { return { content: [{ type: "text", text: "๐ŸŽ‰ No pending tasks found. All tasks may be completed!" }] }; } const context = await unifiedContextManager.buildContext(nextTask.id); return { content: [{ type: "text", text: `๐Ÿ“‹ **Next Task**: ${nextTask.title} **Current Stage**: ${state.current_stage} **Status**: ${nextTask.status} **Priority**: ${nextTask.priority} ${context} Use \`start_task\` to begin working on this task.` }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error getting next task: ${error.message || error}` }] }; } } export async function startTask(taskId, stage = "analyze") { try { const task = await stateManager.getTask(taskId); if (!task) { return { content: [{ type: "text", text: `โŒ Task ${taskId} not found` }] }; } // Update state and track stage iterations const state = await stateManager.getCurrentState(); const previousStage = state.current_stage; const wasAlreadyOnThisTask = state.current_task === taskId; state.current_task = taskId; state.current_stage = stage; // Track stage iterations - increment if staying in same stage on same task let iterationResult = { count: 0 }; if (wasAlreadyOnThisTask && previousStage === stage) { iterationResult = await stateManager.incrementStageIteration(stage); } else { // Reset iteration counter when starting new stage await stateManager.resetStageIteration(stage); } await stateManager.saveState(state); // Update task status await stateManager.updateTask(taskId, { status: "in_progress" }); // D: Auto-create context frame for task/stage tracking try { await unifiedContextManager.createFrame(taskId, stage); await unifiedContextManager.addFact(`Started task "${task.title}" at stage "${stage}"`, false); } catch (error) { console.error('Warning: Could not create context frame:', error); } // Enhanced real-time mistake checking (3-1) let mistakeWarnings = ''; try { // Check for known mistake patterns in task description and context const searchText = `${task.description} ${stage} ${task.title}`; const warnings = await mistakeLearner.checkForKnownMistakes(searchText); if (warnings.length > 0) { mistakeWarnings = `\n\n๐Ÿšจ **Known Mistake Patterns Detected**\n\n`; for (const warning of warnings) { mistakeWarnings += `**Pattern**: ${warning.pattern}\n`; mistakeWarnings += `**Message**: ${warning.message}\n`; if (warning.solutions.length > 0) { mistakeWarnings += `**Solutions**:\n${warning.solutions.map(s => `- ${s}`).join('\n')}\n`; } mistakeWarnings += '\n'; } mistakeWarnings += `โš ๏ธ **Please review these patterns before proceeding to avoid repeating past mistakes.**\n`; } // Reward hacking detection const hackingCheck = await rewardHackingDetector.checkStageAdvancement('pending', stage, { stage_iterations: { [stage]: task.status !== 'pending' ? 1 : 0 }, time_in_stage: 1, // Minimum time to avoid quick advancement warning outputs_created: [] }); if (!hackingCheck.allowed) { mistakeWarnings += `\n\n๐Ÿšซ **Reward Hacking Alert**: ${hackingCheck.reason}\n`; } } catch (error) { // Don't fail the task start if checks fail console.error('Warning: Could not run safety checks:', error); } const context = await unifiedContextManager.buildContext(taskId); // Add iteration warning if applicable let iterationWarning = ''; if (iterationResult.warning) { iterationWarning = `\n\n${iterationResult.warning}`; } const iterationInfo = iterationResult.count > 0 ? ` (iteration ${iterationResult.count})` : ''; return { content: [{ type: "text", text: `๐Ÿš€ **Started Task**: ${task.title} **Stage**: ${stage}${iterationInfo} ${context}${mistakeWarnings}${iterationWarning}` }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error starting task: ${error.message || error}` }] }; } } export async function checkProgress(runTests = false) { try { const state = await stateManager.getCurrentState(); if (!state.current_task) { return { content: [{ type: "text", text: "โš ๏ธ No active task. Use `get_next_task` to see what to work on." }] }; } const task = await stateManager.getTask(state.current_task); if (!task) { return { content: [{ type: "text", text: "โŒ Current task not found" }] }; } let testResults = ""; if (runTests) { const testResult = await tddValidator.runTests(task.test_command); // Enhanced test modification checking with fail fast (3-2) try { // Check test output for suspicious patterns with fail fast enabled const hackingCheck = await rewardHackingDetector.checkTestModification('test_output', '', // old content not available in this context testResult.output, true // Enable fail fast mode ); if (hackingCheck.suspicious) { const severityEmoji = hackingCheck.severity === 'HIGH' ? '๐Ÿ”ด' : hackingCheck.severity === 'MEDIUM' ? '๐ŸŸก' : '๐ŸŸข'; console.error(`๐Ÿšซ ${severityEmoji} Suspicious test patterns detected (${hackingCheck.severity}): ${hackingCheck.patterns.join(', ')}`); // If critical violations detected, add warning to test results if (hackingCheck.severity === 'HIGH') { testResults += `\n\n๐Ÿšจ **CRITICAL TEST INTEGRITY WARNING**\nSuspicious patterns detected: ${hackingCheck.patterns.join(', ')}\nThis may indicate test bypassing or gaming attempts.\n`; } } } catch (error) { console.error('Warning: Could not check test modifications:', error); } testResults = ` ## ๐Ÿงช Test Results **Status**: ${testResult.all_passed ? "โœ… PASSED" : "โŒ FAILED"} **Exit Code**: ${testResult.exit_code} ${testResult.failures.length > 0 ? `**Failures**: ${testResult.failures.map(f => `- ${f}`).join('\n')}` : ''} **Output**: \`\`\` ${testResult.output.slice(-500)} // Last 500 chars \`\`\` `; } // NEW v2.1.1: Check completion conditions if specified let completionResults = ""; if (task.completion_conditions && task.completion_conditions.length > 0) { const conditionCheck = await tddValidator.validateCompletionConditions(task.completion_conditions, task.test_command); completionResults = ` ## ๐Ÿ“‹ Completion Conditions Check **Overall Status**: ${conditionCheck.all_passed ? "โœ… PASSED" : "โŒ FAILED"} ${conditionCheck.results.map(r => `- ${r.passed ? "โœ…" : "โŒ"} **${r.condition}**: ${r.message}`).join('\n')} `; } // Enhanced real-time mistake checking for progress (3-1) let mistakeWarnings = ""; try { // Check for mistake patterns in current context const searchText = `${task.description} ${state.current_stage} progress check ${task.title}`; const warnings = await mistakeLearner.checkForKnownMistakes(searchText); if (warnings.length > 0) { mistakeWarnings = ` ## ๐Ÿšจ Known Mistake Patterns Detected ${warnings.map(warning => ` **Pattern**: ${warning.pattern} **Message**: ${warning.message} ${warning.solutions.length > 0 ? `**Solutions**: ${warning.solutions.map(s => `- ${s}`).join('\n')}` : ''} `).join('\n')} โš ๏ธ **Review these patterns to avoid repeating past mistakes.** `; } } catch (error) { console.error('Warning: Could not check for mistake patterns:', error); } return { content: [{ type: "text", text: `๐Ÿ“Š **Progress Check** **Task**: ${task.title} **Current Stage**: ${state.current_stage} **Status**: ${task.status} ${testResults}${completionResults}${mistakeWarnings} **Next Steps**: - Continue working in current stage, or - Use \`start_task\` with next stage if ready - Use \`save_checkpoint\` to save progress` }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error checking progress: ${error.message || error}` }] }; } } export async function saveCheckpoint(message, files = []) { try { const state = await stateManager.getCurrentState(); if (!state.current_task) { return { content: [{ type: "text", text: "โš ๏ธ No active task to save checkpoint for" }] }; } const checkpoint = { id: Date.now().toString(), task_id: state.current_task, stage: state.current_stage, message, files, timestamp: new Date().toISOString() }; await stateManager.addCheckpoint(checkpoint); return { content: [{ type: "text", text: `๐Ÿ’พ **Checkpoint Saved** **Message**: ${message} **Stage**: ${state.current_stage} **Files**: ${files.length > 0 ? files.join(', ') : 'None specified'} **Time**: ${new Date().toLocaleString()} Progress has been saved. Continue working or move to next stage.` }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error saving checkpoint: ${error.message || error}` }] }; } } export async function recordMistake(pattern, context = "", solution) { try { await mistakeLearner.recordMistake(pattern, context, solution); const mistakeStats = await mistakeLearner.getMistakeStats(); return { content: [{ type: "text", text: `๐Ÿ“ **Mistake Recorded** **Pattern**: ${pattern} **Context**: ${context || 'No context provided'} ${solution ? `**Solution**: ${solution}` : ''} **Learning Stats**: - Total patterns: ${mistakeStats.total} - Recent (7 days): ${mistakeStats.recent} This pattern will be flagged in future similar contexts.` }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error recording mistake: ${error.message || error}` }] }; } } export async function completeTask(summary) { try { const state = await stateManager.getCurrentState(); if (!state.current_task) { return { content: [{ type: "text", text: "โš ๏ธ No active task to complete" }] }; } const task = await stateManager.getTask(state.current_task); if (!task) { return { content: [{ type: "text", text: "โŒ Current task not found" }] }; } // Validate that task can be completed (all tests pass) const validation = await tddValidator.validateStageTransition(state.current_stage, "complete"); if (!validation.allowed) { return { content: [{ type: "text", text: `โŒ **Cannot Complete Task** ${validation.reason} ${validation.failed_tests ? `**Failed Tests**: ${validation.failed_tests.map(f => `- ${f}`).join('\n')}` : ''} Fix the issues and try again.` }] }; } // Mark task as completed await stateManager.updateTask(state.current_task, { status: "completed" }); // D: Auto-update context frame for task completion try { await unifiedContextManager.addFact(`Completed task "${task.title}"`, false); await unifiedContextManager.updateFrame({ summary: summary || `Task completed: ${task.title}` }); } catch (error) { console.error('Warning: Could not update context frame:', error); } // Clear current task state.current_task = null; state.current_stage = "analyze"; await stateManager.saveState(state); // Save completion checkpoint await stateManager.addCheckpoint({ id: Date.now().toString(), task_id: task.id, stage: "complete", message: summary || `Completed task: ${task.title}`, files: [], timestamp: new Date().toISOString() }); // Get next task const nextTask = await stateManager.getNextTask(); const nextTaskInfo = nextTask ? `\n\n**Next Task Available**: ${nextTask.title}\nUse \`get_next_task\` to see details.` : '\n\n๐ŸŽ‰ All tasks completed!'; return { content: [{ type: "text", text: `โœ… **Task Completed** **Task**: ${task.title} **Summary**: ${summary || 'No summary provided'} **Completed**: ${new Date().toLocaleString()} ${nextTaskInfo}` }] }; } catch (error) { return { content: [{ type: "text", text: `โŒ Error completing task: ${error.message || error}` }] }; } } //# sourceMappingURL=core-tool-handlers.js.map