pr-shepherd 0.42.0 → 0.44.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 (145) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +24 -18
  3. package/bin/api.d.mts +3 -2
  4. package/bin/api.mjs +13 -18
  5. package/bin/checks/classify.d.mts +3 -1
  6. package/bin/checks/classify.mjs +5 -2
  7. package/bin/cli/args.mjs +14 -9
  8. package/bin/cli/default-poll.mjs +1 -0
  9. package/bin/cli/fix-formatter.mjs +20 -8
  10. package/bin/cli/handlers.mjs +1 -0
  11. package/bin/cli/help-command-pages.d.mts +9 -6
  12. package/bin/cli/help-command-pages.mjs +7 -4
  13. package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
  14. package/bin/cli/help-iterate-poll-pages.mjs +9 -4
  15. package/bin/cli/help-top-page.d.mts +1 -1
  16. package/bin/cli/help-top-page.mjs +2 -2
  17. package/bin/cli/help.d.mts +10 -7
  18. package/bin/cli/iterate-flags.d.mts +1 -0
  19. package/bin/cli/iterate-flags.mjs +2 -0
  20. package/bin/cli/iterate-formatter.d.mts +1 -1
  21. package/bin/cli/iterate-formatter.mjs +9 -6
  22. package/bin/cli/iterate-instructions.mjs +15 -0
  23. package/bin/cli/iterate-lean.d.mts +1 -2
  24. package/bin/cli/iterate-lean.mjs +16 -17
  25. package/bin/cli/iterate-merge-formatter.d.mts +3 -0
  26. package/bin/cli/iterate-merge-formatter.mjs +52 -0
  27. package/bin/cli/iterate-verbose.d.mts +6 -0
  28. package/bin/cli/iterate-verbose.mjs +14 -0
  29. package/bin/cli/journal-formatter.mjs +3 -0
  30. package/bin/cli/journal-handler.mjs +11 -7
  31. package/bin/cli/list-formatters.d.mts +3 -1
  32. package/bin/cli/list-formatters.mjs +9 -7
  33. package/bin/cli/mark-files-as-viewed-formatter.mjs +7 -1
  34. package/bin/cli/mutate-formatter.mjs +4 -0
  35. package/bin/cli/poll-handler.mjs +1 -0
  36. package/bin/cli/runner.mjs +4 -3
  37. package/bin/commands/check-terminal-report.mjs +1 -0
  38. package/bin/commands/check.mjs +64 -7
  39. package/bin/commands/commit-suggestion-instruction.d.mts +1 -1
  40. package/bin/commands/commit-suggestion-instruction.mjs +2 -2
  41. package/bin/commands/commit-suggestion.mjs +3 -1
  42. package/bin/commands/iterate/base.d.mts +5 -0
  43. package/bin/commands/iterate/base.mjs +25 -0
  44. package/bin/commands/iterate/check-instructions.d.mts +5 -19
  45. package/bin/commands/iterate/check-instructions.mjs +24 -25
  46. package/bin/commands/iterate/classify.d.mts +2 -2
  47. package/bin/commands/iterate/classify.mjs +43 -25
  48. package/bin/commands/iterate/escalate.d.mts +3 -1
  49. package/bin/commands/iterate/escalate.mjs +29 -2
  50. package/bin/commands/iterate/fix-code.mjs +81 -26
  51. package/bin/commands/iterate/helpers.d.mts +0 -2
  52. package/bin/commands/iterate/helpers.mjs +6 -17
  53. package/bin/commands/iterate/index.mjs +31 -43
  54. package/bin/commands/iterate/mark-ready.d.mts +2 -0
  55. package/bin/commands/iterate/mark-ready.mjs +38 -0
  56. package/bin/commands/iterate/merge-state.d.mts +15 -0
  57. package/bin/commands/iterate/merge-state.mjs +82 -0
  58. package/bin/commands/iterate/merge.d.mts +13 -0
  59. package/bin/commands/iterate/merge.mjs +45 -0
  60. package/bin/commands/iterate/render.d.mts +2 -2
  61. package/bin/commands/iterate/render.mjs +19 -20
  62. package/bin/commands/iterate/stall.mjs +4 -2
  63. package/bin/commands/iterate/thread-mutation-routing.d.mts +9 -0
  64. package/bin/commands/iterate/thread-mutation-routing.mjs +29 -0
  65. package/bin/commands/journal/index.d.mts +5 -0
  66. package/bin/commands/journal/index.mjs +11 -2
  67. package/bin/commands/mark-files-as-viewed.d.mts +2 -1
  68. package/bin/commands/mark-files-as-viewed.mjs +5 -92
  69. package/bin/commands/poll.mjs +3 -1
  70. package/bin/commands/resolve-mutate.mjs +51 -9
  71. package/bin/commands/shepherd-journal.d.mts +1 -1
  72. package/bin/commands/shepherd-journal.mjs +2 -2
  73. package/bin/commands/suggestion-patch-item.d.mts +1 -1
  74. package/bin/commands/suggestion-patch-item.mjs +3 -11
  75. package/bin/commands/suggestion-patches.mjs +3 -3
  76. package/bin/comments/authors.d.mts +6 -0
  77. package/bin/comments/authors.mjs +5 -0
  78. package/bin/comments/marker.d.mts +6 -1
  79. package/bin/comments/marker.mjs +8 -1
  80. package/bin/comments/resolve.d.mts +4 -0
  81. package/bin/comments/thread-visibility.mjs +10 -10
  82. package/bin/comments/visible-comments.mjs +2 -1
  83. package/bin/config/load.d.mts +5 -1
  84. package/bin/config/load.mjs +34 -0
  85. package/bin/config/merge-command-args.d.mts +2 -0
  86. package/bin/config/merge-command-args.mjs +44 -0
  87. package/bin/config.json +3 -0
  88. package/bin/exit-codes.d.mts +2 -0
  89. package/bin/exit-codes.mjs +4 -0
  90. package/bin/github/batch-parse-checks.d.mts +3 -0
  91. package/bin/github/batch-parse-checks.mjs +29 -0
  92. package/bin/github/batch-parsers-rules.d.mts +3 -1
  93. package/bin/github/batch-parsers-rules.mjs +33 -0
  94. package/bin/github/batch-parsers.d.mts +2 -2
  95. package/bin/github/batch-parsers.mjs +40 -27
  96. package/bin/github/batch-raw-rules.d.mts +48 -0
  97. package/bin/github/batch-raw-types.d.mts +12 -0
  98. package/bin/github/batch-raw-types.mjs +0 -1
  99. package/bin/github/batch.mjs +3 -1
  100. package/bin/github/client.d.mts +1 -0
  101. package/bin/github/client.mjs +8 -1
  102. package/bin/github/gql/batch-pr-page.gql +6 -0
  103. package/bin/github/gql/batch-pr.gql +105 -0
  104. package/bin/github/gql/commit-check-contexts.gql +58 -0
  105. package/bin/github/gql/get-pr-body.gql +1 -0
  106. package/bin/github/gql/review-thread-comments.gql +1 -0
  107. package/bin/github/gql/suggestion-threads.gql +1 -0
  108. package/bin/github/merge-queue-checks.d.mts +4 -0
  109. package/bin/github/merge-queue-checks.mjs +48 -0
  110. package/bin/github/queries.d.mts +2 -0
  111. package/bin/github/queries.mjs +2 -0
  112. package/bin/github/suggestion-thread.mjs +1 -0
  113. package/bin/mcp/server.mjs +13 -6
  114. package/bin/pr-reference.d.mts +13 -0
  115. package/bin/pr-reference.mjs +23 -1
  116. package/bin/reporters/agent.mjs +11 -3
  117. package/bin/threads/transcript.d.mts +2 -0
  118. package/bin/threads/transcript.mjs +2 -0
  119. package/bin/types/activity.d.mts +2 -0
  120. package/bin/types/agent-thread.d.mts +1 -0
  121. package/bin/types/escalate.d.mts +35 -0
  122. package/bin/types/escalate.mjs +1 -0
  123. package/bin/types/github.d.mts +27 -0
  124. package/bin/types/github.mjs +0 -3
  125. package/bin/types/iterate.d.mts +23 -39
  126. package/bin/types/merge-action.d.mts +12 -0
  127. package/bin/types/merge-action.mjs +1 -0
  128. package/bin/types/merge-queue.d.mts +13 -0
  129. package/bin/types/merge-queue.mjs +1 -0
  130. package/bin/types/merge-requirements.d.mts +17 -0
  131. package/bin/types/report.d.mts +22 -1
  132. package/bin/types/review-thread.d.mts +1 -0
  133. package/bin/types/suggestion-patch.d.mts +1 -1
  134. package/bin/types.d.mts +3 -0
  135. package/bin/types.mjs +3 -0
  136. package/bin/util/markdown.d.mts +2 -0
  137. package/bin/util/markdown.mjs +7 -0
  138. package/package.json +1 -1
  139. package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
  140. package/plugins/pr-shepherd/.codex.mcp.json +1 -1
  141. package/plugins/pr-shepherd/.mcp.json +1 -1
  142. package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +3 -3
  143. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +17 -15
  144. package/bin/commands/iterate/reruns.d.mts +0 -20
  145. package/bin/commands/iterate/reruns.mjs +0 -105
