agentic-qe 2.5.6 → 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 (134) 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 +41 -0
  22. package/README.md +7 -4
  23. package/dist/agents/n8n/N8nAPIClient.d.ts +121 -0
  24. package/dist/agents/n8n/N8nAPIClient.d.ts.map +1 -0
  25. package/dist/agents/n8n/N8nAPIClient.js +367 -0
  26. package/dist/agents/n8n/N8nAPIClient.js.map +1 -0
  27. package/dist/agents/n8n/N8nAuditPersistence.d.ts +120 -0
  28. package/dist/agents/n8n/N8nAuditPersistence.d.ts.map +1 -0
  29. package/dist/agents/n8n/N8nAuditPersistence.js +473 -0
  30. package/dist/agents/n8n/N8nAuditPersistence.js.map +1 -0
  31. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts +159 -0
  32. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts.map +1 -0
  33. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js +697 -0
  34. package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js.map +1 -0
  35. package/dist/agents/n8n/N8nBaseAgent.d.ts +126 -0
  36. package/dist/agents/n8n/N8nBaseAgent.d.ts.map +1 -0
  37. package/dist/agents/n8n/N8nBaseAgent.js +446 -0
  38. package/dist/agents/n8n/N8nBaseAgent.js.map +1 -0
  39. package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts +164 -0
  40. package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts.map +1 -0
  41. package/dist/agents/n8n/N8nCIOrchestratorAgent.js +610 -0
  42. package/dist/agents/n8n/N8nCIOrchestratorAgent.js.map +1 -0
  43. package/dist/agents/n8n/N8nChaosTesterAgent.d.ts +205 -0
  44. package/dist/agents/n8n/N8nChaosTesterAgent.d.ts.map +1 -0
  45. package/dist/agents/n8n/N8nChaosTesterAgent.js +729 -0
  46. package/dist/agents/n8n/N8nChaosTesterAgent.js.map +1 -0
  47. package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts +228 -0
  48. package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts.map +1 -0
  49. package/dist/agents/n8n/N8nComplianceValidatorAgent.js +986 -0
  50. package/dist/agents/n8n/N8nComplianceValidatorAgent.js.map +1 -0
  51. package/dist/agents/n8n/N8nContractTesterAgent.d.ts +213 -0
  52. package/dist/agents/n8n/N8nContractTesterAgent.d.ts.map +1 -0
  53. package/dist/agents/n8n/N8nContractTesterAgent.js +989 -0
  54. package/dist/agents/n8n/N8nContractTesterAgent.js.map +1 -0
  55. package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts +99 -0
  56. package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts.map +1 -0
  57. package/dist/agents/n8n/N8nExpressionValidatorAgent.js +632 -0
  58. package/dist/agents/n8n/N8nExpressionValidatorAgent.js.map +1 -0
  59. package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts +238 -0
  60. package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts.map +1 -0
  61. package/dist/agents/n8n/N8nFailureModeTesterAgent.js +956 -0
  62. package/dist/agents/n8n/N8nFailureModeTesterAgent.js.map +1 -0
  63. package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts +242 -0
  64. package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts.map +1 -0
  65. package/dist/agents/n8n/N8nIdempotencyTesterAgent.js +992 -0
  66. package/dist/agents/n8n/N8nIdempotencyTesterAgent.js.map +1 -0
  67. package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts +104 -0
  68. package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts.map +1 -0
  69. package/dist/agents/n8n/N8nIntegrationTestAgent.js +653 -0
  70. package/dist/agents/n8n/N8nIntegrationTestAgent.js.map +1 -0
  71. package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts +210 -0
  72. package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts.map +1 -0
  73. package/dist/agents/n8n/N8nMonitoringValidatorAgent.js +669 -0
  74. package/dist/agents/n8n/N8nMonitoringValidatorAgent.js.map +1 -0
  75. package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts +142 -0
  76. package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts.map +1 -0
  77. package/dist/agents/n8n/N8nNodeValidatorAgent.js +1090 -0
  78. package/dist/agents/n8n/N8nNodeValidatorAgent.js.map +1 -0
  79. package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts +198 -0
  80. package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts.map +1 -0
  81. package/dist/agents/n8n/N8nPerformanceTesterAgent.js +653 -0
  82. package/dist/agents/n8n/N8nPerformanceTesterAgent.js.map +1 -0
  83. package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts +245 -0
  84. package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts.map +1 -0
  85. package/dist/agents/n8n/N8nReplayabilityTesterAgent.js +952 -0
  86. package/dist/agents/n8n/N8nReplayabilityTesterAgent.js.map +1 -0
  87. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts +325 -0
  88. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts.map +1 -0
  89. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js +1187 -0
  90. package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js.map +1 -0
  91. package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts +91 -0
  92. package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts.map +1 -0
  93. package/dist/agents/n8n/N8nSecurityAuditorAgent.js +825 -0
  94. package/dist/agents/n8n/N8nSecurityAuditorAgent.js.map +1 -0
  95. package/dist/agents/n8n/N8nTestHarness.d.ts +131 -0
  96. package/dist/agents/n8n/N8nTestHarness.d.ts.map +1 -0
  97. package/dist/agents/n8n/N8nTestHarness.js +456 -0
  98. package/dist/agents/n8n/N8nTestHarness.js.map +1 -0
  99. package/dist/agents/n8n/N8nTriggerTestAgent.d.ts +119 -0
  100. package/dist/agents/n8n/N8nTriggerTestAgent.d.ts.map +1 -0
  101. package/dist/agents/n8n/N8nTriggerTestAgent.js +652 -0
  102. package/dist/agents/n8n/N8nTriggerTestAgent.js.map +1 -0
  103. package/dist/agents/n8n/N8nUnitTesterAgent.d.ts +130 -0
  104. package/dist/agents/n8n/N8nUnitTesterAgent.d.ts.map +1 -0
  105. package/dist/agents/n8n/N8nUnitTesterAgent.js +522 -0
  106. package/dist/agents/n8n/N8nUnitTesterAgent.js.map +1 -0
  107. package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts +201 -0
  108. package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts.map +1 -0
  109. package/dist/agents/n8n/N8nVersionComparatorAgent.js +645 -0
  110. package/dist/agents/n8n/N8nVersionComparatorAgent.js.map +1 -0
  111. package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts +120 -0
  112. package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts.map +1 -0
  113. package/dist/agents/n8n/N8nWorkflowExecutorAgent.js +347 -0
  114. package/dist/agents/n8n/N8nWorkflowExecutorAgent.js.map +1 -0
  115. package/dist/agents/n8n/index.d.ts +119 -0
  116. package/dist/agents/n8n/index.d.ts.map +1 -0
  117. package/dist/agents/n8n/index.js +298 -0
  118. package/dist/agents/n8n/index.js.map +1 -0
  119. package/dist/agents/n8n/types.d.ts +486 -0
  120. package/dist/agents/n8n/types.d.ts.map +1 -0
  121. package/dist/agents/n8n/types.js +8 -0
  122. package/dist/agents/n8n/types.js.map +1 -0
  123. package/dist/cli/init/agents.d.ts.map +1 -1
  124. package/dist/cli/init/agents.js +29 -0
  125. package/dist/cli/init/agents.js.map +1 -1
  126. package/dist/cli/init/skills.d.ts.map +1 -1
  127. package/dist/cli/init/skills.js +7 -1
  128. package/dist/cli/init/skills.js.map +1 -1
  129. package/dist/core/memory/HNSWVectorMemory.js +1 -1
  130. package/dist/mcp/server-instructions.d.ts +1 -1
  131. package/dist/mcp/server-instructions.js +1 -1
  132. package/docs/reference/agents.md +91 -2
  133. package/docs/reference/skills.md +97 -2
  134. package/package.json +2 -2
