edsger 0.19.7 → 0.19.9

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.
@@ -87,8 +87,12 @@ export declare function fetchUserStories(featureId: string, verbose?: boolean):
87
87
  export declare function fetchTestCases(featureId: string, verbose?: boolean): Promise<any[]>;
88
88
  /**
89
89
  * Fetch complete code refine context
90
+ * @param featureId - The feature ID
91
+ * @param githubToken - GitHub token for API access
92
+ * @param verbose - Enable verbose logging
93
+ * @param pullRequestUrl - Optional PR URL (for multi-branch features, use branch's PR URL)
90
94
  */
91
- export declare function fetchCodeRefineContext(featureId: string, githubToken: string, verbose?: boolean): Promise<CodeRefineContext>;
95
+ export declare function fetchCodeRefineContext(featureId: string, githubToken: string, verbose?: boolean, pullRequestUrl?: string): Promise<CodeRefineContext>;
92
96
  /**
93
97
  * Format code refine context for prompt
94
98
  */
@@ -304,17 +304,23 @@ async function processGitHubContentImages(reviews, reviewThreads, featureId, ver
304
304
  }
305
305
  /**
306
306
  * Fetch complete code refine context
307
+ * @param featureId - The feature ID
308
+ * @param githubToken - GitHub token for API access
309
+ * @param verbose - Enable verbose logging
310
+ * @param pullRequestUrl - Optional PR URL (for multi-branch features, use branch's PR URL)
307
311
  */
