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
@@ -14,13 +14,15 @@ const withSharedFragments = (query) => `${gql("ref-rules.gql")}\n${gql("pr-merge
14
14
  export const BATCH_PR_QUERY = withSharedFragments(gql("batch-pr.gql"));
15
15
  /** Slim @include follow-up for outstanding batch-query connections. */
16
16
  export const BATCH_PR_PAGE_QUERY = gql("batch-pr-page.gql");
17
- /** Cheap PR fingerprint used to skip an unchanged BatchPr snapshot. */
18
- export const PR_FINGERPRINT_QUERY = withSharedFragments(gql("pr-fingerprint.gql"));
19
17
  const POLL_SUMMARY_CHECK_CONTEXTS_FRAGMENT = gql("poll-summary-check-contexts.gql");
20
18
  /** Compact per-PR fields shared by explicit-list and native-stack summary queries. */
21
19
  export const POLL_SUMMARY_FRAGMENT = `${gql("ref-rules.gql")}\n${POLL_SUMMARY_CHECK_CONTEXTS_FRAGMENT}\n${gql("poll-summary-fragment.gql")}`;
22
- /** Exact compact summary sibling only when a one-PR READY receipt needs evidence. */
23
- export const BATCH_PR_RECEIPT_QUERY = `${POLL_SUMMARY_CHECK_CONTEXTS_FRAGMENT}\n${gql("poll-summary-fragment.gql")}\n${BATCH_PR_QUERY.replace(" pullRequest(number: $pr) {", " receiptSummary: pullRequest(number: $pr) { ...PollSummaryPr }\n pullRequest(number: $pr) {")}`;
20
+ /**
21
+ * Exact compact summary sibling only when a one-PR READY receipt needs evidence.
22
+ * The batch's first context page shrinks to 50 so the sibling still prices at 1 point;
23
+ * `BatchPrPage` reads any further contexts.
24
+ */
25
+ export const BATCH_PR_RECEIPT_QUERY = `${POLL_SUMMARY_CHECK_CONTEXTS_FRAGMENT}\n${gql("poll-summary-fragment.gql")}\n${BATCH_PR_QUERY.replace(" pullRequest(number: $pr) {", " receiptSummary: pullRequest(number: $pr) { ...PollSummaryPr }\n pullRequest(number: $pr) {").replace("contexts(first: 100) {", "contexts(first: 50) {")}`;
24
26
  /** Trunk branch rules plus how far `headRef` is behind that branch. */
25
27
  export const REF_RULES_QUERY = `${gql("ref-rules.gql")}\n${gql("ref-rules-query.gql")}`;
26
28
  /** How far a non-stack head is behind its PR base. One compare, no rules payload. */
@@ -73,3 +75,5 @@ export const MARK_PR_READY_MUTATION = gql("mark-pr-ready.gql");
73
75
  export const GET_PR_BODY_QUERY = gql("get-pr-body.gql");
74
76
  /** Update the PR body. */
75
77
  export const UPDATE_PR_BODY_MUTATION = gql("update-pr-body.gql");
78
+ /** CheckRun titles, summaries, and first annotations for routed stack-layer handoffs. */
79
+ export const STACK_HANDOFF_CHECK_RUNS_QUERY = gql("stack-handoff-check-runs.gql");
@@ -0,0 +1,7 @@
1
+ import type { RateLimitInfo } from "./http-utils.mts";
2
+ /**
3
+ * Same reset window: the lowest remaining and the highest used, taken independently. The Claude
4
+ * Code proxy can answer one tick's routes with `X-RateLimit-Used` values that disagree with each
5
+ * other and with `X-RateLimit-Remaining`, so neither half of one sample is trusted over the other.
6
+ */
7
+ export declare function mostConservativeSample<T extends Pick<RateLimitInfo, "remaining" | "used">>(current: T, candidate: T): T;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Same reset window: the lowest remaining and the highest used, taken independently. The Claude
3
+ * Code proxy can answer one tick's routes with `X-RateLimit-Used` values that disagree with each
4
+ * other and with `X-RateLimit-Remaining`, so neither half of one sample is trusted over the other.
5
+ */
6
+ export function mostConservativeSample(current, candidate) {
7
+ const base = candidate.remaining < current.remaining ? candidate : current;
8
+ const used = current.used === undefined || candidate.used === undefined
9
+ ? (current.used ?? candidate.used)
10
+ : Math.max(current.used, candidate.used);
11
+ return { ...base, ...(used !== undefined && { used }) };
12
+ }
@@ -0,0 +1,50 @@
1
+ import { type RepoInfo } from "./client.mts";
2
+ export interface ReplyEvidence {
3
+ viewer: string;
4
+ comments: Array<{
5
+ id: string;
6
+ body: string;
7
+ author: string | null;
8
+ }>;
9
+ }
10
+ interface Page {
11
+ totalCount: number;
12
+ pageInfo: {
13
+ hasNextPage: boolean;
14
+ endCursor: string | null;
15
+ };
16
+ nodes: Array<{
17
+ id: string;
18
+ databaseId: number;
19
+ body: string;
20
+ author: {
21
+ login: string;
22
+ } | null;
23
+ }>;
24
+ }
25
+ interface Node {
26
+ id: string;
27
+ pullRequest: {
28
+ number: number;
29
+ repository: {
30
+ nameWithOwner: string;
31
+ };
32
+ };
33
+ comments: Page;
34
+ }
35
+ export interface ReplyEvidenceResponse {
36
+ viewer: {
37
+ login: string;
38
+ } | null;
39
+ nodes: Array<Node | null>;
40
+ }
41
+ /** Thread selection shared with the `apply review` preflight, which needs `$cursor: String`. */
42
+ export declare const REPLY_EVIDENCE_THREAD_SELECTION = "... on PullRequestReviewThread {\n id pullRequest { number repository { nameWithOwner } }\n comments(first: 100, after: $cursor) {\n totalCount\n pageInfo { hasNextPage endCursor }\n nodes { id databaseId body author { login } }\n }\n }";
43
+ /**
44
+ * Complete evidence for one GraphQL thread, starting from a response that already holds its first
45
+ * comment page. Later pages use `ReplyRecoveryEvidence`. Throws when anything is unverifiable.
46
+ */
47
+ export declare function threadReplyEvidence(repo: RepoInfo, pr: number, id: string, first: ReplyEvidenceResponse): Promise<ReplyEvidence>;
48
+ /** Complete, bounded evidence for one mutation batch; unavailable evidence never certifies a retry. */
49
+ export declare function readReplyRecoveryEvidence(repo: RepoInfo, pr: number, requestedIds: readonly string[]): Promise<Map<string, ReplyEvidence>>;
50
+ export {};
@@ -0,0 +1,118 @@
1
+ import { graphqlWithRateLimit } from "./client.mjs";
2
+ import { githubOperation } from "./transport.mjs";
3
+ import { recordThreadIdentity, resolveGraphqlThreadId, resolveRestThreadRoot, } from "./rest-identities.mjs";
4
+ import { readRest, readRestPages, restRepoPath } from "./rest-reader-core.mjs";
5
+ import { mapPool } from "../util/pool.mjs";
6
+ /** Thread selection shared with the `apply review` preflight, which needs `$cursor: String`. */
7
+ export const REPLY_EVIDENCE_THREAD_SELECTION = `... on PullRequestReviewThread {
8
+ id pullRequest { number repository { nameWithOwner } }
9
+ comments(first: 100, after: $cursor) {
10
+ totalCount
11
+ pageInfo { hasNextPage endCursor }
12
+ nodes { id databaseId body author { login } }
13
+ }
14
+ }`;
15
+ const QUERY = `query ReplyRecoveryEvidence($ids: [ID!]!, $cursor: String) {
16
+ _shepherdRateLimit: rateLimit { cost limit nodeCount remaining resetAt used }
17
+ viewer { login }
18
+ nodes(ids: $ids) { ${REPLY_EVIDENCE_THREAD_SELECTION} }
19
+ }`;
20
+ const readEvidencePage = (ids, cursor) => graphqlWithRateLimit(QUERY, { ids, cursor });
21
+ /**
22
+ * Complete evidence for one GraphQL thread, starting from a response that already holds its first
23
+ * comment page. Later pages use `ReplyRecoveryEvidence`. Throws when anything is unverifiable.
24
+ */
25
+ export async function threadReplyEvidence(repo, pr, id, first) {
26
+ const viewer = first.viewer?.login;
27
+ if (typeof viewer !== "string" || !viewer)
28
+ throw new Error("Reply recovery viewer is unavailable");
29
+ let node = first.nodes.find((item) => item?.id === id);
30
+ const comments = [];
31
+ const cursors = new Set();
32
+ const total = node?.comments?.totalCount;
33
+ const root = node?.comments?.nodes?.[0]?.databaseId;
34
+ const seenIds = new Set();
35
+ for (let page = 0; page < 100; page++) {
36
+ if (!node ||
37
+ node.pullRequest?.number !== pr ||
38
+ node.pullRequest.repository.nameWithOwner.toLowerCase() !==
39
+ `${repo.owner}/${repo.name}`.toLowerCase() ||
40
+ !node.comments?.pageInfo ||
41
+ typeof node.comments.pageInfo.hasNextPage !== "boolean" ||
42
+ !Array.isArray(node.comments.nodes) ||
43
+ !Number.isSafeInteger(total) ||
44
+ total < 1 ||
45
+ node.comments.totalCount !== total)
46
+ throw new Error("Reply recovery transcript is unavailable");
47
+ if (page === 0) {
48
+ if (!Number.isSafeInteger(root) || root < 1)
49
+ throw new Error("Reply recovery root identity is unavailable");
50
+ await recordThreadIdentity(repo, pr, id, root);
51
+ }
52
+ for (const comment of node.comments.nodes) {
53
+ if (typeof comment.id !== "string" ||
54
+ !comment.id ||
55
+ seenIds.has(comment.id) ||
56
+ typeof comment.body !== "string" ||
57
+ (comment.author !== null && typeof comment.author?.login !== "string"))
58
+ throw new Error("Reply recovery comment is incomplete");
59
+ seenIds.add(comment.id);
60
+ comments.push({ id: comment.id, body: comment.body, author: comment.author?.login ?? null });
61
+ }
62
+ if (!node.comments.pageInfo.hasNextPage && comments.length === total)
63
+ return { viewer, comments };
64
+ if (!node.comments.pageInfo.hasNextPage)
65
+ break;
66
+ const cursor = node.comments.pageInfo.endCursor;
67
+ if (!cursor || cursors.has(cursor))
68
+ break;
69
+ cursors.add(cursor);
70
+ const next = await readEvidencePage([id], cursor);
71
+ if (next.data.viewer?.login !== viewer)
72
+ throw new Error("Reply recovery viewer changed");
73
+ node = next.data.nodes.find((item) => item?.id === id);
74
+ }
75
+ throw new Error("Reply recovery transcript pagination is incomplete");
76
+ }
77
+ /** Complete, bounded evidence for one mutation batch; unavailable evidence never certifies a retry. */
78
+ export async function readReplyRecoveryEvidence(repo, pr, requestedIds) {
79
+ if (requestedIds.length === 0)
80
+ return new Map();
81
+ if (requestedIds.length > 10)
82
+ throw new Error("Reply recovery batch exceeds 10 threads");
83
+ return githubOperation("ReplyRecoveryEvidence", async () => {
84
+ const ids = await Promise.all(requestedIds.map(resolveGraphqlThreadId));
85
+ const first = await readEvidencePage(ids, null);
86
+ const viewer = first.data.viewer?.login;
87
+ if (typeof viewer !== "string" || !viewer)
88
+ throw new Error("Reply recovery viewer is unavailable");
89
+ const entries = await mapPool(ids, 4, async (id, index) => [requestedIds[index], await threadReplyEvidence(repo, pr, id, first.data)]);
90
+ return new Map(entries);
91
+ }, async () => {
92
+ const viewer = await readRest("GET", "/user");
93
+ if (typeof viewer.login !== "string" || !viewer.login)
94
+ throw new Error("Reply recovery viewer is unavailable");
95
+ const inline = (await readRestPages(`${restRepoPath(repo)}/pulls/${pr}/comments`)).nodes;
96
+ const entries = await Promise.all(requestedIds.map(async (id) => {
97
+ const root = await resolveRestThreadRoot(repo, pr, id);
98
+ if (!inline.some((comment) => String(comment.id) === root))
99
+ throw new Error("Reply recovery thread is unavailable");
100
+ const comments = inline
101
+ .filter((comment) => String(comment.id) === root || String(comment.in_reply_to_id) === root)
102
+ .map((comment) => {
103
+ if (typeof comment.node_id !== "string" ||
104
+ !comment.node_id ||
105
+ typeof comment.body !== "string" ||
106
+ (comment.user !== null && typeof comment.user?.login !== "string"))
107
+ throw new Error("Reply recovery comment is incomplete");
108
+ return {
109
+ id: comment.node_id,
110
+ body: comment.body,
111
+ author: comment.user?.login ?? null,
112
+ };
113
+ });
114
+ return [id, { viewer: viewer.login, comments }];
115
+ }));
116
+ return new Map(entries);
117
+ });
118
+ }
@@ -1,3 +1,2 @@
1
1
  import { type RepoInfo } from "./client.mts";
2
- /** Best-effort transcript evidence; it never filters user-supplied mutation IDs. */
3
2
  export declare function fetchReplyThreadTranscripts(pr: number, repo: RepoInfo, requestedIds: readonly string[]): Promise<Map<string, string>>;
@@ -1,3 +1,6 @@
1
+ import { githubOperation } from "./transport.mjs";
2
+ import { readRestFeedback } from "./rest-feedback-read.mjs";
3
+ import { resolveRestThreadRoot, restThreadId } from "./rest-identities.mjs";
1
4
  import { graphqlWithRateLimit } from "./client.mjs";
2
5
  import { GitHubRequestError } from "./errors.mjs";
3
6
  import { rateLimitKind } from "./rate-limit-kind.mjs";
@@ -8,7 +11,7 @@ const IDS_PER_REQUEST = 20;
8
11
  const CONCURRENCY = 4;
9
12
  const MAX_COMMENT_PAGES = 100;
10
13
  /** Best-effort transcript evidence; it never filters user-supplied mutation IDs. */
11
- export async function fetchReplyThreadTranscripts(pr, repo, requestedIds) {
14
+ async function fetchGraphqlReplyThreadTranscripts(pr, repo, requestedIds) {
12
15
  const ids = [...new Set(requestedIds)];
13
16
  if (ids.length === 0)
14
17
  return new Map();
@@ -87,3 +90,23 @@ async function completeThread(thread, isStopped, stop) {
87
90
  function isThrottle(error) {
88
91
  return error instanceof GitHubRequestError && rateLimitKind(error) !== null;
89
92
  }
93
+ export function fetchReplyThreadTranscripts(pr, repo, requestedIds) {
94
+ if (requestedIds.length === 0)
95
+ return Promise.resolve(new Map());
96
+ return githubOperation("ReplyThreadTranscripts", () => fetchGraphqlReplyThreadTranscripts(pr, repo, requestedIds), async () => {
97
+ const feedback = await readRestFeedback(pr, repo);
98
+ const result = new Map();
99
+ for (const id of new Set(requestedIds)) {
100
+ try {
101
+ const root = await resolveRestThreadRoot(repo, pr, id);
102
+ const thread = feedback.threads.find((thread) => thread.id === restThreadId(root));
103
+ if (thread)
104
+ result.set(id, threadTranscriptBodies((thread.comments ?? []).map((comment) => comment.body)));
105
+ }
106
+ catch {
107
+ /* Transcript evidence never prohibits an explicit mutation. */
108
+ }
109
+ }
110
+ return result;
111
+ });
112
+ }
@@ -0,0 +1,5 @@
1
+ import type { CheckAnnotation } from "../types.mts";
2
+ import type { AnnotationCacheOptions } from "./check-annotation-cache.mts";
3
+ /** An annotation fallback can follow a GraphQL snapshot with no persisted REST check IDs. */
4
+ export declare function ensureRestCheckIdentities(checkRunIds: string[], scope?: AnnotationCacheOptions): Promise<void>;
5
+ export declare function readRestCheckAnnotations(checkRunId: string, scope?: AnnotationCacheOptions): Promise<CheckAnnotation[]>;
@@ -0,0 +1,44 @@
1
+ import { readRestPages, restRepoPath, restString, restNumber, restCollection, restObject, } from "./rest-reader-core.mjs";
2
+ import { recordRestIdentity, resolveRestIdentity } from "./rest-identities.mjs";
3
+ import { toCheckAnnotation } from "./check-annotation-shape.mjs";
4
+ import { readRestPull } from "./rest-pr-core.mjs";
5
+ /** An annotation fallback can follow a GraphQL snapshot with no persisted REST check IDs. */
6
+ export async function ensureRestCheckIdentities(checkRunIds, scope) {
7
+ if (!scope || checkRunIds.length === 0)
8
+ return;
9
+ const identities = await Promise.allSettled(checkRunIds.map((id) => resolveRestIdentity(id, "check")));
10
+ if (identities.every((identity) => identity.status === "fulfilled"))
11
+ return;
12
+ const repo = { owner: scope.stateKey.owner, name: scope.stateKey.repo };
13
+ const pr = scope.stateKey.pr;
14
+ const sha = scope.headSha ?? (await readRestPull(pr, repo)).head.sha;
15
+ const checks = await readRestPages(`${restRepoPath(repo)}/commits/${encodeURIComponent(sha)}/check-runs?filter=all`, (body) => restCollection(body, "check_runs"));
16
+ await Promise.all(checks.nodes.map((value) => {
17
+ const check = restObject(value, "check run identity");
18
+ return recordRestIdentity(repo, pr, restString(check.node_id, "check node_id"), restNumber(check.id, "check id"), "check");
19
+ }));
20
+ }
21
+ export async function readRestCheckAnnotations(checkRunId, scope) {
22
+ await ensureRestCheckIdentities([checkRunId], scope);
23
+ const identity = await resolveRestIdentity(checkRunId, "check");
24
+ const result = await readRestPages(`${restRepoPath(identity.repo)}/check-runs/${identity.numericId}/annotations`);
25
+ return result.nodes.map((raw) => toCheckAnnotation(checkRunId, {
26
+ fullDatabaseId: null,
27
+ path: restString(raw.path, "annotation path"),
28
+ annotationLevel: restString(raw.annotation_level, "annotation level").toUpperCase(),
29
+ title: typeof raw.title === "string" ? raw.title : null,
30
+ message: restString(raw.message, "annotation message"),
31
+ rawDetails: typeof raw.raw_details === "string" ? raw.raw_details : null,
32
+ blobUrl: typeof raw.blob_href === "string" ? raw.blob_href : null,
33
+ location: {
34
+ start: {
35
+ line: restNumber(raw.start_line, "annotation start_line"),
36
+ column: typeof raw.start_column === "number" ? raw.start_column : null,
37
+ },
38
+ end: {
39
+ line: restNumber(raw.end_line, "annotation end_line"),
40
+ column: typeof raw.end_column === "number" ? raw.end_column : null,
41
+ },
42
+ },
43
+ }));
44
+ }
@@ -0,0 +1,12 @@
1
+ import type { RepoInfo } from "./client.mts";
2
+ import type { BatchResult } from "./batch.mts";
3
+ import type { RawSummaryPr } from "./poll-summary-raw.mts";
4
+ import type { RestSnapshotContext } from "./rest-snapshot-context.mts";
5
+ /** REST uses multiple resources; retry a moving head/base once rather than combining revisions. */
6
+ export declare function fetchRestPrBatch(pr: number, repo: RepoInfo, opts?: {
7
+ includeReceiptSummary?: boolean;
8
+ terminalShortCircuit?: boolean;
9
+ snapshotContext?: RestSnapshotContext;
10
+ viewerLogin?: string | null;
11
+ }): Promise<BatchResult>;
12
+ export declare function fetchRestRawSummaryPr(pr: number, repo: RepoInfo, snapshotContext?: RestSnapshotContext, viewerLogin?: string | null): Promise<RawSummaryPr>;
@@ -0,0 +1,57 @@
1
+ import { readRestPull, restPullRevision } from "./rest-pr-core.mjs";
2
+ import { readRestSnapshot } from "./rest-batch-snapshot.mjs";
3
+ import { isRestPullMerged, restMergedBatchData } from "./rest-terminal-batch.mjs";
4
+ import { restSummary } from "./rest-summary-read.mjs";
5
+ import { markReadyAnnotationProbeComplete } from "./poll-summary-annotation-probe.mjs";
6
+ import { hydratePollSummaryChecks } from "./poll-summary-check-hydration.mjs";
7
+ import { GitHubRequestError } from "./errors.mjs";
8
+ import { EXIT } from "../exit-codes.mjs";
9
+ /** REST uses multiple resources; retry a moving head/base once rather than combining revisions. */
10
+ export async function fetchRestPrBatch(pr, repo, opts = {}) {
11
+ for (let attempt = 0; attempt < 2; attempt++) {
12
+ const pull = await readRestPull(pr, repo);
13
+ if (opts.terminalShortCircuit && isRestPullMerged(pull)) {
14
+ return { data: restMergedBatchData(pull), checkSuitesComplete: true };
15
+ }
16
+ const snapshot = await readRestSnapshot(pull, repo, opts.snapshotContext, opts.viewerLogin);
17
+ const latest = await readRestPull(pr, repo);
18
+ if (restPullRevision(pull) !== restPullRevision(latest))
19
+ continue;
20
+ opts.snapshotContext?.recordPullRevision(pr, restPullRevision(latest));
21
+ const receiptSummary = restSummary(snapshot.data, pull, snapshot.feedback, snapshot.checks, snapshot.rules.baseRef);
22
+ // Match the canonical check window hashed by aggregate stack reconciliation.
23
+ await hydratePollSummaryChecks(receiptSummary, repo);
24
+ markReadyAnnotationProbeComplete(receiptSummary);
25
+ return {
26
+ data: snapshot.data,
27
+ rateLimit: snapshot.checks.rateLimit,
28
+ checkSuitesComplete: true,
29
+ ...(snapshot.checks.suites.length === 0 && { headCheckSuitesEmpty: true }),
30
+ headWorkflowSuites: snapshot.checks.suites.flatMap((suite) => {
31
+ const run = snapshot.checks.workflowRuns.find((run) => run.check_suite_id === suite.id);
32
+ return run
33
+ ? [
34
+ {
35
+ status: suite.status.toUpperCase(),
36
+ conclusion: suite.conclusion?.toUpperCase() ?? null,
37
+ workflowRun: { event: run.event },
38
+ },
39
+ ]
40
+ : [];
41
+ }),
42
+ ...(opts.includeReceiptSummary && { receiptSummary }),
43
+ };
44
+ }
45
+ throw new GitHubRequestError("Pull request changed while REST snapshot was being read; retry", {
46
+ status: 409,
47
+ exitCodeOverride: EXIT.TEMPFAIL,
48
+ });
49
+ }
50
+ export async function fetchRestRawSummaryPr(pr, repo, snapshotContext, viewerLogin) {
51
+ const snapshot = await fetchRestPrBatch(pr, repo, {
52
+ includeReceiptSummary: true,
53
+ snapshotContext,
54
+ viewerLogin,
55
+ });
56
+ return snapshot.receiptSummary;
57
+ }
@@ -0,0 +1,30 @@
1
+ import type { RepoInfo } from "./client.mts";
2
+ import type { BatchPrData } from "../types.mts";
3
+ import { type RestPull } from "./rest-pr-core.mts";
4
+ import type { RestSnapshotContext } from "./rest-snapshot-context.mts";
5
+ export declare function readRestSnapshot(pull: RestPull, repo: RepoInfo, context?: RestSnapshotContext, knownViewerLogin?: string | null): Promise<{
6
+ data: BatchPrData;
7
+ feedback: {
8
+ threads: import("../types.mts").ReviewThread[];
9
+ comments: import("../types.mts").PrComment[];
10
+ reviews: import("./rest-feedback-read.mts").RestReview[];
11
+ unavailable: {
12
+ field: string;
13
+ reason: string;
14
+ }[];
15
+ viewerLogin: string | null;
16
+ };
17
+ checks: {
18
+ nodes: import("./batch-raw-types.mts").RawContextNode[];
19
+ suites: import("./rest-check-read.mts").RestSuite[];
20
+ workflowRuns: import("./rest-check-read.mts").RestWorkflowRun[];
21
+ rateLimit: import("./http-utils.mts").RateLimitInfo | undefined;
22
+ };
23
+ rules: {
24
+ baseRef?: import("./batch-raw-rules.mts").RawBaseRef;
25
+ unavailable: Array<{
26
+ field: string;
27
+ reason: string;
28
+ }>;
29
+ };
30
+ }>;
@@ -0,0 +1,115 @@
1
+ import { restPullRefs } from "./rest-pr-core.mjs";
2
+ import { readRestFeedback, restReviewToReview } from "./rest-feedback-read.mjs";
3
+ import { readRestCommitChecks } from "./rest-check-read.mjs";
4
+ import { readRestBranchRules } from "./rest-rules-read.mjs";
5
+ import { readRestStackMembership } from "./rest-stack-read.mjs";
6
+ import { mergeStartupFailureChecks } from "../checks/startup-failures.mjs";
7
+ import { parseCheckNodes } from "./batch-parse-checks.mjs";
8
+ import { parseBranchRules } from "./batch-parsers-rules.mjs";
9
+ import { isReviewStale } from "./batch-parser-helpers.mjs";
10
+ import { readRest as rest, restRepoPath, restObject, restString } from "./rest-reader-core.mjs";
11
+ import { restLatestReviews, restPendingReviews } from "./rest-review-read.mjs";
12
+ import { REST_BATCH_UNAVAILABLE } from "./rest-batch-unavailable.mjs";
13
+ export async function readRestSnapshot(pull, repo, context, knownViewerLogin) {
14
+ const [feedback, checks, rules, stack] = await Promise.all([
15
+ readRestFeedback(pull.number, repo, context ? context.viewerLogin : knownViewerLogin),
16
+ readRestCommitChecks(pull.head.sha, repo, pull.number),
17
+ context ? context.readBranchRules(pull.base.ref) : readRestBranchRules(repo, pull.base.ref),
18
+ context ? Promise.resolve(context.stack) : readRestStackMembership(pull.number, repo),
19
+ ]);
20
+ const repository = restObject(context?.repository ?? (await rest("GET", restRepoPath(repo))), "repository merge settings");
21
+ const allowedMergeMethods = [
22
+ ...(repository.allow_merge_commit === true ? ["merge"] : []),
23
+ ...(repository.allow_squash_merge === true ? ["squash"] : []),
24
+ ...(repository.allow_rebase_merge === true ? ["rebase"] : []),
25
+ ];
26
+ const latestReviews = restLatestReviews(feedback.reviews);
27
+ const requested = [
28
+ ...(pull.requested_reviewers ?? []).map((reviewer) => ({ login: reviewer.login })),
29
+ ...(pull.requested_teams ?? []).map((team) => ({ login: team.name })),
30
+ ];
31
+ const changes = feedback.reviews.filter((review) => review.state === "CHANGES_REQUESTED" &&
32
+ !["APPROVED", "DISMISSED"].includes(latestReviews.get(review.user?.login.toLowerCase() ?? "")?.state ?? ""));
33
+ const transportUnavailable = [
34
+ ...feedback.unavailable,
35
+ ...rules.unavailable,
36
+ ...REST_BATCH_UNAVAILABLE,
37
+ ];
38
+ const data = {
39
+ nodeId: pull.node_id,
40
+ ...(feedback.viewerLogin && { viewerLogin: feedback.viewerLogin }),
41
+ ...restPullRefs(pull),
42
+ state: restPullRefs(pull).state,
43
+ isDraft: pull.draft,
44
+ mergeable: pull.mergeable === true ? "MERGEABLE" : pull.mergeable === false ? "CONFLICTING" : "UNKNOWN",
45
+ mergeStateStatus: pull.mergeable_state.toUpperCase(),
46
+ reviewDecision: null,
47
+ ...(pull.auto_merge !== undefined && {
48
+ autoMergeRequest: pull.auto_merge
49
+ ? {
50
+ mergeMethod: restString(pull.auto_merge.merge_method, "auto-merge merge_method").toUpperCase(),
51
+ ...(pull.auto_merge.enabled_by?.login && {
52
+ enabledBy: restString(pull.auto_merge.enabled_by.login, "auto-merge enabled_by login"),
53
+ }),
54
+ }
55
+ : null,
56
+ }),
57
+ headRepoWithOwner: pull.head.repo?.full_name ?? null,
58
+ reviewRequests: requested,
59
+ latestReviews: [...restPendingReviews(feedback.reviews), ...latestReviews.values()],
60
+ reviewThreads: feedback.threads,
61
+ comments: feedback.comments,
62
+ changesRequestedReviews: changes.map((review) => {
63
+ const mapped = restReviewToReview(review);
64
+ if (isReviewStale(mapped, pull.head.sha, feedback.threads))
65
+ mapped.staleReview = true;
66
+ return mapped;
67
+ }),
68
+ reviewSummaries: feedback.reviews
69
+ .filter((review) => review.state === "COMMENTED" && review.body?.trim())
70
+ .map(restReviewToReview),
71
+ approvedReviews: feedback.reviews
72
+ .filter((review) => review.state === "APPROVED")
73
+ .map(restReviewToReview),
74
+ checks: mergeStartupFailureChecks(parseCheckNodes(checks.nodes), checks.suites.flatMap((suite) => {
75
+ const run = checks.workflowRuns.find((run) => run.check_suite_id === suite.id);
76
+ if (suite.conclusion?.toUpperCase() !== "STARTUP_FAILURE" || !run)
77
+ return [];
78
+ return [
79
+ {
80
+ name: run.name || `workflow run ${run.id}`,
81
+ status: "COMPLETED",
82
+ conclusion: "STARTUP_FAILURE",
83
+ source: "startup_failure",
84
+ detailsUrl: run.html_url,
85
+ event: run.event,
86
+ runId: String(run.id),
87
+ },
88
+ ];
89
+ })),
90
+ branchProtection: rules.baseRef?.branchProtectionRule
91
+ ? {
92
+ requiresApprovingReviews: rules.baseRef.branchProtectionRule.requiresApprovingReviews,
93
+ requiredApprovingReviewCount: rules.baseRef.branchProtectionRule.requiredApprovingReviewCount,
94
+ requiresConversationResolution: rules.baseRef.branchProtectionRule.requiresConversationResolution,
95
+ requiresStatusChecks: rules.baseRef.branchProtectionRule.requiresStatusChecks,
96
+ requiredStatusCheckContexts: rules.baseRef.branchProtectionRule.requiredStatusCheckContexts ?? [],
97
+ }
98
+ : null,
99
+ ...(rules.baseRef && { branchRules: parseBranchRules(rules.baseRef) }),
100
+ ...(typeof repository.allow_merge_commit === "boolean" &&
101
+ typeof repository.allow_squash_merge === "boolean" &&
102
+ typeof repository.allow_rebase_merge === "boolean" && { allowedMergeMethods }),
103
+ stack: stack
104
+ ? {
105
+ number: stack.number,
106
+ size: stack.pull_requests.length,
107
+ position: stack.pull_requests.findIndex((member) => member.number === pull.number) + 1,
108
+ baseRefName: stack.base.ref,
109
+ }
110
+ : null,
111
+ transport: "rest",
112
+ transportUnavailable,
113
+ };
114
+ return { data, feedback, checks, rules };
115
+ }
@@ -0,0 +1,5 @@
1
+ /** Batch fields no REST endpoint supplies; they stay unknown rather than defaulting to false. */
2
+ export declare const REST_BATCH_UNAVAILABLE: ReadonlyArray<{
3
+ field: string;
4
+ reason: string;
5
+ }>;
@@ -0,0 +1,16 @@
1
+ /** Batch fields no REST endpoint supplies; they stay unknown rather than defaulting to false. */
2
+ export const REST_BATCH_UNAVAILABLE = [
3
+ {
4
+ field: "reviewDecision",
5
+ reason: "REST does not expose an aggregate review decision; latest review states are supplied",
6
+ },
7
+ { field: "viewerAuthorization", reason: "REST does not expose viewer capability fields" },
8
+ {
9
+ field: "comments.isMinimized",
10
+ reason: "REST does not expose minimization state or support minimizing comments",
11
+ },
12
+ {
13
+ field: "mergeQueue",
14
+ reason: "REST does not expose queue membership, entry or removal history",
15
+ },
16
+ ];
@@ -0,0 +1,34 @@
1
+ import type { RepoInfo } from "./client.mts";
2
+ import type { RawContextNode } from "./batch-raw-types.mts";
3
+ export interface RestSuite {
4
+ id: number;
5
+ node_id: string;
6
+ status: string;
7
+ conclusion: string | null;
8
+ created_at: string;
9
+ updated_at: string;
10
+ }
11
+ export interface RestWorkflowRun {
12
+ id: number;
13
+ check_suite_id: number;
14
+ event: string;
15
+ workflow_id: number;
16
+ name: string;
17
+ created_at: string;
18
+ updated_at: string;
19
+ html_url: string;
20
+ }
21
+ export declare function readRestCommitChecks(oid: string, repo: RepoInfo, pr?: number): Promise<{
22
+ nodes: RawContextNode[];
23
+ suites: RestSuite[];
24
+ workflowRuns: RestWorkflowRun[];
25
+ rateLimit: import("./http-utils.mts").RateLimitInfo | undefined;
26
+ }>;
27
+ export declare function readRestAnnotationCounts(oid: string, repo: RepoInfo): Promise<{
28
+ __typename: "CheckRun";
29
+ id: string;
30
+ annotations: {
31
+ totalCount: number;
32
+ };
33
+ }[]>;
34
+ export declare function readRestBehind(repo: RepoInfo, base: string, head: string): Promise<number>;