@reneturcios/greenlight 0.17.1 → 0.18.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.
- package/README.md +7 -6
- package/dist/behavior.d.ts +13 -3
- package/dist/behavior.js +41 -10
- package/dist/behavior.js.map +1 -1
- package/dist/bounty.d.ts +8 -0
- package/dist/bounty.js +15 -0
- package/dist/bounty.js.map +1 -1
- package/dist/cli.js +60 -5
- package/dist/cli.js.map +1 -1
- package/dist/friction-index.js +13 -4
- package/dist/friction-index.js.map +1 -1
- package/dist/friction.d.ts +1 -1
- package/dist/friction.js +19 -11
- package/dist/friction.js.map +1 -1
- package/dist/github.d.ts +18 -0
- package/dist/github.js +24 -0
- package/dist/github.js.map +1 -1
- package/dist/help.js +13 -2
- package/dist/help.js.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/merge-velocity.js +5 -3
- package/dist/merge-velocity.js.map +1 -1
- package/dist/types.d.ts +11 -3
- package/package.json +1 -1
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -38,12 +38,12 @@ Every verdict and every report cites its evidence: the quoted policy line, the c
|
|
|
38
38
|
## Who it is for
|
|
39
39
|
|
|
40
40
|
* **Contributors (human).** Run `check` before you spend an evening on an issue. Run `scan` when you are picking what to work on. Run `ci-prep` before you push.
|
|
41
|
-
* **AI agents and coding tools.** One command (`init --agent claude-code`, also cursor, copilot, windsurf, cline) installs the MCP config plus the one behavior rule: check Greenlight before opening a PR. Agents waste the most tokens fixing already-taken issues;
|
|
41
|
+
* **AI agents and coding tools.** One command (`init --agent claude-code`, also cursor, copilot, windsurf, cline) installs the MCP config plus the one behavior rule: check Greenlight before opening a PR. Agents waste the most tokens fixing already-taken issues; 32 MCP tools make the whole engine available mid-run.
|
|
42
42
|
* **Maintainers.** `guard` on each incoming PR, `radar` across the whole open queue, `digest` for the weekly triage, and the roadmap below for the control room: stale-claim sweeps, policy enforcement, AI-PR filtering.
|
|
43
43
|
|
|
44
44
|
## Proof, stated plainly
|
|
45
45
|
|
|
46
|
-
*
|
|
46
|
+
* 1045 tests, all passing, including a fixture corpus pinned to real campaign cases (a taken issue, a weak PR mention, claim-first gates, scoped claims, half-shipped issues, stale claims, paused-PR workflows).
|
|
47
47
|
* Dogfooded on real campaigns: the toolkit has authored 80+ pull requests across dozens of public open-source repos. Every feature exists because a real contribution died without it.
|
|
48
48
|
* Distributed everywhere the audience already looks: npm (`@reneturcios/greenlight`), the MCP Registry, and GHCR (`ghcr.io/cloudcorprecords/greenlight`), plus Docker and direct MCP stdio.
|
|
49
49
|
* Two living datasets ship with it: the Contribution Friction Index (`data/friction-index.json`) and the Agent Policy Index (505 repos, 127 gated, 19 agent bans, published at `docs/policy.html`), both built from real campaign field work, not scraped guesses.
|
|
@@ -103,7 +103,7 @@ One command sets it up:
|
|
|
103
103
|
npx @reneturcios/greenlight init --agent claude-code
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
(also `cursor`, `copilot`, `windsurf`, `cline`; repeat `--agent` for more than one). Init copies the MCP config into your project and installs the workflow instruction snippet that teaches your agent the one behavior rule: **check Greenlight before it opens a PR.** Prefer doing it by hand? The [`integrations/`](integrations/README.md) drop-in pack has ready-to-copy MCP configs plus the same snippets. Then verify with a "list your MCP tools" prompt; the greenlight server carries
|
|
106
|
+
(also `cursor`, `copilot`, `windsurf`, `cline`; repeat `--agent` for more than one). Init copies the MCP config into your project and installs the workflow instruction snippet that teaches your agent the one behavior rule: **check Greenlight before it opens a PR.** Prefer doing it by hand? The [`integrations/`](integrations/README.md) drop-in pack has ready-to-copy MCP configs plus the same snippets. Then verify with a "list your MCP tools" prompt; the greenlight server carries 32 tools (see the list below).
|
|
107
107
|
|
|
108
108
|
## CLI
|
|
109
109
|
|
|
@@ -283,7 +283,7 @@ The same engine is exposed over stdio for coding agents (Claude, Cursor, Cline).
|
|
|
283
283
|
}
|
|
284
284
|
```
|
|
285
285
|
|
|
286
|
-
Tools (
|
|
286
|
+
Tools (32):
|
|
287
287
|
|
|
288
288
|
* `check_issue` - verdict for one issue URL
|
|
289
289
|
* `scan_repo` - rank a repo's open issues, GO first (label-tagged starter issues, falling back to recent open unassigned issues; `deep: true` timeline-x-rays the candidates first)
|
|
@@ -293,6 +293,7 @@ Tools (31):
|
|
|
293
293
|
* `verify` - honest base-vs-head test delta for a checked-out repo (red-first, never raw counts)
|
|
294
294
|
* `shipcheck` - release-readiness: GitHub release, npm version, registry record, and GHCR tag, GO / NO-GO per surface
|
|
295
295
|
* `passport` - contributor passport for a GitHub login: ledger profile, merged PR count, honor ratio
|
|
296
|
+
* `bounty_check` - bounty-liveness classification for one issue: live platform, unverifiable claim, or dead platform
|
|
296
297
|
* `claim_issue` - verdict-gated claim comment (dry run unless `execute: true`)
|
|
297
298
|
* `prep_issue` - fork and branch check plus a local PREP.md checklist with the repo's learned conventions (dry run unless `execute: true`)
|
|
298
299
|
* `open_pr` - DCO-aware PR opening from a fork branch (dry run unless `execute: true`)
|
|
@@ -338,7 +339,7 @@ The verdict engine is deterministic (no LLM) and checks, in order:
|
|
|
338
339
|
|
|
339
340
|
Friction score starts at 100 and subtracts gate weights (assignment -25, vouch -35, collaborators-only -50, paused unsolicited PRs -40, scoped pause -20, external PRs auto-closed -50, discussion-first -10, claim-first -5, CLA/DCO -5 each, detected behavioral gate -20), adjusts for external PR merge rate and review/response times when computable, and adds up to +10 for open good-first-issues. Unknown signals stay null and are skipped, never guessed. See `src/friction.ts` for the exact formula.
|
|
340
341
|
|
|
341
|
-
A behavioral gate is not a policy file: it is read from what maintainers do. `friction` walks the closed-PR list until it has the 15 most recent closed-unmerged PRs within a 12-month recency bound (older closures are excluded, with a "stale signal" note when the newest closure itself is older than the bound), then reads maintainer-side comments for AI-rejection evidence (AI attribution plus rejection language, explicit phrases like "AI slop" or an invoked "AI policy", with welcoming overrides like "AI-assisted PRs are welcome" suppressing the signal). Two independent PRs mark the repo as behaviorally gated; a single weak signal is carried as a warning, while a single explicit rejection phrase detects on its own. `friction --json` reports it as the top-level `behavioral_gate` field (`detected`, `strength`, `threshold`, `evidence` with PR numbers, quotes, and URLs, `notes`); that field is the canonical location, and `signals.behavioralGate` is kept as an identical mirror for index-pipeline compatibility. Index pipelines like the rebaseline read the canonical field to reclassify repos whose written policy is silent but whose practice is hostile. API cost is bounded at
|
|
342
|
+
A behavioral gate is not a policy file: it is read from what maintainers do. `friction` walks the closed-PR list until it has the 15 most recent closed-unmerged PRs within a 12-month recency bound (older closures are excluded, with a "stale signal" note when the newest closure itself is older than the bound), then reads maintainer-side comments for AI-rejection evidence (AI attribution plus rejection language, explicit phrases like "AI slop" or an invoked "AI policy", with welcoming overrides like "AI-assisted PRs are welcome" suppressing the signal). Two independent PRs mark the repo as behaviorally gated; a single weak signal is carried as a warning, while a single explicit rejection phrase detects on its own. `friction --json` reports it as the top-level `behavioral_gate` field (`detected`, `strength`, `threshold`, `evidence` with PR numbers, quotes, and URLs, `notes`); that field is the canonical location, and `signals.behavioralGate` is kept as an identical mirror for index-pipeline compatibility. Index pipelines like the rebaseline read the canonical field to reclassify repos whose written policy is silent but whose practice is hostile. API cost is bounded at 48 calls: up to 3 list calls to collect 15 closed-unmerged PRs plus up to 3 evidence pages per PR (issue comments, reviews, review comments); skip it with `--no-behavioral`.
|
|
342
343
|
|
|
343
344
|
`wave` turns the Agent Policy Index into a build queue in one command: pure-open repos with outsider merge share, star band, and starter issues are x-rayed with the existing xray engine (CLEAR / RISKY / TAKEN with competing PRs named), repos with detected behavioral gates are excluded, repos where you already have an open PR are skipped, and the run stops with marked partial results when the core API budget falls under the floor (default 800) or search throttling hits. Human and `--json` output; every stage reports the API calls it used. Candidates rank by winnability by default (outsider merge share, then friction, then stars); `--sort stars` restores the old order.
|
|
344
345
|
|
|
@@ -346,7 +347,7 @@ A scoped intake pause ("not accepting pull requests that add new formatting opti
|
|
|
346
347
|
|
|
347
348
|
Autopilot keeps a standing branch-health board: per-PR mergeable, mergeable_state, base SHA, and behind-count persist in its state between runs, render in the report output, and ride along in the `autopilot_report` MCP tool (`branch_health`, `branch_board`).
|
|
348
349
|
|
|
349
|
-
|
|
350
|
+
Four more CLI commands are agent-callable MCP tools: `verify` (honest base-vs-head test delta), `shipcheck` (release, npm, registry, and GHCR readiness), `passport` (claim-ledger contributor profile), and `bounty` (bounty-liveness for one issue).
|
|
350
351
|
|
|
351
352
|
### Agent-policy gates and triage holds
|
|
352
353
|
|
package/dist/behavior.d.ts
CHANGED
|
@@ -4,12 +4,19 @@ export interface BehavioralClosedPR {
|
|
|
4
4
|
author: string;
|
|
5
5
|
closedAt: string;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* One maintainer-authored text blob on a closed-unmerged PR.
|
|
9
|
+
* v0.18.0 (item 5): maintainer rejections often live in review bodies
|
|
10
|
+
* and line comments, not issue comments, so all three surfaces feed the
|
|
11
|
+
* same matcher. `source` defaults to "comment" for older callers.
|
|
12
|
+
*/
|
|
7
13
|
export interface BehavioralMaintainerComment {
|
|
8
14
|
pr: number;
|
|
9
15
|
author: string;
|
|
10
16
|
association: string;
|
|
11
17
|
body: string;
|
|
12
18
|
url: string;
|
|
19
|
+
source?: "comment" | "review" | "review_comment";
|
|
13
20
|
}
|
|
14
21
|
export interface BehavioralSignal {
|
|
15
22
|
pr: number;
|
|
@@ -19,6 +26,8 @@ export interface BehavioralSignal {
|
|
|
19
26
|
url: string;
|
|
20
27
|
/** True for explicit phrases like "AI slop"; weaker signals can still count toward strength. */
|
|
21
28
|
strong: boolean;
|
|
29
|
+
/** Which surface carried the evidence: "comment" | "review" | "review_comment". */
|
|
30
|
+
source?: "comment" | "review" | "review_comment";
|
|
22
31
|
}
|
|
23
32
|
export interface BehavioralGate {
|
|
24
33
|
/** True when strength >= threshold: the maintainer rejects AI-built PRs in practice. */
|
|
@@ -53,9 +62,10 @@ export declare function partitionByRecency(prs: BehavioralClosedPR[], nowMs: num
|
|
|
53
62
|
newestClosedAt: string | null;
|
|
54
63
|
};
|
|
55
64
|
/**
|
|
56
|
-
* API cost contract: 1-3 calls to walk the closed-PR
|
|
57
|
-
* once 15 unmerged PRs are found) plus
|
|
58
|
-
* closed-unmerged PR
|
|
65
|
+
* API cost contract (v0.18.0, item 5): 1-3 calls to walk the closed-PR
|
|
66
|
+
* list (stops early once 15 unmerged PRs are found) plus up to three
|
|
67
|
+
* evidence pages per closed-unmerged PR (issue comments, reviews,
|
|
68
|
+
* review comments).
|
|
59
69
|
*/
|
|
60
70
|
export declare const BEHAVIORAL_MAX_API_CALLS: number;
|
|
61
71
|
/** Pure: does one comment body read as maintainer AI-rejection evidence? */
|
package/dist/behavior.js
CHANGED
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
* itself is older than the bound). The closed-PR list is
|
|
18
18
|
* walked (newest first, up to 3 pages of 30) until 15 unmerged PRs are
|
|
19
19
|
* collected, because merged PRs carry no closure evidence and an
|
|
20
|
-
* active repo's unmerged closures can sit pages deep.
|
|
21
|
-
* (first page, per_page=100) run only for those unmerged PRs,
|
|
22
|
-
*
|
|
20
|
+
* active repo's unmerged closures can sit pages deep. Evidence fetches
|
|
21
|
+
* (first page, per_page=100) run only for those unmerged PRs, on all
|
|
22
|
+
* three surfaces (issue comments, reviews, review comments), so the
|
|
23
|
+
* total cost is 1-3 list calls + up to 3 pages x 15 PRs (48 max).
|
|
23
24
|
* - Maintainer-side only: comment author_association must be OWNER,
|
|
24
25
|
* MEMBER, or COLLABORATOR, and the comment author must not be the PR
|
|
25
26
|
* author (a maintainer closing their own PR is not evidence against
|
|
@@ -80,11 +81,12 @@ export function partitionByRecency(prs, nowMs, months = BEHAVIORAL_RECENCY_MONTH
|
|
|
80
81
|
return { fresh, staleCount, newestClosedAt };
|
|
81
82
|
}
|
|
82
83
|
/**
|
|
83
|
-
* API cost contract: 1-3 calls to walk the closed-PR
|
|
84
|
-
* once 15 unmerged PRs are found) plus
|
|
85
|
-
* closed-unmerged PR
|
|
84
|
+
* API cost contract (v0.18.0, item 5): 1-3 calls to walk the closed-PR
|
|
85
|
+
* list (stops early once 15 unmerged PRs are found) plus up to three
|
|
86
|
+
* evidence pages per closed-unmerged PR (issue comments, reviews,
|
|
87
|
+
* review comments).
|
|
86
88
|
*/
|
|
87
|
-
export const BEHAVIORAL_MAX_API_CALLS = 3 + BEHAVIORAL_MAX_PRS;
|
|
89
|
+
export const BEHAVIORAL_MAX_API_CALLS = 3 + 3 * BEHAVIORAL_MAX_PRS;
|
|
88
90
|
const AI_TERMS = /\b(ai|a\.i\.|llm|llms|chatgpt|copilot|Muse|gemini|gpt-?4|gpt-?3|generated|slop)\b/i;
|
|
89
91
|
const REJECTION_TERMS = /\b(clos(?:e|ed|ing|ure)?|not\s+accept(?:ing|s)?|won['’]t|will\s+not|do\s+not|don['’]t|reject(?:ed|s|ion)?|declin(?:e|ed)|low[\s-]?effort|slop|refus(?:e|ed|ing)|spam|not\s+welcome|polic(?:y|ies))\b/i;
|
|
90
92
|
/** Explicit phrases: unmistakable even without the two-term rule. */
|
|
@@ -128,7 +130,7 @@ export function detectBehavioralGateFromData(prs, comments) {
|
|
|
128
130
|
const evidence = [];
|
|
129
131
|
const prsWithSignal = new Set();
|
|
130
132
|
const notes = [];
|
|
131
|
-
notes.push(`scanned ${prs.length} closed-unmerged PRs, ${comments.length} maintainer
|
|
133
|
+
notes.push(`scanned ${prs.length} closed-unmerged PRs, ${comments.length} maintainer-authored texts on them (issue comments, reviews, review comments)`);
|
|
132
134
|
for (const c of comments) {
|
|
133
135
|
if (!MAINTAINER_ASSOCIATIONS.has(String(c.association ?? "")))
|
|
134
136
|
continue;
|
|
@@ -147,6 +149,7 @@ export function detectBehavioralGateFromData(prs, comments) {
|
|
|
147
149
|
quote: truncateQuote(c.body),
|
|
148
150
|
url: c.url,
|
|
149
151
|
strong,
|
|
152
|
+
source: c.source ?? "comment",
|
|
150
153
|
});
|
|
151
154
|
prsWithSignal.add(c.pr);
|
|
152
155
|
}
|
|
@@ -200,16 +203,44 @@ export async function detectBehavioralGate(owner, repo, opts = {}) {
|
|
|
200
203
|
// v0.17.1: drop stale closures before paying comment calls for them.
|
|
201
204
|
const recency = partitionByRecency(closedUnmerged, nowMs);
|
|
202
205
|
const live = recency.fresh;
|
|
206
|
+
// v0.18.0 (item 5): maintainer rejections live on three surfaces.
|
|
207
|
+
// One bounded page each: issue comments, reviews, review comments.
|
|
203
208
|
const comments = [];
|
|
204
209
|
for (const pr of live) {
|
|
205
|
-
const
|
|
206
|
-
for (const c of
|
|
210
|
+
const issueComments = (await apiGet(`/repos/${owner}/${repo}/issues/${pr.number}/comments?per_page=100`));
|
|
211
|
+
for (const c of issueComments ?? []) {
|
|
207
212
|
comments.push({
|
|
208
213
|
pr: pr.number,
|
|
209
214
|
author: String(c.user?.login ?? ""),
|
|
210
215
|
association: String(c.author_association ?? ""),
|
|
211
216
|
body: String(c.body ?? ""),
|
|
212
217
|
url: c.html_url,
|
|
218
|
+
source: "comment",
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
const reviews = (await apiGet(`/repos/${owner}/${repo}/pulls/${pr.number}/reviews?per_page=100`));
|
|
222
|
+
for (const r of reviews ?? []) {
|
|
223
|
+
const body = String(r.body ?? "").trim();
|
|
224
|
+
if (!body)
|
|
225
|
+
continue; // bare APPROVE/REQUEST_CHANGES votes carry no text
|
|
226
|
+
comments.push({
|
|
227
|
+
pr: pr.number,
|
|
228
|
+
author: String(r.user?.login ?? ""),
|
|
229
|
+
association: String(r.author_association ?? ""),
|
|
230
|
+
body,
|
|
231
|
+
url: r.html_url,
|
|
232
|
+
source: "review",
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
const reviewComments = (await apiGet(`/repos/${owner}/${repo}/pulls/${pr.number}/comments?per_page=100`));
|
|
236
|
+
for (const c of reviewComments ?? []) {
|
|
237
|
+
comments.push({
|
|
238
|
+
pr: pr.number,
|
|
239
|
+
author: String(c.user?.login ?? ""),
|
|
240
|
+
association: String(c.author_association ?? ""),
|
|
241
|
+
body: String(c.body ?? ""),
|
|
242
|
+
url: c.html_url,
|
|
243
|
+
source: "review_comment",
|
|
213
244
|
});
|
|
214
245
|
}
|
|
215
246
|
}
|
package/dist/behavior.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"behavior.js","sourceRoot":"","sources":["../src/behavior.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"behavior.js","sourceRoot":"","sources":["../src/behavior.ts"],"names":[],"mappings":"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"}
|
package/dist/bounty.d.ts
CHANGED
|
@@ -19,6 +19,14 @@ export interface BountySignal {
|
|
|
19
19
|
/** Evidence string for the flag, or "" when flag is null. */
|
|
20
20
|
evidence: string;
|
|
21
21
|
}
|
|
22
|
+
/** Live: fetch the issue and classify its bounty advertising (v0.18.0, item 23). */
|
|
23
|
+
export declare function detectBountyForIssue(owner: string, repo: string, number: number): Promise<{
|
|
24
|
+
issueUrl: string;
|
|
25
|
+
repo: string;
|
|
26
|
+
labels: string[];
|
|
27
|
+
title: string;
|
|
28
|
+
signal: BountySignal | null;
|
|
29
|
+
}>;
|
|
22
30
|
export declare function detectBounty(input: {
|
|
23
31
|
labels: string[];
|
|
24
32
|
title: string;
|
package/dist/bounty.js
CHANGED
|
@@ -11,6 +11,21 @@
|
|
|
11
11
|
const DEAD_PLATFORMS = {
|
|
12
12
|
algora: "algora.io 404s and its public API returns zero items (dead since 2025)",
|
|
13
13
|
};
|
|
14
|
+
import { apiGet, resolveCanonicalRepo } from "./github.js";
|
|
15
|
+
/** Live: fetch the issue and classify its bounty advertising (v0.18.0, item 23). */
|
|
16
|
+
export async function detectBountyForIssue(owner, repo, number) {
|
|
17
|
+
const canon = await resolveCanonicalRepo(owner, repo);
|
|
18
|
+
const data = (await apiGet(`/repos/${canon.owner}/${canon.repo}/issues/${number}`));
|
|
19
|
+
const labels = (data.labels ?? []).map((l) => String(l.name ?? ""));
|
|
20
|
+
const title = String(data.title ?? "");
|
|
21
|
+
return {
|
|
22
|
+
issueUrl: String(data.html_url ?? ""),
|
|
23
|
+
repo: canon.fullName,
|
|
24
|
+
labels,
|
|
25
|
+
title,
|
|
26
|
+
signal: detectBounty({ labels, title, body: String(data.body ?? "") }),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
14
29
|
const PLATFORM_RE = /(algora|opire|issuehunt|polar|gitcoin|oss[-.]?hunter|bountysource)/i;
|
|
15
30
|
function normalizePlatform(name) {
|
|
16
31
|
return name.toLowerCase().replace(/[-.]/g, "");
|
package/dist/bounty.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bounty.js","sourceRoot":"","sources":["../src/bounty.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAeH,MAAM,cAAc,GAA2B;IAC7C,MAAM,EAAE,wEAAwE;CACjF,CAAC;AAEF,MAAM,WAAW,GAAG,qEAAqE,CAAC;AAE1F,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAI5B;IACC,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzE,MAAM,aAAa,GACjB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QACf,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrE,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAEhC,MAAM,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3D,MAAM,EAAE,GAAG,oCAAoC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAE7C,IAAI,QAAQ,IAAI,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,QAAQ;YACR,MAAM;YACN,IAAI,EAAE,sBAAsB;YAC5B,QAAQ,EAAE,iBAAiB,QAAQ,qBAAqB,cAAc,CAAC,QAAQ,CAAC,EAAE;SACnF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,MAAM;YACN,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,sEAAsE;SACjF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AACxD,CAAC"}
|
|
1
|
+
{"version":3,"file":"bounty.js","sourceRoot":"","sources":["../src/bounty.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* greenlight ci-prep <path> [--base <ref>] [--json] [--act]
|
|
18
18
|
* greenlight babysit [--prs urls] [--mine --repos o/r] [--account] [--claims-only] [--json]
|
|
19
19
|
* greenlight autopilot [--author login] [--prs urls] [--max-prs N] [--apply] [--max-fixes N] [--json]
|
|
20
|
+
* greenlight bounty <issue-url> [--json]
|
|
20
21
|
* greenlight sync [--author login] [--tracker csv|json] [--stale-days N] [--write] [--json]
|
|
21
22
|
* greenlight portfolio [--author login] [--json]
|
|
22
23
|
* greenlight init [--agent <tool>...] [--dry-run] [--force]
|
|
@@ -28,7 +29,7 @@
|
|
|
28
29
|
* The claim/prep/pr commands default to a DRY RUN: nothing is posted or
|
|
29
30
|
* created without --yes, and writes require GITHUB_TOKEN (or GH_TOKEN).
|
|
30
31
|
*/
|
|
31
|
-
import { parseIssueUrl, buildIssueSnapshot, scanCandidates, RateLimitError, fetchComments, apiCallsUsed, } from "./github.js";
|
|
32
|
+
import { parseIssueUrl, buildIssueSnapshot, scanCandidates, RateLimitError, fetchComments, apiCallsUsed, resolveCanonicalRepo, } from "./github.js";
|
|
32
33
|
import { xrayIssue, xrayIssues, sortXrayResults, applyXrayDemotion } from "./xray.js";
|
|
33
34
|
import { CLAIM_MARKER } from "./protocol.js";
|
|
34
35
|
import { llmEnabled, llmModelId } from "./llm-claims.js";
|
|
@@ -64,6 +65,7 @@ import { detectBehavioralGate } from "./behavior.js";
|
|
|
64
65
|
import { viaApiClaim, viaApiRelease, viaApiHeartbeat, deviceFlowLogin, browserLoginFlow, defaultTokenStore, } from "./claim-api.js";
|
|
65
66
|
import { buildEvidencePack } from "./evidence.js";
|
|
66
67
|
import { buildPassport } from "./passport.js";
|
|
68
|
+
import { detectBountyForIssue } from "./bounty.js";
|
|
67
69
|
import { renderLabelsDryRun } from "./guard.js";
|
|
68
70
|
import { writeFileSync } from "node:fs";
|
|
69
71
|
import { createRequire } from "node:module";
|
|
@@ -151,7 +153,14 @@ function loadExternalGates(args) {
|
|
|
151
153
|
}
|
|
152
154
|
}
|
|
153
155
|
async function cmdCheck(issueUrl, asJson, args) {
|
|
154
|
-
const
|
|
156
|
+
const parsed = parseIssueUrl(issueUrl);
|
|
157
|
+
// v0.18.0 (item 15): resolve renames before any name-based fetch.
|
|
158
|
+
const canon = await resolveCanonicalRepo(parsed.owner, parsed.repo);
|
|
159
|
+
const { owner, repo } = canon;
|
|
160
|
+
const number = parsed.number;
|
|
161
|
+
const renameNote = canon.renamed
|
|
162
|
+
? `repo renamed: ${parsed.owner}/${parsed.repo} -> ${canon.fullName}`
|
|
163
|
+
: null;
|
|
155
164
|
// The check pipeline merges the legacy verdict with the Claim Protocol
|
|
156
165
|
// state: a protocol claim verdict overrides legacy claim inference, but
|
|
157
166
|
// never gates or cross-referenced PR evidence (see mergeProtocolVerdict).
|
|
@@ -194,9 +203,12 @@ async function cmdCheck(issueUrl, asJson, args) {
|
|
|
194
203
|
llm_claims: merged.llm_claims ?? [],
|
|
195
204
|
llm_status: merged.llm_status ?? null,
|
|
196
205
|
suggestion,
|
|
206
|
+
renamedFrom: renameNote ? `${parsed.owner}/${parsed.repo}` : null,
|
|
197
207
|
}, null, 2));
|
|
198
208
|
return;
|
|
199
209
|
}
|
|
210
|
+
if (renameNote)
|
|
211
|
+
console.log(renameNote);
|
|
200
212
|
printVerdict(snapshot, result, false);
|
|
201
213
|
for (const line of merged.protocolLines)
|
|
202
214
|
console.log(` ${line}`);
|
|
@@ -247,7 +259,14 @@ async function cmdStatus(issueUrl, asJson) {
|
|
|
247
259
|
}
|
|
248
260
|
}
|
|
249
261
|
async function cmdScan(repoRef, asJson, args) {
|
|
250
|
-
const
|
|
262
|
+
const parsed = parseRepoRef(repoRef);
|
|
263
|
+
// v0.18.0 (item 15): the old name 422s the candidate search; resolve
|
|
264
|
+
// first and say so in the output.
|
|
265
|
+
const canon = await resolveCanonicalRepo(parsed.owner, parsed.repo);
|
|
266
|
+
const { owner, repo } = canon;
|
|
267
|
+
const scanRenameNote = canon.renamed ? `repo renamed: ${parsed.owner}/${parsed.repo} -> ${canon.fullName}` : null;
|
|
268
|
+
if (scanRenameNote && !asJson)
|
|
269
|
+
console.log(scanRenameNote);
|
|
251
270
|
const { issues, fallbackUsed } = await scanCandidates(owner, repo, {
|
|
252
271
|
fallback: !args.includes("--no-fallback"),
|
|
253
272
|
limit: 10,
|
|
@@ -322,7 +341,7 @@ async function cmdScan(repoRef, asJson, args) {
|
|
|
322
341
|
results.sort((a, b) => (rank[a.verdict] ?? 9) - (rank[b.verdict] ?? 9));
|
|
323
342
|
}
|
|
324
343
|
if (asJson) {
|
|
325
|
-
console.log(JSON.stringify({ repo: `${owner}/${repo}`, fallback: fallbackUsed, results }, null, 2));
|
|
344
|
+
console.log(JSON.stringify({ repo: `${owner}/${repo}`, renamedFrom: canon.renamed ? `${parsed.owner}/${parsed.repo}` : null, fallback: fallbackUsed, results }, null, 2));
|
|
326
345
|
return;
|
|
327
346
|
}
|
|
328
347
|
console.log(`Scan of ${owner}/${repo}: ${results.length} candidate issues, GO first`);
|
|
@@ -413,7 +432,9 @@ async function cmdFriction(repoRef, asJson, args = []) {
|
|
|
413
432
|
console.log(JSON.stringify(report, null, 2));
|
|
414
433
|
return;
|
|
415
434
|
}
|
|
416
|
-
console.log(`Friction for ${owner}/${repo}: ${report.score}/100 (100 = easiest)`);
|
|
435
|
+
console.log(`Friction for ${report.owner}/${report.repo}: ${report.score}/100 (100 = easiest)`);
|
|
436
|
+
if (report.resolvedFrom)
|
|
437
|
+
console.log(` repo renamed: ${report.resolvedFrom} -> ${report.owner}/${report.repo}`);
|
|
417
438
|
for (const reason of report.reasons)
|
|
418
439
|
console.log(` - ${reason}`);
|
|
419
440
|
if (report.reasons.length === 0)
|
|
@@ -1281,6 +1302,38 @@ async function cmdPassport(login, args) {
|
|
|
1281
1302
|
console.log(passport.markdown);
|
|
1282
1303
|
}
|
|
1283
1304
|
}
|
|
1305
|
+
/**
|
|
1306
|
+
* `greenlight bounty <issue-url>` (v0.18.0, item 23): is the bounty this
|
|
1307
|
+
* issue advertises actually alive? The classifier never raises a
|
|
1308
|
+
* verdict: bounties are context, not landability. What it kills is
|
|
1309
|
+
* chasing a dead platform (algora has been dead since 2025; thousands
|
|
1310
|
+
* of issues still wear its labels).
|
|
1311
|
+
*/
|
|
1312
|
+
async function cmdBounty(issueUrl, args) {
|
|
1313
|
+
const { owner, repo, number } = parseIssueUrl(issueUrl);
|
|
1314
|
+
const result = await detectBountyForIssue(owner, repo, number);
|
|
1315
|
+
if (args.includes("--json")) {
|
|
1316
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
if (!result.signal) {
|
|
1320
|
+
console.log(`No bounty advertised on ${result.repo}#${number} ("${result.title}").`);
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
const s = result.signal;
|
|
1324
|
+
const head = s.amount ? `Bounty: ${s.amount}` : "Bounty advertised";
|
|
1325
|
+
const via = s.platform ? ` via ${s.platform}` : " (no platform named)";
|
|
1326
|
+
console.log(`${head}${via} on ${result.repo}#${number}`);
|
|
1327
|
+
if (s.flag === "bounty-platform-dead") {
|
|
1328
|
+
console.log(` DEAD PLATFORM: ${s.evidence}`);
|
|
1329
|
+
}
|
|
1330
|
+
else if (s.flag === "bounty-unverified") {
|
|
1331
|
+
console.log(` UNVERIFIED: ${s.evidence}`);
|
|
1332
|
+
}
|
|
1333
|
+
else {
|
|
1334
|
+
console.log(` platform is named and not known-dead; verify terms on the platform before counting on payment`);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1284
1337
|
async function cmdDigest(repoRef, args) {
|
|
1285
1338
|
const asJson = args.includes("--json");
|
|
1286
1339
|
const limitRaw = flagValue(args, "--limit");
|
|
@@ -1587,6 +1640,8 @@ async function main() {
|
|
|
1587
1640
|
return await cmdEvidence(target, args);
|
|
1588
1641
|
if (command === "passport" && target)
|
|
1589
1642
|
return await cmdPassport(target, args);
|
|
1643
|
+
if (command === "bounty" && target)
|
|
1644
|
+
return await cmdBounty(target, args);
|
|
1590
1645
|
if (command && NEEDS_TARGET[command]) {
|
|
1591
1646
|
// Known command with a missing argument: name the need and show its
|
|
1592
1647
|
// help, instead of the generic overview.
|