edsger 0.19.9 → 0.19.11

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 (94) hide show
  1. package/dist/commands/workflow/feature-coordinator.js +1 -0
  2. package/dist/phases/code-refine/index.d.ts +8 -1
  3. package/dist/phases/code-refine/index.js +250 -146
  4. package/dist/phases/code-review/index.js +22 -1
  5. package/dist/services/branches.d.ts +6 -1
  6. package/dist/services/branches.js +28 -9
  7. package/package.json +1 -1
  8. package/.claude/settings.local.json +0 -28
  9. package/dist/api/features/__tests__/regression-prevention.test.d.ts +0 -5
  10. package/dist/api/features/__tests__/regression-prevention.test.js +0 -338
  11. package/dist/api/features/__tests__/status-updater.integration.test.d.ts +0 -5
  12. package/dist/api/features/__tests__/status-updater.integration.test.js +0 -497
  13. package/dist/commands/workflow/pipeline-runner.d.ts +0 -17
  14. package/dist/commands/workflow/pipeline-runner.js +0 -393
  15. package/dist/commands/workflow/runner.d.ts +0 -26
  16. package/dist/commands/workflow/runner.js +0 -119
  17. package/dist/commands/workflow/workflow-runner.d.ts +0 -26
  18. package/dist/commands/workflow/workflow-runner.js +0 -119
  19. package/dist/phases/code-implementation/analyzer-helpers.d.ts +0 -28
  20. package/dist/phases/code-implementation/analyzer-helpers.js +0 -177
  21. package/dist/phases/code-implementation/analyzer.d.ts +0 -32
  22. package/dist/phases/code-implementation/analyzer.js +0 -629
  23. package/dist/phases/code-implementation/context-fetcher.d.ts +0 -17
  24. package/dist/phases/code-implementation/context-fetcher.js +0 -86
  25. package/dist/phases/code-implementation/mcp-server.d.ts +0 -1
  26. package/dist/phases/code-implementation/mcp-server.js +0 -93
  27. package/dist/phases/code-implementation/prompts-improvement.d.ts +0 -5
  28. package/dist/phases/code-implementation/prompts-improvement.js +0 -108
  29. package/dist/phases/code-implementation-verification/verifier.d.ts +0 -31
  30. package/dist/phases/code-implementation-verification/verifier.js +0 -196
  31. package/dist/phases/code-refine/analyzer.d.ts +0 -41
  32. package/dist/phases/code-refine/analyzer.js +0 -561
  33. package/dist/phases/code-refine/context-fetcher.d.ts +0 -94
  34. package/dist/phases/code-refine/context-fetcher.js +0 -423
  35. package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +0 -22
  36. package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +0 -134
  37. package/dist/phases/code-refine-verification/verifier.d.ts +0 -47
  38. package/dist/phases/code-refine-verification/verifier.js +0 -597
  39. package/dist/phases/code-review/analyzer.d.ts +0 -29
  40. package/dist/phases/code-review/analyzer.js +0 -363
  41. package/dist/phases/code-review/context-fetcher.d.ts +0 -92
  42. package/dist/phases/code-review/context-fetcher.js +0 -296
  43. package/dist/phases/feature-analysis/analyzer-helpers.d.ts +0 -10
  44. package/dist/phases/feature-analysis/analyzer-helpers.js +0 -47
  45. package/dist/phases/feature-analysis/analyzer.d.ts +0 -11
  46. package/dist/phases/feature-analysis/analyzer.js +0 -208
  47. package/dist/phases/feature-analysis/context-fetcher.d.ts +0 -26
  48. package/dist/phases/feature-analysis/context-fetcher.js +0 -134
  49. package/dist/phases/feature-analysis/http-fallback.d.ts +0 -20
  50. package/dist/phases/feature-analysis/http-fallback.js +0 -95
  51. package/dist/phases/feature-analysis/mcp-server.d.ts +0 -1
  52. package/dist/phases/feature-analysis/mcp-server.js +0 -144
  53. package/dist/phases/feature-analysis/prompts-improvement.d.ts +0 -8
  54. package/dist/phases/feature-analysis/prompts-improvement.js +0 -109
  55. package/dist/phases/feature-analysis-verification/verifier.d.ts +0 -37
  56. package/dist/phases/feature-analysis-verification/verifier.js +0 -147
  57. package/dist/phases/technical-design/analyzer-helpers.d.ts +0 -25
  58. package/dist/phases/technical-design/analyzer-helpers.js +0 -39
  59. package/dist/phases/technical-design/analyzer.d.ts +0 -21
  60. package/dist/phases/technical-design/analyzer.js +0 -461
  61. package/dist/phases/technical-design/context-fetcher.d.ts +0 -12
  62. package/dist/phases/technical-design/context-fetcher.js +0 -39
  63. package/dist/phases/technical-design/http-fallback.d.ts +0 -17
  64. package/dist/phases/technical-design/http-fallback.js +0 -151
  65. package/dist/phases/technical-design/mcp-server.d.ts +0 -1
  66. package/dist/phases/technical-design/mcp-server.js +0 -157
  67. package/dist/phases/technical-design/prompts-improvement.d.ts +0 -5
  68. package/dist/phases/technical-design/prompts-improvement.js +0 -93
  69. package/dist/phases/technical-design-verification/verifier.d.ts +0 -53
  70. package/dist/phases/technical-design-verification/verifier.js +0 -170
  71. package/dist/services/feature-branches.d.ts +0 -77
  72. package/dist/services/feature-branches.js +0 -205
  73. package/dist/workflow-runner/config/phase-configs.d.ts +0 -5
  74. package/dist/workflow-runner/config/phase-configs.js +0 -120
  75. package/dist/workflow-runner/core/feature-filter.d.ts +0 -16
  76. package/dist/workflow-runner/core/feature-filter.js +0 -46
  77. package/dist/workflow-runner/core/index.d.ts +0 -8
  78. package/dist/workflow-runner/core/index.js +0 -12
  79. package/dist/workflow-runner/core/pipeline-evaluator.d.ts +0 -24
  80. package/dist/workflow-runner/core/pipeline-evaluator.js +0 -32
  81. package/dist/workflow-runner/core/state-manager.d.ts +0 -24
  82. package/dist/workflow-runner/core/state-manager.js +0 -42
  83. package/dist/workflow-runner/core/workflow-logger.d.ts +0 -20
  84. package/dist/workflow-runner/core/workflow-logger.js +0 -65
  85. package/dist/workflow-runner/executors/phase-executor.d.ts +0 -8
  86. package/dist/workflow-runner/executors/phase-executor.js +0 -248
  87. package/dist/workflow-runner/feature-workflow-runner.d.ts +0 -26
  88. package/dist/workflow-runner/feature-workflow-runner.js +0 -119
  89. package/dist/workflow-runner/index.d.ts +0 -2
  90. package/dist/workflow-runner/index.js +0 -2
  91. package/dist/workflow-runner/pipeline-runner.d.ts +0 -17
  92. package/dist/workflow-runner/pipeline-runner.js +0 -393
  93. package/dist/workflow-runner/workflow-processor.d.ts +0 -54
  94. package/dist/workflow-runner/workflow-processor.js +0 -170
