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,338 @@
1
+ /**
2
+ * Session manager for MCP connections
3
+ */ import { MCPError } from '../utils/errors.js';
4
+ import { createHash, timingSafeEqual } from 'node:crypto';
5
+ /**
6
+ * Session manager implementation
7
+ */ export class SessionManager {
8
+ config;
9
+ logger;
10
+ sessions = new Map();
11
+ authConfig;
12
+ sessionTimeout;
13
+ maxSessions;
14
+ cleanupInterval;
15
+ constructor(config, logger){
16
+ this.config = config;
17
+ this.logger = logger;
18
+ this.authConfig = config.auth || {
19
+ enabled: false,
20
+ method: 'token'
21
+ };
22
+ this.sessionTimeout = config.sessionTimeout || 3600000; // 1 hour default
23
+ this.maxSessions = config.maxSessions || 100;
24
+ // Start cleanup timer
25
+ this.cleanupInterval = setInterval(()=>{
26
+ this.cleanupExpiredSessions();
27
+ }, 60000); // Clean up every minute
28
+ }
29
+ createSession(transport) {
30
+ // Check session limit
31
+ if (this.sessions.size >= this.maxSessions) {
32
+ // Try to clean up expired sessions first
33
+ this.cleanupExpiredSessions();
34
+ if (this.sessions.size >= this.maxSessions) {
35
+ throw new MCPError('Maximum number of sessions reached');
36
+ }
37
+ }
38
+ const sessionId = this.generateSessionId();
39
+ const now = new Date();
40
+ const session = {
41
+ id: sessionId,
42
+ clientInfo: {
43
+ name: 'unknown',
44
+ version: 'unknown'
45
+ },
46
+ protocolVersion: {
47
+ major: 0,
48
+ minor: 0,
49
+ patch: 0
50
+ },
51
+ capabilities: {},
52
+ isInitialized: false,
53
+ createdAt: now,
54
+ lastActivity: now,
55
+ transport,
56
+ authenticated: !this.authConfig.enabled
57
+ };
58
+ this.sessions.set(sessionId, session);
59
+ this.logger.info('Session created', {
60
+ sessionId,
61
+ transport,
62
+ totalSessions: this.sessions.size
63
+ });
64
+ return session;
65
+ }
66
+ getSession(id) {
67
+ const session = this.sessions.get(id);
68
+ if (session && this.isSessionExpired(session)) {
69
+ this.removeSession(id);
70
+ return undefined;
71
+ }
72
+ return session;
73
+ }
74
+ initializeSession(sessionId, params) {
75
+ const session = this.getSession(sessionId);
76
+ if (!session) {
77
+ throw new MCPError(`Session not found: ${sessionId}`);
78
+ }
79
+ // Validate protocol version
80
+ this.validateProtocolVersion(params.protocolVersion);
81
+ // Update session with initialization params
82
+ session.clientInfo = params.clientInfo;
83
+ session.protocolVersion = params.protocolVersion;
84
+ session.capabilities = params.capabilities;
85
+ session.isInitialized = true;
86
+ session.lastActivity = new Date();
87
+ this.logger.info('Session initialized', {
88
+ sessionId,
89
+ clientInfo: params.clientInfo,
90
+ protocolVersion: params.protocolVersion
91
+ });
92
+ }
93
+ authenticateSession(sessionId, credentials) {
94
+ const session = this.getSession(sessionId);
95
+ if (!session) {
96
+ return false;
97
+ }
98
+ if (!this.authConfig.enabled) {
99
+ session.authenticated = true;
100
+ return true;
101
+ }
102
+ let authenticated = false;
103
+ switch(this.authConfig.method){
104
+ case 'token':
105
+ authenticated = this.authenticateToken(credentials);
106
+ break;
107
+ case 'basic':
108
+ authenticated = this.authenticateBasic(credentials);
109
+ break;
110
+ case 'oauth':
111
+ authenticated = this.authenticateOAuth(credentials);
112
+ break;
113
+ default:
114
+ this.logger.warn('Unknown authentication method', {
115
+ method: this.authConfig.method
116
+ });
117
+ return false;
118
+ }
119
+ if (authenticated) {
120
+ session.authenticated = true;
121
+ session.authData = this.extractAuthData(credentials);
122
+ session.lastActivity = new Date();
123
+ this.logger.info('Session authenticated', {
124
+ sessionId,
125
+ method: this.authConfig.method
126
+ });
127
+ } else {
128
+ this.logger.warn('Session authentication failed', {
129
+ sessionId,
130
+ method: this.authConfig.method
131
+ });
132
+ }
133
+ return authenticated;
134
+ }
135
+ updateActivity(sessionId) {
136
+ const session = this.getSession(sessionId);
137
+ if (session) {
138
+ session.lastActivity = new Date();
139
+ }
140
+ }
141
+ removeSession(sessionId) {
142
+ const session = this.sessions.get(sessionId);
143
+ if (session) {
144
+ this.sessions.delete(sessionId);
145
+ this.logger.info('Session removed', {
146
+ sessionId,
147
+ duration: Date.now() - session.createdAt.getTime(),
148
+ transport: session.transport
149
+ });
150
+ }
151
+ }
152
+ getActiveSessions() {
153
+ const activeSessions = [];
154
+ for (const session of this.sessions.values()){
155
+ if (!this.isSessionExpired(session)) {
156
+ activeSessions.push(session);
157
+ }
158
+ }
159
+ return activeSessions;
160
+ }
161
+ cleanupExpiredSessions() {
162
+ const expiredSessions = [];
163
+ for (const [sessionId, session] of this.sessions){
164
+ if (this.isSessionExpired(session)) {
165
+ expiredSessions.push(sessionId);
166
+ }
167
+ }
168
+ for (const sessionId of expiredSessions){
169
+ this.removeSession(sessionId);
170
+ }
171
+ if (expiredSessions.length > 0) {
172
+ this.logger.info('Cleaned up expired sessions', {
173
+ count: expiredSessions.length,
174
+ remainingSessions: this.sessions.size
175
+ });
176
+ }
177
+ }
178
+ getSessionMetrics() {
179
+ let active = 0;
180
+ let authenticated = 0;
181
+ let expired = 0;
182
+ for (const session of this.sessions.values()){
183
+ if (this.isSessionExpired(session)) {
184
+ expired++;
185
+ } else {
186
+ active++;
187
+ if (session.authenticated) {
188
+ authenticated++;
189
+ }
190
+ }
191
+ }
192
+ return {
193
+ total: this.sessions.size,
194
+ active,
195
+ authenticated,
196
+ expired
197
+ };
198
+ }
199
+ destroy() {
200
+ if (this.cleanupInterval) {
201
+ clearInterval(this.cleanupInterval);
202
+ }
203
+ this.sessions.clear();
204
+ }
205
+ generateSessionId() {
206
+ const timestamp = Date.now().toString(36);
207
+ const random = Math.random().toString(36).substr(2, 9);
208
+ return `session_${timestamp}_${random}`;
209
+ }
210
+ isSessionExpired(session) {
211
+ const now = Date.now();
212
+ const sessionAge = now - session.lastActivity.getTime();
213
+ return sessionAge > this.sessionTimeout;
214
+ }
215
+ validateProtocolVersion(version) {
216
+ // Currently supporting MCP version 2024-11-05
217
+ const supportedVersions = [
218
+ {
219
+ major: 2024,
220
+ minor: 11,
221
+ patch: 5
222
+ }
223
+ ];
224
+ const isSupported = supportedVersions.some((supported)=>supported.major === version.major && supported.minor === version.minor && supported.patch === version.patch);
225
+ if (!isSupported) {
226
+ throw new MCPError(`Unsupported protocol version: ${version.major}.${version.minor}.${version.patch}`, {
227
+ supportedVersions
228
+ });
229
+ }
230
+ }
231
+ authenticateToken(credentials) {
232
+ if (!this.authConfig.tokens || this.authConfig.tokens.length === 0) {
233
+ return false;
234
+ }
235
+ const token = this.extractToken(credentials);
236
+ if (!token) {
237
+ return false;
238
+ }
239
+ // Use timing-safe comparison to prevent timing attacks
240
+ return this.authConfig.tokens.some((validToken)=>{
241
+ const encoder = new TextEncoder();
242
+ const validTokenBytes = encoder.encode(validToken);
243
+ const providedTokenBytes = encoder.encode(token);
244
+ if (validTokenBytes.length !== providedTokenBytes.length) {
245
+ return false;
246
+ }
247
+ return timingSafeEqual(validTokenBytes, providedTokenBytes);
248
+ });
249
+ }
250
+ authenticateBasic(credentials) {
251
+ if (!this.authConfig.users || this.authConfig.users.length === 0) {
252
+ return false;
253
+ }
254
+ const { username, password } = this.extractBasicAuth(credentials);
255
+ if (!username || !password) {
256
+ return false;
257
+ }
258
+ const user = this.authConfig.users.find((u)=>u.username === username);
259
+ if (!user) {
260
+ return false;
261
+ }
262
+ // Hash the provided password and compare
263
+ const hashedPassword = this.hashPassword(password);
264
+ const expectedHashedPassword = this.hashPassword(user.password);
265
+ const encoder = new TextEncoder();
266
+ const hashedPasswordBytes = encoder.encode(hashedPassword);
267
+ const expectedHashedPasswordBytes = encoder.encode(expectedHashedPassword);
268
+ if (hashedPasswordBytes.length !== expectedHashedPasswordBytes.length) {
269
+ return false;
270
+ }
271
+ return timingSafeEqual(hashedPasswordBytes, expectedHashedPasswordBytes);
272
+ }
273
+ authenticateOAuth(credentials) {
274
+ // TODO: Implement OAuth authentication
275
+ // This would typically involve validating JWT tokens
276
+ this.logger.warn('OAuth authentication not yet implemented');
277
+ return false;
278
+ }
279
+ extractToken(credentials) {
280
+ if (typeof credentials === 'string') {
281
+ return credentials;
282
+ }
283
+ if (typeof credentials === 'object' && credentials !== null) {
284
+ const creds = credentials;
285
+ if (typeof creds.token === 'string') {
286
+ return creds.token;
287
+ }
288
+ if (typeof creds.authorization === 'string') {
289
+ const match = creds.authorization.match(/^Bearer\s+(.+)$/);
290
+ return match ? match[1] : null;
291
+ }
292
+ }
293
+ return null;
294
+ }
295
+ extractBasicAuth(credentials) {
296
+ if (typeof credentials === 'object' && credentials !== null) {
297
+ const creds = credentials;
298
+ if (typeof creds.username === 'string' && typeof creds.password === 'string') {
299
+ return {
300
+ username: creds.username,
301
+ password: creds.password
302
+ };
303
+ }
304
+ if (typeof creds.authorization === 'string') {
305
+ const match = creds.authorization.match(/^Basic\s+(.+)$/);
306
+ if (match) {
307
+ try {
308
+ const decoded = atob(match[1]);
309
+ const [username, password] = decoded.split(':', 2);
310
+ return {
311
+ username,
312
+ password
313
+ };
314
+ } catch {
315
+ return {};
316
+ }
317
+ }
318
+ }
319
+ }
320
+ return {};
321
+ }
322
+ extractAuthData(credentials) {
323
+ if (typeof credentials === 'object' && credentials !== null) {
324
+ const creds = credentials;
325
+ return {
326
+ token: this.extractToken(credentials),
327
+ user: creds.username || creds.user,
328
+ permissions: creds.permissions || []
329
+ };
330
+ }
331
+ return {};
332
+ }
333
+ hashPassword(password) {
334
+ return createHash('sha256').update(password).digest('hex');
335
+ }
336
+ }
337
+
338
+ //# sourceMappingURL=session-manager.js.map