@sparkleideas/shared 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 (96) hide show
  1. package/README.md +323 -0
  2. package/__tests__/hooks/bash-safety.test.ts +289 -0
  3. package/__tests__/hooks/file-organization.test.ts +335 -0
  4. package/__tests__/hooks/git-commit.test.ts +336 -0
  5. package/__tests__/hooks/index.ts +23 -0
  6. package/__tests__/hooks/session-hooks.test.ts +357 -0
  7. package/__tests__/hooks/task-hooks.test.ts +193 -0
  8. package/docs/EVENTS_IMPLEMENTATION_SUMMARY.md +388 -0
  9. package/docs/EVENTS_QUICK_REFERENCE.md +470 -0
  10. package/docs/EVENTS_README.md +352 -0
  11. package/package.json +39 -0
  12. package/src/core/config/defaults.ts +207 -0
  13. package/src/core/config/index.ts +15 -0
  14. package/src/core/config/loader.ts +271 -0
  15. package/src/core/config/schema.ts +188 -0
  16. package/src/core/config/validator.ts +209 -0
  17. package/src/core/event-bus.ts +236 -0
  18. package/src/core/index.ts +22 -0
  19. package/src/core/interfaces/agent.interface.ts +251 -0
  20. package/src/core/interfaces/coordinator.interface.ts +363 -0
  21. package/src/core/interfaces/event.interface.ts +267 -0
  22. package/src/core/interfaces/index.ts +19 -0
  23. package/src/core/interfaces/memory.interface.ts +332 -0
  24. package/src/core/interfaces/task.interface.ts +223 -0
  25. package/src/core/orchestrator/event-coordinator.ts +122 -0
  26. package/src/core/orchestrator/health-monitor.ts +214 -0
  27. package/src/core/orchestrator/index.ts +89 -0
  28. package/src/core/orchestrator/lifecycle-manager.ts +263 -0
  29. package/src/core/orchestrator/session-manager.ts +279 -0
  30. package/src/core/orchestrator/task-manager.ts +317 -0
  31. package/src/events/domain-events.ts +584 -0
  32. package/src/events/event-store.test.ts +387 -0
  33. package/src/events/event-store.ts +588 -0
  34. package/src/events/example-usage.ts +293 -0
  35. package/src/events/index.ts +90 -0
  36. package/src/events/projections.ts +561 -0
  37. package/src/events/state-reconstructor.ts +349 -0
  38. package/src/events.ts +367 -0
  39. package/src/hooks/INTEGRATION.md +658 -0
  40. package/src/hooks/README.md +532 -0
  41. package/src/hooks/example-usage.ts +499 -0
  42. package/src/hooks/executor.ts +379 -0
  43. package/src/hooks/hooks.test.ts +421 -0
  44. package/src/hooks/index.ts +131 -0
  45. package/src/hooks/registry.ts +333 -0
  46. package/src/hooks/safety/bash-safety.ts +604 -0
  47. package/src/hooks/safety/file-organization.ts +473 -0
  48. package/src/hooks/safety/git-commit.ts +623 -0
  49. package/src/hooks/safety/index.ts +46 -0
  50. package/src/hooks/session-hooks.ts +559 -0
  51. package/src/hooks/task-hooks.ts +513 -0
  52. package/src/hooks/types.ts +357 -0
  53. package/src/hooks/verify-exports.test.ts +125 -0
  54. package/src/index.ts +195 -0
  55. package/src/mcp/connection-pool.ts +438 -0
  56. package/src/mcp/index.ts +183 -0
  57. package/src/mcp/server.ts +774 -0
  58. package/src/mcp/session-manager.ts +428 -0
  59. package/src/mcp/tool-registry.ts +566 -0
  60. package/src/mcp/transport/http.ts +557 -0
  61. package/src/mcp/transport/index.ts +294 -0
  62. package/src/mcp/transport/stdio.ts +324 -0
  63. package/src/mcp/transport/websocket.ts +484 -0
  64. package/src/mcp/types.ts +565 -0
  65. package/src/plugin-interface.ts +663 -0
  66. package/src/plugin-loader.ts +638 -0
  67. package/src/plugin-registry.ts +604 -0
  68. package/src/plugins/index.ts +34 -0
  69. package/src/plugins/official/hive-mind-plugin.ts +330 -0
  70. package/src/plugins/official/index.ts +24 -0
  71. package/src/plugins/official/maestro-plugin.ts +508 -0
  72. package/src/plugins/types.ts +108 -0
  73. package/src/resilience/bulkhead.ts +277 -0
  74. package/src/resilience/circuit-breaker.ts +326 -0
  75. package/src/resilience/index.ts +26 -0
  76. package/src/resilience/rate-limiter.ts +420 -0
  77. package/src/resilience/retry.ts +224 -0
  78. package/src/security/index.ts +39 -0
  79. package/src/security/input-validation.ts +265 -0
  80. package/src/security/secure-random.ts +159 -0
  81. package/src/services/index.ts +16 -0
  82. package/src/services/v3-progress.service.ts +505 -0
  83. package/src/types/agent.types.ts +144 -0
  84. package/src/types/index.ts +22 -0
  85. package/src/types/mcp.types.ts +300 -0
  86. package/src/types/memory.types.ts +263 -0
  87. package/src/types/swarm.types.ts +255 -0
  88. package/src/types/task.types.ts +205 -0
  89. package/src/types.ts +367 -0
  90. package/src/utils/secure-logger.d.ts +69 -0
  91. package/src/utils/secure-logger.d.ts.map +1 -0
  92. package/src/utils/secure-logger.js +208 -0
  93. package/src/utils/secure-logger.js.map +1 -0
  94. package/src/utils/secure-logger.ts +257 -0
  95. package/tmp.json +0 -0
  96. package/tsconfig.json +9 -0
