pr-shepherd 0.34.0 → 0.35.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 (187) hide show
  1. package/.claude-plugin/plugin.json +3 -2
  2. package/.grok-plugin/marketplace.json +17 -0
  3. package/README.md +56 -39
  4. package/bin/api.d.mts +80 -0
  5. package/bin/api.mjs +236 -0
  6. package/bin/checks/classify.d.mts +41 -0
  7. package/bin/checks/startup-failures.d.mts +2 -0
  8. package/bin/checks/superseded.d.mts +21 -0
  9. package/bin/checks/triage.d.mts +4 -0
  10. package/bin/classify/apply.d.mts +18 -0
  11. package/bin/classify/apply.mjs +4 -0
  12. package/bin/classify/loader.d.mts +10 -0
  13. package/bin/classify/types.d.mts +35 -0
  14. package/bin/cli/args.d.mts +18 -0
  15. package/bin/cli/clean-formatter.d.mts +2 -0
  16. package/bin/cli/default-poll.d.mts +2 -0
  17. package/bin/cli/duration-flag.d.mts +2 -0
  18. package/bin/cli/duration.d.mts +13 -0
  19. package/bin/cli/fence.d.mts +1 -0
  20. package/bin/cli/fix-formatter-extra.d.mts +3 -0
  21. package/bin/cli/fix-formatter.d.mts +2 -0
  22. package/bin/cli/fix-formatter.mjs +6 -6
  23. package/bin/cli/formatters.d.mts +7 -0
  24. package/bin/cli/handlers.d.mts +4 -0
  25. package/bin/cli/handlers.mjs +11 -10
  26. package/bin/cli/help-command-pages.d.mts +231 -0
  27. package/bin/cli/help-command-pages.mjs +106 -1
  28. package/bin/cli/help-iterate-poll-pages.d.mts +4 -0
  29. package/bin/cli/help-iterate-poll-pages.mjs +4 -2
  30. package/bin/cli/help-log-file-page.d.mts +1 -0
  31. package/bin/cli/help-top-page.d.mts +1 -0
  32. package/bin/cli/help-top-page.mjs +14 -15
  33. package/bin/cli/help.d.mts +236 -0
  34. package/bin/cli/help.mjs +17 -0
  35. package/bin/cli/iterate-emitter.d.mts +8 -0
  36. package/bin/cli/iterate-flags.d.mts +11 -0
  37. package/bin/cli/iterate-formatter.d.mts +19 -0
  38. package/bin/cli/iterate-instructions.d.mts +6 -0
  39. package/bin/cli/iterate-lean.d.mts +12 -0
  40. package/bin/cli/journal-formatter.d.mts +2 -0
  41. package/bin/cli/journal-formatter.mjs +15 -0
  42. package/bin/cli/journal-handler.d.mts +1 -0
  43. package/bin/cli/journal-handler.mjs +7 -20
  44. package/bin/cli/list-formatters.d.mts +76 -0
  45. package/bin/cli/list-formatters.mjs +9 -9
  46. package/bin/cli/mark-files-as-viewed-flags.d.mts +11 -0
  47. package/bin/cli/mark-files-as-viewed-formatter.d.mts +2 -0
  48. package/bin/cli/mutate-formatter.d.mts +2 -0
  49. package/bin/cli/poll-handler.d.mts +1 -0
  50. package/bin/cli/poll-handler.mjs +2 -2
  51. package/bin/cli/resolve-validators.d.mts +3 -0
  52. package/bin/cli/resolve-validators.mjs +3 -3
  53. package/bin/cli/runner.d.mts +7 -0
  54. package/bin/cli/suggestion-renderer.d.mts +3 -0
  55. package/bin/cli/validate-default-args.d.mts +6 -0
  56. package/bin/cli-parser.d.mts +2 -0
  57. package/bin/cli-parser.mjs +72 -16
  58. package/bin/commands/check-annotations.d.mts +5 -0
  59. package/bin/commands/check-status.d.mts +3 -0
  60. package/bin/commands/check-terminal-report.d.mts +5 -0
  61. package/bin/commands/check.d.mts +6 -0
  62. package/bin/commands/check.mjs +2 -1
  63. package/bin/commands/clean.d.mts +21 -0
  64. package/bin/commands/commit-suggestion-instruction.d.mts +8 -0
  65. package/bin/commands/commit-suggestion-instruction.mjs +3 -3
  66. package/bin/commands/commit-suggestion.d.mts +8 -0
  67. package/bin/commands/commit-suggestion.mjs +11 -10
  68. package/bin/commands/iterate/check-instructions.d.mts +16 -0
  69. package/bin/commands/iterate/check-instructions.mjs +3 -3
  70. package/bin/commands/iterate/classify.d.mts +18 -0
  71. package/bin/commands/iterate/classify.mjs +4 -4
  72. package/bin/commands/iterate/escalate.d.mts +31 -0
  73. package/bin/commands/iterate/escalate.mjs +7 -4
  74. package/bin/commands/iterate/fix-code.d.mts +25 -0
  75. package/bin/commands/iterate/helpers.d.mts +13 -0
  76. package/bin/commands/iterate/helpers.mjs +4 -1
  77. package/bin/commands/iterate/index.d.mts +2 -0
  78. package/bin/commands/iterate/index.mjs +5 -2
  79. package/bin/commands/iterate/render.d.mts +5 -0
  80. package/bin/commands/iterate/render.mjs +8 -6
  81. package/bin/commands/iterate/reruns.d.mts +20 -0
  82. package/bin/commands/iterate/stall.d.mts +6 -0
  83. package/bin/commands/journal/index.d.mts +14 -0
  84. package/bin/commands/journal/index.mjs +1 -0
  85. package/bin/commands/journal/transform.d.mts +22 -0
  86. package/bin/commands/log-file.d.mts +5 -0
  87. package/bin/commands/mark-files-as-viewed.d.mts +26 -0
  88. package/bin/commands/mark-files-as-viewed.mjs +1 -0
  89. package/bin/commands/poll.d.mts +10 -0
  90. package/bin/commands/poll.mjs +1 -0
  91. package/bin/commands/ready-delay.d.mts +29 -0
  92. package/bin/commands/ready-mergeability.d.mts +15 -0
  93. package/bin/commands/resolve-mutate.d.mts +4 -0
  94. package/bin/commands/resolve-mutate.mjs +1 -0
  95. package/bin/commands/resolve.d.mts +4 -0
  96. package/bin/commands/shepherd-journal.d.mts +7 -0
  97. package/bin/commands/shepherd-journal.mjs +2 -2
  98. package/bin/comments/authors.d.mts +14 -0
  99. package/bin/comments/marker.d.mts +2 -0
  100. package/bin/comments/minimize-policy.d.mts +4 -0
  101. package/bin/comments/pending-ops.d.mts +15 -0
  102. package/bin/comments/rate-limit.d.mts +18 -0
  103. package/bin/comments/resolve.d.mts +34 -0
  104. package/bin/comments/resolve.mjs +1 -0
  105. package/bin/comments/review-thread-markers.d.mts +8 -0
  106. package/bin/comments/review-visibility.d.mts +28 -0
  107. package/bin/comments/sha-poll.d.mts +2 -0
  108. package/bin/comments/thread-visibility.d.mts +11 -0
  109. package/bin/comments/visible-comments.d.mts +11 -0
  110. package/bin/config/load.d.mts +60 -0
  111. package/bin/config/load.mjs +72 -1
  112. package/bin/config.json +0 -2
  113. package/bin/execution-context.d.mts +9 -0
  114. package/bin/execution-context.mjs +19 -0
  115. package/bin/exit-codes.d.mts +51 -0
  116. package/bin/github/activity.d.mts +3 -0
  117. package/bin/github/activity.mjs +7 -0
  118. package/bin/github/batch-parser-helpers.d.mts +22 -0
  119. package/bin/github/batch-parsers.d.mts +3 -0
  120. package/bin/github/batch-parsers.mjs +6 -0
  121. package/bin/github/batch-raw-types.d.mts +207 -0
  122. package/bin/github/batch-response.d.mts +4 -0
  123. package/bin/github/batch.d.mts +22 -0
  124. package/bin/github/branch-protection.d.mts +3 -0
  125. package/bin/github/check-annotations.d.mts +2 -0
  126. package/bin/github/client.d.mts +46 -0
  127. package/bin/github/client.mjs +7 -2
  128. package/bin/github/errors.d.mts +25 -0
  129. package/bin/github/gql/batch-pr.gql +5 -0
  130. package/bin/github/gql/review-thread-comments.gql +1 -0
  131. package/bin/github/graphql-http.d.mts +19 -0
  132. package/bin/github/graphql-response.d.mts +7 -0
  133. package/bin/github/http-auth.d.mts +4 -0
  134. package/bin/github/http-request.d.mts +7 -0
  135. package/bin/github/http-utils.d.mts +11 -0
  136. package/bin/github/http.d.mts +5 -0
  137. package/bin/github/pagination.d.mts +45 -0
  138. package/bin/github/queries.d.mts +24 -0
  139. package/bin/github/rest-http.d.mts +2 -0
  140. package/bin/github/thread-comments.d.mts +2 -0
  141. package/bin/index.d.mts +10 -0
  142. package/bin/index.mjs +1 -1
  143. package/bin/log/log-file.d.mts +28 -0
  144. package/bin/log/session.d.mts +31 -0
  145. package/bin/log/setup.d.mts +6 -0
  146. package/bin/mcp/index.d.mts +5 -0
  147. package/bin/mcp/index.mjs +8 -0
  148. package/bin/mcp/server.d.mts +8 -0
  149. package/bin/mcp/server.mjs +157 -0
  150. package/bin/mcp-stdio.d.mts +2 -0
  151. package/bin/mcp-stdio.mjs +7 -0
  152. package/bin/merge-status/derive.d.mts +19 -0
  153. package/bin/reporters/agent.d.mts +23 -0
  154. package/bin/reporters/agent.mjs +3 -0
  155. package/bin/state/base.d.mts +1 -0
  156. package/bin/state/bot-cr-seen.d.mts +51 -0
  157. package/bin/state/bot-cr-seen.mjs +1 -1
  158. package/bin/state/fix-attempts.d.mts +27 -0
  159. package/bin/state/iterate-stall.d.mts +27 -0
  160. package/bin/state/seen-comments.d.mts +62 -0
  161. package/bin/suggestions/extract.d.mts +8 -0
  162. package/bin/suggestions/parse.d.mts +48 -0
  163. package/bin/suggestions/patch.d.mts +14 -0
  164. package/bin/threads/transcript.d.mts +14 -0
  165. package/bin/threads/transcript.mjs +4 -0
  166. package/bin/types/activity.d.mts +30 -0
  167. package/bin/types/agent-thread.d.mts +9 -0
  168. package/bin/types/check-annotations.d.mts +14 -0
  169. package/bin/types/check-classification.d.mts +19 -0
  170. package/bin/types/github.d.mts +139 -0
  171. package/bin/types/iterate.d.mts +157 -0
  172. package/bin/types/protected-run.d.mts +6 -0
  173. package/bin/types/report.d.mts +176 -0
  174. package/bin/types/review-thread.d.mts +12 -0
  175. package/bin/types.d.mts +9 -0
  176. package/bin/util/markdown.d.mts +1 -0
  177. package/bin/util/path-segment.d.mts +2 -0
  178. package/bin/util/sleep.d.mts +1 -0
  179. package/bin/util/worktree.d.mts +9 -0
  180. package/bin/util/worktree.mjs +4 -1
  181. package/package.json +51 -37
  182. package/plugins/pr-shepherd/.codex-plugin/plugin.json +3 -2
  183. package/plugins/pr-shepherd/.codex.mcp.json +8 -0
  184. package/plugins/pr-shepherd/.mcp.json +6 -0
  185. package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +5 -19
  186. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +6 -15
  187. package/src/classify/types.mts +12 -0
