pr-shepherd 0.56.5 → 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 (423) 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 +40 -19
  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.d.mts +6 -5
  138. package/bin/commands/iterate/native-stack-rebase.mjs +24 -7
  139. package/bin/commands/iterate/render.d.mts +8 -2
  140. package/bin/commands/iterate/render.mjs +28 -42
  141. package/bin/commands/iterate/stack-trunk-conflict.d.mts +4 -2
  142. package/bin/commands/iterate/stack-trunk-conflict.mjs +44 -19
  143. package/bin/commands/iterate/stale-ancestry.mjs +4 -1
  144. package/bin/commands/iterate/stall.d.mts +5 -1
  145. package/bin/commands/iterate/stall.mjs +19 -7
  146. package/bin/commands/iterate/thread-mutation-routing.d.mts +1 -0
  147. package/bin/commands/iterate/thread-mutation-routing.mjs +4 -2
  148. package/bin/commands/iterate/unreported-required.mjs +5 -2
  149. package/bin/commands/mark-files-as-viewed.mjs +7 -0
  150. package/bin/commands/next-check.d.mts +31 -0
  151. package/bin/commands/next-check.mjs +46 -0
  152. package/bin/commands/playbook.d.mts +13 -0
  153. package/bin/commands/playbook.mjs +48 -0
  154. package/bin/commands/poll-mode.d.mts +8 -0
  155. package/bin/commands/poll-mode.mjs +14 -0
  156. package/bin/commands/poll-progress.d.mts +1 -0
  157. package/bin/commands/poll-progress.mjs +6 -3
  158. package/bin/commands/poll-quota.d.mts +3 -2
  159. package/bin/commands/poll-quota.mjs +7 -3
  160. package/bin/commands/poll-summary-explicit-instructions.d.mts +2 -0
  161. package/bin/commands/poll-summary-explicit-instructions.mjs +10 -1
  162. package/bin/commands/poll-summary-instructions.mjs +16 -17
  163. package/bin/commands/poll-summary.mjs +42 -17
  164. package/bin/commands/poll.d.mts +0 -1
  165. package/bin/commands/poll.mjs +11 -19
  166. package/bin/commands/quota-selection.d.mts +2 -1
  167. package/bin/commands/quota-selection.mjs +12 -7
  168. package/bin/commands/resolve-mutate.mjs +33 -5
  169. package/bin/commands/rest-stack-merge-readiness.d.mts +4 -0
  170. package/bin/commands/rest-stack-merge-readiness.mjs +74 -0
  171. package/bin/commands/rule-auto-resolve.mjs +9 -3
  172. package/bin/commands/shepherd-journal.d.mts +5 -4
  173. package/bin/commands/shepherd-journal.mjs +9 -8
  174. package/bin/commands/stack-drain.d.mts +1 -9
  175. package/bin/commands/stack-drain.mjs +50 -37
  176. package/bin/commands/stack-handoffs.d.mts +10 -0
  177. package/bin/commands/stack-handoffs.mjs +25 -0
  178. package/bin/commands/stack-stall.d.mts +5 -0
  179. package/bin/commands/stack-stall.mjs +11 -0
  180. package/bin/commands/stack-work.d.mts +5 -0
  181. package/bin/commands/stack-work.mjs +32 -0
  182. package/bin/comments/existing-reply-scan.d.mts +17 -0
  183. package/bin/comments/existing-reply-scan.mjs +41 -0
  184. package/bin/comments/rate-limit.mjs +2 -2
  185. package/bin/comments/resolve.d.mts +7 -1
  186. package/bin/comments/resolve.mjs +108 -18
  187. package/bin/comments/rest-reply.d.mts +9 -0
  188. package/bin/comments/rest-reply.mjs +95 -0
  189. package/bin/comments/rest-review-mutations.d.mts +22 -0
  190. package/bin/comments/rest-review-mutations.mjs +125 -0
  191. package/bin/comments/review-visibility.d.mts +1 -1
  192. package/bin/comments/review-visibility.mjs +3 -2
  193. package/bin/comments/sha-poll.mjs +7 -3
  194. package/bin/comments/thread-visibility.mjs +10 -5
  195. package/bin/comments/uncertain-replies.d.mts +11 -0
  196. package/bin/comments/uncertain-replies.mjs +121 -0
  197. package/bin/comments/uncertain-reply-guards.d.mts +10 -0
  198. package/bin/comments/uncertain-reply-guards.mjs +94 -0
  199. package/bin/comments/visible-comments.d.mts +1 -1
  200. package/bin/comments/visible-comments.mjs +4 -2
  201. package/bin/config/load.d.mts +37 -1
  202. package/bin/config/load.mjs +73 -1
  203. package/bin/config.json +6 -2
  204. package/bin/exit-codes.d.mts +3 -0
  205. package/bin/exit-codes.mjs +8 -0
  206. package/bin/github/api-telemetry-aggregate.d.mts +15 -4
  207. package/bin/github/api-telemetry-aggregate.mjs +57 -18
  208. package/bin/github/api-telemetry.d.mts +4 -0
  209. package/bin/github/api-telemetry.mjs +22 -8
  210. package/bin/github/apply-review-preflight.d.mts +20 -0
  211. package/bin/github/apply-review-preflight.mjs +61 -0
  212. package/bin/github/base-behind-cache.d.mts +15 -0
  213. package/bin/github/base-behind-cache.mjs +18 -0
  214. package/bin/github/batch-parse-suites.d.mts +4 -2
  215. package/bin/github/batch-parse-suites.mjs +6 -1
  216. package/bin/github/batch-parser-helpers.mjs +40 -2
  217. package/bin/github/batch-parsers.mjs +1 -0
  218. package/bin/github/batch-raw-rules.d.mts +26 -0
  219. package/bin/github/batch-raw-types.d.mts +8 -6
  220. package/bin/github/batch-stack-evidence.d.mts +28 -0
  221. package/bin/github/batch-stack-evidence.mjs +62 -0
  222. package/bin/github/batch.d.mts +15 -2
  223. package/bin/github/batch.mjs +34 -17
  224. package/bin/github/check-annotations-batch.d.mts +0 -5
  225. package/bin/github/check-annotations-batch.mjs +25 -4
  226. package/bin/github/check-annotations.mjs +3 -1
  227. package/bin/github/client.d.mts +8 -19
  228. package/bin/github/client.mjs +45 -13
  229. package/bin/github/fingerprint-fields.d.mts +8 -0
  230. package/bin/github/fingerprint-fields.mjs +6 -1
  231. package/bin/github/fingerprint.d.mts +4 -2
  232. package/bin/github/fingerprint.mjs +6 -38
  233. package/bin/github/github-fetch.d.mts +2 -0
  234. package/bin/github/github-fetch.mjs +19 -0
  235. package/bin/github/gql/base-behind.gql +3 -0
  236. package/bin/github/gql/batch-pr-page.gql +16 -0
  237. package/bin/github/gql/batch-pr.gql +57 -0
  238. package/bin/github/gql/commit-check-contexts.gql +17 -0
  239. package/bin/github/gql/get-pr-body.gql +1 -0
  240. package/bin/github/gql/poll-stack-summary.gql +1 -0
  241. package/bin/github/gql/poll-summary-check-contexts.gql +5 -0
  242. package/bin/github/gql/poll-summary-fragment.gql +65 -15
  243. package/bin/github/gql/stack-handoff-check-runs.gql +42 -0
  244. package/bin/github/gql/upper-layer-conflict-target.gql +0 -15
  245. package/bin/github/graphql-http.mjs +9 -4
  246. package/bin/github/graphql-internal-retry.d.mts +2 -0
  247. package/bin/github/graphql-internal-retry.mjs +1 -1
  248. package/bin/github/graphql-quota-probe.d.mts +6 -0
  249. package/bin/github/graphql-quota-probe.mjs +56 -0
  250. package/bin/github/graphql-session-refusal.d.mts +8 -0
  251. package/bin/github/graphql-session-refusal.mjs +14 -0
  252. package/bin/github/http-request.d.mts +1 -1
  253. package/bin/github/http-request.mjs +22 -6
  254. package/bin/github/http-utils.mjs +6 -0
  255. package/bin/github/merge-target-rules.d.mts +16 -3
  256. package/bin/github/merge-target-rules.mjs +79 -44
  257. package/bin/github/mutation-policy.d.mts +6 -0
  258. package/bin/github/mutation-policy.mjs +21 -0
  259. package/bin/github/poll-summary-annotation-probe.mjs +17 -10
  260. package/bin/github/poll-summary-check-blockers.d.mts +1 -1
  261. package/bin/github/poll-summary-check-blockers.mjs +2 -2
  262. package/bin/github/poll-summary-check-hydration.mjs +25 -10
  263. package/bin/github/poll-summary-checks.d.mts +2 -2
  264. package/bin/github/poll-summary-checks.mjs +9 -6
  265. package/bin/github/poll-summary-command.d.mts +2 -0
  266. package/bin/github/poll-summary-command.mjs +24 -0
  267. package/bin/github/poll-summary-fingerprint.d.mts +1 -1
  268. package/bin/github/poll-summary-fingerprint.mjs +4 -2
  269. package/bin/github/poll-summary-handoff-fields.d.mts +3 -0
  270. package/bin/github/poll-summary-handoff-fields.mjs +73 -0
  271. package/bin/github/poll-summary-projector.d.mts +1 -1
  272. package/bin/github/poll-summary-projector.mjs +17 -24
  273. package/bin/github/poll-summary-raw.d.mts +70 -10
  274. package/bin/github/poll-summary-readiness.mjs +4 -1
  275. package/bin/github/poll-summary-rest-queue.d.mts +3 -0
  276. package/bin/github/poll-summary-rest-queue.mjs +12 -0
  277. package/bin/github/poll-summary-review.d.mts +1 -1
  278. package/bin/github/poll-summary-review.mjs +23 -11
  279. package/bin/github/poll-summary-route.mjs +19 -3
  280. package/bin/github/poll-summary-stack-page.d.mts +11 -0
  281. package/bin/github/poll-summary-stack-page.mjs +27 -0
  282. package/bin/github/poll-summary-unreported.d.mts +6 -3
  283. package/bin/github/poll-summary-unreported.mjs +15 -7
  284. package/bin/github/poll-summary.d.mts +4 -1
  285. package/bin/github/poll-summary.mjs +48 -34
  286. package/bin/github/queries.d.mts +9 -5
  287. package/bin/github/queries.mjs +10 -6
  288. package/bin/github/rate-limit-sample.d.mts +7 -0
  289. package/bin/github/rate-limit-sample.mjs +12 -0
  290. package/bin/github/reply-recovery-read.d.mts +50 -0
  291. package/bin/github/reply-recovery-read.mjs +118 -0
  292. package/bin/github/reply-thread-transcripts.d.mts +0 -1
  293. package/bin/github/reply-thread-transcripts.mjs +24 -1
  294. package/bin/github/rest-annotation-read.d.mts +5 -0
  295. package/bin/github/rest-annotation-read.mjs +44 -0
  296. package/bin/github/rest-batch-read.d.mts +12 -0
  297. package/bin/github/rest-batch-read.mjs +57 -0
  298. package/bin/github/rest-batch-snapshot.d.mts +30 -0
  299. package/bin/github/rest-batch-snapshot.mjs +115 -0
  300. package/bin/github/rest-batch-unavailable.d.mts +5 -0
  301. package/bin/github/rest-batch-unavailable.mjs +16 -0
  302. package/bin/github/rest-check-read.d.mts +34 -0
  303. package/bin/github/rest-check-read.mjs +124 -0
  304. package/bin/github/rest-comment-authorship.d.mts +7 -0
  305. package/bin/github/rest-comment-authorship.mjs +11 -0
  306. package/bin/github/rest-conditional-scope.d.mts +20 -0
  307. package/bin/github/rest-conditional-scope.mjs +44 -0
  308. package/bin/github/rest-explicit-summary-read.d.mts +3 -0
  309. package/bin/github/rest-explicit-summary-read.mjs +8 -0
  310. package/bin/github/rest-feedback-read.d.mts +36 -0
  311. package/bin/github/rest-feedback-read.mjs +147 -0
  312. package/bin/github/rest-feedback-validation.d.mts +5 -0
  313. package/bin/github/rest-feedback-validation.mjs +28 -0
  314. package/bin/github/rest-http.d.mts +12 -0
  315. package/bin/github/rest-http.mjs +108 -23
  316. package/bin/github/rest-identities.d.mts +22 -0
  317. package/bin/github/rest-identities.mjs +134 -0
  318. package/bin/github/rest-merge-stack-guard.d.mts +14 -0
  319. package/bin/github/rest-merge-stack-guard.mjs +41 -0
  320. package/bin/github/rest-merge.d.mts +29 -0
  321. package/bin/github/rest-merge.mjs +56 -0
  322. package/bin/github/rest-merged-base-read.d.mts +9 -0
  323. package/bin/github/rest-merged-base-read.mjs +48 -0
  324. package/bin/github/rest-pr-core.d.mts +52 -0
  325. package/bin/github/rest-pr-core.mjs +60 -0
  326. package/bin/github/rest-reader-core.d.mts +16 -0
  327. package/bin/github/rest-reader-core.mjs +154 -0
  328. package/bin/github/rest-review-read.d.mts +11 -0
  329. package/bin/github/rest-review-read.mjs +47 -0
  330. package/bin/github/rest-rules-read.d.mts +9 -0
  331. package/bin/github/rest-rules-read.mjs +154 -0
  332. package/bin/github/rest-session-refusal.d.mts +5 -0
  333. package/bin/github/rest-session-refusal.mjs +21 -0
  334. package/bin/github/rest-snapshot-context.d.mts +10 -0
  335. package/bin/github/rest-snapshot-context.mjs +1 -0
  336. package/bin/github/rest-stack-read.d.mts +21 -0
  337. package/bin/github/rest-stack-read.mjs +47 -0
  338. package/bin/github/rest-stack-summary.d.mts +8 -0
  339. package/bin/github/rest-stack-summary.mjs +62 -0
  340. package/bin/github/rest-summary-read.d.mts +7 -0
  341. package/bin/github/rest-summary-read.mjs +112 -0
  342. package/bin/github/rest-terminal-batch.d.mts +14 -0
  343. package/bin/github/rest-terminal-batch.mjs +45 -0
  344. package/bin/github/rest-text.mjs +7 -3
  345. package/bin/github/rest-thread-read.d.mts +4 -0
  346. package/bin/github/rest-thread-read.mjs +35 -0
  347. package/bin/github/rest-viewer-read.d.mts +2 -0
  348. package/bin/github/rest-viewer-read.mjs +41 -0
  349. package/bin/github/stack-bottom.d.mts +3 -0
  350. package/bin/github/stack-bottom.mjs +14 -0
  351. package/bin/github/stack-handoff-context.d.mts +25 -0
  352. package/bin/github/stack-handoff-context.mjs +12 -0
  353. package/bin/github/stack-handoff-page.d.mts +17 -0
  354. package/bin/github/stack-handoff-page.mjs +306 -0
  355. package/bin/github/stack-handoff.d.mts +16 -0
  356. package/bin/github/stack-handoff.mjs +115 -0
  357. package/bin/github/stack-order.d.mts +6 -0
  358. package/bin/github/stack-order.mjs +13 -0
  359. package/bin/github/stack-read.d.mts +7 -3
  360. package/bin/github/stack-read.mjs +22 -11
  361. package/bin/github/stack-size-hint.d.mts +3 -0
  362. package/bin/github/stack-size-hint.mjs +14 -0
  363. package/bin/github/suggestion-thread.mjs +27 -1
  364. package/bin/github/thread-comments.mjs +9 -1
  365. package/bin/github/transport-evidence.d.mts +20 -0
  366. package/bin/github/transport-evidence.mjs +26 -0
  367. package/bin/github/transport-mode.d.mts +2 -0
  368. package/bin/github/transport-mode.mjs +5 -0
  369. package/bin/github/transport.d.mts +19 -0
  370. package/bin/github/transport.mjs +126 -0
  371. package/bin/github/unsupported-rest.d.mts +4 -0
  372. package/bin/github/unsupported-rest.mjs +7 -0
  373. package/bin/mcp/server.mjs +52 -3
  374. package/bin/merge-status/derive.d.mts +2 -0
  375. package/bin/merge-status/derive.mjs +17 -13
  376. package/bin/merge-status/required-check-requirements.d.mts +7 -0
  377. package/bin/merge-status/required-check-requirements.mjs +15 -0
  378. package/bin/merge-status/requirements-format.d.mts +5 -0
  379. package/bin/merge-status/requirements-format.mjs +41 -12
  380. package/bin/merge-status/requirements.mjs +18 -7
  381. package/bin/state/base.mjs +41 -0
  382. package/bin/state/durable-state.d.mts +6 -0
  383. package/bin/state/durable-state.mjs +41 -0
  384. package/bin/state/graphql-quota-policy.mjs +23 -16
  385. package/bin/state/merge-request.d.mts +25 -0
  386. package/bin/state/merge-request.mjs +145 -0
  387. package/bin/state/pr-fingerprint.d.mts +15 -0
  388. package/bin/state/pr-fingerprint.mjs +22 -7
  389. package/bin/state/rest-cache.d.mts +3 -0
  390. package/bin/state/rest-cache.mjs +1 -0
  391. package/bin/state/rest-snapshot-report.d.mts +21 -0
  392. package/bin/state/rest-snapshot-report.mjs +52 -0
  393. package/bin/state/seen-comments.d.mts +3 -0
  394. package/bin/state/seen-comments.mjs +18 -0
  395. package/bin/types/api-usage.d.mts +9 -1
  396. package/bin/types/escalate.d.mts +1 -1
  397. package/bin/types/github.d.mts +23 -9
  398. package/bin/types/iterate.d.mts +24 -2
  399. package/bin/types/merge-action.d.mts +1 -1
  400. package/bin/types/merge-requirements.d.mts +7 -7
  401. package/bin/types/next-check.d.mts +12 -0
  402. package/bin/types/next-check.mjs +1 -0
  403. package/bin/types/poll-summary.d.mts +21 -0
  404. package/bin/types/report.d.mts +13 -1
  405. package/bin/types/review-thread.d.mts +1 -1
  406. package/bin/types.d.mts +1 -0
  407. package/bin/types.mjs +1 -0
  408. package/package.json +3 -2
  409. package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
  410. package/plugins/pr-shepherd/.codex.mcp.json +1 -1
  411. package/plugins/pr-shepherd/.mcp.json +1 -1
  412. package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +1 -1
  413. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +14 -51
  414. package/plugins/pr-shepherd/skills/pr-shepherd/references/ci-failure-triage.md +12 -16
  415. package/plugins/pr-shepherd/skills/pr-shepherd/references/cloud-event-loop.md +14 -0
  416. package/plugins/pr-shepherd/skills/pr-shepherd/references/create-pr.md +10 -0
  417. package/plugins/pr-shepherd/skills/pr-shepherd/references/fix-code-loop.md +10 -0
  418. package/plugins/pr-shepherd/skills/pr-shepherd/references/mcp-fallback.md +9 -0
  419. package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +2 -0
  420. package/bin/github/gql/pr-fingerprint.gql +0 -75
  421. package/plugins/pr-shepherd/skills/pr-shepherd/references/journal.md +0 -7
  422. package/plugins/pr-shepherd/skills/pr-shepherd/references/review-mutations.md +0 -9
  423. package/plugins/pr-shepherd/skills/pr-shepherd/references/stack-merge.md +0 -7
