@sethdouglasford/claude-flow
Version:
Claude Code Flow - Advanced AI-powered development workflows with SPARC methodology
308 lines • 12.9 kB
JavaScript
/**
* Process Manager - Handles lifecycle of system processes
*/
import { EventEmitter } from "./event-emitter.js";
import chalk from "chalk";
import { ProcessType, ProcessStatus, } from "./types.js";
import { Orchestrator } from "../../../core/orchestrator.js";
import { TerminalManager } from "../../../terminal/manager.js";
import { MemoryManager } from "../../../memory/manager.js";
import { CoordinationManager } from "../../../coordination/manager.js";
import { MCPServer } from "../../../mcp/server.js";
import { eventBus } from "../../../core/event-bus.js";
import { ConfigManager } from "../../../config/config-manager.js";
import { Logger } from "../../../core/logger.js";
// Color compatibility
const colors = {
gray: chalk.gray,
yellow: chalk.yellow,
red: chalk.red,
green: chalk.green,
cyan: chalk.cyan,
blue: chalk.blue,
bold: chalk.bold,
};
export class ProcessManager extends EventEmitter {
processes = new Map();
orchestrator;
terminalManager;
memoryManager;
coordinationManager;
mcpServer;
config;
cleanLogger;
constructor() {
super();
this.initializeProcesses();
// Create a cleaner logger for component initialization
this.cleanLogger = new Logger({
level: "info",
format: "text", // Use text format for cleaner output
destination: "console",
});
}
initializeProcesses() {
const processDefinitions = [
{ id: "event-bus", name: "Event Bus", type: ProcessType.EVENT_BUS, status: ProcessStatus.STOPPED, startTime: 0, metrics: {} },
{ id: "memory-manager", name: "Memory Manager", type: ProcessType.MEMORY_MANAGER, status: ProcessStatus.STOPPED, startTime: 0, metrics: {} },
{ id: "terminal-pool", name: "Terminal Pool", type: ProcessType.TERMINAL_POOL, status: ProcessStatus.STOPPED, startTime: 0, metrics: {} },
{ id: "coordinator", name: "Coordination Manager", type: ProcessType.COORDINATOR, status: ProcessStatus.STOPPED, startTime: 0, metrics: {} },
{ id: "mcp-server", name: "MCP Server", type: ProcessType.MCP_SERVER, status: ProcessStatus.STOPPED, startTime: 0, metrics: {} },
{ id: "orchestrator", name: "Orchestrator Engine", type: ProcessType.ORCHESTRATOR, status: ProcessStatus.STOPPED, startTime: 0, metrics: {} },
];
for (const process of processDefinitions) {
this.processes.set(process.id, process);
}
}
async initialize(configPath) {
try {
const configManager = ConfigManager.getInstance();
if (configPath) {
await configManager.load(configPath);
}
else {
// Try to load default config file if it exists
try {
await configManager.load("./claude-flow.config.json");
}
catch (error) {
// If config file doesn't exist, create a default one
if (error.message?.includes("not found")) {
console.log("Creating default configuration file...");
await configManager.createDefaultConfig("./claude-flow.config.json");
await configManager.load("./claude-flow.config.json");
}
else {
throw error;
}
}
}
this.config = configManager.show();
this.emit("initialized", { config: this.config });
}
catch (error) {
this.emit("error", { component: "ProcessManager", error });
throw error;
}
}
async startProcess(processId) {
const process = this.processes.get(processId);
if (!process) {
throw new Error(`Unknown process: ${processId}`);
}
if (process.status === ProcessStatus.RUNNING) {
throw new Error(`Process ${processId} is already running`);
}
// Check dependencies for orchestrator
if (processId === "orchestrator") {
const requiredDeps = ["memory-manager", "terminal-pool", "coordinator", "mcp-server"];
const missingDeps = requiredDeps.filter(dep => {
const depProcess = this.processes.get(dep);
return !depProcess || depProcess.status !== ProcessStatus.RUNNING;
});
if (missingDeps.length > 0) {
throw new Error(`Cannot start orchestrator: missing dependencies: ${missingDeps.join(", ")}. Use "Start All" to start in proper order.`);
}
}
this.updateProcessStatus(processId, ProcessStatus.STARTING);
try {
switch (process.type) {
case ProcessType.EVENT_BUS:
// Event bus is already initialized globally
// Use Node.js process.pid directly
break;
case ProcessType.MEMORY_MANAGER:
this.memoryManager = new MemoryManager(this.config.memory, eventBus, this.cleanLogger);
await this.memoryManager.initialize();
break;
case ProcessType.TERMINAL_POOL:
this.terminalManager = new TerminalManager(this.config.terminal, eventBus, this.cleanLogger);
await this.terminalManager.initialize();
break;
case ProcessType.COORDINATOR:
this.coordinationManager = new CoordinationManager(this.config.coordination, eventBus, this.cleanLogger);
await this.coordinationManager.initialize();
break;
case ProcessType.MCP_SERVER:
// Stop any existing MCP server instance first
if (this.mcpServer) {
try {
await this.mcpServer.stop();
}
catch (error) {
// Ignore errors when stopping existing instance
}
}
this.mcpServer = new MCPServer(this.config.mcp, eventBus, this.cleanLogger);
await this.mcpServer.start();
break;
case ProcessType.ORCHESTRATOR:
if (!this.terminalManager || !this.memoryManager ||
!this.coordinationManager || !this.mcpServer) {
throw new Error("Required components not initialized");
}
this.orchestrator = new Orchestrator(this.config, this.terminalManager, this.memoryManager, this.coordinationManager, this.mcpServer, eventBus, this.cleanLogger);
await this.orchestrator.initialize();
break;
}
process.startTime = Date.now();
this.updateProcessStatus(processId, ProcessStatus.RUNNING);
this.emit("processStarted", { processId, process });
}
catch (error) {
this.updateProcessStatus(processId, ProcessStatus.ERROR);
process.metrics = {
...process.metrics,
lastError: error.message,
};
this.emit("processError", { processId, error });
throw error;
}
}
async stopProcess(processId) {
const process = this.processes.get(processId);
if (!process || process.status !== ProcessStatus.RUNNING) {
throw new Error(`Process ${processId} is not running`);
}
this.updateProcessStatus(processId, ProcessStatus.STOPPING);
try {
switch (process.type) {
case ProcessType.ORCHESTRATOR:
if (this.orchestrator) {
await this.orchestrator.shutdown();
this.orchestrator = undefined;
}
break;
case ProcessType.MCP_SERVER:
if (this.mcpServer) {
await this.mcpServer.stop();
this.mcpServer = undefined;
}
break;
case ProcessType.MEMORY_MANAGER:
if (this.memoryManager) {
await this.memoryManager.shutdown();
this.memoryManager = undefined;
}
break;
case ProcessType.TERMINAL_POOL:
if (this.terminalManager) {
await this.terminalManager.shutdown();
this.terminalManager = undefined;
}
break;
case ProcessType.COORDINATOR:
if (this.coordinationManager) {
await this.coordinationManager.shutdown();
this.coordinationManager = undefined;
}
break;
}
this.updateProcessStatus(processId, ProcessStatus.STOPPED);
this.emit("processStopped", { processId });
}
catch (error) {
this.updateProcessStatus(processId, ProcessStatus.ERROR);
this.emit("processError", { processId, error });
throw error;
}
}
async restartProcess(processId) {
await this.stopProcess(processId);
await new Promise(resolve => setTimeout(resolve, 1000)); // Brief delay
await this.startProcess(processId);
}
async startAll() {
// Start in dependency order
const startOrder = [
"event-bus",
"memory-manager",
"terminal-pool",
"coordinator",
"mcp-server",
"orchestrator",
];
for (const processId of startOrder) {
try {
await this.startProcess(processId);
}
catch (error) {
console.error(colors.red(`Failed to start ${processId}:`), error.message);
// Continue with other processes
}
}
}
async stopAll() {
// Stop in reverse dependency order
const stopOrder = [
"orchestrator",
"mcp-server",
"coordinator",
"terminal-pool",
"memory-manager",
"event-bus",
];
for (const processId of stopOrder) {
const process = this.processes.get(processId);
if (process && process.status === ProcessStatus.RUNNING) {
try {
await this.stopProcess(processId);
}
catch (error) {
console.error(colors.red(`Failed to stop ${processId}:`), error.message);
}
}
}
}
getProcess(processId) {
return this.processes.get(processId);
}
getAllProcesses() {
return Array.from(this.processes.values());
}
getSystemStats() {
const processes = this.getAllProcesses();
const runningProcesses = processes.filter(p => p.status === ProcessStatus.RUNNING);
const stoppedProcesses = processes.filter(p => p.status === ProcessStatus.STOPPED);
const errorProcesses = processes.filter(p => p.status === ProcessStatus.ERROR);
return {
totalProcesses: processes.length,
runningProcesses: runningProcesses.length,
stoppedProcesses: stoppedProcesses.length,
errorProcesses: errorProcesses.length,
systemUptime: this.getSystemUptime(),
totalMemory: this.getTotalMemoryUsage(),
totalCpu: this.getTotalCpuUsage(),
};
}
updateProcessStatus(processId, status) {
const process = this.processes.get(processId);
if (process) {
process.status = status;
this.emit("statusChanged", { processId, status });
}
}
getSystemUptime() {
const orchestrator = this.processes.get("orchestrator");
if (orchestrator?.startTime) {
return Date.now() - orchestrator.startTime;
}
return 0;
}
getTotalMemoryUsage() {
// Placeholder - would integrate with actual memory monitoring
return 0;
}
getTotalCpuUsage() {
// Placeholder - would integrate with actual CPU monitoring
return 0;
}
getProcessLogs(processId, _lines = 50) {
// Placeholder - would integrate with actual logging system
return [
`[${new Date().toISOString()}] Process ${processId} started`,
`[${new Date().toISOString()}] Process ${processId} is running normally`,
];
}
}
//# sourceMappingURL=process-manager.js.map