@@ -14,12 +14,12 @@ export async function handlePoll(args) {
14
14
  if (flags.readyDelaySuffix === null || flags.stallTimeoutSuffix === null)
15
15
  return;
16
16
  const intervalStr = getFlag(extra, "--interval");
17
- const intervalSuffix = validateSecondsDurationFlag("pr-shepherd poll", "--interval", intervalStr, hasFlag(extra, "--interval"));
17
+ const intervalSuffix = validateSecondsDurationFlag("pr-shepherd", "--interval", intervalStr, hasFlag(extra, "--interval"));
18
18
  if (intervalSuffix === null)
19
19
  return;
20
20
  const intervalSeconds = parseDurationToSeconds(intervalSuffix ?? "", DEFAULT_POLL_INTERVAL_SECONDS);
21
21
  const timeoutStr = getFlag(extra, "--timeout");
22
- const timeoutSuffix = validateSecondsDurationFlag("pr-shepherd poll", "--timeout", timeoutStr, hasFlag(extra, "--timeout"));
22
+ const timeoutSuffix = validateSecondsDurationFlag("pr-shepherd", "--timeout", timeoutStr, hasFlag(extra, "--timeout"));
23
23
  if (timeoutSuffix === null)
24
24
  return;
25
25
  const timeoutSeconds = parseDurationToSeconds(timeoutSuffix ?? "", DEFAULT_POLL_TIMEOUT_SECONDS);
@@ -0,0 +1,3 @@
1
+ export declare function rejectPrrcMinimizeIds(ids: string[]): string[];
2
+ export declare function warnPrrcThreadIds(ids: string[]): string[];
3
+ export declare function validateRequireSha(sha: string | undefined): boolean;
@@ -2,7 +2,7 @@ import { EXIT } from "../exit-codes.mjs";
2
2
  export function rejectPrrcMinimizeIds(ids) {
3
3
  const prrcIds = ids.filter((id) => id.startsWith("PRRC_"));
4
4
  if (prrcIds.length > 0) {
5
- process.stderr.write(`pr-shepherd: resolve: --minimize-comment-ids contains thread comment IDs (PRRC_*): ${prrcIds.join(", ")}. Thread comments cannot be minimized individually — resolve the parent thread using --resolve-thread-ids with the PRRT_* thread ID instead.\n`);
5
+ process.stderr.write(`pr-shepherd: apply review: --minimize-comment-ids contains thread comment IDs (PRRC_*): ${prrcIds.join(", ")}. Thread comments cannot be minimized individually — resolve the parent thread using --resolve-thread-ids with the PRRT_* thread ID instead.\n`);
6
6
  process.exitCode = EXIT.DATAERR;
7
7
  }
8
8
  return prrcIds;
@@ -10,7 +10,7 @@ export function rejectPrrcMinimizeIds(ids) {
10
10
  export function warnPrrcThreadIds(ids) {
11
11
  const prrcIds = ids.filter((id) => id.startsWith("PRRC_"));
12
12
  if (prrcIds.length > 0) {
13
- process.stderr.write(`pr-shepherd: resolve: warning: --resolve-thread-ids contains comment IDs (PRRC_*) instead of thread IDs (PRRT_*): ${prrcIds.join(", ")}. The resolveReviewThread mutation requires PRRT_* thread IDs. Run a GraphQL query for pullRequest.reviewThreads to get the correct IDs.\n`);
13
+ process.stderr.write(`pr-shepherd: apply review: warning: --resolve-thread-ids contains comment IDs (PRRC_*) instead of thread IDs (PRRT_*): ${prrcIds.join(", ")}. The resolveReviewThread mutation requires PRRT_* thread IDs. Run a GraphQL query for pullRequest.reviewThreads to get the correct IDs.\n`);
14
14
  }
15
15
  return prrcIds;
16
16
  }
@@ -19,7 +19,7 @@ export function validateRequireSha(sha) {
19
19
  return true;
20
20
  if (/^[0-9a-f]{40}$/.test(sha))
21
21
  return true;
22
- process.stderr.write(`pr-shepherd: resolve: --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 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`);
23
23
  process.exitCode = EXIT.DATAERR;
24
24
  return false;
25
25
  }
@@ -0,0 +1,7 @@
1
+ interface PrShepherdCommand {
2
+ argv: string[];
3
+ text: string;
4
+ }
5
+ export declare function buildPrShepherdCommand(args: string[]): PrShepherdCommand;
6
+ export declare function renderShellCommand(argv: string[]): string;
7
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { SuggestionBlock } from "../types.mts";
2
+ export declare function renderLineRange(startLine: number | undefined, endLine: number | null): string;
3
+ export declare function renderSuggestionBlock(s: SuggestionBlock, indent?: string): string;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Validate args for default-dispatch paths (e.g. `pr-shepherd [PR] [flags]`).
3
+ * Returns false when an unexpected token is found; calls onError with the
4
+ * offending arg so callers can print their own usage message.
5
+ */
6
+ export declare function validateDefaultArgs(args: string[], flagsWithValues: ReadonlySet<string>, booleanFlags: ReadonlySet<string>, onError: (arg: string) => void): boolean;
@@ -0,0 +1,2 @@
1
+ /** CLI argument parsing and subcommand dispatch for pr-shepherd. See --help for usage. */
2
+ export declare function main(argv: string[]): Promise<void>;
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-lines */
1
2
  /** CLI argument parsing and subcommand dispatch for pr-shepherd. See --help for usage. */
2
3
  import { readFileSync } from "node:fs";
3
4
  import { EXIT, errorToExitCode } from "./exit-codes.mjs";
@@ -5,7 +6,7 @@ import { runResolveMutate } from "./commands/resolve.mjs";
5
6
  import { runLogFile } from "./commands/log-file.mjs";
6
7
  import { parseCommonArgs, getFlag, hasFlag, parseList } from "./cli/args.mjs";
7
8
  import { isDefaultPollInvocation, validateDefaultPollArgs } from "./cli/default-poll.mjs";
8
- import { USAGE, maybePrintHelp } from "./cli/help.mjs";
9
+ import { USAGE, helpKeyForArgs, maybePrintHelp } from "./cli/help.mjs";
9
10
  import { formatMutateResult } from "./cli/formatters.mjs";
10
11
  import { handleClean, handleCommitSuggestion, handleIterate, handleMarkFilesAsViewed, } from "./cli/handlers.mjs";
11
12
  import { handleJournal } from "./cli/journal-handler.mjs";
@@ -31,19 +32,33 @@ export async function main(argv) {
31
32
  await handleLogFile(args.slice(1));
32
33
  return;
33
34
  }
35
+ // The public command groups keep admin diagnostics out of the normal
36
+ // command namespace. Keep this before setupLog because log-file reads the
37
+ // log path and must not initialize/tee the log it is reporting.
38
+ if (subcommand === "admin" && args[1] === "log-file") {
39
+ await handleLogFile(args.slice(2), "admin log-file");
40
+ return;
41
+ }
34
42
  // Short-circuit all --help/-h before any I/O or logging.
35
43
  if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
36
44
  if (isDefaultPollInvocation(subcommand)) {
37
- process.stdout.write(`${USAGE.poll}\n`);
45
+ process.stdout.write(`${USAGE.default}\n`);
38
46
  }
39
47
  else {
40
- const key = subcommand != null && subcommand in USAGE
41
- ? subcommand
42
- : "top";
43
- process.stdout.write(`${USAGE[key]}\n`);
48
+ process.stdout.write(`${USAGE[helpKeyForArgs(args)]}\n`);
44
49
  }
45
50
  return;
46
51
  }
52
+ const legacyReplacement = {
53
+ poll: "pr-shepherd [PR] (the default PR polling command)",
54
+ resolve: "apply review",
55
+ "mark-files-as-viewed": "apply files",
56
+ journal: "apply journal",
57
+ "commit-suggestion": "build-suggestion-patch",
58
+ };
59
+ if (subcommand !== undefined && legacyReplacement[subcommand] !== undefined) {
60
+ warnLegacyAlias(subcommand, legacyReplacement[subcommand]);
61
+ }
47
62
  // Initialize the per-worktree log and install a stdout tee.
48
63
  await setupLog(argv);
49
64
  if (isDefaultPollInvocation(subcommand)) {
@@ -53,14 +68,23 @@ export async function main(argv) {
53
68
  return;
54
69
  }
55
70
  switch (subcommand) {
71
+ case "apply":
72
+ await handleApply(args.slice(1));
73
+ break;
74
+ case "build-suggestion-patch":
75
+ await handleCommitSuggestion(args.slice(1));
76
+ break;
77
+ case "admin":
78
+ await handleAdmin(args.slice(1));
79
+ break;
56
80
  case "resolve":
57
- await handleResolve(args.slice(1));
81
+ await handleResolve(args.slice(1), "resolve");
58
82
  break;
59
83
  case "commit-suggestion":
60
- await handleCommitSuggestion(args.slice(1));
84
+ await handleCommitSuggestion(args.slice(1), "commit-suggestion");
61
85
  break;
62
86
  case "mark-files-as-viewed":
63
- await handleMarkFilesAsViewed(args.slice(1));
87
+ await handleMarkFilesAsViewed(args.slice(1), "mark-files-as-viewed");
64
88
  break;
65
89
  case "iterate":
66
90
  await handleIterate(args.slice(1));
@@ -69,10 +93,10 @@ export async function main(argv) {
69
93
  await handlePoll(args.slice(1));
70
94
  break;
71
95
  case "clean":
72
- await handleClean(args.slice(1));
96
+ await handleClean(args.slice(1), "clean");
73
97
  break;
74
98
  case "journal":
75
- await handleJournal(args.slice(1));
99
+ await handleJournal(args.slice(1), "journal");
76
100
  break;
77
101
  default:
78
102
  process.stderr.write(`Unknown subcommand: ${subcommand ?? "(none)"}\n`);
@@ -81,6 +105,38 @@ export async function main(argv) {
81
105
  return;
82
106
  }
83
107
  }
108
+ function warnLegacyAlias(alias, replacement) {
109
+ process.stderr.write(`pr-shepherd: ${alias} is deprecated; use ${replacement.startsWith("pr-shepherd") ? replacement : `pr-shepherd ${replacement}`} instead.\n`);
110
+ }
111
+ async function handleApply(args) {
112
+ const action = args[0];
113
+ switch (action) {
114
+ case "review":
115
+ await handleResolve(args.slice(1));
116
+ return;
117
+ case "files":
118
+ await handleMarkFilesAsViewed(args.slice(1));
119
+ return;
120
+ case "journal":
121
+ await handleJournal(args.slice(1));
122
+ return;
123
+ default:
124
+ process.stderr.write(`Unknown apply action: ${action ?? "(none)"}\n`);
125
+ process.stderr.write(`${USAGE.apply}\n`);
126
+ process.exitCode = EXIT.USAGE;
127
+ }
128
+ }
129
+ async function handleAdmin(args) {
130
+ switch (args[0]) {
131
+ case "clean":
132
+ await handleClean(args.slice(1));
133
+ return;
134
+ default:
135
+ process.stderr.write(`Unknown admin command: ${args[0] ?? "(none)"}\n`);
136
+ process.stderr.write(`${USAGE.admin}\n`);
137
+ process.exitCode = EXIT.USAGE;
138
+ }
139
+ }
84
140
  function readVersion() {
85
141
  const pkgUrl = new URL("../package.json", import.meta.url);
86
142
  const pkg = JSON.parse(readFileSync(pkgUrl, "utf8"));
@@ -89,8 +145,8 @@ function readVersion() {
89
145
  // ---------------------------------------------------------------------------
90
146
  // Subcommand handlers
91
147
  // ---------------------------------------------------------------------------
92
- async function handleLogFile(args) {
93
- if (maybePrintHelp(args, "log-file"))
148
+ async function handleLogFile(args, usageKey = "log-file") {
149
+ if (maybePrintHelp(args, usageKey))
94
150
  return;
95
151
  const jsonOut = args.some((a) => a === "--format=json") ||
96
152
  (() => {
@@ -106,7 +162,7 @@ async function handleLogFile(args) {
106
162
  process.exitCode = errorToExitCode(e);
107
163
  }
108
164
  }
109
- async function handleResolve(args) {
165
+ async function handleResolve(args, command = "apply review") {
110
166
  const { prNumber, global: globalOpts, extra } = parseCommonArgs(args);
111
167
  const resolveThreadIds = parseList(getFlag(extra, "--resolve-thread-ids"));
112
168
  const replyThreadIds = parseList(getFlag(extra, "--reply-thread-ids"));
@@ -120,7 +176,7 @@ async function handleResolve(args) {
120
176
  if (rejectPrrcMinimizeIds(minimizeCommentIds).length > 0)
121
177
  return;
122
178
  if (hasFlag(extra, "--fetch")) {
123
- process.stderr.write("pr-shepherd: resolve: --fetch has been removed; run pr-shepherd iterate or poll to fetch the next action.\n");
179
+ process.stderr.write(`pr-shepherd: ${command}: --fetch has been removed; run pr-shepherd iterate to fetch the next action.\n`);
124
180
  process.exitCode = EXIT.USAGE;
125
181
  return;
126
182
  }
@@ -129,7 +185,7 @@ async function handleResolve(args) {
129
185
  minimizeCommentIds.length > 0 ||
130
186
  dismissReviewIds.length > 0;
131
187
  if (!hasAction) {
132
- process.stderr.write("pr-shepherd: resolve: an action flag is required (--reply-thread-ids, --resolve-thread-ids, --minimize-comment-ids, or --dismiss-review-ids).\n");
188
+ process.stderr.write(`pr-shepherd: ${command}: an action flag is required (--reply-thread-ids, --resolve-thread-ids, --minimize-comment-ids, or --dismiss-review-ids).\n`);
133
189
  process.exitCode = EXIT.USAGE;
134
190
  return;
135
191
  }
@@ -0,0 +1,5 @@
1
+ import type { CheckAnnotation, TriagedCheck } from "../types.mts";
2
+ export declare function attachUnseenCheckAnnotations(checks: TriagedCheck[], seenMap: Map<string, {
3
+ seenAt: number;
4
+ }>, prNumber: number): Promise<TriagedCheck[]>;
5
+ export declare function annotationMarkerBody(a: CheckAnnotation): string;
@@ -0,0 +1,3 @@
1
+ import type { MergeStatusResult, ShepherdStatus } from "../types.mts";
2
+ import type { CiVerdict } from "../checks/classify.mts";
3
+ export declare function computeStatus(verdict: CiVerdict, unresolvedThreads: number, unresolvedComments: number, mergeStatus: MergeStatusResult, changesRequestedReviews: number): ShepherdStatus;
@@ -0,0 +1,5 @@
1
+ import type { BatchPrData, MergeStatusResult, ShepherdReport } from "../types.mts";
2
+ export declare function buildTerminalReport(prNumber: number, repo: {
3
+ owner: string;
4
+ name: string;
5
+ }, batchData: BatchPrData, mergeStatus: MergeStatusResult, status: "MERGED" | "CLOSED"): ShepherdReport;
@@ -0,0 +1,6 @@
1
+ import type { GlobalOptions, ShepherdReport } from "../types.mts";
2
+ export declare function runCheck(opts: GlobalOptions & {
3
+ autoResolve?: boolean;
4
+ autoMinimizeSuppressed?: boolean;
5
+ skipTriage?: boolean;
6
+ }): Promise<ShepherdReport>;
@@ -20,6 +20,7 @@ import { normalizeBotUsernames } from "../comments/authors.mjs";
20
20
  import { discoverRuleFiles, loadRules } from "../classify/loader.mjs";
21
21
  import { buildClassifyIndex, partitionBatch } from "../classify/apply.mjs";
22
22
  import { EXIT, ShepherdError } from "../exit-codes.mjs";
23
+ import { getEffectiveCwd } from "../execution-context.mjs";
23
24
  export async function runCheck(opts) {
24
25
  const repo = await getRepoInfo();
25
26
  const prNumber = opts.prNumber ?? (await getCurrentPrNumber());
@@ -50,7 +51,7 @@ export async function runCheck(opts) {
50
51
  const stateKey = { owner: repo.owner, repo: repo.name, pr: prNumber };
51
52
  const seenMap = await loadSeenMap(stateKey);
52
53
  const botUsernames = normalizeBotUsernames(config.botUsernames);
53
- const ruleSet = await loadRules(discoverRuleFiles(process.cwd()));
54
+ const ruleSet = await loadRules(discoverRuleFiles(getEffectiveCwd()));
54
55
  const classifyIndex = buildClassifyIndex(ruleSet, batchData);
55
56
  const partition = partitionBatch(classifyIndex, batchData);
56
57
  const triaged = await attachUnseenCheckAnnotations(triagedBase, seenMap, prNumber);
@@ -0,0 +1,21 @@
1
+ export type CleanVariant = "pr" | "branch" | "current" | "repo" | "all";
2
+ interface CleanOptions {
3
+ variant: CleanVariant;
4
+ /** PR number string (for "pr") or branch name (for "branch"). Defaults to current. */
5
+ value?: string;
6
+ dryRun?: boolean;
7
+ }
8
+ export interface CleanResult {
9
+ ok: boolean;
10
+ variant: CleanVariant;
11
+ dryRun: boolean;
12
+ base: string;
13
+ target: string;
14
+ /** Paths removed (actual delete) or that would be removed (dry-run). */
15
+ deleted: string[];
16
+ /** Target path when it did not exist. */
17
+ skipped: string[];
18
+ error?: string;
19
+ }
20
+ export declare function runClean(opts: CleanOptions): Promise<CleanResult>;
21
+ export {};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Build the `build-suggestion-patch` instruction step for agent consumers.
3
+ * Currently emitted by iterate `fix_code` for suggestion review threads.
4
+ * @param sectionName - The markdown section heading where suggestion threads appear,
5
+ * e.g. `"## Review threads"`.
6
+ * @param includeDriftHint - Whether to add the trailing note about drift on failed apply.
7
+ */
8
+ export declare function buildCommitSuggestionInstruction(prNumber: number, sectionName: string, includeDriftHint: boolean): string;
@@ -1,6 +1,6 @@
1
1
  import { buildPrShepherdCommand } from "../cli/runner.mjs";
2
2
  /**
3
- * Build the `commit-suggestion` instruction step for agent consumers.
3
+ * Build the `build-suggestion-patch` instruction step for agent consumers.
4
4
  * Currently emitted by iterate `fix_code` for suggestion review threads.
5
5
  * @param sectionName - The markdown section heading where suggestion threads appear,
6
6
  * e.g. `"## Review threads"`.
@@ -8,7 +8,7 @@ import { buildPrShepherdCommand } from "../cli/runner.mjs";
8
8
  */
9
9
  export function buildCommitSuggestionInstruction(prNumber, sectionName, includeDriftHint) {
10
10
  const command = buildPrShepherdCommand([
11
- "commit-suggestion",
11
+ "build-suggestion-patch",
12
12
  String(prNumber),
13
13
  "--thread-id",
14
14
  "<id>",
@@ -19,5 +19,5 @@ export function buildCommitSuggestionInstruction(prNumber, sectionName, includeD
19
19
  const driftHint = includeDriftHint
20
20
  ? " If the patch fails to apply (drift since the suggestion was written), fall through to the manual fix step."
21
21
  : " If the patch fails to apply, fall through to the manual-edit step.";
22
- return `For each thread marked \`[suggestion]\` under \`${sectionName}\`: run \`${command}\` to retrieve the patch and suggested commit. The CLI does not mutate the working tree — apply the patch yourself (run \`git apply\` with the diff shown, or edit the file directly using the line range), then stage the listed file and run the suggested \`git commit\` from the \`## Instructions\` section. Human-authored thread IDs are replied to by the resolve command below; Shepherd does not auto-resolve them.${driftHint} Do not retry the same command.`;
22
+ return `For each thread marked \`[suggestion]\` under \`${sectionName}\`: run \`${command}\` to retrieve the patch and suggested commit. The CLI does not mutate the working tree — apply the patch yourself (run \`git apply\` with the diff shown, or edit the file directly using the line range), then stage the listed file and run the suggested \`git commit\` from the \`## Instructions\` section. Human-authored thread IDs are replied to by the apply command below; Shepherd does not auto-resolve them.${driftHint} Do not retry the same command.`;
23
23
  }
@@ -0,0 +1,8 @@
1
+ import type { CommitSuggestionResult, GlobalOptions } from "../types.mts";
2
+ export interface CommitSuggestionOptions extends GlobalOptions {
3
+ threadId: string;
4
+ message: string;
5
+ description?: string;
6
+ }
7
+ /** @deprecated Hidden implementation for `commit-suggestion`; use `build-suggestion-patch`. */
8
+ export declare function runCommitSuggestion(opts: CommitSuggestionOptions): Promise<CommitSuggestionResult>;
@@ -1,5 +1,6 @@
1
1
  import { execFile as execFileCb } from "node:child_process";
2
2
  import { readFile } from "node:fs/promises";
3
+ import { resolve } from "node:path";
3
4
  import { promisify } from "node:util";
4
5
  import { getRepoInfo, getCurrentPrNumber, getCurrentBranch } from "../github/client.mjs";
5
6
  import { fetchPrBatch } from "../github/batch.mjs";
@@ -7,7 +8,9 @@ import { parseSuggestion, isCommittableSuggestion } from "../suggestions/parse.m
7
8
  import { buildUnifiedDiff } from "../suggestions/patch.mjs";
8
9
  import { EXIT, ShepherdError } from "../exit-codes.mjs";
9
10
  import { buildPrShepherdCommand } from "../cli/runner.mjs";
11
+ import { getEffectiveCwd, getExecutionCwd } from "../execution-context.mjs";
10
12
  const execFile = promisify(execFileCb);
13
+ /** @deprecated Hidden implementation for `commit-suggestion`; use `build-suggestion-patch`. */
11
14
  export async function runCommitSuggestion(opts) {
12
15
  if (!opts.threadId) {
13
16
  throw new ShepherdError("--thread-id is required", EXIT.USAGE);
@@ -21,7 +24,9 @@ export async function runCommitSuggestion(opts) {
21
24
  throw new ShepherdError("No open PR found for current branch. Pass a PR number explicitly.", EXIT.UNAVAILABLE);
22
25
  }
23
26
  const currentBranch = await getCurrentBranch();
24
- const { stdout: localHeadOut } = await execFile("git", ["rev-parse", "HEAD"]);
27
+ const { stdout: localHeadOut } = await execFile("git", ["rev-parse", "HEAD"], {
28
+ cwd: getExecutionCwd(),
29
+ });
25
30
  const localHeadSha = localHeadOut.trim();
26
31
  const { data } = await fetchPrBatch(prNumber, repo);
27
32
  if (!data.headRepoWithOwner) {
@@ -53,14 +58,9 @@ export async function runCommitSuggestion(opts) {
53
58
  }
54
59
  // Validate the target file is clean before generating the patch, so the emitted
55
60
  // `git add -- <file>` instruction cannot accidentally stage unrelated local edits.
56
- const { stdout: fileStatus } = await execFile("git", [
57
- "status",
58
- "--porcelain",
59
- "--",
60
- thread.path,
61
- ]);
61
+ const { stdout: fileStatus } = await execFile("git", ["status", "--porcelain", "--", thread.path], { cwd: getExecutionCwd() });
62
62
  if (fileStatus.trim() !== "") {
63
- throw new ShepherdError(`${thread.path} has uncommitted changes. Commit or stash them before running commit-suggestion.`, EXIT.UNAVAILABLE);
63
+ throw new ShepherdError(`${thread.path} has uncommitted changes. Commit or stash them before running build-suggestion-patch.`, EXIT.UNAVAILABLE);
64
64
  }
65
65
  const parsed = parseSuggestion(thread.body);
66
66
  if (!parsed) {
@@ -73,7 +73,7 @@ export async function runCommitSuggestion(opts) {
73
73
  const startLine = thread.startLine ?? thread.line;
74
74
  const endLine = thread.line;
75
75
  const filePath = thread.path;
76
- const originalContent = await readFile(filePath, "utf8");
76
+ const originalContent = await readFile(resolve(getEffectiveCwd(), filePath), "utf8");
77
77
  const patch = buildUnifiedDiff({
78
78
  path: filePath,
79
79
  originalContent,
@@ -94,7 +94,8 @@ export async function runCommitSuggestion(opts) {
94
94
  ...commitBodyArg.split("\n\n").map((p) => `-m ${sq(p)}`),
95
95
  ].join(" ");
96
96
  const resolveCommand = buildPrShepherdCommand([
97
- "resolve",
97
+ "apply",
98
+ "review",
98
99
  String(prNumber),
99
100
  "--resolve-thread-ids",
100
101
  opts.threadId,
@@ -0,0 +1,16 @@
1
+ import type { AgentCheck, ResolveCommand, Review } from "../../types.mts";
2
+ /** Build the stale-CR clause appended to the `## Changes-requested reviews` instruction. */
3
+ export declare function buildCrStaleClause(reviews: Review[]): string;
4
+ /**
5
+ * Build the optional behind-base push hint. Empty unless the branch is actually behind its base
6
+ * and the user configured a non-blank `iterate.behindBaseHint` — the CLI never prescribes
7
+ * rebase/merge mechanics itself (see "Keep skills and loop prompts minimal" in CLAUDE.md); this
8
+ * only echoes back the caller's own configured pointer. `hint` is trimmed and type-checked at the
9
+ * point of use (rather than at config load) so a malformed rc file value (non-string, or
10
+ * whitespace-only) degrades to "no hint" instead of rendering garbage into agent-facing text or
11
+ * discarding the rest of the user's config.
12
+ */
13
+ export declare function buildBehindBaseHintInstruction(baseBranch: string, hint: string, isBehind: boolean): string[];
14
+ /** Build the `Run the apply review: command` instruction, including its optional substitution hint. */
15
+ export declare function buildResolveCommandInstruction(resolveCommand: ResolveCommand): string[];
16
+ export declare function buildFailingCheckInstructions(checks: AgentCheck[]): string[];
@@ -23,13 +23,13 @@ export function buildBehindBaseHintInstruction(baseBranch, hint, isBehind) {
23
23
  return [];
24
24
  return [`The branch is behind \`origin/${baseBranch}\` — ${trimmedHint} before pushing.`];
25
25
  }
26
- /** Build the `Run the resolve: command` instruction, including its optional substitution hint. */
26
+ /** Build the `Run the apply review: command` instruction, including its optional substitution hint. */
27
27
  export function buildResolveCommandInstruction(resolveCommand) {
28
28
  if (!resolveCommand.hasMutations)
29
29
  return [];
30
30
  const instructions = [];
31
31
  if ((resolveCommand.replyThreadIds?.length ?? 0) > 0) {
32
- instructions.push(`Before running the \`resolve:\` command, remove any thread from \`--reply-thread-ids\` if the latest visible comment in that thread is your own prior Shepherd reply. Do not reply to your own comments.`);
32
+ instructions.push(`Before running the \`apply review:\` command, remove any thread from \`--reply-thread-ids\` if the latest visible comment in that thread is your own prior Shepherd reply. Do not reply to your own comments.`);
33
33
  }
34
34
  const substituteParts = [];
35
35
  if (resolveCommand.requiresHeadSha) {
@@ -39,7 +39,7 @@ export function buildResolveCommandInstruction(resolveCommand) {
39
39
  substituteParts.push(`\`$DISMISS_MESSAGE\` with a one-sentence reply/description of what you changed`);
40
40
  }
41
41
  const substituteHint = substituteParts.length > 0 ? `, substituting ${substituteParts.join(" and ")}` : "";
42
- instructions.push(`Run the \`resolve:\` command shown above${substituteHint}.`);
42
+ instructions.push(`Run the \`apply review:\` command shown above${substituteHint}.`);
43
43
  return instructions;
44
44
  }
45
45
  export function buildFailingCheckInstructions(checks) {
@@ -0,0 +1,18 @@
1
+ import type { AgentThread, Review, ResolveCommand, AgentCheck, ReviewThread } from "../../types.mts";
2
+ import { type NormalizedBotUsernames } from "../../comments/authors.mts";
3
+ import type { MinimizeCommentsPolicy } from "../../config/load.mts";
4
+ export declare function classifyReviewSummaries(summaries: {
5
+ firstLook: Review[];
6
+ seen: Review[];
7
+ edited: Review[];
8
+ }, approvals: Review[], minimizeApprovals: boolean, minimizeComments?: MinimizeCommentsPolicy | undefined, botUsernames?: NormalizedBotUsernames, unresolvedThreads?: ReviewThread[], ruleAutoResolveIds?: string[]): {
9
+ minimizeIds: string[];
10
+ selfMinimizeIds: string[];
11
+ firstLookSummaries: Review[];
12
+ editedSummaries: Review[];
13
+ surfacedApprovals: Review[];
14
+ };
15
+ export declare function buildResolveCommand(threads: AgentThread[], resolutionOnlyThreads: ReviewThread[], allCommentIds: string[], reviews: Review[], checks: AgentCheck[], prNumber: number, botUsernames?: NormalizedBotUsernames, ruleAutoResolveThreadIds?: string[]): {
16
+ resolveCommand: ResolveCommand;
17
+ resolveOnlyCommand?: ResolveCommand;
18
+ };
@@ -17,7 +17,7 @@ export function classifyReviewSummaries(summaries, approvals, minimizeApprovals,
17
17
  const eligible = (r) => shouldMinimizeAuthor(r.authorType, minimizeComments, r.author, botUsernames) &&
18
18
  !blockedReviewIds.has(r.id);
19
19
  // First-look summaries still need one tick to surface their body to the agent,
20
- // so their minimize IDs ride in the agent-facing resolve command. Seen summaries
20
+ // so their minimize IDs ride in the agent-facing apply command. Seen summaries
21
21
  // (already surfaced in a prior tick) have no new content to show — the CLI
22
22
  // self-minimizes them in-process (selfMinimizeIds) instead of routing a
23
23
  // cosmetic-only mutation through fix_code (issue #313). Edited summaries are
@@ -80,7 +80,7 @@ export function buildResolveCommand(threads, resolutionOnlyThreads, allCommentId
80
80
  if (hasMessageMutations && hasResolveOrMinimize) {
81
81
  // Split: message-bearing mutations (replies + dismissals) ride in resolveArgv;
82
82
  // resolve/minimize mutations go in resolveOnlyArgv so they can run without SHA or message.
83
- const resolveArgv = buildPrShepherdCommand(["resolve", String(prNumber)]).argv;
83
+ const resolveArgv = buildPrShepherdCommand(["apply", "review", String(prNumber)]).argv;
84
84
  if (replyThreadIds.length > 0) {
85
85
  resolveArgv.push("--reply-thread-ids", replyThreadIds.join(","));
86
86
  }
@@ -99,7 +99,7 @@ export function buildResolveCommand(threads, resolutionOnlyThreads, allCommentId
99
99
  ...(hasDismiss ? { dismissReviewIds } : undefined),
100
100
  hasMutations: true,
101
101
  };
102
- const resolveOnlyArgv = buildPrShepherdCommand(["resolve", String(prNumber)]).argv;
102
+ const resolveOnlyArgv = buildPrShepherdCommand(["apply", "review", String(prNumber)]).argv;
103
103
  if (resolveThreadIds.length > 0) {
104
104
  resolveOnlyArgv.push("--resolve-thread-ids", resolveThreadIds.join(","));
105
105
  }
@@ -116,7 +116,7 @@ export function buildResolveCommand(threads, resolutionOnlyThreads, allCommentId
116
116
  return { resolveCommand, resolveOnlyCommand };
117
117
  }
118
118
  // Single command: all mutations combined (or only one category present).
119
- const argv = buildPrShepherdCommand(["resolve", String(prNumber)]).argv;
119
+ const argv = buildPrShepherdCommand(["apply", "review", String(prNumber)]).argv;
120
120
  if (replyThreadIds.length > 0) {
121
121
  argv.push("--reply-thread-ids", replyThreadIds.join(","));
122
122
  argv.push("--message", "$DISMISS_MESSAGE");
@@ -0,0 +1,31 @@
1
+ import type { EscalateDetails, EscalateTrigger, ReviewThread } from "../../types.mts";
2
+ interface EscalateCheck {
3
+ triggers: EscalateTrigger[];
4
+ thrashHistory?: EscalateDetails["thrashHistory"];
5
+ }
6
+ export declare function checkEscalateTriggers(actionableThreads: ReviewThread[], threadAttempts: Record<string, number>): EscalateCheck;
7
+ interface BaseBranchLookup {
8
+ branch: string;
9
+ /** True when we could not confirm the branch name from GitHub. Callers must
10
+ * escalate rather than emitting a rebase against a potentially-wrong base. */
11
+ isFallback: boolean;
12
+ /** Populated when `isFallback`; one-line reason shown in escalate output. */
13
+ failureReason?: string;
14
+ }
15
+ /**
16
+ * Validate the base branch name from the GraphQL batch (`report.baseBranch`)
17
+ * and fall back safely if it's missing/unsafe. The branch is interpolated into
18
+ * shell commands by `buildFixInstructions`, so we reject anything outside
19
+ * `[A-Za-z0-9._/-]` to prevent shell injection.
20
+ */
21
+ /**
22
+ * Render a seconds count as an approximate human duration: "8 seconds" below one minute,
23
+ * otherwise whole minutes ("166 minutes", "60 minutes") — matching the precision the
24
+ * generic stall timer has always reported, just adding a seconds tier for sub-minute ages
25
+ * instead of always flooring to "0 minutes".
26
+ */
27
+ export declare function formatDurationApprox(seconds: number): string;
28
+ export declare function validateBaseBranch(raw: string): BaseBranchLookup;
29
+ export declare function buildEscalateHumanMessage(escalate: Omit<EscalateDetails, "humanMessage">, pr: number): string;
30
+ export declare function buildEscalateSuggestion(triggers: EscalateTrigger[], detail?: string): string;
31
+ export {};
@@ -1,4 +1,7 @@
1
1
  import { loadConfig } from "../../config/load.mjs";
2
+ function renderEscalateAuthor(item) {
3
+ return [`@${item.author}`, item.authorType, item.authorAssociation].filter(Boolean).join(" · ");
4
+ }
2
5
  export function checkEscalateTriggers(actionableThreads, threadAttempts) {
3
6
  const triggers = [];
4
7
  const maxAttempts = loadConfig().iterate.fixAttemptsPerThread;
@@ -85,21 +88,21 @@ export function buildEscalateHumanMessage(escalate, pr) {
85
88
  lines.push("");
86
89
  for (const t of escalate.unresolvedThreads) {
87
90
  const loc = t.path ? `\`${t.path}:${t.line ?? "?"}\`` : "(no location)";
88
- lines.push(`- thread \`${t.id}\` — ${loc} (@${t.author}):`);
91
+ lines.push(`- thread \`${t.id}\` — ${loc} (${renderEscalateAuthor(t)}):`);
89
92
  lines.push("");
90
93
  for (const bodyLine of t.body.split("\n"))
91
94
  lines.push(` > ${bodyLine}`);
92
95
  lines.push("");
93
96
  }
94
97
  for (const r of escalate.changesRequestedReviews) {
95
- lines.push(`- review \`${r.id}\` (@${r.author}):`);
98
+ lines.push(`- review \`${r.id}\` (${renderEscalateAuthor(r)}):`);
96
99
  lines.push("");
97
100
  for (const bodyLine of r.body.split("\n"))
98
101
  lines.push(` > ${bodyLine}`);
99
102
  lines.push("");
100
103
  }
101
104
  for (const c of escalate.ambiguousComments) {
102
- lines.push(`- comment \`${c.id}\` (@${c.author}):`);
105
+ lines.push(`- comment \`${c.id}\` (${renderEscalateAuthor(c)}):`);
103
106
  lines.push("");
104
107
  for (const bodyLine of c.body.split("\n"))
105
108
  lines.push(` > ${bodyLine}`);
@@ -137,7 +140,7 @@ export function buildEscalateSuggestion(triggers, detail) {
137
140
  }
138
141
  if (triggers.includes("bot-cr-not-dismissed")) {
139
142
  const ids = detail ? ` (review IDs: ${detail})` : "";
140
- return `Bot CHANGES_REQUESTED review(s) remained undismissed past the stall window${ids}. The agent likely dropped \`--dismiss-review-ids\` from a prior resolve command. Dismiss the review(s) manually (or re-run resolve with the IDs) to unblock the PR.`;
143
+ return `Bot CHANGES_REQUESTED review(s) remained undismissed past the stall window${ids}. The agent likely dropped \`--dismiss-review-ids\` from a prior apply command. Dismiss the review(s) manually (or re-run \`pr-shepherd apply review\` with the IDs) to unblock the PR.`;
141
144
  }
142
145
  return "Ambiguous state — automated handling cannot proceed safely. Inspect the PR and act manually.";
143
146
  }
@@ -0,0 +1,25 @@
1
+ import type { IterateCommandOptions, IterateResult, IterateResultBase, Review, ShepherdReport } from "../../types.mts";
2
+ import type { NormalizedBotUsernames } from "../../comments/authors.mts";
3
+ interface HandleFixCodeContext {
4
+ base: IterateResultBase;
5
+ report: ShepherdReport;
6
+ opts: IterateCommandOptions;
7
+ headSha: string;
8
+ stallKey: {
9
+ owner: string;
10
+ repo: string;
11
+ pr: number;
12
+ };
13
+ prNumber: number;
14
+ stallTimeoutSeconds: number;
15
+ repoOwner: string;
16
+ repoName: string;
17
+ reviewSummaryIds: string[];
18
+ firstLookSummaries: Review[];
19
+ editedSummaries: Review[];
20
+ surfacedApprovals: Review[];
21
+ botUsernames: NormalizedBotUsernames;
22
+ ruleAutoResolveThreadIds?: string[];
23
+ }
24
+ export declare function handleFixCode(ctx: HandleFixCodeContext): Promise<IterateResult>;
25
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { ActiveCheck, IterateResult, IterateResultBase, IterateResultSummary, RelevantCheck, ShepherdReport } from "../../types.mts";
2
+ export { buildAutoCancelRunIdsWithOptions, buildInProgressRunIds, buildRunProtection, } from "./reruns.mts";
3
+ export declare function buildSummary(report: ShepherdReport): IterateResultSummary;
4
+ /** Non-blocking check-name lists (ignored/superseded), omitted from the result when empty. */
5
+ export declare function buildSuppressedCheckFields(report: ShepherdReport): Pick<IterateResultBase, "ignoredNames" | "supersededNames">;
6
+ /** Build the `cancel` result for a merged/closed PR — caller has already updated ready-delay/stall state. */
7
+ export declare function buildTerminalCancelResult(report: ShepherdReport): IterateResult;
8
+ /** Build completed, non-skipped checks relevant to PR readiness. */
9
+ export declare function buildRelevantChecks(report: ShepherdReport): RelevantCheck[];
10
+ export declare function buildActiveChecks(report: ShepherdReport): ActiveCheck[];
11
+ export declare function tryCancelRun(runId: string, owner: string, repo: string): Promise<string | null>;
12
+ export declare function getCurrentHeadSha(): Promise<string | null>;
13
+ export declare function buildWaitLog(base: IterateResultBase): string;