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.
Files changed (40) hide show
  1. package/.claude-flow-novice/dist/mcp/auth.js +347 -0
  2. package/.claude-flow-novice/dist/mcp/claude-code-wrapper.js +717 -0
  3. package/.claude-flow-novice/dist/mcp/claude-flow-tools.js +1365 -0
  4. package/.claude-flow-novice/dist/mcp/client.js +201 -0
  5. package/.claude-flow-novice/dist/mcp/index.js +192 -0
  6. package/.claude-flow-novice/dist/mcp/integrate-wrapper.js +85 -0
  7. package/.claude-flow-novice/dist/mcp/lifecycle-manager.js +348 -0
  8. package/.claude-flow-novice/dist/mcp/load-balancer.js +386 -0
  9. package/.claude-flow-novice/dist/mcp/mcp-config-manager.js +1362 -0
  10. package/.claude-flow-novice/dist/mcp/mcp-server-novice-simplified.js +583 -0
  11. package/.claude-flow-novice/dist/mcp/mcp-server-novice.js +723 -0
  12. package/.claude-flow-novice/dist/mcp/mcp-server-sdk.js +649 -0
  13. package/.claude-flow-novice/dist/mcp/mcp-server.js +2256 -0
  14. package/.claude-flow-novice/dist/mcp/orchestration-integration.js +800 -0
  15. package/.claude-flow-novice/dist/mcp/performance-monitor.js +489 -0
  16. package/.claude-flow-novice/dist/mcp/protocol-manager.js +376 -0
  17. package/.claude-flow-novice/dist/mcp/router.js +220 -0
  18. package/.claude-flow-novice/dist/mcp/ruv-swarm-tools.js +671 -0
  19. package/.claude-flow-novice/dist/mcp/ruv-swarm-wrapper.js +254 -0
  20. package/.claude-flow-novice/dist/mcp/server-with-wrapper.js +32 -0
  21. package/.claude-flow-novice/dist/mcp/server-wrapper-mode.js +26 -0
  22. package/.claude-flow-novice/dist/mcp/server.js +539 -0
  23. package/.claude-flow-novice/dist/mcp/session-manager.js +338 -0
  24. package/.claude-flow-novice/dist/mcp/sparc-modes.js +455 -0
  25. package/.claude-flow-novice/dist/mcp/swarm-tools.js +903 -0
  26. package/.claude-flow-novice/dist/mcp/tools.js +426 -0
  27. package/.claude-flow-novice/dist/src/cli/commands/swarm.js +23 -1
  28. package/.claude-flow-novice/dist/src/cli/commands/swarm.js.map +1 -1
  29. package/.claude-flow-novice/dist/src/cli/simple-commands/init/templates/CLAUDE.md +40 -101
  30. package/.claude-flow-novice/dist/src/coordination/swarm-coordinator-factory.js +36 -0
  31. package/.claude-flow-novice/dist/src/coordination/swarm-coordinator-factory.js.map +1 -0
  32. package/.claude-flow-novice/dist/src/validators/index.js +12 -0
  33. package/.claude-flow-novice/dist/src/validators/index.js.map +1 -0
  34. package/.claude-flow-novice/dist/src/validators/swarm-init-validator.js +261 -0
  35. package/.claude-flow-novice/dist/src/validators/swarm-init-validator.js.map +1 -0
  36. package/.claude-flow-novice/dist/src/validators/todowrite-batching-validator.js +204 -0
  37. package/.claude-flow-novice/dist/src/validators/todowrite-batching-validator.js.map +1 -0
  38. package/.claude-flow-novice/dist/src/validators/todowrite-integration.js +189 -0
  39. package/.claude-flow-novice/dist/src/validators/todowrite-integration.js.map +1 -0
  40. package/package.json +2 -2
