pr-shepherd 0.34.0 → 0.36.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 (231) hide show
  1. package/.claude-plugin/plugin.json +3 -2
  2. package/.grok-plugin/marketplace.json +17 -0
  3. package/README.md +80 -43
  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/checks/triage.mjs +11 -3
  11. package/bin/classify/apply.d.mts +18 -0
  12. package/bin/classify/apply.mjs +4 -0
  13. package/bin/classify/loader.d.mts +10 -0
  14. package/bin/classify/types.d.mts +35 -0
  15. package/bin/cli/args.d.mts +18 -0
  16. package/bin/cli/args.mjs +1 -0
  17. package/bin/cli/clean-formatter.d.mts +2 -0
  18. package/bin/cli/default-poll.d.mts +2 -0
  19. package/bin/cli/default-poll.mjs +1 -0
  20. package/bin/cli/duration-flag.d.mts +2 -0
  21. package/bin/cli/duration.d.mts +13 -0
  22. package/bin/cli/fence.d.mts +1 -0
  23. package/bin/cli/fix-formatter-extra.d.mts +3 -0
  24. package/bin/cli/fix-formatter.d.mts +2 -0
  25. package/bin/cli/fix-formatter.mjs +6 -6
  26. package/bin/cli/formatters.d.mts +7 -0
  27. package/bin/cli/handlers.d.mts +4 -0
  28. package/bin/cli/handlers.mjs +11 -10
  29. package/bin/cli/help-command-pages.d.mts +231 -0
  30. package/bin/cli/help-command-pages.mjs +106 -1
  31. package/bin/cli/help-iterate-poll-pages.d.mts +4 -0
  32. package/bin/cli/help-iterate-poll-pages.mjs +14 -7
  33. package/bin/cli/help-log-file-page.d.mts +1 -0
  34. package/bin/cli/help-top-page.d.mts +1 -0
  35. package/bin/cli/help-top-page.mjs +16 -16
  36. package/bin/cli/help.d.mts +236 -0
  37. package/bin/cli/help.mjs +17 -0
  38. package/bin/cli/iterate-emitter.d.mts +8 -0
  39. package/bin/cli/iterate-flags.d.mts +11 -0
  40. package/bin/cli/iterate-formatter.d.mts +19 -0
  41. package/bin/cli/iterate-formatter.mjs +11 -2
  42. package/bin/cli/iterate-instructions.d.mts +6 -0
  43. package/bin/cli/iterate-lean.d.mts +12 -0
  44. package/bin/cli/iterate-lean.mjs +1 -0
  45. package/bin/cli/journal-formatter.d.mts +2 -0
  46. package/bin/cli/journal-formatter.mjs +15 -0
  47. package/bin/cli/journal-handler.d.mts +1 -0
  48. package/bin/cli/journal-handler.mjs +7 -20
  49. package/bin/cli/list-formatters.d.mts +76 -0
  50. package/bin/cli/list-formatters.mjs +9 -9
  51. package/bin/cli/mark-files-as-viewed-flags.d.mts +11 -0
  52. package/bin/cli/mark-files-as-viewed-formatter.d.mts +2 -0
  53. package/bin/cli/mutate-formatter.d.mts +2 -0
  54. package/bin/cli/poll-handler.d.mts +1 -0
  55. package/bin/cli/poll-handler.mjs +9 -2
  56. package/bin/cli/resolve-validators.d.mts +3 -0
  57. package/bin/cli/resolve-validators.mjs +3 -3
  58. package/bin/cli/runner.d.mts +7 -0
  59. package/bin/cli/suggestion-renderer.d.mts +3 -0
  60. package/bin/cli/validate-default-args.d.mts +6 -0
  61. package/bin/cli-parser.d.mts +2 -0
  62. package/bin/cli-parser.mjs +72 -16
  63. package/bin/commands/check-annotations.d.mts +5 -0
  64. package/bin/commands/check-status.d.mts +3 -0
  65. package/bin/commands/check-terminal-report.d.mts +5 -0
  66. package/bin/commands/check.d.mts +7 -0
  67. package/bin/commands/check.mjs +28 -23
  68. package/bin/commands/clean.d.mts +21 -0
  69. package/bin/commands/commit-suggestion-instruction.d.mts +8 -0
  70. package/bin/commands/commit-suggestion-instruction.mjs +3 -3
  71. package/bin/commands/commit-suggestion.d.mts +8 -0
  72. package/bin/commands/commit-suggestion.mjs +20 -13
  73. package/bin/commands/iterate/check-instructions.d.mts +16 -0
  74. package/bin/commands/iterate/check-instructions.mjs +3 -3
  75. package/bin/commands/iterate/classify.d.mts +18 -0
  76. package/bin/commands/iterate/classify.mjs +4 -4
  77. package/bin/commands/iterate/escalate.d.mts +31 -0
  78. package/bin/commands/iterate/escalate.mjs +7 -4
  79. package/bin/commands/iterate/fix-code.d.mts +25 -0
  80. package/bin/commands/iterate/fix-code.mjs +1 -1
  81. package/bin/commands/iterate/helpers.d.mts +14 -0
  82. package/bin/commands/iterate/helpers.mjs +19 -7
  83. package/bin/commands/iterate/index.d.mts +2 -0
  84. package/bin/commands/iterate/index.mjs +8 -12
  85. package/bin/commands/iterate/render.d.mts +5 -0
  86. package/bin/commands/iterate/render.mjs +8 -6
  87. package/bin/commands/iterate/reruns.d.mts +20 -0
  88. package/bin/commands/iterate/stall.d.mts +6 -0
  89. package/bin/commands/journal/index.d.mts +14 -0
  90. package/bin/commands/journal/index.mjs +1 -0
  91. package/bin/commands/journal/transform.d.mts +22 -0
  92. package/bin/commands/log-file.d.mts +5 -0
  93. package/bin/commands/mark-files-as-viewed.d.mts +26 -0
  94. package/bin/commands/mark-files-as-viewed.mjs +1 -0
  95. package/bin/commands/poll.d.mts +12 -0
  96. package/bin/commands/poll.mjs +52 -17
  97. package/bin/commands/ready-delay.d.mts +29 -0
  98. package/bin/commands/ready-delay.mjs +3 -13
  99. package/bin/commands/ready-mergeability.d.mts +15 -0
  100. package/bin/commands/resolve-mutate.d.mts +4 -0
  101. package/bin/commands/resolve-mutate.mjs +1 -0
  102. package/bin/commands/resolve.d.mts +4 -0
  103. package/bin/commands/shepherd-journal.d.mts +7 -0
  104. package/bin/commands/shepherd-journal.mjs +2 -2
  105. package/bin/comments/authors.d.mts +14 -0
  106. package/bin/comments/marker.d.mts +2 -0
  107. package/bin/comments/minimize-policy.d.mts +4 -0
  108. package/bin/comments/pending-ops.d.mts +15 -0
  109. package/bin/comments/rate-limit.d.mts +18 -0
  110. package/bin/comments/resolve.d.mts +34 -0
  111. package/bin/comments/resolve.mjs +1 -0
  112. package/bin/comments/review-thread-markers.d.mts +8 -0
  113. package/bin/comments/review-visibility.d.mts +28 -0
  114. package/bin/comments/sha-poll.d.mts +2 -0
  115. package/bin/comments/thread-visibility.d.mts +11 -0
  116. package/bin/comments/visible-comments.d.mts +11 -0
  117. package/bin/config/load.d.mts +60 -0
  118. package/bin/config/load.mjs +129 -16
  119. package/bin/config.json +0 -2
  120. package/bin/execution-context.d.mts +9 -0
  121. package/bin/execution-context.mjs +19 -0
  122. package/bin/exit-codes.d.mts +51 -0
  123. package/bin/github/activity.d.mts +3 -0
  124. package/bin/github/activity.mjs +7 -0
  125. package/bin/github/batch-page-helpers.d.mts +45 -0
  126. package/bin/github/batch-page-helpers.mjs +63 -0
  127. package/bin/github/batch-page.d.mts +14 -0
  128. package/bin/github/batch-page.mjs +62 -0
  129. package/bin/github/batch-parse-suites.d.mts +4 -0
  130. package/bin/github/batch-parse-suites.mjs +25 -0
  131. package/bin/github/batch-parser-helpers.d.mts +22 -0
  132. package/bin/github/batch-parsers-rules.d.mts +6 -0
  133. package/bin/github/batch-parsers-rules.mjs +122 -0
  134. package/bin/github/batch-parsers.d.mts +3 -0
  135. package/bin/github/batch-parsers.mjs +12 -0
  136. package/bin/github/batch-raw-rules.d.mts +59 -0
  137. package/bin/github/batch-raw-rules.mjs +1 -0
  138. package/bin/github/batch-raw-types.d.mts +216 -0
  139. package/bin/github/batch-response.d.mts +4 -0
  140. package/bin/github/batch.d.mts +24 -0
  141. package/bin/github/batch.mjs +14 -120
  142. package/bin/github/branch-protection.d.mts +3 -0
  143. package/bin/github/check-annotations.d.mts +2 -0
  144. package/bin/github/client.d.mts +46 -0
  145. package/bin/github/client.mjs +7 -2
  146. package/bin/github/errors.d.mts +25 -0
  147. package/bin/github/gql/batch-pr-page.gql +189 -0
  148. package/bin/github/gql/batch-pr.gql +79 -21
  149. package/bin/github/gql/commit-suggestion-thread.gql +40 -0
  150. package/bin/github/gql/review-thread-comments.gql +1 -0
  151. package/bin/github/graphql-http.d.mts +19 -0
  152. package/bin/github/graphql-response.d.mts +7 -0
  153. package/bin/github/http-auth.d.mts +4 -0
  154. package/bin/github/http-request.d.mts +7 -0
  155. package/bin/github/http-utils.d.mts +11 -0
  156. package/bin/github/http.d.mts +6 -0
  157. package/bin/github/http.mjs +2 -1
  158. package/bin/github/pagination.d.mts +46 -0
  159. package/bin/github/pagination.mjs +3 -2
  160. package/bin/github/queries.d.mts +28 -0
  161. package/bin/github/queries.mjs +4 -0
  162. package/bin/github/rest-http.d.mts +7 -0
  163. package/bin/github/rest-http.mjs +25 -86
  164. package/bin/github/rest-text.d.mts +1 -0
  165. package/bin/github/rest-text.mjs +88 -0
  166. package/bin/github/suggestion-thread.d.mts +9 -0
  167. package/bin/github/suggestion-thread.mjs +45 -0
  168. package/bin/github/thread-comments.d.mts +2 -0
  169. package/bin/github/thread-comments.mjs +12 -8
  170. package/bin/index.d.mts +10 -0
  171. package/bin/index.mjs +1 -1
  172. package/bin/log/log-file.d.mts +28 -0
  173. package/bin/log/session.d.mts +31 -0
  174. package/bin/log/setup.d.mts +6 -0
  175. package/bin/mcp/index.d.mts +5 -0
  176. package/bin/mcp/index.mjs +8 -0
  177. package/bin/mcp/server.d.mts +8 -0
  178. package/bin/mcp/server.mjs +157 -0
  179. package/bin/mcp-stdio.d.mts +2 -0
  180. package/bin/mcp-stdio.mjs +7 -0
  181. package/bin/merge-status/derive.d.mts +19 -0
  182. package/bin/merge-status/derive.mjs +2 -0
  183. package/bin/merge-status/requirements-format.d.mts +3 -0
  184. package/bin/merge-status/requirements-format.mjs +88 -0
  185. package/bin/merge-status/requirements.d.mts +2 -0
  186. package/bin/merge-status/requirements.mjs +51 -0
  187. package/bin/reporters/agent.d.mts +23 -0
  188. package/bin/reporters/agent.mjs +3 -0
  189. package/bin/state/base.d.mts +10 -0
  190. package/bin/state/base.mjs +23 -0
  191. package/bin/state/bot-cr-seen.d.mts +51 -0
  192. package/bin/state/bot-cr-seen.mjs +4 -14
  193. package/bin/state/fix-attempts.d.mts +27 -0
  194. package/bin/state/fix-attempts.mjs +3 -13
  195. package/bin/state/iterate-stall.d.mts +27 -0
  196. package/bin/state/iterate-stall.mjs +3 -13
  197. package/bin/state/seen-comments.d.mts +62 -0
  198. package/bin/state/seen-comments.mjs +6 -13
  199. package/bin/suggestions/extract.d.mts +8 -0
  200. package/bin/suggestions/parse.d.mts +48 -0
  201. package/bin/suggestions/patch.d.mts +14 -0
  202. package/bin/threads/transcript.d.mts +14 -0
  203. package/bin/threads/transcript.mjs +4 -0
  204. package/bin/types/activity.d.mts +30 -0
  205. package/bin/types/agent-thread.d.mts +9 -0
  206. package/bin/types/check-annotations.d.mts +14 -0
  207. package/bin/types/check-classification.d.mts +19 -0
  208. package/bin/types/github.d.mts +136 -0
  209. package/bin/types/iterate.d.mts +156 -0
  210. package/bin/types/merge-requirements.d.mts +82 -0
  211. package/bin/types/merge-requirements.mjs +2 -0
  212. package/bin/types/protected-run.d.mts +6 -0
  213. package/bin/types/report.d.mts +176 -0
  214. package/bin/types/review-thread.d.mts +12 -0
  215. package/bin/types.d.mts +10 -0
  216. package/bin/types.mjs +1 -0
  217. package/bin/util/markdown.d.mts +1 -0
  218. package/bin/util/path-segment.d.mts +4 -0
  219. package/bin/util/path-segment.mjs +2 -0
  220. package/bin/util/pool.d.mts +2 -0
  221. package/bin/util/pool.mjs +18 -0
  222. package/bin/util/sleep.d.mts +1 -0
  223. package/bin/util/worktree.d.mts +9 -0
  224. package/bin/util/worktree.mjs +4 -1
  225. package/package.json +51 -37
  226. package/plugins/pr-shepherd/.codex-plugin/plugin.json +3 -2
  227. package/plugins/pr-shepherd/.codex.mcp.json +8 -0
  228. package/plugins/pr-shepherd/.mcp.json +6 -0
  229. package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +5 -19
  230. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +6 -15
  231. package/src/classify/types.mts +12 -0
