UNPKG

zai-mcp-server

Version:

🚀 REVOLUTIONARY AI-to-AI Collaboration Platform v6.1! NEW: Advanced Debugging Tools with Screenshot Analysis, Console Error Parsing, Automated Fix Generation, 5 Specialized Debugging Agents, Visual UI Analysis, JavaScript Error Intelligence, CSS/HTML Fix

1,296 lines (1,032 loc) 47.2 kB
/** * Predictive Task Management System * AI-powered system to predict task failures, optimize resource allocation, provide accurate timelines, and assess risks */ import { EventEmitter } from 'events'; import crypto from 'crypto'; import fs from 'fs/promises'; import path from 'path'; export class PredictiveTaskManagement extends EventEmitter { constructor(options = {}) { super(); this.predictiveDir = options.predictiveDir || './predictive'; this.maxHistoryEntries = options.maxHistoryEntries || 1000; this.predictionAccuracyThreshold = options.predictionAccuracyThreshold || 0.75; this.riskAssessmentInterval = options.riskAssessmentInterval || 60000; // 1 minute this.taskHistory = []; this.activeProjects = new Map(); this.predictionModels = new Map(); this.resourceMetrics = new Map(); this.riskFactors = new Map(); this.timelineEstimates = new Map(); this.failurePredictions = new Map(); // Prediction model weights this.modelWeights = { complexity: 0.25, teamExperience: 0.20, resourceAvailability: 0.15, historicalSuccess: 0.15, dependencies: 0.10, timeConstraints: 0.10, externalFactors: 0.05 }; console.log('🔮 Predictive Task Management System initialized'); // Initialize prediction models immediately (synchronous) this.initializePredictionModels(); // Initialize directories and load historical data (async) this.initializePredictiveSystem(); this.startRiskAssessment(); } async initializePredictiveSystem() { try { await fs.mkdir(this.predictiveDir, { recursive: true }); await this.loadHistoricalData(); console.log(`📁 Predictive directory initialized: ${this.predictiveDir}`); } catch (error) { console.warn('⚠️ Failed to initialize predictive system:', error.message); } } async loadHistoricalData() { try { const historyFile = path.join(this.predictiveDir, 'task-history.json'); const data = await fs.readFile(historyFile, 'utf8'); this.taskHistory = JSON.parse(data); console.log(`📥 Loaded ${this.taskHistory.length} historical task entries`); } catch (error) { console.log('📝 No existing task history found, starting fresh'); } } async saveHistoricalData() { try { const historyFile = path.join(this.predictiveDir, 'task-history.json'); await fs.writeFile(historyFile, JSON.stringify(this.taskHistory, null, 2)); console.log('💾 Task history saved'); } catch (error) { console.warn('⚠️ Failed to save task history:', error.message); } } initializePredictionModels() { // Initialize different prediction models this.predictionModels.set('failure_prediction', { name: 'Task Failure Prediction', accuracy: 0.82, features: ['complexity', 'team_experience', 'dependencies', 'timeline_pressure'], lastTrained: Date.now(), predictions: 0 }); this.predictionModels.set('timeline_estimation', { name: 'Timeline Estimation', accuracy: 0.78, features: ['task_type', 'complexity', 'team_size', 'historical_velocity'], lastTrained: Date.now(), predictions: 0 }); this.predictionModels.set('resource_optimization', { name: 'Resource Optimization', accuracy: 0.85, features: ['workload_distribution', 'skill_matching', 'availability', 'priority'], lastTrained: Date.now(), predictions: 0 }); this.predictionModels.set('risk_assessment', { name: 'Risk Assessment', accuracy: 0.80, features: ['external_dependencies', 'technology_maturity', 'team_stability', 'scope_clarity'], lastTrained: Date.now(), predictions: 0 }); console.log(`🤖 Initialized ${this.predictionModels.size} prediction models`); } async createProject(projectData) { const projectId = crypto.randomBytes(8).toString('hex'); const project = { id: projectId, name: projectData.name, description: projectData.description, createdAt: Date.now(), lastUpdated: Date.now(), status: 'planning', tasks: [], team: projectData.team || [], timeline: { startDate: projectData.startDate || Date.now(), estimatedEndDate: null, actualEndDate: null, milestones: [] }, resources: { allocated: projectData.resources || {}, utilized: {}, efficiency: 0 }, risks: [], predictions: { failureRisk: 0, timelineAccuracy: 0, resourceOptimization: 0, overallHealth: 0 }, metrics: { velocity: 0, burndownRate: 0, qualityScore: 0, teamSatisfaction: 0 } }; this.activeProjects.set(projectId, project); // Generate initial predictions await this.generateProjectPredictions(projectId); console.log(`🔮 Created predictive project: ${projectData.name} (${projectId})`); this.emit('project:created', { projectId, project, predictions: project.predictions }); return projectId; } async addTaskToProject(projectId, taskData) { const project = this.activeProjects.get(projectId); if (!project) { throw new Error(`Project ${projectId} not found`); } const taskId = crypto.randomBytes(8).toString('hex'); const task = { id: taskId, projectId: projectId, title: taskData.title, description: taskData.description, type: taskData.type || 'development', complexity: taskData.complexity || 'medium', priority: taskData.priority || 'medium', assignee: taskData.assignee, dependencies: taskData.dependencies || [], estimatedHours: taskData.estimatedHours, actualHours: 0, status: 'todo', createdAt: Date.now(), startedAt: null, completedAt: null, tags: taskData.tags || [], risks: [], predictions: { failureRisk: 0, timelineAccuracy: 0, completionProbability: 0, resourceRequirement: 0 } }; project.tasks.push(task); project.lastUpdated = Date.now(); // Generate task-specific predictions await this.generateTaskPredictions(projectId, taskId); // Update project-level predictions await this.generateProjectPredictions(projectId); console.log(`📋 Added task to project ${projectId}: ${taskData.title}`); this.emit('task:added', { projectId, taskId, task, predictions: task.predictions }); return taskId; } async generateTaskPredictions(projectId, taskId) { const project = this.activeProjects.get(projectId); if (!project) return; const task = project.tasks.find(t => t.id === taskId); if (!task) return; // Predict failure risk task.predictions.failureRisk = await this.predictTaskFailureRisk(task, project); // Predict timeline accuracy task.predictions.timelineAccuracy = await this.predictTimelineAccuracy(task, project); // Predict completion probability task.predictions.completionProbability = await this.predictCompletionProbability(task, project); // Predict resource requirements task.predictions.resourceRequirement = await this.predictResourceRequirement(task, project); // Store prediction in cache this.failurePredictions.set(taskId, { taskId, projectId, predictions: task.predictions, timestamp: Date.now(), confidence: this.calculatePredictionConfidence(task, project) }); console.log(`🔮 Generated predictions for task ${taskId}: failure risk ${(task.predictions.failureRisk * 100).toFixed(1)}%`); } async predictTaskFailureRisk(task, project) { let riskScore = 0; // Complexity factor const complexityWeights = { low: 0.1, medium: 0.3, high: 0.6, critical: 0.9 }; riskScore += (complexityWeights[task.complexity] || 0.3) * this.modelWeights.complexity; // Team experience factor const teamExperience = this.calculateTeamExperience(project.team, task.type); riskScore += (1 - teamExperience) * this.modelWeights.teamExperience; // Dependencies factor const dependencyRisk = this.calculateDependencyRisk(task, project); riskScore += dependencyRisk * this.modelWeights.dependencies; // Historical success rate const historicalSuccess = this.getHistoricalSuccessRate(task.type, task.complexity); riskScore += (1 - historicalSuccess) * this.modelWeights.historicalSuccess; // Time constraints factor const timeConstraints = this.calculateTimeConstraints(task, project); riskScore += timeConstraints * this.modelWeights.timeConstraints; // Resource availability factor const resourceAvailability = this.calculateResourceAvailability(task, project); riskScore += (1 - resourceAvailability) * this.modelWeights.resourceAvailability; return Math.min(riskScore, 1.0); } async predictTimelineAccuracy(task, project) { let accuracyScore = 0.8; // Base accuracy // Adjust based on historical data const historicalAccuracy = this.getHistoricalTimelineAccuracy(task.type, task.complexity); accuracyScore *= historicalAccuracy; // Adjust based on team velocity const teamVelocity = this.calculateTeamVelocity(project); accuracyScore *= teamVelocity; // Adjust based on scope clarity const scopeClarity = this.calculateScopeClarity(task); accuracyScore *= scopeClarity; return Math.min(accuracyScore, 1.0); } async predictCompletionProbability(task, project) { const failureRisk = task.predictions.failureRisk || 0; const timelineAccuracy = task.predictions.timelineAccuracy || 0.8; // Base completion probability let completionProb = 0.85; // Adjust for failure risk completionProb *= (1 - failureRisk); // Adjust for timeline accuracy completionProb *= timelineAccuracy; // Adjust for team capacity const teamCapacity = this.calculateTeamCapacity(project); completionProb *= teamCapacity; return Math.min(completionProb, 1.0); } async predictResourceRequirement(task, project) { let resourceMultiplier = 1.0; // Complexity adjustment const complexityMultipliers = { low: 0.8, medium: 1.0, high: 1.5, critical: 2.0 }; resourceMultiplier *= complexityMultipliers[task.complexity] || 1.0; // Team experience adjustment const teamExperience = this.calculateTeamExperience(project.team, task.type); resourceMultiplier *= (2 - teamExperience); // Less experience = more resources needed // Dependencies adjustment const dependencyCount = task.dependencies.length; resourceMultiplier *= (1 + dependencyCount * 0.1); // Historical adjustment const historicalMultiplier = this.getHistoricalResourceMultiplier(task.type, task.complexity); resourceMultiplier *= historicalMultiplier; return Math.min(resourceMultiplier, 3.0); // Cap at 3x } calculateTeamExperience(team, taskType) { if (!team || team.length === 0) return 0.5; const experienceScores = team.map(member => { // Simulate experience calculation const baseExperience = member.experience || 0.7; const typeExperience = member.skills?.[taskType] || 0.5; return (baseExperience + typeExperience) / 2; }); return experienceScores.reduce((sum, score) => sum + score, 0) / experienceScores.length; } calculateDependencyRisk(task, project) { if (!task.dependencies || task.dependencies.length === 0) return 0; let riskScore = 0; for (const depId of task.dependencies) { const depTask = project.tasks.find(t => t.id === depId); if (!depTask) { riskScore += 0.3; // External dependency risk } else if (depTask.status !== 'completed') { riskScore += 0.2; // Internal dependency risk } } return Math.min(riskScore, 1.0); } getHistoricalSuccessRate(taskType, complexity) { const relevantHistory = this.taskHistory.filter(h => h.type === taskType && h.complexity === complexity ); if (relevantHistory.length === 0) return 0.8; // Default success rate const successfulTasks = relevantHistory.filter(h => h.status === 'completed').length; return successfulTasks / relevantHistory.length; } calculateTimeConstraints(task, project) { if (!task.estimatedHours || !project.timeline.estimatedEndDate) return 0.3; const remainingTime = project.timeline.estimatedEndDate - Date.now(); const requiredTime = task.estimatedHours * 60 * 60 * 1000; // Convert to milliseconds if (remainingTime <= 0) return 1.0; // Past deadline if (requiredTime > remainingTime) return 0.8; // Tight timeline if (requiredTime > remainingTime * 0.8) return 0.5; // Moderate pressure return 0.2; // Comfortable timeline } calculateResourceAvailability(task, project) { if (!task.assignee) return 0.7; // No assignee // Simulate resource availability calculation const assigneeWorkload = this.calculateAssigneeWorkload(task.assignee, project); return Math.max(0.1, 1 - assigneeWorkload); } calculateAssigneeWorkload(assignee, project) { const assigneeTasks = project.tasks.filter(t => t.assignee === assignee && ['todo', 'in_progress'].includes(t.status) ); const totalHours = assigneeTasks.reduce((sum, t) => sum + (t.estimatedHours || 8), 0); const weeklyCapacity = 40; // 40 hours per week return Math.min(totalHours / weeklyCapacity, 1.0); } getHistoricalTimelineAccuracy(taskType, complexity) { const relevantHistory = this.taskHistory.filter(h => h.type === taskType && h.complexity === complexity && h.estimatedHours && h.actualHours ); if (relevantHistory.length === 0) return 0.8; const accuracyScores = relevantHistory.map(h => { const accuracy = Math.min(h.estimatedHours / h.actualHours, h.actualHours / h.estimatedHours); return Math.max(accuracy, 0.1); }); return accuracyScores.reduce((sum, score) => sum + score, 0) / accuracyScores.length; } calculateTeamVelocity(project) { const completedTasks = project.tasks.filter(t => t.status === 'completed'); if (completedTasks.length === 0) return 0.8; const velocityScores = completedTasks.map(task => { if (!task.estimatedHours || !task.actualHours) return 0.8; return Math.min(task.estimatedHours / task.actualHours, 1.0); }); return velocityScores.reduce((sum, score) => sum + score, 0) / velocityScores.length; } calculateScopeClarity(task) { let clarityScore = 0.8; // Check description quality if (!task.description || task.description.length < 50) { clarityScore -= 0.2; } // Check if requirements are defined if (!task.estimatedHours) { clarityScore -= 0.1; } // Check if acceptance criteria exist if (!task.acceptanceCriteria || task.acceptanceCriteria.length === 0) { clarityScore -= 0.1; } return Math.max(clarityScore, 0.3); } calculateTeamCapacity(project) { if (!project.team || project.team.length === 0) return 0.5; const capacityScores = project.team.map(member => { const workload = this.calculateAssigneeWorkload(member.id, project); return Math.max(0.1, 1 - workload); }); return capacityScores.reduce((sum, score) => sum + score, 0) / capacityScores.length; } getHistoricalResourceMultiplier(taskType, complexity) { const relevantHistory = this.taskHistory.filter(h => h.type === taskType && h.complexity === complexity && h.estimatedHours && h.actualHours ); if (relevantHistory.length === 0) return 1.0; const multipliers = relevantHistory.map(h => h.actualHours / h.estimatedHours); return multipliers.reduce((sum, mult) => sum + mult, 0) / multipliers.length; } calculatePredictionConfidence(task, project) { let confidence = 0.8; // Adjust based on historical data availability const historicalDataPoints = this.taskHistory.filter(h => h.type === task.type && h.complexity === task.complexity ).length; if (historicalDataPoints > 50) confidence += 0.1; else if (historicalDataPoints < 10) confidence -= 0.2; // Adjust based on team experience const teamExperience = this.calculateTeamExperience(project.team, task.type); confidence += (teamExperience - 0.5) * 0.2; // Adjust based on scope clarity const scopeClarity = this.calculateScopeClarity(task); confidence += (scopeClarity - 0.5) * 0.2; return Math.max(0.3, Math.min(confidence, 0.95)); } async generateProjectPredictions(projectId) { const project = this.activeProjects.get(projectId); if (!project) return; // Calculate overall project health project.predictions.overallHealth = await this.calculateProjectHealth(project); // Calculate failure risk project.predictions.failureRisk = await this.calculateProjectFailureRisk(project); // Calculate timeline accuracy project.predictions.timelineAccuracy = await this.calculateProjectTimelineAccuracy(project); // Calculate resource optimization project.predictions.resourceOptimization = await this.calculateResourceOptimization(project); // Update timeline estimates await this.updateTimelineEstimates(projectId); console.log(`🔮 Updated project predictions for ${projectId}: health ${(project.predictions.overallHealth * 100).toFixed(1)}%`); this.emit('project:predictions_updated', { projectId, predictions: project.predictions }); } async calculateProjectHealth(project) { let healthScore = 0.8; // Task completion rate const completedTasks = project.tasks.filter(t => t.status === 'completed').length; const totalTasks = project.tasks.length; const completionRate = totalTasks > 0 ? completedTasks / totalTasks : 0; healthScore *= (0.5 + completionRate * 0.5); // Average task health const taskHealthScores = project.tasks.map(task => { const failureRisk = task.predictions?.failureRisk || 0.3; return 1 - failureRisk; }); if (taskHealthScores.length > 0) { const avgTaskHealth = taskHealthScores.reduce((sum, score) => sum + score, 0) / taskHealthScores.length; healthScore *= avgTaskHealth; } // Timeline adherence if (project.timeline.estimatedEndDate) { const timeRemaining = project.timeline.estimatedEndDate - Date.now(); const totalDuration = project.timeline.estimatedEndDate - project.timeline.startDate; const timeElapsed = Date.now() - project.timeline.startDate; if (timeRemaining > 0 && totalDuration > 0) { const expectedProgress = timeElapsed / totalDuration; const actualProgress = completionRate; const timelineAdherence = Math.min(actualProgress / expectedProgress, 1.0); healthScore *= (0.7 + timelineAdherence * 0.3); } } return Math.max(0.1, Math.min(healthScore, 1.0)); } async calculateProjectFailureRisk(project) { if (project.tasks.length === 0) return 0.3; // Average task failure risk const taskRisks = project.tasks.map(task => task.predictions?.failureRisk || 0.3); const avgTaskRisk = taskRisks.reduce((sum, risk) => sum + risk, 0) / taskRisks.length; // Project-specific risk factors let projectRisk = avgTaskRisk; // Team stability risk const teamStability = this.calculateTeamStability(project); projectRisk += (1 - teamStability) * 0.2; // Scope creep risk const scopeCreepRisk = this.calculateScopeCreepRisk(project); projectRisk += scopeCreepRisk * 0.15; // External dependency risk const externalDepRisk = this.calculateExternalDependencyRisk(project); projectRisk += externalDepRisk * 0.1; return Math.min(projectRisk, 1.0); } async calculateProjectTimelineAccuracy(project) { if (project.tasks.length === 0) return 0.8; // Average task timeline accuracy const taskAccuracies = project.tasks.map(task => task.predictions?.timelineAccuracy || 0.8); const avgTaskAccuracy = taskAccuracies.reduce((sum, acc) => sum + acc, 0) / taskAccuracies.length; // Project-specific factors let projectAccuracy = avgTaskAccuracy; // Team velocity consistency const velocityConsistency = this.calculateVelocityConsistency(project); projectAccuracy *= velocityConsistency; // Scope clarity const overallScopeClarity = this.calculateOverallScopeClarity(project); projectAccuracy *= overallScopeClarity; return Math.max(0.3, Math.min(projectAccuracy, 1.0)); } async calculateResourceOptimization(project) { let optimizationScore = 0.8; // Workload distribution const workloadDistribution = this.calculateWorkloadDistribution(project); optimizationScore *= workloadDistribution; // Skill-task matching const skillMatching = this.calculateSkillMatching(project); optimizationScore *= skillMatching; // Resource utilization efficiency const utilizationEfficiency = this.calculateUtilizationEfficiency(project); optimizationScore *= utilizationEfficiency; return Math.max(0.3, Math.min(optimizationScore, 1.0)); } calculateTeamStability(project) { // Simulate team stability calculation if (!project.team || project.team.length === 0) return 0.5; // Check for recent team changes const recentChanges = project.team.filter(member => member.joinedAt && (Date.now() - member.joinedAt) < 30 * 24 * 60 * 60 * 1000 // 30 days ).length; const stabilityScore = 1 - (recentChanges / project.team.length) * 0.5; return Math.max(0.3, stabilityScore); } calculateScopeCreepRisk(project) { // Simulate scope creep risk calculation const initialTaskCount = project.initialTaskCount || project.tasks.length; const currentTaskCount = project.tasks.length; if (initialTaskCount === 0) return 0.3; const scopeIncrease = (currentTaskCount - initialTaskCount) / initialTaskCount; return Math.min(scopeIncrease * 0.5, 0.8); } calculateExternalDependencyRisk(project) { const externalDeps = project.tasks.reduce((count, task) => { return count + (task.dependencies?.filter(dep => !project.tasks.find(t => t.id === dep)).length || 0); }, 0); const totalTasks = project.tasks.length; if (totalTasks === 0) return 0.3; return Math.min(externalDeps / totalTasks, 0.7); } calculateVelocityConsistency(project) { const completedTasks = project.tasks.filter(t => t.status === 'completed' && t.actualHours); if (completedTasks.length < 3) return 0.8; const velocities = completedTasks.map(task => task.estimatedHours / task.actualHours); const avgVelocity = velocities.reduce((sum, v) => sum + v, 0) / velocities.length; const variance = velocities.reduce((sum, v) => sum + Math.pow(v - avgVelocity, 2), 0) / velocities.length; const standardDeviation = Math.sqrt(variance); // Lower standard deviation = higher consistency return Math.max(0.5, 1 - standardDeviation); } calculateOverallScopeClarity(project) { if (project.tasks.length === 0) return 0.8; const clarityScores = project.tasks.map(task => this.calculateScopeClarity(task)); return clarityScores.reduce((sum, score) => sum + score, 0) / clarityScores.length; } calculateWorkloadDistribution(project) { if (!project.team || project.team.length === 0) return 0.5; const workloads = project.team.map(member => this.calculateAssigneeWorkload(member.id, project)); const avgWorkload = workloads.reduce((sum, w) => sum + w, 0) / workloads.length; // Calculate variance in workload distribution const variance = workloads.reduce((sum, w) => sum + Math.pow(w - avgWorkload, 2), 0) / workloads.length; const standardDeviation = Math.sqrt(variance); // Lower variance = better distribution return Math.max(0.3, 1 - standardDeviation); } calculateSkillMatching(project) { let matchingScore = 0.8; for (const task of project.tasks) { if (task.assignee && task.type) { const assignee = project.team.find(member => member.id === task.assignee); if (assignee && assignee.skills) { const skillLevel = assignee.skills[task.type] || 0.5; matchingScore *= (0.5 + skillLevel * 0.5); } } } return Math.max(0.3, matchingScore); } calculateUtilizationEfficiency(project) { if (!project.team || project.team.length === 0) return 0.5; const utilizationScores = project.team.map(member => { const workload = this.calculateAssigneeWorkload(member.id, project); // Optimal utilization is around 0.8 (80%) if (workload < 0.5) return workload * 2; // Underutilized if (workload > 0.9) return (1 - workload) * 10; // Overutilized return 1.0; // Well utilized }); return utilizationScores.reduce((sum, score) => sum + score, 0) / utilizationScores.length; } async updateTimelineEstimates(projectId) { const project = this.activeProjects.get(projectId); if (!project) return; const remainingTasks = project.tasks.filter(t => t.status !== 'completed'); let totalEstimatedHours = 0; for (const task of remainingTasks) { const baseEstimate = task.estimatedHours || 8; const resourceMultiplier = task.predictions?.resourceRequirement || 1.0; const adjustedEstimate = baseEstimate * resourceMultiplier; totalEstimatedHours += adjustedEstimate; } // Calculate team capacity const teamCapacity = this.calculateTeamCapacity(project); const effectiveHoursPerWeek = (project.team?.length || 1) * 40 * teamCapacity; if (effectiveHoursPerWeek > 0) { const weeksToComplete = totalEstimatedHours / effectiveHoursPerWeek; const estimatedCompletionDate = Date.now() + (weeksToComplete * 7 * 24 * 60 * 60 * 1000); project.timeline.estimatedEndDate = estimatedCompletionDate; this.timelineEstimates.set(projectId, { projectId, estimatedCompletionDate, totalEstimatedHours, weeksToComplete, confidence: this.calculateTimelineConfidence(project), lastUpdated: Date.now() }); } } calculateTimelineConfidence(project) { let confidence = 0.8; // Adjust based on historical accuracy const timelineAccuracy = project.predictions?.timelineAccuracy || 0.8; confidence *= timelineAccuracy; // Adjust based on scope clarity const scopeClarity = this.calculateOverallScopeClarity(project); confidence *= scopeClarity; // Adjust based on team stability const teamStability = this.calculateTeamStability(project); confidence *= teamStability; return Math.max(0.3, Math.min(confidence, 0.95)); } startRiskAssessment() { setInterval(() => { this.performRiskAssessment(); }, this.riskAssessmentInterval); console.log(`⚠️ Risk assessment started (${this.riskAssessmentInterval / 1000}s interval)`); } async performRiskAssessment() { for (const [projectId, project] of this.activeProjects) { if (project.status === 'active' || project.status === 'planning') { await this.assessProjectRisks(projectId); } } } async assessProjectRisks(projectId) { const project = this.activeProjects.get(projectId); if (!project) return; const risks = []; // Check for high-risk tasks const highRiskTasks = project.tasks.filter(task => (task.predictions?.failureRisk || 0) > 0.7 ); if (highRiskTasks.length > 0) { risks.push({ type: 'high_risk_tasks', severity: 'high', description: `${highRiskTasks.length} tasks have high failure risk`, tasks: highRiskTasks.map(t => t.id), recommendation: 'Review task complexity and resource allocation' }); } // Check for timeline risks if (project.timeline.estimatedEndDate && project.timeline.estimatedEndDate < Date.now()) { risks.push({ type: 'timeline_overrun', severity: 'critical', description: 'Project is behind schedule', recommendation: 'Reassess scope and resource allocation' }); } // Check for resource risks const overloadedMembers = project.team?.filter(member => this.calculateAssigneeWorkload(member.id, project) > 0.9 ) || []; if (overloadedMembers.length > 0) { risks.push({ type: 'resource_overload', severity: 'medium', description: `${overloadedMembers.length} team members are overloaded`, members: overloadedMembers.map(m => m.id), recommendation: 'Redistribute workload or add resources' }); } // Update project risks project.risks = risks; project.lastUpdated = Date.now(); // Store in risk factors cache this.riskFactors.set(projectId, { projectId, risks, riskLevel: this.calculateOverallRiskLevel(risks), timestamp: Date.now() }); if (risks.length > 0) { console.log(`⚠️ Identified ${risks.length} risks for project ${projectId}`); this.emit('project:risks_identified', { projectId, risks, riskLevel: this.calculateOverallRiskLevel(risks) }); } } calculateOverallRiskLevel(risks) { if (risks.length === 0) return 'low'; const severityWeights = { low: 1, medium: 2, high: 3, critical: 4 }; const totalWeight = risks.reduce((sum, risk) => sum + severityWeights[risk.severity], 0); const avgWeight = totalWeight / risks.length; if (avgWeight >= 3.5) return 'critical'; if (avgWeight >= 2.5) return 'high'; if (avgWeight >= 1.5) return 'medium'; return 'low'; } async updateTaskStatus(projectId, taskId, newStatus, actualHours = null) { const project = this.activeProjects.get(projectId); if (!project) { throw new Error(`Project ${projectId} not found`); } const task = project.tasks.find(t => t.id === taskId); if (!task) { throw new Error(`Task ${taskId} not found in project ${projectId}`); } const oldStatus = task.status; task.status = newStatus; if (newStatus === 'in_progress' && !task.startedAt) { task.startedAt = Date.now(); } if (newStatus === 'completed') { task.completedAt = Date.now(); if (actualHours !== null) { task.actualHours = actualHours; } // Add to historical data this.addToHistory(task, project); } project.lastUpdated = Date.now(); // Regenerate predictions await this.generateTaskPredictions(projectId, taskId); await this.generateProjectPredictions(projectId); console.log(`📊 Updated task ${taskId} status: ${oldStatus} → ${newStatus}`); this.emit('task:status_updated', { projectId, taskId, oldStatus, newStatus, task }); } addToHistory(task, project) { const historyEntry = { id: task.id, projectId: project.id, title: task.title, type: task.type, complexity: task.complexity, priority: task.priority, estimatedHours: task.estimatedHours, actualHours: task.actualHours, status: task.status, createdAt: task.createdAt, startedAt: task.startedAt, completedAt: task.completedAt, teamSize: project.team?.length || 1, dependencies: task.dependencies?.length || 0, predictions: task.predictions, timestamp: Date.now() }; this.taskHistory.push(historyEntry); // Keep only recent history if (this.taskHistory.length > this.maxHistoryEntries) { this.taskHistory = this.taskHistory.slice(-this.maxHistoryEntries); } // Save periodically if (this.taskHistory.length % 10 === 0) { this.saveHistoricalData(); } } getProjectPredictions(projectId) { const project = this.activeProjects.get(projectId); if (!project) return null; return { projectId, predictions: project.predictions, risks: project.risks, timeline: this.timelineEstimates.get(projectId), lastUpdated: project.lastUpdated }; } getTaskPredictions(projectId, taskId) { const project = this.activeProjects.get(projectId); if (!project) return null; const task = project.tasks.find(t => t.id === taskId); if (!task) return null; return { taskId, projectId, predictions: task.predictions, confidence: this.failurePredictions.get(taskId)?.confidence || 0.8, lastUpdated: project.lastUpdated }; } getPredictiveAnalytics() { const totalProjects = this.activeProjects.size; const totalTasks = Array.from(this.activeProjects.values()) .reduce((sum, project) => sum + project.tasks.length, 0); const highRiskProjects = Array.from(this.activeProjects.values()) .filter(project => (project.predictions?.failureRisk || 0) > 0.7).length; const highRiskTasks = Array.from(this.activeProjects.values()) .flatMap(project => project.tasks) .filter(task => (task.predictions?.failureRisk || 0) > 0.7).length; const avgProjectHealth = Array.from(this.activeProjects.values()) .reduce((sum, project) => sum + (project.predictions?.overallHealth || 0.8), 0) / Math.max(totalProjects, 1); const modelAccuracy = Array.from(this.predictionModels.values()) .reduce((sum, model) => sum + model.accuracy, 0) / this.predictionModels.size; return { totalProjects, totalTasks, highRiskProjects, highRiskTasks, avgProjectHealth, modelAccuracy, historicalDataPoints: this.taskHistory.length, predictionModels: Array.from(this.predictionModels.values()), riskAssessmentActive: true }; } getResourceOptimizationSuggestions(projectId) { const project = this.activeProjects.get(projectId); if (!project) return []; const suggestions = []; // Check for workload imbalances if (project.team && project.team.length > 1) { const workloads = project.team.map(member => ({ id: member.id, workload: this.calculateAssigneeWorkload(member.id, project) })); const overloaded = workloads.filter(w => w.workload > 0.9); const underutilized = workloads.filter(w => w.workload < 0.5); if (overloaded.length > 0 && underutilized.length > 0) { suggestions.push({ type: 'workload_rebalancing', priority: 'high', description: 'Redistribute tasks to balance workload', overloaded: overloaded.map(w => w.id), underutilized: underutilized.map(w => w.id) }); } } // Check for skill mismatches const mismatchedTasks = project.tasks.filter(task => { if (!task.assignee || !task.type) return false; const assignee = project.team?.find(member => member.id === task.assignee); if (!assignee || !assignee.skills) return false; return (assignee.skills[task.type] || 0.5) < 0.6; }); if (mismatchedTasks.length > 0) { suggestions.push({ type: 'skill_optimization', priority: 'medium', description: 'Reassign tasks to better match team member skills', tasks: mismatchedTasks.map(t => t.id) }); } // Check for dependency bottlenecks const blockedTasks = project.tasks.filter(task => { return task.dependencies?.some(depId => { const depTask = project.tasks.find(t => t.id === depId); return depTask && depTask.status !== 'completed'; }); }); if (blockedTasks.length > project.tasks.length * 0.3) { suggestions.push({ type: 'dependency_optimization', priority: 'high', description: 'Resolve dependency bottlenecks to unblock tasks', blockedTasks: blockedTasks.map(t => t.id) }); } return suggestions; } async optimizeProjectTimeline(projectId) { const project = this.activeProjects.get(projectId); if (!project) { throw new Error(`Project ${projectId} not found`); } const optimizations = []; // Identify critical path const criticalPath = this.calculateCriticalPath(project); // Suggest parallel execution opportunities const parallelOpportunities = this.identifyParallelOpportunities(project); if (parallelOpportunities.length > 0) { optimizations.push({ type: 'parallel_execution', impact: 'high', description: 'Execute independent tasks in parallel', opportunities: parallelOpportunities }); } // Suggest resource reallocation const resourceSuggestions = this.getResourceOptimizationSuggestions(projectId); optimizations.push(...resourceSuggestions); // Suggest scope adjustments for high-risk tasks const highRiskTasks = project.tasks.filter(task => (task.predictions?.failureRisk || 0) > 0.8 ); if (highRiskTasks.length > 0) { optimizations.push({ type: 'scope_adjustment', impact: 'medium', description: 'Consider reducing scope or adding resources for high-risk tasks', tasks: highRiskTasks.map(t => t.id) }); } return { projectId, criticalPath, optimizations, potentialTimeSaving: this.calculatePotentialTimeSaving(optimizations), confidence: 0.8 }; } calculateCriticalPath(project) { // Simplified critical path calculation const tasks = project.tasks.filter(t => t.status !== 'completed'); // Build dependency graph const dependencyMap = new Map(); tasks.forEach(task => { dependencyMap.set(task.id, task.dependencies || []); }); // Find tasks with no dependencies (can start immediately) const startTasks = tasks.filter(task => !task.dependencies || task.dependencies.length === 0 ); // Calculate longest path (simplified) const criticalTasks = []; let currentTasks = startTasks; while (currentTasks.length > 0) { // Find task with highest estimated hours const criticalTask = currentTasks.reduce((max, task) => (task.estimatedHours || 0) > (max.estimatedHours || 0) ? task : max ); criticalTasks.push(criticalTask.id); // Find next tasks that depend on this one currentTasks = tasks.filter(task => task.dependencies?.includes(criticalTask.id) ); } return criticalTasks; } identifyParallelOpportunities(project) { const opportunities = []; const incompleteTasks = project.tasks.filter(t => t.status !== 'completed'); // Group tasks by dependencies const independentTasks = incompleteTasks.filter(task => !task.dependencies || task.dependencies.length === 0 ); if (independentTasks.length > 1) { opportunities.push({ type: 'independent_tasks', tasks: independentTasks.map(t => t.id), description: 'These tasks can be executed in parallel' }); } return opportunities; } calculatePotentialTimeSaving(optimizations) { let timeSaving = 0; for (const optimization of optimizations) { switch (optimization.type) { case 'parallel_execution': timeSaving += 0.3; // 30% time saving potential break; case 'workload_rebalancing': timeSaving += 0.15; // 15% time saving potential break; case 'skill_optimization': timeSaving += 0.2; // 20% time saving potential break; case 'dependency_optimization': timeSaving += 0.25; // 25% time saving potential break; } } return Math.min(timeSaving, 0.6); // Cap at 60% time saving } async deleteProject(projectId) { const project = this.activeProjects.get(projectId); if (!project) { throw new Error(`Project ${projectId} not found`); } // Clean up related data this.activeProjects.delete(projectId); this.timelineEstimates.delete(projectId); this.riskFactors.delete(projectId); // Remove task predictions project.tasks.forEach(task => { this.failurePredictions.delete(task.id); }); console.log(`🗑️ Deleted project ${projectId} and associated predictions`); this.emit('project:deleted', { projectId }); } async trainPredictionModels() { if (this.taskHistory.length < 50) { console.log('⚠️ Insufficient historical data for model training'); return; } // Simulate model training with historical data for (const [modelId, model] of this.predictionModels) { const relevantData = this.taskHistory.filter(entry => this.isRelevantForModel(entry, model) ); if (relevantData.length >= 20) { // Simulate accuracy improvement const improvementFactor = Math.min(relevantData.length / 100, 0.1); model.accuracy = Math.min(model.accuracy + improvementFactor, 0.95); model.lastTrained = Date.now(); console.log(`🤖 Trained ${model.name}: accuracy ${(model.accuracy * 100).toFixed(1)}%`); } } this.emit('models:trained', { modelsUpdated: this.predictionModels.size, averageAccuracy: Array.from(this.predictionModels.values()) .reduce((sum, model) => sum + model.accuracy, 0) / this.predictionModels.size }); } isRelevantForModel(historyEntry, model) { // Check if history entry has the features needed for this model return model.features.every(feature => { switch (feature) { case 'complexity': return historyEntry.complexity !== undefined; case 'team_experience': return historyEntry.teamSize !== undefined; case 'dependencies': return historyEntry.dependencies !== undefined; case 'timeline_pressure': return historyEntry.estimatedHours && historyEntry.actualHours; default: return true; } }); } }