@sparkleideas/testing 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 (42) hide show
  1. package/README.md +547 -0
  2. package/__tests__/framework.test.ts +21 -0
  3. package/package.json +61 -0
  4. package/src/fixtures/agent-fixtures.ts +793 -0
  5. package/src/fixtures/agents.ts +212 -0
  6. package/src/fixtures/configurations.ts +491 -0
  7. package/src/fixtures/index.ts +21 -0
  8. package/src/fixtures/mcp-fixtures.ts +1030 -0
  9. package/src/fixtures/memory-entries.ts +328 -0
  10. package/src/fixtures/memory-fixtures.ts +750 -0
  11. package/src/fixtures/swarm-fixtures.ts +837 -0
  12. package/src/fixtures/tasks.ts +309 -0
  13. package/src/helpers/assertion-helpers.ts +616 -0
  14. package/src/helpers/assertions.ts +286 -0
  15. package/src/helpers/create-mock.ts +200 -0
  16. package/src/helpers/index.ts +182 -0
  17. package/src/helpers/mock-factory.ts +711 -0
  18. package/src/helpers/setup-teardown.ts +678 -0
  19. package/src/helpers/swarm-instance.ts +326 -0
  20. package/src/helpers/test-application.ts +310 -0
  21. package/src/helpers/test-utils.ts +670 -0
  22. package/src/index.ts +232 -0
  23. package/src/mocks/index.ts +29 -0
  24. package/src/mocks/mock-mcp-client.ts +723 -0
  25. package/src/mocks/mock-services.ts +793 -0
  26. package/src/regression/api-contract.ts +473 -0
  27. package/src/regression/index.ts +46 -0
  28. package/src/regression/integration-regression.ts +416 -0
  29. package/src/regression/performance-baseline.ts +356 -0
  30. package/src/regression/regression-runner.ts +339 -0
  31. package/src/regression/security-regression.ts +331 -0
  32. package/src/setup.ts +127 -0
  33. package/src/v2-compat/api-compat.test.ts +590 -0
  34. package/src/v2-compat/cli-compat.test.ts +484 -0
  35. package/src/v2-compat/compatibility-validator.ts +1072 -0
  36. package/src/v2-compat/hooks-compat.test.ts +602 -0
  37. package/src/v2-compat/index.ts +58 -0
  38. package/src/v2-compat/mcp-compat.test.ts +557 -0
  39. package/src/v2-compat/report-generator.ts +441 -0
  40. package/tmp.json +0 -0
  41. package/tsconfig.json +20 -0
  42. package/vitest.config.ts +12 -0
