musubi-sdd 3.10.0 → 5.1.0

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 (44) hide show
  1. package/README.md +24 -19
  2. package/package.json +1 -1
  3. package/src/agents/agent-loop.js +532 -0
  4. package/src/agents/agentic/code-generator.js +767 -0
  5. package/src/agents/agentic/code-reviewer.js +698 -0
  6. package/src/agents/agentic/index.js +43 -0
  7. package/src/agents/function-tool.js +432 -0
  8. package/src/agents/index.js +45 -0
  9. package/src/agents/schema-generator.js +514 -0
  10. package/src/analyzers/ast-extractor.js +870 -0
  11. package/src/analyzers/context-optimizer.js +681 -0
  12. package/src/analyzers/repository-map.js +692 -0
  13. package/src/integrations/index.js +7 -1
  14. package/src/integrations/mcp/index.js +175 -0
  15. package/src/integrations/mcp/mcp-context-provider.js +472 -0
  16. package/src/integrations/mcp/mcp-discovery.js +436 -0
  17. package/src/integrations/mcp/mcp-tool-registry.js +467 -0
  18. package/src/integrations/mcp-connector.js +818 -0
  19. package/src/integrations/tool-discovery.js +589 -0
  20. package/src/managers/index.js +7 -0
  21. package/src/managers/skill-tools.js +565 -0
  22. package/src/monitoring/cost-tracker.js +7 -0
  23. package/src/monitoring/incident-manager.js +10 -0
  24. package/src/monitoring/observability.js +10 -0
  25. package/src/monitoring/quality-dashboard.js +491 -0
  26. package/src/monitoring/release-manager.js +10 -0
  27. package/src/orchestration/agent-skill-binding.js +655 -0
  28. package/src/orchestration/error-handler.js +827 -0
  29. package/src/orchestration/index.js +235 -1
  30. package/src/orchestration/mcp-tool-adapters.js +896 -0
  31. package/src/orchestration/reasoning/index.js +58 -0
  32. package/src/orchestration/reasoning/planning-engine.js +831 -0
  33. package/src/orchestration/reasoning/reasoning-engine.js +710 -0
  34. package/src/orchestration/reasoning/self-correction.js +751 -0
  35. package/src/orchestration/skill-executor.js +665 -0
  36. package/src/orchestration/skill-registry.js +650 -0
  37. package/src/orchestration/workflow-examples.js +1072 -0
  38. package/src/orchestration/workflow-executor.js +779 -0
  39. package/src/phase4-integration.js +248 -0
  40. package/src/phase5-integration.js +402 -0
  41. package/src/steering/steering-auto-update.js +572 -0
  42. package/src/steering/steering-validator.js +547 -0
  43. package/src/templates/template-constraints.js +646 -0
  44. package/src/validators/advanced-validation.js +580 -0