@@ -0,0 +1,46 @@
1
+ /**
2
+ * High-level GitHub client — wraps http.mts for application-level concerns.
3
+ *
4
+ * All GitHub I/O goes through native fetch (via http.mts); the `gh` CLI is no
5
+ * longer used for GitHub API calls, but may be invoked as an auth-token
6
+ * fallback via `gh auth token` when neither GH_TOKEN nor GITHUB_TOKEN is set.
7
+ */
8
+ import type { MergeableState, MergeStateStatus } from "../types.mts";
9
+ export type { RateLimitInfo } from "./http.mts";
10
+ export { graphql, graphqlWithRateLimit } from "./http.mts";
11
+ export interface RepoInfo {
12
+ owner: string;
13
+ name: string;
14
+ }
15
+ /**
16
+ * Returns the current repo's owner and name by parsing `git remote get-url origin`.
17
+ * Handles https://, git@, and ssh:// remote URL formats.
18
+ */
19
+ export declare function getRepoInfo(): Promise<RepoInfo>;
20
+ /**
21
+ * Derives the PR number for the current HEAD branch.
22
+ * Returns null if no open PR is found.
23
+ */
24
+ export declare function getCurrentPrNumber(): Promise<number | null>;
25
+ /** Returns the PR number for a given branch, or null if no open PR is found. */
26
+ export declare function getPrNumberForBranch(branch: string, owner: string, repo: string): Promise<number | null>;
27
+ /** Returns the `headRefOid` (commit SHA) of the given PR as reported by GitHub. */
28
+ export declare function getPrHeadSha(pr: number, owner: string, name: string): Promise<string>;
29
+ /** Fetches the node ID and body text for a PR. GitHub returns null body for empty bodies — coerced to "". */
30
+ export declare function getPullRequestBody(pr: number, owner: string, name: string): Promise<{
31
+ nodeId: string;
32
+ body: string;
33
+ }>;
34
+ /** Overwrites the PR body. */
35
+ export declare function updatePullRequestBody(pullRequestId: string, body: string): Promise<void>;
36
+ /**
37
+ * Fetches `mergeable` and `mergeStateStatus` via the REST API.
38
+ *
39
+ * Used as a fallback when the GraphQL API returns `UNKNOWN` for these fields —
40
+ * a known GitHub quirk where GraphQL lags behind the REST layer.
41
+ */
42
+ export declare function getMergeableState(pr: number, owner: string, repo: string): Promise<{
43
+ mergeable: MergeableState;
44
+ mergeStateStatus: MergeStateStatus;
45
+ }>;
46
+ export declare function getCurrentBranch(): Promise<string>;
@@ -9,6 +9,7 @@ import { execFile as execFileCb } from "node:child_process";
9
9
  import { promisify } from "node:util";
