pr-shepherd 0.56.6 → 0.57.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (421) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +150 -280
  3. package/bin/api.d.mts +25 -3
  4. package/bin/api.mjs +51 -13
  5. package/bin/checks/classify.d.mts +1 -0
  6. package/bin/checks/classify.mjs +1 -1
  7. package/bin/checks/conclusions.d.mts +5 -1
  8. package/bin/checks/conclusions.mjs +8 -2
  9. package/bin/checks/superseded.d.mts +8 -2
  10. package/bin/checks/superseded.mjs +24 -7
  11. package/bin/classify/loader.d.mts +2 -0
  12. package/bin/classify/loader.mjs +15 -0
  13. package/bin/classify/standard/author.d.mts +3 -0
  14. package/bin/classify/standard/author.mjs +10 -0
  15. package/bin/classify/standard/codecov-report.d.mts +4 -0
  16. package/bin/classify/standard/codecov-report.mjs +10 -0
  17. package/bin/classify/standard/coderabbit-notices.d.mts +8 -0
  18. package/bin/classify/standard/coderabbit-notices.mjs +38 -0
  19. package/bin/classify/standard/codex-notices.d.mts +8 -0
  20. package/bin/classify/standard/codex-notices.mjs +34 -0
  21. package/bin/classify/standard/dependabot-notices.d.mts +4 -0
  22. package/bin/classify/standard/dependabot-notices.mjs +15 -0
  23. package/bin/classify/standard/gemini-notices.d.mts +4 -0
  24. package/bin/classify/standard/gemini-notices.mjs +13 -0
  25. package/bin/classify/standard/index.d.mts +7 -0
  26. package/bin/classify/standard/index.mjs +21 -0
  27. package/bin/classify/standard/kilo-no-issues.d.mts +4 -0
  28. package/bin/classify/standard/kilo-no-issues.mjs +17 -0
  29. package/bin/classify/standard/sourcery-notices.d.mts +8 -0
  30. package/bin/classify/standard/sourcery-notices.mjs +20 -0
  31. package/bin/cli/api-usage-formatter.mjs +6 -1
  32. package/bin/cli/apply-merge-handler.d.mts +3 -0
  33. package/bin/cli/apply-merge-handler.mjs +73 -0
  34. package/bin/cli/arg-flags.d.mts +2 -0
  35. package/bin/cli/arg-flags.mjs +47 -0
  36. package/bin/cli/args.mjs +10 -41
  37. package/bin/cli/clean-handler.d.mts +1 -0
  38. package/bin/cli/clean-handler.mjs +71 -0
  39. package/bin/cli/default-poll.mjs +3 -0
  40. package/bin/cli/event-state-scope.d.mts +19 -0
  41. package/bin/cli/event-state-scope.mjs +60 -0
  42. package/bin/cli/fix-formatter.mjs +5 -11
  43. package/bin/cli/handlers.d.mts +0 -1
  44. package/bin/cli/handlers.mjs +8 -64
  45. package/bin/cli/help-command-pages.d.mts +62 -18
  46. package/bin/cli/help-command-pages.mjs +59 -15
  47. package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
  48. package/bin/cli/help-iterate-poll-pages.mjs +6 -0
  49. package/bin/cli/help-log-file-page.d.mts +1 -1
  50. package/bin/cli/help-log-file-page.mjs +4 -1
  51. package/bin/cli/help-top-page.d.mts +1 -1
  52. package/bin/cli/help-top-page.mjs +5 -0
  53. package/bin/cli/help.d.mts +63 -19
  54. package/bin/cli/help.mjs +2 -0
  55. package/bin/cli/iterate-branch-segment.d.mts +2 -0
  56. package/bin/cli/iterate-branch-segment.mjs +12 -7
  57. package/bin/cli/iterate-flags.d.mts +7 -1
  58. package/bin/cli/iterate-flags.mjs +38 -0
  59. package/bin/cli/iterate-formatter.d.mts +6 -6
  60. package/bin/cli/iterate-formatter.mjs +56 -22
  61. package/bin/cli/iterate-instructions.mjs +45 -15
  62. package/bin/cli/iterate-lean.mjs +39 -14
  63. package/bin/cli/iterate-merge-formatter.d.mts +6 -0
  64. package/bin/cli/iterate-merge-formatter.mjs +24 -14
  65. package/bin/cli/iterate-verbose.mjs +3 -6
  66. package/bin/cli/list-formatters.mjs +3 -1
  67. package/bin/cli/mutate-formatter.mjs +10 -5
  68. package/bin/cli/next-check-format.d.mts +7 -0
  69. package/bin/cli/next-check-format.mjs +10 -0
  70. package/bin/cli/playbook-handler.d.mts +5 -0
  71. package/bin/cli/playbook-handler.mjs +40 -0
  72. package/bin/cli/poll-handler.mjs +7 -6
  73. package/bin/cli/poll-summary-formatter.mjs +11 -2
  74. package/bin/cli/poll-targets.mjs +2 -0
  75. package/bin/cli/resolve-validators.mjs +2 -2
  76. package/bin/cli/runner.mjs +6 -1
  77. package/bin/cli/stack-layer-view.d.mts +33 -0
  78. package/bin/cli/stack-layer-view.mjs +1 -0
  79. package/bin/cli/stack-overview.d.mts +10 -28
  80. package/bin/cli/stack-overview.mjs +39 -14
  81. package/bin/cli/transport-args.d.mts +5 -0
  82. package/bin/cli/transport-args.mjs +23 -0
  83. package/bin/cli/transport-formatter.d.mts +9 -0
  84. package/bin/cli/transport-formatter.mjs +13 -0
  85. package/bin/cli-parser.mjs +62 -7
  86. package/bin/commands/apply-merge-options.d.mts +4 -0
  87. package/bin/commands/apply-merge-options.mjs +34 -0
  88. package/bin/commands/apply-merge-output.d.mts +7 -0
  89. package/bin/commands/apply-merge-output.mjs +20 -0
  90. package/bin/commands/apply-merge-pull.d.mts +20 -0
  91. package/bin/commands/apply-merge-pull.mjs +15 -0
  92. package/bin/commands/apply-merge.d.mts +18 -0
  93. package/bin/commands/apply-merge.mjs +126 -0
  94. package/bin/commands/apply-queue-removal.mjs +7 -0
  95. package/bin/commands/check-annotations.mjs +28 -18
  96. package/bin/commands/check-execution-context.d.mts +5 -0
  97. package/bin/commands/check-execution-context.mjs +16 -1
  98. package/bin/commands/check-fingerprint.d.mts +26 -2
  99. package/bin/commands/check-fingerprint.mjs +64 -28
  100. package/bin/commands/check-terminal-report.mjs +11 -1
  101. package/bin/commands/check-unreported.d.mts +6 -2
  102. package/bin/commands/check-unreported.mjs +32 -12
  103. package/bin/commands/check-wait-detectors.d.mts +35 -0
  104. package/bin/commands/check-wait-detectors.mjs +107 -0
  105. package/bin/commands/check.d.mts +4 -2
  106. package/bin/commands/check.mjs +130 -40
  107. package/bin/commands/event-instructions.d.mts +11 -0
  108. package/bin/commands/event-instructions.mjs +27 -0
  109. package/bin/commands/event-mode.d.mts +14 -0
  110. package/bin/commands/event-mode.mjs +138 -0
  111. package/bin/commands/iterate/api-usage.mjs +4 -2
  112. package/bin/commands/iterate/base.mjs +4 -0
  113. package/bin/commands/iterate/check-blocker-gate.mjs +14 -2
  114. package/bin/commands/iterate/check-instructions.d.mts +9 -10
  115. package/bin/commands/iterate/check-instructions.mjs +23 -22
  116. package/bin/commands/iterate/classify.mjs +19 -5
  117. package/bin/commands/iterate/escalate.mjs +13 -3
  118. package/bin/commands/iterate/fix-code.mjs +26 -9
  119. package/bin/commands/iterate/fix-instruction-threads.d.mts +0 -8
  120. package/bin/commands/iterate/fix-instruction-threads.mjs +0 -16
  121. package/bin/commands/iterate/fix-loop-instruction.d.mts +9 -0
  122. package/bin/commands/iterate/fix-loop-instruction.mjs +35 -0
  123. package/bin/commands/iterate/helpers.mjs +15 -2
  124. package/bin/commands/iterate/index.mjs +57 -16
  125. package/bin/commands/iterate/mark-ready.mjs +50 -10
  126. package/bin/commands/iterate/merge-plan.d.mts +19 -0
  127. package/bin/commands/iterate/merge-plan.mjs +88 -0
  128. package/bin/commands/iterate/merge-state.mjs +3 -0
  129. package/bin/commands/iterate/merge.d.mts +4 -15
  130. package/bin/commands/iterate/merge.mjs +18 -51
  131. package/bin/commands/iterate/merged-base-pull-requests.d.mts +2 -6
  132. package/bin/commands/iterate/merged-base-pull-requests.mjs +15 -11
  133. package/bin/commands/iterate/native-stack-rebase.mjs +11 -0
  134. package/bin/commands/iterate/render.d.mts +8 -2
  135. package/bin/commands/iterate/render.mjs +28 -42
  136. package/bin/commands/iterate/stack-trunk-conflict.mjs +17 -1
  137. package/bin/commands/iterate/stale-ancestry.mjs +4 -1
  138. package/bin/commands/iterate/stall.d.mts +5 -1
  139. package/bin/commands/iterate/stall.mjs +19 -7
  140. package/bin/commands/iterate/thread-mutation-routing.d.mts +1 -0
  141. package/bin/commands/iterate/thread-mutation-routing.mjs +4 -2
  142. package/bin/commands/iterate/unreported-required.mjs +5 -2
  143. package/bin/commands/mark-files-as-viewed.mjs +7 -0
  144. package/bin/commands/next-check.d.mts +31 -0
  145. package/bin/commands/next-check.mjs +46 -0
  146. package/bin/commands/playbook.d.mts +13 -0
  147. package/bin/commands/playbook.mjs +48 -0
  148. package/bin/commands/poll-mode.d.mts +8 -0
  149. package/bin/commands/poll-mode.mjs +14 -0
  150. package/bin/commands/poll-progress.d.mts +1 -0
  151. package/bin/commands/poll-progress.mjs +6 -3
  152. package/bin/commands/poll-quota.d.mts +3 -2
  153. package/bin/commands/poll-quota.mjs +7 -3
  154. package/bin/commands/poll-summary-explicit-instructions.d.mts +2 -0
  155. package/bin/commands/poll-summary-explicit-instructions.mjs +10 -1
  156. package/bin/commands/poll-summary-instructions.mjs +16 -17
  157. package/bin/commands/poll-summary.mjs +42 -17
  158. package/bin/commands/poll.d.mts +0 -1
  159. package/bin/commands/poll.mjs +11 -19
  160. package/bin/commands/quota-selection.d.mts +2 -1
  161. package/bin/commands/quota-selection.mjs +12 -7
  162. package/bin/commands/resolve-mutate.mjs +33 -5
  163. package/bin/commands/rest-stack-merge-readiness.d.mts +4 -0
  164. package/bin/commands/rest-stack-merge-readiness.mjs +74 -0
  165. package/bin/commands/rule-auto-resolve.mjs +9 -3
  166. package/bin/commands/shepherd-journal.d.mts +5 -4
  167. package/bin/commands/shepherd-journal.mjs +9 -8
  168. package/bin/commands/stack-drain.d.mts +1 -9
  169. package/bin/commands/stack-drain.mjs +50 -37
  170. package/bin/commands/stack-handoffs.d.mts +10 -0
  171. package/bin/commands/stack-handoffs.mjs +25 -0
  172. package/bin/commands/stack-stall.d.mts +5 -0
  173. package/bin/commands/stack-stall.mjs +11 -0
  174. package/bin/commands/stack-work.d.mts +5 -0
  175. package/bin/commands/stack-work.mjs +32 -0
  176. package/bin/comments/existing-reply-scan.d.mts +17 -0
  177. package/bin/comments/existing-reply-scan.mjs +41 -0
  178. package/bin/comments/rate-limit.mjs +2 -2
  179. package/bin/comments/resolve.d.mts +7 -1
  180. package/bin/comments/resolve.mjs +108 -18
  181. package/bin/comments/rest-reply.d.mts +9 -0
  182. package/bin/comments/rest-reply.mjs +95 -0
  183. package/bin/comments/rest-review-mutations.d.mts +22 -0
  184. package/bin/comments/rest-review-mutations.mjs +125 -0
  185. package/bin/comments/review-visibility.d.mts +1 -1
  186. package/bin/comments/review-visibility.mjs +3 -2
  187. package/bin/comments/sha-poll.mjs +7 -3
  188. package/bin/comments/thread-visibility.mjs +10 -5
  189. package/bin/comments/uncertain-replies.d.mts +11 -0
  190. package/bin/comments/uncertain-replies.mjs +121 -0
  191. package/bin/comments/uncertain-reply-guards.d.mts +10 -0
  192. package/bin/comments/uncertain-reply-guards.mjs +94 -0
  193. package/bin/comments/visible-comments.d.mts +1 -1
  194. package/bin/comments/visible-comments.mjs +4 -2
  195. package/bin/config/load.d.mts +37 -1
  196. package/bin/config/load.mjs +73 -1
  197. package/bin/config.json +6 -2
  198. package/bin/exit-codes.d.mts +3 -0
  199. package/bin/exit-codes.mjs +8 -0
  200. package/bin/github/api-telemetry-aggregate.d.mts +15 -4
  201. package/bin/github/api-telemetry-aggregate.mjs +57 -18
  202. package/bin/github/api-telemetry.d.mts +4 -0
  203. package/bin/github/api-telemetry.mjs +22 -8
  204. package/bin/github/apply-review-preflight.d.mts +20 -0
  205. package/bin/github/apply-review-preflight.mjs +61 -0
  206. package/bin/github/base-behind-cache.d.mts +15 -0
  207. package/bin/github/base-behind-cache.mjs +18 -0
  208. package/bin/github/batch-parse-suites.d.mts +4 -2
  209. package/bin/github/batch-parse-suites.mjs +6 -1
  210. package/bin/github/batch-parser-helpers.mjs +40 -2
  211. package/bin/github/batch-parsers.mjs +1 -0
  212. package/bin/github/batch-raw-rules.d.mts +26 -0
  213. package/bin/github/batch-raw-types.d.mts +8 -6
  214. package/bin/github/batch-stack-evidence.d.mts +28 -0
  215. package/bin/github/batch-stack-evidence.mjs +62 -0
  216. package/bin/github/batch.d.mts +15 -2
  217. package/bin/github/batch.mjs +34 -17
  218. package/bin/github/captured-proxy-agent.d.mts +3 -0
  219. package/bin/github/captured-proxy-agent.mjs +8 -0
  220. package/bin/github/check-annotations-batch.d.mts +0 -5
  221. package/bin/github/check-annotations-batch.mjs +25 -4
  222. package/bin/github/check-annotations.mjs +3 -1
  223. package/bin/github/client.d.mts +8 -19
  224. package/bin/github/client.mjs +45 -13
  225. package/bin/github/fingerprint-fields.d.mts +8 -0
  226. package/bin/github/fingerprint-fields.mjs +6 -1
  227. package/bin/github/fingerprint.d.mts +4 -2
  228. package/bin/github/fingerprint.mjs +6 -38
  229. package/bin/github/github-fetch.d.mts +2 -0
  230. package/bin/github/github-fetch.mjs +32 -0
  231. package/bin/github/gql/base-behind.gql +3 -0
  232. package/bin/github/gql/batch-pr-page.gql +16 -0
  233. package/bin/github/gql/batch-pr.gql +57 -0
  234. package/bin/github/gql/commit-check-contexts.gql +17 -0
  235. package/bin/github/gql/get-pr-body.gql +1 -0
  236. package/bin/github/gql/poll-stack-summary.gql +1 -0
  237. package/bin/github/gql/poll-summary-check-contexts.gql +5 -0
  238. package/bin/github/gql/poll-summary-fragment.gql +65 -15
  239. package/bin/github/gql/stack-handoff-check-runs.gql +42 -0
  240. package/bin/github/graphql-http.mjs +9 -4
  241. package/bin/github/graphql-internal-retry.d.mts +2 -0
  242. package/bin/github/graphql-internal-retry.mjs +1 -1
  243. package/bin/github/graphql-quota-probe.d.mts +6 -0
  244. package/bin/github/graphql-quota-probe.mjs +56 -0
  245. package/bin/github/graphql-session-refusal.d.mts +8 -0
  246. package/bin/github/graphql-session-refusal.mjs +14 -0
  247. package/bin/github/http-request.d.mts +1 -1
  248. package/bin/github/http-request.mjs +22 -6
  249. package/bin/github/http-utils.mjs +6 -0
  250. package/bin/github/legacy-dispatcher.d.mts +6 -0
  251. package/bin/github/legacy-dispatcher.mjs +44 -0
  252. package/bin/github/merge-target-rules.d.mts +12 -3
  253. package/bin/github/merge-target-rules.mjs +71 -34
  254. package/bin/github/mutation-policy.d.mts +6 -0
  255. package/bin/github/mutation-policy.mjs +21 -0
  256. package/bin/github/poll-summary-annotation-probe.mjs +17 -10
  257. package/bin/github/poll-summary-check-blockers.d.mts +1 -1
  258. package/bin/github/poll-summary-check-blockers.mjs +2 -2
  259. package/bin/github/poll-summary-check-hydration.mjs +25 -10
  260. package/bin/github/poll-summary-checks.d.mts +2 -2
  261. package/bin/github/poll-summary-checks.mjs +9 -6
  262. package/bin/github/poll-summary-command.d.mts +2 -0
  263. package/bin/github/poll-summary-command.mjs +24 -0
  264. package/bin/github/poll-summary-fingerprint.d.mts +1 -1
  265. package/bin/github/poll-summary-fingerprint.mjs +4 -2
  266. package/bin/github/poll-summary-handoff-fields.d.mts +3 -0
  267. package/bin/github/poll-summary-handoff-fields.mjs +73 -0
  268. package/bin/github/poll-summary-projector.d.mts +1 -1
  269. package/bin/github/poll-summary-projector.mjs +17 -24
  270. package/bin/github/poll-summary-raw.d.mts +70 -10
  271. package/bin/github/poll-summary-readiness.d.mts +6 -1
  272. package/bin/github/poll-summary-readiness.mjs +13 -4
  273. package/bin/github/poll-summary-rest-queue.d.mts +3 -0
  274. package/bin/github/poll-summary-rest-queue.mjs +12 -0
  275. package/bin/github/poll-summary-review.d.mts +1 -1
  276. package/bin/github/poll-summary-review.mjs +35 -20
  277. package/bin/github/poll-summary-route.mjs +19 -3
  278. package/bin/github/poll-summary-stack-page.d.mts +11 -0
  279. package/bin/github/poll-summary-stack-page.mjs +27 -0
  280. package/bin/github/poll-summary-unreported.d.mts +3 -1
  281. package/bin/github/poll-summary-unreported.mjs +6 -3
  282. package/bin/github/poll-summary.d.mts +4 -1
  283. package/bin/github/poll-summary.mjs +47 -33
  284. package/bin/github/queries.d.mts +7 -3
  285. package/bin/github/queries.mjs +8 -4
  286. package/bin/github/rate-limit-sample.d.mts +7 -0
  287. package/bin/github/rate-limit-sample.mjs +12 -0
  288. package/bin/github/reply-recovery-read.d.mts +50 -0
  289. package/bin/github/reply-recovery-read.mjs +118 -0
  290. package/bin/github/reply-thread-transcripts.d.mts +0 -1
  291. package/bin/github/reply-thread-transcripts.mjs +24 -1
  292. package/bin/github/rest-annotation-read.d.mts +5 -0
  293. package/bin/github/rest-annotation-read.mjs +44 -0
  294. package/bin/github/rest-batch-read.d.mts +12 -0
  295. package/bin/github/rest-batch-read.mjs +57 -0
  296. package/bin/github/rest-batch-snapshot.d.mts +30 -0
  297. package/bin/github/rest-batch-snapshot.mjs +115 -0
  298. package/bin/github/rest-batch-unavailable.d.mts +5 -0
  299. package/bin/github/rest-batch-unavailable.mjs +16 -0
  300. package/bin/github/rest-check-read.d.mts +34 -0
  301. package/bin/github/rest-check-read.mjs +124 -0
  302. package/bin/github/rest-comment-authorship.d.mts +7 -0
  303. package/bin/github/rest-comment-authorship.mjs +11 -0
  304. package/bin/github/rest-conditional-scope.d.mts +20 -0
  305. package/bin/github/rest-conditional-scope.mjs +44 -0
  306. package/bin/github/rest-explicit-summary-read.d.mts +3 -0
  307. package/bin/github/rest-explicit-summary-read.mjs +8 -0
  308. package/bin/github/rest-feedback-read.d.mts +36 -0
  309. package/bin/github/rest-feedback-read.mjs +147 -0
  310. package/bin/github/rest-feedback-validation.d.mts +5 -0
  311. package/bin/github/rest-feedback-validation.mjs +28 -0
  312. package/bin/github/rest-http.d.mts +12 -0
  313. package/bin/github/rest-http.mjs +108 -23
  314. package/bin/github/rest-identities.d.mts +22 -0
  315. package/bin/github/rest-identities.mjs +134 -0
  316. package/bin/github/rest-merge-stack-guard.d.mts +14 -0
  317. package/bin/github/rest-merge-stack-guard.mjs +41 -0
  318. package/bin/github/rest-merge.d.mts +29 -0
  319. package/bin/github/rest-merge.mjs +56 -0
  320. package/bin/github/rest-merged-base-read.d.mts +9 -0
  321. package/bin/github/rest-merged-base-read.mjs +48 -0
  322. package/bin/github/rest-pr-core.d.mts +52 -0
  323. package/bin/github/rest-pr-core.mjs +60 -0
  324. package/bin/github/rest-reader-core.d.mts +16 -0
  325. package/bin/github/rest-reader-core.mjs +154 -0
  326. package/bin/github/rest-review-read.d.mts +11 -0
  327. package/bin/github/rest-review-read.mjs +47 -0
  328. package/bin/github/rest-rules-read.d.mts +9 -0
  329. package/bin/github/rest-rules-read.mjs +154 -0
  330. package/bin/github/rest-session-refusal.d.mts +5 -0
  331. package/bin/github/rest-session-refusal.mjs +21 -0
  332. package/bin/github/rest-snapshot-context.d.mts +10 -0
  333. package/bin/github/rest-snapshot-context.mjs +1 -0
  334. package/bin/github/rest-stack-read.d.mts +21 -0
  335. package/bin/github/rest-stack-read.mjs +47 -0
  336. package/bin/github/rest-stack-summary.d.mts +8 -0
  337. package/bin/github/rest-stack-summary.mjs +62 -0
  338. package/bin/github/rest-summary-read.d.mts +7 -0
  339. package/bin/github/rest-summary-read.mjs +112 -0
  340. package/bin/github/rest-terminal-batch.d.mts +14 -0
  341. package/bin/github/rest-terminal-batch.mjs +45 -0
  342. package/bin/github/rest-text.mjs +7 -3
  343. package/bin/github/rest-thread-read.d.mts +4 -0
  344. package/bin/github/rest-thread-read.mjs +35 -0
  345. package/bin/github/rest-viewer-read.d.mts +2 -0
  346. package/bin/github/rest-viewer-read.mjs +41 -0
  347. package/bin/github/stack-bottom.d.mts +3 -0
  348. package/bin/github/stack-bottom.mjs +14 -0
  349. package/bin/github/stack-handoff-context.d.mts +25 -0
  350. package/bin/github/stack-handoff-context.mjs +12 -0
  351. package/bin/github/stack-handoff-page.d.mts +17 -0
  352. package/bin/github/stack-handoff-page.mjs +306 -0
  353. package/bin/github/stack-handoff.d.mts +16 -0
  354. package/bin/github/stack-handoff.mjs +115 -0
  355. package/bin/github/stack-order.d.mts +6 -0
  356. package/bin/github/stack-order.mjs +13 -0
  357. package/bin/github/stack-read.d.mts +7 -5
  358. package/bin/github/stack-read.mjs +22 -24
  359. package/bin/github/stack-size-hint.d.mts +3 -0
  360. package/bin/github/stack-size-hint.mjs +14 -0
  361. package/bin/github/suggestion-thread.mjs +27 -1
  362. package/bin/github/thread-comments.mjs +9 -1
  363. package/bin/github/transport-evidence.d.mts +20 -0
  364. package/bin/github/transport-evidence.mjs +26 -0
  365. package/bin/github/transport-mode.d.mts +2 -0
  366. package/bin/github/transport-mode.mjs +5 -0
  367. package/bin/github/transport.d.mts +19 -0
  368. package/bin/github/transport.mjs +126 -0
  369. package/bin/github/unsupported-rest.d.mts +4 -0
  370. package/bin/github/unsupported-rest.mjs +7 -0
  371. package/bin/mcp/server.mjs +52 -3
  372. package/bin/merge-status/derive.d.mts +2 -0
  373. package/bin/merge-status/derive.mjs +17 -13
  374. package/bin/merge-status/required-check-requirements.d.mts +7 -0
  375. package/bin/merge-status/required-check-requirements.mjs +15 -0
  376. package/bin/merge-status/requirements-format.d.mts +5 -0
  377. package/bin/merge-status/requirements-format.mjs +41 -12
  378. package/bin/merge-status/requirements.mjs +18 -7
  379. package/bin/state/base.mjs +41 -0
  380. package/bin/state/durable-state.d.mts +6 -0
  381. package/bin/state/durable-state.mjs +41 -0
  382. package/bin/state/graphql-quota-policy.mjs +23 -16
  383. package/bin/state/merge-request.d.mts +25 -0
  384. package/bin/state/merge-request.mjs +145 -0
  385. package/bin/state/pr-fingerprint.d.mts +15 -0
  386. package/bin/state/pr-fingerprint.mjs +22 -7
  387. package/bin/state/rest-cache.d.mts +3 -0
  388. package/bin/state/rest-cache.mjs +1 -0
  389. package/bin/state/rest-snapshot-report.d.mts +21 -0
  390. package/bin/state/rest-snapshot-report.mjs +52 -0
  391. package/bin/state/seen-comments.d.mts +3 -0
  392. package/bin/state/seen-comments.mjs +18 -0
  393. package/bin/types/api-usage.d.mts +9 -1
  394. package/bin/types/escalate.d.mts +1 -1
  395. package/bin/types/github.d.mts +23 -9
  396. package/bin/types/iterate.d.mts +24 -2
  397. package/bin/types/merge-action.d.mts +1 -1
  398. package/bin/types/merge-requirements.d.mts +7 -7
  399. package/bin/types/next-check.d.mts +12 -0
  400. package/bin/types/next-check.mjs +1 -0
  401. package/bin/types/poll-summary.d.mts +21 -0
  402. package/bin/types/report.d.mts +13 -1
  403. package/bin/types/review-thread.d.mts +1 -1
  404. package/bin/types.d.mts +1 -0
  405. package/bin/types.mjs +1 -0
  406. package/package.json +4 -3
  407. package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
  408. package/plugins/pr-shepherd/.codex.mcp.json +1 -1
  409. package/plugins/pr-shepherd/.mcp.json +1 -1
  410. package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +1 -1
  411. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +14 -51
  412. package/plugins/pr-shepherd/skills/pr-shepherd/references/ci-failure-triage.md +12 -16
  413. package/plugins/pr-shepherd/skills/pr-shepherd/references/cloud-event-loop.md +14 -0
  414. package/plugins/pr-shepherd/skills/pr-shepherd/references/create-pr.md +10 -0
  415. package/plugins/pr-shepherd/skills/pr-shepherd/references/fix-code-loop.md +10 -0
  416. package/plugins/pr-shepherd/skills/pr-shepherd/references/mcp-fallback.md +9 -0
  417. package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +3 -1
  418. package/bin/github/gql/pr-fingerprint.gql +0 -75
  419. package/plugins/pr-shepherd/skills/pr-shepherd/references/journal.md +0 -7
  420. package/plugins/pr-shepherd/skills/pr-shepherd/references/review-mutations.md +0 -9
  421. package/plugins/pr-shepherd/skills/pr-shepherd/references/stack-merge.md +0 -7
