UNPKG

@jmkim85/dev-flow-mcp

Version:

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

197 lines (190 loc) β€’ 8.43 kB
/** * Workflow Tool Handlers Module * Implements workflow management MCP tool handlers for Dev Flow */ import { stateManager, tddValidator, rewardHackingDetector, unifiedContextManager, simpleWorkflowManager, PROJECT_ROOT } from './globals.js'; import { findStageOutputs, generateMissingFilesFeedback } from './safety-guards.js'; // Workflow management tool handler implementations export async function loadWorkflow(workflowId) { try { let workflow = await simpleWorkflowManager.loadWorkflow(workflowId); if (!workflow) { // Create default workflows if none exist await simpleWorkflowManager.createDefaultWorkflows(); workflow = await simpleWorkflowManager.loadWorkflow(workflowId); if (!workflow) { const availableWorkflows = await simpleWorkflowManager.listWorkflows(); return { content: [{ type: "text", text: `❌ Workflow '${workflowId}' not found. Available workflows: ${availableWorkflows.join(', ') || 'none'}` }] }; } } // πŸ”Έ μ›Œν¬ν”Œλ‘œμš° λ‘œλ“œ 성곡 ν›„ State 에 반영 const state = await stateManager.getCurrentState(); state.current_workflow = workflowId; await stateManager.saveState(state); return { content: [{ type: "text", text: `πŸ“‹ **Loaded Workflow**: ${workflow.name} **Description**: ${workflow.description} **Stages** (${workflow.stages.length} total): ${workflow.stages.map((s, i) => `${i + 1}. **${s.name}** *Instructions*: ${s.instructions} ${s.entry_criteria ? `*Entry*: ${s.entry_criteria.join(', ')}` : ''} ${s.exit_criteria ? `*Exit*: ${s.exit_criteria.join(', ')}` : ''}`).join('\n\n')} **Current Workflow Set**: ${workflowId} Use \`start_task\` with a stage from this workflow, or \`advance_stage\` to move to the next stage.` }] }; } catch (error) { return { content: [{ type: "text", text: `❌ Error loading workflow: ${error.message}` }] }; } } export async function advanceStage(summary) { const state = await stateManager.getCurrentState(); if (!state.current_task) { return { content: [{ type: "text", text: "⚠️ **No Active Task**\n\nStart a task first using `get_next_task` and `start_task`." }] }; } const workflowId = state.current_workflow || "tdd_strict"; const workflow = await simpleWorkflowManager.loadWorkflow(workflowId); if (!workflow) { return { content: [{ type: "text", text: `❌ **Workflow Not Found**\n\nWorkflow '${workflowId}' not found. Load a workflow first using \`load_workflow\`.` }] }; } const nextStage = simpleWorkflowManager.getNextStage(workflow, state.current_stage); if (!nextStage) { return { content: [{ type: "text", text: `🚩 **Final Stage Reached**\n\n'${state.current_stage}' is the final stage in workflow '${workflowId}'. Use \`complete_task\` to finish.` }] }; } // Get current task for validation const task = await stateManager.getTask(state.current_task); if (!task) { return { content: [{ type: "text", text: `❌ **Task Not Found**\n\nCurrent task '${state.current_task}' not found.` }] }; } // NEW: Workflow Entry/Exit Criteria Validation const exitCheck = await simpleWorkflowManager.checkExitCriteria(workflow, state.current_stage, PROJECT_ROOT); if (!exitCheck.met) { return { content: [{ type: "text", text: `❌ **Exit Criteria Not Met**\n\nCannot leave '${state.current_stage}' stage. The following criteria are not satisfied:\n\n${exitCheck.unmetCriteria.map(c => `β€’ ${c}`).join('\n')}\n\n**Details**: ${exitCheck.details}\n\nComplete these requirements before advancing.` }] }; } const entryCheck = await simpleWorkflowManager.checkEntryCriteria(workflow, nextStage, PROJECT_ROOT); if (!entryCheck.met) { return { content: [{ type: "text", text: `❌ **Entry Criteria Not Met**\n\nCannot enter '${nextStage}' stage. The following criteria are not satisfied:\n\n${entryCheck.unmetCriteria.map(c => `β€’ ${c}`).join('\n')}\n\n**Details**: ${entryCheck.details}\n\nEnsure prerequisites are met before advancing.` }] }; } // TDD validation (legacy - now supplemented by workflow criteria) const validation = await tddValidator.validateStageTransition(state.current_stage, nextStage); if (!validation.allowed) { return { content: [{ type: "text", text: `❌ **TDD Validation Failed**\n\n${validation.reason}\n\nComplete the current stage requirements before advancing.` }] }; } // Reward hacking detection try { // Check for actual outputs created in task-specific directory const outputsCreated = await findStageOutputs(state.current_stage, state.current_task, PROJECT_ROOT); const hackingCheck = await rewardHackingDetector.checkStageAdvancement(state.current_stage, nextStage, { stage_iterations: { [state.current_stage]: 1 }, time_in_stage: 5, // Assume minimum time spent outputs_created: outputsCreated }); if (!hackingCheck.allowed) { // μ•ˆμ „μž₯치 3-4: λˆ„λ½ νŒŒμΌμ— λŒ€ν•œ ꡬ체적 ν”Όλ“œλ°± 제곡 const reason = hackingCheck.reason || 'Unknown reason'; let feedbackMessage = `🚫 **Stage Advancement Blocked**\n\n${reason}`; if (reason.includes('Missing required outputs')) { const missingFilesFeedback = await generateMissingFilesFeedback(state.current_stage, state.current_task, PROJECT_ROOT); if (missingFilesFeedback) { feedbackMessage += `\n\n${missingFilesFeedback}`; } } else { feedbackMessage += '\n\nSpend more time on the current stage before advancing.'; } return { content: [{ type: "text", text: feedbackMessage }] }; } } catch (error) { console.error('Warning: Could not run reward hacking check:', error); } // Update state and track stage iterations const previousStage = state.current_stage; state.current_stage = nextStage; // Type assertion for enum // Reset iteration counter for the new stage and increment for current stage await stateManager.resetStageIteration(nextStage); const iterationResult = await stateManager.incrementStageIteration(previousStage); await stateManager.saveState(state); // Check for excessive iterations warning let iterationWarning = ''; if (iterationResult.warning) { iterationWarning = `\n\n${iterationResult.warning}`; } // Update context frame try { await unifiedContextManager.updateFrame({ stage: nextStage, summary: summary || `Advanced from ${previousStage} to ${nextStage}` }); await unifiedContextManager.addFact(`Advanced to stage "${nextStage}" in workflow "${workflowId}"`, false); } catch (error) { console.error('Warning: Could not update context frame:', error); } return { content: [{ type: "text", text: `βœ… **Stage Advanced Successfully** **Previous Stage**: ${previousStage} (${iterationResult.count} iterations) **Current Stage**: ${nextStage} **Task**: ${task.title} **Workflow**: ${workflowId} ${summary ? `**Summary**: ${summary}` : ''} **Next Steps**: Follow the instructions for the '${nextStage}' stage in your workflow.${iterationWarning}` }] }; } //# sourceMappingURL=workflow-tool-handlers.js.map