@sparkleideas/swarm 3.0.0-alpha.7

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 (65) hide show
  1. package/MIGRATION.md +472 -0
  2. package/README.md +634 -0
  3. package/__tests__/consensus.test.ts +577 -0
  4. package/__tests__/coordinator.test.ts +501 -0
  5. package/__tests__/queen-coordinator.test.ts +1335 -0
  6. package/__tests__/topology.test.ts +621 -0
  7. package/package.json +32 -0
  8. package/src/agent-pool.ts +476 -0
  9. package/src/application/commands/create-task.command.ts +124 -0
  10. package/src/application/commands/spawn-agent.command.ts +122 -0
  11. package/src/application/index.ts +30 -0
  12. package/src/application/services/swarm-application-service.ts +200 -0
  13. package/src/attention-coordinator.ts +1000 -0
  14. package/src/consensus/byzantine.ts +431 -0
  15. package/src/consensus/gossip.ts +513 -0
  16. package/src/consensus/index.ts +267 -0
  17. package/src/consensus/raft.ts +443 -0
  18. package/src/coordination/agent-registry.ts +544 -0
  19. package/src/coordination/index.ts +23 -0
  20. package/src/coordination/swarm-hub.ts +776 -0
  21. package/src/coordination/task-orchestrator.ts +605 -0
  22. package/src/domain/entities/agent.d.ts +151 -0
  23. package/src/domain/entities/agent.d.ts.map +1 -0
  24. package/src/domain/entities/agent.js +280 -0
  25. package/src/domain/entities/agent.js.map +1 -0
  26. package/src/domain/entities/agent.ts +370 -0
  27. package/src/domain/entities/task.d.ts +133 -0
  28. package/src/domain/entities/task.d.ts.map +1 -0
  29. package/src/domain/entities/task.js +261 -0
  30. package/src/domain/entities/task.js.map +1 -0
  31. package/src/domain/entities/task.ts +319 -0
  32. package/src/domain/index.ts +41 -0
  33. package/src/domain/repositories/agent-repository.interface.d.ts +57 -0
  34. package/src/domain/repositories/agent-repository.interface.d.ts.map +1 -0
  35. package/src/domain/repositories/agent-repository.interface.js +9 -0
  36. package/src/domain/repositories/agent-repository.interface.js.map +1 -0
  37. package/src/domain/repositories/agent-repository.interface.ts +69 -0
  38. package/src/domain/repositories/task-repository.interface.d.ts +61 -0
  39. package/src/domain/repositories/task-repository.interface.d.ts.map +1 -0
  40. package/src/domain/repositories/task-repository.interface.js +9 -0
  41. package/src/domain/repositories/task-repository.interface.js.map +1 -0
  42. package/src/domain/repositories/task-repository.interface.ts +75 -0
  43. package/src/domain/services/coordination-service.ts +320 -0
  44. package/src/federation-hub.d.ts +284 -0
  45. package/src/federation-hub.d.ts.map +1 -0
  46. package/src/federation-hub.js +692 -0
  47. package/src/federation-hub.js.map +1 -0
  48. package/src/federation-hub.ts +979 -0
  49. package/src/index.ts +348 -0
  50. package/src/message-bus.ts +607 -0
  51. package/src/queen-coordinator.ts +2025 -0
  52. package/src/shared/events.ts +285 -0
  53. package/src/shared/types.ts +389 -0
  54. package/src/topology-manager.ts +656 -0
  55. package/src/types.ts +545 -0
  56. package/src/unified-coordinator.ts +1844 -0
  57. package/src/workers/index.ts +65 -0
  58. package/src/workers/worker-dispatch.d.ts +234 -0
  59. package/src/workers/worker-dispatch.d.ts.map +1 -0
  60. package/src/workers/worker-dispatch.js +842 -0
  61. package/src/workers/worker-dispatch.js.map +1 -0
  62. package/src/workers/worker-dispatch.ts +1076 -0
  63. package/tmp.json +0 -0
  64. package/tsconfig.json +9 -0
  65. package/vitest.config.ts +20 -0