308
- export async function fetchCodeRefineContext(featureId, githubToken, verbose) {
312
+ export async function fetchCodeRefineContext(featureId, githubToken, verbose, pullRequestUrl) {
309
313
  // Fetch feature info using shared API
310
314
  const feature = await getFeature(featureId, verbose);
311
- if (!feature.pull_request_url) {
315
+ // Use provided PR URL (from branch) or fall back to feature's PR URL
316
+ const prUrl = pullRequestUrl || feature.pull_request_url;
317
+ if (!prUrl) {
312
318
  throw new Error(`Feature ${featureId} does not have a pull request URL. Cannot perform code refine.`);
313
319
  }
314
320
  // Parse PR URL
315
- const prInfo = parsePullRequestUrl(feature.pull_request_url);
321
+ const prInfo = parsePullRequestUrl(prUrl);
316
322
  if (!prInfo) {
317
- throw new Error(`Invalid pull request URL: ${feature.pull_request_url}. Expected format: https://github.com/owner/repo/pull/123`);
323
+ throw new Error(`Invalid pull request URL: ${prUrl}. Expected format: https://github.com/owner/repo/pull/123`);
318
324
  }
319
325
  const { owner, repo, prNumber } = prInfo;
320
326
  // Initialize Octokit with GitHub token
@@ -338,7 +344,7 @@ export async function fetchCodeRefineContext(featureId, githubToken, verbose) {
338
344
  featureId,
339
345
  featureName: feature.name,
340
346
  featureDescription: feature.description ?? null,
341
- pullRequestUrl: feature.pull_request_url,
347
+ pullRequestUrl: prUrl,
342
348
  pullRequestNumber: prNumber,
343
349
  owner,
344
350
  repo,
@@ -10,7 +10,7 @@ import { getFeedbacksForPhase, formatFeedbacksForContext, } from '../../services
10
10
  import { createSystemPrompt, createCodeRefinePrompt } from './prompts.js';
11
11
  import { preparePhaseGitEnvironment, prepareCustomBranchGitEnvironment, hasUncommittedChanges, getUncommittedFiles, syncFeatBranchWithMain, } from '../../utils/git-branch-manager.js';
12
12
  import { getFeature } from '../../api/features/get-feature.js';
13
- import { getReadyForReviewBranch } from '../../services/branches.js';
13
+ import { getReadyForReviewBranch, } from '../../services/branches.js';
14
14
  import { parsePullRequestUrl } from './context.js';
15
15
  function userMessage(content) {
16
16
  return {
@@ -88,22 +88,41 @@ export const refineCodeFromPRFeedback = async (options, config) => {
88
88
  logInfo(`Note: Could not fetch feature branches, using default branch`);
89
89
  }
90
90
  }
91
+ // Get PR URL from branch (for multi-branch features) or feature
92
+ let pullRequestUrl = null;
93
+ if (currentBranch && currentBranch.pull_request_url) {
94
+ pullRequestUrl = currentBranch.pull_request_url;
95
+ if (verbose) {
96
+ logInfo(`📝 Using PR URL from branch: ${pullRequestUrl}`);
97
+ }
98
+ }
99
+ else {
100
+ // Fall back to feature's PR URL for single-branch features
101
+ try {
102
+ const feature = await getFeature(featureId, verbose);
103
+ pullRequestUrl = feature.pull_request_url || null;
104
+ }
105
+ catch (error) {
106
+ if (verbose) {
107
+ logInfo(`Note: Could not fetch feature PR URL`);
108
+ }
109
+ }
110
+ }
91
111
  // Sync feat branch with main before preparing git environment
92
112
  // This prevents extra commits from appearing in PR when dev branch is rebased
93
- try {
94
- const feature = await getFeature(featureId, verbose);
95
- if (feature.pull_request_url) {
96
- const prInfo = parsePullRequestUrl(feature.pull_request_url);
113
+ if (pullRequestUrl) {
114
+ try {
115
+ const prInfo = parsePullRequestUrl(pullRequestUrl);
97
116
  if (prInfo) {
98
117
  await syncFeatBranchWithMain(featureId, githubToken, prInfo.owner, prInfo.repo, 'main', verbose);
99
118
  }
100
119
  }
101
- }
102
- catch (error) {
103
- if (verbose) {
104
- logInfo(`⚠️ Could not sync feat branch: ${error instanceof Error ? error.message : String(error)}`);
120
+ catch (error) {
121
+ if (verbose) {
122
+ logInfo(`⚠️ Could not sync feat branch: ${error instanceof Error ? error.message : String(error)}`);
123
+ }
124
+ // Continue even if sync fails - it's not critical
105
125
  }
106
- // Continue even if sync fails - it's not critical
107
126
  }
108
127
  // Prepare git environment: switch to the appropriate branch
109
128
  const cleanupGit = currentBranch
@@ -114,7 +133,7 @@ export const refineCodeFromPRFeedback = async (options, config) => {
114
133
  if (verbose) {
115
134
  logInfo('Fetching code refine context from GitHub PR...');
116
135
  }
117
- const context = await fetchCodeRefineContext(featureId, githubToken, verbose);
136
+ const context = await fetchCodeRefineContext(featureId, githubToken, verbose, pullRequestUrl || undefined);
118
137
  // Check if there are any reviews or comments to address
119
138
  if (context.reviews.length === 0 && context.reviewComments.length === 0) {
120
139
  if (verbose) {
@@ -131,13 +150,15 @@ export const refineCodeFromPRFeedback = async (options, config) => {
131
150
  logInfo(`📋 Found ${context.reviews.length} reviews and ${context.reviewComments.length} comments to address`);
132
151
  }
133
152
  // Fetch additional feedbacks for code-refine phase
153
+ // For multi-branch features, filter by the current branch to get branch-specific feedbacks
134
154
  let feedbacksInfo;
135
155
  try {
136
- const feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'code_refine');
156
+ const feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'code_refine', currentBranch?.id // Pass branch_id if we have a current branch
157
+ );
137
158
  if (feedbacksContext.feedbacks.length > 0) {
138
159
  feedbacksInfo = await formatFeedbacksForContext(feedbacksContext);
139
160
  if (verbose) {
140
- logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to code refine context`);
161
+ logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to code refine context${currentBranch ? ` (including branch-specific for "${currentBranch.name}")` : ''}`);
141
162
  }
142
163
  }
143
164
  }
@@ -7,6 +7,7 @@ import { Octokit } from '@octokit/rest';
7
7
  import { logInfo, logError } from '../../utils/logger.js';
8
8
  import { parsePullRequestUrl, fetchPRReviews } from '../code-refine/context.js';
9
9
  import { getFeature } from '../../api/features/get-feature.js';
10
+ import { getReadyForReviewBranch, } from '../../services/branches.js';
10
11
  import { fetchPRFileChanges, fetchUnresolvedReviewThreads, resolveReviewThreads, dismissReviews, } from './github.js';
11
12
  import { analyzeAllThreads } from './llm-analyzer.js';
12
13
  // Re-export types for backward compatibility
@@ -20,15 +21,39 @@ export async function verifyAndResolveComments(options) {
20
21
  logInfo(`Starting code refine verification for feature ID: ${featureId}`);
21
22
  }
22
23
  try {
23
- // Fetch feature info using shared API
24
- const feature = await getFeature(featureId, verbose);
25
- if (!feature.pull_request_url) {
24
+ // For multi-branch features, find the branch that is ready for review
25
+ let currentBranch = null;
26
+ try {
27
+ currentBranch = await getReadyForReviewBranch({ featureId, verbose });
28
+ if (currentBranch && verbose) {
29
+ logInfo(`📋 Found ready_for_review branch: ${currentBranch.name}`);
30
+ }
31
+ }
32
+ catch (error) {
33
+ if (verbose) {
34
+ logInfo(`Note: Could not fetch feature branches`);
35
+ }
36
+ }
37
+ // Get PR URL from branch (for multi-branch features) or feature
38
+ let pullRequestUrl = null;
39
+ if (currentBranch && currentBranch.pull_request_url) {
40
+ pullRequestUrl = currentBranch.pull_request_url;
41
+ if (verbose) {
42
+ logInfo(`📝 Using PR URL from branch: ${pullRequestUrl}`);
43
+ }
44
+ }
45
+ else {
46
+ // Fall back to feature's PR URL for single-branch features
47
+ const feature = await getFeature(featureId, verbose);
48
+ pullRequestUrl = feature.pull_request_url || null;
49
+ }
50
+ if (!pullRequestUrl) {
26
51
  throw new Error(`Feature ${featureId} does not have a pull request URL. Cannot perform verification.`);
27
52
  }
28
53
  // Parse PR URL
29
- const prInfo = parsePullRequestUrl(feature.pull_request_url);
54
+ const prInfo = parsePullRequestUrl(pullRequestUrl);
30
55
  if (!prInfo) {
31
- throw new Error(`Invalid pull request URL: ${feature.pull_request_url}. Expected format: https://github.com/owner/repo/pull/123`);
56
+ throw new Error(`Invalid pull request URL: ${pullRequestUrl}. Expected format: https://github.com/owner/repo/pull/123`);
32
57
  }
33
58
  const { owner, repo, prNumber } = prInfo;
34
59
  // Initialize Octokit with GitHub token (supports both REST and GraphQL)
@@ -84,8 +84,12 @@ export declare function fetchUserStories(featureId: string, verbose?: boolean):
84
84
  export declare function fetchTestCases(featureId: string, verbose?: boolean): Promise<any[]>;
85
85
  /**
86
86
  * Fetch complete code review context
87
+ * @param featureId - The feature ID
88
+ * @param githubToken - GitHub token for API access
89
+ * @param verbose - Enable verbose logging
90
+ * @param pullRequestUrl - Optional PR URL (for multi-branch features, use branch's PR URL)
87
91
  */
88
- export declare function fetchCodeReviewContext(featureId: string, githubToken: string, verbose?: boolean): Promise<CodeReviewContext>;
92
+ export declare function fetchCodeReviewContext(featureId: string, githubToken: string, verbose?: boolean, pullRequestUrl?: string): Promise<CodeReviewContext>;
89
93
  /**
90
94
  * Format code review context for prompt
91
95
  */
@@ -167,17 +167,23 @@ export async function fetchTestCases(featureId, verbose) {
167
167
  }
168
168
  /**
169
169
  * Fetch complete code review context
170
+ * @param featureId - The feature ID
171
+ * @param githubToken - GitHub token for API access
172
+ * @param verbose - Enable verbose logging
173
+ * @param pullRequestUrl - Optional PR URL (for multi-branch features, use branch's PR URL)
170
174
  */
171
- export async function fetchCodeReviewContext(featureId, githubToken, verbose) {
175
+ export async function fetchCodeReviewContext(featureId, githubToken, verbose, pullRequestUrl) {
172
176
  // Fetch feature info using shared API
173
177
  const feature = await getFeature(featureId, verbose);
174
- if (!feature.pull_request_url) {
178
+ // Use provided PR URL (from branch) or fall back to feature's PR URL
179
+ const prUrl = pullRequestUrl || feature.pull_request_url;
180
+ if (!prUrl) {
175
181
  throw new Error(`Feature ${featureId} does not have a pull request URL. Cannot perform code review.`);
176
182
  }
177
183
  // Parse PR URL
178
- const prInfo = parsePullRequestUrl(feature.pull_request_url);
184
+ const prInfo = parsePullRequestUrl(prUrl);
179
185
  if (!prInfo) {
180
- throw new Error(`Invalid pull request URL: ${feature.pull_request_url}. Expected format: https://github.com/owner/repo/pull/123`);
186
+ throw new Error(`Invalid pull request URL: ${prUrl}. Expected format: https://github.com/owner/repo/pull/123`);
181
187
  }
182
188
  const { owner, repo, prNumber } = prInfo;
183
189
  // Initialize Octokit with GitHub token
@@ -199,7 +205,7 @@ export async function fetchCodeReviewContext(featureId, githubToken, verbose) {
199
205
  featureId,
200
206
  featureName: feature.name,
201
207
  featureDescription: feature.description ?? null,
202
- pullRequestUrl: feature.pull_request_url,
208
+ pullRequestUrl: prUrl,
203
209
  pullRequestNumber: prNumber,
204
210
  owner,
205
211
  repo,
@@ -8,7 +8,8 @@ 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, } from '../../services/branches.js';
12
+ import { getFeature } from '../../api/features/get-feature.js';
12
13
  function userMessage(content) {
13
14
  return {
14
15
  type: 'user',
@@ -144,6 +145,26 @@ export const reviewPullRequest = async (options, config) => {
144
145
  logInfo(`Note: Could not fetch feature branches, using default branch`);
145
146
  }
146
147
  }
148
+ // Get PR URL from branch (for multi-branch features) or feature
149
+ let pullRequestUrl = null;
150
+ if (currentBranch && currentBranch.pull_request_url) {
151
+ pullRequestUrl = currentBranch.pull_request_url;
152
+ if (verbose) {
153
+ logInfo(`📝 Using PR URL from branch: ${pullRequestUrl}`);
154
+ }
155
+ }
156
+ else {
157
+ // Fall back to feature's PR URL for single-branch features
158
+ try {
159
+ const feature = await getFeature(featureId, verbose);
160
+ pullRequestUrl = feature.pull_request_url || null;
161
+ }
162
+ catch (error) {
163
+ if (verbose) {
164
+ logInfo(`Note: Could not fetch feature PR URL`);
165
+ }
166
+ }
167
+ }
147
168
  // Prepare git environment: switch to the appropriate branch
148
169
  const cleanupGit = currentBranch
149
170
  ? prepareCustomBranchGitEnvironment(branchName, 'main', verbose)
@@ -153,7 +174,7 @@ export const reviewPullRequest = async (options, config) => {
153
174
  if (verbose) {
154
175
  logInfo('Fetching code review context from GitHub PR...');
155
176
  }
156
- const context = await fetchCodeReviewContext(featureId, githubToken, verbose);
177
+ const context = await fetchCodeReviewContext(featureId, githubToken, verbose, pullRequestUrl || undefined);
157
178
  // Check if there are any files to review
158
179
  if (context.files.length === 0) {
159
180
  if (verbose) {
@@ -170,13 +191,15 @@ export const reviewPullRequest = async (options, config) => {
170
191
  logInfo(`📋 Found ${context.files.length} files to review across ${context.commits.length} commits`);
171
192
  }
172
193
  // Fetch additional feedbacks for code-review phase
194
+ // For multi-branch features, filter by the current branch to get branch-specific feedbacks
173
195
  let feedbacksInfo;
174
196
  try {
175
- const feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'code_review');
197
+ const feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'code_review', currentBranch?.id // Pass branch_id if we have a current branch
198
+ );
176
199
  if (feedbacksContext.feedbacks.length > 0) {
177
200
  feedbacksInfo = await formatFeedbacksForContext(feedbacksContext);
178
201
  if (verbose) {
179
- logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to code review context`);
202
+ logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to code review context${currentBranch ? ` (including branch-specific for "${currentBranch.name}")` : ''}`);
180
203
  }
181
204
  }
182
205
  }
@@ -7,7 +7,7 @@ import { fetchFunctionalTestingContext, formatContextForPrompt, } from './contex
7
7
  import { updateFeatureStatus } from '../../api/features/index.js';
8
8
  import { createTestReport, } from './test-report-creator.js';
9
9
  import { preparePhaseGitEnvironment, prepareCustomBranchGitEnvironment, } from '../../utils/git-branch-manager.js';
10
- import { getReadyForReviewBranch } from '../../services/branches.js';
10
+ import { getReadyForReviewBranch, } from '../../services/branches.js';
11
11
  function userMessage(content) {
12
12
  return {
13
13
  type: 'user',
@@ -57,13 +57,15 @@ export const runFunctionalTesting = async (options, config, checklistContext) =>
57
57
  }
58
58
  const context = await fetchFunctionalTestingContext(featureId, verbose);
59
59
  // Fetch feedbacks for functional testing phase
60
+ // For multi-branch features, include branch-specific feedbacks
60
61
  let feedbacksInfo;
61
62
  try {
62
- const feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'functional_testing');
63
+ const feedbacksContext = await getFeedbacksForPhase({ featureId, verbose }, 'functional_testing', currentBranch?.id // Pass branch_id if we have a current branch
64
+ );
63
65
  if (feedbacksContext.feedbacks.length > 0) {
64
66
  feedbacksInfo = await formatFeedbacksForContext(feedbacksContext);
65
67
  if (verbose) {
66
- logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to testing context`);
68
+ logInfo(`Added ${feedbacksContext.feedbacks.length} human feedbacks to testing context${currentBranch ? ` (including branch-specific for "${currentBranch.name}")` : ''}`);
67
69
  }
68
70
  }
69
71
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.19.7",
3
+ "version": "0.19.9",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"