@@ -0,0 +1,1090 @@
1
+ "use strict";
2
+ /**
3
+ * N8nNodeValidatorAgent
4
+ *
5
+ * Validates n8n node configurations, connections, and data mappings:
6
+ * - Node structure validation
7
+ * - Connection integrity checks
8
+ * - Credential reference validation
9
+ * - Data mapping validation
10
+ * - Conditional routing logic validation
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.N8nNodeValidatorAgent = void 0;
14
+ const N8nBaseAgent_1 = require("./N8nBaseAgent");
15
+ // Node type configurations for validation
16
+ // Extended coverage: 70+ node types (from ~12)
17
+ const NODE_CONFIGS = {
18
+ // ============================================================================
19
+ // Trigger Nodes
20
+ // ============================================================================
21
+ 'n8n-nodes-base.webhook': {
22
+ requiredParams: ['httpMethod', 'path'],
23
+ optionalParams: ['authentication', 'responseMode', 'responseData'],
24
+ requiresCredential: false,
25
+ category: 'trigger',
26
+ },
27
+ 'n8n-nodes-base.manualTrigger': {
28
+ requiredParams: [],
29
+ optionalParams: [],
30
+ requiresCredential: false,
31
+ category: 'trigger',
32
+ },
33
+ 'n8n-nodes-base.scheduleTrigger': {
34
+ requiredParams: ['rule'],
35
+ optionalParams: ['cronExpression'],
36
+ requiresCredential: false,
37
+ category: 'trigger',
38
+ },
39
+ 'n8n-nodes-base.emailReadImap': {
40
+ requiredParams: [],
41
+ optionalParams: ['mailbox', 'format'],
42
+ requiresCredential: true,
43
+ credentialTypes: ['imap'],
44
+ category: 'trigger',
45
+ },
46
+ 'n8n-nodes-base.rssFeedReadTrigger': {
47
+ requiredParams: ['feedUrl'],
48
+ optionalParams: ['pollTimes'],
49
+ requiresCredential: false,
50
+ category: 'trigger',
51
+ },
52
+ // ============================================================================
53
+ // Core/Logic Nodes
54
+ // ============================================================================
55
+ 'n8n-nodes-base.if': {
56
+ requiredParams: ['conditions'],
57
+ optionalParams: [],
58
+ requiresCredential: false,
59
+ category: 'logic',
60
+ },
61
+ 'n8n-nodes-base.switch': {
62
+ requiredParams: ['rules'],
63
+ optionalParams: ['fallbackOutput'],
64
+ requiresCredential: false,
65
+ category: 'logic',
66
+ },
67
+ 'n8n-nodes-base.merge': {
68
+ requiredParams: ['mode'],
69
+ optionalParams: ['joinMode', 'propertyName1', 'propertyName2'],
70
+ requiresCredential: false,
71
+ category: 'logic',
72
+ },
73
+ 'n8n-nodes-base.splitInBatches': {
74
+ requiredParams: ['batchSize'],
75
+ optionalParams: [],
76
+ requiresCredential: false,
77
+ category: 'logic',
78
+ },
79
+ 'n8n-nodes-base.wait': {
80
+ requiredParams: [],
81
+ optionalParams: ['resume', 'amount', 'unit'],
82
+ requiresCredential: false,
83
+ category: 'logic',
84
+ },
85
+ 'n8n-nodes-base.noOp': {
86
+ requiredParams: [],
87
+ optionalParams: [],
88
+ requiresCredential: false,
89
+ category: 'logic',
90
+ },
91
+ 'n8n-nodes-base.filter': {
92
+ requiredParams: ['conditions'],
93
+ optionalParams: [],
94
+ requiresCredential: false,
95
+ category: 'logic',
96
+ },
97
+ 'n8n-nodes-base.limit': {
98
+ requiredParams: ['maxItems'],
99
+ optionalParams: [],
100
+ requiresCredential: false,
101
+ category: 'logic',
102
+ },
103
+ 'n8n-nodes-base.removeDuplicates': {
104
+ requiredParams: [],
105
+ optionalParams: ['compareMode', 'fieldsToCompare'],
106
+ requiresCredential: false,
107
+ category: 'logic',
108
+ },
109
+ 'n8n-nodes-base.sort': {
110
+ requiredParams: ['sortFieldsUi'],
111
+ optionalParams: [],
112
+ requiresCredential: false,
113
+ category: 'logic',
114
+ },
115
+ // ============================================================================
116
+ // Data Transformation Nodes
117
+ // ============================================================================
118
+ 'n8n-nodes-base.set': {
119
+ requiredParams: [],
120
+ optionalParams: ['mode', 'assignments', 'keepOnlySet'],
121
+ requiresCredential: false,
122
+ category: 'transform',
123
+ },
124
+ 'n8n-nodes-base.code': {
125
+ requiredParams: [],
126
+ optionalParams: ['jsCode', 'mode', 'language'],
127
+ requiresCredential: false,
128
+ category: 'transform',
129
+ },
130
+ 'n8n-nodes-base.itemLists': {
131
+ requiredParams: ['operation'],
132
+ optionalParams: ['fieldToSplitOut', 'include'],
133
+ requiresCredential: false,
134
+ category: 'transform',
135
+ },
136
+ 'n8n-nodes-base.dateTime': {
137
+ requiredParams: ['action'],
138
+ optionalParams: ['format', 'timezone'],
139
+ requiresCredential: false,
140
+ category: 'transform',
141
+ },
142
+ 'n8n-nodes-base.crypto': {
143
+ requiredParams: ['action'],
144
+ optionalParams: ['type', 'encoding'],
145
+ requiresCredential: false,
146
+ category: 'transform',
147
+ },
148
+ 'n8n-nodes-base.html': {
149
+ requiredParams: ['operation'],
150
+ optionalParams: ['cssSelector', 'options'],
151
+ requiresCredential: false,
152
+ category: 'transform',
153
+ },
154
+ 'n8n-nodes-base.xml': {
155
+ requiredParams: ['mode'],
156
+ optionalParams: ['options'],
157
+ requiresCredential: false,
158
+ category: 'transform',
159
+ },
160
+ 'n8n-nodes-base.spreadsheetFile': {
161
+ requiredParams: ['operation'],
162
+ optionalParams: ['fileFormat', 'options'],
163
+ requiresCredential: false,
164
+ category: 'transform',
165
+ },
166
+ 'n8n-nodes-base.markdown': {
167
+ requiredParams: ['mode'],
168
+ optionalParams: ['options'],
169
+ requiresCredential: false,
170
+ category: 'transform',
171
+ },
172
+ 'n8n-nodes-base.compressFiles': {
173
+ requiredParams: ['operation'],
174
+ optionalParams: ['outputFormat'],
175
+ requiresCredential: false,
176
+ category: 'transform',
177
+ },
178
+ // ============================================================================
179
+ // HTTP/API Nodes
180
+ // ============================================================================
181
+ 'n8n-nodes-base.httpRequest': {
182
+ requiredParams: ['url', 'method'],
183
+ optionalParams: ['authentication', 'bodyParameters', 'headers', 'queryParameters'],
184
+ requiresCredential: false,
185
+ category: 'http',
186
+ },
187
+ 'n8n-nodes-base.respondToWebhook': {
188
+ requiredParams: [],
189
+ optionalParams: ['respondWith', 'responseBody', 'responseHeaders'],
190
+ requiresCredential: false,
191
+ category: 'http',
192
+ },
193
+ 'n8n-nodes-base.graphql': {
194
+ requiredParams: ['endpoint', 'query'],
195
+ optionalParams: ['authentication', 'variables'],
196
+ requiresCredential: false,
197
+ category: 'http',
198
+ },
199
+ 'n8n-nodes-base.soapRequest': {
200
+ requiredParams: ['url', 'bodyXml'],
201
+ optionalParams: ['authentication'],
202
+ requiresCredential: false,
203
+ category: 'http',
204
+ },
205
+ // ============================================================================
206
+ // Database Nodes
207
+ // ============================================================================
208
+ 'n8n-nodes-base.postgres': {
209
+ requiredParams: ['operation'],
210
+ optionalParams: ['query', 'table', 'schema'],
211
+ requiresCredential: true,
212
+ credentialTypes: ['postgres'],
213
+ category: 'database',
214
+ },
215
+ 'n8n-nodes-base.mysql': {
216
+ requiredParams: ['operation'],
217
+ optionalParams: ['query', 'table'],
218
+ requiresCredential: true,
219
+ credentialTypes: ['mysql'],
220
+ category: 'database',
221
+ },
222
+ 'n8n-nodes-base.mongodb': {
223
+ requiredParams: ['operation'],
224
+ optionalParams: ['collection', 'query'],
225
+ requiresCredential: true,
226
+ credentialTypes: ['mongoDb'],
227
+ category: 'database',
228
+ },
229
+ 'n8n-nodes-base.redis': {
230
+ requiredParams: ['operation'],
231
+ optionalParams: ['key', 'keyType'],
232
+ requiresCredential: true,
233
+ credentialTypes: ['redis'],
234
+ category: 'database',
235
+ },
236
+ 'n8n-nodes-base.mssql': {
237
+ requiredParams: ['operation'],
238
+ optionalParams: ['query', 'table'],
239
+ requiresCredential: true,
240
+ credentialTypes: ['microsoftSql'],
241
+ category: 'database',
242
+ },
243
+ 'n8n-nodes-base.elasticsearch': {
244
+ requiredParams: ['operation'],
245
+ optionalParams: ['index', 'documentId'],
246
+ requiresCredential: true,
247
+ credentialTypes: ['elasticsearch'],
248
+ category: 'database',
249
+ },
250
+ 'n8n-nodes-base.supabase': {
251
+ requiredParams: ['operation'],
252
+ optionalParams: ['tableId'],
253
+ requiresCredential: true,
254
+ credentialTypes: ['supabaseApi'],
255
+ category: 'database',
256
+ },
257
+ 'n8n-nodes-base.snowflake': {
258
+ requiredParams: ['operation'],
259
+ optionalParams: ['query'],
260
+ requiresCredential: true,
261
+ credentialTypes: ['snowflake'],
262
+ category: 'database',
263
+ },
264
+ 'n8n-nodes-base.qdrant': {
265
+ requiredParams: ['operation'],
266
+ optionalParams: ['collection'],
267
+ requiresCredential: true,
268
+ credentialTypes: ['qdrantApi'],
269
+ category: 'database',
270
+ },
271
+ 'n8n-nodes-base.pinecone': {
272
+ requiredParams: ['operation'],
273
+ optionalParams: ['index'],
274
+ requiresCredential: true,
275
+ credentialTypes: ['pineconeApi'],
276
+ category: 'database',
277
+ },
278
+ // ============================================================================
279
+ // Communication Nodes
280
+ // ============================================================================
281
+ 'n8n-nodes-base.slack': {
282
+ requiredParams: ['resource', 'operation'],
283
+ optionalParams: ['channel', 'text', 'attachments'],
284
+ requiresCredential: true,
285
+ credentialTypes: ['slackApi', 'slackOAuth2Api'],
286
+ category: 'communication',
287
+ },
288
+ 'n8n-nodes-base.discord': {
289
+ requiredParams: ['resource', 'operation'],
290
+ optionalParams: ['channelId', 'content'],
291
+ requiresCredential: true,
292
+ credentialTypes: ['discordApi', 'discordWebhookApi'],
293
+ category: 'communication',
294
+ },
295
+ 'n8n-nodes-base.telegram': {
296
+ requiredParams: ['resource', 'operation'],
297
+ optionalParams: ['chatId', 'text'],
298
+ requiresCredential: true,
299
+ credentialTypes: ['telegramApi'],
300
+ category: 'communication',
301
+ },
302
+ 'n8n-nodes-base.microsoftTeams': {
303
+ requiredParams: ['resource', 'operation'],
304
+ optionalParams: ['teamId', 'channelId', 'message'],
305
+ requiresCredential: true,
306
+ credentialTypes: ['microsoftTeamsOAuth2Api'],
307
+ category: 'communication',
308
+ },
309
+ 'n8n-nodes-base.emailSend': {
310
+ requiredParams: ['toEmail', 'subject'],
311
+ optionalParams: ['text', 'html', 'attachments'],
312
+ requiresCredential: true,
313
+ credentialTypes: ['smtp'],
314
+ category: 'communication',
315
+ },
316
+ 'n8n-nodes-base.gmail': {
317
+ requiredParams: ['resource', 'operation'],
318
+ optionalParams: ['subject', 'message'],
319
+ requiresCredential: true,
320
+ credentialTypes: ['gmailOAuth2'],
321
+ category: 'communication',
322
+ },
323
+ 'n8n-nodes-base.sendGrid': {
324
+ requiredParams: ['resource', 'operation'],
325
+ optionalParams: ['toEmail', 'subject'],
326
+ requiresCredential: true,
327
+ credentialTypes: ['sendGridApi'],
328
+ category: 'communication',
329
+ },
330
+ 'n8n-nodes-base.twilio': {
331
+ requiredParams: ['resource', 'operation'],
332
+ optionalParams: ['from', 'to', 'message'],
333
+ requiresCredential: true,
334
+ credentialTypes: ['twilioApi'],
335
+ category: 'communication',
336
+ },
337
+ // ============================================================================
338
+ // Productivity/SaaS Nodes
339
+ // ============================================================================
340
+ 'n8n-nodes-base.googleSheets': {
341
+ requiredParams: ['operation'],
342
+ optionalParams: ['documentId', 'sheetName', 'range'],
343
+ requiresCredential: true,
344
+ credentialTypes: ['googleSheetsOAuth2Api'],
345
+ category: 'productivity',
346
+ },
347
+ 'n8n-nodes-base.googleDrive': {
348
+ requiredParams: ['operation'],
349
+ optionalParams: ['fileId', 'folderId'],
350
+ requiresCredential: true,
351
+ credentialTypes: ['googleDriveOAuth2Api'],
352
+ category: 'productivity',
353
+ },
354
+ 'n8n-nodes-base.googleDocs': {
355
+ requiredParams: ['operation'],
356
+ optionalParams: ['documentId'],
357
+ requiresCredential: true,
358
+ credentialTypes: ['googleDocsOAuth2Api'],
359
+ category: 'productivity',
360
+ },
361
+ 'n8n-nodes-base.googleCalendar': {
362
+ requiredParams: ['resource', 'operation'],
363
+ optionalParams: ['calendar', 'eventId'],
364
+ requiresCredential: true,
365
+ credentialTypes: ['googleCalendarOAuth2Api'],
366
+ category: 'productivity',
367
+ },
368
+ 'n8n-nodes-base.notion': {
369
+ requiredParams: ['resource', 'operation'],
370
+ optionalParams: ['databaseId', 'pageId'],
371
+ requiresCredential: true,
372
+ credentialTypes: ['notionApi'],
373
+ category: 'productivity',
374
+ },
375
+ 'n8n-nodes-base.airtable': {
376
+ requiredParams: ['operation'],
377
+ optionalParams: ['baseId', 'tableId'],
378
+ requiresCredential: true,
379
+ credentialTypes: ['airtableApi', 'airtableTokenApi'],
380
+ category: 'productivity',
381
+ },
382
+ 'n8n-nodes-base.trello': {
383
+ requiredParams: ['resource', 'operation'],
384
+ optionalParams: ['boardId', 'listId', 'cardId'],
385
+ requiresCredential: true,
386
+ credentialTypes: ['trelloApi'],
387
+ category: 'productivity',
388
+ },
389
+ 'n8n-nodes-base.asana': {
390
+ requiredParams: ['resource', 'operation'],
391
+ optionalParams: ['workspaceId', 'projectId'],
392
+ requiresCredential: true,
393
+ credentialTypes: ['asanaApi'],
394
+ category: 'productivity',
395
+ },
396
+ 'n8n-nodes-base.jira': {
397
+ requiredParams: ['resource', 'operation'],
398
+ optionalParams: ['issueKey', 'projectId'],
399
+ requiresCredential: true,
400
+ credentialTypes: ['jiraSoftwareCloudApi', 'jiraSoftwareServerApi'],
401
+ category: 'productivity',
402
+ },
403
+ 'n8n-nodes-base.linearApp': {
404
+ requiredParams: ['resource', 'operation'],
405
+ optionalParams: ['issueId', 'teamId'],
406
+ requiresCredential: true,
407
+ credentialTypes: ['linearApi'],
408
+ category: 'productivity',
409
+ },
410
+ 'n8n-nodes-base.dropbox': {
411
+ requiredParams: ['resource', 'operation'],
412
+ optionalParams: ['path'],
413
+ requiresCredential: true,
414
+ credentialTypes: ['dropboxApi', 'dropboxOAuth2Api'],
415
+ category: 'productivity',
416
+ },
417
+ 'n8n-nodes-base.box': {
418
+ requiredParams: ['resource', 'operation'],
419
+ optionalParams: ['fileId', 'folderId'],
420
+ requiresCredential: true,
421
+ credentialTypes: ['boxOAuth2Api'],
422
+ category: 'productivity',
423
+ },
424
+ // ============================================================================
425
+ // Developer/DevOps Nodes
426
+ // ============================================================================
427
+ 'n8n-nodes-base.github': {
428
+ requiredParams: ['resource', 'operation'],
429
+ optionalParams: ['owner', 'repository'],
430
+ requiresCredential: true,
431
+ credentialTypes: ['githubApi', 'githubOAuth2Api'],
432
+ category: 'devops',
433
+ },
434
+ 'n8n-nodes-base.gitlab': {
435
+ requiredParams: ['resource', 'operation'],
436
+ optionalParams: ['owner', 'repository'],
437
+ requiresCredential: true,
438
+ credentialTypes: ['gitlabApi', 'gitlabOAuth2Api'],
439
+ category: 'devops',
440
+ },
441
+ 'n8n-nodes-base.bitbucket': {
442
+ requiredParams: ['resource', 'operation'],
443
+ optionalParams: ['workspace', 'repositorySlug'],
444
+ requiresCredential: true,
445
+ credentialTypes: ['bitbucketApi'],
446
+ category: 'devops',
447
+ },
448
+ 'n8n-nodes-base.executeCommand': {
449
+ requiredParams: ['command'],
450
+ optionalParams: ['cwd'],
451
+ requiresCredential: false,
452
+ category: 'devops',
453
+ },
454
+ 'n8n-nodes-base.ssh': {
455
+ requiredParams: ['command'],
456
+ optionalParams: ['cwd'],
457
+ requiresCredential: true,
458
+ credentialTypes: ['sshPassword', 'sshPrivateKey'],
459
+ category: 'devops',
460
+ },
461
+ 'n8n-nodes-base.ftp': {
462
+ requiredParams: ['operation'],
463
+ optionalParams: ['path'],
464
+ requiresCredential: true,
465
+ credentialTypes: ['ftp', 'sftp'],
466
+ category: 'devops',
467
+ },
468
+ 'n8n-nodes-base.awsS3': {
469
+ requiredParams: ['operation'],
470
+ optionalParams: ['bucketName', 'fileKey'],
471
+ requiresCredential: true,
472
+ credentialTypes: ['aws'],
473
+ category: 'devops',
474
+ },
475
+ 'n8n-nodes-base.awsLambda': {
476
+ requiredParams: ['operation'],
477
+ optionalParams: ['functionName'],
478
+ requiresCredential: true,
479
+ credentialTypes: ['aws'],
480
+ category: 'devops',
481
+ },
482
+ 'n8n-nodes-base.awsSns': {
483
+ requiredParams: ['operation'],
484
+ optionalParams: ['topicArn'],
485
+ requiresCredential: true,
486
+ credentialTypes: ['aws'],
487
+ category: 'devops',
488
+ },
489
+ 'n8n-nodes-base.awsSqs': {
490
+ requiredParams: ['operation'],
491
+ optionalParams: ['queueUrl'],
492
+ requiresCredential: true,
493
+ credentialTypes: ['aws'],
494
+ category: 'devops',
495
+ },
496
+ // ============================================================================
497
+ // CRM/Marketing Nodes
498
+ // ============================================================================
499
+ 'n8n-nodes-base.salesforce': {
500
+ requiredParams: ['resource', 'operation'],
501
+ optionalParams: ['accountId', 'contactId'],
502
+ requiresCredential: true,
503
+ credentialTypes: ['salesforceOAuth2Api'],
504
+ category: 'crm',
505
+ },
506
+ 'n8n-nodes-base.hubspot': {
507
+ requiredParams: ['resource', 'operation'],
508
+ optionalParams: ['contactId'],
509
+ requiresCredential: true,
510
+ credentialTypes: ['hubspotApi', 'hubspotOAuth2Api'],
511
+ category: 'crm',
512
+ },
513
+ 'n8n-nodes-base.mailchimp': {
514
+ requiredParams: ['resource', 'operation'],
515
+ optionalParams: ['listId'],
516
+ requiresCredential: true,
517
+ credentialTypes: ['mailchimpApi'],
518
+ category: 'crm',
519
+ },
520
+ 'n8n-nodes-base.stripe': {
521
+ requiredParams: ['resource', 'operation'],
522
+ optionalParams: ['customerId'],
523
+ requiresCredential: true,
524
+ credentialTypes: ['stripeApi'],
525
+ category: 'crm',
526
+ },
527
+ 'n8n-nodes-base.shopify': {
528
+ requiredParams: ['resource', 'operation'],
529
+ optionalParams: ['orderId', 'productId'],
530
+ requiresCredential: true,
531
+ credentialTypes: ['shopifyApi', 'shopifyAccessTokenApi'],
532
+ category: 'crm',
533
+ },
534
+ // ============================================================================
535
+ // AI/LLM Nodes
536
+ // ============================================================================
537
+ '@n8n/n8n-nodes-langchain.openAi': {
538
+ requiredParams: ['resource', 'operation'],
539
+ optionalParams: ['model', 'prompt', 'messages'],
540
+ requiresCredential: true,
541
+ credentialTypes: ['openAiApi'],
542
+ category: 'ai',
543
+ },
544
+ '@n8n/n8n-nodes-langchain.agent': {
545
+ requiredParams: [],
546
+ optionalParams: ['promptType', 'text'],
547
+ requiresCredential: false,
548
+ category: 'ai',
549
+ },
550
+ '@n8n/n8n-nodes-langchain.lmChatOpenAi': {
551
+ requiredParams: [],
552
+ optionalParams: ['model', 'options'],
553
+ requiresCredential: true,
554
+ credentialTypes: ['openAiApi'],
555
+ category: 'ai',
556
+ },
557
+ '@n8n/n8n-nodes-langchain.lmChatAnthropic': {
558
+ requiredParams: [],
559
+ optionalParams: ['model', 'options'],
560
+ requiresCredential: true,
561
+ credentialTypes: ['anthropicApi'],
562
+ category: 'ai',
563
+ },
564
+ '@n8n/n8n-nodes-langchain.vectorStoreInMemory': {
565
+ requiredParams: [],
566
+ optionalParams: ['mode'],
567
+ requiresCredential: false,
568
+ category: 'ai',
569
+ },
570
+ '@n8n/n8n-nodes-langchain.embeddingsOpenAi': {
571
+ requiredParams: [],
572
+ optionalParams: ['model', 'options'],
573
+ requiresCredential: true,
574
+ credentialTypes: ['openAiApi'],
575
+ category: 'ai',
576
+ },
577
+ '@n8n/n8n-nodes-langchain.toolHttpRequest': {
578
+ requiredParams: ['url'],
579
+ optionalParams: ['method', 'description'],
580
+ requiresCredential: false,
581
+ category: 'ai',
582
+ },
583
+ '@n8n/n8n-nodes-langchain.toolCode': {
584
+ requiredParams: ['jsCode'],
585
+ optionalParams: ['name', 'description'],
586
+ requiresCredential: false,
587
+ category: 'ai',
588
+ },
589
+ '@n8n/n8n-nodes-langchain.memoryBufferWindow': {
590
+ requiredParams: [],
591
+ optionalParams: ['sessionIdType', 'contextWindowLength'],
592
+ requiresCredential: false,
593
+ category: 'ai',
594
+ },
595
+ '@n8n/n8n-nodes-langchain.chainSummarization': {
596
+ requiredParams: [],
597
+ optionalParams: ['options'],
598
+ requiresCredential: false,
599
+ category: 'ai',
600
+ },
601
+ };
602
+ class N8nNodeValidatorAgent extends N8nBaseAgent_1.N8nBaseAgent {
603
+ constructor(config) {
604
+ const capabilities = [
605
+ {
606
+ name: 'node-validation',
607
+ version: '1.0.0',
608
+ description: 'Validate n8n node configurations',
609
+ parameters: {},
610
+ },
611
+ {
612
+ name: 'connection-validation',
613
+ version: '1.0.0',
614
+ description: 'Validate connections between nodes',
615
+ parameters: {},
616
+ },
617
+ {
618
+ name: 'credential-validation',
619
+ version: '1.0.0',
620
+ description: 'Validate credential references',
621
+ parameters: {},
622
+ },
623
+ {
624
+ name: 'data-mapping-validation',
625
+ version: '1.0.0',
626
+ description: 'Validate data mappings between nodes',
627
+ parameters: {},
628
+ },
629
+ ];
630
+ super({
631
+ ...config,
632
+ type: 'n8n-node-validator',
633
+ capabilities: [...capabilities, ...(config.capabilities || [])],
634
+ });
635
+ }
636
+ async performTask(task) {
637
+ const validationTask = task;
638
+ if (validationTask.type !== 'node-validation') {
639
+ throw new Error(`Unsupported task type: ${validationTask.type}`);
640
+ }
641
+ return this.validateWorkflow(validationTask.target, validationTask.options);
642
+ }
643
+ /**
644
+ * Validate entire workflow with optional REAL execution test
645
+ */
646
+ async validateWorkflow(workflowId, options) {
647
+ const workflow = await this.getWorkflow(workflowId);
648
+ // Validate nodes (static analysis)
649
+ const nodeResults = await this.validateNodes(workflow, options?.strictMode);
650
+ // Validate connections (static analysis)
651
+ const connectionResults = this.validateConnections(workflow);
652
+ // Validate credentials (static analysis)
653
+ let credentialResults = [];
654
+ if (options?.validateCredentials) {
655
+ credentialResults = await this.validateCredentials(workflow);
656
+ }
657
+ // RUNTIME VALIDATION: Actually execute the workflow to verify nodes work
658
+ let runtimeValidation;
659
+ if (options?.executeRuntimeTest) {
660
+ runtimeValidation = await this.executeRuntimeValidation(workflowId, options.testInput || {});
661
+ // Add runtime errors to node results
662
+ for (const error of runtimeValidation.errors) {
663
+ const nodeResult = nodeResults.find(n => n.nodeName === error.nodeName);
664
+ if (nodeResult) {
665
+ nodeResult.valid = false;
666
+ nodeResult.issues.push({
667
+ severity: 'error',
668
+ code: 'RUNTIME_ERROR',
669
+ message: `Runtime execution failed: ${error.errorMessage}`,
670
+ node: error.nodeName,
671
+ });
672
+ }
673
+ }
674
+ }
675
+ // Calculate summary
676
+ const validNodes = nodeResults.filter(r => r.valid).length;
677
+ const validConnections = connectionResults.filter(r => r.valid).length;
678
+ const totalIssues = [
679
+ ...nodeResults.flatMap(r => r.issues),
680
+ ...connectionResults.flatMap(r => r.issues),
681
+ ];
682
+ const issues = totalIssues.filter(i => i.severity === 'error').length;
683
+ const warnings = totalIssues.filter(i => i.severity === 'warning').length;
684
+ // Calculate score (including runtime validation if performed)
685
+ let nodeScore = workflow.nodes.length > 0 ? (validNodes / workflow.nodes.length) * 40 : 40;
686
+ const connectionScore = Object.keys(workflow.connections).length > 0
687
+ ? (validConnections / Object.keys(workflow.connections).length) * 20
688
+ : 20;
689
+ const credentialScore = credentialResults.length > 0
690
+ ? (credentialResults.filter(r => r.valid).length / credentialResults.length) * 15
691
+ : 15;
692
+ // Runtime score is worth 25% if executed
693
+ let runtimeScore = 25; // Default if not executed
694
+ if (runtimeValidation?.executed) {
695
+ const runtimePassed = runtimeValidation.status === 'success' &&
696
+ runtimeValidation.nodesFailed.length === 0;
697
+ runtimeScore = runtimePassed ? 25 : 0;
698
+ }
699
+ const score = Math.round(nodeScore + connectionScore + credentialScore + runtimeScore);
700
+ const result = {
701
+ workflowId,
702
+ valid: issues === 0 && (!runtimeValidation?.executed || runtimeValidation.status === 'success'),
703
+ score,
704
+ nodeResults,
705
+ connectionResults,
706
+ credentialResults,
707
+ runtimeValidation,
708
+ summary: {
709
+ totalNodes: workflow.nodes.length,
710
+ validNodes,
711
+ totalConnections: Object.keys(workflow.connections).length,
712
+ validConnections,
713
+ issues,
714
+ warnings,
715
+ runtimeExecuted: runtimeValidation?.executed,
716
+ runtimePassed: runtimeValidation?.executed ?
717
+ runtimeValidation.status === 'success' && runtimeValidation.nodesFailed.length === 0 :
718
+ undefined,
719
+ },
720
+ };
721
+ // Store result
722
+ await this.storeTestResult(`node-validation:${workflowId}`, result);
723
+ // Emit event
724
+ this.emitEvent('node.validation.completed', {
725
+ workflowId,
726
+ valid: result.valid,
727
+ score: result.score,
728
+ issues: result.summary.issues,
729
+ runtimeExecuted: result.summary.runtimeExecuted,
730
+ runtimePassed: result.summary.runtimePassed,
731
+ });
732
+ return result;
733
+ }
734
+ /**
735
+ * Execute REAL runtime validation by actually running the workflow
736
+ * This catches issues that static analysis cannot find:
737
+ * - Credential authentication failures
738
+ * - API connectivity issues
739
+ * - Runtime type mismatches
740
+ * - External service availability
741
+ */
742
+ async executeRuntimeValidation(workflowId, testInput) {
743
+ const startTime = Date.now();
744
+ try {
745
+ // Execute the workflow
746
+ const execution = await this.executeWorkflow(workflowId, testInput);
747
+ // Wait for completion with timeout
748
+ const completedExecution = await this.waitForExecution(execution.id, 60000);
749
+ // Extract results
750
+ const nodesExecuted = this.extractExecutedNodes(completedExecution);
751
+ const errors = this.extractNodeErrors(completedExecution);
752
+ const nodesFailed = errors.map(e => e.nodeName);
753
+ return {
754
+ executed: true,
755
+ executionId: completedExecution.id,
756
+ status: completedExecution.status,
757
+ nodesExecuted,
758
+ nodesFailed,
759
+ errors,
760
+ duration: Date.now() - startTime,
761
+ };
762
+ }
763
+ catch (error) {
764
+ return {
765
+ executed: true,
766
+ nodesExecuted: [],
767
+ nodesFailed: [],
768
+ errors: [{
769
+ nodeName: 'workflow',
770
+ errorMessage: error instanceof Error ? error.message : String(error),
771
+ errorType: 'execution_error',
772
+ }],
773
+ duration: Date.now() - startTime,
774
+ };
775
+ }
776
+ }
777
+ /**
778
+ * Wait for workflow execution to complete
779
+ */
780
+ async waitForExecution(executionId, timeout) {
781
+ const startTime = Date.now();
782
+ while (Date.now() - startTime < timeout) {
783
+ const execution = await this.n8nClient.getExecution(executionId);
784
+ if (execution.finished) {
785
+ return execution;
786
+ }
787
+ await new Promise(resolve => setTimeout(resolve, 500));
788
+ }
789
+ return this.n8nClient.getExecution(executionId);
790
+ }
791
+ /**
792
+ * Extract list of executed nodes from execution data
793
+ */
794
+ extractExecutedNodes(execution) {
795
+ if (!execution.data?.resultData?.runData) {
796
+ return [];
797
+ }
798
+ return Object.keys(execution.data.resultData.runData);
799
+ }
800
+ /**
801
+ * Extract node errors from execution data
802
+ */
803
+ extractNodeErrors(execution) {
804
+ const errors = [];
805
+ if (!execution.data?.resultData?.runData) {
806
+ // Check for top-level error
807
+ if (execution.data?.resultData?.error) {
808
+ const error = execution.data.resultData.error;
809
+ errors.push({
810
+ nodeName: 'workflow',
811
+ errorMessage: typeof error === 'string' ? error : error.message || 'Unknown error',
812
+ errorType: 'workflow_error',
813
+ });
814
+ }
815
+ return errors;
816
+ }
817
+ const runData = execution.data.resultData.runData;
818
+ for (const [nodeName, nodeRuns] of Object.entries(runData)) {
819
+ if (Array.isArray(nodeRuns)) {
820
+ for (const run of nodeRuns) {
821
+ if (run.error) {
822
+ errors.push({
823
+ nodeName,
824
+ errorMessage: typeof run.error === 'string'
825
+ ? run.error
826
+ : run.error.message || 'Node execution failed',
827
+ errorType: run.error.name || 'node_error',
828
+ });
829
+ }
830
+ }
831
+ }
832
+ }
833
+ return errors;
834
+ }
835
+ /**
836
+ * Validate all nodes in workflow
837
+ */
838
+ async validateNodes(workflow, strictMode = false) {
839
+ const results = [];
840
+ for (const node of workflow.nodes) {
841
+ const issues = this.validateNode(node, strictMode);
842
+ results.push({
843
+ nodeId: node.id,
844
+ nodeName: node.name,
845
+ nodeType: node.type,
846
+ valid: issues.filter(i => i.severity === 'error').length === 0,
847
+ issues,
848
+ });
849
+ }
850
+ return results;
851
+ }
852
+ /**
853
+ * Validate single node
854
+ */
855
+ validateNode(node, strictMode) {
856
+ const issues = [];
857
+ // Basic structure validation
858
+ if (!node.id) {
859
+ issues.push({
860
+ severity: 'error',
861
+ code: 'MISSING_NODE_ID',
862
+ message: 'Node is missing ID',
863
+ node: node.name,
864
+ });
865
+ }
866
+ if (!node.type) {
867
+ issues.push({
868
+ severity: 'error',
869
+ code: 'MISSING_NODE_TYPE',
870
+ message: 'Node is missing type',
871
+ node: node.name,
872
+ });
873
+ }
874
+ if (!node.position || node.position.length !== 2) {
875
+ issues.push({
876
+ severity: 'warning',
877
+ code: 'INVALID_POSITION',
878
+ message: 'Node has invalid position',
879
+ node: node.name,
880
+ });
881
+ }
882
+ // Type-specific validation
883
+ const config = NODE_CONFIGS[node.type];
884
+ if (config) {
885
+ // Check required parameters
886
+ for (const param of config.requiredParams) {
887
+ if (!this.hasParameter(node, param)) {
888
+ issues.push({
889
+ severity: strictMode ? 'error' : 'warning',
890
+ code: 'MISSING_REQUIRED_PARAM',
891
+ message: `Missing required parameter: ${param}`,
892
+ node: node.name,
893
+ field: param,
894
+ suggestion: `Add the "${param}" parameter to this node`,
895
+ });
896
+ }
897
+ }
898
+ // Check credential requirement
899
+ if (config.requiresCredential && !node.credentials) {
900
+ issues.push({
901
+ severity: 'error',
902
+ code: 'MISSING_CREDENTIAL',
903
+ message: `Node requires credentials but none configured`,
904
+ node: node.name,
905
+ suggestion: `Configure ${config.credentialTypes?.join(' or ')} credentials`,
906
+ });
907
+ }
908
+ }
909
+ // Check for disabled nodes in active workflow
910
+ if (node.disabled) {
911
+ issues.push({
912
+ severity: 'info',
913
+ code: 'DISABLED_NODE',
914
+ message: 'Node is disabled',
915
+ node: node.name,
916
+ });
917
+ }
918
+ // Validate IF/Switch conditions
919
+ if (node.type === 'n8n-nodes-base.if' || node.type === 'n8n-nodes-base.switch') {
920
+ issues.push(...this.validateConditionalNode(node));
921
+ }
922
+ return issues;
923
+ }
924
+ /**
925
+ * Validate conditional nodes (IF/Switch)
926
+ */
927
+ validateConditionalNode(node) {
928
+ const issues = [];
929
+ if (node.type === 'n8n-nodes-base.if') {
930
+ const conditions = node.parameters.conditions;
931
+ if (!conditions) {
932
+ issues.push({
933
+ severity: 'error',
934
+ code: 'MISSING_CONDITIONS',
935
+ message: 'IF node has no conditions configured',
936
+ node: node.name,
937
+ });
938
+ }
939
+ else {
940
+ // Check condition structure
941
+ const hasValidConditions = Object.values(conditions).some(group => Array.isArray(group) && group.length > 0);
942
+ if (!hasValidConditions) {
943
+ issues.push({
944
+ severity: 'warning',
945
+ code: 'EMPTY_CONDITIONS',
946
+ message: 'IF node has empty conditions',
947
+ node: node.name,
948
+ });
949
+ }
950
+ }
951
+ }
952
+ if (node.type === 'n8n-nodes-base.switch') {
953
+ const rules = node.parameters.rules;
954
+ if (!rules || !Array.isArray(rules) || rules.length === 0) {
955
+ issues.push({
956
+ severity: 'error',
957
+ code: 'MISSING_RULES',
958
+ message: 'Switch node has no rules configured',
959
+ node: node.name,
960
+ });
961
+ }
962
+ }
963
+ return issues;
964
+ }
965
+ /**
966
+ * Validate connections between nodes
967
+ */
968
+ validateConnections(workflow) {
969
+ const results = [];
970
+ const nodeNames = new Set(workflow.nodes.map(n => n.name));
971
+ for (const [sourceName, connections] of Object.entries(workflow.connections)) {
972
+ const issues = [];
973
+ // Check source exists
974
+ if (!nodeNames.has(sourceName)) {
975
+ issues.push({
976
+ severity: 'error',
977
+ code: 'INVALID_SOURCE',
978
+ message: `Connection source "${sourceName}" does not exist`,
979
+ });
980
+ }
981
+ // Check each target
982
+ if (connections.main) {
983
+ for (let outputIndex = 0; outputIndex < connections.main.length; outputIndex++) {
984
+ const output = connections.main[outputIndex];
985
+ for (const conn of output) {
986
+ const targetIssues = [];
987
+ if (!nodeNames.has(conn.node)) {
988
+ targetIssues.push({
989
+ severity: 'error',
990
+ code: 'INVALID_TARGET',
991
+ message: `Connection target "${conn.node}" does not exist`,
992
+ });
993
+ }
994
+ // Check for self-references
995
+ if (conn.node === sourceName) {
996
+ targetIssues.push({
997
+ severity: 'warning',
998
+ code: 'SELF_REFERENCE',
999
+ message: 'Node connects to itself',
1000
+ node: sourceName,
1001
+ });
1002
+ }
1003
+ results.push({
1004
+ source: sourceName,
1005
+ target: conn.node,
1006
+ valid: targetIssues.filter(i => i.severity === 'error').length === 0,
1007
+ issues: targetIssues,
1008
+ });
1009
+ }
1010
+ }
1011
+ }
1012
+ }
1013
+ return results;
1014
+ }
1015
+ /**
1016
+ * Validate credential references
1017
+ */
1018
+ async validateCredentials(workflow) {
1019
+ const results = [];
1020
+ // Get available credentials
1021
+ let availableCredentials;
1022
+ try {
1023
+ const credentials = await this.n8nClient.listCredentials();
1024
+ availableCredentials = new Map(credentials.map(c => [c.id, true]));
1025
+ }
1026
+ catch {
1027
+ // If we can't fetch credentials, skip validation
1028
+ return results;
1029
+ }
1030
+ for (const node of workflow.nodes) {
1031
+ if (node.credentials) {
1032
+ for (const [credType, credRef] of Object.entries(node.credentials)) {
1033
+ const exists = availableCredentials.has(credRef.id);
1034
+ results.push({
1035
+ nodeId: node.id,
1036
+ nodeName: node.name,
1037
+ credentialType: credType,
1038
+ credentialId: credRef.id,
1039
+ valid: exists,
1040
+ exists,
1041
+ issue: exists ? undefined : `Credential "${credRef.name}" (${credRef.id}) not found`,
1042
+ });
1043
+ }
1044
+ }
1045
+ }
1046
+ return results;
1047
+ }
1048
+ /**
1049
+ * Check if node has a parameter (handles nested paths)
1050
+ */
1051
+ hasParameter(node, param) {
1052
+ const parts = param.split('.');
1053
+ let current = node.parameters;
1054
+ for (const part of parts) {
1055
+ if (current === null || current === undefined)
1056
+ return false;
1057
+ if (typeof current !== 'object')
1058
+ return false;
1059
+ current = current[part];
1060
+ }
1061
+ return current !== undefined && current !== null && current !== '';
1062
+ }
1063
+ /**
1064
+ * Get validation summary for a workflow
1065
+ */
1066
+ async getValidationSummary(workflowId) {
1067
+ const result = await this.validateWorkflow(workflowId);
1068
+ const recommendations = [];
1069
+ // Generate recommendations based on issues
1070
+ if (result.summary.issues > 0) {
1071
+ recommendations.push('Fix all error-level issues before deployment');
1072
+ }
1073
+ if (result.credentialResults.some(r => !r.valid)) {
1074
+ recommendations.push('Configure missing credentials');
1075
+ }
1076
+ const orphanNodes = result.nodeResults.filter(r => r.issues.some(i => i.code === 'ORPHAN_NODE'));
1077
+ if (orphanNodes.length > 0) {
1078
+ recommendations.push(`Connect or remove ${orphanNodes.length} orphan node(s)`);
1079
+ }
1080
+ return {
1081
+ valid: result.valid,
1082
+ score: result.score,
1083
+ issues: result.summary.issues,
1084
+ warnings: result.summary.warnings,
1085
+ recommendations,
1086
+ };
1087
+ }
1088
+ }
1089
+ exports.N8nNodeValidatorAgent = N8nNodeValidatorAgent;
1090
+ //# sourceMappingURL=N8nNodeValidatorAgent.js.map