pr-shepherd 0.41.0 → 0.43.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.
Files changed (109) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +14 -9
  3. package/bin/api.d.mts +12 -1
  4. package/bin/api.mjs +34 -1
  5. package/bin/checks/classify.d.mts +3 -1
  6. package/bin/checks/classify.mjs +5 -2
  7. package/bin/cli/args.mjs +1 -0
  8. package/bin/cli/default-poll.mjs +1 -0
  9. package/bin/cli/fix-formatter.mjs +12 -2
  10. package/bin/cli/formatters.d.mts +2 -1
  11. package/bin/cli/formatters.mjs +33 -0
  12. package/bin/cli/handlers.d.mts +1 -0
  13. package/bin/cli/handlers.mjs +21 -1
  14. package/bin/cli/help-command-pages.d.mts +22 -6
  15. package/bin/cli/help-command-pages.mjs +20 -4
  16. package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
  17. package/bin/cli/help-iterate-poll-pages.mjs +7 -2
  18. package/bin/cli/help-top-page.d.mts +1 -1
  19. package/bin/cli/help-top-page.mjs +3 -3
  20. package/bin/cli/help.d.mts +23 -7
  21. package/bin/cli/iterate-flags.d.mts +1 -0
  22. package/bin/cli/iterate-flags.mjs +2 -0
  23. package/bin/cli/iterate-formatter.mjs +4 -1
  24. package/bin/cli/iterate-instructions.mjs +15 -0
  25. package/bin/cli/iterate-lean.d.mts +1 -2
  26. package/bin/cli/iterate-lean.mjs +12 -17
  27. package/bin/cli/iterate-merge-formatter.d.mts +3 -0
  28. package/bin/cli/iterate-merge-formatter.mjs +52 -0
  29. package/bin/cli/iterate-verbose.d.mts +6 -0
  30. package/bin/cli/iterate-verbose.mjs +14 -0
  31. package/bin/cli/poll-handler.mjs +1 -0
  32. package/bin/cli/runner.mjs +4 -3
  33. package/bin/cli/suggestion-patch-flags.d.mts +11 -0
  34. package/bin/cli/suggestion-patch-flags.mjs +83 -0
  35. package/bin/cli-parser.mjs +6 -2
  36. package/bin/commands/check-terminal-report.mjs +1 -0
  37. package/bin/commands/check.mjs +42 -1
  38. package/bin/commands/commit-suggestion-instruction.d.mts +1 -1
  39. package/bin/commands/commit-suggestion-instruction.mjs +3 -3
  40. package/bin/commands/commit-suggestion.d.mts +1 -1
  41. package/bin/commands/commit-suggestion.mjs +19 -138
  42. package/bin/commands/iterate/base.d.mts +5 -0
  43. package/bin/commands/iterate/base.mjs +25 -0
  44. package/bin/commands/iterate/escalate.d.mts +3 -1
  45. package/bin/commands/iterate/escalate.mjs +18 -2
  46. package/bin/commands/iterate/fix-code.mjs +16 -0
  47. package/bin/commands/iterate/helpers.mjs +6 -2
  48. package/bin/commands/iterate/index.mjs +29 -35
  49. package/bin/commands/iterate/merge-state.d.mts +15 -0
  50. package/bin/commands/iterate/merge-state.mjs +53 -0
  51. package/bin/commands/iterate/merge.d.mts +13 -0
  52. package/bin/commands/iterate/merge.mjs +46 -0
  53. package/bin/commands/poll.mjs +3 -1
  54. package/bin/commands/suggestion-patch-git.d.mts +6 -0
  55. package/bin/commands/suggestion-patch-git.mjs +54 -0
  56. package/bin/commands/suggestion-patch-item.d.mts +15 -0
  57. package/bin/commands/suggestion-patch-item.mjs +106 -0
  58. package/bin/commands/suggestion-patches.d.mts +6 -0
  59. package/bin/commands/suggestion-patches.mjs +108 -0
  60. package/bin/config/load.d.mts +4 -0
  61. package/bin/config/load.mjs +34 -0
  62. package/bin/config/merge-command-args.d.mts +2 -0
  63. package/bin/config/merge-command-args.mjs +44 -0
  64. package/bin/config.json +3 -0
  65. package/bin/exit-codes.d.mts +2 -0
  66. package/bin/exit-codes.mjs +4 -0
  67. package/bin/github/batch-parse-checks.d.mts +3 -0
  68. package/bin/github/batch-parse-checks.mjs +29 -0
  69. package/bin/github/batch-parsers-rules.d.mts +3 -1
  70. package/bin/github/batch-parsers-rules.mjs +33 -0
  71. package/bin/github/batch-parsers.mjs +23 -26
  72. package/bin/github/batch-raw-rules.d.mts +48 -0
  73. package/bin/github/batch-raw-types.mjs +0 -1
  74. package/bin/github/batch.mjs +2 -0
  75. package/bin/github/gql/batch-pr.gql +92 -0
  76. package/bin/github/gql/commit-check-contexts.gql +58 -0
  77. package/bin/github/gql/{commit-suggestion-thread.gql → suggestion-threads.gql} +2 -2
  78. package/bin/github/merge-queue-checks.d.mts +4 -0
  79. package/bin/github/merge-queue-checks.mjs +48 -0
  80. package/bin/github/queries.d.mts +3 -1
  81. package/bin/github/queries.mjs +3 -1
  82. package/bin/github/suggestion-thread.d.mts +3 -3
  83. package/bin/github/suggestion-thread.mjs +8 -5
  84. package/bin/mcp/server.d.mts +1 -1
  85. package/bin/mcp/server.mjs +24 -3
  86. package/bin/reporters/agent.mjs +6 -3
  87. package/bin/types/activity.d.mts +2 -0
  88. package/bin/types/escalate.d.mts +30 -0
  89. package/bin/types/escalate.mjs +1 -0
  90. package/bin/types/github.d.mts +8 -0
  91. package/bin/types/github.mjs +0 -3
  92. package/bin/types/iterate.d.mts +14 -31
  93. package/bin/types/merge-action.d.mts +12 -0
  94. package/bin/types/merge-action.mjs +1 -0
  95. package/bin/types/merge-queue.d.mts +13 -0
  96. package/bin/types/merge-queue.mjs +1 -0
  97. package/bin/types/merge-requirements.d.mts +17 -0
  98. package/bin/types/report.d.mts +8 -19
  99. package/bin/types/suggestion-patch.d.mts +30 -0
  100. package/bin/types/suggestion-patch.mjs +1 -0
  101. package/bin/types.d.mts +4 -0
  102. package/bin/types.mjs +4 -0
  103. package/bin/util/markdown.d.mts +2 -0
  104. package/bin/util/markdown.mjs +7 -0
  105. package/package.json +1 -1
  106. package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
  107. package/plugins/pr-shepherd/.codex.mcp.json +1 -1
  108. package/plugins/pr-shepherd/.mcp.json +1 -1
  109. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +11 -10
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pr-shepherd",
3
3
  "description": "Autonomous PR CI monitor and review-comment resolver for agentic coding tools",
