claude-flow-novice
Version:
Claude Flow Novice - Advanced orchestration platform for multi-agent AI workflows with CFN Loop architecture Includes Local RuVector Accelerator and all CFN skills for complete functionality.
193 lines (192 loc) • 6.33 kB
JavaScript
/**
* Dependency Resolver
* Resolves agent task dependencies and builds execution graphs
*/ import { Logger } from '../core/logger.js';
/**
* Dependency Resolver: Parse dependencies and build execution graphs
*/ export class DependencyResolver {
logger;
constructor(){
const loggerConfig = process.env.CLAUDE_FLOW_ENV === 'test' ? {
level: 'error',
format: 'json',
destination: 'console'
} : {
level: 'info',
format: 'json',
destination: 'console'
};
this.logger = new Logger(loggerConfig, {
component: 'DependencyResolver'
});
}
/**
* Resolve dependencies and build execution graph
*/ resolveDependencies(tasks) {
this.logger.info('Resolving task dependencies', {
taskCount: tasks.length
});
// Build dependency graph
const graph = this.buildGraph(tasks);
// Detect cycles
const cycles = this.detectCycles(graph);
if (cycles.length > 0) {
this.logger.warn('Dependency cycles detected', {
cycleCount: cycles.length
});
}
// Perform topological sort
const executionOrder = this.topologicalSort(graph);
// Calculate max level
const maxLevel = Math.max(...Array.from(graph.values()).map((node)=>node.level));
const result = {
executionOrder,
graph,
cycles,
maxLevel
};
this.logger.info('Dependency resolution complete', {
levels: executionOrder.length,
maxLevel,
cycles: cycles.length
});
return result;
}
/**
* Build dependency graph from task definitions
*/ buildGraph(tasks) {
const graph = new Map();
// Initialize nodes
tasks.forEach((task)=>{
graph.set(task.taskId, {
taskId: task.taskId,
agentId: task.agentId,
dependencies: task.dependsOn || [],
dependents: [],
level: 0,
priority: task.priority || 0
});
});
// Build dependent relationships
tasks.forEach((task)=>{
task.dependsOn?.forEach((depId)=>{
const depNode = graph.get(depId);
if (depNode) {
depNode.dependents.push(task.taskId);
}
});
});
// Calculate levels (topological depth)
this.calculateLevels(graph);
return graph;
}
/**
* Calculate topological levels for each node
*/ calculateLevels(graph) {
const visited = new Set();
const calculateLevel = (nodeId)=>{
if (visited.has(nodeId)) {
return graph.get(nodeId)?.level ?? 0;
}
visited.add(nodeId);
const node = graph.get(nodeId);
if (!node) return 0;
if (node.dependencies.length === 0) {
node.level = 0;
return 0;
}
const maxDepLevel = Math.max(...node.dependencies.map((depId)=>calculateLevel(depId)));
node.level = maxDepLevel + 1;
return node.level;
};
graph.forEach((_, nodeId)=>{
calculateLevel(nodeId);
});
}
/**
* Perform topological sort to get execution order
*/ topologicalSort(graph) {
const levels = new Map();
// Group nodes by level
graph.forEach((node)=>{
if (!levels.has(node.level)) {
levels.set(node.level, []);
}
levels.get(node.level).push(node.taskId);
});
// Sort levels and sort within each level by priority
const sortedLevels = [];
const levelKeys = Array.from(levels.keys()).sort((a, b)=>a - b);
levelKeys.forEach((level)=>{
const taskIds = levels.get(level);
taskIds.sort((a, b)=>{
const nodeA = graph.get(a);
const nodeB = graph.get(b);
return (nodeB.priority || 0) - (nodeA.priority || 0);
});
sortedLevels.push(taskIds);
});
return sortedLevels;
}
/**
* Detect cycles in dependency graph
*/ detectCycles(graph) {
const cycles = [];
const visited = new Set();
const recursionStack = new Set();
const currentPath = [];
const detectCycle = (nodeId)=>{
if (recursionStack.has(nodeId)) {
// Cycle detected - extract cycle from current path
const cycleStart = currentPath.indexOf(nodeId);
cycles.push([
...currentPath.slice(cycleStart),
nodeId
]);
return true;
}
if (visited.has(nodeId)) {
return false;
}
visited.add(nodeId);
recursionStack.add(nodeId);
currentPath.push(nodeId);
const node = graph.get(nodeId);
if (node) {
for (const depId of node.dependencies){
if (detectCycle(depId)) {
// Continue searching for all cycles
}
}
}
currentPath.pop();
recursionStack.delete(nodeId);
return false;
};
graph.forEach((_, nodeId)=>{
if (!visited.has(nodeId)) {
detectCycle(nodeId);
}
});
return cycles;
}
/**
* Get tasks ready to execute (no pending dependencies)
*/ getReadyTasks(graph, completed) {
const ready = [];
graph.forEach((node)=>{
if (completed.has(node.taskId)) {
return;
}
const allDepsCompleted = node.dependencies.every((depId)=>completed.has(depId));
if (allDepsCompleted) {
ready.push(node);
}
});
// Sort by priority
ready.sort((a, b)=>(b.priority || 0) - (a.priority || 0));
return ready;
}
}
export default DependencyResolver;
//# sourceMappingURL=dependency-resolver.js.map