@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
JavaScript
/**
* 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