@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,294 @@
1
+ /**
2
+ * V3 MCP Transport Factory
3
+ *
4
+ * Central factory for creating transport instances:
5
+ * - Unified transport creation API
6
+ * - Transport type validation
7
+ * - Configuration defaults
8
+ * - Multi-transport support
9
+ *
10
+ * Supported transports:
11
+ * - stdio: Standard I/O (default for CLI)
12
+ * - http: HTTP/REST with WebSocket upgrade
13
+ * - websocket: Standalone WebSocket
14
+ * - in-process: Direct function calls (fastest)
15
+ */
16
+
17
+ import {
18
+ ITransport,
19
+ TransportType,
20
+ TransportHealthStatus,
21
+ ILogger,
22
+ } from '../types.js';
23
+ import { StdioTransport, StdioTransportConfig, createStdioTransport } from './stdio.js';
24
+ import { HttpTransport, HttpTransportConfig, createHttpTransport } from './http.js';
25
+ import { WebSocketTransport, WebSocketTransportConfig, createWebSocketTransport } from './websocket.js';
26
+
27
+ // Re-export transport classes (values)
28
+ export { StdioTransport } from './stdio.js';
29
+ export { HttpTransport } from './http.js';
30
+ export { WebSocketTransport } from './websocket.js';
31
+
32
+ // Re-export transport config types
33
+ export type { StdioTransportConfig } from './stdio.js';
34
+ export type { HttpTransportConfig } from './http.js';
35
+ export type { WebSocketTransportConfig } from './websocket.js';
36
+
37
+ /**
38
+ * Transport configuration union
39
+ */
40
+ export type TransportConfig =
41
+ | { type: 'stdio' } & StdioTransportConfig
42
+ | { type: 'http' } & HttpTransportConfig
43
+ | { type: 'websocket' } & WebSocketTransportConfig
44
+ | { type: 'in-process' };
45
+
46
+ /**
47
+ * Create a transport instance based on type
48
+ */
49
+ export function createTransport(
50
+ type: TransportType,
51
+ logger: ILogger,
52
+ config?: Partial<TransportConfig>
53
+ ): ITransport {
54
+ switch (type) {
55
+ case 'stdio':
56
+ return createStdioTransport(logger, config as StdioTransportConfig);
57
+
58
+ case 'http':
59
+ if (!config || !('host' in config) || !('port' in config)) {
60
+ throw new Error('HTTP transport requires host and port configuration');
61
+ }
62
+ return createHttpTransport(logger, {
63
+ host: config.host as string,
64
+ port: config.port as number,
65
+ ...config,
66
+ } as HttpTransportConfig);
67
+
68
+ case 'websocket':
69
+ if (!config || !('host' in config) || !('port' in config)) {
70
+ throw new Error('WebSocket transport requires host and port configuration');
71
+ }
72
+ return createWebSocketTransport(logger, {
73
+ host: config.host as string,
74
+ port: config.port as number,
75
+ ...config,
76
+ } as WebSocketTransportConfig);
77
+
78
+ case 'in-process':
79
+ // In-process transport is handled directly by the server
80
+ // Return a no-op transport wrapper
81
+ return createInProcessTransport(logger);
82
+
83
+ default:
84
+ throw new Error(`Unknown transport type: ${type}`);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * In-process transport (no-op wrapper)
90
+ *
91
+ * Used when tools are executed directly without network transport
92
+ */
93
+ class InProcessTransport implements ITransport {
94
+ public readonly type: TransportType = 'in-process';
95
+
96
+ constructor(private readonly logger: ILogger) {}
97
+
98
+ async start(): Promise<void> {
99
+ this.logger.debug('In-process transport started');
100
+ }
101
+
102
+ async stop(): Promise<void> {
103
+ this.logger.debug('In-process transport stopped');
104
+ }
105
+
106
+ onRequest(): void {
107
+ // No-op - requests are handled directly
108
+ }
109
+
110
+ onNotification(): void {
111
+ // No-op - notifications are handled directly
112
+ }
113
+
114
+ async getHealthStatus(): Promise<TransportHealthStatus> {
115
+ return {
116
+ healthy: true,
117
+ metrics: {
118
+ latency: 0,
119
+ connections: 1,
120
+ },
121
+ };
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Create in-process transport
127
+ */
128
+ export function createInProcessTransport(logger: ILogger): ITransport {
129
+ return new InProcessTransport(logger);
130
+ }
131
+
132
+ /**
133
+ * Transport manager for multi-transport scenarios
134
+ */
135
+ export class TransportManager {
136
+ private transports: Map<string, ITransport> = new Map();
137
+ private running = false;
138
+
139
+ constructor(private readonly logger: ILogger) {}
140
+
141
+ /**
142
+ * Add a transport
143
+ */
144
+ addTransport(name: string, transport: ITransport): void {
145
+ if (this.transports.has(name)) {
146
+ throw new Error(`Transport "${name}" already exists`);
147
+ }
148
+ this.transports.set(name, transport);
149
+ this.logger.debug('Transport added', { name, type: transport.type });
150
+ }
151
+
152
+ /**
153
+ * Remove a transport
154
+ */
155
+ async removeTransport(name: string): Promise<boolean> {
156
+ const transport = this.transports.get(name);
157
+ if (!transport) {
158
+ return false;
159
+ }
160
+
161
+ await transport.stop();
162
+ this.transports.delete(name);
163
+ this.logger.debug('Transport removed', { name });
164
+ return true;
165
+ }
166
+
167
+ /**
168
+ * Get a transport by name
169
+ */
170
+ getTransport(name: string): ITransport | undefined {
171
+ return this.transports.get(name);
172
+ }
173
+
174
+ /**
175
+ * Get all transport names
176
+ */
177
+ getTransportNames(): string[] {
178
+ return Array.from(this.transports.keys());
179
+ }
180
+
181
+ /**
182
+ * Start all transports
183
+ */
184
+ async startAll(): Promise<void> {
185
+ if (this.running) {
186
+ throw new Error('TransportManager already running');
187
+ }
188
+
189
+ this.logger.info('Starting all transports', { count: this.transports.size });
190
+
191
+ const startPromises = Array.from(this.transports.entries()).map(
192
+ async ([name, transport]) => {
193
+ try {
194
+ await transport.start();
195
+ this.logger.info('Transport started', { name, type: transport.type });
196
+ } catch (error) {
197
+ this.logger.error('Failed to start transport', { name, error });
198
+ throw error;
199
+ }
200
+ }
201
+ );
202
+
203
+ await Promise.all(startPromises);
204
+ this.running = true;
205
+ this.logger.info('All transports started');
206
+ }
207
+
208
+ /**
209
+ * Stop all transports
210
+ */
211
+ async stopAll(): Promise<void> {
212
+ if (!this.running) {
213
+ return;
214
+ }
215
+
216
+ this.logger.info('Stopping all transports');
217
+
218
+ const stopPromises = Array.from(this.transports.entries()).map(
219
+ async ([name, transport]) => {
220
+ try {
221
+ await transport.stop();
222
+ this.logger.info('Transport stopped', { name });
223
+ } catch (error) {
224
+ this.logger.error('Error stopping transport', { name, error });
225
+ }
226
+ }
227
+ );
228
+
229
+ await Promise.all(stopPromises);
230
+ this.running = false;
231
+ this.logger.info('All transports stopped');
232
+ }
233
+
234
+ /**
235
+ * Get health status of all transports
236
+ */
237
+ async getHealthStatus(): Promise<Record<string, { healthy: boolean; error?: string }>> {
238
+ const results: Record<string, { healthy: boolean; error?: string }> = {};
239
+
240
+ for (const [name, transport] of this.transports) {
241
+ try {
242
+ const status = await transport.getHealthStatus();
243
+ results[name] = { healthy: status.healthy, error: status.error };
244
+ } catch (error) {
245
+ results[name] = {
246
+ healthy: false,
247
+ error: error instanceof Error ? error.message : 'Unknown error',
248
+ };
249
+ }
250
+ }
251
+
252
+ return results;
253
+ }
254
+
255
+ /**
256
+ * Check if any transport is running
257
+ */
258
+ isRunning(): boolean {
259
+ return this.running;
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Create a transport manager
265
+ */
266
+ export function createTransportManager(logger: ILogger): TransportManager {
267
+ return new TransportManager(logger);
268
+ }
269
+
270
+ /**
271
+ * Default transport configurations
272
+ */
273
+ export const DEFAULT_TRANSPORT_CONFIGS = {
274
+ stdio: {} as StdioTransportConfig,
275
+
276
+ http: {
277
+ host: 'localhost',
278
+ port: 3000,
279
+ corsEnabled: true,
280
+ corsOrigins: ['*'],
281
+ maxRequestSize: '10mb',
282
+ requestTimeout: 30000,
283
+ } as HttpTransportConfig,
284
+
285
+ websocket: {
286
+ host: 'localhost',
287
+ port: 3001,
288
+ path: '/ws',
289
+ maxConnections: 100,
290
+ heartbeatInterval: 30000,
291
+ heartbeatTimeout: 10000,
292
+ maxMessageSize: 10 * 1024 * 1024,
293
+ } as WebSocketTransportConfig,
294
+ } as const;
@@ -0,0 +1,324 @@
1
+ /**
2
+ * V3 MCP Stdio Transport
3
+ *
4
+ * Standard I/O transport for MCP communication:
5
+ * - Optimized JSON parsing with streaming
6
+ * - Buffer management for large messages
7
+ * - Graceful shutdown handling
8
+ *
9
+ * Performance Targets:
10
+ * - Message parsing: <5ms
11
+ * - Response sending: <2ms
12
+ */
13
+
14
+ import { EventEmitter } from 'events';
15
+ import * as readline from 'readline';
16
+ import {
17
+ ITransport,
18
+ TransportType,
19
+ MCPRequest,
20
+ MCPResponse,
21
+ MCPNotification,
22
+ RequestHandler,
23
+ NotificationHandler,
24
+ TransportHealthStatus,
25
+ ILogger,
26
+ } from '../types.js';
27
+
28
+ /**
29
+ * Stdio Transport Configuration
30
+ */
31
+ export interface StdioTransportConfig {
32
+ inputStream?: NodeJS.ReadableStream;
33
+ outputStream?: NodeJS.WritableStream;
34
+ maxMessageSize?: number;
35
+ }
36
+
37
+ /**
38
+ * Stdio Transport Implementation
39
+ *
40
+ * Uses readline for efficient line-by-line processing of JSON-RPC messages
41
+ */
42
+ export class StdioTransport extends EventEmitter implements ITransport {
43
+ public readonly type: TransportType = 'stdio';
44
+
45
+ private requestHandler?: RequestHandler;
46
+ private notificationHandler?: NotificationHandler;
47
+ private rl?: readline.Interface;
48
+ private running = false;
49
+ private messageBuffer = '';
50
+
51
+ // Statistics
52
+ private messagesReceived = 0;
53
+ private messagesSent = 0;
54
+ private errors = 0;
55
+
56
+ private readonly inputStream: NodeJS.ReadableStream;
57
+ private readonly outputStream: NodeJS.WritableStream;
58
+ private readonly maxMessageSize: number;
59
+
60
+ constructor(
61
+ private readonly logger: ILogger,
62
+ config: StdioTransportConfig = {}
63
+ ) {
64
+ super();
65
+ this.inputStream = config.inputStream || process.stdin;
66
+ this.outputStream = config.outputStream || process.stdout;
67
+ this.maxMessageSize = config.maxMessageSize || 10 * 1024 * 1024; // 10MB default
68
+ }
69
+
70
+ /**
71
+ * Start the transport
72
+ */
73
+ async start(): Promise<void> {
74
+ if (this.running) {
75
+ throw new Error('Stdio transport already running');
76
+ }
77
+
78
+ this.logger.info('Starting stdio transport');
79
+
80
+ // Create readline interface for efficient line processing
81
+ this.rl = readline.createInterface({
82
+ input: this.inputStream,
83
+ crlfDelay: Infinity,
84
+ });
85
+
86
+ // Handle incoming lines
87
+ this.rl.on('line', (line) => {
88
+ this.handleLine(line);
89
+ });
90
+
91
+ // Handle close
92
+ this.rl.on('close', () => {
93
+ this.handleClose();
94
+ });
95
+
96
+ // Handle errors on input stream
97
+ this.inputStream.on('error', (error) => {
98
+ this.handleError(error);
99
+ });
100
+
101
+ this.running = true;
102
+ this.logger.info('Stdio transport started');
103
+ }
104
+
105
+ /**
106
+ * Stop the transport
107
+ */
108
+ async stop(): Promise<void> {
109
+ if (!this.running) {
110
+ return;
111
+ }
112
+
113
+ this.logger.info('Stopping stdio transport');
114
+ this.running = false;
115
+
116
+ if (this.rl) {
117
+ this.rl.close();
118
+ this.rl = undefined;
119
+ }
120
+
121
+ this.logger.info('Stdio transport stopped');
122
+ }
123
+
124
+ /**
125
+ * Register request handler
126
+ */
127
+ onRequest(handler: RequestHandler): void {
128
+ this.requestHandler = handler;
129
+ }
130
+
131
+ /**
132
+ * Register notification handler
133
+ */
134
+ onNotification(handler: NotificationHandler): void {
135
+ this.notificationHandler = handler;
136
+ }
137
+
138
+ /**
139
+ * Get health status
140
+ */
141
+ async getHealthStatus(): Promise<TransportHealthStatus> {
142
+ return {
143
+ healthy: this.running,
144
+ metrics: {
145
+ messagesReceived: this.messagesReceived,
146
+ messagesSent: this.messagesSent,
147
+ errors: this.errors,
148
+ },
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Handle incoming line
154
+ */
155
+ private async handleLine(line: string): Promise<void> {
156
+ if (!line.trim()) {
157
+ return;
158
+ }
159
+
160
+ // Check message size
161
+ if (line.length > this.maxMessageSize) {
162
+ this.logger.error('Message exceeds maximum size', {
163
+ size: line.length,
164
+ max: this.maxMessageSize,
165
+ });
166
+ this.errors++;
167
+ return;
168
+ }
169
+
170
+ try {
171
+ const message = JSON.parse(line);
172
+ this.messagesReceived++;
173
+
174
+ // Validate JSON-RPC format
175
+ if (message.jsonrpc !== '2.0') {
176
+ this.logger.warn('Invalid JSON-RPC version', { received: message.jsonrpc });
177
+ await this.sendError(message.id, -32600, 'Invalid JSON-RPC version');
178
+ return;
179
+ }
180
+
181
+ if (!message.method) {
182
+ this.logger.warn('Missing method in request');
183
+ await this.sendError(message.id, -32600, 'Missing method');
184
+ return;
185
+ }
186
+
187
+ // Determine if this is a request or notification
188
+ if (message.id !== undefined) {
189
+ // Request - needs response
190
+ await this.handleRequest(message as MCPRequest);
191
+ } else {
192
+ // Notification - no response needed
193
+ await this.handleNotification(message as MCPNotification);
194
+ }
195
+ } catch (error) {
196
+ this.errors++;
197
+ this.logger.error('Failed to parse message', { error, line: line.substring(0, 100) });
198
+ await this.sendError(null, -32700, 'Parse error');
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Handle MCP request
204
+ */
205
+ private async handleRequest(request: MCPRequest): Promise<void> {
206
+ if (!this.requestHandler) {
207
+ this.logger.warn('No request handler registered');
208
+ await this.sendError(request.id, -32603, 'No request handler');
209
+ return;
210
+ }
211
+
212
+ try {
213
+ const startTime = performance.now();
214
+ const response = await this.requestHandler(request);
215
+ const duration = performance.now() - startTime;
216
+
217
+ this.logger.debug('Request processed', {
218
+ method: request.method,
219
+ duration: `${duration.toFixed(2)}ms`,
220
+ });
221
+
222
+ await this.sendResponse(response);
223
+ } catch (error) {
224
+ this.logger.error('Request handler error', { method: request.method, error });
225
+ await this.sendError(
226
+ request.id,
227
+ -32603,
228
+ error instanceof Error ? error.message : 'Internal error'
229
+ );
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Handle MCP notification
235
+ */
236
+ private async handleNotification(notification: MCPNotification): Promise<void> {
237
+ if (!this.notificationHandler) {
238
+ this.logger.debug('Notification received but no handler', { method: notification.method });
239
+ return;
240
+ }
241
+
242
+ try {
243
+ await this.notificationHandler(notification);
244
+ } catch (error) {
245
+ this.logger.error('Notification handler error', { method: notification.method, error });
246
+ // Notifications don't send error responses
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Send response to stdout
252
+ */
253
+ private async sendResponse(response: MCPResponse): Promise<void> {
254
+ const json = JSON.stringify(response);
255
+ await this.write(json);
256
+ this.messagesSent++;
257
+ }
258
+
259
+ /**
260
+ * Send error response
261
+ */
262
+ private async sendError(id: string | number | null, code: number, message: string): Promise<void> {
263
+ const response: MCPResponse = {
264
+ jsonrpc: '2.0',
265
+ id,
266
+ error: { code, message },
267
+ };
268
+ await this.sendResponse(response);
269
+ this.errors++;
270
+ }
271
+
272
+ /**
273
+ * Send notification to stdout
274
+ */
275
+ async sendNotification(notification: MCPNotification): Promise<void> {
276
+ const json = JSON.stringify(notification);
277
+ await this.write(json);
278
+ this.messagesSent++;
279
+ }
280
+
281
+ /**
282
+ * Write to output stream
283
+ */
284
+ private write(data: string): Promise<void> {
285
+ return new Promise((resolve, reject) => {
286
+ this.outputStream.write(data + '\n', (error) => {
287
+ if (error) {
288
+ this.errors++;
289
+ reject(error);
290
+ } else {
291
+ resolve();
292
+ }
293
+ });
294
+ });
295
+ }
296
+
297
+ /**
298
+ * Handle stream close
299
+ */
300
+ private handleClose(): void {
301
+ this.logger.info('Stdio stream closed');
302
+ this.running = false;
303
+ this.emit('close');
304
+ }
305
+
306
+ /**
307
+ * Handle stream error
308
+ */
309
+ private handleError(error: Error): void {
310
+ this.logger.error('Stdio stream error', error);
311
+ this.errors++;
312
+ this.emit('error', error);
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Create stdio transport
318
+ */
319
+ export function createStdioTransport(
320
+ logger: ILogger,
321
+ config: StdioTransportConfig = {}
322
+ ): StdioTransport {
323
+ return new StdioTransport(logger, config);
324
+ }