UNPKG

task-master-neo-sdlc

Version:

Enhanced task management system with Neo SDLC agents and MCP tools for comprehensive, AI-driven software development lifecycle management.

289 lines (248 loc) 8.34 kB
import { log } from '../../utils/logging.js'; /** * @typedef {Object} ChainConfig * @property {string} id - Unique chain identifier * @property {string} type - Chain type (e.g., 'sequential', 'parallel', 'conditional') * @property {Object} options - Chain-specific options * @property {Array<string>} steps - Step IDs in execution order */ /** * @typedef {Object} StepResult * @property {string} stepId - ID of the completed step * @property {boolean} success - Whether the step completed successfully * @property {Object} data - Output data from the step * @property {Object} metrics - Performance metrics */ export class ChainSystem { constructor(knowledgeGraph) { this.knowledgeGraph = knowledgeGraph; this.chains = new Map(); this.stepHandlers = new Map(); this.activeChains = new Map(); this.chainTypes = new Map(); } async initialize() { // Register chain system in knowledge graph await this.knowledgeGraph.addNode({ id: 'chain-system', type: 'system', data: { status: 'active', registeredChains: 0, activeChains: 0, completedChains: 0 } }); // Register built-in chain types this._registerBuiltInChainTypes(); log.info('Chain system initialized'); } _registerBuiltInChainTypes() { // Sequential chain - executes steps in order this.registerChainType('sequential', { validate: (config) => { if (!config.steps || !Array.isArray(config.steps) || config.steps.length === 0) { return { valid: false, errors: ['Sequential chain requires non-empty steps array'] }; } return { valid: true }; }, getNextStep: (chain, completedSteps) => { const nextIndex = completedSteps.length; return nextIndex < chain.steps.length ? chain.steps[nextIndex] : null; } }); // Parallel chain - executes steps concurrently this.registerChainType('parallel', { validate: (config) => { if (!config.steps || !Array.isArray(config.steps) || config.steps.length === 0) { return { valid: false, errors: ['Parallel chain requires non-empty steps array'] }; } if (!config.options?.maxConcurrent) { return { valid: false, errors: ['Parallel chain requires maxConcurrent option'] }; } return { valid: true }; }, getNextStep: (chain, completedSteps) => { const remainingSteps = chain.steps.filter(step => !completedSteps.includes(step)); const activeCount = chain.steps.length - completedSteps.length; if (activeCount >= chain.options.maxConcurrent) return null; return remainingSteps[0] || null; } }); // Conditional chain - executes steps based on conditions this.registerChainType('conditional', { validate: (config) => { if (!config.options?.conditions || typeof config.options.conditions !== 'object') { return { valid: false, errors: ['Conditional chain requires conditions map'] }; } return { valid: true }; }, getNextStep: (chain, completedSteps, stepResults) => { if (completedSteps.length === 0) return chain.steps[0]; const lastResult = stepResults[stepResults.length - 1]; const nextStep = chain.options.conditions[lastResult.data.condition]; return nextStep || null; } }); } registerChainType(type, handlers) { if (this.chainTypes.has(type)) { throw new Error(`Chain type ${type} already registered`); } if (!handlers.validate || !handlers.getNextStep) { throw new Error('Chain type handlers must include validate and getNextStep functions'); } this.chainTypes.set(type, handlers); log.info(`Registered chain type: ${type}`); } async registerChain(config) { // Validate chain configuration if (!config.id || !config.type) { throw new Error('Chain requires id and type'); } const chainType = this.chainTypes.get(config.type); if (!chainType) { throw new Error(`Unknown chain type: ${config.type}`); } const validation = chainType.validate(config); if (!validation.valid) { throw new Error(`Invalid chain configuration: ${validation.errors.join(', ')}`); } this.chains.set(config.id, { ...config, status: 'registered', completedSteps: [], stepResults: [] }); // Update knowledge graph await this.knowledgeGraph.addNode({ id: `chain:${config.id}`, type: 'workflow-chain', data: config }); await this._updateSystemMetrics(); return config.id; } async executeChain(chainId) { const chain = this.chains.get(chainId); if (!chain) { throw new Error(`Chain not found: ${chainId}`); } if (this.activeChains.has(chainId)) { throw new Error(`Chain ${chainId} is already executing`); } chain.status = 'active'; this.activeChains.set(chainId, chain); try { await this._executeChainSteps(chain); chain.status = 'completed'; log.info(`Chain ${chainId} completed successfully`); } catch (error) { chain.status = 'failed'; log.error(`Chain ${chainId} failed: ${error.message}`); throw error; } finally { this.activeChains.delete(chainId); await this._updateSystemMetrics(); } return chain.stepResults; } async _executeChainSteps(chain) { const chainType = this.chainTypes.get(chain.type); while (true) { const nextStep = chainType.getNextStep(chain, chain.completedSteps, chain.stepResults); if (!nextStep) break; try { const result = await this.executeStep(nextStep, chain); chain.completedSteps.push(nextStep); chain.stepResults.push(result); // Update knowledge graph await this.knowledgeGraph.updateContext({ id: `chain:${chain.id}`, type: 'workflow-chain', data: { completedSteps: chain.completedSteps, lastStepResult: result } }); } catch (error) { log.error(`Step ${nextStep} failed: ${error.message}`); throw error; } } } async executeStep(stepId, chain) { const handler = this.stepHandlers.get(stepId); if (!handler) { throw new Error(`No handler registered for step: ${stepId}`); } const startTime = Date.now(); try { const data = await handler(chain); const result = { stepId, success: true, data, metrics: { executionTime: Date.now() - startTime, timestamp: new Date().toISOString() } }; // Log step completion log.info(`Step ${stepId} completed successfully`, { chainId: chain.id, executionTime: result.metrics.executionTime }); return result; } catch (error) { const result = { stepId, success: false, error: error.message, metrics: { executionTime: Date.now() - startTime, timestamp: new Date().toISOString() } }; // Log step failure log.error(`Step ${stepId} failed`, { chainId: chain.id, error: error.message }); throw error; } } registerStepHandler(stepId, handler) { if (typeof handler !== 'function') { throw new Error('Step handler must be a function'); } this.stepHandlers.set(stepId, handler); } async getChainStatus(chainId) { const chain = this.chains.get(chainId); if (!chain) { throw new Error(`Chain not found: ${chainId}`); } return { id: chain.id, type: chain.type, status: chain.status, completedSteps: chain.completedSteps, progress: chain.steps.length > 0 ? (chain.completedSteps.length / chain.steps.length) * 100 : 0 }; } async _updateSystemMetrics() { await this.knowledgeGraph.updateContext({ id: 'chain-system', type: 'system', data: { registeredChains: this.chains.size, activeChains: this.activeChains.size, completedChains: Array.from(this.chains.values()) .filter(chain => chain.status === 'completed').length } }); } }