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
@@ -1,4 +1,5 @@
1
1
  import type { RawBaseRef } from "./batch-raw-rules.mts";
2
+ import type { AutoMergeRequestStatus } from "../types/merge-requirements.mts";
2
3
  export interface RawAuthor {
3
4
  __typename?: string;
4
5
  login: string;
@@ -6,11 +7,24 @@ export interface RawAuthor {
6
7
  interface RawSummaryComment {
7
8
  id: string;
8
9
  body: string;
9
- isMinimized: boolean;
10
+ isMinimized?: boolean;
10
11
  viewerDidAuthor?: boolean;
11
12
  authorAssociation?: string;
12
13
  url?: string;
13
14
  author: RawAuthor | null;
15
+ /** GraphQL handoff fields; absent on REST summaries. */
16
+ viewerCanMinimize?: boolean;
17
+ createdAt?: string;
18
+ updatedAt?: string;
19
+ pullRequestReview?: {
20
+ id: string;
21
+ } | null;
22
+ path?: string | null;
23
+ line?: number | null;
24
+ startLine?: number | null;
25
+ commit?: {
26
+ oid: string;
27
+ } | null;
14
28
  }
15
29
  interface SummaryConnection<T> {
16
30
  totalCount: number;
@@ -25,7 +39,7 @@ type RawCheckContext = {
25
39
  name: string;
26
40
  status: string;
27
41
  conclusion: string | null;
28
- detailsUrl?: string;
42
+ detailsUrl?: string | null;
29
43
  startedAt?: string | null;
30
44
  completedAt?: string | null;
31
45
  annotations?: {
@@ -33,10 +47,12 @@ type RawCheckContext = {
33
47
  };
34
48
  checkSuite: {
35
49
  createdAt?: string | null;
50
+ updatedAt?: string | null;
36
51
  workflowRun: {
37
52
  databaseId?: string | number;
38
53
  event: string;
39
54
  createdAt?: string | null;
55
+ updatedAt?: string | null;
40
56
  workflow?: {
41
57
  name: string;
42
58
  databaseId: string | number;
@@ -47,6 +63,9 @@ type RawCheckContext = {
47
63
  __typename: "StatusContext";
48
64
  context: string;
49
65
  state: string;
66
+ createdAt?: string;
67
+ targetUrl?: string | null;
68
+ description?: string | null;
50
69
  };
51
70
  interface RawCheckContexts {
52
71
  totalCount: number;
@@ -58,6 +77,7 @@ interface RawCheckContexts {
58
77
  nodes: RawCheckContext[];
59
78
  }
60
79
  export interface RawCheckRollup {
80
+ state?: string | null;
61
81
  contexts: RawCheckContexts;
62
82
  }
63
83
  /** A commit whose status contexts the compact summary reads. */
@@ -66,16 +86,47 @@ export interface RawSummaryCommit {
66
86
  committedDate?: string;
67
87
  statusCheckRollup: RawCheckRollup | null;
68
88
  checkSuites?: {
89
+ pageInfo?: {
90
+ hasNextPage: boolean;
91
+ };
69
92
  nodes: Array<{
93
+ id?: string;
70
94
  status?: string | null;
71
95
  conclusion: string | null;
72
96
  workflowRun: {
97
+ databaseId?: number | null;
73
98
  event: string | null;
99
+ url?: string | null;
100
+ workflow?: {
101
+ name: string | null;
102
+ } | null;
74
103
  } | null;
75
104
  }>;
76
105
  } | null;
77
106
  }
78
107
  export interface RawSummaryPr {
108
+ transport?: "rest";
109
+ transportUnavailable?: Array<{
110
+ field: string;
111
+ reason: string;
112
+ }>;
113
+ /** GraphQL handoff fields (see `stack-handoff.mts`); absent on REST summaries. */
114
+ id?: string;
115
+ viewerDidAuthor?: boolean;
116
+ viewerCanEnableAutoMerge?: boolean;
117
+ viewerCanEditFiles?: boolean;
118
+ headRepository?: {
119
+ nameWithOwner: string;
120
+ viewerPermission: string | null;
121
+ } | null;
122
+ isMergeQueueEnabled?: boolean;
123
+ batchAutoMergeRequest?: {
124
+ enabledAt: string;
125
+ mergeMethod: string;
126
+ enabledBy?: {
127
+ login: string;
128
+ } | null;
129
+ } | null;
79
130
  number: number;
80
131
  title: string;
81
132
  url: string;
@@ -91,7 +142,7 @@ export interface RawSummaryPr {
91
142
  }>;
92
143
  } | null;
93
144
  isDraft: boolean;
94
- viewerCanUpdate: boolean;
145
+ viewerCanUpdate?: boolean;
95
146
  headRefName: string;
96
147
  headRefOid: string;
97
148
  baseRefOid: string;
@@ -102,7 +153,9 @@ export interface RawSummaryPr {
102
153
  reviewDecision: string | null;
103
154
  reviewRequests?: {
104
155
  nodes: Array<{
105
- requestedReviewer: RawAuthor | null;
156
+ requestedReviewer: (Partial<RawAuthor> & {
157
+ name?: string;
158
+ }) | null;
106
159
  }>;
107
160
  };
108
161
  latestReviews?: {
@@ -111,7 +164,8 @@ export interface RawSummaryPr {
111
164
  author: RawAuthor | null;
112
165
  }>;
113
166
  };
114
- isInMergeQueue: boolean;
167
+ isInMergeQueue?: boolean;
168
+ autoMergeRequest?: AutoMergeRequestStatus | null;
115
169
  mergeQueueAdditions?: {
116
170
  nodes: Array<{
117
171
  createdAt: string;
@@ -158,15 +212,21 @@ export interface RawSummaryPr {
158
212
  }>;
159
213
  reviewThreads: SummaryConnection<{
160
214
  id: string;
161
- isResolved: boolean;
162
- isOutdated: boolean;
215
+ isResolved?: boolean;
216
+ isOutdated?: boolean;
217
+ viewerCanReply?: boolean;
218
+ viewerCanResolve?: boolean;
163
219
  path: string | null;
164
- rootComments?: {
165
- nodes: RawSummaryComment[];
166
- };
220
+ line?: number | null;
221
+ startLine?: number | null;
222
+ /**
223
+ * The first comments from the root. `pageInfo.hasPreviousPage` is GraphQL's
224
+ * `hasNextPage` (aliased): true when comments exist outside this window.
225
+ */
167
226
  comments: SummaryConnection<RawSummaryComment>;
168
227
  }>;
169
228
  commits: {
229
+ totalCount?: number;
170
230
  nodes: Array<{
171
231
  commit: RawSummaryCommit;
172
232
  }>;
@@ -1,6 +1,11 @@
1
1
  import type { PollSummaryChecks, PollSummaryReview } from "../types.mts";
2
2
  import type { RawSummaryPr } from "./poll-summary-raw.mts";
3
- /** Fresh compact evidence required before a READY receipt can be used. */
3
+ /**
4
+ * Fresh compact evidence required before a READY receipt can be used.
5
+ * `allowBlocked` asks whether GitHub's BLOCKED state is the only gap, so a
6
+ * caller can tell a blocker it cannot clear from missing or stale evidence.
7
+ */
4
8
  export declare function isCurrentSummaryReady(raw: RawSummaryPr, checks: PollSummaryChecks, review: PollSummaryReview, options?: {
5
9
  allowQueuedProgress?: boolean;
10
+ allowBlocked?: boolean;
6
11
  }): boolean;
@@ -1,8 +1,16 @@
1
1
  import { summarizePollSummaryChecks } from "./poll-summary-checks.mjs";
2
2
  import { parseBranchRules } from "./batch-parsers-rules.mjs";
3
3
  import { rulesComplete } from "./fingerprint-fields.mjs";
4
- /** Fresh compact evidence required before a READY receipt can be used. */
4
+ import { isKnownMergeStateStatus, transportReadinessGaps } from "./transport-evidence.mjs";
5
+ /**
6
+ * Fresh compact evidence required before a READY receipt can be used.
7
+ * `allowBlocked` asks whether GitHub's BLOCKED state is the only gap, so a
8
+ * caller can tell a blocker it cannot clear from missing or stale evidence.
9
+ */
5
10
  export function isCurrentSummaryReady(raw, checks, review, options = {}) {
11
+ const blockedStates = options.allowBlocked
12
+ ? ["DIRTY", "BEHIND", "UNKNOWN", "HAS_HOOKS"]
13
+ : ["DIRTY", "BEHIND", "UNKNOWN", "BLOCKED", "HAS_HOOKS"];
6
14
  const queued = options.allowQueuedProgress === true && raw.isInMergeQueue;
7
15
  // Merge-group checks may still be running after the PR earned its receipt;
8
16
  // source-commit checks must remain complete. A fresh pending source check is
@@ -16,7 +24,9 @@ export function isCurrentSummaryReady(raw, checks, review, options = {}) {
16
24
  // satisfied. BLOCKED is not conversation-specific, and queue progress
17
25
  // alone is not that proof.
18
26
  const requiresConversationResolution = parseBranchRules(raw.baseRef).requiresConversationResolution;
19
- return (checks.incomplete !== true &&
27
+ return (isKnownMergeStateStatus(raw.mergeStateStatus) &&
28
+ transportReadinessGaps(raw, raw.mergeStateStatus).length === 0 &&
29
+ checks.incomplete !== true &&
20
30
  sourceChecks.incomplete !== true &&
21
31
  (review.incomplete !== true ||
22
32
  raw.mergeStateStatus === "CLEAN" ||
@@ -26,8 +36,7 @@ export function isCurrentSummaryReady(raw, checks, review, options = {}) {
26
36
  raw.mergeable !== "CONFLICTING" &&
27
37
  raw.mergeStateStatus !== "DIRTY" &&
28
38
  (queued || raw.mergeable === "MERGEABLE") &&
29
- (queued ||
30
- !["DIRTY", "BEHIND", "UNKNOWN", "BLOCKED", "HAS_HOOKS"].includes(raw.mergeStateStatus)) &&
39
+ (queued || !blockedStates.includes(raw.mergeStateStatus)) &&
31
40
  (checks.failing ?? 0) === 0 &&
32
41
  (sourceChecks.failing ?? 0) === 0 &&
33
42
  (sourceChecks.inProgress ?? 0) === 0 &&
@@ -0,0 +1,3 @@
1
+ import type { RawSummaryPr } from "./poll-summary-raw.mts";
2
+ /** Positive rules remain authoritative even when other branch policy is unavailable. */
3
+ export declare function restQueueRequirement(raw: Pick<RawSummaryPr, "baseRef" | "transportUnavailable">): boolean | undefined;
@@ -0,0 +1,12 @@
1
+ import { parseBranchRules } from "./batch-parsers-rules.mjs";
2
+ /** Positive rules remain authoritative even when other branch policy is unavailable. */
3
+ export function restQueueRequirement(raw) {
4
+ if (parseBranchRules(raw.baseRef).requiresMergeQueue)
5
+ return true;
6
+ if (!raw.baseRef?.rules ||
7
+ raw.baseRef.rules.pageInfo?.hasNextPage !== false ||
8
+ raw.baseRef.branchProtectionRule !== null ||
9
+ raw.transportUnavailable?.some(({ field }) => ["branchProtection", "branchRules"].includes(field)))
10
+ return undefined;
11
+ return false;
12
+ }
@@ -1,4 +1,4 @@
1
1
  import { type SeenMarker } from "../state/seen-comments.mts";
2
2
  import type { PollSummaryReview } from "../types.mts";
3
3
  import type { RawSummaryPr } from "./poll-summary-raw.mts";
4
- export declare function summarizePollSummaryReview(raw: RawSummaryPr, seen: Map<string, SeenMarker>, viewerCanAdminister: boolean): Promise<PollSummaryReview>;
4
+ export declare function summarizePollSummaryReview(raw: RawSummaryPr, seen: Map<string, SeenMarker>, viewerCanAdminister: boolean | undefined): Promise<PollSummaryReview>;
@@ -1,14 +1,18 @@
1
1
  import { normalizeBotUsernames } from "../comments/authors.mjs";
2
2
  import { applyRules } from "../classify/apply.mjs";
3
- import { discoverRuleFiles, loadRules } from "../classify/loader.mjs";
3
+ import { normalizeAuthorType } from "../comments/authors.mjs";
4
+ import { loadClassifyRules } from "../classify/loader.mjs";
4
5
  import { loadConfig } from "../config/load.mjs";
5
6
  import { getEffectiveCwd } from "../execution-context.mjs";
6
7
  import { classifyItem } from "../state/seen-comments.mjs";
8
+ import { mutationWasDenied } from "../state/seen-comments.mjs";
9
+ import { canGenerateGithubMutation } from "./mutation-policy.mjs";
10
+ import { threadEndedByShepherd } from "../comments/marker.mjs";
7
11
  const THREAD_COMMENT_SEPARATOR = "\n\n--- thread comment ---\n\n";
8
12
  export async function summarizePollSummaryReview(raw, seen, viewerCanAdminister) {
9
13
  const config = loadConfig();
10
14
  const bots = normalizeBotUsernames(config.botUsernames);
11
- const rules = await loadRules(discoverRuleFiles(getEffectiveCwd()));
15
+ const rules = await loadClassifyRules(getEffectiveCwd(), config.standardRules);
12
16
  let actionable = 0;
13
17
  let incomplete = raw.comments.pageInfo.hasPreviousPage ||
14
18
  raw.reviews.pageInfo.hasPreviousPage ||
@@ -37,24 +41,35 @@ export async function summarizePollSummaryReview(raw, seen, viewerCanAdminister)
37
41
  if (isSuppressed(rules, "changes-requested", review))
38
42
  continue;
39
43
  const isBot = review.author?.__typename === "Bot" || bots.has(review.author?.login.toLowerCase() ?? "");
40
- if ((isBot && viewerCanAdminister) ||
44
+ if ((isBot &&
45
+ canGenerateGithubMutation(viewerCanAdminister, "dismiss") &&
46
+ !mutationWasDenied(review.id, review.body, seen)) ||
41
47
  classifyItem(review.id, review.body, seen) !== "unchanged")
42
48
  actionable += 1;
43
49
  }
44
50
  for (const thread of raw.reviewThreads.nodes) {
45
- if (thread.comments.pageInfo.hasPreviousPage)
51
+ // The window holds the first comments. Past it, a new reply leaves the window
52
+ // unchanged, so a long thread cannot prove it was seen.
53
+ const truncated = thread.comments.pageInfo.hasPreviousPage;
54
+ if (truncated)
46
55
  incomplete = true;
47
- const root = thread.rootComments?.nodes[0] ?? thread.comments.nodes[0];
56
+ const root = thread.comments.nodes[0];
48
57
  const transcript = thread.comments.nodes
49
58
  .map((comment) => comment.body)
50
59
  .join(THREAD_COMMENT_SEPARATOR);
51
- if (isSuppressed(rules, "review-thread", root, thread.id, thread.path, transcript))
60
+ const completeResolved = thread.isResolved === true && !truncated;
61
+ if (completeResolved &&
62
+ threadEndedByShepherd({ body: root?.body ?? "", comments: thread.comments.nodes }))
52
63
  continue;
53
- const repeatable = root?.viewerDidAuthor === true ||
54
- root?.author?.__typename === "Bot" ||
55
- bots.has(root?.author?.login.toLowerCase() ?? "");
56
- const unseen = classifyItem(thread.id, transcript, seen) !== "unchanged";
57
- if ((!thread.isResolved && (repeatable || unseen)) ||
64
+ if (isSuppressed(rules, "review-thread", root, thread.id, thread.path ?? root?.path ?? null, root?.body ?? "", completeResolved))
65
+ continue;
66
+ const repeatable = !mutationWasDenied(thread.id, transcript, seen) &&
67
+ (root?.viewerDidAuthor === true ||
68
+ root?.author?.__typename === "Bot" ||
69
+ bots.has(root?.author?.login.toLowerCase() ?? ""));
70
+ const unseen = truncated || classifyItem(thread.id, transcript, seen) !== "unchanged";
71
+ if ((thread.isResolved === false && (repeatable || unseen)) ||
72
+ (thread.isResolved === undefined && unseen) ||
58
73
  ((thread.isResolved || thread.isOutdated) && unseen))
59
74
  actionable += 1;
60
75
  }
@@ -66,20 +81,20 @@ export async function summarizePollSummaryReview(raw, seen, viewerCanAdminister)
66
81
  ...(incomplete && { incomplete: true }),
67
82
  };
68
83
  }
69
- function isSuppressed(rules, kind, raw, id = raw?.id ?? "unknown", path, body = raw?.body ?? "") {
84
+ function isSuppressed(rules, kind, raw, id = raw?.id ?? "unknown", path, body = raw?.body ?? "", autoResolveSatisfied = false) {
70
85
  const item = {
71
86
  kind,
72
87
  id,
73
88
  author: raw?.author?.login ?? "unknown",
74
- authorType: raw?.author?.__typename === "Bot"
75
- ? "Bot"
76
- : raw?.author?.__typename === "User"
77
- ? "User"
78
- : "Unknown",
79
- ...(raw?.authorAssociation && { authorAssociation: raw.authorAssociation }),
89
+ authorType: normalizeAuthorType(raw?.author?.__typename, raw?.author?.login),
90
+ ...(raw?.authorAssociation !== undefined && { authorAssociation: raw.authorAssociation }),
80
91
  body,
81
- ...(raw?.url && { url: raw.url }),
92
+ ...(kind === "review-thread" ? { url: raw?.url ?? "" } : raw?.url ? { url: raw.url } : {}),
82
93
  ...(kind === "review-thread" && { path }),
83
94
  };
84
- return applyRules(rules, item).suppress === true;
95
+ const action = applyRules(rules, item);
96
+ // An auto-resolve match is hidden only once the full check minimizes or resolves it, or
97
+ // surfaces a denied mutation once; until then it stays actionable so that check runs.
98
+ return (action.suppress === true &&
99
+ (action.autoResolve !== true || kind === "changes-requested" || autoResolveSatisfied));
85
100
  }
@@ -1,4 +1,7 @@
1
1
  import { loadConfig } from "../config/load.mjs";
2
+ import { isKnownMergeStateStatus, transportReadinessGaps } from "./transport-evidence.mjs";
3
+ import { canGenerateGithubMutation } from "./mutation-policy.mjs";
4
+ import { getGithubTransport, isCcrTransport } from "./transport.mjs";
2
5
  export function routePollSummary(raw, checks, review, opts) {
3
6
  const actions = loadConfig().actions;
4
7
  const state = normalizePollSummaryState(raw.state);
@@ -22,7 +25,13 @@ export function routePollSummary(raw, checks, review, opts) {
22
25
  return { action: "fix_code", reasons: ["unreported-required-checks"] };
23
26
  }
24
27
  if ((checks.inProgress ?? 0) > 0 ||
28
+ !isKnownMergeStateStatus(raw.mergeStateStatus) ||
25
29
  raw.mergeable === "UNKNOWN" ||
30
+ raw.mergeStateStatus === "UNKNOWN")
31
+ return { action: "wait", reasons: ["pending-or-unknown"] };
32
+ if (transportReadinessGaps(raw, raw.mergeStateStatus).length > 0)
33
+ return { action: "escalate", reasons: ["transport-unsupported"] };
34
+ if (raw.mergeable === "UNKNOWN" ||
26
35
  raw.mergeStateStatus === "UNKNOWN" ||
27
36
  raw.mergeStateStatus === "BEHIND" ||
28
37
  raw.mergeStateStatus === "BLOCKED" ||
@@ -33,15 +42,22 @@ export function routePollSummary(raw, checks, review, opts) {
33
42
  const autoMarkReadyDisabled = opts.noAutoMarkReady || actions.autoMarkReady === false;
34
43
  // The stack selector asks the agent to mark a disabled draft ready, so
35
44
  // that transition needs the same capability as the automatic one.
36
- if (!raw.viewerCanUpdate && (!autoMarkReadyDisabled || opts.stackPrNumber !== undefined)) {
45
+ if (!canGenerateGithubMutation(raw.viewerCanUpdate, "ready") &&
46
+ (!autoMarkReadyDisabled || opts.stackPrNumber !== undefined)) {
47
+ const unsupported = getGithubTransport() === "rest" && raw.viewerCanUpdate !== false && !isCcrTransport();
48
+ if (unsupported)
49
+ return { action: "escalate", reasons: ["transport-unsupported"] };
37
50
  return { action: "escalate", reasons: ["mark-ready-authorization-required"] };
38
51
  }
39
52
  return autoMarkReadyDisabled
40
53
  ? { action: "wait", reasons: ["draft-auto-mark-ready-disabled"] }
41
54
  : { action: "mark_ready", reasons: ["draft-appears-ready"] };
42
55
  }
43
- if (opts.merge && raw.isInMergeQueue) {
44
- return { action: "wait", reasons: ["already-in-merge-queue"] };
56
+ if (opts.merge && (raw.isInMergeQueue || raw.autoMergeRequest)) {
57
+ return {
58
+ action: "wait",
59
+ reasons: [raw.isInMergeQueue ? "already-in-merge-queue" : "already-auto-merging"],
60
+ };
45
61
  }
46
62
  if (opts.merge && raw.stack && opts.stackPrNumber === undefined) {
47
63
  return { action: "fix_code", reasons: ["authoritative-poll-required"] };
@@ -0,0 +1,11 @@
1
+ import type { RepoInfo } from "./client.mts";
2
+ import type { RawSummaryPr } from "./poll-summary-raw.mts";
3
+ import { type StackRead } from "./stack-read.mts";
4
+ /**
5
+ * Read the hydrated stack in pages of at most `stackSize` entries.
6
+ * A wide check matrix can blow GitHub's per-query resource limit on the full
7
+ * page. Halve `first` down to one entry and let `readStack` follow `after`.
8
+ * The shared summary fragment stays intact: one layer is the same shape as an
9
+ * explicit summary, and check hydration still completes windows past 100.
10
+ */
11
+ export declare function readGraphqlStackSummary(anchor: number, repo: RepoInfo, stackSize: number): Promise<StackRead<RawSummaryPr>>;
@@ -0,0 +1,27 @@
1
+ import { GitHubRequestError, isRetryableGraphQlResourceLimit } from "./errors.mjs";
2
+ import { POLL_STACK_SUMMARY_QUERY } from "./queries.mjs";
3
+ import { MAX_STACK_ENTRIES_PER_PAGE, readStack } from "./stack-read.mjs";
4
+ /**
5
+ * Read the hydrated stack in pages of at most `stackSize` entries.
6
+ * A wide check matrix can blow GitHub's per-query resource limit on the full
7
+ * page. Halve `first` down to one entry and let `readStack` follow `after`.
8
+ * The shared summary fragment stays intact: one layer is the same shape as an
9
+ * explicit summary, and check hydration still completes windows past 100.
10
+ */
11
+ export async function readGraphqlStackSummary(anchor, repo, stackSize) {
12
+ let ceiling = MAX_STACK_ENTRIES_PER_PAGE;
13
+ for (;;) {
14
+ const first = Math.max(1, Math.min(stackSize, ceiling));
15
+ try {
16
+ return await readStack(POLL_STACK_SUMMARY_QUERY, anchor, repo, { first }, ceiling);
17
+ }
18
+ catch (err) {
19
+ if (!(err instanceof GitHubRequestError) ||
20
+ !isRetryableGraphQlResourceLimit(err.graphqlErrors) ||
21
+ first <= 1) {
22
+ throw err;
23
+ }
24
+ ceiling = Math.floor(first / 2);
25
+ }
26
+ }
27
+ }
@@ -3,5 +3,7 @@ import type { PollSummaryChecks } from "../types.mts";
3
3
  import type { RawSummaryPr } from "./poll-summary-raw.mts";
4
4
  /** Current trunk rules may remain available on a merged layer's base ref. */
5
5
  export declare function trunkRequiredContexts(ordered: readonly RawSummaryPr[], repo: RepoInfo): Promise<string[] | undefined>;
6
+ /** Required contexts of the layer's merge target: the trunk's for a stack layer when known. */
7
+ export declare function summaryRequiredContexts(raw: RawSummaryPr, mergeTargetContexts: readonly string[] | undefined): string[];
6
8
  /** Record missing required contexts. A running Actions workflow does not clear the names. */
7
- export declare function applyUnreportedRequiredChecks(raw: RawSummaryPr, checks: PollSummaryChecks, mergeTargetContexts: readonly string[] | undefined): void;
9
+ export declare function applyUnreportedRequiredChecks(raw: RawSummaryPr, checks: PollSummaryChecks, required: readonly string[]): void;
@@ -16,15 +16,18 @@ export async function trunkRequiredContexts(ordered, repo) {
16
16
  const loaded = await loadRefRules(repo.owner, repo.name, `refs/heads/${trunk}`, bottom.headRefOid);
17
17
  return loaded.contexts;
18
18
  }
19
- /** Record missing required contexts. A running Actions workflow does not clear the names. */
20
- export function applyUnreportedRequiredChecks(raw, checks, mergeTargetContexts) {
19
+ /** Required contexts of the layer's merge target: the trunk's for a stack layer when known. */
20
+ export function summaryRequiredContexts(raw, mergeTargetContexts) {
21
21
  const trunk = raw.stack?.baseRefName;
22
- const required = selectMergeTargetContexts({
22
+ return selectMergeTargetContexts({
23
23
  localContexts: parseBranchRules(raw.baseRef).requiredStatusCheckContexts,
24
24
  ...(mergeTargetContexts !== undefined && { trunkContexts: mergeTargetContexts }),
25
25
  baseRefName: raw.baseRefName,
26
26
  ...(trunk !== undefined && mergeTargetContexts !== undefined && { trunkRefName: trunk }),
27
27
  });
28
+ }
29
+ /** Record missing required contexts. A running Actions workflow does not clear the names. */
30
+ export function applyUnreportedRequiredChecks(raw, checks, required) {
28
31
  const missing = unreportedRequiredContexts(required, reportedNames(raw));
29
32
  if (missing.length === 0)
30
33
  return;
@@ -1,12 +1,15 @@
1
1
  import type { PollSummaryCommandOptions, PollSummaryItem, PollSummarySelection, PollSummaryStackAncestry } from "../types.mts";
2
2
  import { type RepoInfo } from "./client.mts";
3
3
  import type { RawSummaryPr } from "./poll-summary-raw.mts";
4
+ import type { StackHandoffSource } from "./stack-handoff-page.mts";
4
5
  export interface FetchedPollSummary {
5
6
  selection: PollSummarySelection;
6
7
  prs: PollSummaryItem[];
7
8
  stackAncestry?: PollSummaryStackAncestry[];
8
9
  allowedMergeMethods?: import("../config/merge-method.mts").MergeMethod[];
10
+ /** GraphQL stack reads only: the raw layers a routing tick hands to its one-PR sessions. */
11
+ handoffSource?: StackHandoffSource;
9
12
  }
10
- export declare function fetchPollSummary(opts: PollSummaryCommandOptions, repo: RepoInfo): Promise<FetchedPollSummary>;
11
13
  /** Fresh, read-only snapshot used to bind a one-PR READY receipt to stack routing. */
12
14
  export declare function fetchRawSummaryPr(pr: number, repo: RepoInfo): Promise<RawSummaryPr>;
15
+ export declare function fetchPollSummary(opts: PollSummaryCommandOptions, repo: RepoInfo): Promise<FetchedPollSummary>;
@@ -1,22 +1,29 @@
1
+ import { readRestStackSummary } from "./rest-stack-summary.mjs";
2
+ import { githubOperation, getGithubTransport, runWithGithubTransport } from "./transport.mjs";
3
+ import { readRestExplicitSummary } from "./rest-explicit-summary-read.mjs";
4
+ import { withRestConditionalScope } from "./rest-conditional-scope.mjs";
1
5
  import { EXIT, ShepherdError } from "../exit-codes.mjs";
2
6
  import { graphqlWithRateLimit } from "./client.mjs";
3
- import { GitHubRequestError, isRetryableGraphQlResourceLimit, missingRepositoryError, } from "./errors.mjs";
7
+ import { missingRepositoryError } from "./errors.mjs";
4
8
  import { hydratePollSummaryChecks } from "./poll-summary-check-hydration.mjs";
5
9
  import { refreshUnknownSummaryMergeability } from "./poll-summary-mergeability.mjs";
6
10
  import { summarizePollSummaryPr } from "./poll-summary-projector.mjs";
7
11
  import { trunkRequiredContexts } from "./poll-summary-unreported.mjs";
8
- import { POLL_STACK_SUMMARY_QUERY, POLL_SUMMARY_FRAGMENT } from "./queries.mjs";
9
- import { MAX_STACK_ENTRIES_PER_PAGE, readStack, readStackTopology, stackAncestryGaps, } from "./stack-read.mjs";
12
+ import { loadStackSizeHint, storeStackSizeHint } from "./stack-size-hint.mjs";
13
+ import { POLL_SUMMARY_FRAGMENT } from "./queries.mjs";
14
+ import { stackAncestryGaps } from "./stack-read.mjs";
15
+ import { readGraphqlStackSummary } from "./poll-summary-stack-page.mjs";
16
+ import { stackHandoffSource } from "./stack-handoff.mjs";
10
17
  const MAX_EXPLICIT_PRS_PER_QUERY = 50;
11
- export async function fetchPollSummary(opts, repo) {
18
+ async function fetchSelectedPollSummary(opts, repo) {
12
19
  if (opts.stackPrNumber !== undefined)
13
20
  return fetchStackSummary(opts, repo);
14
- const requested = deduplicate(opts.prNumbers ?? []);
21
+ const requested = [...new Set(opts.prNumbers ?? [])];
15
22
  if (requested.length === 0) {
16
23
  throw new ShepherdError("Aggregate poll requires at least two PRs or --stack <PR>", EXIT.USAGE);
17
24
  }
18
25
  const raw = [];
19
- let viewerCanAdminister = false;
26
+ let viewerCanAdminister;
20
27
  for (let offset = 0; offset < requested.length; offset += MAX_EXPLICIT_PRS_PER_QUERY) {
21
28
  const chunk = requested.slice(offset, offset + MAX_EXPLICIT_PRS_PER_QUERY);
22
29
  const fetched = await fetchExplicitChunk(chunk, repo);
@@ -33,7 +40,7 @@ export async function fetchRawSummaryPr(pr, repo) {
33
40
  const fetched = await fetchExplicitChunk([pr], repo);
34
41
  return fetched.prs[0];
35
42
  }
36
- async function fetchExplicitChunk(prs, repo) {
43
+ async function fetchGraphqlExplicitChunk(prs, repo) {
37
44
  const declarations = prs.map((_, index) => `$pr${index}: Int!`).join(", ");
38
45
  const aliases = prs
39
46
  .map((_, index) => `pr${index}: pullRequest(number: $pr${index}) { ...PollSummaryPr }`)
@@ -59,18 +66,39 @@ async function fetchExplicitChunk(prs, repo) {
59
66
  }
60
67
  return { prs: rawPrs, viewerCanAdminister: result.data.repository.viewerCanAdminister };
61
68
  }
69
+ async function fetchExplicitChunk(prs, repo) {
70
+ return githubOperation("PollSummary", () => runWithGithubTransport("graphql", () => fetchGraphqlExplicitChunk(prs, repo)), async () => ({
71
+ prs: await withSummaryConditionalScope(repo, prs[0], () => readRestExplicitSummary(prs, repo)),
72
+ }));
73
+ }
74
+ /**
75
+ * Entries on an unsized first summary page. GitHub prices `first`, not the
76
+ * nodes returned, and four layers are the most that still price at 1 point.
77
+ * Larger stacks page on, sized to the entries that remain.
78
+ */
79
+ const UNSIZED_STACK_SUMMARY_FIRST = 4;
62
80
  /**
63
- * Read the stack's topology first so the hydrated page requests only as many
64
- * entries as the stack holds: GitHub prices `first`, not the nodes returned.
81
+ * Size the hydrated page to the stack so it requests only as many entries as the
82
+ * stack holds. The size comes from the anchor's last summary; the first summary
83
+ * reads four entries and pages on, which never costs more than reading the
84
+ * topology first. A stack that has since grown pages on, and one that shrank
85
+ * overpays once.
65
86
  */
66
87
  async function fetchStackSummary(opts, repo) {
67
88
  const anchor = opts.stackPrNumber;
68
- const topology = await readStackTopology(anchor, repo);
69
- const { stackNumber, stackSize, viewerLogin, viewerCanAdminister, ordered, allowedMergeMethods } = await readStackSummary(anchor, repo, topology.stackSize);
89
+ const stateKey = { owner: repo.owner, repo: repo.name, pr: anchor };
90
+ const graphql = getGithubTransport() !== "rest";
91
+ const hint = graphql ? await loadStackSizeHint(stateKey) : 0;
92
+ const sizeHint = hint || UNSIZED_STACK_SUMMARY_FIRST;
93
+ const read = await readStackSummary(anchor, repo, sizeHint);
94
+ const { stackNumber, stackSize, viewerLogin, viewerCanAdminister, ordered, allowedMergeMethods } = read;
95
+ if (graphql && stackSize !== hint)
96
+ await storeStackSizeHint(stateKey, stackSize);
70
97
  for (const pr of ordered) {
71
98
  await hydratePollSummaryChecks(pr, repo);
72
99
  await refreshUnknownSummaryMergeability(pr, repo);
73
100
  }
101
+ const handoffSource = getGithubTransport() === "rest" ? undefined : stackHandoffSource(read);
74
102
  const stackAncestry = stackAncestryGaps(ordered);
75
103
  const required = await trunkRequiredContexts(ordered, repo);
76
104
  return {
@@ -78,30 +106,16 @@ async function fetchStackSummary(opts, repo) {
78
106
  prs: await Promise.all(ordered.map((pr) => summarizePollSummaryPr(pr, repo, opts, viewerCanAdminister, required, viewerLogin))),
79
107
  ...(stackAncestry.length > 0 && { stackAncestry }),
80
108
  ...(allowedMergeMethods && { allowedMergeMethods }),
109
+ ...(handoffSource && { handoffSource }),
81
110
  };
82
111
  }
83
- /**
84
- * A wide check matrix can blow GitHub's per-query resource limit on the full
85
- * page. Halve `first` down to one entry and let `readStack` follow `after`.
86
- * The shared summary fragment stays intact: one layer is the same shape as an
87
- * explicit summary, and check hydration still completes windows past 100.
88
- */
89
112
  async function readStackSummary(anchor, repo, stackSize) {
90
- let first = Math.min(stackSize, MAX_STACK_ENTRIES_PER_PAGE);
91
- for (;;) {
92
- try {
93
- return await readStack(POLL_STACK_SUMMARY_QUERY, anchor, repo, { first });
94
- }
95
- catch (err) {
96
- if (!(err instanceof GitHubRequestError) ||
97
- !isRetryableGraphQlResourceLimit(err.graphqlErrors) ||
98
- first <= 1) {
99
- throw err;
100
- }
101
- first = Math.floor(first / 2);
102
- }
103
- }
113
+ return githubOperation("PollStackSummary", () => readGraphqlStackSummary(anchor, repo, stackSize), () => withSummaryConditionalScope(repo, anchor, () => readRestStackSummary(anchor, repo)));
114
+ }
115
+ /** REST summary reads are conditional under the anchor PR's state: an unchanged body is a free 304. */
116
+ function withSummaryConditionalScope(repo, pr, read) {
117
+ return withRestConditionalScope({ owner: repo.owner, repo: repo.name, pr }, read);
104
118
  }
105
- function deduplicate(values) {
106
- return [...new Set(values)];
119
+ export function fetchPollSummary(opts, repo) {
120
+ return githubOperation("PollSummarySelection", () => runWithGithubTransport("graphql", () => fetchSelectedPollSummary(opts, repo)), () => fetchSelectedPollSummary(opts, repo));
107
121
  }
@@ -10,11 +10,13 @@
10
10
  export declare const BATCH_PR_QUERY: string;
11
11
  /** Slim @include follow-up for outstanding batch-query connections. */
12
12
  export declare const BATCH_PR_PAGE_QUERY: string;
13
- /** Cheap PR fingerprint used to skip an unchanged BatchPr snapshot. */
14
- export declare const PR_FINGERPRINT_QUERY: string;
15
13
  /** Compact per-PR fields shared by explicit-list and native-stack summary queries. */
16
14
  export declare const POLL_SUMMARY_FRAGMENT: string;
17
- /** Exact compact summary sibling only when a one-PR READY receipt needs evidence. */
15
+ /**
16
+ * Exact compact summary sibling only when a one-PR READY receipt needs evidence.
17
+ * The batch's first context page shrinks to 50 so the sibling still prices at 1 point;
18
+ * `BatchPrPage` reads any further contexts.
19
+ */
18
20
  export declare const BATCH_PR_RECEIPT_QUERY: string;
19
21
  /** Trunk branch rules plus how far `headRef` is behind that branch. */
20
22
  export declare const REF_RULES_QUERY: string;
@@ -68,3 +70,5 @@ export declare const MARK_PR_READY_MUTATION: string;
68
70
  export declare const GET_PR_BODY_QUERY: string;
69
71
  /** Update the PR body. */
70
72
  export declare const UPDATE_PR_BODY_MUTATION: string;
73
+ /** CheckRun titles, summaries, and first annotations for routed stack-layer handoffs. */
74
+ export declare const STACK_HANDOFF_CHECK_RUNS_QUERY: string;