edsger 0.4.8 → 0.4.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.
@@ -9,29 +9,76 @@ import { logInfo, logError } from '../../utils/logger.js';
9
9
  import { parsePullRequestUrl, fetchPRReviews, } from '../code-refine/context-fetcher.js';
10
10
  import { getFeature } from '../../api/features/get-feature.js';
11
11
  /**
12
- * Fetch PR file changes (diff information)
12
+ * Fetch complete file content from a specific ref (branch/commit)
13
+ */
14
+ async function fetchFileContent(octokit, owner, repo, ref, path, verbose) {
15
+ try {
16
+ const { data } = await octokit.repos.getContent({
17
+ owner,
18
+ repo,
19
+ ref,
20
+ path,
21
+ });
22
+ // Handle file content (not directory)
23
+ if ('content' in data && !Array.isArray(data)) {
24
+ // Content is base64 encoded
25
+ return Buffer.from(data.content, 'base64').toString('utf-8');
26
+ }
27
+ return undefined;
28
+ }
29
+ catch (error) {
30
+ if (verbose) {
31
+ logError(`Failed to fetch content for ${path} at ref ${ref}: ${error}`);
32
+ }
33
+ return undefined;
34
+ }
35
+ }
36
+ /**
37
+ * Fetch PR file changes (diff information and full content)
13
38
  */
