agentic-qe 2.5.5 → 2.5.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 (168) hide show
  1. package/.claude/agents/n8n/n8n-base-agent.md +376 -0
  2. package/.claude/agents/n8n/n8n-bdd-scenario-tester.md +613 -0
  3. package/.claude/agents/n8n/n8n-chaos-tester.md +654 -0
  4. package/.claude/agents/n8n/n8n-ci-orchestrator.md +850 -0
  5. package/.claude/agents/n8n/n8n-compliance-validator.md +685 -0
  6. package/.claude/agents/n8n/n8n-expression-validator.md +560 -0
  7. package/.claude/agents/n8n/n8n-integration-test.md +602 -0
  8. package/.claude/agents/n8n/n8n-monitoring-validator.md +589 -0
  9. package/.claude/agents/n8n/n8n-node-validator.md +455 -0
  10. package/.claude/agents/n8n/n8n-performance-tester.md +630 -0
  11. package/.claude/agents/n8n/n8n-security-auditor.md +786 -0
  12. package/.claude/agents/n8n/n8n-trigger-test.md +500 -0
  13. package/.claude/agents/n8n/n8n-unit-tester.md +633 -0
  14. package/.claude/agents/n8n/n8n-version-comparator.md +567 -0
  15. package/.claude/agents/n8n/n8n-workflow-executor.md +392 -0
  16. package/.claude/skills/n8n-expression-testing/SKILL.md +434 -0
  17. package/.claude/skills/n8n-integration-testing-patterns/SKILL.md +540 -0
  18. package/.claude/skills/n8n-security-testing/SKILL.md +599 -0
  19. package/.claude/skills/n8n-trigger-testing-strategies/SKILL.md +541 -0
  20. package/.claude/skills/n8n-workflow-testing-fundamentals/SKILL.md +447 -0
  21. package/CHANGELOG.md +111 -0
  22. package/README.md +7 -4
  23. package/dist/adapters/MemoryStoreAdapter.d.ts +75 -123
  24. package/dist/adapters/MemoryStoreAdapter.d.ts.map +1 -1
  25. package/dist/adapters/MemoryStoreAdapter.js +204 -219
  26. package/dist/adapters/MemoryStoreAdapter.js.map +1 -1
  27. package/dist/agents/AccessibilityAllyAgent.d.ts.map +1 -1
  28. package/dist/agents/AccessibilityAllyAgent.js +17 -1
  29. package/dist/agents/AccessibilityAllyAgent.js.map +1 -1
  30. package/dist/agents/BaseAgent.d.ts +18 -250
  31. package/dist/agents/BaseAgent.d.ts.map +1 -1
  32. package/dist/agents/BaseAgent.js +122 -520
  33. package/dist/agents/BaseAgent.js.map +1 -1
  34. package/dist/agents/n8n/N8nAPIClient.d.ts +121 -0
  35. package/dist/agents/n8n/N8nAPIClient.d.ts.map +1 -0
  36. package/dist/agents/n8n/N8nAPIClient.js +367 -0
  37. package/dist/agents/n8n/N8nAPIClient.js.map +1 -0
  38. package/dist/agents/n8n/N8nAuditPersistence.d.ts +120 -0
  39. package/dist/agents/n8n/N8nAuditPersistence.d.ts.map +1 -0
  40. package/dist/agents/n8n/N8nAuditPersistence.js +473 -0
  41. package/dist/agents/n8n/N8nAuditPersistence.js.map +1 -0
  42. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts +159 -0
  43. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts.map +1 -0
  44. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js +697 -0
  45. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js.map +1 -0
  46. package/dist/agents/n8n/N8nBaseAgent.d.ts +126 -0
  47. package/dist/agents/n8n/N8nBaseAgent.d.ts.map +1 -0
  48. package/dist/agents/n8n/N8nBaseAgent.js +446 -0
  49. package/dist/agents/n8n/N8nBaseAgent.js.map +1 -0
  50. package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts +164 -0
  51. package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts.map +1 -0
  52. package/dist/agents/n8n/N8nCIOrchestratorAgent.js +610 -0
  53. package/dist/agents/n8n/N8nCIOrchestratorAgent.js.map +1 -0
  54. package/dist/agents/n8n/N8nChaosTesterAgent.d.ts +205 -0
  55. package/dist/agents/n8n/N8nChaosTesterAgent.d.ts.map +1 -0
  56. package/dist/agents/n8n/N8nChaosTesterAgent.js +729 -0
  57. package/dist/agents/n8n/N8nChaosTesterAgent.js.map +1 -0
  58. package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts +228 -0
  59. package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts.map +1 -0
  60. package/dist/agents/n8n/N8nComplianceValidatorAgent.js +986 -0
  61. package/dist/agents/n8n/N8nComplianceValidatorAgent.js.map +1 -0
  62. package/dist/agents/n8n/N8nContractTesterAgent.d.ts +213 -0
  63. package/dist/agents/n8n/N8nContractTesterAgent.d.ts.map +1 -0
  64. package/dist/agents/n8n/N8nContractTesterAgent.js +989 -0
  65. package/dist/agents/n8n/N8nContractTesterAgent.js.map +1 -0
  66. package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts +99 -0
  67. package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts.map +1 -0
  68. package/dist/agents/n8n/N8nExpressionValidatorAgent.js +632 -0
  69. package/dist/agents/n8n/N8nExpressionValidatorAgent.js.map +1 -0
  70. package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts +238 -0
  71. package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts.map +1 -0
  72. package/dist/agents/n8n/N8nFailureModeTesterAgent.js +956 -0
  73. package/dist/agents/n8n/N8nFailureModeTesterAgent.js.map +1 -0
  74. package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts +242 -0
  75. package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts.map +1 -0
  76. package/dist/agents/n8n/N8nIdempotencyTesterAgent.js +992 -0
  77. package/dist/agents/n8n/N8nIdempotencyTesterAgent.js.map +1 -0
  78. package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts +104 -0
  79. package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts.map +1 -0
  80. package/dist/agents/n8n/N8nIntegrationTestAgent.js +653 -0
  81. package/dist/agents/n8n/N8nIntegrationTestAgent.js.map +1 -0
  82. package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts +210 -0
  83. package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts.map +1 -0
  84. package/dist/agents/n8n/N8nMonitoringValidatorAgent.js +669 -0
  85. package/dist/agents/n8n/N8nMonitoringValidatorAgent.js.map +1 -0
  86. package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts +142 -0
  87. package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts.map +1 -0
  88. package/dist/agents/n8n/N8nNodeValidatorAgent.js +1090 -0
  89. package/dist/agents/n8n/N8nNodeValidatorAgent.js.map +1 -0
  90. package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts +198 -0
  91. package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts.map +1 -0
  92. package/dist/agents/n8n/N8nPerformanceTesterAgent.js +653 -0
  93. package/dist/agents/n8n/N8nPerformanceTesterAgent.js.map +1 -0
  94. package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts +245 -0
  95. package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts.map +1 -0
  96. package/dist/agents/n8n/N8nReplayabilityTesterAgent.js +952 -0
  97. package/dist/agents/n8n/N8nReplayabilityTesterAgent.js.map +1 -0
  98. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts +325 -0
  99. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts.map +1 -0
  100. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js +1187 -0
  101. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js.map +1 -0
  102. package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts +91 -0
  103. package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts.map +1 -0
  104. package/dist/agents/n8n/N8nSecurityAuditorAgent.js +825 -0
  105. package/dist/agents/n8n/N8nSecurityAuditorAgent.js.map +1 -0
  106. package/dist/agents/n8n/N8nTestHarness.d.ts +131 -0
  107. package/dist/agents/n8n/N8nTestHarness.d.ts.map +1 -0
  108. package/dist/agents/n8n/N8nTestHarness.js +456 -0
  109. package/dist/agents/n8n/N8nTestHarness.js.map +1 -0
  110. package/dist/agents/n8n/N8nTriggerTestAgent.d.ts +119 -0
  111. package/dist/agents/n8n/N8nTriggerTestAgent.d.ts.map +1 -0
  112. package/dist/agents/n8n/N8nTriggerTestAgent.js +652 -0
  113. package/dist/agents/n8n/N8nTriggerTestAgent.js.map +1 -0
  114. package/dist/agents/n8n/N8nUnitTesterAgent.d.ts +130 -0
  115. package/dist/agents/n8n/N8nUnitTesterAgent.d.ts.map +1 -0
  116. package/dist/agents/n8n/N8nUnitTesterAgent.js +522 -0
  117. package/dist/agents/n8n/N8nUnitTesterAgent.js.map +1 -0
  118. package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts +201 -0
  119. package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts.map +1 -0
  120. package/dist/agents/n8n/N8nVersionComparatorAgent.js +645 -0
  121. package/dist/agents/n8n/N8nVersionComparatorAgent.js.map +1 -0
  122. package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts +120 -0
  123. package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts.map +1 -0
  124. package/dist/agents/n8n/N8nWorkflowExecutorAgent.js +347 -0
  125. package/dist/agents/n8n/N8nWorkflowExecutorAgent.js.map +1 -0
  126. package/dist/agents/n8n/index.d.ts +119 -0
  127. package/dist/agents/n8n/index.d.ts.map +1 -0
  128. package/dist/agents/n8n/index.js +298 -0
  129. package/dist/agents/n8n/index.js.map +1 -0
  130. package/dist/agents/n8n/types.d.ts +486 -0
  131. package/dist/agents/n8n/types.d.ts.map +1 -0
  132. package/dist/agents/n8n/types.js +8 -0
  133. package/dist/agents/n8n/types.js.map +1 -0
  134. package/dist/agents/utils/generators.d.ts +30 -0
  135. package/dist/agents/utils/generators.d.ts.map +1 -0
  136. package/dist/agents/utils/generators.js +44 -0
  137. package/dist/agents/utils/generators.js.map +1 -0
  138. package/dist/agents/utils/index.d.ts +10 -0
  139. package/dist/agents/utils/index.d.ts.map +1 -0
  140. package/dist/agents/utils/index.js +19 -0
  141. package/dist/agents/utils/index.js.map +1 -0
  142. package/dist/agents/utils/validation.d.ts +72 -0
  143. package/dist/agents/utils/validation.d.ts.map +1 -0
  144. package/dist/agents/utils/validation.js +75 -0
  145. package/dist/agents/utils/validation.js.map +1 -0
  146. package/dist/cli/init/agents.d.ts.map +1 -1
  147. package/dist/cli/init/agents.js +29 -0
  148. package/dist/cli/init/agents.js.map +1 -1
  149. package/dist/cli/init/skills.d.ts.map +1 -1
  150. package/dist/cli/init/skills.js +7 -1
  151. package/dist/cli/init/skills.js.map +1 -1
  152. package/dist/core/memory/HNSWVectorMemory.js +1 -1
  153. package/dist/core/memory/SwarmMemoryManager.d.ts +114 -90
  154. package/dist/core/memory/SwarmMemoryManager.d.ts.map +1 -1
  155. package/dist/core/memory/SwarmMemoryManager.js +277 -235
  156. package/dist/core/memory/SwarmMemoryManager.js.map +1 -1
  157. package/dist/learning/baselines/StandardTaskSuite.d.ts.map +1 -1
  158. package/dist/learning/baselines/StandardTaskSuite.js +38 -0
  159. package/dist/learning/baselines/StandardTaskSuite.js.map +1 -1
  160. package/dist/mcp/server-instructions.d.ts +1 -1
  161. package/dist/mcp/server-instructions.js +1 -1
  162. package/dist/types/memory-interfaces.d.ts +76 -68
  163. package/dist/types/memory-interfaces.d.ts.map +1 -1
  164. package/dist/types/memory-interfaces.js +3 -0
  165. package/dist/types/memory-interfaces.js.map +1 -1
  166. package/docs/reference/agents.md +91 -2
  167. package/docs/reference/skills.md +97 -2
  168. package/package.json +2 -2
