pr-shepherd 0.56.6 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (420) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +44 -27
  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/coderabbit-review-summary.d.mts +8 -0
  20. package/bin/classify/standard/coderabbit-review-summary.mjs +37 -0
  21. package/bin/classify/standard/codex-notices.d.mts +7 -0
  22. package/bin/classify/standard/codex-notices.mjs +36 -0
  23. package/bin/classify/standard/codex-review-summary.d.mts +7 -0
  24. package/bin/classify/standard/codex-review-summary.mjs +20 -0
  25. package/bin/classify/standard/dependabot-notices.d.mts +4 -0
  26. package/bin/classify/standard/dependabot-notices.mjs +15 -0
  27. package/bin/classify/standard/gemini-notices.d.mts +4 -0
  28. package/bin/classify/standard/gemini-notices.mjs +13 -0
  29. package/bin/classify/standard/index.d.mts +4 -0
  30. package/bin/classify/standard/index.mjs +22 -0
  31. package/bin/classify/standard/kilo-no-issues.d.mts +4 -0
  32. package/bin/classify/standard/kilo-no-issues.mjs +17 -0
  33. package/bin/classify/standard/sourcery-notices.d.mts +8 -0
  34. package/bin/classify/standard/sourcery-notices.mjs +20 -0
  35. package/bin/cli/api-usage-formatter.mjs +6 -1
  36. package/bin/cli/apply-merge-handler.d.mts +3 -0
  37. package/bin/cli/apply-merge-handler.mjs +73 -0
  38. package/bin/cli/arg-flags.d.mts +2 -0
  39. package/bin/cli/arg-flags.mjs +47 -0
  40. package/bin/cli/args.mjs +10 -41
  41. package/bin/cli/clean-handler.d.mts +1 -0
  42. package/bin/cli/clean-handler.mjs +71 -0
  43. package/bin/cli/default-poll.mjs +3 -0
  44. package/bin/cli/event-state-scope.d.mts +19 -0
  45. package/bin/cli/event-state-scope.mjs +60 -0
  46. package/bin/cli/fix-formatter.mjs +5 -11
  47. package/bin/cli/handlers.d.mts +0 -1
  48. package/bin/cli/handlers.mjs +8 -64
  49. package/bin/cli/help-command-pages.d.mts +62 -18
  50. package/bin/cli/help-command-pages.mjs +59 -15
  51. package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
  52. package/bin/cli/help-iterate-poll-pages.mjs +6 -0
  53. package/bin/cli/help-log-file-page.d.mts +1 -1
  54. package/bin/cli/help-log-file-page.mjs +4 -1
  55. package/bin/cli/help-top-page.d.mts +1 -1
  56. package/bin/cli/help-top-page.mjs +5 -0
  57. package/bin/cli/help.d.mts +63 -19
  58. package/bin/cli/help.mjs +2 -0
  59. package/bin/cli/iterate-branch-segment.d.mts +2 -0
  60. package/bin/cli/iterate-branch-segment.mjs +12 -7
  61. package/bin/cli/iterate-flags.d.mts +7 -1
  62. package/bin/cli/iterate-flags.mjs +38 -0
  63. package/bin/cli/iterate-formatter.d.mts +6 -6
  64. package/bin/cli/iterate-formatter.mjs +56 -22
  65. package/bin/cli/iterate-instructions.mjs +45 -15
  66. package/bin/cli/iterate-lean.mjs +39 -14
  67. package/bin/cli/iterate-merge-formatter.d.mts +6 -0
  68. package/bin/cli/iterate-merge-formatter.mjs +24 -14
  69. package/bin/cli/iterate-verbose.mjs +3 -6
  70. package/bin/cli/list-formatters.mjs +3 -1
  71. package/bin/cli/mutate-formatter.mjs +10 -5
  72. package/bin/cli/next-check-format.d.mts +7 -0
  73. package/bin/cli/next-check-format.mjs +10 -0
  74. package/bin/cli/playbook-handler.d.mts +5 -0
  75. package/bin/cli/playbook-handler.mjs +40 -0
  76. package/bin/cli/poll-handler.mjs +7 -6
  77. package/bin/cli/poll-summary-formatter.mjs +11 -2
  78. package/bin/cli/poll-targets.mjs +2 -0
  79. package/bin/cli/resolve-validators.mjs +2 -2
  80. package/bin/cli/runner.mjs +6 -1
  81. package/bin/cli/stack-layer-view.d.mts +33 -0
  82. package/bin/cli/stack-layer-view.mjs +1 -0
  83. package/bin/cli/stack-overview.d.mts +10 -28
  84. package/bin/cli/stack-overview.mjs +39 -14
  85. package/bin/cli/transport-args.d.mts +5 -0
  86. package/bin/cli/transport-args.mjs +23 -0
  87. package/bin/cli/transport-formatter.d.mts +9 -0
  88. package/bin/cli/transport-formatter.mjs +13 -0
  89. package/bin/cli-parser.mjs +62 -7
  90. package/bin/commands/apply-merge-options.d.mts +4 -0
  91. package/bin/commands/apply-merge-options.mjs +34 -0
  92. package/bin/commands/apply-merge-output.d.mts +7 -0
  93. package/bin/commands/apply-merge-output.mjs +20 -0
  94. package/bin/commands/apply-merge-pull.d.mts +20 -0
  95. package/bin/commands/apply-merge-pull.mjs +15 -0
  96. package/bin/commands/apply-merge.d.mts +18 -0
  97. package/bin/commands/apply-merge.mjs +126 -0
  98. package/bin/commands/apply-queue-removal.mjs +7 -0
  99. package/bin/commands/check-annotations.mjs +28 -18
  100. package/bin/commands/check-execution-context.d.mts +5 -0
  101. package/bin/commands/check-execution-context.mjs +16 -1
  102. package/bin/commands/check-fingerprint.d.mts +26 -2
  103. package/bin/commands/check-fingerprint.mjs +64 -28
  104. package/bin/commands/check-terminal-report.mjs +11 -1
  105. package/bin/commands/check-unreported.d.mts +6 -2
  106. package/bin/commands/check-unreported.mjs +32 -12
  107. package/bin/commands/check-wait-detectors.d.mts +35 -0
  108. package/bin/commands/check-wait-detectors.mjs +107 -0
  109. package/bin/commands/check.d.mts +4 -2
  110. package/bin/commands/check.mjs +130 -40
  111. package/bin/commands/event-instructions.d.mts +11 -0
  112. package/bin/commands/event-instructions.mjs +27 -0
  113. package/bin/commands/event-mode.d.mts +14 -0
  114. package/bin/commands/event-mode.mjs +138 -0
  115. package/bin/commands/iterate/api-usage.mjs +4 -2
  116. package/bin/commands/iterate/base.mjs +4 -0
  117. package/bin/commands/iterate/check-blocker-gate.mjs +14 -2
  118. package/bin/commands/iterate/check-instructions.d.mts +9 -10
  119. package/bin/commands/iterate/check-instructions.mjs +23 -22
  120. package/bin/commands/iterate/classify.mjs +19 -5
  121. package/bin/commands/iterate/escalate.mjs +13 -3
  122. package/bin/commands/iterate/fix-code.mjs +26 -9
  123. package/bin/commands/iterate/fix-instruction-threads.d.mts +0 -8
  124. package/bin/commands/iterate/fix-instruction-threads.mjs +0 -16
  125. package/bin/commands/iterate/fix-loop-instruction.d.mts +9 -0
  126. package/bin/commands/iterate/fix-loop-instruction.mjs +35 -0
  127. package/bin/commands/iterate/helpers.mjs +15 -2
  128. package/bin/commands/iterate/index.mjs +26 -4
  129. package/bin/commands/iterate/mark-ready.mjs +50 -10
  130. package/bin/commands/iterate/merge-plan.d.mts +19 -0
  131. package/bin/commands/iterate/merge-plan.mjs +88 -0
  132. package/bin/commands/iterate/merge-state.mjs +3 -0
  133. package/bin/commands/iterate/merge.d.mts +4 -15
  134. package/bin/commands/iterate/merge.mjs +18 -51
  135. package/bin/commands/iterate/merged-base-pull-requests.d.mts +2 -6
  136. package/bin/commands/iterate/merged-base-pull-requests.mjs +15 -11
  137. package/bin/commands/iterate/native-stack-rebase.mjs +11 -0
  138. package/bin/commands/iterate/render.d.mts +8 -2
  139. package/bin/commands/iterate/render.mjs +28 -42
  140. package/bin/commands/iterate/stack-trunk-conflict.mjs +17 -1
  141. package/bin/commands/iterate/stale-ancestry.mjs +4 -1
  142. package/bin/commands/iterate/stall.d.mts +5 -1
  143. package/bin/commands/iterate/stall.mjs +19 -7
  144. package/bin/commands/iterate/thread-mutation-routing.d.mts +1 -0
  145. package/bin/commands/iterate/thread-mutation-routing.mjs +4 -2
  146. package/bin/commands/iterate/unreported-required.mjs +5 -2
  147. package/bin/commands/mark-files-as-viewed.mjs +7 -0
  148. package/bin/commands/next-check.d.mts +31 -0
  149. package/bin/commands/next-check.mjs +46 -0
  150. package/bin/commands/playbook.d.mts +13 -0
  151. package/bin/commands/playbook.mjs +48 -0
  152. package/bin/commands/poll-mode.d.mts +8 -0
  153. package/bin/commands/poll-mode.mjs +14 -0
  154. package/bin/commands/poll-progress.d.mts +1 -0
  155. package/bin/commands/poll-progress.mjs +6 -3
  156. package/bin/commands/poll-quota.d.mts +3 -2
  157. package/bin/commands/poll-quota.mjs +7 -3
  158. package/bin/commands/poll-summary-explicit-instructions.d.mts +2 -0
  159. package/bin/commands/poll-summary-explicit-instructions.mjs +10 -1
  160. package/bin/commands/poll-summary-instructions.mjs +16 -17
  161. package/bin/commands/poll-summary.mjs +42 -17
  162. package/bin/commands/poll.d.mts +0 -1
  163. package/bin/commands/poll.mjs +11 -19
  164. package/bin/commands/quota-selection.d.mts +2 -1
  165. package/bin/commands/quota-selection.mjs +12 -7
  166. package/bin/commands/resolve-mutate.mjs +33 -5
  167. package/bin/commands/rest-stack-merge-readiness.d.mts +4 -0
  168. package/bin/commands/rest-stack-merge-readiness.mjs +74 -0
  169. package/bin/commands/rule-auto-resolve.mjs +9 -3
  170. package/bin/commands/shepherd-journal.d.mts +5 -4
  171. package/bin/commands/shepherd-journal.mjs +9 -8
  172. package/bin/commands/stack-drain.d.mts +1 -9
  173. package/bin/commands/stack-drain.mjs +50 -37
  174. package/bin/commands/stack-handoffs.d.mts +10 -0
  175. package/bin/commands/stack-handoffs.mjs +25 -0
  176. package/bin/commands/stack-stall.d.mts +5 -0
  177. package/bin/commands/stack-stall.mjs +11 -0
  178. package/bin/commands/stack-work.d.mts +5 -0
  179. package/bin/commands/stack-work.mjs +32 -0
  180. package/bin/comments/existing-reply-scan.d.mts +17 -0
  181. package/bin/comments/existing-reply-scan.mjs +41 -0
  182. package/bin/comments/rate-limit.mjs +2 -2
  183. package/bin/comments/resolve.d.mts +7 -1
  184. package/bin/comments/resolve.mjs +108 -18
  185. package/bin/comments/rest-reply.d.mts +9 -0
  186. package/bin/comments/rest-reply.mjs +95 -0
  187. package/bin/comments/rest-review-mutations.d.mts +22 -0
  188. package/bin/comments/rest-review-mutations.mjs +125 -0
  189. package/bin/comments/review-visibility.d.mts +1 -1
  190. package/bin/comments/review-visibility.mjs +3 -2
  191. package/bin/comments/sha-poll.mjs +7 -3
  192. package/bin/comments/thread-visibility.mjs +10 -5
  193. package/bin/comments/uncertain-replies.d.mts +11 -0
  194. package/bin/comments/uncertain-replies.mjs +121 -0
  195. package/bin/comments/uncertain-reply-guards.d.mts +10 -0
  196. package/bin/comments/uncertain-reply-guards.mjs +94 -0
  197. package/bin/comments/visible-comments.d.mts +1 -1
  198. package/bin/comments/visible-comments.mjs +4 -2
  199. package/bin/config/load.d.mts +37 -1
  200. package/bin/config/load.mjs +73 -1
  201. package/bin/config.json +6 -2
  202. package/bin/exit-codes.d.mts +3 -0
  203. package/bin/exit-codes.mjs +8 -0
  204. package/bin/github/api-telemetry-aggregate.d.mts +15 -4
  205. package/bin/github/api-telemetry-aggregate.mjs +57 -18
  206. package/bin/github/api-telemetry.d.mts +4 -0
  207. package/bin/github/api-telemetry.mjs +22 -8
  208. package/bin/github/apply-review-preflight.d.mts +20 -0
  209. package/bin/github/apply-review-preflight.mjs +61 -0
  210. package/bin/github/base-behind-cache.d.mts +15 -0
  211. package/bin/github/base-behind-cache.mjs +18 -0
  212. package/bin/github/batch-parse-suites.d.mts +4 -2
  213. package/bin/github/batch-parse-suites.mjs +6 -1
  214. package/bin/github/batch-parser-helpers.mjs +40 -2
  215. package/bin/github/batch-parsers.mjs +1 -0
  216. package/bin/github/batch-raw-rules.d.mts +26 -0
  217. package/bin/github/batch-raw-types.d.mts +8 -6
  218. package/bin/github/batch-stack-evidence.d.mts +28 -0
  219. package/bin/github/batch-stack-evidence.mjs +62 -0
  220. package/bin/github/batch.d.mts +15 -2
  221. package/bin/github/batch.mjs +34 -17
  222. package/bin/github/check-annotations-batch.d.mts +0 -5
  223. package/bin/github/check-annotations-batch.mjs +25 -4
  224. package/bin/github/check-annotations.mjs +3 -1
  225. package/bin/github/client.d.mts +8 -19
  226. package/bin/github/client.mjs +45 -13
  227. package/bin/github/fingerprint-fields.d.mts +8 -0
  228. package/bin/github/fingerprint-fields.mjs +6 -1
  229. package/bin/github/fingerprint.d.mts +4 -2
  230. package/bin/github/fingerprint.mjs +6 -38
  231. package/bin/github/github-fetch.d.mts +2 -0
  232. package/bin/github/github-fetch.mjs +19 -0
  233. package/bin/github/gql/base-behind.gql +3 -0
  234. package/bin/github/gql/batch-pr-page.gql +16 -0
  235. package/bin/github/gql/batch-pr.gql +57 -0
  236. package/bin/github/gql/commit-check-contexts.gql +17 -0
  237. package/bin/github/gql/get-pr-body.gql +1 -0
  238. package/bin/github/gql/poll-stack-summary.gql +1 -0
  239. package/bin/github/gql/poll-summary-check-contexts.gql +5 -0
  240. package/bin/github/gql/poll-summary-fragment.gql +65 -15
  241. package/bin/github/gql/stack-handoff-check-runs.gql +42 -0
  242. package/bin/github/graphql-http.mjs +9 -4
  243. package/bin/github/graphql-internal-retry.d.mts +2 -0
  244. package/bin/github/graphql-internal-retry.mjs +1 -1
  245. package/bin/github/graphql-quota-probe.d.mts +6 -0
  246. package/bin/github/graphql-quota-probe.mjs +56 -0
  247. package/bin/github/graphql-session-refusal.d.mts +8 -0
  248. package/bin/github/graphql-session-refusal.mjs +14 -0
  249. package/bin/github/http-request.d.mts +1 -1
  250. package/bin/github/http-request.mjs +22 -6
  251. package/bin/github/http-utils.mjs +6 -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.mjs +4 -1
  272. package/bin/github/poll-summary-rest-queue.d.mts +3 -0
  273. package/bin/github/poll-summary-rest-queue.mjs +12 -0
  274. package/bin/github/poll-summary-review.d.mts +1 -1
  275. package/bin/github/poll-summary-review.mjs +23 -11
  276. package/bin/github/poll-summary-route.mjs +19 -3
  277. package/bin/github/poll-summary-stack-page.d.mts +11 -0
  278. package/bin/github/poll-summary-stack-page.mjs +27 -0
  279. package/bin/github/poll-summary-unreported.d.mts +3 -1
  280. package/bin/github/poll-summary-unreported.mjs +6 -3
  281. package/bin/github/poll-summary.d.mts +4 -1
  282. package/bin/github/poll-summary.mjs +47 -33
  283. package/bin/github/queries.d.mts +7 -3
  284. package/bin/github/queries.mjs +8 -4
  285. package/bin/github/rate-limit-sample.d.mts +7 -0
  286. package/bin/github/rate-limit-sample.mjs +12 -0
  287. package/bin/github/reply-recovery-read.d.mts +50 -0
  288. package/bin/github/reply-recovery-read.mjs +118 -0
  289. package/bin/github/reply-thread-transcripts.d.mts +0 -1
  290. package/bin/github/reply-thread-transcripts.mjs +24 -1
  291. package/bin/github/rest-annotation-read.d.mts +5 -0
  292. package/bin/github/rest-annotation-read.mjs +44 -0
  293. package/bin/github/rest-batch-read.d.mts +12 -0
  294. package/bin/github/rest-batch-read.mjs +57 -0
  295. package/bin/github/rest-batch-snapshot.d.mts +30 -0
  296. package/bin/github/rest-batch-snapshot.mjs +115 -0
  297. package/bin/github/rest-batch-unavailable.d.mts +5 -0
  298. package/bin/github/rest-batch-unavailable.mjs +16 -0
  299. package/bin/github/rest-check-read.d.mts +34 -0
  300. package/bin/github/rest-check-read.mjs +124 -0
  301. package/bin/github/rest-comment-authorship.d.mts +7 -0
  302. package/bin/github/rest-comment-authorship.mjs +11 -0
  303. package/bin/github/rest-conditional-scope.d.mts +20 -0
  304. package/bin/github/rest-conditional-scope.mjs +44 -0
  305. package/bin/github/rest-explicit-summary-read.d.mts +3 -0
  306. package/bin/github/rest-explicit-summary-read.mjs +8 -0
  307. package/bin/github/rest-feedback-read.d.mts +36 -0
  308. package/bin/github/rest-feedback-read.mjs +147 -0
  309. package/bin/github/rest-feedback-validation.d.mts +5 -0
  310. package/bin/github/rest-feedback-validation.mjs +28 -0
  311. package/bin/github/rest-http.d.mts +12 -0
  312. package/bin/github/rest-http.mjs +108 -23
  313. package/bin/github/rest-identities.d.mts +22 -0
  314. package/bin/github/rest-identities.mjs +134 -0
  315. package/bin/github/rest-merge-stack-guard.d.mts +14 -0
  316. package/bin/github/rest-merge-stack-guard.mjs +41 -0
  317. package/bin/github/rest-merge.d.mts +29 -0
  318. package/bin/github/rest-merge.mjs +56 -0
  319. package/bin/github/rest-merged-base-read.d.mts +9 -0
  320. package/bin/github/rest-merged-base-read.mjs +48 -0
  321. package/bin/github/rest-pr-core.d.mts +52 -0
  322. package/bin/github/rest-pr-core.mjs +60 -0
  323. package/bin/github/rest-reader-core.d.mts +16 -0
  324. package/bin/github/rest-reader-core.mjs +154 -0
  325. package/bin/github/rest-review-read.d.mts +11 -0
  326. package/bin/github/rest-review-read.mjs +47 -0
  327. package/bin/github/rest-rules-read.d.mts +9 -0
  328. package/bin/github/rest-rules-read.mjs +154 -0
  329. package/bin/github/rest-session-refusal.d.mts +5 -0
  330. package/bin/github/rest-session-refusal.mjs +21 -0
  331. package/bin/github/rest-snapshot-context.d.mts +10 -0
  332. package/bin/github/rest-snapshot-context.mjs +1 -0
  333. package/bin/github/rest-stack-read.d.mts +21 -0
  334. package/bin/github/rest-stack-read.mjs +47 -0
  335. package/bin/github/rest-stack-summary.d.mts +8 -0
  336. package/bin/github/rest-stack-summary.mjs +62 -0
  337. package/bin/github/rest-summary-read.d.mts +7 -0
  338. package/bin/github/rest-summary-read.mjs +112 -0
  339. package/bin/github/rest-terminal-batch.d.mts +14 -0
  340. package/bin/github/rest-terminal-batch.mjs +45 -0
  341. package/bin/github/rest-text.mjs +7 -3
  342. package/bin/github/rest-thread-read.d.mts +4 -0
  343. package/bin/github/rest-thread-read.mjs +35 -0
  344. package/bin/github/rest-viewer-read.d.mts +2 -0
  345. package/bin/github/rest-viewer-read.mjs +41 -0
  346. package/bin/github/stack-bottom.d.mts +3 -0
  347. package/bin/github/stack-bottom.mjs +14 -0
  348. package/bin/github/stack-handoff-context.d.mts +25 -0
  349. package/bin/github/stack-handoff-context.mjs +12 -0
  350. package/bin/github/stack-handoff-page.d.mts +17 -0
  351. package/bin/github/stack-handoff-page.mjs +306 -0
  352. package/bin/github/stack-handoff.d.mts +16 -0
  353. package/bin/github/stack-handoff.mjs +115 -0
  354. package/bin/github/stack-order.d.mts +6 -0
  355. package/bin/github/stack-order.mjs +13 -0
  356. package/bin/github/stack-read.d.mts +7 -5
  357. package/bin/github/stack-read.mjs +22 -24
  358. package/bin/github/stack-size-hint.d.mts +3 -0
  359. package/bin/github/stack-size-hint.mjs +14 -0
  360. package/bin/github/suggestion-thread.mjs +27 -1
  361. package/bin/github/thread-comments.mjs +9 -1
  362. package/bin/github/transport-evidence.d.mts +20 -0
  363. package/bin/github/transport-evidence.mjs +26 -0
  364. package/bin/github/transport-mode.d.mts +2 -0
  365. package/bin/github/transport-mode.mjs +5 -0
  366. package/bin/github/transport.d.mts +19 -0
  367. package/bin/github/transport.mjs +126 -0
  368. package/bin/github/unsupported-rest.d.mts +4 -0
  369. package/bin/github/unsupported-rest.mjs +7 -0
  370. package/bin/mcp/server.mjs +52 -3
  371. package/bin/merge-status/derive.d.mts +2 -0
  372. package/bin/merge-status/derive.mjs +17 -13
  373. package/bin/merge-status/required-check-requirements.d.mts +7 -0
  374. package/bin/merge-status/required-check-requirements.mjs +15 -0
  375. package/bin/merge-status/requirements-format.d.mts +5 -0
  376. package/bin/merge-status/requirements-format.mjs +41 -12
  377. package/bin/merge-status/requirements.mjs +18 -7
  378. package/bin/state/base.mjs +41 -0
  379. package/bin/state/durable-state.d.mts +6 -0
  380. package/bin/state/durable-state.mjs +41 -0
  381. package/bin/state/graphql-quota-policy.mjs +23 -16
  382. package/bin/state/merge-request.d.mts +25 -0
  383. package/bin/state/merge-request.mjs +145 -0
  384. package/bin/state/pr-fingerprint.d.mts +15 -0
  385. package/bin/state/pr-fingerprint.mjs +22 -7
  386. package/bin/state/rest-cache.d.mts +3 -0
  387. package/bin/state/rest-cache.mjs +1 -0
  388. package/bin/state/rest-snapshot-report.d.mts +21 -0
  389. package/bin/state/rest-snapshot-report.mjs +52 -0
  390. package/bin/state/seen-comments.d.mts +3 -0
  391. package/bin/state/seen-comments.mjs +18 -0
  392. package/bin/types/api-usage.d.mts +9 -1
  393. package/bin/types/escalate.d.mts +1 -1
  394. package/bin/types/github.d.mts +23 -9
  395. package/bin/types/iterate.d.mts +24 -2
  396. package/bin/types/merge-action.d.mts +1 -1
  397. package/bin/types/merge-requirements.d.mts +7 -7
  398. package/bin/types/next-check.d.mts +12 -0
  399. package/bin/types/next-check.mjs +1 -0
  400. package/bin/types/poll-summary.d.mts +21 -0
  401. package/bin/types/report.d.mts +13 -1
  402. package/bin/types/review-thread.d.mts +1 -1
  403. package/bin/types.d.mts +1 -0
  404. package/bin/types.mjs +1 -0
  405. package/package.json +3 -2
  406. package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
  407. package/plugins/pr-shepherd/.codex.mcp.json +1 -1
  408. package/plugins/pr-shepherd/.mcp.json +1 -1
  409. package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +1 -1
  410. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +14 -51
  411. package/plugins/pr-shepherd/skills/pr-shepherd/references/ci-failure-triage.md +12 -16
  412. package/plugins/pr-shepherd/skills/pr-shepherd/references/cloud-event-loop.md +14 -0
  413. package/plugins/pr-shepherd/skills/pr-shepherd/references/create-pr.md +10 -0
  414. package/plugins/pr-shepherd/skills/pr-shepherd/references/fix-code-loop.md +10 -0
  415. package/plugins/pr-shepherd/skills/pr-shepherd/references/mcp-fallback.md +9 -0
  416. package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +2 -0
  417. package/bin/github/gql/pr-fingerprint.gql +0 -75
  418. package/plugins/pr-shepherd/skills/pr-shepherd/references/journal.md +0 -7
  419. package/plugins/pr-shepherd/skills/pr-shepherd/references/review-mutations.md +0 -9
  420. package/plugins/pr-shepherd/skills/pr-shepherd/references/stack-merge.md +0 -7
