UNPKG

cortexweaver

Version:

CortexWeaver is a command-line interface (CLI) tool that orchestrates a swarm of specialized AI agents, powered by Claude Code and Gemini CLI, to assist in software development. It transforms a high-level project plan (plan.md) into a series of coordinate

363 lines 16.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.Orchestrator = void 0; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const cognitive_canvas_1 = require("../cognitive-canvas"); const plan_parser_1 = require("../plan-parser"); const claude_client_1 = require("../claude-client"); const workspace_1 = require("../workspace"); const session_1 = require("../session"); const critique_1 = require("../agents/critique"); const debugger_1 = require("../agents/debugger"); const cognitive_canvas_navigator_1 = require("../agents/cognitive-canvas-navigator"); // Import modular components const workflow_manager_1 = require("./workflow-manager"); const task_executor_1 = require("./task-executor"); const agent_spawner_1 = require("./agent-spawner"); const error_handler_1 = require("./error-handler"); const status_manager_1 = require("./status-manager"); const utils_1 = require("./utils"); class Orchestrator { constructor(config) { // State this.parsedPlan = null; if (!config.neo4j) { throw new Error('Neo4j configuration is required'); } if (!config.claude) { throw new Error('Claude configuration is required'); } // Initialize core dependencies this.canvas = new cognitive_canvas_1.CognitiveCanvas(config.neo4j); this.parser = new plan_parser_1.PlanParser(); this.client = new claude_client_1.ClaudeClient(config.claude); this.workspace = new workspace_1.WorkspaceManager(); this.sessionManager = new session_1.SessionManager(); this.critiqueAgent = new critique_1.CritiqueAgent(this.client, this.canvas); this.debuggerAgent = new debugger_1.DebuggerAgent(); this.cognitiveCanvasNavigator = new cognitive_canvas_navigator_1.CognitiveCanvasNavigator(); // Initialize modular components this.workflowManager = new workflow_manager_1.WorkflowManager(); this.agentSpawner = new agent_spawner_1.AgentSpawner(this.workspace, this.sessionManager); this.statusManager = new status_manager_1.StatusManager(this.canvas, this.client, this.sessionManager, this.workflowManager); this.taskExecutor = new task_executor_1.TaskExecutor(this.canvas, this.workspace, this.sessionManager, this.workflowManager); this.errorHandler = new error_handler_1.ErrorHandler(this.canvas, this.sessionManager, this.agentSpawner, this.workflowManager, this.critiqueAgent, this.debuggerAgent); } async initialize(projectPath) { try { console.log('Initializing Orchestrator...'); // Initialize Cognitive Canvas schema await this.canvas.initializeSchema(); // Load and parse plan const planPath = path.join(projectPath, 'plan.md'); if (!fs.existsSync(planPath)) { throw new Error(`Plan file not found at ${planPath}`); } const planContent = fs.readFileSync(planPath, 'utf-8'); this.parsedPlan = this.parser.parse(planContent); // Create project in Cognitive Canvas const projectData = { id: `project-${Date.now()}`, name: this.parsedPlan.title, description: this.parsedPlan.overview, status: 'initialized', createdAt: new Date().toISOString() }; const project = await this.canvas.createProject(projectData); this.statusManager.setProjectId(project.id); // Create tasks with dependency ordering await (0, utils_1.createTasks)(this.parsedPlan, this.canvas, this.statusManager, this.workflowManager); // Initialize workflow states for all tasks await (0, utils_1.initializeTaskWorkflowStates)(this.canvas, this.statusManager, this.workflowManager); // Store architectural decisions await (0, utils_1.storeArchitecturalDecisions)(this.parsedPlan, this.canvas, this.statusManager); this.statusManager.setStatus('initialized'); console.log(`Project ${this.parsedPlan.title} initialized successfully`); } catch (error) { this.statusManager.setStatus('error'); throw new Error(`Failed to initialize orchestrator: ${error.message}`); } } async start() { const projectId = this.statusManager.getProjectId(); if (!projectId || !this.parsedPlan) { throw new Error('Project must be initialized before starting'); } this.statusManager.setRunning(true); this.statusManager.setStatus('running'); console.log('Starting orchestration...'); try { while (this.statusManager.isRunning()) { // Check budget before processing if (!this.statusManager.checkBudgetLimit()) { console.log('Budget limit reached, stopping orchestration'); break; } await this.processNextTask(); await this.taskExecutor.monitorTasks(projectId); // Check if all tasks completed const allCompleted = await this.statusManager.areAllTasksCompleted(); if (allCompleted) { console.log('All tasks completed!'); this.statusManager.setStatus('completed'); break; } // Log status summary periodically await this.statusManager.logStatusSummary(); // Small delay to prevent busy waiting await new Promise(resolve => setTimeout(resolve, 1000)); } } catch (error) { console.error('Orchestration error:', error); this.statusManager.setStatus('error'); } finally { this.statusManager.setRunning(false); } } async processNextTask() { try { const projectId = this.statusManager.getProjectId(); if (!projectId) return; const tasks = await this.canvas.getTasksByProject(projectId); const availableTasks = tasks.filter(task => task.status === 'pending'); for (const task of availableTasks) { const dependencies = await this.canvas.getTaskDependencies(task.id); const unmetDependencies = dependencies.filter(dep => dep.status !== 'completed'); if (unmetDependencies.length === 0) { // Perform critique check const shouldProceed = await this.errorHandler.performCritiqueCheck(task.id); if (!shouldProceed) { console.log(`Task ${task.id} blocked by critique findings`); continue; } // Prime context for task before spawning agent const contextData = await this.primeContextForTask(task.id, task); // Process task with workflow awareness await this.taskExecutor.processTaskWithWorkflow(task); break; // Process one task at a time } } } catch (error) { console.error('Error processing next task:', error); } } async spawnAgent(task, agentType) { const contextData = await this.primeContextForTask(task.id, task); const result = await this.agentSpawner.spawnAgent(task, agentType, contextData); if (!result.success) { throw new Error(result.error || 'Failed to spawn agent'); } } async handleImpasse(taskId) { const result = await this.errorHandler.handleImpasse(taskId); if (!result.success) { console.error(`Failed to handle impasse for task ${taskId}: ${result.message}`); } } async handleTaskCompletion(taskId) { await this.taskExecutor.handleTaskCompletion(taskId); } async handleTaskFailure(taskId, failure) { const result = await this.errorHandler.handleTaskFailure(taskId, failure); if (!result.success && result.escalated) { console.error(`Task failure escalated for ${taskId}: ${result.message}`); } } // Public status methods checkBudgetLimit() { return this.statusManager.checkBudgetLimit(); } getTokenUsage() { return this.statusManager.getTokenUsage(); } getStatus() { return this.statusManager.getStatus(); } isRunning() { return this.statusManager.isRunning(); } async getProjectProgress() { return this.statusManager.getProjectProgress(); } async getSystemHealth() { return this.statusManager.getSystemHealth(); } async getDetailedStatusReport() { return this.statusManager.getDetailedStatusReport(); } // Additional methods for backward compatibility async monitorTasks() { const projectId = this.statusManager.getProjectId(); if (projectId) { await this.taskExecutor.monitorTasks(projectId); } } // Enhanced error handling methods for compatibility getActiveCodeSavantSessions() { // Return active sessions tracked by error handler return this.errorHandler.getActiveCodeSavantSessions(); } getTaskErrorHistory(taskId) { // Return error history for a specific task return this.errorHandler.getTaskErrorHistory(taskId); } getErrorRecoveryStatistics() { // Return error recovery statistics return this.errorHandler.getErrorRecoveryStatistics(); } async shutdown() { console.log('Shutting down Orchestrator...'); this.statusManager.setRunning(false); // Kill all active sessions const sessions = this.sessionManager.listSessions(); for (const session of sessions) { await this.sessionManager.killSession(session.sessionId); } // Close database connection await this.canvas.close(); // Reset status manager this.statusManager.reset(); console.log('Orchestrator shutdown complete'); } async primeContextForTask(taskId, task) { try { // Get current workflow state for context-aware priming const workflowState = this.workflowManager.getTaskWorkflowState(taskId); const currentStep = workflowState?.currentStep || 'DEFINE_REQUIREMENTS'; // Enhanced targeted context retrieval with workflow awareness const baseQuery = `${task.title} ${task.description}`; const enhancedQuery = this.workflowManager.enhanceQueryForWorkflowStep(baseQuery, currentStep); // Prepare navigation task for CognitiveCanvasNavigator const navigationTask = { id: `nav-${taskId}`, title: `Navigate context for ${task.title}`, description: `Find relevant context for workflow step ${currentStep}`, status: 'pending', priority: task.priority, projectId: task.projectId, createdAt: new Date().toISOString() }; const navigationContext = { query: { type: 'semantic', query: enhancedQuery, context: { taskId, taskType: 'feature_implementation', priority: task.priority, workflowStep: currentStep, limit: 50, nodeType: this.workflowManager.getTargetedNodeTypes(currentStep), selectProperties: this.workflowManager.getRelevantProperties(currentStep) }, filters: [ { type: 'node', field: 'type', operator: 'equals', value: this.workflowManager.getTargetedNodeTypes(currentStep) } ] } }; // Initialize navigator if not already done if (!this.cognitiveCanvasNavigator.getStatus || this.cognitiveCanvasNavigator.getStatus() === 'uninitialized') { await this.cognitiveCanvasNavigator.initialize({ id: 'orchestrator-navigator', role: 'navigator', capabilities: ['graph-navigation'], claudeConfig: { apiKey: this.client.getConfiguration()?.apiKey || 'default', }, workspaceRoot: process.cwd(), cognitiveCanvasConfig: { uri: 'bolt://localhost:7687', username: 'neo4j', password: 'password' } }); } // Execute navigation task await this.cognitiveCanvasNavigator.receiveTask(navigationTask, navigationContext); const navigationResultTask = await this.cognitiveCanvasNavigator.run(); const navigationResult = navigationResultTask.result || { nodes: [], relationships: [], paths: [], insights: [], metadata: { queryTime: 0, resultCount: 0, confidence: 0.5 } }; // Extract context specific to workflow step const relevantArtifacts = (0, utils_1.filterArtifactsByWorkflowStep)(navigationResult.nodes, currentStep); const patterns = (0, utils_1.extractWorkflowRelevantPatterns)(navigationResult.insights, currentStep); // Get step-specific relationships const relevantRelationships = navigationResult.relationships .filter((rel) => (0, utils_1.isRelationshipRelevantForStep)(rel, currentStep)) .slice(0, 20); // Limit relationships return { workflowStep: currentStep, relevantArtifacts, patterns, relationships: relevantRelationships, paths: navigationResult.paths.slice(0, 3), priming: { stepSpecificGuidance: this.workflowManager.getStepSpecificGuidance(currentStep), requiredInputs: this.workflowManager.getRequiredInputsForStep(currentStep), expectedOutputs: this.workflowManager.getExpectedOutputsForStep(currentStep) } }; } catch (error) { console.error(`Error priming context for task ${taskId}:`, error); return { workflowStep: 'DEFINE_REQUIREMENTS', relevantArtifacts: [], patterns: [], relationships: [], paths: [], priming: {} }; } } } exports.Orchestrator = Orchestrator; //# sourceMappingURL=index.js.map