Files
Codewalkers/docs/dispatch-events.md
Lukas May 0407f05332 refactor: Rename agent modes breakdown→plan, decompose→detail
Full rename across the codebase for clarity:
- breakdown (initiative→phases) is now "plan"
- decompose (phase→tasks) is now "detail"

Updates schema enums, TypeScript types, events, prompts, output handler,
tRPC procedures, CLI commands, frontend components, tests, and docs.
Also fixes 0022 migration multi-statement issue (adds statement-breakpoint markers).
2026-02-10 10:51:42 +01:00

4.2 KiB

Dispatch & Events

src/dispatch/ — Task and phase dispatch queues. src/events/ — Typed event bus.

Event Bus

src/events/ — Typed pub/sub system for inter-module communication.

Architecture

  • Port: EventBus interface with emit(event) and on(type, handler)
  • Adapter: TypedEventBus using Node.js EventEmitter
  • All events implement BaseEvent { type, timestamp, payload }

Event Types (48)

Category Events Count
Agent agent:spawned, agent:stopped, agent:crashed, agent:resumed, agent:account_switched, agent:deleted, agent:waiting, agent:output 8
Task task:queued, task:dispatched, task:completed, task:blocked, task:pending_approval 5
Phase phase:queued, phase:started, phase:completed, phase:blocked 4
Merge merge:queued, merge:started, merge:completed, merge:conflicted 4
Page page:created, page:updated, page:deleted 3
Process process:spawned, process:stopped, process:crashed 3
Server server:started, server:stopped 2
Worktree worktree:created, worktree:removed, worktree:merged, worktree:conflict 4
Account account:credentials_refreshed, account:credentials_expired, account:credentials_validated 3
Log log:entry 1

Key Event Payloads

AgentSpawnedEvent    { agentId, name, taskId, worktreeId, provider }
AgentStoppedEvent    { agentId, name, taskId, reason }
  // reason: 'user_requested'|'task_complete'|'error'|'waiting_for_input'|
  //         'context_complete'|'plan_complete'|'detail_complete'|'refine_complete'
AgentWaitingEvent    { agentId, name, taskId, sessionId, questions[] }
AgentOutputEvent     { agentId, stream, data }
TaskCompletedEvent   { taskId, agentId, success, message }
TaskQueuedEvent      { taskId, priority, dependsOn[] }
PhaseStartedEvent    { phaseId, initiativeId }
MergeConflictedEvent { taskId, agentId, worktreeId, targetBranch, conflictingFiles[] }
AccountCredentialsRefreshedEvent { accountId, expiresAt, previousExpiresAt? }

Task Dispatch

src/dispatch/ — In-memory queue with dependency-ordered dispatch.

Architecture

  • Port: DispatchManager interface
  • Adapter: DefaultDispatchManager

How Task Dispatch Works

  1. Queuequeue(taskId) fetches task dependencies, adds to internal Map
  2. DispatchdispatchNext() finds highest-priority task with all deps complete
  3. Priority order: high > medium > low, then oldest first (FIFO within priority)
  4. Checkpoint skip — Tasks with type starting with checkpoint: skip auto-dispatch
  5. Approval checkcompleteTask() checks requiresApproval (task-level, then initiative-level)
  6. Approval flow — If approval required: status → pending_approval, emit task:pending_approval

DispatchManager Methods

Method Purpose
queue(taskId) Add task to dispatch queue
dispatchNext() Find and dispatch next ready task
getNextDispatchable() Get next task without dispatching
completeTask(taskId, agentId?) Complete with approval check
approveTask(taskId) Approve pending task
blockTask(taskId, reason) Block task with reason
getQueueState() Return queued, ready, blocked tasks

Phase Dispatch

DefaultPhaseDispatchManager — Same pattern for phases:

  1. QueuequeuePhase(phaseId) validates phase is approved, gets dependencies
  2. DispatchdispatchNextPhase() finds phase with all deps complete
  3. Auto-queue tasks — When phase starts, all pending tasks are queued
  4. Eventsphase:queued, phase:started, phase:completed, phase:blocked

PhaseDispatchManager Methods

Method Purpose
queuePhase(phaseId) Queue approved phase
dispatchNextPhase() Start next ready phase, auto-queue its tasks
getNextDispatchablePhase() Get next phase without dispatching
completePhase(phaseId) Mark phase complete
blockPhase(phaseId, reason) Block phase
getPhaseQueueState() Return queued, ready, blocked phases