pr-shepherd 0.49.0 → 0.51.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/.claude-plugin/plugin.json +1 -1
- package/README.md +13 -6
- package/bin/cli/help-command-pages.d.mts +8 -8
- package/bin/cli/help-command-pages.mjs +8 -8
- package/bin/cli/help.d.mts +8 -8
- package/bin/cli/iterate-instructions.mjs +9 -2
- package/bin/cli/iterate-lean.mjs +11 -0
- package/bin/cli/poll-summary-emitter.mjs +15 -0
- package/bin/cli/poll-summary-formatter.mjs +10 -24
- package/bin/cli-parser.mjs +3 -0
- package/bin/commands/iterate/check-instructions.d.mts +2 -8
- package/bin/commands/iterate/check-instructions.mjs +2 -11
- package/bin/commands/iterate/escalate.mjs +30 -2
- package/bin/commands/iterate/fix-code.mjs +62 -20
- package/bin/commands/iterate/render.mjs +1 -1
- package/bin/commands/iterate/stall.mjs +30 -0
- package/bin/commands/iterate/thread-mutation-routing.d.mts +0 -2
- package/bin/commands/iterate/thread-mutation-routing.mjs +1 -2
- package/bin/commands/poll-quota.d.mts +2 -1
- package/bin/commands/poll-quota.mjs +12 -0
- package/bin/commands/poll-summary-explicit-instructions.d.mts +2 -0
- package/bin/commands/poll-summary-explicit-instructions.mjs +22 -0
- package/bin/commands/poll-summary-instructions.d.mts +3 -0
- package/bin/commands/poll-summary-instructions.mjs +139 -0
- package/bin/commands/poll-summary-signature.d.mts +2 -0
- package/bin/commands/poll-summary-signature.mjs +16 -0
- package/bin/commands/poll-summary.mjs +25 -39
- package/bin/commands/resolve-mutate.mjs +22 -68
- package/bin/comments/resolve.d.mts +5 -0
- package/bin/comments/resolve.mjs +2 -11
- package/bin/github/gql/poll-summary-fragment.gql +1 -0
- package/bin/github/poll-summary-projector.mjs +2 -1
- package/bin/github/poll-summary-raw.d.mts +1 -0
- package/bin/github/poll-summary-route.mjs +4 -1
- package/bin/github/poll-summary.d.mts +2 -1
- package/bin/github/poll-summary.mjs +19 -0
- package/bin/state/fix-attempts.d.mts +3 -4
- package/bin/state/fix-attempts.mjs +2 -3
- package/bin/types/escalate.d.mts +10 -0
- package/bin/types/poll-summary.d.mts +14 -0
- package/package.json +1 -1
- package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
- package/plugins/pr-shepherd/.codex.mcp.json +1 -1
- package/plugins/pr-shepherd/.mcp.json +1 -1
- package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +6 -11
- package/plugins/pr-shepherd/skills/reduce-pr-noise/SKILL.md +17 -0
- package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +24 -0
- package/plugins/pr-shepherd/skills/reduce-pr-noise/references/settings.md +27 -0
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ Conversations Resolved: No [Not Required]
|
|
|
72
72
|
2. Apply every warranted review fix in each file referenced above.
|
|
73
73
|
3. Triage every failure under `## Failing checks`. See "CI failure triage" in the pr-shepherd skill for read-only inspection rules.
|
|
74
74
|
4. If you changed code, commit any remaining changes and push to the PR head branch, then run review mutations using the pushed commit SHA and iterate immediately with the same options. If you did not change code, do not commit and continue.
|
|
75
|
-
5.
|
|
75
|
+
5. Substitute any command placeholders and run the generated review mutations.
|
|
76
76
|
6. If you did not change code, replace `$HEAD_SHA` with `$(git rev-parse HEAD)`, which must equal the current remote PR head. If you changed code, commit and push to the PR head branch first, then replace `$HEAD_SHA` with the pushed commit SHA.
|
|
77
77
|
7. Replace `$DISMISS_MESSAGE` with one sentence describing what changed.
|
|
78
78
|
8. Run the `apply review:` command shown above. See "Review-mutation mechanics" in the pr-shepherd skill for dismiss-ID retention.
|
|
@@ -92,7 +92,7 @@ This system is opinionated and works best with PRs that use required status chec
|
|
|
92
92
|
- Draft PRs can be marked ready automatically when clean; disable with `actions.autoMarkReady: false` or `--no-auto-mark-ready`.
|
|
93
93
|
- With `--merge`, actionable review threads/comments/reviews/summaries are held back (`WAIT`, with raw deferred-work counts) while a PR sits in the merge queue, since a Shepherd-initiated push would eject it; set `actions.workWhileQueued: true` to act on them immediately instead. Failing checks and merge conflicts are never deferred.
|
|
94
94
|
- The CLI never performs git mutations itself — it only emits commit/push instructions for the agent to run. Push access to the PR head is a usage precondition; GitHub viewer fields do not create a separate push-authorization handoff.
|
|
95
|
-
- Generated iterate mutations and automatic actions are capability-aware and omit unauthorized commands. Explicit `apply` operations
|
|
95
|
+
- Generated iterate mutations and automatic actions are capability-aware and omit unauthorized commands. Explicit `apply` operations forward the caller's requested IDs without iterate's author or capability policy and surface GitHub's result.
|
|
96
96
|
- `build_suggestion_patches` turns one or more ordered GitHub suggestion threads into checked patches and commit metadata, but never edits the working tree or git history. Local HEAD may be ahead when the live PR head is its ancestor.
|
|
97
97
|
|
|
98
98
|
## Usage
|
|
@@ -144,10 +144,15 @@ needs agent work, all rows are terminal, the bounded timeout expires, or `--unti
|
|
|
144
144
|
a configured GraphQL quota-warning band. Check counts use the same ignored, protected-run,
|
|
145
145
|
superseded-run, and event rules as singular iteration and include active merge-queue commit checks.
|
|
146
146
|
Bounded review/check overflow remains visible without permanently forcing work, and clean rows use
|
|
147
|
-
the configured ready-delay before becoming terminal.
|
|
148
|
-
|
|
149
|
-
Stack rows are ordered bottom-to-top
|
|
150
|
-
|
|
147
|
+
the configured ready-delay before becoming terminal. Explicit PR sets give each actionable row an
|
|
148
|
+
exact single-PR `pollCommand`, so independent rows can proceed before the next aggregate poll.
|
|
149
|
+
Stack rows are ordered bottom-to-top and follow the one ordered stack instruction block instead.
|
|
150
|
+
The summary also checks that every open child was based on
|
|
151
|
+
its direct parent's current head. A stale child/parent OID pair is actionable even when GitHub
|
|
152
|
+
reports both PRs clean: without `--merge`, rebase the upstack branches from their parent and push
|
|
153
|
+
them with the emitted `gh stack` commands; with `--merge`, finish the contiguous ready lower
|
|
154
|
+
layers with the emitted `gh stack merge --squash` command, recheck, then repair the child. API and
|
|
155
|
+
MCP aggregate calls perform one summary tick and leave recurrence to the caller.
|
|
151
156
|
|
|
152
157
|
Polling defaults can be set under `poll` in `.pr-shepherdrc.yml`: `intervalSeconds`, `timeoutSeconds`, `debounceSeconds`, and `quietStatus`. Explicit flags override configuration, including `--no-quiet-status` when a shared config enables quiet output. Quiet status remains off by default.
|
|
153
158
|
|
|
@@ -286,6 +291,8 @@ Environment variables:
|
|
|
286
291
|
|
|
287
292
|
See [docs/configuration.md](docs/configuration.md) for the full reference.
|
|
288
293
|
|
|
294
|
+
For guided noise reduction, use the plugin's `reduce-pr-noise` skill. It loads focused guidance for bot-comment classifiers or settings only when relevant; see [docs/skills.md](docs/skills.md).
|
|
295
|
+
|
|
289
296
|
### Classification rules
|
|
290
297
|
|
|
291
298
|
Drop `.ts` / `.mts` / `.mjs` / `.js` files under `.pr-shepherd/classification/` to suppress and/or auto-resolve specific bot comments — useful for silencing repetitive noise like rate-limit notices from `gemini-code-assist` or "Reviews paused" from `coderabbitai`.
|
|
@@ -14,7 +14,8 @@ Run 'pr-shepherd apply <review|files|journal> --help' for command-specific detai
|
|
|
14
14
|
--help, -h Print this help and exit before GitHub I/O.`;
|
|
15
15
|
readonly "apply review": `pr-shepherd apply review
|
|
16
16
|
|
|
17
|
-
Apply GitHub review-state mutations after fixes.
|
|
17
|
+
Apply user-directed GitHub review-state mutations after fixes. Supplied IDs are forwarded to GitHub;
|
|
18
|
+
GitHub accepts or rejects each mutation.
|
|
18
19
|
|
|
19
20
|
Usage:
|
|
20
21
|
pr-shepherd apply review [PR] --reply-thread-ids A,B --message MSG
|
|
@@ -24,10 +25,9 @@ Usage:
|
|
|
24
25
|
|
|
25
26
|
Flags:
|
|
26
27
|
--resolve-thread-ids <ids> Comma-separated review thread IDs (PRRT_*) to resolve.
|
|
27
|
-
|
|
28
|
-
--reply-thread-ids <ids> Comma-separated human review thread IDs to reply to.
|
|
28
|
+
--reply-thread-ids <ids> Comma-separated review thread IDs to reply to.
|
|
29
29
|
--minimize-comment-ids <ids> Comma-separated issue/review comment IDs to minimize.
|
|
30
|
-
--dismiss-review-ids <ids> Comma-separated
|
|
30
|
+
--dismiss-review-ids <ids> Comma-separated review IDs to dismiss.
|
|
31
31
|
--message <text> Reply/dismiss message. Required with reply or dismiss IDs.
|
|
32
32
|
--require-sha <sha> Wait for this full 40-character lowercase PR head SHA.
|
|
33
33
|
--format text|json Output format. Default: text.
|
|
@@ -121,7 +121,8 @@ Use --dry-run to preview paths without removing them.
|
|
|
121
121
|
readonly "admin log-file": string;
|
|
122
122
|
readonly resolve: `pr-shepherd resolve
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
Deprecated compatibility alias for user-directed GitHub review-state mutations. Supplied IDs are forwarded to GitHub;
|
|
125
|
+
GitHub accepts or rejects each mutation.
|
|
125
126
|
|
|
126
127
|
Usage:
|
|
127
128
|
pr-shepherd resolve [PR] --reply-thread-ids A,B --message MSG
|
|
@@ -131,11 +132,10 @@ Usage:
|
|
|
131
132
|
|
|
132
133
|
Flags:
|
|
133
134
|
--resolve-thread-ids <ids> Comma-separated review thread IDs (PRRT_*) to resolve.
|
|
134
|
-
Human-authored thread IDs are skipped; use --reply-thread-ids.
|
|
135
135
|
Note: comment IDs (PRRC_*) from gh api are not thread IDs and will fail.
|
|
136
|
-
--reply-thread-ids <ids> Comma-separated
|
|
136
|
+
--reply-thread-ids <ids> Comma-separated review thread IDs to reply to.
|
|
137
137
|
--minimize-comment-ids <ids> Comma-separated issue/review comment IDs to minimize.
|
|
138
|
-
--dismiss-review-ids <ids> Comma-separated
|
|
138
|
+
--dismiss-review-ids <ids> Comma-separated review IDs to dismiss.
|
|
139
139
|
--message <text> Reply/dismiss message. Required with --reply-thread-ids
|
|
140
140
|
or --dismiss-review-ids.
|
|
141
141
|
--require-sha <sha> Wait until GitHub reports this PR head SHA before mutating.
|
|
@@ -17,7 +17,8 @@ Run 'pr-shepherd apply <review|files|journal> --help' for command-specific detai
|
|
|
17
17
|
--help, -h Print this help and exit before GitHub I/O.`,
|
|
18
18
|
"apply review": `pr-shepherd apply review
|
|
19
19
|
|
|
20
|
-
Apply GitHub review-state mutations after fixes.
|
|
20
|
+
Apply user-directed GitHub review-state mutations after fixes. Supplied IDs are forwarded to GitHub;
|
|
21
|
+
GitHub accepts or rejects each mutation.
|
|
21
22
|
|
|
22
23
|
Usage:
|
|
23
24
|
pr-shepherd apply review [PR] --reply-thread-ids A,B --message MSG
|
|
@@ -27,10 +28,9 @@ Usage:
|
|
|
27
28
|
|
|
28
29
|
Flags:
|
|
29
30
|
--resolve-thread-ids <ids> Comma-separated review thread IDs (PRRT_*) to resolve.
|
|
30
|
-
|
|
31
|
-
--reply-thread-ids <ids> Comma-separated human review thread IDs to reply to.
|
|
31
|
+
--reply-thread-ids <ids> Comma-separated review thread IDs to reply to.
|
|
32
32
|
--minimize-comment-ids <ids> Comma-separated issue/review comment IDs to minimize.
|
|
33
|
-
--dismiss-review-ids <ids> Comma-separated
|
|
33
|
+
--dismiss-review-ids <ids> Comma-separated review IDs to dismiss.
|
|
34
34
|
--message <text> Reply/dismiss message. Required with reply or dismiss IDs.
|
|
35
35
|
--require-sha <sha> Wait for this full 40-character lowercase PR head SHA.
|
|
36
36
|
--format text|json Output format. Default: text.
|
|
@@ -124,7 +124,8 @@ Use --dry-run to preview paths without removing them.
|
|
|
124
124
|
"admin log-file": LOG_FILE_USAGE.replaceAll("pr-shepherd log-file", "pr-shepherd admin log-file"),
|
|
125
125
|
resolve: `pr-shepherd resolve
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
Deprecated compatibility alias for user-directed GitHub review-state mutations. Supplied IDs are forwarded to GitHub;
|
|
128
|
+
GitHub accepts or rejects each mutation.
|
|
128
129
|
|
|
129
130
|
Usage:
|
|
130
131
|
pr-shepherd resolve [PR] --reply-thread-ids A,B --message MSG
|
|
@@ -134,11 +135,10 @@ Usage:
|
|
|
134
135
|
|
|
135
136
|
Flags:
|
|
136
137
|
--resolve-thread-ids <ids> Comma-separated review thread IDs (PRRT_*) to resolve.
|
|
137
|
-
Human-authored thread IDs are skipped; use --reply-thread-ids.
|
|
138
138
|
Note: comment IDs (PRRC_*) from gh api are not thread IDs and will fail.
|
|
139
|
-
--reply-thread-ids <ids> Comma-separated
|
|
139
|
+
--reply-thread-ids <ids> Comma-separated review thread IDs to reply to.
|
|
140
140
|
--minimize-comment-ids <ids> Comma-separated issue/review comment IDs to minimize.
|
|
141
|
-
--dismiss-review-ids <ids> Comma-separated
|
|
141
|
+
--dismiss-review-ids <ids> Comma-separated review IDs to dismiss.
|
|
142
142
|
--message <text> Reply/dismiss message. Required with --reply-thread-ids
|
|
143
143
|
or --dismiss-review-ids.
|
|
144
144
|
--require-sha <sha> Wait until GitHub reports this PR head SHA before mutating.
|
package/bin/cli/help.d.mts
CHANGED
|
@@ -14,7 +14,8 @@ Run 'pr-shepherd apply <review|files|journal> --help' for command-specific detai
|
|
|
14
14
|
--help, -h Print this help and exit before GitHub I/O.`;
|
|
15
15
|
readonly "apply review": `pr-shepherd apply review
|
|
16
16
|
|
|
17
|
-
Apply GitHub review-state mutations after fixes.
|
|
17
|
+
Apply user-directed GitHub review-state mutations after fixes. Supplied IDs are forwarded to GitHub;
|
|
18
|
+
GitHub accepts or rejects each mutation.
|
|
18
19
|
|
|
19
20
|
Usage:
|
|
20
21
|
pr-shepherd apply review [PR] --reply-thread-ids A,B --message MSG
|
|
@@ -24,10 +25,9 @@ Usage:
|
|
|
24
25
|
|
|
25
26
|
Flags:
|
|
26
27
|
--resolve-thread-ids <ids> Comma-separated review thread IDs (PRRT_*) to resolve.
|
|
27
|
-
|
|
28
|
-
--reply-thread-ids <ids> Comma-separated human review thread IDs to reply to.
|
|
28
|
+
--reply-thread-ids <ids> Comma-separated review thread IDs to reply to.
|
|
29
29
|
--minimize-comment-ids <ids> Comma-separated issue/review comment IDs to minimize.
|
|
30
|
-
--dismiss-review-ids <ids> Comma-separated
|
|
30
|
+
--dismiss-review-ids <ids> Comma-separated review IDs to dismiss.
|
|
31
31
|
--message <text> Reply/dismiss message. Required with reply or dismiss IDs.
|
|
32
32
|
--require-sha <sha> Wait for this full 40-character lowercase PR head SHA.
|
|
33
33
|
--format text|json Output format. Default: text.
|
|
@@ -121,7 +121,8 @@ Use --dry-run to preview paths without removing them.
|
|
|
121
121
|
readonly "admin log-file": string;
|
|
122
122
|
readonly resolve: `pr-shepherd resolve
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
Deprecated compatibility alias for user-directed GitHub review-state mutations. Supplied IDs are forwarded to GitHub;
|
|
125
|
+
GitHub accepts or rejects each mutation.
|
|
125
126
|
|
|
126
127
|
Usage:
|
|
127
128
|
pr-shepherd resolve [PR] --reply-thread-ids A,B --message MSG
|
|
@@ -131,11 +132,10 @@ Usage:
|
|
|
131
132
|
|
|
132
133
|
Flags:
|
|
133
134
|
--resolve-thread-ids <ids> Comma-separated review thread IDs (PRRT_*) to resolve.
|
|
134
|
-
Human-authored thread IDs are skipped; use --reply-thread-ids.
|
|
135
135
|
Note: comment IDs (PRRC_*) from gh api are not thread IDs and will fail.
|
|
136
|
-
--reply-thread-ids <ids> Comma-separated
|
|
136
|
+
--reply-thread-ids <ids> Comma-separated review thread IDs to reply to.
|
|
137
137
|
--minimize-comment-ids <ids> Comma-separated issue/review comment IDs to minimize.
|
|
138
|
-
--dismiss-review-ids <ids> Comma-separated
|
|
138
|
+
--dismiss-review-ids <ids> Comma-separated review IDs to dismiss.
|
|
139
139
|
--message <text> Reply/dismiss message. Required with --reply-thread-ids
|
|
140
140
|
or --dismiss-review-ids.
|
|
141
141
|
--require-sha <sha> Wait until GitHub reports this PR head SHA before mutating.
|
|
@@ -38,8 +38,15 @@ export function buildSimpleIterateInstructions(result) {
|
|
|
38
38
|
}
|
|
39
39
|
case "cancel":
|
|
40
40
|
return ["Stop — the PR loop is complete. No further polling is needed."];
|
|
41
|
-
case "escalate":
|
|
42
|
-
|
|
41
|
+
case "escalate": {
|
|
42
|
+
const pending = result.escalate.pendingReviewCommands;
|
|
43
|
+
if (!pending)
|
|
44
|
+
return ["Stop — human direction is required before automated polling can resume."];
|
|
45
|
+
return [
|
|
46
|
+
"Stop polling. Ask the user whether to run the pending review commands shown above.",
|
|
47
|
+
"If yes, replace any `$HEAD_SHA` with the full 40-character pushed PR-head SHA and any `$DISMISS_MESSAGE` with a one-sentence disposition, run every pending command, then rerun Shepherd with the same options.",
|
|
48
|
+
];
|
|
49
|
+
}
|
|
43
50
|
}
|
|
44
51
|
}
|
|
45
52
|
export function adaptIterateLog(log) {
|
package/bin/cli/iterate-lean.mjs
CHANGED
|
@@ -160,6 +160,14 @@ export function projectIterateLean(result, opts) {
|
|
|
160
160
|
...(result.escalate.changesRequestedReviews.length > 0 && {
|
|
161
161
|
changesRequestedReviews: result.escalate.changesRequestedReviews,
|
|
162
162
|
}),
|
|
163
|
+
...(result.escalate.firstLookSummaries &&
|
|
164
|
+
result.escalate.firstLookSummaries.length > 0 && {
|
|
165
|
+
firstLookSummaries: result.escalate.firstLookSummaries,
|
|
166
|
+
}),
|
|
167
|
+
...(result.escalate.editedSummaries &&
|
|
168
|
+
result.escalate.editedSummaries.length > 0 && {
|
|
169
|
+
editedSummaries: result.escalate.editedSummaries,
|
|
170
|
+
}),
|
|
163
171
|
...(result.escalate.checks &&
|
|
164
172
|
result.escalate.checks.length > 0 && {
|
|
165
173
|
checks: result.escalate.checks,
|
|
@@ -182,6 +190,9 @@ export function projectIterateLean(result, opts) {
|
|
|
182
190
|
result.escalate.authorization.length > 0 && {
|
|
183
191
|
authorization: result.escalate.authorization,
|
|
184
192
|
}),
|
|
193
|
+
...(result.escalate.pendingReviewCommands && {
|
|
194
|
+
pendingReviewCommands: result.escalate.pendingReviewCommands,
|
|
195
|
+
}),
|
|
185
196
|
suggestion: result.escalate.suggestion,
|
|
186
197
|
humanMessage: result.escalate.humanMessage,
|
|
187
198
|
},
|
|
@@ -5,6 +5,21 @@ export function emitPollSummaryResult(result, opts) {
|
|
|
5
5
|
process.exitCode = pollSummaryExitCode(result);
|
|
6
6
|
}
|
|
7
7
|
function pollSummaryExitCode(result) {
|
|
8
|
+
if (result.nextAction === "cancel" &&
|
|
9
|
+
result.prs.some((item) => item.reasons.includes("closed"))) {
|
|
10
|
+
return EXIT.CLOSED;
|
|
11
|
+
}
|
|
12
|
+
if (result.nextAction) {
|
|
13
|
+
const stackExitCode = {
|
|
14
|
+
escalate: EXIT.ESCALATE,
|
|
15
|
+
fix_code: EXIT.FIX_CODE,
|
|
16
|
+
merge: EXIT.MERGE,
|
|
17
|
+
mark_ready: EXIT.MARK_READY,
|
|
18
|
+
wait: EXIT.WAIT,
|
|
19
|
+
cancel: EXIT.OK,
|
|
20
|
+
};
|
|
21
|
+
return stackExitCode[result.nextAction] ?? EXIT.OK;
|
|
22
|
+
}
|
|
8
23
|
const actions = new Set(result.prs.map((item) => item.action));
|
|
9
24
|
if (actions.has("escalate"))
|
|
10
25
|
return EXIT.ESCALATE;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formatApiUsage, formatQuotaWarning } from "./api-usage-formatter.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { withPollSummaryInstructions } from "../commands/poll-summary-instructions.mjs";
|
|
3
3
|
export function formatPollSummaryResult(result) {
|
|
4
4
|
const selection = result.selection.kind === "stack"
|
|
5
5
|
? `stack #${result.selection.stackNumber} anchored at PR #${result.selection.anchor} (${result.selection.stackSize} PRs)`
|
|
@@ -7,42 +7,28 @@ export function formatPollSummaryResult(result) {
|
|
|
7
7
|
const lines = [
|
|
8
8
|
`# Poll summary [${result.reason.toUpperCase()}]`,
|
|
9
9
|
"",
|
|
10
|
-
`**repo** \`${result.repo}\` · **selection** ${selection} · **mode** \`${result.mode}
|
|
10
|
+
`**repo** \`${result.repo}\` · **selection** ${selection} · **mode** \`${result.mode}\`${result.nextAction ? ` · **next action** \`${result.nextAction}\`` : ""}`,
|
|
11
11
|
"",
|
|
12
12
|
"## Pull requests",
|
|
13
13
|
"",
|
|
14
14
|
...result.prs.map(formatItem),
|
|
15
15
|
];
|
|
16
|
+
if (result.stackAncestry?.length) {
|
|
17
|
+
lines.push("", "## Stack ancestry", "");
|
|
18
|
+
for (const pair of result.stackAncestry) {
|
|
19
|
+
lines.push(`- PR #${pair.childPr} base \`${pair.childBaseRefName}\` at \`${pair.childBaseRefOid}\` differs from parent PR #${pair.parentPr} head \`${pair.parentHeadRefName}\` at \`${pair.parentHeadRefOid}\`.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
16
22
|
const apiUsage = result.apiUsage ? formatApiUsage(result.apiUsage) : null;
|
|
17
23
|
const quotaWarning = formatQuotaWarning(result.quotaWarning);
|
|
18
24
|
if (quotaWarning)
|
|
19
25
|
lines.push("", quotaWarning);
|
|
20
26
|
if (apiUsage)
|
|
21
27
|
lines.push("", apiUsage);
|
|
22
|
-
|
|
28
|
+
const instructions = result.instructions ?? withPollSummaryInstructions(result, false).instructions ?? [];
|
|
29
|
+
lines.push("", "## Instructions", "", ...instructions);
|
|
23
30
|
return lines.join("\n");
|
|
24
31
|
}
|
|
25
|
-
function formatInstructions(result) {
|
|
26
|
-
if (result.reason === "all_terminal")
|
|
27
|
-
return ["1. Stop — every selected PR is terminal."];
|
|
28
|
-
if (result.quotaWarning && result.reason !== "actionable") {
|
|
29
|
-
return [
|
|
30
|
-
buildQuotaAwareContinuation(result.quotaWarning, "1. This aggregate selection is non-terminal. Before continuing,"),
|
|
31
|
-
];
|
|
32
|
-
}
|
|
33
|
-
if (result.reason === "waiting" || result.reason === "timeout") {
|
|
34
|
-
return ["1. Run this aggregate selector again when the caller is ready to recheck."];
|
|
35
|
-
}
|
|
36
|
-
const instructions = [
|
|
37
|
-
"1. Choose each non-WAIT, non-CANCEL row that can proceed independently and run or delegate its exact `pollCommand`.",
|
|
38
|
-
"2. Follow each selected one-PR poll's `## Instructions` until it returns `CANCEL` or `ESCALATE`.",
|
|
39
|
-
"3. Run this aggregate poll again after selected work completes; one row's `ESCALATE` does not stop work on other rows.",
|
|
40
|
-
];
|
|
41
|
-
if (result.quotaWarning) {
|
|
42
|
-
instructions[2] = buildQuotaAwareContinuation(result.quotaWarning, "3. After selected work completes,");
|
|
43
|
-
}
|
|
44
|
-
return instructions;
|
|
45
|
-
}
|
|
46
32
|
function formatItem(item) {
|
|
47
33
|
const flags = [item.isDraft ? "draft" : null, item.isInMergeQueue ? "queued" : null]
|
|
48
34
|
.filter((value) => value !== null)
|
package/bin/cli-parser.mjs
CHANGED
|
@@ -213,4 +213,7 @@ async function handleResolve(args, command = "apply review") {
|
|
|
213
213
|
process.stdout.write(globalOpts.format === "json"
|
|
214
214
|
? `${JSON.stringify(result, null, 2)}\n`
|
|
215
215
|
: `${formatMutateResult(result)}\n`);
|
|
216
|
+
if (result.errors.length > 0) {
|
|
217
|
+
process.exitCode = result.rateLimit ? EXIT.TEMPFAIL : EXIT.UNAVAILABLE;
|
|
218
|
+
}
|
|
216
219
|
}
|
|
@@ -26,15 +26,9 @@ export declare function buildRepeatedWorkflowBranchRecoveryInstructions(baseBran
|
|
|
26
26
|
*
|
|
27
27
|
* - `$HEAD_SHA`/`$DISMISS_MESSAGE` substitution: without it, the printed command has an
|
|
28
28
|
* empty `--message`/invalid `--require-sha` and `apply review` rejects the mutation.
|
|
29
|
-
* Marker-based self-reply routing is already reflected in the generated IDs. The instruction
|
|
30
|
-
* below makes that behavior explicit so an authenticated viewer's unmarked human feedback is
|
|
31
|
-
* not mistaken for an automated reply merely because the GitHub login matches.
|
|
32
|
-
*
|
|
33
29
|
* Contrast with what *does* stay in the skill's "Review-mutation mechanics" playbook —
|
|
34
|
-
* dismiss-ID retention
|
|
35
|
-
*
|
|
36
|
-
* command run unmodified is already correct for them. The pointer below is load-bearing:
|
|
37
|
-
* without it, nothing in CLI output tells the agent that playbook exists.
|
|
30
|
+
* dismiss-ID retention. The pointer below is load-bearing: without it, nothing in CLI output
|
|
31
|
+
* tells the agent that playbook exists.
|
|
38
32
|
*/
|
|
39
33
|
export declare function buildResolveCommandInstruction(resolveCommand: ResolveCommand): string[];
|
|
40
34
|
/** Build the CI-triage pointer; the skill limits follow-up actions to included evidence. */
|
|
@@ -43,23 +43,14 @@ export function buildRepeatedWorkflowBranchRecoveryInstructions(baseBranch, hasE
|
|
|
43
43
|
*
|
|
44
44
|
* - `$HEAD_SHA`/`$DISMISS_MESSAGE` substitution: without it, the printed command has an
|
|
45
45
|
* empty `--message`/invalid `--require-sha` and `apply review` rejects the mutation.
|
|
46
|
-
* Marker-based self-reply routing is already reflected in the generated IDs. The instruction
|
|
47
|
-
* below makes that behavior explicit so an authenticated viewer's unmarked human feedback is
|
|
48
|
-
* not mistaken for an automated reply merely because the GitHub login matches.
|
|
49
|
-
*
|
|
50
46
|
* Contrast with what *does* stay in the skill's "Review-mutation mechanics" playbook —
|
|
51
|
-
* dismiss-ID retention
|
|
52
|
-
*
|
|
53
|
-
* command run unmodified is already correct for them. The pointer below is load-bearing:
|
|
54
|
-
* without it, nothing in CLI output tells the agent that playbook exists.
|
|
47
|
+
* dismiss-ID retention. The pointer below is load-bearing: without it, nothing in CLI output
|
|
48
|
+
* tells the agent that playbook exists.
|
|
55
49
|
*/
|
|
56
50
|
export function buildResolveCommandInstruction(resolveCommand) {
|
|
57
51
|
if (!resolveCommand.hasMutations)
|
|
58
52
|
return [];
|
|
59
53
|
const instructions = [];
|
|
60
|
-
if ((resolveCommand.replyThreadIds?.length ?? 0) > 0) {
|
|
61
|
-
instructions.push("Run the generated thread IDs unchanged. A latest comment beginning `<!-- pr-shepherd -->` is an established Shepherd reply; a marked thread that is still being resolved is emitted resolve-only, not for another reply.");
|
|
62
|
-
}
|
|
63
54
|
if (resolveCommand.requiresHeadSha) {
|
|
64
55
|
instructions.push("If you did not change code, replace `$HEAD_SHA` with `$(git rev-parse HEAD)`, which must equal the current remote PR head. If you changed code, commit and push to the PR head branch first, then replace `$HEAD_SHA` with the pushed commit SHA.");
|
|
65
56
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { loadConfig } from "../../config/load.mjs";
|
|
2
2
|
import { inlineCode } from "../../util/markdown.mjs";
|
|
3
|
+
import { renderResolveCommand } from "./render.mjs";
|
|
3
4
|
function renderEscalateAuthor(item) {
|
|
4
5
|
return [`@${item.author}`, item.authorType, item.authorAssociation].filter(Boolean).join(" · ");
|
|
5
6
|
}
|
|
@@ -121,6 +122,8 @@ export function buildEscalateHumanMessage(escalate, pr, opts) {
|
|
|
121
122
|
const hasItems = escalate.unresolvedThreads.length > 0 ||
|
|
122
123
|
escalate.changesRequestedReviews.length > 0 ||
|
|
123
124
|
escalate.ambiguousComments.length > 0 ||
|
|
125
|
+
(escalate.firstLookSummaries?.length ?? 0) > 0 ||
|
|
126
|
+
(escalate.editedSummaries?.length ?? 0) > 0 ||
|
|
124
127
|
(escalate.checks?.length ?? 0) > 0 ||
|
|
125
128
|
(escalate.stalledChecks?.length ?? 0) > 0;
|
|
126
129
|
if (hasItems) {
|
|
@@ -157,6 +160,20 @@ export function buildEscalateHumanMessage(escalate, pr, opts) {
|
|
|
157
160
|
lines.push(` > ${bodyLine}`);
|
|
158
161
|
lines.push("");
|
|
159
162
|
}
|
|
163
|
+
for (const [heading, summaries] of [
|
|
164
|
+
["Review summaries (first look)", escalate.firstLookSummaries ?? []],
|
|
165
|
+
["Review summaries (edited since first look)", escalate.editedSummaries ?? []],
|
|
166
|
+
]) {
|
|
167
|
+
if (summaries.length === 0)
|
|
168
|
+
continue;
|
|
169
|
+
lines.push(`### ${heading}`, "");
|
|
170
|
+
for (const summary of summaries) {
|
|
171
|
+
lines.push(`- review \`${summary.id}\` (${renderEscalateAuthor(summary)}):`, "");
|
|
172
|
+
for (const bodyLine of summary.body.split("\n"))
|
|
173
|
+
lines.push(` > ${bodyLine}`);
|
|
174
|
+
lines.push("");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
160
177
|
for (const c of escalate.ambiguousComments) {
|
|
161
178
|
lines.push(`- comment \`${c.id}\` (${renderEscalateAuthor(c)}):`);
|
|
162
179
|
lines.push("");
|
|
@@ -194,7 +211,17 @@ export function buildEscalateHumanMessage(escalate, pr, opts) {
|
|
|
194
211
|
lines.push("## Fix attempts");
|
|
195
212
|
lines.push("");
|
|
196
213
|
for (const a of escalate.thrashHistory) {
|
|
197
|
-
lines.push(`- thread \`${a.threadId}\`
|
|
214
|
+
lines.push(`- thread \`${a.threadId}\` pending commands returned ${a.attempts} times`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const pending = escalate.pendingReviewCommands;
|
|
218
|
+
if (pending?.resolveOnlyCommand?.hasMutations || pending?.resolveCommand?.hasMutations) {
|
|
219
|
+
lines.push("", "## Pending review commands", "");
|
|
220
|
+
if (pending.resolveOnlyCommand?.hasMutations) {
|
|
221
|
+
lines.push(`- resolve-only: \`${renderResolveCommand(pending.resolveOnlyCommand)}\``);
|
|
222
|
+
}
|
|
223
|
+
if (pending.resolveCommand?.hasMutations) {
|
|
224
|
+
lines.push(`- apply review: \`${renderResolveCommand(pending.resolveCommand)}\``);
|
|
198
225
|
}
|
|
199
226
|
}
|
|
200
227
|
lines.push("");
|
|
@@ -227,7 +254,8 @@ export function buildEscalateSuggestion(triggers, detail) {
|
|
|
227
254
|
return `Could not determine the PR's base branch${reason} — automated rebases are paused because branch safety is unclear. Run the rebase manually against the PR's real target branch.`;
|
|
228
255
|
}
|
|
229
256
|
if (triggers.includes("fix-thrash")) {
|
|
230
|
-
|
|
257
|
+
const attempts = loadConfig().iterate.fixAttemptsPerThread;
|
|
258
|
+
return `The same thread(s) remain unresolved after their pending review commands were returned for ${attempts} FIX_CODE ticks. Automated iteration is paused for a manual decision.`;
|
|
231
259
|
}
|
|
232
260
|
if (triggers.includes("bot-cr-not-dismissed")) {
|
|
233
261
|
const ids = detail ? ` (review IDs: ${detail})` : "";
|