@@ -0,0 +1,10 @@
1
+ import { isBotItem } from "./author.mjs";
2
+ /** Codecov's coverage report comment. Coverage gates still report through their status checks. */
3
+ const rule = (item) => {
4
+ if (!isBotItem(item, ["codecov"], ["pr-comment"]))
5
+ return null;
6
+ if (!/^#{1,6}\s*\[?Codecov\b/i.test(item.body.trimStart()))
7
+ return null;
8
+ return { autoResolve: true, suppress: true, reason: "Codecov coverage report" };
9
+ };
10
+ export default rule;
@@ -0,0 +1,8 @@
1
+ import type { ClassifyRule } from "../types.mts";
2
+ /**
3
+ * CodeRabbit progress, rate-limit, review-skipped and draft notices, plus its "Action not
4
+ * completed" command replies. The summarize comment is later edited in place into the PR
5
+ * walkthrough, so the rule only hides it from agent output and never minimizes it.
6
+ */
7
+ declare const rule: ClassifyRule;
8
+ export default rule;
@@ -0,0 +1,38 @@
1
+ import { isBotItem } from "./author.mjs";
2
+ const NOTICE_ENVELOPE = /^<!-- This is an auto-generated comment: (rate limited|skip review|review in progress) by coderabbit.ai -->\n([\s\S]*?)\n<!-- end of auto-generated comment: \1 by coderabbit.ai -->$/;
3
+ const COMMAND_REPLY = /^<!-- This is an auto-generated reply by CodeRabbit -->\n<!-- CodeRabbit review command invocation: v2:[a-f0-9]+ -->\n<details>\n<summary>⚠️ Action not completed<\/summary>\n\n(?:Review rate limited\.|Review skipped: \d+ files exceed the limit of \d+\.)\n\n(?:> Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits\. This command is applicable only when automatic reviews are paused\.|---\n\nYour included review limit is currently reached under our \[Fair Usage Limits Policy\]\(https:\/\/docs.coderabbit.ai\/management\/plans#fair-usage-limits-policy\)\. This review may still proceed through usage-based billing if eligible\. Your next included review will be available in \d+ minutes?\.)\n\n<\/details>$/;
4
+ /** Strips CodeRabbit's footer and header blocks so only the notice envelope remains. */
5
+ function stripChrome(body) {
6
+ return body
7
+ .trim()
8
+ .replace(/\n<!-- tips_start -->[\s\S]*?<!-- tips_end -->$/, "")
9
+ .trim()
10
+ .replace(/\n<!-- autopilot:start -->[\s\S]*?<!-- autopilot:end -->$/, "")
11
+ .trim()
12
+ .replace(/^<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\s*/, "")
13
+ .replace(/^<!-- review_stack_entry_start -->[\s\S]*?<!-- review_stack_entry_end -->\s*/, "");
14
+ }
15
+ function isQuotedNotice(quoted) {
16
+ const onlyQuotedLines = quoted.split("\n").every((line) => !line.trim() || line.startsWith(">"));
17
+ if (!onlyQuotedLines)
18
+ return false;
19
+ return (quoted.includes("> ## Review limit reached\n") ||
20
+ quoted.includes("> ## Draft PR not reviewed\n") ||
21
+ quoted.includes("> ## Review skipped\n") ||
22
+ quoted.includes("> Currently processing new changes in this PR. This may take a few minutes, please wait..."));
23
+ }
24
+ /**
25
+ * CodeRabbit progress, rate-limit, review-skipped and draft notices, plus its "Action not
26
+ * completed" command replies. The summarize comment is later edited in place into the PR
27
+ * walkthrough, so the rule only hides it from agent output and never minimizes it.
28
+ */
29
+ const rule = (item) => {
30
+ if (!isBotItem(item, ["coderabbitai"], ["pr-comment"]))
31
+ return null;
32
+ const body = stripChrome(item.body);
33
+ const quoted = body.match(NOTICE_ENVELOPE)?.[2]?.trim();
34
+ if (!(quoted && isQuotedNotice(quoted)) && !COMMAND_REPLY.test(body))
35
+ return null;
36
+ return { suppress: true, reason: "CodeRabbit progress, review-limit, or skipped-review notice" };
37
+ };
38
+ export default rule;
@@ -0,0 +1,8 @@
1
+ import type { ClassifyRule } from "../types.mts";
2
+ /**
3
+ * CodeRabbit review summaries that only count and re-prompt their inline threads. The threads
4
+ * carry the findings, so the summary adds nothing. Any outside-diff, nitpick, duplicate or
5
+ * other body-only section keeps the summary visible.
6
+ */
7
+ declare const rule: ClassifyRule;
8
+ export default rule;
@@ -0,0 +1,37 @@
1
+ import { isBotItem } from "./author.mjs";
2
+ const HEADING = /^\*\*Actionable comments posted: \d+\*\*\n/;
3
+ const PROMPT_BLOCK = /\n<details>\n<summary>🤖 Prompt to fix review comments<\/summary>\n\n```\n([\s\S]*?)\n```\n\n<\/details>\n/;
4
+ const REVIEW_INFO_BLOCK = /\n<details>\n<summary>ℹ️ Review info<\/summary>\n[\s\S]*<\/details>\n/;
5
+ const AUTOFIX_BLOCK = /\n<!-- autofix_checkbox_start -->[\s\S]*?<!-- autofix_checkbox_end -->\n/;
6
+ /** Sections that carry findings only in the summary body, never in an inline thread. */
7
+ const BODY_ONLY_FINDINGS = /\[!CAUTION\]|Outside diff range comments|Nitpick comments|Duplicate comments|Additional comments|Outside diff comments:/;
8
+ /**
9
+ * CodeRabbit review summaries that only count and re-prompt their inline threads. The threads
10
+ * carry the findings, so the summary adds nothing. Any outside-diff, nitpick, duplicate or
11
+ * other body-only section keeps the summary visible.
12
+ */
13
+ const rule = (item) => {
14
+ if (!isBotItem(item, ["coderabbitai"], ["review-summary"]))
15
+ return null;
16
+ const body = `${item.body.trim()}\n`;
17
+ if (!HEADING.test(body) || BODY_ONLY_FINDINGS.test(body))
18
+ return null;
19
+ const prompt = body.match(PROMPT_BLOCK)?.[1];
20
+ if (prompt !== undefined && !prompt.includes("\nInline comments:\n"))
21
+ return null;
22
+ const rest = body
23
+ .replace(HEADING, "\n")
24
+ .replace(AUTOFIX_BLOCK, "\n")
25
+ .replace(PROMPT_BLOCK, "\n")
26
+ .replace(REVIEW_INFO_BLOCK, "\n")
27
+ .replace(/<!--[\s\S]*?-->/g, "")
28
+ .replace(/^---$/gm, "");
29
+ if (rest.trim() !== "")
30
+ return null;
31
+ return {
32
+ autoResolve: true,
33
+ suppress: true,
34
+ reason: "CodeRabbit review summary that only repeats its inline threads",
35
+ };
36
+ };
37
+ export default rule;
@@ -0,0 +1,7 @@
1
+ import type { ClassifyRule } from "../types.mts";
2
+ /**
3
+ * Codex quota notices, the review-activity status table, and no-findings notices. Each pattern
4
+ * matches the whole comment, so a notice with any appended finding stays visible.
5
+ */
6
+ declare const rule: ClassifyRule;
7
+ export default rule;
@@ -0,0 +1,36 @@
1
+ import { isBotItem } from "./author.mjs";
2
+ const QUOTA_NOTICES = [
3
+ /^You have reached your Codex usage limits for security reviews\. Please try again later\.$/,
4
+ /^You have reached your Codex usage limits for code reviews\. You can see your limits in the \[Codex usage dashboard\]\(https:\/\/chatgpt.com\/codex\/cloud\/settings\/usage\)\.(?:\nTo continue using code reviews, add credits to your account and enable them for code reviews in your \[settings\]\(https:\/\/chatgpt.com\/codex\/cloud\/settings\/code-review\)\.)?$/,
5
+ /^Codex usage limits have been reached for code reviews\. Please check with the admins of this repo to increase the limits by adding credits\.\nRepo admins can enable using credits for code reviews in their \[settings\]\(https:\/\/chatgpt.com\/codex\/cloud\/settings\/code-review\)\.$/,
6
+ /^Codex usage limits have been reached\. Please try again later\.$/,
7
+ ];
8
+ const ABOUT_BLOCK = /\n\n<details> <summary>ℹ️ About Codex (?:in GitHub|security reviews in GitHub)<\/summary>[\s\S]*?<\/details>$/;
9
+ const ACTIVITY_SUMMARY = /^<!-- codex-pull-request-review-summary -->\n(?:<!-- codex-security-review:v1 \{[^\n]*\} -->\n)?\n?## Codex Review Summary\n\nThis comment shows the latest Codex review activity on this pull request\.\n\n\| Review \| Status \| Commit \| Review trigger \|\n\| --- \| --- \| --- \| --- \|\n(?:\|[^\n]+\|\n?)+$/;
10
+ const CLEAN_REVIEW = /^Codex Review: Didn't find any major issues\. (?:Bravo\.|Breezy!|Hooray!|:\+1:)\n\n\*\*Reviewed commit:\*\* `[a-f0-9]+`$/;
11
+ const CLEAN_SECURITY = /^### 🛡️ Codex Security Review(?: · _Automatically triggered_)?\n\nSecurity review completed\. No security issues were found in this pull request\.\n\n\*\*Reviewed commit:\*\* `[a-f0-9]+`\n\n\[View security finding report\]\(https:\/\/chatgpt.com\/codex\/cloud\/tasks\/[a-zA-Z0-9_]+\)\n\n_Only the user who started this review can view the report in Codex\._$/;
12
+ /**
13
+ * Codex quota notices, the review-activity status table, and no-findings notices. Each pattern
14
+ * matches the whole comment, so a notice with any appended finding stays visible.
15
+ */
16
+ const rule = (item) => {
17
+ if (!isBotItem(item, ["chatgpt-codex-connector"], ["pr-comment", "review-summary"])) {
18
+ return null;
19
+ }
20
+ const body = item.body.trim();
21
+ if (QUOTA_NOTICES.some((notice) => notice.test(body))) {
22
+ return { autoResolve: true, suppress: true, reason: "Codex usage-limit notice" };
23
+ }
24
+ if (item.kind !== "pr-comment")
25
+ return null;
26
+ // Strip only the trailing About block; extra findings after it stay visible.
27
+ const content = body.replace(ABOUT_BLOCK, "").trim();
28
+ if (ACTIVITY_SUMMARY.test(content)) {
29
+ return { autoResolve: true, suppress: true, reason: "Codex review-activity table" };
30
+ }
31
+ if (CLEAN_REVIEW.test(content) || CLEAN_SECURITY.test(content)) {
32
+ return { autoResolve: true, suppress: true, reason: "Codex no-findings notice" };
33
+ }
34
+ return null;
35
+ };
36
+ export default rule;
@@ -0,0 +1,7 @@
1
+ import type { ClassifyRule } from "../types.mts";
2
+ /**
3
+ * The Codex review summary that only introduces its inline threads. A summary that carries a
4
+ * finding in its own body (for example, a permalink to a line outside the diff) stays visible.
5
+ */
6
+ declare const rule: ClassifyRule;
7
+ export default rule;
@@ -0,0 +1,20 @@
1
+ import { isBotItem } from "./author.mjs";
2
+ const ABOUT_BLOCK = /\n\n<details> <summary>ℹ️ About Codex in GitHub<\/summary>[\s\S]*?<\/details>$/;
3
+ const ENVELOPE = /^### 💡 Codex Review\n\nHere are some automated review suggestions for this pull request\.\n\n\*\*Reviewed commit:\*\* `[a-f0-9]+`$/;
4
+ /**
5
+ * The Codex review summary that only introduces its inline threads. A summary that carries a
6
+ * finding in its own body (for example, a permalink to a line outside the diff) stays visible.
7
+ */
8
+ const rule = (item) => {
9
+ if (!isBotItem(item, ["chatgpt-codex-connector"], ["review-summary"]))
10
+ return null;
11
+ const content = item.body.trim().replace(ABOUT_BLOCK, "").trim();
12
+ if (!ENVELOPE.test(content))
13
+ return null;
14
+ return {
15
+ autoResolve: true,
16
+ suppress: true,
17
+ reason: "Codex review summary that only introduces its inline threads",
18
+ };
19
+ };
20
+ export default rule;
@@ -0,0 +1,4 @@
1
+ import type { ClassifyRule } from "../types.mts";
2
+ /** Dependabot's replies that report no change to make. */
3
+ declare const rule: ClassifyRule;
4
+ export default rule;
@@ -0,0 +1,15 @@
1
+ import { isBotItem } from "./author.mjs";
2
+ const NOTICES = [
3
+ /^Looks like this PR is already up-to-date with [^\s!]+! If you'd still like to recreate it from scratch, overwriting any edits, you can request `@dependabot recreate`\.$/,
4
+ /^Looks like these dependencies are updatable in another way, so this is no longer needed\.$/,
5
+ ];
6
+ /** Dependabot's replies that report no change to make. */
7
+ const rule = (item) => {
8
+ if (!isBotItem(item, ["dependabot"], ["pr-comment"]))
9
+ return null;
10
+ const body = item.body.trim();
11
+ if (!NOTICES.some((notice) => notice.test(body)))
12
+ return null;
13
+ return { autoResolve: true, suppress: true, reason: "Dependabot no-op reply" };
14
+ };
15
+ export default rule;
@@ -0,0 +1,4 @@
1
+ import type { ClassifyRule } from "../types.mts";
2
+ /** Gemini Code Assist daily-quota and review-limit notices. A heading means a real review. */
3
+ declare const rule: ClassifyRule;
4
+ export default rule;
@@ -0,0 +1,13 @@
1
+ import { isBotItem } from "./author.mjs";
2
+ /** Gemini Code Assist daily-quota and review-limit notices. A heading means a real review. */
3
+ const rule = (item) => {
4
+ if (!isBotItem(item, ["gemini-code-assist"], ["pr-comment", "review-summary"]))
5
+ return null;
6
+ if (/^#{1,6}\s/m.test(item.body))
7
+ return null;
8
+ if (!/You have reached your daily quota limit|Review limit reached/i.test(item.body)) {
9
+ return null;
10
+ }
11
+ return { autoResolve: true, suppress: true, reason: "Gemini quota or review-limit notice" };
12
+ };
13
+ export default rule;
@@ -0,0 +1,4 @@
1
+ import type { ClassifyRule } from "../types.mts";
2
+ /** Bundled classification rules that `classify.standard` can enable by name. */
3
+ export declare const STANDARD_RULES: Readonly<Record<string, ClassifyRule>>;
4
+ export declare const STANDARD_RULE_NAMES: readonly string[];
@@ -0,0 +1,22 @@
1
+ import coderabbitNotices from "./coderabbit-notices.mjs";
2
+ import coderabbitReviewSummary from "./coderabbit-review-summary.mjs";
3
+ import codecovReport from "./codecov-report.mjs";
4
+ import codexNotices from "./codex-notices.mjs";
5
+ import codexReviewSummary from "./codex-review-summary.mjs";
6
+ import dependabotNotices from "./dependabot-notices.mjs";
7
+ import geminiNotices from "./gemini-notices.mjs";
8
+ import kiloNoIssues from "./kilo-no-issues.mjs";
9
+ import sourceryNotices from "./sourcery-notices.mjs";
10
+ /** Bundled classification rules that `classify.standard` can enable by name. */
11
+ export const STANDARD_RULES = {
12
+ "coderabbit-notices": coderabbitNotices,
13
+ "coderabbit-review-summary": coderabbitReviewSummary,
14
+ "codecov-report": codecovReport,
15
+ "codex-notices": codexNotices,
16
+ "codex-review-summary": codexReviewSummary,
17
+ "dependabot-notices": dependabotNotices,
18
+ "gemini-notices": geminiNotices,
19
+ "kilo-no-issues": kiloNoIssues,
20
+ "sourcery-notices": sourceryNotices,
21
+ };
22
+ export const STANDARD_RULE_NAMES = Object.keys(STANDARD_RULES);
@@ -0,0 +1,4 @@
1
+ import type { ClassifyRule } from "../types.mts";
2
+ /** Kilo Code's report whose status line reads "No Issues Found" and that carries no findings. */
3
+ declare const rule: ClassifyRule;
4
+ export default rule;
@@ -0,0 +1,17 @@
1
+ import { isBotItem } from "./author.mjs";
2
+ const STATUS_LINE = /^[^\S\n]*(?:\*\*)?Status:?(?:\*\*)?:?[^\S\n]*(?:\p{Extended_Pictographic}️?[^\S\n]*)?No Issues Found\b/imu;
3
+ /** Headings a no-issues report carries; any other heading means real feedback. */
4
+ const REPORT_HEADING = /^(?:Code Review Summary|Files Reviewed\b.*)$/i;
5
+ /** Kilo Code's report whose status line reads "No Issues Found" and that carries no findings. */
6
+ const rule = (item) => {
7
+ if (!isBotItem(item, ["kilo-code-bot"], ["pr-comment", "review-summary"]))
8
+ return null;
9
+ if (!STATUS_LINE.test(item.body))
10
+ return null;
11
+ for (const [, heading] of item.body.matchAll(/^#{1,6}\s+(.*)$/gm)) {
12
+ if (!REPORT_HEADING.test(heading.trim()))
13
+ return null;
14
+ }
15
+ return { autoResolve: true, suppress: true, reason: "Kilo Code no-issues report" };
16
+ };
17
+ export default rule;
@@ -0,0 +1,8 @@
1
+ import type { ClassifyRule } from "../types.mts";
2
+ /**
3
+ * Sourcery's private-repo upsell and weekly rate-limit notices. A real Sourcery review opens
4
+ * with a Markdown heading ("Reviewer's Guide", "Summary by Sourcery"); the notices carry none,
5
+ * so a heading means genuine feedback that merely quotes the phrase.
6
+ */
7
+ declare const rule: ClassifyRule;
8
+ export default rule;
@@ -0,0 +1,20 @@
1
+ import { isBotItem } from "./author.mjs";
2
+ /**
3
+ * Sourcery's private-repo upsell and weekly rate-limit notices. A real Sourcery review opens
4
+ * with a Markdown heading ("Reviewer's Guide", "Summary by Sourcery"); the notices carry none,
5
+ * so a heading means genuine feedback that merely quotes the phrase.
6
+ */
7
+ const rule = (item) => {
8
+ if (!isBotItem(item, ["sourcery-ai"], ["pr-comment", "review-summary"]))
9
+ return null;
10
+ if (/^#{1,6}\s/m.test(item.body))
11
+ return null;
12
+ if (/does not have access to Sourcery/i.test(item.body)) {
13
+ return { autoResolve: true, suppress: true, reason: "Sourcery no-access upsell" };
14
+ }
15
+ if (/reached your weekly rate limit/i.test(item.body)) {
16
+ return { autoResolve: true, suppress: true, reason: "Sourcery rate-limit notice" };
17
+ }
18
+ return null;
19
+ };
20
+ export default rule;
@@ -3,7 +3,9 @@ function resetTime(resetAt) {
3
3
  }
4
4
  function formatResource(resource) {
5
5
  const used = resource.used === undefined ? "" : ` · used ${resource.used}`;
6
- return `- \`${resource.resource}\`: ${resource.remaining}/${resource.limit} remaining${used} · ${resource.requestCount} requests · resets ${resetTime(resource.resetAt)}`;
6
+ const notModified = resource.notModified === undefined ? "" : ` · ${resource.notModified} not modified (304)`;
7
+ const requests = resource.requestCount === undefined ? "" : ` · ${resource.requestCount} requests`;
8
+ return `- \`${resource.resource}\`: ${resource.remaining}/${resource.limit} remaining${used}${requests}${notModified} · resets ${resetTime(resource.resetAt)}`;
7
9
  }
8
10
  export function formatQuotaWarning(warning) {
9
11
  if (warning === undefined)
@@ -46,5 +48,8 @@ export function formatApiUsage(usage) {
46
48
  }
47
49
  for (const resource of usage.rest ?? [])
48
50
  lines.push(formatResource(resource));
51
+ if (usage.unmeteredRestRequestCount !== undefined) {
52
+ lines.push(`- REST requests without rate-limit headers (unmetered): ${usage.unmeteredRestRequestCount}`);
53
+ }
49
54
  return lines.join("\n");
50
55
  }
@@ -0,0 +1,3 @@
1
+ import { type ApplyMergeResult } from "../commands/apply-merge.mts";
2
+ export declare function handleApplyMerge(args: string[]): Promise<void>;
3
+ export declare function formatApplyMergeResult(result: ApplyMergeResult): string;
@@ -0,0 +1,73 @@
1
+ import { EXIT, ShepherdError, errorToExitCode } from "../exit-codes.mjs";
2
+ import { runApplyMerge } from "../commands/apply-merge.mjs";
3
+ import { getFlag, parseCommonArgs } from "./args.mjs";
4
+ import { maybePrintHelp, USAGE } from "./help.mjs";
5
+ const flags = new Set(["--require-sha", "--merge-action", "--method", "--expected-stack"]);
6
+ export async function handleApplyMerge(args) {
7
+ if (maybePrintHelp(args, "apply merge"))
8
+ return;
9
+ try {
10
+ const { prNumber, global, extra } = parseCommonArgs(args);
11
+ for (let index = 0; index < extra.length; index += 1) {
12
+ const arg = extra[index];
13
+ const name = arg.split("=", 1)[0];
14
+ if (!flags.has(name))
15
+ throw new ShepherdError(`Unknown apply merge argument: ${arg}`, EXIT.USAGE);
16
+ if (!arg.includes("=")) {
17
+ if (!extra[index + 1] || extra[index + 1].startsWith("--"))
18
+ throw new ShepherdError(`${name} requires a value`, EXIT.USAGE);
19
+ index += 1;
20
+ }
21
+ }
22
+ const requireSha = getFlag(extra, "--require-sha");
23
+ const mergeAction = getFlag(extra, "--merge-action");
24
+ if (requireSha === null || mergeAction === null) {
25
+ process.stderr.write(`${USAGE["apply merge"]}\n`);
26
+ process.exitCode = EXIT.USAGE;
27
+ return;
28
+ }
29
+ const result = await runApplyMerge({
30
+ prNumber,
31
+ targetRepository: global.targetRepository,
32
+ requireSha,
33
+ mergeAction: mergeAction,
34
+ mergeMethod: (getFlag(extra, "--method") ?? undefined),
35
+ expectedStack: parseExpectedStack(getFlag(extra, "--expected-stack")),
36
+ });
37
+ process.stdout.write(`${global.format === "json" ? JSON.stringify(result, null, 2) : formatApplyMergeResult(result)}\n`);
38
+ process.exitCode =
39
+ result.status === "pending"
40
+ ? EXIT.WAIT
41
+ : result.status === "failed"
42
+ ? result.uncertain
43
+ ? EXIT.TEMPFAIL
44
+ : EXIT.UNAVAILABLE
45
+ : EXIT.OK;
46
+ }
47
+ catch (error) {
48
+ process.stderr.write(`pr-shepherd: apply merge: ${error instanceof Error ? error.message : String(error)}\n`);
49
+ process.exitCode = errorToExitCode(error);
50
+ }
51
+ }
52
+ function parseExpectedStack(raw) {
53
+ if (raw === null)
54
+ return undefined;
55
+ try {
56
+ return JSON.parse(raw);
57
+ }
58
+ catch {
59
+ throw new ShepherdError("--expected-stack must be valid JSON", EXIT.DATAERR);
60
+ }
61
+ }
62
+ export function formatApplyMergeResult(result) {
63
+ const lines = [`PR: ${result.repo}#${result.pr}`, `status: ${result.status}`];
64
+ if (result.uncertain)
65
+ lines.push("uncertain: true");
66
+ if (result.note)
67
+ lines.push(`note: ${result.note}`);
68
+ for (const [name, value] of Object.entries(result.details)) {
69
+ if (value !== undefined)
70
+ lines.push(`- ${name}: ${typeof value === "string" ? value : JSON.stringify(value)}`);
71
+ }
72
+ return lines.join("\n");
73
+ }
@@ -0,0 +1,2 @@
1
+ export declare const FLAGS_WITH_VALUES: Set<string>;
2
+ export declare const BOOLEAN_FLAGS: Set<string>;
@@ -0,0 +1,47 @@
1
+ // Flags that consume the next argument as their value (used for PR-number
2
+ // detection only — prevents a flag's value from being mistaken for a PR number).
3
+ export const FLAGS_WITH_VALUES = new Set([
4
+ "--transport",
5
+ "--merge-action",
6
+ "--method",
7
+ "--format",
8
+ "--ready-delay",
9
+ "--stall-timeout",
10
+ "--instructions",
11
+ "--poll-mode",
12
+ "--require-sha",
13
+ "--message",
14
+ "--description",
15
+ "--body-file",
16
+ "--file",
17
+ "--stack",
18
+ "--thread-id",
19
+ "--resolve-thread-ids",
20
+ "--reply-thread-ids",
21
+ "--minimize-comment-ids",
22
+ "--dismiss-review-ids",
23
+ "--interval",
24
+ "--timeout",
25
+ "--debounce",
26
+ "--match",
27
+ "--check",
28
+ "--blocked-by",
29
+ "--queue-commit",
30
+ "--removed-at",
31
+ ]);
32
+ // Boolean flags that do NOT consume the next argument. Any --flag not in this
33
+ // set and not in FLAGS_WITH_VALUES is treated conservatively as value-taking
34
+ // for PR-number detection — so removed flags don't silently cause their
35
+ // numeric value to be misidentified as the PR number.
36
+ export const BOOLEAN_FLAGS = new Set([
37
+ "--no-auto-mark-ready",
38
+ "--no-auto-cancel-actionable",
39
+ "--quiet-status",
40
+ "--no-quiet-status",
41
+ "--until-terminal",
42
+ "--merge",
43
+ "--dry-run",
44
+ "--verbose",
45
+ "--clear",
46
+ "--adopt-existing-replies",
47
+ ]);
package/bin/cli/args.mjs CHANGED
@@ -3,45 +3,8 @@
3
3
  */
4
4
  import { parseArgs } from "node:util";
5
5
  import { parseCliPrReference, resolveParsedPrTarget } from "../pr-reference.mjs";
6
- // Flags that consume the next argument as their value (used for PR-number
7
- // detection only — prevents a flag's value from being mistaken for a PR number).
8
- const FLAGS_WITH_VALUES = new Set([
9
- "--format",
10
- "--ready-delay",
11
- "--stall-timeout",
12
- "--require-sha",
13
- "--message",
14
- "--description",
15
- "--thread-id",
16
- "--resolve-thread-ids",
17
- "--reply-thread-ids",
18
- "--minimize-comment-ids",
19
- "--dismiss-review-ids",
20
- "--interval",
21
- "--timeout",
22
- "--debounce",
23
- "--match",
24
- "--check",
25
- "--blocked-by",
26
- "--require-sha",
27
- "--queue-commit",
28
- "--removed-at",
29
- ]);
30
- // Boolean flags that do NOT consume the next argument. Any --flag not in this
31
- // set and not in FLAGS_WITH_VALUES is treated conservatively as value-taking
32
- // for PR-number detection — so removed flags don't silently cause their
33
- // numeric value to be misidentified as the PR number.
34
- const BOOLEAN_FLAGS = new Set([
35
- "--no-auto-mark-ready",
36
- "--no-auto-cancel-actionable",
37
- "--quiet-status",
38
- "--no-quiet-status",
39
- "--until-terminal",
40
- "--merge",
41
- "--dry-run",
42
- "--verbose",
43
- "--clear",
44
- ]);
6
+ import { parseGithubTransport } from "../github/transport-mode.mjs";
7
+ import { FLAGS_WITH_VALUES, BOOLEAN_FLAGS } from "./arg-flags.mjs";
45
8
  // ---------------------------------------------------------------------------
46
9
  // Strict integer parsing
47
10
  // ---------------------------------------------------------------------------
@@ -58,7 +21,9 @@ export function parseCommonArgs(args) {
58
21
  allowPositionals: true,
59
22
  tokens: true,
60
23
  options: {
24
+ ...Object.fromEntries([...FLAGS_WITH_VALUES].map((flag) => [flag.slice(2), { type: "string" }])),
61
25
  format: { type: "string" },
26
+ transport: { type: "string" },
62
27
  verbose: { type: "boolean" },
63
28
  },
64
29
  });
@@ -68,11 +33,12 @@ export function parseCommonArgs(args) {
68
33
  // them from `extra`. Subcommand-specific flags are left untouched.
69
34
  const consumedIndices = new Set();
70
35
  for (const tok of tokens ?? []) {
71
- if (tok.kind === "option" && (tok.name === "format" || tok.name === "verbose")) {
36
+ if (tok.kind === "option" &&
37
+ (tok.name === "format" || tok.name === "verbose" || tok.name === "transport")) {
72
38
  consumedIndices.add(tok.index);
73
39
  // When the value is a separate arg (--flag value, not --flag=value),
74
40
  // inlineValue is false and the value occupies tok.index + 1.
75
- if (tok.name === "format" &&
41
+ if ((tok.name === "format" || tok.name === "transport") &&
76
42
  "inlineValue" in tok &&
77
43
  tok.inlineValue === false &&
78
44
  tok.value != null) {
@@ -122,6 +88,9 @@ export function parseCommonArgs(args) {
122
88
  global: {
123
89
  format,
124
90
  verbose,
91
+ ...(values.transport !== undefined
92
+ ? { transport: parseGithubTransport(values.transport) }
93
+ : {}),
125
94
  ...(target.targetRepository !== undefined
126
95
  ? { targetRepository: target.targetRepository }
127
96
  : undefined),
@@ -0,0 +1 @@
1
+ export declare function handleClean(args: string[], command?: "admin clean" | "clean"): Promise<void>;
@@ -0,0 +1,71 @@
1
+ import { runClean } from "../commands/clean.mjs";
2
+ import { EXIT } from "../exit-codes.mjs";
3
+ import { USAGE } from "./help.mjs";
4
+ import { formatCleanResult } from "./formatters.mjs";
5
+ import { rejectInvalidPollModeFlag, runInPollModeScope } from "./event-state-scope.mjs";
6
+ const CLEAN_VARIANTS = new Set(["pr", "branch", "current", "repo", "all"]);
7
+ export async function handleClean(args, command = "admin clean") {
8
+ const usage = command === "admin clean" ? USAGE["admin clean"] : USAGE.clean;
9
+ const variant = args[0];
10
+ if (!variant || !CLEAN_VARIANTS.has(variant)) {
11
+ process.stderr.write(`${usage}\n`);
12
+ process.exitCode = EXIT.USAGE;
13
+ return;
14
+ }
15
+ const rest = args.slice(1);
16
+ for (const a of rest) {
17
+ if (!a.startsWith("--"))
18
+ continue;
19
+ if (a === "--dry-run" || a === "--format" || a.startsWith("--format="))
20
+ continue;
21
+ if (a === "--poll-mode" || a.startsWith("--poll-mode="))
22
+ continue;
23
+ process.stderr.write(`pr-shepherd: ${command}: unknown flag: "${a}"\n`);
24
+ process.exitCode = EXIT.USAGE;
25
+ return;
26
+ }
27
+ const fmtIdx = rest.indexOf("--format");
28
+ const fmtEqEntry = rest.find((a) => a.startsWith("--format="));
29
+ let formatValue;
30
+ if (fmtEqEntry !== undefined) {
31
+ formatValue = fmtEqEntry.slice("--format=".length);
32
+ }
33
+ else if (fmtIdx !== -1 && fmtIdx + 1 < rest.length && !rest[fmtIdx + 1].startsWith("--")) {
34
+ formatValue = rest[fmtIdx + 1];
35
+ }
36
+ if (formatValue !== undefined && formatValue !== "text" && formatValue !== "json") {
37
+ process.stderr.write(`pr-shepherd: ${command}: invalid --format value: "${formatValue}". Expected "text" or "json".\n`);
38
+ process.exitCode = EXIT.USAGE;
39
+ return;
40
+ }
41
+ if (rejectInvalidPollModeFlag(rest, command))
42
+ return;
43
+ const jsonOut = formatValue === "json";
44
+ const dryRun = rest.includes("--dry-run");
45
+ // Skip values consumed by --format <value> / --poll-mode <value> so they aren't positionals.
46
+ const flagConsumedIndices = new Set();
47
+ if (fmtIdx !== -1 && fmtIdx + 1 < rest.length && !rest[fmtIdx + 1].startsWith("--")) {
48
+ flagConsumedIndices.add(fmtIdx);
49
+ flagConsumedIndices.add(fmtIdx + 1);
50
+ }
51
+ const pollModeIdx = rest.indexOf("--poll-mode");
52
+ if (pollModeIdx !== -1) {
53
+ flagConsumedIndices.add(pollModeIdx);
54
+ flagConsumedIndices.add(pollModeIdx + 1);
55
+ }
56
+ const positionals = rest.filter((a, i) => !flagConsumedIndices.has(i) && !a.startsWith("--"));
57
+ if (positionals.length > 1) {
58
+ process.stderr.write(`pr-shepherd: ${command}: too many positional arguments (expected at most 1, got ${positionals.length})\n`);
59
+ process.exitCode = EXIT.USAGE;
60
+ return;
61
+ }
62
+ const value = positionals[0];
63
+ // Event mode keeps its state under the durable state base; clean must target that same scope.
64
+ const result = await runInPollModeScope(rest, () => runClean({ variant: variant, value, dryRun }));
65
+ if (!result.ok) {
66
+ process.stderr.write(`pr-shepherd: ${command}: ${result.error}\n`);
67
+ process.exitCode = EXIT.SOFTWARE;
68
+ return;
69
+ }
70
+ process.stdout.write(jsonOut ? `${JSON.stringify(result, null, 2)}\n` : `${formatCleanResult(result)}\n`);
71
+ }
@@ -3,9 +3,12 @@ import { parsePrNumber } from "./args.mjs";
3
3
  import { validateDefaultArgs } from "./validate-default-args.mjs";
4
4
  import { USAGE } from "./help.mjs";
5
5
  const DEFAULT_POLL_FLAGS_WITH_VALUES = new Set([
6
+ "--transport",
6
7
  "--format",
7
8
  "--ready-delay",
8
9
  "--stall-timeout",
10
+ "--instructions",
11
+ "--poll-mode",
9
12
  "--interval",
10
13
  "--timeout",
11
14
  "--debounce",