pr-shepherd 0.5.2 → 0.6.0
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.
package/bin/commands/check.mjs
CHANGED
|
@@ -85,7 +85,7 @@ export async function runCheck(opts) {
|
|
|
85
85
|
!verdict.anyInProgress &&
|
|
86
86
|
verdict.filteredNames.length > 0;
|
|
87
87
|
// Compute overall status.
|
|
88
|
-
const status = computeStatus(verdict, actionableThreads.length, actionableComments.length, mergeStatus
|
|
88
|
+
const status = computeStatus(verdict, actionableThreads.length, actionableComments.length, mergeStatus, batchData.changesRequestedReviews.length);
|
|
89
89
|
return {
|
|
90
90
|
pr: prNumber,
|
|
91
91
|
repo: `${repo.owner}/${repo.name}`,
|
|
@@ -117,7 +117,7 @@ export async function runCheck(opts) {
|
|
|
117
117
|
// ---------------------------------------------------------------------------
|
|
118
118
|
function computeStatus(verdict, unresolvedThreads, unresolvedComments, mergeStatus, changesRequestedReviews) {
|
|
119
119
|
// Merge conflicts are always terminal regardless of CI state.
|
|
120
|
-
if (mergeStatus === "CONFLICTS")
|
|
120
|
+
if (mergeStatus.status === "CONFLICTS")
|
|
121
121
|
return "FAILING";
|
|
122
122
|
// Check CI state before merge-blocking states: BLOCKED/UNSTABLE/BEHIND are
|
|
123
123
|
// often caused by CI not having passed yet, so they shouldn't mask IN_PROGRESS.
|
|
@@ -125,16 +125,29 @@ function computeStatus(verdict, unresolvedThreads, unresolvedComments, mergeStat
|
|
|
125
125
|
return "FAILING";
|
|
126
126
|
if (verdict.anyInProgress)
|
|
127
127
|
return "IN_PROGRESS";
|
|
128
|
-
|
|
128
|
+
// BLOCKED solely because a human reviewer hasn't approved yet — shepherd is done, hand off.
|
|
129
|
+
// copilotReviewInProgress means a bot still owes a review, which is not this case.
|
|
130
|
+
if (verdict.allPassed &&
|
|
131
|
+
unresolvedThreads === 0 &&
|
|
132
|
+
unresolvedComments === 0 &&
|
|
133
|
+
changesRequestedReviews === 0 &&
|
|
134
|
+
mergeStatus.status === "BLOCKED" &&
|
|
135
|
+
!mergeStatus.copilotReviewInProgress &&
|
|
136
|
+
mergeStatus.reviewDecision === "REVIEW_REQUIRED") {
|
|
137
|
+
return "READY";
|
|
138
|
+
}
|
|
139
|
+
if (mergeStatus.status === "BLOCKED" ||
|
|
140
|
+
mergeStatus.status === "UNSTABLE" ||
|
|
141
|
+
mergeStatus.status === "BEHIND")
|
|
129
142
|
return "FAILING";
|
|
130
|
-
if (mergeStatus === "UNKNOWN")
|
|
143
|
+
if (mergeStatus.status === "UNKNOWN")
|
|
131
144
|
return "UNKNOWN";
|
|
132
145
|
if (changesRequestedReviews > 0)
|
|
133
146
|
return "UNRESOLVED_COMMENTS";
|
|
134
147
|
if (unresolvedThreads > 0 || unresolvedComments > 0)
|
|
135
148
|
return "UNRESOLVED_COMMENTS";
|
|
136
149
|
// DRAFT is treated the same as CLEAN for readiness — marking the PR ready resolves it.
|
|
137
|
-
if ((mergeStatus === "CLEAN" || mergeStatus === "DRAFT") && verdict.allPassed)
|
|
150
|
+
if ((mergeStatus.status === "CLEAN" || mergeStatus.status === "DRAFT") && verdict.allPassed)
|
|
138
151
|
return "READY";
|
|
139
152
|
return "UNKNOWN";
|
|
140
153
|
}
|
package/bin/commands/resolve.mjs
CHANGED
|
@@ -40,7 +40,7 @@ export async function runResolveFetch(opts) {
|
|
|
40
40
|
}
|
|
41
41
|
const activeThreads = unresolvedThreads.filter((t) => !t.isOutdated);
|
|
42
42
|
return {
|
|
43
|
-
actionableThreads: activeThreads.map(({ isResolved, isOutdated, ...rest }) => rest),
|
|
43
|
+
actionableThreads: activeThreads.map(({ isResolved: _r, isOutdated: _o, ...rest }) => rest),
|
|
44
44
|
actionableComments: visibleComments,
|
|
45
45
|
changesRequestedReviews: data.changesRequestedReviews,
|
|
46
46
|
};
|
package/package.json
CHANGED
|
@@ -39,6 +39,14 @@ Invoke `/loop <INTERVAL> --max-turns 50 --expires 8h` via the Skill tool. Use th
|
|
|
39
39
|
|
|
40
40
|
````
|
|
41
41
|
# pr-shepherd-loop:pr=<PR_NUMBER>
|
|
42
|
+
|
|
43
|
+
**IMPORTANT — recurrence rules for this session:**
|
|
44
|
+
- **Do NOT call `ScheduleWakeup`.** This session was fired by a recurring cron job. Calling `ScheduleWakeup` (with a `/loop` prompt) would create a duplicate cron job, leading to concurrent git operations and `.git/index.lock` collisions.
|
|
45
|
+
- **Do NOT invoke `/loop`.** Same reason — `/loop` with an interval calls `CronCreate`, which creates a second recurrent runner.
|
|
46
|
+
- After completing the actions below, end the turn cleanly. The cron job handles the next fire automatically.
|
|
47
|
+
|
|
48
|
+
**Self-dedup:** Run `CronList`. If more than one job has a prompt containing `# pr-shepherd-loop:pr=<PR_NUMBER>`, duplicate runners exist. Keep the job with the lowest job ID and `CronDelete` the rest (ignore errors if a job is already gone — another concurrent runner may have deleted it first), then continue this iteration.
|
|
49
|
+
|
|
42
50
|
Run the following in a single Bash invocation:
|
|
43
51
|
npx pr-shepherd iterate <PR_NUMBER> --ready-delay <READY_DELAY> --no-cache --last-push-time "$(git log -1 --format=%ct HEAD)" --format=json
|
|
44
52
|
|