pr-shepherd 0.56.6 → 0.57.1

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 (421) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +150 -280
  3. package/bin/api.d.mts +25 -3
  4. package/bin/api.mjs +51 -13
  5. package/bin/checks/classify.d.mts +1 -0
  6. package/bin/checks/classify.mjs +1 -1
  7. package/bin/checks/conclusions.d.mts +5 -1
  8. package/bin/checks/conclusions.mjs +8 -2
  9. package/bin/checks/superseded.d.mts +8 -2
  10. package/bin/checks/superseded.mjs +24 -7
  11. package/bin/classify/loader.d.mts +2 -0
  12. package/bin/classify/loader.mjs +15 -0
  13. package/bin/classify/standard/author.d.mts +3 -0
  14. package/bin/classify/standard/author.mjs +10 -0
  15. package/bin/classify/standard/codecov-report.d.mts +4 -0
  16. package/bin/classify/standard/codecov-report.mjs +10 -0
  17. package/bin/classify/standard/coderabbit-notices.d.mts +8 -0
  18. package/bin/classify/standard/coderabbit-notices.mjs +38 -0
  19. package/bin/classify/standard/codex-notices.d.mts +8 -0
  20. package/bin/classify/standard/codex-notices.mjs +34 -0
  21. package/bin/classify/standard/dependabot-notices.d.mts +4 -0
  22. package/bin/classify/standard/dependabot-notices.mjs +15 -0
  23. package/bin/classify/standard/gemini-notices.d.mts +4 -0
  24. package/bin/classify/standard/gemini-notices.mjs +13 -0
  25. package/bin/classify/standard/index.d.mts +7 -0
  26. package/bin/classify/standard/index.mjs +21 -0
  27. package/bin/classify/standard/kilo-no-issues.d.mts +4 -0
  28. package/bin/classify/standard/kilo-no-issues.mjs +17 -0
  29. package/bin/classify/standard/sourcery-notices.d.mts +8 -0
  30. package/bin/classify/standard/sourcery-notices.mjs +20 -0
  31. package/bin/cli/api-usage-formatter.mjs +6 -1
  32. package/bin/cli/apply-merge-handler.d.mts +3 -0
  33. package/bin/cli/apply-merge-handler.mjs +73 -0
  34. package/bin/cli/arg-flags.d.mts +2 -0
  35. package/bin/cli/arg-flags.mjs +47 -0
  36. package/bin/cli/args.mjs +10 -41
  37. package/bin/cli/clean-handler.d.mts +1 -0
  38. package/bin/cli/clean-handler.mjs +71 -0
  39. package/bin/cli/default-poll.mjs +3 -0
  40. package/bin/cli/event-state-scope.d.mts +19 -0
  41. package/bin/cli/event-state-scope.mjs +60 -0
  42. package/bin/cli/fix-formatter.mjs +5 -11
  43. package/bin/cli/handlers.d.mts +0 -1
  44. package/bin/cli/handlers.mjs +8 -64
  45. package/bin/cli/help-command-pages.d.mts +62 -18
  46. package/bin/cli/help-command-pages.mjs +59 -15
  47. package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
  48. package/bin/cli/help-iterate-poll-pages.mjs +6 -0
  49. package/bin/cli/help-log-file-page.d.mts +1 -1
  50. package/bin/cli/help-log-file-page.mjs +4 -1
  51. package/bin/cli/help-top-page.d.mts +1 -1
  52. package/bin/cli/help-top-page.mjs +5 -0
  53. package/bin/cli/help.d.mts +63 -19
  54. package/bin/cli/help.mjs +2 -0
  55. package/bin/cli/iterate-branch-segment.d.mts +2 -0
  56. package/bin/cli/iterate-branch-segment.mjs +12 -7
  57. package/bin/cli/iterate-flags.d.mts +7 -1
  58. package/bin/cli/iterate-flags.mjs +38 -0
  59. package/bin/cli/iterate-formatter.d.mts +6 -6
  60. package/bin/cli/iterate-formatter.mjs +56 -22
  61. package/bin/cli/iterate-instructions.mjs +45 -15
  62. package/bin/cli/iterate-lean.mjs +39 -14
  63. package/bin/cli/iterate-merge-formatter.d.mts +6 -0
  64. package/bin/cli/iterate-merge-formatter.mjs +24 -14
  65. package/bin/cli/iterate-verbose.mjs +3 -6
  66. package/bin/cli/list-formatters.mjs +3 -1
  67. package/bin/cli/mutate-formatter.mjs +10 -5
  68. package/bin/cli/next-check-format.d.mts +7 -0
  69. package/bin/cli/next-check-format.mjs +10 -0
  70. package/bin/cli/playbook-handler.d.mts +5 -0
  71. package/bin/cli/playbook-handler.mjs +40 -0
  72. package/bin/cli/poll-handler.mjs +7 -6
  73. package/bin/cli/poll-summary-formatter.mjs +11 -2
  74. package/bin/cli/poll-targets.mjs +2 -0
  75. package/bin/cli/resolve-validators.mjs +2 -2
  76. package/bin/cli/runner.mjs +6 -1
  77. package/bin/cli/stack-layer-view.d.mts +33 -0
  78. package/bin/cli/stack-layer-view.mjs +1 -0
  79. package/bin/cli/stack-overview.d.mts +10 -28
  80. package/bin/cli/stack-overview.mjs +39 -14
  81. package/bin/cli/transport-args.d.mts +5 -0
  82. package/bin/cli/transport-args.mjs +23 -0
  83. package/bin/cli/transport-formatter.d.mts +9 -0
  84. package/bin/cli/transport-formatter.mjs +13 -0
  85. package/bin/cli-parser.mjs +62 -7
  86. package/bin/commands/apply-merge-options.d.mts +4 -0
  87. package/bin/commands/apply-merge-options.mjs +34 -0
  88. package/bin/commands/apply-merge-output.d.mts +7 -0
  89. package/bin/commands/apply-merge-output.mjs +20 -0
  90. package/bin/commands/apply-merge-pull.d.mts +20 -0
  91. package/bin/commands/apply-merge-pull.mjs +15 -0
  92. package/bin/commands/apply-merge.d.mts +18 -0
  93. package/bin/commands/apply-merge.mjs +126 -0
  94. package/bin/commands/apply-queue-removal.mjs +7 -0
  95. package/bin/commands/check-annotations.mjs +28 -18
  96. package/bin/commands/check-execution-context.d.mts +5 -0
  97. package/bin/commands/check-execution-context.mjs +16 -1
  98. package/bin/commands/check-fingerprint.d.mts +26 -2
  99. package/bin/commands/check-fingerprint.mjs +64 -28
  100. package/bin/commands/check-terminal-report.mjs +11 -1
  101. package/bin/commands/check-unreported.d.mts +6 -2
  102. package/bin/commands/check-unreported.mjs +32 -12
  103. package/bin/commands/check-wait-detectors.d.mts +35 -0
  104. package/bin/commands/check-wait-detectors.mjs +107 -0
  105. package/bin/commands/check.d.mts +4 -2
  106. package/bin/commands/check.mjs +130 -40
  107. package/bin/commands/event-instructions.d.mts +11 -0
  108. package/bin/commands/event-instructions.mjs +27 -0
  109. package/bin/commands/event-mode.d.mts +14 -0
  110. package/bin/commands/event-mode.mjs +138 -0
  111. package/bin/commands/iterate/api-usage.mjs +4 -2
  112. package/bin/commands/iterate/base.mjs +4 -0
  113. package/bin/commands/iterate/check-blocker-gate.mjs +14 -2
  114. package/bin/commands/iterate/check-instructions.d.mts +9 -10
  115. package/bin/commands/iterate/check-instructions.mjs +23 -22
  116. package/bin/commands/iterate/classify.mjs +19 -5
  117. package/bin/commands/iterate/escalate.mjs +13 -3
  118. package/bin/commands/iterate/fix-code.mjs +26 -9
  119. package/bin/commands/iterate/fix-instruction-threads.d.mts +0 -8
  120. package/bin/commands/iterate/fix-instruction-threads.mjs +0 -16
  121. package/bin/commands/iterate/fix-loop-instruction.d.mts +9 -0
  122. package/bin/commands/iterate/fix-loop-instruction.mjs +35 -0
  123. package/bin/commands/iterate/helpers.mjs +15 -2
  124. package/bin/commands/iterate/index.mjs +57 -16
  125. package/bin/commands/iterate/mark-ready.mjs +50 -10
  126. package/bin/commands/iterate/merge-plan.d.mts +19 -0
  127. package/bin/commands/iterate/merge-plan.mjs +88 -0
  128. package/bin/commands/iterate/merge-state.mjs +3 -0
  129. package/bin/commands/iterate/merge.d.mts +4 -15
  130. package/bin/commands/iterate/merge.mjs +18 -51
  131. package/bin/commands/iterate/merged-base-pull-requests.d.mts +2 -6
  132. package/bin/commands/iterate/merged-base-pull-requests.mjs +15 -11
  133. package/bin/commands/iterate/native-stack-rebase.mjs +11 -0
  134. package/bin/commands/iterate/render.d.mts +8 -2
  135. package/bin/commands/iterate/render.mjs +28 -42
  136. package/bin/commands/iterate/stack-trunk-conflict.mjs +17 -1
  137. package/bin/commands/iterate/stale-ancestry.mjs +4 -1
  138. package/bin/commands/iterate/stall.d.mts +5 -1
  139. package/bin/commands/iterate/stall.mjs +19 -7
  140. package/bin/commands/iterate/thread-mutation-routing.d.mts +1 -0
  141. package/bin/commands/iterate/thread-mutation-routing.mjs +4 -2
  142. package/bin/commands/iterate/unreported-required.mjs +5 -2
  143. package/bin/commands/mark-files-as-viewed.mjs +7 -0
  144. package/bin/commands/next-check.d.mts +31 -0
  145. package/bin/commands/next-check.mjs +46 -0
  146. package/bin/commands/playbook.d.mts +13 -0
  147. package/bin/commands/playbook.mjs +48 -0
  148. package/bin/commands/poll-mode.d.mts +8 -0
  149. package/bin/commands/poll-mode.mjs +14 -0
  150. package/bin/commands/poll-progress.d.mts +1 -0
  151. package/bin/commands/poll-progress.mjs +6 -3
  152. package/bin/commands/poll-quota.d.mts +3 -2
  153. package/bin/commands/poll-quota.mjs +7 -3
  154. package/bin/commands/poll-summary-explicit-instructions.d.mts +2 -0
  155. package/bin/commands/poll-summary-explicit-instructions.mjs +10 -1
  156. package/bin/commands/poll-summary-instructions.mjs +16 -17
  157. package/bin/commands/poll-summary.mjs +42 -17
  158. package/bin/commands/poll.d.mts +0 -1
  159. package/bin/commands/poll.mjs +11 -19
  160. package/bin/commands/quota-selection.d.mts +2 -1
  161. package/bin/commands/quota-selection.mjs +12 -7
  162. package/bin/commands/resolve-mutate.mjs +33 -5
  163. package/bin/commands/rest-stack-merge-readiness.d.mts +4 -0
  164. package/bin/commands/rest-stack-merge-readiness.mjs +74 -0
  165. package/bin/commands/rule-auto-resolve.mjs +9 -3
  166. package/bin/commands/shepherd-journal.d.mts +5 -4
  167. package/bin/commands/shepherd-journal.mjs +9 -8
  168. package/bin/commands/stack-drain.d.mts +1 -9
  169. package/bin/commands/stack-drain.mjs +50 -37
  170. package/bin/commands/stack-handoffs.d.mts +10 -0
  171. package/bin/commands/stack-handoffs.mjs +25 -0
  172. package/bin/commands/stack-stall.d.mts +5 -0
  173. package/bin/commands/stack-stall.mjs +11 -0
  174. package/bin/commands/stack-work.d.mts +5 -0
  175. package/bin/commands/stack-work.mjs +32 -0
  176. package/bin/comments/existing-reply-scan.d.mts +17 -0
  177. package/bin/comments/existing-reply-scan.mjs +41 -0
  178. package/bin/comments/rate-limit.mjs +2 -2
  179. package/bin/comments/resolve.d.mts +7 -1
  180. package/bin/comments/resolve.mjs +108 -18
  181. package/bin/comments/rest-reply.d.mts +9 -0
  182. package/bin/comments/rest-reply.mjs +95 -0
  183. package/bin/comments/rest-review-mutations.d.mts +22 -0
  184. package/bin/comments/rest-review-mutations.mjs +125 -0
  185. package/bin/comments/review-visibility.d.mts +1 -1
  186. package/bin/comments/review-visibility.mjs +3 -2
  187. package/bin/comments/sha-poll.mjs +7 -3
  188. package/bin/comments/thread-visibility.mjs +10 -5
  189. package/bin/comments/uncertain-replies.d.mts +11 -0
  190. package/bin/comments/uncertain-replies.mjs +121 -0
  191. package/bin/comments/uncertain-reply-guards.d.mts +10 -0
  192. package/bin/comments/uncertain-reply-guards.mjs +94 -0
  193. package/bin/comments/visible-comments.d.mts +1 -1
  194. package/bin/comments/visible-comments.mjs +4 -2
  195. package/bin/config/load.d.mts +37 -1
  196. package/bin/config/load.mjs +73 -1
  197. package/bin/config.json +6 -2
  198. package/bin/exit-codes.d.mts +3 -0
  199. package/bin/exit-codes.mjs +8 -0
  200. package/bin/github/api-telemetry-aggregate.d.mts +15 -4
  201. package/bin/github/api-telemetry-aggregate.mjs +57 -18
  202. package/bin/github/api-telemetry.d.mts +4 -0
  203. package/bin/github/api-telemetry.mjs +22 -8
  204. package/bin/github/apply-review-preflight.d.mts +20 -0
  205. package/bin/github/apply-review-preflight.mjs +61 -0
  206. package/bin/github/base-behind-cache.d.mts +15 -0
  207. package/bin/github/base-behind-cache.mjs +18 -0
  208. package/bin/github/batch-parse-suites.d.mts +4 -2
  209. package/bin/github/batch-parse-suites.mjs +6 -1
  210. package/bin/github/batch-parser-helpers.mjs +40 -2
  211. package/bin/github/batch-parsers.mjs +1 -0
  212. package/bin/github/batch-raw-rules.d.mts +26 -0
  213. package/bin/github/batch-raw-types.d.mts +8 -6
  214. package/bin/github/batch-stack-evidence.d.mts +28 -0
  215. package/bin/github/batch-stack-evidence.mjs +62 -0
  216. package/bin/github/batch.d.mts +15 -2
  217. package/bin/github/batch.mjs +34 -17
  218. package/bin/github/captured-proxy-agent.d.mts +3 -0
  219. package/bin/github/captured-proxy-agent.mjs +8 -0
  220. package/bin/github/check-annotations-batch.d.mts +0 -5
  221. package/bin/github/check-annotations-batch.mjs +25 -4
  222. package/bin/github/check-annotations.mjs +3 -1
  223. package/bin/github/client.d.mts +8 -19
  224. package/bin/github/client.mjs +45 -13
  225. package/bin/github/fingerprint-fields.d.mts +8 -0
  226. package/bin/github/fingerprint-fields.mjs +6 -1
  227. package/bin/github/fingerprint.d.mts +4 -2
  228. package/bin/github/fingerprint.mjs +6 -38
  229. package/bin/github/github-fetch.d.mts +2 -0
  230. package/bin/github/github-fetch.mjs +32 -0
  231. package/bin/github/gql/base-behind.gql +3 -0
  232. package/bin/github/gql/batch-pr-page.gql +16 -0
  233. package/bin/github/gql/batch-pr.gql +57 -0
  234. package/bin/github/gql/commit-check-contexts.gql +17 -0
  235. package/bin/github/gql/get-pr-body.gql +1 -0
  236. package/bin/github/gql/poll-stack-summary.gql +1 -0
  237. package/bin/github/gql/poll-summary-check-contexts.gql +5 -0
  238. package/bin/github/gql/poll-summary-fragment.gql +65 -15
  239. package/bin/github/gql/stack-handoff-check-runs.gql +42 -0
  240. package/bin/github/graphql-http.mjs +9 -4
  241. package/bin/github/graphql-internal-retry.d.mts +2 -0
  242. package/bin/github/graphql-internal-retry.mjs +1 -1
  243. package/bin/github/graphql-quota-probe.d.mts +6 -0
  244. package/bin/github/graphql-quota-probe.mjs +56 -0
  245. package/bin/github/graphql-session-refusal.d.mts +8 -0
  246. package/bin/github/graphql-session-refusal.mjs +14 -0
  247. package/bin/github/http-request.d.mts +1 -1
  248. package/bin/github/http-request.mjs +22 -6
  249. package/bin/github/http-utils.mjs +6 -0
  250. package/bin/github/legacy-dispatcher.d.mts +6 -0
  251. package/bin/github/legacy-dispatcher.mjs +44 -0
  252. package/bin/github/merge-target-rules.d.mts +12 -3
  253. package/bin/github/merge-target-rules.mjs +71 -34
  254. package/bin/github/mutation-policy.d.mts +6 -0
  255. package/bin/github/mutation-policy.mjs +21 -0
  256. package/bin/github/poll-summary-annotation-probe.mjs +17 -10
  257. package/bin/github/poll-summary-check-blockers.d.mts +1 -1
  258. package/bin/github/poll-summary-check-blockers.mjs +2 -2
  259. package/bin/github/poll-summary-check-hydration.mjs +25 -10
  260. package/bin/github/poll-summary-checks.d.mts +2 -2
  261. package/bin/github/poll-summary-checks.mjs +9 -6
  262. package/bin/github/poll-summary-command.d.mts +2 -0
  263. package/bin/github/poll-summary-command.mjs +24 -0
  264. package/bin/github/poll-summary-fingerprint.d.mts +1 -1
  265. package/bin/github/poll-summary-fingerprint.mjs +4 -2
  266. package/bin/github/poll-summary-handoff-fields.d.mts +3 -0
  267. package/bin/github/poll-summary-handoff-fields.mjs +73 -0
  268. package/bin/github/poll-summary-projector.d.mts +1 -1
  269. package/bin/github/poll-summary-projector.mjs +17 -24
  270. package/bin/github/poll-summary-raw.d.mts +70 -10
  271. package/bin/github/poll-summary-readiness.d.mts +6 -1
  272. package/bin/github/poll-summary-readiness.mjs +13 -4
  273. package/bin/github/poll-summary-rest-queue.d.mts +3 -0
  274. package/bin/github/poll-summary-rest-queue.mjs +12 -0
  275. package/bin/github/poll-summary-review.d.mts +1 -1
  276. package/bin/github/poll-summary-review.mjs +35 -20
  277. package/bin/github/poll-summary-route.mjs +19 -3
  278. package/bin/github/poll-summary-stack-page.d.mts +11 -0
  279. package/bin/github/poll-summary-stack-page.mjs +27 -0
  280. package/bin/github/poll-summary-unreported.d.mts +3 -1
  281. package/bin/github/poll-summary-unreported.mjs +6 -3
  282. package/bin/github/poll-summary.d.mts +4 -1
  283. package/bin/github/poll-summary.mjs +47 -33
  284. package/bin/github/queries.d.mts +7 -3
  285. package/bin/github/queries.mjs +8 -4
  286. package/bin/github/rate-limit-sample.d.mts +7 -0
  287. package/bin/github/rate-limit-sample.mjs +12 -0
  288. package/bin/github/reply-recovery-read.d.mts +50 -0
  289. package/bin/github/reply-recovery-read.mjs +118 -0
  290. package/bin/github/reply-thread-transcripts.d.mts +0 -1
  291. package/bin/github/reply-thread-transcripts.mjs +24 -1
  292. package/bin/github/rest-annotation-read.d.mts +5 -0
  293. package/bin/github/rest-annotation-read.mjs +44 -0
  294. package/bin/github/rest-batch-read.d.mts +12 -0
  295. package/bin/github/rest-batch-read.mjs +57 -0
  296. package/bin/github/rest-batch-snapshot.d.mts +30 -0
  297. package/bin/github/rest-batch-snapshot.mjs +115 -0
  298. package/bin/github/rest-batch-unavailable.d.mts +5 -0
  299. package/bin/github/rest-batch-unavailable.mjs +16 -0
  300. package/bin/github/rest-check-read.d.mts +34 -0
  301. package/bin/github/rest-check-read.mjs +124 -0
  302. package/bin/github/rest-comment-authorship.d.mts +7 -0
  303. package/bin/github/rest-comment-authorship.mjs +11 -0
  304. package/bin/github/rest-conditional-scope.d.mts +20 -0
  305. package/bin/github/rest-conditional-scope.mjs +44 -0
  306. package/bin/github/rest-explicit-summary-read.d.mts +3 -0
  307. package/bin/github/rest-explicit-summary-read.mjs +8 -0
  308. package/bin/github/rest-feedback-read.d.mts +36 -0
  309. package/bin/github/rest-feedback-read.mjs +147 -0
  310. package/bin/github/rest-feedback-validation.d.mts +5 -0
  311. package/bin/github/rest-feedback-validation.mjs +28 -0
  312. package/bin/github/rest-http.d.mts +12 -0
  313. package/bin/github/rest-http.mjs +108 -23
  314. package/bin/github/rest-identities.d.mts +22 -0
  315. package/bin/github/rest-identities.mjs +134 -0
  316. package/bin/github/rest-merge-stack-guard.d.mts +14 -0
  317. package/bin/github/rest-merge-stack-guard.mjs +41 -0
  318. package/bin/github/rest-merge.d.mts +29 -0
  319. package/bin/github/rest-merge.mjs +56 -0
  320. package/bin/github/rest-merged-base-read.d.mts +9 -0
  321. package/bin/github/rest-merged-base-read.mjs +48 -0
  322. package/bin/github/rest-pr-core.d.mts +52 -0
  323. package/bin/github/rest-pr-core.mjs +60 -0
  324. package/bin/github/rest-reader-core.d.mts +16 -0
  325. package/bin/github/rest-reader-core.mjs +154 -0
  326. package/bin/github/rest-review-read.d.mts +11 -0
  327. package/bin/github/rest-review-read.mjs +47 -0
  328. package/bin/github/rest-rules-read.d.mts +9 -0
  329. package/bin/github/rest-rules-read.mjs +154 -0
  330. package/bin/github/rest-session-refusal.d.mts +5 -0
  331. package/bin/github/rest-session-refusal.mjs +21 -0
  332. package/bin/github/rest-snapshot-context.d.mts +10 -0
  333. package/bin/github/rest-snapshot-context.mjs +1 -0
  334. package/bin/github/rest-stack-read.d.mts +21 -0
  335. package/bin/github/rest-stack-read.mjs +47 -0
  336. package/bin/github/rest-stack-summary.d.mts +8 -0
  337. package/bin/github/rest-stack-summary.mjs +62 -0
  338. package/bin/github/rest-summary-read.d.mts +7 -0
  339. package/bin/github/rest-summary-read.mjs +112 -0
  340. package/bin/github/rest-terminal-batch.d.mts +14 -0
  341. package/bin/github/rest-terminal-batch.mjs +45 -0
  342. package/bin/github/rest-text.mjs +7 -3
  343. package/bin/github/rest-thread-read.d.mts +4 -0
  344. package/bin/github/rest-thread-read.mjs +35 -0
  345. package/bin/github/rest-viewer-read.d.mts +2 -0
  346. package/bin/github/rest-viewer-read.mjs +41 -0
  347. package/bin/github/stack-bottom.d.mts +3 -0
  348. package/bin/github/stack-bottom.mjs +14 -0
  349. package/bin/github/stack-handoff-context.d.mts +25 -0
  350. package/bin/github/stack-handoff-context.mjs +12 -0
  351. package/bin/github/stack-handoff-page.d.mts +17 -0
  352. package/bin/github/stack-handoff-page.mjs +306 -0
  353. package/bin/github/stack-handoff.d.mts +16 -0
  354. package/bin/github/stack-handoff.mjs +115 -0
  355. package/bin/github/stack-order.d.mts +6 -0
  356. package/bin/github/stack-order.mjs +13 -0
  357. package/bin/github/stack-read.d.mts +7 -5
  358. package/bin/github/stack-read.mjs +22 -24
  359. package/bin/github/stack-size-hint.d.mts +3 -0
  360. package/bin/github/stack-size-hint.mjs +14 -0
  361. package/bin/github/suggestion-thread.mjs +27 -1
  362. package/bin/github/thread-comments.mjs +9 -1
  363. package/bin/github/transport-evidence.d.mts +20 -0
  364. package/bin/github/transport-evidence.mjs +26 -0
  365. package/bin/github/transport-mode.d.mts +2 -0
  366. package/bin/github/transport-mode.mjs +5 -0
  367. package/bin/github/transport.d.mts +19 -0
  368. package/bin/github/transport.mjs +126 -0
  369. package/bin/github/unsupported-rest.d.mts +4 -0
  370. package/bin/github/unsupported-rest.mjs +7 -0
  371. package/bin/mcp/server.mjs +52 -3
  372. package/bin/merge-status/derive.d.mts +2 -0
  373. package/bin/merge-status/derive.mjs +17 -13
  374. package/bin/merge-status/required-check-requirements.d.mts +7 -0
  375. package/bin/merge-status/required-check-requirements.mjs +15 -0
  376. package/bin/merge-status/requirements-format.d.mts +5 -0
  377. package/bin/merge-status/requirements-format.mjs +41 -12
  378. package/bin/merge-status/requirements.mjs +18 -7
  379. package/bin/state/base.mjs +41 -0
  380. package/bin/state/durable-state.d.mts +6 -0
  381. package/bin/state/durable-state.mjs +41 -0
  382. package/bin/state/graphql-quota-policy.mjs +23 -16
  383. package/bin/state/merge-request.d.mts +25 -0
  384. package/bin/state/merge-request.mjs +145 -0
  385. package/bin/state/pr-fingerprint.d.mts +15 -0
  386. package/bin/state/pr-fingerprint.mjs +22 -7
  387. package/bin/state/rest-cache.d.mts +3 -0
  388. package/bin/state/rest-cache.mjs +1 -0
  389. package/bin/state/rest-snapshot-report.d.mts +21 -0
  390. package/bin/state/rest-snapshot-report.mjs +52 -0
  391. package/bin/state/seen-comments.d.mts +3 -0
  392. package/bin/state/seen-comments.mjs +18 -0
  393. package/bin/types/api-usage.d.mts +9 -1
  394. package/bin/types/escalate.d.mts +1 -1
  395. package/bin/types/github.d.mts +23 -9
  396. package/bin/types/iterate.d.mts +24 -2
  397. package/bin/types/merge-action.d.mts +1 -1
  398. package/bin/types/merge-requirements.d.mts +7 -7
  399. package/bin/types/next-check.d.mts +12 -0
  400. package/bin/types/next-check.mjs +1 -0
  401. package/bin/types/poll-summary.d.mts +21 -0
  402. package/bin/types/report.d.mts +13 -1
  403. package/bin/types/review-thread.d.mts +1 -1
  404. package/bin/types.d.mts +1 -0
  405. package/bin/types.mjs +1 -0
  406. package/package.json +4 -3
  407. package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
  408. package/plugins/pr-shepherd/.codex.mcp.json +1 -1
  409. package/plugins/pr-shepherd/.mcp.json +1 -1
  410. package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +1 -1
  411. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +14 -51
  412. package/plugins/pr-shepherd/skills/pr-shepherd/references/ci-failure-triage.md +12 -16
  413. package/plugins/pr-shepherd/skills/pr-shepherd/references/cloud-event-loop.md +14 -0
  414. package/plugins/pr-shepherd/skills/pr-shepherd/references/create-pr.md +10 -0
  415. package/plugins/pr-shepherd/skills/pr-shepherd/references/fix-code-loop.md +10 -0
  416. package/plugins/pr-shepherd/skills/pr-shepherd/references/mcp-fallback.md +9 -0
  417. package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +3 -1
  418. package/bin/github/gql/pr-fingerprint.gql +0 -75
  419. package/plugins/pr-shepherd/skills/pr-shepherd/references/journal.md +0 -7
  420. package/plugins/pr-shepherd/skills/pr-shepherd/references/review-mutations.md +0 -9
  421. package/plugins/pr-shepherd/skills/pr-shepherd/references/stack-merge.md +0 -7
