@claude-flow/swarm 3.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/.agentic-flow/intelligence.json +16 -0
  2. package/MIGRATION.md +472 -0
  3. package/README.md +634 -0
  4. package/__tests__/consensus.test.ts +577 -0
  5. package/__tests__/coordinator.test.ts +501 -0
  6. package/__tests__/queen-coordinator.test.ts +1335 -0
  7. package/__tests__/topology.test.ts +621 -0
  8. package/dist/agent-pool.d.ts +52 -0
  9. package/dist/agent-pool.d.ts.map +1 -0
  10. package/dist/agent-pool.js +365 -0
  11. package/dist/agent-pool.js.map +1 -0
  12. package/dist/application/commands/create-task.command.d.ts +64 -0
  13. package/dist/application/commands/create-task.command.d.ts.map +1 -0
  14. package/dist/application/commands/create-task.command.js +77 -0
  15. package/dist/application/commands/create-task.command.js.map +1 -0
  16. package/dist/application/commands/spawn-agent.command.d.ts +63 -0
  17. package/dist/application/commands/spawn-agent.command.d.ts.map +1 -0
  18. package/dist/application/commands/spawn-agent.command.js +74 -0
  19. package/dist/application/commands/spawn-agent.command.js.map +1 -0
  20. package/dist/application/index.d.ts +9 -0
  21. package/dist/application/index.d.ts.map +1 -0
  22. package/dist/application/index.js +11 -0
  23. package/dist/application/index.js.map +1 -0
  24. package/dist/application/services/swarm-application-service.d.ts +112 -0
  25. package/dist/application/services/swarm-application-service.d.ts.map +1 -0
  26. package/dist/application/services/swarm-application-service.js +153 -0
  27. package/dist/application/services/swarm-application-service.js.map +1 -0
  28. package/dist/attention-coordinator.d.ts +212 -0
  29. package/dist/attention-coordinator.d.ts.map +1 -0
  30. package/dist/attention-coordinator.js +667 -0
  31. package/dist/attention-coordinator.js.map +1 -0
  32. package/dist/consensus/byzantine.d.ts +63 -0
  33. package/dist/consensus/byzantine.d.ts.map +1 -0
  34. package/dist/consensus/byzantine.js +316 -0
  35. package/dist/consensus/byzantine.js.map +1 -0
  36. package/dist/consensus/gossip.d.ts +69 -0
  37. package/dist/consensus/gossip.d.ts.map +1 -0
  38. package/dist/consensus/gossip.js +378 -0
  39. package/dist/consensus/gossip.js.map +1 -0
  40. package/dist/consensus/index.d.ts +49 -0
  41. package/dist/consensus/index.d.ts.map +1 -0
  42. package/dist/consensus/index.js +203 -0
  43. package/dist/consensus/index.js.map +1 -0
  44. package/dist/consensus/raft.d.ts +62 -0
  45. package/dist/consensus/raft.d.ts.map +1 -0
  46. package/dist/consensus/raft.js +324 -0
  47. package/dist/consensus/raft.js.map +1 -0
  48. package/dist/coordination/agent-registry.d.ts +68 -0
  49. package/dist/coordination/agent-registry.d.ts.map +1 -0
  50. package/dist/coordination/agent-registry.js +412 -0
  51. package/dist/coordination/agent-registry.js.map +1 -0
  52. package/dist/coordination/index.d.ts +8 -0
  53. package/dist/coordination/index.d.ts.map +1 -0
  54. package/dist/coordination/index.js +8 -0
  55. package/dist/coordination/index.js.map +1 -0
  56. package/dist/coordination/swarm-hub.d.ts +150 -0
  57. package/dist/coordination/swarm-hub.d.ts.map +1 -0
  58. package/dist/coordination/swarm-hub.js +617 -0
  59. package/dist/coordination/swarm-hub.js.map +1 -0
  60. package/dist/coordination/task-orchestrator.d.ts +96 -0
  61. package/dist/coordination/task-orchestrator.d.ts.map +1 -0
  62. package/dist/coordination/task-orchestrator.js +412 -0
  63. package/dist/coordination/task-orchestrator.js.map +1 -0
  64. package/dist/domain/entities/agent.d.ts +151 -0
  65. package/dist/domain/entities/agent.d.ts.map +1 -0
  66. package/dist/domain/entities/agent.js +280 -0
  67. package/dist/domain/entities/agent.js.map +1 -0
  68. package/dist/domain/entities/task.d.ts +133 -0
  69. package/dist/domain/entities/task.d.ts.map +1 -0
  70. package/dist/domain/entities/task.js +261 -0
  71. package/dist/domain/entities/task.js.map +1 -0
  72. package/dist/domain/index.d.ts +11 -0
  73. package/dist/domain/index.d.ts.map +1 -0
  74. package/dist/domain/index.js +11 -0
  75. package/dist/domain/index.js.map +1 -0
  76. package/dist/domain/repositories/agent-repository.interface.d.ts +57 -0
  77. package/dist/domain/repositories/agent-repository.interface.d.ts.map +1 -0
  78. package/dist/domain/repositories/agent-repository.interface.js +9 -0
  79. package/dist/domain/repositories/agent-repository.interface.js.map +1 -0
  80. package/dist/domain/repositories/task-repository.interface.d.ts +61 -0
  81. package/dist/domain/repositories/task-repository.interface.d.ts.map +1 -0
  82. package/dist/domain/repositories/task-repository.interface.js +9 -0
  83. package/dist/domain/repositories/task-repository.interface.js.map +1 -0
  84. package/dist/domain/services/coordination-service.d.ts +84 -0
  85. package/dist/domain/services/coordination-service.d.ts.map +1 -0
  86. package/dist/domain/services/coordination-service.js +231 -0
  87. package/dist/domain/services/coordination-service.js.map +1 -0
  88. package/dist/federation-hub.d.ts +284 -0
  89. package/dist/federation-hub.d.ts.map +1 -0
  90. package/dist/federation-hub.js +692 -0
  91. package/dist/federation-hub.js.map +1 -0
  92. package/dist/index.d.ts +107 -0
  93. package/dist/index.d.ts.map +1 -0
  94. package/dist/index.js +142 -0
  95. package/dist/index.js.map +1 -0
  96. package/dist/message-bus.d.ts +48 -0
  97. package/dist/message-bus.d.ts.map +1 -0
  98. package/dist/message-bus.js +499 -0
  99. package/dist/message-bus.js.map +1 -0
  100. package/dist/queen-coordinator.d.ts +576 -0
  101. package/dist/queen-coordinator.d.ts.map +1 -0
  102. package/dist/queen-coordinator.js +1307 -0
  103. package/dist/queen-coordinator.js.map +1 -0
  104. package/dist/shared/events.d.ts +63 -0
  105. package/dist/shared/events.d.ts.map +1 -0
  106. package/dist/shared/events.js +203 -0
  107. package/dist/shared/events.js.map +1 -0
  108. package/dist/shared/types.d.ts +212 -0
  109. package/dist/shared/types.d.ts.map +1 -0
  110. package/dist/shared/types.js +22 -0
  111. package/dist/shared/types.js.map +1 -0
  112. package/dist/topology-manager.d.ts +62 -0
  113. package/dist/topology-manager.d.ts.map +1 -0
  114. package/dist/topology-manager.js +538 -0
  115. package/dist/topology-manager.js.map +1 -0
  116. package/dist/types.d.ts +353 -0
  117. package/dist/types.d.ts.map +1 -0
  118. package/dist/types.js +43 -0
  119. package/dist/types.js.map +1 -0
  120. package/dist/unified-coordinator.d.ts +260 -0
  121. package/dist/unified-coordinator.d.ts.map +1 -0
  122. package/dist/unified-coordinator.js +1460 -0
  123. package/dist/unified-coordinator.js.map +1 -0
  124. package/dist/workers/index.d.ts +29 -0
  125. package/dist/workers/index.d.ts.map +1 -0
  126. package/dist/workers/index.js +49 -0
  127. package/dist/workers/index.js.map +1 -0
  128. package/dist/workers/worker-dispatch.d.ts +234 -0
  129. package/dist/workers/worker-dispatch.d.ts.map +1 -0
  130. package/dist/workers/worker-dispatch.js +842 -0
  131. package/dist/workers/worker-dispatch.js.map +1 -0
  132. package/package.json +33 -0
  133. package/src/agent-pool.ts +476 -0
  134. package/src/application/commands/create-task.command.ts +124 -0
  135. package/src/application/commands/spawn-agent.command.ts +122 -0
  136. package/src/application/index.ts +30 -0
  137. package/src/application/services/swarm-application-service.ts +200 -0
  138. package/src/attention-coordinator.ts +1000 -0
  139. package/src/consensus/byzantine.ts +431 -0
  140. package/src/consensus/gossip.ts +513 -0
  141. package/src/consensus/index.ts +267 -0
  142. package/src/consensus/raft.ts +443 -0
  143. package/src/coordination/agent-registry.ts +544 -0
  144. package/src/coordination/index.ts +23 -0
  145. package/src/coordination/swarm-hub.ts +776 -0
  146. package/src/coordination/task-orchestrator.ts +605 -0
  147. package/src/domain/entities/agent.d.ts +151 -0
  148. package/src/domain/entities/agent.d.ts.map +1 -0
  149. package/src/domain/entities/agent.js +280 -0
  150. package/src/domain/entities/agent.js.map +1 -0
  151. package/src/domain/entities/agent.ts +370 -0
  152. package/src/domain/entities/task.d.ts +133 -0
  153. package/src/domain/entities/task.d.ts.map +1 -0
  154. package/src/domain/entities/task.js +261 -0
  155. package/src/domain/entities/task.js.map +1 -0
  156. package/src/domain/entities/task.ts +319 -0
  157. package/src/domain/index.ts +41 -0
  158. package/src/domain/repositories/agent-repository.interface.d.ts +57 -0
  159. package/src/domain/repositories/agent-repository.interface.d.ts.map +1 -0
  160. package/src/domain/repositories/agent-repository.interface.js +9 -0
  161. package/src/domain/repositories/agent-repository.interface.js.map +1 -0
  162. package/src/domain/repositories/agent-repository.interface.ts +69 -0
  163. package/src/domain/repositories/task-repository.interface.d.ts +61 -0
  164. package/src/domain/repositories/task-repository.interface.d.ts.map +1 -0
  165. package/src/domain/repositories/task-repository.interface.js +9 -0
  166. package/src/domain/repositories/task-repository.interface.js.map +1 -0
  167. package/src/domain/repositories/task-repository.interface.ts +75 -0
  168. package/src/domain/services/coordination-service.ts +320 -0
  169. package/src/federation-hub.d.ts +284 -0
  170. package/src/federation-hub.d.ts.map +1 -0
  171. package/src/federation-hub.js +692 -0
  172. package/src/federation-hub.js.map +1 -0
  173. package/src/federation-hub.ts +979 -0
  174. package/src/index.ts +348 -0
  175. package/src/message-bus.ts +607 -0
  176. package/src/queen-coordinator.ts +2024 -0
  177. package/src/shared/events.ts +285 -0
  178. package/src/shared/types.ts +389 -0
  179. package/src/topology-manager.ts +656 -0
  180. package/src/types.ts +545 -0
  181. package/src/unified-coordinator.ts +1844 -0
  182. package/src/workers/index.ts +65 -0
  183. package/src/workers/worker-dispatch.d.ts +234 -0
  184. package/src/workers/worker-dispatch.d.ts.map +1 -0
  185. package/src/workers/worker-dispatch.js +842 -0
  186. package/src/workers/worker-dispatch.js.map +1 -0
  187. package/src/workers/worker-dispatch.ts +1072 -0
  188. package/tsconfig.json +9 -0
  189. package/tsconfig.tsbuildinfo +1 -0
  190. package/vitest.config.ts +20 -0