10
10
  import { graphql as httpGraphql, rest } from "./http.mjs";
11
11
  import { PR_NUMBER_BY_BRANCH_QUERY, GET_PR_HEAD_SHA_QUERY, GET_PR_BODY_QUERY, UPDATE_PR_BODY_MUTATION, } from "./queries.mjs";
12
+ import { getExecutionCwd } from "../execution-context.mjs";
12
13
  const execFile = promisify(execFileCb);
13
14
  // ---------------------------------------------------------------------------
14
15
  // GraphQL — thin re-exports so callers don't need to import http.mts directly
@@ -19,7 +20,9 @@ export { graphql, graphqlWithRateLimit } from "./http.mjs";
19
20
  * Handles https://, git@, and ssh:// remote URL formats.
20
21
  */
21
22
  export async function getRepoInfo() {
22
- const { stdout } = await execFile("git", ["remote", "get-url", "origin"]);
23
+ const { stdout } = await execFile("git", ["remote", "get-url", "origin"], {
24
+ cwd: getExecutionCwd(),
25
+ });
23
26
  const url = stdout.trim();
24
27
  return parseRemoteUrl(url);
25
28
  }
@@ -95,7 +98,9 @@ export async function getMergeableState(pr, owner, repo) {
95
98
  // Internal helpers
96
99
  // ---------------------------------------------------------------------------
97
100
  export async function getCurrentBranch() {
98
- const { stdout } = await execFile("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
101
+ const { stdout } = await execFile("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
102
+ cwd: getExecutionCwd(),
103
+ });
99
104
  return stdout.trim();
100
105
  }
101
106
  function parseRemoteUrl(url) {
@@ -0,0 +1,25 @@
1
+ import { ShepherdError } from "../exit-codes.mts";
2
+ import type { RateLimitInfo } from "./http.mts";
3
+ export interface GitHubGraphQlError {
4
+ message: string;
5
+ path?: unknown;
6
+ }
7
+ export declare class GitHubRequestError extends ShepherdError {
8
+ readonly status: number;
9
+ readonly rateLimit?: RateLimitInfo;
10
+ readonly retryAfterSeconds?: number;
11
+ readonly graphqlErrors?: GitHubGraphQlError[];
12
+ constructor(message: string, opts: {
13
+ status: number;
14
+ rateLimit?: RateLimitInfo;
15
+ retryAfterSeconds?: number;
16
+ graphqlErrors?: GitHubGraphQlError[];
17
+ /**
18
+ * Bypasses status-based classification entirely — for callers that already
19
+ * know the failure kind better than the HTTP status can express (e.g. a
20
+ * response that failed to parse at all, which is an internal failure, not
21
+ * an availability or permission problem).
22
+ */
23
+ exitCodeOverride?: number;
24
+ });
25
+ }
@@ -0,0 +1,189 @@
1
+ # Follow-up pages only — skipped connections are omitted via @include so extra
2
+ # pages do not re-pay the full batch-pr.gql node cost. Outstanding cursors are
3
+ # sent together in one request.
4
+ query BatchPrPage(
5
+ $owner: String!
6
+ $repo: String!
7
+ $pr: Int!
8
+ $includeThreads: Boolean!
9
+ $threadsCursor: String
10
+ $includeComments: Boolean!
11
+ $commentsCursor: String
12
+ $includeChangesRequested: Boolean!
13
+ $changesRequestedCursor: String
14
+ $includeReviewSummaries: Boolean!
15
+ $reviewSummariesCursor: String
16
+ $includeApprovedReviews: Boolean!
17
+ $approvedReviewsCursor: String
18
+ $includeChecks: Boolean!
19
+ $checksCursor: String
20
+ ) {
21
+ repository(owner: $owner, name: $repo) {
22
+ pullRequest(number: $pr) {
23
+ reviewThreads(last: 100, before: $threadsCursor) @include(if: $includeThreads) {
24
+ pageInfo {
25
+ hasPreviousPage
26
+ startCursor
27
+ }
28
+ nodes {
29
+ id
30
+ isResolved
31
+ isOutdated
32
+ path
33
+ line
34
+ startLine
35
+ comments(first: 100) {
36
+ pageInfo {
37
+ hasNextPage
38
+ endCursor
39
+ }
40
+ nodes {
41
+ id
42
+ isMinimized
43
+ url
44
+ authorAssociation
45
+ author {
46
+ __typename
47
+ login
48
+ }
49
+ pullRequestReview {
50
+ id
51
+ }
52
+ body
53
+ path
54
+ line
55
+ startLine
56
+ createdAt
57
+ }
58
+ }
59
+ }
60
+ }
61
+ comments(last: 100, before: $commentsCursor) @include(if: $includeComments) {
62
+ pageInfo {
63
+ hasPreviousPage
64
+ startCursor
65
+ }
66
+ nodes {
67
+ id
68
+ isMinimized
69
+ url
70
+ authorAssociation
71
+ author {
72
+ __typename
73
+ login
74
+ }
75
+ body
76
+ createdAt
77
+ }
78
+ }
79
+ changesRequestedReviews: reviews(
80
+ states: CHANGES_REQUESTED
81
+ last: 50
82
+ before: $changesRequestedCursor
83
+ ) @include(if: $includeChangesRequested) {
84
+ pageInfo {
85
+ hasPreviousPage
86
+ startCursor
87
+ }
88
+ nodes {
89
+ id
90
+ authorAssociation
91
+ author {
92
+ __typename
93
+ login
94
+ }
95
+ body
96
+ createdAt
97
+ commit {
98
+ oid
99
+ }
100
+ }
101
+ }
102
+ reviewSummaries: reviews(states: COMMENTED, last: 50, before: $reviewSummariesCursor)
103
+ @include(if: $includeReviewSummaries) {
104
+ pageInfo {
105
+ hasPreviousPage
106
+ startCursor
107
+ }
108
+ nodes {
109
+ id
110
+ isMinimized
111
+ authorAssociation
112
+ author {
113
+ __typename
114
+ login
115
+ }
116
+ body
117
+ createdAt
118
+ }
119
+ }
120
+ approvedReviews: reviews(states: APPROVED, last: 50, before: $approvedReviewsCursor)
121
+ @include(if: $includeApprovedReviews) {
122
+ pageInfo {
123
+ hasPreviousPage
124
+ startCursor
125
+ }
126
+ nodes {
127
+ id
128
+ isMinimized
129
+ authorAssociation
130
+ author {
131
+ __typename
132
+ login
133
+ }
134
+ body
135
+ createdAt
136
+ }
137
+ }
138
+ commits(last: 1) @include(if: $includeChecks) {
139
+ nodes {
140
+ commit {
141
+ oid
142
+ statusCheckRollup {
143
+ contexts(first: 100, after: $checksCursor) {
144
+ pageInfo {
145
+ hasNextPage
146
+ endCursor
147
+ }
148
+ nodes {
149
+ __typename
150
+ ... on CheckRun {
151
+ id
152
+ name
153
+ status
154
+ conclusion
155
+ detailsUrl
156
+ completedAt
157
+ startedAt
158
+ title
159
+ summary
160
+ checkSuite {
161
+ createdAt
162
+ updatedAt
163
+ workflowRun {
164
+ event
165
+ createdAt
166
+ updatedAt
167
+ workflow {
168
+ name
169
+ databaseId
170
+ }
171
+ }
172
+ }
173
+ }
174
+ ... on StatusContext {
175
+ context
176
+ state
177
+ createdAt
178
+ targetUrl
179
+ description
180
+ }
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
@@ -1,14 +1,6 @@
1
- query BatchPr(
2
- $owner: String!
3
- $repo: String!
4
- $pr: Int!
5
- $threadsCursor: String
6
- $checksCursor: String
7
- $commentsCursor: String
8
- $changesRequestedCursor: String
9
- $reviewSummariesCursor: String
10
- $approvedReviewsCursor: String
11
- ) {
1
+ # First page only. Extra pages use batch-pr-page.gql so follow-ups do not
2
+ # re-select every connection (GraphQL points scale with possible nodes).
3
+ query BatchPr($owner: String!, $repo: String!, $pr: Int!) {
12
4
  repository(owner: $owner, name: $repo) {
13
5
  pullRequest(number: $pr) {
14
6
  id
@@ -24,13 +16,62 @@ query BatchPr(
24
16
  nameWithOwner
25
17
  }
26
18
  baseRefName
19
+ isInMergeQueue
20
+ isMergeQueueEnabled
21
+ mergeQueueEntry {
22
+ position
23
+ state
24
+ estimatedTimeToMerge
25
+ }
26
+ stack {
27
+ number
28
+ size
29
+ baseRefName
30
+ }
31
+ stackEntry {
32
+ position
33
+ }
27
34
  baseRef {
28
35
  branchProtectionRule {
29
36
  requiresApprovingReviews
30
37
  requiredApprovingReviewCount
31
38
  requiresConversationResolution
39
+ requiresCodeOwnerReviews
40
+ requireLastPushApproval
41
+ requiresCommitSignatures
42
+ requiresLinearHistory
32
43
  requiresStatusChecks
33
44
  requiredStatusCheckContexts
45
+ requiresStrictStatusChecks
46
+ requiresDeployments
47
+ requiredDeploymentEnvironments
48
+ }
49
+ rules(first: 100) {
50
+ nodes {
51
+ type
52
+ parameters {
53
+ ... on PullRequestParameters {
54
+ requiredApprovingReviewCount
55
+ requiredReviewThreadResolution
56
+ requireCodeOwnerReview
57
+ requireLastPushApproval
58
+ }
59
+ ... on RequiredStatusChecksParameters {
60
+ strictRequiredStatusChecksPolicy
61
+ requiredStatusChecks {
62
+ context
63
+ }
64
+ }
65
+ ... on RequiredDeploymentsParameters {
66
+ requiredDeploymentEnvironments
67
+ }
68
+ ... on CodeScanningParameters {
69
+ codeScanningTools {
70
+ tool
71
+ }
72
+ }
73
+ }
74
+ }
34
75
  }
35
76
  }
36
77
  # Not paginated — capped at 50; PRs with more pending reviewers truncate silently.
@@ -61,7 +102,7 @@ query BatchPr(
61
102
  state
62
103
  }
63
104
  }
64
- reviewThreads(last: 100, before: $threadsCursor) {
105
+ reviewThreads(last: 100) {
65
106
  pageInfo {
66
107
  hasPreviousPage
67
108
  startCursor
@@ -82,6 +123,7 @@ query BatchPr(
82
123
  id
83
124
  isMinimized
84
125
  url
126
+ authorAssociation
85
127
  author {
86
128
  __typename
87
129
  login
@@ -98,7 +140,7 @@ query BatchPr(
98
140
  }
99
141
  }
100
142
  }
101
- comments(last: 100, before: $commentsCursor) {
143
+ comments(last: 100) {
102
144
  pageInfo {
103
145
  hasPreviousPage
104
146
  startCursor
@@ -107,6 +149,7 @@ query BatchPr(
107
149
  id
108
150
  isMinimized
109
151
  url
152
+ authorAssociation
110
153
  author {
111
154
  __typename
112
155
  login
@@ -115,17 +158,14 @@ query BatchPr(
115
158
  createdAt
116
159
  }
117
160
  }
118
- changesRequestedReviews: reviews(
119
- states: CHANGES_REQUESTED
120
- last: 50
121
- before: $changesRequestedCursor
122
- ) {
161
+ changesRequestedReviews: reviews(states: CHANGES_REQUESTED, last: 50) {
123
162
  pageInfo {
124
163
  hasPreviousPage
125
164
  startCursor
126
165
  }
127
166
  nodes {
128
167
  id
168
+ authorAssociation
129
169
  author {
130
170
  __typename
131
171
  login
@@ -137,7 +177,7 @@ query BatchPr(
137
177
  }
138
178
  }
139
179
  }
140
- reviewSummaries: reviews(states: COMMENTED, last: 50, before: $reviewSummariesCursor) {
180
+ reviewSummaries: reviews(states: COMMENTED, last: 50) {
141
181
  pageInfo {
142
182
  hasPreviousPage
143
183
  startCursor
@@ -145,6 +185,7 @@ query BatchPr(
145
185
  nodes {
146
186
  id
147
187
  isMinimized
188
+ authorAssociation
148
189
  author {
149
190
  __typename
150
191
  login
@@ -156,7 +197,7 @@ query BatchPr(
156
197
  allReviews: reviews(last: 1) {
157
198
  totalCount
158
199
  }
159
- approvedReviews: reviews(states: APPROVED, last: 50, before: $approvedReviewsCursor) {
200
+ approvedReviews: reviews(states: APPROVED, last: 50) {
160
201
  pageInfo {
161
202
  hasPreviousPage
162
203
  startCursor
@@ -164,6 +205,7 @@ query BatchPr(
164
205
  nodes {
165
206
  id
166
207
  isMinimized
208
+ authorAssociation
167
209
  author {
168
210
  __typename
169
211
  login
@@ -178,8 +220,24 @@ query BatchPr(
178
220
  commit {
179
221
  oid
180
222
  committedDate
223
+ checkSuites(first: 50) {
224
+ pageInfo {
225
+ hasNextPage
226
+ }
227
+ nodes {
228
+ conclusion
229
+ workflowRun {
230
+ databaseId
231
+ event
232
+ url
233
+ workflow {
234
+ name
235
+ }
236
+ }
237
+ }
238
+ }
181
239
  statusCheckRollup {
182
- contexts(first: 100, after: $checksCursor) {
240
+ contexts(first: 100) {
183
241
  pageInfo {
184
242
  hasNextPage
185
243
  endCursor
@@ -0,0 +1,40 @@
1
+ query CommitSuggestionThread($owner: String!, $repo: String!, $pr: Int!, $threadId: ID!) {
2
+ repository(owner: $owner, name: $repo) {
3
+ pullRequest(number: $pr) {
4
+ headRefOid
5
+ headRefName
6
+ headRepository {
7
+ nameWithOwner
8
+ }
9
+ }
10
+ }
11
+ node(id: $threadId) {
12
+ ... on PullRequestReviewThread {
13
+ id
14
+ isResolved
15
+ isOutdated
16
+ path
17
+ line
18
+ startLine
19
+ pullRequest {
20
+ number
21
+ }
22
+ comments(first: 1) {
23
+ nodes {
24
+ isMinimized
25
+ url
26
+ authorAssociation
27
+ author {
28
+ __typename
29
+ login
30
+ }
31
+ body
32
+ path
33
+ line
34
+ startLine
35
+ createdAt
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
@@ -11,6 +11,7 @@ query ReviewThreadComments($threadId: ID!, $commentsCursor: String) {
11
11
  id
12
12
  isMinimized
13
13
  url
14
+ authorAssociation
14
15
  author {
15
16
  __typename
16
17
  login
@@ -0,0 +1,19 @@
1
+ import { type GitHubGraphQlError } from "./errors.mts";
2
+ import { type RateLimitInfo } from "./http-utils.mts";
3
+ interface GraphQlResult<T = unknown> {
4
+ data: T;
5
+ rateLimit?: RateLimitInfo;
6
+ retryAfterSeconds?: number;
7
+ errors?: GitHubGraphQlError[];
8
+ }
9
+ export interface GraphQlRequestOptions {
10
+ /**
11
+ * Mutation batches use partial GraphQL data to preserve per-alias successes.
12
+ * Read paths must keep the strict default so incomplete snapshots never drive
13
+ * PR state transitions.
14
+ */
15
+ allowPartialData?: boolean;
16
+ }
17
+ export declare function graphql<T = unknown>(query: string, vars?: Record<string, unknown>, opts?: GraphQlRequestOptions): Promise<GraphQlResult<T>>;
18
+ export declare function graphqlWithRateLimit<T = unknown>(query: string, vars?: Record<string, unknown>, opts?: GraphQlRequestOptions): Promise<GraphQlResult<T>>;
19
+ export {};
@@ -0,0 +1,7 @@
1
+ import { type GitHubGraphQlError } from "./errors.mts";
2
+ import type { RateLimitInfo } from "./http-utils.mts";
3
+ export declare function parseGraphQlPayload<T>(parsed: unknown, status: number, rateLimit: RateLimitInfo | null, retryAfterSeconds: number | undefined): {
4
+ data: T | null;
5
+ errors?: GitHubGraphQlError[];
6
+ };
7
+ export declare function formatGraphQlErrors(errors: GitHubGraphQlError[] | undefined): string;
@@ -0,0 +1,4 @@
1
+ export declare function _resetTokenCache(): void;
2
+ export declare function hasCachedToken(): boolean;
3
+ export declare function clearTokenCache(): void;
4
+ export declare function makeHeaders(): Promise<Record<string, string>>;
@@ -0,0 +1,7 @@
1
+ type RetryLogFn = (status: number, durationMs: number) => void;
2
+ export declare function requestWithTokenRetry(fn: () => Promise<Response>, t0: number, onIntermediate?: RetryLogFn): Promise<{
3
+ res: Response;
4
+ attempt: number;
5
+ retryT0: number;
6
+ }>;
7
+ export {};
@@ -0,0 +1,11 @@
1
+ export declare function isTransportError(err: unknown): boolean;
2
+ export interface RateLimitInfo {
3
+ remaining: number;
4
+ limit: number;
5
+ resetAt: number;
6
+ }
7
+ export declare function sanitizeBody(body: string): string;
8
+ export declare function redactToken(body: string): string;
9
+ export declare function redactUrl(url: string): string;
10
+ export declare function parseRateLimit(headers: Headers): RateLimitInfo | null;
11
+ export declare function parseRetryAfter(headers: Headers): number | undefined;
@@ -0,0 +1,6 @@
1
+ export { GitHubRequestError } from "./errors.mts";
2
+ export { _resetTokenCache } from "./http-auth.mts";
3
+ export { graphql, graphqlWithRateLimit } from "./graphql-http.mts";
4
+ export { rest, restWithRateLimit } from "./rest-http.mts";
5
+ export { restText } from "./rest-text.mts";
6
+ export type { RateLimitInfo } from "./http-utils.mts";
@@ -1,4 +1,5 @@
1
1
  export { GitHubRequestError } from "./errors.mjs";
2
2
  export { _resetTokenCache } from "./http-auth.mjs";
3
3
  export { graphql, graphqlWithRateLimit } from "./graphql-http.mjs";
4
- export { rest, restText } from "./rest-http.mjs";
4
+ export { rest, restWithRateLimit } from "./rest-http.mjs";
5
+ export { restText } from "./rest-text.mjs";
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Generic GraphQL cursor-based paginator for shepherd.
3
+ *
4
+ * Both paginators accept a `fetchFn` instead of calling `graphql` directly,
5
+ * which makes them testable without any mocking — tests supply a pure function
6
+ * that returns pages of fake data.
7
+ *
8
+ * GitHub's GraphQL connections support two cursor directions:
9
+ * - Forward (`after` + `first`) — used by check contexts and nested thread comments.
10
+ * - Backward (`before` + `last`) — used by reviewThreads/comments/reviews extra pages
11
+ * (combined in `batch-page.mts`; `paginateBackward` remains the generic primitive).
12
+ */
13
+ interface PageInfo {
14
+ hasNextPage?: boolean;
15
+ hasPreviousPage?: boolean;
16
+ endCursor?: string | null;
17
+ startCursor?: string | null;
18
+ }
19
+ export interface Connection<T> {
20
+ pageInfo: PageInfo;
21
+ nodes: T[];
22
+ }
23
+ /**
24
+ * Paginate forward through a GraphQL connection (`first` / `after` cursors).
25
+ *
26
+ * @param fetchFn Called once per page. Receives the cursor (or null for
27
+ * the very first page) and returns a Connection<T>.
28
+ * @param initialCursor Start from this cursor instead of null. Pass the
29
+ * `endCursor` of an already-fetched page to fetch only
30
+ * the pages *after* it, avoiding a duplicate re-fetch.
31
+ */
32
+ export declare function paginateForward<T>(fetchFn: (cursor: string | null) => Promise<Connection<T>>, initialCursor?: string | null): Promise<T[]>;
33
+ /**
34
+ * Paginate backward through a GraphQL connection (`last` / `before` cursors).
35
+ *
36
+ * Used for `reviewThreads(last: 100, before: $before)`.
37
+ *
38
+ * @param fetchFn Called once per page. Receives the cursor (or null for
39
+ * the very first page). Returns a Connection<T> with
40
+ * `hasPreviousPage` and `startCursor` in pageInfo.
41
+ * @param initialCursor Start from this cursor instead of null. Pass the
42
+ * `startCursor` of an already-fetched page to avoid
43
+ * re-fetching it (fetch only the pages *before* it).
44
+ */
45
+ export declare function paginateBackward<T>(fetchFn: (cursor: string | null) => Promise<Connection<T>>, initialCursor?: string | null): Promise<T[]>;
46
+ export {};
@@ -6,8 +6,9 @@
6
6
  * that returns pages of fake data.
7
7
  *
8
8
  * GitHub's GraphQL connections support two cursor directions:
9
- * - Forward (`after` + `first`) — used by check contexts.
10
- * - Backward (`before` + `last`) — used by reviewThreads (default GitHub order).
9
+ * - Forward (`after` + `first`) — used by check contexts and nested thread comments.
10
+ * - Backward (`before` + `last`) — used by reviewThreads/comments/reviews extra pages
11
+ * (combined in `batch-page.mts`; `paginateBackward` remains the generic primitive).
11
12
  */
12
13
  /**
13
14
  * Paginate forward through a GraphQL connection (`first` / `after` cursors).