ExecutionOrchestrator now listens for phase:queued and agent:stopped events to drive the dispatch cycle, closing the gap between queueing phases (Execute button) and actually spawning agents. Coalesced scheduling prevents reentrancy with synchronous EventEmitter.
276 lines
9.0 KiB
TypeScript
276 lines
9.0 KiB
TypeScript
/**
|
|
* 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,
|
|
} 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 { 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 { 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 12 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;
|
|
}
|
|
|
|
/**
|
|
* Create all 12 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),
|
|
};
|
|
}
|
|
|
|
// =============================================================================
|
|
// 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;
|
|
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<Container> {
|
|
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,
|
|
);
|
|
log.info('agent manager created');
|
|
|
|
// Reconcile agent state from any previous server session
|
|
await agentManager.reconcileAfterRestart();
|
|
log.info('agent reconciliation complete');
|
|
|
|
// Branch manager
|
|
const branchManager = new SimpleGitBranchManager();
|
|
log.info('branch manager created');
|
|
|
|
// Dispatch managers
|
|
const dispatchManager = new DefaultDispatchManager(
|
|
repos.taskRepository,
|
|
repos.messageRepository,
|
|
agentManager,
|
|
eventBus,
|
|
repos.initiativeRepository,
|
|
repos.phaseRepository,
|
|
repos.agentRepository,
|
|
repos.pageRepository,
|
|
);
|
|
const phaseDispatchManager = new DefaultPhaseDispatchManager(
|
|
repos.phaseRepository,
|
|
repos.taskRepository,
|
|
dispatchManager,
|
|
eventBus,
|
|
repos.initiativeRepository,
|
|
repos.projectRepository,
|
|
branchManager,
|
|
workspaceRoot,
|
|
);
|
|
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,
|
|
);
|
|
executionOrchestrator.start();
|
|
log.info('execution orchestrator started');
|
|
|
|
// Preview manager
|
|
const previewManager = new PreviewManager(
|
|
repos.projectRepository,
|
|
eventBus,
|
|
workspaceRoot,
|
|
);
|
|
log.info('preview manager created');
|
|
|
|
return {
|
|
db,
|
|
eventBus,
|
|
processManager,
|
|
logManager,
|
|
workspaceRoot,
|
|
credentialManager,
|
|
agentManager,
|
|
dispatchManager,
|
|
phaseDispatchManager,
|
|
branchManager,
|
|
executionOrchestrator,
|
|
previewManager,
|
|
...repos,
|
|
|
|
toContextDeps(): ServerContextDeps {
|
|
return {
|
|
agentManager,
|
|
credentialManager,
|
|
dispatchManager,
|
|
phaseDispatchManager,
|
|
branchManager,
|
|
executionOrchestrator,
|
|
previewManager,
|
|
workspaceRoot,
|
|
...repos,
|
|
};
|
|
},
|
|
};
|
|
}
|