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.

187 lines (157 loc) 5.4 kB
import { readJSON, writeJSON } from '../../utils/file-utils.js'; import { log } from '../../utils/logging.js'; export class KnowledgeGraph { constructor() { this.nodes = new Map(); this.edges = new Map(); this.contextCache = new Map(); this.typeValidators = new Map(); } async initialize() { // Initialize type validators this.typeValidators.set('task', this.validateTaskContext); this.typeValidators.set('agent', this.validateAgentContext); this.typeValidators.set('chain', this.validateChainContext); this.typeValidators.set('workflow', this.validateWorkflowContext); log.info('Knowledge graph initialized'); } async addNode(node) { const { id, type, data } = node; if (!id || !type) { throw new Error('Node must have id and type'); } const timestamp = Date.now(); const nodeData = { ...node, data: data || {}, created: timestamp, updated: timestamp }; this.nodes.set(id, nodeData); this.contextCache.delete(id); // Invalidate cache return nodeData; } async addEdge(sourceId, targetId, type, data = {}) { if (!this.nodes.has(sourceId) || !this.nodes.has(targetId)) { throw new Error('Source or target node does not exist'); } const edgeId = `${sourceId}:${targetId}:${type}`; const timestamp = Date.now(); const edge = { id: edgeId, source: sourceId, target: targetId, type, data, created: timestamp, updated: timestamp }; this.edges.set(edgeId, edge); this.contextCache.delete(sourceId); this.contextCache.delete(targetId); return edge; } async updateContext(context) { const { id, type, ...data } = context; // Add or update node let node = this.nodes.get(id); if (node) { node = { ...node, data: { ...node.data, ...data }, updated: Date.now() }; } else { node = await this.addNode({ id, type, data }); } this.nodes.set(id, node); this.contextCache.set(id, { ...node, connected: await this.getConnectedNodes(id) }); return this.contextCache.get(id); } async getContext(id) { if (!this.nodes.has(id)) { throw new Error(`Node ${id} not found`); } if (!this.contextCache.has(id)) { const node = this.nodes.get(id); const connected = await this.getConnectedNodes(id); this.contextCache.set(id, { ...node, connected }); } return this.contextCache.get(id); } async findNodes(type, criteria = {}) { return Array.from(this.nodes.values()) .filter(node => { if (type && node.type !== type) return false; return Object.entries(criteria).every(([key, value]) => node.data[key] === value ); }); } async getConnectedNodes(id, edgeType = null) { const connected = {}; for (const edge of this.edges.values()) { if (edgeType && edge.type !== edgeType) continue; if (edge.source === id) { const target = this.nodes.get(edge.target); if (!connected[edge.type]) connected[edge.type] = []; connected[edge.type].push(target); } if (edge.target === id) { const source = this.nodes.get(edge.source); const reverseType = `${edge.type}_by`; if (!connected[reverseType]) connected[reverseType] = []; connected[reverseType].push(source); } } return connected; } validateTaskContext(context) { const required = ['title', 'status', 'priority']; return required.every(field => context.data[field] !== undefined); } validateAgentContext(context) { const required = ['capabilities', 'status', 'metrics']; return required.every(field => context.data[field] !== undefined); } validateChainContext(context) { const required = ['type', 'steps', 'status']; return required.every(field => context.data[field] !== undefined); } validateWorkflowContext(context) { const required = ['steps', 'status', 'assignedAgents']; return required.every(field => context.data[field] !== undefined); } async validateContext(context) { const validator = this.typeValidators.get(context.type); if (!validator) return true; // No validation rules for this type return validator.call(this, context); } async analyzeContext(id) { const context = await this.getContext(id); const connected = await this.getConnectedNodes(id); const analysis = { type: context.type, metrics: { connections: Object.values(connected).flat().length, lastUpdated: context.updated } }; // Type-specific analysis switch (context.type) { case 'task': analysis.metrics.dependencies = connected.depends_on?.length || 0; analysis.metrics.blockers = connected.blocked_by?.length || 0; break; case 'agent': analysis.metrics.assignedTasks = connected.assigned?.length || 0; analysis.metrics.completedTasks = connected.completed?.length || 0; break; case 'chain': analysis.metrics.activeSteps = connected.contains?.filter(n => n.data.status === 'active').length || 0; analysis.metrics.completedSteps = connected.contains?.filter(n => n.data.status === 'completed').length || 0; break; } return analysis; } }