@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,379 @@
1
+ /**
2
+ * V3 Hooks System - Hook Executor
3
+ *
4
+ * Executes hooks in priority order with timeout handling and error recovery.
5
+ * Integrates with event bus for coordination and monitoring.
6
+ *
7
+ * @module v3/shared/hooks/executor
8
+ */
9
+
10
+ import type { IEventBus } from '../core/interfaces/event.interface.js';
11
+ import { HookRegistry } from './registry.js';
12
+ import {
13
+ HookEvent,
14
+ HookContext,
15
+ HookResult,
16
+ HookExecutionOptions,
17
+ } from './types.js';
18
+
19
+ /**
20
+ * Hook execution result aggregation
21
+ */
22
+ export interface AggregatedHookResult {
23
+ /** Whether all hooks succeeded */
24
+ success: boolean;
25
+
26
+ /** Individual hook results */
27
+ results: HookResult[];
28
+
29
+ /** Total execution time in ms */
30
+ totalExecutionTime: number;
31
+
32
+ /** Number of hooks executed */
33
+ hooksExecuted: number;
34
+
35
+ /** Number of hooks failed */
36
+ hooksFailed: number;
37
+
38
+ /** Whether operation was aborted */
39
+ aborted: boolean;
40
+
41
+ /** Final merged context (from all hooks) */
42
+ finalContext?: Partial<HookContext>;
43
+ }
44
+
45
+ /**
46
+ * Hook executor implementation
47
+ */
48
+ export class HookExecutor {
49
+ private registry: HookRegistry;
50
+ private eventBus?: IEventBus;
51
+
52
+ constructor(registry: HookRegistry, eventBus?: IEventBus) {
53
+ this.registry = registry;
54
+ this.eventBus = eventBus;
55
+ }
56
+
57
+ /**
58
+ * Execute all hooks for an event
59
+ *
60
+ * @param event - Hook event type
61
+ * @param context - Hook context
62
+ * @param options - Execution options
63
+ * @returns Aggregated results
64
+ */
65
+ async execute(
66
+ event: HookEvent,
67
+ context: HookContext,
68
+ options: HookExecutionOptions = {}
69
+ ): Promise<AggregatedHookResult> {
70
+ const startTime = Date.now();
71
+ const results: HookResult[] = [];
72
+ let aborted = false;
73
+ let finalContext: Partial<HookContext> = {};
74
+
75
+ // Get enabled hooks for this event
76
+ const hooks = this.registry.getHandlers(event, false);
77
+
78
+ // Emit pre-execution event
79
+ this.eventBus?.emit('hooks:pre-execute', {
80
+ event,
81
+ hookCount: hooks.length,
82
+ context,
83
+ });
84
+
85
+ // Execute hooks in priority order
86
+ for (const hook of hooks) {
87
+ if (aborted) {
88
+ break;
89
+ }
90
+
91
+ try {
92
+ const result = await this.executeSingleHook(
93
+ hook.handler,
94
+ context,
95
+ hook.timeout || options.timeout
96
+ );
97
+
98
+ results.push(result);
99
+
100
+ // Record execution statistics
101
+ this.registry.recordExecution(result.success, result.executionTime || 0);
102
+
103
+ // Merge context modifications
104
+ if (result.data) {
105
+ finalContext = { ...finalContext, ...result.data };
106
+ // Update context for next hooks
107
+ Object.assign(context, result.data);
108
+ }
109
+
110
+ // Check if we should abort
111
+ if (result.abort) {
112
+ aborted = true;
113
+ break;
114
+ }
115
+
116
+ // Check if we should stop the chain
117
+ if (result.continueChain === false) {
118
+ break;
119
+ }
120
+
121
+ // Check if we should stop on error
122
+ if (!result.success && !options.continueOnError) {
123
+ aborted = true;
124
+ break;
125
+ }
126
+ } catch (error) {
127
+ const errorResult: HookResult = {
128
+ success: false,
129
+ error: error instanceof Error ? error : new Error(String(error)),
130
+ continueChain: options.continueOnError,
131
+ };
132
+
133
+ results.push(errorResult);
134
+ this.registry.recordExecution(false, 0);
135
+
136
+ // Emit error event
137
+ this.eventBus?.emit('hooks:error', {
138
+ event,
139
+ hookId: hook.id,
140
+ error,
141
+ });
142
+
143
+ if (!options.continueOnError) {
144
+ aborted = true;
145
+ break;
146
+ }
147
+ }
148
+ }
149
+
150
+ const totalExecutionTime = Date.now() - startTime;
151
+ const hooksFailed = results.filter(r => !r.success).length;
152
+
153
+ // Build aggregated result
154
+ const aggregatedResult: AggregatedHookResult = {
155
+ success: hooksFailed === 0 && !aborted,
156
+ results: options.collectResults ? results : [],
157
+ totalExecutionTime,
158
+ hooksExecuted: results.length,
159
+ hooksFailed,
160
+ aborted,
161
+ finalContext,
162
+ };
163
+
164
+ // Emit post-execution event
165
+ this.eventBus?.emit('hooks:post-execute', {
166
+ event,
167
+ ...aggregatedResult,
168
+ });
169
+
170
+ return aggregatedResult;
171
+ }
172
+
173
+ /**
174
+ * Execute hooks with timeout
175
+ *
176
+ * @param event - Hook event type
177
+ * @param context - Hook context
178
+ * @param timeout - Timeout in ms
179
+ * @returns Aggregated results
180
+ */
181
+ async executeWithTimeout(
182
+ event: HookEvent,
183
+ context: HookContext,
184
+ timeout: number
185
+ ): Promise<AggregatedHookResult> {
186
+ return this.withTimeout(
187
+ this.execute(event, context, { timeout }),
188
+ timeout
189
+ );
190
+ }
191
+
192
+ /**
193
+ * Execute a single hook with timeout and error handling
194
+ *
195
+ * @param handler - Hook handler function
196
+ * @param context - Hook context
197
+ * @param timeout - Optional timeout in ms
198
+ * @returns Hook result
199
+ */
200
+ private async executeSingleHook(
201
+ handler: (context: HookContext) => Promise<HookResult> | HookResult,
202
+ context: HookContext,
203
+ timeout?: number
204
+ ): Promise<HookResult> {
205
+ const startTime = Date.now();
206
+
207
+ try {
208
+ let resultPromise = Promise.resolve(handler(context));
209
+
210
+ // Apply timeout if specified
211
+ if (timeout && timeout > 0) {
212
+ resultPromise = this.withTimeout(resultPromise, timeout);
213
+ }
214
+
215
+ const result = await resultPromise;
216
+ const executionTime = Date.now() - startTime;
217
+
218
+ return {
219
+ ...result,
220
+ executionTime,
221
+ };
222
+ } catch (error) {
223
+ const executionTime = Date.now() - startTime;
224
+
225
+ return {
226
+ success: false,
227
+ error: error instanceof Error ? error : new Error(String(error)),
228
+ executionTime,
229
+ };
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Execute multiple hooks in parallel
235
+ *
236
+ * @param events - Array of hook events
237
+ * @param contexts - Array of contexts (matched by index)
238
+ * @param options - Execution options
239
+ * @returns Array of aggregated results
240
+ */
241
+ async executeParallel(
242
+ events: HookEvent[],
243
+ contexts: HookContext[],
244
+ options: HookExecutionOptions = {}
245
+ ): Promise<AggregatedHookResult[]> {
246
+ if (events.length !== contexts.length) {
247
+ throw new Error('Events and contexts arrays must have same length');
248
+ }
249
+
250
+ const maxParallel = options.maxParallel || events.length;
251
+ const results: AggregatedHookResult[] = [];
252
+
253
+ // Execute in batches
254
+ for (let i = 0; i < events.length; i += maxParallel) {
255
+ const batch = events.slice(i, i + maxParallel);
256
+ const batchContexts = contexts.slice(i, i + maxParallel);
257
+
258
+ const batchResults = await Promise.allSettled(
259
+ batch.map((event, index) =>
260
+ this.execute(event, batchContexts[index], options)
261
+ )
262
+ );
263
+
264
+ for (const result of batchResults) {
265
+ if (result.status === 'fulfilled') {
266
+ results.push(result.value);
267
+ } else {
268
+ // Create error result for rejected promises
269
+ results.push({
270
+ success: false,
271
+ results: [{
272
+ success: false,
273
+ error: result.reason instanceof Error
274
+ ? result.reason
275
+ : new Error(String(result.reason)),
276
+ }],
277
+ totalExecutionTime: 0,
278
+ hooksExecuted: 0,
279
+ hooksFailed: 1,
280
+ aborted: true,
281
+ });
282
+ }
283
+ }
284
+ }
285
+
286
+ return results;
287
+ }
288
+
289
+ /**
290
+ * Execute hooks sequentially with context chaining
291
+ *
292
+ * @param events - Array of hook events
293
+ * @param initialContext - Initial context
294
+ * @param options - Execution options
295
+ * @returns Final aggregated result with chained context
296
+ */
297
+ async executeSequential(
298
+ events: HookEvent[],
299
+ initialContext: HookContext,
300
+ options: HookExecutionOptions = {}
301
+ ): Promise<AggregatedHookResult> {
302
+ const results: HookResult[] = [];
303
+ let currentContext = { ...initialContext };
304
+ let totalExecutionTime = 0;
305
+ let aborted = false;
306
+
307
+ for (const event of events) {
308
+ if (aborted) {
309
+ break;
310
+ }
311
+
312
+ const result = await this.execute(event, currentContext, options);
313
+
314
+ results.push(...result.results);
315
+ totalExecutionTime += result.totalExecutionTime;
316
+
317
+ // Merge context for next event
318
+ if (result.finalContext) {
319
+ currentContext = { ...currentContext, ...result.finalContext };
320
+ }
321
+
322
+ if (result.aborted || !result.success) {
323
+ aborted = true;
324
+ break;
325
+ }
326
+ }
327
+
328
+ const hooksFailed = results.filter(r => !r.success).length;
329
+
330
+ return {
331
+ success: hooksFailed === 0 && !aborted,
332
+ results: options.collectResults ? results : [],
333
+ totalExecutionTime,
334
+ hooksExecuted: results.length,
335
+ hooksFailed,
336
+ aborted,
337
+ finalContext: currentContext,
338
+ };
339
+ }
340
+
341
+ /**
342
+ * Wrap a promise with timeout
343
+ */
344
+ private async withTimeout<T>(
345
+ promise: Promise<T>,
346
+ timeout: number
347
+ ): Promise<T> {
348
+ return Promise.race([
349
+ promise,
350
+ new Promise<T>((_, reject) =>
351
+ setTimeout(() => reject(new Error(`Hook execution timeout after ${timeout}ms`)), timeout)
352
+ ),
353
+ ]);
354
+ }
355
+
356
+ /**
357
+ * Set event bus for coordination
358
+ */
359
+ setEventBus(eventBus: IEventBus): void {
360
+ this.eventBus = eventBus;
361
+ }
362
+
363
+ /**
364
+ * Get hook registry
365
+ */
366
+ getRegistry(): HookRegistry {
367
+ return this.registry;
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Create a new hook executor
373
+ */
374
+ export function createHookExecutor(
375
+ registry: HookRegistry,
376
+ eventBus?: IEventBus
377
+ ): HookExecutor {
378
+ return new HookExecutor(registry, eventBus);
379
+ }