@reneturcios/greenlight 0.0.0-stage → 0.3.2

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,220 @@
1
+ import { detectClaims, strongClaimants } from "./claims.js";
2
+ import { parseGates, parseGatesFromSources, hardGates, gateLabel } from "./gates.js";
3
+ import { isClosingPR } from "./linkstrength.js";
4
+ import { extractPRReferences } from "./github.js";
5
+ const FRESH_CLAIM_DAYS = 45;
6
+ const STALE_INACTIVITY_DAYS = 180;
7
+ function daysSince(iso, now) {
8
+ return Math.max(0, Math.round((now.getTime() - new Date(iso).getTime()) / (1000 * 60 * 60 * 24)));
9
+ }
10
+ export function scoreIssue(snapshot, now = new Date()) {
11
+ const claims = detectClaims(snapshot.author ?? "", snapshot.comments, now);
12
+ // House-rules files (CONTRIBUTING variants, AGENTS.md, CLAUDE.md) are
13
+ // parsed per-file so each gate records which file its evidence came from.
14
+ const gates = snapshot.houseRules && snapshot.houseRules.length > 0
15
+ ? parseGatesFromSources(snapshot.houseRules)
16
+ : parseGates(snapshot.contributing);
17
+ // A committed gatefile gates document outranks prose re-derivation for
18
+ // any kind the prose pass did not already detect: the repo extracted and
19
+ // committed those gates itself.
20
+ if (snapshot.externalGates) {
21
+ for (const eg of snapshot.externalGates) {
22
+ const m = gates.find((x) => x.kind === eg.kind);
23
+ if (m && !m.detected) {
24
+ m.detected = true;
25
+ m.evidence = eg.evidence;
26
+ m.source = eg.source;
27
+ }
28
+ }
29
+ }
30
+ const reasons = [];
31
+ const flags = [];
32
+ const repoRef = `${snapshot.owner}/${snapshot.repo}`;
33
+ // Rule 1: closed.
34
+ if (snapshot.state === "closed") {
35
+ reasons.push(`issue is closed on ${repoRef}`);
36
+ return { verdict: "TAKEN", reasons, claims, gates, flags };
37
+ }
38
+ // Rule 2: assignees.
39
+ if (snapshot.assignees.length > 0) {
40
+ reasons.push(`assigned to ${snapshot.assignees.join(", ")}`);
41
+ return { verdict: "TAKEN", reasons, claims, gates, flags };
42
+ }
43
+ // Rule 3: open linked PR that closes the issue.
44
+ const openClosingPR = snapshot.linkedPRs.find((pr) => pr.state === "open" && isClosingPR(pr));
45
+ if (openClosingPR) {
46
+ reasons.push(`open PR #${openClosingPR.number} closes this issue`);
47
+ return { verdict: "TAKEN", reasons, claims, gates, flags };
48
+ }
49
+ // An open PR that only mentions the issue is a weak signal, not a takeover.
50
+ const openMentionPRs = snapshot.linkedPRs.filter((pr) => pr.state === "open" && !isClosingPR(pr));
51
+ if (openMentionPRs.length > 0)
52
+ flags.push("weak-pr-mention");
53
+ const strong = strongClaimants(claims);
54
+ // Whole-issue claims compete for the whole issue; scoped claims leave part
55
+ // of the work open, so only whole-issue claims can form a claim race.
56
+ const fullStrong = strong.filter((c) => c.scope !== "partial");
57
+ const partialStrong = strong.filter((c) => c.scope === "partial");
58
+ // Rule 4: claim race.
59
+ if (fullStrong.length >= 2) {
60
+ const names = fullStrong.map((c) => c.author).join(", ");
61
+ reasons.push(`claim race: ${fullStrong.length} strong claimants (${names})`);
62
+ flags.push("claimed");
63
+ return { verdict: "TAKEN", reasons, claims, gates, flags };
64
+ }
65
+ // Rule 5/6: single whole-issue strong claim.
66
+ if (fullStrong.length === 1) {
67
+ const c = fullStrong[0];
68
+ if (c.ageDays <= FRESH_CLAIM_DAYS) {
69
+ reasons.push(`claimed by ${c.author} ${c.ageDays} day(s) ago ("${c.phrase}")`);
70
+ flags.push("claimed");
71
+ return { verdict: "RISKY", reasons, claims, gates, flags };
72
+ }
73
+ // A closing PR (open or not) counts as "a PR was opened"; a mention does not.
74
+ if (!snapshot.linkedPRs.some(isClosingPR)) {
75
+ reasons.push(`stale claim by ${c.author} ${c.ageDays} day(s) ago ("${c.phrase}"), no PR ever opened`);
76
+ flags.push("stale_claim");
77
+ return { verdict: "RISKY", reasons, claims, gates, flags };
78
+ }
79
+ }
80
+ // Rule 5b/6b: scoped (partial) claim. A fresh partial claim does not take
81
+ // the issue (part of the work remains), but it downgrades an otherwise-GO
82
+ // verdict to RISKY with a reason naming the claimer and the scope. A stale
83
+ // partial claim gets the same treatment as other stale claims.
84
+ if (partialStrong.length > 0) {
85
+ const c = partialStrong[0];
86
+ const part = c.scopeWord ? `the ${c.scopeWord} part` : "part of the issue";
87
+ flags.push("claimed");
88
+ flags.push("partial-claim");
89
+ if (c.ageDays <= FRESH_CLAIM_DAYS) {
90
+ reasons.push(`${c.author} claimed ${part} ${c.ageDays} day(s) ago; the rest may still be open`);
91
+ return { verdict: "RISKY", reasons, claims, gates, flags };
92
+ }
93
+ if (!snapshot.linkedPRs.some(isClosingPR)) {
94
+ reasons.push(`stale partial claim by ${c.author} ${c.ageDays} day(s) ago ("${c.phrase}")`);
95
+ flags.push("stale_claim");
96
+ return { verdict: "RISKY", reasons, claims, gates, flags };
97
+ }
98
+ }
99
+ // Rule 7: hard gate with nobody assigned.
100
+ const hard = hardGates(gates);
101
+ if (hard.length > 0) {
102
+ reasons.push(`repo gate blocks outside PRs: ${hard.map((g) => gateLabel(g.kind)).join("; ")}`);
103
+ if (hard[0].evidence)
104
+ reasons.push(`gate evidence: "${hard[0].evidence}"`);
105
+ return { verdict: "GATED", reasons, claims, gates, flags };
106
+ }
107
+ // Rule 8: stale by inactivity.
108
+ const inactivityDays = daysSince(snapshot.updatedAt, now);
109
+ if (inactivityDays >= STALE_INACTIVITY_DAYS) {
110
+ reasons.push(`no activity for ${inactivityDays} days`);
111
+ return { verdict: "STALE", reasons, claims, gates, flags };
112
+ }
113
+ // Rule 9: soft claim-first gate. Comment-first is a ritual you satisfy by
114
+ // posting a comment, not a hard block, so it never yields GATED. It caps
115
+ // an otherwise-GO verdict at RISKY with a note, the same downgrade shape
116
+ // as the weak-PR-mention rule below.
117
+ const claimFirst = gates.some((g) => g.kind === "claim_first" && g.detected);
118
+ const claimFirstNote = "repo asks contributors to comment before starting (claim first)";
119
+ // Rule 10: nothing blocking, unless an open PR merely mentions the issue.
120
+ let verdict = "GO";
121
+ if (openMentionPRs.length > 0) {
122
+ const n = openMentionPRs[0].number;
123
+ reasons.push(`PR #${n} mentions this issue but does not close it; verify it is not already being worked`);
124
+ verdict = "RISKY";
125
+ }
126
+ else {
127
+ reasons.push(`open, unassigned, no linked closing PRs, no claim signals, no blocking gates on ${repoRef}`);
128
+ }
129
+ if (claimFirst) {
130
+ reasons.push(claimFirstNote);
131
+ flags.push("claim_first");
132
+ verdict = "RISKY";
133
+ }
134
+ // Rule 11: comment-mentioned PR cross-check. A PR cited in a non-author
135
+ // comment whose title/body mentions this issue number may already cover
136
+ // part of the work: downgrade an otherwise-GO verdict to RISKY. A merged
137
+ // one is handled by rule 12 below; neither can produce TAKEN.
138
+ const mentioned = snapshot.commentMentionedPRs ?? [];
139
+ const openMentioned = mentioned.filter((p) => p.state === "open" && p.mentionsIssue && !p.fromAuthor);
140
+ const mergedMentioned = mentioned.filter((p) => p.state === "merged" && p.mentionsIssue);
141
+ if (openMentioned.length > 0) {
142
+ flags.push("comment-mentioned-pr");
143
+ if (verdict === "GO") {
144
+ reasons.push(`PR #${openMentioned[0].number} referenced in comments may already cover part of this issue`);
145
+ verdict = "RISKY";
146
+ }
147
+ }
148
+ // Rule 12: partially-addressed. A merged PR is evidence that part of
149
+ // the issue already shipped when (a) its title/body references this
150
+ // issue number, or (b) a maintainer comment signaling shipped work
151
+ // cites it. Case (b) matters because maintainers often narrate shipped
152
+ // work ("Half addressed by #905, merged to main in #915") without the
153
+ // PR itself naming the issue. A plain GO hides the scoping work a
154
+ // contributor must do, so flag it and cap GO at RISKY. Never TAKEN:
155
+ // only an open closing PR does that (rule 3).
156
+ const shipperCitedNumbers = new Set();
157
+ for (const c of snapshot.comments) {
158
+ if (PARTIALLY_SHIPPED_COMMENT_RES.some((re) => re.test(c.body)) ||
159
+ hasShippedInVersionSignal([c], snapshot.number)) {
160
+ for (const n of extractPRReferences([c], snapshot.owner, snapshot.repo)) {
161
+ shipperCitedNumbers.add(n);
162
+ }
163
+ }
164
+ }
165
+ const shippedPRs = new Map();
166
+ const addShipped = (n) => {
167
+ if (!shippedPRs.has(n))
168
+ shippedPRs.set(n, `PR #${n}, merged`);
169
+ };
170
+ for (const p of mentioned) {
171
+ if (p.state === "merged" && (p.mentionsIssue || shipperCitedNumbers.has(p.number))) {
172
+ addShipped(p.number);
173
+ }
174
+ }
175
+ for (const pr of snapshot.linkedPRs) {
176
+ if (pr.state === "merged" && (isClosingPR(pr) || shipperCitedNumbers.has(pr.number))) {
177
+ addShipped(pr.number);
178
+ }
179
+ }
180
+ const shippedParts = [...shippedPRs.values()];
181
+ const partiallyShippedComment = snapshot.comments.some((c) => PARTIALLY_SHIPPED_COMMENT_RES.some((re) => re.test(c.body))) ||
182
+ hasShippedInVersionSignal(snapshot.comments, snapshot.number);
183
+ const consumedByRule12 = new Set(shippedPRs.keys());
184
+ if (shippedParts.length > 0 || partiallyShippedComment) {
185
+ flags.push("partially-addressed");
186
+ const detail = shippedParts.length > 0 ? shippedParts.join("; ") : "a maintainer comment";
187
+ reasons.push(`part of this issue already shipped (${detail}); scope your work to what remains`);
188
+ if (verdict === "GO")
189
+ verdict = "RISKY";
190
+ }
191
+ // Rule 11's informational merged note, for merged references that did
192
+ // not already produce the rule-12 reason.
193
+ for (const p of mergedMentioned) {
194
+ if (consumedByRule12.has(p.number))
195
+ continue;
196
+ reasons.push(`PR #${p.number} (merged) referenced in comments; issue may be partially addressed`);
197
+ }
198
+ return { verdict, reasons, claims, gates, flags };
199
+ }
200
+ /**
201
+ * Comment shapes that signal part of an issue already shipped while the
202
+ * rest stays open. Seen on reticlehq/reticle#894: "Half addressed by #905,
203
+ * merged to main in #915", "leaving this open for half B", "Shipped in
204
+ * v3.1.0".
205
+ */
206
+ const PARTIALLY_SHIPPED_COMMENT_RES = [
207
+ /half (addressed|done|fixed)/i,
208
+ /leaving (this|it) open for/i,
209
+ /\bstill (open|remaining)\b/i,
210
+ /part of this (is|was) (fixed|shipped)/i,
211
+ ];
212
+ /** "/shipped in v/i near an issue reference" is the last pattern; the
213
+ * four above run on every comment, and this one runs below with its
214
+ * issue-reference guard. */
215
+ export function hasShippedInVersionSignal(comments, issueNumber) {
216
+ return comments.some((c) => /shipped in v/i.test(c.body) &&
217
+ (c.body.includes(`#${issueNumber}`) || /this issue/i.test(c.body)));
218
+ }
219
+ export { FRESH_CLAIM_DAYS, STALE_INACTIVITY_DAYS };
220
+ //# sourceMappingURL=verdict.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verdict.js","sourceRoot":"","sources":["../src/verdict.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
+ "bin": {
3
+ "greenlight": "dist/cli.js"
4
+ },
5
+ "dependencies": {
6
+ "@modelcontextprotocol/sdk": "^1",
7
+ "zod": "^3"
8
+ },
9
+ "description": "Pre-flight checks for open-source contributions: is this issue actually landable?",
10
+ "devDependencies": {
11
+ "@types/node": "^20",
12
+ "tsx": "^4",
13
+ "typescript": "^5"
14
+ },
15
+ "engines": {
16
+ "node": ">=20"
17
+ },
18
+ "license": "MIT",
2
19
  "name": "@reneturcios/greenlight",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