@@ -0,0 +1,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 conversation comment 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"]))
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 on conversation comments. A real 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 on conversation comments. A real 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"]))
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",
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Run a dispatched command, entering the durable state scope first when it resolves to event
3
+ * mode. Entering before log setup keeps the per-worktree log a peer of the seen markers and
4
+ * stall state an event session writes. Invalid flags or config fall through unscoped so the
5
+ * command handler reports them.
6
+ */
7
+ export declare function runInEventStateScope<T>(args: string[], work: () => Promise<T>): Promise<T>;
8
+ /**
9
+ * Report an invalid `--poll-mode` value as a usage error. Commands that only use the flag to
10
+ * pick a state scope (`log-file`, `clean`) call this before `runInPollModeScope`, because no
11
+ * later handler would reject a typo there. Returns true after printing the error.
12
+ */
13
+ export declare function rejectInvalidPollModeFlag(args: string[], command: string): boolean;
14
+ /**
15
+ * Run `work` in the durable state scope when `--poll-mode` in `args`, or else `poll.mode`,
16
+ * resolves to event mode. `log-file` and `clean` use this to reach the state an event tick
17
+ * writes.
18
+ */
19
+ export declare function runInPollModeScope<T>(args: string[], work: () => Promise<T>): Promise<T>;
@@ -0,0 +1,60 @@
1
+ import { loadConfig } from "../config/load.mjs";
2
+ import { EXIT } from "../exit-codes.mjs";
3
+ import { resolvePollMode } from "../commands/poll-mode.mjs";
4
+ import { runWithDurableState } from "../state/durable-state.mjs";
5
+ import { getFlag } from "./args.mjs";
6
+ import { isDefaultPollInvocation } from "./default-poll.mjs";
7
+ /** Subcommands that honor `--poll-mode`; the default poll invocation honors it too. */
8
+ const POLL_MODE_SUBCOMMANDS = new Set(["iterate", "poll"]);
9
+ const REQUESTABLE = ["auto", "poll", "event"];
10
+ function requestedPollMode(value) {
11
+ return REQUESTABLE.find((mode) => mode === value);
12
+ }
13
+ /**
14
+ * Run a dispatched command, entering the durable state scope first when it resolves to event
15
+ * mode. Entering before log setup keeps the per-worktree log a peer of the seen markers and
16
+ * stall state an event session writes. Invalid flags or config fall through unscoped so the
17
+ * command handler reports them.
18
+ */
19
+ export function runInEventStateScope(args, work) {
20
+ const subcommand = args[0];
21
+ const honorsPollMode = isDefaultPollInvocation(subcommand) || POLL_MODE_SUBCOMMANDS.has(subcommand ?? "");
22
+ return honorsPollMode ? runInPollModeScope(args, work) : work();
23
+ }
24
+ /**
25
+ * Report an invalid `--poll-mode` value as a usage error. Commands that only use the flag to
26
+ * pick a state scope (`log-file`, `clean`) call this before `runInPollModeScope`, because no
27
+ * later handler would reject a typo there. Returns true after printing the error.
28
+ */
29
+ export function rejectInvalidPollModeFlag(args, command) {
30
+ if (!args.some((arg) => arg === "--poll-mode" || arg.startsWith("--poll-mode=")))
31
+ return false;
32
+ const value = getFlag(args, "--poll-mode");
33
+ if (requestedPollMode(value))
34
+ return false;
35
+ process.stderr.write(`pr-shepherd: ${command}: --poll-mode must be one of ${REQUESTABLE.join(", ")}, got ${JSON.stringify(value ?? "")}\n`);
36
+ process.exitCode = EXIT.USAGE;
37
+ return true;
38
+ }
39
+ /**
40
+ * Run `work` in the durable state scope when `--poll-mode` in `args`, or else `poll.mode`,
41
+ * resolves to event mode. `log-file` and `clean` use this to reach the state an event tick
42
+ * writes.
43
+ */
44
+ export function runInPollModeScope(args, work) {
45
+ return resolvesToEvent(args) ? runWithDurableState(work) : work();
46
+ }
47
+ function resolvesToEvent(args) {
48
+ const flag = getFlag(args, "--poll-mode");
49
+ const requested = requestedPollMode(flag);
50
+ // An explicit poll or event request wins without reading config, so a malformed config
51
+ // cannot drop an explicit `--poll-mode event` out of the durable scope.
52
+ if (requested === "event" || requested === "poll")
53
+ return requested === "event";
54
+ try {
55
+ return resolvePollMode(requested, loadConfig().poll.mode) === "event";
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }
@@ -1,5 +1,4 @@
1
1
  /* eslint-disable max-lines */
2
- import { renderResolveCommand } from "../commands/iterate/render.mjs";
3
2
  import { inlineCode, joinSections } from "../util/markdown.mjs";
4
3
  import { renderSuggestionBlock, renderLineRange } from "./suggestion-renderer.mjs";
5
4
  import { renderThreadBullet, renderReviewBullet, renderThreadResolutionStatusTag, renderAuthor, buildFirstLookBullets, renderThreadConversation, blockquote, } from "./list-formatters.mjs";
@@ -77,9 +76,8 @@ export function formatFixCodeResult(header, result, opts = {}) {
77
76
  const scopeTag = ch.scope
78
77
  ? ` [scope: ${ch.scope}${ch.commitOid ? `, commit: ${ch.commitOid}` : ""}]`
79
78
  : "";
80
- const rerunTag = ch.rerunCommand ? " [rerun authorized]" : "";
81
79
  const lines = [
82
- `- ${locator} — \`${workflowPrefix}${jobLabel}\`${conclusionTag}${attemptTag}${scopeTag}${rerunTag}`,
80
+ `- ${locator} — \`${workflowPrefix}${jobLabel}\`${conclusionTag}${attemptTag}${scopeTag}`,
83
81
  ];
84
82
  if (ch.conclusion !== "CANCELLED") {
85
83
  if (ch.failedStep)
@@ -184,13 +182,8 @@ export function formatFixCodeResult(header, result, opts = {}) {
184
182
  sections.push("## Cancelled runs");
185
183
  sections.push(result.cancelled.map((id) => `- \`${id}\``).join("\n"));
186
184
  }
187
- sections.push("## Post-fix actions");
188
- const postFixLines = [`- base: \`${result.baseBranch}\``];
189
- if (result.fix.resolveOnlyCommand?.hasMutations)
190
- postFixLines.push(`- resolve-only: \`${renderResolveCommand(result.fix.resolveOnlyCommand)}\``);
191
- if (result.fix.resolveCommand.hasMutations) {
192
- postFixLines.push(`- apply review: \`${renderResolveCommand(result.fix.resolveCommand)}\``);
193
- }
185
+ // The review mutation commands render inline in their `## Instructions` steps.
186
+ const postFixLines = verbose ? [`- base: \`${result.baseBranch}\``] : [];
194
187
  if (result.fix.requeue) {
195
188
  postFixLines.push(`- requeue: ${inlineCode(renderMergeCommand(result.fix.requeue.command))}`);
196
189
  if (result.fix.requeue.queueApiFallbackCommand) {
@@ -200,7 +193,8 @@ export function formatFixCodeResult(header, result, opts = {}) {
200
193
  if (result.fix.queueRemovalAcknowledgment) {
201
194
  postFixLines.push(`- acknowledge queue removal: ${inlineCode(renderMergeCommand(result.fix.queueRemovalAcknowledgment))}`);
202
195
  }
203
- sections.push(postFixLines.join("\n"));
196
+ if (postFixLines.length > 0)
197
+ sections.push("## Post-fix actions", postFixLines.join("\n"));
204
198
  sections.push("## Instructions");
205
199
  sections.push(numberInstructions(result.fix.instructions));
206
200
  return joinSections(sections);
@@ -1,4 +1,3 @@
1
- export declare function handleClean(args: string[], command?: "admin clean" | "clean"): Promise<void>;
2
1
  export declare function handleCommitSuggestion(args: string[], command?: "build-suggestion-patch" | "commit-suggestion"): Promise<void>;
3
2
  export declare function handleSuggestionPatches(args: string[]): Promise<void>;
4
3
  export declare function handleIterate(args: string[]): Promise<void>;
@@ -1,73 +1,16 @@
1
1
  import { runCommitSuggestion } from "../commands/commit-suggestion.mjs";
2
2
  import { runSuggestionPatches } from "../commands/suggestion-patches.mjs";
3
3
  import { runMarkFilesAsViewed } from "../commands/mark-files-as-viewed.mjs";
4
- import { runIterate } from "../commands/iterate/index.mjs";
5
- import { runClean } from "../commands/clean.mjs";
4
+ import { runIterateForMode } from "../commands/event-mode.mjs";
6
5
  import { loadConfig } from "../config/load.mjs";
7
6
  import { EXIT } from "../exit-codes.mjs";
8
7
  import { parseCommonArgs, getFlag } from "./args.mjs";
9
8
  import { USAGE } from "./help.mjs";
10
- import { formatCommitSuggestionResult, formatSuggestionPatchesResult, formatCleanResult, formatMarkFilesAsViewedResult, } from "./formatters.mjs";
9
+ import { formatCommitSuggestionResult, formatSuggestionPatchesResult, formatMarkFilesAsViewedResult, } from "./formatters.mjs";
11
10
  import { parseSuggestionPatchGroups } from "./suggestion-patch-flags.mjs";
12
- import { parseIterateFlags } from "./iterate-flags.mjs";
11
+ import { hasInvalidIterateFlags, parseIterateFlags } from "./iterate-flags.mjs";
13
12
  import { emitIterateResult } from "./iterate-emitter.mjs";
14
13
  import { parseMarkFilesAsViewedArgs } from "./mark-files-as-viewed-flags.mjs";
15
- const CLEAN_VARIANTS = new Set(["pr", "branch", "current", "repo", "all"]);
16
- export async function handleClean(args, command = "admin clean") {
17
- const usage = command === "admin clean" ? USAGE["admin clean"] : USAGE.clean;
18
- const variant = args[0];
19
- if (!variant || !CLEAN_VARIANTS.has(variant)) {
20
- process.stderr.write(`${usage}\n`);
21
- process.exitCode = EXIT.USAGE;
22
- return;
23
- }
24
- const rest = args.slice(1);
25
- for (const a of rest) {
26
- if (!a.startsWith("--"))
27
- continue;
28
- if (a === "--dry-run" || a === "--format" || a.startsWith("--format="))
29
- continue;
30
- process.stderr.write(`pr-shepherd: ${command}: unknown flag: "${a}"\n`);
31
- process.exitCode = EXIT.USAGE;
32
- return;
33
- }
34
- const fmtIdx = rest.indexOf("--format");
35
- const fmtEqEntry = rest.find((a) => a.startsWith("--format="));
36
- let formatValue;
37
- if (fmtEqEntry !== undefined) {
38
- formatValue = fmtEqEntry.slice("--format=".length);
39
- }
40
- else if (fmtIdx !== -1 && fmtIdx + 1 < rest.length && !rest[fmtIdx + 1].startsWith("--")) {
41
- formatValue = rest[fmtIdx + 1];
42
- }
43
- if (formatValue !== undefined && formatValue !== "text" && formatValue !== "json") {
44
- process.stderr.write(`pr-shepherd: ${command}: invalid --format value: "${formatValue}". Expected "text" or "json".\n`);
45
- process.exitCode = EXIT.USAGE;
46
- return;
47
- }
48
- const jsonOut = formatValue === "json";
49
- const dryRun = rest.includes("--dry-run");
50
- // Skip the value consumed by --format <value> so it isn't mistaken for the positional.
51
- const flagConsumedIndices = new Set();
52
- if (fmtIdx !== -1 && fmtIdx + 1 < rest.length && !rest[fmtIdx + 1].startsWith("--")) {
53
- flagConsumedIndices.add(fmtIdx);
54
- flagConsumedIndices.add(fmtIdx + 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
- const result = await runClean({ variant: variant, value, dryRun });
64
- if (!result.ok) {
65
- process.stderr.write(`pr-shepherd: ${command}: ${result.error}\n`);
66
- process.exitCode = EXIT.SOFTWARE;
67
- return;
68
- }
69
- process.stdout.write(jsonOut ? `${JSON.stringify(result, null, 2)}\n` : `${formatCleanResult(result)}\n`);
70
- }
71
14
  export async function handleCommitSuggestion(args, command = "build-suggestion-patch") {
72
15
  const { prNumber, global: globalOpts, extra } = parseCommonArgs(args);
73
16
  const threadId = getFlag(extra, "--thread-id");
@@ -113,11 +56,10 @@ export async function handleSuggestionPatches(args) {
113
56
  }
114
57
  export async function handleIterate(args) {
115
58
  const { prNumber, global: globalOpts, extra } = parseCommonArgs(args);
116
- const cfg = loadConfig();
117
- const flags = parseIterateFlags(extra, cfg);
118
- if (flags.readyDelaySuffix === null || flags.stallTimeoutSuffix === null)
59
+ const flags = parseIterateFlags(extra, loadConfig());
60
+ if (hasInvalidIterateFlags(flags))
119
61
  return;
120
- const result = await runIterate({
62
+ const result = await runIterateForMode({
121
63
  ...globalOpts,
122
64
  prNumber,
123
65
  readyDelaySeconds: flags.readyDelaySeconds,
@@ -125,6 +67,8 @@ export async function handleIterate(args) {
125
67
  noAutoMarkReady: flags.noAutoMarkReady,
126
68
  noAutoCancelActionable: flags.noAutoCancelActionable,
127
69
  merge: flags.merge,
70
+ instructions: flags.instructions ?? undefined,
71
+ pollMode: flags.pollMode ?? undefined,
128
72
  });
129
73
  emitIterateResult(result, {
130
74
  format: globalOpts.format,