bellwether 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/.claude-plugin/plugin.json +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +120 -0
  4. package/SKILL.md +92 -0
  5. package/dist/bin.d.ts +3 -0
  6. package/dist/bin.d.ts.map +1 -0
  7. package/dist/bin.js +17 -0
  8. package/dist/bin.js.map +1 -0
  9. package/dist/cli.d.ts +13 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +36 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/commands/check.d.ts +191 -0
  14. package/dist/commands/check.d.ts.map +1 -0
  15. package/dist/commands/check.js +186 -0
  16. package/dist/commands/check.js.map +1 -0
  17. package/dist/commands/ci.d.ts +8 -0
  18. package/dist/commands/ci.d.ts.map +1 -0
  19. package/dist/commands/ci.js +28 -0
  20. package/dist/commands/ci.js.map +1 -0
  21. package/dist/commands/hook-add.d.ts +2 -0
  22. package/dist/commands/hook-add.d.ts.map +1 -0
  23. package/dist/commands/hook-add.js +97 -0
  24. package/dist/commands/hook-add.js.map +1 -0
  25. package/dist/commands/hook-check.d.ts +2 -0
  26. package/dist/commands/hook-check.d.ts.map +1 -0
  27. package/dist/commands/hook-check.js +29 -0
  28. package/dist/commands/hook-check.js.map +1 -0
  29. package/dist/commands/reviews.d.ts +74 -0
  30. package/dist/commands/reviews.d.ts.map +1 -0
  31. package/dist/commands/reviews.js +133 -0
  32. package/dist/commands/reviews.js.map +1 -0
  33. package/dist/context.d.ts +13 -0
  34. package/dist/context.d.ts.map +1 -0
  35. package/dist/context.js +53 -0
  36. package/dist/context.js.map +1 -0
  37. package/dist/github/auth.d.ts +9 -0
  38. package/dist/github/auth.d.ts.map +1 -0
  39. package/dist/github/auth.js +49 -0
  40. package/dist/github/auth.js.map +1 -0
  41. package/dist/github/checks.d.ts +19 -0
  42. package/dist/github/checks.d.ts.map +1 -0
  43. package/dist/github/checks.js +112 -0
  44. package/dist/github/checks.js.map +1 -0
  45. package/dist/github/comments.d.ts +86 -0
  46. package/dist/github/comments.d.ts.map +1 -0
  47. package/dist/github/comments.js +309 -0
  48. package/dist/github/comments.js.map +1 -0
  49. package/dist/github/fetch.d.ts +21 -0
  50. package/dist/github/fetch.d.ts.map +1 -0
  51. package/dist/github/fetch.js +177 -0
  52. package/dist/github/fetch.js.map +1 -0
  53. package/dist/github/index.d.ts +6 -0
  54. package/dist/github/index.d.ts.map +1 -0
  55. package/dist/github/index.js +6 -0
  56. package/dist/github/index.js.map +1 -0
  57. package/dist/github/repo.d.ts +27 -0
  58. package/dist/github/repo.d.ts.map +1 -0
  59. package/dist/github/repo.js +72 -0
  60. package/dist/github/repo.js.map +1 -0
  61. package/hooks/hooks.json +29 -0
  62. package/package.json +65 -0
  63. package/skills/bellwether/SKILL.md +92 -0
  64. package/src/bin.ts +15 -0
  65. package/src/cli.ts +39 -0
  66. package/src/commands/check.ts +251 -0
  67. package/src/commands/ci.ts +44 -0
  68. package/src/commands/hook-add.ts +139 -0
  69. package/src/commands/hook-check.ts +35 -0
  70. package/src/commands/reviews.ts +225 -0
  71. package/src/context.ts +86 -0
  72. package/src/github/auth.ts +40 -0
  73. package/src/github/checks.ts +187 -0
  74. package/src/github/comments.ts +522 -0
  75. package/src/github/fetch.ts +233 -0
  76. package/src/github/index.ts +35 -0
  77. package/src/github/repo.ts +146 -0
