pr-shepherd 0.60.1 → 1.1.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 (245) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +7 -5
  3. package/bin/api.d.mts +35 -24
  4. package/bin/api.mjs +68 -48
  5. package/bin/checks/classify.d.mts +1 -1
  6. package/bin/checks/classify.mjs +4 -4
  7. package/bin/checks/log-excerpt.mjs +1 -1
  8. package/bin/cli/arg-flags.mjs +0 -3
  9. package/bin/cli/clean-handler.d.mts +1 -1
  10. package/bin/cli/clean-handler.mjs +5 -15
  11. package/bin/cli/default-poll.d.mts +2 -0
  12. package/bin/cli/default-poll.mjs +9 -6
  13. package/bin/cli/formatters.d.mts +2 -3
  14. package/bin/cli/formatters.mjs +0 -26
  15. package/bin/cli/handlers.d.mts +3 -3
  16. package/bin/cli/handlers.mjs +45 -35
  17. package/bin/cli/help-command-pages.d.mts +13 -158
  18. package/bin/cli/help-command-pages.mjs +12 -157
  19. package/bin/cli/help-iterate-poll-pages.d.mts +4 -3
  20. package/bin/cli/help-iterate-poll-pages.mjs +76 -36
  21. package/bin/cli/help-log-file-page.d.mts +1 -1
  22. package/bin/cli/help-log-file-page.mjs +3 -5
  23. package/bin/cli/help-top-page.d.mts +1 -1
  24. package/bin/cli/help-top-page.mjs +19 -20
  25. package/bin/cli/help.d.mts +14 -159
  26. package/bin/cli/iterate-checks-formatter.mjs +1 -1
  27. package/bin/cli/iterate-flags.d.mts +2 -4
  28. package/bin/cli/iterate-flags.mjs +4 -20
  29. package/bin/cli/iterate-formatter.d.mts +1 -1
  30. package/bin/cli/iterate-formatter.mjs +6 -6
  31. package/bin/cli/iterate-instructions.d.mts +1 -1
  32. package/bin/cli/iterate-instructions.mjs +5 -6
  33. package/bin/cli/iterate-lean.mjs +32 -40
  34. package/bin/cli/iterate-verbose.mjs +1 -1
  35. package/bin/cli/journal-formatter.mjs +0 -3
  36. package/bin/cli/journal-handler.d.mts +1 -1
  37. package/bin/cli/journal-handler.mjs +2 -1
  38. package/bin/cli/mutate-formatter.mjs +0 -9
  39. package/bin/cli/next-check-format.d.mts +0 -4
  40. package/bin/cli/next-check-format.mjs +0 -4
  41. package/bin/cli/poll-handler.d.mts +3 -0
  42. package/bin/cli/poll-handler.mjs +88 -47
  43. package/bin/cli/poll-summary-emitter.mjs +2 -2
  44. package/bin/cli/poll-summary-formatter.mjs +5 -2
  45. package/bin/cli/poll-targets.d.mts +2 -2
  46. package/bin/cli/poll-targets.mjs +15 -35
  47. package/bin/cli/removed-flags.d.mts +3 -0
  48. package/bin/cli/removed-flags.mjs +24 -0
  49. package/bin/cli/rule-auto-resolve-lines.d.mts +3 -0
  50. package/bin/cli/rule-auto-resolve-lines.mjs +12 -0
  51. package/bin/cli/runner.d.mts +1 -1
  52. package/bin/cli/runner.mjs +2 -2
  53. package/bin/cli/stack-layer-view.d.mts +2 -1
  54. package/bin/cli/stack-overview.d.mts +0 -1
  55. package/bin/cli/stack-overview.mjs +4 -2
  56. package/bin/cli/{fix-formatter-extra.d.mts → triage-formatter-extra.d.mts} +1 -2
  57. package/bin/cli/{fix-formatter-extra.mjs → triage-formatter-extra.mjs} +0 -6
  58. package/bin/cli/triage-formatter.d.mts +4 -0
  59. package/bin/cli/{fix-formatter.mjs → triage-formatter.mjs} +31 -42
  60. package/bin/cli/unknown-flags.d.mts +6 -0
  61. package/bin/cli/unknown-flags.mjs +29 -0
  62. package/bin/cli-parser.mjs +41 -62
  63. package/bin/commands/check-activity.d.mts +8 -0
  64. package/bin/commands/check-activity.mjs +26 -0
  65. package/bin/commands/check-annotations.d.mts +1 -1
  66. package/bin/commands/check-annotations.mjs +3 -2
  67. package/bin/commands/check-review-budget.d.mts +1 -1
  68. package/bin/commands/check-review-budget.mjs +1 -1
  69. package/bin/commands/check-wait-detectors.d.mts +1 -1
  70. package/bin/commands/check-wait-detectors.mjs +12 -1
  71. package/bin/commands/check.d.mts +1 -1
  72. package/bin/commands/check.mjs +13 -8
  73. package/bin/commands/commit-suggestion-instruction.d.mts +2 -2
  74. package/bin/commands/commit-suggestion-instruction.mjs +3 -3
  75. package/bin/commands/iterate/api-usage.mjs +8 -8
  76. package/bin/commands/iterate/check-instructions.d.mts +4 -4
  77. package/bin/commands/iterate/check-instructions.mjs +8 -8
  78. package/bin/commands/iterate/classify.mjs +2 -2
  79. package/bin/commands/iterate/escalate.mjs +6 -6
  80. package/bin/commands/iterate/index.mjs +20 -23
  81. package/bin/commands/iterate/merge-plan.mjs +3 -3
  82. package/bin/commands/iterate/merge-state.mjs +4 -7
  83. package/bin/commands/iterate/native-stack-rebase.mjs +1 -1
  84. package/bin/commands/iterate/render.d.mts +1 -1
  85. package/bin/commands/iterate/render.mjs +2 -2
  86. package/bin/commands/iterate/stall.mjs +11 -9
  87. package/bin/commands/iterate/{fix-loop-instruction.mjs → triage-loop-instruction.mjs} +7 -3
  88. package/bin/commands/iterate/{fix-code.d.mts → triage.d.mts} +2 -2
  89. package/bin/commands/iterate/{fix-code.mjs → triage.mjs} +14 -23
  90. package/bin/commands/iterate/unreported-required.mjs +2 -5
  91. package/bin/commands/journal/index.d.mts +1 -3
  92. package/bin/commands/journal/index.mjs +1 -1
  93. package/bin/commands/mark-files-as-viewed.d.mts +1 -3
  94. package/bin/commands/mark-files-as-viewed.mjs +1 -1
  95. package/bin/commands/next-check.d.mts +2 -2
  96. package/bin/commands/next-check.mjs +4 -2
  97. package/bin/commands/poll-progress.mjs +1 -1
  98. package/bin/commands/poll-summary-explicit-instructions.mjs +1 -1
  99. package/bin/commands/poll-summary-instructions.mjs +7 -7
  100. package/bin/commands/poll-summary-signature.d.mts +6 -0
  101. package/bin/commands/poll-summary-signature.mjs +19 -2
  102. package/bin/commands/poll-summary.mjs +11 -4
  103. package/bin/commands/poll.d.mts +1 -1
  104. package/bin/commands/poll.mjs +4 -4
  105. package/bin/commands/ready-delay.d.mts +1 -0
  106. package/bin/commands/ready-delay.mjs +8 -3
  107. package/bin/commands/resolve-mutate.d.mts +1 -1
  108. package/bin/commands/resolve-mutate.mjs +1 -1
  109. package/bin/commands/rest-stack-merge-readiness.mjs +1 -1
  110. package/bin/commands/rule-auto-resolve-format.d.mts +7 -0
  111. package/bin/commands/rule-auto-resolve-format.mjs +11 -4
  112. package/bin/commands/rule-auto-resolve.d.mts +14 -2
  113. package/bin/commands/single-tick.d.mts +5 -0
  114. package/bin/commands/single-tick.mjs +7 -0
  115. package/bin/commands/stack-drain.mjs +1 -1
  116. package/bin/commands/stack-merge-flag.mjs +1 -1
  117. package/bin/commands/stack-stall.d.mts +2 -2
  118. package/bin/commands/stack-stall.mjs +2 -2
  119. package/bin/commands/stack-work.d.mts +2 -2
  120. package/bin/commands/stack-work.mjs +2 -2
  121. package/bin/commands/suggestion-patch-item.d.mts +0 -1
  122. package/bin/commands/suggestion-patch-item.mjs +0 -12
  123. package/bin/commands/suggestion-patches.d.mts +2 -2
  124. package/bin/commands/suggestion-patches.mjs +1 -1
  125. package/bin/commands/tick-instructions.d.mts +9 -0
  126. package/bin/commands/tick-instructions.mjs +23 -0
  127. package/bin/commands/tick.d.mts +15 -0
  128. package/bin/commands/{event-mode.mjs → tick.mjs} +39 -55
  129. package/bin/comments/minimize-policy.mjs +1 -3
  130. package/bin/comments/resolve.d.mts +0 -23
  131. package/bin/comments/resolve.mjs +0 -4
  132. package/bin/comments/review-output-budget.d.mts +1 -1
  133. package/bin/comments/review-output-budget.mjs +1 -1
  134. package/bin/comments/sha-poll.mjs +3 -1
  135. package/bin/comments/thread-visibility.d.mts +6 -0
  136. package/bin/comments/thread-visibility.mjs +30 -15
  137. package/bin/config/default-bot-usernames.d.mts +2 -0
  138. package/bin/config/default-bot-usernames.mjs +15 -0
  139. package/bin/config/load.d.mts +4 -138
  140. package/bin/config/load.mjs +88 -443
  141. package/bin/config/merge-command-args.mjs +2 -2
  142. package/bin/config/merge-method.d.mts +1 -2
  143. package/bin/config/merge-method.mjs +1 -8
  144. package/bin/config/renames.d.mts +8 -0
  145. package/bin/config/renames.mjs +87 -0
  146. package/bin/config/resolve.d.mts +31 -0
  147. package/bin/config/resolve.mjs +89 -0
  148. package/bin/config/schema.d.mts +161 -0
  149. package/bin/config/schema.mjs +168 -0
  150. package/bin/exit-codes.d.mts +1 -1
  151. package/bin/exit-codes.mjs +3 -3
  152. package/bin/github/batch-parse-suites.d.mts +14 -0
  153. package/bin/github/batch-parse-suites.mjs +4 -1
  154. package/bin/github/batch-parser-helpers.mjs +3 -0
  155. package/bin/github/check-annotation-cache.d.mts +5 -0
  156. package/bin/github/check-annotation-cache.mjs +6 -3
  157. package/bin/github/fingerprint.mjs +4 -0
  158. package/bin/github/poll-summary-annotation-probe.d.mts +5 -0
  159. package/bin/github/poll-summary-annotation-probe.mjs +17 -3
  160. package/bin/github/poll-summary-annotations.d.mts +14 -0
  161. package/bin/github/poll-summary-annotations.mjs +75 -0
  162. package/bin/github/poll-summary-blocking-reviewer.d.mts +2 -0
  163. package/bin/github/poll-summary-blocking-reviewer.mjs +9 -0
  164. package/bin/github/poll-summary-check-blockers.mjs +1 -1
  165. package/bin/github/poll-summary-checks.d.mts +1 -0
  166. package/bin/github/poll-summary-checks.mjs +20 -2
  167. package/bin/github/poll-summary-command.mjs +8 -6
  168. package/bin/github/poll-summary-fingerprint.d.mts +7 -0
  169. package/bin/github/poll-summary-fingerprint.mjs +7 -0
  170. package/bin/github/poll-summary-projector.d.mts +3 -1
  171. package/bin/github/poll-summary-projector.mjs +14 -25
  172. package/bin/github/poll-summary-queue-removal.d.mts +2 -0
  173. package/bin/github/poll-summary-queue-removal.mjs +11 -0
  174. package/bin/github/poll-summary-readiness.mjs +1 -0
  175. package/bin/github/poll-summary-review-parity.d.mts +24 -0
  176. package/bin/github/poll-summary-review-parity.mjs +82 -0
  177. package/bin/github/poll-summary-review.d.mts +11 -2
  178. package/bin/github/poll-summary-review.mjs +88 -60
  179. package/bin/github/poll-summary-route.mjs +9 -9
  180. package/bin/github/poll-summary-row-error.d.mts +16 -0
  181. package/bin/github/poll-summary-row-error.mjs +74 -0
  182. package/bin/github/poll-summary-rule-auto-resolve.d.mts +32 -0
  183. package/bin/github/poll-summary-rule-auto-resolve.mjs +119 -0
  184. package/bin/github/poll-summary-rule-handoff.d.mts +7 -0
  185. package/bin/github/poll-summary-rule-handoff.mjs +20 -0
  186. package/bin/github/poll-summary-rule-items.d.mts +20 -0
  187. package/bin/github/poll-summary-rule-items.mjs +28 -0
  188. package/bin/github/poll-summary-unreported.mjs +1 -1
  189. package/bin/github/poll-summary.mjs +16 -8
  190. package/bin/github/queries.d.mts +1 -1
  191. package/bin/github/queries.mjs +1 -1
  192. package/bin/github/rest-reader-core.mjs +13 -2
  193. package/bin/github/rest-summary-read.mjs +12 -1
  194. package/bin/mcp/server.mjs +48 -54
  195. package/bin/merge-status/derive.mjs +1 -1
  196. package/bin/state/durable-state.d.mts +1 -3
  197. package/bin/state/durable-state.mjs +2 -8
  198. package/bin/state/fix-attempts.d.mts +2 -2
  199. package/bin/state/fix-attempts.mjs +1 -1
  200. package/bin/state/merge-request.mjs +1 -1
  201. package/bin/state/pr-fingerprint.mjs +4 -11
  202. package/bin/state/seen-comments.d.mts +4 -5
  203. package/bin/state/seen-comments.mjs +8 -14
  204. package/bin/state/stack-stall.d.mts +1 -1
  205. package/bin/state/stack-stall.mjs +1 -1
  206. package/bin/state/stall-state-store.d.mts +1 -1
  207. package/bin/state/stall-state-store.mjs +1 -1
  208. package/bin/types/escalate.d.mts +2 -2
  209. package/bin/types/github.d.mts +2 -0
  210. package/bin/types/iterate.d.mts +12 -26
  211. package/bin/types/merge-queue.d.mts +2 -2
  212. package/bin/types/next-check.d.mts +1 -1
  213. package/bin/types/poll-summary.d.mts +26 -6
  214. package/bin/types/report.d.mts +2 -2
  215. package/bin/types/suggestion-patch.d.mts +1 -8
  216. package/package.json +3 -2
  217. package/plugins/pr-shepherd/.claude-plugin/plugin.json +1 -1
  218. package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
  219. package/plugins/pr-shepherd/.codex.mcp.json +1 -1
  220. package/plugins/pr-shepherd/.mcp.json +1 -1
  221. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +6 -6
  222. package/plugins/pr-shepherd/skills/pr-shepherd/references/ci-failure-triage.md +1 -1
  223. package/plugins/pr-shepherd/skills/pr-shepherd/references/{cloud-event-loop.md → event-loop.md} +5 -5
  224. package/plugins/pr-shepherd/skills/pr-shepherd/references/mcp-fallback.md +3 -3
  225. package/plugins/pr-shepherd/skills/pr-shepherd/references/merge-queue-ejection.md +1 -1
  226. package/plugins/pr-shepherd/skills/pr-shepherd/references/suggestion-patches.md +1 -1
  227. package/plugins/pr-shepherd/skills/pr-shepherd/references/{fix-code-loop.md → triage-loop.md} +3 -3
  228. package/plugins/pr-shepherd/skills/reduce-pr-noise/SKILL.md +1 -1
  229. package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +2 -2
  230. package/plugins/pr-shepherd/skills/reduce-pr-noise/references/settings.md +11 -11
  231. package/pr-shepherd.schema.json +361 -0
  232. package/bin/cli/event-state-scope.d.mts +0 -19
  233. package/bin/cli/event-state-scope.mjs +0 -60
  234. package/bin/cli/fix-formatter.d.mts +0 -4
  235. package/bin/commands/commit-suggestion.d.mts +0 -8
  236. package/bin/commands/commit-suggestion.mjs +0 -26
  237. package/bin/commands/event-instructions.d.mts +0 -11
  238. package/bin/commands/event-instructions.mjs +0 -27
  239. package/bin/commands/event-mode.d.mts +0 -14
  240. package/bin/commands/poll-mode.d.mts +0 -8
  241. package/bin/commands/poll-mode.mjs +0 -14
  242. package/bin/config.json +0 -68
  243. package/bin/types/protected-run.d.mts +0 -6
  244. package/bin/types/protected-run.mjs +0 -1
  245. /package/bin/commands/iterate/{fix-loop-instruction.d.mts → triage-loop-instruction.d.mts} +0 -0