@@ -0,0 +1,428 @@
1
+ /**
2
+ * V3 MCP Session Manager
3
+ *
4
+ * Manages MCP sessions with:
5
+ * - Session lifecycle management
6
+ * - Authentication integration
7
+ * - Session timeout handling
8
+ * - Concurrent session support
9
+ * - Session metrics and monitoring
10
+ *
11
+ * Performance Targets:
12
+ * - Session creation: <5ms
13
+ * - Session lookup: <1ms
14
+ * - Session cleanup: <10ms
15
+ */
16
+
17
+ import { EventEmitter } from 'events';
18
+ import {
19
+ MCPSession,
20
+ SessionState,
21
+ SessionMetrics,
22
+ MCPInitializeParams,
23
+ MCPCapabilities,
24
+ MCPClientInfo,
25
+ MCPProtocolVersion,
26
+ TransportType,
27
+ ILogger,
28
+ } from './types.js';
29
+
30
+ /**
31
+ * Session configuration
32
+ */
33
+ export interface SessionConfig {
34
+ maxSessions?: number;
35
+ sessionTimeout?: number;
36
+ cleanupInterval?: number;
37
+ enableMetrics?: boolean;
38
+ }
39
+
40
+ /**
41
+ * Default session configuration
42
+ */
43
+ const DEFAULT_SESSION_CONFIG: Required<SessionConfig> = {
44
+ maxSessions: 100,
45
+ sessionTimeout: 30 * 60 * 1000, // 30 minutes
46
+ cleanupInterval: 60 * 1000, // 1 minute
47
+ enableMetrics: true,
48
+ };
49
+
50
+ /**
51
+ * Session Manager
52
+ *
53
+ * Handles creation, tracking, and cleanup of MCP sessions
54
+ */
55
+ export class SessionManager extends EventEmitter {
56
+ private readonly sessions: Map<string, MCPSession> = new Map();
57
+ private readonly config: Required<SessionConfig>;
58
+ private cleanupTimer?: NodeJS.Timeout;
59
+ private sessionCounter = 0;
60
+
61
+ // Statistics
62
+ private totalCreated = 0;
63
+ private totalClosed = 0;
64
+ private totalExpired = 0;
65
+
66
+ constructor(
67
+ private readonly logger: ILogger,
68
+ config: SessionConfig = {}
69
+ ) {
70
+ super();
71
+ this.config = { ...DEFAULT_SESSION_CONFIG, ...config };
72
+ this.startCleanupTimer();
73
+ }
74
+
75
+ /**
76
+ * Create a new session
77
+ */
78
+ createSession(transport: TransportType): MCPSession {
79
+ // Check max sessions
80
+ if (this.sessions.size >= this.config.maxSessions) {
81
+ throw new Error(`Maximum sessions (${this.config.maxSessions}) reached`);
82
+ }
83
+
84
+ const id = this.generateSessionId();
85
+ const now = new Date();
86
+
87
+ const session: MCPSession = {
88
+ id,
89
+ state: 'created',
90
+ transport,
91
+ createdAt: now,
92
+ lastActivityAt: now,
93
+ isInitialized: false,
94
+ isAuthenticated: false,
95
+ };
96
+
97
+ this.sessions.set(id, session);
98
+ this.totalCreated++;
99
+
100
+ this.logger.debug('Session created', { id, transport });
101
+ this.emit('session:created', session);
102
+
103
+ return session;
104
+ }
105
+
106
+ /**
107
+ * Initialize a session with client information
108
+ */
109
+ initializeSession(
110
+ sessionId: string,
111
+ params: MCPInitializeParams
112
+ ): MCPSession | undefined {
113
+ const session = this.sessions.get(sessionId);
114
+ if (!session) {
115
+ this.logger.warn('Session not found for initialization', { sessionId });
116
+ return undefined;
117
+ }
118
+
119
+ session.state = 'ready';
120
+ session.isInitialized = true;
121
+ session.clientInfo = params.clientInfo;
122
+ session.protocolVersion = params.protocolVersion;
123
+ session.capabilities = params.capabilities;
124
+ session.lastActivityAt = new Date();
125
+
126
+ this.logger.info('Session initialized', {
127
+ sessionId,
128
+ clientInfo: params.clientInfo,
129
+ protocolVersion: params.protocolVersion,
130
+ });
131
+
132
+ this.emit('session:initialized', session);
133
+ return session;
134
+ }
135
+
136
+ /**
137
+ * Authenticate a session
138
+ */
139
+ authenticateSession(sessionId: string): boolean {
140
+ const session = this.sessions.get(sessionId);
141
+ if (!session) {
142
+ return false;
143
+ }
144
+
145
+ session.isAuthenticated = true;
146
+ session.lastActivityAt = new Date();
147
+
148
+ this.logger.debug('Session authenticated', { sessionId });
149
+ this.emit('session:authenticated', session);
150
+
151
+ return true;
152
+ }
153
+
154
+ /**
155
+ * Get a session by ID
156
+ */
157
+ getSession(sessionId: string): MCPSession | undefined {
158
+ return this.sessions.get(sessionId);
159
+ }
160
+
161
+ /**
162
+ * Check if session exists
163
+ */
164
+ hasSession(sessionId: string): boolean {
165
+ return this.sessions.has(sessionId);
166
+ }
167
+
168
+ /**
169
+ * Get all active sessions
170
+ */
171
+ getActiveSessions(): MCPSession[] {
172
+ return Array.from(this.sessions.values()).filter(
173
+ (s) => s.state === 'ready' || s.state === 'created' || s.state === 'initializing'
174
+ );
175
+ }
176
+
177
+ /**
178
+ * Update session activity timestamp
179
+ */
180
+ updateActivity(sessionId: string): boolean {
181
+ const session = this.sessions.get(sessionId);
182
+ if (!session) {
183
+ return false;
184
+ }
185
+
186
+ session.lastActivityAt = new Date();
187
+ return true;
188
+ }
189
+
190
+ /**
191
+ * Set session state
192
+ */
193
+ setState(sessionId: string, state: SessionState): boolean {
194
+ const session = this.sessions.get(sessionId);
195
+ if (!session) {
196
+ return false;
197
+ }
198
+
199
+ const oldState = session.state;
200
+ session.state = state;
201
+ session.lastActivityAt = new Date();
202
+
203
+ this.logger.debug('Session state changed', {
204
+ sessionId,
205
+ oldState,
206
+ newState: state,
207
+ });
208
+
209
+ this.emit('session:stateChanged', { session, oldState, newState: state });
210
+ return true;
211
+ }
212
+
213
+ /**
214
+ * Set session metadata
215
+ */
216
+ setMetadata(sessionId: string, key: string, value: unknown): boolean {
217
+ const session = this.sessions.get(sessionId);
218
+ if (!session) {
219
+ return false;
220
+ }
221
+
222
+ if (!session.metadata) {
223
+ session.metadata = {};
224
+ }
225
+ session.metadata[key] = value;
226
+ session.lastActivityAt = new Date();
227
+
228
+ return true;
229
+ }
230
+
231
+ /**
232
+ * Get session metadata
233
+ */
234
+ getMetadata(sessionId: string, key: string): unknown {
235
+ const session = this.sessions.get(sessionId);
236
+ return session?.metadata?.[key];
237
+ }
238
+
239
+ /**
240
+ * Close a session
241
+ */
242
+ closeSession(sessionId: string, reason?: string): boolean {
243
+ const session = this.sessions.get(sessionId);
244
+ if (!session) {
245
+ return false;
246
+ }
247
+
248
+ session.state = 'closed';
249
+ this.sessions.delete(sessionId);
250
+ this.totalClosed++;
251
+
252
+ this.logger.info('Session closed', { sessionId, reason });
253
+ this.emit('session:closed', { session, reason });
254
+
255
+ return true;
256
+ }
257
+
258
+ /**
259
+ * Remove a session (alias for closeSession)
260
+ */
261
+ removeSession(sessionId: string): boolean {
262
+ return this.closeSession(sessionId);
263
+ }
264
+
265
+ /**
266
+ * Get session metrics
267
+ */
268
+ getSessionMetrics(): SessionMetrics {
269
+ let authenticated = 0;
270
+ let active = 0;
271
+
272
+ for (const session of this.sessions.values()) {
273
+ if (session.isAuthenticated) authenticated++;
274
+ if (session.state === 'ready') active++;
275
+ }
276
+
277
+ return {
278
+ total: this.sessions.size,
279
+ active,
280
+ authenticated,
281
+ expired: this.totalExpired,
282
+ };
283
+ }
284
+
285
+ /**
286
+ * Get detailed statistics
287
+ */
288
+ getStats(): {
289
+ total: number;
290
+ byState: Record<SessionState, number>;
291
+ byTransport: Record<TransportType, number>;
292
+ totalCreated: number;
293
+ totalClosed: number;
294
+ totalExpired: number;
295
+ oldestSession?: Date;
296
+ newestSession?: Date;
297
+ } {
298
+ const byState: Record<string, number> = {
299
+ created: 0,
300
+ initializing: 0,
301
+ ready: 0,
302
+ closing: 0,
303
+ closed: 0,
304
+ error: 0,
305
+ };
306
+
307
+ const byTransport: Record<string, number> = {
308
+ stdio: 0,
309
+ http: 0,
310
+ websocket: 0,
311
+ 'in-process': 0,
312
+ };
313
+
314
+ let oldest: Date | undefined;
315
+ let newest: Date | undefined;
316
+
317
+ for (const session of this.sessions.values()) {
318
+ byState[session.state] = (byState[session.state] || 0) + 1;
319
+ byTransport[session.transport] = (byTransport[session.transport] || 0) + 1;
320
+
321
+ if (!oldest || session.createdAt < oldest) {
322
+ oldest = session.createdAt;
323
+ }
324
+ if (!newest || session.createdAt > newest) {
325
+ newest = session.createdAt;
326
+ }
327
+ }
328
+
329
+ return {
330
+ total: this.sessions.size,
331
+ byState: byState as Record<SessionState, number>,
332
+ byTransport: byTransport as Record<TransportType, number>,
333
+ totalCreated: this.totalCreated,
334
+ totalClosed: this.totalClosed,
335
+ totalExpired: this.totalExpired,
336
+ oldestSession: oldest,
337
+ newestSession: newest,
338
+ };
339
+ }
340
+
341
+ /**
342
+ * Clean up expired sessions
343
+ */
344
+ cleanupExpiredSessions(): number {
345
+ const now = Date.now();
346
+ const expired: string[] = [];
347
+
348
+ for (const [id, session] of this.sessions) {
349
+ const inactiveTime = now - session.lastActivityAt.getTime();
350
+ if (inactiveTime > this.config.sessionTimeout) {
351
+ expired.push(id);
352
+ }
353
+ }
354
+
355
+ for (const id of expired) {
356
+ const session = this.sessions.get(id);
357
+ if (session) {
358
+ session.state = 'closed';
359
+ this.sessions.delete(id);
360
+ this.totalExpired++;
361
+ this.logger.info('Session expired', { sessionId: id });
362
+ this.emit('session:expired', session);
363
+ }
364
+ }
365
+
366
+ if (expired.length > 0) {
367
+ this.logger.info('Cleaned up expired sessions', { count: expired.length });
368
+ }
369
+
370
+ return expired.length;
371
+ }
372
+
373
+ /**
374
+ * Start cleanup timer
375
+ */
376
+ private startCleanupTimer(): void {
377
+ this.cleanupTimer = setInterval(() => {
378
+ this.cleanupExpiredSessions();
379
+ }, this.config.cleanupInterval);
380
+ }
381
+
382
+ /**
383
+ * Stop cleanup timer
384
+ */
385
+ private stopCleanupTimer(): void {
386
+ if (this.cleanupTimer) {
387
+ clearInterval(this.cleanupTimer);
388
+ this.cleanupTimer = undefined;
389
+ }
390
+ }
391
+
392
+ /**
393
+ * Generate a unique session ID
394
+ */
395
+ private generateSessionId(): string {
396
+ return `session-${++this.sessionCounter}-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
397
+ }
398
+
399
+ /**
400
+ * Clear all sessions
401
+ */
402
+ clearAll(): void {
403
+ for (const id of this.sessions.keys()) {
404
+ this.closeSession(id, 'Session manager cleared');
405
+ }
406
+ this.logger.info('All sessions cleared');
407
+ }
408
+
409
+ /**
410
+ * Destroy the session manager
411
+ */
412
+ destroy(): void {
413
+ this.stopCleanupTimer();
414
+ this.clearAll();
415
+ this.removeAllListeners();
416
+ this.logger.info('Session manager destroyed');
417
+ }
418
+ }
419
+
420
+ /**
421
+ * Create a session manager
422
+ */
423
+ export function createSessionManager(
424
+ logger: ILogger,
425
+ config?: SessionConfig
426
+ ): SessionManager {
427
+ return new SessionManager(logger, config);
428
+ }