4
- "version": "0.41.0",
4
+ "version": "0.43.0",
5
5
  "author": {
6
6
  "name": "Jonathan Ong",
7
7
  "email": "jonathanrichardong@gmail.com"
package/README.md CHANGED
@@ -9,14 +9,14 @@ An agent finishing a PR should think about code, not reconstruct GitHub state or
9
9
  ## What it does
10
10
 
11
11
  1. **Gather all context for a PR** in one invocation: review threads, comments, replies, summaries, CI, mergeability, merge requirements, first-look / outdated / edited items, and author provenance.
12
- 2. **Provide deterministic actions for the agent**: exactly one of `WAIT`, `MARK_READY`, `FIX_CODE`, `CANCEL`, or `ESCALATE`, plus numbered `## Instructions` and explicit `apply` / `build_suggestion_patch` mutations. The agent still decides whether a comment or CI failure needs a code change. Shepherd does not classify signal vs noise and does not mutate git.
12
+ 2. **Provide deterministic actions for the agent**: exactly one of `WAIT`, `MARK_READY`, `FIX_CODE`, `MERGE`, `CANCEL`, or `ESCALATE`, plus numbered `## Instructions` and explicit commands. The agent still decides whether a comment or CI failure needs a code change. Shepherd does not classify signal vs noise and does not mutate git.
13
13
 
14
14
  Highlights:
15
15
 
16
16
  - Batched GraphQL reads and writes (plus REST where GraphQL cannot) so one poll replaces a tool-call fan-out. MCP `iterate` is one tick and the client owns recurrence; `--debounce` is a poll-dispatcher settle window, not an MCP tool.
17
17
  - CI summaries include failed checks, and the failed job/step plus a log excerpt when triage can fetch them. Job and log details are omitted for `STARTUP_FAILURE` and `CANCELLED`; agents may still inspect logs.
18
18
  - Handles GitHub comment types (comments, threads, replies) and their states, including first-look, outdated, resolved, minimized, and edited.
19
- - `apply` batches resolve / reply / minimize / dismiss. `build_suggestion_patch` emits a unified diff in output, not a patch file, and does not mutate git.
19
+ - `apply` batches resolve / reply / minimize / dismiss. `build_suggestion_patches` validates and returns ordered diffs without mutating git.
20
20
  - `BEHIND` is mergeability information, not a rebase or a guarantee that the next push is at the default-branch tip. The agent can update the branch before pushing.
21
21
 
22
22
  Full reference: [docs/README.md](docs/README.md). Feature matrix: [docs/features.md](docs/features.md).
@@ -25,13 +25,14 @@ Full reference: [docs/README.md](docs/README.md). Feature matrix: [docs/features
25
25
 
26
26
  `pr-shepherd` moves deterministic PR orchestration into a local MCP server, with a CLI for shells and CI. Both interfaces fetch the same GitHub state, emit raw-enough context, and return a numbered plan for the calling agent to follow.
27
27
 
28
- The MCP server exposes three tools: `iterate`, `apply`, and `build_suggestion_patch`. `apply` accepts ordered review mutations, file-view mutations, and journal entries. Direct MCP calls require a repository-qualified `pr`: a GitHub PR URL or `owner/repo#N`, matching the repository where the server started. The CLI and programmatic API also retain bare-number and current-branch PR discovery. The shipped skills are thin dispatchers for those tools.
28
+ The MCP server exposes canonical `iterate`, `apply`, and `build_suggestion_patches` tools. `apply` accepts ordered review mutations, file-view mutations, and journal entries; the deprecated singular suggestion tool remains temporarily as an adapter. Direct MCP calls require a repository-qualified `pr`: a GitHub PR URL or `owner/repo#N`, matching the repository where the server started. The CLI and programmatic API also retain bare-number and current-branch PR discovery. The shipped skills are thin dispatchers for those tools.
29
29
 
30
30
  Each tick returns exactly one action:
31
31
 
32
32
  - `WAIT` — no immediate action; continue with the next poll.
33
33
  - `MARK_READY` — the CLI converted an eligible draft PR to ready; continue polling.
34
34
  - `FIX_CODE` — agent work is required; complete it, then continue polling.
35
+ - `MERGE` — run the emitted auto-merge or merge-queue command, then continue polling.
35
36
  - `CANCEL` — stop polling because the PR merged, closed, or completed its ready-delay.
36
37
  - `ESCALATE` — stop polling until a human provides direction.
37
38
 
@@ -76,7 +77,7 @@ Conversations Resolved: No [Not Required]
76
77
  9. `[FIX_CODE]` is non-terminal. After completing these steps, iterate again with the same options to continue.
77
78
  ```
78
79
 
79
- See [docs/actions.md](docs/actions.md) for the complete output contract. Iterate/poll PR outcomes use exit codes `0` and `10`–`14`; command and GitHub failures use `sysexits.h` codes — [docs/exit-codes.md](docs/exit-codes.md).
80
+ See [docs/actions.md](docs/actions.md) for the complete output contract. Iterate/poll PR outcomes use exit codes `0` and `10`–`15`; command and GitHub failures use `sysexits.h` codes — [docs/exit-codes.md](docs/exit-codes.md).
80
81
 
81
82
  ## Workflow Assumptions
82
83
 
@@ -88,7 +89,7 @@ This system is opinionated and works best with PRs that use required status chec
88
89
  - Every review thread/comment/review summary is surfaced at least once, even if already outdated, resolved, or minimized; edited items re-surface through seen markers.
89
90
  - Draft PRs can be marked ready automatically when clean; disable with `actions.autoMarkReady: false` or `--no-auto-mark-ready`.
90
91
  - The CLI never performs git mutations. It emits instructions; the caller commits, rebases, pushes, and handles repository hooks.
91
- - `build_suggestion_patch` turns one GitHub suggestion thread into a patch and commit metadata, but never edits the working tree or git history.
92
+ - `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.
92
93
 
93
94
  ## Usage
94
95
 
@@ -115,7 +116,7 @@ Grok:
115
116
  /pr-shepherd 42
116
117
  ```
117
118
 
118
- MCP clients call `iterate` once per tick, then use `apply` for review/file/journal mutations and `build_suggestion_patch` for an anchored suggestion. Every direct MCP call supplies the same repository-qualified PR reference. `iterate` returns the same structured action data as the CLI, including its review mutation arguments. The client owns recurrence, so this works consistently in Codex, Claude Code, Grok, and any other stdio MCP client.
119
+ MCP clients call `iterate` once per tick, then use `apply` for review/file/journal mutations and `build_suggestion_patches` for anchored suggestions. Every direct MCP call supplies the same repository-qualified PR reference. `iterate` returns the same structured action data as the CLI, including its review mutation arguments. The client owns recurrence, so this works consistently in Codex, Claude Code, Grok, and any other stdio MCP client.
119
120
 
120
121
  The CLI remains useful for shell workflows. Its canonical polling form is:
121
122
 
@@ -126,12 +127,13 @@ pr-shepherd 42 --quiet-status # print only changed WAIT status snapshot
126
127
  pr-shepherd 42 --until-terminal # continue through WAIT/MARK_READY until work or terminal state
127
128
  pr-shepherd 42 --debounce 5m # wait 5m after first FIX_CODE, then return one batched tick
128
129
  pr-shepherd 42 --ready-delay 15m
130
+ pr-shepherd 42 --merge # enable auto-merge or enter an enabled/required merge queue when ready
129
131
  pr-shepherd iterate 42 # single tick
130
132
  ```
131
133
 
132
134
  ### Apply Review, File, And Journal Changes
133
135
 
134
- Use `apply` with ordered operations to reply/resolve/minimize/dismiss review items, mark changed files viewed, or append an idempotent Shepherd Journal item. Use `build_suggestion_patch` to turn one review suggestion into a validated patch and commit metadata; it never changes the worktree or git history.
136
+ Use `apply` with ordered operations to reply/resolve/minimize/dismiss review items, mark changed files viewed, or append an idempotent Shepherd Journal item. Use `build_suggestion_patches` to turn ordered review suggestions into checked patches and commit metadata; it never changes the worktree or git history.
135
137
 
136
138
  ### Extract Shepherd Journal Entries
137
139
 
@@ -236,7 +238,10 @@ checks:
236
238
  ciTriggerEvents:
237
239
  - pull_request
238
240
  - pull_request_target
239
- - merge_group
241
+ merge:
242
+ commandArgs:
243
+ - --squash
244
+ - --delete-branch
240
245
  actions:
241
246
  autoMinimizeSuppressed: true
242
247
  autoMarkReady: false
@@ -276,7 +281,7 @@ Ready-to-use examples for common patterns are in [`examples/classification/`](ex
276
281
 
277
282
  ## CLI aliases
278
283
 
279
- `poll`, `resolve`, `commit-suggestion`, `mark-files-as-viewed`, `journal`, `clean`, and `log-file` are CLI aliases. Prefer default polling/`iterate` in a shell and the MCP `iterate`, `apply`, and `build_suggestion_patch` tools in an agent client.
284
+ `poll`, `resolve`, `build-suggestion-patch`, `commit-suggestion`, `mark-files-as-viewed`, `journal`, `clean`, and `log-file` are CLI aliases or deprecated adapters. Prefer default polling/`iterate` in a shell and the MCP `iterate`, `apply`, and `build_suggestion_patches` tools in an agent client.
280
285
 
281
286
  ## Requirements
282
287
 
package/bin/api.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type JournalResult } from "./commands/journal/index.mts";
2
2
  import { type MarkFilesAsViewedResult } from "./commands/mark-files-as-viewed.mts";
3
3
  import type { ResolveResult } from "./comments/resolve.mts";
4
- import type { CommitSuggestionResult, IterateCommandOptions, IterateResult } from "./types.mts";
4
+ import type { BuildSuggestionPatchesResult, CommitSuggestionResult, IterateCommandOptions, IterateResult } from "./types.mts";
5
5
  export interface CreatePrShepherdOptions {
6
6
  /** Working directory used for git, config, and classification-rule lookups. */
7
7
  cwd?: string;
@@ -58,9 +58,20 @@ export interface BuildSuggestionPatchInput {
58
58
  message: string;
59
59
  description?: string;
60
60
  }
61
+ export interface SuggestionPatchInput {
62
+ threadId: string;
63
+ message: string;
64
+ description?: string;
65
+ }
66
+ export interface BuildSuggestionPatchesInput {
67
+ pr?: PrReference;
68
+ suggestions: SuggestionPatchInput[];
69
+ }
61
70
  export interface PrShepherd {
62
71
  iterate(input?: IterateInput): Promise<IterateResult>;
63
72
  apply(input: ApplyInput): Promise<ApplyResult>;
73
+ buildSuggestionPatches(input: BuildSuggestionPatchesInput): Promise<BuildSuggestionPatchesResult>;
74
+ /** Compatibility adapter; prefer buildSuggestionPatches. */
64
75
  buildSuggestionPatch(input: BuildSuggestionPatchInput): Promise<CommitSuggestionResult>;
65
76
  }
66
77
  /** Raised before any API mutation when an input cannot be validated. */
package/bin/api.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable max-lines */
2
2
  import { resolve } from "node:path";
3
3
  import { runCommitSuggestion } from "./commands/commit-suggestion.mjs";
4
+ import { runSuggestionPatches } from "./commands/suggestion-patches.mjs";
4
5
  import { runIterate } from "./commands/iterate/index.mjs";
5
6
  import { runJournal } from "./commands/journal/index.mjs";
6
7
  import { validateJournalItem } from "./commands/journal/transform.mjs";
@@ -101,6 +102,14 @@ export function createPrShepherd(options = {}) {
101
102
  return runCommitSuggestion({ ...options, prNumber, format: "json" });
102
103
  });
103
104
  },
105
+ buildSuggestionPatches(input) {
106
+ validateSuggestionPatchesInput(input);
107
+ const { pr: _pr, ...options } = input;
108
+ return runWithExecutionCwd(cwd, async () => {
109
+ const prNumber = await resolvePrReference(input.pr);
110
+ return runSuggestionPatches({ ...options, prNumber, format: "json" });
111
+ });
112
+ },
104
113
  });
