UNPKG

claudemaster

Version:

Task management MCP server optimized for Claude Code - no API keys required

375 lines (327 loc) 12.5 kB
/** * claude-guided-task-expansion.js * Intelligent task breakdown and expansion tools for Claude Code */ import { z } from 'zod'; import TaskEngine from '../core/task-engine.js'; import { generateClaudePrompt } from '../core/claude-templates.js'; export function registerClaudeGuidedTaskExpansionTool(server) { server.addTool({ name: 'claude_guided_task_expansion', description: 'Guide Claude Code through intelligent task breakdown into manageable subtasks with detailed implementation guidance.', parameters: z.object({ projectRoot: z.string().describe('Absolute path to project root directory'), taskId: z.number().describe('ID of the task to expand'), targetSubtasks: z.number().optional().default(5).describe('Target number of subtasks to create'), context: z.string().optional().describe('Additional context for task expansion'), focusAreas: z.array(z.string()).optional().describe('Specific areas to focus on (e.g., security, performance, testing)') }), execute: async (args) => { try { const { projectRoot, taskId, targetSubtasks, context, focusAreas } = args; const taskEngine = new TaskEngine(projectRoot); const task = taskEngine.getTask(taskId); // Build context for expansion let expansionContext = context || ''; if (focusAreas && focusAreas.length > 0) { expansionContext += `\n\nFocus Areas: ${focusAreas.join(', ')}`; } // Generate Claude-optimized prompt for task expansion const prompt = generateClaudePrompt('TASK_EXPANSION', task, expansionContext); // Analyze task complexity for better guidance const complexityIndicators = analyzeTaskComplexity(task); return { success: true, task: { id: task.id, title: task.title, description: task.description, details: task.details, currentSubtasks: task.subtasks || [] }, complexityAnalysis: complexityIndicators, claudeInstructions: { systemPrompt: prompt.system, userPrompt: prompt.user, expansionGuidelines: { targetSubtasks, suggestedFocus: getSuggestedFocus(complexityIndicators), estimatedTimePerSubtask: '1-4 hours', requiredFields: ['title', 'description', 'estimatedHours', 'acceptanceCriteria'] }, nextSteps: [ 'Analyze the task and break it into logical subtasks', 'Ensure each subtask is specific and actionable', 'Use save_task_subtasks to save the results', 'Consider creating implementation plans for complex subtasks' ] }, expansionHints: generateExpansionHints(task, complexityIndicators), recommendations: { breakdownStrategy: getBreakdownStrategy(complexityIndicators), riskAreas: identifyRiskAreas(task), dependencies: suggestSubtaskDependencies(task) } }; } catch (error) { return { success: false, error: error.message }; } } }); } export function registerSaveTaskSubtasksTool(server) { server.addTool({ name: 'save_task_subtasks', description: 'Save subtasks created through Claude Code analysis. Use this after Claude Code has broken down a task.', parameters: z.object({ projectRoot: z.string().describe('Absolute path to project root directory'), taskId: z.number().describe('ID of the parent task'), subtasks: z.array(z.object({ id: z.string().optional(), title: z.string(), description: z.string(), estimatedHours: z.number().optional(), acceptanceCriteria: z.string().optional(), priority: z.enum(['high', 'medium', 'low']).default('medium'), status: z.enum(['pending', 'in-progress', 'done']).default('pending') })).describe('Array of subtasks to save'), replaceExisting: z.boolean().default(true).describe('Whether to replace existing subtasks') }), execute: async (args) => { try { const { projectRoot, taskId, subtasks, replaceExisting } = args; const taskEngine = new TaskEngine(projectRoot); const task = taskEngine.getTask(taskId); if (replaceExisting) { // Clear existing subtasks task.subtasks = []; } // Add new subtasks const savedSubtasks = []; for (const subtaskData of subtasks) { const subtask = { id: subtaskData.id || generateSubtaskId(), title: subtaskData.title, description: subtaskData.description, status: subtaskData.status || 'pending', priority: subtaskData.priority || 'medium', estimatedHours: subtaskData.estimatedHours, acceptanceCriteria: subtaskData.acceptanceCriteria, createdAt: new Date().toISOString() }; task.subtasks = task.subtasks || []; task.subtasks.push(subtask); savedSubtasks.push(subtask); } // Update the task const updatedTask = taskEngine.updateTask(taskId, { subtasks: task.subtasks, status: task.status === 'pending' ? 'pending' : task.status // Keep current status unless pending }); return { success: true, message: `Successfully saved ${savedSubtasks.length} subtasks for task ${taskId}`, parentTask: { id: updatedTask.id, title: updatedTask.title, status: updatedTask.status }, subtasks: savedSubtasks, nextSteps: [ 'Review the subtasks to ensure they cover all aspects', 'Use get_next_task to see which subtask to work on first', 'Consider creating implementation plans for complex subtasks' ], recommendations: { workflowSuggestion: 'Start with foundational subtasks before moving to complex ones', testingStrategy: 'Test each subtask completion before moving to the next', progressTracking: 'Update subtask status regularly to track progress' } }; } catch (error) { return { success: false, error: error.message }; } } }); } export function registerGenerateImplementationPlanTool(server) { server.addTool({ name: 'generate_implementation_plan', description: 'Generate detailed implementation plans for tasks or subtasks using Claude Code intelligence.', parameters: z.object({ projectRoot: z.string().describe('Absolute path to project root directory'), taskId: z.number().describe('ID of the task to create implementation plan for'), subtaskId: z.string().optional().describe('ID of specific subtask (if planning for a subtask)'), includeCodeExamples: z.boolean().default(false).describe('Include code examples in the plan'), projectContext: z.string().optional().describe('Additional project context (tech stack, patterns, etc.)') }), execute: async (args) => { try { const { projectRoot, taskId, subtaskId, includeCodeExamples, projectContext } = args; const taskEngine = new TaskEngine(projectRoot); const task = taskEngine.getTask(taskId); let targetTask = task; if (subtaskId && task.subtasks) { const subtask = task.subtasks.find(st => st.id === subtaskId); if (!subtask) { throw new Error(`Subtask ${subtaskId} not found in task ${taskId}`); } targetTask = subtask; } // Generate implementation plan prompt const prompt = generateClaudePrompt('IMPLEMENTATION_PLAN', targetTask, projectContext); return { success: true, target: { type: subtaskId ? 'subtask' : 'task', id: subtaskId || taskId, title: targetTask.title, description: targetTask.description, details: targetTask.details }, claudeInstructions: { systemPrompt: prompt.system, userPrompt: prompt.user, planningGuidelines: { includeCodeExamples, requiredSections: [ 'Implementation Steps', 'Files to Create/Modify', 'Dependencies', 'Testing Strategy', 'Potential Challenges' ], outputFormat: 'structured_markdown' }, nextSteps: [ 'Create a detailed step-by-step implementation plan', 'Identify all files that need to be created or modified', 'List any dependencies or prerequisites', 'Define testing approach and acceptance criteria' ] }, context: { parentTask: subtaskId ? task : null, projectContext: projectContext || 'General development project', suggestedApproach: getSuggestedApproach(targetTask) }, planningTemplate: { sections: [ '## Overview', '## Implementation Steps', '## Files to Create/Modify', '## Dependencies & Prerequisites', '## Testing Strategy', '## Potential Challenges & Solutions', '## Success Criteria' ] } }; } catch (error) { return { success: false, error: error.message }; } } }); } // Helper functions function analyzeTaskComplexity(task) { const indicators = { hasDetails: !!(task.details && task.details.length > 50), hasExistingSubtasks: !!(task.subtasks && task.subtasks.length > 0), hasDependencies: !!(task.dependencies && task.dependencies.length > 0), isHighPriority: task.priority === 'high', descriptionLength: task.description ? task.description.length : 0, detailsLength: task.details ? task.details.length : 0 }; // Calculate complexity score let complexityScore = 0; if (indicators.descriptionLength > 100) complexityScore += 2; if (indicators.detailsLength > 200) complexityScore += 3; if (indicators.hasDependencies) complexityScore += 2; if (indicators.isHighPriority) complexityScore += 1; if (indicators.hasExistingSubtasks) complexityScore += 1; indicators.complexityLevel = complexityScore >= 6 ? 'high' : complexityScore >= 3 ? 'medium' : 'low'; indicators.complexityScore = complexityScore; return indicators; } function getSuggestedFocus(complexityIndicators) { const suggestions = ['implementation_details', 'clear_acceptance_criteria']; if (complexityIndicators.complexityLevel === 'high') { suggestions.push('risk_mitigation', 'incremental_development'); } if (complexityIndicators.hasDependencies) { suggestions.push('dependency_management'); } return suggestions; } function generateExpansionHints(task, complexityIndicators) { const hints = []; if (task.details && task.details.includes('API')) { hints.push('Consider separating API design, implementation, and testing into different subtasks'); } if (task.details && task.details.includes('database')) { hints.push('Break down into schema design, migration, and data access layer subtasks'); } if (task.title.toLowerCase().includes('setup') || task.title.toLowerCase().includes('config')) { hints.push('Consider environment setup, dependency installation, and configuration as separate subtasks'); } if (complexityIndicators.complexityLevel === 'high') { hints.push('For complex tasks, create subtasks that can be completed independently when possible'); } return hints; } function getBreakdownStrategy(complexityIndicators) { if (complexityIndicators.complexityLevel === 'high') { return 'layered_approach'; } else if (complexityIndicators.hasDependencies) { return 'dependency_first'; } else { return 'sequential'; } } function identifyRiskAreas(task) { const risks = []; if (task.details && task.details.toLowerCase().includes('integration')) { risks.push('integration_complexity'); } if (task.details && task.details.toLowerCase().includes('performance')) { risks.push('performance_optimization'); } if (task.priority === 'high') { risks.push('tight_timeline'); } return risks; } function suggestSubtaskDependencies(task) { const suggestions = []; if (task.title.toLowerCase().includes('implement')) { suggestions.push('Design and planning subtasks should be completed before implementation subtasks'); } if (task.details && task.details.includes('test')) { suggestions.push('Implementation subtasks should be completed before testing subtasks'); } return suggestions; } function getSuggestedApproach(task) { if (task.title.toLowerCase().includes('api')) { return 'api_first_development'; } else if (task.title.toLowerCase().includes('ui') || task.title.toLowerCase().includes('component')) { return 'component_driven_development'; } else if (task.title.toLowerCase().includes('database') || task.title.toLowerCase().includes('schema')) { return 'data_first_approach'; } else { return 'incremental_development'; } } function generateSubtaskId() { return `st_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; }