dependency-container.tsā¢9.18 kB
/**
 * Dependency Container - Centralized Dependency Injection
 * 
 * Manages dependencies between agent modules to prevent circular imports
 * Implements singleton pattern with lazy loading and safe initialization
 */
import { ImportCycleBreaker } from '../utils/import-cycle-breaker.js';
import logger from '../logger.js';
// Type definitions for agent classes
interface AgentRegistryClass {
  getInstance(): AgentRegistryInstance;
}
interface AgentTaskQueueClass {
  getInstance(): AgentTaskQueueInstance;
}
interface AgentResponseProcessorClass {
  getInstance(): AgentResponseProcessorInstance;
}
interface AgentIntegrationBridgeClass {
  getInstance(): AgentIntegrationBridgeInstance;
}
// Instance type definitions
interface AgentRegistryInstance {
  registerAgent(registration: unknown): Promise<void>;
  getAgent(agentId: string): Promise<unknown>;
  getAllAgents(): Promise<unknown[]>;
}
interface AgentTaskQueueInstance {
  addTask(agentId: string, task: unknown): Promise<string>;
  getTasks(agentId: string, maxTasks?: number): Promise<unknown[]>;
  getQueueLength(agentId: string): Promise<number>;
}
interface AgentResponseProcessorInstance {
  processResponse(response: unknown): Promise<void>;
  getResponse(taskId: string): Promise<unknown>;
  getAllResponses(): Promise<unknown[]>;
}
interface AgentIntegrationBridgeInstance {
  bridgeAgentData(agentId: string): Promise<unknown>;
  syncAgentStatus(agentId: string): Promise<void>;
}
export interface AgentDependencies {
  agentRegistry?: AgentRegistryInstance | null;
  agentTaskQueue?: AgentTaskQueueInstance | null;
  agentResponseProcessor?: AgentResponseProcessorInstance | null;
  agentIntegrationBridge?: AgentIntegrationBridgeInstance | null;
}
/**
 * Centralized dependency container for agent modules
 */
