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.
Files changed (103) hide show
  1. package/.claude/settings.local.json +23 -3
  2. package/.env.local +12 -0
  3. package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
  4. package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
  5. package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
  6. package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
  7. package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
  8. package/dist/commands/workflow/pipeline-runner.js +393 -0
  9. package/dist/commands/workflow/runner.d.ts +26 -0
  10. package/dist/commands/workflow/runner.js +119 -0
  11. package/dist/commands/workflow/workflow-runner.d.ts +26 -0
  12. package/dist/commands/workflow/workflow-runner.js +119 -0
  13. package/dist/index.js +0 -0
  14. package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
  15. package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
  16. package/dist/phases/code-implementation/analyzer.d.ts +32 -0
  17. package/dist/phases/code-implementation/analyzer.js +629 -0
  18. package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
  19. package/dist/phases/code-implementation/context-fetcher.js +86 -0
  20. package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
  21. package/dist/phases/code-implementation/mcp-server.js +93 -0
  22. package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
  23. package/dist/phases/code-implementation/prompts-improvement.js +108 -0
  24. package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
  25. package/dist/phases/code-implementation-verification/verifier.js +196 -0
  26. package/dist/phases/code-refine/analyzer.d.ts +41 -0
  27. package/dist/phases/code-refine/analyzer.js +561 -0
  28. package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
  29. package/dist/phases/code-refine/context-fetcher.js +423 -0
  30. package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
  31. package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
  32. package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
  33. package/dist/phases/code-refine-verification/verifier.js +597 -0
  34. package/dist/phases/code-review/analyzer.d.ts +29 -0
  35. package/dist/phases/code-review/analyzer.js +363 -0
  36. package/dist/phases/code-review/context-fetcher.d.ts +92 -0
  37. package/dist/phases/code-review/context-fetcher.js +296 -0
  38. package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
  39. package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
  40. package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
  41. package/dist/phases/feature-analysis/analyzer.js +208 -0
  42. package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
  43. package/dist/phases/feature-analysis/context-fetcher.js +134 -0
  44. package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
  45. package/dist/phases/feature-analysis/http-fallback.js +95 -0
  46. package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
  47. package/dist/phases/feature-analysis/mcp-server.js +144 -0
  48. package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
  49. package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
  50. package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
  51. package/dist/phases/feature-analysis-verification/verifier.js +147 -0
  52. package/dist/phases/pr-execution/file-assigner.js +20 -12
  53. package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
  54. package/dist/phases/technical-design/analyzer-helpers.js +39 -0
  55. package/dist/phases/technical-design/analyzer.d.ts +21 -0
  56. package/dist/phases/technical-design/analyzer.js +461 -0
  57. package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
  58. package/dist/phases/technical-design/context-fetcher.js +39 -0
  59. package/dist/phases/technical-design/http-fallback.d.ts +17 -0
  60. package/dist/phases/technical-design/http-fallback.js +151 -0
  61. package/dist/phases/technical-design/mcp-server.d.ts +1 -0
  62. package/dist/phases/technical-design/mcp-server.js +157 -0
  63. package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
  64. package/dist/phases/technical-design/prompts-improvement.js +93 -0
  65. package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
  66. package/dist/phases/technical-design-verification/verifier.js +170 -0
  67. package/dist/services/feature-branches.d.ts +77 -0
  68. package/dist/services/feature-branches.js +205 -0
  69. package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
  70. package/dist/workflow-runner/config/phase-configs.js +120 -0
  71. package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
  72. package/dist/workflow-runner/core/feature-filter.js +46 -0
  73. package/dist/workflow-runner/core/index.d.ts +8 -0
  74. package/dist/workflow-runner/core/index.js +12 -0
  75. package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
  76. package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
  77. package/dist/workflow-runner/core/state-manager.d.ts +24 -0
  78. package/dist/workflow-runner/core/state-manager.js +42 -0
  79. package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
  80. package/dist/workflow-runner/core/workflow-logger.js +65 -0
  81. package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
  82. package/dist/workflow-runner/executors/phase-executor.js +248 -0
  83. package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
  84. package/dist/workflow-runner/feature-workflow-runner.js +119 -0
  85. package/dist/workflow-runner/index.d.ts +2 -0
  86. package/dist/workflow-runner/index.js +2 -0
  87. package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
  88. package/dist/workflow-runner/pipeline-runner.js +393 -0
  89. package/dist/workflow-runner/workflow-processor.d.ts +54 -0
  90. package/dist/workflow-runner/workflow-processor.js +170 -0
  91. package/package.json +1 -1
  92. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
  93. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
  94. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
  95. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
  96. package/dist/services/lifecycle-agent/index.d.ts +0 -24
  97. package/dist/services/lifecycle-agent/index.js +0 -25
  98. package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
  99. package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
  100. package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
  101. package/dist/services/lifecycle-agent/transition-rules.js +0 -184
  102. package/dist/services/lifecycle-agent/types.d.ts +0 -190
  103. 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,5 @@
1
+ /**
2
+ * Phase configurations for the pipeline runner
3
+ */
4
+ import { PhaseConfig } from '../../types/pipeline.js';
5
+ export declare const phaseConfigs: readonly PhaseConfig[];
@@ -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,8 @@
1
+ /**
2
+ * Core workflow processor modules
3
+ * Centralized exports for all core functionality
4
+ */
5
+ export * from './state-manager.js';
6
+ export * from './feature-filter.js';
7
+ export * from './pipeline-evaluator.js';
8
+ export * from './workflow-logger.js';
@@ -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, };