@@ -0,0 +1,386 @@
1
+ /**
2
+ * Load balancer and rate limiting for MCP
3
+ */ import { MCPError } from '../utils/errors.js';
4
+ /**
5
+ * Circuit breaker state
6
+ */ var CircuitBreakerState = /*#__PURE__*/ function(CircuitBreakerState) {
7
+ CircuitBreakerState["CLOSED"] = "closed";
8
+ CircuitBreakerState["OPEN"] = "open";
9
+ CircuitBreakerState["HALF_OPEN"] = "half_open";
10
+ return CircuitBreakerState;
11
+ }(CircuitBreakerState || {});
12
+ /**
13
+ * Rate limiter using token bucket algorithm
14
+ */ let RateLimiter = class RateLimiter {
15
+ maxTokens;
16
+ refillRate;
17
+ tokens;
18
+ lastRefill;
19
+ constructor(maxTokens, refillRate){
20
+ this.maxTokens = maxTokens;
21
+ this.refillRate = refillRate;
22
+ this.tokens = maxTokens;
23
+ this.lastRefill = Date.now();
24
+ }
25
+ tryConsume(tokens = 1) {
26
+ this.refill();
27
+ if (this.tokens >= tokens) {
28
+ this.tokens -= tokens;
29
+ return true;
30
+ }
31
+ return false;
32
+ }
33
+ refill() {
34
+ const now = Date.now();
35
+ const timePassed = (now - this.lastRefill) / 1000;
36
+ const tokensToAdd = Math.floor(timePassed * this.refillRate);
37
+ if (tokensToAdd > 0) {
38
+ this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);
39
+ this.lastRefill = now;
40
+ }
41
+ }
42
+ getTokens() {
43
+ this.refill();
44
+ return this.tokens;
45
+ }
46
+ };
47
+ /**
48
+ * Circuit breaker implementation
49
+ */ let CircuitBreaker = class CircuitBreaker {
50
+ failureThreshold;
51
+ recoveryTimeout;
52
+ halfOpenMaxRequests;
53
+ state = "closed";
54
+ failureCount = 0;
55
+ lastFailureTime = 0;
56
+ successCount = 0;
57
+ constructor(failureThreshold, recoveryTimeout, halfOpenMaxRequests = 3){
58
+ this.failureThreshold = failureThreshold;
59
+ this.recoveryTimeout = recoveryTimeout;
60
+ this.halfOpenMaxRequests = halfOpenMaxRequests;
61
+ }
62
+ canExecute() {
63
+ const now = Date.now();
64
+ switch(this.state){
65
+ case "closed":
66
+ return true;
67
+ case "open":
68
+ if (now - this.lastFailureTime >= this.recoveryTimeout) {
69
+ this.state = "half_open";
70
+ this.successCount = 0;
71
+ return true;
72
+ }
73
+ return false;
74
+ case "half_open":
75
+ return this.successCount < this.halfOpenMaxRequests;
76
+ default:
77
+ return false;
78
+ }
79
+ }
80
+ recordSuccess() {
81
+ if (this.state === "half_open") {
82
+ this.successCount++;
83
+ if (this.successCount >= this.halfOpenMaxRequests) {
84
+ this.state = "closed";
85
+ this.failureCount = 0;
86
+ }
87
+ } else if (this.state === "closed") {
88
+ this.failureCount = 0;
89
+ }
90
+ }
91
+ recordFailure() {
92
+ this.failureCount++;
93
+ this.lastFailureTime = Date.now();
94
+ if (this.state === "half_open") {
95
+ this.state = "open";
96
+ } else if (this.state === "closed" && this.failureCount >= this.failureThreshold) {
97
+ this.state = "open";
98
+ }
99
+ }
100
+ getState() {
101
+ return this.state;
102
+ }
103
+ getMetrics() {
104
+ return {
105
+ state: this.state,
106
+ failureCount: this.failureCount,
107
+ successCount: this.successCount
108
+ };
109
+ }
110
+ };
111
+ /**
112
+ * Load balancer implementation
113
+ */ export class LoadBalancer {
114
+ config;
115
+ logger;
116
+ rateLimiter;
117
+ circuitBreaker;
118
+ sessionRateLimiters = new Map();
119
+ metrics;
120
+ requestTimes = [];
121
+ requestsInLastSecond = 0;
122
+ lastSecondTimestamp = 0;
123
+ constructor(config, logger){
124
+ this.config = config;
125
+ this.logger = logger;
126
+ this.rateLimiter = new RateLimiter(config.maxRequestsPerSecond, config.maxRequestsPerSecond);
127
+ this.circuitBreaker = new CircuitBreaker(config.circuitBreakerThreshold, 30000);
128
+ this.metrics = {
129
+ totalRequests: 0,
130
+ successfulRequests: 0,
131
+ failedRequests: 0,
132
+ rateLimitedRequests: 0,
133
+ averageResponseTime: 0,
134
+ requestsPerSecond: 0,
135
+ circuitBreakerTrips: 0,
136
+ lastReset: new Date()
137
+ };
138
+ // Clean up old session rate limiters periodically
139
+ setInterval(()=>{
140
+ this.cleanupSessionRateLimiters();
141
+ }, 300000); // Every 5 minutes
142
+ }
143
+ async shouldAllowRequest(session, request) {
144
+ if (!this.config.enabled) {
145
+ return true;
146
+ }
147
+ // Check circuit breaker
148
+ if (!this.circuitBreaker.canExecute()) {
149
+ this.logger.warn('Request rejected by circuit breaker', {
150
+ sessionId: session.id,
151
+ method: request.method,
152
+ circuitState: this.circuitBreaker.getState()
153
+ });
154
+ this.metrics.circuitBreakerTrips++;
155
+ return false;
156
+ }
157
+ // Check global rate limit
158
+ if (!this.rateLimiter.tryConsume()) {
159
+ this.logger.warn('Request rejected by global rate limiter', {
160
+ sessionId: session.id,
161
+ method: request.method,
162
+ remainingTokens: this.rateLimiter.getTokens()
163
+ });
164
+ this.metrics.rateLimitedRequests++;
165
+ return false;
166
+ }
167
+ // Check per-session rate limit
168
+ const sessionRateLimiter = this.getSessionRateLimiter(session.id);
169
+ if (!sessionRateLimiter.tryConsume()) {
170
+ this.logger.warn('Request rejected by session rate limiter', {
171
+ sessionId: session.id,
172
+ method: request.method,
173
+ remainingTokens: sessionRateLimiter.getTokens()
174
+ });
175
+ this.metrics.rateLimitedRequests++;
176
+ return false;
177
+ }
178
+ return true;
179
+ }
180
+ recordRequestStart(session, request) {
181
+ const requestMetrics = {
182
+ requestId: request.id.toString(),
183
+ sessionId: session.id,
184
+ method: request.method,
185
+ startTime: Date.now()
186
+ };
187
+ this.metrics.totalRequests++;
188
+ this.updateRequestsPerSecond();
189
+ this.logger.debug('Request started', {
190
+ requestId: requestMetrics.requestId,
191
+ sessionId: session.id,
192
+ method: request.method
193
+ });
194
+ return requestMetrics;
195
+ }
196
+ recordRequestEnd(metrics, response, error) {
197
+ metrics.endTime = Date.now();
198
+ const duration = metrics.endTime - metrics.startTime;
199
+ // Update response time tracking
200
+ this.requestTimes.push(duration);
201
+ if (this.requestTimes.length > 1000) {
202
+ this.requestTimes.shift(); // Keep only last 1000 requests
203
+ }
204
+ const success = !error && (!response || !response.error);
205
+ metrics.success = success;
206
+ const errorMessage = error?.message || response?.error?.message;
207
+ if (errorMessage) {
208
+ metrics.error = errorMessage;
209
+ }
210
+ if (success) {
211
+ this.metrics.successfulRequests++;
212
+ this.circuitBreaker.recordSuccess();
213
+ } else {
214
+ this.metrics.failedRequests++;
215
+ this.circuitBreaker.recordFailure();
216
+ }
217
+ // Update average response time
218
+ this.metrics.averageResponseTime = this.calculateAverageResponseTime();
219
+ this.logger.debug('Request completed', {
220
+ requestId: metrics.requestId,
221
+ sessionId: metrics.sessionId,
222
+ method: metrics.method,
223
+ duration,
224
+ success,
225
+ error: metrics.error
226
+ });
227
+ }
228
+ getMetrics() {
229
+ return {
230
+ ...this.metrics
231
+ };
232
+ }
233
+ resetMetrics() {
234
+ this.metrics = {
235
+ totalRequests: 0,
236
+ successfulRequests: 0,
237
+ failedRequests: 0,
238
+ rateLimitedRequests: 0,
239
+ averageResponseTime: 0,
240
+ requestsPerSecond: 0,
241
+ circuitBreakerTrips: 0,
242
+ lastReset: new Date()
243
+ };
244
+ this.requestTimes = [];
245
+ this.logger.info('Load balancer metrics reset');
246
+ }
247
+ isCircuitBreakerOpen() {
248
+ return this.circuitBreaker.getState() === "open";
249
+ }
250
+ getDetailedMetrics() {
251
+ return {
252
+ loadBalancer: this.getMetrics(),
253
+ circuitBreaker: this.circuitBreaker.getMetrics(),
254
+ rateLimiter: {
255
+ tokens: this.rateLimiter.getTokens(),
256
+ maxTokens: this.config.maxRequestsPerSecond
257
+ },
258
+ sessions: this.sessionRateLimiters.size
259
+ };
260
+ }
261
+ getSessionRateLimiter(sessionId) {
262
+ let rateLimiter = this.sessionRateLimiters.get(sessionId);
263
+ if (!rateLimiter) {
264
+ // Create a per-session rate limiter (more restrictive than global)
265
+ const sessionLimit = Math.max(1, Math.floor(this.config.maxRequestsPerSecond / 10));
266
+ rateLimiter = new RateLimiter(sessionLimit, sessionLimit);
267
+ this.sessionRateLimiters.set(sessionId, rateLimiter);
268
+ }
269
+ return rateLimiter;
270
+ }
271
+ calculateAverageResponseTime() {
272
+ if (this.requestTimes.length === 0) {
273
+ return 0;
274
+ }
275
+ const sum = this.requestTimes.reduce((acc, time)=>acc + time, 0);
276
+ return sum / this.requestTimes.length;
277
+ }
278
+ updateRequestsPerSecond() {
279
+ const now = Math.floor(Date.now() / 1000);
280
+ if (now !== this.lastSecondTimestamp) {
281
+ this.metrics.requestsPerSecond = this.requestsInLastSecond;
282
+ this.requestsInLastSecond = 1;
283
+ this.lastSecondTimestamp = now;
284
+ } else {
285
+ this.requestsInLastSecond++;
286
+ }
287
+ }
288
+ cleanupSessionRateLimiters() {
289
+ // Remove rate limiters for sessions that haven't been used recently
290
+ const cutoffTime = Date.now() - 300000; // 5 minutes ago
291
+ let cleaned = 0;
292
+ for (const [sessionId, rateLimiter] of this.sessionRateLimiters.entries()){
293
+ // If the rate limiter has full tokens, it hasn't been used recently
294
+ if (rateLimiter.getTokens() === this.config.maxRequestsPerSecond) {
295
+ this.sessionRateLimiters.delete(sessionId);
296
+ cleaned++;
297
+ }
298
+ }
299
+ if (cleaned > 0) {
300
+ this.logger.debug('Cleaned up session rate limiters', {
301
+ count: cleaned
302
+ });
303
+ }
304
+ }
305
+ }
306
+ /**
307
+ * Request queue for handling backpressure
308
+ */ export class RequestQueue {
309
+ logger;
310
+ queue = [];
311
+ processing = false;
312
+ maxQueueSize;
313
+ requestTimeout;
314
+ constructor(maxQueueSize = 1000, requestTimeout = 30000, logger){
315
+ this.logger = logger;
316
+ this.maxQueueSize = maxQueueSize;
317
+ this.requestTimeout = requestTimeout;
318
+ // Clean up expired requests periodically
319
+ setInterval(()=>{
320
+ this.cleanupExpiredRequests();
321
+ }, 10000); // Every 10 seconds
322
+ }
323
+ async enqueue(session, request, processor) {
324
+ if (this.queue.length >= this.maxQueueSize) {
325
+ throw new MCPError('Request queue is full');
326
+ }
327
+ return new Promise((resolve, reject)=>{
328
+ this.queue.push({
329
+ session,
330
+ request,
331
+ resolve,
332
+ reject,
333
+ timestamp: Date.now()
334
+ });
335
+ if (!this.processing) {
336
+ this.processQueue(processor);
337
+ }
338
+ });
339
+ }
340
+ async processQueue(processor) {
341
+ if (this.processing) {
342
+ return;
343
+ }
344
+ this.processing = true;
345
+ while(this.queue.length > 0){
346
+ const item = this.queue.shift();
347
+ // Check if request has expired
348
+ if (Date.now() - item.timestamp > this.requestTimeout) {
349
+ item.reject(new MCPError('Request timeout'));
350
+ continue;
351
+ }
352
+ try {
353
+ const result = await processor(item.session, item.request);
354
+ item.resolve(result);
355
+ } catch (error) {
356
+ item.reject(error instanceof Error ? error : new Error(String(error)));
357
+ }
358
+ }
359
+ this.processing = false;
360
+ }
361
+ cleanupExpiredRequests() {
362
+ const now = Date.now();
363
+ let cleaned = 0;
364
+ this.queue = this.queue.filter((item)=>{
365
+ if (now - item.timestamp > this.requestTimeout) {
366
+ item.reject(new MCPError('Request timeout'));
367
+ cleaned++;
368
+ return false;
369
+ }
370
+ return true;
371
+ });
372
+ if (cleaned > 0) {
373
+ this.logger.warn('Cleaned up expired requests from queue', {
374
+ count: cleaned
375
+ });
376
+ }
377
+ }
378
+ getQueueSize() {
379
+ return this.queue.length;
380
+ }
381
+ isProcessing() {
382
+ return this.processing;
383
+ }
384
+ }
385
+
386
+ //# sourceMappingURL=load-balancer.js.map