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
JavaScript
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;
}
}