14
39
  async function fetchPRFileChanges(octokit, owner, repo, prNumber, verbose) {
15
40
  try {
16
41
  if (verbose) {
17
- logInfo('📂 Fetching PR file changes...');
42
+ logInfo('📂 Fetching PR file changes and content...');
18
43
  }
44
+ // Get PR details to get the head ref
45
+ const { data: pr } = await octokit.pulls.get({
46
+ owner,
47
+ repo,
48
+ pull_number: prNumber,
49
+ });
50
+ const headRef = pr.head.sha;
51
+ // Get list of changed files
19
52
  const { data: files } = await octokit.pulls.listFiles({
20
53
  owner,
21
54
  repo,
22
55
  pull_number: prNumber,
23
56
  per_page: 100,
24
57
  });
25
- const fileChanges = files.map((file) => ({
26
- filename: file.filename,
27
- status: file.status,
28
- additions: file.additions,
29
- deletions: file.deletions,
30
- changes: file.changes,
31
- patch: file.patch,
58
+ if (verbose) {
59
+ logInfo(`✅ Found ${files.length} changed files`);
60
+ logInfo(`📥 Fetching full content for changed files from ${headRef.substring(0, 7)}...`);
61
+ }
62
+ // Fetch full content for each file in parallel
63
+ const fileChanges = await Promise.all(files.map(async (file) => {
64
+ let fullContent;
65
+ // Only fetch content for files that were not deleted
66
+ if (file.status !== 'removed') {
67
+ fullContent = await fetchFileContent(octokit, owner, repo, headRef, file.filename, verbose);
68
+ }
69
+ return {
70
+ filename: file.filename,
71
+ status: file.status,
72
+ additions: file.additions,
73
+ deletions: file.deletions,
74
+ changes: file.changes,
75
+ patch: file.patch,
76
+ fullContent,
77
+ };
32
78
  }));
33
79
  if (verbose) {
34
- logInfo(`✅ Found ${fileChanges.length} changed files`);
80
+ const filesWithContent = fileChanges.filter((f) => f.fullContent).length;
81
+ logInfo(`✅ Retrieved full content for ${filesWithContent}/${fileChanges.length} files`);
35
82
  }
36
83
  return fileChanges;
37
84
  }
@@ -221,6 +268,35 @@ function createThreadAnalysisPrompt(thread, fileChange, firstComment) {
221
268
  const allComments = thread.comments.nodes
222
269
  .map((c, idx) => `Comment ${idx + 1} by @${c.author.login}:\n${c.body}`)
223
270
  .join('\n\n');
271
+ // Build the code context section
272
+ let codeContext = '';
273
+ // Include diff (what changed)
274
+ if (fileChange.patch) {
275
+ codeContext += `**Code Changes (Diff):**
276
+ \`\`\`diff
277
+ ${fileChange.patch}
278
+ \`\`\`
279
+
280
+ `;
281
+ }
282
+ // Include full file content for better context
283
+ if (fileChange.fullContent) {
284
+ // Truncate very large files to avoid context limits
285
+ const maxLength = 10000;
286
+ const content = fileChange.fullContent.length > maxLength
287
+ ? fileChange.fullContent.substring(0, maxLength) +
288
+ '\n\n... (file truncated, showing first 10000 characters)'
289
+ : fileChange.fullContent;
290
+ codeContext += `**Complete File Content (After Changes):**
291
+ \`\`\`
292
+ ${content}
293
+ \`\`\`
294
+
295
+ `;
296
+ }
297
+ if (!codeContext) {
298
+ codeContext = '(No code information available)\n\n';
299
+ }
224
300
  return `You are analyzing whether a code review comment has been addressed by subsequent code changes.
225
301
 
226
302
  **Review Thread Information:**
@@ -231,18 +307,24 @@ function createThreadAnalysisPrompt(thread, fileChange, firstComment) {
231
307
  **Review Comments:**
232
308
  ${allComments}
233
309
 
234
- **Code Changes in This File:**
235
- \`\`\`diff
236
- ${fileChange.patch || '(No patch available)'}
237
- \`\`\`
310
+ ${codeContext}
238
311
 
239
312
  **Your Task:**
240
- Analyze whether the code changes adequately address the feedback in the review comments. Consider:
313
+ Analyze whether the code changes adequately address the feedback in the review comments. You have access to:
314
+ 1. **The diff** showing what was changed
315
+ 2. **The complete file content** after changes for full context
316
+
317
+ Consider:
241
318
  1. Does the feedback request a specific code change?
242
319
  2. Have those changes (or equivalent changes) been made?
243
- 3. If the feedback points to a specific line, have related areas of code been modified to address the concern?
320
+ 3. If the feedback points to a specific line, use the full file content to understand the broader context
321
+ 4. Check if related areas of code were modified to address the concern
322
+ 5. Use the complete file to verify the fix is properly integrated
244
323
 
245
- **Important:** The comment may point to a specific line, but the fix might be in nearby code. Focus on whether the **underlying issue** was addressed, not just whether that exact line was modified.
324
+ **Important:**
325
+ - The comment may point to a specific line, but the fix might be in nearby code
326
+ - Focus on whether the **underlying issue** was addressed, not just whether that exact line was modified
327
+ - Use the full file content to understand the complete context and verify the implementation
246
328
 
247
329
  Return your analysis in this JSON format:
248
330
  \`\`\`json
@@ -253,9 +335,10 @@ Return your analysis in this JSON format:
253
335
  \`\`\`
254
336
 
255
337
  Example responses:
256
- - If a comment says "add null check" and the diff shows a null check was added nearby: {"isAddressed": true, "reason": "Null check added in related code"}
257
- - If a comment suggests a refactor but no relevant changes are visible: {"isAddressed": false, "reason": "No refactoring changes visible in diff"}
338
+ - If a comment says "add null check" and the code shows a null check was added: {"isAddressed": true, "reason": "Null check added in the updated code"}
339
+ - If a comment suggests a refactor but no relevant changes are visible: {"isAddressed": false, "reason": "No refactoring changes visible in diff or file content"}
258
340
  - If code was modified in related areas addressing the concern: {"isAddressed": true, "reason": "Related code modified to address the concern"}
341
+ - If the full context shows the issue is resolved differently: {"isAddressed": true, "reason": "Issue resolved through alternative implementation visible in full file"}
259
342
  `;
260
343
  }
261
344
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {