@hardlydifficult/pr-analyzer 1.0.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.
@@ -0,0 +1,38 @@
1
+ /**
2
+ * PR Action Resolution
3
+ *
4
+ * Determines which actions are available for a PR based on its status.
5
+ * This is the single source of truth for core action definitions — clients
6
+ * (web, Discord, voice) render from these descriptors.
7
+ *
8
+ * Consumers can provide extra actions via ActionDefinition[].
9
+ */
10
+ import type { ActionDefinition, ScannedPR } from "./types.js";
11
+ /**
12
+ * Core action types built into the package.
13
+ * Consumers can define additional action types via ActionDefinition.
14
+ */
15
+ export type CorePRActionType = "merge" | "mark_ready" | "enable_auto_merge";
16
+ /**
17
+ * Describes an available action for a PR.
18
+ * `type` is `string` to allow custom action types from consumers.
19
+ */
20
+ export interface PRActionDescriptor {
21
+ readonly type: string;
22
+ readonly label: string;
23
+ readonly description: string;
24
+ }
25
+ /**
26
+ * Core action registry — maps each core action type to its metadata.
27
+ */
28
+ export declare const PR_ACTIONS: Record<CorePRActionType, Omit<PRActionDescriptor, "type">>;
29
+ /**
30
+ * Determine which actions are available for a given PR.
31
+ *
32
+ * @param pr - The scanned PR object
33
+ * @param extraActions - Additional actions provided by consumers
34
+ * @param context - Key-value context for evaluating extra action conditions
35
+ * @returns Array of available action descriptors
36
+ */
37
+ export declare function getAvailableActions(pr: ScannedPR, extraActions?: readonly ActionDefinition[], context?: Record<string, boolean>): PRActionDescriptor[];
38
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE9D;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,YAAY,GAAG,mBAAmB,CAAC;AAE5E;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAC7B,gBAAgB,EAChB,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAWjC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,SAAS,EACb,YAAY,CAAC,EAAE,SAAS,gBAAgB,EAAE,EAC1C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,kBAAkB,EAAE,CA2CtB"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * PR Action Resolution
4
+ *
5
+ * Determines which actions are available for a PR based on its status.
6
+ * This is the single source of truth for core action definitions — clients
7
+ * (web, Discord, voice) render from these descriptors.
8
+ *
9
+ * Consumers can provide extra actions via ActionDefinition[].
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.PR_ACTIONS = void 0;
13
+ exports.getAvailableActions = getAvailableActions;
14
+ /**
15
+ * Core action registry — maps each core action type to its metadata.
16
+ */
17
+ exports.PR_ACTIONS = {
18
+ merge: { label: "Merge", description: "Squash and merge this PR" },
19
+ mark_ready: {
20
+ label: "Mark Ready",
21
+ description: "Mark this draft PR as ready for review",
22
+ },
23
+ enable_auto_merge: {
24
+ label: "Enable Auto-Merge",
25
+ description: "Enable GitHub auto-merge when checks pass",
26
+ },
27
+ };
28
+ /**
29
+ * Determine which actions are available for a given PR.
30
+ *
31
+ * @param pr - The scanned PR object
32
+ * @param extraActions - Additional actions provided by consumers
33
+ * @param context - Key-value context for evaluating extra action conditions
34
+ * @returns Array of available action descriptors
35
+ */
36
+ function getAvailableActions(pr, extraActions, context) {
37
+ const actions = [];
38
+ const { status } = pr;
39
+ // Core actions based on status
40
+ switch (status) {
41
+ case "ready_to_merge":
42
+ case "approved":
43
+ actions.push({ type: "merge", ...exports.PR_ACTIONS.merge });
44
+ break;
45
+ case "draft":
46
+ if (pr.ciStatus.allPassed && !pr.hasConflicts) {
47
+ actions.push({ type: "mark_ready", ...exports.PR_ACTIONS.mark_ready });
48
+ }
49
+ break;
50
+ case "ci_running":
51
+ case "needs_review":
52
+ if (!pr.pr.draft && !pr.hasConflicts && pr.pr.merged_at === null) {
53
+ actions.push({
54
+ type: "enable_auto_merge",
55
+ ...exports.PR_ACTIONS.enable_auto_merge,
56
+ });
57
+ }
58
+ break;
59
+ default:
60
+ break;
61
+ }
62
+ // Evaluate extra actions from consumers
63
+ if (extraActions) {
64
+ const ctx = context ?? {};
65
+ for (const action of extraActions) {
66
+ if (action.when(pr, ctx)) {
67
+ actions.push({
68
+ type: action.type,
69
+ label: action.label,
70
+ description: action.description,
71
+ });
72
+ }
73
+ }
74
+ }
75
+ return actions;
76
+ }
77
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AA8CH,kDA+CC;AAzED;;GAEG;AACU,QAAA,UAAU,GAGnB;IACF,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE;IAClE,UAAU,EAAE;QACV,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,wCAAwC;KACtD;IACD,iBAAiB,EAAE;QACjB,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,2CAA2C;KACzD;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,mBAAmB,CACjC,EAAa,EACb,YAA0C,EAC1C,OAAiC;IAEjC,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAEtB,+BAA+B;IAC/B,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,gBAAgB,CAAC;QACtB,KAAK,UAAU;YACb,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,kBAAU,CAAC,KAAK,EAAE,CAAC,CAAC;YACrD,MAAM;QACR,KAAK,OAAO;YACV,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;gBAC9C,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,kBAAU,CAAC,UAAU,EAAE,CAAC,CAAC;YACjE,CAAC;YACD,MAAM;QACR,KAAK,YAAY,CAAC;QAClB,KAAK,cAAc;YACjB,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;gBACjE,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,mBAAmB;oBACzB,GAAG,kBAAU,CAAC,iBAAiB;iBAChC,CAAC,CAAC;YACL,CAAC;YACD,MAAM;QACR;YACE,MAAM;IACV,CAAC;IAED,wCAAwC;IACxC,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,OAAO,IAAI,EAAE,CAAC;QAC1B,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;YAClC,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,KAAK,EAAE,MAAM,CAAC,KAAK;oBACnB,WAAW,EAAE,MAAM,CAAC,WAAW;iBAChC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * PR Analysis
3
+ *
4
+ * Analyzes a single PR to determine its status:
5
+ * 1. Fetch CI checks, comments, reviews, and repo info
6
+ * 2. Analyze CI status (running, failed, passed)
7
+ * 3. Check if waiting on a bot response
8
+ * 4. Determine overall PR status based on all factors
9
+ *
10
+ * Custom status logic can be injected via AnalyzerHooks.resolveStatus.
11
+ */
12
+ import type { GitHubClient, PullRequest } from "@hardlydifficult/github";
13
+ import type { AnalyzerHooks, DiscoveredPR, Logger, ScannedPR } from "./types.js";
14
+ /**
15
+ * Analyze a PR and determine its status
16
+ */
17
+ export declare function analyzePR(client: GitHubClient, owner: string, repo: string, pr: PullRequest, botMention: string, hooks?: AnalyzerHooks): Promise<ScannedPR>;
18
+ /**
19
+ * Analyze all discovered PRs, logging any failures
20
+ */
21
+ export declare function analyzeAll(prs: readonly DiscoveredPR[], client: GitHubClient, botMention: string, logger?: Logger, hooks?: AnalyzerHooks): Promise<ScannedPR[]>;
22
+ //# sourceMappingURL=analysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAEV,YAAY,EACZ,WAAW,EAGZ,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EACV,aAAa,EAGb,YAAY,EACZ,MAAM,EACN,SAAS,EACV,MAAM,YAAY,CAAC;AAmBpB;;GAEG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,WAAW,EACf,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,CAAC,CAwCpB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,SAAS,YAAY,EAAE,EAC5B,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,EAAE,CAAC,CAkBtB"}
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ /**
3
+ * PR Analysis
4
+ *
5
+ * Analyzes a single PR to determine its status:
6
+ * 1. Fetch CI checks, comments, reviews, and repo info
7
+ * 2. Analyze CI status (running, failed, passed)
8
+ * 3. Check if waiting on a bot response
9
+ * 4. Determine overall PR status based on all factors
10
+ *
11
+ * Custom status logic can be injected via AnalyzerHooks.resolveStatus.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.analyzePR = analyzePR;
15
+ exports.analyzeAll = analyzeAll;
16
+ // Bot usernames to detect when waiting for bot response
17
+ const BOT_USERNAMES = new Set([
18
+ "cursor",
19
+ "cursor-bot",
20
+ "github-actions",
21
+ "github-actions[bot]",
22
+ "dependabot",
23
+ "dependabot[bot]",
24
+ "renovate",
25
+ "renovate[bot]",
26
+ "codecov",
27
+ "codecov[bot]",
28
+ "vercel",
29
+ "vercel[bot]",
30
+ "claude",
31
+ ]);
32
+ /**
33
+ * Analyze a PR and determine its status
34
+ */
35
+ async function analyzePR(client, owner, repo, pr, botMention, hooks) {
36
+ // Fetch all required data in parallel
37
+ const repoClient = client.repo(owner, repo);
38
+ const prClient = repoClient.pr(pr.number);
39
+ const [checks, comments, reviews, repoInfo] = await Promise.all([
40
+ prClient.getCheckRuns(),
41
+ prClient.getComments(),
42
+ prClient.getReviews(),
43
+ repoClient.get(),
44
+ ]);
45
+ // Analyze the fetched data
46
+ const ciStatus = analyzeCIStatus(checks);
47
+ const waitingOnBot = isWaitingOnBot(comments, botMention);
48
+ const conflicting = hasConflicts(pr);
49
+ const coreStatus = determineStatus(pr, ciStatus, reviews, waitingOnBot);
50
+ // Allow hook to override status
51
+ const status = hooks?.resolveStatus?.(coreStatus, {
52
+ comments,
53
+ checks,
54
+ reviews,
55
+ ciStatus,
56
+ hasConflicts: conflicting,
57
+ waitingOnBot,
58
+ }) ?? coreStatus;
59
+ const daysSinceUpdate = calculateDaysSinceUpdate(pr.updated_at);
60
+ return {
61
+ pr,
62
+ repo: repoInfo,
63
+ status,
64
+ ciStatus,
65
+ ciSummary: ciStatus.summary,
66
+ hasConflicts: conflicting,
67
+ waitingOnBot,
68
+ daysSinceUpdate,
69
+ };
70
+ }
71
+ /**
72
+ * Analyze all discovered PRs, logging any failures
73
+ */
74
+ async function analyzeAll(prs, client, botMention, logger, hooks) {
75
+ const results = [];
76
+ for (const { pr, repoOwner, repoName } of prs) {
77
+ try {
78
+ results.push(await analyzePR(client, repoOwner, repoName, pr, botMention, hooks));
79
+ }
80
+ catch (err) {
81
+ logger?.error("Failed to analyze PR", {
82
+ repo: `${repoOwner}/${repoName}`,
83
+ pr: pr.number,
84
+ error: err instanceof Error ? err.message : String(err),
85
+ });
86
+ }
87
+ }
88
+ return results;
89
+ }
90
+ // --- Status Determination ---
91
+ /**
92
+ * Determine the core status of a PR based on GitHub data.
93
+ *
94
+ * Priority order:
95
+ * 1. Draft → draft
96
+ * 2. CI running → ci_running
97
+ * 3. CI failed → ci_failed
98
+ * 4. Has conflicts → has_conflicts
99
+ * 5. Waiting on bot → waiting_on_bot
100
+ * 6. Changes requested → changes_requested
101
+ * 7. CI passed → ready_to_merge
102
+ * 8. Approved → approved
103
+ * 9. Default → needs_review
104
+ */
105
+ function determineStatus(pr, ci, reviews, waitingOnBot) {
106
+ if (pr.draft) {
107
+ return "draft";
108
+ }
109
+ if (ci.isRunning) {
110
+ return "ci_running";
111
+ }
112
+ if (ci.hasFailed) {
113
+ return "ci_failed";
114
+ }
115
+ if (hasConflicts(pr)) {
116
+ return "has_conflicts";
117
+ }
118
+ if (waitingOnBot) {
119
+ return "waiting_on_bot";
120
+ }
121
+ const reviewStatus = analyzeReviews(reviews);
122
+ if (reviewStatus.hasChangesRequested) {
123
+ return "changes_requested";
124
+ }
125
+ if (ci.allPassed) {
126
+ return "ready_to_merge";
127
+ }
128
+ if (reviewStatus.hasApproval) {
129
+ return "approved";
130
+ }
131
+ return "needs_review";
132
+ }
133
+ // --- CI Analysis ---
134
+ function analyzeCIStatus(checks) {
135
+ if (checks.length === 0) {
136
+ return {
137
+ isRunning: false,
138
+ hasFailed: false,
139
+ allPassed: true,
140
+ summary: "No CI checks",
141
+ };
142
+ }
143
+ const running = checks.filter(isCheckRunning);
144
+ const failed = checks.filter(isCheckFailed);
145
+ const passed = checks.filter(isCheckPassed);
146
+ // Validate that all checks are categorized
147
+ const categorized = running.length + failed.length + passed.length;
148
+ if (categorized !== checks.length) {
149
+ const uncategorized = checks.filter((c) => !isCheckRunning(c) && !isCheckFailed(c) && !isCheckPassed(c));
150
+ running.push(...uncategorized);
151
+ }
152
+ const isRunning = running.length > 0;
153
+ const hasFailed = failed.length > 0;
154
+ const allPassed = !isRunning && !hasFailed && passed.length === checks.length;
155
+ return {
156
+ isRunning,
157
+ hasFailed,
158
+ allPassed,
159
+ summary: formatCISummary(running, failed, passed, checks.length),
160
+ };
161
+ }
162
+ function isCheckRunning(check) {
163
+ if (check.status === "in_progress" || check.status === "queued") {
164
+ return true;
165
+ }
166
+ return check.conclusion === null;
167
+ }
168
+ function isCheckFailed(check) {
169
+ return (check.status === "completed" &&
170
+ (check.conclusion === "failure" ||
171
+ check.conclusion === "timed_out" ||
172
+ check.conclusion === "cancelled" ||
173
+ check.conclusion === "action_required"));
174
+ }
175
+ function isCheckPassed(check) {
176
+ return (check.status === "completed" &&
177
+ (check.conclusion === "success" ||
178
+ check.conclusion === "skipped" ||
179
+ check.conclusion === "neutral"));
180
+ }
181
+ function formatCISummary(running, failed, passed, total) {
182
+ if (running.length > 0 && passed.length > 0) {
183
+ return `CI running: ${String(running.length)} in progress, ${String(passed.length)} passed`;
184
+ }
185
+ if (running.length > 0) {
186
+ return `CI running: ${String(running.length)} in progress`;
187
+ }
188
+ if (failed.length > 0 && passed.length > 0) {
189
+ return `CI failed: ${String(failed.length)} failed, ${String(passed.length)} passed`;
190
+ }
191
+ if (failed.length > 0) {
192
+ return `CI failed: ${failed.map((c) => c.name).join(", ")}`;
193
+ }
194
+ if (passed.length === total) {
195
+ return `CI passed: ${String(passed.length)} checks`;
196
+ }
197
+ return `CI: ${String(total)} checks`;
198
+ }
199
+ // --- Review Analysis ---
200
+ function analyzeReviews(reviews) {
201
+ const latestByUser = new Map();
202
+ for (const review of reviews) {
203
+ const existing = latestByUser.get(review.user.login);
204
+ if (existing === undefined ||
205
+ new Date(review.submitted_at) > new Date(existing.submitted_at)) {
206
+ latestByUser.set(review.user.login, review);
207
+ }
208
+ }
209
+ const latestReviews = Array.from(latestByUser.values());
210
+ return {
211
+ hasChangesRequested: latestReviews.some((r) => r.state === "CHANGES_REQUESTED"),
212
+ hasApproval: latestReviews.some((r) => r.state === "APPROVED"),
213
+ };
214
+ }
215
+ // --- Bot Detection ---
216
+ function isWaitingOnBot(comments, botMention) {
217
+ if (comments.length === 0) {
218
+ return false;
219
+ }
220
+ const botMentionLower = botMention.toLowerCase();
221
+ const mentionComments = comments.filter((c) => c.body.toLowerCase().includes(botMentionLower));
222
+ if (mentionComments.length === 0) {
223
+ return false;
224
+ }
225
+ const lastMention = mentionComments[mentionComments.length - 1];
226
+ const botComments = comments.filter((c) => isBot(c.user.login));
227
+ if (botComments.length === 0) {
228
+ return true;
229
+ }
230
+ const lastBotComment = botComments[botComments.length - 1];
231
+ return new Date(lastBotComment.created_at) < new Date(lastMention.created_at);
232
+ }
233
+ function isBot(username) {
234
+ const lower = username.toLowerCase();
235
+ return (BOT_USERNAMES.has(lower) || lower.endsWith("[bot]") || lower.includes("bot"));
236
+ }
237
+ // --- Utility ---
238
+ function hasConflicts(pr) {
239
+ return pr.mergeable === false || pr.mergeable_state === "conflicting";
240
+ }
241
+ function calculateDaysSinceUpdate(updatedAt) {
242
+ return Math.floor((Date.now() - new Date(updatedAt).getTime()) / (1000 * 60 * 60 * 24));
243
+ }
244
+ //# sourceMappingURL=analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.js","sourceRoot":"","sources":["../src/analysis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * PR Classification
3
+ *
4
+ * Classifies PRs into action buckets:
5
+ * - readyForHuman: PRs that need human attention (review, approve, merge)
6
+ * - needsBotBump: PRs waiting on a bot response
7
+ * - inProgress: PRs with active work (CI running)
8
+ * - blocked: PRs waiting but no active work (draft, CI failed, conflicts)
9
+ *
10
+ * Consumers can extend buckets via ClassificationConfig.
11
+ */
12
+ import type { ClassificationConfig, ScannedPR, ScanResult } from "./types.js";
13
+ /**
14
+ * Classify PRs into action buckets.
15
+ *
16
+ * @param prs - The PRs to classify
17
+ * @param config - Optional extra statuses to include in each bucket
18
+ */
19
+ export declare function classifyPRs(prs: readonly ScannedPR[], config?: ClassificationConfig): ScanResult;
20
+ //# sourceMappingURL=classification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classification.d.ts","sourceRoot":"","sources":["../src/classification.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAqB9E;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,SAAS,SAAS,EAAE,EACzB,MAAM,CAAC,EAAE,oBAAoB,GAC5B,UAAU,CAmBZ"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * PR Classification
4
+ *
5
+ * Classifies PRs into action buckets:
6
+ * - readyForHuman: PRs that need human attention (review, approve, merge)
7
+ * - needsBotBump: PRs waiting on a bot response
8
+ * - inProgress: PRs with active work (CI running)
9
+ * - blocked: PRs waiting but no active work (draft, CI failed, conflicts)
10
+ *
11
+ * Consumers can extend buckets via ClassificationConfig.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.classifyPRs = classifyPRs;
15
+ // --- Core status lists ---
16
+ const READY_FOR_HUMAN_STATUSES = [
17
+ "needs_review",
18
+ "changes_requested",
19
+ "approved",
20
+ "ready_to_merge",
21
+ ];
22
+ const IN_PROGRESS_STATUSES = ["ci_running"];
23
+ const BLOCKED_STATUSES = [
24
+ "draft",
25
+ "ci_failed",
26
+ "has_conflicts",
27
+ ];
28
+ const NEEDS_BOT_BUMP_STATUSES = ["waiting_on_bot"];
29
+ /**
30
+ * Classify PRs into action buckets.
31
+ *
32
+ * @param prs - The PRs to classify
33
+ * @param config - Optional extra statuses to include in each bucket
34
+ */
35
+ function classifyPRs(prs, config) {
36
+ const readyForHuman = mergeStatuses(READY_FOR_HUMAN_STATUSES, config?.readyForHuman);
37
+ const inProgress = mergeStatuses(IN_PROGRESS_STATUSES, config?.inProgress);
38
+ const blocked = mergeStatuses(BLOCKED_STATUSES, config?.blocked);
39
+ const needsBotBump = mergeStatuses(NEEDS_BOT_BUMP_STATUSES, config?.needsBotBump);
40
+ return {
41
+ all: prs,
42
+ readyForHuman: prs.filter((pr) => readyForHuman.includes(pr.status)),
43
+ needsBotBump: prs.filter((pr) => needsBotBump.includes(pr.status)),
44
+ inProgress: prs.filter((pr) => inProgress.includes(pr.status)),
45
+ blocked: prs.filter((pr) => blocked.includes(pr.status)),
46
+ };
47
+ }
48
+ function mergeStatuses(base, extra) {
49
+ if (!extra || extra.length === 0) {
50
+ return base;
51
+ }
52
+ return [...base, ...extra];
53
+ }
54
+ //# sourceMappingURL=classification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classification.js","sourceRoot":"","sources":["../src/classification.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AA6BH,kCAsBC;AA/CD,4BAA4B;AAE5B,MAAM,wBAAwB,GAAsB;IAClD,cAAc;IACd,mBAAmB;IACnB,UAAU;IACV,gBAAgB;CACjB,CAAC;AAEF,MAAM,oBAAoB,GAAsB,CAAC,YAAY,CAAC,CAAC;AAE/D,MAAM,gBAAgB,GAAsB;IAC1C,OAAO;IACP,WAAW;IACX,eAAe;CAChB,CAAC;AAEF,MAAM,uBAAuB,GAAsB,CAAC,gBAAgB,CAAC,CAAC;AAEtE;;;;;GAKG;AACH,SAAgB,WAAW,CACzB,GAAyB,EACzB,MAA6B;IAE7B,MAAM,aAAa,GAAG,aAAa,CACjC,wBAAwB,EACxB,MAAM,EAAE,aAAa,CACtB,CAAC;IACF,MAAM,UAAU,GAAG,aAAa,CAAC,oBAAoB,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,aAAa,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACjE,MAAM,YAAY,GAAG,aAAa,CAChC,uBAAuB,EACvB,MAAM,EAAE,YAAY,CACrB,CAAC;IAEF,OAAO;QACL,GAAG,EAAE,GAAG;QACR,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QACpE,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QAClE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QAC9D,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;KACzD,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CACpB,IAAuB,EACvB,KAAyB;IAEzB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * PR Analyzer
3
+ *
4
+ * Analyzes and classifies GitHub PRs.
5
+ * See workflow.ts for single-PR scanning.
6
+ */
7
+ export { scanSinglePR } from "./workflow.js";
8
+ export { analyzePR, analyzeAll } from "./analysis.js";
9
+ export { classifyPRs } from "./classification.js";
10
+ export { getAvailableActions, PR_ACTIONS } from "./actions.js";
11
+ export type { CorePRStatus, ScannedPR, ScanResult, CIStatus, DiscoveredPR, Logger, AnalysisDetails, AnalyzerHooks, ClassificationConfig, ActionDefinition, } from "./types.js";
12
+ export type { CorePRActionType, PRActionDescriptor } from "./actions.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EACV,YAAY,EACZ,SAAS,EACT,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * PR Analyzer
4
+ *
5
+ * Analyzes and classifies GitHub PRs.
6
+ * See workflow.ts for single-PR scanning.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PR_ACTIONS = exports.getAvailableActions = exports.classifyPRs = exports.analyzeAll = exports.analyzePR = exports.scanSinglePR = void 0;
10
+ var workflow_js_1 = require("./workflow.js");
11
+ Object.defineProperty(exports, "scanSinglePR", { enumerable: true, get: function () { return workflow_js_1.scanSinglePR; } });
12
+ var analysis_js_1 = require("./analysis.js");
13
+ Object.defineProperty(exports, "analyzePR", { enumerable: true, get: function () { return analysis_js_1.analyzePR; } });
14
+ Object.defineProperty(exports, "analyzeAll", { enumerable: true, get: function () { return analysis_js_1.analyzeAll; } });
15
+ var classification_js_1 = require("./classification.js");
16
+ Object.defineProperty(exports, "classifyPRs", { enumerable: true, get: function () { return classification_js_1.classifyPRs; } });
17
+ var actions_js_1 = require("./actions.js");
18
+ Object.defineProperty(exports, "getAvailableActions", { enumerable: true, get: function () { return actions_js_1.getAvailableActions; } });
19
+ Object.defineProperty(exports, "PR_ACTIONS", { enumerable: true, get: function () { return actions_js_1.PR_ACTIONS; } });
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,6CAA6C;AAApC,2GAAA,YAAY,OAAA;AACrB,6CAAsD;AAA7C,wGAAA,SAAS,OAAA;AAAE,yGAAA,UAAU,OAAA;AAC9B,yDAAkD;AAAzC,gHAAA,WAAW,OAAA;AACpB,2CAA+D;AAAtD,iHAAA,mBAAmB,OAAA;AAAE,wGAAA,UAAU,OAAA"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * PR Analysis Types
3
+ */
4
+ import type { CheckRun, PullRequest, PullRequestComment, PullRequestReview, Repository } from "@hardlydifficult/github";
5
+ /**
6
+ * Core PR statuses derived purely from GitHub data.
7
+ * Consumers can extend with custom statuses via AnalyzerHooks.
8
+ */
9
+ export type CorePRStatus = "draft" | "ci_running" | "ci_failed" | "needs_review" | "changes_requested" | "approved" | "has_conflicts" | "ready_to_merge" | "waiting_on_bot";
10
+ /**
11
+ * A PR that has been scanned and analyzed.
12
+ * Status is `string` to allow custom statuses from hooks.
13
+ */
14
+ export interface ScannedPR {
15
+ readonly pr: PullRequest;
16
+ readonly repo: Repository;
17
+ readonly status: string;
18
+ readonly ciStatus: CIStatus;
19
+ readonly ciSummary: string;
20
+ readonly hasConflicts: boolean;
21
+ readonly waitingOnBot: boolean;
22
+ readonly daysSinceUpdate: number;
23
+ }
24
+ /**
25
+ * Result of scanning all PRs, classified into buckets
26
+ */
27
+ export interface ScanResult {
28
+ readonly all: readonly ScannedPR[];
29
+ readonly readyForHuman: readonly ScannedPR[];
30
+ readonly needsBotBump: readonly ScannedPR[];
31
+ readonly inProgress: readonly ScannedPR[];
32
+ readonly blocked: readonly ScannedPR[];
33
+ }
34
+ /**
35
+ * CI status analysis result
36
+ */
37
+ export interface CIStatus {
38
+ readonly isRunning: boolean;
39
+ readonly hasFailed: boolean;
40
+ readonly allPassed: boolean;
41
+ readonly summary: string;
42
+ }
43
+ /**
44
+ * A discovered PR with its repository context (used internally by analysis)
45
+ */
46
+ export interface DiscoveredPR {
47
+ readonly pr: PullRequest;
48
+ readonly repoOwner: string;
49
+ readonly repoName: string;
50
+ }
51
+ /**
52
+ * Logger interface for pr-analyzer consumers to implement
53
+ */
54
+ export interface Logger {
55
+ info(message: string, context?: Record<string, unknown>): void;
56
+ error(message: string, context?: Record<string, unknown>): void;
57
+ }
58
+ /**
59
+ * Raw analysis data passed to hooks for custom status resolution.
60
+ */
61
+ export interface AnalysisDetails {
62
+ readonly comments: readonly PullRequestComment[];
63
+ readonly checks: readonly CheckRun[];
64
+ readonly reviews: readonly PullRequestReview[];
65
+ readonly ciStatus: CIStatus;
66
+ readonly hasConflicts: boolean;
67
+ readonly waitingOnBot: boolean;
68
+ }
69
+ /**
70
+ * Hooks for customizing analysis behavior.
71
+ * Consumers can override status determination with custom logic.
72
+ */
73
+ export interface AnalyzerHooks {
74
+ /**
75
+ * Called after the core status is determined.
76
+ * Return a custom status string to override, or undefined to keep the core status.
77
+ */
78
+ readonly resolveStatus?: (coreStatus: CorePRStatus, details: AnalysisDetails) => string | undefined;
79
+ }
80
+ /**
81
+ * Configuration for extending classification buckets with custom statuses.
82
+ */
83
+ export interface ClassificationConfig {
84
+ readonly readyForHuman?: readonly string[];
85
+ readonly inProgress?: readonly string[];
86
+ readonly blocked?: readonly string[];
87
+ readonly needsBotBump?: readonly string[];
88
+ }
89
+ /**
90
+ * Definition for a custom action provided by consumers.
91
+ */
92
+ export interface ActionDefinition {
93
+ readonly type: string;
94
+ readonly label: string;
95
+ readonly description: string;
96
+ readonly when: (pr: ScannedPR, context: Record<string, boolean>) => boolean;
97
+ }
98
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * PR Analysis Types
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;GAEG"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * PR Scanning Workflow
3
+ *
4
+ * Scans a single PR by repo and number for real-time event handling.
5
+ */
6
+ import type { GitHubClient } from "@hardlydifficult/github";
7
+ import type { AnalyzerHooks, ScannedPR } from "./types.js";
8
+ /**
9
+ * Scan a single PR by repo and number.
10
+ * Used for real-time event handling - much faster than a full scan.
11
+ */
12
+ export declare function scanSinglePR(client: GitHubClient, botMention: string, owner: string, repo: string, prNumber: number, hooks?: AnalyzerHooks): Promise<ScannedPR>;
13
+ //# sourceMappingURL=workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE3D;;;GAGG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,aAAa,GACpB,OAAO,CAAC,SAAS,CAAC,CAGpB"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /**
3
+ * PR Scanning Workflow
4
+ *
5
+ * Scans a single PR by repo and number for real-time event handling.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.scanSinglePR = scanSinglePR;
9
+ const analysis_js_1 = require("./analysis.js");
10
+ /**
11
+ * Scan a single PR by repo and number.
12
+ * Used for real-time event handling - much faster than a full scan.
13
+ */
14
+ async function scanSinglePR(client, botMention, owner, repo, prNumber, hooks) {
15
+ const pr = await client.repo(owner, repo).pr(prNumber).get();
16
+ return (0, analysis_js_1.analyzePR)(client, owner, repo, pr, botMention, hooks);
17
+ }
18
+ //# sourceMappingURL=workflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow.js","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAWH,oCAUC;AAjBD,+CAA0C;AAG1C;;;GAGG;AACI,KAAK,UAAU,YAAY,CAChC,MAAoB,EACpB,UAAkB,EAClB,KAAa,EACb,IAAY,EACZ,QAAgB,EAChB,KAAqB;IAErB,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;IAC7D,OAAO,IAAA,uBAAS,EAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;AAC/D,CAAC"}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@hardlydifficult/pr-analyzer",
3
+ "version": "1.0.0",
4
+ "main": "./dist/index.js",
5
+ "types": "./dist/index.d.ts",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
13
+ "test:coverage": "vitest run --coverage",
14
+ "lint": "tsc --noEmit",
15
+ "clean": "rm -rf dist"
16
+ },
17
+ "dependencies": {
18
+ "@hardlydifficult/github": "1.0.22"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "25.2.3",
22
+ "typescript": "5.9.3",
23
+ "vitest": "4.0.18"
24
+ }
25
+ }