@@ -8,7 +8,7 @@ import { buildWaitLog, buildTerminalCancelResult, blockedCancelNote } from "./he
8
8
  import { classifyReviewSummaries } from "./classify.mjs";
9
9
  import { applyStallGuard } from "./stall.mjs";
10
10
  import { clearStallState } from "../../state/iterate-stall.mjs";
11
- import { handleFixCode } from "./fix-code.mjs";
11
+ import { handleTriage } from "./triage.mjs";
12
12
  import { normalizeBotUsernames } from "../../comments/authors.mjs";
13
13
  import { autoMinimizeComments } from "../../comments/resolve.mjs";
14
14
  import { hasCheckDrivenActionableWork } from "../check-annotations.mjs";
@@ -60,24 +60,21 @@ async function attachEditedComments(result, tick, opts) {
60
60
  }
61
61
  async function runIterateCore(opts, tick) {
62
62
  const config = loadConfig();
63
- const botUsernames = normalizeBotUsernames(config.botUsernames);
64
- const readyDelaySeconds = opts.readyDelaySeconds ?? config.watch.readyDelayMinutes * 60;
65
- const stallTimeoutSeconds = opts.stallTimeoutSeconds ?? config.iterate.stallTimeoutMinutes * 60;
63
+ const botUsernames = normalizeBotUsernames(config["bot-usernames"]);
64
+ const readyDelaySeconds = opts.readyDelaySeconds ?? config.iterate["ready-delay-minutes"] * 60;
65
+ const stallTimeoutSeconds = opts.stallTimeoutSeconds ?? config.iterate["stall-timeout-minutes"] * 60;
66
66
  const prNumber = opts.prNumber ?? (await getCurrentPrNumber());
67
67
  if (prNumber === null) {
68
68
  throw new ShepherdError("No open PR found for current branch. Pass a PR number explicitly.", EXIT.UNAVAILABLE);
69
69
  }
70
- const neverCancelRuns = opts.neverCancelRuns ?? config.actions.neverCancelRuns;
71
70
  const checkContext = createCheckExecutionContext(readyDelaySeconds);
72
71
  const report = await runCheck({
73
72
  ...opts,
74
73
  prNumber,
75
- // Outdated Shepherd-visible threads are always resolved by iterate. The
76
- // old actions.autoResolveOutdated switch is retained only as an ignored
77
- // compatibility key in the config loader.
74
+ // Outdated Shepherd-visible threads are always resolved by iterate.
78
75
  autoResolve: true,
79
- autoMinimizeSuppressed: config.actions.autoMinimizeSuppressed,
80
- reviewOutputMaxChars: config.iterate.reviewOutputMaxChars,
76
+ autoMinimizeSuppressed: config.actions["auto-minimize-suppressed"],
77
+ reviewOutputMaxChars: config.iterate["review-output-max-chars"],
81
78
  }, checkContext);
82
79
  tick.report = report;
83
80
  const [repoOwner, repoName] = report.repo.split("/");
@@ -107,7 +104,7 @@ async function runIterateCore(opts, tick) {
107
104
  firstLook: report.firstLookSummaries,
108
105
  seen: report.reviewSummaries,
109
106
  edited: report.editedSummaries,
110
- }, report.approvedReviews, config.iterate.minimizeApprovals, config.iterate.minimizeComments, botUsernames, [
107
+ }, report.approvedReviews, config.iterate["minimize-approvals"], config.iterate["minimize-comments"], botUsernames, [
111
108
  ...report.threads.actionable,
112
109
  ...report.threads.resolutionOnly,
113
110
  ...(report.heldThreadReviewIds ?? []).map((reviewId) => ({ reviewId })),
@@ -128,7 +125,7 @@ async function runIterateCore(opts, tick) {
128
125
  }
129
126
  // A first look at an already-minimized comment is only an acknowledgment. Edited PR comments
130
127
  // (report.comments.edited) are neither: they never block readiness or restart the ready delay.
131
- // Review items held back by iterate.reviewOutputMaxChars keep the PR out of ready/merge: a
128
+ // Review items held back by iterate.review-output-max-chars keep the PR out of ready/merge: a
132
129
  // capped tick that shows only first-look comments still counts, since held work follows.
133
130
  const hasReadinessWork = (report.reviewItems !== undefined && report.comments.firstLook.length > 0) ||
134
131
  report.threads.actionable.length > 0 ||
@@ -142,7 +139,7 @@ async function runIterateCore(opts, tick) {
142
139
  reviewSummaryIds.length > 0 ||
143
140
  firstLookSummaries.length > 0 ||
144
141
  editedSummaries.length > 0 ||
145
- (config.iterate.minimizeApprovals && surfacedApprovals.length > 0);
142
+ (config.iterate["minimize-approvals"] && surfacedApprovals.length > 0);
146
143
  const hasActionableWork = hasReadinessWork || report.comments.firstLook.length > 0;
147
144
  const activeMerge = Boolean(opts.merge &&
148
145
  (report.mergeQueue?.inQueue ||
@@ -183,12 +180,12 @@ async function runIterateCore(opts, tick) {
183
180
  const checkDrivenActionableWork = hasCheckDrivenActionableWork(reportForWork.checks, report.mergeStatus.status);
184
181
  const deferWhileQueued = opts.merge === true &&
185
182
  report.mergeQueue?.inQueue === true &&
186
- config.actions.workWhileQueued !== true;
183
+ config.actions["work-while-queued"] !== true;
187
184
  if (hasActionableWork && !(deferWhileQueued && !checkDrivenActionableWork)) {
188
- return handleFixCode({
185
+ return handleTriage({
189
186
  base,
190
187
  report: reportForWork,
191
- opts: { ...opts, prNumber, neverCancelRuns },
188
+ opts: { ...opts, prNumber },
192
189
  headSha,
193
190
  stallKey,
194
191
  prNumber,
@@ -208,10 +205,10 @@ async function runIterateCore(opts, tick) {
208
205
  });
209
206
  }
210
207
  if (unreportedRepair.length > 0 && staleAncestry) {
211
- return handleFixCode({
208
+ return handleTriage({
212
209
  base,
213
210
  report: reportForWork,
214
- opts: { ...opts, prNumber, neverCancelRuns },
211
+ opts: { ...opts, prNumber },
215
212
  headSha,
216
213
  stallKey,
217
214
  prNumber,
@@ -241,15 +238,15 @@ async function runIterateCore(opts, tick) {
241
238
  firstLookSummaries,
242
239
  editedSummaries,
243
240
  surfacedApprovals,
244
- minimizeApprovals: config.iterate.minimizeApprovals,
241
+ minimizeApprovals: config.iterate["minimize-approvals"],
245
242
  });
246
243
  if (mergeStateResult)
247
244
  return annotateBlockedWait(mergeStateResult, blockerGate);
248
245
  if (staleAncestry) {
249
- return handleFixCode({
246
+ return handleTriage({
250
247
  base,
251
248
  report: reportForWork,
252
- opts: { ...opts, prNumber, neverCancelRuns },
249
+ opts: { ...opts, prNumber },
253
250
  headSha,
254
251
  stallKey,
255
252
  prNumber,
@@ -287,7 +284,7 @@ async function runIterateCore(opts, tick) {
287
284
  escalate: { ...escalation, humanMessage: buildEscalateHumanMessage(escalation, report.pr) },
288
285
  };
289
286
  }
290
- const autoMarkReady = !opts.noAutoMarkReady && config.actions.autoMarkReady;
287
+ const autoMarkReady = !opts.noAutoMarkReady && config["mark-ready"].auto;
291
288
  if (canMarkReady && !autoMarkReady) {
292
289
  await clearReadyDelay(report.pr, repoOwner, repoName);
293
290
  await clearStallState(stallKey);
@@ -307,7 +304,7 @@ async function runIterateCore(opts, tick) {
307
304
  const receipt = receiptCurrent
308
305
  ? "written"
309
306
  : await recordReadyReceipt(receiptKey, report, checkContext);
310
- // Aggregate --stack routing trusts only a layer's receipt, so an unwritten
307
+ // Aggregate `stack` routing trusts only a layer's receipt, so an unwritten
311
308
  // one keeps the elapsed marker and retries next tick. A one-PR receipt
312
309
  // only lets a rerun skip the wait, so its failure never changes the action.
313
310
  // A layer GitHub reports BLOCKED gets no receipt, so aggregate routing
@@ -7,7 +7,7 @@ import { getGithubTransport } from "../../github/transport.mjs";
7
7
  const ENQUEUE_MUTATION = "mutation EnqueuePullRequest($pullRequestId: ID!, $expectedHeadOid: GitObjectID!) { enqueuePullRequest(input: { pullRequestId: $pullRequestId, expectedHeadOid: $expectedHeadOid }) { mergeQueueEntry { id } } }";
8
8
  export function buildMergeCommandPlan(input) {
9
9
  if (input.transport === "rest" || getGithubTransport() === "rest") {
10
- const configured = configuredMergeMethod(loadConfig().merge ?? {});
10
+ const configured = configuredMergeMethod(loadConfig().merge);
11
11
  if (!input.queue && input.queueKnown !== true && configured)
12
12
  return {
13
13
  unavailable: "REST cannot verify merge-queue policy and cannot apply a configured direct merge method to an automatic merge request. Refresh branch policy before merging.",
@@ -70,10 +70,10 @@ export function buildMergeCommandPlan(input) {
70
70
  };
71
71
  }
72
72
  const mergeConfig = loadConfig().merge;
73
- const configuredArgs = mergeConfig?.commandArgs ?? [];
73
+ const configuredArgs = mergeConfig["command-args"];
74
74
  const decision = chooseMergeMethod({
75
75
  allowed: input.allowedMergeMethods,
76
- configured: configuredMergeMethod(mergeConfig ?? {}),
76
+ configured: configuredMergeMethod(mergeConfig),
77
77
  fallback: "merge",
78
78
  });
79
79
  if ("unavailable" in decision)
@@ -6,14 +6,14 @@ import { buildPrShepherdCommand } from "../../cli/runner.mjs";
6
6
  import { inlineCode } from "../../util/markdown.mjs";
7
7
  /**
8
8
  * A one-PR poll cannot prove the layers below it merged or that its PR number is a safe merge
9
- * selector. Route it through the aggregate stack selector, which merges one bottom layer at a time.
9
+ * selector. Route it through the aggregate stack command, which merges one bottom layer at a time.
10
10
  */
11
11
  function buildStackedRouteResult(base, report, stack) {
12
12
  const prUrl = formatPrUrl(report.repo, report.pr);
13
13
  return {
14
14
  ...base,
15
- action: "fix_code",
16
- fix: {
15
+ action: "triage",
16
+ triage: {
17
17
  threads: [],
18
18
  resolutionOnlyThreads: [],
19
19
  actionableComments: [],
@@ -31,14 +31,11 @@ function buildStackedRouteResult(base, report, stack) {
31
31
  },
32
32
  instructions: [
33
33
  `PR #${report.pr} is layer ${stack.position} of ${stack.size} in native stack #${stack.number}; do not run \`gh pr merge\` for this layer.`,
34
- `Run ${inlineCode(buildPrShepherdCommand(["--stack", prUrl, "--until-terminal", "--merge"]).text)} to reconcile the stack and run each bottom-layer merge command it emits.`,
34
+ `Run ${inlineCode(buildPrShepherdCommand(["stack", prUrl, "--until-terminal", "--merge"]).text)} to reconcile the stack and run each bottom-layer merge command it emits.`,
35
35
  ],
36
- inProgressRunIds: [],
37
- protectedRuns: [],
38
36
  firstLookThreads: [],
39
37
  firstLookComments: [],
40
38
  },
41
- cancelled: [],
42
39
  };
43
40
  }
44
41
  export function buildReadyMergeOutcome(enabled, readyElapsed, base, report) {
@@ -15,7 +15,7 @@ export function buildNativeStackRebaseInstruction(repo, stackNumber, start) {
15
15
  : "trunk" in start
16
16
  ? `trunk \`${start.trunk}\``
17
17
  : `bottom open layer PR #${start.bottomPr}`;
18
- return `Use the repository's stack-update procedure for native stack #${stackNumber} in \`${repo}\`, starting at ${boundary} and preserving the ordered parent boundaries of every affected upper layer. Read membership with REST-backed Shepherd \`--stack\` output and update and push affected branches using the caller's git workflow. ${playbookPointer("Branch update")}`;
18
+ return `Use the repository's stack-update procedure for native stack #${stackNumber} in \`${repo}\`, starting at ${boundary} and preserving the ordered parent boundaries of every affected upper layer. Read membership with REST-backed Shepherd \`stack\` output and update and push affected branches using the caller's git workflow. ${playbookPointer("Branch update")}`;
19
19
  }
20
20
  const [checkout, command] = "parentBranch" in start
21
21
  ? [
@@ -7,7 +7,7 @@ import type { InstructionStyle } from "../../config/load.mts";
7
7
  * if it is not. `apply review` reads that HEAD itself with a read-only `git rev-parse HEAD`.
8
8
  */
9
9
  export declare function renderResolveCommand(rc: ResolveCommand): string;
10
- export declare function buildFixInstructions(threads: AgentThread[], actionableComments: AgentComment[], checks: AgentCheck[], changesRequestedReviews: Review[], baseBranch: string, resolveCommand: ResolveCommand, hasConflicts: boolean, prReference: string | number, _cancelledCount: number, firstLookThreads?: FirstLookThread[], firstLookComments?: FirstLookComment[], firstLookSummaries?: Review[], editedSummaries?: Review[], _inProgressRunIds?: string[], resolutionOnlyThreads?: ReviewThread[], resolveOnlyCommand?: ResolveCommand, behindBaseHint?: string, // iterate.behindBaseHint — see buildBehindBaseHintInstruction
10
+ export declare function buildFixInstructions(threads: AgentThread[], actionableComments: AgentComment[], checks: AgentCheck[], changesRequestedReviews: Review[], baseBranch: string, resolveCommand: ResolveCommand, hasConflicts: boolean, prReference: string | number, firstLookThreads?: FirstLookThread[], firstLookComments?: FirstLookComment[], firstLookSummaries?: Review[], editedSummaries?: Review[], resolutionOnlyThreads?: ReviewThread[], resolveOnlyCommand?: ResolveCommand, behindBaseHint?: string, // iterate.behind-base-hint — see buildBehindBaseHintInstruction
11
11
  isBehind?: boolean, _viewerCanUpdate?: boolean, hasExhaustedWorkflowRerun?: boolean, stackRebase?: string, // native stack layers rebase with gh-stack, not branch by branch
12
12
  queueEjection?: QueueEjectionRecovery, // current merge-queue removal with failing queue checks
13
13
  instructionStyle?: InstructionStyle): string[];
@@ -5,7 +5,7 @@ import { buildCommitSuggestionInstruction } from "../commit-suggestion-instructi
5
5
  import { partitionFixThreads } from "./fix-instruction-threads.mjs";
6
6
  import { buildBranchPushInstruction, buildConflictInstruction } from "./native-stack-rebase.mjs";
7
7
  import { queueEjectionSteps } from "./queue-recovery-instructions.mjs";
8
- import { buildPushSteps } from "./fix-loop-instruction.mjs";
8
+ import { buildPushSteps } from "./triage-loop-instruction.mjs";
9
9
  /**
10
10
  * Render a resolve command as a shell snippet. Appends `--require-sha HEAD` when set: run after
11
11
  * the push step, the local HEAD is the pushed PR head, and `apply review` rejects the mutations
@@ -16,7 +16,7 @@ export function renderResolveCommand(rc) {
16
16
  return rc.requiresHeadSha ? `${command} ${REQUIRE_HEAD_SHA}` : command;
17
17
  }
18
18
  const REQUIRE_HEAD_SHA = "--require-sha HEAD";
19
- export function buildFixInstructions(threads, actionableComments, checks, changesRequestedReviews, baseBranch, resolveCommand, hasConflicts, prReference, _cancelledCount, firstLookThreads = [], firstLookComments = [], firstLookSummaries = [], editedSummaries = [], _inProgressRunIds = [], resolutionOnlyThreads = [], resolveOnlyCommand, behindBaseHint = "", // iterate.behindBaseHint — see buildBehindBaseHintInstruction
19
+ export function buildFixInstructions(threads, actionableComments, checks, changesRequestedReviews, baseBranch, resolveCommand, hasConflicts, prReference, firstLookThreads = [], firstLookComments = [], firstLookSummaries = [], editedSummaries = [], resolutionOnlyThreads = [], resolveOnlyCommand, behindBaseHint = "", // iterate.behind-base-hint — see buildBehindBaseHintInstruction
20
20
  isBehind = false, _viewerCanUpdate = false, hasExhaustedWorkflowRerun = false, stackRebase, // native stack layers rebase with gh-stack, not branch by branch
21
21
  queueEjection, // current merge-queue removal with failing queue checks
22
22
  instructionStyle = "inline") {
@@ -5,25 +5,27 @@ import { buildEscalateSuggestion, buildEscalateHumanMessage, formatDurationAppro
5
5
  import { checksWithActionableAnnotations } from "../check-annotations.mjs";
6
6
  import { formatPrUrl } from "../../pr-reference.mjs";
7
7
  function pendingReviewCommandsFromResult(result) {
8
- if (result.action !== "fix_code")
8
+ if (result.action !== "triage")
9
9
  return undefined;
10
10
  const pending = {
11
- ...(result.fix.resolveOnlyCommand?.hasMutations && {
12
- resolveOnlyCommand: result.fix.resolveOnlyCommand,
11
+ ...(result.triage.resolveOnlyCommand?.hasMutations && {
12
+ resolveOnlyCommand: result.triage.resolveOnlyCommand,
13
+ }),
14
+ ...(result.triage.resolveCommand.hasMutations && {
15
+ resolveCommand: result.triage.resolveCommand,
13
16
  }),
14
- ...(result.fix.resolveCommand.hasMutations && { resolveCommand: result.fix.resolveCommand }),
15
17
  };
16
18
  return Object.keys(pending).length > 0 ? pending : undefined;
17
19
  }
18
20
  function surfacedSummariesFromResult(result) {
19
- if (result.action !== "fix_code")
21
+ if (result.action !== "triage")
20
22
  return {};
21
23
  return {
22
- ...(result.fix.firstLookSummaries.length > 0 && {
23
- firstLookSummaries: result.fix.firstLookSummaries,
24
+ ...(result.triage.firstLookSummaries.length > 0 && {
25
+ firstLookSummaries: result.triage.firstLookSummaries,
24
26
  }),
25
- ...(result.fix.editedSummaries.length > 0 && {
26
- editedSummaries: result.fix.editedSummaries,
27
+ ...(result.triage.editedSummaries.length > 0 && {
28
+ editedSummaries: result.triage.editedSummaries,
27
29
  }),
28
30
  };
29
31
  }
@@ -1,7 +1,7 @@
1
1
  import { renderShellCommand } from "../../cli/runner.mjs";
2
2
  import { loadConfig } from "../../config/load.mjs";
3
3
  import { playbookPointer } from "../playbook-pointer.mjs";
4
- const FIX_CODE_LOOP_PLAYBOOK = "Fix-code loop";
4
+ const TRIAGE_LOOP_PLAYBOOK = "Triage loop";
5
5
  /** The generic push stays separate from conflict and queue-recovery push instructions. */
6
6
  export function buildPushSteps(style, genericPush) {
7
7
  if (!genericPush)
@@ -9,6 +9,10 @@ export function buildPushSteps(style, genericPush) {
9
9
  const push = "Commit and push any changes.";
10
10
  if (style === "inline")
11
11
  return [push];
12
- const cli = renderShellCommand([...loadConfig().cliCommand, "playbook", FIX_CODE_LOOP_PLAYBOOK]);
13
- return [`${push} ${playbookPointer(FIX_CODE_LOOP_PLAYBOOK)} CLI: \`${cli}\`.`];
12
+ const cli = renderShellCommand([
13
+ ...loadConfig()["cli-command"],
14
+ "playbook",
15
+ TRIAGE_LOOP_PLAYBOOK,
16
+ ]);
17
+ return [`${push} ${playbookPointer(TRIAGE_LOOP_PLAYBOOK)} CLI: \`${cli}\`.`];
14
18
  }
@@ -1,6 +1,6 @@
1
1
  import type { IterateCommandOptions, IterateResult, IterateResultBase, Review, ShepherdReport } from "../../types.mts";
2
2
  import type { NormalizedBotUsernames } from "../../comments/authors.mts";
3
- interface HandleFixCodeContext {
3
+ interface HandleTriageContext {
4
4
  base: IterateResultBase;
5
5
  report: ShepherdReport;
6
6
  opts: IterateCommandOptions;
@@ -25,5 +25,5 @@ interface HandleFixCodeContext {
25
25
  /** Verified stack-repair guidance, when ancestry is stale. */
26
26
  repairInstructions?: string[];
27
27
  }
28
- export declare function handleFixCode(ctx: HandleFixCodeContext): Promise<IterateResult>;
28
+ export declare function handleTriage(ctx: HandleTriageContext): Promise<IterateResult>;
29
29
  export {};
@@ -77,22 +77,22 @@ function pendingReviewCommands(resolveCommand, resolveOnlyCommand) {
77
77
  };
78
78
  return Object.keys(pending).length > 0 ? pending : undefined;
79
79
  }
80
- export async function handleFixCode(ctx) {
81
- const result = await handleFixCodeTick(ctx);
80
+ export async function handleTriage(ctx) {
81
+ const result = await handleTriageTick(ctx);
82
82
  // Every escalation from a capped tick carries the rollup: the reader sees a subset.
83
83
  const { reviewItems } = ctx.report;
84
84
  if (result.action !== "escalate" || reviewItems === undefined)
85
85
  return result;
86
86
  return { ...result, escalate: { ...result.escalate, reviewItems } };
87
87
  }
88
- async function handleFixCodeTick(ctx) {
88
+ async function handleTriageTick(ctx) {
89
89
  const { base, report, opts, headSha, stallKey, prNumber, stallTimeoutSeconds, repoOwner, repoName, reviewSummaryIds, firstLookSummaries, editedSummaries, surfacedApprovals, botUsernames, releasedCheckNames = EMPTY_RELEASED, ruleAutoResolveThreadIds, repairInstructions, } = ctx;
90
90
  const prReference = formatPrUrl(report.repo, prNumber);
91
91
  const failingChecks = report.checks.failing;
92
92
  const annotatedExtra = checksWithActionableAnnotations(report).filter((c) => c.category !== "failing");
93
93
  const allThreads = [...report.threads.actionable, ...report.threads.resolutionOnly];
94
94
  const ruleAutoResolveIds = new Set(ruleAutoResolveThreadIds ?? []);
95
- const resolveOtherHumanThreads = loadConfig().iterate.resolveOtherHumanThreads ?? "none";
95
+ const resolveOtherHumanThreads = loadConfig().iterate["resolve-other-human-threads"] ?? "none";
96
96
  const routedThreadMutations = buildThreadMutationRouting(allThreads, botUsernames, [...ruleAutoResolveIds], resolveOtherHumanThreads);
97
97
  const replyIdSet = new Set(routedThreadMutations.replyThreadIds);
98
98
  const resolveIdSet = new Set(routedThreadMutations.resolveThreadIds);
@@ -107,12 +107,11 @@ async function handleFixCodeTick(ctx) {
107
107
  ((thread.path !== null && thread.line !== null) ||
108
108
  threadHasAuthorizedMutation(thread, replyIdSet, resolveIdSet)));
109
109
  const retryableActionableThreads = mutationActionableThreads.filter((thread) => thread.path !== null && thread.line !== null);
110
- const protectedRuns = [];
111
110
  const stored = await readFixAttempts({ owner: repoOwner, repo: repoName, pr: prNumber });
112
111
  await aliasThreadFixAttempts({ owner: repoOwner, name: repoName }, prNumber, retryableActionableThreads.map(({ id }) => id), stored);
113
- const countFixCodeAttempt = opts.persistSeen !== false;
112
+ const countTriageAttempt = opts.persistSeen !== false;
114
113
  const priorThreadAttempts = previousFixAttempts(stored, retryableActionableThreads);
115
- const { threadAttempts, threadBodyHashes } = nextFixAttempts(stored, retryableActionableThreads, countFixCodeAttempt);
114
+ const { threadAttempts, threadBodyHashes } = nextFixAttempts(stored, retryableActionableThreads, countTriageAttempt);
116
115
  const resolutionOnlyThreadsForWork = report.threads.resolutionOnly.filter((thread) => !skippedThreadIds.has(thread.id) &&
117
116
  ((thread.path !== null && thread.line !== null) ||
118
117
  threadHasAuthorizedMutation(thread, replyIdSet, resolveIdSet)));
@@ -126,7 +125,7 @@ async function handleFixCodeTick(ctx) {
126
125
  ...(report.comments.minimizeIds ?? report.comments.actionable.map((comment) => comment.id)),
127
126
  ...reviewSummaryIds,
128
127
  ], changesRequestedReviewsForWork, checks, prReference, botUsernames, ruleAutoResolveThreadIds, report.viewerAuthorization, allThreads, resolveOtherHumanThreads);
129
- const escalateTriggers = countFixCodeAttempt
128
+ const escalateTriggers = countTriageAttempt
130
129
  ? checkEscalateTriggers(retryableActionableThreads, priorThreadAttempts)
131
130
  : { triggers: [], thrashHistory: undefined };
132
131
  if (escalateTriggers.triggers.length > 0) {
@@ -161,7 +160,6 @@ async function handleFixCodeTick(ctx) {
161
160
  // it does not confirm the credential executing `gh` has that scope; an unauthorized rerun
162
161
  // simply fails when the agent runs it, the same residual risk as every other CLI-recommended
163
162
  // git/gh mutation in this codebase.
164
- const cancelled = [];
165
163
  const baseLookup = validateBaseBranch(report.baseBranch);
166
164
  const threads = report.threads.actionable.map(toAgentThread);
167
165
  const resolutionOnlyThreads = report.threads.resolutionOnly;
@@ -204,11 +202,7 @@ async function handleFixCodeTick(ctx) {
204
202
  const { changesRequestedReviews } = report;
205
203
  const hasConflicts = report.mergeStatus.status === "CONFLICTS";
206
204
  const isBehind = report.mergeStatus.status === "BEHIND";
207
- const { behindBaseHint, instructions: configuredInstructions } = loadConfig().iterate;
208
- // Only surface in-progress runs when a push is plausible — resolution-only and
209
- // summary-only iterations have no path to a push, so listing runs would prompt
210
- // unnecessary cancellation.
211
- const inProgressRunIds = [];
205
+ const { "behind-base-hint": behindBaseHint, instructions: configuredInstructions } = loadConfig().iterate;
212
206
  const commentMinimizeIds = report.comments.minimizeIds ?? actionableComments.map((c) => c.id);
213
207
  const belongsToActiveWorkflowRun = (check) => check.runId !== null && inProgressWorkflowRunIds.has(check.runId);
214
208
  const manualFollowUpChecks = failingAgentChecks.filter((check) => !releasedCheckNames.has(check.name) &&
@@ -265,7 +259,7 @@ async function handleFixCodeTick(ctx) {
265
259
  };
266
260
  }
267
261
  // Push access to the PR head branch is a usage precondition. Build review mutations for
268
- // conflict ticks normally so the caller can push and complete the same fix_code cycle.
262
+ // conflict ticks normally so the caller can push and complete the same triage cycle.
269
263
  const { resolveCommand, resolveOnlyCommand } = buildReviewCommands(failingAgentChecks);
270
264
  // Safety: if the base branch is unknown, escalate when a push is plausible — the agent
271
265
  // would need the correct base to rebase safely. This is a conservative guard, not a
@@ -346,7 +340,7 @@ async function handleFixCodeTick(ctx) {
346
340
  const stackRebase = hasConflicts || (isBehind && exhaustedAttempts.length > 0) || queueEjection
347
341
  ? buildNativeStackLayerRebase(report.repo, { number: prNumber, baseBranch: baseLookup.branch }, stack, trunkConflict, report.stackBottomPr)
348
342
  : undefined;
349
- const instructions = buildFixInstructions(threads, actionableComments, checks, changesRequestedReviews, baseLookup.branch, resolveCommand, hasConflicts, prReference, cancelled.length, firstLookThreads, firstLookComments, firstLookSummaries, editedSummaries, inProgressRunIds, resolutionOnlyThreads, resolveOnlyCommand, behindBaseHint, isBehind, canGenerateGithubMutation(report.viewerAuthorization?.viewerCanUpdate, "ready"), exhaustedAttempts.length > 0, stackRebase, queueEjection, opts.instructions ?? configuredInstructions);
343
+ const instructions = buildFixInstructions(threads, actionableComments, checks, changesRequestedReviews, baseLookup.branch, resolveCommand, hasConflicts, prReference, firstLookThreads, firstLookComments, firstLookSummaries, editedSummaries, resolutionOnlyThreads, resolveOnlyCommand, behindBaseHint, isBehind, canGenerateGithubMutation(report.viewerAuthorization?.viewerCanUpdate, "ready"), exhaustedAttempts.length > 0, stackRebase, queueEjection, opts.instructions ?? configuredInstructions);
350
344
  if (recovery && "unavailable" in recovery)
351
345
  instructions.unshift(recovery.unavailable);
352
346
  if (acknowledgmentRecovery && "unavailable" in acknowledgmentRecovery)
@@ -391,8 +385,8 @@ async function handleFixCodeTick(ctx) {
391
385
  baseBranch: baseLookup.branch,
392
386
  ...(mergedBasePullRequests.length > 0 && { mergedBasePullRequests }),
393
387
  ...(trunkConflict && { stackTrunkConflict: trunkConflict.trunk }),
394
- action: "fix_code",
395
- fix: {
388
+ action: "triage",
389
+ triage: {
396
390
  threads,
397
391
  resolutionOnlyThreads,
398
392
  actionableComments,
@@ -409,16 +403,13 @@ async function handleFixCodeTick(ctx) {
409
403
  instructions,
410
404
  firstLookThreads,
411
405
  firstLookComments,
412
- inProgressRunIds,
413
- protectedRuns,
414
406
  ...(report.reviewItems && { reviewItems: report.reviewItems }),
415
407
  },
416
- cancelled,
417
408
  };
418
409
  const result = await applyStallGuard(stallKey, stallTimeoutSeconds, headSha, base, prNumber, prospectiveResult, report, reviewSummaryIds);
419
- if (result.action === "fix_code" && opts.persistSeen !== false) {
410
+ if (result.action === "triage" && opts.persistSeen !== false) {
420
411
  await writeFixAttempts({ owner: repoOwner, repo: repoName, pr: prNumber }, { headSha, threadAttempts, threadBodyHashes });
421
- await Promise.allSettled(result.fix.checks.flatMap((ch) => (ch.annotations ?? []).map((a) => markSeen(stallKey, a.id, annotationMarkerBody(a)))));
412
+ await Promise.allSettled(result.triage.checks.flatMap((ch) => (ch.annotations ?? []).map((a) => markSeen(stallKey, a.id, annotationMarkerBody(a)))));
422
413
  }
423
414
  return result;
424
415
  }
@@ -84,8 +84,8 @@ export function buildUnreportedFixResult(base, report, instructions) {
84
84
  const prUrl = formatPrUrl(report.repo, report.pr);
85
85
  return {
86
86
  ...base,
87
- action: "fix_code",
88
- fix: {
87
+ action: "triage",
88
+ triage: {
89
89
  threads: [],
90
90
  resolutionOnlyThreads: [],
91
91
  actionableComments: [],
@@ -102,12 +102,9 @@ export function buildUnreportedFixResult(base, report, instructions) {
102
102
  hasMutations: false,
103
103
  },
104
104
  instructions: [...instructions, buildFixCompletionInstruction()],
105
- inProgressRunIds: [],
106
- protectedRuns: [],
107
105
  firstLookThreads: [],
108
106
  firstLookComments: [],
109
107
  },
110
- cancelled: [],
111
108
  };
112
109
  }
113
110
  function stackRebase(report) {
@@ -13,8 +13,6 @@ export interface JournalResult {
13
13
  sectionExisted: boolean;
14
14
  dryRun: boolean;
15
15
  previewBody?: string;
16
- /** @deprecated Explicit journal requests now rely on GitHub's mutation response. */
17
- authorizationSkipped?: "denied-or-unverifiable";
18
16
  }
19
- /** @deprecated Hidden implementation for standalone `journal`; use `apply journal`. */
17
+ /** Implementation for `apply journal`. */
20
18
  export declare function runJournal(opts: RunJournalOptions): Promise<JournalResult>;
@@ -1,6 +1,6 @@
1
1
  import { getRepoInfo, getPullRequestBody, updatePullRequestBody, getCurrentPrNumber, } from "../../github/client.mjs";
2
2
  import { validateJournalItem, appendJournalItem } from "./transform.mjs";
3
- /** @deprecated Hidden implementation for standalone `journal`; use `apply journal`. */
3
+ /** Implementation for `apply journal`. */
4
4
  export async function runJournal(opts) {
5
5
  const validation = validateJournalItem(opts.rawItem);
6
6
  if (!validation.ok) {
@@ -21,8 +21,6 @@ export interface MarkFilesAsViewedResult {
21
21
  errors: string[];
22
22
  rateLimit?: ResolveRateLimitStop;
23
23
  unmarkedPaths?: string[];
24
- /** @deprecated Explicit file-view requests are attempted; GitHub authorizes the mutation. */
25
- authorizationSkipped?: "unverifiable";
26
24
  }
27
- /** @deprecated Hidden implementation for `mark-files-as-viewed`; use `apply files`. */
25
+ /** Implementation for `apply files`. */
28
26
  export declare function runMarkFilesAsViewed(opts: MarkFilesAsViewedOptions): Promise<MarkFilesAsViewedResult>;
@@ -34,7 +34,7 @@ const FILES_QUERY = `query PullRequestFiles($owner: String!, $repo: String!, $pr
34
34
  const TEST_FILE_RE = /(^|\/)(tests?|__tests__|spec)(\/|$)|\.(test|spec)\.[cm]?[jt]sx?$|_tests?\.rs$|(^|\/)tests?\.rs$/i;
35
35
  // Keep mutation batches small so rate-limit stops leave an ordered pending list.
36
36
  const MARK_FILES_CHUNK_SIZE = 10;
37
- /** @deprecated Hidden implementation for `mark-files-as-viewed`; use `apply files`. */
37
+ /** Implementation for `apply files`. */
38
38
  export async function runMarkFilesAsViewed(opts) {
39
39
  return githubOperation("markFileAsViewed", () => runGraphqlMarkFilesAsViewed(opts), async () => {
40
40
  throw new UnsupportedRestOperationError("markFileAsViewed");
@@ -8,10 +8,10 @@ export interface NextCheckCandidate {
8
8
  seconds: number;
9
9
  }
10
10
  /** The earliest candidate as a `NextCheck`, with `at` rounded up to a whole minute. */
11
- export declare function earliestNextCheck(candidates: NextCheckCandidate[], nowMs?: number): NextCheck | undefined;
11
+ export declare function earliestNextCheck(candidates: NextCheckCandidate[], nowMs?: number, minimumSeconds?: number): NextCheck | undefined;
12
12
  interface NextCheckFacts {
13
13
  /** The action Shepherd returned for this tick. */
14
- action: "wait" | "ready" | "mark_ready" | "fix_code" | "merge" | "cancel" | "escalate";
14
+ action: "wait" | "ready" | "mark_ready" | "triage" | "merge" | "cancel" | "escalate";
15
15
  /** Ready-delay seconds left; only meaningful for `ready`. */
16
16
  remainingSeconds?: number;
17
17
  queued?: boolean;
@@ -3,11 +3,13 @@ export const MERGE_QUEUE_RECHECK_SECONDS = 300;
3
3
  /** Backstop for a missed GitHub event; events normally wake the session long before this. */
4
4
  export const SAFETY_NET_SECONDS = 3000;
5
5
  /** The earliest candidate as a `NextCheck`, with `at` rounded up to a whole minute. */
6
- export function earliestNextCheck(candidates, nowMs = Date.now()) {
6
+ export function earliestNextCheck(candidates, nowMs = Date.now(), minimumSeconds = 0) {
7
7
  const first = [...candidates].sort((a, b) => a.seconds - b.seconds)[0];
8
8
  if (!first)
9
9
  return undefined;
10
- const atMs = Math.ceil((nowMs + Math.max(0, first.seconds) * 1000) / 60_000) * 60_000;
10
+ // A quota warning's interval is a floor: no wake-up may come sooner than it permits.
11
+ const seconds = Math.max(0, first.seconds, minimumSeconds);
12
+ const atMs = Math.ceil((nowMs + seconds * 1000) / 60_000) * 60_000;
11
13
  return {
12
14
  at: new Date(atMs).toISOString().replace(/\.\d{3}Z$/, "Z"),
13
15
  inSeconds: Math.max(0, Math.round((atMs - nowMs) / 1000)),
@@ -53,7 +53,7 @@ export function writeWaitProgress(opts) {
53
53
  export function writeDebounceProgress(tick, elapsedMs, remainingMs) {
54
54
  const elapsedSeconds = Math.round(elapsedMs / 1000);
55
55
  const remainingSeconds = Math.round(remainingMs / 1000);
56
- process.stderr.write(`[poll tick ${tick} / +${elapsedSeconds}s] FIX_CODE — debounce ${remainingSeconds}s remaining\n`);
56
+ process.stderr.write(`[poll tick ${tick} / +${elapsedSeconds}s] TRIAGE — debounce ${remainingSeconds}s remaining\n`);
57
57
  }
58
58
  export function writeRuleAutoResolveProgress(result) {
59
59
  if (result.ruleAutoResolve?.summary)
@@ -25,7 +25,7 @@ export function explicitInstructions(result) {
25
25
  ];
26
26
  }
27
27
  if (result.reason === "waiting" || result.reason === "timeout") {
28
- return ["1. Run this aggregate selector again when the caller is ready to recheck."];
28
+ return ["1. Run this aggregate command again when the caller is ready to recheck."];
29
29
  }
30
30
  const instructions = [
31
31
  "1. Choose each non-WAIT, non-CANCEL row that can proceed independently and run or delegate its exact `pollCommand`.",
@@ -24,7 +24,7 @@ export function planPollSummary(result, mergeRequested) {
24
24
  const layer = needsOwnSession
25
25
  ? {
26
26
  ...item,
27
- action: "fix_code",
27
+ action: "triage",
28
28
  reasons: [
29
29
  ...item.reasons,
30
30
  staleChildren.has(item.pr) ? "stale-ancestry" : "ready-receipt-required",
@@ -108,8 +108,8 @@ function planStack(result, mergeRequested) {
108
108
  if (ownedWork) {
109
109
  const rerun = onlyDraftReadinessVerification(work.sessions, work.idle) &&
110
110
  work.sessions.every((item) => item.owned)
111
- ? "If every listed one-PR probe returns `[CANCEL]` with reason `auto-mark-ready-disabled`, report the human handoff above and stop this selector. If any probe returns `[ESCALATE]`, report that handoff and stop after the other probes finish. Otherwise follow each probe's instructions and rerun this same `--stack` selector when that work completes."
112
- : "After the listed one-PR sessions, rerun this same `--stack` selector. Stop for the human handoff only when no autonomous shepherding remains.";
111
+ ? "If every listed one-PR probe returns `[CANCEL]` with reason `auto-mark-ready-disabled`, report the human handoff above and stop this `stack` command. If any probe returns `[ESCALATE]`, report that handoff and stop after the other probes finish. Otherwise follow each probe's instructions and rerun this same `stack` command when that work completes."
112
+ : "After the listed one-PR sessions, rerun this same `stack` command. Stop for the human handoff only when no autonomous shepherding remains.";
113
113
  appendStackRerunInstruction(instructions, runnableCandidates, rerun);
114
114
  }
115
115
  return { action: stop ? "escalate" : "shepherd", stackMergeable: false, instructions };
@@ -129,7 +129,7 @@ function planStack(result, mergeRequested) {
129
129
  instructions.push(`${instructions.length + 1}. PR #${item.pr} needs a one-PR session, but Shepherd could not produce its command. ${ownedWork ? "After autonomous shepherding, ask" : "Stop and ask"} for direction.`);
130
130
  }
131
131
  if (ownedWork) {
132
- appendStackRerunInstruction(instructions, runnableCandidates, "After the listed one-PR sessions, rerun this same `--stack` selector. Stop for the human handoff only when no autonomous shepherding remains.");
132
+ appendStackRerunInstruction(instructions, runnableCandidates, "After the listed one-PR sessions, rerun this same `stack` command. Stop for the human handoff only when no autonomous shepherding remains.");
133
133
  }
134
134
  return { action: ownedWork ? "shepherd" : "escalate", stackMergeable: false, instructions };
135
135
  }
@@ -149,10 +149,10 @@ function planStack(result, mergeRequested) {
149
149
  appendAutonomousInstructions(instructions, work.sessions);
150
150
  if (onlyDraftReadinessVerification(work.sessions, work.idle) &&
151
151
  work.sessions.every((item) => item.owned)) {
152
- instructions.push(`${instructions.length + 1}. If every listed one-PR probe returns \`[CANCEL]\` with reason \`auto-mark-ready-disabled\`, stop shepherding this stack and leave those drafts unchanged. If any probe returns \`[ESCALATE]\`, report that handoff and stop after the other probes finish. Otherwise follow each probe's instructions and rerun this same \`--stack\` selector when that work completes.`);
152
+ instructions.push(`${instructions.length + 1}. If every listed one-PR probe returns \`[CANCEL]\` with reason \`auto-mark-ready-disabled\`, stop shepherding this stack and leave those drafts unchanged. If any probe returns \`[ESCALATE]\`, report that handoff and stop after the other probes finish. Otherwise follow each probe's instructions and rerun this same \`stack\` command when that work completes.`);
153
153
  return { action: "shepherd", stackMergeable: false, instructions };
154
154
  }
155
- const action = appendStackRerunInstruction(instructions, work.sessions, "After the selected one-PR sessions, rerun this same `--stack` selector.");
155
+ const action = appendStackRerunInstruction(instructions, work.sessions, "After the selected one-PR sessions, rerun this same `stack` command.");
156
156
  return { action, stackMergeable: false, instructions };
157
157
  }
158
158
  if (open.some((item) => item.isInMergeQueue)) {
@@ -176,7 +176,7 @@ function planStack(result, mergeRequested) {
176
176
  const instructions = [];
177
177
  const sessions = open.filter((item) => item.action !== "cancel");
178
178
  appendAutonomousInstructions(instructions, sessions);
179
- const action = appendStackRerunInstruction(instructions, sessions, "After the selected one-PR sessions, rerun this same `--stack` selector.");
179
+ const action = appendStackRerunInstruction(instructions, sessions, "After the selected one-PR sessions, rerun this same `stack` command.");
180
180
  return { action, stackMergeable, instructions };
181
181
  }
182
182
  return retargetWaitPlan(open[0]);
@@ -1,2 +1,8 @@
1
1
  import type { PollSummaryResult } from "../types.mts";
2
+ /**
3
+ * Decision-relevant state only. Raw review totals and the ignored, skipped, filtered, and
4
+ * superseded check counts move when rules suppress a bot notice or a bot reposts a status
5
+ * check, which would reprint quiet polls and keep an idle stack from reaching `stall-timeout`.
6
+ * Post-rule `actionable` and the check transitions that drive routing stay in.
7
+ */
2
8
  export declare function summaryStatusSignature(result: PollSummaryResult): string;