patchrelay 0.35.12 → 0.35.13

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.
@@ -151,6 +151,67 @@ function appendLinearContext(lines, context) {
151
151
  lines.push("## Human Follow-up Comment", "", userComment, "");
152
152
  }
153
153
  }
154
+ function readReviewFixComments(context) {
155
+ const raw = context?.reviewComments;
156
+ if (!Array.isArray(raw)) {
157
+ return [];
158
+ }
159
+ const comments = [];
160
+ for (const entry of raw) {
161
+ if (!entry || typeof entry !== "object")
162
+ continue;
163
+ const record = entry;
164
+ const body = typeof record.body === "string" ? record.body.trim() : "";
165
+ if (!body)
166
+ continue;
167
+ comments.push({
168
+ body,
169
+ ...(typeof record.path === "string" ? { path: record.path } : {}),
170
+ ...(typeof record.line === "number" ? { line: record.line } : {}),
171
+ ...(typeof record.side === "string" ? { side: record.side } : {}),
172
+ ...(typeof record.startLine === "number" ? { startLine: record.startLine } : {}),
173
+ ...(typeof record.startSide === "string" ? { startSide: record.startSide } : {}),
174
+ ...(typeof record.url === "string" ? { url: record.url } : {}),
175
+ ...(typeof record.authorLogin === "string" ? { authorLogin: record.authorLogin } : {}),
176
+ });
177
+ }
178
+ return comments;
179
+ }
180
+ function appendStructuredReviewContext(lines, context) {
181
+ const reviewId = typeof context?.reviewId === "number" ? context.reviewId : undefined;
182
+ const reviewCommitId = typeof context?.reviewCommitId === "string" ? context.reviewCommitId : undefined;
183
+ const reviewUrl = typeof context?.reviewUrl === "string" ? context.reviewUrl : undefined;
184
+ const reviewComments = readReviewFixComments(context);
185
+ if (!reviewId && !reviewCommitId && !reviewUrl && reviewComments.length === 0) {
186
+ return;
187
+ }
188
+ lines.push("## Structured Review Context", "");
189
+ if (reviewId !== undefined) {
190
+ lines.push(`Review ID: ${reviewId}`);
191
+ }
192
+ if (reviewCommitId) {
193
+ lines.push(`Reviewed commit: ${reviewCommitId}`);
194
+ }
195
+ if (reviewUrl) {
196
+ lines.push(`Review URL: ${reviewUrl}`);
197
+ }
198
+ if (reviewComments.length === 0) {
199
+ lines.push("No inline review comments were captured for this review.", "");
200
+ return;
201
+ }
202
+ lines.push(`Inline review comments captured: ${reviewComments.length}`, "Resolve each comment below or verify it is already fixed on the current head before you stop.", "");
203
+ for (const comment of reviewComments) {
204
+ const location = comment.path
205
+ ? `${comment.path}${comment.line !== undefined ? `:${comment.line}` : ""}${comment.side ? ` (${comment.side})` : ""}`
206
+ : "general";
207
+ lines.push(`- ${location}`);
208
+ lines.push(comment.body);
209
+ if (comment.url) {
210
+ lines.push(` URL: ${comment.url}`);
211
+ }
212
+ }
213
+ lines.push("");
214
+ }
154
215
  function collectFollowUpInputs(context) {
155
216
  const followUps = Array.isArray(context?.followUps) ? context.followUps : [];
156
217
  const inputs = [];
@@ -330,7 +391,8 @@ export function buildInitialRunPrompt(issue, runType, repoPath, context) {
330
391
  break;
331
392
  }
332
393
  case "review_fix":
333
- lines.push("## Review Changes Requested", "", "A reviewer has requested changes on your PR. Address the feedback and push.", context?.reviewerName ? `Reviewer: ${String(context.reviewerName)}` : "", context?.reviewBody ? `\n## Review comment\n\n${String(context.reviewBody)}` : "", "", "Steps:", "1. Read the review feedback and PR comments (`gh pr view --comments`).", "2. Check the current diff (`git diff origin/main`) — a prior rebase may have already resolved some concerns (e.g., scope-bundling from stale commits).", "3. For each review point: if already resolved, note why. If not, fix it.", "4. Run verification, commit and push.", "5. If you believe all concerns are resolved, request a re-review: `gh pr edit <PR#> --add-reviewer <reviewer>`.", " Do NOT just post a comment saying \"resolved\" — the reviewer must re-review to dismiss the CHANGES_REQUESTED state.", "");
394
+ lines.push("## Review Changes Requested", "", "A reviewer has requested changes on your PR. Address the feedback and push.", context?.reviewerName ? `Reviewer: ${String(context.reviewerName)}` : "", context?.reviewBody ? `\n## Review comment\n\n${String(context.reviewBody)}` : "", "", "Steps:", "1. Start with the structured review context below. Treat the inline review comments as the primary repair checklist for this turn.", "2. Check the current diff (`git diff origin/main`) — a prior rebase may have already resolved some concerns (e.g., scope-bundling from stale commits).", "3. For each review point: if already resolved on the current head, note why. If not, fix it.", "4. If the structured review context looks incomplete, inspect the latest GitHub review threads directly before deciding you are done.", "5. Run verification, commit and push.", "6. If you believe all concerns are resolved, request a re-review: `gh pr edit <PR#> --add-reviewer <reviewer>`.", " Do NOT just post a comment saying \"resolved\" — the reviewer must re-review to dismiss the CHANGES_REQUESTED state.", "");
395
+ appendStructuredReviewContext(lines, context);
334
396
  break;
335
397
  case "queue_repair":
336
398
  appendQueueRepairContext(lines, context);
@@ -364,7 +426,8 @@ export function buildFollowUpRunPrompt(issue, runType, repoPath, context) {
364
426
  break;
365
427
  }
366
428
  case "review_fix":
367
- lines.push("## Review Changes Requested", "", "A reviewer has requested changes on your PR. Address the feedback and push.", context?.reviewerName ? `Reviewer: ${String(context.reviewerName)}` : "", context?.reviewBody ? `\n## Review comment\n\n${String(context.reviewBody)}` : "", "", "Steps:", "1. Read the review feedback and PR comments (`gh pr view --comments`).", "2. Check the current diff (`git diff origin/main`) — a prior rebase may have already resolved some concerns (e.g., scope-bundling from stale commits).", "3. For each review point: if already resolved, note why. If not, fix it.", "4. Run verification, commit and push.", "5. If you believe all concerns are resolved, request a re-review: `gh pr edit <PR#> --add-reviewer <reviewer>`.", " Do NOT just post a comment saying \"resolved\" — the reviewer must re-review to dismiss the CHANGES_REQUESTED state.", "");
429
+ lines.push("## Review Changes Requested", "", "A reviewer has requested changes on your PR. Address the feedback and push.", context?.reviewerName ? `Reviewer: ${String(context.reviewerName)}` : "", context?.reviewBody ? `\n## Review comment\n\n${String(context.reviewBody)}` : "", "", "Steps:", "1. Start with the structured review context below. Treat the inline review comments as the primary repair checklist for this turn.", "2. Check the current diff (`git diff origin/main`) — a prior rebase may have already resolved some concerns (e.g., scope-bundling from stale commits).", "3. For each review point: if already resolved on the current head, note why. If not, fix it.", "4. If the structured review context looks incomplete, inspect the latest GitHub review threads directly before deciding you are done.", "5. Run verification, commit and push.", "6. If you believe all concerns are resolved, request a re-review: `gh pr edit <PR#> --add-reviewer <reviewer>`.", " Do NOT just post a comment saying \"resolved\" — the reviewer must re-review to dismiss the CHANGES_REQUESTED state.", "");
430
+ appendStructuredReviewContext(lines, context);
368
431
  break;
369
432
  case "queue_repair":
370
433
  appendQueueRepairContext(lines, context);
@@ -401,6 +464,9 @@ function shouldCompactThread(issue, threadGeneration, context) {
401
464
  && (threadGeneration ?? 0) >= MAX_THREAD_GENERATION_BEFORE_COMPACTION
402
465
  && followUpCount >= MAX_FOLLOW_UPS_BEFORE_COMPACTION;
403
466
  }
467
+ export function shouldReuseIssueThread(params) {
468
+ return Boolean(params.existingThreadId) && !params.compactThread && params.resumeThread;
469
+ }
404
470
  function isBranchUpkeepRequired(context) {
405
471
  return context?.branchUpkeepRequired === true;
406
472
  }
@@ -663,15 +729,17 @@ export class RunOrchestrator {
663
729
  throw new Error(`prepare-worktree hook failed (exit ${prepareResult.exitCode}): ${prepareResult.stderr?.slice(0, 500) ?? ""}`);
664
730
  }
665
731
  this.assertLaunchLease(run, "before starting the Codex turn");
666
- // Reuse the existing thread when the wake source is an additive follow-up
667
- // or when review-fix work benefits from carrying reviewer context forward.
668
- // If the thread has accumulated many resumptions and batched follow-ups,
669
- // compact by starting a fresh main thread while keeping a parent link.
732
+ // Reuse the existing thread only for additive follow-ups that explicitly
733
+ // request continuity. Fresh review-fix runs now start a new thread so the
734
+ // model is not anchored to the implementation conversation that produced
735
+ // the rejected patch. If the thread has accumulated many resumptions and
736
+ // batched follow-ups, compact by starting a fresh main thread while
737
+ // keeping a parent link.
670
738
  const compactThread = shouldCompactThread(issue, issueSession?.threadGeneration, effectiveContext);
671
739
  if (compactThread && issue.threadId) {
672
740
  parentThreadId = issue.threadId;
673
741
  }
674
- if (issue.threadId && !compactThread && (resumeThread || runType === "review_fix")) {
742
+ if (shouldReuseIssueThread({ existingThreadId: issue.threadId, compactThread, resumeThread })) {
675
743
  threadId = issue.threadId;
676
744
  }
677
745
  else {
@@ -38,7 +38,7 @@ export function deriveIssueStatusNote(params) {
38
38
  break;
39
39
  case "failed":
40
40
  case "escalated":
41
- note = latestRunNote ?? latestEventNote ?? failureSummary ?? sessionSummary;
41
+ note = latestEventNote ?? failureSummary ?? latestRunNote ?? sessionSummary;
42
42
  break;
43
43
  case "repairing_ci":
44
44
  case "repairing_queue":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchrelay",
3
- "version": "0.35.12",
3
+ "version": "0.35.13",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -25,7 +25,8 @@
25
25
  "node": ">=24.0.0"
26
26
  },
27
27
  "workspaces": [
28
- "packages/merge-steward"
28
+ "packages/merge-steward",
29
+ "packages/review-quill"
29
30
  ],
30
31
  "scripts": {
31
32
  "dev": "node --watch --experimental-transform-types src/index.ts",