@@ -0,0 +1,793 @@
1
+ /**
2
+ * @sparkleideas/testing - Mock Services
3
+ *
4
+ * Comprehensive mock implementations of V3 core services.
5
+ * Provides realistic behavior for testing with full state tracking.
6
+ */
7
+ import { vi, type Mock } from 'vitest';
8
+ import type { V3AgentType } from '../fixtures/agent-fixtures.js';
9
+
10
+ /**
11
+ * Mock AgentDB - Vector database mock with HNSW simulation
12
+ */
13
+ export class MockAgentDB {
14
+ private vectors = new Map<string, { embedding: number[]; metadata: Record<string, unknown> }>();
15
+ private indexConfig = {
16
+ M: 16,
17
+ efConstruction: 200,
18
+ efSearch: 50,
19
+ dimensions: 384,
20
+ };
21
+
22
+ // Mock methods for verification
23
+ insert = vi.fn(async (id: string, embedding: number[], metadata?: Record<string, unknown>) => {
24
+ if (embedding.length !== this.indexConfig.dimensions) {
25
+ throw new Error(`Invalid embedding dimensions: expected ${this.indexConfig.dimensions}, got ${embedding.length}`);
26
+ }
27
+ this.vectors.set(id, { embedding, metadata: metadata ?? {} });
28
+ });
29
+
30
+ search = vi.fn(async (embedding: number[], k: number, threshold?: number) => {
31
+ const results: Array<{ id: string; score: number; metadata: Record<string, unknown> }> = [];
32
+
33
+ for (const [id, data] of this.vectors) {
34
+ const score = this.cosineSimilarity(embedding, data.embedding);
35
+ if (threshold === undefined || score >= threshold) {
36
+ results.push({ id, score, metadata: data.metadata });
37
+ }
38
+ }
39
+
40
+ return results
41
+ .sort((a, b) => b.score - a.score)
42
+ .slice(0, k);
43
+ });
44
+
45
+ delete = vi.fn(async (id: string) => {
46
+ this.vectors.delete(id);
47
+ });
48
+
49
+ update = vi.fn(async (id: string, embedding: number[], metadata?: Record<string, unknown>) => {
50
+ const existing = this.vectors.get(id);
51
+ if (!existing) {
52
+ throw new Error(`Vector not found: ${id}`);
53
+ }
54
+ this.vectors.set(id, { embedding, metadata: metadata ?? existing.metadata });
55
+ });
56
+
57
+ getVector = vi.fn(async (id: string) => {
58
+ return this.vectors.get(id) ?? null;
59
+ });
60
+
61
+ getStats = vi.fn(() => ({
62
+ vectorCount: this.vectors.size,
63
+ indexSize: this.vectors.size * this.indexConfig.dimensions * 4, // 4 bytes per float
64
+ dimensions: this.indexConfig.dimensions,
65
+ M: this.indexConfig.M,
66
+ efConstruction: this.indexConfig.efConstruction,
67
+ }));
68
+
69
+ rebuildIndex = vi.fn(async () => {
70
+ // Simulate index rebuild
71
+ await new Promise(resolve => setTimeout(resolve, 10));
72
+ });
73
+
74
+ clear = vi.fn(() => {
75
+ this.vectors.clear();
76
+ });
77
+
78
+ private cosineSimilarity(a: number[], b: number[]): number {
79
+ let dotProduct = 0;
80
+ let normA = 0;
81
+ let normB = 0;
82
+
83
+ for (let i = 0; i < a.length; i++) {
84
+ dotProduct += a[i] * b[i];
85
+ normA += a[i] * a[i];
86
+ normB += b[i] * b[i];
87
+ }
88
+
89
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
90
+ }
91
+
92
+ /**
93
+ * Configure the mock index
94
+ */
95
+ configure(config: Partial<typeof this.indexConfig>): void {
96
+ Object.assign(this.indexConfig, config);
97
+ }
98
+
99
+ /**
100
+ * Get all stored vectors (for testing)
101
+ */
102
+ getAllVectors(): Map<string, { embedding: number[]; metadata: Record<string, unknown> }> {
103
+ return new Map(this.vectors);
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Mock Unified Swarm Coordinator
109
+ */
110
+ export class MockSwarmCoordinator {
111
+ private agents = new Map<string, MockSwarmAgent>();
112
+ private state: SwarmState = {
113
+ id: `swarm-${Date.now()}`,
114
+ topology: 'hierarchical-mesh',
115
+ status: 'idle',
116
+ agentCount: 0,
117
+ activeAgentCount: 0,
118
+ leaderId: undefined,
119
+ createdAt: new Date(),
120
+ };
121
+ private messageQueue: SwarmMessage[] = [];
122
+ private taskQueue: SwarmTask[] = [];
123
+
124
+ initialize = vi.fn(async (config: SwarmInitConfig) => {
125
+ this.state = {
126
+ ...this.state,
127
+ topology: config.topology ?? 'hierarchical-mesh',
128
+ status: 'active',
129
+ };
130
+ return this.state;
131
+ });
132
+
133
+ shutdown = vi.fn(async (graceful: boolean = true) => {
134
+ if (graceful) {
135
+ // Complete pending tasks
136
+ await Promise.all(
137
+ Array.from(this.agents.values()).map(agent => agent.terminate())
138
+ );
139
+ }
140
+ this.state.status = 'shutdown';
141
+ this.agents.clear();
142
+ });
143
+
144
+ addAgent = vi.fn(async (config: AgentConfig) => {
145
+ const id = `agent-${config.type}-${Date.now()}`;
146
+ const agent = new MockSwarmAgent(id, config);
147
+ this.agents.set(id, agent);
148
+ this.state.agentCount++;
149
+ this.state.activeAgentCount++;
150
+
151
+ if (config.type === 'queen-coordinator' && !this.state.leaderId) {
152
+ this.state.leaderId = id;
153
+ }
154
+
155
+ return agent;
156
+ });
157
+
158
+ removeAgent = vi.fn(async (agentId: string) => {
159
+ const agent = this.agents.get(agentId);
160
+ if (agent) {
161
+ await agent.terminate();
162
+ this.agents.delete(agentId);
163
+ this.state.agentCount--;
164
+ this.state.activeAgentCount--;
165
+
166
+ if (this.state.leaderId === agentId) {
167
+ this.electNewLeader();
168
+ }
169
+ }
170
+ });
171
+
172
+ coordinate = vi.fn(async (task: SwarmTask) => {
173
+ this.taskQueue.push(task);
174
+
175
+ // Find suitable agents
176
+ const suitableAgents = Array.from(this.agents.values())
177
+ .filter(agent => agent.canHandle(task.type))
178
+ .sort((a, b) => b.priority - a.priority);
179
+
180
+ if (suitableAgents.length === 0) {
181
+ return {
182
+ success: false,
183
+ error: 'No suitable agents available',
184
+ taskId: task.id,
185
+ duration: 0,
186
+ };
187
+ }
188
+
189
+ const startTime = Date.now();
190
+ const results: TaskResult[] = [];
191
+
192
+ for (const agent of suitableAgents.slice(0, task.maxAgents ?? 1)) {
193
+ const result = await agent.execute(task);
194
+ results.push(result);
195
+ }
196
+
197
+ return {
198
+ success: results.every(r => r.success),
199
+ taskId: task.id,
200
+ duration: Date.now() - startTime,
201
+ results,
202
+ };
203
+ });
204
+
205
+ broadcast = vi.fn(async (message: Omit<SwarmMessage, 'id' | 'timestamp'>) => {
206
+ const fullMessage: SwarmMessage = {
207
+ ...message,
208
+ id: `msg-${Date.now()}`,
209
+ timestamp: new Date(),
210
+ to: 'broadcast',
211
+ };
212
+ this.messageQueue.push(fullMessage);
213
+
214
+ for (const agent of this.agents.values()) {
215
+ await agent.receive(fullMessage);
216
+ }
217
+ });
218
+
219
+ sendMessage = vi.fn(async (message: SwarmMessage) => {
220
+ this.messageQueue.push(message);
221
+
222
+ if (message.to === 'broadcast') {
223
+ for (const agent of this.agents.values()) {
224
+ await agent.receive(message);
225
+ }
226
+ } else {
227
+ const agent = this.agents.get(message.to);
228
+ if (agent) {
229
+ await agent.receive(message);
230
+ }
231
+ }
232
+ });
233
+
234
+ requestConsensus = vi.fn(async <T>(request: ConsensusRequest<T>): Promise<ConsensusResponse<T>> => {
235
+ const voters = request.voters ?? Array.from(this.agents.keys());
236
+ const votes = new Map<string, T>();
237
+
238
+ for (const voterId of voters) {
239
+ const agent = this.agents.get(voterId);
240
+ if (agent) {
241
+ // Simulate voting - random selection
242
+ const vote = request.options[Math.floor(Math.random() * request.options.length)];
243
+ votes.set(voterId, vote);
244
+ }
245
+ }
246
+
247
+ const voteCounts = new Map<string, number>();
248
+ for (const vote of votes.values()) {
249
+ const key = JSON.stringify(vote);
250
+ voteCounts.set(key, (voteCounts.get(key) ?? 0) + 1);
251
+ }
252
+
253
+ const majority = Math.floor(voters.length / 2) + 1;
254
+ let decision: T | null = null;
255
+ let consensus = false;
256
+
257
+ for (const [key, count] of voteCounts) {
258
+ if (count >= majority) {
259
+ decision = JSON.parse(key);
260
+ consensus = true;
261
+ break;
262
+ }
263
+ }
264
+
265
+ return {
266
+ topic: request.topic,
267
+ decision,
268
+ votes,
269
+ consensus,
270
+ votingDuration: 100,
271
+ participatingAgents: Array.from(votes.keys()),
272
+ };
273
+ });
274
+
275
+ getState = vi.fn(() => ({ ...this.state }));
276
+
277
+ getAgent = vi.fn((id: string) => this.agents.get(id));
278
+
279
+ getAgents = vi.fn(() => Array.from(this.agents.values()));
280
+
281
+ getMessageQueue = vi.fn(() => [...this.messageQueue]);
282
+
283
+ getTaskQueue = vi.fn(() => [...this.taskQueue]);
284
+
285
+ private electNewLeader(): void {
286
+ const candidates = Array.from(this.agents.values())
287
+ .filter(a => a.config.type === 'queen-coordinator')
288
+ .sort((a, b) => b.priority - a.priority);
289
+
290
+ this.state.leaderId = candidates[0]?.id;
291
+ }
292
+
293
+ reset(): void {
294
+ this.agents.clear();
295
+ this.messageQueue = [];
296
+ this.taskQueue = [];
297
+ this.state = {
298
+ id: `swarm-${Date.now()}`,
299
+ topology: 'hierarchical-mesh',
300
+ status: 'idle',
301
+ agentCount: 0,
302
+ activeAgentCount: 0,
303
+ leaderId: undefined,
304
+ createdAt: new Date(),
305
+ };
306
+ vi.clearAllMocks();
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Mock Swarm Agent
312
+ */
313
+ export class MockSwarmAgent {
314
+ readonly id: string;
315
+ readonly config: AgentConfig;
316
+ status: 'idle' | 'busy' | 'terminated' = 'idle';
317
+ priority: number;
318
+ private messages: SwarmMessage[] = [];
319
+ private taskResults: TaskResult[] = [];
320
+
321
+ execute = vi.fn();
322
+ receive = vi.fn();
323
+ send = vi.fn();
324
+ terminate = vi.fn();
325
+
326
+ constructor(id: string, config: AgentConfig) {
327
+ this.id = id;
328
+ this.config = config;
329
+ this.priority = config.priority ?? 50;
330
+
331
+ this.execute.mockImplementation(async (task: SwarmTask) => {
332
+ this.status = 'busy';
333
+ await new Promise(resolve => setTimeout(resolve, 10));
334
+ this.status = 'idle';
335
+
336
+ const result: TaskResult = {
337
+ taskId: task.id,
338
+ agentId: this.id,
339
+ success: true,
340
+ duration: Math.random() * 100 + 10,
341
+ };
342
+ this.taskResults.push(result);
343
+ return result;
344
+ });
345
+
346
+ this.receive.mockImplementation(async (message: SwarmMessage) => {
347
+ this.messages.push(message);
348
+ });
349
+
350
+ this.send.mockImplementation(async () => {});
351
+
352
+ this.terminate.mockImplementation(async () => {
353
+ this.status = 'terminated';
354
+ });
355
+ }
356
+
357
+ canHandle(taskType: string): boolean {
358
+ const capabilities = agentCapabilities[this.config.type] ?? [];
359
+ return capabilities.some(cap =>
360
+ cap.includes(taskType) || taskType.includes(cap)
361
+ );
362
+ }
363
+
364
+ getMessages(): SwarmMessage[] {
365
+ return [...this.messages];
366
+ }
367
+
368
+ getTaskResults(): TaskResult[] {
369
+ return [...this.taskResults];
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Mock Memory Service with caching
375
+ */
376
+ export class MockMemoryService {
377
+ private store = new Map<string, { value: unknown; metadata: MemoryMetadata; expiresAt?: Date }>();
378
+ private cache = new Map<string, { value: unknown; accessCount: number }>();
379
+ private cacheHits = 0;
380
+ private cacheMisses = 0;
381
+
382
+ set = vi.fn(async (key: string, value: unknown, metadata?: MemoryMetadata) => {
383
+ const expiresAt = metadata?.ttl ? new Date(Date.now() + metadata.ttl) : undefined;
384
+ this.store.set(key, { value, metadata: metadata ?? { type: 'short-term', tags: [] }, expiresAt });
385
+ this.cache.delete(key); // Invalidate cache
386
+ });
387
+
388
+ get = vi.fn(async (key: string) => {
389
+ // Check cache first
390
+ const cached = this.cache.get(key);
391
+ if (cached) {
392
+ this.cacheHits++;
393
+ cached.accessCount++;
394
+ return cached.value;
395
+ }
396
+
397
+ this.cacheMisses++;
398
+ const entry = this.store.get(key);
399
+
400
+ if (!entry) {
401
+ return null;
402
+ }
403
+
404
+ // Check expiration
405
+ if (entry.expiresAt && entry.expiresAt < new Date()) {
406
+ this.store.delete(key);
407
+ return null;
408
+ }
409
+
410
+ // Add to cache
411
+ this.cache.set(key, { value: entry.value, accessCount: 1 });
412
+
413
+ return entry.value;
414
+ });
415
+
416
+ delete = vi.fn(async (key: string) => {
417
+ this.store.delete(key);
418
+ this.cache.delete(key);
419
+ });
420
+
421
+ search = vi.fn(async (query: VectorSearchQuery) => {
422
+ // Simulate vector search with filtering
423
+ const results: SearchResult[] = [];
424
+
425
+ for (const [key, entry] of this.store) {
426
+ if (query.filters) {
427
+ const matches = Object.entries(query.filters).every(([k, v]) =>
428
+ entry.metadata[k as keyof MemoryMetadata] === v
429
+ );
430
+ if (!matches) continue;
431
+ }
432
+
433
+ results.push({
434
+ key,
435
+ value: entry.value,
436
+ score: Math.random() * 0.3 + 0.7, // Random score 0.7-1.0
437
+ metadata: entry.metadata,
438
+ });
439
+ }
440
+
441
+ return results
442
+ .filter(r => !query.threshold || r.score >= query.threshold)
443
+ .sort((a, b) => b.score - a.score)
444
+ .slice(0, query.topK);
445
+ });
446
+
447
+ clear = vi.fn(async () => {
448
+ this.store.clear();
449
+ this.cache.clear();
450
+ });
451
+
452
+ getStats = vi.fn(() => ({
453
+ totalEntries: this.store.size,
454
+ cacheSize: this.cache.size,
455
+ cacheHitRate: this.cacheHits / (this.cacheHits + this.cacheMisses) || 0,
456
+ cacheHits: this.cacheHits,
457
+ cacheMisses: this.cacheMisses,
458
+ }));
459
+
460
+ prune = vi.fn(async () => {
461
+ const now = new Date();
462
+ let pruned = 0;
463
+
464
+ for (const [key, entry] of this.store) {
465
+ if (entry.expiresAt && entry.expiresAt < now) {
466
+ this.store.delete(key);
467
+ this.cache.delete(key);
468
+ pruned++;
469
+ }
470
+ }
471
+
472
+ return pruned;
473
+ });
474
+
475
+ reset(): void {
476
+ this.store.clear();
477
+ this.cache.clear();
478
+ this.cacheHits = 0;
479
+ this.cacheMisses = 0;
480
+ vi.clearAllMocks();
481
+ }
482
+ }
483
+
484
+ /**
485
+ * Mock Event Bus with history tracking
486
+ */
487
+ export class MockEventBus {
488
+ private subscribers = new Map<string, Set<EventHandler>>();
489
+ private history: DomainEvent[] = [];
490
+ private maxHistorySize = 1000;
491
+
492
+ publish = vi.fn(async (event: DomainEvent) => {
493
+ this.history.push(event);
494
+ if (this.history.length > this.maxHistorySize) {
495
+ this.history.shift();
496
+ }
497
+
498
+ const handlers = this.subscribers.get(event.type) ?? new Set();
499
+ const wildcardHandlers = this.subscribers.get('*') ?? new Set();
500
+
501
+ const allHandlers = [...handlers, ...wildcardHandlers];
502
+
503
+ await Promise.all(allHandlers.map(handler => handler(event)));
504
+ });
505
+
506
+ subscribe = vi.fn((eventType: string, handler: EventHandler) => {
507
+ if (!this.subscribers.has(eventType)) {
508
+ this.subscribers.set(eventType, new Set());
509
+ }
510
+ this.subscribers.get(eventType)!.add(handler);
511
+
512
+ return () => this.unsubscribe(eventType, handler);
513
+ });
514
+
515
+ unsubscribe = vi.fn((eventType: string, handler: EventHandler) => {
516
+ this.subscribers.get(eventType)?.delete(handler);
517
+ });
518
+
519
+ getHistory(eventType?: string): DomainEvent[] {
520
+ if (eventType) {
521
+ return this.history.filter(e => e.type === eventType);
522
+ }
523
+ return [...this.history];
524
+ }
525
+
526
+ getSubscriberCount(eventType: string): number {
527
+ return this.subscribers.get(eventType)?.size ?? 0;
528
+ }
529
+
530
+ clear(): void {
531
+ this.history = [];
532
+ vi.clearAllMocks();
533
+ }
534
+
535
+ reset(): void {
536
+ this.subscribers.clear();
537
+ this.history = [];
538
+ vi.clearAllMocks();
539
+ }
540
+ }
541
+
542
+ /**
543
+ * Mock Security Service
544
+ */
545
+ export class MockSecurityService {
546
+ private blockedPaths = ['../', '~/', '/etc/', '/tmp/', '/var/', '/root/'];
547
+ private allowedCommands = ['npm', 'npx', 'node', 'git'];
548
+ private tokens = new Map<string, { payload: Record<string, unknown>; expiresAt: Date }>();
549
+
550
+ validatePath = vi.fn((path: string) => {
551
+ return !this.blockedPaths.some(blocked => path.includes(blocked));
552
+ });
553
+
554
+ validateInput = vi.fn((input: string, options?: InputValidationOptions) => {
555
+ const errors: string[] = [];
556
+
557
+ if (options?.maxLength && input.length > options.maxLength) {
558
+ errors.push(`Input exceeds maximum length of ${options.maxLength}`);
559
+ }
560
+
561
+ if (options?.allowedChars && !options.allowedChars.test(input)) {
562
+ errors.push('Input contains disallowed characters');
563
+ }
564
+
565
+ return {
566
+ valid: errors.length === 0,
567
+ sanitized: options?.sanitize ? this.sanitize(input) : input,
568
+ errors: errors.length > 0 ? errors : undefined,
569
+ };
570
+ });
571
+
572
+ hashPassword = vi.fn(async (password: string) => {
573
+ // Simulate argon2 hash format
574
+ return `$argon2id$v=19$m=65536,t=3,p=4$${Buffer.from(password).toString('base64')}`;
575
+ });
576
+
577
+ verifyPassword = vi.fn(async (password: string, hash: string) => {
578
+ const parts = hash.split('$');
579
+ if (parts.length < 5) return false;
580
+ return Buffer.from(parts[4], 'base64').toString() === password;
581
+ });
582
+
583
+ generateToken = vi.fn(async (payload: Record<string, unknown>, expiresIn: number = 3600000) => {
584
+ const token = `token_${Date.now()}_${Math.random().toString(36).slice(2)}`;
585
+ this.tokens.set(token, {
586
+ payload,
587
+ expiresAt: new Date(Date.now() + expiresIn),
588
+ });
589
+ return token;
590
+ });
591
+
592
+ verifyToken = vi.fn(async (token: string) => {
593
+ const entry = this.tokens.get(token);
594
+ if (!entry) {
595
+ throw new Error('Invalid token');
596
+ }
597
+ if (entry.expiresAt < new Date()) {
598
+ this.tokens.delete(token);
599
+ throw new Error('Token expired');
600
+ }
601
+ return entry.payload;
602
+ });
603
+
604
+ executeSecurely = vi.fn(async (command: string, options?: ExecuteOptions) => {
605
+ const [cmd] = command.split(' ');
606
+
607
+ if (!this.allowedCommands.includes(cmd)) {
608
+ throw new Error(`Command not allowed: ${cmd}`);
609
+ }
610
+
611
+ return {
612
+ stdout: '',
613
+ stderr: '',
614
+ exitCode: 0,
615
+ duration: Math.random() * 100,
616
+ };
617
+ });
618
+
619
+ private sanitize(input: string): string {
620
+ return input
621
+ .replace(/</g, '&lt;')
622
+ .replace(/>/g, '&gt;')
623
+ .replace(/"/g, '&quot;')
624
+ .replace(/'/g, '&#39;');
625
+ }
626
+
627
+ reset(): void {
628
+ this.tokens.clear();
629
+ vi.clearAllMocks();
630
+ }
631
+ }
632
+
633
+ // Supporting types
634
+ interface SwarmState {
635
+ id: string;
636
+ topology: string;
637
+ status: string;
638
+ agentCount: number;
639
+ activeAgentCount: number;
640
+ leaderId?: string;
641
+ createdAt: Date;
642
+ }
643
+
644
+ interface SwarmInitConfig {
645
+ topology?: string;
646
+ maxAgents?: number;
647
+ }
648
+
649
+ interface AgentConfig {
650
+ type: V3AgentType;
651
+ name?: string;
652
+ capabilities?: string[];
653
+ priority?: number;
654
+ }
655
+
656
+ interface SwarmTask {
657
+ id: string;
658
+ type: string;
659
+ payload: unknown;
660
+ priority?: number;
661
+ maxAgents?: number;
662
+ }
663
+
664
+ interface SwarmMessage {
665
+ id: string;
666
+ from: string;
667
+ to: string;
668
+ type: string;
669
+ payload: unknown;
670
+ timestamp: Date;
671
+ }
672
+
673
+ interface TaskResult {
674
+ taskId: string;
675
+ agentId: string;
676
+ success: boolean;
677
+ output?: unknown;
678
+ error?: Error;
679
+ duration: number;
680
+ }
681
+
682
+ interface ConsensusRequest<T> {
683
+ topic: string;
684
+ options: T[];
685
+ voters?: string[];
686
+ timeout?: number;
687
+ }
688
+
689
+ interface ConsensusResponse<T> {
690
+ topic: string;
691
+ decision: T | null;
692
+ votes: Map<string, T>;
693
+ consensus: boolean;
694
+ votingDuration: number;
695
+ participatingAgents: string[];
696
+ }
697
+
698
+ interface MemoryMetadata {
699
+ type: 'short-term' | 'long-term' | 'semantic' | 'episodic';
700
+ tags: string[];
701
+ ttl?: number;
702
+ [key: string]: unknown;
703
+ }
704
+
705
+ interface VectorSearchQuery {
706
+ embedding?: number[];
707
+ topK: number;
708
+ threshold?: number;
709
+ filters?: Record<string, unknown>;
710
+ }
711
+
712
+ interface SearchResult {
713
+ key: string;
714
+ value: unknown;
715
+ score: number;
716
+ metadata: MemoryMetadata;
717
+ }
718
+
719
+ interface DomainEvent {
720
+ id: string;
721
+ type: string;
722
+ payload: unknown;
723
+ timestamp: Date;
724
+ correlationId?: string;
725
+ }
726
+
727
+ type EventHandler = (event: DomainEvent) => Promise<void>;
728
+
729
+ interface InputValidationOptions {
730
+ maxLength?: number;
731
+ allowedChars?: RegExp;
732
+ sanitize?: boolean;
733
+ }
734
+
735
+ interface ExecuteOptions {
736
+ timeout?: number;
737
+ cwd?: string;
738
+ shell?: boolean;
739
+ }
740
+
741
+ // Agent capabilities mapping
742
+ const agentCapabilities: Record<V3AgentType, string[]> = {
743
+ 'queen-coordinator': ['orchestration', 'coordination', 'task-distribution'],
744
+ 'security-architect': ['security', 'design', 'threat-modeling'],
745
+ 'security-auditor': ['security', 'audit', 'vulnerability'],
746
+ 'memory-specialist': ['memory', 'optimization', 'caching'],
747
+ 'swarm-specialist': ['coordination', 'consensus', 'communication'],
748
+ 'integration-architect': ['integration', 'api', 'compatibility'],
749
+ 'performance-engineer': ['performance', 'optimization', 'benchmarking'],
750
+ 'core-architect': ['architecture', 'design', 'domain'],
751
+ 'test-architect': ['testing', 'tdd', 'quality'],
752
+ 'project-coordinator': ['project', 'planning', 'scheduling'],
753
+ 'coder': ['coding', 'implementation', 'debugging'],
754
+ 'reviewer': ['review', 'quality', 'suggestions'],
755
+ 'tester': ['testing', 'execution', 'coverage'],
756
+ 'planner': ['planning', 'estimation', 'roadmap'],
757
+ 'researcher': ['research', 'analysis', 'documentation'],
758
+ };
759
+
760
+ /**
761
+ * Create all mock services as a bundle
762
+ */
763
+ export function createMockServices(): MockServiceBundle {
764
+ return {
765
+ agentDB: new MockAgentDB(),
766
+ swarmCoordinator: new MockSwarmCoordinator(),
767
+ memoryService: new MockMemoryService(),
768
+ eventBus: new MockEventBus(),
769
+ securityService: new MockSecurityService(),
770
+ };
771
+ }
772
+
773
+ /**
774
+ * Mock service bundle interface
775
+ */
776
+ export interface MockServiceBundle {
777
+ agentDB: MockAgentDB;
778
+ swarmCoordinator: MockSwarmCoordinator;
779
+ memoryService: MockMemoryService;
780
+ eventBus: MockEventBus;
781
+ securityService: MockSecurityService;
782
+ }
783
+
784
+ /**
785
+ * Reset all mock services
786
+ */
787
+ export function resetMockServices(services: MockServiceBundle): void {
788
+ services.agentDB.clear();
789
+ services.swarmCoordinator.reset();
790
+ services.memoryService.reset();
791
+ services.eventBus.reset();
792
+ services.securityService.reset();
793
+ }