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
@@ -1,12 +1,19 @@
1
- import { renderMergeCommand } from "../commands/iterate/merge.mjs";
2
1
  import { inlineCode } from "../util/markdown.mjs";
3
2
  import { buildQuotaAwareContinuation } from "../quota-warning.mjs";
4
3
  import { formatPrUrl } from "../pr-reference.mjs";
5
4
  import { AUTO_MARK_READY_DISABLED_HOLD } from "../commands/stack-work.mjs";
6
- import { buildPrShepherdCommand } from "./runner.mjs";
5
+ import { buildPrShepherdCommand, renderShellCommand } from "./runner.mjs";
6
+ import { eventWaitSteps } from "../commands/event-instructions.mjs";
7
+ import { playbookPointer } from "../commands/playbook-pointer.mjs";
7
8
  export function buildSimpleIterateInstructions(result) {
8
9
  switch (result.action) {
9
10
  case "ready": {
11
+ if (result.nextCheck) {
12
+ return [
13
+ `PR #${result.pr} is ready. Ready-delay has ${result.remainingSeconds}s left. Do not invent unrelated work.`,
14
+ ...eventWaitSteps(result.nextCheck),
15
+ ];
16
+ }
10
17
  const sentence = `PR #${result.pr} is ready. Ready-delay has ${result.remainingSeconds}s left. Rerun this command when the timer elapses. Do not invent unrelated work.`;
11
18
  return [
12
19
  result.quotaWarning ? buildQuotaAwareContinuation(result.quotaWarning, sentence) : sentence,
@@ -14,7 +21,10 @@ export function buildSimpleIterateInstructions(result) {
14
21
  }
15
22
  case "wait":
16
23
  if (result.stackDraftHold)
17
- return [buildStackDraftHoldInstruction(result, result.stackDraftHold)];
24
+ return buildStackDraftHoldInstructions(result, result.stackDraftHold);
25
+ if (result.nextCheck) {
26
+ return ["Non-terminal — no action needed this tick.", ...eventWaitSteps(result.nextCheck)];
27
+ }
18
28
  if (result.quotaWarning) {
19
29
  return [
20
30
  buildQuotaAwareContinuation(result.quotaWarning, "Non-terminal — no action needed this tick."),
@@ -24,7 +34,8 @@ export function buildSimpleIterateInstructions(result) {
24
34
  "Non-terminal — no action needed this tick. Iterate immediately with the same options to continue.",
25
35
  ];
26
36
  case "mark_ready":
27
- if (result.quotaWarning) {
37
+ // Event mode reruns at once too: Shepherd is not polling, so no cadence applies.
38
+ if (result.quotaWarning && result.pollMode !== "event") {
28
39
  return [
29
40
  buildQuotaAwareContinuation(result.quotaWarning, "The CLI marked the PR ready for review."),
30
41
  ];
@@ -33,32 +44,43 @@ export function buildSimpleIterateInstructions(result) {
33
44
  "The CLI marked the PR ready for review. Iterate immediately with the same options to continue.",
34
45
  ];
35
46
  case "merge": {
47
+ // The commands are inline, so no separate `## Merge command` section repeats them.
48
+ const command = inlineCode(renderShellCommand(result.merge.command.argv));
49
+ if (result.merge.mode === "rest" && result.nextCheck)
50
+ return [
51
+ `Run the REST merge command exactly as printed: ${command}. \`enqueued\` is not merged.`,
52
+ ...eventWaitSteps(result.nextCheck),
53
+ ];
54
+ if (result.merge.mode === "rest")
55
+ return [
56
+ `Run the REST merge command exactly as printed: ${command}. If its status is \`pending\`, rerun that same command at the configured polling cadence to resume the recorded request; \`enqueued\` is not merged.`,
57
+ "Then iterate with the same options until GitHub confirms the PR merged or needs work.",
58
+ ];
36
59
  const instructions = [
37
- `Run the \`${result.merge.mode === "queue" ? "merge queue" : "auto-merge"}\` command shown above exactly as printed.`,
60
+ `Run the ${result.merge.mode === "queue" ? "merge queue" : "auto-merge"} command exactly as printed: ${command}.`,
38
61
  ];
39
62
  if (result.merge.mode === "queue" && result.merge.queueApiFallbackCommand) {
40
- instructions.push(`If the gh CLI says auto-merge is disabled instead of adding the PR to the queue, run the \`queue API fallback\` command: ${inlineCode(renderMergeCommand(result.merge.queueApiFallbackCommand))}.`);
63
+ instructions.push(`If gh says auto-merge is disabled instead of adding the PR to the queue, run the queue API fallback: ${inlineCode(renderShellCommand(result.merge.queueApiFallbackCommand.argv))}.`);
41
64
  }
42
65
  else if (result.merge.fallbackCommand) {
43
- instructions.push(`Only if GitHub reports that auto-merge is unavailable, run the \`plain merge fallback\` command: ${inlineCode(renderMergeCommand(result.merge.fallbackCommand))}.`);
66
+ instructions.push(`Only if GitHub reports that auto-merge is unavailable, run the plain merge fallback: ${inlineCode(renderShellCommand(result.merge.fallbackCommand.argv))}.`);
44
67
  }
45
68
  instructions.push(result.quotaWarning
46
69
  ? buildQuotaAwareContinuation(result.quotaWarning, "After running the merge command.")
47
- : "Then iterate immediately with the same options to monitor until the PR merges or needs work.");
70
+ : "Then iterate immediately with the same options until the PR merges or needs work.");
48
71
  return instructions;
49
72
  }
50
73
  case "cancel":
51
- return [
52
- "Stop polling this pull request — its poll is complete.",
53
- "Continue any remaining pull requests or issues from the original request.",
54
- ];
74
+ // `[CANCEL]` needs no steps: stopping, then continuing the original request, is the skill's
75
+ // invariant recurrence rule, and nothing remains to run for this PR.
76
+ return [];
55
77
  case "escalate": {
56
78
  const pending = result.escalate.pendingReviewCommands;
57
79
  if (!pending)
58
80
  return ["Stop — human direction is required before automated polling can resume."];
59
81
  return [
60
82
  "Stop polling. Ask the user whether to run the pending review commands shown above.",
61
- "If yes, replace any `$HEAD_SHA` with the full 40-character pushed PR-head SHA and any `$DISMISS_MESSAGE` with a one-sentence disposition, run every pending command, then rerun Shepherd with the same options.",
83
+ "If yes, set any `$DISMISS_MESSAGE` to a one-sentence disposition, run every pending command from the pushed PR head, then rerun Shepherd with the same options.",
62
84
  ];
63
85
  }
64
86
  }
@@ -67,18 +89,26 @@ export function buildSimpleIterateInstructions(result) {
67
89
  * A held stack draft cannot advance by repeating its one-PR session, so hand control back
68
90
  * to the stack selector instead of asking for another immediate iteration.
69
91
  */
70
- function buildStackDraftHoldInstruction(result, hold) {
92
+ function buildStackDraftHoldInstructions(result, hold) {
93
+ const event = result.pollMode === "event";
71
94
  const stackCommand = buildPrShepherdCommand([
72
95
  "--stack",
73
96
  formatPrUrl(result.repo, result.pr),
74
97
  "--until-terminal",
98
+ ...(event ? ["--poll-mode", "event"] : []),
75
99
  ]).text;
76
100
  const handoff = `a \`--stack\` selector listed this session, finish that selector's remaining steps and rerun it with its original flags; otherwise run ${inlineCode(stackCommand)}, adding \`--merge\` when merging was requested.`;
77
101
  const reason = hold.kind === "auto-mark-ready-disabled" ? AUTO_MARK_READY_DISABLED_HOLD : hold.kind;
78
102
  const instruction = `PR #${result.pr} stays in draft because ${reason}, so repeating this one-PR session cannot advance it. If ${handoff}`;
79
- return result.quotaWarning
103
+ const step = result.quotaWarning
80
104
  ? buildQuotaAwareContinuation(result.quotaWarning, instruction)
81
105
  : instruction;
106
+ if (!event)
107
+ return [step];
108
+ return [
109
+ step,
110
+ `Event mode: do not rerun this one-PR session and keep no wake-up for it. After the handoff, follow only the stack selector's output; it ends the turn and schedules the next tick through its own \`nextCheck\`. ${playbookPointer("Cloud event loop")}`,
111
+ ];
82
112
  }
83
113
  export function adaptIterateLog(log) {
84
114
  return log.replace(/\s+—\s+\d+s until auto-cancel/g, "");
@@ -1,5 +1,8 @@
1
1
  import { adaptIterateLog, buildSimpleIterateInstructions } from "./iterate-instructions.mjs";
2
2
  import { projectRuleAutoResolve } from "../commands/rule-auto-resolve-format.mjs";
3
+ import { projectMergeRequirements } from "../merge-status/requirements-format.mjs";
4
+ import { branchSegmentShowsBase } from "./iterate-branch-segment.mjs";
5
+ import { isRedundantMergeQueue } from "./iterate-merge-formatter.mjs";
3
6
  /**
4
7
  * Project an IterateResult to a lean JSON shape for the default (non-verbose) output.
5
8
  * Omits fields that are the trivial default (false, 0, empty) or state-gated fields
@@ -17,38 +20,56 @@ export function projectIterateLean(result, opts) {
17
20
  const hasActivity = activity.commitCount > 0 ||
18
21
  activity.reviewRoundCount > 0 ||
19
22
  activity.reviewItemsSinceLatestCommit.length > 0;
23
+ if (result.action === "cancel" && (result.reason === "merged" || result.reason === "closed")) {
24
+ // Terminal: the PR's checks, reviews, and merge state no longer drive any action.
25
+ return {
26
+ action: result.action,
27
+ pr: result.pr,
28
+ reason: result.reason,
29
+ ...(result.ruleAutoResolve && {
30
+ ruleAutoResolve: projectRuleAutoResolve(result.ruleAutoResolve),
31
+ }),
32
+ };
33
+ }
34
+ const counts = Object.fromEntries(["passing", "skipped", "filtered", "inProgress", "superseded"]
35
+ .filter((k) => result.summary[k] > 0)
36
+ .map((k) => [k, result.summary[k]]));
37
+ const summary = Object.keys(counts).length > 0 ? counts : null;
38
+ const mergeRequirements = result.mergeRequirements
39
+ ? projectMergeRequirements(result.mergeRequirements)
40
+ : null;
20
41
  const base = {
21
42
  action: result.action,
22
43
  pr: result.pr,
23
44
  repo: result.repo || undefined,
45
+ ...(result.transport && { transport: result.transport }),
46
+ ...(result.transportUnavailable?.length && {
47
+ transportUnavailable: result.transportUnavailable,
48
+ }),
24
49
  status: result.status,
25
- state: result.state,
26
- mergeStateStatus: result.mergeStateStatus,
50
+ // OPEN and CLEAN are the trivial defaults; the text header omits them the same way.
51
+ ...(result.state !== "OPEN" && { state: result.state }),
52
+ ...(result.mergeStateStatus !== "CLEAN" && { mergeStateStatus: result.mergeStateStatus }),
27
53
  ...(result.mergeStatus !== "CLEAN" && { mergeStatus: result.mergeStatus }), // mergeStateStatus alone can't always reconstruct this
28
54
  ...(readyDelaySuffix && { readyDelayOverride: readyDelaySuffix }),
29
55
  ...(result.mergeStatus === "BLOCKED" &&
30
56
  result.reviewDecision !== null && { reviewDecision: result.reviewDecision }),
31
57
  ...(result.blockingBotReviewInProgress && { blockingBotReviewInProgress: true }),
32
58
  ...(result.isDraft && { isDraft: true }),
33
- summary: {
34
- passing: result.summary.passing,
35
- ...(result.summary.skipped > 0 && { skipped: result.summary.skipped }),
36
- ...(result.summary.filtered > 0 && { filtered: result.summary.filtered }),
37
- ...(result.summary.inProgress > 0 && { inProgress: result.summary.inProgress }),
38
- ...(result.summary.superseded > 0 && { superseded: result.summary.superseded }),
39
- },
59
+ ...(summary && { summary }),
40
60
  ...(result.status === "READY" &&
41
61
  result.remainingSeconds > 0 && {
42
62
  remainingSeconds: result.remainingSeconds,
43
63
  }),
44
- ...(result.baseBranch && { baseBranch: result.baseBranch }),
64
+ // Lean text shows the base branch only in the behind/conflicts branch segment.
65
+ ...(branchSegmentShowsBase(result) && { baseBranch: result.baseBranch }),
45
66
  ...(result.stackTrunkConflict && { stackTrunkConflict: result.stackTrunkConflict }),
46
67
  ...((result.mergedBasePullRequests?.length ?? 0) > 0 && {
47
68
  mergedBasePullRequests: result.mergedBasePullRequests,
48
69
  }),
49
70
  ...(result.branchProtection !== null && { branchProtection: result.branchProtection }),
50
- ...(result.mergeRequirements && { mergeRequirements: result.mergeRequirements }),
51
- ...(result.mergeQueue && { mergeQueue: result.mergeQueue }),
71
+ ...(mergeRequirements && { mergeRequirements }),
72
+ ...(result.mergeQueue && !isRedundantMergeQueue(result) && { mergeQueue: result.mergeQueue }),
52
73
  ...(hasActivity && {
53
74
  activity: {
54
75
  commitCount: activity.commitCount,
@@ -78,6 +99,8 @@ export function projectIterateLean(result, opts) {
78
99
  ...(result.baseBehindBy !== undefined &&
79
100
  result.baseBehindBy > 0 && { baseBehindBy: result.baseBehindBy }),
80
101
  ...(result.quotaWarning && { quotaWarning: result.quotaWarning }),
102
+ ...(result.pollMode && { pollMode: result.pollMode }),
103
+ ...(result.nextCheck && { nextCheck: result.nextCheck }),
81
104
  ...(result.ruleAutoResolve && {
82
105
  ruleAutoResolve: projectRuleAutoResolve(result.ruleAutoResolve),
83
106
  }),
@@ -92,7 +115,10 @@ export function projectIterateLean(result, opts) {
92
115
  case "wait":
93
116
  return {
94
117
  ...base,
95
- ...(result.deferredWork && { deferredWork: result.deferredWork }),
118
+ // Zero counts are omitted, matching the text `**deferred (in merge queue)**` rollup.
119
+ ...(result.deferredWork && {
120
+ deferredWork: Object.fromEntries(Object.entries(result.deferredWork).filter(([, n]) => n > 0)),
121
+ }),
96
122
  ...(result.stackDraftHold && { stackDraftHold: result.stackDraftHold }),
97
123
  log: adaptIterateLog(result.log),
98
124
  instructions: simpleInstructions(result),
@@ -102,7 +128,6 @@ export function projectIterateLean(result, opts) {
102
128
  ...base,
103
129
  reason: result.reason,
104
130
  log: adaptIterateLog(result.log),
105
- instructions: simpleInstructions(result),
106
131
  };
107
132
  case "mark_ready":
108
133
  // drop markedReady — always true, redundant with action discriminator
@@ -1,5 +1,11 @@
1
1
  import type { IterateDeferredWork, IterateResult, IterateResultMerge } from "../types.mts";
2
2
  /** One inline rollup line of the non-CI work held back while the PR sits in the merge queue. */
3
3
  export declare function formatDeferredWorkLine(dw: IterateDeferredWork): string;
4
+ /**
5
+ * True when `mergeQueue` adds nothing to the `Merge queue:` requirement line: it carries only
6
+ * `enabled`/`inQueue`, the queue is required (so enabled), and membership matches. Text and JSON
7
+ * both omit it then.
8
+ */
9
+ export declare function isRedundantMergeQueue(result: IterateResult): boolean;
4
10
  export declare function appendMergeQueueHeader(lines: string[], result: IterateResult): void;
5
11
  export declare function formatMergeAction(header: string, result: IterateResultMerge): string;
@@ -1,5 +1,4 @@
1
- import { renderMergeCommand } from "../commands/iterate/merge.mjs";
2
- import { inlineCode, joinSections } from "../util/markdown.mjs";
1
+ import { joinSections } from "../util/markdown.mjs";
3
2
  import { buildSimpleIterateInstructions, numberInstructions } from "./iterate-instructions.mjs";
4
3
  /** One inline rollup line of the non-CI work held back while the PR sits in the merge queue. */
5
4
  export function formatDeferredWorkLine(dw) {
@@ -16,9 +15,25 @@ export function formatDeferredWorkLine(dw) {
16
15
  }
17
16
  return `**deferred (in merge queue)** ${parts.join(", ")}`;
18
17
  }
18
+ /**
19
+ * True when `mergeQueue` adds nothing to the `Merge queue:` requirement line: it carries only
20
+ * `enabled`/`inQueue`, the queue is required (so enabled), and membership matches. Text and JSON
21
+ * both omit it then.
22
+ */
23
+ export function isRedundantMergeQueue(result) {
24
+ const queue = result.mergeQueue;
25
+ const req = result.mergeRequirements?.mergeQueue;
26
+ if (!queue || !req)
27
+ return false;
28
+ return (Object.keys(queue).every((k) => k === "enabled" || k === "inQueue") &&
29
+ queue.enabled &&
30
+ req.required &&
31
+ req.enabled === true &&
32
+ req.inQueue === queue.inQueue);
33
+ }
19
34
  export function appendMergeQueueHeader(lines, result) {
20
35
  const queue = result.mergeQueue;
21
- if (!queue)
36
+ if (!queue || isRedundantMergeQueue(result))
22
37
  return;
23
38
  const parts = [`enabled \`${queue.enabled}\``, `inQueue \`${queue.inQueue}\``];
24
39
  if (queue.entry) {
@@ -46,7 +61,12 @@ export function appendMergeQueueHeader(lines, result) {
46
61
  parts.push("removal acknowledged");
47
62
  lines.push(`**merge queue** ${parts.join(" · ")}`);
48
63
  if (queue.autoMergeRequest) {
49
- lines.push(`**auto-merge** method \`${queue.autoMergeRequest.mergeMethod}\` · enabledAtUnix \`${queue.autoMergeRequest.enabledAtUnix}\`${queue.autoMergeRequest.enabledBy ? ` · by \`@${queue.autoMergeRequest.enabledBy}\`` : ""}`);
64
+ const autoMergeParts = [`method \`${queue.autoMergeRequest.mergeMethod}\``];
65
+ if (queue.autoMergeRequest.enabledAtUnix !== undefined)
66
+ autoMergeParts.push(`enabledAtUnix \`${queue.autoMergeRequest.enabledAtUnix}\``);
67
+ if (queue.autoMergeRequest.enabledBy)
68
+ autoMergeParts.push(`by \`@${queue.autoMergeRequest.enabledBy}\``);
69
+ lines.push(`**auto-merge** ${autoMergeParts.join(" · ")}`);
50
70
  }
51
71
  if (queue.latestRemoval) {
52
72
  const removal = queue.latestRemoval;
@@ -54,18 +74,8 @@ export function appendMergeQueueHeader(lines, result) {
54
74
  }
55
75
  }
56
76
  export function formatMergeAction(header, result) {
57
- const commandLines = [
58
- `- ${result.merge.mode === "queue" ? "merge queue" : "auto-merge"}: ${inlineCode(renderMergeCommand(result.merge.command))}`,
59
- ];
60
- if (result.merge.fallbackCommand) {
61
- commandLines.push(`- plain merge fallback: ${inlineCode(renderMergeCommand(result.merge.fallbackCommand))}`);
62
- }
63
- if (result.merge.queueApiFallbackCommand) {
64
- commandLines.push(`- queue API fallback: ${inlineCode(renderMergeCommand(result.merge.queueApiFallbackCommand))}`);
65
- }
66
77
  return joinSections([
67
78
  header,
68
- `## Merge command\n\n${commandLines.join("\n")}`,
69
79
  `## Instructions\n\n${numberInstructions(buildSimpleIterateInstructions(result))}`,
70
80
  ]);
71
81
  }
@@ -5,10 +5,7 @@ export function projectIterateVerbose(result, opts) {
5
5
  if (result.action === "fix_code")
6
6
  return { ...result, ...readyDelayOverride };
7
7
  const log = "log" in result && typeof result.log === "string" ? { log: adaptIterateLog(result.log) } : {};
8
- return {
9
- ...result,
10
- ...log,
11
- ...readyDelayOverride,
12
- instructions: buildSimpleIterateInstructions(result),
13
- };
8
+ // `cancel` has no instructions, so verbose JSON omits the field as verbose Markdown omits the section.
9
+ const instructions = result.action === "cancel" ? {} : { instructions: buildSimpleIterateInstructions(result) };
10
+ return { ...result, ...log, ...readyDelayOverride, ...instructions };
14
11
  }
@@ -3,7 +3,9 @@ import { threadComments } from "../threads/transcript.mjs";
3
3
  import { truncateBody, BODY_TRUNCATE_MAX_CHARS, NESTED_BODY_TRUNCATE_MAX_CHARS, } from "./body-truncate.mjs";
4
4
  const BODY_PREVIEW_MAX = 100;
5
5
  export function renderAuthor(author, authorType, authorAssociation, viewerDidAuthor) {
6
- return [`@${author}`, authorType, authorAssociation, viewerDidAuthor ? "viewer-authored" : null]
6
+ // `User` is the default author type; only `Bot` and `Unknown` are worth a label.
7
+ const type = authorType === "User" ? null : authorType;
8
+ return [`@${author}`, type, authorAssociation, viewerDidAuthor ? "viewer-authored" : null]
7
9
  .filter(Boolean)
8
10
  .join(" · ");
9
11
  }
@@ -1,6 +1,6 @@
1
1
  function pushIds(lines, label, ids) {
2
2
  if (ids?.length)
3
- lines.push(`${label} (${ids.length}): ${ids.join(", ")}`);
3
+ lines.push(`${label}: ${ids.join(", ")}`);
4
4
  }
5
5
  function formatRateLimit(result) {
6
6
  const rateLimit = result.rateLimit;
@@ -27,6 +27,8 @@ function formatRateLimit(result) {
27
27
  }
28
28
  export function formatMutateResult(result) {
29
29
  const lines = [];
30
+ if (result.sessionRefusal)
31
+ lines.push(`Stopped: GitHub session access refused — ${result.sessionRefusal}`);
30
32
  pushIds(lines, "Replied to threads", result.repliedThreads);
31
33
  pushIds(lines, "Resolved threads", result.resolvedThreads);
32
34
  pushIds(lines, "Minimized comments", result.minimizedComments);
@@ -43,14 +45,17 @@ export function formatMutateResult(result) {
43
45
  const rateLimit = formatRateLimit(result);
44
46
  if (rateLimit)
45
47
  lines.push(rateLimit);
46
- pushIds(lines, "Not replied due to rate limit", result.unrepliedThreads);
47
- pushIds(lines, "Not resolved due to rate limit", result.unresolvedThreads);
48
- pushIds(lines, "Not minimized due to rate limit", result.unminimizedComments);
49
- pushIds(lines, "Not dismissed due to rate limit", result.undismissedReviews);
48
+ const pendingReason = result.sessionRefusal ? "session access" : "rate limit";
49
+ pushIds(lines, `Not replied due to ${pendingReason}`, result.unrepliedThreads);
50
+ pushIds(lines, `Not resolved due to ${pendingReason}`, result.unresolvedThreads);
51
+ pushIds(lines, `Not minimized due to ${pendingReason}`, result.unminimizedComments);
52
+ pushIds(lines, `Not dismissed due to ${pendingReason}`, result.undismissedReviews);
50
53
  const errors = result.rateLimit
51
54
  ? result.errors.filter((e) => !e.startsWith("rate limit:"))
52
55
  : result.errors;
53
56
  if (errors.length)
54
57
  lines.push(`Errors:\n ${errors.join("\n ")}`);
58
+ if (result.instructions?.length)
59
+ lines.push(`## Instructions\n\n${result.instructions.map((instruction, index) => `${index + 1}. ${instruction}`).join("\n")}`);
55
60
  return lines.join("\n");
56
61
  }
@@ -0,0 +1,7 @@
1
+ import type { NextCheck } from "../types/next-check.mts";
2
+ /** ` · **pollMode** \`event\``, or nothing in poll mode. */
3
+ export declare function formatPollModeSegment(result: {
4
+ pollMode?: "event";
5
+ }): string;
6
+ /** The header line naming the next wake-up, or nothing when none applies. */
7
+ export declare function formatNextCheckLines(next: NextCheck | undefined): string[];
@@ -0,0 +1,10 @@
1
+ /** ` · **pollMode** \`event\``, or nothing in poll mode. */
2
+ export function formatPollModeSegment(result) {
3
+ return result.pollMode ? ` · **pollMode** \`${result.pollMode}\`` : "";
4
+ }
5
+ /** The header line naming the next wake-up, or nothing when none applies. */
6
+ export function formatNextCheckLines(next) {
7
+ if (!next)
8
+ return [];
9
+ return [`**nextCheck** \`${next.at}\` · in ${next.inSeconds}s · reason \`${next.reason}\``];
10
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Print a playbook shipped in the package, or list the names. Local read only: no GitHub,
3
+ * git, or log I/O, so playbook pointers resolve without the skill installed.
4
+ */
5
+ export declare function handlePlaybook(args: string[]): void;
@@ -0,0 +1,40 @@
1
+ import { EXIT, ShepherdError } from "../exit-codes.mjs";
2
+ import { formatPlaybookResult, runPlaybook } from "../commands/playbook.mjs";
3
+ import { maybePrintHelp } from "./help.mjs";
4
+ /**
5
+ * Print a playbook shipped in the package, or list the names. Local read only: no GitHub,
6
+ * git, or log I/O, so playbook pointers resolve without the skill installed.
7
+ */
8
+ export function handlePlaybook(args) {
9
+ if (maybePrintHelp(args, "playbook"))
10
+ return;
11
+ let format = "text";
12
+ const words = [];
13
+ for (let index = 0; index < args.length; index++) {
14
+ const arg = args[index];
15
+ if (arg === "--format" || arg.startsWith("--format=")) {
16
+ const value = arg === "--format" ? args[++index] : arg.slice("--format=".length);
17
+ if (value !== "text" && value !== "json")
18
+ return usageError(`invalid --format ${value}`);
19
+ format = value;
20
+ }
21
+ else if (arg.startsWith("-")) {
22
+ return usageError(`unknown flag ${arg}`);
23
+ }
24
+ else {
25
+ words.push(arg);
26
+ }
27
+ }
28
+ try {
29
+ const result = runPlaybook(words.join(" "));
30
+ process.stdout.write(format === "json" ? `${JSON.stringify(result)}\n` : `${formatPlaybookResult(result)}\n`);
31
+ }
32
+ catch (error) {
33
+ process.stderr.write(`pr-shepherd: playbook: ${String(error)}\n`);
34
+ process.exitCode = error instanceof ShepherdError ? error.exitCode : EXIT.USAGE;
35
+ }
36
+ }
37
+ function usageError(message) {
38
+ process.stderr.write(`pr-shepherd: playbook: ${message}\n`);
39
+ process.exitCode = EXIT.USAGE;
40
+ }
@@ -1,12 +1,11 @@
1
- import { runPoll } from "../commands/poll.mjs";
1
+ import { runAggregatePollForMode, runPollForMode } from "../commands/event-mode.mjs";
2
2
  import { loadConfig } from "../config/load.mjs";
3
3
  import { parseCommonArgs, getFlag, hasFlag } from "./args.mjs";
4
4
  import { parseDurationToSeconds } from "./duration.mjs";
5
5
  import { validateSecondsDurationFlag } from "./duration-flag.mjs";
6
- import { parseIterateFlags } from "./iterate-flags.mjs";
6
+ import { hasInvalidIterateFlags, parseIterateFlags } from "./iterate-flags.mjs";
7
7
  import { emitIterateResult } from "./iterate-emitter.mjs";
8
8
  import { EXIT } from "../exit-codes.mjs";
9
- import { runAggregatePoll } from "../commands/poll-summary.mjs";
10
9
  import { emitPollSummaryResult } from "./poll-summary-emitter.mjs";
11
10
  import { parsePollTargets, resolvePollTargets } from "./poll-targets.mjs";
12
11
  export async function handlePoll(args) {
@@ -23,7 +22,7 @@ export async function handlePoll(args) {
23
22
  const extra = isAggregate ? parsedTargets.extra : commonExtra;
24
23
  const cfg = loadConfig();
25
24
  const flags = parseIterateFlags(extra, cfg);
26
- if (flags.readyDelaySuffix === null || flags.stallTimeoutSuffix === null)
25
+ if (hasInvalidIterateFlags(flags))
27
26
  return;
28
27
  const intervalStr = getFlag(extra, "--interval");
29
28
  const intervalSuffix = validateSecondsDurationFlag("pr-shepherd", "--interval", intervalStr, hasFlag(extra, "--interval"));
@@ -61,6 +60,8 @@ export async function handlePoll(args) {
61
60
  noAutoMarkReady: flags.noAutoMarkReady,
62
61
  noAutoCancelActionable: flags.noAutoCancelActionable,
63
62
  merge: flags.merge,
63
+ instructions: flags.instructions ?? undefined,
64
+ pollMode: flags.pollMode ?? undefined,
64
65
  intervalSeconds,
65
66
  timeoutSeconds,
66
67
  debounceSeconds,
@@ -68,14 +69,14 @@ export async function handlePoll(args) {
68
69
  untilTerminal: hasFlag(extra, "--until-terminal"),
69
70
  };
70
71
  if (isAggregate) {
71
- const result = await runAggregatePoll({
72
+ const result = await runAggregatePollForMode({
72
73
  ...shared,
73
74
  ...resolvedTargets,
74
75
  });
75
76
  emitPollSummaryResult(result, { format: globalOpts.format });
76
77
  return;
77
78
  }
78
- const result = await runPoll({ ...shared, prNumber });
79
+ const result = await runPollForMode({ ...shared, prNumber });
79
80
  emitIterateResult(result, {
80
81
  format: globalOpts.format,
81
82
  verbose: globalOpts.verbose ?? false,
@@ -1,6 +1,8 @@
1
1
  import { formatApiUsage, formatQuotaWarning } from "./api-usage-formatter.mjs";
2
2
  import { withPollSummaryInstructions } from "../commands/poll-summary-instructions.mjs";
3
3
  import { formatStackOverview, projectStackOverview } from "./stack-overview.mjs";
4
+ import { formatTransportEvidence } from "./transport-formatter.mjs";
5
+ import { formatNextCheckLines, formatPollModeSegment } from "./next-check-format.mjs";
4
6
  export function formatPollSummaryResult(result) {
5
7
  if (result.selection.kind === "stack")
6
8
  return formatStackOverview(projectStackOverview(result));
@@ -8,11 +10,13 @@ export function formatPollSummaryResult(result) {
8
10
  const lines = [
9
11
  `# Poll summary [${result.reason.toUpperCase()}]`,
10
12
  "",
11
- `**repo** \`${result.repo}\` · **selection** ${selection} · **mode** \`${result.mode}\`${result.stackMergeable !== undefined ? ` · **stack mergeable** \`${result.stackMergeable}\`` : ""}${result.nextAction ? ` · **next action** \`${result.nextAction}\`` : ""}`,
13
+ `**repo** \`${result.repo}\` · **selection** ${selection} · **mode** \`${result.mode}\`${formatPollModeSegment(result)}${result.stackMergeable !== undefined ? ` · **stack mergeable** \`${result.stackMergeable}\`` : ""}${result.nextAction ? ` · **next action** \`${result.nextAction}\`` : ""}`,
14
+ ...formatNextCheckLines(result.nextCheck),
12
15
  "",
13
16
  "## Pull requests",
14
17
  "",
15
18
  ...result.prs.map(formatItem),
19
+ ...formatTransportEvidence(result),
16
20
  ];
17
21
  if (result.stackAncestry?.length) {
18
22
  lines.push("", "## Stack ancestry", "");
@@ -44,11 +48,14 @@ function formatItem(item) {
44
48
  : "";
45
49
  const readyDelay = item.remainingSeconds !== undefined ? ` · ready delay \`${item.remainingSeconds}s\`` : "";
46
50
  const readyReceipt = item.readyReceipt ? " · Shepherd READY completion `verified`" : "";
51
+ const queuePolicy = item.requiresMergeQueue !== undefined
52
+ ? ` · merge queue ${item.requiresMergeQueue ? "required" : "not required"}`
53
+ : "";
47
54
  const checks = item.checks;
48
55
  const review = item.review;
49
56
  return [
50
57
  `- [PR #${item.pr}: ${escapeMarkdownText(item.title)}](${item.url}) [${item.action.toUpperCase()}]`,
51
- ` - state \`${item.state}\` · mergeable \`${item.mergeable}\` · merge \`${item.mergeStateStatus}\`${reviewDecision}${stateFlags}${blockingReviewer}${readyDelay}${readyReceipt}${stack}`,
58
+ ` - state \`${item.state}\` · mergeable \`${item.mergeable}\` · merge \`${item.mergeStateStatus}\`${reviewDecision}${stateFlags}${blockingReviewer}${readyDelay}${readyReceipt}${queuePolicy}${stack}`,
52
59
  ` - head \`${item.headRefName}\` at \`${item.headRefOid}\` · base \`${item.baseRefName}\``,
53
60
  ...(checks
54
61
  ? [` - checks: ${formatCounts(checks, checks.incomplete ? ", incomplete" : "")}`]
@@ -68,6 +75,8 @@ function formatItem(item) {
68
75
  ]
69
76
  : []),
70
77
  ` - reasons: ${item.reasons.map((reason) => `\`${reason}\``).join(", ")}`,
78
+ ...(item.transport ? [` - transport \`${item.transport}\``] : []),
79
+ ...(item.transportUnavailable ?? []).map(({ field, reason }) => ` - unavailable \`${field}\`: ${reason}`),
71
80
  ...(item.pollCommand
72
81
  ? [` - pollCommand: \`${item.pollCommand}\`${item.pollProbe ? " · bounded probe" : ""}`]
73
82
  : []),
@@ -6,6 +6,8 @@ const VALUE_FLAGS = new Set([
6
6
  "--format",
7
7
  "--ready-delay",
8
8
  "--stall-timeout",
9
+ "--instructions",
10
+ "--poll-mode",
9
11
  "--interval",
10
12
  "--timeout",
11
13
  "--debounce",
@@ -15,11 +15,11 @@ export function warnPrrcThreadIds(ids) {
15
15
  return prrcIds;
16
16
  }
17
17
  export function validateRequireSha(sha) {
18
- if (sha === undefined)
18
+ if (sha === undefined || sha === "HEAD")
19
19
  return true;
20
20
  if (/^[0-9a-f]{40}$/.test(sha))
21
21
  return true;
22
- process.stderr.write(`pr-shepherd: apply review: --require-sha must be a full 40-character lowercase hex SHA, got "${sha}". Short SHAs will never match GitHub's headRefOid. Use $(git rev-parse HEAD) to get the full SHA.\n`);
22
+ process.stderr.write(`pr-shepherd: apply review: --require-sha must be HEAD or a full 40-character lowercase hex SHA, got "${sha}". Short SHAs will never match GitHub's headRefOid.\n`);
23
23
  process.exitCode = EXIT.DATAERR;
24
24
  return false;
25
25
  }
@@ -1,7 +1,12 @@
1
1
  import { loadConfig } from "../config/load.mjs";
2
+ import { getGithubTransport } from "../github/transport.mjs";
2
3
  /** Every emitted pr-shepherd command starts with the configured `cliCommand` launcher. */
3
4
  export function buildPrShepherdCommand(args) {
4
- const argv = [...loadConfig().cliCommand, ...args];
5
+ const transport = getGithubTransport() === "rest" &&
6
+ !args.some((arg) => arg === "--transport" || arg.startsWith("--transport="))
7
+ ? ["--transport", "rest"]
8
+ : [];
9
+ const argv = [...loadConfig().cliCommand, ...args, ...transport];
5
10
  return { argv, text: renderShellCommand(argv) };
6
11
  }
7
12
  export function renderShellCommand(argv) {
@@ -0,0 +1,33 @@
1
+ import type { PollSummaryItem } from "../types.mts";
2
+ /** One lean stack row shared by Markdown, JSON, and MCP. */
3
+ export interface StackLayerView {
4
+ transport?: "rest";
5
+ transportUnavailable?: Array<{
6
+ field: string;
7
+ reason: string;
8
+ }>;
9
+ pr: number;
10
+ title: string;
11
+ url: string;
12
+ state: PollSummaryItem["state"];
13
+ shepherded?: true;
14
+ mergeable?: boolean;
15
+ blocker?: string;
16
+ author?: string;
17
+ owned?: true;
18
+ isDraft?: true;
19
+ isInMergeQueue?: true;
20
+ requiresMergeQueue?: boolean;
21
+ position?: number;
22
+ stackSize?: number;
23
+ baseRefName: string;
24
+ failing?: number;
25
+ inProgress?: number;
26
+ actionable?: number;
27
+ checksIncomplete?: true;
28
+ reviewIncomplete?: true;
29
+ queueRemoval?: {
30
+ reason: string | null;
31
+ actor?: string;
32
+ };
33
+ }
@@ -0,0 +1 @@
1
+ export {};