105
114
  }
106
115
  function validateApplyInput(input) {
@@ -184,7 +193,7 @@ function validateMarkFilesViewed(operation) {
184
193
  }
185
194
  }
186
195
  function validateSuggestionPatchInput(input) {
187
- if (!input || typeof input.threadId !== "string" || input.threadId === "") {
196
+ if (!input || typeof input.threadId !== "string" || input.threadId.trim() === "") {
188
197
  throw new PrShepherdValidationError("buildSuggestionPatch.threadId is required");
189
198
  }
190
199
  if (typeof input.message !== "string" || input.message.trim() === "") {
@@ -195,6 +204,30 @@ function validateSuggestionPatchInput(input) {
195
204
  }
196
205
  validatePrReference(input.pr);
197
206
  }
207
+ function validateSuggestionPatchesInput(input) {
208
+ if (!input || !Array.isArray(input.suggestions) || input.suggestions.length === 0) {
209
+ throw new PrShepherdValidationError("buildSuggestionPatches.suggestions must be a non-empty array");
210
+ }
211
+ const seen = new Set();
212
+ for (const suggestion of input.suggestions) {
213
+ if (!suggestion ||
214
+ typeof suggestion.threadId !== "string" ||
215
+ suggestion.threadId.trim() === "") {
216
+ throw new PrShepherdValidationError("each suggestion.threadId is required");
217
+ }
218
+ if (typeof suggestion.message !== "string" || suggestion.message.trim() === "") {
219
+ throw new PrShepherdValidationError("each suggestion.message must be non-empty");
220
+ }
221
+ if (suggestion.description !== undefined && typeof suggestion.description !== "string") {
222
+ throw new PrShepherdValidationError("each suggestion.description must be a string");
223
+ }
224
+ if (seen.has(suggestion.threadId)) {
225
+ throw new PrShepherdValidationError(`duplicate suggestion thread ID: ${suggestion.threadId}`);
226
+ }
227
+ seen.add(suggestion.threadId);
228
+ }
229
+ validatePrReference(input.pr);
230
+ }
198
231
  function validatePrReference(pr) {
199
232
  const parsed = parsePrReference(pr);
200
233
  if (parsed !== null)
@@ -20,7 +20,9 @@ import type { CheckRun, ClassifiedCheck } from "../types.mts";
20
20
  * @param checks Raw check runs from the batch query.
21
21
  * @returns Classified checks. "filtered" items were excluded from the tally.
22
22
  */
23
- export declare function classifyChecks(checks: CheckRun[]): ClassifiedCheck[];
23
+ export declare function classifyChecks(checks: CheckRun[], opts?: {
24
+ additionalRelevantEvents?: string[];
25
+ }): ClassifiedCheck[];
24
26
  export interface CiVerdict {
25
27
  /** True when all relevant (non-filtered, non-skipped, non-ignored) checks passed. */
26
28
  allPassed: boolean;
@@ -22,9 +22,12 @@ import picomatch from "picomatch";
22
22
  * @param checks Raw check runs from the batch query.
23
23
  * @returns Classified checks. "filtered" items were excluded from the tally.
24
24
  */
25
- export function classifyChecks(checks) {
25
+ export function classifyChecks(checks, opts = {}) {
26
26
  const config = loadConfig();
27
- const relevantEvents = new Set(config.checks.ciTriggerEvents);
27
+ const relevantEvents = new Set([
28
+ ...config.checks.ciTriggerEvents,
29
+ ...(opts.additionalRelevantEvents ?? []),
30
+ ]);
28
31
  const isIgnored = buildMatcher(config.ignoreChecks ?? []);
29
32
  const isProtected = buildMatcher(config.actions.neverCancelRuns ?? []);
30
33
  const protectedRunIds = buildProtectedRunIds(checks, isProtected);
package/bin/cli/args.mjs CHANGED
@@ -30,6 +30,7 @@ const BOOLEAN_FLAGS = new Set([
30
30
  "--no-auto-cancel-actionable",
31
31
  "--quiet-status",
32
32
  "--until-terminal",
33
+ "--merge",
33
34
  "--dry-run",
34
35
  "--verbose",
35
36
  ]);
@@ -16,6 +16,7 @@ const DEFAULT_POLL_BOOLEAN_FLAGS = new Set([
16
16
  "--no-auto-cancel-actionable",
17
17
  "--quiet-status",
18
18
  "--until-terminal",
19
+ "--merge",
19
20
  ]);
20
21
  export function isDefaultPollInvocation(subcommand) {
21
22
  if (subcommand === "--help" || subcommand === "-h")
@@ -1,10 +1,11 @@
1
1
  import { renderResolveCommand } from "../commands/iterate/render.mjs";
2
- import { joinSections } from "../util/markdown.mjs";
2
+ import { inlineCode, joinSections } from "../util/markdown.mjs";
3
3
  import { renderSuggestionBlock, renderLineRange } from "./suggestion-renderer.mjs";
4
4
  import { renderThreadBullet, renderReviewBullet, renderThreadResolutionStatusTag, renderAuthor, buildFirstLookBullets, renderThreadConversation, blockquote, } from "./list-formatters.mjs";
5
5
  import { numberInstructions } from "./iterate-instructions.mjs";
6
6
  import { renderCheckAnnotation, renderProtectedRun } from "./fix-formatter-extra.mjs";
7
7
  import { isFailingAgentCheck } from "../checks/conclusions.mjs";
8
+ import { renderMergeCommand } from "../commands/iterate/merge.mjs";
8
9
  export function formatFixCodeResult(header, result) {
9
10
  const sections = [header];
10
11
  if (result.fix.threads.length > 0) {
@@ -50,7 +51,10 @@ export function formatFixCodeResult(header, result) {
50
51
  ? `external \`${ch.detailsUrl}\``
51
52
  : "(no runId)";
52
53
  const conclusionTag = ch.conclusion !== null ? ` [conclusion: ${ch.conclusion}]` : "";
53
- const lines = [`- ${locator} — \`${workflowPrefix}${jobLabel}\`${conclusionTag}`];
54
+ const scopeTag = ch.scope
55
+ ? ` [scope: ${ch.scope}${ch.commitOid ? `, commit: ${ch.commitOid}` : ""}]`
56
+ : "";
57
+ const lines = [`- ${locator} — \`${workflowPrefix}${jobLabel}\`${conclusionTag}${scopeTag}`];
54
58
  if (ch.conclusion !== "CANCELLED") {
55
59
  if (ch.failedStep)
56
60
  lines.push(` > ${ch.failedStep}`);
@@ -133,6 +137,12 @@ export function formatFixCodeResult(header, result) {
133
137
  if (result.fix.resolveCommand.hasMutations) {
134
138
  postFixLines.push(`- apply review: \`${renderResolveCommand(result.fix.resolveCommand)}\``);
135
139
  }
140
+ if (result.fix.requeue) {
141
+ postFixLines.push(`- requeue: ${inlineCode(renderMergeCommand(result.fix.requeue.command))}`);
142
+ if (result.fix.requeue.queueApiFallbackCommand) {
143
+ postFixLines.push(`- requeue API fallback: ${inlineCode(renderMergeCommand(result.fix.requeue.queueApiFallbackCommand))}`);
144
+ }
145
+ }
136
146
  sections.push(postFixLines.join("\n"));
137
147
  sections.push("## Instructions");
138
148
  sections.push(numberInstructions(result.fix.instructions));
@@ -3,5 +3,6 @@ export { projectIterateLean, projectIterateVerbose } from "./iterate-lean.mts";
3
3
  export { formatCleanResult } from "./clean-formatter.mts";
4
4
  export { formatMarkFilesAsViewedResult } from "./mark-files-as-viewed-formatter.mts";
5
5
  export { formatMutateResult } from "./mutate-formatter.mts";
6
- import type { CommitSuggestionResult } from "../types.mts";
6
+ import type { BuildSuggestionPatchesResult, CommitSuggestionResult } from "../types.mts";
7
+ export declare function formatSuggestionPatchesResult(result: BuildSuggestionPatchesResult): string;
7
8
  export declare function formatCommitSuggestionResult(result: CommitSuggestionResult): string;
@@ -4,6 +4,14 @@ export { formatCleanResult } from "./clean-formatter.mjs";
4
4
  export { formatMarkFilesAsViewedResult } from "./mark-files-as-viewed-formatter.mjs";
5
5
  export { formatMutateResult } from "./mutate-formatter.mjs";
6
6
  import { safeFence } from "./fence.mjs";
7
+ export function formatSuggestionPatchesResult(result) {
8
+ const lines = [`Suggestion patches for PR #${result.pr}:`, ` repo: ${result.repo}`];
9
+ result.patches.forEach((patch, index) => {
10
+ lines.push("", ...formatPatch(patch, `## Patch ${index + 1}`).split("\n"));
11
+ });
12
+ appendInstructions(lines, result.postActionInstructions);
13
+ return lines.join("\n");
14
+ }
7
15
  export function formatCommitSuggestionResult(result) {
8
16
  const lines = [];
9
17
  const range = result.startLine === result.endLine
@@ -30,3 +38,28 @@ export function formatCommitSuggestionResult(result) {
30
38
  }
31
39
  return lines.join("\n");
32
40
  }
41
+ function formatPatch(patch, heading) {
42
+ const range = patch.startLine === patch.endLine
43
+ ? `line ${patch.startLine}`
44
+ : `lines ${patch.startLine}–${patch.endLine}`;
45
+ const lines = [
46
+ heading,
47
+ "",
48
+ `Suggestion from @${patch.author} — thread ${patch.threadId}:`,
49
+ ` ${patch.path} (${range})`,
50
+ ];
51
+ if (patch.patch) {
52
+ const fence = safeFence(patch.patch);
53
+ lines.push("", `${fence}diff`, patch.patch.trimEnd(), fence);
54
+ }
55
+ lines.push("", "### Suggested commit message", "", patch.commitMessage, "", patch.commitBody);
56
+ return lines.join("\n");
57
+ }
58
+ function appendInstructions(lines, instructions) {
59
+ if (instructions.length === 0)
60
+ return;
61
+ lines.push("", "## Instructions", "");
62
+ instructions.forEach((instruction, index) => {
63
+ lines.push(`${index + 1}. ${instruction}`);
64
+ });
65
+ }
@@ -1,4 +1,5 @@
1
1
  export declare function handleClean(args: string[], command?: "admin clean" | "clean"): Promise<void>;
2
2
  export declare function handleCommitSuggestion(args: string[], command?: "build-suggestion-patch" | "commit-suggestion"): Promise<void>;
3
+ export declare function handleSuggestionPatches(args: string[]): Promise<void>;
3
4
  export declare function handleIterate(args: string[]): Promise<void>;
4
5
  export declare function handleMarkFilesAsViewed(args: string[], command?: "apply files" | "mark-files-as-viewed"): Promise<void>;
@@ -1,4 +1,5 @@
1
1
  import { runCommitSuggestion } from "../commands/commit-suggestion.mjs";
2
+ import { runSuggestionPatches } from "../commands/suggestion-patches.mjs";
2
3
  import { runMarkFilesAsViewed } from "../commands/mark-files-as-viewed.mjs";
3
4
  import { runIterate } from "../commands/iterate/index.mjs";
4
5
  import { runClean } from "../commands/clean.mjs";
@@ -6,7 +7,8 @@ import { loadConfig } from "../config/load.mjs";
6
7
  import { EXIT } from "../exit-codes.mjs";
7
8
  import { parseCommonArgs, getFlag } from "./args.mjs";
8
9
  import { USAGE } from "./help.mjs";
9
- import { formatCommitSuggestionResult, formatCleanResult, formatMarkFilesAsViewedResult, } from "./formatters.mjs";
10
+ import { formatCommitSuggestionResult, formatSuggestionPatchesResult, formatCleanResult, formatMarkFilesAsViewedResult, } from "./formatters.mjs";
11
+ import { parseSuggestionPatchGroups } from "./suggestion-patch-flags.mjs";
10
12
  import { parseIterateFlags } from "./iterate-flags.mjs";
11
13
  import { emitIterateResult } from "./iterate-emitter.mjs";
12
14
  import { parseMarkFilesAsViewedArgs } from "./mark-files-as-viewed-flags.mjs";
@@ -92,6 +94,23 @@ export async function handleCommitSuggestion(args, command = "build-suggestion-p
92
94
  ? `${JSON.stringify(result, null, 2)}\n`
93
95
  : `${formatCommitSuggestionResult(result)}\n`);
94
96
  }
97
+ export async function handleSuggestionPatches(args) {
98
+ const { prNumber, global: globalOpts, extra } = parseCommonArgs(args);
99
+ const parsed = parseSuggestionPatchGroups(extra);
100
+ if (!parsed.ok) {
101
+ process.stderr.write(`${parsed.error}\n${USAGE["build-suggestion-patches"]}\n`);
102
+ process.exitCode = EXIT.USAGE;
103
+ return;
104
+ }
105
+ const result = await runSuggestionPatches({
106
+ ...globalOpts,
107
+ prNumber,
108
+ suggestions: parsed.suggestions,
109
+ });
110
+ process.stdout.write(globalOpts.format === "json"
111
+ ? `${JSON.stringify(result, null, 2)}\n`
112
+ : `${formatSuggestionPatchesResult(result)}\n`);
113
+ }
95
114
  export async function handleIterate(args) {
96
115
  const { prNumber, global: globalOpts, extra } = parseCommonArgs(args);
97
116
  const cfg = loadConfig();
@@ -105,6 +124,7 @@ export async function handleIterate(args) {
105
124
  stallTimeoutSeconds: flags.stallTimeoutSeconds,
106
125
  noAutoMarkReady: flags.noAutoMarkReady,
107
126
  noAutoCancelActionable: flags.noAutoCancelActionable,
127
+ merge: flags.merge,
108
128
  });
109
129
  emitIterateResult(result, {
110
130
  format: globalOpts.format,
@@ -61,11 +61,27 @@ PR may be a number or GitHub pull request URL. An item must start with '- ' foll
61
61
  Use --file to read an item from a file, or --file - to read it from stdin. Exactly one item source
62
62
  is required. --dry-run previews the resulting body without writing it.
63
63
  --help, -h Print this help and exit before GitHub I/O.`;
64
- readonly "build-suggestion-patch": `pr-shepherd build-suggestion-patch
64
+ readonly "build-suggestion-patches": `pr-shepherd build-suggestion-patches
65
65
 
66
- Build a patch and commit instructions for one GitHub review thread containing a suggestion block.
66
+ Build an ordered list of patches and commit instructions from GitHub review suggestions.
67
67
  The command does not edit files or mutate git history.
68
68
 
69
+ Usage:
70
+ pr-shepherd build-suggestion-patches [PR]
71
+ --thread-id ID --message MSG [--description DESC]
72
+ [--thread-id ID --message MSG [--description DESC] ...]
73
+ [--format text|json]
74
+
75
+ Each --thread-id starts a suggestion group. Its following --message and optional --description
76
+ belong to that suggestion. Groups are validated and returned in command-line order.
77
+
78
+ The current branch must match the PR head ref. Local HEAD may equal or descend from the PR head;
79
+ every generated patch is dry-run in order with git apply --check before output.
80
+ --help, -h Print this help and exit before GitHub, git, config, or log I/O.`;
81
+ readonly "build-suggestion-patch": `pr-shepherd build-suggestion-patch
82
+
83
+ Deprecated one-suggestion adapter. Use build-suggestion-patches.
84
+
69
85
  Usage:
70
86
  pr-shepherd build-suggestion-patch [PR] --thread-id ID --message MSG
71
87
  [--description DESC] [--format text|json]
@@ -76,7 +92,7 @@ Flags:
76
92
  --description <text> Optional longer commit body.
77
93
  --format text|json Output format. Default: text.
78
94
 
79
- The current branch must match the PR head ref and local HEAD must match the PR head SHA.
95
+ The current branch must match the PR head ref. Local HEAD may equal or descend from the PR head.
80
96
  --help, -h Print this help and exit before GitHub, git, config, or log I/O.`;
81
97
  readonly admin: `pr-shepherd admin
82
98
 
@@ -149,7 +165,7 @@ Flags:
149
165
  --help, -h Print this help and exit before GitHub, git, config, or log I/O.
150
166
 
151
167
  Preconditions:
152
- The current branch must match the PR head ref, and local HEAD must match the PR head SHA.
168
+ The current branch must match the PR head ref. Local HEAD may equal or descend from the PR head.
153
169
 
154
170
  Exit codes:
155
171
  0 suggestion patch and instructions produced
@@ -176,8 +192,8 @@ Flags:
176
192
 
177
193
  PR may be a number or GitHub pull request URL. When omitted, the current branch PR is inferred.
178
194
  Exit code: 0 on success; nonzero on failure (sysexits.h — see docs/exit-codes.md).`;
179
- readonly iterate: "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number is minutes; decimals are allowed only with an explicit unit (4.5m).\n\nActions:\n WAIT No immediate action; continue with the next poll.\n MARK_READY Draft PR was marked ready; continue with the next poll.\n FIX_CODE Agent action is required; follow the instructions, then continue polling.\n CANCEL Stop polling: merged/closed or ready-delay elapsed.\n ESCALATE Stop polling until a human provides direction.\n\nExit codes:\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
180
- readonly poll: "pr-shepherd poll\n\nRun iterate repeatedly for WAIT ticks and during the FIX_CODE debounce window. Print only the\nfinal tick to stdout.\nPoll exits as soon as iterate returns MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR] [poll-flags] [iterate-flags]\n\nPoll flags:\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: 60s.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: 4.5m.\n --debounce <duration> Settle window after first FIX_CODE before returning. Bare number = seconds. Default: 60s. 0 disables.\n --quiet-status During WAIT polling, print only changed status snapshots.\n --until-terminal Continue through WAIT/MARK_READY until FIX_CODE/CANCEL/ESCALATE.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed per-tick lines.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number uses each flag's default unit (seconds\nfor --interval/--timeout/--debounce, minutes for --ready-delay/--stall-timeout); decimals are allowed only with\nan explicit unit (4.5m).\nEach WAIT tick writes an explicit still-running line to stderr by default; --quiet-status prints only changed WAIT snapshots, and --verbose emits detailed per-tick lines.\nFIX_CODE debounce writes a remaining-seconds line to stderr. --timeout does not cut an in-flight debounce short.\nWith --until-terminal, --timeout is ignored for WAIT ticks and polling continues until FIX_CODE, CANCEL, or ESCALATE.\n\nExit codes: same as iterate (the final tick's action/reason decides the code).\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT (including a WAIT returned by --timeout)\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
195
+ readonly iterate: "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number is minutes; decimals are allowed only with an explicit unit (4.5m).\n\nActions:\n WAIT No immediate action; continue with the next poll.\n MARK_READY Draft PR was marked ready; continue with the next poll.\n FIX_CODE Agent action is required; follow the instructions, then continue polling.\n CANCEL Stop polling: merged/closed or ready-delay elapsed.\n ESCALATE Stop polling until a human provides direction.\n MERGE Run the emitted merge/queue command, then continue monitoring.\n\nExit codes:\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
196
+ readonly poll: "pr-shepherd poll\n\nRun iterate repeatedly for WAIT ticks and during the FIX_CODE debounce window. Print only the\nfinal tick to stdout.\nPoll exits as soon as iterate returns MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal or --merge, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR] [poll-flags] [iterate-flags]\n\nPoll flags:\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: 60s.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: 4.5m.\n --debounce <duration> Settle window after first FIX_CODE before returning. Bare number = seconds. Default: 60s. 0 disables.\n --quiet-status During WAIT polling, print only changed status snapshots.\n --until-terminal Continue through WAIT/MARK_READY until FIX_CODE/CANCEL/ESCALATE.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed per-tick lines.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number uses each flag's default unit (seconds\nfor --interval/--timeout/--debounce, minutes for --ready-delay/--stall-timeout); decimals are allowed only with\nan explicit unit (4.5m).\nEach WAIT tick writes an explicit still-running line to stderr by default; --quiet-status prints only changed WAIT snapshots, and --verbose emits detailed per-tick lines.\nFIX_CODE debounce writes a remaining-seconds line to stderr. --timeout does not cut an in-flight debounce short.\nWith --until-terminal, --timeout is ignored for WAIT ticks and polling continues until FIX_CODE, MERGE, CANCEL, or ESCALATE. With --merge, --timeout still bounds WAIT ticks; it only continues through MARK_READY while polling remains within that timeout.\n\nExit codes: same as iterate (the final tick's action/reason decides the code).\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT (including a WAIT returned by --timeout)\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
181
197
  readonly clean: `pr-shepherd clean
182
198
 
183
199
  Remove pr-shepherd state files from PR_SHEPHERD_STATE_DIR.
@@ -64,11 +64,27 @@ PR may be a number or GitHub pull request URL. An item must start with '- ' foll
64
64
  Use --file to read an item from a file, or --file - to read it from stdin. Exactly one item source
65
65
  is required. --dry-run previews the resulting body without writing it.
66
66
  --help, -h Print this help and exit before GitHub I/O.`,
67
- "build-suggestion-patch": `pr-shepherd build-suggestion-patch
67
+ "build-suggestion-patches": `pr-shepherd build-suggestion-patches
68
68
 
69
- Build a patch and commit instructions for one GitHub review thread containing a suggestion block.
69
+ Build an ordered list of patches and commit instructions from GitHub review suggestions.
70
70
  The command does not edit files or mutate git history.
71
71
 
72
+ Usage:
73
+ pr-shepherd build-suggestion-patches [PR]
74
+ --thread-id ID --message MSG [--description DESC]
75
+ [--thread-id ID --message MSG [--description DESC] ...]
76
+ [--format text|json]
77
+
78
+ Each --thread-id starts a suggestion group. Its following --message and optional --description
79
+ belong to that suggestion. Groups are validated and returned in command-line order.
80
+
81
+ The current branch must match the PR head ref. Local HEAD may equal or descend from the PR head;
82
+ every generated patch is dry-run in order with git apply --check before output.
83
+ --help, -h Print this help and exit before GitHub, git, config, or log I/O.`,
84
+ "build-suggestion-patch": `pr-shepherd build-suggestion-patch
85
+
86
+ Deprecated one-suggestion adapter. Use build-suggestion-patches.
87
+
72
88
  Usage:
73
89
  pr-shepherd build-suggestion-patch [PR] --thread-id ID --message MSG
74
90
  [--description DESC] [--format text|json]
@@ -79,7 +95,7 @@ Flags:
79
95
  --description <text> Optional longer commit body.
80
96
  --format text|json Output format. Default: text.
81
97
 
82
- The current branch must match the PR head ref and local HEAD must match the PR head SHA.
98
+ The current branch must match the PR head ref. Local HEAD may equal or descend from the PR head.
83
99
  --help, -h Print this help and exit before GitHub, git, config, or log I/O.`,
84
100
  admin: `pr-shepherd admin
85
101
 
@@ -152,7 +168,7 @@ Flags:
152
168
  --help, -h Print this help and exit before GitHub, git, config, or log I/O.
153
169
 
154
170
  Preconditions:
155
- The current branch must match the PR head ref, and local HEAD must match the PR head SHA.
171
+ The current branch must match the PR head ref. Local HEAD may equal or descend from the PR head.
156
172
 
157
173
  Exit codes:
158
174
  0 suggestion patch and instructions produced
@@ -1,4 +1,4 @@
1
- export declare const ITERATE_USAGE = "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number is minutes; decimals are allowed only with an explicit unit (4.5m).\n\nActions:\n WAIT No immediate action; continue with the next poll.\n MARK_READY Draft PR was marked ready; continue with the next poll.\n FIX_CODE Agent action is required; follow the instructions, then continue polling.\n CANCEL Stop polling: merged/closed or ready-delay elapsed.\n ESCALATE Stop polling until a human provides direction.\n\nExit codes:\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
2
- export declare const POLL_USAGE = "pr-shepherd poll\n\nRun iterate repeatedly for WAIT ticks and during the FIX_CODE debounce window. Print only the\nfinal tick to stdout.\nPoll exits as soon as iterate returns MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR] [poll-flags] [iterate-flags]\n\nPoll flags:\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: 60s.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: 4.5m.\n --debounce <duration> Settle window after first FIX_CODE before returning. Bare number = seconds. Default: 60s. 0 disables.\n --quiet-status During WAIT polling, print only changed status snapshots.\n --until-terminal Continue through WAIT/MARK_READY until FIX_CODE/CANCEL/ESCALATE.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed per-tick lines.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number uses each flag's default unit (seconds\nfor --interval/--timeout/--debounce, minutes for --ready-delay/--stall-timeout); decimals are allowed only with\nan explicit unit (4.5m).\nEach WAIT tick writes an explicit still-running line to stderr by default; --quiet-status prints only changed WAIT snapshots, and --verbose emits detailed per-tick lines.\nFIX_CODE debounce writes a remaining-seconds line to stderr. --timeout does not cut an in-flight debounce short.\nWith --until-terminal, --timeout is ignored for WAIT ticks and polling continues until FIX_CODE, CANCEL, or ESCALATE.\n\nExit codes: same as iterate (the final tick's action/reason decides the code).\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT (including a WAIT returned by --timeout)\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
1
+ export declare const ITERATE_USAGE = "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number is minutes; decimals are allowed only with an explicit unit (4.5m).\n\nActions:\n WAIT No immediate action; continue with the next poll.\n MARK_READY Draft PR was marked ready; continue with the next poll.\n FIX_CODE Agent action is required; follow the instructions, then continue polling.\n CANCEL Stop polling: merged/closed or ready-delay elapsed.\n ESCALATE Stop polling until a human provides direction.\n MERGE Run the emitted merge/queue command, then continue monitoring.\n\nExit codes:\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
2
+ export declare const POLL_USAGE = "pr-shepherd poll\n\nRun iterate repeatedly for WAIT ticks and during the FIX_CODE debounce window. Print only the\nfinal tick to stdout.\nPoll exits as soon as iterate returns MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal or --merge, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR] [poll-flags] [iterate-flags]\n\nPoll flags:\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: 60s.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: 4.5m.\n --debounce <duration> Settle window after first FIX_CODE before returning. Bare number = seconds. Default: 60s. 0 disables.\n --quiet-status During WAIT polling, print only changed status snapshots.\n --until-terminal Continue through WAIT/MARK_READY until FIX_CODE/CANCEL/ESCALATE.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed per-tick lines.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number uses each flag's default unit (seconds\nfor --interval/--timeout/--debounce, minutes for --ready-delay/--stall-timeout); decimals are allowed only with\nan explicit unit (4.5m).\nEach WAIT tick writes an explicit still-running line to stderr by default; --quiet-status prints only changed WAIT snapshots, and --verbose emits detailed per-tick lines.\nFIX_CODE debounce writes a remaining-seconds line to stderr. --timeout does not cut an in-flight debounce short.\nWith --until-terminal, --timeout is ignored for WAIT ticks and polling continues until FIX_CODE, MERGE, CANCEL, or ESCALATE. With --merge, --timeout still bounds WAIT ticks; it only continues through MARK_READY while polling remains within that timeout.\n\nExit codes: same as iterate (the final tick's action/reason decides the code).\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT (including a WAIT returned by --timeout)\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
3
3
  /** Public help page for the default PR polling invocation. */
4
4
  export declare const DEFAULT_USAGE: string;
@@ -11,6 +11,7 @@ Iterate flags:
11
11
  --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.
12
12
  --no-auto-mark-ready Do not convert draft PRs to ready for review.
13
13
  --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.
14
+ --merge Shepherd through readiness, then emit a merge or merge-queue command.
14
15
  --format text|json Output Markdown text or JSON. Default: text.
15
16
  --verbose Include verbose iterate fields.
16
17
  --help, -h Print this help and exit before GitHub, git, config, or log I/O.
@@ -23,6 +24,7 @@ Actions:
23
24
  FIX_CODE Agent action is required; follow the instructions, then continue polling.
24
25
  CANCEL Stop polling: merged/closed or ready-delay elapsed.
25
26
  ESCALATE Stop polling until a human provides direction.
27
+ MERGE Run the emitted merge/queue command, then continue monitoring.
26
28
 
27
29
  Exit codes:
28
30
  0 CANCEL (merged or ready-delay elapsed)
@@ -31,6 +33,7 @@ Exit codes:
31
33
  12 FIX_CODE
32
34
  13 ESCALATE
33
35
  14 CANCEL (closed without merging)
36
+ 15 MERGE
34
37
  A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).`;
35
38
  export const POLL_USAGE = `pr-shepherd poll
36
39
 
@@ -39,7 +42,7 @@ final tick to stdout.
39
42
  Poll exits as soon as iterate returns MARK_READY, CANCEL, or ESCALATE, or when timeout
40
43
  returns the last WAIT result. FIX_CODE starts a --debounce settle window (default 1m): poll keeps
41
44
  iterating at --interval, then runs one more tick after the window and returns that result.
42
- With --until-terminal, poll also continues through MARK_READY.
45
+ With --until-terminal or --merge, poll also continues through MARK_READY.
43
46
 
44
47
  Usage:
45
48
  pr-shepherd poll [PR] [poll-flags] [iterate-flags]
@@ -56,6 +59,7 @@ Forwarded iterate flags:
56
59
  --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.
57
60
  --no-auto-mark-ready Do not convert draft PRs to ready for review.
58
61
  --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.
62
+ --merge Shepherd through readiness, then emit a merge or merge-queue command.
59
63
  --format text|json Output Markdown text or JSON. Default: text.
60
64
  --verbose Include verbose iterate fields and detailed per-tick lines.
61
65
  --help, -h Print this help and exit before GitHub, git, config, or log I/O.
@@ -65,7 +69,7 @@ for --interval/--timeout/--debounce, minutes for --ready-delay/--stall-timeout);
65
69
  an explicit unit (4.5m).
66
70
  Each WAIT tick writes an explicit still-running line to stderr by default; --quiet-status prints only changed WAIT snapshots, and --verbose emits detailed per-tick lines.
67
71
  FIX_CODE debounce writes a remaining-seconds line to stderr. --timeout does not cut an in-flight debounce short.
68
- With --until-terminal, --timeout is ignored for WAIT ticks and polling continues until FIX_CODE, CANCEL, or ESCALATE.
72
+ With --until-terminal, --timeout is ignored for WAIT ticks and polling continues until FIX_CODE, MERGE, CANCEL, or ESCALATE. With --merge, --timeout still bounds WAIT ticks; it only continues through MARK_READY while polling remains within that timeout.
69
73
 
70
74
  Exit codes: same as iterate (the final tick's action/reason decides the code).
71
75
  0 CANCEL (merged or ready-delay elapsed)
@@ -74,6 +78,7 @@ Exit codes: same as iterate (the final tick's action/reason decides the code).
74
78
  12 FIX_CODE
75
79
  13 ESCALATE
76
80
  14 CANCEL (closed without merging)
81
+ 15 MERGE
77
82
  A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).`;
78
83
  /** Public help page for the default PR polling invocation. */
79
84
  export const DEFAULT_USAGE = POLL_USAGE.replace(/^pr-shepherd poll$/m, "pr-shepherd [PR]").replace(/^ {2}pr-shepherd poll \[PR\]/m, " pr-shepherd [PR]");
@@ -1 +1 @@
1
- export declare const TOP_USAGE = "pr-shepherd\n\nAutonomous PR CI monitor and review-comment resolver for agentic coding tools.\n\nUsage:\n pr-shepherd --version | -v\n pr-shepherd --help | -h\n pr-shepherd [PR] [poll-flags] [iterate-flags]\n pr-shepherd iterate [PR] [iterate-flags]\n pr-shepherd apply review [PR] [review-flags]\n pr-shepherd apply files [PR] [files...] [--tests] [--match REGEX]\n pr-shepherd apply journal [PR] <item> [--dry-run] [--format text|json]\n pr-shepherd build-suggestion-patch [PR] --thread-id ID --message MSG [flags]\n pr-shepherd admin clean <pr|branch|current|repo|all> [value] [flags]\n pr-shepherd admin log-file [--format text|json]\n\nCommands:\n [PR] Poll until non-WAIT or timeout. This is the default command.\n iterate Run one iterate tick (single-tick alias).\n apply review Apply review-state mutations after fixes.\n apply files Mark changed files as viewed in GitHub.\n apply journal Append a list item to the Shepherd Journal details block of a PR body.\n build-suggestion-patch\n Convert one GitHub suggestion thread into a patch and commit instructions.\n admin clean Remove pr-shepherd state files.\n admin log-file Print the per-worktree debug log path.\n\nPR argument:\n PR may be a number such as 42 or a GitHub pull request URL.\n When omitted, pr-shepherd infers the current branch's pull request.\n\nCommon flags:\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed poll-tick lines.\n --help, -h Print help and exit before any GitHub, git, config, or log I/O.\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n\nPolling flags:\n --interval <duration> Delay between WAIT ticks. Bare number = seconds. Default: 60s.\n --timeout <duration> Poll wall-clock cap for WAIT ticks. Bare number = seconds. Default: 4.5m.\n --debounce <duration> Settle window after first FIX_CODE before returning. Bare number = seconds. Default: 60s. 0 disables.\n --quiet-status During WAIT polling, print only changed status snapshots.\n --until-terminal Continue through WAIT/MARK_READY until FIX_CODE/CANCEL/ESCALATE.\n\nClean variants:\n pr [number] Remove state for one PR. Defaults to current branch PR.\n branch [name] Remove state for a branch's PR. Defaults to current branch.\n current Alias for branch against the current branch.\n repo Remove all state for the current repository.\n all Remove all pr-shepherd state.\n\nExit codes: 0 done, 10-19 PR state, 64-78 shepherd failed (sysexits.h).\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\nSee docs/exit-codes.md for the full sysexits.h error-code table.\n\nDuration examples: 30s, 4.5m, 1h. A bare number uses each flag's default unit (see above); decimals are allowed with an explicit unit (4.5m).\n\nRun 'pr-shepherd <command> --help' for command-specific details.";
1
+ export declare const TOP_USAGE = "pr-shepherd\n\nAutonomous PR CI monitor and review-comment resolver for agentic coding tools.\n\nUsage:\n pr-shepherd --version | -v\n pr-shepherd --help | -h\n pr-shepherd [PR] [poll-flags] [iterate-flags]\n pr-shepherd iterate [PR] [iterate-flags]\n pr-shepherd apply review [PR] [review-flags]\n pr-shepherd apply files [PR] [files...] [--tests] [--match REGEX]\n pr-shepherd apply journal [PR] <item> [--dry-run] [--format text|json]\n pr-shepherd build-suggestion-patches [PR] --thread-id ID --message MSG [groups...]\n pr-shepherd admin clean <pr|branch|current|repo|all> [value] [flags]\n pr-shepherd admin log-file [--format text|json]\n\nCommands:\n [PR] Poll until non-WAIT or timeout. This is the default command.\n iterate Run one iterate tick (single-tick alias).\n apply review Apply review-state mutations after fixes.\n apply files Mark changed files as viewed in GitHub.\n apply journal Append a list item to the Shepherd Journal details block of a PR body.\n build-suggestion-patches\n Convert ordered GitHub suggestion threads into patches and commit instructions.\n admin clean Remove pr-shepherd state files.\n admin log-file Print the per-worktree debug log path.\n\nPR argument:\n PR may be a number such as 42 or a GitHub pull request URL.\n When omitted, pr-shepherd infers the current branch's pull request.\n\nCommon flags:\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed poll-tick lines.\n --help, -h Print help and exit before any GitHub, git, config, or log I/O.\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Do not convert draft PRs to ready for review.\n --no-auto-cancel-actionable Do not cancel in-progress runs before actionable fixes.\n\nPolling flags:\n --interval <duration> Delay between WAIT ticks. Bare number = seconds. Default: 60s.\n --timeout <duration> Poll wall-clock cap for WAIT ticks. Bare number = seconds. Default: 4.5m.\n --debounce <duration> Settle window after first FIX_CODE before returning. Bare number = seconds. Default: 60s. 0 disables.\n --quiet-status During WAIT polling, print only changed status snapshots.\n --until-terminal Continue through WAIT/MARK_READY until FIX_CODE/CANCEL/ESCALATE.\n\nClean variants:\n pr [number] Remove state for one PR. Defaults to current branch PR.\n branch [name] Remove state for a branch's PR. Defaults to current branch.\n current Alias for branch against the current branch.\n repo Remove all state for the current repository.\n all Remove all pr-shepherd state.\n\nExit codes: 0 done, 10-19 PR state, 64-78 shepherd failed (sysexits.h).\n 0 CANCEL (merged or ready-delay elapsed)\n 10 WAIT\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\nSee docs/exit-codes.md for the full sysexits.h error-code table.\n\nDuration examples: 30s, 4.5m, 1h. A bare number uses each flag's default unit (see above); decimals are allowed with an explicit unit (4.5m).\n\nRun 'pr-shepherd <command> --help' for command-specific details.";