@@ -1,3 +1,6 @@
1
+ import { recordThreadIdentity } from "./rest-identities.mjs";
2
+ import { githubOperation, runWithGithubTransport } from "./transport.mjs";
3
+ import { fetchRestPrBatch } from "./rest-batch-read.mjs";
1
4
  import { graphqlWithRateLimit } from "./client.mjs";
2
5
  import { hydrateThreadCommentPages } from "./thread-comments.mjs";
3
6
  import { BATCH_PR_QUERY, BATCH_PR_RECEIPT_QUERY } from "./queries.mjs";
@@ -5,30 +8,24 @@ import { prepareBatchReceiptEvidence } from "./batch-receipt-evidence.mjs";
5
8
  import { GitHubRequestError, isRetryableGraphQlResourceLimit, } from "./errors.mjs";
6
9
  import { rateLimitKind } from "./rate-limit-kind.mjs";
7
10
  import { parseRawPr } from "./batch-parsers.mjs";
8
- import { parseCheckSuitesComplete, parseHeadCheckSuitesEmpty, parseHeadWorkflowSuites, parseSuiteStartupFailures, } from "./batch-parse-suites.mjs";
11
+ import { parseCheckSuitesComplete, parseHeadCheckSuitesEmpty, workflowSuites, parseSuiteStartupFailures, } from "./batch-parse-suites.mjs";
9
12
  import { mergeStartupFailureChecks } from "../checks/startup-failures.mjs";