@@ -0,0 +1,19 @@
1
+ import { type MergeMethod } from "../../config/merge-method.mts";
2
+ import type { MergeCommandPlan } from "../../types.mts";
3
+ import type { RestMergeStackGuard } from "../../github/rest-merge.mts";
4
+ export interface MergePlanInput {
5
+ transport?: "rest";
6
+ pr: number;
7
+ repo: string;
8
+ nodeId: string;
9
+ headSha: string;
10
+ queue: boolean;
11
+ queueKnown?: boolean;
12
+ /** Omitted when the batch did not select repository merge settings. */
13
+ allowedMergeMethods?: readonly MergeMethod[];
14
+ expectedStack?: RestMergeStackGuard;
15
+ }
16
+ export interface MergeMethodUnavailable {
17
+ unavailable: string;
18
+ }
19
+ export declare function buildMergeCommandPlan(input: MergePlanInput): MergeCommandPlan | MergeMethodUnavailable;
@@ -0,0 +1,88 @@
1
+ import { loadConfig } from "../../config/load.mjs";
2
+ import { findMergeStrategies } from "../../config/merge-command-args.mjs";
3
+ import { chooseMergeMethod, configuredMergeMethod, } from "../../config/merge-method.mjs";
4
+ import { formatPrUrl } from "../../pr-reference.mjs";
5
+ import { buildPrShepherdCommand } from "../../cli/runner.mjs";
6
+ import { getGithubTransport } from "../../github/transport.mjs";
7
+ const ENQUEUE_MUTATION = "mutation EnqueuePullRequest($pullRequestId: ID!, $expectedHeadOid: GitObjectID!) { enqueuePullRequest(input: { pullRequestId: $pullRequestId, expectedHeadOid: $expectedHeadOid }) { mergeQueueEntry { id } } }";
8
+ export function buildMergeCommandPlan(input) {
9
+ if (input.transport === "rest" || getGithubTransport() === "rest") {
10
+ const configured = configuredMergeMethod(loadConfig().merge ?? {});
11
+ if (!input.queue && input.queueKnown !== true && configured)
12
+ return {
13
+ unavailable: "REST cannot verify merge-queue policy and cannot apply a configured direct merge method to an automatic merge request. Refresh branch policy before merging.",
14
+ };
15
+ let method;
16
+ if (!input.queue && input.queueKnown === true) {
17
+ const decision = chooseMergeMethod({
18
+ allowed: input.allowedMergeMethods,
19
+ configured,
20
+ fallback: "merge",
21
+ });
22
+ if ("unavailable" in decision)
23
+ return decision;
24
+ method = decision.method;
25
+ }
26
+ return {
27
+ mode: "rest",
28
+ command: buildPrShepherdCommand([
29
+ "apply",
30
+ "merge",
31
+ formatPrUrl(input.repo, input.pr),
32
+ "--require-sha",
33
+ input.headSha,
34
+ "--merge-action",
35
+ input.queue ? "merge_queue" : input.queueKnown ? "direct_merge" : "default",
36
+ ...(method ? ["--method", method] : []),
37
+ ...(input.expectedStack ? ["--expected-stack", JSON.stringify(input.expectedStack)] : []),
38
+ "--transport",
39
+ "rest",
40
+ ]),
41
+ };
42
+ }
43
+ const base = [
44
+ "gh",
45
+ "pr",
46
+ "merge",
47
+ String(input.pr),
48
+ "--repo",
49
+ input.repo,
50
+ "--match-head-commit",
51
+ input.headSha,
52
+ ];
53
+ if (input.queue) {
54
+ return {
55
+ mode: "queue",
56
+ command: { argv: base },
57
+ queueApiFallbackCommand: {
58
+ argv: [
59
+ "gh",
60
+ "api",
61
+ "graphql",
62
+ "-f",
63
+ `query=${ENQUEUE_MUTATION}`,
64
+ "-f",
65
+ `pullRequestId=${input.nodeId}`,
66
+ "-f",
67
+ `expectedHeadOid=${input.headSha}`,
68
+ ],
69
+ },
70
+ };
71
+ }
72
+ const mergeConfig = loadConfig().merge;
73
+ const configuredArgs = mergeConfig?.commandArgs ?? [];
74
+ const decision = chooseMergeMethod({
75
+ allowed: input.allowedMergeMethods,
76
+ configured: configuredMergeMethod(mergeConfig ?? {}),
77
+ fallback: "merge",
78
+ });
79
+ if ("unavailable" in decision)
80
+ return decision;
81
+ const hasStrategy = findMergeStrategies(configuredArgs).length > 0;
82
+ const commandArgs = hasStrategy ? configuredArgs : [...configuredArgs, `--${decision.method}`];
83
+ return {
84
+ mode: "auto",
85
+ command: { argv: [...base, "--auto", ...commandArgs] },
86
+ fallbackCommand: { argv: [...base, ...commandArgs] },
87
+ };
88
+ }
@@ -51,10 +51,13 @@ export function buildReadyMergeOutcome(enabled, readyElapsed, base, report) {
51
51
  report.mergeStatus.mergeRequirements?.mergeQueue?.enabled);
52
52
  const plan = buildMergeCommandPlan({
53
53
  pr: report.pr,
54
+ ...(report.transport && { transport: report.transport }),
54
55
  repo: report.repo,
55
56
  nodeId: report.nodeId,
56
57
  headSha: report.headSha ?? "unknown",
57
58
  queue,
59
+ queueKnown: (report.transport !== "rest" || report.branchProtection === null) &&
60
+ !(report.transportUnavailable ?? []).some(({ field }) => ["branchProtection", "branchRules"].includes(field)),
58
61
  ...(report.allowedMergeMethods && { allowedMergeMethods: report.allowedMergeMethods }),
59
62
  });
60
63
  if ("unavailable" in plan)
@@ -1,29 +1,18 @@
1
- import { type MergeMethod } from "../../config/merge-method.mts";
1
+ export { buildMergeCommandPlan } from "./merge-plan.mts";
2
2
  import type { AgentCheck, IterateResult, IterateResultBase, MergeCommandPlan, ShepherdReport } from "../../types.mts";
3
- interface MergePlanInput {
4
- pr: number;
5
- repo: string;
6
- nodeId: string;
7
- headSha: string;
8
- queue: boolean;
9
- /** Omitted when the batch did not select repository merge settings. */
10
- allowedMergeMethods?: readonly MergeMethod[];
11
- }
12
- export interface MergeMethodUnavailable {
3
+ interface QueueRecoveryUnavailable {
13
4
  unavailable: string;
14
5
  }
15
- export declare function buildMergeCommandPlan(input: MergePlanInput): MergeCommandPlan | MergeMethodUnavailable;
16
6
  export declare function renderMergeCommand(command: {
17
7
  argv: string[];
18
8
  }): string;
19
9
  /** Offer a guarded queue command; the caller decides whether the failure warrants a PR fix. */
20
- export declare function buildRemovedQueueRecovery(report: ShepherdReport, checks: AgentCheck[], merge: boolean | undefined): MergeCommandPlan | undefined;
10
+ export declare function buildRemovedQueueRecovery(report: ShepherdReport, checks: AgentCheck[], merge: boolean | undefined): MergeCommandPlan | QueueRecoveryUnavailable | undefined;
21
11
  /** Bind a caller's disposition to one removed stack queue commit, without submitting a merge. */
22
12
  export declare function buildStackQueueRemovalAcknowledgment(report: ShepherdReport, checks: AgentCheck[]): {
23
13
  argv: string[];
24
- } | undefined;
14
+ } | QueueRecoveryUnavailable | undefined;
25
15
  export declare function unavailableMergeResult(base: IterateResultBase, report: {
26
16
  pr: number;
27
17
  repo: string;
28
18
  }, unavailable: string): IterateResult;
29
- export {};
@@ -1,59 +1,11 @@
1
- import { loadConfig } from "../../config/load.mjs";
2
- import { findMergeStrategies } from "../../config/merge-command-args.mjs";
3
- import { chooseMergeMethod, configuredMergeMethod, } from "../../config/merge-method.mjs";
1
+ import { buildMergeCommandPlan } from "./merge-plan.mjs";
2
+ export { buildMergeCommandPlan } from "./merge-plan.mjs";
4
3
  import { formatPrUrl } from "../../pr-reference.mjs";
5
4
  import { renderShellCommand, buildPrShepherdCommand } from "../../cli/runner.mjs";
6
5
  import { hasQueueRecoveryEvidence } from "./check-evidence.mjs";
7
6
  import { isCiQueueRemovalReason } from "../../state/queue-removal-ack.mjs";
8
7
  import { buildEscalateHumanMessage } from "./escalate.mjs";
9
- const ENQUEUE_MUTATION = "mutation EnqueuePullRequest($pullRequestId: ID!, $expectedHeadOid: GitObjectID!) { enqueuePullRequest(input: { pullRequestId: $pullRequestId, expectedHeadOid: $expectedHeadOid }) { mergeQueueEntry { id } } }";
10
- export function buildMergeCommandPlan(input) {
11
- const base = [
12
- "gh",
13
- "pr",
14
- "merge",
15
- String(input.pr),
16
- "--repo",
17
- input.repo,
18
- "--match-head-commit",
19
- input.headSha,
20
- ];
21
- if (input.queue) {
22
- return {
23
- mode: "queue",
24
- command: { argv: base },
25
- queueApiFallbackCommand: {
26
- argv: [
27
- "gh",
28
- "api",
29
- "graphql",
30
- "-f",
31
- `query=${ENQUEUE_MUTATION}`,
32
- "-f",
33
- `pullRequestId=${input.nodeId}`,
34
- "-f",
35
- `expectedHeadOid=${input.headSha}`,
36
- ],
37
- },
38
- };
39
- }
40
- const mergeConfig = loadConfig().merge;
41
- const configuredArgs = mergeConfig?.commandArgs ?? [];
42
- const decision = chooseMergeMethod({
43
- allowed: input.allowedMergeMethods,
44
- configured: configuredMergeMethod(mergeConfig ?? {}),
45
- fallback: "merge",
46
- });
47
- if ("unavailable" in decision)
48
- return decision;
49
- const hasStrategy = findMergeStrategies(configuredArgs).length > 0;
50
- const commandArgs = hasStrategy ? configuredArgs : [...configuredArgs, `--${decision.method}`];
51
- return {
52
- mode: "auto",
53
- command: { argv: [...base, "--auto", ...commandArgs] },
54
- fallbackCommand: { argv: [...base, ...commandArgs] },
55
- };
56
- }
8
+ import { getGithubTransport } from "../../github/transport.mjs";
57
9
  export function renderMergeCommand(command) {
58
10
  return renderShellCommand(command.argv);
59
11
  }