@@ -0,0 +1,605 @@
1
+ /**
2
+ * V3 Task Orchestrator
3
+ * Manages task decomposition, dependency resolution, and parallel execution
4
+ *
5
+ * Based on ADR-003 (Single Coordination Engine) and ADR-001 (agentic-flow integration)
6
+ */
7
+
8
+ import {
9
+ TaskId,
10
+ TaskType,
11
+ TaskStatus,
12
+ TaskPriority,
13
+ TaskDefinition,
14
+ TaskMetadata,
15
+ TaskResult,
16
+ TaskResultMetrics,
17
+ AgentId,
18
+ AgentDomain,
19
+ PhaseId,
20
+ SwarmEvent
21
+ } from '../shared/types';
22
+ import {
23
+ IEventBus,
24
+ taskCreatedEvent,
25
+ taskQueuedEvent,
26
+ taskAssignedEvent,
27
+ taskStartedEvent,
28
+ taskCompletedEvent,
29
+ taskFailedEvent,
30
+ taskBlockedEvent
31
+ } from '../shared/events';
32
+ import { IAgentRegistry } from './agent-registry';
33
+
34
+ // =============================================================================
35
+ // Task Orchestrator Interface
36
+ // =============================================================================
37
+
38
+ export interface ITaskOrchestrator {
39
+ // Task Creation
40
+ createTask(spec: TaskSpec): TaskDefinition;
41
+ createBatchTasks(specs: TaskSpec[]): TaskDefinition[];
42
+
43
+ // Task Lifecycle
44
+ queueTask(taskId: TaskId): void;
45
+ assignTask(taskId: TaskId, agentId: AgentId): void;
46
+ startTask(taskId: TaskId): void;
47
+ completeTask(taskId: TaskId, result: TaskResult): void;
48
+ failTask(taskId: TaskId, error: Error): void;
49
+ cancelTask(taskId: TaskId): void;
50
+
51
+ // Dependency Management
52
+ addDependency(taskId: TaskId, dependsOn: TaskId): void;
53
+ removeDependency(taskId: TaskId, dependsOn: TaskId): void;
54
+ getDependencies(taskId: TaskId): TaskId[];
55
+ getDependents(taskId: TaskId): TaskId[];
56
+ isBlocked(taskId: TaskId): boolean;
57
+ getBlockingTasks(taskId: TaskId): TaskId[];
58
+
59
+ // Queries
60
+ getTask(taskId: TaskId): TaskDefinition | undefined;
61
+ getAllTasks(): TaskDefinition[];
62
+ getTasksByStatus(status: TaskStatus): TaskDefinition[];
63
+ getTasksByAgent(agentId: AgentId): TaskDefinition[];
64
+ getTasksByDomain(domain: AgentDomain): TaskDefinition[];
65
+ getTasksByPhase(phase: PhaseId): TaskDefinition[];
66
+
67
+ // Queue Management
68
+ getNextTask(agentId?: AgentId): TaskDefinition | undefined;
69
+ getPriorityQueue(): TaskDefinition[];
70
+
71
+ // Metrics
72
+ getTaskMetrics(): TaskOrchestratorMetrics;
73
+ }
74
+
75
+ export interface TaskSpec {
76
+ type: TaskType;
77
+ title: string;
78
+ description: string;
79
+ priority?: TaskPriority;
80
+ dependencies?: TaskId[];
81
+ domain: AgentDomain;
82
+ phase: PhaseId;
83
+ estimatedDuration?: number;
84
+ tags?: string[];
85
+ }
86
+
87
+ export interface TaskOrchestratorMetrics {
88
+ totalTasks: number;
89
+ tasksByStatus: Record<TaskStatus, number>;
90
+ tasksByPriority: Record<TaskPriority, number>;
91
+ tasksByDomain: Record<AgentDomain, number>;
92
+ averageQueueTime: number;
93
+ averageExecutionTime: number;
94
+ throughput: number;
95
+ }
96
+
97
+ // =============================================================================
98
+ // Task Orchestrator Implementation
99
+ // =============================================================================
100
+
101
+ export class TaskOrchestrator implements ITaskOrchestrator {
102
+ private tasks: Map<TaskId, TaskDefinition> = new Map();
103
+ private dependencyGraph: Map<TaskId, Set<TaskId>> = new Map();
104
+ private dependentGraph: Map<TaskId, Set<TaskId>> = new Map();
105
+ private taskCounter: number = 0;
106
+ private eventBus: IEventBus;
107
+ private agentRegistry: IAgentRegistry;
108
+
109
+ constructor(eventBus: IEventBus, agentRegistry: IAgentRegistry) {
110
+ this.eventBus = eventBus;
111
+ this.agentRegistry = agentRegistry;
112
+
113
+ this.eventBus.subscribe('agent:task-completed', this.handleAgentTaskCompleted.bind(this));
114
+ }
115
+
116
+ // ==========================================================================
117
+ // Task Creation
118
+ // ==========================================================================
119
+
120
+ createTask(spec: TaskSpec): TaskDefinition {
121
+ const taskId: TaskId = `task-${Date.now()}-${++this.taskCounter}`;
122
+
123
+ const task: TaskDefinition = {
124
+ id: taskId,
125
+ type: spec.type,
126
+ title: spec.title,
127
+ description: spec.description,
128
+ assignedAgent: null,
129
+ status: 'pending',
130
+ priority: spec.priority ?? 'medium',
131
+ dependencies: spec.dependencies ?? [],
132
+ blockedBy: [],
133
+ metadata: {
134
+ domain: spec.domain,
135
+ phase: spec.phase,
136
+ estimatedDuration: spec.estimatedDuration ?? 0,
137
+ actualDuration: null,
138
+ retryCount: 0,
139
+ maxRetries: 3,
140
+ artifacts: [],
141
+ tags: spec.tags ?? []
142
+ },
143
+ createdAt: Date.now(),
144
+ updatedAt: Date.now(),
145
+ completedAt: null
146
+ };
147
+
148
+ this.tasks.set(taskId, task);
149
+ this.dependencyGraph.set(taskId, new Set(task.dependencies));
150
+ this.dependentGraph.set(taskId, new Set());
151
+
152
+ for (const depId of task.dependencies) {
153
+ if (this.dependentGraph.has(depId)) {
154
+ this.dependentGraph.get(depId)!.add(taskId);
155
+ }
156
+ }
157
+
158
+ this.updateBlockedStatus(taskId);
159
+
160
+ this.eventBus.emitSync(taskCreatedEvent(taskId, { type: spec.type, title: spec.title }));
161
+
162
+ return task;
163
+ }
164
+
165
+ createBatchTasks(specs: TaskSpec[]): TaskDefinition[] {
166
+ return specs.map(spec => this.createTask(spec));
167
+ }
168
+
169
+ // ==========================================================================
170
+ // Task Lifecycle
171
+ // ==========================================================================
172
+
173
+ queueTask(taskId: TaskId): void {
174
+ const task = this.getTaskOrThrow(taskId);
175
+
176
+ if (this.isBlocked(taskId)) {
177
+ this.updateTaskStatus(taskId, 'blocked');
178
+ return;
179
+ }
180
+
181
+ this.updateTaskStatus(taskId, 'queued');
182
+ this.eventBus.emitSync(taskQueuedEvent(taskId, this.getQueuePosition(taskId)));
183
+ }
184
+
185
+ assignTask(taskId: TaskId, agentId: AgentId): void {
186
+ const task = this.getTaskOrThrow(taskId);
187
+
188
+ if (task.status !== 'queued') {
189
+ throw new Error(`Task ${taskId} is not queued (status: ${task.status})`);
190
+ }
191
+
192
+ if (this.isBlocked(taskId)) {
193
+ throw new Error(`Task ${taskId} is blocked by dependencies`);
194
+ }
195
+
196
+ task.assignedAgent = agentId;
197
+ this.updateTaskStatus(taskId, 'assigned');
198
+
199
+ this.agentRegistry.assignTask(agentId, taskId);
200
+
201
+ this.eventBus.emitSync(taskAssignedEvent(taskId, agentId));
202
+ }
203
+
204
+ startTask(taskId: TaskId): void {
205
+ const task = this.getTaskOrThrow(taskId);
206
+
207
+ if (task.status !== 'assigned') {
208
+ throw new Error(`Task ${taskId} is not assigned (status: ${task.status})`);
209
+ }
210
+
211
+ this.updateTaskStatus(taskId, 'in-progress');
212
+
213
+ if (task.assignedAgent) {
214
+ this.eventBus.emitSync(taskStartedEvent(taskId, task.assignedAgent));
215
+ }
216
+ }
217
+
218
+ completeTask(taskId: TaskId, result: TaskResult): void {
219
+ const task = this.getTaskOrThrow(taskId);
220
+
221
+ if (task.status !== 'in-progress') {
222
+ throw new Error(`Task ${taskId} is not in progress (status: ${task.status})`);
223
+ }
224
+
225
+ task.metadata.actualDuration = result.duration;
226
+ task.completedAt = Date.now();
227
+
228
+ this.updateTaskStatus(taskId, 'completed');
229
+
230
+ if (task.assignedAgent) {
231
+ this.agentRegistry.completeTask(task.assignedAgent, taskId);
232
+ }
233
+
234
+ this.eventBus.emitSync(taskCompletedEvent(taskId, result));
235
+
236
+ this.unblockDependentTasks(taskId);
237
+ }
238
+
239
+ failTask(taskId: TaskId, error: Error): void {
240
+ const task = this.getTaskOrThrow(taskId);
241
+
242
+ task.metadata.retryCount++;
243
+
244
+ if (task.metadata.retryCount < task.metadata.maxRetries) {
245
+ this.updateTaskStatus(taskId, 'queued');
246
+ task.assignedAgent = null;
247
+ } else {
248
+ this.updateTaskStatus(taskId, 'failed');
249
+
250
+ if (task.assignedAgent) {
251
+ const agentState = this.agentRegistry.getState(task.assignedAgent);
252
+ if (agentState) {
253
+ agentState.metrics.tasksFailed++;
254
+ }
255
+ }
256
+ }
257
+
258
+ this.eventBus.emitSync(taskFailedEvent(taskId, error));
259
+ }
260
+
261
+ cancelTask(taskId: TaskId): void {
262
+ const task = this.getTaskOrThrow(taskId);
263
+
264
+ if (task.status === 'completed' || task.status === 'failed') {
265
+ throw new Error(`Cannot cancel ${task.status} task ${taskId}`);
266
+ }
267
+
268
+ if (task.assignedAgent) {
269
+ this.agentRegistry.updateStatus(task.assignedAgent, 'idle');
270
+ }
271
+
272
+ this.updateTaskStatus(taskId, 'cancelled');
273
+ }
274
+
275
+ // ==========================================================================
276
+ // Dependency Management
277
+ // ==========================================================================
278
+
279
+ addDependency(taskId: TaskId, dependsOn: TaskId): void {
280
+ const task = this.getTaskOrThrow(taskId);
281
+ this.getTaskOrThrow(dependsOn);
282
+
283
+ if (this.wouldCreateCycle(taskId, dependsOn)) {
284
+ throw new Error(`Adding dependency ${dependsOn} to ${taskId} would create a cycle`);
285
+ }
286
+
287
+ task.dependencies.push(dependsOn);
288
+ this.dependencyGraph.get(taskId)!.add(dependsOn);
289
+ this.dependentGraph.get(dependsOn)!.add(taskId);
290
+
291
+ this.updateBlockedStatus(taskId);
292
+ }
293
+
294
+ removeDependency(taskId: TaskId, dependsOn: TaskId): void {
295
+ const task = this.getTaskOrThrow(taskId);
296
+
297
+ const index = task.dependencies.indexOf(dependsOn);
298
+ if (index > -1) {
299
+ task.dependencies.splice(index, 1);
300
+ }
301
+
302
+ this.dependencyGraph.get(taskId)?.delete(dependsOn);
303
+ this.dependentGraph.get(dependsOn)?.delete(taskId);
304
+
305
+ this.updateBlockedStatus(taskId);
306
+ }
307
+
308
+ getDependencies(taskId: TaskId): TaskId[] {
309
+ return Array.from(this.dependencyGraph.get(taskId) ?? []);
310
+ }
311
+
312
+ getDependents(taskId: TaskId): TaskId[] {
313
+ return Array.from(this.dependentGraph.get(taskId) ?? []);
314
+ }
315
+
316
+ isBlocked(taskId: TaskId): boolean {
317
+ const blockingTasks = this.getBlockingTasks(taskId);
318
+ return blockingTasks.length > 0;
319
+ }
320
+
321
+ getBlockingTasks(taskId: TaskId): TaskId[] {
322
+ const dependencies = this.dependencyGraph.get(taskId);
323
+ if (!dependencies) {
324
+ return [];
325
+ }
326
+
327
+ return Array.from(dependencies).filter(depId => {
328
+ const depTask = this.tasks.get(depId);
329
+ return depTask && depTask.status !== 'completed';
330
+ });
331
+ }
332
+
333
+ // ==========================================================================
334
+ // Queries
335
+ // ==========================================================================
336
+
337
+ getTask(taskId: TaskId): TaskDefinition | undefined {
338
+ return this.tasks.get(taskId);
339
+ }
340
+
341
+ getAllTasks(): TaskDefinition[] {
342
+ return Array.from(this.tasks.values());
343
+ }
344
+
345
+ getTasksByStatus(status: TaskStatus): TaskDefinition[] {
346
+ return this.getAllTasks().filter(t => t.status === status);
347
+ }
348
+
349
+ getTasksByAgent(agentId: AgentId): TaskDefinition[] {
350
+ return this.getAllTasks().filter(t => t.assignedAgent === agentId);
351
+ }
352
+
353
+ getTasksByDomain(domain: AgentDomain): TaskDefinition[] {
354
+ return this.getAllTasks().filter(t => t.metadata.domain === domain);
355
+ }
356
+
357
+ getTasksByPhase(phase: PhaseId): TaskDefinition[] {
358
+ return this.getAllTasks().filter(t => t.metadata.phase === phase);
359
+ }
360
+
361
+ // ==========================================================================
362
+ // Queue Management
363
+ // ==========================================================================
364
+
365
+ getNextTask(agentId?: AgentId): TaskDefinition | undefined {
366
+ const queuedTasks = this.getTasksByStatus('queued')
367
+ .filter(t => !this.isBlocked(t.id))
368
+ .sort((a, b) => {
369
+ const priorityOrder: Record<TaskPriority, number> = {
370
+ 'critical': 0,
371
+ 'high': 1,
372
+ 'medium': 2,
373
+ 'low': 3
374
+ };
375
+
376
+ const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
377
+ if (priorityDiff !== 0) return priorityDiff;
378
+
379
+ return a.createdAt - b.createdAt;
380
+ });
381
+
382
+ if (!agentId) {
383
+ return queuedTasks[0];
384
+ }
385
+
386
+ const agentDef = this.agentRegistry.getDefinition(agentId);
387
+ if (!agentDef) {
388
+ return queuedTasks[0];
389
+ }
390
+
391
+ const supportedTypes = agentDef.capabilities.flatMap(c => c.supportedTaskTypes);
392
+
393
+ return queuedTasks.find(t => supportedTypes.includes(t.type));
394
+ }
395
+
396
+ getPriorityQueue(): TaskDefinition[] {
397
+ return this.getTasksByStatus('queued')
398
+ .filter(t => !this.isBlocked(t.id))
399
+ .sort((a, b) => {
400
+ const priorityOrder: Record<TaskPriority, number> = {
401
+ 'critical': 0,
402
+ 'high': 1,
403
+ 'medium': 2,
404
+ 'low': 3
405
+ };
406
+ return priorityOrder[a.priority] - priorityOrder[b.priority];
407
+ });
408
+ }
409
+
410
+ // ==========================================================================
411
+ // Metrics
412
+ // ==========================================================================
413
+
414
+ getTaskMetrics(): TaskOrchestratorMetrics {
415
+ const allTasks = this.getAllTasks();
416
+
417
+ const tasksByStatus: Record<TaskStatus, number> = {
418
+ 'pending': 0,
419
+ 'queued': 0,
420
+ 'assigned': 0,
421
+ 'in-progress': 0,
422
+ 'blocked': 0,
423
+ 'completed': 0,
424
+ 'failed': 0,
425
+ 'cancelled': 0
426
+ };
427
+
428
+ const tasksByPriority: Record<TaskPriority, number> = {
429
+ 'critical': 0,
430
+ 'high': 0,
431
+ 'medium': 0,
432
+ 'low': 0
433
+ };
434
+
435
+ const tasksByDomain: Record<AgentDomain, number> = {
436
+ 'security': 0,
437
+ 'core': 0,
438
+ 'integration': 0,
439
+ 'quality': 0,
440
+ 'performance': 0,
441
+ 'deployment': 0
442
+ };
443
+
444
+ let totalQueueTime = 0;
445
+ let totalExecutionTime = 0;
446
+ let completedCount = 0;
447
+
448
+ for (const task of allTasks) {
449
+ tasksByStatus[task.status]++;
450
+ tasksByPriority[task.priority]++;
451
+ tasksByDomain[task.metadata.domain]++;
452
+
453
+ if (task.status === 'completed' && task.metadata.actualDuration) {
454
+ totalExecutionTime += task.metadata.actualDuration;
455
+ completedCount++;
456
+ }
457
+ }
458
+
459
+ const now = Date.now();
460
+ const firstTask = allTasks[0];
461
+ const runtimeMs = firstTask ? now - firstTask.createdAt : 1;
462
+ const throughput = completedCount / (runtimeMs / 1000 / 60);
463
+
464
+ return {
465
+ totalTasks: allTasks.length,
466
+ tasksByStatus,
467
+ tasksByPriority,
468
+ tasksByDomain,
469
+ averageQueueTime: totalQueueTime / (completedCount || 1),
470
+ averageExecutionTime: totalExecutionTime / (completedCount || 1),
471
+ throughput
472
+ };
473
+ }
474
+
475
+ // ==========================================================================
476
+ // Private Helpers
477
+ // ==========================================================================
478
+
479
+ private getTaskOrThrow(taskId: TaskId): TaskDefinition {
480
+ const task = this.tasks.get(taskId);
481
+ if (!task) {
482
+ throw new Error(`Task ${taskId} not found`);
483
+ }
484
+ return task;
485
+ }
486
+
487
+ private updateTaskStatus(taskId: TaskId, status: TaskStatus): void {
488
+ const task = this.getTaskOrThrow(taskId);
489
+ task.status = status;
490
+ task.updatedAt = Date.now();
491
+
492
+ if (status === 'blocked') {
493
+ task.blockedBy = this.getBlockingTasks(taskId);
494
+ } else {
495
+ task.blockedBy = [];
496
+ }
497
+ }
498
+
499
+ private updateBlockedStatus(taskId: TaskId): void {
500
+ const task = this.tasks.get(taskId);
501
+ if (!task || task.status === 'completed' || task.status === 'failed') {
502
+ return;
503
+ }
504
+
505
+ const isBlocked = this.isBlocked(taskId);
506
+
507
+ if (isBlocked && task.status !== 'blocked') {
508
+ this.updateTaskStatus(taskId, 'blocked');
509
+ const blockingTasks = this.getBlockingTasks(taskId);
510
+ this.eventBus.emitSync(taskBlockedEvent(taskId, 'Blocked by dependencies', blockingTasks[0]));
511
+ } else if (!isBlocked && task.status === 'blocked') {
512
+ this.updateTaskStatus(taskId, 'queued');
513
+ }
514
+ }
515
+
516
+ private unblockDependentTasks(taskId: TaskId): void {
517
+ const dependents = this.getDependents(taskId);
518
+
519
+ for (const dependentId of dependents) {
520
+ this.updateBlockedStatus(dependentId);
521
+ }
522
+ }
523
+
524
+ private wouldCreateCycle(taskId: TaskId, newDependency: TaskId): boolean {
525
+ const visited = new Set<TaskId>();
526
+ const stack = [newDependency];
527
+
528
+ while (stack.length > 0) {
529
+ const current = stack.pop()!;
530
+
531
+ if (current === taskId) {
532
+ return true;
533
+ }
534
+
535
+ if (visited.has(current)) {
536
+ continue;
537
+ }
538
+
539
+ visited.add(current);
540
+
541
+ const deps = this.dependencyGraph.get(current);
542
+ if (deps) {
543
+ stack.push(...deps);
544
+ }
545
+ }
546
+
547
+ return false;
548
+ }
549
+
550
+ private handleAgentTaskCompleted(event: SwarmEvent): void {
551
+ const payload = event.payload as { taskId: TaskId; result: unknown };
552
+
553
+ if (payload.taskId && this.tasks.has(payload.taskId)) {
554
+ const task = this.tasks.get(payload.taskId)!;
555
+ if (task.status === 'in-progress') {
556
+ this.completeTask(payload.taskId, {
557
+ taskId: payload.taskId,
558
+ success: true,
559
+ output: payload.result,
560
+ error: null,
561
+ duration: Date.now() - task.updatedAt,
562
+ metrics: this.createDefaultMetrics()
563
+ });
564
+ }
565
+ }
566
+ }
567
+
568
+ private createDefaultMetrics(): TaskResultMetrics {
569
+ return {
570
+ linesOfCode: 0,
571
+ testsWritten: 0,
572
+ testsPassed: 0,
573
+ coveragePercent: 0,
574
+ performanceImpact: 0
575
+ };
576
+ }
577
+
578
+ private getQueuePosition(taskId: TaskId): number {
579
+ const priorityOrder: Record<string, number> = {
580
+ critical: 5,
581
+ high: 4,
582
+ normal: 3,
583
+ low: 2,
584
+ background: 1,
585
+ };
586
+
587
+ const queuedTasks = Array.from(this.tasks.values())
588
+ .filter(t => t.status === 'queued')
589
+ .sort((a, b) => (priorityOrder[b.priority] || 0) - (priorityOrder[a.priority] || 0));
590
+
591
+ const position = queuedTasks.findIndex(t => t.id === taskId);
592
+ return position >= 0 ? position + 1 : queuedTasks.length + 1;
593
+ }
594
+ }
595
+
596
+ // =============================================================================
597
+ // Factory Function
598
+ // =============================================================================
599
+
600
+ export function createTaskOrchestrator(
601
+ eventBus: IEventBus,
602
+ agentRegistry: IAgentRegistry
603
+ ): ITaskOrchestrator {
604
+ return new TaskOrchestrator(eventBus, agentRegistry);
605
+ }