/** * V3 Daemon Manager * * Manages background daemon processes for: * - Metrics collection * - Swarm monitoring * - Pattern learning consolidation * - Statusline updates */ /** * Default daemon manager configuration */ const DEFAULT_CONFIG = { pidDirectory: '.claude-flow/pids', logDirectory: '.claude-flow/logs', daemons: [], autoRestart: true, maxRestartAttempts: 3, }; /** * Daemon Manager - controls background daemon processes */ export class DaemonManager { config; daemons = new Map(); restartCounts = new Map(); constructor(config) { this.config = { ...DEFAULT_CONFIG, ...config }; } /** * Register a daemon */ register(config, task) { if (this.daemons.has(config.name)) { throw new Error(`Daemon '${config.name}' is already registered`); } const state = { name: config.name, status: 'stopped', executionCount: 0, failureCount: 0, }; this.daemons.set(config.name, { config, state, task }); } /** * Start a daemon */ async start(name) { const daemon = this.daemons.get(name); if (!daemon) { throw new Error(`Daemon '${name}' not found`); } if (daemon.state.status === 'running') { return; // Already running } if (!daemon.config.enabled) { throw new Error(`Daemon '${name}' is disabled`); } daemon.state.status = 'starting'; daemon.state.startedAt = new Date(); try { // Start interval timer daemon.timer = setInterval(async () => { await this.executeDaemonTask(name); }, daemon.config.interval); daemon.state.status = 'running'; daemon.state.pid = process.pid; // Use current process for in-process daemons // Run initial execution await this.executeDaemonTask(name); } catch (error) { daemon.state.status = 'error'; daemon.state.error = error instanceof Error ? error.message : String(error); throw error; } } /** * Stop a daemon */ async stop(name) { const daemon = this.daemons.get(name); if (!daemon) { throw new Error(`Daemon '${name}' not found`); } if (daemon.state.status === 'stopped') { return; // Already stopped } daemon.state.status = 'stopping'; if (daemon.timer) { clearInterval(daemon.timer); daemon.timer = undefined; } daemon.state.status = 'stopped'; daemon.state.pid = undefined; } /** * Restart a daemon */ async restart(name) { await this.stop(name); await this.start(name); } /** * Start all registered daemons */ async startAll() { const promises = []; for (const [name, daemon] of this.daemons) { if (daemon.config.enabled) { promises.push(this.start(name)); } } await Promise.all(promises); } /** * Stop all daemons */ async stopAll() { const promises = []; for (const name of this.daemons.keys()) { promises.push(this.stop(name)); } await Promise.all(promises); } /** * Get daemon state */ getState(name) { return this.daemons.get(name)?.state; } /** * Get all daemon states */ getAllStates() { return Array.from(this.daemons.values()).map((d) => d.state); } /** * Check if daemon is running */ isRunning(name) { return this.daemons.get(name)?.state.status === 'running'; } /** * Update daemon interval */ updateInterval(name, interval) { const daemon = this.daemons.get(name); if (!daemon) { throw new Error(`Daemon '${name}' not found`); } daemon.config.interval = interval; // Restart if running to apply new interval if (daemon.state.status === 'running') { this.restart(name).catch(() => { }); } } /** * Enable a daemon */ enable(name) { const daemon = this.daemons.get(name); if (daemon) { daemon.config.enabled = true; } } /** * Disable a daemon */ disable(name) { const daemon = this.daemons.get(name); if (daemon) { daemon.config.enabled = false; this.stop(name).catch(() => { }); } } /** * Get daemon count */ get count() { return this.daemons.size; } /** * Get running daemon count */ get runningCount() { return Array.from(this.daemons.values()).filter((d) => d.state.status === 'running').length; } /** * Execute a daemon task */ async executeDaemonTask(name) { const daemon = this.daemons.get(name); if (!daemon || !daemon.task) { return; } try { await daemon.task(); daemon.state.executionCount++; daemon.state.lastUpdateAt = new Date(); daemon.state.error = undefined; // Reset restart count on successful execution this.restartCounts.set(name, 0); } catch (error) { daemon.state.failureCount++; daemon.state.error = error instanceof Error ? error.message : String(error); // Handle auto-restart if (this.config.autoRestart) { const restartCount = (this.restartCounts.get(name) ?? 0) + 1; this.restartCounts.set(name, restartCount); if (restartCount <= this.config.maxRestartAttempts) { // Schedule restart setTimeout(() => { this.restart(name).catch(() => { }); }, 1000 * restartCount); // Exponential backoff } else { daemon.state.status = 'error'; } } } } } /** * Metrics Daemon - collects and syncs metrics */ export class MetricsDaemon { manager; metricsStore = new Map(); constructor(manager) { this.manager = manager ?? new DaemonManager(); // Register metrics daemon this.manager.register({ name: 'metrics-sync', interval: 30000, // 30 seconds enabled: true, }, () => this.syncMetrics()); } /** * Start metrics collection */ async start() { await this.manager.start('metrics-sync'); } /** * Stop metrics collection */ async stop() { await this.manager.stop('metrics-sync'); } /** * Sync metrics */ async syncMetrics() { // Collect various metrics this.metricsStore.set('timestamp', new Date().toISOString()); this.metricsStore.set('memory', process.memoryUsage()); // Additional metrics would be collected here } /** * Get current metrics */ getMetrics() { return Object.fromEntries(this.metricsStore); } } /** * Swarm Monitor Daemon - monitors swarm activity */ export class SwarmMonitorDaemon { manager; swarmData = { activeAgents: 0, maxAgents: 15, coordinationActive: false, lastCheck: null, }; constructor(manager) { this.manager = manager ?? new DaemonManager(); // Register swarm monitor daemon this.manager.register({ name: 'swarm-monitor', interval: 3000, // 3 seconds enabled: true, }, () => this.checkSwarm()); } /** * Start swarm monitoring */ async start() { await this.manager.start('swarm-monitor'); } /** * Stop swarm monitoring */ async stop() { await this.manager.stop('swarm-monitor'); } /** * Check swarm status */ async checkSwarm() { // In a real implementation, this would check running processes // and coordination state this.swarmData.lastCheck = new Date(); } /** * Get swarm data */ getSwarmData() { return { ...this.swarmData }; } /** * Update active agent count */ updateAgentCount(count) { this.swarmData.activeAgents = count; } /** * Set coordination state */ setCoordinationActive(active) { this.swarmData.coordinationActive = active; } } /** * Hooks Learning Daemon - consolidates learned patterns using ReasoningBank */ export class HooksLearningDaemon { manager; patternsLearned = 0; routingAccuracy = 0; reasoningBank = null; lastConsolidation = null; consolidationStats = { totalRuns: 0, patternsPromoted: 0, patternsPruned: 0, duplicatesRemoved: 0, }; constructor(manager) { this.manager = manager ?? new DaemonManager(); // Register hooks learning daemon this.manager.register({ name: 'hooks-learning', interval: 60000, // 60 seconds enabled: true, }, () => this.consolidate()); } /** * Start learning consolidation */ async start() { // Lazy load ReasoningBank to avoid circular dependencies try { const { reasoningBank } = await import('../reasoningbank/index.js'); this.reasoningBank = reasoningBank; await this.reasoningBank.initialize(); } catch (error) { console.warn('[HooksLearningDaemon] ReasoningBank not available:', error); } await this.manager.start('hooks-learning'); } /** * Stop learning consolidation */ async stop() { await this.manager.stop('hooks-learning'); } /** * Consolidate learned patterns using ReasoningBank */ async consolidate() { if (!this.reasoningBank) { return; } try { const result = await this.reasoningBank.consolidate(); // Update stats this.consolidationStats.totalRuns++; this.consolidationStats.patternsPromoted += result.patternsPromoted; this.consolidationStats.patternsPruned += result.patternsPruned; this.consolidationStats.duplicatesRemoved += result.duplicatesRemoved; this.lastConsolidation = new Date(); // Update pattern count from ReasoningBank stats const stats = this.reasoningBank.getStats(); this.patternsLearned = stats.shortTermCount + stats.longTermCount; // Emit consolidation event if (result.patternsPromoted > 0 || result.patternsPruned > 0) { console.log(`[HooksLearningDaemon] Consolidated: ${result.patternsPromoted} promoted, ` + `${result.patternsPruned} pruned, ${result.duplicatesRemoved} deduped`); } } catch (error) { console.error('[HooksLearningDaemon] Consolidation failed:', error); } } /** * Get learning stats */ getStats() { return { patternsLearned: this.patternsLearned, routingAccuracy: this.routingAccuracy, consolidationStats: { ...this.consolidationStats }, lastConsolidation: this.lastConsolidation, }; } /** * Update pattern count */ updatePatternCount(count) { this.patternsLearned = count; } /** * Update routing accuracy */ updateRoutingAccuracy(accuracy) { this.routingAccuracy = accuracy; } /** * Get ReasoningBank stats (if available) */ getReasoningBankStats() { if (!this.reasoningBank) { return null; } return this.reasoningBank.getStats(); } /** * Force immediate consolidation */ async forceConsolidate() { await this.consolidate(); } } /** * Default daemon manager instance */ export const defaultDaemonManager = new DaemonManager(); export { DaemonManager as default, }; //# sourceMappingURL=index.js.map