@@ -16,6 +16,7 @@ import { logPhaseResult } from '../../utils/pipeline-logger.js';
16
16
  import { runFeatureAnalysisPhase, runTechnicalDesignPhase, runBranchPlanningPhase, runCodeImplementationPhase, runFunctionalTestingPhase, runCodeRefinePhase, runCodeReviewPhase, } from './executors/phase-executor.js';
17
17
  /**
18
18
  * Map workflow phase names (underscore format) to phase runner functions
19
+ * Note: code_refine includes built-in verification loop (similar to technical_design)
19
20
  */
20
21
  const PHASE_RUNNERS = {
21
22
  feature_analysis: runFeatureAnalysisPhase,
@@ -1,8 +1,11 @@
1
1
  /**
2
2
  * Code Refine Analyzer
3
3
  * Processes GitHub PR review feedback and refines code accordingly
4
+ * Includes built-in verification loop that resolves PR comments and dismisses reviews
4
5
  */
5
6
  import { EdsgerConfig } from '../../types/index.js';
7
+ import { type CodeRefineVerificationResult } from '../code-refine-verification/index.js';
8
+ export declare const MAX_REFINE_ITERATIONS = 10;
6
9
  export interface CodeRefineOptions {
7
10
  featureId: string;
8
11
  githubToken: string;
@@ -34,8 +37,12 @@ export interface CodeRefineResult {
34
37
  summary?: string;
35
38
  filesModified?: string[];
36
39
  commitsCreated?: number;
40
+ iterations?: number;
41
+ verificationResult?: CodeRefineVerificationResult;
37
42
  }
38
43
  /**
39
- * Main code refine function
44
+ * Main code refine function with built-in verification loop
45
+ * Similar to technical-design, this includes an iterative improvement cycle:
46
+ * refine → verification → improve → re-refine (if needed)
40
47
  */
41
48
  export declare const refineCodeFromPRFeedback: (options: CodeRefineOptions, config: EdsgerConfig) => Promise<CodeRefineResult>;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Code Refine Analyzer
3
3
  * Processes GitHub PR review feedback and refines code accordingly
4
+ * Includes built-in verification loop that resolves PR comments and dismisses reviews
4
5
  */
5
6
  import { query } from '@anthropic-ai/claude-agent-sdk';
6
7
  import { logInfo, logError } from '../../utils/logger.js';
@@ -10,8 +11,11 @@ import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services
10
11
  import { createSystemPrompt, createCodeRefinePrompt } from './prompts.js';
11
12
  import { preparePhaseGitEnvironment, prepareCustomBranchGitEnvironment, hasUncommittedChanges, getUncommittedFiles, syncFeatBranchWithMain, } from '../../utils/git-branch-manager.js';
12
13
  import { getFeature } from '../../api/features/get-feature.js';
13
- import { getReadyForReviewBranch, } from '../../services/branches.js';
14
+ import { getReviewedBranch, updateBranch, } from '../../services/branches.js';
14
15
  import { parsePullRequestUrl } from './context.js';
16
+ import { verifyAndResolveComments, } from '../code-refine-verification/index.js';
17
+ // Maximum number of refine + verification iterations
18
+ export const MAX_REFINE_ITERATIONS = 10;
15
19
  function userMessage(content) {
16
20
  return {
17
21
  type: 'user',
@@ -58,29 +62,31 @@ const pushChanges = (verbose) => {
58
62
  }
59
63
  };
60
64
  /**
61
- * Main code refine function
65
+ * Main code refine function with built-in verification loop
66
+ * Similar to technical-design, this includes an iterative improvement cycle:
67
+ * refine → verification → improve → re-refine (if needed)
62
68
  */
63
69
  export const refineCodeFromPRFeedback = async (options, config) => {
64
70
  const { featureId, githubToken, verbose } = options;
65
71
  if (verbose) {
66
72
  logInfo(`Starting code refine for feature ID: ${featureId}`);
67
73
  }
68
- // For multi-branch features, find the branch that is ready for review
69
- // and use its branch_name for refine (branch_name is stored as dev/...)
74
+ // For multi-branch features, find the branch that has been reviewed
75
+ // (status = 'reviewed' after code-review phase) and use its branch_name for refine
70
76
  let branchName = `dev/${featureId}`; // Default for single-branch features
71
77
  let currentBranch = null;
72
78
  try {
73
- currentBranch = await getReadyForReviewBranch({ featureId, verbose });
79
+ currentBranch = await getReviewedBranch({ featureId, verbose });
74
80
  if (currentBranch && currentBranch.branch_name) {
75
81
  // Use branch_name directly (already stored as dev/...)
76
82
  branchName = currentBranch.branch_name;
77
83
  if (verbose) {
78
- logInfo(`📋 Found ready_for_review branch: ${currentBranch.name}`);
84
+ logInfo(`📋 Found reviewed branch: ${currentBranch.name}`);
79
85
  logInfo(` Using dev branch: ${branchName}`);
80
86
  }
81
87
  }
82
88
  else if (verbose) {
83
- logInfo(`ℹ️ No ready_for_review branch found, using default: ${branchName}`);
89
+ logInfo(`ℹ️ No reviewed branch found, using default: ${branchName}`);
84
90
  }
85
91
  }
86
92
  catch (error) {
@@ -129,13 +135,14 @@ export const refineCodeFromPRFeedback = async (options, config) => {
129
135
  ? prepareCustomBranchGitEnvironment(branchName, 'main', verbose)
130
136
  : preparePhaseGitEnvironment(featureId, 'main', verbose);
131
137
  try {
132
- // Fetch code refine context (PR reviews and comments)
138
+ // Fetch initial code refine context (PR reviews and comments)
133
139
  if (verbose) {
134
140
  logInfo('Fetching code refine context from GitHub PR...');
135
141
  }
136
- const context = await fetchCodeRefineContext(featureId, githubToken, verbose, pullRequestUrl || undefined);
142
+ const initialContext = await fetchCodeRefineContext(featureId, githubToken, verbose, pullRequestUrl || undefined);
137
143
  // Check if there are any reviews or comments to address
138
- if (context.reviews.length === 0 && context.reviewComments.length === 0) {
144
+ if (initialContext.reviews.length === 0 &&
145
+ initialContext.reviewComments.length === 0) {
139
146
  if (verbose) {
140
147
  logInfo('✅ No review comments or change requests found. Nothing to refine.');
141
148
  }
@@ -144,129 +151,43 @@ export const refineCodeFromPRFeedback = async (options, config) => {
144
151
  status: 'success',
145
152
  message: 'No review feedback to address',
146
153
  summary: 'No change requests or review comments found on the PR',
154
+ iterations: 0,
147
155
  };
148
156
  }
149
157
  if (verbose) {
150
- logInfo(`📋 Found ${context.reviews.length} reviews and ${context.reviewComments.length} comments to address`);
158
+ logInfo(`📋 Found ${initialContext.reviews.length} reviews and ${initialContext.reviewComments.length} comments to address`);
151
159
  }
152
- // Fetch additional feedbacks for code-refine phase
153
- // For multi-branch features, filter by the current branch to get branch-specific feedbacks
154
- let feedbacksInfo;
155
- try {
156
- const feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'code_refine', currentBranch?.id // Pass branch_id if we have a current branch
157
- );
158
- if (feedbacksContext.feedbacks.length > 0) {
159
- feedbacksInfo = await formatFeedbacksForContext(feedbacksContext);
160
- if (verbose) {
161
- logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to code refine context${currentBranch ? ` (including branch-specific for "${currentBranch.name}")` : ''}`);
162
- }
163
- }
164
- }
165
- catch (error) {
160
+ // Iterative refine verification loop
161
+ let currentIteration = 0;
162
+ let verificationFailureContext;
163
+ let lastRefineResult = null;
164
+ let lastVerificationResult = null;
165
+ while (currentIteration < MAX_REFINE_ITERATIONS) {
166
+ currentIteration++;
166
167
  if (verbose) {
167
- logInfo(`Note: Could not fetch feedbacks (${error instanceof Error ? error.message : String(error)})`);
168
- }
169
- }
170
- // Feature branch switching is handled by preparePhaseGitEnvironment above
171
- // Create prompt for code refine
172
- const systemPrompt = createSystemPrompt();
173
- const refinePrompt = createCodeRefinePrompt(featureId, context, feedbacksInfo, options.verificationFailureContext);
174
- let lastAssistantResponse = '';
175
- let structuredRefineResult = null;
176
- if (verbose) {
177
- logInfo('Starting Claude Code query for code refine...');
178
- }
179
- // Use Claude Code SDK to refine the code
180
- for await (const message of query({
181
- prompt: prompt(refinePrompt),
182
- options: {
183
- systemPrompt: {
184
- type: 'preset',
185
- preset: 'claude_code',
186
- append: systemPrompt,
187
- },
188
- model: config.claude.model || 'sonnet',
189
- maxTurns: 2000,
190
- permissionMode: 'bypassPermissions',
191
- },
192
- })) {
193
- if (verbose) {
194
- logInfo(`Received message type: ${message.type}`);
195
- }
196
- // Stream the code refine process
197
- if (message.type === 'assistant' && message.message?.content) {
198
- for (const content of message.message.content) {
199
- if (content.type === 'text') {
200
- lastAssistantResponse += content.text + '\n';
201
- if (verbose) {
202
- console.log(`\n🔧 ${content.text}`);
203
- }
204
- }
205
- else if (content.type === 'tool_use') {
206
- if (verbose) {
207
- console.log(`\n🛠️ ${content.name}: ${content.input.description || 'Running...'}`);
208
- }
209
- }
210
- }
211
- }
212
- else if (message.type === 'result') {
213
- if (message.subtype === 'success') {
214
- logInfo('\n🛠️ Code refine completed, parsing results...');
215
- try {
216
- const responseText = message.result || lastAssistantResponse;
217
- let jsonResult = null;
218
- const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
219
- if (jsonBlockMatch) {
220
- jsonResult = JSON.parse(jsonBlockMatch[1]);
221
- }
222
- else {
223
- jsonResult = JSON.parse(responseText);
224
- }
225
- if (jsonResult && jsonResult.refine_result) {
226
- structuredRefineResult = jsonResult.refine_result;
227
- }
228
- else {
229
- throw new Error('Invalid JSON structure');
230
- }
231
- }
232
- catch (error) {
233
- logError(`Failed to parse structured refine result: ${error}`);
234
- structuredRefineResult = parseCodeRefineResponse(message.result || lastAssistantResponse);
235
- }
168
+ if (currentIteration === 1) {
169
+ logInfo(`\n🔄 Starting refine iteration ${currentIteration}/${MAX_REFINE_ITERATIONS}`);
236
170
  }
237
171
  else {
238
- logError(`\n⚠️ Code refine incomplete: ${message.subtype}`);
239
- if (message.subtype === 'error_max_turns') {
240
- logError('💡 Try simplifying the changes or reducing scope');
241
- }
242
- if (lastAssistantResponse) {
243
- try {
244
- const responseText = lastAssistantResponse;
245
- let jsonResult = null;
246
- const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
247
- if (jsonBlockMatch) {
248
- jsonResult = JSON.parse(jsonBlockMatch[1]);
249
- if (jsonResult && jsonResult.refine_result) {
250
- structuredRefineResult = jsonResult.refine_result;
251
- }
252
- }
253
- else {
254
- structuredRefineResult = parseCodeRefineResponse(lastAssistantResponse);
255
- }
256
- }
257
- catch (error) {
258
- logError(`Failed to parse assistant response: ${error}`);
259
- }
260
- }
172
+ logInfo(`\n🔄 Retry iteration ${currentIteration}/${MAX_REFINE_ITERATIONS}: Improving based on verification feedback...`);
261
173
  }
262
174
  }
263
- }
264
- // Push changes to remote
265
- if (structuredRefineResult) {
266
- // Verify all changes are committed before pushing
175
+ // Execute refine for this iteration
176
+ const refineResult = await executeRefineIteration(featureId, githubToken, config, pullRequestUrl || undefined, currentBranch, verificationFailureContext, verbose);
177
+ if (refineResult.status === 'error') {
178
+ // Refine failed - return error
179
+ return {
180
+ featureId,
181
+ status: 'error',
182
+ message: refineResult.message || 'Code refine failed',
183
+ iterations: currentIteration,
184
+ };
185
+ }
186
+ lastRefineResult = refineResult;
187
+ // Push changes before verification
267
188
  if (hasUncommittedChanges()) {
268
189
  const uncommittedFiles = getUncommittedFiles();
269
- const errorMsg = `Code refine completed but there are uncommitted changes. All changes must be committed before verification.
190
+ const errorMsg = `Code refine completed but there are uncommitted changes.
270
191
 
271
192
  Uncommitted files:
272
193
  ${uncommittedFiles.join('\n')}
@@ -277,6 +198,7 @@ Please ensure Claude Code commits all changes before completing the refine phase
277
198
  featureId,
278
199
  status: 'error',
279
200
  message: errorMsg,
201
+ iterations: currentIteration,
280
202
  };
281
203
  }
282
204
  if (verbose) {
@@ -284,24 +206,6 @@ Please ensure Claude Code commits all changes before completing the refine phase
284
206
  }
285
207
  try {
286
208
  pushChanges(verbose);
287
- const { summary, files_modified, commits_created } = structuredRefineResult;
288
- if (verbose) {
289
- logInfo(`Code refine completed for feature: ${featureId}`);
290
- if (files_modified?.length > 0) {
291
- logInfo(`Files modified: ${files_modified.join(', ')}`);
292
- }
293
- if (commits_created) {
294
- logInfo(`Commits created: ${commits_created}`);
295
- }
296
- }
297
- return {
298
- featureId,
299
- status: 'success',
300
- message: 'Code successfully refined based on PR feedback',
301
- summary: summary || 'Code refined based on PR review feedback',
302
- filesModified: files_modified || [],
303
- commitsCreated: commits_created || 1,
304
- };
305
209
  }
306
210
  catch (pushError) {
307
211
  logError(`Failed to push changes: ${pushError}`);
@@ -309,16 +213,86 @@ Please ensure Claude Code commits all changes before completing the refine phase
309
213
  featureId,
310
214
  status: 'error',
311
215
  message: `Code refined but failed to push: ${pushError}`,
216
+ iterations: currentIteration,
312
217
  };
313
218
  }
314
- }
315
- else {
316
- return {
219
+ // Run verification
220
+ if (verbose) {
221
+ logInfo('\n🔍 Running verification to check if all comments are addressed...');
222
+ }
223
+ const verificationResult = await verifyAndResolveComments({
317
224
  featureId,
318
- status: 'error',
319
- message: 'Code refine failed or incomplete',
320
- };
225
+ githubToken,
226
+ config,
227
+ verbose,
228
+ });
229
+ lastVerificationResult = verificationResult;
230
+ // If verification passed, we're done!
231
+ if (verificationResult.status === 'success') {
232
+ if (verbose) {
233
+ logInfo('✅ Verification passed! All PR comments have been addressed and resolved.');
234
+ }
235
+ // Update branch status to 'refined' for multi-branch features
236
+ if (currentBranch) {
237
+ await updateBranch(currentBranch.id, { status: 'refined' }, verbose);
238
+ if (verbose) {
239
+ logInfo(`✅ Branch "${currentBranch.name}" status updated to 'refined'`);
240
+ }
241
+ }
242
+ return {
243
+ featureId,
244
+ status: 'success',
245
+ message: verificationResult.message,
246
+ summary: lastRefineResult.summary ||
247
+ 'Code refined based on PR review feedback',
248
+ filesModified: lastRefineResult.files_modified || [],
249
+ commitsCreated: lastRefineResult.commits_created || 1,
250
+ iterations: currentIteration,
251
+ verificationResult,
252
+ };
253
+ }
254
+ // Verification failed - prepare context for retry
255
+ if (currentIteration < MAX_REFINE_ITERATIONS) {
256
+ const verificationData = verificationResult.data;
257
+ const suggestions = verificationData.suggestions || [];
258
+ const unresolvedCommentDetails = verificationData.unresolvedCommentDetails || [];
259
+ const unresolvedReviewDetails = verificationData.unresolvedReviewDetails;
260
+ verificationFailureContext = {
261
+ attempt: currentIteration + 1,
262
+ suggestions,
263
+ unresolvedCommentDetails,
264
+ unresolvedReviewDetails,
265
+ };
266
+ if (verbose) {
267
+ logInfo(`\n⚠️ Verification failed: ${verificationResult.message}`);
268
+ if (suggestions.length > 0) {
269
+ logInfo(`💡 Suggestions for next iteration:`);
270
+ suggestions.forEach((suggestion) => {
271
+ logInfo(` ${suggestion}`);
272
+ });
273
+ }
274
+ logInfo(`\n🔄 Will retry... (${MAX_REFINE_ITERATIONS - currentIteration} attempts remaining)`);
275
+ }
276
+ }
277
+ else {
278
+ // Max iterations reached
279
+ if (verbose) {
280
+ logInfo(`\n⚠️ Maximum iterations (${MAX_REFINE_ITERATIONS}) reached. Verification still failing.`);
281
+ }
282
+ }
321
283
  }
284
+ // Return last verification result (which failed)
285
+ return {
286
+ featureId,
287
+ status: 'error',
288
+ message: lastVerificationResult?.message ||
289
+ 'Verification failed after max iterations',
290
+ summary: lastRefineResult?.summary,
291
+ filesModified: lastRefineResult?.files_modified || [],
292
+ commitsCreated: lastRefineResult?.commits_created || 1,
293
+ iterations: currentIteration,
294
+ verificationResult: lastVerificationResult || undefined,
295
+ };
322
296
  }
323
297
  catch (error) {
324
298
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -334,6 +308,136 @@ Please ensure Claude Code commits all changes before completing the refine phase
334
308
  cleanupGit();
335
309
  }
336
310
  };
311
+ /**
312
+ * Execute a single refine iteration
313
+ */
314
+ async function executeRefineIteration(featureId, githubToken, config, pullRequestUrl, currentBranch, verificationFailureContext, verbose) {
315
+ // Fetch code refine context (PR reviews and comments)
316
+ const context = await fetchCodeRefineContext(featureId, githubToken, verbose, pullRequestUrl);
317
+ // Fetch additional feedbacks for code-refine phase
318
+ let feedbacksInfo;
319
+ try {
320
+ const feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'code_refine', currentBranch?.id);
321
+ if (feedbacksContext.feedbacks.length > 0) {
322
+ feedbacksInfo = await formatFeedbacksForContext(feedbacksContext);
323
+ if (verbose) {
324
+ logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to code refine context${currentBranch ? ` (including branch-specific for "${currentBranch.name}")` : ''}`);
325
+ }
326
+ }
327
+ }
328
+ catch (error) {
329
+ if (verbose) {
330
+ logInfo(`Note: Could not fetch feedbacks (${error instanceof Error ? error.message : String(error)})`);
331
+ }
332
+ }
333
+ // Create prompt for code refine
334
+ const systemPrompt = createSystemPrompt();
335
+ const refinePrompt = createCodeRefinePrompt(featureId, context, feedbacksInfo, verificationFailureContext);
336
+ let lastAssistantResponse = '';
337
+ let structuredRefineResult = null;
338
+ if (verbose) {
339
+ logInfo('Starting Claude Code query for code refine...');
340
+ }
341
+ // Use Claude Code SDK to refine the code
342
+ for await (const message of query({
343
+ prompt: prompt(refinePrompt),
344
+ options: {
345
+ systemPrompt: {
346
+ type: 'preset',
347
+ preset: 'claude_code',
348
+ append: systemPrompt,
349
+ },
350
+ model: config.claude.model || 'sonnet',
351
+ maxTurns: 2000,
352
+ permissionMode: 'bypassPermissions',
353
+ },
354
+ })) {
355
+ if (verbose) {
356
+ logInfo(`Received message type: ${message.type}`);
357
+ }
358
+ // Stream the code refine process
359
+ if (message.type === 'assistant' && message.message?.content) {
360
+ for (const content of message.message.content) {
361
+ if (content.type === 'text') {
362
+ lastAssistantResponse += content.text + '\n';
363
+ if (verbose) {
364
+ console.log(`\n🔧 ${content.text}`);
365
+ }
366
+ }
367
+ else if (content.type === 'tool_use') {
368
+ if (verbose) {
369
+ console.log(`\n🛠️ ${content.name}: ${content.input.description || 'Running...'}`);
370
+ }
371
+ }
372
+ }
373
+ }
374
+ else if (message.type === 'result') {
375
+ if (message.subtype === 'success') {
376
+ logInfo('\n🛠️ Code refine completed, parsing results...');
377
+ try {
378
+ const responseText = message.result || lastAssistantResponse;
379
+ let jsonResult = null;
380
+ const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
381
+ if (jsonBlockMatch) {
382
+ jsonResult = JSON.parse(jsonBlockMatch[1]);
383
+ }
384
+ else {
385
+ jsonResult = JSON.parse(responseText);
386
+ }
387
+ if (jsonResult && jsonResult.refine_result) {
388
+ structuredRefineResult = jsonResult.refine_result;
389
+ }
390
+ else {
391
+ throw new Error('Invalid JSON structure');
392
+ }
393
+ }
394
+ catch (error) {
395
+ logError(`Failed to parse structured refine result: ${error}`);
396
+ structuredRefineResult = parseCodeRefineResponse(message.result || lastAssistantResponse);
397
+ }
398
+ }
399
+ else {
400
+ logError(`\n⚠️ Code refine incomplete: ${message.subtype}`);
401
+ if (message.subtype === 'error_max_turns') {
402
+ logError('💡 Try simplifying the changes or reducing scope');
403
+ }
404
+ if (lastAssistantResponse) {
405
+ try {
406
+ const responseText = lastAssistantResponse;
407
+ let jsonResult = null;
408
+ const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
409
+ if (jsonBlockMatch) {
410
+ jsonResult = JSON.parse(jsonBlockMatch[1]);
411
+ if (jsonResult && jsonResult.refine_result) {
412
+ structuredRefineResult = jsonResult.refine_result;
413
+ }
414
+ }
415
+ else {
416
+ structuredRefineResult = parseCodeRefineResponse(lastAssistantResponse);
417
+ }
418
+ }
419
+ catch (error) {
420
+ logError(`Failed to parse assistant response: ${error}`);
421
+ }
422
+ }
423
+ }
424
+ }
425
+ }
426
+ if (structuredRefineResult) {
427
+ return {
428
+ status: 'success',
429
+ summary: structuredRefineResult.summary,
430
+ files_modified: structuredRefineResult.files_modified,
431
+ commits_created: structuredRefineResult.commits_created,
432
+ };
433
+ }
434
+ else {
435
+ return {
436
+ status: 'error',
437
+ message: 'Code refine failed or incomplete',
438
+ };
439
+ }
440
+ }
337
441
  function parseCodeRefineResponse(response) {
338
442
  const summaryMatch = response.match(/## Refine Summary\n([\s\S]*?)(?=\n##|\n\n|$)/);
339
443
  const summary = summaryMatch
@@ -8,7 +8,7 @@ import { Octokit } from '@octokit/rest';
8
8
  import { fetchCodeReviewContext, formatContextForPrompt, } from './context.js';
9
9
  import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services/feedbacks.js';
10
10
  import { preparePhaseGitEnvironment, prepareCustomBranchGitEnvironment, } from '../../utils/git-branch-manager.js';
11
- import { getReadyForReviewBranch, } from '../../services/branches.js';
11
+ import { getReadyForReviewBranch, updateBranch, } from '../../services/branches.js';
12
12
  import { getFeature } from '../../api/features/get-feature.js';
13
13
  function userMessage(content) {
14
14
  return {
@@ -319,6 +319,13 @@ export const reviewPullRequest = async (options, config) => {
319
319
  overall_assessment ||
320
320
  'Code review completed. No issues found.',
321
321
  });
322
+ // Update branch status to 'reviewed' for multi-branch features
323
+ if (currentBranch) {
324
+ await updateBranch(currentBranch.id, { status: 'reviewed' }, verbose);
325
+ if (verbose) {
326
+ logInfo(`✅ Branch "${currentBranch.name}" status updated to 'reviewed'`);
327
+ }
328
+ }
322
329
  return {
323
330
  featureId,
324
331
  status: 'success',
@@ -389,6 +396,13 @@ export const reviewPullRequest = async (options, config) => {
389
396
  body: (summary || overall_assessment || 'Code review completed.') +
390
397
  '\n\n**Note**: Some review comments could not be posted because they referenced lines not present in the diff.',
391
398
  });
399
+ // Update branch status to 'reviewed' for multi-branch features
400
+ if (currentBranch) {
401
+ await updateBranch(currentBranch.id, { status: 'reviewed' }, verbose);
402
+ if (verbose) {
403
+ logInfo(`✅ Branch "${currentBranch.name}" status updated to 'reviewed'`);
404
+ }
405
+ }
392
406
  return {
393
407
  featureId,
394
408
  status: 'success',
@@ -418,6 +432,13 @@ export const reviewPullRequest = async (options, config) => {
418
432
  logInfo(`Review ID: ${review.data.id}`);
419
433
  logInfo(`Comments posted: ${comments.length}`);
420
434
  }
435
+ // Update branch status to 'reviewed' for multi-branch features
436
+ if (currentBranch) {
437
+ await updateBranch(currentBranch.id, { status: 'reviewed' }, verbose);
438
+ if (verbose) {
439
+ logInfo(`✅ Branch "${currentBranch.name}" status updated to 'reviewed'`);
440
+ }
441
+ }
421
442
  return {
422
443
  featureId,
423
444
  status: 'success',
@@ -12,7 +12,7 @@ export interface Branch {
12
12
  base_branch_id: string | null;
13
13
  pull_request_url: string | null;
14
14
  pull_request_number: number | null;
15
- status: 'pending' | 'in_progress' | 'ready_for_review' | 'merged' | 'closed';
15
+ status: 'pending' | 'in_progress' | 'ready_for_review' | 'reviewed' | 'refined' | 'merged' | 'closed';
16
16
  created_at: string;
17
17
  updated_at: string;
18
18
  }
@@ -80,6 +80,11 @@ export declare function getBranchById(branchId: string, verbose?: boolean): Prom
80
80
  * Returns the first branch with status 'ready_for_review'
81
81
  */
82
82
  export declare function getReadyForReviewBranch(options: PipelinePhaseOptions): Promise<Branch | null>;
83
+ /**
84
+ * Get the branch that has been reviewed (for code-refine phase)
85
+ * Returns the first branch with status 'reviewed'
86
+ */
87
+ export declare function getReviewedBranch(options: PipelinePhaseOptions): Promise<Branch | null>;
83
88
  /**
84
89
  * Get the branch that is in progress (in_progress or ready_for_review)
85
90
  * Useful for phases that need to work on the current active branch
@@ -95,17 +95,28 @@ export function formatBranchesForContext(branches) {
95
95
  if (!branches || branches.length === 0) {
96
96
  return 'No branches defined yet.';
97
97
  }
98
+ const getStatusEmoji = (status) => {
99
+ switch (status) {
100
+ case 'merged':
101
+ return '✅';
102
+ case 'refined':
103
+ return '🎯';
104
+ case 'reviewed':
105
+ return '📝';
106
+ case 'ready_for_review':
107
+ return '👀';
108
+ case 'in_progress':
109
+ return '🔄';
110
+ case 'closed':
111
+ return '❌';
112
+ case 'pending':
113
+ default:
114
+ return '⏳';
115
+ }
116
+ };
98
117
  const branchList = branches
99
118
  .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
- : '⏳';
119
+ const statusEmoji = getStatusEmoji(b.status);
109
120
  return `${idx + 1}. **${b.name}** ${statusEmoji}
110
121
  - Status: ${b.status}
111
122
  - Branch: ${b.branch_name || 'Not created'}
@@ -211,6 +222,14 @@ export async function getReadyForReviewBranch(options) {
211
222
  const branches = await getBranches(options);
212
223
  return branches.find((b) => b.status === 'ready_for_review') || null;
213
224
  }
225
+ /**
226
+ * Get the branch that has been reviewed (for code-refine phase)
227
+ * Returns the first branch with status 'reviewed'
228
+ */
229
+ export async function getReviewedBranch(options) {
230
+ const branches = await getBranches(options);
231
+ return branches.find((b) => b.status === 'reviewed') || null;
232
+ }
214
233
  /**
215
234
  * Get the branch that is in progress (in_progress or ready_for_review)
216
235
  * Useful for phases that need to work on the current active branch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.19.9",
3
+ "version": "0.19.11",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"