export class DependencyContainer {
  private static instance: DependencyContainer;
  private static isInitializing = false;
  private dependencies: AgentDependencies = {};
  private initializationPromises = new Map<string, Promise<unknown>>();
  static getInstance(): DependencyContainer {
    if (DependencyContainer.isInitializing) {
      logger.warn('Circular initialization detected in DependencyContainer, using safe fallback');
      return DependencyContainer.createSafeFallback();
    }
    if (!DependencyContainer.instance) {
      DependencyContainer.isInitializing = true;
      try {
        DependencyContainer.instance = new DependencyContainer();
      } finally {
        DependencyContainer.isInitializing = false;
      }
    }
    return DependencyContainer.instance;
  }
  private static createSafeFallback(): DependencyContainer {
    const fallback = Object.create(DependencyContainer.prototype);
    fallback.dependencies = {};
    fallback.initializationPromises = new Map();
    
    // Provide safe no-op methods
    fallback.getAgentRegistry = async () => null;
    fallback.getAgentTaskQueue = async () => null;
    fallback.getAgentResponseProcessor = async () => null;
    fallback.getAgentIntegrationBridge = async () => null;
    
    return fallback;
  }
  /**
   * Get AgentRegistry instance with safe loading
   */
  async getAgentRegistry(): Promise<unknown | null> {
    if (this.dependencies.agentRegistry) {
      return this.dependencies.agentRegistry;
    }
    // Check if initialization is already in progress
    if (this.initializationPromises.has('agentRegistry')) {
      return this.initializationPromises.get('agentRegistry');
    }
    // Start initialization
    const initPromise = this.initializeAgentRegistry();
    this.initializationPromises.set('agentRegistry', initPromise);
    
    try {
      const registry = await initPromise;
      this.dependencies.agentRegistry = registry;
      return registry;
    } finally {
      this.initializationPromises.delete('agentRegistry');
    }
  }
  private async initializeAgentRegistry(): Promise<AgentRegistryInstance | null> {
    try {
      const registryModule = await ImportCycleBreaker.safeImport<{ AgentRegistry: AgentRegistryClass }>('../tools/agent-registry/index.js');
      if (registryModule?.AgentRegistry) {
        return registryModule.AgentRegistry.getInstance();
      }
      logger.warn('AgentRegistry not available due to circular dependency');
      return null;
    } catch (error) {
      logger.error('Failed to initialize AgentRegistry:', error);
      return null;
    }
  }
  /**
   * Get AgentTaskQueue instance with safe loading
   */
  async getAgentTaskQueue(): Promise<unknown | null> {
    if (this.dependencies.agentTaskQueue) {
      return this.dependencies.agentTaskQueue;
    }
    if (this.initializationPromises.has('agentTaskQueue')) {
      return this.initializationPromises.get('agentTaskQueue');
    }
    const initPromise = this.initializeAgentTaskQueue();
    this.initializationPromises.set('agentTaskQueue', initPromise);
    
    try {
      const taskQueue = await initPromise;
      this.dependencies.agentTaskQueue = taskQueue;
      return taskQueue;
    } finally {
      this.initializationPromises.delete('agentTaskQueue');
    }
  }
  private async initializeAgentTaskQueue(): Promise<AgentTaskQueueInstance | null> {
    try {
      const taskQueueModule = await ImportCycleBreaker.safeImport<{ AgentTaskQueue: AgentTaskQueueClass }>('../tools/agent-tasks/index.js');
      if (taskQueueModule?.AgentTaskQueue) {
        return taskQueueModule.AgentTaskQueue.getInstance();
      }
      logger.warn('AgentTaskQueue not available due to circular dependency');
      return null;
    } catch (error) {
      logger.error('Failed to initialize AgentTaskQueue:', error);
      return null;
    }
  }
  /**
   * Get AgentResponseProcessor instance with safe loading
   */
  async getAgentResponseProcessor(): Promise<unknown | null> {
    if (this.dependencies.agentResponseProcessor) {
      return this.dependencies.agentResponseProcessor;
    }
    if (this.initializationPromises.has('agentResponseProcessor')) {
      return this.initializationPromises.get('agentResponseProcessor');
    }
    const initPromise = this.initializeAgentResponseProcessor();
    this.initializationPromises.set('agentResponseProcessor', initPromise);
    
    try {
      const responseProcessor = await initPromise;
      this.dependencies.agentResponseProcessor = responseProcessor;
      return responseProcessor;
    } finally {
      this.initializationPromises.delete('agentResponseProcessor');
    }
  }
  private async initializeAgentResponseProcessor(): Promise<AgentResponseProcessorInstance | null> {
    try {
      const responseModule = await ImportCycleBreaker.safeImport<{ AgentResponseProcessor: AgentResponseProcessorClass }>('../tools/agent-response/index.js');
      if (responseModule?.AgentResponseProcessor) {
        return responseModule.AgentResponseProcessor.getInstance();
      }
      logger.warn('AgentResponseProcessor not available due to circular dependency');
      return null;
    } catch (error) {
      logger.error('Failed to initialize AgentResponseProcessor:', error);
      return null;
    }
  }
  /**
   * Get AgentIntegrationBridge instance with safe loading
   */
  async getAgentIntegrationBridge(): Promise<unknown | null> {
    if (this.dependencies.agentIntegrationBridge) {
      return this.dependencies.agentIntegrationBridge;
    }
    if (this.initializationPromises.has('agentIntegrationBridge')) {
      return this.initializationPromises.get('agentIntegrationBridge');
    }
    const initPromise = this.initializeAgentIntegrationBridge();
    this.initializationPromises.set('agentIntegrationBridge', initPromise);
    
    try {
      const bridge = await initPromise;
      this.dependencies.agentIntegrationBridge = bridge;
      return bridge;
    } finally {
      this.initializationPromises.delete('agentIntegrationBridge');
    }
  }
  private async initializeAgentIntegrationBridge(): Promise<AgentIntegrationBridgeInstance | null> {
    try {
      const bridgeModule = await ImportCycleBreaker.safeImport<{ AgentIntegrationBridge: AgentIntegrationBridgeClass }>('../tools/vibe-task-manager/services/agent-integration-bridge.js');
      if (bridgeModule?.AgentIntegrationBridge) {
        return bridgeModule.AgentIntegrationBridge.getInstance();
      }
      logger.warn('AgentIntegrationBridge not available due to circular dependency');
      return null;
    } catch (error) {
      logger.error('Failed to initialize AgentIntegrationBridge:', error);
      return null;
    }
  }
  /**
   * Clear all cached dependencies (useful for testing)
   */
  clearCache(): void {
    this.dependencies = {};
    this.initializationPromises.clear();
  }
  /**
   * Get current dependency status for debugging
   */
  getDependencyStatus(): Record<string, boolean> {
    return {
      agentRegistry: !!this.dependencies.agentRegistry,
      agentTaskQueue: !!this.dependencies.agentTaskQueue,
      agentResponseProcessor: !!this.dependencies.agentResponseProcessor,
      agentIntegrationBridge: !!this.dependencies.agentIntegrationBridge
    };
  }
}
// Export singleton instance
export const dependencyContainer = DependencyContainer.getInstance();