/** * Dependency Container * * Factory functions for creating the full dependency graph. * Keeps startServer() thin and makes repo wiring reusable by the test harness. */ import type { DrizzleDatabase } from './db/index.js'; import { createDatabase, ensureSchema, DrizzleInitiativeRepository, DrizzlePhaseRepository, DrizzleTaskRepository, DrizzleMessageRepository, DrizzleAgentRepository, DrizzlePageRepository, DrizzleProjectRepository, DrizzleAccountRepository, DrizzleChangeSetRepository, DrizzleLogChunkRepository, DrizzleConversationRepository, DrizzleChatSessionRepository, DrizzleReviewCommentRepository, DrizzleErrandRepository, } from './db/index.js'; import type { InitiativeRepository } from './db/repositories/initiative-repository.js'; import type { PhaseRepository } from './db/repositories/phase-repository.js'; import type { TaskRepository } from './db/repositories/task-repository.js'; import type { MessageRepository } from './db/repositories/message-repository.js'; import type { AgentRepository } from './db/repositories/agent-repository.js'; import type { PageRepository } from './db/repositories/page-repository.js'; import type { ProjectRepository } from './db/repositories/project-repository.js'; import type { AccountRepository } from './db/repositories/account-repository.js'; import type { ChangeSetRepository } from './db/repositories/change-set-repository.js'; import type { LogChunkRepository } from './db/repositories/log-chunk-repository.js'; import type { ConversationRepository } from './db/repositories/conversation-repository.js'; import type { ChatSessionRepository } from './db/repositories/chat-session-repository.js'; import type { ReviewCommentRepository } from './db/repositories/review-comment-repository.js'; import type { ErrandRepository } from './db/repositories/errand-repository.js'; import type { EventBus } from './events/index.js'; import { createEventBus } from './events/index.js'; import { ProcessManager, ProcessRegistry } from './process/index.js'; import { LogManager } from './logging/index.js'; import { MultiProviderAgentManager } from './agent/index.js'; import { DefaultAccountCredentialManager } from './agent/credentials/index.js'; import type { AccountCredentialManager } from './agent/credentials/types.js'; import { DefaultDispatchManager } from './dispatch/manager.js'; import { DefaultPhaseDispatchManager } from './dispatch/phase-manager.js'; import type { DispatchManager, PhaseDispatchManager } from './dispatch/types.js'; import { SimpleGitBranchManager } from './git/simple-git-branch-manager.js'; import type { BranchManager } from './git/branch-manager.js'; import { ProjectSyncManager } from './git/remote-sync.js'; import { ExecutionOrchestrator } from './execution/orchestrator.js'; import { DefaultConflictResolutionService } from './coordination/conflict-resolution-service.js'; import { PreviewManager } from './preview/index.js'; import { findWorkspaceRoot } from './config/index.js'; import { createModuleLogger } from './logger/index.js'; import type { ServerContextDeps } from './server/index.js'; // ============================================================================= // Repositories // ============================================================================= /** * All 13 repository ports. */ export interface Repositories { initiativeRepository: InitiativeRepository; phaseRepository: PhaseRepository; taskRepository: TaskRepository; messageRepository: MessageRepository; agentRepository: AgentRepository; pageRepository: PageRepository; projectRepository: ProjectRepository; accountRepository: AccountRepository; changeSetRepository: ChangeSetRepository; logChunkRepository: LogChunkRepository; conversationRepository: ConversationRepository; chatSessionRepository: ChatSessionRepository; reviewCommentRepository: ReviewCommentRepository; errandRepository: ErrandRepository; } /** * Create all 13 Drizzle repository adapters from a database instance. * Reusable by both the production server and the test harness. */ export function createRepositories(db: DrizzleDatabase): Repositories { return { initiativeRepository: new DrizzleInitiativeRepository(db), phaseRepository: new DrizzlePhaseRepository(db), taskRepository: new DrizzleTaskRepository(db), messageRepository: new DrizzleMessageRepository(db), agentRepository: new DrizzleAgentRepository(db), pageRepository: new DrizzlePageRepository(db), projectRepository: new DrizzleProjectRepository(db), accountRepository: new DrizzleAccountRepository(db), changeSetRepository: new DrizzleChangeSetRepository(db), logChunkRepository: new DrizzleLogChunkRepository(db), conversationRepository: new DrizzleConversationRepository(db), chatSessionRepository: new DrizzleChatSessionRepository(db), reviewCommentRepository: new DrizzleReviewCommentRepository(db), errandRepository: new DrizzleErrandRepository(db), }; } // ============================================================================= // Container // ============================================================================= /** * Full dependency graph for the coordination server. */ export interface Container extends Repositories { db: DrizzleDatabase; eventBus: EventBus; processManager: ProcessManager; logManager: LogManager; workspaceRoot: string; credentialManager: AccountCredentialManager; agentManager: MultiProviderAgentManager; dispatchManager: DispatchManager; phaseDispatchManager: PhaseDispatchManager; branchManager: BranchManager; projectSyncManager: ProjectSyncManager; executionOrchestrator: ExecutionOrchestrator; previewManager: PreviewManager; /** Extract the subset of deps that CoordinationServer needs. */ toContextDeps(): ServerContextDeps; } /** * Options for container creation. */ export interface ContainerOptions { debug?: boolean; } /** * Create the full dependency container. * * Wires: ProcessRegistry → EventBus → ProcessManager → LogManager → * Database → Repositories → CredentialManager → AgentManager. * Runs ensureSchema() and reconcileAfterRestart() before returning. */ export async function createContainer(options?: ContainerOptions): Promise { const log = createModuleLogger('container'); // Infrastructure const registry = new ProcessRegistry(); const eventBus = createEventBus(); const processManager = new ProcessManager(registry, eventBus); const logManager = new LogManager(); // Database const db = createDatabase(); ensureSchema(db); log.info('database initialized'); // Repositories const repos = createRepositories(db); log.info('repositories created'); // Workspace root const workspaceRoot = findWorkspaceRoot(process.cwd()) ?? process.cwd(); log.info({ workspaceRoot }, 'workspace root resolved'); // Credential manager const credentialManager = new DefaultAccountCredentialManager(eventBus); log.info('credential manager created'); // Agent manager const agentManager = new MultiProviderAgentManager( repos.agentRepository, workspaceRoot, repos.projectRepository, repos.accountRepository, eventBus, credentialManager, repos.changeSetRepository, repos.phaseRepository, repos.taskRepository, repos.pageRepository, repos.logChunkRepository, options?.debug ?? false, undefined, // processManagerOverride repos.chatSessionRepository, repos.reviewCommentRepository, ); log.info('agent manager created'); // Branch manager const branchManager = new SimpleGitBranchManager(); log.info('branch manager created'); // Project sync manager const projectSyncManager = new ProjectSyncManager( repos.projectRepository, workspaceRoot, eventBus, ); log.info('project sync manager created'); // Dispatch managers const dispatchManager = new DefaultDispatchManager( repos.taskRepository, repos.messageRepository, agentManager, eventBus, repos.initiativeRepository, repos.phaseRepository, repos.agentRepository, repos.pageRepository, repos.projectRepository, branchManager, workspaceRoot, ); const phaseDispatchManager = new DefaultPhaseDispatchManager( repos.phaseRepository, repos.taskRepository, dispatchManager, eventBus, repos.initiativeRepository, repos.projectRepository, branchManager, workspaceRoot, projectSyncManager, ); log.info('dispatch managers created'); // Conflict resolution service (for orchestrator) const conflictResolutionService = new DefaultConflictResolutionService( repos.taskRepository, repos.agentRepository, repos.messageRepository, eventBus, ); // Execution orchestrator const executionOrchestrator = new ExecutionOrchestrator( branchManager, repos.phaseRepository, repos.taskRepository, repos.initiativeRepository, repos.projectRepository, phaseDispatchManager, dispatchManager, conflictResolutionService, eventBus, workspaceRoot, repos.agentRepository, agentManager, ); executionOrchestrator.start(); log.info('execution orchestrator started'); // Reconcile agent state from any previous server session. // Must run AFTER orchestrator.start() so event listeners are registered // and agent:stopped / agent:crashed events are not lost. await agentManager.reconcileAfterRestart(); log.info('agent reconciliation complete'); // Preview manager const previewManager = new PreviewManager( repos.projectRepository, eventBus, workspaceRoot, repos.phaseRepository, repos.initiativeRepository, ); log.info('preview manager created'); return { db, eventBus, processManager, logManager, workspaceRoot, credentialManager, agentManager, dispatchManager, phaseDispatchManager, branchManager, projectSyncManager, executionOrchestrator, previewManager, ...repos, toContextDeps(): ServerContextDeps { return { agentManager, credentialManager, dispatchManager, phaseDispatchManager, branchManager, projectSyncManager, executionOrchestrator, previewManager, workspaceRoot, ...repos, }; }, }; }