edsger 0.41.0 → 0.41.2
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/.claude/settings.local.json +23 -3
- package/.env.local +12 -0
- package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
- package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
- package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
- package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
- package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
- package/dist/commands/workflow/pipeline-runner.js +393 -0
- package/dist/commands/workflow/runner.d.ts +26 -0
- package/dist/commands/workflow/runner.js +119 -0
- package/dist/commands/workflow/workflow-runner.d.ts +26 -0
- package/dist/commands/workflow/workflow-runner.js +119 -0
- package/dist/index.js +0 -0
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
- package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
- package/dist/phases/code-implementation/analyzer.d.ts +32 -0
- package/dist/phases/code-implementation/analyzer.js +629 -0
- package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
- package/dist/phases/code-implementation/context-fetcher.js +86 -0
- package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
- package/dist/phases/code-implementation/mcp-server.js +93 -0
- package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
- package/dist/phases/code-implementation/prompts-improvement.js +108 -0
- package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
- package/dist/phases/code-implementation-verification/verifier.js +196 -0
- package/dist/phases/code-refine/analyzer.d.ts +41 -0
- package/dist/phases/code-refine/analyzer.js +561 -0
- package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
- package/dist/phases/code-refine/context-fetcher.js +423 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
- package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
- package/dist/phases/code-refine-verification/verifier.js +597 -0
- package/dist/phases/code-review/analyzer.d.ts +29 -0
- package/dist/phases/code-review/analyzer.js +363 -0
- package/dist/phases/code-review/context-fetcher.d.ts +92 -0
- package/dist/phases/code-review/context-fetcher.js +296 -0
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
- package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
- package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
- package/dist/phases/feature-analysis/analyzer.js +208 -0
- package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
- package/dist/phases/feature-analysis/context-fetcher.js +134 -0
- package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
- package/dist/phases/feature-analysis/http-fallback.js +95 -0
- package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
- package/dist/phases/feature-analysis/mcp-server.js +144 -0
- package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
- package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
- package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
- package/dist/phases/feature-analysis-verification/verifier.js +147 -0
- package/dist/phases/pr-execution/file-assigner.js +20 -12
- package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
- package/dist/phases/technical-design/analyzer-helpers.js +39 -0
- package/dist/phases/technical-design/analyzer.d.ts +21 -0
- package/dist/phases/technical-design/analyzer.js +461 -0
- package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
- package/dist/phases/technical-design/context-fetcher.js +39 -0
- package/dist/phases/technical-design/http-fallback.d.ts +17 -0
- package/dist/phases/technical-design/http-fallback.js +151 -0
- package/dist/phases/technical-design/mcp-server.d.ts +1 -0
- package/dist/phases/technical-design/mcp-server.js +157 -0
- package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
- package/dist/phases/technical-design/prompts-improvement.js +93 -0
- package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
- package/dist/phases/technical-design-verification/verifier.js +170 -0
- package/dist/services/feature-branches.d.ts +77 -0
- package/dist/services/feature-branches.js +205 -0
- package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
- package/dist/workflow-runner/config/phase-configs.js +120 -0
- package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
- package/dist/workflow-runner/core/feature-filter.js +46 -0
- package/dist/workflow-runner/core/index.d.ts +8 -0
- package/dist/workflow-runner/core/index.js +12 -0
- package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
- package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
- package/dist/workflow-runner/core/state-manager.d.ts +24 -0
- package/dist/workflow-runner/core/state-manager.js +42 -0
- package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
- package/dist/workflow-runner/core/workflow-logger.js +65 -0
- package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
- package/dist/workflow-runner/executors/phase-executor.js +248 -0
- package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
- package/dist/workflow-runner/feature-workflow-runner.js +119 -0
- package/dist/workflow-runner/index.d.ts +2 -0
- package/dist/workflow-runner/index.js +2 -0
- package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
- package/dist/workflow-runner/pipeline-runner.js +393 -0
- package/dist/workflow-runner/workflow-processor.d.ts +54 -0
- package/dist/workflow-runner/workflow-processor.js +170 -0
- package/package.json +1 -1
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
- package/dist/services/lifecycle-agent/index.d.ts +0 -24
- package/dist/services/lifecycle-agent/index.js +0 -25
- package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
- package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
- package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
- package/dist/services/lifecycle-agent/transition-rules.js +0 -184
- package/dist/services/lifecycle-agent/types.d.ts +0 -190
- package/dist/services/lifecycle-agent/types.js +0 -12
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline runner for executing development workflow phases
|
|
3
|
+
* Complete pipeline flow:
|
|
4
|
+
* feature-analysis → technical-design → code-implementation →
|
|
5
|
+
* functional-testing → pull-request → code-review → code-refine → code-refine-verification
|
|
6
|
+
* Uses functional programming principles
|
|
7
|
+
*/
|
|
8
|
+
import { updateFeatureStatusForPhase } from '../api/features/index.js';
|
|
9
|
+
import { runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeReviewPhase, } from './executors/phase-executor.js';
|
|
10
|
+
import { logPipelineStart, logPhaseResult, logPipelineComplete, shouldContinuePipeline, } from '../utils/pipeline-logger.js';
|
|
11
|
+
import { handleTestFailuresWithRetry } from '../phases/functional-testing/test-retry-handler.js';
|
|
12
|
+
import { handleCodeRefineWithRetry } from '../phases/code-refine/retry-handler.js';
|
|
13
|
+
import { handlePullRequestCreation } from '../phases/pull-request/handler.js';
|
|
14
|
+
/**
|
|
15
|
+
* Run pipeline based on execution mode
|
|
16
|
+
*/
|
|
17
|
+
export const runPipelineByMode = async (options, config, executionMode) => {
|
|
18
|
+
const { featureId, verbose } = options;
|
|
19
|
+
if (verbose) {
|
|
20
|
+
console.log(`🚀 Starting pipeline with mode: ${executionMode} for feature: ${featureId}`);
|
|
21
|
+
console.log(`📋 Execution mode details:`);
|
|
22
|
+
console.log(` - Mode value: "${executionMode}"`);
|
|
23
|
+
console.log(` - Mode type: ${typeof executionMode}`);
|
|
24
|
+
console.log(` - Mode === 'only_feature_analysis': ${executionMode === 'only_feature_analysis'}`);
|
|
25
|
+
}
|
|
26
|
+
switch (executionMode) {
|
|
27
|
+
// Complete pipeline
|
|
28
|
+
case 'full_pipeline':
|
|
29
|
+
case 'from_feature_analysis':
|
|
30
|
+
if (verbose) {
|
|
31
|
+
console.log(` ➡️ Matched: full_pipeline or from_feature_analysis - running complete pipeline`);
|
|
32
|
+
}
|
|
33
|
+
return await runFromFeatureAnalysis(options, config);
|
|
34
|
+
// Feature Analysis
|
|
35
|
+
case 'only_feature_analysis':
|
|
36
|
+
if (verbose) {
|
|
37
|
+
console.log(` ➡️ Matched: only_feature_analysis - running analysis only`);
|
|
38
|
+
}
|
|
39
|
+
return await runOnlyFeatureAnalysis(options, config);
|
|
40
|
+
// Technical Design
|
|
41
|
+
case 'only_technical_design':
|
|
42
|
+
return await runOnlyTechnicalDesign(options, config);
|
|
43
|
+
case 'from_technical_design':
|
|
44
|
+
return await runFromTechnicalDesign(options, config);
|
|
45
|
+
// Code Implementation
|
|
46
|
+
case 'only_code_implementation':
|
|
47
|
+
return await runOnlyCodeImplementation(options, config);
|
|
48
|
+
case 'from_code_implementation':
|
|
49
|
+
return await runFromCodeImplementation(options, config);
|
|
50
|
+
// Functional Testing
|
|
51
|
+
case 'only_functional_testing':
|
|
52
|
+
return await runOnlyFunctionalTesting(options, config);
|
|
53
|
+
case 'from_functional_testing':
|
|
54
|
+
return await runFromFunctionalTesting(options, config);
|
|
55
|
+
// Code Refine
|
|
56
|
+
case 'only_code_refine':
|
|
57
|
+
return await runOnlyCodeRefine(options, config);
|
|
58
|
+
// Code Review
|
|
59
|
+
case 'only_code_review':
|
|
60
|
+
return await runOnlyCodeReview(options, config);
|
|
61
|
+
case 'from_code_review':
|
|
62
|
+
return await runFromCodeReview(options, config);
|
|
63
|
+
default:
|
|
64
|
+
throw new Error(`Unsupported execution mode: ${executionMode}`);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Run complete pipeline for a feature using functional composition (legacy)
|
|
69
|
+
*/
|
|
70
|
+
export const runCompletePipeline = (options, config) => {
|
|
71
|
+
return async () => {
|
|
72
|
+
return await runFromFeatureAnalysis(options, config);
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
// Helper functions for different execution patterns
|
|
76
|
+
/**
|
|
77
|
+
* Run only feature analysis phase
|
|
78
|
+
*/
|
|
79
|
+
const runOnlyFeatureAnalysis = async (options, config) => {
|
|
80
|
+
const { featureId, verbose } = options;
|
|
81
|
+
logPipelineStart(featureId, verbose);
|
|
82
|
+
const results = [];
|
|
83
|
+
const analysisResult = await runFeatureAnalysisPhase(options, config);
|
|
84
|
+
results.push(logPhaseResult(analysisResult, verbose));
|
|
85
|
+
return logPipelineComplete(results, verbose);
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Run only technical design phase
|
|
89
|
+
*/
|
|
90
|
+
const runOnlyTechnicalDesign = async (options, config) => {
|
|
91
|
+
const { featureId, verbose } = options;
|
|
92
|
+
logPipelineStart(featureId, verbose);
|
|
93
|
+
const results = [];
|
|
94
|
+
const designResult = await runTechnicalDesignPhase(options, config);
|
|
95
|
+
results.push(logPhaseResult(designResult, verbose));
|
|
96
|
+
return logPipelineComplete(results, verbose);
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Run only code implementation phase
|
|
100
|
+
*/
|
|
101
|
+
const runOnlyCodeImplementation = async (options, config) => {
|
|
102
|
+
const { featureId, verbose } = options;
|
|
103
|
+
logPipelineStart(featureId, verbose);
|
|
104
|
+
const results = [];
|
|
105
|
+
const implementationResult = await runCodeImplementationPhase(options, config);
|
|
106
|
+
results.push(logPhaseResult(implementationResult, verbose));
|
|
107
|
+
return logPipelineComplete(results, verbose);
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Run only functional testing phase
|
|
111
|
+
*/
|
|
112
|
+
const runOnlyFunctionalTesting = async (options, config) => {
|
|
113
|
+
const { featureId, verbose } = options;
|
|
114
|
+
logPipelineStart(featureId, verbose);
|
|
115
|
+
const results = [];
|
|
116
|
+
const testingResult = await runFunctionalTestingPhase(options, config);
|
|
117
|
+
results.push(logPhaseResult(testingResult, verbose));
|
|
118
|
+
return logPipelineComplete(results, verbose);
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Run from feature analysis to end
|
|
122
|
+
*/
|
|
123
|
+
const runFromFeatureAnalysis = async (options, config) => {
|
|
124
|
+
const { featureId, mcpServerUrl, mcpToken, verbose } = options;
|
|
125
|
+
logPipelineStart(featureId, verbose);
|
|
126
|
+
const results = [];
|
|
127
|
+
// 1. Feature Analysis
|
|
128
|
+
const analysisResult = await runFeatureAnalysisPhase(options, config);
|
|
129
|
+
results.push(logPhaseResult(analysisResult, verbose));
|
|
130
|
+
if (!shouldContinuePipeline(results)) {
|
|
131
|
+
return logPipelineComplete(results, verbose);
|
|
132
|
+
}
|
|
133
|
+
// 2. Technical Design
|
|
134
|
+
const designResult = await runTechnicalDesignPhase(options, config);
|
|
135
|
+
results.push(logPhaseResult(designResult, verbose));
|
|
136
|
+
if (!shouldContinuePipeline(results)) {
|
|
137
|
+
return logPipelineComplete(results, verbose);
|
|
138
|
+
}
|
|
139
|
+
// 3. Code Implementation
|
|
140
|
+
const implementationResult = await runCodeImplementationPhase(options, config);
|
|
141
|
+
results.push(logPhaseResult(implementationResult, verbose));
|
|
142
|
+
if (!shouldContinuePipeline(results)) {
|
|
143
|
+
return logPipelineComplete(results, verbose);
|
|
144
|
+
}
|
|
145
|
+
// 4. Functional Testing with retry loop for bug fixes
|
|
146
|
+
const testingResult = await handleTestFailuresWithRetry({
|
|
147
|
+
options,
|
|
148
|
+
config,
|
|
149
|
+
results,
|
|
150
|
+
verbose,
|
|
151
|
+
});
|
|
152
|
+
// Update final status based on functional testing result
|
|
153
|
+
const finalStatus = testingResult.status === 'success' ? 'testing_passed' : 'testing_failed';
|
|
154
|
+
await updateFeatureStatusForPhase({ mcpServerUrl, mcpToken }, featureId, finalStatus === 'testing_passed' ? 'testing-passed' : 'testing-failed', verbose);
|
|
155
|
+
// Create pull request if tests passed
|
|
156
|
+
if (testingResult.status === 'success') {
|
|
157
|
+
const prCreated = await handlePullRequestCreation({
|
|
158
|
+
featureId,
|
|
159
|
+
mcpServerUrl,
|
|
160
|
+
mcpToken,
|
|
161
|
+
results,
|
|
162
|
+
testingResult,
|
|
163
|
+
verbose,
|
|
164
|
+
});
|
|
165
|
+
// Continue with code review and refine workflow only if PR was created
|
|
166
|
+
if (prCreated) {
|
|
167
|
+
await continueWithCodeReviewAndRefine(options, config, results, verbose);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
if (verbose) {
|
|
171
|
+
console.log('⚠️ Skipping code review and refine workflow: pull request creation failed');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return logPipelineComplete(results, verbose);
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Run from technical design to end
|
|
179
|
+
*/
|
|
180
|
+
const runFromTechnicalDesign = async (options, config) => {
|
|
181
|
+
const { featureId, mcpServerUrl, mcpToken, verbose } = options;
|
|
182
|
+
logPipelineStart(featureId, verbose);
|
|
183
|
+
const results = [];
|
|
184
|
+
// 1. Technical Design
|
|
185
|
+
const designResult = await runTechnicalDesignPhase(options, config);
|
|
186
|
+
results.push(logPhaseResult(designResult, verbose));
|
|
187
|
+
if (!shouldContinuePipeline(results)) {
|
|
188
|
+
return logPipelineComplete(results, verbose);
|
|
189
|
+
}
|
|
190
|
+
// 2. Code Implementation
|
|
191
|
+
const implementationResult = await runCodeImplementationPhase(options, config);
|
|
192
|
+
results.push(logPhaseResult(implementationResult, verbose));
|
|
193
|
+
if (!shouldContinuePipeline(results)) {
|
|
194
|
+
return logPipelineComplete(results, verbose);
|
|
195
|
+
}
|
|
196
|
+
// 3. Functional Testing with retry loop for bug fixes
|
|
197
|
+
const testingResult = await handleTestFailuresWithRetry({
|
|
198
|
+
options,
|
|
199
|
+
config,
|
|
200
|
+
results,
|
|
201
|
+
verbose,
|
|
202
|
+
});
|
|
203
|
+
// Update final status based on functional testing result
|
|
204
|
+
const finalStatus = testingResult.status === 'success' ? 'testing_passed' : 'testing_failed';
|
|
205
|
+
await updateFeatureStatusForPhase({ mcpServerUrl, mcpToken }, featureId, finalStatus === 'testing_passed' ? 'testing-passed' : 'testing-failed', verbose);
|
|
206
|
+
// Create pull request if tests passed
|
|
207
|
+
if (testingResult.status === 'success') {
|
|
208
|
+
const prCreated = await handlePullRequestCreation({
|
|
209
|
+
featureId,
|
|
210
|
+
mcpServerUrl,
|
|
211
|
+
mcpToken,
|
|
212
|
+
results,
|
|
213
|
+
testingResult,
|
|
214
|
+
verbose,
|
|
215
|
+
});
|
|
216
|
+
// Continue with code review and refine workflow only if PR was created
|
|
217
|
+
if (prCreated) {
|
|
218
|
+
await continueWithCodeReviewAndRefine(options, config, results, verbose);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
if (verbose) {
|
|
222
|
+
console.log('⚠️ Skipping code review and refine workflow: pull request creation failed');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return logPipelineComplete(results, verbose);
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Run from code implementation to end
|
|
230
|
+
*/
|
|
231
|
+
const runFromCodeImplementation = async (options, config) => {
|
|
232
|
+
const { featureId, mcpServerUrl, mcpToken, verbose } = options;
|
|
233
|
+
logPipelineStart(featureId, verbose);
|
|
234
|
+
const results = [];
|
|
235
|
+
// 1. Code Implementation
|
|
236
|
+
const implementationResult = await runCodeImplementationPhase(options, config);
|
|
237
|
+
results.push(logPhaseResult(implementationResult, verbose));
|
|
238
|
+
if (!shouldContinuePipeline(results)) {
|
|
239
|
+
return logPipelineComplete(results, verbose);
|
|
240
|
+
}
|
|
241
|
+
// 2. Functional Testing with retry loop for bug fixes
|
|
242
|
+
const testingResult = await handleTestFailuresWithRetry({
|
|
243
|
+
options,
|
|
244
|
+
config,
|
|
245
|
+
results,
|
|
246
|
+
verbose,
|
|
247
|
+
});
|
|
248
|
+
// Update final status based on functional testing result
|
|
249
|
+
const finalStatus = testingResult.status === 'success' ? 'testing_passed' : 'testing_failed';
|
|
250
|
+
await updateFeatureStatusForPhase({ mcpServerUrl, mcpToken }, featureId, finalStatus === 'testing_passed' ? 'testing-passed' : 'testing-failed', verbose);
|
|
251
|
+
// Create pull request if tests passed
|
|
252
|
+
if (testingResult.status === 'success') {
|
|
253
|
+
const prCreated = await handlePullRequestCreation({
|
|
254
|
+
featureId,
|
|
255
|
+
mcpServerUrl,
|
|
256
|
+
mcpToken,
|
|
257
|
+
results,
|
|
258
|
+
testingResult,
|
|
259
|
+
verbose,
|
|
260
|
+
});
|
|
261
|
+
// Continue with code review and refine workflow only if PR was created
|
|
262
|
+
if (prCreated) {
|
|
263
|
+
await continueWithCodeReviewAndRefine(options, config, results, verbose);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
if (verbose) {
|
|
267
|
+
console.log('⚠️ Skipping code review and refine workflow: pull request creation failed');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return logPipelineComplete(results, verbose);
|
|
272
|
+
};
|
|
273
|
+
/**
|
|
274
|
+
* Run from functional testing to end
|
|
275
|
+
*/
|
|
276
|
+
const runFromFunctionalTesting = async (options, config) => {
|
|
277
|
+
const { featureId, mcpServerUrl, mcpToken, verbose } = options;
|
|
278
|
+
logPipelineStart(featureId, verbose);
|
|
279
|
+
const results = [];
|
|
280
|
+
// 1. Functional Testing with retry loop for bug fixes
|
|
281
|
+
const testingResult = await handleTestFailuresWithRetry({
|
|
282
|
+
options,
|
|
283
|
+
config,
|
|
284
|
+
results,
|
|
285
|
+
verbose,
|
|
286
|
+
});
|
|
287
|
+
// Update final status based on functional testing result
|
|
288
|
+
const finalStatus = testingResult.status === 'success' ? 'testing_passed' : 'testing_failed';
|
|
289
|
+
await updateFeatureStatusForPhase({ mcpServerUrl, mcpToken }, featureId, finalStatus === 'testing_passed' ? 'testing-passed' : 'testing-failed', verbose);
|
|
290
|
+
// Create pull request if tests passed
|
|
291
|
+
if (testingResult.status === 'success') {
|
|
292
|
+
const prCreated = await handlePullRequestCreation({
|
|
293
|
+
featureId,
|
|
294
|
+
mcpServerUrl,
|
|
295
|
+
mcpToken,
|
|
296
|
+
results,
|
|
297
|
+
testingResult,
|
|
298
|
+
verbose,
|
|
299
|
+
});
|
|
300
|
+
// Continue with code review and refine workflow only if PR was created
|
|
301
|
+
if (prCreated) {
|
|
302
|
+
await continueWithCodeReviewAndRefine(options, config, results, verbose);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
if (verbose) {
|
|
306
|
+
console.log('⚠️ Skipping code review and refine workflow: pull request creation failed');
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return logPipelineComplete(results, verbose);
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* Run only code refine phase (refine code based on PR feedback)
|
|
314
|
+
* Includes automatic retry loop for verification failures
|
|
315
|
+
*/
|
|
316
|
+
const runOnlyCodeRefine = async (options, config) => {
|
|
317
|
+
const { featureId, verbose } = options;
|
|
318
|
+
logPipelineStart(featureId, verbose);
|
|
319
|
+
const results = [];
|
|
320
|
+
// Code Refine with automatic retry for verification failures
|
|
321
|
+
await handleCodeRefineWithRetry({
|
|
322
|
+
options,
|
|
323
|
+
config,
|
|
324
|
+
results,
|
|
325
|
+
verbose,
|
|
326
|
+
});
|
|
327
|
+
return logPipelineComplete(results, verbose);
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* Run only code review phase (review PR and create review comments)
|
|
331
|
+
*/
|
|
332
|
+
const runOnlyCodeReview = async (options, config) => {
|
|
333
|
+
const { featureId, verbose } = options;
|
|
334
|
+
logPipelineStart(featureId, verbose);
|
|
335
|
+
const results = [];
|
|
336
|
+
// Code Review - analyze PR and create review comments
|
|
337
|
+
const reviewResult = await runCodeReviewPhase(options, config);
|
|
338
|
+
results.push(logPhaseResult(reviewResult, verbose));
|
|
339
|
+
return logPipelineComplete(results, verbose);
|
|
340
|
+
};
|
|
341
|
+
/**
|
|
342
|
+
* Run from code review to end (code-review → code-refine → code-refine-verification)
|
|
343
|
+
*/
|
|
344
|
+
const runFromCodeReview = async (options, config) => {
|
|
345
|
+
const { featureId, verbose } = options;
|
|
346
|
+
logPipelineStart(featureId, verbose);
|
|
347
|
+
const results = [];
|
|
348
|
+
// 1. Code Review - analyze PR and create review comments
|
|
349
|
+
const reviewResult = await runCodeReviewPhase(options, config);
|
|
350
|
+
results.push(logPhaseResult(reviewResult, verbose));
|
|
351
|
+
if (!shouldContinuePipeline(results)) {
|
|
352
|
+
return logPipelineComplete(results, verbose);
|
|
353
|
+
}
|
|
354
|
+
// 2. Code Refine with automatic retry for verification failures
|
|
355
|
+
await handleCodeRefineWithRetry({
|
|
356
|
+
options,
|
|
357
|
+
config,
|
|
358
|
+
results,
|
|
359
|
+
verbose,
|
|
360
|
+
});
|
|
361
|
+
return logPipelineComplete(results, verbose);
|
|
362
|
+
};
|
|
363
|
+
/**
|
|
364
|
+
* Continue with code review and refine after PR creation
|
|
365
|
+
* This is the post-PR workflow: code-review → code-refine → code-refine-verification → code-testing
|
|
366
|
+
*/
|
|
367
|
+
const continueWithCodeReviewAndRefine = async (options, config, results, verbose) => {
|
|
368
|
+
if (verbose) {
|
|
369
|
+
console.log('\n🔄 Continuing with code review and refine workflow...');
|
|
370
|
+
}
|
|
371
|
+
// 1. Code Review - analyze PR and create review comments
|
|
372
|
+
const reviewResult = await runCodeReviewPhase(options, config);
|
|
373
|
+
results.push(logPhaseResult(reviewResult, verbose));
|
|
374
|
+
if (!shouldContinuePipeline(results)) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
// 2. Code Refine with automatic retry for verification failures
|
|
378
|
+
await handleCodeRefineWithRetry({
|
|
379
|
+
options,
|
|
380
|
+
config,
|
|
381
|
+
results,
|
|
382
|
+
verbose,
|
|
383
|
+
});
|
|
384
|
+
if (!shouldContinuePipeline(results)) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
// 3. Code Testing - write automated tests for the implemented code
|
|
388
|
+
if (verbose) {
|
|
389
|
+
console.log('\n📝 Starting code testing phase...');
|
|
390
|
+
}
|
|
391
|
+
const testingResult = await runCodeTestingPhase(options, config);
|
|
392
|
+
results.push(logPhaseResult(testingResult, verbose));
|
|
393
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main workflow processor for continuous feature development
|
|
3
|
+
* Monitors for ready_for_dev features and processes them through the complete pipeline
|
|
4
|
+
* Uses functional programming principles
|
|
5
|
+
*/
|
|
6
|
+
import { EdsgerConfig } from '../types/index.js';
|
|
7
|
+
import { type WorkflowStats } from './core/state-manager.js';
|
|
8
|
+
export interface WorkflowOptions {
|
|
9
|
+
readonly productId: string;
|
|
10
|
+
readonly mcpServerUrl: string;
|
|
11
|
+
readonly mcpToken: string;
|
|
12
|
+
readonly pollInterval?: number;
|
|
13
|
+
readonly maxRetries?: number;
|
|
14
|
+
readonly verbose?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export type { FeatureProcessingState, WorkflowStats, } from './core/state-manager.js';
|
|
17
|
+
/**
|
|
18
|
+
* Workflow processor using functional programming principles
|
|
19
|
+
*/
|
|
20
|
+
export declare class WorkflowProcessor {
|
|
21
|
+
private readonly options;
|
|
22
|
+
private readonly config;
|
|
23
|
+
private isRunning;
|
|
24
|
+
private processedFeatures;
|
|
25
|
+
private pollTimer?;
|
|
26
|
+
constructor(options: WorkflowOptions, config: EdsgerConfig);
|
|
27
|
+
/**
|
|
28
|
+
* Start the workflow processor
|
|
29
|
+
*/
|
|
30
|
+
start(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Stop the workflow processor
|
|
33
|
+
*/
|
|
34
|
+
stop(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Process the next available feature using functional composition
|
|
37
|
+
*/
|
|
38
|
+
private processNextFeature;
|
|
39
|
+
/**
|
|
40
|
+
* Process a single feature through the complete pipeline using functional composition
|
|
41
|
+
*/
|
|
42
|
+
private processFeature;
|
|
43
|
+
/**
|
|
44
|
+
* Get current processing statistics using pure function
|
|
45
|
+
*/
|
|
46
|
+
getStats(): WorkflowStats;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create and start a workflow processor using functional composition
|
|
50
|
+
*/
|
|
51
|
+
export declare const startWorkflowProcessor: (options: WorkflowOptions, config: EdsgerConfig) => () => Promise<WorkflowProcessor>;
|
|
52
|
+
export { createInitialState, updateFeatureState, createProcessingState, createCompletedState, createFailedState, calculateStats, } from './core/state-manager.js';
|
|
53
|
+
export { shouldProcessFeature, findNextFeature } from './core/feature-filter.js';
|
|
54
|
+
export { evaluatePipelineResults } from './core/pipeline-evaluator.js';
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main workflow processor for continuous feature development
|
|
3
|
+
* Monitors for ready_for_dev features and processes them through the complete pipeline
|
|
4
|
+
* Uses functional programming principles
|
|
5
|
+
*/
|
|
6
|
+
import { getReadyForDevFeatures } from '../api/features/index.js';
|
|
7
|
+
import { runFeatureWorkflow } from './feature-workflow-runner.js';
|
|
8
|
+
import { logInfo } from '../utils/logger.js';
|
|
9
|
+
// Import core modules
|
|
10
|
+
import { createInitialState, updateFeatureState, createProcessingState, createCompletedState, createFailedState, calculateStats, } from './core/state-manager.js';
|
|
11
|
+
import { findNextFeature } from './core/feature-filter.js';
|
|
12
|
+
import { evaluatePipelineResults } from './core/pipeline-evaluator.js';
|
|
13
|
+
import { logProcessingStart, logRetryInfo, logPipelineResults, logProcessorStart, logProcessorReady, logProcessorStop, logFeatureSuccess, logFeatureFailed, logFeatureError, logNoFeaturesFound, logAllFeaturesProcessed, logSkippingProcessing, logPollingError, logProcessNextFeatureError, } from './core/workflow-logger.js';
|
|
14
|
+
/**
|
|
15
|
+
* Workflow processor using functional programming principles
|
|
16
|
+
*/
|
|
17
|
+
export class WorkflowProcessor {
|
|
18
|
+
options;
|
|
19
|
+
config;
|
|
20
|
+
isRunning = false;
|
|
21
|
+
processedFeatures = createInitialState();
|
|
22
|
+
pollTimer;
|
|
23
|
+
constructor(options, config) {
|
|
24
|
+
this.options = {
|
|
25
|
+
pollInterval: 30000, // 30 seconds default
|
|
26
|
+
maxRetries: 3,
|
|
27
|
+
verbose: false, // default value
|
|
28
|
+
...options,
|
|
29
|
+
};
|
|
30
|
+
this.config = config;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Start the workflow processor
|
|
34
|
+
*/
|
|
35
|
+
async start() {
|
|
36
|
+
if (this.isRunning) {
|
|
37
|
+
logInfo('Workflow processor is already running');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
this.isRunning = true;
|
|
41
|
+
logProcessorStart(this.options.productId, this.options.pollInterval);
|
|
42
|
+
// Initial check
|
|
43
|
+
await this.processNextFeature();
|
|
44
|
+
// Set up polling for new features
|
|
45
|
+
this.pollTimer = setInterval(() => {
|
|
46
|
+
this.processNextFeature().catch((error) => {
|
|
47
|
+
logPollingError(error);
|
|
48
|
+
});
|
|
49
|
+
}, this.options.pollInterval);
|
|
50
|
+
logProcessorReady();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Stop the workflow processor
|
|
54
|
+
*/
|
|
55
|
+
stop() {
|
|
56
|
+
if (!this.isRunning) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.isRunning = false;
|
|
60
|
+
if (this.pollTimer) {
|
|
61
|
+
clearInterval(this.pollTimer);
|
|
62
|
+
this.pollTimer = undefined;
|
|
63
|
+
}
|
|
64
|
+
logProcessorStop();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Process the next available feature using functional composition
|
|
68
|
+
*/
|
|
69
|
+
async processNextFeature() {
|
|
70
|
+
try {
|
|
71
|
+
// Skip feature fetching if there are any features currently being processed
|
|
72
|
+
const stats = calculateStats(this.processedFeatures, this.isRunning);
|
|
73
|
+
if (stats.processing > 0) {
|
|
74
|
+
if (this.options.verbose) {
|
|
75
|
+
logSkippingProcessing(stats.processing);
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Fetch features using unified API
|
|
80
|
+
const features = await getReadyForDevFeatures(this.options.mcpServerUrl, this.options.mcpToken, this.options.productId, this.options.verbose);
|
|
81
|
+
if (features.length === 0) {
|
|
82
|
+
if (this.options.verbose) {
|
|
83
|
+
logNoFeaturesFound();
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Find next feature to process using pure functions
|
|
88
|
+
const nextFeature = findNextFeature(features, this.processedFeatures, this.options.maxRetries);
|
|
89
|
+
if (!nextFeature) {
|
|
90
|
+
if (this.options.verbose) {
|
|
91
|
+
logAllFeaturesProcessed();
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Process the feature
|
|
96
|
+
await this.processFeature(nextFeature);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
logProcessNextFeatureError(error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Process a single feature through the complete pipeline using functional composition
|
|
104
|
+
*/
|
|
105
|
+
async processFeature(feature) {
|
|
106
|
+
const featureId = feature.id;
|
|
107
|
+
// Check if this is a reprocess due to feature update
|
|
108
|
+
const existingState = this.processedFeatures.get(featureId);
|
|
109
|
+
if (existingState &&
|
|
110
|
+
existingState.status === 'completed' &&
|
|
111
|
+
this.options.verbose) {
|
|
112
|
+
logInfo(`🔄 Reprocessing feature "${feature.name}" - detected status change`);
|
|
113
|
+
if (feature.updated_at) {
|
|
114
|
+
logInfo(` Previous process: ${existingState.lastAttempt.toISOString()}`);
|
|
115
|
+
logInfo(` Feature updated: ${feature.updated_at}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Update state to processing using pure function
|
|
119
|
+
this.processedFeatures = updateFeatureState(this.processedFeatures, featureId, (currentState) => createProcessingState(featureId, currentState));
|
|
120
|
+
logProcessingStart(feature, this.options.verbose);
|
|
121
|
+
try {
|
|
122
|
+
// Run pipeline using feature workflow with execution mode support
|
|
123
|
+
const results = await runFeatureWorkflow({
|
|
124
|
+
featureId,
|
|
125
|
+
mcpServerUrl: this.options.mcpServerUrl,
|
|
126
|
+
mcpToken: this.options.mcpToken,
|
|
127
|
+
verbose: this.options.verbose,
|
|
128
|
+
}, this.config);
|
|
129
|
+
// Evaluate results using pure function
|
|
130
|
+
const allSuccessful = evaluatePipelineResults(results);
|
|
131
|
+
if (allSuccessful) {
|
|
132
|
+
// Mark as completed using pure function
|
|
133
|
+
this.processedFeatures = updateFeatureState(this.processedFeatures, featureId, (currentState) => createCompletedState(featureId, currentState));
|
|
134
|
+
logFeatureSuccess(feature.name);
|
|
135
|
+
logPipelineResults(results);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// Mark as failed using pure function
|
|
139
|
+
this.processedFeatures = updateFeatureState(this.processedFeatures, featureId, (currentState) => createFailedState(featureId, currentState));
|
|
140
|
+
logFeatureFailed(feature.name);
|
|
141
|
+
logPipelineResults(results);
|
|
142
|
+
const currentState = this.processedFeatures.get(featureId);
|
|
143
|
+
logRetryInfo(feature.name, currentState.retryCount, this.options.maxRetries);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
// Mark as failed using pure function
|
|
148
|
+
this.processedFeatures = updateFeatureState(this.processedFeatures, featureId, (currentState) => createFailedState(featureId, currentState));
|
|
149
|
+
logFeatureError(feature.name, error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get current processing statistics using pure function
|
|
154
|
+
*/
|
|
155
|
+
getStats() {
|
|
156
|
+
return calculateStats(this.processedFeatures, this.isRunning);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Create and start a workflow processor using functional composition
|
|
161
|
+
*/
|
|
162
|
+
export const startWorkflowProcessor = (options, config) => async () => {
|
|
163
|
+
const processor = new WorkflowProcessor(options, config);
|
|
164
|
+
await processor.start();
|
|
165
|
+
return processor;
|
|
166
|
+
};
|
|
167
|
+
// Re-export core functions for testing and external use
|
|
168
|
+
export { createInitialState, updateFeatureState, createProcessingState, createCompletedState, createFailedState, calculateStats, } from './core/state-manager.js';
|
|
169
|
+
export { shouldProcessFeature, findNextFeature } from './core/feature-filter.js';
|
|
170
|
+
export { evaluatePipelineResults } from './core/pipeline-evaluator.js';
|
package/package.json
CHANGED