20
+ "private": false,
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "dev": "tsx src/cli.ts",
24
+ "index": "tsx src/friction-index.ts",
25
+ "test": "tsx --test test/*.test.ts"
26
+ },
27
+ "type": "module",
28
+ "version": "0.3.2",
29
+ "mcpName": "io.github.CloudCorpRecords/greenlight",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/CloudCorpRecords/greenlight.git"
36
+ },
37
+ "homepage": "https://github.com/CloudCorpRecords/greenlight#readme",
38
+ "files": [
39
+ "dist",
40
+ "server.json"
41
+ ]
6
42
  }
package/server.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.CloudCorpRecords/greenlight",
4
+ "description": "Pre-flight checks for open-source contributions: is this GitHub issue actually landable?",
5
+ "repository": {
6
+ "url": "https://github.com/CloudCorpRecords/greenlight",
7
+ "source": "github"
8
+ },
9
+ "version": "0.3.2",
10
+ "packages": [
11
+ {
12
+ "registryType": "npm",
13
+ "registryBaseUrl": "https://registry.npmjs.org",
14
+ "identifier": "@reneturcios/greenlight",
15
+ "version": "0.3.2",
16
+ "runtimeHint": "npx",
17
+ "packageArguments": [
18
+ {
19
+ "type": "positional",
20
+ "value": "mcp"
21
+ }
22
+ ],
23
+ "transport": {
24
+ "type": "stdio"
25
+ }
26
+ }
27
+ ]
28
+ }