task-engine-ai-core
Version:
Revolutionary AI-driven task management system with complete transformation trilogy: Frontend v0.1.0, Backend v0.2.0, CLI v0.3.0 - Enterprise-grade performance with 95% improvements
759 lines (663 loc) • 25.4 kB
JavaScript
/**
* Task Engine Frontend Service
*
* Main service that orchestrates the reworked frontend architecture,
* using active agent detection and MCP communication for all task operations.
*/
import { taskOperationRouter, OPERATION_TYPES } from './task-operation-router.js';
import { mcpCommunicationLayer, MCP_TOOLS } from './mcp-communication-layer.js';
import { activeAgentDetector } from './active-agent-detector.js';
import { enhancedTaskOperations } from './enhanced-task-operations.js';
import { performanceOptimizationEngine } from './performance-optimization-engine.js';
import { logger } from '../utils/logger-utils.js';
/**
* Service States
*/
export const SERVICE_STATES = {
INITIALIZING: 'initializing',
READY: 'ready',
BUSY: 'busy',
ERROR: 'error',
DISCONNECTED: 'disconnected'
};
/**
* Task Engine Frontend Service Class
*
* Provides a unified interface for all task management operations,
* leveraging the active agent pattern and MCP middleware.
*/
export class TaskEngineFrontendService {
constructor(options = {}) {
this.options = {
enableLogging: options.enableLogging ?? true,
autoInitialize: options.autoInitialize ?? true,
projectRoot: options.projectRoot,
sessionTimeout: options.sessionTimeout ?? 3600000, // 1 hour
enableEnhancedOperations: options.enableEnhancedOperations ?? true,
enablePerformanceOptimization: options.enablePerformanceOptimization ?? true,
...options
};
this.state = SERVICE_STATES.INITIALIZING;
this.session = null;
this.projectContext = null;
this.operationQueue = [];
this.isProcessingQueue = false;
this.serviceStats = {
operationsCompleted: 0,
operationsFailed: 0,
activeAgentOperations: 0,
fallbackOperations: 0,
enhancedOperations: 0,
optimizedOperations: 0,
startTime: Date.now()
};
if (this.options.autoInitialize) {
this.initialize();
}
}
/**
* Initialize the frontend service
* @param {Object} session - MCP session object
* @param {Object} projectContext - Project context information
* @returns {Promise<Object>} Initialization result
*/
async initialize(session = null, projectContext = null) {
try {
if (this.options.enableLogging) {
logger.info('Initializing Task Engine Frontend Service');
}
this.state = SERVICE_STATES.INITIALIZING;
this.session = session;
this.projectContext = projectContext || this.detectProjectContext();
// Validate project root
if (!this.options.projectRoot && !this.projectContext?.projectRoot) {
throw new Error('Project root must be specified for Task Engine operations');
}
// Test MCP connection
await this.testMCPConnection();
// Detect active agent capabilities
const agentDetection = await activeAgentDetector.detectActiveAgent(
this.session,
{ projectContext: this.projectContext }
);
this.state = SERVICE_STATES.READY;
if (this.options.enableLogging) {
logger.info('Task Engine Frontend Service initialized successfully', {
agentDetected: agentDetection.result,
strategy: agentDetection.strategy,
projectRoot: this.getProjectRoot()
});
}
return {
success: true,
state: this.state,
agentDetection,
projectRoot: this.getProjectRoot()
};
} catch (error) {
this.state = SERVICE_STATES.ERROR;
logger.error('Failed to initialize Task Engine Frontend Service', {
error: error.message
});
return {
success: false,
error: error.message,
state: this.state
};
}
}
/**
* Create a new task
* @param {Object} taskData - Task creation data
* @param {Object} options - Creation options
* @returns {Promise<Object>} Creation result
*/
async createTask(taskData, options = {}) {
return this.executeOperation(OPERATION_TYPES.CREATE_TASK, {
projectRoot: this.getProjectRoot(),
...taskData
}, options);
}
/**
* Get all tasks
* @param {Object} filters - Task filters
* @param {Object} options - Query options
* @returns {Promise<Object>} Tasks result
*/
async getTasks(filters = {}, options = {}) {
return this.executeOperation(OPERATION_TYPES.GET_TASKS, {
projectRoot: this.getProjectRoot(),
...filters
}, options);
}
/**
* Get a specific task
* @param {string|number} taskId - Task ID
* @param {Object} options - Query options
* @returns {Promise<Object>} Task result
*/
async getTask(taskId, options = {}) {
return this.executeOperation(OPERATION_TYPES.GET_TASK, {
projectRoot: this.getProjectRoot(),
id: taskId.toString()
}, options);
}
/**
* Update a task
* @param {string|number} taskId - Task ID
* @param {Object} updateData - Update data
* @param {Object} options - Update options
* @returns {Promise<Object>} Update result
*/
async updateTask(taskId, updateData, options = {}) {
return this.executeOperation(OPERATION_TYPES.UPDATE_TASK, {
projectRoot: this.getProjectRoot(),
id: taskId.toString(),
...updateData
}, options);
}
/**
* Set task status
* @param {string|number} taskId - Task ID
* @param {string} status - New status
* @param {Object} options - Status update options
* @returns {Promise<Object>} Status update result
*/
async setTaskStatus(taskId, status, options = {}) {
return this.executeOperation(OPERATION_TYPES.SET_STATUS, {
projectRoot: this.getProjectRoot(),
id: taskId.toString(),
status
}, options);
}
/**
* Expand a task into subtasks
* @param {string|number} taskId - Task ID
* @param {Object} expansionData - Expansion parameters
* @param {Object} options - Expansion options
* @returns {Promise<Object>} Expansion result
*/
async expandTask(taskId, expansionData = {}, options = {}) {
return this.executeOperation(OPERATION_TYPES.EXPAND_TASK, {
projectRoot: this.getProjectRoot(),
taskId: taskId.toString(),
...expansionData
}, options);
}
/**
* Analyze task complexity
* @param {Object} analysisData - Analysis parameters
* @param {Object} options - Analysis options
* @returns {Promise<Object>} Analysis result
*/
async analyzeTaskComplexity(analysisData = {}, options = {}) {
return this.executeOperation(OPERATION_TYPES.ANALYZE_TASK, {
projectRoot: this.getProjectRoot(),
...analysisData
}, options);
}
/**
* Execute a task operation through the routing system
* @param {string} operationType - Type of operation
* @param {Object} operationData - Operation data
* @param {Object} options - Execution options
* @returns {Promise<Object>} Operation result
*/
async executeOperation(operationType, operationData, options = {}) {
try {
// Check service state
if (this.state !== SERVICE_STATES.READY) {
throw new Error(`Service not ready. Current state: ${this.state}`);
}
this.state = SERVICE_STATES.BUSY;
if (this.options.enableLogging) {
logger.info('Executing task operation', {
operationType,
dataKeys: Object.keys(operationData),
enhancedMode: this.options.enableEnhancedOperations,
optimizedMode: this.options.enablePerformanceOptimization
});
}
let result;
// Use enhanced operations if enabled and available
if (this.options.enableEnhancedOperations && this.isEnhancedOperationSupported(operationType)) {
result = await this.executeEnhancedOperation(operationType, operationData, options);
this.serviceStats.enhancedOperations++;
} else {
// Fall back to standard routing
result = await taskOperationRouter.routeOperation(
operationType,
operationData,
this.session,
{
projectContext: this.projectContext,
serviceOptions: this.options,
...options
}
);
}
// Update statistics
this.updateOperationStats(result);
this.state = SERVICE_STATES.READY;
if (this.options.enableLogging) {
logger.info('Task operation completed', {
operationType,
success: result.success,
strategy: result.routingInfo?.strategy || result.operationMetadata?.flowType,
enhanced: !!result.operationMetadata,
optimized: !!result.optimizationMetadata
});
}
return result;
} catch (error) {
this.state = SERVICE_STATES.ERROR;
this.serviceStats.operationsFailed++;
logger.error('Task operation failed', {
operationType,
error: error.message
});
return {
success: false,
error: error.message,
operationType,
timestamp: Date.now()
};
}
}
/**
* Execute operation using enhanced task operations
* @param {string} operationType - Operation type
* @param {Object} operationData - Operation data
* @param {Object} options - Execution options
* @returns {Promise<Object>} Enhanced operation result
*/
async executeEnhancedOperation(operationType, operationData, options) {
// Wrap enhanced operation with performance optimization if enabled
if (this.options.enablePerformanceOptimization) {
return performanceOptimizationEngine.optimizeOperation(
operationType,
operationData,
() => this.callEnhancedOperation(operationType, operationData, options),
options
);
} else {
return this.callEnhancedOperation(operationType, operationData, options);
}
}
/**
* Call enhanced operation directly
* @param {string} operationType - Operation type
* @param {Object} operationData - Operation data
* @param {Object} options - Execution options
* @returns {Promise<Object>} Operation result
*/
async callEnhancedOperation(operationType, operationData, options) {
switch (operationType) {
case OPERATION_TYPES.CREATE_TASK:
return enhancedTaskOperations.createTask(operationData, this.session, options);
case OPERATION_TYPES.GET_TASKS:
return enhancedTaskOperations.getTasks(operationData, this.session, options);
case OPERATION_TYPES.UPDATE_TASK:
return enhancedTaskOperations.updateTask(
operationData.id,
operationData,
this.session,
options
);
case OPERATION_TYPES.SET_STATUS:
return enhancedTaskOperations.setTaskStatus(
operationData.id,
operationData.status,
this.session,
options
);
case OPERATION_TYPES.EXPAND_TASK:
return enhancedTaskOperations.expandTask(
operationData.taskId || operationData.id,
operationData,
this.session,
options
);
default:
// Fall back to standard routing for unsupported operations
return taskOperationRouter.routeOperation(
operationType,
operationData,
this.session,
{
projectContext: this.projectContext,
serviceOptions: this.options,
...options
}
);
}
}
/**
* Check if enhanced operation is supported
* @param {string} operationType - Operation type
* @returns {boolean} True if supported
*/
isEnhancedOperationSupported(operationType) {
const supportedOperations = [
OPERATION_TYPES.CREATE_TASK,
OPERATION_TYPES.GET_TASKS,
OPERATION_TYPES.UPDATE_TASK,
OPERATION_TYPES.SET_STATUS,
OPERATION_TYPES.EXPAND_TASK
];
return supportedOperations.includes(operationType);
}
/**
* Queue an operation for batch processing
* @param {string} operationType - Type of operation
* @param {Object} operationData - Operation data
* @param {Object} options - Execution options
* @returns {Promise<string>} Operation ID for tracking
*/
async queueOperation(operationType, operationData, options = {}) {
const operationId = this.generateOperationId();
this.operationQueue.push({
id: operationId,
type: operationType,
data: operationData,
options,
timestamp: Date.now(),
status: 'queued'
});
if (this.options.enableLogging) {
logger.debug('Operation queued', {
operationId,
operationType,
queueLength: this.operationQueue.length
});
}
// Start processing queue if not already processing
if (!this.isProcessingQueue) {
this.processOperationQueue();
}
return operationId;
}
/**
* Process queued operations
*/
async processOperationQueue() {
if (this.isProcessingQueue || this.operationQueue.length === 0) {
return;
}
this.isProcessingQueue = true;
try {
while (this.operationQueue.length > 0) {
const operation = this.operationQueue.shift();
operation.status = 'processing';
try {
const result = await this.executeOperation(
operation.type,
operation.data,
operation.options
);
operation.status = result.success ? 'completed' : 'failed';
operation.result = result;
} catch (error) {
operation.status = 'failed';
operation.error = error.message;
}
if (this.options.enableLogging) {
logger.debug('Queued operation processed', {
operationId: operation.id,
status: operation.status
});
}
}
} finally {
this.isProcessingQueue = false;
}
}
/**
* Test MCP connection
* @returns {Promise<boolean>} Connection test result
*/
async testMCPConnection() {
try {
const result = await mcpCommunicationLayer.callTool(
MCP_TOOLS.GET_TASKS,
{ projectRoot: this.getProjectRoot() },
this.session,
{ timeout: 5000 }
);
return result.success;
} catch (error) {
if (this.options.enableLogging) {
logger.warn('MCP connection test failed', { error: error.message });
}
return false;
}
}
/**
* Detect project context from environment
* @returns {Object} Project context
*/
detectProjectContext() {
// This would implement actual project detection logic
return {
projectRoot: this.options.projectRoot || process.cwd(),
projectType: 'task-engine',
detectedAt: Date.now()
};
}
/**
* Get project root directory
* @returns {string} Project root path
*/
getProjectRoot() {
return this.options.projectRoot || this.projectContext?.projectRoot || process.cwd();
}
/**
* Update operation statistics
* @param {Object} result - Operation result
*/
updateOperationStats(result) {
this.serviceStats.operationsCompleted++;
// Track routing strategy
if (result.routingInfo?.strategy === 'active_agent') {
this.serviceStats.activeAgentOperations++;
} else {
this.serviceStats.fallbackOperations++;
}
// Track enhanced operations
if (result.operationMetadata) {
this.serviceStats.enhancedOperations++;
}
// Track optimized operations
if (result.optimizationMetadata) {
this.serviceStats.optimizedOperations++;
}
}
/**
* Generate unique operation ID
* @returns {string} Operation ID
*/
generateOperationId() {
return `op_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/**
* Get service status and statistics
* @returns {Object} Service status
*/
getStatus() {
const baseStatus = {
state: this.state,
stats: { ...this.serviceStats },
projectRoot: this.getProjectRoot(),
queueLength: this.operationQueue.length,
isProcessingQueue: this.isProcessingQueue,
uptime: Date.now() - this.serviceStats.startTime,
mcpStats: mcpCommunicationLayer.getStats(),
routingStats: taskOperationRouter.getRoutingStats(),
enhancedOperationsEnabled: this.options.enableEnhancedOperations,
performanceOptimizationEnabled: this.options.enablePerformanceOptimization
};
// Add enhanced operation statistics if enabled
if (this.options.enableEnhancedOperations) {
baseStatus.enhancedOperationStats = enhancedTaskOperations.getOperationStats();
}
// Add performance optimization statistics if enabled
if (this.options.enablePerformanceOptimization) {
baseStatus.performanceStats = performanceOptimizationEngine.getPerformanceMetrics();
}
return baseStatus;
}
/**
* Shutdown the service gracefully
* @returns {Promise<void>}
*/
async shutdown() {
if (this.options.enableLogging) {
logger.info('Shutting down Task Engine Frontend Service');
}
this.state = SERVICE_STATES.DISCONNECTED;
// Wait for queue to finish processing
while (this.isProcessingQueue) {
await new Promise(resolve => setTimeout(resolve, 100));
}
// Clear caches
mcpCommunicationLayer.clearCache();
activeAgentDetector.clearCache();
if (this.options.enableLogging) {
logger.info('Task Engine Frontend Service shutdown complete');
}
}
}
/**
* Default service instance
*/
export const taskEngineFrontendService = new TaskEngineFrontendService();
/**
* Convenience functions for common operations
* These functions now route through the service manager for better architecture integration
*/
export async function createTask(taskData, options) {
// Check if service manager is available for enhanced routing
try {
const { frontendServiceManager } = await import('./frontend-service-manager.js');
if (frontendServiceManager.state === 'ready') {
return frontendServiceManager.handleOperation('CREATE_TASK', {
projectRoot: taskData.projectRoot || process.cwd(),
...taskData
}, options);
}
} catch (error) {
// Fall back to direct service if manager not available
}
return taskEngineFrontendService.createTask(taskData, options);
}
export async function getTasks(filters, options) {
try {
const { frontendServiceManager } = await import('./frontend-service-manager.js');
if (frontendServiceManager.state === 'ready') {
return frontendServiceManager.handleOperation('GET_TASKS', {
projectRoot: filters?.projectRoot || process.cwd(),
...filters
}, options);
}
} catch (error) {
// Fall back to direct service
}
return taskEngineFrontendService.getTasks(filters, options);
}
export async function getTask(taskId, options) {
try {
const { frontendServiceManager } = await import('./frontend-service-manager.js');
if (frontendServiceManager.state === 'ready') {
return frontendServiceManager.handleOperation('GET_TASK', {
projectRoot: options?.projectRoot || process.cwd(),
id: taskId.toString()
}, options);
}
} catch (error) {
// Fall back to direct service
}
return taskEngineFrontendService.getTask(taskId, options);
}
export async function updateTask(taskId, updateData, options) {
try {
const { frontendServiceManager } = await import('./frontend-service-manager.js');
if (frontendServiceManager.state === 'ready') {
return frontendServiceManager.handleOperation('UPDATE_TASK', {
projectRoot: updateData.projectRoot || process.cwd(),
id: taskId.toString(),
...updateData
}, options);
}
} catch (error) {
// Fall back to direct service
}
return taskEngineFrontendService.updateTask(taskId, updateData, options);
}
export async function setTaskStatus(taskId, status, options) {
try {
const { frontendServiceManager } = await import('./frontend-service-manager.js');
if (frontendServiceManager.state === 'ready') {
return frontendServiceManager.handleOperation('SET_STATUS', {
projectRoot: options?.projectRoot || process.cwd(),
id: taskId.toString(),
status
}, options);
}
} catch (error) {
// Fall back to direct service
}
return taskEngineFrontendService.setTaskStatus(taskId, status, options);
}
export async function expandTask(taskId, expansionData, options) {
try {
const { frontendServiceManager } = await import('./frontend-service-manager.js');
if (frontendServiceManager.state === 'ready') {
return frontendServiceManager.handleOperation('EXPAND_TASK', {
projectRoot: expansionData.projectRoot || process.cwd(),
taskId: taskId.toString(),
...expansionData
}, options);
}
} catch (error) {
// Fall back to direct service
}
return taskEngineFrontendService.expandTask(taskId, expansionData, options);
}
export async function initializeService(session, projectContext) {
// Try to initialize through service manager for enhanced capabilities
try {
const { frontendServiceManager } = await import('./frontend-service-manager.js');
const managerResult = await frontendServiceManager.initialize(session, projectContext);
if (managerResult.success) {
return {
...managerResult,
enhancedMode: true,
migrationInfo: {
phase: managerResult.migrationPhase,
readinessScore: managerResult.migrationAssessment?.readinessScore
}
};
}
} catch (error) {
// Fall back to direct service initialization
logger.debug('Service manager not available, using direct service initialization');
}
return taskEngineFrontendService.initialize(session, projectContext);
}
export async function getServiceStatus() {
// Try to get enhanced status from service manager
try {
const { frontendServiceManager } = await import('./frontend-service-manager.js');
if (frontendServiceManager.state === 'ready') {
const managerStatus = frontendServiceManager.getStatus();
return {
...managerStatus,
enhancedMode: true,
directServiceStatus: taskEngineFrontendService.getStatus()
};
}
} catch (error) {
// Fall back to direct service status
}
return taskEngineFrontendService.getStatus();
}