@@ -0,0 +1,1844 @@
1
+ /**
2
+ * V3 Unified Swarm Coordinator
3
+ * Consolidates SwarmCoordinator, HiveMind, Maestro, and AgentManager into a single system
4
+ * Supports the 15-agent hierarchical mesh structure with domain-based task routing
5
+ *
6
+ * Performance Targets:
7
+ * - Agent coordination: <100ms for 15 agents
8
+ * - Consensus: <100ms
9
+ * - Message throughput: 1000+ msgs/sec
10
+ *
11
+ * Agent Hierarchy:
12
+ * - Queen (Agent 1): Top-level coordinator
13
+ * - Security Domain (Agents 2-4): security-architect, security-auditor, test-architect
14
+ * - Core Domain (Agents 5-9): core-architect, type-modernization, memory-specialist, swarm-specialist, mcp-optimizer
15
+ * - Integration Domain (Agents 10-12): integration-architect, cli-modernizer, neural-integrator
16
+ * - Support Domain (Agents 13-15): test-architect, performance-engineer, deployment-engineer
17
+ */
18
+
19
+ import { EventEmitter } from 'events';
20
+ import {
21
+ SwarmId,
22
+ AgentId,
23
+ TaskId,
24
+ AgentState,
25
+ AgentType,
26
+ AgentStatus,
27
+ AgentCapabilities,
28
+ AgentMetrics,
29
+ TaskDefinition,
30
+ TaskType,
31
+ TaskStatus,
32
+ TaskPriority,
33
+ CoordinatorConfig,
34
+ CoordinatorState,
35
+ CoordinatorMetrics,
36
+ SwarmStatus,
37
+ SwarmEvent,
38
+ SwarmEventType,
39
+ TopologyConfig,
40
+ TopologyType,
41
+ ConsensusConfig,
42
+ ConsensusResult,
43
+ Message,
44
+ MessageType,
45
+ PerformanceReport,
46
+ IUnifiedSwarmCoordinator,
47
+ SWARM_CONSTANTS,
48
+ } from './types.js';
49
+ import { TopologyManager, createTopologyManager } from './topology-manager.js';
50
+ import { MessageBus, createMessageBus } from './message-bus.js';
51
+ import { AgentPool, createAgentPool } from './agent-pool.js';
52
+ import { ConsensusEngine, createConsensusEngine } from './consensus/index.js';
53
+
54
+ // =============================================================================
55
+ // Domain Types for 15-Agent Hierarchy
56
+ // =============================================================================
57
+
58
+ export type AgentDomain = 'queen' | 'security' | 'core' | 'integration' | 'support';
59
+
60
+ export interface DomainConfig {
61
+ name: AgentDomain;
62
+ agentNumbers: number[];
63
+ priority: number;
64
+ capabilities: string[];
65
+ description: string;
66
+ }
67
+
68
+ export interface TaskAssignment {
69
+ taskId: string;
70
+ domain: AgentDomain;
71
+ agentId: string;
72
+ priority: TaskPriority;
73
+ assignedAt: Date;
74
+ }
75
+
76
+ export interface ParallelExecutionResult {
77
+ taskId: string;
78
+ domain: AgentDomain;
79
+ success: boolean;
80
+ result?: unknown;
81
+ error?: Error;
82
+ durationMs: number;
83
+ }
84
+
85
+ export interface DomainStatus {
86
+ name: AgentDomain;
87
+ agentCount: number;
88
+ availableAgents: number;
89
+ busyAgents: number;
90
+ tasksQueued: number;
91
+ tasksCompleted: number;
92
+ }
93
+
94
+ // =============================================================================
95
+ // 15-Agent Domain Configuration
96
+ // =============================================================================
97
+
98
+ const DOMAIN_CONFIGS: DomainConfig[] = [
99
+ {
100
+ name: 'queen',
101
+ agentNumbers: [1],
102
+ priority: 0,
103
+ capabilities: ['coordination', 'planning', 'oversight', 'consensus'],
104
+ description: 'Top-level swarm coordination and orchestration',
105
+ },
106
+ {
107
+ name: 'security',
108
+ agentNumbers: [2, 3, 4],
109
+ priority: 1,
110
+ capabilities: ['security-architecture', 'cve-remediation', 'security-testing', 'threat-modeling'],
111
+ description: 'Security architecture, CVE fixes, and security testing',
112
+ },
113
+ {
114
+ name: 'core',
115
+ agentNumbers: [5, 6, 7, 8, 9],
116
+ priority: 2,
117
+ capabilities: ['ddd-design', 'type-modernization', 'memory-unification', 'swarm-coordination', 'mcp-optimization'],
118
+ description: 'Core architecture, DDD, memory unification, and MCP optimization',
119
+ },
120
+ {
121
+ name: 'integration',
122
+ agentNumbers: [10, 11, 12],
123
+ priority: 3,
124
+ capabilities: ['agentic-flow-integration', 'cli-modernization', 'neural-integration', 'hooks-system'],
125
+ description: '@sparkleideas/agentic-flow integration, CLI modernization, and neural features',
126
+ },
127
+ {
128
+ name: 'support',
129
+ agentNumbers: [13, 14, 15],
130
+ priority: 4,
131
+ capabilities: ['tdd-testing', 'performance-benchmarking', 'deployment', 'release-management'],
132
+ description: 'Testing, performance optimization, and deployment',
133
+ },
134
+ ];
135
+
136
+ export class UnifiedSwarmCoordinator extends EventEmitter implements IUnifiedSwarmCoordinator {
137
+ private config: CoordinatorConfig;
138
+ private state: CoordinatorState;
139
+ private topologyManager: TopologyManager;
140
+ private messageBus: MessageBus;
141
+ private consensusEngine: ConsensusEngine;
142
+ private agentPools: Map<AgentType, AgentPool> = new Map();
143
+
144
+ // Domain-based tracking for 15-agent hierarchy
145
+ private domainConfigs: Map<AgentDomain, DomainConfig> = new Map();
146
+ private domainPools: Map<AgentDomain, AgentPool> = new Map();
147
+ private agentDomainMap: Map<string, AgentDomain> = new Map();
148
+ private taskAssignments: Map<string, TaskAssignment> = new Map();
149
+ private domainTaskQueues: Map<AgentDomain, string[]> = new Map();
150
+
151
+ // Performance tracking
152
+ private startTime?: Date;
153
+ private taskCounter: number = 0;
154
+ private agentCounter: number = 0;
155
+ private coordinationLatencies: number[] = [];
156
+ private lastMetricsUpdate: Date = new Date();
157
+
158
+ // Background intervals
159
+ private heartbeatInterval?: NodeJS.Timeout;
160
+ private healthCheckInterval?: NodeJS.Timeout;
161
+ private metricsInterval?: NodeJS.Timeout;
162
+
163
+ constructor(config: Partial<CoordinatorConfig> = {}) {
164
+ super();
165
+
166
+ this.config = this.createDefaultConfig(config);
167
+ this.state = this.createInitialState();
168
+
169
+ // Initialize components
170
+ this.topologyManager = createTopologyManager(this.config.topology);
171
+ this.messageBus = createMessageBus(this.config.messageBus);
172
+ this.consensusEngine = createConsensusEngine(
173
+ this.state.id.id,
174
+ this.config.consensus.algorithm,
175
+ this.config.consensus
176
+ );
177
+
178
+ // Initialize domain configurations
179
+ this.initializeDomainConfigs();
180
+
181
+ this.setupEventForwarding();
182
+ }
183
+
184
+ // =============================================================================
185
+ // Domain Configuration Initialization
186
+ // =============================================================================
187
+
188
+ private initializeDomainConfigs(): void {
189
+ for (const config of DOMAIN_CONFIGS) {
190
+ this.domainConfigs.set(config.name, config);
191
+ this.domainTaskQueues.set(config.name, []);
192
+ }
193
+ }
194
+
195
+ async initialize(): Promise<void> {
196
+ if (this.state.status !== 'initializing' && this.state.status !== 'stopped') {
197
+ throw new Error(`Cannot initialize from status: ${this.state.status}`);
198
+ }
199
+
200
+ const startTime = performance.now();
201
+
202
+ try {
203
+ // Initialize all components in parallel
204
+ await Promise.all([
205
+ this.topologyManager.initialize(this.config.topology),
206
+ this.messageBus.initialize(this.config.messageBus),
207
+ this.consensusEngine.initialize(this.config.consensus),
208
+ ]);
209
+
210
+ // Initialize default agent pools
211
+ await this.initializeAgentPools();
212
+
213
+ // Start background processes
214
+ this.startBackgroundProcesses();
215
+
216
+ this.state.status = 'running';
217
+ this.startTime = new Date();
218
+ this.state.startedAt = this.startTime;
219
+
220
+ const duration = performance.now() - startTime;
221
+ this.recordCoordinationLatency(duration);
222
+
223
+ this.emitEvent('swarm.initialized', {
224
+ swarmId: this.state.id.id,
225
+ initDurationMs: duration,
226
+ });
227
+
228
+ this.emitEvent('swarm.started', {
229
+ swarmId: this.state.id.id,
230
+ topology: this.config.topology.type,
231
+ consensus: this.config.consensus.algorithm,
232
+ });
233
+ } catch (error) {
234
+ this.state.status = 'failed';
235
+ throw error;
236
+ }
237
+ }
238
+
239
+ async shutdown(): Promise<void> {
240
+ if (this.state.status === 'stopped') {
241
+ return;
242
+ }
243
+
244
+ this.state.status = 'shutting_down';
245
+
246
+ // Stop background processes
247
+ this.stopBackgroundProcesses();
248
+
249
+ // Shutdown all components including domain pools
250
+ await Promise.all([
251
+ this.messageBus.shutdown(),
252
+ this.consensusEngine.shutdown(),
253
+ ...Array.from(this.agentPools.values()).map(pool => pool.shutdown()),
254
+ ...Array.from(this.domainPools.values()).map(pool => pool.shutdown()),
255
+ ]);
256
+
257
+ // Clear all tracking data
258
+ this.state.agents.clear();
259
+ this.state.tasks.clear();
260
+ this.agentDomainMap.clear();
261
+ this.taskAssignments.clear();
262
+ for (const queue of this.domainTaskQueues.values()) {
263
+ queue.length = 0;
264
+ }
265
+
266
+ this.state.status = 'stopped';
267
+
268
+ this.emitEvent('swarm.stopped', {
269
+ swarmId: this.state.id.id,
270
+ totalTasks: this.state.metrics.totalTasks,
271
+ completedTasks: this.state.metrics.completedTasks,
272
+ });
273
+ }
274
+
275
+ async pause(): Promise<void> {
276
+ if (this.state.status !== 'running') {
277
+ return;
278
+ }
279
+
280
+ this.state.status = 'paused';
281
+ this.stopBackgroundProcesses();
282
+
283
+ this.emitEvent('swarm.paused', { swarmId: this.state.id.id });
284
+ }
285
+
286
+ async resume(): Promise<void> {
287
+ if (this.state.status !== 'paused') {
288
+ return;
289
+ }
290
+
291
+ this.startBackgroundProcesses();
292
+ this.state.status = 'running';
293
+
294
+ this.emitEvent('swarm.resumed', { swarmId: this.state.id.id });
295
+ }
296
+
297
+ // ===== AGENT MANAGEMENT =====
298
+
299
+ async registerAgent(
300
+ agentData: Omit<AgentState, 'id'>
301
+ ): Promise<string> {
302
+ const startTime = performance.now();
303
+
304
+ if (this.state.agents.size >= this.config.maxAgents) {
305
+ throw new Error(`Maximum agents (${this.config.maxAgents}) reached`);
306
+ }
307
+
308
+ this.agentCounter++;
309
+ const agentId: AgentId = {
310
+ id: `agent_${this.state.id.id}_${this.agentCounter}`,
311
+ swarmId: this.state.id.id,
312
+ type: agentData.type,
313
+ instance: this.agentCounter,
314
+ };
315
+
316
+ const agent: AgentState = {
317
+ ...agentData,
318
+ id: agentId,
319
+ lastHeartbeat: new Date(),
320
+ connections: [],
321
+ };
322
+
323
+ // Add to state
324
+ this.state.agents.set(agentId.id, agent);
325
+
326
+ // Add to topology
327
+ const role = this.determineTopologyRole(agent.type);
328
+ await this.topologyManager.addNode(agentId.id, role);
329
+
330
+ // Subscribe to message bus
331
+ this.messageBus.subscribe(agentId.id, (message) => {
332
+ this.handleAgentMessage(agentId.id, message);
333
+ });
334
+
335
+ // Add to consensus engine
336
+ this.consensusEngine.addNode(agentId.id);
337
+
338
+ const duration = performance.now() - startTime;
339
+ this.recordCoordinationLatency(duration);
340
+
341
+ this.emitEvent('agent.joined', {
342
+ agentId: agentId.id,
343
+ type: agent.type,
344
+ registrationDurationMs: duration,
345
+ });
346
+
347
+ return agentId.id;
348
+ }
349
+
350
+ async unregisterAgent(agentId: string): Promise<void> {
351
+ const agent = this.state.agents.get(agentId);
352
+ if (!agent) {
353
+ return;
354
+ }
355
+
356
+ // Cancel any assigned tasks
357
+ if (agent.currentTask) {
358
+ await this.cancelTask(agent.currentTask.id);
359
+ }
360
+
361
+ // Remove from components
362
+ await this.topologyManager.removeNode(agentId);
363
+ this.messageBus.unsubscribe(agentId);
364
+ this.consensusEngine.removeNode(agentId);
365
+
366
+ // Remove from state
367
+ this.state.agents.delete(agentId);
368
+
369
+ this.emitEvent('agent.left', { agentId });
370
+ }
371
+
372
+ getAgent(agentId: string): AgentState | undefined {
373
+ return this.state.agents.get(agentId);
374
+ }
375
+
376
+ getAllAgents(): AgentState[] {
377
+ return Array.from(this.state.agents.values());
378
+ }
379
+
380
+ getAgentsByType(type: AgentType): AgentState[] {
381
+ return this.getAllAgents().filter(a => a.type === type);
382
+ }
383
+
384
+ getAvailableAgents(): AgentState[] {
385
+ return this.getAllAgents().filter(a => a.status === 'idle');
386
+ }
387
+
388
+ // ===== TASK MANAGEMENT =====
389
+
390
+ async submitTask(
391
+ taskData: Omit<TaskDefinition, 'id' | 'status' | 'createdAt'>
392
+ ): Promise<string> {
393
+ const startTime = performance.now();
394
+
395
+ if (this.state.tasks.size >= this.config.maxTasks) {
396
+ throw new Error(`Maximum tasks (${this.config.maxTasks}) reached`);
397
+ }
398
+
399
+ this.taskCounter++;
400
+ const taskId: TaskId = {
401
+ id: `task_${this.state.id.id}_${this.taskCounter}`,
402
+ swarmId: this.state.id.id,
403
+ sequence: this.taskCounter,
404
+ priority: taskData.priority,
405
+ };
406
+
407
+ const task: TaskDefinition = {
408
+ ...taskData,
409
+ id: taskId,
410
+ status: 'created',
411
+ createdAt: new Date(),
412
+ };
413
+
414
+ this.state.tasks.set(taskId.id, task);
415
+ this.state.metrics.totalTasks++;
416
+
417
+ // Assign to available agent
418
+ const assignedAgent = await this.assignTask(task);
419
+
420
+ const duration = performance.now() - startTime;
421
+ this.recordCoordinationLatency(duration);
422
+
423
+ this.emitEvent('task.created', {
424
+ taskId: taskId.id,
425
+ type: task.type,
426
+ priority: task.priority,
427
+ assignedTo: assignedAgent?.id.id,
428
+ assignmentDurationMs: duration,
429
+ });
430
+
431
+ return taskId.id;
432
+ }
433
+
434
+ async cancelTask(taskId: string): Promise<void> {
435
+ const task = this.state.tasks.get(taskId);
436
+ if (!task) {
437
+ return;
438
+ }
439
+
440
+ // Notify assigned agent
441
+ if (task.assignedTo) {
442
+ await this.messageBus.send({
443
+ type: 'task_fail',
444
+ from: this.state.id.id,
445
+ to: task.assignedTo.id,
446
+ payload: { taskId, reason: 'cancelled' },
447
+ priority: 'high',
448
+ requiresAck: true,
449
+ ttlMs: SWARM_CONSTANTS.DEFAULT_MESSAGE_TTL_MS,
450
+ });
451
+
452
+ // Release agent
453
+ const agent = this.state.agents.get(task.assignedTo.id);
454
+ if (agent) {
455
+ agent.status = 'idle';
456
+ agent.currentTask = undefined;
457
+ }
458
+ }
459
+
460
+ task.status = 'cancelled';
461
+
462
+ this.emitEvent('task.failed', {
463
+ taskId,
464
+ reason: 'cancelled',
465
+ });
466
+ }
467
+
468
+ getTask(taskId: string): TaskDefinition | undefined {
469
+ return this.state.tasks.get(taskId);
470
+ }
471
+
472
+ getAllTasks(): TaskDefinition[] {
473
+ return Array.from(this.state.tasks.values());
474
+ }
475
+
476
+ getTasksByStatus(status: TaskStatus): TaskDefinition[] {
477
+ return this.getAllTasks().filter(t => t.status === status);
478
+ }
479
+
480
+ // ===== COORDINATION =====
481
+
482
+ async proposeConsensus(value: unknown): Promise<ConsensusResult> {
483
+ const startTime = performance.now();
484
+
485
+ const proposal = await this.consensusEngine.propose(value, this.state.id.id);
486
+ const result = await this.consensusEngine.awaitConsensus(proposal.id);
487
+
488
+ const duration = performance.now() - startTime;
489
+ this.recordCoordinationLatency(duration);
490
+
491
+ if (result.approved) {
492
+ this.emitEvent('consensus.achieved', {
493
+ proposalId: proposal.id,
494
+ approvalRate: result.approvalRate,
495
+ durationMs: duration,
496
+ });
497
+ } else {
498
+ this.emitEvent('consensus.failed', {
499
+ proposalId: proposal.id,
500
+ approvalRate: result.approvalRate,
501
+ reason: 'threshold_not_met',
502
+ });
503
+ }
504
+
505
+ return result;
506
+ }
507
+
508
+ async broadcastMessage(
509
+ payload: unknown,
510
+ priority: Message['priority'] = 'normal'
511
+ ): Promise<void> {
512
+ await this.messageBus.broadcast({
513
+ type: 'broadcast',
514
+ from: this.state.id.id,
515
+ payload,
516
+ priority,
517
+ requiresAck: false,
518
+ ttlMs: SWARM_CONSTANTS.DEFAULT_MESSAGE_TTL_MS,
519
+ });
520
+ }
521
+
522
+ // ===== MONITORING =====
523
+
524
+ getState(): CoordinatorState {
525
+ return {
526
+ ...this.state,
527
+ agents: new Map(this.state.agents),
528
+ tasks: new Map(this.state.tasks),
529
+ topology: this.topologyManager.getState(),
530
+ };
531
+ }
532
+
533
+ getMetrics(): CoordinatorMetrics {
534
+ return { ...this.state.metrics };
535
+ }
536
+
537
+ getPerformanceReport(): PerformanceReport {
538
+ const recentLatencies = this.coordinationLatencies.slice(-100);
539
+ const sortedLatencies = [...recentLatencies].sort((a, b) => a - b);
540
+
541
+ return {
542
+ timestamp: new Date(),
543
+ window: 60000, // 1 minute
544
+ coordinationLatencyP50: sortedLatencies[Math.floor(sortedLatencies.length * 0.5)] || 0,
545
+ coordinationLatencyP99: sortedLatencies[Math.floor(sortedLatencies.length * 0.99)] || 0,
546
+ messagesPerSecond: this.messageBus.getStats().messagesPerSecond,
547
+ taskThroughput: this.calculateTaskThroughput(),
548
+ agentUtilization: this.calculateAgentUtilization(),
549
+ consensusSuccessRate: this.state.metrics.consensusSuccessRate,
550
+ };
551
+ }
552
+
553
+ // ===== PRIVATE METHODS =====
554
+
555
+ private createDefaultConfig(config: Partial<CoordinatorConfig>): CoordinatorConfig {
556
+ return {
557
+ topology: {
558
+ type: config.topology?.type ?? 'mesh',
559
+ maxAgents: config.topology?.maxAgents ?? SWARM_CONSTANTS.DEFAULT_MAX_AGENTS,
560
+ replicationFactor: config.topology?.replicationFactor ?? 2,
561
+ partitionStrategy: config.topology?.partitionStrategy ?? 'hash',
562
+ failoverEnabled: config.topology?.failoverEnabled ?? true,
563
+ autoRebalance: config.topology?.autoRebalance ?? true,
564
+ },
565
+ consensus: {
566
+ algorithm: config.consensus?.algorithm ?? 'raft',
567
+ threshold: config.consensus?.threshold ?? SWARM_CONSTANTS.DEFAULT_CONSENSUS_THRESHOLD,
568
+ timeoutMs: config.consensus?.timeoutMs ?? SWARM_CONSTANTS.DEFAULT_CONSENSUS_TIMEOUT_MS,
569
+ maxRounds: config.consensus?.maxRounds ?? 10,
570
+ requireQuorum: config.consensus?.requireQuorum ?? true,
571
+ },
572
+ messageBus: {
573
+ maxQueueSize: config.messageBus?.maxQueueSize ?? SWARM_CONSTANTS.MAX_QUEUE_SIZE,
574
+ processingIntervalMs: config.messageBus?.processingIntervalMs ?? 10,
575
+ ackTimeoutMs: config.messageBus?.ackTimeoutMs ?? 5000,
576
+ retryAttempts: config.messageBus?.retryAttempts ?? SWARM_CONSTANTS.MAX_RETRIES,
577
+ enablePersistence: config.messageBus?.enablePersistence ?? false,
578
+ compressionEnabled: config.messageBus?.compressionEnabled ?? false,
579
+ },
580
+ maxAgents: config.maxAgents ?? SWARM_CONSTANTS.DEFAULT_MAX_AGENTS,
581
+ maxTasks: config.maxTasks ?? SWARM_CONSTANTS.DEFAULT_MAX_TASKS,
582
+ heartbeatIntervalMs: config.heartbeatIntervalMs ?? SWARM_CONSTANTS.DEFAULT_HEARTBEAT_INTERVAL_MS,
583
+ healthCheckIntervalMs: config.healthCheckIntervalMs ?? SWARM_CONSTANTS.DEFAULT_HEALTH_CHECK_INTERVAL_MS,
584
+ taskTimeoutMs: config.taskTimeoutMs ?? SWARM_CONSTANTS.DEFAULT_TASK_TIMEOUT_MS,
585
+ autoScaling: config.autoScaling ?? true,
586
+ autoRecovery: config.autoRecovery ?? true,
587
+ };
588
+ }
589
+
590
+ private createInitialState(): CoordinatorState {
591
+ const swarmId: SwarmId = {
592
+ id: `swarm_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
593
+ namespace: 'default',
594
+ version: '3.0.0',
595
+ createdAt: new Date(),
596
+ };
597
+
598
+ return {
599
+ id: swarmId,
600
+ status: 'initializing',
601
+ topology: {
602
+ type: 'mesh',
603
+ nodes: [],
604
+ edges: [],
605
+ partitions: [],
606
+ },
607
+ agents: new Map(),
608
+ tasks: new Map(),
609
+ metrics: {
610
+ uptime: 0,
611
+ activeAgents: 0,
612
+ totalTasks: 0,
613
+ completedTasks: 0,
614
+ failedTasks: 0,
615
+ avgTaskDurationMs: 0,
616
+ messagesPerSecond: 0,
617
+ consensusSuccessRate: 1.0,
618
+ coordinationLatencyMs: 0,
619
+ memoryUsageBytes: 0,
620
+ },
621
+ };
622
+ }
623
+
624
+ private async initializeAgentPools(): Promise<void> {
625
+ // Initialize type-based pools (legacy support)
626
+ const defaultPoolTypes: AgentType[] = ['worker', 'coordinator', 'researcher', 'coder'];
627
+
628
+ for (const type of defaultPoolTypes) {
629
+ const pool = createAgentPool({
630
+ name: `${type}-pool`,
631
+ type,
632
+ minSize: 0,
633
+ maxSize: Math.floor(this.config.maxAgents / defaultPoolTypes.length),
634
+ scaleUpThreshold: 0.8,
635
+ scaleDownThreshold: 0.2,
636
+ cooldownMs: 30000,
637
+ healthCheckIntervalMs: this.config.healthCheckIntervalMs,
638
+ });
639
+
640
+ await pool.initialize();
641
+ this.agentPools.set(type, pool);
642
+ }
643
+
644
+ // Initialize domain-based pools for 15-agent hierarchy
645
+ await this.initializeDomainPools();
646
+ }
647
+
648
+ private async initializeDomainPools(): Promise<void> {
649
+ for (const [domain, config] of this.domainConfigs) {
650
+ const agentType = this.domainToAgentType(domain);
651
+ const pool = createAgentPool({
652
+ name: `${domain}-domain-pool`,
653
+ type: agentType,
654
+ minSize: 0,
655
+ maxSize: config.agentNumbers.length,
656
+ scaleUpThreshold: 0.8,
657
+ scaleDownThreshold: 0.2,
658
+ cooldownMs: 30000,
659
+ healthCheckIntervalMs: this.config.healthCheckIntervalMs,
660
+ });
661
+
662
+ await pool.initialize();
663
+ this.domainPools.set(domain, pool);
664
+ }
665
+ }
666
+
667
+ private domainToAgentType(domain: AgentDomain): AgentType {
668
+ switch (domain) {
669
+ case 'queen':
670
+ return 'queen';
671
+ case 'security':
672
+ return 'specialist';
673
+ case 'core':
674
+ return 'architect';
675
+ case 'integration':
676
+ return 'coder';
677
+ case 'support':
678
+ return 'tester';
679
+ default:
680
+ return 'worker';
681
+ }
682
+ }
683
+
684
+ private setupEventForwarding(): void {
685
+ // Forward topology events
686
+ this.topologyManager.on('node.added', (data) => {
687
+ this.emitEvent('topology.updated', { action: 'node_added', ...data });
688
+ });
689
+
690
+ this.topologyManager.on('node.removed', (data) => {
691
+ this.emitEvent('topology.updated', { action: 'node_removed', ...data });
692
+ });
693
+
694
+ this.topologyManager.on('topology.rebalanced', (data) => {
695
+ this.emitEvent('topology.rebalanced', data);
696
+ });
697
+
698
+ // Forward consensus events
699
+ this.consensusEngine.on('consensus.achieved', (data) => {
700
+ this.state.metrics.consensusSuccessRate =
701
+ (this.state.metrics.consensusSuccessRate * 0.9) + (data.approved ? 0.1 : 0);
702
+ });
703
+
704
+ // Forward message bus events
705
+ this.messageBus.on('message.delivered', (data) => {
706
+ this.emitEvent('message.received', data);
707
+ });
708
+ }
709
+
710
+ private startBackgroundProcesses(): void {
711
+ // Heartbeat monitoring
712
+ this.heartbeatInterval = setInterval(() => {
713
+ this.checkHeartbeats();
714
+ }, this.config.heartbeatIntervalMs);
715
+
716
+ // Health checks
717
+ this.healthCheckInterval = setInterval(() => {
718
+ this.performHealthChecks();
719
+ }, this.config.healthCheckIntervalMs);
720
+
721
+ // Metrics collection
722
+ this.metricsInterval = setInterval(() => {
723
+ this.updateMetrics();
724
+ }, 1000);
725
+ }
726
+
727
+ private stopBackgroundProcesses(): void {
728
+ if (this.heartbeatInterval) {
729
+ clearInterval(this.heartbeatInterval);
730
+ this.heartbeatInterval = undefined;
731
+ }
732
+ if (this.healthCheckInterval) {
733
+ clearInterval(this.healthCheckInterval);
734
+ this.healthCheckInterval = undefined;
735
+ }
736
+ if (this.metricsInterval) {
737
+ clearInterval(this.metricsInterval);
738
+ this.metricsInterval = undefined;
739
+ }
740
+ }
741
+
742
+ private async assignTask(task: TaskDefinition): Promise<AgentState | undefined> {
743
+ // Find best available agent
744
+ const availableAgents = this.getAvailableAgents();
745
+ if (availableAgents.length === 0) {
746
+ task.status = 'queued';
747
+ return undefined;
748
+ }
749
+
750
+ // Score agents based on capabilities and workload
751
+ const scoredAgents = availableAgents.map(agent => ({
752
+ agent,
753
+ score: this.scoreAgentForTask(agent, task),
754
+ })).sort((a, b) => b.score - a.score);
755
+
756
+ const bestAgent = scoredAgents[0]?.agent;
757
+ if (!bestAgent) {
758
+ task.status = 'queued';
759
+ return undefined;
760
+ }
761
+
762
+ // Assign task
763
+ task.assignedTo = bestAgent.id;
764
+ task.status = 'assigned';
765
+ bestAgent.status = 'busy';
766
+ bestAgent.currentTask = task.id;
767
+
768
+ // Notify agent via message bus
769
+ await this.messageBus.send({
770
+ type: 'task_assign',
771
+ from: this.state.id.id,
772
+ to: bestAgent.id.id,
773
+ payload: { task },
774
+ priority: this.mapTaskPriorityToMessagePriority(task.priority),
775
+ requiresAck: true,
776
+ ttlMs: this.config.taskTimeoutMs,
777
+ });
778
+
779
+ this.emitEvent('task.assigned', {
780
+ taskId: task.id.id,
781
+ agentId: bestAgent.id.id,
782
+ });
783
+
784
+ return bestAgent;
785
+ }
786
+
787
+ private scoreAgentForTask(agent: AgentState, task: TaskDefinition): number {
788
+ let score = 100;
789
+
790
+ // Type matching
791
+ const typeScores: Record<TaskType, AgentType[]> = {
792
+ research: ['researcher'],
793
+ analysis: ['analyst', 'researcher'],
794
+ coding: ['coder'],
795
+ testing: ['tester'],
796
+ review: ['reviewer'],
797
+ documentation: ['documenter'],
798
+ coordination: ['coordinator', 'queen'],
799
+ consensus: ['coordinator', 'queen'],
800
+ custom: ['worker'],
801
+ };
802
+
803
+ const preferredTypes = typeScores[task.type] || ['worker'];
804
+ if (preferredTypes.includes(agent.type)) {
805
+ score += 50;
806
+ }
807
+
808
+ // Workload adjustment
809
+ score -= agent.workload * 20;
810
+
811
+ // Health adjustment
812
+ score *= agent.health;
813
+
814
+ // Metrics-based adjustment
815
+ score += agent.metrics.successRate * 10;
816
+ score -= (agent.metrics.averageExecutionTime / 60000) * 5;
817
+
818
+ return score;
819
+ }
820
+
821
+ private mapTaskPriorityToMessagePriority(
822
+ priority: TaskPriority
823
+ ): Message['priority'] {
824
+ const mapping: Record<TaskPriority, Message['priority']> = {
825
+ critical: 'urgent',
826
+ high: 'high',
827
+ normal: 'normal',
828
+ low: 'low',
829
+ background: 'low',
830
+ };
831
+ return mapping[priority];
832
+ }
833
+
834
+ private determineTopologyRole(
835
+ agentType: AgentType
836
+ ): 'queen' | 'worker' | 'coordinator' | 'peer' {
837
+ switch (agentType) {
838
+ case 'queen':
839
+ return 'queen';
840
+ case 'coordinator':
841
+ return 'coordinator';
842
+ default:
843
+ return this.config.topology.type === 'mesh' ? 'peer' : 'worker';
844
+ }
845
+ }
846
+
847
+ private handleAgentMessage(agentId: string, message: Message): void {
848
+ const agent = this.state.agents.get(agentId);
849
+ if (!agent) return;
850
+
851
+ // Update heartbeat
852
+ agent.lastHeartbeat = new Date();
853
+ agent.metrics.messagesProcessed++;
854
+
855
+ switch (message.type) {
856
+ case 'task_complete':
857
+ this.handleTaskComplete(agentId, message.payload as { taskId: string; result: unknown });
858
+ break;
859
+ case 'task_fail':
860
+ this.handleTaskFail(agentId, message.payload as { taskId: string; error: string });
861
+ break;
862
+ case 'heartbeat':
863
+ this.handleHeartbeat(agentId, message.payload as Record<string, unknown>);
864
+ break;
865
+ case 'status_update':
866
+ this.handleStatusUpdate(agentId, message.payload as Partial<AgentState>);
867
+ break;
868
+ }
869
+ }
870
+
871
+ private handleTaskComplete(agentId: string, data: { taskId: string; result: unknown }): void {
872
+ const task = this.state.tasks.get(data.taskId);
873
+ const agent = this.state.agents.get(agentId);
874
+
875
+ if (task && agent) {
876
+ task.status = 'completed';
877
+ task.output = data.result;
878
+ task.completedAt = new Date();
879
+
880
+ agent.status = 'idle';
881
+ agent.currentTask = undefined;
882
+ agent.metrics.tasksCompleted++;
883
+
884
+ this.state.metrics.completedTasks++;
885
+
886
+ // Update average task duration
887
+ if (task.startedAt) {
888
+ const duration = task.completedAt.getTime() - task.startedAt.getTime();
889
+ this.state.metrics.avgTaskDurationMs =
890
+ (this.state.metrics.avgTaskDurationMs * 0.9) + (duration * 0.1);
891
+ }
892
+
893
+ this.emitEvent('task.completed', {
894
+ taskId: data.taskId,
895
+ agentId,
896
+ result: data.result,
897
+ });
898
+ }
899
+ }
900
+
901
+ private handleTaskFail(agentId: string, data: { taskId: string; error: string }): void {
902
+ const task = this.state.tasks.get(data.taskId);
903
+ const agent = this.state.agents.get(agentId);
904
+
905
+ if (task && agent) {
906
+ // Check retry
907
+ if (task.retries < task.maxRetries) {
908
+ task.retries++;
909
+ task.status = 'queued';
910
+ task.assignedTo = undefined;
911
+ agent.currentTask = undefined;
912
+ agent.status = 'idle';
913
+
914
+ // Re-assign
915
+ this.assignTask(task);
916
+ } else {
917
+ task.status = 'failed';
918
+ agent.status = 'idle';
919
+ agent.currentTask = undefined;
920
+ agent.metrics.tasksFailed++;
921
+
922
+ this.state.metrics.failedTasks++;
923
+
924
+ this.emitEvent('task.failed', {
925
+ taskId: data.taskId,
926
+ agentId,
927
+ error: data.error,
928
+ });
929
+ }
930
+ }
931
+ }
932
+
933
+ private handleHeartbeat(agentId: string, data: Record<string, unknown>): void {
934
+ const agent = this.state.agents.get(agentId);
935
+ if (agent) {
936
+ agent.lastHeartbeat = new Date();
937
+ if (data.metrics) {
938
+ agent.metrics = { ...agent.metrics, ...(data.metrics as Partial<typeof agent.metrics>) };
939
+ }
940
+
941
+ this.emitEvent('agent.heartbeat', { agentId });
942
+ }
943
+ }
944
+
945
+ private handleStatusUpdate(agentId: string, data: Partial<AgentState>): void {
946
+ const agent = this.state.agents.get(agentId);
947
+ if (agent) {
948
+ if (data.status) agent.status = data.status;
949
+ if (data.health !== undefined) agent.health = data.health;
950
+ if (data.workload !== undefined) agent.workload = data.workload;
951
+
952
+ this.emitEvent('agent.status_changed', { agentId, status: agent.status });
953
+ }
954
+ }
955
+
956
+ private checkHeartbeats(): void {
957
+ const now = Date.now();
958
+ const timeout = this.config.heartbeatIntervalMs * 3;
959
+
960
+ for (const [agentId, agent] of this.state.agents) {
961
+ const timeSinceHeartbeat = now - agent.lastHeartbeat.getTime();
962
+
963
+ if (timeSinceHeartbeat > timeout && agent.status !== 'terminated') {
964
+ agent.status = 'error';
965
+ agent.health = Math.max(0, agent.health - 0.2);
966
+
967
+ // Auto-recovery
968
+ if (this.config.autoRecovery && agent.health <= 0.2) {
969
+ this.recoverAgent(agentId);
970
+ }
971
+ }
972
+ }
973
+ }
974
+
975
+ private async recoverAgent(agentId: string): Promise<void> {
976
+ const agent = this.state.agents.get(agentId);
977
+ if (!agent) return;
978
+
979
+ // Reassign any tasks
980
+ if (agent.currentTask) {
981
+ const task = this.state.tasks.get(agent.currentTask.id);
982
+ if (task) {
983
+ task.status = 'queued';
984
+ task.assignedTo = undefined;
985
+ await this.assignTask(task);
986
+ }
987
+ }
988
+
989
+ // Reset agent
990
+ agent.status = 'idle';
991
+ agent.currentTask = undefined;
992
+ agent.health = 1.0;
993
+ agent.lastHeartbeat = new Date();
994
+ }
995
+
996
+ private performHealthChecks(): void {
997
+ const activeAgents = this.getAllAgents().filter(
998
+ a => a.status === 'idle' || a.status === 'busy'
999
+ );
1000
+
1001
+ this.state.metrics.activeAgents = activeAgents.length;
1002
+
1003
+ // Update topology state
1004
+ this.state.topology = this.topologyManager.getState();
1005
+ }
1006
+
1007
+ private updateMetrics(): void {
1008
+ const now = new Date();
1009
+ const uptime = this.startTime
1010
+ ? (now.getTime() - this.startTime.getTime()) / 1000
1011
+ : 0;
1012
+
1013
+ this.state.metrics.uptime = uptime;
1014
+ this.state.metrics.messagesPerSecond = this.messageBus.getStats().messagesPerSecond;
1015
+
1016
+ // Calculate coordination latency
1017
+ if (this.coordinationLatencies.length > 0) {
1018
+ const recent = this.coordinationLatencies.slice(-50);
1019
+ this.state.metrics.coordinationLatencyMs =
1020
+ recent.reduce((a, b) => a + b, 0) / recent.length;
1021
+ }
1022
+
1023
+ // Memory usage (approximation)
1024
+ this.state.metrics.memoryUsageBytes =
1025
+ (this.state.agents.size * 2000) +
1026
+ (this.state.tasks.size * 1000) +
1027
+ (this.messageBus.getQueueDepth() * 500);
1028
+
1029
+ this.lastMetricsUpdate = now;
1030
+ }
1031
+
1032
+ private recordCoordinationLatency(latencyMs: number): void {
1033
+ this.coordinationLatencies.push(latencyMs);
1034
+ if (this.coordinationLatencies.length > 1000) {
1035
+ this.coordinationLatencies.shift();
1036
+ }
1037
+ }
1038
+
1039
+ private calculateTaskThroughput(): number {
1040
+ if (!this.startTime) return 0;
1041
+ const uptimeSeconds = (Date.now() - this.startTime.getTime()) / 1000;
1042
+ return uptimeSeconds > 0
1043
+ ? this.state.metrics.completedTasks / uptimeSeconds
1044
+ : 0;
1045
+ }
1046
+
1047
+ private calculateAgentUtilization(): number {
1048
+ const agents = this.getAllAgents();
1049
+ if (agents.length === 0) return 0;
1050
+ const busyAgents = agents.filter(a => a.status === 'busy').length;
1051
+ return busyAgents / agents.length;
1052
+ }
1053
+
1054
+ private emitEvent(type: SwarmEventType, data: Record<string, unknown>): void {
1055
+ const event: SwarmEvent = {
1056
+ id: `event_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
1057
+ type,
1058
+ source: this.state.id.id,
1059
+ timestamp: new Date(),
1060
+ data,
1061
+ };
1062
+
1063
+ this.emit(type, event);
1064
+ this.emit('event', event);
1065
+ }
1066
+
1067
+ // ===== UTILITY METHODS =====
1068
+
1069
+ getTopology(): TopologyType {
1070
+ return this.config.topology.type;
1071
+ }
1072
+
1073
+ setTopology(type: TopologyType): void {
1074
+ this.config.topology.type = type;
1075
+ }
1076
+
1077
+ getConsensusAlgorithm(): string {
1078
+ return this.config.consensus.algorithm;
1079
+ }
1080
+
1081
+ isHealthy(): boolean {
1082
+ return (
1083
+ this.state.status === 'running' &&
1084
+ this.state.metrics.activeAgents > 0 &&
1085
+ this.state.metrics.coordinationLatencyMs < SWARM_CONSTANTS.COORDINATION_LATENCY_TARGET_MS * 2
1086
+ );
1087
+ }
1088
+
1089
+ getAgentPool(type: AgentType): AgentPool | undefined {
1090
+ return this.agentPools.get(type);
1091
+ }
1092
+
1093
+ // =============================================================================
1094
+ // DOMAIN-BASED TASK ROUTING (15-Agent Hierarchy Support)
1095
+ // =============================================================================
1096
+
1097
+ /**
1098
+ * Assign a task to a specific domain
1099
+ * Routes the task to the most suitable agent within that domain
1100
+ */
1101
+ async assignTaskToDomain(taskId: string, domain: AgentDomain): Promise<string | undefined> {
1102
+ const startTime = performance.now();
1103
+ const task = this.state.tasks.get(taskId);
1104
+
1105
+ if (!task) {
1106
+ throw new Error(`Task ${taskId} not found`);
1107
+ }
1108
+
1109
+ const pool = this.domainPools.get(domain);
1110
+ if (!pool) {
1111
+ throw new Error(`Domain pool ${domain} not found`);
1112
+ }
1113
+
1114
+ // Try to acquire an agent from the domain pool
1115
+ const agent = await pool.acquire();
1116
+ if (!agent) {
1117
+ // Add to domain queue if no agents available
1118
+ const queue = this.domainTaskQueues.get(domain) || [];
1119
+ queue.push(taskId);
1120
+ this.domainTaskQueues.set(domain, queue);
1121
+ task.status = 'queued';
1122
+
1123
+ this.emitEvent('task.queued', {
1124
+ taskId,
1125
+ domain,
1126
+ queuePosition: queue.length,
1127
+ reason: 'no_available_agents'
1128
+ });
1129
+
1130
+ return undefined;
1131
+ }
1132
+
1133
+ // Update task
1134
+ task.status = 'assigned';
1135
+ task.assignedTo = agent.id;
1136
+ task.startedAt = new Date();
1137
+
1138
+ // Track assignment
1139
+ const assignment: TaskAssignment = {
1140
+ taskId,
1141
+ domain,
1142
+ agentId: agent.id.id,
1143
+ priority: task.priority,
1144
+ assignedAt: new Date(),
1145
+ };
1146
+ this.taskAssignments.set(taskId, assignment);
1147
+
1148
+ // Notify agent via message bus
1149
+ await this.messageBus.send({
1150
+ type: 'task_assign',
1151
+ from: this.state.id.id,
1152
+ to: agent.id.id,
1153
+ payload: { taskId, task, domain },
1154
+ priority: this.mapTaskPriorityToMessagePriority(task.priority),
1155
+ requiresAck: true,
1156
+ ttlMs: this.config.taskTimeoutMs,
1157
+ });
1158
+
1159
+ const duration = performance.now() - startTime;
1160
+ this.recordCoordinationLatency(duration);
1161
+
1162
+ this.emitEvent('task.assigned', {
1163
+ taskId,
1164
+ agentId: agent.id.id,
1165
+ domain,
1166
+ assignmentDurationMs: duration,
1167
+ });
1168
+
1169
+ return agent.id.id;
1170
+ }
1171
+
1172
+ /**
1173
+ * Get all agents belonging to a specific domain
1174
+ */
1175
+ getAgentsByDomain(domain: AgentDomain): AgentState[] {
1176
+ const agents: AgentState[] = [];
1177
+ for (const [agentId, agentDomain] of this.agentDomainMap) {
1178
+ if (agentDomain === domain) {
1179
+ const agent = this.state.agents.get(agentId);
1180
+ if (agent) {
1181
+ agents.push(agent);
1182
+ }
1183
+ }
1184
+ }
1185
+ return agents;
1186
+ }
1187
+
1188
+ /**
1189
+ * Execute multiple tasks in parallel across different domains
1190
+ * This is the key method for achieving >85% agent utilization
1191
+ */
1192
+ async executeParallel(tasks: Array<{
1193
+ task: Omit<TaskDefinition, 'id' | 'status' | 'createdAt'>;
1194
+ domain: AgentDomain;
1195
+ }>): Promise<ParallelExecutionResult[]> {
1196
+ const startTime = performance.now();
1197
+ const executionPromises: Promise<ParallelExecutionResult>[] = [];
1198
+
1199
+ // Submit all tasks first
1200
+ const taskIds: Array<{ taskId: string; domain: AgentDomain }> = [];
1201
+ for (const { task, domain } of tasks) {
1202
+ const taskId = await this.submitTask(task);
1203
+ taskIds.push({ taskId, domain });
1204
+ }
1205
+
1206
+ // Execute all tasks in parallel across domains
1207
+ for (const { taskId, domain } of taskIds) {
1208
+ const promise = this.executeTaskInDomain(taskId, domain);
1209
+ executionPromises.push(promise);
1210
+ }
1211
+
1212
+ // Wait for all tasks to complete (with individual error handling)
1213
+ const settledResults = await Promise.allSettled(executionPromises);
1214
+
1215
+ const results: ParallelExecutionResult[] = [];
1216
+ for (let i = 0; i < settledResults.length; i++) {
1217
+ const result = settledResults[i];
1218
+ const { taskId, domain } = taskIds[i];
1219
+
1220
+ if (result.status === 'fulfilled') {
1221
+ results.push(result.value);
1222
+ } else {
1223
+ results.push({
1224
+ taskId,
1225
+ domain,
1226
+ success: false,
1227
+ error: result.reason instanceof Error ? result.reason : new Error(String(result.reason)),
1228
+ durationMs: performance.now() - startTime,
1229
+ });
1230
+ }
1231
+ }
1232
+
1233
+ this.emitEvent('parallel.execution.completed', {
1234
+ totalTasks: tasks.length,
1235
+ successful: results.filter(r => r.success).length,
1236
+ failed: results.filter(r => !r.success).length,
1237
+ totalDurationMs: performance.now() - startTime,
1238
+ });
1239
+
1240
+ return results;
1241
+ }
1242
+
1243
+ private async executeTaskInDomain(taskId: string, domain: AgentDomain): Promise<ParallelExecutionResult> {
1244
+ const startTime = performance.now();
1245
+
1246
+ try {
1247
+ // Assign to domain
1248
+ const agentId = await this.assignTaskToDomain(taskId, domain);
1249
+ if (!agentId) {
1250
+ // Task was queued, wait for it to be assigned and complete
1251
+ return await this.waitForQueuedTask(taskId, domain, startTime);
1252
+ }
1253
+
1254
+ // Wait for completion
1255
+ const result = await this.waitForTaskCompletion(taskId, this.config.taskTimeoutMs);
1256
+
1257
+ return {
1258
+ taskId,
1259
+ domain,
1260
+ success: result.status === 'completed',
1261
+ result: result.output,
1262
+ durationMs: performance.now() - startTime,
1263
+ };
1264
+ } catch (error) {
1265
+ return {
1266
+ taskId,
1267
+ domain,
1268
+ success: false,
1269
+ error: error instanceof Error ? error : new Error(String(error)),
1270
+ durationMs: performance.now() - startTime,
1271
+ };
1272
+ }
1273
+ }
1274
+
1275
+ private async waitForQueuedTask(
1276
+ taskId: string,
1277
+ domain: AgentDomain,
1278
+ startTime: number
1279
+ ): Promise<ParallelExecutionResult> {
1280
+ return new Promise((resolve) => {
1281
+ const checkInterval = setInterval(() => {
1282
+ const task = this.state.tasks.get(taskId);
1283
+ if (!task) {
1284
+ clearInterval(checkInterval);
1285
+ resolve({
1286
+ taskId,
1287
+ domain,
1288
+ success: false,
1289
+ error: new Error(`Task ${taskId} not found`),
1290
+ durationMs: performance.now() - startTime,
1291
+ });
1292
+ return;
1293
+ }
1294
+
1295
+ if (task.status === 'completed') {
1296
+ clearInterval(checkInterval);
1297
+ resolve({
1298
+ taskId,
1299
+ domain,
1300
+ success: true,
1301
+ result: task.output,
1302
+ durationMs: performance.now() - startTime,
1303
+ });
1304
+ } else if (task.status === 'failed' || task.status === 'cancelled' || task.status === 'timeout') {
1305
+ clearInterval(checkInterval);
1306
+ resolve({
1307
+ taskId,
1308
+ domain,
1309
+ success: false,
1310
+ error: new Error(`Task ${task.status}`),
1311
+ durationMs: performance.now() - startTime,
1312
+ });
1313
+ }
1314
+ }, 100);
1315
+
1316
+ // Timeout after configured duration
1317
+ setTimeout(() => {
1318
+ clearInterval(checkInterval);
1319
+ const task = this.state.tasks.get(taskId);
1320
+ if (task && task.status !== 'completed') {
1321
+ task.status = 'timeout';
1322
+ }
1323
+ resolve({
1324
+ taskId,
1325
+ domain,
1326
+ success: false,
1327
+ error: new Error('Task timed out'),
1328
+ durationMs: performance.now() - startTime,
1329
+ });
1330
+ }, this.config.taskTimeoutMs);
1331
+ });
1332
+ }
1333
+
1334
+ private async waitForTaskCompletion(taskId: string, timeoutMs: number): Promise<TaskDefinition> {
1335
+ return new Promise((resolve, reject) => {
1336
+ const checkInterval = setInterval(() => {
1337
+ const task = this.state.tasks.get(taskId);
1338
+ if (!task) {
1339
+ clearInterval(checkInterval);
1340
+ reject(new Error(`Task ${taskId} not found`));
1341
+ return;
1342
+ }
1343
+
1344
+ if (task.status === 'completed' || task.status === 'failed' || task.status === 'cancelled') {
1345
+ clearInterval(checkInterval);
1346
+ resolve(task);
1347
+ }
1348
+ }, 100);
1349
+
1350
+ setTimeout(() => {
1351
+ clearInterval(checkInterval);
1352
+ const task = this.state.tasks.get(taskId);
1353
+ if (task) {
1354
+ task.status = 'timeout';
1355
+ task.completedAt = new Date();
1356
+ resolve(task);
1357
+ } else {
1358
+ reject(new Error(`Task ${taskId} timed out`));
1359
+ }
1360
+ }, timeoutMs);
1361
+ });
1362
+ }
1363
+
1364
+ /**
1365
+ * Get the current status of all domains
1366
+ */
1367
+ getStatus(): {
1368
+ swarmId: SwarmId;
1369
+ status: SwarmStatus;
1370
+ topology: TopologyType;
1371
+ domains: DomainStatus[];
1372
+ metrics: CoordinatorMetrics;
1373
+ } {
1374
+ const domains: DomainStatus[] = [];
1375
+
1376
+ for (const [domain, config] of this.domainConfigs) {
1377
+ const pool = this.domainPools.get(domain);
1378
+ const stats = pool?.getPoolStats();
1379
+ const queue = this.domainTaskQueues.get(domain) || [];
1380
+
1381
+ const completedTasks = Array.from(this.taskAssignments.values())
1382
+ .filter(a => a.domain === domain)
1383
+ .map(a => this.state.tasks.get(a.taskId))
1384
+ .filter(t => t?.status === 'completed')
1385
+ .length;
1386
+
1387
+ domains.push({
1388
+ name: domain,
1389
+ agentCount: stats?.total ?? 0,
1390
+ availableAgents: stats?.available ?? 0,
1391
+ busyAgents: stats?.busy ?? 0,
1392
+ tasksQueued: queue.length,
1393
+ tasksCompleted: completedTasks,
1394
+ });
1395
+ }
1396
+
1397
+ return {
1398
+ swarmId: this.state.id,
1399
+ status: this.state.status,
1400
+ topology: this.config.topology.type,
1401
+ domains,
1402
+ metrics: this.getMetrics(),
1403
+ };
1404
+ }
1405
+
1406
+ /**
1407
+ * Register an agent and automatically assign it to the appropriate domain
1408
+ * based on its agent number (1-15)
1409
+ */
1410
+ async registerAgentWithDomain(
1411
+ agentData: Omit<AgentState, 'id'>,
1412
+ agentNumber: number
1413
+ ): Promise<{ agentId: string; domain: AgentDomain }> {
1414
+ // First register the agent normally
1415
+ const agentId = await this.registerAgent(agentData);
1416
+
1417
+ // Determine domain based on agent number
1418
+ const domain = this.getAgentDomain(agentNumber);
1419
+
1420
+ // Add to domain tracking
1421
+ this.agentDomainMap.set(agentId, domain);
1422
+
1423
+ // Add to domain pool
1424
+ const pool = this.domainPools.get(domain);
1425
+ const agent = this.state.agents.get(agentId);
1426
+ if (pool && agent) {
1427
+ await pool.add(agent);
1428
+ }
1429
+
1430
+ this.emitEvent('agent.domain_assigned', {
1431
+ agentId,
1432
+ agentNumber,
1433
+ domain,
1434
+ });
1435
+
1436
+ return { agentId, domain };
1437
+ }
1438
+
1439
+ /**
1440
+ * Get the domain for a given agent number (1-15)
1441
+ */
1442
+ getAgentDomain(agentNumber: number): AgentDomain {
1443
+ for (const [domain, config] of this.domainConfigs) {
1444
+ if (config.agentNumbers.includes(agentNumber)) {
1445
+ return domain;
1446
+ }
1447
+ }
1448
+ return 'core'; // Default to core domain
1449
+ }
1450
+
1451
+ /**
1452
+ * Spawn the full 15-agent hierarchy
1453
+ * Returns a map of agent numbers to their IDs and domains
1454
+ */
1455
+ async spawnFullHierarchy(): Promise<Map<number, { agentId: string; domain: AgentDomain }>> {
1456
+ const results = new Map<number, { agentId: string; domain: AgentDomain }>();
1457
+
1458
+ for (const [domain, config] of this.domainConfigs) {
1459
+ for (const agentNumber of config.agentNumbers) {
1460
+ const agentType = this.domainToAgentType(domain);
1461
+
1462
+ const agentData: Omit<AgentState, 'id'> = {
1463
+ name: `${domain}-agent-${agentNumber}`,
1464
+ type: agentType,
1465
+ status: 'idle',
1466
+ capabilities: this.createDomainCapabilities(domain),
1467
+ metrics: this.createDefaultAgentMetrics(),
1468
+ workload: 0,
1469
+ health: 1.0,
1470
+ lastHeartbeat: new Date(),
1471
+ topologyRole: domain === 'queen' ? 'queen' : 'worker',
1472
+ connections: [],
1473
+ };
1474
+
1475
+ const result = await this.registerAgentWithDomain(agentData, agentNumber);
1476
+ results.set(agentNumber, result);
1477
+ }
1478
+ }
1479
+
1480
+ this.emitEvent('hierarchy.spawned', {
1481
+ totalAgents: results.size,
1482
+ domains: Array.from(this.domainConfigs.keys()),
1483
+ });
1484
+
1485
+ return results;
1486
+ }
1487
+
1488
+ private createDomainCapabilities(domain: AgentDomain): AgentCapabilities {
1489
+ const domainConfig = this.domainConfigs.get(domain);
1490
+ const capabilities = domainConfig?.capabilities || [];
1491
+
1492
+ return {
1493
+ codeGeneration: domain === 'core' || domain === 'integration',
1494
+ codeReview: domain === 'security' || domain === 'core',
1495
+ testing: domain === 'support' || domain === 'security',
1496
+ documentation: true,
1497
+ research: true,
1498
+ analysis: true,
1499
+ coordination: domain === 'queen',
1500
+ languages: ['typescript', 'javascript', 'python'],
1501
+ frameworks: ['node', 'react', 'vitest'],
1502
+ domains: capabilities,
1503
+ tools: ['git', 'npm', 'editor', 'claude'],
1504
+ maxConcurrentTasks: domain === 'queen' ? 1 : 3,
1505
+ maxMemoryUsage: 512 * 1024 * 1024,
1506
+ maxExecutionTime: SWARM_CONSTANTS.DEFAULT_TASK_TIMEOUT_MS,
1507
+ reliability: 0.95,
1508
+ speed: 1.0,
1509
+ quality: 0.9,
1510
+ };
1511
+ }
1512
+
1513
+ private createDefaultAgentMetrics(): AgentMetrics {
1514
+ return {
1515
+ tasksCompleted: 0,
1516
+ tasksFailed: 0,
1517
+ averageExecutionTime: 0,
1518
+ successRate: 1.0,
1519
+ cpuUsage: 0,
1520
+ memoryUsage: 0,
1521
+ messagesProcessed: 0,
1522
+ lastActivity: new Date(),
1523
+ responseTime: 0,
1524
+ health: 1.0,
1525
+ };
1526
+ }
1527
+
1528
+ /**
1529
+ * Get the domain pool for a specific domain
1530
+ */
1531
+ getDomainPool(domain: AgentDomain): AgentPool | undefined {
1532
+ return this.domainPools.get(domain);
1533
+ }
1534
+
1535
+ /**
1536
+ * Get all domain configurations
1537
+ */
1538
+ getDomainConfigs(): Map<AgentDomain, DomainConfig> {
1539
+ return new Map(this.domainConfigs);
1540
+ }
1541
+
1542
+ /**
1543
+ * Release an agent back to its domain pool after task completion
1544
+ */
1545
+ async releaseAgentToDomain(agentId: string): Promise<void> {
1546
+ const domain = this.agentDomainMap.get(agentId);
1547
+ if (!domain) return;
1548
+
1549
+ const pool = this.domainPools.get(domain);
1550
+ if (pool) {
1551
+ await pool.release(agentId);
1552
+ }
1553
+
1554
+ // Check if there are queued tasks for this domain
1555
+ const queue = this.domainTaskQueues.get(domain) || [];
1556
+ if (queue.length > 0) {
1557
+ const nextTaskId = queue.shift()!;
1558
+ this.domainTaskQueues.set(domain, queue);
1559
+ await this.assignTaskToDomain(nextTaskId, domain);
1560
+ }
1561
+ }
1562
+
1563
+ // =============================================================================
1564
+ // MCP-Compatible API Methods (@sparkleideas/agentic-flow@alpha compatibility)
1565
+ // =============================================================================
1566
+
1567
+ /**
1568
+ * Spawn a new agent (MCP-compatible alias for registerAgent)
1569
+ * Compatible with @sparkleideas/agentic-flow@alpha's agent spawn API
1570
+ *
1571
+ * @param options - Agent spawn options
1572
+ * @returns Spawned agent ID and details
1573
+ */
1574
+ async spawnAgent(options: {
1575
+ type: AgentType;
1576
+ name?: string;
1577
+ capabilities?: string[];
1578
+ domain?: AgentDomain;
1579
+ agentNumber?: number;
1580
+ metadata?: Record<string, unknown>;
1581
+ }): Promise<{
1582
+ agentId: string;
1583
+ domain: AgentDomain;
1584
+ status: AgentStatus;
1585
+ spawned: boolean;
1586
+ }> {
1587
+ const startTime = performance.now();
1588
+
1589
+ // Create agent data from options
1590
+ const agentData: Omit<AgentState, 'id'> = {
1591
+ name: options.name || `${options.type}-agent-${this.agentCounter + 1}`,
1592
+ type: options.type,
1593
+ status: 'idle',
1594
+ capabilities: this.createCapabilitiesFromList(options.capabilities || []),
1595
+ metrics: this.createDefaultAgentMetrics(),
1596
+ workload: 0,
1597
+ health: 1.0,
1598
+ lastHeartbeat: new Date(),
1599
+ topologyRole: options.type === 'queen' ? 'queen' : 'worker',
1600
+ connections: [],
1601
+ };
1602
+
1603
+ // Determine domain and agent number
1604
+ let domain: AgentDomain;
1605
+ let agentId: string;
1606
+
1607
+ if (options.agentNumber) {
1608
+ // Use provided agent number to determine domain
1609
+ const result = await this.registerAgentWithDomain(agentData, options.agentNumber);
1610
+ agentId = result.agentId;
1611
+ domain = result.domain;
1612
+ } else if (options.domain) {
1613
+ // Use provided domain, assign next available number in that domain
1614
+ const config = this.domainConfigs.get(options.domain);
1615
+ const existingAgents = Array.from(this.agentDomainMap.entries())
1616
+ .filter(([, d]) => d === options.domain)
1617
+ .length;
1618
+ const nextNumber = config?.agentNumbers[existingAgents] || config?.agentNumbers[0] || 1;
1619
+ const result = await this.registerAgentWithDomain(agentData, nextNumber);
1620
+ agentId = result.agentId;
1621
+ domain = result.domain;
1622
+ } else {
1623
+ // Auto-assign to most appropriate domain based on type
1624
+ domain = this.agentTypeToDomain(options.type);
1625
+ agentId = await this.registerAgent(agentData);
1626
+ this.agentDomainMap.set(agentId, domain);
1627
+ }
1628
+
1629
+ const duration = performance.now() - startTime;
1630
+
1631
+ this.emitEvent('agent.joined', {
1632
+ agentId,
1633
+ type: options.type,
1634
+ domain,
1635
+ durationMs: duration,
1636
+ });
1637
+
1638
+ return {
1639
+ agentId,
1640
+ domain,
1641
+ status: 'idle',
1642
+ spawned: true,
1643
+ };
1644
+ }
1645
+
1646
+ /**
1647
+ * Terminate an agent (MCP-compatible alias for unregisterAgent)
1648
+ * Compatible with @sparkleideas/agentic-flow@alpha's agent terminate API
1649
+ *
1650
+ * @param agentId - Agent ID to terminate
1651
+ * @param options - Termination options
1652
+ * @returns Termination result
1653
+ */
1654
+ async terminateAgent(
1655
+ agentId: string,
1656
+ options?: {
1657
+ force?: boolean;
1658
+ reason?: string;
1659
+ gracePeriodMs?: number;
1660
+ }
1661
+ ): Promise<{
1662
+ terminated: boolean;
1663
+ agentId: string;
1664
+ reason?: string;
1665
+ tasksReassigned?: number;
1666
+ }> {
1667
+ const agent = this.state.agents.get(agentId);
1668
+ if (!agent) {
1669
+ return {
1670
+ terminated: false,
1671
+ agentId,
1672
+ reason: 'Agent not found',
1673
+ };
1674
+ }
1675
+
1676
+ // If agent has active tasks and not forcing, wait or reassign
1677
+ let tasksReassigned = 0;
1678
+ if (agent.currentTask && !options?.force) {
1679
+ const gracePeriodMs = options?.gracePeriodMs || 5000;
1680
+
1681
+ // Wait for grace period or force terminate
1682
+ const task = agent.currentTask;
1683
+ await new Promise(resolve => setTimeout(resolve, gracePeriodMs));
1684
+
1685
+ // Check if task still running
1686
+ const currentAgent = this.state.agents.get(agentId);
1687
+ if (currentAgent?.currentTask?.id === task.id) {
1688
+ // Reassign the task
1689
+ await this.cancelTask(task.id);
1690
+ tasksReassigned = 1;
1691
+ }
1692
+ }
1693
+
1694
+ // Remove from domain tracking
1695
+ this.agentDomainMap.delete(agentId);
1696
+
1697
+ // Unregister the agent
1698
+ await this.unregisterAgent(agentId);
1699
+
1700
+ this.emitEvent('agent.left', {
1701
+ agentId,
1702
+ reason: options?.reason || 'manual termination',
1703
+ tasksReassigned,
1704
+ });
1705
+
1706
+ return {
1707
+ terminated: true,
1708
+ agentId,
1709
+ reason: options?.reason || 'manual termination',
1710
+ tasksReassigned,
1711
+ };
1712
+ }
1713
+
1714
+ /**
1715
+ * Get agent status by ID (MCP-compatible)
1716
+ */
1717
+ async getAgentStatus(agentId: string): Promise<{
1718
+ found: boolean;
1719
+ agentId: string;
1720
+ status?: AgentStatus;
1721
+ domain?: AgentDomain;
1722
+ workload?: number;
1723
+ health?: number;
1724
+ currentTask?: string;
1725
+ metrics?: AgentMetrics;
1726
+ }> {
1727
+ const agent = this.state.agents.get(agentId);
1728
+ if (!agent) {
1729
+ return { found: false, agentId };
1730
+ }
1731
+
1732
+ const domain = this.agentDomainMap.get(agentId);
1733
+
1734
+ return {
1735
+ found: true,
1736
+ agentId,
1737
+ status: agent.status,
1738
+ domain,
1739
+ workload: agent.workload,
1740
+ health: agent.health,
1741
+ currentTask: agent.currentTask?.id,
1742
+ metrics: agent.metrics,
1743
+ };
1744
+ }
1745
+
1746
+ /**
1747
+ * List all agents with optional filters (MCP-compatible)
1748
+ */
1749
+ listAgents(filters?: {
1750
+ status?: AgentStatus;
1751
+ domain?: AgentDomain;
1752
+ type?: AgentType;
1753
+ available?: boolean;
1754
+ }): Array<{
1755
+ agentId: string;
1756
+ name: string;
1757
+ type: AgentType;
1758
+ status: AgentStatus;
1759
+ domain?: AgentDomain;
1760
+ workload: number;
1761
+ health: number;
1762
+ }> {
1763
+ let agents = this.getAllAgents();
1764
+
1765
+ if (filters?.status) {
1766
+ agents = agents.filter(a => a.status === filters.status);
1767
+ }
1768
+ if (filters?.type) {
1769
+ agents = agents.filter(a => a.type === filters.type);
1770
+ }
1771
+ if (filters?.available) {
1772
+ agents = agents.filter(a => a.status === 'idle');
1773
+ }
1774
+ if (filters?.domain) {
1775
+ agents = agents.filter(a => {
1776
+ const domain = this.agentDomainMap.get(a.id.id);
1777
+ return domain === filters.domain;
1778
+ });
1779
+ }
1780
+
1781
+ return agents.map(a => ({
1782
+ agentId: a.id.id,
1783
+ name: a.name,
1784
+ type: a.type,
1785
+ status: a.status,
1786
+ domain: this.agentDomainMap.get(a.id.id),
1787
+ workload: a.workload,
1788
+ health: a.health,
1789
+ }));
1790
+ }
1791
+
1792
+ // =============================================================================
1793
+ // Helper Methods for MCP API
1794
+ // =============================================================================
1795
+
1796
+ private createCapabilitiesFromList(capabilities: string[]): AgentCapabilities {
1797
+ return {
1798
+ codeGeneration: capabilities.includes('code-generation'),
1799
+ codeReview: capabilities.includes('code-review'),
1800
+ testing: capabilities.includes('testing'),
1801
+ documentation: capabilities.includes('documentation'),
1802
+ research: capabilities.includes('research'),
1803
+ analysis: capabilities.includes('analysis'),
1804
+ coordination: capabilities.includes('coordination'),
1805
+ languages: ['typescript', 'javascript', 'python'],
1806
+ frameworks: ['node', 'react', 'vitest'],
1807
+ domains: capabilities,
1808
+ tools: ['git', 'npm', 'editor', 'claude'],
1809
+ maxConcurrentTasks: 3,
1810
+ maxMemoryUsage: 512 * 1024 * 1024,
1811
+ maxExecutionTime: SWARM_CONSTANTS.DEFAULT_TASK_TIMEOUT_MS,
1812
+ reliability: 0.95,
1813
+ speed: 1.0,
1814
+ quality: 0.9,
1815
+ };
1816
+ }
1817
+
1818
+ private agentTypeToDomain(type: AgentType): AgentDomain {
1819
+ const typeMapping: Record<string, AgentDomain> = {
1820
+ queen: 'queen',
1821
+ coordinator: 'queen',
1822
+ security: 'security',
1823
+ architect: 'core',
1824
+ coder: 'core',
1825
+ developer: 'core',
1826
+ tester: 'support',
1827
+ reviewer: 'security',
1828
+ researcher: 'integration',
1829
+ analyst: 'core',
1830
+ optimizer: 'support',
1831
+ documenter: 'support',
1832
+ monitor: 'support',
1833
+ specialist: 'core',
1834
+ worker: 'core',
1835
+ };
1836
+ return typeMapping[type as string] || 'core';
1837
+ }
1838
+ }
1839
+
1840
+ export function createUnifiedSwarmCoordinator(
1841
+ config?: Partial<CoordinatorConfig>
1842
+ ): UnifiedSwarmCoordinator {
1843
+ return new UnifiedSwarmCoordinator(config);
1844
+ }