@@ -0,0 +1,669 @@
1
+ "use strict";
2
+ /**
3
+ * N8nMonitoringValidatorAgent
4
+ *
5
+ * Validates monitoring and observability configuration:
6
+ * - Logging configuration validation
7
+ * - Alerting rule verification
8
+ * - Metrics collection validation
9
+ * - SLA compliance checking
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.N8nMonitoringValidatorAgent = void 0;
13
+ const N8nBaseAgent_1 = require("./N8nBaseAgent");
14
+ // Standard metrics that should be collected
15
+ const REQUIRED_METRICS = [
16
+ { name: 'n8n_workflow_executions_total', type: 'counter', description: 'Total workflow executions' },
17
+ { name: 'n8n_workflow_execution_duration_seconds', type: 'histogram', description: 'Workflow execution duration' },
18
+ { name: 'n8n_workflow_execution_errors_total', type: 'counter', description: 'Total workflow errors' },
19
+ { name: 'n8n_node_execution_duration_seconds', type: 'histogram', description: 'Node execution duration' },
20
+ { name: 'n8n_workflow_active_executions', type: 'gauge', description: 'Currently active executions' },
21
+ ];
22
+ class N8nMonitoringValidatorAgent extends N8nBaseAgent_1.N8nBaseAgent {
23
+ constructor(config) {
24
+ const capabilities = [
25
+ {
26
+ name: 'logging-validation',
27
+ version: '1.0.0',
28
+ description: 'Validate logging configuration',
29
+ parameters: {},
30
+ },
31
+ {
32
+ name: 'alerting-validation',
33
+ version: '1.0.0',
34
+ description: 'Validate alerting rules',
35
+ parameters: {},
36
+ },
37
+ {
38
+ name: 'metrics-validation',
39
+ version: '1.0.0',
40
+ description: 'Validate metrics collection',
41
+ parameters: {},
42
+ },
43
+ {
44
+ name: 'sla-compliance',
45
+ version: '1.0.0',
46
+ description: 'Check SLA compliance',
47
+ parameters: {},
48
+ },
49
+ ];
50
+ super({
51
+ ...config,
52
+ type: 'n8n-monitoring-validator',
53
+ capabilities: [...capabilities, ...(config.capabilities || [])],
54
+ });
55
+ this.monitoringExecutionHistory = new Map();
56
+ }
57
+ async performTask(task) {
58
+ const monitoringTask = task;
59
+ if (monitoringTask.type !== 'monitoring-validation') {
60
+ throw new Error(`Unsupported task type: ${monitoringTask.type}`);
61
+ }
62
+ return this.validateMonitoring(monitoringTask.target, monitoringTask.options);
63
+ }
64
+ /**
65
+ * Validate monitoring configuration
66
+ *
67
+ * PRODUCTION DEFAULT: Runtime validation and SLA checking are ENABLED by default.
68
+ * This ensures actual metrics are collected and validated, not just configuration.
69
+ * Set executeRuntimeValidation: false to skip if workflow cannot be executed.
70
+ */
71
+ async validateMonitoring(workflowId, options) {
72
+ const workflow = await this.getWorkflow(workflowId);
73
+ // Validate logging (static analysis)
74
+ const loggingValidation = options?.validateLogging !== false
75
+ ? this.validateLogging(workflow)
76
+ : this.getDefaultLoggingResult();
77
+ // Validate alerting (static analysis)
78
+ const alertingValidation = options?.validateAlerting !== false
79
+ ? this.validateAlerting(workflow)
80
+ : this.getDefaultAlertingResult();
81
+ // Validate metrics (static analysis)
82
+ const metricsValidation = options?.validateMetrics !== false
83
+ ? this.validateMetrics(workflow)
84
+ : this.getDefaultMetricsResult();
85
+ // Runtime validation - ENABLED BY DEFAULT
86
+ // Actually execute workflows to collect real metrics
87
+ // Set executeRuntimeValidation: false explicitly to skip
88
+ if (options?.executeRuntimeValidation !== false) {
89
+ try {
90
+ await this.executeRuntimeMetricsValidation(workflowId, options?.testInput, options?.iterations || 5);
91
+ }
92
+ catch (error) {
93
+ // If runtime execution fails, emit warning but continue with static results
94
+ this.emitEvent('monitoring.runtime.skipped', {
95
+ workflowId,
96
+ reason: error instanceof Error ? error.message : 'Runtime metrics validation failed',
97
+ note: 'Static monitoring analysis completed, but runtime metrics collection was skipped',
98
+ });
99
+ }
100
+ }
101
+ // Check SLA compliance - ENABLED BY DEFAULT for production
102
+ // Real execution data is used if runtime validation was run
103
+ // Set checkSLACompliance: false explicitly to skip
104
+ let slaCompliance;
105
+ if (options?.checkSLACompliance !== false) {
106
+ slaCompliance = await this.checkSLACompliance(workflowId, options?.slaThresholds || this.getDefaultSLAThresholds());
107
+ }
108
+ // Generate recommendations
109
+ const recommendations = this.generateRecommendations(loggingValidation, alertingValidation, metricsValidation, slaCompliance);
110
+ // Calculate overall score
111
+ const overallScore = this.calculateOverallScore(loggingValidation, alertingValidation, metricsValidation, slaCompliance);
112
+ const result = {
113
+ workflowId,
114
+ loggingValidation,
115
+ alertingValidation,
116
+ metricsValidation,
117
+ slaCompliance,
118
+ recommendations,
119
+ overallScore,
120
+ };
121
+ // Store result
122
+ await this.storeTestResult(`monitoring-validation:${workflowId}`, result);
123
+ // Emit event
124
+ this.emitEvent('monitoring.validation.completed', {
125
+ workflowId,
126
+ overallScore,
127
+ recommendationCount: recommendations.length,
128
+ slaCompliant: slaCompliance?.isCompliant ?? true,
129
+ });
130
+ return result;
131
+ }
132
+ /**
133
+ * Validate logging configuration
134
+ */
135
+ validateLogging(workflow) {
136
+ const issues = [];
137
+ let nodesWithLogging = 0;
138
+ // Check workflow-level settings
139
+ const loggingLevel = workflow.settings?.saveExecutionProgress ? 'detailed' :
140
+ workflow.settings?.saveDataErrorExecution ? 'errors' : 'minimal';
141
+ // Check node-level logging
142
+ for (const node of workflow.nodes) {
143
+ const hasLogging = this.nodeHasLogging(node);
144
+ if (hasLogging) {
145
+ nodesWithLogging++;
146
+ }
147
+ // Check for sensitive data logging
148
+ if (this.nodeLogsSensitiveData(node)) {
149
+ issues.push({
150
+ type: 'sensitive-data',
151
+ severity: 'high',
152
+ location: node.name,
153
+ description: 'Node may log sensitive data',
154
+ recommendation: 'Add data masking or reduce log verbosity',
155
+ });
156
+ }
157
+ }
158
+ // Check for missing error logging
159
+ const errorNodes = workflow.nodes.filter(n => n.type.includes('Error') || n.type.includes('error'));
160
+ if (errorNodes.length === 0) {
161
+ issues.push({
162
+ type: 'missing',
163
+ severity: 'medium',
164
+ location: 'workflow',
165
+ description: 'No explicit error handling/logging nodes',
166
+ recommendation: 'Add error trigger node to capture and log errors',
167
+ });
168
+ }
169
+ // Check for insufficient logging
170
+ if (loggingLevel === 'minimal' && workflow.nodes.length > 5) {
171
+ issues.push({
172
+ type: 'insufficient',
173
+ severity: 'medium',
174
+ location: 'workflow',
175
+ description: 'Complex workflow with minimal logging',
176
+ recommendation: 'Enable saveExecutionProgress for debugging',
177
+ });
178
+ }
179
+ return {
180
+ isConfigured: loggingLevel !== 'minimal',
181
+ level: loggingLevel,
182
+ issues,
183
+ coverage: {
184
+ nodesWithLogging,
185
+ totalNodes: workflow.nodes.length,
186
+ percentage: workflow.nodes.length > 0
187
+ ? (nodesWithLogging / workflow.nodes.length) * 100
188
+ : 0,
189
+ },
190
+ };
191
+ }
192
+ /**
193
+ * Check if node has logging configured
194
+ */
195
+ nodeHasLogging(node) {
196
+ // Check for explicit logging configuration
197
+ const params = node.parameters;
198
+ return !!(params.onError ||
199
+ params.logging ||
200
+ params.debug ||
201
+ node.type.includes('log') ||
202
+ node.type.includes('debug'));
203
+ }
204
+ /**
205
+ * Check if node might log sensitive data
206
+ */
207
+ nodeLogsSensitiveData(node) {
208
+ const sensitivePatterns = ['password', 'token', 'secret', 'key', 'credential'];
209
+ const paramsStr = JSON.stringify(node.parameters).toLowerCase();
210
+ return sensitivePatterns.some(p => paramsStr.includes(p));
211
+ }
212
+ /**
213
+ * Validate alerting configuration
214
+ */
215
+ validateAlerting(workflow) {
216
+ const rules = [];
217
+ const issues = [];
218
+ // Check for error workflow
219
+ const errorWorkflow = workflow.settings?.errorWorkflow;
220
+ if (errorWorkflow) {
221
+ rules.push({
222
+ name: 'Error Workflow Trigger',
223
+ type: 'error',
224
+ condition: 'Workflow execution fails',
225
+ channels: ['error-workflow'],
226
+ severity: 'error',
227
+ isValid: true,
228
+ });
229
+ }
230
+ else {
231
+ issues.push({
232
+ type: 'missing',
233
+ severity: 'high',
234
+ description: 'No error workflow configured',
235
+ recommendation: 'Configure an error workflow to handle failures',
236
+ });
237
+ }
238
+ // Check for notification nodes
239
+ const notificationNodes = workflow.nodes.filter(n => n.type.includes('slack') ||
240
+ n.type.includes('email') ||
241
+ n.type.includes('telegram') ||
242
+ n.type.includes('webhook'));
243
+ for (const node of notificationNodes) {
244
+ // Check if it's in error handling path
245
+ const isErrorHandler = this.isInErrorHandlingPath(workflow, node);
246
+ if (isErrorHandler) {
247
+ rules.push({
248
+ name: `Alert: ${node.name}`,
249
+ type: 'error',
250
+ condition: 'Error detected',
251
+ channels: [node.type],
252
+ severity: 'warning',
253
+ isValid: true,
254
+ });
255
+ }
256
+ }
257
+ // Check coverage
258
+ const hasErrorAlerts = rules.some(r => r.type === 'error');
259
+ const hasPerformanceAlerts = rules.some(r => r.type === 'performance');
260
+ const hasBusinessAlerts = rules.some(r => r.type === 'business');
261
+ if (!hasPerformanceAlerts) {
262
+ issues.push({
263
+ type: 'blind-spot',
264
+ severity: 'medium',
265
+ description: 'No performance alerting configured',
266
+ recommendation: 'Add alerts for slow execution or timeout',
267
+ });
268
+ }
269
+ return {
270
+ isConfigured: rules.length > 0,
271
+ rules,
272
+ issues,
273
+ coverage: {
274
+ errorAlerts: hasErrorAlerts,
275
+ performanceAlerts: hasPerformanceAlerts,
276
+ businessAlerts: hasBusinessAlerts,
277
+ },
278
+ };
279
+ }
280
+ /**
281
+ * Check if node is in error handling path
282
+ */
283
+ isInErrorHandlingPath(workflow, node) {
284
+ // Simplified check - look for connection from error nodes
285
+ for (const [sourceNode, outputs] of Object.entries(workflow.connections)) {
286
+ const sourceNodeDef = workflow.nodes.find(n => n.id === sourceNode || n.name === sourceNode);
287
+ if (sourceNodeDef?.type.includes('Error')) {
288
+ for (const outputType of Object.values(outputs)) {
289
+ for (const connections of outputType) {
290
+ if (connections.some(c => c.node === node.id || c.node === node.name)) {
291
+ return true;
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+ return false;
298
+ }
299
+ /**
300
+ * Validate metrics configuration
301
+ */
302
+ validateMetrics(workflow) {
303
+ const metrics = [];
304
+ const issues = [];
305
+ // Check for standard metrics (these would be collected by n8n)
306
+ for (const requiredMetric of REQUIRED_METRICS) {
307
+ metrics.push({
308
+ ...requiredMetric,
309
+ type: requiredMetric.type,
310
+ labels: ['workflow_id', 'workflow_name'],
311
+ isCollected: true, // Assume n8n collects these
312
+ });
313
+ }
314
+ // Check for custom metrics in code nodes
315
+ const codeNodes = workflow.nodes.filter(n => n.type === 'n8n-nodes-base.code');
316
+ for (const node of codeNodes) {
317
+ const code = node.parameters.jsCode || '';
318
+ if (code.includes('metrics') || code.includes('counter') || code.includes('gauge')) {
319
+ metrics.push({
320
+ name: `custom_${node.name}_metric`,
321
+ type: 'custom',
322
+ description: 'Custom metric in code node',
323
+ labels: [],
324
+ isCollected: true,
325
+ });
326
+ }
327
+ }
328
+ // Check for high cardinality
329
+ const httpNodes = workflow.nodes.filter(n => n.type.includes('httpRequest'));
330
+ if (httpNodes.length > 0) {
331
+ issues.push({
332
+ type: 'cardinality',
333
+ severity: 'medium',
334
+ description: 'HTTP request nodes may generate high cardinality metrics',
335
+ recommendation: 'Use bucketed labels for URL paths',
336
+ });
337
+ }
338
+ // Check coverage
339
+ const hasExecutionMetrics = metrics.some(m => m.name.includes('execution'));
340
+ const hasNodeMetrics = metrics.some(m => m.name.includes('node'));
341
+ const hasBusinessMetrics = metrics.some(m => !m.name.startsWith('n8n_'));
342
+ if (!hasBusinessMetrics) {
343
+ issues.push({
344
+ type: 'coverage',
345
+ severity: 'low',
346
+ description: 'No business-specific metrics defined',
347
+ recommendation: 'Consider adding custom metrics for business KPIs',
348
+ });
349
+ }
350
+ return {
351
+ isConfigured: metrics.length > 0,
352
+ metrics,
353
+ issues,
354
+ coverage: {
355
+ executionMetrics: hasExecutionMetrics,
356
+ nodeMetrics: hasNodeMetrics,
357
+ businessMetrics: hasBusinessMetrics,
358
+ },
359
+ };
360
+ }
361
+ /**
362
+ * Check SLA compliance
363
+ */
364
+ async checkSLACompliance(workflowId, thresholds) {
365
+ // Get recent executions
366
+ const executions = this.monitoringExecutionHistory.get(workflowId) || [];
367
+ // Calculate actual metrics
368
+ const durations = executions
369
+ .filter(e => e.stoppedAt)
370
+ .map(e => new Date(e.stoppedAt).getTime() - new Date(e.startedAt).getTime());
371
+ const successCount = executions.filter(e => e.status === 'success').length;
372
+ const errorCount = executions.filter(e => e.status === 'failed' || e.status === 'crashed').length;
373
+ const totalCount = executions.length || 1;
374
+ const avgExecutionTime = durations.length > 0
375
+ ? durations.reduce((a, b) => a + b, 0) / durations.length
376
+ : 0;
377
+ const sortedDurations = [...durations].sort((a, b) => a - b);
378
+ const p99Index = Math.floor(sortedDurations.length * 0.99);
379
+ const p99Latency = sortedDurations[p99Index] || avgExecutionTime;
380
+ const actualMetrics = {
381
+ avgExecutionTime,
382
+ successRate: (successCount / totalCount) * 100,
383
+ errorRate: (errorCount / totalCount) * 100,
384
+ p99Latency,
385
+ throughput: totalCount, // executions in sample period
386
+ };
387
+ // Check violations
388
+ const violations = [];
389
+ if (thresholds.maxExecutionTime && avgExecutionTime > thresholds.maxExecutionTime) {
390
+ violations.push({
391
+ metric: 'avgExecutionTime',
392
+ threshold: thresholds.maxExecutionTime,
393
+ actual: avgExecutionTime,
394
+ severity: avgExecutionTime > thresholds.maxExecutionTime * 2 ? 'critical' : 'major',
395
+ timestamp: new Date(),
396
+ });
397
+ }
398
+ if (thresholds.minSuccessRate && actualMetrics.successRate < thresholds.minSuccessRate) {
399
+ violations.push({
400
+ metric: 'successRate',
401
+ threshold: thresholds.minSuccessRate,
402
+ actual: actualMetrics.successRate,
403
+ severity: actualMetrics.successRate < thresholds.minSuccessRate - 10 ? 'critical' : 'major',
404
+ timestamp: new Date(),
405
+ });
406
+ }
407
+ if (thresholds.maxErrorRate && actualMetrics.errorRate > thresholds.maxErrorRate) {
408
+ violations.push({
409
+ metric: 'errorRate',
410
+ threshold: thresholds.maxErrorRate,
411
+ actual: actualMetrics.errorRate,
412
+ severity: actualMetrics.errorRate > thresholds.maxErrorRate * 2 ? 'critical' : 'major',
413
+ timestamp: new Date(),
414
+ });
415
+ }
416
+ if (thresholds.maxP99Latency && p99Latency > thresholds.maxP99Latency) {
417
+ violations.push({
418
+ metric: 'p99Latency',
419
+ threshold: thresholds.maxP99Latency,
420
+ actual: p99Latency,
421
+ severity: 'major',
422
+ timestamp: new Date(),
423
+ });
424
+ }
425
+ return {
426
+ isCompliant: violations.length === 0,
427
+ thresholds,
428
+ actualMetrics,
429
+ violations,
430
+ trend: 'stable', // Would need historical data for real trend
431
+ };
432
+ }
433
+ /**
434
+ * Get default SLA thresholds
435
+ */
436
+ getDefaultSLAThresholds() {
437
+ return {
438
+ maxExecutionTime: 30000, // 30 seconds
439
+ minSuccessRate: 99, // 99%
440
+ maxErrorRate: 1, // 1%
441
+ maxP99Latency: 60000, // 60 seconds
442
+ minThroughput: 10, // 10 per hour
443
+ };
444
+ }
445
+ /**
446
+ * Generate recommendations
447
+ */
448
+ generateRecommendations(logging, alerting, metrics, sla) {
449
+ const recommendations = [];
450
+ // Logging recommendations
451
+ for (const issue of logging.issues) {
452
+ recommendations.push({
453
+ priority: issue.severity === 'high' ? 'high' : 'medium',
454
+ category: 'logging',
455
+ issue: issue.description,
456
+ recommendation: issue.recommendation,
457
+ impact: 'Improved debugging and troubleshooting',
458
+ });
459
+ }
460
+ // Alerting recommendations
461
+ for (const issue of alerting.issues) {
462
+ recommendations.push({
463
+ priority: issue.severity === 'high' ? 'high' : 'medium',
464
+ category: 'alerting',
465
+ issue: issue.description,
466
+ recommendation: issue.recommendation,
467
+ impact: 'Faster incident detection and response',
468
+ });
469
+ }
470
+ // Metrics recommendations
471
+ for (const issue of metrics.issues) {
472
+ recommendations.push({
473
+ priority: issue.severity === 'high' ? 'high' : 'low',
474
+ category: 'metrics',
475
+ issue: issue.description,
476
+ recommendation: issue.recommendation,
477
+ impact: 'Better observability and performance insights',
478
+ });
479
+ }
480
+ // SLA recommendations
481
+ if (sla && !sla.isCompliant) {
482
+ for (const violation of sla.violations) {
483
+ recommendations.push({
484
+ priority: violation.severity === 'critical' ? 'critical' : 'high',
485
+ category: 'sla',
486
+ issue: `SLA violation: ${violation.metric} is ${violation.actual.toFixed(2)}, threshold is ${violation.threshold}`,
487
+ recommendation: `Investigate and optimize ${violation.metric} to meet SLA`,
488
+ impact: 'Meeting business SLAs and customer expectations',
489
+ });
490
+ }
491
+ }
492
+ // Sort by priority
493
+ const priorityOrder = {
494
+ critical: 0,
495
+ high: 1,
496
+ medium: 2,
497
+ low: 3,
498
+ };
499
+ recommendations.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
500
+ return recommendations;
501
+ }
502
+ /**
503
+ * Calculate overall score
504
+ */
505
+ calculateOverallScore(logging, alerting, metrics, sla) {
506
+ let score = 100;
507
+ // Logging deductions
508
+ if (!logging.isConfigured)
509
+ score -= 15;
510
+ score -= logging.issues.filter(i => i.severity === 'high').length * 10;
511
+ score -= logging.issues.filter(i => i.severity === 'medium').length * 5;
512
+ // Alerting deductions
513
+ if (!alerting.isConfigured)
514
+ score -= 20;
515
+ if (!alerting.coverage.errorAlerts)
516
+ score -= 10;
517
+ if (!alerting.coverage.performanceAlerts)
518
+ score -= 5;
519
+ score -= alerting.issues.filter(i => i.severity === 'high').length * 10;
520
+ // Metrics deductions
521
+ if (!metrics.isConfigured)
522
+ score -= 10;
523
+ if (!metrics.coverage.executionMetrics)
524
+ score -= 5;
525
+ score -= metrics.issues.filter(i => i.severity === 'high').length * 5;
526
+ // SLA deductions
527
+ if (sla && !sla.isCompliant) {
528
+ score -= sla.violations.filter(v => v.severity === 'critical').length * 15;
529
+ score -= sla.violations.filter(v => v.severity === 'major').length * 10;
530
+ }
531
+ return Math.max(0, Math.min(100, score));
532
+ }
533
+ /**
534
+ * Get default results
535
+ */
536
+ getDefaultLoggingResult() {
537
+ return {
538
+ isConfigured: false,
539
+ level: 'unknown',
540
+ issues: [],
541
+ coverage: { nodesWithLogging: 0, totalNodes: 0, percentage: 0 },
542
+ };
543
+ }
544
+ getDefaultAlertingResult() {
545
+ return {
546
+ isConfigured: false,
547
+ rules: [],
548
+ issues: [],
549
+ coverage: { errorAlerts: false, performanceAlerts: false, businessAlerts: false },
550
+ };
551
+ }
552
+ getDefaultMetricsResult() {
553
+ return {
554
+ isConfigured: false,
555
+ metrics: [],
556
+ issues: [],
557
+ coverage: { executionMetrics: false, nodeMetrics: false, businessMetrics: false },
558
+ };
559
+ }
560
+ /**
561
+ * Record execution for SLA tracking
562
+ */
563
+ recordExecution(workflowId, execution) {
564
+ const executions = this.monitoringExecutionHistory.get(workflowId) || [];
565
+ executions.push(execution);
566
+ // Keep last 100 executions
567
+ if (executions.length > 100) {
568
+ executions.shift();
569
+ }
570
+ this.monitoringExecutionHistory.set(workflowId, executions);
571
+ }
572
+ /**
573
+ * Execute workflows multiple times to collect real metrics
574
+ * This validates that metrics are actually being collected correctly
575
+ */
576
+ async executeRuntimeMetricsValidation(workflowId, testInput, iterations = 5) {
577
+ const input = testInput || { test: true, timestamp: Date.now() };
578
+ for (let i = 0; i < iterations; i++) {
579
+ try {
580
+ // Execute workflow
581
+ const execution = await this.executeWorkflow(workflowId, {
582
+ ...input,
583
+ iteration: i + 1,
584
+ }, {
585
+ waitForCompletion: true,
586
+ timeout: 30000,
587
+ });
588
+ // Wait for completion
589
+ const completedExecution = await this.waitForExecution(execution.id, 30000);
590
+ // Record the execution for metrics
591
+ this.recordExecution(workflowId, completedExecution);
592
+ // Verify that execution metadata is captured
593
+ this.verifyExecutionMetadata(completedExecution, i + 1);
594
+ }
595
+ catch (error) {
596
+ // Record failed execution too - important for error rate
597
+ const failedExecution = {
598
+ id: `failed-${Date.now()}-${i}`,
599
+ finished: true,
600
+ status: 'failed',
601
+ mode: 'manual',
602
+ startedAt: new Date().toISOString(),
603
+ stoppedAt: new Date().toISOString(),
604
+ workflowId,
605
+ data: {
606
+ resultData: {
607
+ error: {
608
+ message: error instanceof Error ? error.message : 'Unknown error',
609
+ node: 'unknown',
610
+ },
611
+ runData: {},
612
+ lastNodeExecuted: '',
613
+ },
614
+ },
615
+ };
616
+ this.recordExecution(workflowId, failedExecution);
617
+ }
618
+ }
619
+ }
620
+ /**
621
+ * Verify execution has proper metadata for monitoring
622
+ */
623
+ verifyExecutionMetadata(execution, iteration) {
624
+ const issues = [];
625
+ // Check for required fields
626
+ if (!execution.startedAt) {
627
+ issues.push('Missing startedAt timestamp');
628
+ }
629
+ if (!execution.stoppedAt && execution.finished) {
630
+ issues.push('Missing stoppedAt timestamp');
631
+ }
632
+ if (!execution.workflowId) {
633
+ issues.push('Missing workflowId');
634
+ }
635
+ // Check run data for node metrics
636
+ const runData = execution.data?.resultData?.runData;
637
+ if (runData) {
638
+ for (const [nodeName, nodeRuns] of Object.entries(runData)) {
639
+ for (const run of nodeRuns) {
640
+ if (!run.startTime) {
641
+ issues.push(`Node ${nodeName}: Missing startTime`);
642
+ }
643
+ if (run.executionStatus === undefined) {
644
+ issues.push(`Node ${nodeName}: Missing executionStatus`);
645
+ }
646
+ }
647
+ }
648
+ }
649
+ if (issues.length > 0) {
650
+ console.warn(`Execution ${execution.id} (iteration ${iteration}) has monitoring issues:`, issues);
651
+ }
652
+ }
653
+ /**
654
+ * Wait for workflow execution to complete
655
+ */
656
+ async waitForExecution(executionId, timeoutMs) {
657
+ const startTime = Date.now();
658
+ while (Date.now() - startTime < timeoutMs) {
659
+ const execution = await this.getExecution(executionId);
660
+ if (execution.status !== 'running' && execution.status !== 'waiting') {
661
+ return execution;
662
+ }
663
+ await new Promise(resolve => setTimeout(resolve, 500));
664
+ }
665
+ throw new Error(`Execution ${executionId} timed out after ${timeoutMs}ms`);
666
+ }
667
+ }
668
+ exports.N8nMonitoringValidatorAgent = N8nMonitoringValidatorAgent;
669
+ //# sourceMappingURL=N8nMonitoringValidatorAgent.js.map