10
13
  import { paginateBatchConnections } from "./batch-page.mjs";
11
14
  import { requireRawPr } from "./batch-response.mjs";
12
15
  import { hydrateMergeQueueChecks } from "./merge-queue-checks.mjs";
13
16
  import { fingerprintFromRaw } from "./fingerprint.mjs";
17
+ import { stackEvidenceFromRaw } from "./batch-stack-evidence.mjs";
18
+ import { takeStackHandoff } from "./stack-handoff.mjs";
14
19
  function onlyReceiptSummaryErrors(errors) {
15
20
  return (!!errors?.length &&
16
21
  errors.every((error) => Array.isArray(error.path) &&
17
22
  error.path[0] === "repository" &&
18
23
  error.path[1] === "receiptSummary"));
19
24
  }
20
- /**
21
- * Fetch all PR data needed for a `shepherd check` in one (or a few, if paginating) GraphQL requests.
22
- */
23
- export async function fetchPrBatch(pr, repo, opts = {}) {
24
- const variables = {
25
- owner: repo.owner,
26
- repo: repo.name,
27
- pr,
28
- };
29
- let result;
25
+ async function readBatchFirstPage(pr, repo, opts) {
26
+ const variables = { owner: repo.owner, repo: repo.name, pr };
30
27
  try {
31
- result = await graphqlWithRateLimit(opts.includeReceiptSummary ? BATCH_PR_RECEIPT_QUERY : BATCH_PR_QUERY, variables);
28
+ return await graphqlWithRateLimit(opts.includeReceiptSummary ? BATCH_PR_RECEIPT_QUERY : BATCH_PR_QUERY, variables);
32
29
  }
33
30
  catch (error) {
34
31
  if (!opts.includeReceiptSummary ||
@@ -39,9 +36,23 @@ export async function fetchPrBatch(pr, repo, opts = {}) {
39
36
  throw error;
40
37
  // Receipt evidence is optional; a resource-limited combined query or an
41
38
  // error confined to its sibling must not prevent the ordinary snapshot.
42
- result = await graphqlWithRateLimit(BATCH_PR_QUERY, variables);
39
+ return graphqlWithRateLimit(BATCH_PR_QUERY, variables);
43
40
  }
41
+ }
42
+ /**
43
+ * Fetch all PR data needed for a `shepherd check` in one (or a few, if paginating) GraphQL requests.
44
+ */
45
+ async function fetchGraphqlPrBatch(pr, repo, opts = {}, reuse) {
46
+ const handoff = await takeStackHandoff(repo, pr); // a routed stack layer's first read
47
+ const result = handoff ? { data: handoff } : await readBatchFirstPage(pr, repo, opts);
44
48
  const raw = requireRawPr(result.data, pr, repo);
49
+ const fingerprint = fingerprintFromRaw(raw, result.data.repository?.viewerPermission ?? null, result.data.viewer?.login ?? null);
50
+ // Decide reuse from the first page alone, before any supplement is paid for.
51
+ const reused = reuse && (await reuse(fingerprint));
52
+ const baseTipOid = raw.baseRef?.target?.oid;
53
+ const stackEvidence = stackEvidenceFromRaw(raw, result.data);
54
+ if (reused)
55
+ return { reused, ...(baseTipOid && { baseTipOid }), ...(stackEvidence && { stackEvidence }) };
45
56
  const queueRateLimit = await hydrateMergeQueueChecks(raw, repo, result.rateLimit);
46
57
  const paged = await paginateBatchConnections(pr, repo, raw, opts, queueRateLimit);
47
58
  const threadPages = await hydrateThreadCommentPages(paged.threads, paged.rateLimit);
@@ -54,6 +65,12 @@ export async function fetchPrBatch(pr, repo, opts = {}) {
54
65
  // Malformed supplemental evidence must not discard a complete BatchPr.
55
66
  }
56
67
  }
68
+ for (const thread of threadPages.threads) {
69
+ const root = thread.comments.nodes[0];
70
+ const numericId = root?.url?.match(/discussion_r([0-9]+)/)?.[1];
71
+ if (numericId)
72
+ await recordThreadIdentity(repo, pr, thread.id, numericId);
73
+ }
57
74
  const data = parseRawPr(raw, threadPages.threads, paged.comments, paged.changesRequested, paged.reviewSummaries, paged.approvedReviews, paged.checks, result.data.repository);
58
75
  const viewerLogin = result.data.viewer?.login;
59
76
  if (viewerLogin)
@@ -61,15 +78,15 @@ export async function fetchPrBatch(pr, repo, opts = {}) {
61
78
  data.checks = mergeStartupFailureChecks(data.checks, parseSuiteStartupFailures(raw));
62
79
  return {
63
80
  data,
64
- fingerprint: fingerprintFromRaw(raw, result.data.repository?.viewerPermission ?? null, result.data.viewer?.login ?? null),
81
+ fingerprint,
65
82
  rateLimit: threadPages.rateLimit ?? paged.rateLimit ?? result.rateLimit,
66
83
  ...(parseCheckSuitesComplete(raw) && { checkSuitesComplete: true }),
67
84
  ...(parseHeadCheckSuitesEmpty(raw) && { headCheckSuitesEmpty: true }),
68
85
  ...workflowSuites(raw),
69
86
  ...(receiptSummary && { receiptSummary }),
87
+ ...(stackEvidence && { stackEvidence }),
70
88
  };
71
89
  }
72
- function workflowSuites(raw) {
73
- const suites = parseHeadWorkflowSuites(raw);
74
- return suites.length > 0 ? { headWorkflowSuites: suites } : {};
90
+ export function fetchPrBatch(pr, repo, opts = {}, reuse) {
91
+ return githubOperation("BatchPr", () => runWithGithubTransport("graphql", () => fetchGraphqlPrBatch(pr, repo, opts, reuse)), () => fetchRestPrBatch(pr, repo, opts));
75
92
  }
@@ -8,10 +8,5 @@ interface CheckAnnotationBatchResult {
8
8
  annotations: Map<string, CheckAnnotation[]>;
9
9
  failures: AnnotationBatchFailure[];
10
10
  }
11
- /**
12
- * First annotation page for every uncached id, in chunks of 20. Further pages
13
- * use the single-node query and only run when that first page has `hasNextPage`.
14
- * A retryable rate limit aborts the remaining chunks and pages.
15
- */
16
11
  export declare function fetchCheckRunAnnotationsBatch(checkRunIds: string[], cacheOpts?: AnnotationCacheOptions): Promise<CheckAnnotationBatchResult>;
17
12
  export {};
@@ -1,3 +1,6 @@
1
+ import { githubOperation, runWithGithubTransport, isGithubReadFallbackError, } from "./transport.mjs";
2
+ import { mapPool } from "../util/pool.mjs";
3
+ import { ensureRestCheckIdentities } from "./rest-annotation-read.mjs";
1
4
  import { pollRateLimitRetryAfterMs } from "../commands/poll-quota.mjs";
2
5
  import { readFreshCheckAnnotations, } from "./check-annotation-cache.mjs";
3
6
  import {} from "./check-annotation-shape.mjs";
@@ -24,7 +27,7 @@ function retryableRateLimit(err) {
24
27
  * use the single-node query and only run when that first page has `hasNextPage`.
25
28
  * A retryable rate limit aborts the remaining chunks and pages.
26
29
  */
27
- export async function fetchCheckRunAnnotationsBatch(checkRunIds, cacheOpts) {
30
+ async function fetchGraphqlCheckRunAnnotationsBatch(checkRunIds, cacheOpts) {
28
31
  const annotations = new Map();
29
32
  const failures = [];
30
33
  const cached = await Promise.all(checkRunIds.map((id) => readFreshCheckAnnotations(id, cacheOpts)));
@@ -48,7 +51,7 @@ async function fetchChunk(chunk, annotations, failures, cacheOpts) {
48
51
  await applyBatchNodes(chunk, nodes, annotations, failures, cacheOpts);
49
52
  }
50
53
  catch (err) {
51
- if (retryableRateLimit(err))
54
+ if (retryableRateLimit(err) || isGithubReadFallbackError(err))
52
55
  throw err;
53
56
  // A non-rate-limit batch failure (one NOT_FOUND or FORBIDDEN node rejects
54
57
  // the whole `nodes(ids:)` request) must not drop the other ids.
@@ -67,7 +70,7 @@ async function applyBatchNodes(chunk, nodes, annotations, failures, cacheOpts) {
67
70
  annotations.set(id, await fetchCheckRunAnnotations(id, cacheOpts, node.annotations));
68
71
  }
69
72
  catch (err) {
70
- if (retryableRateLimit(err))
73
+ if (retryableRateLimit(err) || isGithubReadFallbackError(err))
71
74
  throw err;
72
75
  failures.push({ checkRunId: id, error: err });
73
76
  }
@@ -80,7 +83,7 @@ async function fetchChunkOneByOne(chunk, annotations, failures, cacheOpts) {
80
83
  annotations.set(id, await fetchCheckRunAnnotations(id, cacheOpts));
81
84
  }
82
85
  catch (err) {
83
- if (retryableRateLimit(err))
86
+ if (retryableRateLimit(err) || isGithubReadFallbackError(err))
84
87
  throw err;
85
88
  failures.push({ checkRunId: id, error: err });
86
89
  }
@@ -90,3 +93,21 @@ async function requestFirstPages(ids) {
90
93
  const res = await graphql(CHECK_RUN_ANNOTATIONS_BATCH_QUERY, { ids }, { allowPartialData: true });
91
94
  return res.data.nodes ?? [];
92
95
  }
96
+ export function fetchCheckRunAnnotationsBatch(checkRunIds, cacheOpts) {
97
+ return githubOperation("CheckRunAnnotationsBatch", () => runWithGithubTransport("graphql", () => fetchGraphqlCheckRunAnnotationsBatch(checkRunIds, cacheOpts)), async () => {
98
+ const annotations = new Map();
99
+ const failures = [];
100
+ await ensureRestCheckIdentities(checkRunIds, cacheOpts);
101
+ await mapPool([...new Set(checkRunIds)], 4, async (id) => {
102
+ try {
103
+ annotations.set(id, await fetchCheckRunAnnotations(id, cacheOpts));
104
+ }
105
+ catch (error) {
106
+ if (retryableRateLimit(error))
107
+ throw error;
108
+ failures.push({ checkRunId: id, error });
109
+ }
110
+ });
111
+ return { annotations, failures };
112
+ });
113
+ }
@@ -1,3 +1,5 @@
1
+ import { githubOperation } from "./transport.mjs";
2
+ import { readRestCheckAnnotations } from "./rest-annotation-read.mjs";
1
3
  import { readFreshCheckAnnotations, storeCheckAnnotations, } from "./check-annotation-cache.mjs";
2
4
  import { collectAnnotations } from "./check-annotation-pages.mjs";
3
5
  /**
@@ -14,7 +16,7 @@ export async function fetchCheckRunAnnotations(checkRunId, cacheOpts, initialPag
14
16
  if (cached)
15
17
  return cached;
16
18
  }
17
- const annotations = await collectAnnotations(checkRunId, initialPage);
19
+ const annotations = await githubOperation("CheckRunAnnotations", () => collectAnnotations(checkRunId, initialPage), () => readRestCheckAnnotations(checkRunId, cacheOpts));
18
20
  await storeCheckAnnotations(checkRunId, annotations, cacheOpts);
19
21
  return annotations;
20
22
  }
@@ -1,10 +1,3 @@
1
- /**
2
- * High-level GitHub client — wraps http.mts for application-level concerns.
3
- *
4
- * All GitHub I/O goes through native fetch (via http.mts); the `gh` CLI is no
5
- * longer used for GitHub API calls, but may be invoked as an auth-token
6
- * fallback via `gh auth token` when neither GH_TOKEN nor GITHUB_TOKEN is set.
7
- */
8
1
  import type { MergeableState, MergeStateStatus } from "../types.mts";
9
2
  export type { RateLimitInfo } from "./http.mts";
10
3
  export { graphql, graphqlWithRateLimit } from "./http.mts";
@@ -22,22 +15,11 @@ export declare function getRepoInfo(): Promise<RepoInfo>;
22
15
  * Returns null if no open PR is found.
23
16
  */
24
17
  export declare function getCurrentPrNumber(): Promise<number | null>;
25
- /** Returns the PR number for a given branch, or null if no open PR is found. */
26
- export declare function getPrNumberForBranch(branch: string, owner: string, repo: string): Promise<number | null>;
27
- /** Returns the `headRefOid` (commit SHA) of the given PR as reported by GitHub. */
28
- export declare function getPrHeadSha(pr: number, owner: string, name: string): Promise<string>;
29
- /** Fetches the node ID and body text for a PR. GitHub returns null body for empty bodies — coerced to "". */
30
- export declare function getPullRequestBody(pr: number, owner: string, name: string): Promise<{
31
- nodeId: string;
32
- body: string;
33
- }>;
34
- /** Overwrites the PR body. */
35
- export declare function updatePullRequestBody(pullRequestId: string, body: string): Promise<void>;
36
18
  /**
37
19
  * Fetches PR state, `mergeable`, and `mergeStateStatus` via the REST API.
38
20
  *
39
21
  * Used when the GraphQL API returns `UNKNOWN` for mergeability or before a
40
- * READY state. The same response carries state so a concurrent merge or
22
+ * READY state. The read is conditional inside a PR's REST conditional scope. The same response carries state so a concurrent merge or
41
23
  * close can supersede the earlier GraphQL snapshot without another request.
42
24
  */
43
25
  export declare function getMergeableState(pr: number, owner: string, repo: string): Promise<{
@@ -46,3 +28,10 @@ export declare function getMergeableState(pr: number, owner: string, repo: strin
46
28
  state?: "OPEN" | "CLOSED" | "MERGED";
47
29
  }>;
48
30
  export declare function getCurrentBranch(): Promise<string>;
31
+ export declare function getPrNumberForBranch(branch: string, owner: string, name: string): Promise<number | null>;
32
+ export declare function getPrHeadSha(pr: number, owner: string, name: string): Promise<string>;
33
+ export declare function getPullRequestBody(pr: number, owner: string, name: string): Promise<{
34
+ nodeId: string;
35
+ body: string;
36
+ }>;
37
+ export declare function updatePullRequestBody(pullRequestId: string, body: string): Promise<void>;
@@ -1,3 +1,7 @@
1
+ import { githubOperation } from "./transport.mjs";
2
+ import { readRestPull } from "./rest-pr-core.mjs";
3
+ import { readRest, readRestPages, restRepoPath, restObject, restNumber, restString, } from "./rest-reader-core.mjs";
4
+ import { recordRestIdentity, resolveRestIdentity } from "./rest-identities.mjs";
1
5
  /* eslint-disable max-lines */
2
6
  /**
3
7
  * High-level GitHub client — wraps http.mts for application-level concerns.
@@ -44,17 +48,12 @@ export async function getCurrentPrNumber() {
44
48
  }
45
49
  }
46
50
  /** Returns the PR number for a given branch, or null if no open PR is found. */
47
- export async function getPrNumberForBranch(branch, owner, repo) {
48
- try {
49
- const result = await httpGraphql(PR_NUMBER_BY_BRANCH_QUERY, { owner, repo, branch });
50
- return result.data.repository?.pullRequests.nodes[0]?.number ?? null;
51
- }
52
- catch {
53
- return null;
54
- }
51
+ async function getGraphqlPrNumberForBranch(branch, owner, repo) {
52
+ const result = await httpGraphql(PR_NUMBER_BY_BRANCH_QUERY, { owner, repo, branch });
53
+ return result.data.repository?.pullRequests.nodes[0]?.number ?? null;
55
54
  }
56
55
  /** Returns the `headRefOid` (commit SHA) of the given PR as reported by GitHub. */
57
- export async function getPrHeadSha(pr, owner, name) {
56
+ async function getGraphqlPrHeadSha(pr, owner, name) {
58
57
  const result = await httpGraphql(GET_PR_HEAD_SHA_QUERY, { owner, repo: name, pr });
59
58
  const sha = result.data.repository?.pullRequest?.headRefOid;
60
59
  if (!sha) {
@@ -68,7 +67,7 @@ export async function getPrHeadSha(pr, owner, name) {
68
67
  return sha;
69
68
  }
70
69
  /** Fetches the node ID and body text for a PR. GitHub returns null body for empty bodies — coerced to "". */
71
- export async function getPullRequestBody(pr, owner, name) {
70
+ async function getGraphqlPullRequestBody(pr, owner, name) {
72
71
  const result = await httpGraphql(GET_PR_BODY_QUERY, { owner, repo: name, pr });
73
72
  const pullRequest = result.data.repository?.pullRequest;
74
73
  if (!pullRequest) {
@@ -77,24 +76,31 @@ export async function getPullRequestBody(pr, owner, name) {
77
76
  : "PR not found or access denied";
78
77
  throw new Error(`Could not fetch body for ${owner}/${name} PR #${pr}: ${detail}`);
79
78
  }
79
+ if (pullRequest.fullDatabaseId != null) {
80
+ if (typeof pullRequest.fullDatabaseId !== "string")
81
+ restNumber(pullRequest.fullDatabaseId, "pull request fullDatabaseId");
82
+ await recordRestIdentity({ owner, name }, pr, pullRequest.id, pullRequest.fullDatabaseId, "pull");
83
+ }
80
84
  return {
81
85
  nodeId: pullRequest.id,
82
86
  body: pullRequest.body ?? "",
83
87
  };
84
88
  }
85
89
  /** Overwrites the PR body. */
86
- export async function updatePullRequestBody(pullRequestId, body) {
90
+ async function updateGraphqlPullRequestBody(pullRequestId, body) {
87
91
  await httpGraphql(UPDATE_PR_BODY_MUTATION, { pullRequestId, body });
88
92
  }
89
93
  /**
90
94
  * Fetches PR state, `mergeable`, and `mergeStateStatus` via the REST API.
91
95
  *
92
96
  * Used when the GraphQL API returns `UNKNOWN` for mergeability or before a
93
- * READY state. The same response carries state so a concurrent merge or
97
+ * READY state. The read is conditional inside a PR's REST conditional scope. The same response carries state so a concurrent merge or
94
98
  * close can supersede the earlier GraphQL snapshot without another request.
95
99
  */
96
100
  export async function getMergeableState(pr, owner, repo) {
97
- const data = await rest("GET", `/repos/${owner}/${repo}/pulls/${pr}`);
101
+ // Inside a PR's conditional scope this shares the pull's ETag with the snapshot and wait
102
+ // detectors: a 304 proves GitHub's current mergeability equals the stored settled body.
103
+ const data = await readRest("GET", `${restRepoPath({ owner, name: repo })}/pulls/${pr}`);
98
104
  const mergeable = data.mergeable === true ? "MERGEABLE" : data.mergeable === false ? "CONFLICTING" : "UNKNOWN";
99
105
  const mergeStateStatus = data.mergeable_state.toUpperCase();
100
106
  const rawState = data.state?.toUpperCase();
@@ -137,3 +143,29 @@ function parseRemoteUrl(url) {
137
143
  }
138
144
  throw new Error(`Cannot parse GitHub remote URL: ${url}`);
139
145
  }
146
+ export function getPrNumberForBranch(branch, owner, name) {
147
+ return githubOperation("PrNumberByBranch", () => getGraphqlPrNumberForBranch(branch, owner, name), async () => {
148
+ const listed = await readRestPages(`${restRepoPath({ owner, name })}/pulls?state=open`);
149
+ // REST's head filter requires an owner, but GraphQL's headRefName also matches fork heads.
150
+ const pull = listed.nodes.find((value) => {
151
+ const head = restObject(restObject(value, "pull request").head, "pull request head");
152
+ return restString(head.ref, "pull request head ref") === branch;
153
+ });
154
+ return pull ? restNumber(pull.number, "pull number") : null;
155
+ }).catch(() => null);
156
+ }
157
+ export function getPrHeadSha(pr, owner, name) {
158
+ return githubOperation("GetPrHeadSha", () => getGraphqlPrHeadSha(pr, owner, name), async () => (await readRestPull(pr, { owner, name })).head.sha);
159
+ }
160
+ export function getPullRequestBody(pr, owner, name) {
161
+ return githubOperation("GetPrBody", () => getGraphqlPullRequestBody(pr, owner, name), async () => {
162
+ const pull = await readRestPull(pr, { owner, name });
163
+ return { nodeId: pull.node_id, body: pull.body ?? "" };
164
+ });
165
+ }
166
+ export function updatePullRequestBody(pullRequestId, body) {
167
+ return githubOperation("UpdatePrBody", () => updateGraphqlPullRequestBody(pullRequestId, body), async () => {
168
+ const identity = await resolveRestIdentity(pullRequestId, "pull");
169
+ await rest("PATCH", `${restRepoPath(identity.repo)}/pulls/${identity.pr}`, { body });
170
+ }, { mutation: true });
171
+ }
@@ -35,9 +35,17 @@ export declare function threadCommentRevisions(nodes: Array<{
35
35
  }>;
36
36
  };
37
37
  }>): string;
38
+ /**
39
+ * A thread whose earlier comments the fingerprint cannot see. BatchPr's `comments(first: 100)`
40
+ * carries the nodes and `hasNextPage`; a stored `totalCount` is honored when present.
41
+ */
38
42
  export declare function hasMultiCommentThreads(nodes: Array<{
39
43
  comments?: {
40
44
  totalCount?: number;
45
+ nodes?: unknown[];
46
+ pageInfo?: {
47
+ hasNextPage?: boolean;
48
+ };
41
49
  };
42
50
  }>): boolean;
43
51
  export declare function rulesComplete(baseRef?: {
@@ -26,8 +26,13 @@ export function threadCommentRevisions(nodes) {
26
26
  })
27
27
  .join(",");
28
28
  }
29
+ /**
30
+ * A thread whose earlier comments the fingerprint cannot see. BatchPr's `comments(first: 100)`
31
+ * carries the nodes and `hasNextPage`; a stored `totalCount` is honored when present.
32
+ */
29
33
  export function hasMultiCommentThreads(nodes) {
30
- return nodes.some((thread) => (thread.comments?.totalCount ?? 0) > 1);
34
+ return nodes.some(({ comments }) => (comments?.totalCount ?? comments?.nodes?.length ?? 0) > 1 ||
35
+ comments?.pageInfo?.hasNextPage === true);
31
36
  }
32
37
  export function rulesComplete(baseRef) {
33
38
  return baseRef?.rules?.pageInfo?.hasNextPage !== true;
@@ -1,5 +1,8 @@
1
- import type { RepoInfo } from "./client.mts";
2
1
  import type { RawPr } from "./batch-raw-types.mts";
2
+ /**
3
+ * Summary of BatchPr's first page. Two equal fingerprints mean the first page is unchanged, as
4
+ * long as every window it summarizes is complete (see `fingerprintReuser`).
5
+ */
3
6
  export interface PrFingerprint {
4
7
  headRefOid: string;
5
8
  updatedAt: string;
@@ -32,4 +35,3 @@ export interface PrFingerprint {
32
35
  }
33
36
  export declare function fingerprintFromRaw(raw: RawPr, viewerPermission?: string | null, viewerLogin?: string | null): PrFingerprint;
34
37
  export declare function fingerprintsEqual(left: PrFingerprint, right: PrFingerprint): boolean;
35
- export declare function fetchPrFingerprint(pr: number, repo: RepoInfo): Promise<PrFingerprint>;
@@ -1,9 +1,5 @@
1
- import { graphqlWithRateLimit } from "./client.mjs";
2
- import { PR_FINGERPRINT_QUERY } from "./queries.mjs";
3
- import { GitHubRequestError } from "./errors.mjs";
4
- import { EXIT, ShepherdError } from "../exit-codes.mjs";
5
1
  import { commentRevisions, mergePolicyFingerprint, rulesComplete, stackKey, suiteFingerprint, hasMultiCommentThreads, threadCommentRevisions, } from "./fingerprint-fields.mjs";
6
- function coreFingerprint(raw, counts, viewer) {
2
+ export function fingerprintFromRaw(raw, viewerPermission = null, viewerLogin = null) {
7
3
  return {
8
4
  headRefOid: raw.headRefOid,
9
5
  updatedAt: raw.updatedAt ?? "",
@@ -18,50 +14,22 @@ function coreFingerprint(raw, counts, viewer) {
18
14
  commentCount: raw.comments.totalCount ?? raw.comments.nodes.length,
19
15
  commentRevisions: commentRevisions(raw.comments.nodes),
20
16
  threadCount: raw.reviewThreads.totalCount ?? raw.reviewThreads.nodes.length,
21
- reviewCount: counts.reviewCount,
22
- reviewRevisions: counts.reviewRevisions,
17
+ reviewCount: raw.allReviews?.totalCount ?? 0,
18
+ reviewRevisions: commentRevisions(raw.allReviews?.nodes ?? []),
23
19
  latestCommentId: raw.comments.nodes.at(-1)?.id ?? null,
24
20
  latestThreadId: raw.reviewThreads.nodes.at(-1)?.id ?? null,
25
- latestReviewId: counts.latestReviewId,
21
+ latestReviewId: raw.allReviews?.nodes?.at(-1)?.id ?? null,
26
22
  checkRollupState: raw.commits.nodes[0]?.commit.statusCheckRollup?.state ?? null,
27
23
  ...suiteFingerprint(raw.commits.nodes[0]?.commit.checkSuites),
28
24
  viewerCanUpdate: raw.viewerCanUpdate === true,
29
- viewerPermission: viewer.permission,
30
- viewerLogin: viewer.login,
25
+ viewerPermission,
26
+ viewerLogin,
31
27
  stackKey: stackKey(raw),
32
28
  threadCommentRevisions: threadCommentRevisions(raw.reviewThreads.nodes),
33
29
  rulesComplete: rulesComplete(raw.baseRef),
34
30
  hasMultiCommentThreads: hasMultiCommentThreads(raw.reviewThreads.nodes),
35
31
  };
36
32
  }
37
- export function fingerprintFromRaw(raw, viewerPermission = null, viewerLogin = null) {
38
- return coreFingerprint(raw, {
39
- reviewCount: raw.allReviews?.totalCount ?? 0,
40
- latestReviewId: raw.allReviews?.nodes?.at(-1)?.id ?? null,
41
- reviewRevisions: commentRevisions(raw.allReviews?.nodes ?? []),
42
- }, { permission: viewerPermission, login: viewerLogin });
43
- }
44
33
  export function fingerprintsEqual(left, right) {
45
34
  return JSON.stringify(left) === JSON.stringify(right);
46
35
  }
47
- export async function fetchPrFingerprint(pr, repo) {
48
- const result = await graphqlWithRateLimit(PR_FINGERPRINT_QUERY, {
49
- owner: repo.owner,
50
- repo: repo.name,
51
- pr,
52
- });
53
- if (!result.data.repository) {
54
- throw new GitHubRequestError(`GitHub GraphQL response did not include repository ${repo.owner}/${repo.name} (not found or access denied)`, { status: 200 });
55
- }
56
- const raw = result.data.repository.pullRequest;
57
- if (!raw)
58
- throw new ShepherdError(`PR #${pr} not found`, EXIT.UNAVAILABLE);
59
- return coreFingerprint(raw, {
60
- reviewCount: raw.reviews.totalCount,
61
- latestReviewId: raw.reviews.nodes.at(-1)?.id ?? null,
62
- reviewRevisions: commentRevisions(raw.reviews.nodes),
63
- }, {
64
- permission: result.data.repository.viewerPermission,
65
- login: result.data.viewer?.login ?? null,
66
- });
67
- }
@@ -0,0 +1,2 @@
1
+ /** Attach proxy routing to GitHub requests without changing the host's dispatcher. */
2
+ export declare function githubFetch(input: string | URL, init?: RequestInit): Promise<Response>;
@@ -0,0 +1,19 @@
1
+ import { EnvHttpProxyAgent } from "undici";
2
+ let proxyAgent;
3
+ let proxyConfiguration;
4
+ /** Attach proxy routing to GitHub requests without changing the host's dispatcher. */
5
+ export function githubFetch(input, init) {
6
+ const httpProxy = process.env["http_proxy"] ?? process.env["HTTP_PROXY"] ?? "";
7
+ const httpsProxy = process.env["https_proxy"] ?? process.env["HTTPS_PROXY"] ?? "";
8
+ if (!httpProxy && !httpsProxy)
9
+ return fetch(input, init);
10
+ const configuration = JSON.stringify([httpProxy, httpsProxy]);
11
+ if (!proxyAgent || configuration !== proxyConfiguration) {
12
+ const previous = proxyAgent;
13
+ proxyAgent = new EnvHttpProxyAgent();
14
+ proxyConfiguration = configuration;
15
+ // close waits for in-flight bodies before releasing the previous pool.
16
+ void previous?.close().catch(() => { });
17
+ }
18
+ return fetch(input, { ...init, dispatcher: proxyAgent });
19
+ }
@@ -12,6 +12,9 @@ query BaseBehind($owner: String!, $repo: String!, $qualifiedName: String!, $head
12
12
  }
13
13
  repository(owner: $owner, name: $repo) {
14
14
  ref(qualifiedName: $qualifiedName) {
15
+ target {
16
+ oid
17
+ }
15
18
  compare(headRef: $headRef) {
16
19
  behindBy
17
20
  }
@@ -176,7 +176,23 @@ query BatchPrPage(
176
176
  annotations(first: 1) {
177
177
  totalCount
178
178
  nodes {
179
+ fullDatabaseId
180
+ path
181
+ annotationLevel
182
+ title
179
183
  message
184
+ rawDetails
185
+ blobUrl
186
+ location {
187
+ start {
188
+ line
189
+ column
190
+ }
191
+ end {
192
+ line
193
+ column
194
+ }
195
+ }
180
196
  }
181
197
  }
182
198
  checkSuite {
@@ -39,6 +39,12 @@ query BatchPr($owner: String!, $repo: String!, $pr: Int!) {
39
39
  }
40
40
  baseRefName
41
41
  baseRefOid
42
+ # Live base tip (an object, no connection cost): keys the BaseBehind cache.
43
+ baseRef {
44
+ target {
45
+ oid
46
+ }
47
+ }
42
48
  isInMergeQueue
43
49
  ...PrMergePolicy
44
50
  autoMergeRequest {
@@ -102,10 +108,45 @@ query BatchPr($owner: String!, $repo: String!, $pr: Int!) {
102
108
  }
103
109
  }
104
110
  }
111
+ # Native-stack topology and trunk rules ride along so a stack layer needs no
112
+ # separate PollStackTopology or RefRules read. Neither nested selection
113
+ # multiplies a connection by 50, so together they add about 3 requests.
105
114
  stack {
115
+ id
106
116
  number
107
117
  size
108
118
  baseRefName
119
+ entries(first: 50) {
120
+ pageInfo {
121
+ hasNextPage
122
+ endCursor
123
+ }
124
+ nodes {
125
+ position
126
+ pullRequest {
127
+ number
128
+ state
129
+ headRefName
130
+ headRefOid
131
+ baseRefName
132
+ baseRefOid
133
+ }
134
+ }
135
+ }
136
+ # The bottom entry's base is the trunk: its rules and live tip.
137
+ trunkEntry: entries(first: 1) {
138
+ nodes {
139
+ pullRequest {
140
+ baseRefName
141
+ baseRef {
142
+ ...RefRules
143
+ target {
144
+ oid
145
+ }
146
+ }
147
+ }
148
+ }
149
+ }
109
150
  }
110
151
  stackEntry {
111
152
  position
@@ -295,7 +336,23 @@ query BatchPr($owner: String!, $repo: String!, $pr: Int!) {
295
336
  annotations(first: 1) {
296
337
  totalCount
297
338
  nodes {
339
+ fullDatabaseId
340
+ path
341
+ annotationLevel
342
+ title
298
343
  message
344
+ rawDetails
345
+ blobUrl
346
+ location {
347
+ start {
348
+ line
349
+ column
350
+ }
351
+ end {
352
+ line
353
+ column
354
+ }
355
+ }
299
356
  }
300
357
  }
301
358
  checkSuite {
@@ -31,8 +31,25 @@ query CommitCheckContexts($owner: String!, $repo: String!, $oid: String!, $curso
31
31
  title
32
32
  summary
33
33
  annotations(first: 1) {
34
+ totalCount
34
35
  nodes {
36
+ fullDatabaseId
37
+ path
38
+ annotationLevel
39
+ title
35
40
  message
41
+ rawDetails
42
+ blobUrl
43
+ location {
44
+ start {
45
+ line
46
+ column
47
+ }
48
+ end {
49
+ line
50
+ column
51
+ }
52
+ }
36
53
  }
37
54
  }
38
55
  checkSuite {
@@ -10,6 +10,7 @@ query GetPrBody($owner: String!, $repo: String!, $pr: Int!) {
10
10
  repository(owner: $owner, name: $repo) {
11
11
  pullRequest(number: $pr) {
12
12
  id
13
+ fullDatabaseId
13
14
  body
14
15
  }
15
16
  }
@@ -17,6 +17,7 @@ query PollStackSummary(
17
17
  login
18
18
  }
19
19
  repository(owner: $owner, name: $repo) {
20
+ viewerPermission
20
21
  viewerCanAdminister
21
22
  mergeCommitAllowed
22
23
  squashMergeAllowed