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,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Branches service for pipeline integration
|
|
3
|
+
* Allows phases to manage feature branches via MCP
|
|
4
|
+
*/
|
|
5
|
+
import { callMcpEndpoint } from '../api/mcp-client.js';
|
|
6
|
+
/**
|
|
7
|
+
* List all branches for a feature
|
|
8
|
+
*/
|
|
9
|
+
export async function getFeatureBranches(options) {
|
|
10
|
+
const { featureId, verbose } = options;
|
|
11
|
+
if (verbose) {
|
|
12
|
+
console.log(`đ Fetching feature branches for feature: ${featureId}`);
|
|
13
|
+
}
|
|
14
|
+
const result = (await callMcpEndpoint('feature_branches/list', {
|
|
15
|
+
feature_id: featureId,
|
|
16
|
+
}));
|
|
17
|
+
const branches = result?.feature_branches || [];
|
|
18
|
+
if (verbose) {
|
|
19
|
+
console.log(`â
Found ${branches.length} feature branches`);
|
|
20
|
+
}
|
|
21
|
+
return branches;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the current active branch for a feature
|
|
25
|
+
*/
|
|
26
|
+
export async function getCurrentBranch(options) {
|
|
27
|
+
const { featureId, verbose } = options;
|
|
28
|
+
if (verbose) {
|
|
29
|
+
console.log(`đ Getting current branch for feature: ${featureId}`);
|
|
30
|
+
}
|
|
31
|
+
const result = (await callMcpEndpoint('feature_branches/current', {
|
|
32
|
+
feature_id: featureId,
|
|
33
|
+
}));
|
|
34
|
+
return result?.current_branch || null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create feature branches
|
|
38
|
+
*/
|
|
39
|
+
export async function createFeatureBranches(options, branches) {
|
|
40
|
+
const { featureId, verbose } = options;
|
|
41
|
+
if (verbose) {
|
|
42
|
+
console.log(`đ Creating ${branches.length} feature branches for feature: ${featureId}`);
|
|
43
|
+
}
|
|
44
|
+
const result = (await callMcpEndpoint('feature_branches/create', {
|
|
45
|
+
feature_id: featureId,
|
|
46
|
+
branches: branches,
|
|
47
|
+
}));
|
|
48
|
+
const createdBranches = result?.created_branches || [];
|
|
49
|
+
if (verbose) {
|
|
50
|
+
console.log(`â
Created ${createdBranches.length} feature branches`);
|
|
51
|
+
createdBranches.forEach((b, idx) => {
|
|
52
|
+
console.log(` ${idx + 1}. ${b.name} (status: ${b.status})`);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return createdBranches;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Update a feature branch
|
|
59
|
+
*/
|
|
60
|
+
export async function updateFeatureBranch(branchId, updates, verbose) {
|
|
61
|
+
if (verbose) {
|
|
62
|
+
console.log(`đ Updating feature branch: ${branchId}`);
|
|
63
|
+
}
|
|
64
|
+
const result = (await callMcpEndpoint('feature_branches/update', {
|
|
65
|
+
branch_id: branchId,
|
|
66
|
+
...updates,
|
|
67
|
+
}));
|
|
68
|
+
if (verbose) {
|
|
69
|
+
console.log(`â
Feature branch updated successfully`);
|
|
70
|
+
}
|
|
71
|
+
return result?.feature_branch;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Clear all branches for a feature (used before re-planning)
|
|
75
|
+
*/
|
|
76
|
+
export async function clearFeatureBranches(options, force = false) {
|
|
77
|
+
const { featureId, verbose } = options;
|
|
78
|
+
if (verbose) {
|
|
79
|
+
console.log(`đ Clearing feature branches for feature: ${featureId}`);
|
|
80
|
+
}
|
|
81
|
+
const result = (await callMcpEndpoint('feature_branches/clear', {
|
|
82
|
+
feature_id: featureId,
|
|
83
|
+
force: force,
|
|
84
|
+
}));
|
|
85
|
+
const deletedCount = result?.deleted_count || 0;
|
|
86
|
+
if (verbose) {
|
|
87
|
+
console.log(`â
Cleared ${deletedCount} feature branches`);
|
|
88
|
+
}
|
|
89
|
+
return deletedCount;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Format feature branches for context (to include in prompts)
|
|
93
|
+
*/
|
|
94
|
+
export function formatBranchesForContext(branches) {
|
|
95
|
+
if (!branches || branches.length === 0) {
|
|
96
|
+
return 'No feature branches defined yet.';
|
|
97
|
+
}
|
|
98
|
+
const branchList = branches
|
|
99
|
+
.map((b, idx) => {
|
|
100
|
+
const statusEmoji = b.status === 'merged'
|
|
101
|
+
? 'â
'
|
|
102
|
+
: b.status === 'in_progress'
|
|
103
|
+
? 'đ'
|
|
104
|
+
: b.status === 'ready_for_review'
|
|
105
|
+
? 'đ'
|
|
106
|
+
: b.status === 'closed'
|
|
107
|
+
? 'â'
|
|
108
|
+
: 'âŗ';
|
|
109
|
+
return `${idx + 1}. **${b.name}** ${statusEmoji}
|
|
110
|
+
- Status: ${b.status}
|
|
111
|
+
- Branch: ${b.branch_name || 'Not created'}
|
|
112
|
+
- PR: ${b.pull_request_url || 'Not created'}
|
|
113
|
+
- Description: ${b.description || 'No description'}`;
|
|
114
|
+
})
|
|
115
|
+
.join('\n\n');
|
|
116
|
+
return `# Feature Branches
|
|
117
|
+
|
|
118
|
+
${branchList}
|
|
119
|
+
|
|
120
|
+
Total: ${branches.length} branches
|
|
121
|
+
Merged: ${branches.filter((b) => b.status === 'merged').length}
|
|
122
|
+
In Progress: ${branches.filter((b) => b.status === 'in_progress').length}
|
|
123
|
+
Pending: ${branches.filter((b) => b.status === 'pending').length}`;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if feature has multiple branches planned
|
|
127
|
+
*/
|
|
128
|
+
export async function hasMultipleBranches(options) {
|
|
129
|
+
const branches = await getFeatureBranches(options);
|
|
130
|
+
return branches.length > 1;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get next pending branch to work on
|
|
134
|
+
*/
|
|
135
|
+
export async function getNextPendingBranch(options) {
|
|
136
|
+
const branches = await getFeatureBranches(options);
|
|
137
|
+
return branches.find((b) => b.status === 'pending') || null;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Check if all branches are completed
|
|
141
|
+
*/
|
|
142
|
+
export async function allBranchesCompleted(options) {
|
|
143
|
+
const branches = await getFeatureBranches(options);
|
|
144
|
+
if (branches.length === 0)
|
|
145
|
+
return true;
|
|
146
|
+
return branches.every((b) => b.status === 'merged' || b.status === 'closed');
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get the base branch information for a feature branch.
|
|
150
|
+
* Returns:
|
|
151
|
+
* - If base_branch_id is set and that branch is merged: use main
|
|
152
|
+
* - If base_branch_id is set and that branch is not merged: use that branch's branch_name
|
|
153
|
+
* - If base_branch_id is null: use main
|
|
154
|
+
*/
|
|
155
|
+
export async function getBaseBranchInfo(branch, allBranches, mainBranch = 'main') {
|
|
156
|
+
// No base branch - start from main
|
|
157
|
+
if (!branch.base_branch_id) {
|
|
158
|
+
return {
|
|
159
|
+
baseBranch: mainBranch,
|
|
160
|
+
needsRebase: false,
|
|
161
|
+
baseBranchMerged: true,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
// Find the base branch
|
|
165
|
+
const baseBranch = allBranches.find((b) => b.id === branch.base_branch_id);
|
|
166
|
+
if (!baseBranch) {
|
|
167
|
+
// Base branch not found - fall back to main
|
|
168
|
+
return {
|
|
169
|
+
baseBranch: mainBranch,
|
|
170
|
+
needsRebase: false,
|
|
171
|
+
baseBranchMerged: true,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
// Check if base branch is merged
|
|
175
|
+
if (baseBranch.status === 'merged') {
|
|
176
|
+
// Base branch is merged to main - we should base on main and rebase if needed
|
|
177
|
+
return { baseBranch: mainBranch, needsRebase: true, baseBranchMerged: true };
|
|
178
|
+
}
|
|
179
|
+
// Base branch is not merged - we should base on that branch
|
|
180
|
+
if (!baseBranch.branch_name) {
|
|
181
|
+
// Base branch doesn't have a git branch yet - fall back to main
|
|
182
|
+
return {
|
|
183
|
+
baseBranch: mainBranch,
|
|
184
|
+
needsRebase: false,
|
|
185
|
+
baseBranchMerged: false,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
baseBranch: baseBranch.branch_name,
|
|
190
|
+
needsRebase: false,
|
|
191
|
+
baseBranchMerged: false,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get branch by ID
|
|
196
|
+
*/
|
|
197
|
+
export async function getBranchById(branchId, verbose) {
|
|
198
|
+
if (verbose) {
|
|
199
|
+
console.log(`đ Fetching feature branch: ${branchId}`);
|
|
200
|
+
}
|
|
201
|
+
const result = (await callMcpEndpoint('feature_branches/get', {
|
|
202
|
+
branch_id: branchId,
|
|
203
|
+
}));
|
|
204
|
+
return result?.feature_branch || null;
|
|
205
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase configurations for the pipeline runner
|
|
3
|
+
*/
|
|
4
|
+
import { analyzeFeatureWithMCP, checkFeatureAnalysisRequirements, } from '../../phases/feature-analysis/analyzer.js';
|
|
5
|
+
import { generateTechnicalDesign, checkTechnicalDesignRequirements, } from '../../phases/technical-design/analyzer.js';
|
|
6
|
+
import { implementFeatureCode, checkCodeImplementationRequirements, } from '../../phases/code-implementation/analyzer.js';
|
|
7
|
+
import { runFunctionalTesting, checkFunctionalTestingRequirements, } from '../../phases/functional-testing/analyzer.js';
|
|
8
|
+
import { writeCodeTests, checkCodeTestingRequirements, } from '../../phases/code-testing/analyzer.js';
|
|
9
|
+
import { refineCodeFromPRFeedback, checkCodeRefineRequirements, } from '../../phases/code-refine/analyzer.js';
|
|
10
|
+
import { verifyAndResolveComments, checkCodeRefineVerificationRequirements, } from '../../phases/code-refine-verification/verifier.js';
|
|
11
|
+
import { reviewPullRequest, checkCodeReviewRequirements, } from '../../phases/code-review/analyzer.js';
|
|
12
|
+
/**
|
|
13
|
+
* Wrapper for code-refine phase to inject GitHub token
|
|
14
|
+
*/
|
|
15
|
+
const executeCodeRefine = async (options, config) => {
|
|
16
|
+
const githubToken = process.env.GITHUB_TOKEN || process.env.GITHUB_ACCESS_TOKEN;
|
|
17
|
+
if (!githubToken) {
|
|
18
|
+
return {
|
|
19
|
+
status: 'error',
|
|
20
|
+
message: 'GitHub token not found. Set GITHUB_TOKEN or GITHUB_ACCESS_TOKEN environment variable.',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return refineCodeFromPRFeedback({
|
|
24
|
+
featureId: options.featureId,
|
|
25
|
+
mcpServerUrl: options.mcpServerUrl,
|
|
26
|
+
mcpToken: options.mcpToken,
|
|
27
|
+
githubToken,
|
|
28
|
+
verbose: options.verbose,
|
|
29
|
+
}, config);
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Wrapper for code-refine-verification phase to inject GitHub token
|
|
33
|
+
*/
|
|
34
|
+
const executeCodeRefineVerification = async (options, config) => {
|
|
35
|
+
const githubToken = process.env.GITHUB_TOKEN || process.env.GITHUB_ACCESS_TOKEN;
|
|
36
|
+
if (!githubToken) {
|
|
37
|
+
return {
|
|
38
|
+
status: 'error',
|
|
39
|
+
message: 'GitHub token not found. Set GITHUB_TOKEN or GITHUB_ACCESS_TOKEN environment variable.',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return verifyAndResolveComments({
|
|
43
|
+
featureId: options.featureId,
|
|
44
|
+
mcpServerUrl: options.mcpServerUrl,
|
|
45
|
+
mcpToken: options.mcpToken,
|
|
46
|
+
githubToken,
|
|
47
|
+
config, // Add config parameter for LLM analysis
|
|
48
|
+
verbose: options.verbose,
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Wrapper for code-review phase to inject GitHub token
|
|
53
|
+
*/
|
|
54
|
+
const executeCodeReview = async (options, config) => {
|
|
55
|
+
const githubToken = process.env.GITHUB_TOKEN || process.env.GITHUB_ACCESS_TOKEN;
|
|
56
|
+
if (!githubToken) {
|
|
57
|
+
return {
|
|
58
|
+
status: 'error',
|
|
59
|
+
message: 'GitHub token not found. Set GITHUB_TOKEN or GITHUB_ACCESS_TOKEN environment variable.',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return reviewPullRequest({
|
|
63
|
+
featureId: options.featureId,
|
|
64
|
+
mcpServerUrl: options.mcpServerUrl,
|
|
65
|
+
mcpToken: options.mcpToken,
|
|
66
|
+
githubToken,
|
|
67
|
+
verbose: options.verbose,
|
|
68
|
+
}, config);
|
|
69
|
+
};
|
|
70
|
+
// Pipeline phase configurations
|
|
71
|
+
export const phaseConfigs = [
|
|
72
|
+
{
|
|
73
|
+
name: 'feature-analysis',
|
|
74
|
+
checkRequirements: checkFeatureAnalysisRequirements,
|
|
75
|
+
execute: analyzeFeatureWithMCP,
|
|
76
|
+
requirementsError: 'Feature analysis requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'technical-design',
|
|
80
|
+
checkRequirements: checkTechnicalDesignRequirements,
|
|
81
|
+
execute: generateTechnicalDesign,
|
|
82
|
+
requirementsError: 'Technical design requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'code-implementation',
|
|
86
|
+
checkRequirements: checkCodeImplementationRequirements,
|
|
87
|
+
execute: implementFeatureCode,
|
|
88
|
+
requirementsError: 'Code implementation requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'functional-testing',
|
|
92
|
+
checkRequirements: checkFunctionalTestingRequirements,
|
|
93
|
+
execute: runFunctionalTesting,
|
|
94
|
+
requirementsError: 'Functional testing requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'code-testing',
|
|
98
|
+
checkRequirements: checkCodeTestingRequirements,
|
|
99
|
+
execute: writeCodeTests,
|
|
100
|
+
requirementsError: 'Code testing requirements not met. Install with: npm install @anthropic-ai/claude-code zod',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'code-refine',
|
|
104
|
+
checkRequirements: checkCodeRefineRequirements,
|
|
105
|
+
execute: executeCodeRefine,
|
|
106
|
+
requirementsError: 'Code refine requirements not met. Install with: npm install @anthropic-ai/claude-code @octokit/rest',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'code-refine-verification',
|
|
110
|
+
checkRequirements: checkCodeRefineVerificationRequirements,
|
|
111
|
+
execute: executeCodeRefineVerification,
|
|
112
|
+
requirementsError: 'Code refine verification requirements not met. Install with: npm install @octokit/rest',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'code-review',
|
|
116
|
+
checkRequirements: checkCodeReviewRequirements,
|
|
117
|
+
execute: executeCodeReview,
|
|
118
|
+
requirementsError: 'Code review requirements not met. Install with: npm install @anthropic-ai/claude-code @octokit/rest',
|
|
119
|
+
},
|
|
120
|
+
];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature filtering utilities for workflow processor
|
|
3
|
+
* Pure functions for filtering and selecting features for processing
|
|
4
|
+
*/
|
|
5
|
+
import type { FeatureInfo } from '../../types/features.js';
|
|
6
|
+
import type { FeatureProcessingState } from './state-manager.js';
|
|
7
|
+
export declare const shouldProcessFeature: (maxRetries: number) => (feature: FeatureInfo, states: Map<string, FeatureProcessingState>) => boolean;
|
|
8
|
+
export declare const findNextFeature: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>, maxRetries: number) => FeatureInfo | undefined;
|
|
9
|
+
export declare const isFeatureProcessing: (featureId: string, states: Map<string, FeatureProcessingState>) => boolean;
|
|
10
|
+
export declare const isFeatureCompleted: (featureId: string, states: Map<string, FeatureProcessingState>) => boolean;
|
|
11
|
+
export declare const isFeatureFailed: (featureId: string, states: Map<string, FeatureProcessingState>) => boolean;
|
|
12
|
+
export declare const hasReachedMaxRetries: (featureId: string, states: Map<string, FeatureProcessingState>, maxRetries: number) => boolean;
|
|
13
|
+
export declare const filterProcessingFeatures: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>) => FeatureInfo[];
|
|
14
|
+
export declare const filterCompletedFeatures: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>) => FeatureInfo[];
|
|
15
|
+
export declare const filterFailedFeatures: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>) => FeatureInfo[];
|
|
16
|
+
export declare const filterAvailableFeatures: (features: readonly FeatureInfo[], states: Map<string, FeatureProcessingState>, maxRetries: number) => FeatureInfo[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature filtering utilities for workflow processor
|
|
3
|
+
* Pure functions for filtering and selecting features for processing
|
|
4
|
+
*/
|
|
5
|
+
// Feature filtering functions (pure)
|
|
6
|
+
export const shouldProcessFeature = (maxRetries) => (feature, states) => {
|
|
7
|
+
const state = states.get(feature.id);
|
|
8
|
+
// If never processed, should process
|
|
9
|
+
if (!state)
|
|
10
|
+
return true;
|
|
11
|
+
// If feature was updated after last processing attempt, should reprocess
|
|
12
|
+
// This handles cases where user manually changes status back to ready_for_dev
|
|
13
|
+
if (feature.updated_at) {
|
|
14
|
+
const featureUpdatedTime = new Date(feature.updated_at).getTime();
|
|
15
|
+
const lastAttemptTime = state.lastAttempt.getTime();
|
|
16
|
+
if (featureUpdatedTime > lastAttemptTime) {
|
|
17
|
+
// Feature has been updated since last processing, reprocess it
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// If failed and haven't exceeded retry limit, should retry
|
|
22
|
+
return state.status === 'failed' && state.retryCount < maxRetries;
|
|
23
|
+
};
|
|
24
|
+
export const findNextFeature = (features, states, maxRetries) => features.find((feature) => shouldProcessFeature(maxRetries)(feature, states));
|
|
25
|
+
// Feature status checking functions (pure)
|
|
26
|
+
export const isFeatureProcessing = (featureId, states) => {
|
|
27
|
+
const state = states.get(featureId);
|
|
28
|
+
return state?.status === 'processing';
|
|
29
|
+
};
|
|
30
|
+
export const isFeatureCompleted = (featureId, states) => {
|
|
31
|
+
const state = states.get(featureId);
|
|
32
|
+
return state?.status === 'completed';
|
|
33
|
+
};
|
|
34
|
+
export const isFeatureFailed = (featureId, states) => {
|
|
35
|
+
const state = states.get(featureId);
|
|
36
|
+
return state?.status === 'failed';
|
|
37
|
+
};
|
|
38
|
+
export const hasReachedMaxRetries = (featureId, states, maxRetries) => {
|
|
39
|
+
const state = states.get(featureId);
|
|
40
|
+
return state ? state.retryCount >= maxRetries : false;
|
|
41
|
+
};
|
|
42
|
+
// Feature collection filtering functions (pure)
|
|
43
|
+
export const filterProcessingFeatures = (features, states) => features.filter((feature) => isFeatureProcessing(feature.id, states));
|
|
44
|
+
export const filterCompletedFeatures = (features, states) => features.filter((feature) => isFeatureCompleted(feature.id, states));
|
|
45
|
+
export const filterFailedFeatures = (features, states) => features.filter((feature) => isFeatureFailed(feature.id, states));
|
|
46
|
+
export const filterAvailableFeatures = (features, states, maxRetries) => features.filter((feature) => shouldProcessFeature(maxRetries)(feature, states));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core workflow processor modules
|
|
3
|
+
* Centralized exports for all core functionality
|
|
4
|
+
*/
|
|
5
|
+
// State management
|
|
6
|
+
export * from './state-manager.js';
|
|
7
|
+
// Feature filtering
|
|
8
|
+
export * from './feature-filter.js';
|
|
9
|
+
// Pipeline evaluation
|
|
10
|
+
export * from './pipeline-evaluator.js';
|
|
11
|
+
// Workflow logging
|
|
12
|
+
export * from './workflow-logger.js';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline result evaluation utilities for workflow processor
|
|
3
|
+
* Pure functions for evaluating pipeline execution results
|
|
4
|
+
*/
|
|
5
|
+
import type { PipelineResult } from '../../types/pipeline.js';
|
|
6
|
+
export declare const evaluatePipelineResults: (results: readonly PipelineResult[]) => boolean;
|
|
7
|
+
export declare const hasAnyPipelineFailures: (results: readonly PipelineResult[]) => boolean;
|
|
8
|
+
export declare const countSuccessfulPhases: (results: readonly PipelineResult[]) => number;
|
|
9
|
+
export declare const countFailedPhases: (results: readonly PipelineResult[]) => number;
|
|
10
|
+
export declare const getFailedPhases: (results: readonly PipelineResult[]) => PipelineResult[];
|
|
11
|
+
export declare const getSuccessfulPhases: (results: readonly PipelineResult[]) => PipelineResult[];
|
|
12
|
+
export declare const getFirstFailure: (results: readonly PipelineResult[]) => PipelineResult | undefined;
|
|
13
|
+
export declare const getLastPhaseResult: (results: readonly PipelineResult[]) => PipelineResult | undefined;
|
|
14
|
+
export declare const isPipelineFullySuccessful: (results: readonly PipelineResult[]) => boolean;
|
|
15
|
+
export declare const isPipelinePartiallySuccessful: (results: readonly PipelineResult[]) => boolean;
|
|
16
|
+
export declare const isPipelineCompleteFailure: (results: readonly PipelineResult[]) => boolean;
|
|
17
|
+
export declare const isPipelineEmpty: (results: readonly PipelineResult[]) => boolean;
|
|
18
|
+
export interface PipelineStats {
|
|
19
|
+
readonly total: number;
|
|
20
|
+
readonly successful: number;
|
|
21
|
+
readonly failed: number;
|
|
22
|
+
readonly successRate: number;
|
|
23
|
+
}
|
|
24
|
+
export declare const calculatePipelineStats: (results: readonly PipelineResult[]) => PipelineStats;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline result evaluation utilities for workflow processor
|
|
3
|
+
* Pure functions for evaluating pipeline execution results
|
|
4
|
+
*/
|
|
5
|
+
// Pipeline result evaluation (pure)
|
|
6
|
+
export const evaluatePipelineResults = (results) => results.every((result) => result.status === 'success');
|
|
7
|
+
export const hasAnyPipelineFailures = (results) => results.some((result) => result.status !== 'success');
|
|
8
|
+
export const countSuccessfulPhases = (results) => results.filter((result) => result.status === 'success').length;
|
|
9
|
+
export const countFailedPhases = (results) => results.filter((result) => result.status !== 'success').length;
|
|
10
|
+
export const getFailedPhases = (results) => results.filter((result) => result.status !== 'success');
|
|
11
|
+
export const getSuccessfulPhases = (results) => results.filter((result) => result.status === 'success');
|
|
12
|
+
export const getFirstFailure = (results) => results.find((result) => result.status !== 'success');
|
|
13
|
+
export const getLastPhaseResult = (results) => results.length > 0 ? results[results.length - 1] : undefined;
|
|
14
|
+
// Pipeline completion status
|
|
15
|
+
export const isPipelineFullySuccessful = (results) => results.length > 0 && evaluatePipelineResults(results);
|
|
16
|
+
export const isPipelinePartiallySuccessful = (results) => results.length > 0 &&
|
|
17
|
+
countSuccessfulPhases(results) > 0 &&
|
|
18
|
+
hasAnyPipelineFailures(results);
|
|
19
|
+
export const isPipelineCompleteFailure = (results) => results.length > 0 && countSuccessfulPhases(results) === 0;
|
|
20
|
+
export const isPipelineEmpty = (results) => results.length === 0;
|
|
21
|
+
export const calculatePipelineStats = (results) => {
|
|
22
|
+
const total = results.length;
|
|
23
|
+
const successful = countSuccessfulPhases(results);
|
|
24
|
+
const failed = countFailedPhases(results);
|
|
25
|
+
const successRate = total > 0 ? successful / total : 0;
|
|
26
|
+
return {
|
|
27
|
+
total,
|
|
28
|
+
successful,
|
|
29
|
+
failed,
|
|
30
|
+
successRate,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State management utilities for workflow processor
|
|
3
|
+
* Pure functions for handling feature processing states
|
|
4
|
+
*/
|
|
5
|
+
export interface FeatureProcessingState {
|
|
6
|
+
readonly featureId: string;
|
|
7
|
+
readonly retryCount: number;
|
|
8
|
+
readonly lastAttempt: Date;
|
|
9
|
+
readonly status: 'processing' | 'completed' | 'failed';
|
|
10
|
+
readonly featureUpdatedAt?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface WorkflowStats {
|
|
13
|
+
readonly totalProcessed: number;
|
|
14
|
+
readonly completed: number;
|
|
15
|
+
readonly failed: number;
|
|
16
|
+
readonly processing: number;
|
|
17
|
+
readonly isRunning: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const createInitialState: () => Map<string, FeatureProcessingState>;
|
|
20
|
+
export declare const createProcessingState: (featureId: string, currentState?: FeatureProcessingState) => FeatureProcessingState;
|
|
21
|
+
export declare const createCompletedState: (featureId: string, currentState?: FeatureProcessingState) => FeatureProcessingState;
|
|
22
|
+
export declare const createFailedState: (featureId: string, currentState?: FeatureProcessingState) => FeatureProcessingState;
|
|
23
|
+
export declare const updateFeatureState: (states: Map<string, FeatureProcessingState>, featureId: string, updateFn: (currentState?: FeatureProcessingState) => FeatureProcessingState) => Map<string, FeatureProcessingState>;
|
|
24
|
+
export declare const calculateStats: (states: Map<string, FeatureProcessingState>, isRunning: boolean) => WorkflowStats;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State management utilities for workflow processor
|
|
3
|
+
* Pure functions for handling feature processing states
|
|
4
|
+
*/
|
|
5
|
+
// State creation functions (pure)
|
|
6
|
+
export const createInitialState = () => new Map();
|
|
7
|
+
export const createProcessingState = (featureId, currentState) => ({
|
|
8
|
+
featureId,
|
|
9
|
+
retryCount: currentState ? currentState.retryCount + 1 : 1,
|
|
10
|
+
lastAttempt: new Date(),
|
|
11
|
+
status: 'processing',
|
|
12
|
+
});
|
|
13
|
+
export const createCompletedState = (featureId, currentState) => ({
|
|
14
|
+
featureId,
|
|
15
|
+
retryCount: currentState ? currentState.retryCount : 1,
|
|
16
|
+
lastAttempt: new Date(),
|
|
17
|
+
status: 'completed',
|
|
18
|
+
});
|
|
19
|
+
export const createFailedState = (featureId, currentState) => ({
|
|
20
|
+
featureId,
|
|
21
|
+
retryCount: currentState ? currentState.retryCount : 1,
|
|
22
|
+
lastAttempt: new Date(),
|
|
23
|
+
status: 'failed',
|
|
24
|
+
});
|
|
25
|
+
// State update function (pure)
|
|
26
|
+
export const updateFeatureState = (states, featureId, updateFn) => {
|
|
27
|
+
const newStates = new Map(states);
|
|
28
|
+
const currentState = newStates.get(featureId);
|
|
29
|
+
newStates.set(featureId, updateFn(currentState));
|
|
30
|
+
return newStates;
|
|
31
|
+
};
|
|
32
|
+
// Statistics calculation (pure)
|
|
33
|
+
export const calculateStats = (states, isRunning) => {
|
|
34
|
+
const stateArray = Array.from(states.values());
|
|
35
|
+
return {
|
|
36
|
+
totalProcessed: stateArray.length,
|
|
37
|
+
completed: stateArray.filter((s) => s.status === 'completed').length,
|
|
38
|
+
failed: stateArray.filter((s) => s.status === 'failed').length,
|
|
39
|
+
processing: stateArray.filter((s) => s.status === 'processing').length,
|
|
40
|
+
isRunning,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging utilities for workflow processor
|
|
3
|
+
* Centralized logging functions for workflow operations
|
|
4
|
+
*/
|
|
5
|
+
import type { FeatureInfo } from '../../types/features.js';
|
|
6
|
+
import type { PipelineResult } from '../../types/pipeline.js';
|
|
7
|
+
export declare const logProcessingStart: (feature: FeatureInfo, verbose?: boolean) => void;
|
|
8
|
+
export declare const logRetryInfo: (featureName: string, retryCount: number, maxRetries: number) => void;
|
|
9
|
+
export declare const logPipelineResults: (results: readonly PipelineResult[]) => void;
|
|
10
|
+
export declare const logProcessorStart: (productId: string, pollInterval: number) => void;
|
|
11
|
+
export declare const logProcessorReady: () => void;
|
|
12
|
+
export declare const logProcessorStop: () => void;
|
|
13
|
+
export declare const logFeatureSuccess: (featureName: string) => void;
|
|
14
|
+
export declare const logFeatureFailed: (featureName: string) => void;
|
|
15
|
+
export declare const logFeatureError: (featureName: string, error: unknown) => void;
|
|
16
|
+
export declare const logNoFeaturesFound: () => void;
|
|
17
|
+
export declare const logAllFeaturesProcessed: () => void;
|
|
18
|
+
export declare const logSkippingProcessing: (processingCount: number) => void;
|
|
19
|
+
export declare const logPollingError: (error: unknown) => void;
|
|
20
|
+
export declare const logProcessNextFeatureError: (error: unknown) => void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging utilities for workflow processor
|
|
3
|
+
* Centralized logging functions for workflow operations
|
|
4
|
+
*/
|
|
5
|
+
import { logInfo, logError, logSuccess } from '../../utils/logger.js';
|
|
6
|
+
export const logProcessingStart = (feature, verbose) => {
|
|
7
|
+
logInfo(`đ¯ Processing feature: ${feature.name} (${feature.id})`);
|
|
8
|
+
if (verbose) {
|
|
9
|
+
logInfo(` Description: ${feature.description}`);
|
|
10
|
+
logInfo(` Last updated: ${feature.updated_at}`);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export const logRetryInfo = (featureName, retryCount, maxRetries) => {
|
|
14
|
+
if (retryCount < maxRetries) {
|
|
15
|
+
logInfo(`đ Will retry feature ${featureName} (attempt ${retryCount + 1}/${maxRetries})`);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
logError(`â Max retries reached for feature ${featureName}, marking as permanently failed`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
export const logPipelineResults = (results) => {
|
|
22
|
+
console.log('\n' + '='.repeat(60));
|
|
23
|
+
console.log('đ Pipeline Results Summary');
|
|
24
|
+
console.log('='.repeat(60));
|
|
25
|
+
results.forEach((result, index) => {
|
|
26
|
+
const statusIcon = result.status === 'success' ? 'â
' : 'â';
|
|
27
|
+
console.log(`${index + 1}. ${statusIcon} ${result.phase}: ${result.message}`);
|
|
28
|
+
});
|
|
29
|
+
console.log('='.repeat(60) + '\n');
|
|
30
|
+
};
|
|
31
|
+
export const logProcessorStart = (productId, pollInterval) => {
|
|
32
|
+
logInfo('đ Starting workflow processor...');
|
|
33
|
+
logInfo(`đ Product ID: ${productId}`);
|
|
34
|
+
logInfo(`đ Poll interval: ${pollInterval}ms`);
|
|
35
|
+
};
|
|
36
|
+
export const logProcessorReady = () => {
|
|
37
|
+
logInfo('â
Workflow processor started and monitoring for new features');
|
|
38
|
+
};
|
|
39
|
+
export const logProcessorStop = () => {
|
|
40
|
+
logInfo('âšī¸ Workflow processor stopped');
|
|
41
|
+
};
|
|
42
|
+
export const logFeatureSuccess = (featureName) => {
|
|
43
|
+
logSuccess(`â
Feature ${featureName} completed successfully!`);
|
|
44
|
+
};
|
|
45
|
+
export const logFeatureFailed = (featureName) => {
|
|
46
|
+
logError(`â Feature ${featureName} failed in pipeline`);
|
|
47
|
+
};
|
|
48
|
+
export const logFeatureError = (featureName, error) => {
|
|
49
|
+
logError(`â Error processing feature ${featureName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
+
};
|
|
51
|
+
export const logNoFeaturesFound = () => {
|
|
52
|
+
logInfo('đ No ready_for_dev features found, continuing to monitor...');
|
|
53
|
+
};
|
|
54
|
+
export const logAllFeaturesProcessed = () => {
|
|
55
|
+
logInfo('đ All current features are processed or being processed, continuing to monitor...');
|
|
56
|
+
};
|
|
57
|
+
export const logSkippingProcessing = (processingCount) => {
|
|
58
|
+
logInfo(`âŗ Skipping feature fetching as ${processingCount} feature(s) are currently being processed`);
|
|
59
|
+
};
|
|
60
|
+
export const logPollingError = (error) => {
|
|
61
|
+
logError(`Error in polling cycle: ${error instanceof Error ? error.message : String(error)}`);
|
|
62
|
+
};
|
|
63
|
+
export const logProcessNextFeatureError = (error) => {
|
|
64
|
+
logError(`Error in processNextFeature: ${error instanceof Error ? error.message : String(error)}`);
|
|
65
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase execution logic for pipeline runner
|
|
3
|
+
*/
|
|
4
|
+
import { EdsgerConfig } from '../../types/index.js';
|
|
5
|
+
import { PipelinePhaseOptions, PipelineResult, PhaseConfig } from '../../types/pipeline.js';
|
|
6
|
+
export declare const createPhaseRunner: (phaseConfig: PhaseConfig) => (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
|
|
7
|
+
declare const runFeatureAnalysisPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runTechnicalDesignPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeImplementationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runFunctionalTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeTestingPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefinePhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeRefineVerificationPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>, runCodeReviewPhase: (options: PipelinePhaseOptions, config: EdsgerConfig) => Promise<PipelineResult>;
|
|
8
|
+
export { runFeatureAnalysisPhase, runTechnicalDesignPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeTestingPhase, runCodeRefinePhase, runCodeRefineVerificationPhase, runCodeReviewPhase, };
|