n8n-mcp 2.11.3 → 2.13.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.
- package/.env.example +26 -0
- package/README.md +8 -6
- package/data/nodes.db +0 -0
- package/dist/config/n8n-api.d.ts +6 -0
- package/dist/config/n8n-api.d.ts.map +1 -1
- package/dist/config/n8n-api.js +12 -0
- package/dist/config/n8n-api.js.map +1 -1
- package/dist/http-server-single-session.d.ts +6 -1
- package/dist/http-server-single-session.d.ts.map +1 -1
- package/dist/http-server-single-session.js +116 -4
- package/dist/http-server-single-session.js.map +1 -1
- package/dist/mcp/handlers-n8n-manager.d.ts +22 -17
- package/dist/mcp/handlers-n8n-manager.d.ts.map +1 -1
- package/dist/mcp/handlers-n8n-manager.js +255 -46
- package/dist/mcp/handlers-n8n-manager.js.map +1 -1
- package/dist/mcp/handlers-workflow-diff.d.ts +2 -1
- package/dist/mcp/handlers-workflow-diff.d.ts.map +1 -1
- package/dist/mcp/handlers-workflow-diff.js +2 -2
- package/dist/mcp/handlers-workflow-diff.js.map +1 -1
- package/dist/mcp/server.d.ts +3 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +41 -22
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-docs/index.d.ts.map +1 -1
- package/dist/mcp/tool-docs/index.js +1 -0
- package/dist/mcp/tool-docs/index.js.map +1 -1
- package/dist/mcp/tool-docs/validation/validate-workflow.js +1 -1
- package/dist/mcp/tool-docs/validation/validate-workflow.js.map +1 -1
- package/dist/mcp/tool-docs/workflow_management/index.d.ts +1 -0
- package/dist/mcp/tool-docs/workflow_management/index.d.ts.map +1 -1
- package/dist/mcp/tool-docs/workflow_management/index.js +3 -1
- package/dist/mcp/tool-docs/workflow_management/index.js.map +1 -1
- package/dist/mcp/tool-docs/workflow_management/n8n-autofix-workflow.d.ts +3 -0
- package/dist/mcp/tool-docs/workflow_management/n8n-autofix-workflow.d.ts.map +1 -0
- package/dist/mcp/tool-docs/workflow_management/n8n-autofix-workflow.js +127 -0
- package/dist/mcp/tool-docs/workflow_management/n8n-autofix-workflow.js.map +1 -0
- package/dist/mcp/tool-docs/workflow_management/n8n-validate-workflow.js +1 -1
- package/dist/mcp/tool-docs/workflow_management/n8n-validate-workflow.js.map +1 -1
- package/dist/mcp/tools-n8n-manager.d.ts.map +1 -1
- package/dist/mcp/tools-n8n-manager.js +35 -0
- package/dist/mcp/tools-n8n-manager.js.map +1 -1
- package/dist/mcp-engine.d.ts +2 -1
- package/dist/mcp-engine.d.ts.map +1 -1
- package/dist/mcp-engine.js +2 -2
- package/dist/mcp-engine.js.map +1 -1
- package/dist/scripts/debug-http-search.d.ts +3 -0
- package/dist/scripts/debug-http-search.d.ts.map +1 -0
- package/dist/scripts/debug-http-search.js +57 -0
- package/dist/scripts/debug-http-search.js.map +1 -0
- package/dist/scripts/sanitize-templates.js +11 -1
- package/dist/scripts/sanitize-templates.js.map +1 -1
- package/dist/scripts/test-autofix-documentation.d.ts +3 -0
- package/dist/scripts/test-autofix-documentation.d.ts.map +1 -0
- package/dist/scripts/test-autofix-documentation.js +103 -0
- package/dist/scripts/test-autofix-documentation.js.map +1 -0
- package/dist/scripts/test-autofix-workflow.d.ts +2 -0
- package/dist/scripts/test-autofix-workflow.d.ts.map +1 -0
- package/dist/scripts/test-autofix-workflow.js +223 -0
- package/dist/scripts/test-autofix-workflow.js.map +1 -0
- package/dist/scripts/test-node-suggestions.d.ts +3 -0
- package/dist/scripts/test-node-suggestions.d.ts.map +1 -0
- package/dist/scripts/test-node-suggestions.js +165 -0
- package/dist/scripts/test-node-suggestions.js.map +1 -0
- package/dist/scripts/test-summary.d.ts +3 -0
- package/dist/scripts/test-summary.d.ts.map +1 -0
- package/dist/scripts/test-summary.js +77 -0
- package/dist/scripts/test-summary.js.map +1 -0
- package/dist/scripts/test-validation-parity.d.ts +2 -0
- package/dist/scripts/test-validation-parity.d.ts.map +1 -0
- package/dist/scripts/test-validation-parity.js +153 -0
- package/dist/scripts/test-validation-parity.js.map +1 -0
- package/dist/scripts/test-webhook-autofix.d.ts +3 -0
- package/dist/scripts/test-webhook-autofix.d.ts.map +1 -0
- package/dist/scripts/test-webhook-autofix.js +117 -0
- package/dist/scripts/test-webhook-autofix.js.map +1 -0
- package/dist/services/confidence-scorer.d.ts +24 -0
- package/dist/services/confidence-scorer.d.ts.map +1 -0
- package/dist/services/confidence-scorer.js +139 -0
- package/dist/services/confidence-scorer.js.map +1 -0
- package/dist/services/expression-format-validator.d.ts +33 -0
- package/dist/services/expression-format-validator.d.ts.map +1 -0
- package/dist/services/expression-format-validator.js +209 -0
- package/dist/services/expression-format-validator.js.map +1 -0
- package/dist/services/node-similarity-service.d.ts +51 -0
- package/dist/services/node-similarity-service.d.ts.map +1 -0
- package/dist/services/node-similarity-service.js +335 -0
- package/dist/services/node-similarity-service.js.map +1 -0
- package/dist/services/universal-expression-validator.d.ts +20 -0
- package/dist/services/universal-expression-validator.d.ts.map +1 -0
- package/dist/services/universal-expression-validator.js +192 -0
- package/dist/services/universal-expression-validator.js.map +1 -0
- package/dist/services/workflow-auto-fixer.d.ts +65 -0
- package/dist/services/workflow-auto-fixer.d.ts.map +1 -0
- package/dist/services/workflow-auto-fixer.js +394 -0
- package/dist/services/workflow-auto-fixer.js.map +1 -0
- package/dist/services/workflow-ownership.d.ts +35 -0
- package/dist/services/workflow-ownership.d.ts.map +1 -0
- package/dist/services/workflow-ownership.js +195 -0
- package/dist/services/workflow-ownership.js.map +1 -0
- package/dist/services/workflow-validator.d.ts +2 -1
- package/dist/services/workflow-validator.d.ts.map +1 -1
- package/dist/services/workflow-validator.js +131 -90
- package/dist/services/workflow-validator.js.map +1 -1
- package/dist/types/instance-context.d.ts +15 -0
- package/dist/types/instance-context.d.ts.map +1 -0
- package/dist/types/instance-context.js +127 -0
- package/dist/types/instance-context.js.map +1 -0
- package/dist/types/n8n-api.d.ts +6 -0
- package/dist/types/n8n-api.d.ts.map +1 -1
- package/dist/types/n8n-api.js.map +1 -1
- package/dist/utils/cache-utils.d.ts +58 -0
- package/dist/utils/cache-utils.d.ts.map +1 -0
- package/dist/utils/cache-utils.js +243 -0
- package/dist/utils/cache-utils.js.map +1 -0
- package/dist/utils/node-type-utils.d.ts +9 -0
- package/dist/utils/node-type-utils.d.ts.map +1 -0
- package/dist/utils/node-type-utils.js +78 -0
- package/dist/utils/node-type-utils.js.map +1 -0
- package/dist/utils/template-sanitizer.d.ts.map +1 -1
- package/dist/utils/template-sanitizer.js +6 -3
- package/dist/utils/template-sanitizer.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"universal-expression-validator.d.ts","sourceRoot":"","sources":["../../src/services/universal-expression-validator.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,GAAG,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,4BAA4B;IACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;IAChE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAO;IAMhD,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAG,GAAG,yBAAyB;IA4DtE,OAAO,CAAC,MAAM,CAAC,eAAe;IAe9B,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,yBAAyB;IA8DzE,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,yBAAyB;IAwDvE,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,yBAAyB,EAAE;IAyCxD,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAWhD"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UniversalExpressionValidator = void 0;
|
|
4
|
+
class UniversalExpressionValidator {
|
|
5
|
+
static validateExpressionPrefix(value) {
|
|
6
|
+
if (typeof value !== 'string') {
|
|
7
|
+
return {
|
|
8
|
+
isValid: true,
|
|
9
|
+
hasExpression: false,
|
|
10
|
+
needsPrefix: false,
|
|
11
|
+
isMixedContent: false,
|
|
12
|
+
confidence: 1.0,
|
|
13
|
+
explanation: 'Not a string value'
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const hasExpression = this.EXPRESSION_PATTERN.test(value);
|
|
17
|
+
if (!hasExpression) {
|
|
18
|
+
return {
|
|
19
|
+
isValid: true,
|
|
20
|
+
hasExpression: false,
|
|
21
|
+
needsPrefix: false,
|
|
22
|
+
isMixedContent: false,
|
|
23
|
+
confidence: 1.0,
|
|
24
|
+
explanation: 'No n8n expression found'
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const hasPrefix = value.startsWith(this.EXPRESSION_PREFIX);
|
|
28
|
+
const isMixedContent = this.hasMixedContent(value);
|
|
29
|
+
if (!hasPrefix) {
|
|
30
|
+
return {
|
|
31
|
+
isValid: false,
|
|
32
|
+
hasExpression: true,
|
|
33
|
+
needsPrefix: true,
|
|
34
|
+
isMixedContent,
|
|
35
|
+
confidence: 1.0,
|
|
36
|
+
suggestion: `${this.EXPRESSION_PREFIX}${value}`,
|
|
37
|
+
explanation: isMixedContent
|
|
38
|
+
? 'Mixed literal text and expression requires = prefix for expression evaluation'
|
|
39
|
+
: 'Expression requires = prefix to be evaluated'
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
isValid: true,
|
|
44
|
+
hasExpression: true,
|
|
45
|
+
needsPrefix: false,
|
|
46
|
+
isMixedContent,
|
|
47
|
+
confidence: 1.0,
|
|
48
|
+
explanation: 'Expression is properly formatted with = prefix'
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
static hasMixedContent(value) {
|
|
52
|
+
const content = value.startsWith(this.EXPRESSION_PREFIX)
|
|
53
|
+
? value.substring(1)
|
|
54
|
+
: value;
|
|
55
|
+
const withoutExpressions = content.replace(/\{\{[\s\S]+?\}\}/g, '');
|
|
56
|
+
return withoutExpressions.trim().length > 0;
|
|
57
|
+
}
|
|
58
|
+
static validateExpressionSyntax(value) {
|
|
59
|
+
const hasAnyBrackets = value.includes('{{') || value.includes('}}');
|
|
60
|
+
if (!hasAnyBrackets) {
|
|
61
|
+
return {
|
|
62
|
+
isValid: true,
|
|
63
|
+
hasExpression: false,
|
|
64
|
+
needsPrefix: false,
|
|
65
|
+
isMixedContent: false,
|
|
66
|
+
confidence: 1.0,
|
|
67
|
+
explanation: 'No expression to validate'
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const openCount = (value.match(/\{\{/g) || []).length;
|
|
71
|
+
const closeCount = (value.match(/\}\}/g) || []).length;
|
|
72
|
+
if (openCount !== closeCount) {
|
|
73
|
+
return {
|
|
74
|
+
isValid: false,
|
|
75
|
+
hasExpression: true,
|
|
76
|
+
needsPrefix: false,
|
|
77
|
+
isMixedContent: false,
|
|
78
|
+
confidence: 1.0,
|
|
79
|
+
explanation: `Unmatched expression brackets: ${openCount} opening, ${closeCount} closing`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const expressions = value.match(/\{\{[\s\S]+?\}\}/g) || [];
|
|
83
|
+
for (const expr of expressions) {
|
|
84
|
+
const content = expr.slice(2, -2).trim();
|
|
85
|
+
if (!content) {
|
|
86
|
+
return {
|
|
87
|
+
isValid: false,
|
|
88
|
+
hasExpression: true,
|
|
89
|
+
needsPrefix: false,
|
|
90
|
+
isMixedContent: false,
|
|
91
|
+
confidence: 1.0,
|
|
92
|
+
explanation: 'Empty expression {{ }} is not valid'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
isValid: true,
|
|
98
|
+
hasExpression: expressions.length > 0,
|
|
99
|
+
needsPrefix: false,
|
|
100
|
+
isMixedContent: this.hasMixedContent(value),
|
|
101
|
+
confidence: 1.0,
|
|
102
|
+
explanation: 'Expression syntax is valid'
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
static validateCommonPatterns(value) {
|
|
106
|
+
if (!this.EXPRESSION_PATTERN.test(value)) {
|
|
107
|
+
return {
|
|
108
|
+
isValid: true,
|
|
109
|
+
hasExpression: false,
|
|
110
|
+
needsPrefix: false,
|
|
111
|
+
isMixedContent: false,
|
|
112
|
+
confidence: 1.0,
|
|
113
|
+
explanation: 'No expression to validate'
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const expressions = value.match(/\{\{[\s\S]+?\}\}/g) || [];
|
|
117
|
+
const warnings = [];
|
|
118
|
+
for (const expr of expressions) {
|
|
119
|
+
const content = expr.slice(2, -2).trim();
|
|
120
|
+
if (content.includes('${') && content.includes('}')) {
|
|
121
|
+
warnings.push(`Template literal syntax \${} found - use n8n syntax instead: ${expr}`);
|
|
122
|
+
}
|
|
123
|
+
if (content.startsWith('=')) {
|
|
124
|
+
warnings.push(`Double prefix detected in expression: ${expr}`);
|
|
125
|
+
}
|
|
126
|
+
if (content.includes('{{') || content.includes('}}')) {
|
|
127
|
+
warnings.push(`Nested brackets detected: ${expr}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (warnings.length > 0) {
|
|
131
|
+
return {
|
|
132
|
+
isValid: false,
|
|
133
|
+
hasExpression: true,
|
|
134
|
+
needsPrefix: false,
|
|
135
|
+
isMixedContent: false,
|
|
136
|
+
confidence: 1.0,
|
|
137
|
+
explanation: warnings.join('; ')
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
isValid: true,
|
|
142
|
+
hasExpression: true,
|
|
143
|
+
needsPrefix: false,
|
|
144
|
+
isMixedContent: this.hasMixedContent(value),
|
|
145
|
+
confidence: 1.0,
|
|
146
|
+
explanation: 'Expression patterns are valid'
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
static validate(value) {
|
|
150
|
+
const results = [];
|
|
151
|
+
const prefixResult = this.validateExpressionPrefix(value);
|
|
152
|
+
if (!prefixResult.isValid) {
|
|
153
|
+
results.push(prefixResult);
|
|
154
|
+
}
|
|
155
|
+
if (typeof value === 'string') {
|
|
156
|
+
const syntaxResult = this.validateExpressionSyntax(value);
|
|
157
|
+
if (!syntaxResult.isValid) {
|
|
158
|
+
results.push(syntaxResult);
|
|
159
|
+
}
|
|
160
|
+
const patternResult = this.validateCommonPatterns(value);
|
|
161
|
+
if (!patternResult.isValid) {
|
|
162
|
+
results.push(patternResult);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (results.length === 0) {
|
|
166
|
+
results.push({
|
|
167
|
+
isValid: true,
|
|
168
|
+
hasExpression: prefixResult.hasExpression,
|
|
169
|
+
needsPrefix: false,
|
|
170
|
+
isMixedContent: prefixResult.isMixedContent,
|
|
171
|
+
confidence: 1.0,
|
|
172
|
+
explanation: prefixResult.hasExpression
|
|
173
|
+
? 'Expression is valid'
|
|
174
|
+
: 'No expression found'
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return results;
|
|
178
|
+
}
|
|
179
|
+
static getCorrectedValue(value) {
|
|
180
|
+
if (!this.EXPRESSION_PATTERN.test(value)) {
|
|
181
|
+
return value;
|
|
182
|
+
}
|
|
183
|
+
if (!value.startsWith(this.EXPRESSION_PREFIX)) {
|
|
184
|
+
return `${this.EXPRESSION_PREFIX}${value}`;
|
|
185
|
+
}
|
|
186
|
+
return value;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
exports.UniversalExpressionValidator = UniversalExpressionValidator;
|
|
190
|
+
UniversalExpressionValidator.EXPRESSION_PATTERN = /\{\{[\s\S]+?\}\}/;
|
|
191
|
+
UniversalExpressionValidator.EXPRESSION_PREFIX = '=';
|
|
192
|
+
//# sourceMappingURL=universal-expression-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"universal-expression-validator.js","sourceRoot":"","sources":["../../src/services/universal-expression-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { WorkflowValidationResult } from './workflow-validator';
|
|
2
|
+
import { ExpressionFormatIssue } from './expression-format-validator';
|
|
3
|
+
import { NodeRepository } from '../database/node-repository';
|
|
4
|
+
import { WorkflowDiffOperation } from '../types/workflow-diff';
|
|
5
|
+
import { Workflow } from '../types/n8n-api';
|
|
6
|
+
export type FixConfidenceLevel = 'high' | 'medium' | 'low';
|
|
7
|
+
export type FixType = 'expression-format' | 'typeversion-correction' | 'error-output-config' | 'node-type-correction' | 'webhook-missing-path';
|
|
8
|
+
export interface AutoFixConfig {
|
|
9
|
+
applyFixes: boolean;
|
|
10
|
+
fixTypes?: FixType[];
|
|
11
|
+
confidenceThreshold?: FixConfidenceLevel;
|
|
12
|
+
maxFixes?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface FixOperation {
|
|
15
|
+
node: string;
|
|
16
|
+
field: string;
|
|
17
|
+
type: FixType;
|
|
18
|
+
before: any;
|
|
19
|
+
after: any;
|
|
20
|
+
confidence: FixConfidenceLevel;
|
|
21
|
+
description: string;
|
|
22
|
+
}
|
|
23
|
+
export interface AutoFixResult {
|
|
24
|
+
operations: WorkflowDiffOperation[];
|
|
25
|
+
fixes: FixOperation[];
|
|
26
|
+
summary: string;
|
|
27
|
+
stats: {
|
|
28
|
+
total: number;
|
|
29
|
+
byType: Record<FixType, number>;
|
|
30
|
+
byConfidence: Record<FixConfidenceLevel, number>;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface NodeFormatIssue extends ExpressionFormatIssue {
|
|
34
|
+
nodeName: string;
|
|
35
|
+
nodeId: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function isNodeFormatIssue(issue: ExpressionFormatIssue): issue is NodeFormatIssue;
|
|
38
|
+
export interface NodeTypeError {
|
|
39
|
+
type: 'error';
|
|
40
|
+
nodeId?: string;
|
|
41
|
+
nodeName?: string;
|
|
42
|
+
message: string;
|
|
43
|
+
suggestions?: Array<{
|
|
44
|
+
nodeType: string;
|
|
45
|
+
confidence: number;
|
|
46
|
+
reason: string;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
export declare class WorkflowAutoFixer {
|
|
50
|
+
private readonly defaultConfig;
|
|
51
|
+
private similarityService;
|
|
52
|
+
constructor(repository?: NodeRepository);
|
|
53
|
+
generateFixes(workflow: Workflow, validationResult: WorkflowValidationResult, formatIssues?: ExpressionFormatIssue[], config?: Partial<AutoFixConfig>): AutoFixResult;
|
|
54
|
+
private processExpressionFormatFixes;
|
|
55
|
+
private processTypeVersionFixes;
|
|
56
|
+
private processErrorOutputFixes;
|
|
57
|
+
private processNodeTypeFixes;
|
|
58
|
+
private processWebhookPathFixes;
|
|
59
|
+
private setNestedValue;
|
|
60
|
+
private filterByConfidence;
|
|
61
|
+
private filterOperationsByFixes;
|
|
62
|
+
private calculateStats;
|
|
63
|
+
private generateSummary;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=workflow-auto-fixer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-auto-fixer.d.ts","sourceRoot":"","sources":["../../src/services/workflow-auto-fixer.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EACL,qBAAqB,EAEtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAgB,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAK1D,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAC3D,MAAM,MAAM,OAAO,GACf,mBAAmB,GACnB,wBAAwB,GACxB,qBAAqB,GACrB,sBAAsB,GACtB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,mBAAmB,CAAC,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,GAAG,CAAC;IACZ,KAAK,EAAE,GAAG,CAAC;IACX,UAAU,EAAE,kBAAkB,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,qBAAqB,EAAE,CAAC;IACpC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAChC,YAAY,EAAE,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;KAClD,CAAC;CACH;AAED,MAAM,WAAW,eAAgB,SAAQ,qBAAqB;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAKD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,GAAG,KAAK,IAAI,eAAe,CAIxF;AAKD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAI5B;IACF,OAAO,CAAC,iBAAiB,CAAsC;gBAEnD,UAAU,CAAC,EAAE,cAAc;IASvC,aAAa,CACX,QAAQ,EAAE,QAAQ,EAClB,gBAAgB,EAAE,wBAAwB,EAC1C,YAAY,GAAE,qBAAqB,EAAO,EAC1C,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM,GAClC,aAAa;IA4DhB,OAAO,CAAC,4BAA4B;IAqEpC,OAAO,CAAC,uBAAuB;IA8C/B,OAAO,CAAC,uBAAuB;IA0C/B,OAAO,CAAC,oBAAoB;IAkD5B,OAAO,CAAC,uBAAuB;IA+D/B,OAAO,CAAC,cAAc;IAmGtB,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,uBAAuB;IAiB/B,OAAO,CAAC,cAAc;IA4BtB,OAAO,CAAC,eAAe;CA6BxB"}
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WorkflowAutoFixer = void 0;
|
|
7
|
+
exports.isNodeFormatIssue = isNodeFormatIssue;
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const node_similarity_service_1 = require("./node-similarity-service");
|
|
10
|
+
const logger_1 = require("../utils/logger");
|
|
11
|
+
const logger = new logger_1.Logger({ prefix: '[WorkflowAutoFixer]' });
|
|
12
|
+
function isNodeFormatIssue(issue) {
|
|
13
|
+
return 'nodeName' in issue && 'nodeId' in issue &&
|
|
14
|
+
typeof issue.nodeName === 'string' &&
|
|
15
|
+
typeof issue.nodeId === 'string';
|
|
16
|
+
}
|
|
17
|
+
class WorkflowAutoFixer {
|
|
18
|
+
constructor(repository) {
|
|
19
|
+
this.defaultConfig = {
|
|
20
|
+
applyFixes: false,
|
|
21
|
+
confidenceThreshold: 'medium',
|
|
22
|
+
maxFixes: 50
|
|
23
|
+
};
|
|
24
|
+
this.similarityService = null;
|
|
25
|
+
if (repository) {
|
|
26
|
+
this.similarityService = new node_similarity_service_1.NodeSimilarityService(repository);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
generateFixes(workflow, validationResult, formatIssues = [], config = {}) {
|
|
30
|
+
const fullConfig = { ...this.defaultConfig, ...config };
|
|
31
|
+
const operations = [];
|
|
32
|
+
const fixes = [];
|
|
33
|
+
const nodeMap = new Map();
|
|
34
|
+
workflow.nodes.forEach(node => {
|
|
35
|
+
nodeMap.set(node.name, node);
|
|
36
|
+
nodeMap.set(node.id, node);
|
|
37
|
+
});
|
|
38
|
+
if (!fullConfig.fixTypes || fullConfig.fixTypes.includes('expression-format')) {
|
|
39
|
+
this.processExpressionFormatFixes(formatIssues, nodeMap, operations, fixes);
|
|
40
|
+
}
|
|
41
|
+
if (!fullConfig.fixTypes || fullConfig.fixTypes.includes('typeversion-correction')) {
|
|
42
|
+
this.processTypeVersionFixes(validationResult, nodeMap, operations, fixes);
|
|
43
|
+
}
|
|
44
|
+
if (!fullConfig.fixTypes || fullConfig.fixTypes.includes('error-output-config')) {
|
|
45
|
+
this.processErrorOutputFixes(validationResult, nodeMap, workflow, operations, fixes);
|
|
46
|
+
}
|
|
47
|
+
if (!fullConfig.fixTypes || fullConfig.fixTypes.includes('node-type-correction')) {
|
|
48
|
+
this.processNodeTypeFixes(validationResult, nodeMap, operations, fixes);
|
|
49
|
+
}
|
|
50
|
+
if (!fullConfig.fixTypes || fullConfig.fixTypes.includes('webhook-missing-path')) {
|
|
51
|
+
this.processWebhookPathFixes(validationResult, nodeMap, operations, fixes);
|
|
52
|
+
}
|
|
53
|
+
const filteredFixes = this.filterByConfidence(fixes, fullConfig.confidenceThreshold);
|
|
54
|
+
const filteredOperations = this.filterOperationsByFixes(operations, filteredFixes, fixes);
|
|
55
|
+
const limitedFixes = filteredFixes.slice(0, fullConfig.maxFixes);
|
|
56
|
+
const limitedOperations = this.filterOperationsByFixes(filteredOperations, limitedFixes, filteredFixes);
|
|
57
|
+
const stats = this.calculateStats(limitedFixes);
|
|
58
|
+
const summary = this.generateSummary(stats);
|
|
59
|
+
return {
|
|
60
|
+
operations: limitedOperations,
|
|
61
|
+
fixes: limitedFixes,
|
|
62
|
+
summary,
|
|
63
|
+
stats
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
processExpressionFormatFixes(formatIssues, nodeMap, operations, fixes) {
|
|
67
|
+
const fixesByNode = new Map();
|
|
68
|
+
for (const issue of formatIssues) {
|
|
69
|
+
if (issue.issueType === 'missing-prefix') {
|
|
70
|
+
if (!isNodeFormatIssue(issue)) {
|
|
71
|
+
logger.warn('Expression format issue missing node information', {
|
|
72
|
+
fieldPath: issue.fieldPath,
|
|
73
|
+
issueType: issue.issueType
|
|
74
|
+
});
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const nodeName = issue.nodeName;
|
|
78
|
+
if (!fixesByNode.has(nodeName)) {
|
|
79
|
+
fixesByNode.set(nodeName, []);
|
|
80
|
+
}
|
|
81
|
+
fixesByNode.get(nodeName).push(issue);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
for (const [nodeName, nodeIssues] of fixesByNode) {
|
|
85
|
+
const node = nodeMap.get(nodeName);
|
|
86
|
+
if (!node)
|
|
87
|
+
continue;
|
|
88
|
+
const updatedParameters = JSON.parse(JSON.stringify(node.parameters || {}));
|
|
89
|
+
for (const issue of nodeIssues) {
|
|
90
|
+
const fieldPath = issue.fieldPath.split('.');
|
|
91
|
+
this.setNestedValue(updatedParameters, fieldPath, issue.correctedValue);
|
|
92
|
+
fixes.push({
|
|
93
|
+
node: nodeName,
|
|
94
|
+
field: issue.fieldPath,
|
|
95
|
+
type: 'expression-format',
|
|
96
|
+
before: issue.currentValue,
|
|
97
|
+
after: issue.correctedValue,
|
|
98
|
+
confidence: 'high',
|
|
99
|
+
description: issue.explanation
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const operation = {
|
|
103
|
+
type: 'updateNode',
|
|
104
|
+
nodeId: nodeName,
|
|
105
|
+
updates: {
|
|
106
|
+
parameters: updatedParameters
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
operations.push(operation);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
processTypeVersionFixes(validationResult, nodeMap, operations, fixes) {
|
|
113
|
+
for (const error of validationResult.errors) {
|
|
114
|
+
if (error.message.includes('typeVersion') && error.message.includes('exceeds maximum')) {
|
|
115
|
+
const versionMatch = error.message.match(/typeVersion (\d+(?:\.\d+)?) exceeds maximum supported version (\d+(?:\.\d+)?)/);
|
|
116
|
+
if (versionMatch) {
|
|
117
|
+
const currentVersion = parseFloat(versionMatch[1]);
|
|
118
|
+
const maxVersion = parseFloat(versionMatch[2]);
|
|
119
|
+
const nodeName = error.nodeName || error.nodeId;
|
|
120
|
+
if (!nodeName)
|
|
121
|
+
continue;
|
|
122
|
+
const node = nodeMap.get(nodeName);
|
|
123
|
+
if (!node)
|
|
124
|
+
continue;
|
|
125
|
+
fixes.push({
|
|
126
|
+
node: nodeName,
|
|
127
|
+
field: 'typeVersion',
|
|
128
|
+
type: 'typeversion-correction',
|
|
129
|
+
before: currentVersion,
|
|
130
|
+
after: maxVersion,
|
|
131
|
+
confidence: 'medium',
|
|
132
|
+
description: `Corrected typeVersion from ${currentVersion} to maximum supported ${maxVersion}`
|
|
133
|
+
});
|
|
134
|
+
const operation = {
|
|
135
|
+
type: 'updateNode',
|
|
136
|
+
nodeId: nodeName,
|
|
137
|
+
updates: {
|
|
138
|
+
typeVersion: maxVersion
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
operations.push(operation);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
processErrorOutputFixes(validationResult, nodeMap, workflow, operations, fixes) {
|
|
147
|
+
for (const error of validationResult.errors) {
|
|
148
|
+
if (error.message.includes('onError: \'continueErrorOutput\'') &&
|
|
149
|
+
error.message.includes('no error output connections')) {
|
|
150
|
+
const nodeName = error.nodeName || error.nodeId;
|
|
151
|
+
if (!nodeName)
|
|
152
|
+
continue;
|
|
153
|
+
const node = nodeMap.get(nodeName);
|
|
154
|
+
if (!node)
|
|
155
|
+
continue;
|
|
156
|
+
fixes.push({
|
|
157
|
+
node: nodeName,
|
|
158
|
+
field: 'onError',
|
|
159
|
+
type: 'error-output-config',
|
|
160
|
+
before: 'continueErrorOutput',
|
|
161
|
+
after: undefined,
|
|
162
|
+
confidence: 'medium',
|
|
163
|
+
description: 'Removed onError setting due to missing error output connections'
|
|
164
|
+
});
|
|
165
|
+
const operation = {
|
|
166
|
+
type: 'updateNode',
|
|
167
|
+
nodeId: nodeName,
|
|
168
|
+
updates: {
|
|
169
|
+
onError: undefined
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
operations.push(operation);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
processNodeTypeFixes(validationResult, nodeMap, operations, fixes) {
|
|
177
|
+
if (!this.similarityService) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
for (const error of validationResult.errors) {
|
|
181
|
+
const nodeError = error;
|
|
182
|
+
if (error.message?.includes('Unknown node type:') && nodeError.suggestions) {
|
|
183
|
+
const highConfidenceSuggestion = nodeError.suggestions.find(s => s.confidence >= 0.9);
|
|
184
|
+
if (highConfidenceSuggestion && nodeError.nodeId) {
|
|
185
|
+
const node = nodeMap.get(nodeError.nodeId) || nodeMap.get(nodeError.nodeName || '');
|
|
186
|
+
if (node) {
|
|
187
|
+
fixes.push({
|
|
188
|
+
node: node.name,
|
|
189
|
+
field: 'type',
|
|
190
|
+
type: 'node-type-correction',
|
|
191
|
+
before: node.type,
|
|
192
|
+
after: highConfidenceSuggestion.nodeType,
|
|
193
|
+
confidence: 'high',
|
|
194
|
+
description: `Fix node type: "${node.type}" → "${highConfidenceSuggestion.nodeType}" (${highConfidenceSuggestion.reason})`
|
|
195
|
+
});
|
|
196
|
+
const operation = {
|
|
197
|
+
type: 'updateNode',
|
|
198
|
+
nodeId: node.name,
|
|
199
|
+
updates: {
|
|
200
|
+
type: highConfidenceSuggestion.nodeType
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
operations.push(operation);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
processWebhookPathFixes(validationResult, nodeMap, operations, fixes) {
|
|
210
|
+
for (const error of validationResult.errors) {
|
|
211
|
+
if (error.message === 'Webhook path is required') {
|
|
212
|
+
const nodeName = error.nodeName || error.nodeId;
|
|
213
|
+
if (!nodeName)
|
|
214
|
+
continue;
|
|
215
|
+
const node = nodeMap.get(nodeName);
|
|
216
|
+
if (!node)
|
|
217
|
+
continue;
|
|
218
|
+
if (!node.type?.includes('webhook'))
|
|
219
|
+
continue;
|
|
220
|
+
const webhookId = crypto_1.default.randomUUID();
|
|
221
|
+
const currentTypeVersion = node.typeVersion || 1;
|
|
222
|
+
const needsVersionUpdate = currentTypeVersion < 2.1;
|
|
223
|
+
fixes.push({
|
|
224
|
+
node: nodeName,
|
|
225
|
+
field: 'path',
|
|
226
|
+
type: 'webhook-missing-path',
|
|
227
|
+
before: undefined,
|
|
228
|
+
after: webhookId,
|
|
229
|
+
confidence: 'high',
|
|
230
|
+
description: needsVersionUpdate
|
|
231
|
+
? `Generated webhook path and ID: ${webhookId} (also updating typeVersion to 2.1)`
|
|
232
|
+
: `Generated webhook path and ID: ${webhookId}`
|
|
233
|
+
});
|
|
234
|
+
const updates = {
|
|
235
|
+
'parameters.path': webhookId,
|
|
236
|
+
'webhookId': webhookId
|
|
237
|
+
};
|
|
238
|
+
if (needsVersionUpdate) {
|
|
239
|
+
updates['typeVersion'] = 2.1;
|
|
240
|
+
}
|
|
241
|
+
const operation = {
|
|
242
|
+
type: 'updateNode',
|
|
243
|
+
nodeId: nodeName,
|
|
244
|
+
updates
|
|
245
|
+
};
|
|
246
|
+
operations.push(operation);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
setNestedValue(obj, path, value) {
|
|
251
|
+
if (!obj || typeof obj !== 'object') {
|
|
252
|
+
throw new Error('Cannot set value on non-object');
|
|
253
|
+
}
|
|
254
|
+
if (path.length === 0) {
|
|
255
|
+
throw new Error('Cannot set value with empty path');
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
let current = obj;
|
|
259
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
260
|
+
const key = path[i];
|
|
261
|
+
if (key.includes('[')) {
|
|
262
|
+
const matches = key.match(/^([^[]+)\[(\d+)\]$/);
|
|
263
|
+
if (!matches) {
|
|
264
|
+
throw new Error(`Invalid array notation: ${key}`);
|
|
265
|
+
}
|
|
266
|
+
const [, arrayKey, indexStr] = matches;
|
|
267
|
+
const index = parseInt(indexStr, 10);
|
|
268
|
+
if (isNaN(index) || index < 0) {
|
|
269
|
+
throw new Error(`Invalid array index: ${indexStr}`);
|
|
270
|
+
}
|
|
271
|
+
if (!current[arrayKey]) {
|
|
272
|
+
current[arrayKey] = [];
|
|
273
|
+
}
|
|
274
|
+
if (!Array.isArray(current[arrayKey])) {
|
|
275
|
+
throw new Error(`Expected array at ${arrayKey}, got ${typeof current[arrayKey]}`);
|
|
276
|
+
}
|
|
277
|
+
while (current[arrayKey].length <= index) {
|
|
278
|
+
current[arrayKey].push({});
|
|
279
|
+
}
|
|
280
|
+
current = current[arrayKey][index];
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
if (current[key] === null || current[key] === undefined) {
|
|
284
|
+
current[key] = {};
|
|
285
|
+
}
|
|
286
|
+
if (typeof current[key] !== 'object' || Array.isArray(current[key])) {
|
|
287
|
+
throw new Error(`Cannot traverse through ${typeof current[key]} at ${key}`);
|
|
288
|
+
}
|
|
289
|
+
current = current[key];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const lastKey = path[path.length - 1];
|
|
293
|
+
if (lastKey.includes('[')) {
|
|
294
|
+
const matches = lastKey.match(/^([^[]+)\[(\d+)\]$/);
|
|
295
|
+
if (!matches) {
|
|
296
|
+
throw new Error(`Invalid array notation: ${lastKey}`);
|
|
297
|
+
}
|
|
298
|
+
const [, arrayKey, indexStr] = matches;
|
|
299
|
+
const index = parseInt(indexStr, 10);
|
|
300
|
+
if (isNaN(index) || index < 0) {
|
|
301
|
+
throw new Error(`Invalid array index: ${indexStr}`);
|
|
302
|
+
}
|
|
303
|
+
if (!current[arrayKey]) {
|
|
304
|
+
current[arrayKey] = [];
|
|
305
|
+
}
|
|
306
|
+
if (!Array.isArray(current[arrayKey])) {
|
|
307
|
+
throw new Error(`Expected array at ${arrayKey}, got ${typeof current[arrayKey]}`);
|
|
308
|
+
}
|
|
309
|
+
while (current[arrayKey].length <= index) {
|
|
310
|
+
current[arrayKey].push(null);
|
|
311
|
+
}
|
|
312
|
+
current[arrayKey][index] = value;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
current[lastKey] = value;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
logger.error('Failed to set nested value', {
|
|
320
|
+
path: path.join('.'),
|
|
321
|
+
error: error instanceof Error ? error.message : String(error)
|
|
322
|
+
});
|
|
323
|
+
throw error;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
filterByConfidence(fixes, threshold) {
|
|
327
|
+
if (!threshold)
|
|
328
|
+
return fixes;
|
|
329
|
+
const levels = ['high', 'medium', 'low'];
|
|
330
|
+
const thresholdIndex = levels.indexOf(threshold);
|
|
331
|
+
return fixes.filter(fix => {
|
|
332
|
+
const fixIndex = levels.indexOf(fix.confidence);
|
|
333
|
+
return fixIndex <= thresholdIndex;
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
filterOperationsByFixes(operations, filteredFixes, allFixes) {
|
|
337
|
+
const fixedNodes = new Set(filteredFixes.map(f => f.node));
|
|
338
|
+
return operations.filter(op => {
|
|
339
|
+
if (op.type === 'updateNode') {
|
|
340
|
+
return fixedNodes.has(op.nodeId || '');
|
|
341
|
+
}
|
|
342
|
+
return true;
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
calculateStats(fixes) {
|
|
346
|
+
const stats = {
|
|
347
|
+
total: fixes.length,
|
|
348
|
+
byType: {
|
|
349
|
+
'expression-format': 0,
|
|
350
|
+
'typeversion-correction': 0,
|
|
351
|
+
'error-output-config': 0,
|
|
352
|
+
'node-type-correction': 0,
|
|
353
|
+
'webhook-missing-path': 0
|
|
354
|
+
},
|
|
355
|
+
byConfidence: {
|
|
356
|
+
'high': 0,
|
|
357
|
+
'medium': 0,
|
|
358
|
+
'low': 0
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
for (const fix of fixes) {
|
|
362
|
+
stats.byType[fix.type]++;
|
|
363
|
+
stats.byConfidence[fix.confidence]++;
|
|
364
|
+
}
|
|
365
|
+
return stats;
|
|
366
|
+
}
|
|
367
|
+
generateSummary(stats) {
|
|
368
|
+
if (stats.total === 0) {
|
|
369
|
+
return 'No fixes available';
|
|
370
|
+
}
|
|
371
|
+
const parts = [];
|
|
372
|
+
if (stats.byType['expression-format'] > 0) {
|
|
373
|
+
parts.push(`${stats.byType['expression-format']} expression format ${stats.byType['expression-format'] === 1 ? 'error' : 'errors'}`);
|
|
374
|
+
}
|
|
375
|
+
if (stats.byType['typeversion-correction'] > 0) {
|
|
376
|
+
parts.push(`${stats.byType['typeversion-correction']} version ${stats.byType['typeversion-correction'] === 1 ? 'issue' : 'issues'}`);
|
|
377
|
+
}
|
|
378
|
+
if (stats.byType['error-output-config'] > 0) {
|
|
379
|
+
parts.push(`${stats.byType['error-output-config']} error output ${stats.byType['error-output-config'] === 1 ? 'configuration' : 'configurations'}`);
|
|
380
|
+
}
|
|
381
|
+
if (stats.byType['node-type-correction'] > 0) {
|
|
382
|
+
parts.push(`${stats.byType['node-type-correction']} node type ${stats.byType['node-type-correction'] === 1 ? 'correction' : 'corrections'}`);
|
|
383
|
+
}
|
|
384
|
+
if (stats.byType['webhook-missing-path'] > 0) {
|
|
385
|
+
parts.push(`${stats.byType['webhook-missing-path']} webhook ${stats.byType['webhook-missing-path'] === 1 ? 'path' : 'paths'}`);
|
|
386
|
+
}
|
|
387
|
+
if (parts.length === 0) {
|
|
388
|
+
return `Fixed ${stats.total} ${stats.total === 1 ? 'issue' : 'issues'}`;
|
|
389
|
+
}
|
|
390
|
+
return `Fixed ${parts.join(', ')}`;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
exports.WorkflowAutoFixer = WorkflowAutoFixer;
|
|
394
|
+
//# sourceMappingURL=workflow-auto-fixer.js.map
|