claude-flow-novice 1.5.12 → 1.5.13
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-flow-novice/dist/mcp/auth.js +347 -0
- package/.claude-flow-novice/dist/mcp/claude-code-wrapper.js +717 -0
- package/.claude-flow-novice/dist/mcp/claude-flow-tools.js +1365 -0
- package/.claude-flow-novice/dist/mcp/client.js +201 -0
- package/.claude-flow-novice/dist/mcp/index.js +192 -0
- package/.claude-flow-novice/dist/mcp/integrate-wrapper.js +85 -0
- package/.claude-flow-novice/dist/mcp/lifecycle-manager.js +348 -0
- package/.claude-flow-novice/dist/mcp/load-balancer.js +386 -0
- package/.claude-flow-novice/dist/mcp/mcp-config-manager.js +1362 -0
- package/.claude-flow-novice/dist/mcp/mcp-server-novice-simplified.js +583 -0
- package/.claude-flow-novice/dist/mcp/mcp-server-novice.js +723 -0
- package/.claude-flow-novice/dist/mcp/mcp-server-sdk.js +649 -0
- package/.claude-flow-novice/dist/mcp/mcp-server.js +2256 -0
- package/.claude-flow-novice/dist/mcp/orchestration-integration.js +800 -0
- package/.claude-flow-novice/dist/mcp/performance-monitor.js +489 -0
- package/.claude-flow-novice/dist/mcp/protocol-manager.js +376 -0
- package/.claude-flow-novice/dist/mcp/router.js +220 -0
- package/.claude-flow-novice/dist/mcp/ruv-swarm-tools.js +671 -0
- package/.claude-flow-novice/dist/mcp/ruv-swarm-wrapper.js +254 -0
- package/.claude-flow-novice/dist/mcp/server-with-wrapper.js +32 -0
- package/.claude-flow-novice/dist/mcp/server-wrapper-mode.js +26 -0
- package/.claude-flow-novice/dist/mcp/server.js +539 -0
- package/.claude-flow-novice/dist/mcp/session-manager.js +338 -0
- package/.claude-flow-novice/dist/mcp/sparc-modes.js +455 -0
- package/.claude-flow-novice/dist/mcp/swarm-tools.js +903 -0
- package/.claude-flow-novice/dist/mcp/tools.js +426 -0
- package/.claude-flow-novice/dist/src/cli/commands/swarm.js +23 -1
- package/.claude-flow-novice/dist/src/cli/commands/swarm.js.map +1 -1
- package/.claude-flow-novice/dist/src/cli/simple-commands/init/templates/CLAUDE.md +40 -101
- package/.claude-flow-novice/dist/src/coordination/swarm-coordinator-factory.js +36 -0
- package/.claude-flow-novice/dist/src/coordination/swarm-coordinator-factory.js.map +1 -0
- package/.claude-flow-novice/dist/src/validators/index.js +12 -0
- package/.claude-flow-novice/dist/src/validators/index.js.map +1 -0
- package/.claude-flow-novice/dist/src/validators/swarm-init-validator.js +261 -0
- package/.claude-flow-novice/dist/src/validators/swarm-init-validator.js.map +1 -0
- package/.claude-flow-novice/dist/src/validators/todowrite-batching-validator.js +204 -0
- package/.claude-flow-novice/dist/src/validators/todowrite-batching-validator.js.map +1 -0
- package/.claude-flow-novice/dist/src/validators/todowrite-integration.js +189 -0
- package/.claude-flow-novice/dist/src/validators/todowrite-integration.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Lifecycle Manager
|
|
3
|
+
* Handles server lifecycle operations including start, stop, restart, and health checks
|
|
4
|
+
*/ import { EventEmitter } from 'node:events';
|
|
5
|
+
import { MCPError } from '../utils/errors.js';
|
|
6
|
+
export var LifecycleState = /*#__PURE__*/ function(LifecycleState) {
|
|
7
|
+
LifecycleState["STOPPED"] = "stopped";
|
|
8
|
+
LifecycleState["STARTING"] = "starting";
|
|
9
|
+
LifecycleState["RUNNING"] = "running";
|
|
10
|
+
LifecycleState["STOPPING"] = "stopping";
|
|
11
|
+
LifecycleState["RESTARTING"] = "restarting";
|
|
12
|
+
LifecycleState["ERROR"] = "error";
|
|
13
|
+
return LifecycleState;
|
|
14
|
+
}({});
|
|
15
|
+
/**
|
|
16
|
+
* MCP Server Lifecycle Manager
|
|
17
|
+
* Manages the complete lifecycle of MCP servers with robust error handling
|
|
18
|
+
*/ export class MCPLifecycleManager extends EventEmitter {
|
|
19
|
+
mcpConfig;
|
|
20
|
+
logger;
|
|
21
|
+
serverFactory;
|
|
22
|
+
state = "stopped";
|
|
23
|
+
server;
|
|
24
|
+
healthCheckTimer;
|
|
25
|
+
startTime;
|
|
26
|
+
lastRestart;
|
|
27
|
+
restartAttempts = 0;
|
|
28
|
+
shutdownPromise;
|
|
29
|
+
history = [];
|
|
30
|
+
config = {
|
|
31
|
+
healthCheckInterval: 30000,
|
|
32
|
+
gracefulShutdownTimeout: 10000,
|
|
33
|
+
maxRestartAttempts: 3,
|
|
34
|
+
restartDelay: 5000,
|
|
35
|
+
enableAutoRestart: true,
|
|
36
|
+
enableHealthChecks: true
|
|
37
|
+
};
|
|
38
|
+
constructor(mcpConfig, logger, serverFactory, config){
|
|
39
|
+
super(), this.mcpConfig = mcpConfig, this.logger = logger, this.serverFactory = serverFactory;
|
|
40
|
+
if (config) {
|
|
41
|
+
Object.assign(this.config, config);
|
|
42
|
+
}
|
|
43
|
+
this.setupEventHandlers();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Start the MCP server
|
|
47
|
+
*/ async start() {
|
|
48
|
+
if (this.state !== "stopped") {
|
|
49
|
+
throw new MCPError(`Cannot start server in state: ${this.state}`);
|
|
50
|
+
}
|
|
51
|
+
this.setState("starting");
|
|
52
|
+
this.logger.info('Starting MCP server lifecycle manager');
|
|
53
|
+
try {
|
|
54
|
+
// Create server instance
|
|
55
|
+
this.server = this.serverFactory();
|
|
56
|
+
// Start the server
|
|
57
|
+
await this.server.start();
|
|
58
|
+
// Record start time
|
|
59
|
+
this.startTime = new Date();
|
|
60
|
+
this.restartAttempts = 0;
|
|
61
|
+
// Start health checks
|
|
62
|
+
if (this.config.enableHealthChecks) {
|
|
63
|
+
this.startHealthChecks();
|
|
64
|
+
}
|
|
65
|
+
this.setState("running");
|
|
66
|
+
this.logger.info('MCP server started successfully');
|
|
67
|
+
} catch (error) {
|
|
68
|
+
this.setState("error", error);
|
|
69
|
+
this.logger.error('Failed to start MCP server', error);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Stop the MCP server gracefully
|
|
75
|
+
*/ async stop() {
|
|
76
|
+
if (this.state === "stopped") {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (this.shutdownPromise) {
|
|
80
|
+
return this.shutdownPromise;
|
|
81
|
+
}
|
|
82
|
+
this.setState("stopping");
|
|
83
|
+
this.logger.info('Stopping MCP server');
|
|
84
|
+
this.shutdownPromise = this.performShutdown();
|
|
85
|
+
await this.shutdownPromise;
|
|
86
|
+
this.shutdownPromise = undefined;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Restart the MCP server
|
|
90
|
+
*/ async restart() {
|
|
91
|
+
if (this.state === "stopped") {
|
|
92
|
+
return this.start();
|
|
93
|
+
}
|
|
94
|
+
this.setState("restarting");
|
|
95
|
+
this.logger.info('Restarting MCP server');
|
|
96
|
+
try {
|
|
97
|
+
await this.stop();
|
|
98
|
+
// Add restart delay
|
|
99
|
+
if (this.config.restartDelay > 0) {
|
|
100
|
+
await new Promise((resolve)=>setTimeout(resolve, this.config.restartDelay));
|
|
101
|
+
}
|
|
102
|
+
await this.start();
|
|
103
|
+
this.lastRestart = new Date();
|
|
104
|
+
this.restartAttempts++;
|
|
105
|
+
this.logger.info('MCP server restarted successfully');
|
|
106
|
+
} catch (error) {
|
|
107
|
+
this.setState("error", error);
|
|
108
|
+
this.logger.error('Failed to restart MCP server', error);
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Perform comprehensive health check
|
|
114
|
+
*/ async healthCheck() {
|
|
115
|
+
const startTime = Date.now();
|
|
116
|
+
const result = {
|
|
117
|
+
healthy: false,
|
|
118
|
+
state: this.state,
|
|
119
|
+
uptime: this.getUptime(),
|
|
120
|
+
lastRestart: this.lastRestart,
|
|
121
|
+
components: {
|
|
122
|
+
server: false,
|
|
123
|
+
transport: false,
|
|
124
|
+
sessions: false,
|
|
125
|
+
tools: false,
|
|
126
|
+
auth: false,
|
|
127
|
+
loadBalancer: false
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
try {
|
|
131
|
+
if (!this.server || this.state !== "running") {
|
|
132
|
+
result.error = 'Server not running';
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
// Check server health
|
|
136
|
+
const serverHealth = await this.server.getHealthStatus();
|
|
137
|
+
result.components.server = serverHealth.healthy;
|
|
138
|
+
result.metrics = serverHealth.metrics;
|
|
139
|
+
if (serverHealth.error) {
|
|
140
|
+
result.error = serverHealth.error;
|
|
141
|
+
}
|
|
142
|
+
// Check individual components
|
|
143
|
+
result.components.transport = serverHealth.metrics?.transportConnections !== undefined;
|
|
144
|
+
result.components.sessions = serverHealth.metrics?.activeSessions !== undefined;
|
|
145
|
+
result.components.tools = (serverHealth.metrics?.registeredTools || 0) > 0;
|
|
146
|
+
result.components.auth = serverHealth.metrics?.authenticatedSessions !== undefined;
|
|
147
|
+
result.components.loadBalancer = serverHealth.metrics?.rateLimitedRequests !== undefined;
|
|
148
|
+
// Overall health assessment
|
|
149
|
+
result.healthy = result.components.server && result.components.transport && result.components.sessions && result.components.tools;
|
|
150
|
+
const checkDuration = Date.now() - startTime;
|
|
151
|
+
if (result.metrics) {
|
|
152
|
+
result.metrics.healthCheckDuration = checkDuration;
|
|
153
|
+
}
|
|
154
|
+
this.logger.debug('Health check completed', {
|
|
155
|
+
healthy: result.healthy,
|
|
156
|
+
duration: checkDuration,
|
|
157
|
+
components: result.components
|
|
158
|
+
});
|
|
159
|
+
return result;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
result.error = error instanceof Error ? error.message : 'Unknown error';
|
|
162
|
+
this.logger.error('Health check failed', error);
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get current server state
|
|
168
|
+
*/ getState() {
|
|
169
|
+
return this.state;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get server metrics
|
|
173
|
+
*/ getMetrics() {
|
|
174
|
+
return this.server?.getMetrics();
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Get active sessions
|
|
178
|
+
*/ getSessions() {
|
|
179
|
+
return this.server?.getSessions() || [];
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get server uptime in milliseconds
|
|
183
|
+
*/ getUptime() {
|
|
184
|
+
return this.startTime ? Date.now() - this.startTime.getTime() : 0;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get lifecycle event history
|
|
188
|
+
*/ getHistory() {
|
|
189
|
+
return [
|
|
190
|
+
...this.history
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Force terminate server (emergency stop)
|
|
195
|
+
*/ async forceStop() {
|
|
196
|
+
this.logger.warn('Force stopping MCP server');
|
|
197
|
+
// Stop health checks
|
|
198
|
+
this.stopHealthChecks();
|
|
199
|
+
// Force close server
|
|
200
|
+
if (this.server) {
|
|
201
|
+
try {
|
|
202
|
+
await this.server.stop();
|
|
203
|
+
} catch (error) {
|
|
204
|
+
this.logger.error('Error during force stop', error);
|
|
205
|
+
}
|
|
206
|
+
this.server = undefined;
|
|
207
|
+
}
|
|
208
|
+
this.setState("stopped");
|
|
209
|
+
this.startTime = undefined;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Enable or disable auto-restart
|
|
213
|
+
*/ setAutoRestart(enabled) {
|
|
214
|
+
this.config.enableAutoRestart = enabled;
|
|
215
|
+
this.logger.info('Auto-restart', {
|
|
216
|
+
enabled
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Enable or disable health checks
|
|
221
|
+
*/ setHealthChecks(enabled) {
|
|
222
|
+
this.config.enableHealthChecks = enabled;
|
|
223
|
+
if (enabled && this.state === "running") {
|
|
224
|
+
this.startHealthChecks();
|
|
225
|
+
} else {
|
|
226
|
+
this.stopHealthChecks();
|
|
227
|
+
}
|
|
228
|
+
this.logger.info('Health checks', {
|
|
229
|
+
enabled
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
setState(newState, error) {
|
|
233
|
+
const previousState = this.state;
|
|
234
|
+
this.state = newState;
|
|
235
|
+
const event = {
|
|
236
|
+
timestamp: new Date(),
|
|
237
|
+
state: newState,
|
|
238
|
+
previousState,
|
|
239
|
+
error
|
|
240
|
+
};
|
|
241
|
+
this.history.push(event);
|
|
242
|
+
// Keep only last 100 events
|
|
243
|
+
if (this.history.length > 100) {
|
|
244
|
+
this.history.shift();
|
|
245
|
+
}
|
|
246
|
+
this.emit('stateChange', event);
|
|
247
|
+
this.logger.info('State change', {
|
|
248
|
+
from: previousState,
|
|
249
|
+
to: newState,
|
|
250
|
+
error: error?.message
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
setupEventHandlers() {
|
|
254
|
+
// Handle uncaught errors
|
|
255
|
+
process.on('uncaughtException', (error)=>{
|
|
256
|
+
this.logger.error('Uncaught exception', error);
|
|
257
|
+
this.handleServerError(error);
|
|
258
|
+
});
|
|
259
|
+
process.on('unhandledRejection', (reason)=>{
|
|
260
|
+
this.logger.error('Unhandled rejection', reason);
|
|
261
|
+
this.handleServerError(reason instanceof Error ? reason : new Error(String(reason)));
|
|
262
|
+
});
|
|
263
|
+
// Handle process signals
|
|
264
|
+
process.on('SIGINT', ()=>{
|
|
265
|
+
this.logger.info('Received SIGINT, shutting down gracefully');
|
|
266
|
+
this.stop().catch((error)=>{
|
|
267
|
+
this.logger.error('Error during graceful shutdown', error);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
process.on('SIGTERM', ()=>{
|
|
272
|
+
this.logger.info('Received SIGTERM, shutting down gracefully');
|
|
273
|
+
this.stop().catch((error)=>{
|
|
274
|
+
this.logger.error('Error during graceful shutdown', error);
|
|
275
|
+
process.exit(1);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
async handleServerError(error) {
|
|
280
|
+
this.logger.error('Server error detected', error);
|
|
281
|
+
this.setState("error", error);
|
|
282
|
+
if (this.config.enableAutoRestart && this.restartAttempts < this.config.maxRestartAttempts) {
|
|
283
|
+
this.logger.info('Attempting auto-restart', {
|
|
284
|
+
attempt: this.restartAttempts + 1,
|
|
285
|
+
maxAttempts: this.config.maxRestartAttempts
|
|
286
|
+
});
|
|
287
|
+
try {
|
|
288
|
+
await this.restart();
|
|
289
|
+
} catch (restartError) {
|
|
290
|
+
this.logger.error('Auto-restart failed', restartError);
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
this.logger.error('Max restart attempts reached or auto-restart disabled');
|
|
294
|
+
await this.forceStop();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
startHealthChecks() {
|
|
298
|
+
if (this.healthCheckTimer) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
this.healthCheckTimer = setInterval(async ()=>{
|
|
302
|
+
try {
|
|
303
|
+
const health = await this.healthCheck();
|
|
304
|
+
if (!health.healthy && this.state === "running") {
|
|
305
|
+
this.logger.warn('Health check failed', health);
|
|
306
|
+
this.handleServerError(new Error(health.error || 'Health check failed'));
|
|
307
|
+
}
|
|
308
|
+
} catch (error) {
|
|
309
|
+
this.logger.error('Health check error', error);
|
|
310
|
+
}
|
|
311
|
+
}, this.config.healthCheckInterval);
|
|
312
|
+
this.logger.debug('Health checks started', {
|
|
313
|
+
interval: this.config.healthCheckInterval
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
stopHealthChecks() {
|
|
317
|
+
if (this.healthCheckTimer) {
|
|
318
|
+
clearInterval(this.healthCheckTimer);
|
|
319
|
+
this.healthCheckTimer = undefined;
|
|
320
|
+
this.logger.debug('Health checks stopped');
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async performShutdown() {
|
|
324
|
+
try {
|
|
325
|
+
// Stop health checks
|
|
326
|
+
this.stopHealthChecks();
|
|
327
|
+
// Graceful shutdown with timeout
|
|
328
|
+
const shutdownPromise = this.server?.stop() || Promise.resolve();
|
|
329
|
+
const timeoutPromise = new Promise((_, reject)=>{
|
|
330
|
+
setTimeout(()=>reject(new Error('Shutdown timeout')), this.config.gracefulShutdownTimeout);
|
|
331
|
+
});
|
|
332
|
+
await Promise.race([
|
|
333
|
+
shutdownPromise,
|
|
334
|
+
timeoutPromise
|
|
335
|
+
]);
|
|
336
|
+
this.server = undefined;
|
|
337
|
+
this.setState("stopped");
|
|
338
|
+
this.startTime = undefined;
|
|
339
|
+
this.logger.info('MCP server stopped successfully');
|
|
340
|
+
} catch (error) {
|
|
341
|
+
this.logger.error('Error during shutdown', error);
|
|
342
|
+
await this.forceStop();
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
//# sourceMappingURL=lifecycle-manager.js.map
|