- PhaseQueuedEvent for tracking phases awaiting execution - PhaseStartedEvent for phase execution start - PhaseCompletedEvent for phase completion with success flag - PhaseBlockedEvent for blocked phases with reason
404 lines
7.9 KiB
TypeScript
404 lines
7.9 KiB
TypeScript
/**
|
|
* Event Bus Types
|
|
*
|
|
* Port interface for the event bus - the backbone of the hexagonal architecture.
|
|
* EventBus is the PORT. Implementations (EventEmitterBus, RabbitMQ, etc.) are ADAPTERS.
|
|
*/
|
|
|
|
/**
|
|
* Base interface for all domain events.
|
|
* Every event in the system extends this.
|
|
*/
|
|
export interface DomainEvent {
|
|
/** Event type identifier (e.g., 'process:spawned', 'server:started') */
|
|
type: string;
|
|
/** When the event occurred */
|
|
timestamp: Date;
|
|
/** Event-specific data */
|
|
payload: unknown;
|
|
}
|
|
|
|
/**
|
|
* Event Bus Port Interface
|
|
*
|
|
* All modules communicate through this interface.
|
|
* Can be swapped for external systems (RabbitMQ, WebSocket forwarding) later.
|
|
*/
|
|
// =============================================================================
|
|
// Domain Event Types - Typed payloads for each event
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Process Events
|
|
*/
|
|
|
|
export interface ProcessSpawnedEvent extends DomainEvent {
|
|
type: 'process:spawned';
|
|
payload: {
|
|
processId: string;
|
|
pid: number;
|
|
command: string;
|
|
};
|
|
}
|
|
|
|
export interface ProcessStoppedEvent extends DomainEvent {
|
|
type: 'process:stopped';
|
|
payload: {
|
|
processId: string;
|
|
pid: number;
|
|
exitCode: number | null;
|
|
};
|
|
}
|
|
|
|
export interface ProcessCrashedEvent extends DomainEvent {
|
|
type: 'process:crashed';
|
|
payload: {
|
|
processId: string;
|
|
pid: number;
|
|
signal: string | null;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Server Events
|
|
*/
|
|
|
|
export interface ServerStartedEvent extends DomainEvent {
|
|
type: 'server:started';
|
|
payload: {
|
|
port: number;
|
|
host: string;
|
|
pid: number;
|
|
};
|
|
}
|
|
|
|
export interface ServerStoppedEvent extends DomainEvent {
|
|
type: 'server:stopped';
|
|
payload: {
|
|
uptime: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Log Events
|
|
*/
|
|
|
|
export interface LogEntryEvent extends DomainEvent {
|
|
type: 'log:entry';
|
|
payload: {
|
|
processId: string;
|
|
stream: 'stdout' | 'stderr';
|
|
data: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Git Worktree Events
|
|
*/
|
|
|
|
export interface WorktreeCreatedEvent extends DomainEvent {
|
|
type: 'worktree:created';
|
|
payload: {
|
|
worktreeId: string;
|
|
branch: string;
|
|
path: string;
|
|
};
|
|
}
|
|
|
|
export interface WorktreeRemovedEvent extends DomainEvent {
|
|
type: 'worktree:removed';
|
|
payload: {
|
|
worktreeId: string;
|
|
branch: string;
|
|
};
|
|
}
|
|
|
|
export interface WorktreeMergedEvent extends DomainEvent {
|
|
type: 'worktree:merged';
|
|
payload: {
|
|
worktreeId: string;
|
|
sourceBranch: string;
|
|
targetBranch: string;
|
|
};
|
|
}
|
|
|
|
export interface WorktreeConflictEvent extends DomainEvent {
|
|
type: 'worktree:conflict';
|
|
payload: {
|
|
worktreeId: string;
|
|
sourceBranch: string;
|
|
targetBranch: string;
|
|
conflictingFiles: string[];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Agent Events
|
|
*/
|
|
|
|
export interface AgentSpawnedEvent extends DomainEvent {
|
|
type: 'agent:spawned';
|
|
payload: {
|
|
agentId: string;
|
|
name: string;
|
|
taskId: string;
|
|
worktreeId: string;
|
|
};
|
|
}
|
|
|
|
export interface AgentStoppedEvent extends DomainEvent {
|
|
type: 'agent:stopped';
|
|
payload: {
|
|
agentId: string;
|
|
name: string;
|
|
taskId: string;
|
|
reason:
|
|
| 'user_requested'
|
|
| 'task_complete'
|
|
| 'error'
|
|
| 'waiting_for_input'
|
|
| 'context_complete'
|
|
| 'breakdown_complete'
|
|
| 'decompose_complete';
|
|
};
|
|
}
|
|
|
|
export interface AgentCrashedEvent extends DomainEvent {
|
|
type: 'agent:crashed';
|
|
payload: {
|
|
agentId: string;
|
|
name: string;
|
|
taskId: string;
|
|
error: string;
|
|
};
|
|
}
|
|
|
|
export interface AgentResumedEvent extends DomainEvent {
|
|
type: 'agent:resumed';
|
|
payload: {
|
|
agentId: string;
|
|
name: string;
|
|
taskId: string;
|
|
sessionId: string;
|
|
};
|
|
}
|
|
|
|
export interface AgentWaitingEvent extends DomainEvent {
|
|
type: 'agent:waiting';
|
|
payload: {
|
|
agentId: string;
|
|
name: string;
|
|
taskId: string;
|
|
sessionId: string;
|
|
questions: Array<{
|
|
id: string;
|
|
question: string;
|
|
options?: Array<{ label: string; description?: string }>;
|
|
multiSelect?: boolean;
|
|
}>;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Task Dispatch Events
|
|
*/
|
|
|
|
export interface TaskQueuedEvent extends DomainEvent {
|
|
type: 'task:queued';
|
|
payload: {
|
|
taskId: string;
|
|
priority: string;
|
|
dependsOn: string[];
|
|
};
|
|
}
|
|
|
|
export interface TaskDispatchedEvent extends DomainEvent {
|
|
type: 'task:dispatched';
|
|
payload: {
|
|
taskId: string;
|
|
agentId: string;
|
|
agentName: string;
|
|
};
|
|
}
|
|
|
|
export interface TaskCompletedEvent extends DomainEvent {
|
|
type: 'task:completed';
|
|
payload: {
|
|
taskId: string;
|
|
agentId: string;
|
|
success: boolean;
|
|
message: string;
|
|
};
|
|
}
|
|
|
|
export interface TaskBlockedEvent extends DomainEvent {
|
|
type: 'task:blocked';
|
|
payload: {
|
|
taskId: string;
|
|
reason: string;
|
|
blockedBy?: string[];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Phase Events
|
|
*/
|
|
|
|
export interface PhaseQueuedEvent extends DomainEvent {
|
|
type: 'phase:queued';
|
|
payload: {
|
|
phaseId: string;
|
|
initiativeId: string;
|
|
dependsOn: string[];
|
|
};
|
|
}
|
|
|
|
export interface PhaseStartedEvent extends DomainEvent {
|
|
type: 'phase:started';
|
|
payload: {
|
|
phaseId: string;
|
|
initiativeId: string;
|
|
};
|
|
}
|
|
|
|
export interface PhaseCompletedEvent extends DomainEvent {
|
|
type: 'phase:completed';
|
|
payload: {
|
|
phaseId: string;
|
|
initiativeId: string;
|
|
success: boolean;
|
|
message?: string;
|
|
};
|
|
}
|
|
|
|
export interface PhaseBlockedEvent extends DomainEvent {
|
|
type: 'phase:blocked';
|
|
payload: {
|
|
phaseId: string;
|
|
reason: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Merge Coordination Events
|
|
*/
|
|
|
|
export interface MergeQueuedEvent extends DomainEvent {
|
|
type: 'merge:queued';
|
|
payload: {
|
|
taskId: string;
|
|
agentId: string;
|
|
worktreeId: string;
|
|
priority: 'low' | 'medium' | 'high';
|
|
};
|
|
}
|
|
|
|
export interface MergeStartedEvent extends DomainEvent {
|
|
type: 'merge:started';
|
|
payload: {
|
|
taskId: string;
|
|
agentId: string;
|
|
worktreeId: string;
|
|
targetBranch: string;
|
|
};
|
|
}
|
|
|
|
export interface MergeCompletedEvent extends DomainEvent {
|
|
type: 'merge:completed';
|
|
payload: {
|
|
taskId: string;
|
|
agentId: string;
|
|
worktreeId: string;
|
|
targetBranch: string;
|
|
};
|
|
}
|
|
|
|
export interface MergeConflictedEvent extends DomainEvent {
|
|
type: 'merge:conflicted';
|
|
payload: {
|
|
taskId: string;
|
|
agentId: string;
|
|
worktreeId: string;
|
|
targetBranch: string;
|
|
conflictingFiles: string[];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Union of all domain events - enables type-safe event handling
|
|
*/
|
|
export type DomainEventMap =
|
|
| ProcessSpawnedEvent
|
|
| ProcessStoppedEvent
|
|
| ProcessCrashedEvent
|
|
| ServerStartedEvent
|
|
| ServerStoppedEvent
|
|
| LogEntryEvent
|
|
| WorktreeCreatedEvent
|
|
| WorktreeRemovedEvent
|
|
| WorktreeMergedEvent
|
|
| WorktreeConflictEvent
|
|
| AgentSpawnedEvent
|
|
| AgentStoppedEvent
|
|
| AgentCrashedEvent
|
|
| AgentResumedEvent
|
|
| AgentWaitingEvent
|
|
| TaskQueuedEvent
|
|
| TaskDispatchedEvent
|
|
| TaskCompletedEvent
|
|
| TaskBlockedEvent
|
|
| PhaseQueuedEvent
|
|
| PhaseStartedEvent
|
|
| PhaseCompletedEvent
|
|
| PhaseBlockedEvent
|
|
| MergeQueuedEvent
|
|
| MergeStartedEvent
|
|
| MergeCompletedEvent
|
|
| MergeConflictedEvent;
|
|
|
|
/**
|
|
* Event type literal union for type checking
|
|
*/
|
|
export type DomainEventType = DomainEventMap['type'];
|
|
|
|
// =============================================================================
|
|
// Event Bus Port Interface
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Event Bus Port Interface
|
|
*
|
|
* All modules communicate through this interface.
|
|
* Can be swapped for external systems (RabbitMQ, WebSocket forwarding) later.
|
|
*/
|
|
export interface EventBus {
|
|
/**
|
|
* Emit an event to all subscribed handlers
|
|
*/
|
|
emit<T extends DomainEvent>(event: T): void;
|
|
|
|
/**
|
|
* Subscribe to events of a specific type
|
|
*/
|
|
on<T extends DomainEvent>(
|
|
eventType: T['type'],
|
|
handler: (event: T) => void
|
|
): void;
|
|
|
|
/**
|
|
* Unsubscribe from events of a specific type
|
|
*/
|
|
off<T extends DomainEvent>(
|
|
eventType: T['type'],
|
|
handler: (event: T) => void
|
|
): void;
|
|
|
|
/**
|
|
* Subscribe to a single occurrence of an event type
|
|
*/
|
|
once<T extends DomainEvent>(
|
|
eventType: T['type'],
|
|
handler: (event: T) => void
|
|
): void;
|
|
}
|