claudemaster
Version:
Task management MCP server optimized for Claude Code - no API keys required
375 lines (327 loc) • 12.5 kB
JavaScript
/**
* 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)}`;
}