@@ -0,0 +1,309 @@
1
+ import { fetchAllPages, ghFetch } from "./fetch.js";
2
+ const DEFAULT_META_FILTERS = [
3
+ (_user, body) => body.startsWith("> Re: comment "),
4
+ (user, body) => (user === "vercel[bot]" || user === "vercel") && body.startsWith("[vc]:"),
5
+ (user, body) => (user === "supabase[bot]" || user === "supabase") && body.startsWith("[supa]:"),
6
+ (user, body) => (user === "cursor[bot]" || user === "cursor") &&
7
+ body.startsWith("Cursor Bugbot has reviewed your changes"),
8
+ (user, body) => (user === "copilot-pull-request-reviewer[bot]" || user === "copilot-pull-request-reviewer") &&
9
+ body.includes("Pull request overview"),
10
+ (user, body) => (user === "coderabbitai[bot]" || user === "coderabbitai") &&
11
+ body.includes("<!-- This is an auto-generated comment: summarize by coderabbit.ai -->"),
12
+ (user, body) => (user === "sourcery-ai[bot]" || user === "sourcery-ai") &&
13
+ body.includes("<!-- Generated by sourcery-ai[bot]:"),
14
+ (user, body) => (user === "codacy-production[bot]" || user === "codacy-production") &&
15
+ (body.includes("Codacy's Analysis Summary") || body.includes("Coverage summary from Codacy")),
16
+ (user, body) => (user === "sonarcloud[bot]" ||
17
+ user === "sonarcloud" ||
18
+ user === "sonarqubecloud[bot]" ||
19
+ user === "sonarqubecloud" ||
20
+ user === "sonarqube-cloud-us[bot]" ||
21
+ user === "sonarqube-cloud-us") &&
22
+ body.includes("Quality Gate"),
23
+ ];
24
+ function isMetaComment(user, body) {
25
+ if (!body) {
26
+ return false;
27
+ }
28
+ return DEFAULT_META_FILTERS.some((filter) => filter(user, body));
29
+ }
30
+ // ---------------------------------------------------------------------------
31
+ // Bot detection
32
+ // ---------------------------------------------------------------------------
33
+ const KNOWN_BOT_LOGINS = new Set([
34
+ "cursor",
35
+ "vercel",
36
+ "supabase",
37
+ "chatgpt-codex-connector",
38
+ "github-actions",
39
+ "Copilot",
40
+ "copilot-pull-request-reviewer",
41
+ "coderabbitai",
42
+ "sourcery-ai",
43
+ "codacy-production",
44
+ "sonarcloud",
45
+ "sonarqubecloud",
46
+ "sonarqube-cloud-us",
47
+ ]);
48
+ function isBot(username) {
49
+ if (!username) {
50
+ return false;
51
+ }
52
+ return username.endsWith("[bot]") || KNOWN_BOT_LOGINS.has(username) || username.includes("bot");
53
+ }
54
+ // ---------------------------------------------------------------------------
55
+ // Body cleanup
56
+ // ---------------------------------------------------------------------------
57
+ function cleanBody(body) {
58
+ if (!body) {
59
+ return "";
60
+ }
61
+ let cleaned = body;
62
+ // Remove HTML comments (single and multi-line)
63
+ cleaned = cleaned.replaceAll(/<!--[\s\S]*?-->/g, "");
64
+ // Remove <details> blocks containing "Additional Locations"
65
+ cleaned = cleaned.replaceAll(/<details>\s*<summary>\s*Additional Locations[\s\S]*?<\/details>/gi, "");
66
+ // Remove <p> blocks containing cursor.com links
67
+ cleaned = cleaned.replaceAll(/<p>\s*<a [^>]*cursor\.com[\s\S]*?<\/p>/gi, "");
68
+ // Collapse runs of 3+ newlines into 2
69
+ cleaned = cleaned.replaceAll(/\n{3,}/g, "\n\n");
70
+ return cleaned.trim();
71
+ }
72
+ export async function fetchPRComments(owner, repo, prNumber, token, proxyFetch) {
73
+ const baseUrl = `https://api.github.com/repos/${owner}/${repo}`;
74
+ const [reviewComments, issueComments, reviews] = await Promise.all([
75
+ fetchAllPages(`${baseUrl}/pulls/${prNumber}/comments?per_page=100`, token, proxyFetch),
76
+ fetchAllPages(`${baseUrl}/issues/${prNumber}/comments?per_page=100`, token, proxyFetch),
77
+ fetchAllPages(`${baseUrl}/pulls/${prNumber}/reviews?per_page=100`, token, proxyFetch),
78
+ ]);
79
+ return { reviewComments, issueComments, reviews };
80
+ }
81
+ export function processComments(data) {
82
+ const { reviewComments, issueComments, reviews } = data;
83
+ // Build reply map
84
+ const repliesMap = new Map();
85
+ for (const comment of reviewComments) {
86
+ if (comment.in_reply_to_id) {
87
+ if (!repliesMap.has(comment.in_reply_to_id)) {
88
+ repliesMap.set(comment.in_reply_to_id, []);
89
+ }
90
+ repliesMap.get(comment.in_reply_to_id).push({
91
+ id: comment.id,
92
+ user: comment.user?.login ?? "unknown",
93
+ body: cleanBody(comment.body),
94
+ createdAt: comment.created_at,
95
+ isBot: isBot(comment.user?.login),
96
+ });
97
+ }
98
+ }
99
+ const processed = [];
100
+ // Review comments (inline code comments)
101
+ for (const comment of reviewComments) {
102
+ if (comment.in_reply_to_id) {
103
+ continue;
104
+ }
105
+ if (isMetaComment(comment.user?.login ?? "", comment.body)) {
106
+ continue;
107
+ }
108
+ const replies = repliesMap.get(comment.id) ?? [];
109
+ const hasHumanReply = replies.some((r) => !r.isBot);
110
+ const hasAnyReply = replies.length > 0;
111
+ processed.push({
112
+ id: comment.id,
113
+ type: "review_comment",
114
+ user: comment.user?.login ?? "unknown",
115
+ isBot: isBot(comment.user?.login),
116
+ path: comment.path,
117
+ // oxlint-disable-next-line typescript/prefer-nullish-coalescing -- 0 is "no line", intentional falsy check
118
+ line: comment.line || comment.original_line,
119
+ diffHunk: comment.diff_hunk ?? null,
120
+ body: cleanBody(comment.body),
121
+ createdAt: comment.created_at,
122
+ updatedAt: comment.updated_at,
123
+ url: comment.html_url,
124
+ replies,
125
+ hasHumanReply,
126
+ hasAnyReply,
127
+ isResolved: false,
128
+ });
129
+ }
130
+ // Issue comments (general PR comments)
131
+ for (const comment of issueComments) {
132
+ if (isMetaComment(comment.user?.login ?? "", comment.body)) {
133
+ continue;
134
+ }
135
+ processed.push({
136
+ id: comment.id,
137
+ type: "issue_comment",
138
+ user: comment.user?.login ?? "unknown",
139
+ isBot: isBot(comment.user?.login),
140
+ path: null,
141
+ line: null,
142
+ diffHunk: null,
143
+ body: cleanBody(comment.body),
144
+ createdAt: comment.created_at,
145
+ updatedAt: comment.updated_at,
146
+ url: comment.html_url,
147
+ replies: [],
148
+ hasHumanReply: false,
149
+ hasAnyReply: false,
150
+ isResolved: false,
151
+ });
152
+ }
153
+ // Reviews (only human, with body)
154
+ for (const review of reviews) {
155
+ if (isBot(review.user?.login)) {
156
+ continue;
157
+ }
158
+ if (isMetaComment(review.user?.login ?? "", review.body ?? "")) {
159
+ continue;
160
+ }
161
+ if (!review.body?.trim()) {
162
+ continue;
163
+ }
164
+ processed.push({
165
+ id: review.id,
166
+ type: "review",
167
+ user: review.user?.login ?? "unknown",
168
+ isBot: false,
169
+ path: null,
170
+ line: null,
171
+ diffHunk: null,
172
+ body: cleanBody(review.body),
173
+ state: review.state,
174
+ createdAt: review.submitted_at,
175
+ updatedAt: review.submitted_at,
176
+ url: review.html_url,
177
+ replies: [],
178
+ hasHumanReply: false,
179
+ hasAnyReply: false,
180
+ isResolved: review.state === "APPROVED" || review.state === "DISMISSED",
181
+ });
182
+ }
183
+ processed.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
184
+ return processed;
185
+ }
186
+ export function filterComments(comments, options) {
187
+ let filtered = comments;
188
+ if (options.botsOnly) {
189
+ filtered = filtered.filter((c) => c.isBot);
190
+ }
191
+ else if (options.humansOnly) {
192
+ filtered = filtered.filter((c) => !c.isBot);
193
+ }
194
+ if (options.filter === "unresolved") {
195
+ filtered = filtered.filter((c) => !(c.isResolved || c.hasHumanReply));
196
+ }
197
+ else if (options.filter === "unanswered") {
198
+ filtered = filtered.filter((c) => !c.hasAnyReply);
199
+ }
200
+ return filtered;
201
+ }
202
+ // ---------------------------------------------------------------------------
203
+ // Reply & resolve
204
+ // ---------------------------------------------------------------------------
205
+ export async function replyToComment(owner, repo, prNumber, commentId, message, token, proxyFetch) {
206
+ // Try review comment reply endpoint first
207
+ const response = await ghFetch(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/comments/${commentId}/replies`, token, proxyFetch, {
208
+ method: "POST",
209
+ headers: { "Content-Type": "application/json" },
210
+ body: JSON.stringify({ body: message }),
211
+ });
212
+ if (!response.ok) {
213
+ // Fallback to issue comment endpoint
214
+ const issueResponse = await ghFetch(`https://api.github.com/repos/${owner}/${repo}/issues/${prNumber}/comments`, token, proxyFetch, {
215
+ method: "POST",
216
+ headers: { "Content-Type": "application/json" },
217
+ body: JSON.stringify({
218
+ body: `> Re: comment ${commentId}\n\n${message}`,
219
+ }),
220
+ });
221
+ if (!issueResponse.ok) {
222
+ const error = await issueResponse.text();
223
+ throw new Error(`Failed to reply: ${issueResponse.status} - ${error}`);
224
+ }
225
+ return issueResponse.json();
226
+ }
227
+ return response.json();
228
+ }
229
+ export async function resolveThread(owner, repo, prNumber, commentId, token, proxyFetch) {
230
+ const query = `
231
+ query($owner: String!, $repo: String!, $pr: Int!, $cursor: String) {
232
+ repository(owner: $owner, name: $repo) {
233
+ pullRequest(number: $pr) {
234
+ reviewThreads(first: 100, after: $cursor) {
235
+ pageInfo { hasNextPage endCursor }
236
+ nodes {
237
+ id
238
+ isResolved
239
+ comments(first: 1) {
240
+ nodes { databaseId }
241
+ }
242
+ }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ `;
248
+ let cursor = null;
249
+ let thread = null;
250
+ while (!thread) {
251
+ const response = await ghFetch("https://api.github.com/graphql", token, proxyFetch, {
252
+ method: "POST",
253
+ headers: { "Content-Type": "application/json" },
254
+ body: JSON.stringify({
255
+ query,
256
+ variables: { owner, repo, pr: prNumber, cursor },
257
+ }),
258
+ });
259
+ if (!response.ok) {
260
+ throw new Error(`GraphQL query failed: ${response.status}`);
261
+ }
262
+ const data = (await response.json());
263
+ if (data.errors?.[0]) {
264
+ throw new Error(`GraphQL error: ${data.errors[0].message}`);
265
+ }
266
+ const reviewThreads = data.data?.repository?.pullRequest?.reviewThreads;
267
+ if (!reviewThreads) {
268
+ break;
269
+ }
270
+ thread =
271
+ reviewThreads.nodes.find((t) => t.comments.nodes.some((c) => c.databaseId === commentId)) ?? null;
272
+ if (!thread && reviewThreads.pageInfo.hasNextPage) {
273
+ cursor = reviewThreads.pageInfo.endCursor;
274
+ }
275
+ else {
276
+ break;
277
+ }
278
+ }
279
+ if (!thread) {
280
+ return { skipped: true, reason: "not a review comment thread" };
281
+ }
282
+ if (thread.isResolved) {
283
+ return { alreadyResolved: true, threadId: thread.id };
284
+ }
285
+ const mutation = `
286
+ mutation($threadId: ID!) {
287
+ resolveReviewThread(input: { threadId: $threadId }) {
288
+ thread { id isResolved }
289
+ }
290
+ }
291
+ `;
292
+ const resolveResponse = await ghFetch("https://api.github.com/graphql", token, proxyFetch, {
293
+ method: "POST",
294
+ headers: { "Content-Type": "application/json" },
295
+ body: JSON.stringify({
296
+ query: mutation,
297
+ variables: { threadId: thread.id },
298
+ }),
299
+ });
300
+ if (!resolveResponse.ok) {
301
+ throw new Error(`Failed to resolve thread: ${resolveResponse.status}`);
302
+ }
303
+ const resolveData = (await resolveResponse.json());
304
+ if (resolveData.errors?.[0]) {
305
+ throw new Error(`GraphQL error: ${resolveData.errors[0].message}`);
306
+ }
307
+ return { resolved: true, threadId: thread.id };
308
+ }
309
+ //# sourceMappingURL=comments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/github/comments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export type ProxyFetch = (url: string, options?: ProxyFetchOptions) => Promise<ProxyFetchResponse>;
2
+ export interface ProxyFetchOptions {
3
+ method?: string;
4
+ headers?: Record<string, string>;
5
+ body?: string;
6
+ }
7
+ interface HeaderMap {
8
+ get(name: string): string | null;
9
+ }
10
+ export interface ProxyFetchResponse {
11
+ ok: boolean;
12
+ status: number;
13
+ headers: HeaderMap;
14
+ text(): Promise<string>;
15
+ json(): Promise<any>;
16
+ }
17
+ export declare function getProxyFetch(): ProxyFetch;
18
+ export declare function ghFetch(url: string, token: string, proxyFetch: ProxyFetch, options?: ProxyFetchOptions): Promise<ProxyFetchResponse>;
19
+ export declare function fetchAllPages<T>(url: string, token: string, proxyFetch: ProxyFetch): Promise<T[]>;
20
+ export {};
21
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/github/fetch.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEnG,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,SAAS;IACjB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,SAAS,CAAC;IACnB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAExB,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;CACtB;AA0HD,wBAAgB,aAAa,IAAI,UAAU,CAuB1C;AAcD,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CAK7B;AAED,wBAAsB,aAAa,CAAC,CAAC,EACnC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,CAAC,EAAE,CAAC,CAwBd"}
@@ -0,0 +1,177 @@
1
+ import { join } from "node:path";
2
+ import { tmpdir } from "node:os";
3
+ import { mkdtempSync } from "node:fs";
4
+ import { readFile, rm } from "node:fs/promises";
5
+ import { spawnSync } from "node:child_process";
6
+ import { createRequire } from "node:module";
7
+ const require = createRequire(import.meta.url);
8
+ const USER_AGENT = "bellwether";
9
+ // ---------------------------------------------------------------------------
10
+ // Header parsing (for curl responses & proxied headers)
11
+ // ---------------------------------------------------------------------------
12
+ function parseHeaderMap(rawHeaders) {
13
+ const lines = rawHeaders.split(/\r?\n/).filter(Boolean);
14
+ const map = new Map();
15
+ for (const line of lines) {
16
+ const idx = line.indexOf(":");
17
+ if (idx === -1) {
18
+ continue;
19
+ }
20
+ const key = line.slice(0, idx).trim().toLowerCase();
21
+ const value = line.slice(idx + 1).trim();
22
+ map.set(key, value);
23
+ }
24
+ return {
25
+ get(name) {
26
+ return map.get(String(name).toLowerCase()) ?? null;
27
+ },
28
+ };
29
+ }
30
+ function parseLastHeaderBlock(headerContent) {
31
+ const blocks = headerContent
32
+ .split(/\r?\n\r?\n/)
33
+ .map((b) => b.trim())
34
+ .filter(Boolean);
35
+ for (let i = blocks.length - 1; i >= 0; i -= 1) {
36
+ const block = blocks[i];
37
+ if (block?.startsWith("HTTP/")) {
38
+ return block;
39
+ }
40
+ }
41
+ return "";
42
+ }
43
+ // ---------------------------------------------------------------------------
44
+ // Curl-based fetch (fallback when undici is unavailable behind a proxy)
45
+ // ---------------------------------------------------------------------------
46
+ function createCurlFetch() {
47
+ return async (url, options = {}) => {
48
+ const tempDir = mkdtempSync(join(tmpdir(), "bellwether-"));
49
+ const headersFile = join(tempDir, "headers.txt");
50
+ const bodyFile = join(tempDir, "body.txt");
51
+ const args = [
52
+ "--silent",
53
+ "--show-error",
54
+ "--location",
55
+ "--connect-timeout",
56
+ "10",
57
+ "--max-time",
58
+ "60",
59
+ "--dump-header",
60
+ headersFile,
61
+ "--output",
62
+ bodyFile,
63
+ "--request",
64
+ options.method ?? "GET",
65
+ "--write-out",
66
+ "%{http_code}",
67
+ ];
68
+ if (options.headers) {
69
+ for (const [key, value] of Object.entries(options.headers)) {
70
+ args.push("--header", `${key}: ${value}`);
71
+ }
72
+ }
73
+ if (options.body) {
74
+ args.push("--data", options.body);
75
+ }
76
+ args.push(String(url));
77
+ try {
78
+ const result = spawnSync("curl", args, {
79
+ encoding: "utf-8",
80
+ timeout: 65_000,
81
+ });
82
+ if (result.error) {
83
+ throw new Error(`curl failed to start: ${result.error.message}`);
84
+ }
85
+ if (result.status !== 0) {
86
+ const stderr = String(result.stderr).trim();
87
+ throw new Error(`curl exited with status ${String(result.status)}${stderr ? `: ${stderr}` : ""}`);
88
+ }
89
+ const statusCodeRaw = String(result.stdout).trim();
90
+ const status = Number.parseInt(statusCodeRaw, 10);
91
+ if (!statusCodeRaw || Number.isNaN(status)) {
92
+ throw new Error("curl did not return a valid HTTP status code");
93
+ }
94
+ const body = await readFile(bodyFile, "utf-8");
95
+ const headersRaw = await readFile(headersFile, "utf-8");
96
+ const lastHeaderBlock = parseLastHeaderBlock(headersRaw);
97
+ return {
98
+ ok: status >= 200 && status < 300,
99
+ status,
100
+ headers: parseHeaderMap(lastHeaderBlock),
101
+ async text() {
102
+ return body;
103
+ },
104
+ async json() {
105
+ return JSON.parse(body || "null");
106
+ },
107
+ };
108
+ }
109
+ finally {
110
+ await rm(tempDir, { recursive: true, force: true });
111
+ }
112
+ };
113
+ }
114
+ // ---------------------------------------------------------------------------
115
+ // Proxy-aware fetch factory
116
+ // ---------------------------------------------------------------------------
117
+ export function getProxyFetch() {
118
+ const proxyUrl = process.env.HTTPS_PROXY ?? process.env.https_proxy;
119
+ if (proxyUrl) {
120
+ try {
121
+ const { ProxyAgent, fetch: undiciFetch } = require("undici");
122
+ const agent = new ProxyAgent(proxyUrl);
123
+ return ((url, options = {}) => undiciFetch(url, { ...options, dispatcher: agent }));
124
+ }
125
+ catch {
126
+ return createCurlFetch();
127
+ }
128
+ }
129
+ return async (url, options = {}) => {
130
+ const response = await fetch(url, options);
131
+ return {
132
+ ok: response.ok,
133
+ status: response.status,
134
+ headers: { get: (name) => response.headers.get(name) },
135
+ text: () => response.text(),
136
+ json: () => response.json(),
137
+ };
138
+ };
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // Authenticated GitHub fetch + pagination
142
+ // ---------------------------------------------------------------------------
143
+ function authHeaders(token) {
144
+ return {
145
+ Authorization: `Bearer ${token}`,
146
+ Accept: "application/vnd.github.v3+json",
147
+ "User-Agent": USER_AGENT,
148
+ };
149
+ }
150
+ export async function ghFetch(url, token, proxyFetch, options = {}) {
151
+ return proxyFetch(url, {
152
+ ...options,
153
+ headers: { ...authHeaders(token), ...options.headers },
154
+ });
155
+ }
156
+ export async function fetchAllPages(url, token, proxyFetch) {
157
+ const results = [];
158
+ let nextUrl = url;
159
+ while (nextUrl) {
160
+ const response = await ghFetch(nextUrl, token, proxyFetch);
161
+ if (!response.ok) {
162
+ throw new Error(`API request failed: ${response.status}`);
163
+ }
164
+ const data = (await response.json());
165
+ results.push(...data);
166
+ const linkHeader = response.headers.get("link");
167
+ nextUrl = null;
168
+ if (linkHeader) {
169
+ const nextMatch = linkHeader.match(/<([^>]+)>;\s*rel="next"/);
170
+ if (nextMatch?.[1]) {
171
+ nextUrl = nextMatch[1];
172
+ }
173
+ }
174
+ }
175
+ return results;
176
+ }
177
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../src/github/fetch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { type ProxyFetch, type ProxyFetchOptions, type ProxyFetchResponse, getProxyFetch, ghFetch, fetchAllPages, } from "./fetch.js";
2
+ export { getGitHubToken } from "./auth.js";
3
+ export { type RepoInfo, type PR, type PRMergeState, getRepoRoot, getRepoInfo, getCurrentBranch, findPRForBranch, listOpenPRs, fetchPRMergeState, } from "./repo.js";
4
+ export { type ProcessedComment, type Reply, type FilterOptions, fetchPRComments, processComments, filterComments, replyToComment, resolveThread, } from "./comments.js";
5
+ export { type FailingCheck, type CIStatus, fetchCIStatus } from "./checks.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,aAAa,EACb,OAAO,EACP,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,EAAE,EACP,KAAK,YAAY,EACjB,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EACd,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { getProxyFetch, ghFetch, fetchAllPages, } from "./fetch.js";
2
+ export { getGitHubToken } from "./auth.js";
3
+ export { getRepoRoot, getRepoInfo, getCurrentBranch, findPRForBranch, listOpenPRs, fetchPRMergeState, } from "./repo.js";
4
+ export { fetchPRComments, processComments, filterComments, replyToComment, resolveThread, } from "./comments.js";
5
+ export { fetchCIStatus } from "./checks.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/github/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EACb,OAAO,EACP,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAIL,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAIL,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EACd,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAoC,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { type ProxyFetch } from "./fetch.js";
2
+ export declare function getRepoRoot(): string | null;
3
+ export interface RepoInfo {
4
+ owner: string;
5
+ repo: string;
6
+ }
7
+ export declare function getRepoInfo(): RepoInfo | null;
8
+ export declare function getCurrentBranch(): string | null;
9
+ export interface PR {
10
+ number: number;
11
+ title: string;
12
+ html_url: string;
13
+ head: {
14
+ ref: string;
15
+ sha: string;
16
+ };
17
+ state: string;
18
+ }
19
+ export declare function findPRForBranch(owner: string, repo: string, branch: string, token: string, proxyFetch: ProxyFetch): Promise<PR | null>;
20
+ export declare function listOpenPRs(owner: string, repo: string, token: string, proxyFetch: ProxyFetch): Promise<PR[]>;
21
+ export interface PRMergeState {
22
+ state: "open" | "closed" | "merged";
23
+ mergeable: boolean | null;
24
+ mergeableState: string;
25
+ }
26
+ export declare function fetchPRMergeState(owner: string, repo: string, prNumber: number, token: string, proxyFetch: ProxyFetch): Promise<PRMergeState>;
27
+ //# sourceMappingURL=repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../src/github/repo.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAkBtD,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAE3C;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,WAAW,IAAI,QAAQ,GAAG,IAAI,CAyB7C;AAED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEhD;AAMD,MAAM,WAAW,EAAE;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAWpB;AAED,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,EAAE,EAAE,CAAC,CAUf;AAMD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACpC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AASD,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,YAAY,CAAC,CAevB"}