@@ -63,6 +15,11 @@ export function buildRemovedQueueRecovery(report, checks, merge) {
63
15
  return undefined;
64
16
  if (!removedQueueRecoveryAvailable(report, checks, merge))
65
17
  return undefined;
18
+ // REST cannot prove that a recorded enqueue was removed or that no later enqueue exists.
19
+ // Never offer a resume command as if it could authorize a fresh same-head submission.
20
+ const unsupported = unsupportedRestQueueRecovery(report);
21
+ if (unsupported)
22
+ return unsupported;
66
23
  const plan = buildMergeCommandPlan({
67
24
  pr: report.pr,
68
25
  repo: report.repo,
@@ -79,6 +36,9 @@ export function buildStackQueueRemovalAcknowledgment(report, checks) {
79
36
  // This records a local disposition, without enqueueing; aggregate child sessions omit --merge.
80
37
  if (!removedQueueRecoveryAvailable(report, checks, true))
81
38
  return undefined;
39
+ const unsupported = unsupportedRestQueueRecovery(report);
40
+ if (unsupported)
41
+ return unsupported;
82
42
  const removal = report.mergeQueue.latestRemoval;
83
43
  return buildPrShepherdCommand([
84
44
  "apply",
@@ -92,6 +52,13 @@ export function buildStackQueueRemovalAcknowledgment(report, checks) {
92
52
  String(removal.createdAtUnix),
93
53
  ]);
94
54
  }
55
+ function unsupportedRestQueueRecovery(report) {
56
+ if (report.transport !== "rest" && getGithubTransport() !== "rest")
57
+ return undefined;
58
+ return {
59
+ unavailable: "Queue recovery is transport-unsupported: REST cannot verify current merge-queue removal evidence. Continue the printed fix steps; requeue and removal acknowledgment require verified current removal evidence.",
60
+ };
61
+ }
95
62
  function removedQueueRecoveryAvailable(report, checks, merge) {
96
63
  const queue = report.mergeQueue;
97
64
  const removedCommit = queue?.latestRemoval?.beforeCommitOid;
@@ -1,8 +1,4 @@
1
1
  import type { MergedBasePullRequest } from "../../types.mts";
2
+ import { type MergedBaseLookupInput } from "../../github/rest-merged-base-read.mts";
2
3
  /** A bounded, best-effort lookup; matching OIDs and repository prevent branch-name reuse false positives. */
3
- export declare function lookupMergedBasePullRequests(input: {
4
- owner: string;
5
- repo: string;
6
- baseRefName: string;
7
- baseRefOid: string;
8
- }): Promise<MergedBasePullRequest[]>;
4
+ export declare function lookupMergedBasePullRequests(input: MergedBaseLookupInput): Promise<MergedBasePullRequest[]>;
@@ -1,22 +1,26 @@
1
1
  import { graphql } from "../../github/client.mjs";
2
2
  import { MERGED_BASE_PULL_REQUESTS_QUERY } from "../../github/queries.mjs";
3
3
  import { pollRateLimitRetryAfterMs } from "../poll-quota.mjs";
4
+ import { githubOperation, isGithubReadFallbackError } from "../../github/transport.mjs";
5
+ import { readRestMergedBasePullRequests, } from "../../github/rest-merged-base-read.mjs";
4
6
  /** A bounded, best-effort lookup; matching OIDs and repository prevent branch-name reuse false positives. */
5
7
  export async function lookupMergedBasePullRequests(input) {
6
8
  try {
7
- const { data } = await graphql(MERGED_BASE_PULL_REQUESTS_QUERY, {
8
- owner: input.owner,
9
- repo: input.repo,
10
- branch: input.baseRefName,
11
- });
12
- return (data.repository?.pullRequests.nodes ?? []).filter((candidate) => candidate !== null &&
13
- candidate.state === "MERGED" &&
14
- candidate.headRefName === input.baseRefName &&
15
- candidate.headRefOid === input.baseRefOid &&
16
- candidate.headRepository?.nameWithOwner === `${input.owner}/${input.repo}`);
9
+ return await githubOperation("MergedBasePullRequests", async () => {
10
+ const { data } = await graphql(MERGED_BASE_PULL_REQUESTS_QUERY, {
11
+ owner: input.owner,
12
+ repo: input.repo,
13
+ branch: input.baseRefName,
14
+ });
15
+ return (data.repository?.pullRequests.nodes ?? []).filter((candidate) => candidate !== null &&
16
+ candidate.state === "MERGED" &&
17
+ candidate.headRefName === input.baseRefName &&
18
+ candidate.headRefOid === input.baseRefOid &&
19
+ candidate.headRepository?.nameWithOwner === `${input.owner}/${input.repo}`);
20
+ }, () => readRestMergedBasePullRequests(input));
17
21
  }
18
22
  catch (error) {
19
- if (pollRateLimitRetryAfterMs(error) !== null)
23
+ if (pollRateLimitRetryAfterMs(error) !== null || isGithubReadFallbackError(error))
20
24
  throw error;
21
25
  process.stderr.write(`pr-shepherd: merged-base PR lookup unavailable (ignored): ${error instanceof Error ? error.message : String(error)}\n`);
22
26
  return [];
@@ -1,4 +1,5 @@
1
1
  import { playbookPointer } from "../playbook-pointer.mjs";
2
+ import { getGithubTransport } from "../../github/transport.mjs";
2
3
  /**
3
4
  * One gh-stack rebase step. A native stack layer must not be rebased or merged from its base
4
5
  * branch alone: that rewrites one branch and strands every layer above it.
@@ -8,6 +9,14 @@ import { playbookPointer } from "../playbook-pointer.mjs";
8
9
  * stack number before a PR number) and checks each local layer against its PR head.
9
10
  */
10
11
  export function buildNativeStackRebaseInstruction(repo, stackNumber, start) {
12
+ if (getGithubTransport() === "rest") {
13
+ const boundary = "parentBranch" in start
14
+ ? `parent branch \`${start.parentBranch}\``
15
+ : "trunk" in start
16
+ ? `trunk \`${start.trunk}\``
17
+ : `bottom open layer PR #${start.bottomPr}`;
18
+ return `Use the repository's stack-update procedure for native stack #${stackNumber} in \`${repo}\`, starting at ${boundary} and preserving the ordered parent boundaries of every affected upper layer. Read membership with REST-backed Shepherd \`--stack\` output and update and push affected branches using the caller's git workflow. ${playbookPointer("Branch update")}`;
19
+ }
11
20
  const [checkout, command] = "parentBranch" in start
12
21
  ? [
13
22
  `check out the parent stack branch \`${start.parentBranch}\``,
@@ -55,6 +64,8 @@ export function buildConflictInstruction(stackRebase) {
55
64
  * After a merge-queue ejection update, push only when the update or a fix changed the head.
56
65
  */
57
66
  export function buildBranchPushInstruction(stackRebase, hasConflicts, mutationSuffix, ejectionUpdate = false) {
67
+ if (stackRebase && getGithubTransport() === "rest")
68
+ return `If the base update or a fix changed any heads, commit the remaining changes and push every affected stack branch using the repository's stack-update procedure${mutationSuffix}. If no heads changed, do not push.`;
58
69
  if (ejectionUpdate) {
59
70
  const push = stackRebase
60
71
  ? "commit any remaining changes on the PR head branch and push the rewritten stack with `gh stack push`"
@@ -1,7 +1,13 @@
1
1
  import type { AgentThread, AgentComment, AgentCheck, Review, ResolveCommand, FirstLookThread, FirstLookComment, ReviewThread } from "../../types.mts";
2
2
  import { type QueueEjectionRecovery } from "./queue-recovery-instructions.mts";
3
- /** Render a resolve command as a shell snippet. Appends `--require-sha "$HEAD_SHA"` when set. */
3
+ import type { InstructionStyle } from "../../config/load.mts";
4
+ /**
5
+ * Render a resolve command as a shell snippet. Appends `--require-sha HEAD` when set: run after
6
+ * the push step, the local HEAD is the pushed PR head, and `apply review` rejects the mutations
7
+ * if it is not. `apply review` reads that HEAD itself with a read-only `git rev-parse HEAD`.
8
+ */
4
9
  export declare function renderResolveCommand(rc: ResolveCommand): string;
5
10
  export declare function buildFixInstructions(threads: AgentThread[], actionableComments: AgentComment[], checks: AgentCheck[], changesRequestedReviews: Review[], baseBranch: string, resolveCommand: ResolveCommand, hasConflicts: boolean, prReference: string | number, _cancelledCount: number, firstLookThreads?: FirstLookThread[], firstLookComments?: FirstLookComment[], firstLookSummaries?: Review[], editedSummaries?: Review[], _inProgressRunIds?: string[], resolutionOnlyThreads?: ReviewThread[], resolveOnlyCommand?: ResolveCommand, behindBaseHint?: string, // iterate.behindBaseHint — see buildBehindBaseHintInstruction
6
11
  isBehind?: boolean, viewerCanUpdate?: boolean, hasExhaustedWorkflowRerun?: boolean, stackRebase?: string, // native stack layers rebase with gh-stack, not branch by branch
7
- queueEjection?: QueueEjectionRecovery): string[];
12
+ queueEjection?: QueueEjectionRecovery, // current merge-queue removal with failing queue checks
13
+ instructionStyle?: InstructionStyle): string[];
@@ -1,23 +1,28 @@
1
1
  import { renderShellCommand } from "../../cli/runner.mjs";
2
2
  import { buildFailingCheckInstructions, buildCrStaleClause, buildBehindBaseHintInstruction, buildRepeatedWorkflowBranchRecoveryInstructions, buildResolveCommandInstruction, buildFixCompletionInstruction, } from "./check-instructions.mjs";
3
- import { SHEPHERD_JOURNAL_FIRST_LOOK_GUIDANCE, buildShepherdJournalInstruction, } from "../shepherd-journal.mjs";
3
+ import { SHEPHERD_JOURNAL_FIRST_LOOK_GUIDANCE } from "../shepherd-journal.mjs";
4
4
  import { isFailingAgentCheck } from "../../checks/conclusions.mjs";
5
5
  import { buildCommitSuggestionInstruction } from "../commit-suggestion-instruction.mjs";
6
- import { partitionFixThreads, reviewSectionRefs } from "./fix-instruction-threads.mjs";
6
+ import { partitionFixThreads } from "./fix-instruction-threads.mjs";
7
7
  import { buildBranchPushInstruction, buildConflictInstruction } from "./native-stack-rebase.mjs";
8
8
  import { queueEjectionSteps } from "./queue-recovery-instructions.mjs";
9
- /** Render a resolve command as a shell snippet. Appends `--require-sha "$HEAD_SHA"` when set. */
9
+ import { buildPushJournalSteps } from "./fix-loop-instruction.mjs";
10
+ /**
11
+ * Render a resolve command as a shell snippet. Appends `--require-sha HEAD` when set: run after
12
+ * the push step, the local HEAD is the pushed PR head, and `apply review` rejects the mutations
13
+ * if it is not. `apply review` reads that HEAD itself with a read-only `git rev-parse HEAD`.
14
+ */
10
15
  export function renderResolveCommand(rc) {
11
- const parts = [...rc.argv];
12
- if (rc.requiresHeadSha)
13
- parts.push("--require-sha", "$HEAD_SHA");
14
- return renderShellCommand(parts);
16
+ const command = renderShellCommand(rc.argv);
17
+ return rc.requiresHeadSha ? `${command} ${REQUIRE_HEAD_SHA}` : command;
15
18
  }
19
+ const REQUIRE_HEAD_SHA = "--require-sha HEAD";
16
20
  export function buildFixInstructions(threads, actionableComments, checks, changesRequestedReviews, baseBranch, resolveCommand, hasConflicts, prReference, _cancelledCount, firstLookThreads = [], firstLookComments = [], firstLookSummaries = [], editedSummaries = [], _inProgressRunIds = [], resolutionOnlyThreads = [], resolveOnlyCommand, behindBaseHint = "", // iterate.behindBaseHint — see buildBehindBaseHintInstruction
17
21
  isBehind = false, viewerCanUpdate = false, hasExhaustedWorkflowRerun = false, stackRebase, // native stack layers rebase with gh-stack, not branch by branch
18
- queueEjection) {
22
+ queueEjection, // current merge-queue removal with failing queue checks
23
+ instructionStyle = "inline") {
19
24
  const instructions = [];
20
- const { locatedThreads, unlocatedMutatedThreads, unlocatedThreads } = partitionFixThreads(threads, resolveCommand, resolveOnlyCommand);
25
+ const { locatedThreads, unlocatedThreads } = partitionFixThreads(threads, resolveCommand, resolveOnlyCommand);
21
26
  const failingChecks = checks.filter((c) => isFailingAgentCheck(c));
22
27
  const repeatedWorkflowBranchRecoveryInstructions = buildRepeatedWorkflowBranchRecoveryInstructions(baseBranch, hasExhaustedWorkflowRerun, { isBehind, hasConflicts }, stackRebase);
23
28
  const hasRepeatedWorkflowBranchRecovery = repeatedWorkflowBranchRecoveryInstructions.length > 0;
@@ -28,18 +33,8 @@ queueEjection) {
28
33
  changesRequestedReviews.length > 0 ||
29
34
  actionableComments.length > 0;
30
35
  // Start with interpretation. The agent decides what raw feedback warrants a code change.
31
- if (hasNonConflictHints) {
32
- const actionableSections = reviewSectionRefs({
33
- hasReviewThreads: locatedThreads.length > 0 || unlocatedMutatedThreads.length > 0,
34
- hasUnlocatedSkipThreads: unlocatedThreads.length > 0,
35
- hasActionableComments: actionableComments.length > 0,
36
- hasFailingChecks: failingChecks.length > 0,
37
- hasAnnotations,
38
- hasChangesRequested: changesRequestedReviews.length > 0,
39
- });
40
- const sectionRef = actionableSections.length > 0 ? `under ${actionableSections.join(", ")}` : "above";
41
- instructions.push(`Review each item ${sectionRef} and decide whether it needs a code change.`);
42
- }
36
+ if (hasNonConflictHints)
37
+ instructions.push("Fix each warranted item.");
43
38
  // A conflicting native stack layer follows the printed gh-stack route, so it omits the hint.
44
39
  const branchUpdateHint = buildBehindBaseHintInstruction(baseBranch, behindBaseHint, {
45
40
  isBehind,
@@ -66,41 +61,32 @@ queueEjection) {
66
61
  const hasSuggestions = locatedThreads.some((t) => t.suggestion);
67
62
  if (hasSuggestions)
68
63
  instructions.push(buildCommitSuggestionInstruction(prReference, "## Review threads"));
69
- if (locatedThreads.length > 0 || actionableComments.length > 0) {
70
- // Actionable comments carry no file/line location (unlike threads), so "referenced above"
71
- // is only accurate when threads are present.
72
- const filesRef = locatedThreads.length > 0 ? "each file referenced above" : "the relevant files";
73
- instructions.push(`Apply every warranted review fix in ${filesRef}.`);
74
- }
75
64
  if (resolutionOnlyThreads.length > 0)
76
65
  instructions.push("Review the threads under `## Review threads to resolve` before running the generated mutations.");
77
66
  instructions.push(...buildFailingCheckInstructions(failingChecks), ...repeatedWorkflowBranchRecoveryInstructions, ...queueEjectionSteps(queueEjection, stackRebase, branchRecovery));
78
67
  if (hasAnnotations)
79
68
  instructions.push("Inspect every referenced range under `## Check annotations` and apply any warranted change.");
80
- if (changesRequestedReviews.length > 0) {
81
- const staleClause = buildCrStaleClause(changesRequestedReviews);
82
- instructions.push(`Read every body under \`## Changes-requested reviews\` and apply any warranted change.${staleClause}`);
83
- }
69
+ // The first step already covers applying changes-requested bodies; only stale CRs add a step.
70
+ const staleClause = buildCrStaleClause(changesRequestedReviews);
71
+ if (staleClause)
72
+ instructions.push(staleClause);
84
73
  if (!hintWithConflictStep)
85
74
  instructions.push(...branchUpdateHint);
86
75
  const hasReviewMutations = resolveCommand.hasMutations || resolveOnlyCommand?.hasMutations === true;
87
76
  const mutationSuffix = hasReviewMutations ? " before review mutations" : "";
88
- if (branchRecovery || queueEjection) {
89
- instructions.push(buildBranchPushInstruction(stackRebase, hasConflicts, mutationSuffix, !branchRecovery));
90
- }
91
- else if (hasNonConflictHints) {
92
- instructions.push("If you changed code, commit any remaining changes and push to the PR head branch. If you did not, do not commit.");
93
- }
94
- if (viewerCanUpdate &&
77
+ const genericPush = !(branchRecovery || queueEjection) && hasNonConflictHints;
78
+ const wantsJournal = viewerCanUpdate &&
95
79
  (hasReviewMutations ||
96
80
  hasNonConflictHints ||
97
81
  firstLookTotal > 0 ||
98
82
  firstLookSummaries.length > 0 ||
99
- editedTotal > 0)) {
100
- instructions.push(buildShepherdJournalInstruction(prReference));
83
+ editedTotal > 0);
84
+ if (branchRecovery || queueEjection) {
85
+ instructions.push(buildBranchPushInstruction(stackRebase, hasConflicts, mutationSuffix, !branchRecovery));
101
86
  }
87
+ instructions.push(...buildPushJournalSteps(instructionStyle, prReference, genericPush, wantsJournal));
102
88
  if (resolveOnlyCommand?.hasMutations)
103
- instructions.push("Run the `resolve-only:` command shown above.");
104
- instructions.push(...buildResolveCommandInstruction(resolveCommand), buildFixCompletionInstruction());
89
+ instructions.push(`Run: \`${renderResolveCommand(resolveOnlyCommand)}\``);
90
+ instructions.push(...buildResolveCommandInstruction(resolveCommand, renderResolveCommand(resolveCommand)), buildFixCompletionInstruction());
105
91
  return instructions;
106
92
  }
@@ -2,6 +2,9 @@ import { graphql } from "../../github/client.mjs";
2
2
  import { readStackTopology, verifiedBottomOpenLayer } from "../../github/stack-read.mjs";
3
3
  import { UPPER_LAYER_CONFLICT_TARGET_QUERY } from "../../github/queries.mjs";
4
4
  import { pollRateLimitRetryAfterMs } from "../poll-quota.mjs";
5
+ import { githubOperation } from "../../github/transport.mjs";
6
+ import { readRestPull } from "../../github/rest-pr-core.mjs";
7
+ import { readRestBehind } from "../../github/rest-check-read.mjs";
5
8
  export async function lookupUpperLayerTrunkConflict(input) {
6
9
  let bottomPr = input.bottomPr;
7
10
  if (bottomPr === undefined) {
@@ -31,11 +34,24 @@ export async function lookupUpperLayerTrunkConflict(input) {
31
34
  return { trunk: input.trunk, bottomPr };
32
35
  let data;
33
36
  try {
34
- ({ data } = await graphql(UPPER_LAYER_CONFLICT_TARGET_QUERY, {
37
+ ({ data } = await githubOperation("UpperLayerConflictTarget", () => graphql(UPPER_LAYER_CONFLICT_TARGET_QUERY, {
35
38
  owner: input.owner,
36
39
  name: input.name,
37
40
  number: input.pr,
38
41
  headRef: input.headRef,
42
+ }), async () => {
43
+ const repo = { owner: input.owner, name: input.name };
44
+ const pull = await readRestPull(input.pr, repo);
45
+ const behindBy = await readRestBehind(repo, pull.base.ref, input.headRef);
46
+ return {
47
+ data: {
48
+ repository: {
49
+ pullRequest: {
50
+ baseRef: { compare: { behindBy } },
51
+ },
52
+ },
53
+ },
54
+ };
39
55
  }));
40
56
  }
41
57
  catch (err) {
@@ -1,5 +1,6 @@
1
1
  import { readStackTopology, stackAncestryGaps } from "../../github/stack-read.mjs";
2
2
  import { buildNativeStackRebaseInstruction } from "./native-stack-rebase.mjs";
3
+ import { getGithubTransport } from "../../github/transport.mjs";
3
4
  /**
4
5
  * Find a stale immediate parent boundary for one PR.
5
6
  *
@@ -36,6 +37,8 @@ function buildStaleNativeStackAncestryInstructions(repo, stackNumber, ancestry)
36
37
  buildNativeStackRebaseInstruction(`${repo.owner}/${repo.name}`, stackNumber, {
37
38
  parentBranch: ancestry.parentHeadRefName,
38
39
  }),
39
- "Push the rewritten stack with `gh stack push`.",
40
+ getGithubTransport() === "rest"
41
+ ? "Push every affected stack branch using the repository's stack-update procedure."
42
+ : "Push the rewritten stack with `gh stack push`.",
40
43
  ];
41
44
  }
@@ -3,4 +3,8 @@ export declare function applyStallGuard(stallKey: {
3
3
  owner: string;
4
4
  repo: string;
5
5
  pr: number;
6
- }, stallTimeoutSeconds: number, headSha: string, base: IterateResultBase, prNumber: number, prospectiveResult: IterateResult, report: ShepherdReport, reviewSummaryIds: string[]): Promise<IterateResult>;
6
+ }, stallTimeoutSeconds: number, headSha: string, base: IterateResultBase, prNumber: number, prospectiveResult: IterateResult, report: ShepherdReport, reviewSummaryIds: string[], stallDeadlineSink?: StallDeadlineSink): Promise<IterateResult>;
7
+ /** Internal out-parameter: when the earliest unstarted check would trip the CI-start stall. */
8
+ export interface StallDeadlineSink {
9
+ ciStartDeadlineSeconds?: number;
10
+ }
@@ -62,13 +62,14 @@ function computeStallFingerprint(action, headSha, base, report, reviewSummaryIds
62
62
  annotations,
63
63
  });
64
64
  }
65
- export async function applyStallGuard(stallKey, stallTimeoutSeconds, headSha, base, prNumber, prospectiveResult, report, reviewSummaryIds) {
65
+ export async function applyStallGuard(stallKey, stallTimeoutSeconds, headSha, base, prNumber, prospectiveResult, report, reviewSummaryIds, stallDeadlineSink) {
66
66
  const prReference = formatPrUrl(report.repo, prNumber);
67
67
  const nowSeconds = Math.floor(Date.now() / 1000);
68
- const stalledChecks = findCiStartStalledChecks(report.checks.inProgress, nowSeconds, {
69
- stallTimeoutSeconds,
70
- action: prospectiveResult.action,
71
- });
68
+ const ciStartOpts = { stallTimeoutSeconds, action: prospectiveResult.action };
69
+ const stalledChecks = findCiStartStalledChecks(report.checks.inProgress, nowSeconds, ciStartOpts);
70
+ if (stallDeadlineSink) {
71
+ stallDeadlineSink.ciStartDeadlineSeconds = ciStartStallDeadline(report.checks.inProgress, nowSeconds, ciStartOpts);
72
+ }
72
73
  if (stalledChecks.length > 0) {
73
74
  const pending = pendingReviewCommandsFromResult(prospectiveResult);
74
75
  const stalledDuration = formatDurationApprox(Math.max(...stalledChecks.map((c) => c.ageSeconds)));
@@ -168,13 +169,24 @@ function stallStateUnavailable(base, prReference, prospectiveResult, reason) {
168
169
  },
169
170
  };
170
171
  }
171
- function findCiStartStalledChecks(checks, nowSeconds, opts) {
172
+ function unstartedStallCandidates(checks, nowSeconds, opts) {
172
173
  if (opts.stallTimeoutSeconds <= 0 || opts.action !== "wait")
173
174
  return [];
174
175
  return checks
175
176
  .filter((c) => isUnstartedCheck(c))
176
177
  .map((c) => toAgentStalledCheck(c, nowSeconds))
177
- .filter((c) => c.createdAtUnix !== undefined && c.ageSeconds >= opts.stallTimeoutSeconds);
178
+ .filter((c) => c.createdAtUnix !== undefined);
179
+ }
180
+ function findCiStartStalledChecks(checks, nowSeconds, opts) {
181
+ return unstartedStallCandidates(checks, nowSeconds, opts).filter((c) => c.ageSeconds >= opts.stallTimeoutSeconds);
182
+ }
183
+ /** Unix seconds at which the oldest unstarted check reaches the stall timeout, if any. */
184
+ function ciStartStallDeadline(checks, nowSeconds, opts) {
185
+ const candidates = unstartedStallCandidates(checks, nowSeconds, opts);
186
+ if (candidates.length === 0)
187
+ return undefined;
188
+ const maxAge = Math.max(...candidates.map((c) => c.ageSeconds));
189
+ return nowSeconds - maxAge + opts.stallTimeoutSeconds;
178
190
  }
179
191
  function isUnstartedCheck(check) {
180
192
  if (check.source === "status_context")
@@ -10,6 +10,7 @@ export interface ThreadMutationRouting {
10
10
  }
11
11
  export declare function threadHasAuthorizedMutation(thread: {
12
12
  id: string;
13
+ isResolved?: boolean;
13
14
  viewerCanReply?: boolean;
14
15
  viewerCanResolve?: boolean;
15
16
  }, replyThreadIds: ReadonlySet<string>, resolveThreadIds: ReadonlySet<string>): boolean;
@@ -1,6 +1,7 @@
1
1
  import { isConfiguredBotAuthor, isHumanAuthor, isViewerAuthoredHuman, } from "../../comments/authors.mjs";
2
2
  import { threadEndedByShepherd } from "../../comments/marker.mjs";
3
3
  import { shouldResolveOtherHumanThread } from "../../comments/thread-resolve-policy.mjs";
4
+ import { canGenerateGithubMutation } from "../../github/mutation-policy.mjs";
4
5
  function dedupeIds(ids) {
5
6
  return [...new Set(ids)];
6
7
  }
@@ -19,9 +20,10 @@ export function threadHasAuthorizedMutation(thread, replyThreadIds, resolveThrea
19
20
  const inResolve = resolveThreadIds.has(thread.id);
20
21
  if (!inReply && !inResolve)
21
22
  return false;
22
- if (inReply && thread.viewerCanReply !== true)
23
+ if (inReply && !canGenerateGithubMutation(thread.viewerCanReply, "reply"))
23
24
  return false;
24
- if (inResolve && thread.viewerCanResolve !== true)
25
+ if (inResolve &&
26
+ (thread.isResolved !== false || !canGenerateGithubMutation(thread.viewerCanResolve, "resolve")))
25
27
  return false;
26
28
  return true;
27
29
  }
@@ -4,6 +4,7 @@ import { readCiRetrigger, sameCiRetrigger, writeCiRetrigger } from "../../state/
4
4
  import { buildFixCompletionInstruction } from "./check-instructions.mjs";
5
5
  import { buildEscalateHumanMessage, buildEscalateSuggestion } from "./escalate.mjs";
6
6
  import { buildNativeStackRebaseInstruction } from "./native-stack-rebase.mjs";
7
+ import { getGithubTransport } from "../../github/transport.mjs";
7
8
  /** Rebase when the trunk or the PR base is behind; otherwise close and reopen once. */
8
9
  function decideUnreportedRequired(input) {
9
10
  if (input.behind)
@@ -29,12 +30,14 @@ function buildUnreportedRequiredInstructions(input) {
29
30
  if (!input.behind) {
30
31
  return [
31
32
  facts,
32
- `Retrigger workflows once for this head with \`gh pr close ${input.pr} -R ${input.repo}\` then \`gh pr reopen ${input.pr} -R ${input.repo}\`.`,
33
+ getGithubTransport() === "rest"
34
+ ? `Retrigger workflows once for this head: run \`gh api --method PATCH repos/${input.repo}/pulls/${input.pr} -f state=closed\`, then run \`gh api --method PATCH repos/${input.repo}/pulls/${input.pr} -f state=open\`.`
35
+ : `Retrigger workflows once for this head with \`gh pr close ${input.pr} -R ${input.repo}\` then \`gh pr reopen ${input.pr} -R ${input.repo}\`.`,
33
36
  "If those checks are still missing on the next poll, investigate why the workflows did not start. Do not close the PR again. Shepherd escalates with `required-checks-unreported` when this remains the only blocker.",
34
37
  ];
35
38
  }
36
39
  const rebase = input.stackRebase
37
- ? `${input.stackRebase} Then push the rewritten stack with \`gh stack push\`.`
40
+ ? `${input.stackRebase} Then push the rewritten stack${getGithubTransport() === "rest" ? " using the repository's stack-update procedure" : " with `gh stack push`"}.`
38
41
  : `Rebase onto \`${input.baseBranch}\` and push.`;
39
42
  return [
40
43
  facts,