claude-flow 2.0.0-alpha.98 → 2.0.0
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.
- package/.claude/agents/MIGRATION_SUMMARY.md +7 -0
- package/.claude/agents/README.md +7 -0
- package/.claude/agents/consensus/README.md +7 -0
- package/.claude/agents/flow-nexus/app-store.md +88 -0
- package/.claude/agents/flow-nexus/authentication.md +69 -0
- package/.claude/agents/flow-nexus/challenges.md +81 -0
- package/.claude/agents/flow-nexus/neural-network.md +88 -0
- package/.claude/agents/flow-nexus/payments.md +83 -0
- package/.claude/agents/flow-nexus/sandbox.md +76 -0
- package/.claude/agents/flow-nexus/swarm.md +76 -0
- package/.claude/agents/flow-nexus/user-tools.md +96 -0
- package/.claude/agents/flow-nexus/workflow.md +84 -0
- package/.claude/agents/optimization/README.md +7 -0
- package/.claude/agents/optimization/benchmark-suite.md +7 -0
- package/.claude/agents/optimization/load-balancer.md +7 -0
- package/.claude/agents/optimization/performance-monitor.md +7 -0
- package/.claude/agents/optimization/resource-allocator.md +7 -0
- package/.claude/agents/optimization/topology-optimizer.md +7 -0
- package/.claude/agents/swarm/README.md +7 -0
- package/.claude/checkpoints/1756227204.json +1 -0
- package/.claude/checkpoints/1756227205.json +1 -0
- package/.claude/checkpoints/1756227276.json +1 -0
- package/.claude/checkpoints/1756227278.json +1 -0
- package/.claude/checkpoints/1756227280.json +1 -0
- package/.claude/checkpoints/1756227282.json +1 -0
- package/.claude/checkpoints/1756227652.json +1 -0
- package/.claude/checkpoints/1756227653.json +1 -0
- package/.claude/checkpoints/1756227666.json +1 -0
- package/.claude/checkpoints/1756227668.json +1 -0
- package/.claude/checkpoints/1756227723.json +1 -0
- package/.claude/checkpoints/1756227725.json +1 -0
- package/.claude/checkpoints/1756227731.json +1 -0
- package/.claude/checkpoints/1756227733.json +1 -0
- package/.claude/checkpoints/1756231330.json +1 -0
- package/.claude/checkpoints/1756231331.json +1 -0
- package/.claude/checkpoints/1756231342.json +1 -0
- package/.claude/checkpoints/1756231344.json +1 -0
- package/.claude/checkpoints/1756231355.json +1 -0
- package/.claude/checkpoints/1756231357.json +1 -0
- package/.claude/checkpoints/1756231367.json +1 -0
- package/.claude/checkpoints/1756231368.json +1 -0
- package/.claude/checkpoints/1756231458.json +1 -0
- package/.claude/checkpoints/1756231459.json +1 -0
- package/.claude/checkpoints/1756231477.json +1 -0
- package/.claude/checkpoints/1756231479.json +1 -0
- package/.claude/checkpoints/1756233026.json +1 -0
- package/.claude/checkpoints/1756233028.json +1 -0
- package/.claude/checkpoints/1756233040.json +1 -0
- package/.claude/checkpoints/1756233041.json +1 -0
- package/.claude/checkpoints/1756233057.json +1 -0
- package/.claude/checkpoints/1756233059.json +1 -0
- package/.claude/checkpoints/1756233090.json +1 -0
- package/.claude/checkpoints/1756233092.json +1 -0
- package/.claude/checkpoints/1756233141.json +1 -0
- package/.claude/checkpoints/1756233143.json +1 -0
- package/.claude/checkpoints/1756475935.json +1 -0
- package/.claude/checkpoints/1756475936.json +1 -0
- package/.claude/checkpoints/1756475996.json +1 -0
- package/.claude/checkpoints/1756475998.json +1 -0
- package/.claude/checkpoints/1756476093.json +1 -0
- package/.claude/checkpoints/1756476098.json +1 -0
- package/.claude/checkpoints/1756476100.json +1 -0
- package/.claude/checkpoints/1756476101.json +1 -0
- package/.claude/checkpoints/1756476161.json +1 -0
- package/.claude/checkpoints/1756476163.json +1 -0
- package/.claude/checkpoints/1756476183.json +1 -0
- package/.claude/checkpoints/1756476184.json +1 -0
- package/.claude/checkpoints/1756476193.json +1 -0
- package/.claude/checkpoints/1756476194.json +1 -0
- package/.claude/checkpoints/1756476202.json +1 -0
- package/.claude/checkpoints/1756476204.json +1 -0
- package/.claude/checkpoints/1756476268.json +1 -0
- package/.claude/checkpoints/1756476269.json +1 -0
- package/.claude/checkpoints/1756476287.json +1 -0
- package/.claude/checkpoints/1756476288.json +1 -0
- package/.claude/checkpoints/1756997935.json +1 -0
- package/.claude/checkpoints/1756997937.json +1 -0
- package/.claude/checkpoints/1756997938.json +1 -0
- package/.claude/checkpoints/1756997940.json +1 -0
- package/.claude/checkpoints/1756997942.json +1 -0
- package/.claude/checkpoints/1756997944.json +1 -0
- package/.claude/checkpoints/1756997945.json +1 -0
- package/.claude/checkpoints/1756997947.json +1 -0
- package/.claude/checkpoints/1756997949.json +1 -0
- package/.claude/checkpoints/1756997951.json +1 -0
- package/.claude/checkpoints/1756997953.json +1 -0
- package/.claude/checkpoints/1756997955.json +1 -0
- package/.claude/checkpoints/1756997956.json +1 -0
- package/.claude/checkpoints/1756997958.json +1 -0
- package/.claude/checkpoints/1756997960.json +1 -0
- package/.claude/checkpoints/1756997962.json +1 -0
- package/.claude/checkpoints/1756997964.json +1 -0
- package/.claude/checkpoints/1756997966.json +1 -0
- package/.claude/checkpoints/1756997968.json +1 -0
- package/.claude/checkpoints/1756997970.json +1 -0
- package/.claude/checkpoints/1757190213.json +1 -0
- package/.claude/checkpoints/1757190215.json +1 -0
- package/.claude/checkpoints/1757190217.json +1 -0
- package/.claude/checkpoints/1757190219.json +1 -0
- package/.claude/checkpoints/1757190220.json +1 -0
- package/.claude/checkpoints/1757190222.json +1 -0
- package/.claude/checkpoints/1757190224.json +1 -0
- package/.claude/checkpoints/1757190225.json +1 -0
- package/.claude/checkpoints/1757190227.json +1 -0
- package/.claude/checkpoints/1757190229.json +1 -0
- package/.claude/checkpoints/1757190231.json +1 -0
- package/.claude/checkpoints/1757190232.json +1 -0
- package/.claude/checkpoints/1757190234.json +1 -0
- package/.claude/checkpoints/1757190236.json +1 -0
- package/.claude/checkpoints/1757190238.json +1 -0
- package/.claude/checkpoints/1757190240.json +1 -0
- package/.claude/checkpoints/1757190241.json +1 -0
- package/.claude/checkpoints/1757190243.json +1 -0
- package/.claude/checkpoints/1757190245.json +1 -0
- package/.claude/checkpoints/1757190247.json +1 -0
- package/.claude/checkpoints/1757190608.json +1 -0
- package/.claude/checkpoints/1757190610.json +1 -0
- package/.claude/checkpoints/1757190626.json +1 -0
- package/.claude/checkpoints/1757190628.json +1 -0
- package/.claude/checkpoints/1757190993.json +1 -0
- package/.claude/checkpoints/1757190997.json +1 -0
- package/.claude/checkpoints/1757191001.json +1 -0
- package/.claude/checkpoints/1757191004.json +1 -0
- package/.claude/checkpoints/1757191007.json +1 -0
- package/.claude/checkpoints/1757191009.json +1 -0
- package/.claude/checkpoints/1757191012.json +1 -0
- package/.claude/checkpoints/1757191014.json +1 -0
- package/.claude/checkpoints/1757191016.json +1 -0
- package/.claude/checkpoints/1757191019.json +1 -0
- package/.claude/checkpoints/1757191022.json +1 -0
- package/.claude/checkpoints/1757191024.json +1 -0
- package/.claude/checkpoints/1757191027.json +1 -0
- package/.claude/checkpoints/1757191029.json +1 -0
- package/.claude/checkpoints/1757191032.json +1 -0
- package/.claude/checkpoints/1757191034.json +1 -0
- package/.claude/checkpoints/1757191037.json +1 -0
- package/.claude/checkpoints/1757191040.json +1 -0
- package/.claude/checkpoints/1757191061.json +1 -0
- package/.claude/checkpoints/1757191063.json +1 -0
- package/.claude/checkpoints/1757191084.json +1 -0
- package/.claude/checkpoints/1757191086.json +1 -0
- package/.claude/checkpoints/1757192316.json +1 -0
- package/.claude/checkpoints/1757192318.json +1 -0
- package/.claude/checkpoints/1757192389.json +1 -0
- package/.claude/checkpoints/1757192391.json +1 -0
- package/.claude/checkpoints/1757192489.json +1 -0
- package/.claude/checkpoints/1757192491.json +1 -0
- package/.claude/checkpoints/1757192521.json +1 -0
- package/.claude/checkpoints/1757192523.json +1 -0
- package/.claude/checkpoints/1757192541.json +1 -0
- package/.claude/checkpoints/1757192543.json +1 -0
- package/.claude/checkpoints/1757193796.json +1 -0
- package/.claude/checkpoints/summary-session-20250826-164827.md +1342 -0
- package/.claude/checkpoints/summary-session-20250826-165852.md +1351 -0
- package/.claude/checkpoints/summary-session-20250826-170402.md +1367 -0
- package/.claude/checkpoints/summary-session-20250826-175112.md +1327 -0
- package/.claude/checkpoints/summary-session-20250826-175609.md +1324 -0
- package/.claude/checkpoints/summary-session-20250826-175743.md +1327 -0
- package/.claude/checkpoints/summary-session-20250826-180554.md +1340 -0
- package/.claude/checkpoints/summary-session-20250826-181530.md +1344 -0
- package/.claude/checkpoints/summary-session-20250826-181633.md +1347 -0
- package/.claude/checkpoints/summary-session-20250826-182235.md +1350 -0
- package/.claude/checkpoints/summary-session-20250826-182618.md +1353 -0
- package/.claude/checkpoints/summary-session-20250826-183200.md +1372 -0
- package/.claude/checkpoints/summary-session-20250826-183232.md +1379 -0
- package/.claude/checkpoints/summary-session-20250829-133605.md +38 -0
- package/.claude/checkpoints/summary-session-20250829-134121.md +41 -0
- package/.claude/checkpoints/summary-session-20250829-134400.md +46 -0
- package/.claude/checkpoints/summary-session-20250829-134858.md +49 -0
- package/.claude/checkpoints/summary-session-20250829-135402.md +52 -0
- package/.claude/checkpoints/summary-session-20250829-135640.md +58 -0
- package/.claude/checkpoints/summary-session-20250829-135754.md +65 -0
- package/.claude/checkpoints/summary-session-20250829-135902.md +71 -0
- package/.claude/checkpoints/summary-session-20250829-140629.md +119 -0
- package/.claude/checkpoints/summary-session-20250829-140733.md +121 -0
- package/.claude/checkpoints/summary-session-20250902-190126.md +38 -0
- package/.claude/checkpoints/summary-session-20250904-150003.md +87 -0
- package/.claude/checkpoints/summary-session-20250906-202218.md +2757 -0
- package/.claude/checkpoints/summary-session-20250906-202622.md +2814 -0
- package/.claude/checkpoints/summary-session-20250906-203037.md +2826 -0
- package/.claude/checkpoints/task-1756227096.json +1 -0
- package/.claude/checkpoints/task-1756227619.json +1 -0
- package/.claude/checkpoints/task-1756230633.json +1 -0
- package/.claude/checkpoints/task-1756230902.json +1 -0
- package/.claude/checkpoints/task-1756230993.json +1 -0
- package/.claude/checkpoints/task-1756231253.json +1 -0
- package/.claude/checkpoints/task-1756232070.json +1 -0
- package/.claude/checkpoints/task-1756232144.json +1 -0
- package/.claude/checkpoints/task-1756232251.json +1 -0
- package/.claude/checkpoints/task-1756232564.json +1 -0
- package/.claude/checkpoints/task-1756232982.json +1 -0
- package/.claude/checkpoints/task-1756233131.json +1 -0
- package/.claude/checkpoints/task-1756474562.json +1 -0
- package/.claude/checkpoints/task-1756474754.json +1 -0
- package/.claude/checkpoints/task-1756474922.json +1 -0
- package/.claude/checkpoints/task-1756475028.json +1 -0
- package/.claude/checkpoints/task-1756475307.json +1 -0
- package/.claude/checkpoints/task-1756475349.json +1 -0
- package/.claude/checkpoints/task-1756475699.json +1 -0
- package/.claude/checkpoints/task-1756475719.json +1 -0
- package/.claude/checkpoints/task-1756475828.json +1 -0
- package/.claude/checkpoints/task-1756475858.json +1 -0
- package/.claude/checkpoints/task-1756475868.json +1 -0
- package/.claude/checkpoints/task-1756476373.json +1 -0
- package/.claude/checkpoints/task-1756839595.json +1 -0
- package/.claude/checkpoints/task-1756997821.json +1 -0
- package/.claude/checkpoints/task-1757189936.json +1 -0
- package/.claude/checkpoints/task-1757190154.json +1 -0
- package/.claude/checkpoints/task-1757190301.json +1 -0
- package/.claude/checkpoints/task-1757190369.json +1 -0
- package/.claude/checkpoints/task-1757190483.json +1 -0
- package/.claude/checkpoints/task-1757190841.json +1 -0
- package/.claude/checkpoints/task-1757191219.json +1 -0
- package/.claude/checkpoints/task-1757192639.json +1 -0
- package/.claude/checkpoints/task-1757194091.json +1 -0
- package/.claude/commands/flow-nexus/app-store.md +124 -0
- package/.claude/commands/flow-nexus/challenges.md +120 -0
- package/.claude/commands/flow-nexus/login-registration.md +65 -0
- package/.claude/commands/flow-nexus/neural-network.md +134 -0
- package/.claude/commands/flow-nexus/payments.md +116 -0
- package/.claude/commands/flow-nexus/sandbox.md +83 -0
- package/.claude/commands/flow-nexus/swarm.md +87 -0
- package/.claude/commands/flow-nexus/user-tools.md +152 -0
- package/.claude/commands/flow-nexus/workflow.md +115 -0
- package/bin/claude-flow +1 -1
- package/package.json +1 -1
- package/src/api/auth-service.ts +644 -0
- package/src/api/database-schema.sql +366 -0
- package/src/api/database-service.ts +788 -0
- package/src/api/swarm-api.ts +741 -0
- package/src/cli/commands/index.ts +711 -1
- package/src/cli/simple-commands/hive-mind/session-manager.js +12 -0
- package/src/cli/simple-commands/init/agent-copier.js +129 -1
- package/src/cli/simple-commands/init/hive-mind-init.js +12 -7
- package/src/cli/simple-commands/init/index.js +116 -1
- package/src/cli/simple-commands/init/templates/claude-md.js +295 -1
- package/src/core/version.js +1 -1
- package/src/ui/console/index.html +4 -0
- package/src/ui/console/js/real-time-dashboard.js +715 -0
- package/src/ui/console/js/swarm-integration.js +485 -0
- package/src/ui/console/js/swarm-visualizer.js +879 -0
- package/src/ui/console/styles/swarm-visualizer.css +487 -0
- package/src/cli/simple-commands/init/.claude-flow/metrics/agent-metrics.json +0 -1
- package/src/cli/simple-commands/init/.claude-flow/metrics/performance.json +0 -9
- package/src/cli/simple-commands/init/.claude-flow/metrics/task-metrics.json +0 -10
- package/src/cli/simple-commands/init/.swarm/memory.db +0 -0
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swarm API - RESTful API for swarm coordination and management
|
|
3
|
+
* Provides HTTP endpoints for swarm operations, agent management, and task orchestration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { ILogger } from '../core/logger.js';
|
|
8
|
+
import { ClaudeAPIClient } from './claude-client.js';
|
|
9
|
+
import { ConfigManager } from '../config/config-manager.js';
|
|
10
|
+
import { ICoordinationManager } from '../coordination/manager.js';
|
|
11
|
+
import { SwarmCoordinator } from '../swarm/coordinator.js';
|
|
12
|
+
import { AgentManager } from '../agents/agent-manager.js';
|
|
13
|
+
import { ResourceManager } from '../resources/resource-manager.js';
|
|
14
|
+
import { Task, Agent, SwarmConfig, SwarmStatus } from '../utils/types.js';
|
|
15
|
+
import { ValidationError, SwarmError } from '../utils/errors.js';
|
|
16
|
+
import { nanoid } from 'nanoid';
|
|
17
|
+
|
|
18
|
+
export interface SwarmApiConfig {
|
|
19
|
+
rateLimit: {
|
|
20
|
+
windowMs: number;
|
|
21
|
+
maxRequests: number;
|
|
22
|
+
};
|
|
23
|
+
authentication: {
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
apiKeys?: string[];
|
|
26
|
+
jwtSecret?: string;
|
|
27
|
+
};
|
|
28
|
+
cors: {
|
|
29
|
+
origins: string[];
|
|
30
|
+
methods: string[];
|
|
31
|
+
};
|
|
32
|
+
swagger: {
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
title: string;
|
|
35
|
+
version: string;
|
|
36
|
+
description: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface SwarmCreateRequest {
|
|
41
|
+
name: string;
|
|
42
|
+
topology: 'hierarchical' | 'mesh' | 'ring' | 'star';
|
|
43
|
+
maxAgents?: number;
|
|
44
|
+
strategy?: 'balanced' | 'specialized' | 'adaptive';
|
|
45
|
+
config?: Partial<SwarmConfig>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface AgentSpawnRequest {
|
|
49
|
+
type: string;
|
|
50
|
+
name?: string;
|
|
51
|
+
capabilities?: string[];
|
|
52
|
+
config?: Record<string, unknown>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface TaskOrchestrationRequest {
|
|
56
|
+
task: string;
|
|
57
|
+
priority?: 'low' | 'medium' | 'high' | 'critical';
|
|
58
|
+
strategy?: 'parallel' | 'sequential' | 'adaptive';
|
|
59
|
+
maxAgents?: number;
|
|
60
|
+
requirements?: string[];
|
|
61
|
+
metadata?: Record<string, unknown>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface SwarmMetrics {
|
|
65
|
+
swarmId: string;
|
|
66
|
+
agentCount: number;
|
|
67
|
+
activeTasks: number;
|
|
68
|
+
completedTasks: number;
|
|
69
|
+
failedTasks: number;
|
|
70
|
+
averageResponseTime: number;
|
|
71
|
+
resourceUtilization: Record<string, number>;
|
|
72
|
+
healthScore: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Swarm API implementation
|
|
77
|
+
*/
|
|
78
|
+
export class SwarmApi {
|
|
79
|
+
private router: Router;
|
|
80
|
+
private swarms = new Map<string, SwarmCoordinator>();
|
|
81
|
+
|
|
82
|
+
constructor(
|
|
83
|
+
private config: SwarmApiConfig,
|
|
84
|
+
private logger: ILogger,
|
|
85
|
+
private claudeClient: ClaudeAPIClient,
|
|
86
|
+
private configManager: ConfigManager,
|
|
87
|
+
private coordinationManager: ICoordinationManager,
|
|
88
|
+
private agentManager: AgentManager,
|
|
89
|
+
private resourceManager: ResourceManager,
|
|
90
|
+
) {
|
|
91
|
+
this.router = Router();
|
|
92
|
+
this.setupRoutes();
|
|
93
|
+
this.setupMiddleware();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getRouter(): Router {
|
|
97
|
+
return this.router;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private setupMiddleware(): void {
|
|
101
|
+
// Request logging
|
|
102
|
+
this.router.use((req, res, next) => {
|
|
103
|
+
this.logger.info('Swarm API request', {
|
|
104
|
+
method: req.method,
|
|
105
|
+
path: req.path,
|
|
106
|
+
ip: req.ip,
|
|
107
|
+
userAgent: req.get('User-Agent'),
|
|
108
|
+
});
|
|
109
|
+
next();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Request validation
|
|
113
|
+
this.router.use((req, res, next) => {
|
|
114
|
+
if (req.method === 'POST' || req.method === 'PUT') {
|
|
115
|
+
if (!req.body) {
|
|
116
|
+
return res.status(400).json({
|
|
117
|
+
error: 'Request body is required',
|
|
118
|
+
code: 'MISSING_BODY',
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
next();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Error handling
|
|
126
|
+
this.router.use((err: Error, req: any, res: any, next: any) => {
|
|
127
|
+
this.logger.error('Swarm API error', {
|
|
128
|
+
error: err.message,
|
|
129
|
+
stack: err.stack,
|
|
130
|
+
method: req.method,
|
|
131
|
+
path: req.path,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (err instanceof ValidationError) {
|
|
135
|
+
return res.status(400).json({
|
|
136
|
+
error: err.message,
|
|
137
|
+
code: 'VALIDATION_ERROR',
|
|
138
|
+
details: err.details,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (err instanceof SwarmError) {
|
|
143
|
+
return res.status(409).json({
|
|
144
|
+
error: err.message,
|
|
145
|
+
code: 'SWARM_ERROR',
|
|
146
|
+
details: err.details,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
res.status(500).json({
|
|
151
|
+
error: 'Internal server error',
|
|
152
|
+
code: 'INTERNAL_ERROR',
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private setupRoutes(): void {
|
|
158
|
+
// Health check
|
|
159
|
+
this.router.get('/health', async (req, res) => {
|
|
160
|
+
try {
|
|
161
|
+
const health = await this.getSystemHealth();
|
|
162
|
+
res.json(health);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
res.status(500).json({
|
|
165
|
+
healthy: false,
|
|
166
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Swarm management
|
|
172
|
+
this.router.post('/swarms', this.createSwarm.bind(this));
|
|
173
|
+
this.router.get('/swarms', this.listSwarms.bind(this));
|
|
174
|
+
this.router.get('/swarms/:swarmId', this.getSwarm.bind(this));
|
|
175
|
+
this.router.delete('/swarms/:swarmId', this.destroySwarm.bind(this));
|
|
176
|
+
this.router.post('/swarms/:swarmId/scale', this.scaleSwarm.bind(this));
|
|
177
|
+
|
|
178
|
+
// Agent management
|
|
179
|
+
this.router.post('/swarms/:swarmId/agents', this.spawnAgent.bind(this));
|
|
180
|
+
this.router.get('/swarms/:swarmId/agents', this.listAgents.bind(this));
|
|
181
|
+
this.router.get('/swarms/:swarmId/agents/:agentId', this.getAgent.bind(this));
|
|
182
|
+
this.router.delete('/swarms/:swarmId/agents/:agentId', this.terminateAgent.bind(this));
|
|
183
|
+
|
|
184
|
+
// Task orchestration
|
|
185
|
+
this.router.post('/swarms/:swarmId/tasks', this.orchestrateTask.bind(this));
|
|
186
|
+
this.router.get('/swarms/:swarmId/tasks', this.listTasks.bind(this));
|
|
187
|
+
this.router.get('/swarms/:swarmId/tasks/:taskId', this.getTask.bind(this));
|
|
188
|
+
this.router.delete('/swarms/:swarmId/tasks/:taskId', this.cancelTask.bind(this));
|
|
189
|
+
|
|
190
|
+
// Metrics and monitoring
|
|
191
|
+
this.router.get('/swarms/:swarmId/metrics', this.getSwarmMetrics.bind(this));
|
|
192
|
+
this.router.get('/swarms/:swarmId/status', this.getSwarmStatus.bind(this));
|
|
193
|
+
this.router.get('/system/metrics', this.getSystemMetrics.bind(this));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private async createSwarm(req: any, res: any): Promise<void> {
|
|
197
|
+
try {
|
|
198
|
+
const request = req.body as SwarmCreateRequest;
|
|
199
|
+
|
|
200
|
+
// Validate request
|
|
201
|
+
if (!request.name || !request.topology) {
|
|
202
|
+
return res.status(400).json({
|
|
203
|
+
error: 'Name and topology are required',
|
|
204
|
+
code: 'VALIDATION_ERROR',
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Create swarm configuration
|
|
209
|
+
const swarmConfig: SwarmConfig = {
|
|
210
|
+
name: request.name,
|
|
211
|
+
topology: request.topology,
|
|
212
|
+
maxAgents: request.maxAgents || 8,
|
|
213
|
+
strategy: request.strategy || 'balanced',
|
|
214
|
+
...request.config,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// Generate swarm ID
|
|
218
|
+
const swarmId = `swarm_${Date.now()}_${nanoid(10)}`;
|
|
219
|
+
|
|
220
|
+
// Create swarm coordinator
|
|
221
|
+
const swarm = new SwarmCoordinator(
|
|
222
|
+
swarmId,
|
|
223
|
+
swarmConfig,
|
|
224
|
+
this.logger,
|
|
225
|
+
this.claudeClient,
|
|
226
|
+
this.configManager,
|
|
227
|
+
this.coordinationManager,
|
|
228
|
+
this.agentManager,
|
|
229
|
+
this.resourceManager,
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
// Initialize swarm
|
|
233
|
+
await swarm.initialize();
|
|
234
|
+
|
|
235
|
+
// Store swarm
|
|
236
|
+
this.swarms.set(swarmId, swarm);
|
|
237
|
+
|
|
238
|
+
this.logger.info('Swarm created', {
|
|
239
|
+
swarmId,
|
|
240
|
+
name: request.name,
|
|
241
|
+
topology: request.topology,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
res.status(201).json({
|
|
245
|
+
swarmId,
|
|
246
|
+
name: request.name,
|
|
247
|
+
topology: request.topology,
|
|
248
|
+
maxAgents: swarmConfig.maxAgents,
|
|
249
|
+
strategy: swarmConfig.strategy,
|
|
250
|
+
status: 'active',
|
|
251
|
+
createdAt: new Date().toISOString(),
|
|
252
|
+
});
|
|
253
|
+
} catch (error) {
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private async listSwarms(req: any, res: any): Promise<void> {
|
|
259
|
+
try {
|
|
260
|
+
const swarmList = Array.from(this.swarms.entries()).map(([swarmId, swarm]) => ({
|
|
261
|
+
swarmId,
|
|
262
|
+
name: swarm.getConfig().name,
|
|
263
|
+
topology: swarm.getConfig().topology,
|
|
264
|
+
agentCount: swarm.getAgentCount(),
|
|
265
|
+
status: swarm.getStatus(),
|
|
266
|
+
createdAt: swarm.getCreatedAt(),
|
|
267
|
+
}));
|
|
268
|
+
|
|
269
|
+
res.json({
|
|
270
|
+
swarms: swarmList,
|
|
271
|
+
total: swarmList.length,
|
|
272
|
+
});
|
|
273
|
+
} catch (error) {
|
|
274
|
+
throw error;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private async getSwarm(req: any, res: any): Promise<void> {
|
|
279
|
+
try {
|
|
280
|
+
const { swarmId } = req.params;
|
|
281
|
+
const swarm = this.swarms.get(swarmId);
|
|
282
|
+
|
|
283
|
+
if (!swarm) {
|
|
284
|
+
return res.status(404).json({
|
|
285
|
+
error: 'Swarm not found',
|
|
286
|
+
code: 'SWARM_NOT_FOUND',
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const config = swarm.getConfig();
|
|
291
|
+
const status = swarm.getStatus();
|
|
292
|
+
const agents = await swarm.getAgents();
|
|
293
|
+
const metrics = await swarm.getMetrics();
|
|
294
|
+
|
|
295
|
+
res.json({
|
|
296
|
+
swarmId,
|
|
297
|
+
config,
|
|
298
|
+
status,
|
|
299
|
+
agents: agents.map(agent => ({
|
|
300
|
+
id: agent.id,
|
|
301
|
+
type: agent.type,
|
|
302
|
+
name: agent.name,
|
|
303
|
+
status: agent.status,
|
|
304
|
+
capabilities: agent.capabilities,
|
|
305
|
+
})),
|
|
306
|
+
metrics,
|
|
307
|
+
createdAt: swarm.getCreatedAt(),
|
|
308
|
+
});
|
|
309
|
+
} catch (error) {
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private async destroySwarm(req: any, res: any): Promise<void> {
|
|
315
|
+
try {
|
|
316
|
+
const { swarmId } = req.params;
|
|
317
|
+
const swarm = this.swarms.get(swarmId);
|
|
318
|
+
|
|
319
|
+
if (!swarm) {
|
|
320
|
+
return res.status(404).json({
|
|
321
|
+
error: 'Swarm not found',
|
|
322
|
+
code: 'SWARM_NOT_FOUND',
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
await swarm.destroy();
|
|
327
|
+
this.swarms.delete(swarmId);
|
|
328
|
+
|
|
329
|
+
this.logger.info('Swarm destroyed', { swarmId });
|
|
330
|
+
|
|
331
|
+
res.json({
|
|
332
|
+
message: 'Swarm destroyed successfully',
|
|
333
|
+
swarmId,
|
|
334
|
+
});
|
|
335
|
+
} catch (error) {
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private async scaleSwarm(req: any, res: any): Promise<void> {
|
|
341
|
+
try {
|
|
342
|
+
const { swarmId } = req.params;
|
|
343
|
+
const { targetSize } = req.body;
|
|
344
|
+
|
|
345
|
+
if (!targetSize || targetSize < 1) {
|
|
346
|
+
return res.status(400).json({
|
|
347
|
+
error: 'Valid targetSize is required',
|
|
348
|
+
code: 'VALIDATION_ERROR',
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const swarm = this.swarms.get(swarmId);
|
|
353
|
+
if (!swarm) {
|
|
354
|
+
return res.status(404).json({
|
|
355
|
+
error: 'Swarm not found',
|
|
356
|
+
code: 'SWARM_NOT_FOUND',
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
await swarm.scale(targetSize);
|
|
361
|
+
|
|
362
|
+
res.json({
|
|
363
|
+
message: 'Swarm scaled successfully',
|
|
364
|
+
swarmId,
|
|
365
|
+
newSize: targetSize,
|
|
366
|
+
});
|
|
367
|
+
} catch (error) {
|
|
368
|
+
throw error;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
private async spawnAgent(req: any, res: any): Promise<void> {
|
|
373
|
+
try {
|
|
374
|
+
const { swarmId } = req.params;
|
|
375
|
+
const request = req.body as AgentSpawnRequest;
|
|
376
|
+
|
|
377
|
+
if (!request.type) {
|
|
378
|
+
return res.status(400).json({
|
|
379
|
+
error: 'Agent type is required',
|
|
380
|
+
code: 'VALIDATION_ERROR',
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const swarm = this.swarms.get(swarmId);
|
|
385
|
+
if (!swarm) {
|
|
386
|
+
return res.status(404).json({
|
|
387
|
+
error: 'Swarm not found',
|
|
388
|
+
code: 'SWARM_NOT_FOUND',
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const agent = await swarm.spawnAgent({
|
|
393
|
+
type: request.type,
|
|
394
|
+
name: request.name,
|
|
395
|
+
capabilities: request.capabilities || [],
|
|
396
|
+
config: request.config,
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
res.status(201).json({
|
|
400
|
+
agent: {
|
|
401
|
+
id: agent.id,
|
|
402
|
+
type: agent.type,
|
|
403
|
+
name: agent.name,
|
|
404
|
+
status: agent.status,
|
|
405
|
+
capabilities: agent.capabilities,
|
|
406
|
+
},
|
|
407
|
+
swarmId,
|
|
408
|
+
});
|
|
409
|
+
} catch (error) {
|
|
410
|
+
throw error;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
private async orchestrateTask(req: any, res: any): Promise<void> {
|
|
415
|
+
try {
|
|
416
|
+
const { swarmId } = req.params;
|
|
417
|
+
const request = req.body as TaskOrchestrationRequest;
|
|
418
|
+
|
|
419
|
+
if (!request.task) {
|
|
420
|
+
return res.status(400).json({
|
|
421
|
+
error: 'Task description is required',
|
|
422
|
+
code: 'VALIDATION_ERROR',
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const swarm = this.swarms.get(swarmId);
|
|
427
|
+
if (!swarm) {
|
|
428
|
+
return res.status(404).json({
|
|
429
|
+
error: 'Swarm not found',
|
|
430
|
+
code: 'SWARM_NOT_FOUND',
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const task = await swarm.orchestrateTask({
|
|
435
|
+
description: request.task,
|
|
436
|
+
priority: request.priority || 'medium',
|
|
437
|
+
strategy: request.strategy || 'adaptive',
|
|
438
|
+
maxAgents: request.maxAgents,
|
|
439
|
+
requirements: request.requirements,
|
|
440
|
+
metadata: request.metadata,
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
res.status(201).json({
|
|
444
|
+
task: {
|
|
445
|
+
id: task.id,
|
|
446
|
+
description: task.description,
|
|
447
|
+
status: task.status,
|
|
448
|
+
priority: task.priority,
|
|
449
|
+
strategy: task.strategy,
|
|
450
|
+
},
|
|
451
|
+
swarmId,
|
|
452
|
+
});
|
|
453
|
+
} catch (error) {
|
|
454
|
+
throw error;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private async getSwarmMetrics(req: any, res: any): Promise<void> {
|
|
459
|
+
try {
|
|
460
|
+
const { swarmId } = req.params;
|
|
461
|
+
const swarm = this.swarms.get(swarmId);
|
|
462
|
+
|
|
463
|
+
if (!swarm) {
|
|
464
|
+
return res.status(404).json({
|
|
465
|
+
error: 'Swarm not found',
|
|
466
|
+
code: 'SWARM_NOT_FOUND',
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const metrics = await swarm.getMetrics();
|
|
471
|
+
res.json(metrics);
|
|
472
|
+
} catch (error) {
|
|
473
|
+
throw error;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
private async getSwarmStatus(req: any, res: any): Promise<void> {
|
|
478
|
+
try {
|
|
479
|
+
const { swarmId } = req.params;
|
|
480
|
+
const swarm = this.swarms.get(swarmId);
|
|
481
|
+
|
|
482
|
+
if (!swarm) {
|
|
483
|
+
return res.status(404).json({
|
|
484
|
+
error: 'Swarm not found',
|
|
485
|
+
code: 'SWARM_NOT_FOUND',
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const status = await swarm.getDetailedStatus();
|
|
490
|
+
res.json(status);
|
|
491
|
+
} catch (error) {
|
|
492
|
+
throw error;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
private async getSystemHealth(): Promise<{
|
|
497
|
+
healthy: boolean;
|
|
498
|
+
services: Record<string, { healthy: boolean; error?: string }>;
|
|
499
|
+
metrics: Record<string, number>;
|
|
500
|
+
}> {
|
|
501
|
+
const services: Record<string, { healthy: boolean; error?: string }> = {};
|
|
502
|
+
let allHealthy = true;
|
|
503
|
+
|
|
504
|
+
// Check Claude API health
|
|
505
|
+
const claudeHealth = this.claudeClient.getHealthStatus();
|
|
506
|
+
services.claude = {
|
|
507
|
+
healthy: claudeHealth?.healthy || false,
|
|
508
|
+
error: claudeHealth?.error,
|
|
509
|
+
};
|
|
510
|
+
allHealthy = allHealthy && services.claude.healthy;
|
|
511
|
+
|
|
512
|
+
// Check coordination manager health
|
|
513
|
+
const coordHealth = await this.coordinationManager.getHealthStatus();
|
|
514
|
+
services.coordination = {
|
|
515
|
+
healthy: coordHealth.healthy,
|
|
516
|
+
error: coordHealth.error,
|
|
517
|
+
};
|
|
518
|
+
allHealthy = allHealthy && services.coordination.healthy;
|
|
519
|
+
|
|
520
|
+
// Check agent manager health
|
|
521
|
+
const agentHealth = await this.agentManager.getHealthStatus();
|
|
522
|
+
services.agents = {
|
|
523
|
+
healthy: agentHealth.healthy,
|
|
524
|
+
error: agentHealth.error,
|
|
525
|
+
};
|
|
526
|
+
allHealthy = allHealthy && services.agents.healthy;
|
|
527
|
+
|
|
528
|
+
// Collect metrics
|
|
529
|
+
const metrics = {
|
|
530
|
+
totalSwarms: this.swarms.size,
|
|
531
|
+
...coordHealth.metrics,
|
|
532
|
+
...agentHealth.metrics,
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
return {
|
|
536
|
+
healthy: allHealthy,
|
|
537
|
+
services,
|
|
538
|
+
metrics,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
private async getSystemMetrics(req: any, res: any): Promise<void> {
|
|
543
|
+
try {
|
|
544
|
+
const systemMetrics = await this.getSystemHealth();
|
|
545
|
+
const swarmMetrics = await Promise.all(
|
|
546
|
+
Array.from(this.swarms.values()).map(async (swarm) => {
|
|
547
|
+
const metrics = await swarm.getMetrics();
|
|
548
|
+
return {
|
|
549
|
+
swarmId: swarm.getId(),
|
|
550
|
+
...metrics,
|
|
551
|
+
};
|
|
552
|
+
}),
|
|
553
|
+
);
|
|
554
|
+
|
|
555
|
+
res.json({
|
|
556
|
+
system: systemMetrics,
|
|
557
|
+
swarms: swarmMetrics,
|
|
558
|
+
timestamp: new Date().toISOString(),
|
|
559
|
+
});
|
|
560
|
+
} catch (error) {
|
|
561
|
+
throw error;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Additional helper methods
|
|
566
|
+
private async listAgents(req: any, res: any): Promise<void> {
|
|
567
|
+
try {
|
|
568
|
+
const { swarmId } = req.params;
|
|
569
|
+
const swarm = this.swarms.get(swarmId);
|
|
570
|
+
|
|
571
|
+
if (!swarm) {
|
|
572
|
+
return res.status(404).json({
|
|
573
|
+
error: 'Swarm not found',
|
|
574
|
+
code: 'SWARM_NOT_FOUND',
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const agents = await swarm.getAgents();
|
|
579
|
+
res.json({
|
|
580
|
+
agents: agents.map(agent => ({
|
|
581
|
+
id: agent.id,
|
|
582
|
+
type: agent.type,
|
|
583
|
+
name: agent.name,
|
|
584
|
+
status: agent.status,
|
|
585
|
+
capabilities: agent.capabilities,
|
|
586
|
+
createdAt: agent.createdAt,
|
|
587
|
+
})),
|
|
588
|
+
total: agents.length,
|
|
589
|
+
});
|
|
590
|
+
} catch (error) {
|
|
591
|
+
throw error;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
private async getAgent(req: any, res: any): Promise<void> {
|
|
596
|
+
try {
|
|
597
|
+
const { swarmId, agentId } = req.params;
|
|
598
|
+
const swarm = this.swarms.get(swarmId);
|
|
599
|
+
|
|
600
|
+
if (!swarm) {
|
|
601
|
+
return res.status(404).json({
|
|
602
|
+
error: 'Swarm not found',
|
|
603
|
+
code: 'SWARM_NOT_FOUND',
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const agent = await swarm.getAgent(agentId);
|
|
608
|
+
if (!agent) {
|
|
609
|
+
return res.status(404).json({
|
|
610
|
+
error: 'Agent not found',
|
|
611
|
+
code: 'AGENT_NOT_FOUND',
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
res.json(agent);
|
|
616
|
+
} catch (error) {
|
|
617
|
+
throw error;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
private async terminateAgent(req: any, res: any): Promise<void> {
|
|
622
|
+
try {
|
|
623
|
+
const { swarmId, agentId } = req.params;
|
|
624
|
+
const swarm = this.swarms.get(swarmId);
|
|
625
|
+
|
|
626
|
+
if (!swarm) {
|
|
627
|
+
return res.status(404).json({
|
|
628
|
+
error: 'Swarm not found',
|
|
629
|
+
code: 'SWARM_NOT_FOUND',
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
await swarm.terminateAgent(agentId);
|
|
634
|
+
res.json({
|
|
635
|
+
message: 'Agent terminated successfully',
|
|
636
|
+
agentId,
|
|
637
|
+
swarmId,
|
|
638
|
+
});
|
|
639
|
+
} catch (error) {
|
|
640
|
+
throw error;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
private async listTasks(req: any, res: any): Promise<void> {
|
|
645
|
+
try {
|
|
646
|
+
const { swarmId } = req.params;
|
|
647
|
+
const swarm = this.swarms.get(swarmId);
|
|
648
|
+
|
|
649
|
+
if (!swarm) {
|
|
650
|
+
return res.status(404).json({
|
|
651
|
+
error: 'Swarm not found',
|
|
652
|
+
code: 'SWARM_NOT_FOUND',
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const tasks = await swarm.getTasks();
|
|
657
|
+
res.json({
|
|
658
|
+
tasks: tasks.map(task => ({
|
|
659
|
+
id: task.id,
|
|
660
|
+
description: task.description,
|
|
661
|
+
status: task.status,
|
|
662
|
+
priority: task.priority,
|
|
663
|
+
assignedTo: task.assignedTo,
|
|
664
|
+
createdAt: task.createdAt,
|
|
665
|
+
completedAt: task.completedAt,
|
|
666
|
+
})),
|
|
667
|
+
total: tasks.length,
|
|
668
|
+
});
|
|
669
|
+
} catch (error) {
|
|
670
|
+
throw error;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
private async getTask(req: any, res: any): Promise<void> {
|
|
675
|
+
try {
|
|
676
|
+
const { swarmId, taskId } = req.params;
|
|
677
|
+
const swarm = this.swarms.get(swarmId);
|
|
678
|
+
|
|
679
|
+
if (!swarm) {
|
|
680
|
+
return res.status(404).json({
|
|
681
|
+
error: 'Swarm not found',
|
|
682
|
+
code: 'SWARM_NOT_FOUND',
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const task = await swarm.getTask(taskId);
|
|
687
|
+
if (!task) {
|
|
688
|
+
return res.status(404).json({
|
|
689
|
+
error: 'Task not found',
|
|
690
|
+
code: 'TASK_NOT_FOUND',
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
res.json(task);
|
|
695
|
+
} catch (error) {
|
|
696
|
+
throw error;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
private async cancelTask(req: any, res: any): Promise<void> {
|
|
701
|
+
try {
|
|
702
|
+
const { swarmId, taskId } = req.params;
|
|
703
|
+
const { reason } = req.body;
|
|
704
|
+
const swarm = this.swarms.get(swarmId);
|
|
705
|
+
|
|
706
|
+
if (!swarm) {
|
|
707
|
+
return res.status(404).json({
|
|
708
|
+
error: 'Swarm not found',
|
|
709
|
+
code: 'SWARM_NOT_FOUND',
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
await swarm.cancelTask(taskId, reason || 'User requested cancellation');
|
|
714
|
+
res.json({
|
|
715
|
+
message: 'Task cancelled successfully',
|
|
716
|
+
taskId,
|
|
717
|
+
swarmId,
|
|
718
|
+
});
|
|
719
|
+
} catch (error) {
|
|
720
|
+
throw error;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Clean up resources
|
|
726
|
+
*/
|
|
727
|
+
async destroy(): Promise<void> {
|
|
728
|
+
this.logger.info('Destroying Swarm API');
|
|
729
|
+
|
|
730
|
+
// Destroy all swarms
|
|
731
|
+
for (const [swarmId, swarm] of this.swarms) {
|
|
732
|
+
try {
|
|
733
|
+
await swarm.destroy();
|
|
734
|
+
} catch (error) {
|
|
735
|
+
this.logger.error('Error destroying swarm', { swarmId, error });
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
this.swarms.clear();
|
|
740
|
+
}
|
|
741
|
+
}
|