@@ -0,0 +1,827 @@
1
+ /**
2
+ * ErrorHandler - Comprehensive error handling patterns
3
+ * Sprint 3.5: Advanced Workflows
4
+ *
5
+ * Provides:
6
+ * - Error classification and categorization
7
+ * - Recovery strategies
8
+ * - Error aggregation and reporting
9
+ * - Circuit breaker pattern
10
+ * - Graceful degradation
11
+ */
12
+
13
+ const EventEmitter = require('events');
14
+
15
+ /**
16
+ * Error severity levels
17
+ */
18
+ const ErrorSeverity = {
19
+ LOW: 'low',
20
+ MEDIUM: 'medium',
21
+ HIGH: 'high',
22
+ CRITICAL: 'critical'
23
+ };
24
+
25
+ /**
26
+ * Error categories
27
+ */
28
+ const ErrorCategory = {
29
+ VALIDATION: 'validation',
30
+ AUTHENTICATION: 'authentication',
31
+ AUTHORIZATION: 'authorization',
32
+ NETWORK: 'network',
33
+ TIMEOUT: 'timeout',
34
+ RATE_LIMIT: 'rate-limit',
35
+ RESOURCE_NOT_FOUND: 'resource-not-found',
36
+ CONFLICT: 'conflict',
37
+ INTERNAL: 'internal',
38
+ EXTERNAL_SERVICE: 'external-service',
39
+ CONFIGURATION: 'configuration',
40
+ USER_INPUT: 'user-input',
41
+ UNKNOWN: 'unknown'
42
+ };
43
+
44
+ /**
45
+ * Circuit breaker states
46
+ */
47
+ const CircuitState = {
48
+ CLOSED: 'closed',
49
+ OPEN: 'open',
50
+ HALF_OPEN: 'half-open'
51
+ };
52
+
53
+ /**
54
+ * Enhanced error with metadata
55
+ */
56
+ class WorkflowError extends Error {
57
+ constructor(message, options = {}) {
58
+ super(message);
59
+ this.name = 'WorkflowError';
60
+ this.code = options.code || 'WORKFLOW_ERROR';
61
+ this.category = options.category || ErrorCategory.UNKNOWN;
62
+ this.severity = options.severity || ErrorSeverity.MEDIUM;
63
+ this.recoverable = options.recoverable !== false;
64
+ this.retryable = options.retryable || false;
65
+ this.context = options.context || {};
66
+ this.cause = options.cause || null;
67
+ this.timestamp = new Date().toISOString();
68
+ this.suggestions = options.suggestions || [];
69
+ }
70
+
71
+ toJSON() {
72
+ return {
73
+ name: this.name,
74
+ message: this.message,
75
+ code: this.code,
76
+ category: this.category,
77
+ severity: this.severity,
78
+ recoverable: this.recoverable,
79
+ retryable: this.retryable,
80
+ context: this.context,
81
+ timestamp: this.timestamp,
82
+ suggestions: this.suggestions,
83
+ stack: this.stack
84
+ };
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Error classifier - categorizes errors based on patterns
90
+ */
91
+ class ErrorClassifier {
92
+ constructor() {
93
+ this.patterns = this._initializePatterns();
94
+ }
95
+
96
+ _initializePatterns() {
97
+ return [
98
+ // Network errors
99
+ {
100
+ category: ErrorCategory.NETWORK,
101
+ severity: ErrorSeverity.MEDIUM,
102
+ retryable: true,
103
+ patterns: [
104
+ /ECONNREFUSED/i,
105
+ /ECONNRESET/i,
106
+ /ENOTFOUND/i,
107
+ /network/i,
108
+ /connection failed/i,
109
+ /socket hang up/i
110
+ ]
111
+ },
112
+ // Timeout errors
113
+ {
114
+ category: ErrorCategory.TIMEOUT,
115
+ severity: ErrorSeverity.MEDIUM,
116
+ retryable: true,
117
+ patterns: [
118
+ /timeout/i,
119
+ /ETIMEDOUT/i,
120
+ /timed out/i,
121
+ /deadline exceeded/i
122
+ ]
123
+ },
124
+ // Rate limit errors
125
+ {
126
+ category: ErrorCategory.RATE_LIMIT,
127
+ severity: ErrorSeverity.LOW,
128
+ retryable: true,
129
+ patterns: [
130
+ /rate limit/i,
131
+ /too many requests/i,
132
+ /429/,
133
+ /throttl/i
134
+ ]
135
+ },
136
+ // Authentication errors
137
+ {
138
+ category: ErrorCategory.AUTHENTICATION,
139
+ severity: ErrorSeverity.HIGH,
140
+ retryable: false,
141
+ patterns: [
142
+ /unauthorized/i,
143
+ /authentication failed/i,
144
+ /invalid token/i,
145
+ /401/,
146
+ /not authenticated/i
147
+ ]
148
+ },
149
+ // Authorization errors
150
+ {
151
+ category: ErrorCategory.AUTHORIZATION,
152
+ severity: ErrorSeverity.HIGH,
153
+ retryable: false,
154
+ patterns: [
155
+ /forbidden/i,
156
+ /access denied/i,
157
+ /permission denied/i,
158
+ /403/,
159
+ /not authorized/i
160
+ ]
161
+ },
162
+ // Resource not found
163
+ {
164
+ category: ErrorCategory.RESOURCE_NOT_FOUND,
165
+ severity: ErrorSeverity.MEDIUM,
166
+ retryable: false,
167
+ patterns: [
168
+ /not found/i,
169
+ /404/,
170
+ /does not exist/i,
171
+ /no such/i
172
+ ]
173
+ },
174
+ // Validation errors
175
+ {
176
+ category: ErrorCategory.VALIDATION,
177
+ severity: ErrorSeverity.LOW,
178
+ retryable: false,
179
+ patterns: [
180
+ /validation/i,
181
+ /invalid/i,
182
+ /required field/i,
183
+ /must be/i,
184
+ /expected/i
185
+ ]
186
+ },
187
+ // Conflict errors
188
+ {
189
+ category: ErrorCategory.CONFLICT,
190
+ severity: ErrorSeverity.MEDIUM,
191
+ retryable: false,
192
+ patterns: [
193
+ /conflict/i,
194
+ /already exists/i,
195
+ /duplicate/i,
196
+ /409/
197
+ ]
198
+ },
199
+ // Configuration errors
200
+ {
201
+ category: ErrorCategory.CONFIGURATION,
202
+ severity: ErrorSeverity.HIGH,
203
+ retryable: false,
204
+ patterns: [
205
+ /configuration/i,
206
+ /config/i,
207
+ /missing setting/i,
208
+ /not configured/i
209
+ ]
210
+ }
211
+ ];
212
+ }
213
+
214
+ /**
215
+ * Classify an error
216
+ */
217
+ classify(error) {
218
+ const errorString = `${error.message} ${error.code || ''} ${error.name || ''}`;
219
+
220
+ for (const pattern of this.patterns) {
221
+ for (const regex of pattern.patterns) {
222
+ if (regex.test(errorString)) {
223
+ return {
224
+ category: pattern.category,
225
+ severity: pattern.severity,
226
+ retryable: pattern.retryable,
227
+ recoverable: pattern.severity !== ErrorSeverity.CRITICAL
228
+ };
229
+ }
230
+ }
231
+ }
232
+
233
+ return {
234
+ category: ErrorCategory.UNKNOWN,
235
+ severity: ErrorSeverity.MEDIUM,
236
+ retryable: false,
237
+ recoverable: true
238
+ };
239
+ }
240
+
241
+ /**
242
+ * Enhance an error with classification metadata
243
+ */
244
+ enhance(error) {
245
+ if (error instanceof WorkflowError) {
246
+ return error;
247
+ }
248
+
249
+ const classification = this.classify(error);
250
+
251
+ return new WorkflowError(error.message, {
252
+ code: error.code || 'UNKNOWN_ERROR',
253
+ category: classification.category,
254
+ severity: classification.severity,
255
+ retryable: classification.retryable,
256
+ recoverable: classification.recoverable,
257
+ cause: error,
258
+ context: { originalName: error.name }
259
+ });
260
+ }
261
+
262
+ /**
263
+ * Add custom pattern
264
+ */
265
+ addPattern(pattern) {
266
+ this.patterns.unshift(pattern); // Add to beginning for priority
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Circuit breaker for protecting against cascading failures
272
+ */
273
+ class CircuitBreaker extends EventEmitter {
274
+ constructor(options = {}) {
275
+ super();
276
+ this.name = options.name || 'default';
277
+ this.failureThreshold = options.failureThreshold || 5;
278
+ this.successThreshold = options.successThreshold || 2;
279
+ this.timeout = options.timeout || 30000; // 30 seconds
280
+ this.halfOpenMaxCalls = options.halfOpenMaxCalls || 1;
281
+
282
+ this.state = CircuitState.CLOSED;
283
+ this.failures = 0;
284
+ this.successes = 0;
285
+ this.lastFailureTime = null;
286
+ this.halfOpenCalls = 0;
287
+ }
288
+
289
+ /**
290
+ * Execute function with circuit breaker protection
291
+ */
292
+ async execute(fn) {
293
+ if (this.state === CircuitState.OPEN) {
294
+ // Check if we should transition to half-open
295
+ if (Date.now() - this.lastFailureTime >= this.timeout) {
296
+ this._transitionTo(CircuitState.HALF_OPEN);
297
+ } else {
298
+ throw new WorkflowError('Circuit breaker is open', {
299
+ code: 'CIRCUIT_OPEN',
300
+ category: ErrorCategory.EXTERNAL_SERVICE,
301
+ severity: ErrorSeverity.HIGH,
302
+ retryable: true,
303
+ context: { circuitName: this.name }
304
+ });
305
+ }
306
+ }
307
+
308
+ if (this.state === CircuitState.HALF_OPEN) {
309
+ if (this.halfOpenCalls >= this.halfOpenMaxCalls) {
310
+ throw new WorkflowError('Circuit breaker half-open limit reached', {
311
+ code: 'CIRCUIT_HALF_OPEN_LIMIT',
312
+ category: ErrorCategory.EXTERNAL_SERVICE,
313
+ severity: ErrorSeverity.MEDIUM,
314
+ retryable: true
315
+ });
316
+ }
317
+ this.halfOpenCalls++;
318
+ }
319
+
320
+ try {
321
+ const result = await fn();
322
+ this._onSuccess();
323
+ return result;
324
+ } catch (error) {
325
+ this._onFailure(error);
326
+ throw error;
327
+ }
328
+ }
329
+
330
+ _onSuccess() {
331
+ this.failures = 0;
332
+
333
+ if (this.state === CircuitState.HALF_OPEN) {
334
+ this.successes++;
335
+ if (this.successes >= this.successThreshold) {
336
+ this._transitionTo(CircuitState.CLOSED);
337
+ }
338
+ }
339
+ }
340
+
341
+ _onFailure(error) {
342
+ this.failures++;
343
+ this.lastFailureTime = Date.now();
344
+ this.successes = 0;
345
+
346
+ if (this.state === CircuitState.HALF_OPEN) {
347
+ this._transitionTo(CircuitState.OPEN);
348
+ } else if (this.failures >= this.failureThreshold) {
349
+ this._transitionTo(CircuitState.OPEN);
350
+ }
351
+
352
+ this.emit('failure', { error, failures: this.failures });
353
+ }
354
+
355
+ _transitionTo(newState) {
356
+ const oldState = this.state;
357
+ this.state = newState;
358
+
359
+ if (newState === CircuitState.CLOSED) {
360
+ this.failures = 0;
361
+ this.successes = 0;
362
+ } else if (newState === CircuitState.HALF_OPEN) {
363
+ this.halfOpenCalls = 0;
364
+ this.successes = 0;
365
+ }
366
+
367
+ this.emit('state-change', { from: oldState, to: newState });
368
+ }
369
+
370
+ getState() {
371
+ return {
372
+ state: this.state,
373
+ failures: this.failures,
374
+ successes: this.successes,
375
+ lastFailureTime: this.lastFailureTime
376
+ };
377
+ }
378
+
379
+ reset() {
380
+ this._transitionTo(CircuitState.CLOSED);
381
+ }
382
+ }
383
+
384
+ /**
385
+ * Error aggregator for collecting and analyzing errors
386
+ */
387
+ class ErrorAggregator {
388
+ constructor(options = {}) {
389
+ this.maxErrors = options.maxErrors || 1000;
390
+ this.errors = [];
391
+ this.categoryCounts = new Map();
392
+ this.severityCounts = new Map();
393
+ }
394
+
395
+ /**
396
+ * Add an error to the aggregator
397
+ */
398
+ add(error, context = {}) {
399
+ const enhanced = error instanceof WorkflowError ? error :
400
+ new ErrorClassifier().enhance(error);
401
+
402
+ const entry = {
403
+ error: enhanced.toJSON(),
404
+ context,
405
+ timestamp: new Date().toISOString()
406
+ };
407
+
408
+ this.errors.push(entry);
409
+
410
+ // Trim if necessary
411
+ if (this.errors.length > this.maxErrors) {
412
+ this.errors = this.errors.slice(-this.maxErrors);
413
+ }
414
+
415
+ // Update counts
416
+ this._incrementCount(this.categoryCounts, enhanced.category);
417
+ this._incrementCount(this.severityCounts, enhanced.severity);
418
+
419
+ return entry;
420
+ }
421
+
422
+ _incrementCount(map, key) {
423
+ map.set(key, (map.get(key) || 0) + 1);
424
+ }
425
+
426
+ /**
427
+ * Get error statistics
428
+ */
429
+ getStats() {
430
+ return {
431
+ totalErrors: this.errors.length,
432
+ byCategory: Object.fromEntries(this.categoryCounts),
433
+ bySeverity: Object.fromEntries(this.severityCounts),
434
+ recentErrors: this.errors.slice(-10),
435
+ mostCommonCategory: this._getMostCommon(this.categoryCounts),
436
+ criticalCount: this.severityCounts.get(ErrorSeverity.CRITICAL) || 0
437
+ };
438
+ }
439
+
440
+ _getMostCommon(map) {
441
+ let maxKey = null;
442
+ let maxCount = 0;
443
+ for (const [key, count] of map) {
444
+ if (count > maxCount) {
445
+ maxKey = key;
446
+ maxCount = count;
447
+ }
448
+ }
449
+ return maxKey;
450
+ }
451
+
452
+ /**
453
+ * Get errors by category
454
+ */
455
+ getByCategory(category) {
456
+ return this.errors.filter(e => e.error.category === category);
457
+ }
458
+
459
+ /**
460
+ * Get errors by severity
461
+ */
462
+ getBySeverity(severity) {
463
+ return this.errors.filter(e => e.error.severity === severity);
464
+ }
465
+
466
+ /**
467
+ * Get retryable errors
468
+ */
469
+ getRetryable() {
470
+ return this.errors.filter(e => e.error.retryable);
471
+ }
472
+
473
+ /**
474
+ * Clear all errors
475
+ */
476
+ clear() {
477
+ this.errors = [];
478
+ this.categoryCounts.clear();
479
+ this.severityCounts.clear();
480
+ }
481
+
482
+ /**
483
+ * Generate error report
484
+ */
485
+ generateReport() {
486
+ const stats = this.getStats();
487
+
488
+ return {
489
+ summary: {
490
+ total: stats.totalErrors,
491
+ critical: stats.criticalCount,
492
+ mostCommonCategory: stats.mostCommonCategory
493
+ },
494
+ breakdown: {
495
+ byCategory: stats.byCategory,
496
+ bySeverity: stats.bySeverity
497
+ },
498
+ recentErrors: stats.recentErrors.map(e => ({
499
+ message: e.error.message,
500
+ category: e.error.category,
501
+ severity: e.error.severity,
502
+ timestamp: e.timestamp
503
+ })),
504
+ recommendations: this._generateRecommendations(stats)
505
+ };
506
+ }
507
+
508
+ _generateRecommendations(stats) {
509
+ const recommendations = [];
510
+
511
+ if (stats.criticalCount > 0) {
512
+ recommendations.push({
513
+ priority: 'high',
514
+ message: `${stats.criticalCount} critical errors require immediate attention`
515
+ });
516
+ }
517
+
518
+ const networkErrors = this.categoryCounts.get(ErrorCategory.NETWORK) || 0;
519
+ if (networkErrors > 5) {
520
+ recommendations.push({
521
+ priority: 'medium',
522
+ message: 'Multiple network errors detected. Check connectivity and service availability.'
523
+ });
524
+ }
525
+
526
+ const authErrors = this.categoryCounts.get(ErrorCategory.AUTHENTICATION) || 0;
527
+ if (authErrors > 0) {
528
+ recommendations.push({
529
+ priority: 'high',
530
+ message: 'Authentication errors detected. Verify credentials and tokens.'
531
+ });
532
+ }
533
+
534
+ const rateLimitErrors = this.categoryCounts.get(ErrorCategory.RATE_LIMIT) || 0;
535
+ if (rateLimitErrors > 3) {
536
+ recommendations.push({
537
+ priority: 'medium',
538
+ message: 'Rate limiting detected. Consider implementing backoff or reducing request frequency.'
539
+ });
540
+ }
541
+
542
+ return recommendations;
543
+ }
544
+ }
545
+
546
+ /**
547
+ * Graceful degradation manager
548
+ */
549
+ class GracefulDegradation {
550
+ constructor() {
551
+ this.fallbacks = new Map();
552
+ this.degradedServices = new Set();
553
+ }
554
+
555
+ /**
556
+ * Register a fallback for a service
557
+ */
558
+ registerFallback(serviceName, fallbackFn, options = {}) {
559
+ this.fallbacks.set(serviceName, {
560
+ fn: fallbackFn,
561
+ ttl: options.ttl || 60000, // 1 minute default cache
562
+ lastResult: null,
563
+ lastResultTime: null
564
+ });
565
+ }
566
+
567
+ /**
568
+ * Execute with graceful degradation
569
+ */
570
+ async execute(serviceName, primaryFn, options = {}) {
571
+ try {
572
+ const result = await primaryFn();
573
+
574
+ // Service recovered
575
+ if (this.degradedServices.has(serviceName)) {
576
+ this.degradedServices.delete(serviceName);
577
+ }
578
+
579
+ // Cache successful result for fallback
580
+ const fallback = this.fallbacks.get(serviceName);
581
+ if (fallback) {
582
+ fallback.lastResult = result;
583
+ fallback.lastResultTime = Date.now();
584
+ }
585
+
586
+ return { result, degraded: false };
587
+
588
+ } catch (error) {
589
+ const fallback = this.fallbacks.get(serviceName);
590
+
591
+ if (!fallback) {
592
+ throw error;
593
+ }
594
+
595
+ this.degradedServices.add(serviceName);
596
+
597
+ // Try cached result first
598
+ if (fallback.lastResult &&
599
+ (Date.now() - fallback.lastResultTime) < fallback.ttl) {
600
+ return {
601
+ result: fallback.lastResult,
602
+ degraded: true,
603
+ source: 'cache',
604
+ error: error.message
605
+ };
606
+ }
607
+
608
+ // Execute fallback function
609
+ try {
610
+ const fallbackResult = await fallback.fn(error);
611
+ return {
612
+ result: fallbackResult,
613
+ degraded: true,
614
+ source: 'fallback',
615
+ error: error.message
616
+ };
617
+ } catch (fallbackError) {
618
+ // Both primary and fallback failed
619
+ throw new WorkflowError('Primary and fallback both failed', {
620
+ code: 'DEGRADATION_FAILED',
621
+ category: ErrorCategory.INTERNAL,
622
+ severity: ErrorSeverity.CRITICAL,
623
+ cause: error,
624
+ context: {
625
+ serviceName,
626
+ primaryError: error.message,
627
+ fallbackError: fallbackError.message
628
+ }
629
+ });
630
+ }
631
+ }
632
+ }
633
+
634
+ /**
635
+ * Get degraded services
636
+ */
637
+ getDegradedServices() {
638
+ return [...this.degradedServices];
639
+ }
640
+
641
+ /**
642
+ * Check if service is degraded
643
+ */
644
+ isDegraded(serviceName) {
645
+ return this.degradedServices.has(serviceName);
646
+ }
647
+ }
648
+
649
+ /**
650
+ * Main error handler combining all strategies
651
+ */
652
+ class ErrorHandler extends EventEmitter {
653
+ constructor(options = {}) {
654
+ super();
655
+ this.classifier = new ErrorClassifier();
656
+ this.aggregator = new ErrorAggregator(options.aggregator);
657
+ this.degradation = new GracefulDegradation();
658
+ this.circuitBreakers = new Map();
659
+ this.globalRetryPolicy = options.retryPolicy || {
660
+ maxRetries: 3,
661
+ backoffMs: 1000,
662
+ backoffMultiplier: 2,
663
+ maxBackoffMs: 30000
664
+ };
665
+ }
666
+
667
+ /**
668
+ * Get or create circuit breaker for a service
669
+ */
670
+ getCircuitBreaker(serviceName, options = {}) {
671
+ if (!this.circuitBreakers.has(serviceName)) {
672
+ const breaker = new CircuitBreaker({ name: serviceName, ...options });
673
+ breaker.on('state-change', (event) => {
674
+ this.emit('circuit-state-change', { service: serviceName, ...event });
675
+ });
676
+ this.circuitBreakers.set(serviceName, breaker);
677
+ }
678
+ return this.circuitBreakers.get(serviceName);
679
+ }
680
+
681
+ /**
682
+ * Handle an error with full error handling pipeline
683
+ */
684
+ handle(error, context = {}) {
685
+ // Classify and enhance error
686
+ const enhanced = this.classifier.enhance(error);
687
+
688
+ // Add to aggregator
689
+ this.aggregator.add(enhanced, context);
690
+
691
+ // Emit error event
692
+ this.emit('error', { error: enhanced, context });
693
+
694
+ // Log based on severity
695
+ this._logError(enhanced, context);
696
+
697
+ // Return enhanced error with handling suggestions
698
+ return {
699
+ error: enhanced,
700
+ handled: true,
701
+ suggestions: this._getSuggestions(enhanced)
702
+ };
703
+ }
704
+
705
+ _logError(error, context) {
706
+ const logData = {
707
+ message: error.message,
708
+ category: error.category,
709
+ severity: error.severity,
710
+ context: { ...error.context, ...context }
711
+ };
712
+
713
+ switch (error.severity) {
714
+ case ErrorSeverity.CRITICAL:
715
+ console.error('[CRITICAL]', JSON.stringify(logData));
716
+ break;
717
+ case ErrorSeverity.HIGH:
718
+ console.error('[ERROR]', JSON.stringify(logData));
719
+ break;
720
+ case ErrorSeverity.MEDIUM:
721
+ console.warn('[WARN]', JSON.stringify(logData));
722
+ break;
723
+ default:
724
+ console.info('[INFO]', JSON.stringify(logData));
725
+ }
726
+ }
727
+
728
+ _getSuggestions(error) {
729
+ const suggestions = [...(error.suggestions || [])];
730
+
731
+ switch (error.category) {
732
+ case ErrorCategory.NETWORK:
733
+ suggestions.push('Check network connectivity');
734
+ suggestions.push('Verify service endpoints are accessible');
735
+ break;
736
+ case ErrorCategory.AUTHENTICATION:
737
+ suggestions.push('Verify credentials are correct');
738
+ suggestions.push('Check if tokens have expired');
739
+ break;
740
+ case ErrorCategory.RATE_LIMIT:
741
+ suggestions.push('Implement exponential backoff');
742
+ suggestions.push('Consider caching responses');
743
+ break;
744
+ case ErrorCategory.TIMEOUT:
745
+ suggestions.push('Increase timeout values');
746
+ suggestions.push('Consider breaking operation into smaller chunks');
747
+ break;
748
+ case ErrorCategory.CONFIGURATION:
749
+ suggestions.push('Review configuration settings');
750
+ suggestions.push('Check environment variables');
751
+ break;
752
+ }
753
+
754
+ if (error.retryable) {
755
+ suggestions.push('This error may be resolved by retrying');
756
+ }
757
+
758
+ return suggestions;
759
+ }
760
+
761
+ /**
762
+ * Execute with retry
763
+ */
764
+ async executeWithRetry(fn, options = {}) {
765
+ const policy = { ...this.globalRetryPolicy, ...options };
766
+ let lastError;
767
+ let currentBackoff = policy.backoffMs;
768
+
769
+ for (let attempt = 0; attempt <= policy.maxRetries; attempt++) {
770
+ try {
771
+ return await fn();
772
+ } catch (error) {
773
+ lastError = error;
774
+ const enhanced = this.classifier.enhance(error);
775
+
776
+ if (!enhanced.retryable || attempt >= policy.maxRetries) {
777
+ await this.handle(enhanced, { attempt, maxRetries: policy.maxRetries });
778
+ throw enhanced;
779
+ }
780
+
781
+ this.emit('retry', {
782
+ attempt: attempt + 1,
783
+ maxRetries: policy.maxRetries,
784
+ backoffMs: currentBackoff,
785
+ error: enhanced.message
786
+ });
787
+
788
+ await this._sleep(currentBackoff);
789
+ currentBackoff = Math.min(
790
+ currentBackoff * policy.backoffMultiplier,
791
+ policy.maxBackoffMs
792
+ );
793
+ }
794
+ }
795
+
796
+ throw lastError;
797
+ }
798
+
799
+ /**
800
+ * Get error report
801
+ */
802
+ getReport() {
803
+ return {
804
+ ...this.aggregator.generateReport(),
805
+ circuitBreakers: Object.fromEntries(
806
+ [...this.circuitBreakers].map(([name, breaker]) => [name, breaker.getState()])
807
+ ),
808
+ degradedServices: this.degradation.getDegradedServices()
809
+ };
810
+ }
811
+
812
+ _sleep(ms) {
813
+ return new Promise(resolve => setTimeout(resolve, ms));
814
+ }
815
+ }
816
+
817
+ module.exports = {
818
+ ErrorHandler,
819
+ ErrorClassifier,
820
+ ErrorAggregator,
821
+ CircuitBreaker,
822
+ GracefulDegradation,
823
+ WorkflowError,
824
+ ErrorSeverity,
825
+ ErrorCategory,
826
+ CircuitState
827
+ };