@@ -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.42.0",
4
+ "version": "0.44.0",
5
5
  "author": {
6
6
  "name": "Jonathan Ong",
7
7
  "email": "jonathanrichardong@gmail.com"
package/README.md CHANGED
@@ -9,7 +9,7 @@ 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_patches` operations. 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
 
@@ -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 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.
28
+ The MCP server exposes canonical `iterate`, `apply`, and `build_suggestion_patches` tools. `apply` accepts ordered review mutations, selection-only file-view diagnostics, 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`; the explicit repository is the target for GitHub I/O, even when it differs from the local checkout. 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 command only when GitHub reports `viewerCanEnableAutoMerge`; queue enrollment otherwise hands off for authorization.
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
 
@@ -58,7 +59,7 @@ Conversations Resolved: No [Not Required]
58
59
  - `24697658766` — `CI › lint / typecheck / test (22.x)` [conclusion: FAILURE]
59
60
  > oxfmt
60
61
 
61
- ## Post-fix push
62
+ ## Post-fix actions
62
63
 
63
64
  - base: `main`
64
65
  - apply review: `pr-shepherd apply review 123 --reply-thread-ids PRRT_kwDOSGizTs58XB1L --message "$DISMISS_MESSAGE" --require-sha "$HEAD_SHA"`
@@ -67,27 +68,28 @@ Conversations Resolved: No [Not Required]
67
68
 
68
69
  1. Review each item under `## Review threads` and `## Failing checks` and decide whether it needs a code change.
69
70
  2. Apply every warranted review fix in each file referenced above.
70
- 3. Triage every failure under `## Failing checks`. See "CI failure triage" in the pr-shepherd skill for `gh run view` / `gh run rerun` rules.
71
- 4. If you changed code, commit any remaining changes and push before review mutations. Otherwise, do not commit or push.
72
- 5. Before `apply review:`, remove any `--reply-thread-ids` entry whose latest visible comment is your own Shepherd reply. Do not reply to yourself.
73
- 6. Replace `$HEAD_SHA` with the pushed commit SHA, or `$(git rev-parse HEAD)` if you did not push.
71
+ 3. Triage every failure under `## Failing checks`. See "CI failure triage" in the pr-shepherd skill for read-only inspection rules.
72
+ 4. If you changed code, commit any remaining changes, then stop and hand off for a push whose authorization is established outside Shepherd; do not run review mutations or iterate until the remote PR head changes. If you did not change code, do not commit and continue.
73
+ 5. Run the generated thread IDs unchanged. A latest comment beginning `<!-- pr-shepherd -->` is an earlier Shepherd reply: a marked viewer-authored human thread is emitted resolve-only when authorized, while a marked other-human thread is already acknowledged and has no further mutation.
74
+ 6. If you did not change code, replace `$HEAD_SHA` with `$(git rev-parse HEAD)`, which must equal the current remote PR head. After changed code, wait for an authorized push and use its SHA.
74
75
  7. Replace `$DISMISS_MESSAGE` with one sentence describing what changed.
75
76
  8. Run the `apply review:` command shown above. See "Review-mutation mechanics" in the pr-shepherd skill for dismiss-ID retention.
76
- 9. `[FIX_CODE]` is non-terminal. After completing these steps, iterate again with the same options to continue.
77
+ 9. `[FIX_CODE]` is conditional: after changed code, stop until an authorized push changes the remote PR head; without code changes, complete the authorized review mutations and iterate again.
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
 
83
84
  This system is opinionated and works best with PRs that use required status checks and conversation resolution.
84
85
 
85
- - Human-authored threads are replied to, not resolved or minimized by Shepherd.
86
+ - A human inline thread whose original comment has `viewerDidAuthor: true` is replied to and resolved when its latest comment is unmarked. An unmarked other-human inline thread remains reply-only; a marker-ended other-human thread is already acknowledged and receives no further mutation. Human items are never minimized.
86
87
  - Detected bots and configured `botUsernames` review threads are returned until resolved; bot/non-human threads, PR comments, and review summaries can be resolved or minimized when eligible. Review summaries are not minimized while known inline child threads from that review remain unresolved.
87
- - Agents must not reply to their own latest thread reply; generated instructions call this out before `--reply-thread-ids` mutations.
88
+ - Shepherd identifies its own latest reply only when that comment begins `<!-- pr-shepherd -->`, not from author equality. A marked viewer-authored thread can be resolved without another reply as a retry.
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
- - The CLI never performs git mutations. It emits instructions; the caller commits, rebases, pushes, and handles repository hooks.
91
+ - The CLI never performs git mutations. It may emit local commit guidance, but it does not recommend a push because GitHub viewer fields cannot verify the local Git credential.
92
+ - Every GitHub mutation is permission-aware. Shepherd uses raw viewer capability fields, omits unauthorized commands, and repeats authorization checks in direct `apply` commands. Missing capability data fails closed.
91
93
  - `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
94
 
93
95
  ## Usage
@@ -126,12 +128,15 @@ pr-shepherd 42 --quiet-status # print only changed WAIT status snapshot
126
128
  pr-shepherd 42 --until-terminal # continue through WAIT/MARK_READY until work or terminal state
127
129
  pr-shepherd 42 --debounce 5m # wait 5m after first FIX_CODE, then return one batched tick
128
130
  pr-shepherd 42 --ready-delay 15m
131
+ pr-shepherd 42 --merge # enable auto-merge when GitHub confirms viewer authorization
129
132
  pr-shepherd iterate 42 # single tick
133
+ pr-shepherd owner/repo#42 # poll a PR in an explicit repository
134
+ pr-shepherd https://github.com/owner/repo/pull/42
130
135
  ```
131
136
 
132
- ### Apply Review, File, And Journal Changes
137
+ ### Apply Review And Journal Changes, Or Select Files
133
138
 
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_patches` to turn ordered review suggestions into checked patches and commit metadata; it never changes the worktree or git history.
139
+ Use `apply` with ordered operations to reply/resolve/minimize/dismiss review items, select changed files for viewed-state authorization diagnostics, or append an idempotent Shepherd Journal item. File-view selection never mutates viewed state because GitHub exposes no exact viewer capability. Use `build_suggestion_patches` to turn ordered review suggestions into checked patches and commit metadata; it never changes the worktree or git history.
135
140
 
136
141
  ### Extract Shepherd Journal Entries
137
142
 
@@ -236,12 +241,13 @@ checks:
236
241
  ciTriggerEvents:
237
242
  - pull_request
238
243
  - pull_request_target
239
- - merge_group
244
+ merge:
245
+ commandArgs:
246
+ - --squash
247
+ - --delete-branch
240
248
  actions:
241
249
  autoMinimizeSuppressed: true
242
250
  autoMarkReady: false
243
- neverCancelRuns:
244
- - "Final Code Review"
245
251
  ```
246
252
 
247
253
  Environment variables:
@@ -268,7 +274,7 @@ const rule: ClassifyRule = (item) => {
268
274
  export default rule;
269
275
  ```
270
276
 
271
- `suppress: true` hides the item from agent output. `autoResolve: true` queues it for the minimize/resolve mutation. When both apply together, Shepherd performs that mutation silently during `iterate` by default (`actions.autoMinimizeSuppressed: true`) so repetitive bot noise does not create a `fix_code` handoff.
277
+ `suppress: true` hides the item from agent output. `autoResolve: true` queues it for the minimize/resolve mutation. When both apply together, Shepherd performs that mutation silently during `iterate` by default (`actions.autoMinimizeSuppressed: true`) only when GitHub reports the exact per-object capability. Denied or unverifiable items return to the normal first-look/edit visibility gate and produce no mutation recommendation.
272
278
 
273
279
  TypeScript rules are loaded by the runtime's native TypeScript support; keep them to erasable syntax such as type annotations and `import type`. Runtime TypeScript features that need transpilation, such as enums, namespaces, parameter properties, and decorators, are not supported. Use `.mts` for portable ESM rules across Node, Bun, and Deno.
274
280
 
package/bin/api.d.mts CHANGED
@@ -8,7 +8,7 @@ export interface CreatePrShepherdOptions {
8
8
  }
9
9
  /** A positive PR number, GitHub pull-request URL, or owner/repo#number reference. */
10
10
  export type PrReference = number | string;
11
- export type IterateInput = Omit<IterateCommandOptions, "format" | "prNumber"> & {
11
+ export type IterateInput = Omit<IterateCommandOptions, "format" | "prNumber" | "targetRepository"> & {
12
12
  pr?: PrReference;
13
13
  };
14
14
  export interface ReviewMutationsOperation {
@@ -22,6 +22,7 @@ export interface ReviewMutationsOperation {
22
22
  requireSha?: string;
23
23
  }
24
24
  export interface MarkFilesViewedOperation {
25
+ /** Compatibility-named selection only; always skips mutation because authorization is unverifiable. */
25
26
  type: "mark_files_viewed";
26
27
  files?: string[];
27
28
  tests?: boolean;
@@ -32,7 +33,7 @@ export interface AppendJournalOperation {
32
33
  item: string;
33
34
  dryRun?: boolean;
34
35
  }
35
- /** Mutations are run in this exact list order after every operation is validated. */
36
+ /** Operations run in this exact list order after validation; file-view selection is non-mutating. */
36
37
  export type ApplyOperation = ReviewMutationsOperation | MarkFilesViewedOperation | AppendJournalOperation;
37
38
  export interface ApplyInput {
38
39
  /** PR shared by every operation in this ordered apply request. */
package/bin/api.mjs CHANGED
@@ -8,8 +8,7 @@ import { validateJournalItem } from "./commands/journal/transform.mjs";
8
8
  import { runMarkFilesAsViewed, } from "./commands/mark-files-as-viewed.mjs";
9
9
  import { runResolveMutate } from "./commands/resolve-mutate.mjs";
10
10
  import { runWithExecutionCwd } from "./execution-context.mjs";
11
- import { getRepoInfo } from "./github/client.mjs";
12
- import { parsePrReference } from "./pr-reference.mjs";
11
+ import { parsePrReference, resolveParsedPrTarget, } from "./pr-reference.mjs";
13
12
  /** Raised before any API mutation when an input cannot be validated. */
14
13
  export class PrShepherdValidationError extends Error {
15
14
  constructor(message) {
@@ -39,14 +38,14 @@ export function createPrShepherd(options = {}) {
39
38
  iterate(input = {}) {
40
39
  const { pr: _pr, ...options } = input;
41
40
  return runWithExecutionCwd(cwd, async () => {
42
- const prNumber = await resolvePrReference(input.pr);
43
- return runIterate({ ...options, prNumber, format: "json" });
41
+ const target = resolvePrReference(input.pr);
42
+ return runIterate({ ...options, ...target, format: "json" });
44
43
  });
45
44
  },
46
45
  apply(input) {
47
46
  return runWithExecutionCwd(cwd, async () => {
48
47
  validateApplyInput(input);
49
- const prNumber = await resolvePrReference(input.pr);
48
+ const { prNumber, targetRepository } = resolvePrReference(input.pr);
50
49
  const results = [];
51
50
  for (let index = 0; index < input.operations.length; index += 1) {
52
51
  const operation = input.operations[index];
@@ -57,6 +56,7 @@ export function createPrShepherd(options = {}) {
57
56
  const result = await runResolveMutate({
58
57
  ...options,
59
58
  prNumber,
59
+ targetRepository,
60
60
  dismissMessage: message,
61
61
  format: "json",
62
62
  });
@@ -66,6 +66,7 @@ export function createPrShepherd(options = {}) {
66
66
  case "mark_files_viewed": {
67
67
  const result = await runMarkFilesAsViewed({
68
68
  prNumber,
69
+ targetRepository,
69
70
  files: operation.files ?? [],
70
71
  tests: operation.tests,
71
72
  matchPatterns: operation.matchPatterns,
@@ -77,6 +78,7 @@ export function createPrShepherd(options = {}) {
77
78
  case "append_journal": {
78
79
  const result = await runJournal({
79
80
  prNumber,
81
+ targetRepository,
80
82
  rawItem: operation.item,
81
83
  dryRun: operation.dryRun ?? false,
82
84
  });
@@ -98,16 +100,16 @@ export function createPrShepherd(options = {}) {
98
100
  validateSuggestionPatchInput(input);
99
101
  const { pr: _pr, ...options } = input;
100
102
  return runWithExecutionCwd(cwd, async () => {
101
- const prNumber = await resolvePrReference(input.pr);
102
- return runCommitSuggestion({ ...options, prNumber, format: "json" });
103
+ const target = resolvePrReference(input.pr);
104
+ return runCommitSuggestion({ ...options, ...target, format: "json" });
103
105
  });
104
106
  },
105
107
  buildSuggestionPatches(input) {
106
108
  validateSuggestionPatchesInput(input);
107
109
  const { pr: _pr, ...options } = input;
108
110
  return runWithExecutionCwd(cwd, async () => {
109
- const prNumber = await resolvePrReference(input.pr);
110
- return runSuggestionPatches({ ...options, prNumber, format: "json" });
111
+ const target = resolvePrReference(input.pr);
112
+ return runSuggestionPatches({ ...options, ...target, format: "json" });
111
113
  });
112
114
  },
113
115
  });
@@ -234,16 +236,9 @@ function validatePrReference(pr) {
234
236
  return parsed;
235
237
  throw new PrShepherdValidationError("pr must be a positive number, a GitHub pull-request URL, or owner/repo#number");
236
238
  }
237
- async function resolvePrReference(pr) {
239
+ function resolvePrReference(pr) {
238
240
  const parsed = validatePrReference(pr);
239
- if (parsed.repository !== undefined) {
240
- const repo = await getRepoInfo();
241
- const currentRepository = `${repo.owner}/${repo.name}`;
242
- if (parsed.repository.toLowerCase() !== currentRepository.toLowerCase()) {
243
- throw new PrShepherdValidationError(`PR reference repository ${parsed.repository} does not match the configured repository ${currentRepository}`);
244
- }
245
- }
246
- return parsed.number;
241
+ return resolveParsedPrTarget(parsed);
247
242
  }
248
243
  function validateStringArray(value, label) {
249
244
  if (value !== undefined &&
@@ -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
@@ -2,6 +2,7 @@
2
2
  * CLI argument-parsing helpers extracted from cli.mts for testability.
3
3
  */
4
4
  import { parseArgs } from "node:util";
5
+ import { parseCliPrReference, resolveParsedPrTarget } from "../pr-reference.mjs";
5
6
  // Flags that consume the next argument as their value (used for PR-number
6
7
  // detection only — prevents a flag's value from being mistaken for a PR number).
7
8
  const FLAGS_WITH_VALUES = new Set([
@@ -30,6 +31,7 @@ const BOOLEAN_FLAGS = new Set([
30
31
  "--no-auto-cancel-actionable",
31
32
  "--quiet-status",
32
33
  "--until-terminal",
34
+ "--merge",
33
35
  "--dry-run",
34
36
  "--verbose",
35
37
  ]);
@@ -100,25 +102,28 @@ export function parseCommonArgs(args) {
100
102
  }
101
103
  }
102
104
  const prIndex = args.findIndex((a, index) => !skipForPrDetect.has(index) && !a.startsWith("--") && parsePrNumber(a) !== null);
103
- const prNumber = prIndex !== -1 ? parsePrNumber(args[prIndex]) : undefined;
105
+ const target = prIndex !== -1
106
+ ? resolveParsedPrTarget(parseCliPrReference(args[prIndex]))
107
+ : { prNumber: undefined };
104
108
  // Remove consumed global-flag indices (and the PR number itself) from extra.
105
109
  if (prIndex !== -1) {
106
110
  consumedIndices.add(prIndex);
107
111
  }
108
112
  const extra = args.filter((_, i) => !consumedIndices.has(i));
109
113
  return {
110
- prNumber,
111
- global: { format, verbose },
114
+ prNumber: target.prNumber,
115
+ global: {
116
+ format,
117
+ verbose,
118
+ ...(target.targetRepository !== undefined
119
+ ? { targetRepository: target.targetRepository }
120
+ : undefined),
121
+ },
112
122
  extra,
113
123
  };
114
124
  }
115
125
  export function parsePrNumber(value) {
116
- if (/^\d+$/.test(value))
117
- return parseInt(value, 10);
118
- const match = value.match(/^https?:\/\/github\.com\/[^/]+\/[^/]+\/pull\/(\d+)(?:[/?#].*)?$/);
119
- if (match)
120
- return parseInt(match[1], 10);
121
- return null;
126
+ return parseCliPrReference(value)?.number ?? null;
122
127
  }
123
128
  /** Get the value of a flag like `--flag value` or `--flag=value`. */
124
129
  export function getFlag(args, name) {
@@ -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,12 @@
1
+ /* eslint-disable max-lines */
1
2
  import { renderResolveCommand } from "../commands/iterate/render.mjs";
2
- import { joinSections } from "../util/markdown.mjs";
3
+ import { inlineCode, joinSections } from "../util/markdown.mjs";
3
4
  import { renderSuggestionBlock, renderLineRange } from "./suggestion-renderer.mjs";
4
5
  import { renderThreadBullet, renderReviewBullet, renderThreadResolutionStatusTag, renderAuthor, buildFirstLookBullets, renderThreadConversation, blockquote, } from "./list-formatters.mjs";
5
6
  import { numberInstructions } from "./iterate-instructions.mjs";
6
7
  import { renderCheckAnnotation, renderProtectedRun } from "./fix-formatter-extra.mjs";
7
8
  import { isFailingAgentCheck } from "../checks/conclusions.mjs";
9
+ import { renderMergeCommand } from "../commands/iterate/merge.mjs";
8
10
  export function formatFixCodeResult(header, result) {
9
11
  const sections = [header];
10
12
  if (result.fix.threads.length > 0) {
@@ -16,7 +18,7 @@ export function formatFixCodeResult(header, result) {
16
18
  const reviewMarker = t.reviewId ? ` [reviewId=${t.reviewId}]` : "";
17
19
  const suggestionMarker = t.suggestion ? " [suggestion]" : "";
18
20
  const editedMarker = t.edited ? " [edited since first look]" : "";
19
- sections.push(`### ${heading} — ${loc} (${renderAuthor(t.author, t.authorType, t.authorAssociation)})${reviewMarker}${suggestionMarker}${editedMarker}`);
21
+ sections.push(`### ${heading} — ${loc} (${renderAuthor(t.author, t.authorType, t.authorAssociation, t.viewerDidAuthor)})${reviewMarker}${suggestionMarker}${editedMarker}`);
20
22
  sections.push(renderThreadConversation(t));
21
23
  if (t.suggestion) {
22
24
  sections.push(renderSuggestionBlock(t.suggestion, ""));
@@ -34,7 +36,8 @@ export function formatFixCodeResult(header, result) {
34
36
  for (const c of result.fix.actionableComments) {
35
37
  const heading = c.url ? `[commentId=${c.id}](${c.url})` : `\`commentId=${c.id}\``;
36
38
  const editedMarker = c.edited ? " [edited since first look]" : "";
37
- sections.push(`### ${heading} (${renderAuthor(c.author, c.authorType, c.authorAssociation)})${editedMarker}`);
39
+ const authorizationMarker = c.viewerCanMinimize === false ? " [viewer cannot minimize]" : "";
40
+ sections.push(`### ${heading} (${renderAuthor(c.author, c.authorType, c.authorAssociation)})${authorizationMarker}${editedMarker}`);
38
41
  sections.push(blockquote(c.body));
39
42
  }
40
43
  }
@@ -50,7 +53,10 @@ export function formatFixCodeResult(header, result) {
50
53
  ? `external \`${ch.detailsUrl}\``
51
54
  : "(no runId)";
52
55
  const conclusionTag = ch.conclusion !== null ? ` [conclusion: ${ch.conclusion}]` : "";
53
- const lines = [`- ${locator} — \`${workflowPrefix}${jobLabel}\`${conclusionTag}`];
56
+ const scopeTag = ch.scope
57
+ ? ` [scope: ${ch.scope}${ch.commitOid ? `, commit: ${ch.commitOid}` : ""}]`
58
+ : "";
59
+ const lines = [`- ${locator} — \`${workflowPrefix}${jobLabel}\`${conclusionTag}${scopeTag}`];
54
60
  if (ch.conclusion !== "CANCELLED") {
55
61
  if (ch.failedStep)
56
62
  lines.push(` > ${ch.failedStep}`);
@@ -85,14 +91,14 @@ export function formatFixCodeResult(header, result) {
85
91
  if (result.fix.firstLookSummaries.length > 0) {
86
92
  sections.push("## Review summaries (first look)");
87
93
  for (const r of result.fix.firstLookSummaries) {
88
- sections.push(`### \`reviewId=${r.id}\` (${renderAuthor(r.author, r.authorType, r.authorAssociation)})`);
94
+ sections.push(`### \`reviewId=${r.id}\` (${renderAuthor(r.author, r.authorType, r.authorAssociation)})${r.viewerCanMinimize === false ? " [viewer cannot minimize]" : ""}`);
89
95
  sections.push(r.body.trim() === "" ? "(no review body)" : blockquote(r.body));
90
96
  }
91
97
  }
92
98
  if (result.fix.editedSummaries.length > 0) {
93
99
  sections.push("## Review summaries (edited since first look — already minimized; do not re-minimize)");
94
100
  for (const r of result.fix.editedSummaries) {
95
- sections.push(`### \`reviewId=${r.id}\` (${renderAuthor(r.author, r.authorType, r.authorAssociation)})`);
101
+ sections.push(`### \`reviewId=${r.id}\` (${renderAuthor(r.author, r.authorType, r.authorAssociation)})${r.viewerCanMinimize === false ? " [viewer cannot minimize]" : ""}`);
96
102
  sections.push(r.body.trim() === "" ? "(no review body)" : blockquote(r.body));
97
103
  }
98
104
  }
@@ -105,7 +111,7 @@ export function formatFixCodeResult(header, result) {
105
111
  if (result.fix.surfacedApprovals.length > 0) {
106
112
  sections.push("## Approvals (surfaced — not minimized)");
107
113
  for (const r of result.fix.surfacedApprovals) {
108
- sections.push(`### \`reviewId=${r.id}\` (${renderAuthor(r.author, r.authorType, r.authorAssociation)})`);
114
+ sections.push(`### \`reviewId=${r.id}\` (${renderAuthor(r.author, r.authorType, r.authorAssociation)})${r.viewerCanMinimize === false ? " [viewer cannot minimize]" : ""}`);
109
115
  sections.push(r.body.trim() === "" ? "(no review body)" : blockquote(r.body));
110
116
  }
111
117
  }
@@ -126,13 +132,19 @@ export function formatFixCodeResult(header, result) {
126
132
  sections.push("## Cancelled runs");
127
133
  sections.push(result.cancelled.map((id) => `- \`${id}\``).join("\n"));
128
134
  }
129
- sections.push("## Post-fix push");
135
+ sections.push("## Post-fix actions");
130
136
  const postFixLines = [`- base: \`${result.baseBranch}\``];
131
137
  if (result.fix.resolveOnlyCommand?.hasMutations)
132
138
  postFixLines.push(`- resolve-only: \`${renderResolveCommand(result.fix.resolveOnlyCommand)}\``);
133
139
  if (result.fix.resolveCommand.hasMutations) {
134
140
  postFixLines.push(`- apply review: \`${renderResolveCommand(result.fix.resolveCommand)}\``);
135
141
  }
142
+ if (result.fix.requeue) {
143
+ postFixLines.push(`- requeue: ${inlineCode(renderMergeCommand(result.fix.requeue.command))}`);
144
+ if (result.fix.requeue.queueApiFallbackCommand) {
145
+ postFixLines.push(`- requeue API fallback: ${inlineCode(renderMergeCommand(result.fix.requeue.queueApiFallbackCommand))}`);
146
+ }
147
+ }
136
148
  sections.push(postFixLines.join("\n"));
137
149
  sections.push("## Instructions");
138
150
  sections.push(numberInstructions(result.fix.instructions));
@@ -124,6 +124,7 @@ export async function handleIterate(args) {
124
124
  stallTimeoutSeconds: flags.stallTimeoutSeconds,
125
125
  noAutoMarkReady: flags.noAutoMarkReady,
126
126
  noAutoCancelActionable: flags.noAutoCancelActionable,
127
+ merge: flags.merge,
127
128
  });
128
129
  emitIterateResult(result, {
129
130
  format: globalOpts.format,
@@ -2,7 +2,7 @@ export declare const COMMAND_USAGE: {
2
2
  readonly default: string;
3
3
  readonly apply: `pr-shepherd apply
4
4
 
5
- Apply a review mutation, mark changed files as viewed, or append a PR journal item.
5
+ Apply a review mutation, select changed files for authorization diagnostics, or append a PR journal item.
6
6
 
7
7
  Usage:
8
8
  pr-shepherd apply review [PR] [review-flags]
@@ -36,7 +36,8 @@ At least one action flag is required.
36
36
  --help, -h Print this help and exit before GitHub I/O.`;
37
37
  readonly "apply files": `pr-shepherd apply files
38
38
 
39
- Mark changed files as viewed in the GitHub pull request diff.
39
+ Select changed files and report that viewed-state authorization cannot be verified.
40
+ No file viewed-state mutation is attempted.
40
41
 
41
42
  Usage:
42
43
  pr-shepherd apply files [PR] [files...] [--tests] [--match REGEX]
@@ -139,7 +140,8 @@ Flags:
139
140
  --message <text> Reply/dismiss message. Required with --reply-thread-ids
140
141
  or --dismiss-review-ids.
141
142
  --require-sha <sha> Wait until GitHub reports this PR head SHA before mutating.
142
- Must be a full 40-character lowercase hex SHA. Use $(git rev-parse HEAD).
143
+ Must be a full 40-character lowercase hex SHA. Local HEAD is valid
144
+ only when it equals the current remote PR head.
143
145
  --format text|json Output format. Default: text.
144
146
  --help, -h Print this help and exit before GitHub I/O.
145
147
 
@@ -174,7 +176,8 @@ Exit codes:
174
176
  See docs/exit-codes.md for the full sysexits.h table.`;
175
177
  readonly "mark-files-as-viewed": `pr-shepherd mark-files-as-viewed
176
178
 
177
- Mark changed files as viewed in the GitHub pull request diff.
179
+ Deprecated compatibility alias for selection-only file-view authorization diagnostics.
180
+ No file viewed-state mutation is attempted.
178
181
 
179
182
  Usage:
180
183
  pr-shepherd mark-files-as-viewed [PR] [files...] [--tests] [--match REGEX]
@@ -192,8 +195,8 @@ Flags:
192
195
 
193
196
  PR may be a number or GitHub pull request URL. When omitted, the current branch PR is inferred.
194
197
  Exit code: 0 on success; nonzero on failure (sysexits.h — 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 --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).";
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, 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).";
198
+ 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 Legacy no-op; workflow runs are never cancelled.\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).";
199
+ 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 Legacy no-op; workflow runs are never cancelled.\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).";
197
200
  readonly clean: `pr-shepherd clean
198
201
 
199
202
  Remove pr-shepherd state files from PR_SHEPHERD_STATE_DIR.
@@ -5,7 +5,7 @@ export const COMMAND_USAGE = {
5
5
  default: DEFAULT_USAGE,
6
6
  apply: `pr-shepherd apply
7
7
 
8
- Apply a review mutation, mark changed files as viewed, or append a PR journal item.
8
+ Apply a review mutation, select changed files for authorization diagnostics, or append a PR journal item.
9
9
 
10
10
  Usage:
11
11
  pr-shepherd apply review [PR] [review-flags]
@@ -39,7 +39,8 @@ At least one action flag is required.
39
39
  --help, -h Print this help and exit before GitHub I/O.`,
40
40
  "apply files": `pr-shepherd apply files
41
41
 
42
- Mark changed files as viewed in the GitHub pull request diff.
42
+ Select changed files and report that viewed-state authorization cannot be verified.
43
+ No file viewed-state mutation is attempted.
43
44
 
44
45
  Usage:
45
46
  pr-shepherd apply files [PR] [files...] [--tests] [--match REGEX]
@@ -142,7 +143,8 @@ Flags:
142
143
  --message <text> Reply/dismiss message. Required with --reply-thread-ids
143
144
  or --dismiss-review-ids.
144
145
  --require-sha <sha> Wait until GitHub reports this PR head SHA before mutating.
145
- Must be a full 40-character lowercase hex SHA. Use $(git rev-parse HEAD).
146
+ Must be a full 40-character lowercase hex SHA. Local HEAD is valid
147
+ only when it equals the current remote PR head.
146
148
  --format text|json Output format. Default: text.
147
149
  --help, -h Print this help and exit before GitHub I/O.
148
150
 
@@ -177,7 +179,8 @@ Exit codes:
177
179
  See docs/exit-codes.md for the full sysexits.h table.`,
178
180
  "mark-files-as-viewed": `pr-shepherd mark-files-as-viewed
179
181
 
180
- Mark changed files as viewed in the GitHub pull request diff.
182
+ Deprecated compatibility alias for selection-only file-view authorization diagnostics.
183
+ No file viewed-state mutation is attempted.
181
184
 
182
185
  Usage:
183
186
  pr-shepherd mark-files-as-viewed [PR] [files...] [--tests] [--match REGEX]
@@ -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 Legacy no-op; workflow runs are never cancelled.\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 Legacy no-op; workflow runs are never cancelled.\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;