@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.
- package/LICENSE +21 -0
- package/README.md +213 -2
- package/dist/automate.d.ts +184 -0
- package/dist/automate.js +637 -0
- package/dist/automate.js.map +1 -0
- package/dist/claims.d.ts +20 -0
- package/dist/claims.js +112 -0
- package/dist/claims.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +337 -0
- package/dist/cli.js.map +1 -0
- package/dist/friction-index.d.ts +1 -0
- package/dist/friction-index.js +152 -0
- package/dist/friction-index.js.map +1 -0
- package/dist/friction.d.ts +28 -0
- package/dist/friction.js +54 -0
- package/dist/friction.js.map +1 -0
- package/dist/gates.d.ts +51 -0
- package/dist/gates.js +198 -0
- package/dist/gates.js.map +1 -0
- package/dist/github.d.ts +155 -0
- package/dist/github.js +531 -0
- package/dist/github.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +173 -0
- package/dist/index.js.map +1 -0
- package/dist/linkstrength.d.ts +27 -0
- package/dist/linkstrength.js +25 -0
- package/dist/linkstrength.js.map +1 -0
- package/dist/types.d.ts +131 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/verdict.d.ts +64 -0
- package/dist/verdict.js +220 -0
- package/dist/verdict.js.map +1 -0
- package/package.json +39 -3
- package/server.json +28 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rene Turcios
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,214 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Greenlight
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Greenlight checks a GitHub issue before you spend hours on it, and tells you in plain words whether your pull request is likely to land.
|
|
4
|
+
|
|
5
|
+
## The problem
|
|
6
|
+
|
|
7
|
+
You find an issue that looks perfect. You code all evening. Then one of these happens:
|
|
8
|
+
|
|
9
|
+
* Someone already claimed the work in a comment. The issue still says "unassigned", but three volunteers wrote "I'll take this" weeks ago and you never saw it.
|
|
10
|
+
* The repo wanted you to ask first. Your pull request gets closed because the maintainers require contributors to request assignment or get a vouch (a recommendation from someone they know) before anyone may open a PR, and nobody told you.
|
|
11
|
+
* Your commits get rejected on a technicality. The repo requires a "Signed-off-by" line on every commit (called DCO sign-off, short for Developer Certificate of Origin) or an entry in its changelog folder, and you find out after you push.
|
|
12
|
+
|
|
13
|
+
These are all contribution rituals: unwritten rules a repo expects before an outside pull request counts. Every repo has different ones, and they hide in different places, from CONTRIBUTING files to AGENTS.md house-rules files (plain-language instruction files that tell people and coding agents how to work in that repo). We hit all of these by hand while vetting real issues, so Greenlight automates the checking.
|
|
14
|
+
|
|
15
|
+
## What Greenlight does
|
|
16
|
+
|
|
17
|
+
One engine, four plain steps:
|
|
18
|
+
|
|
19
|
+
1. **Check before you claim.** Point it at any issue URL. It reads the issue, its comments, linked and mentioned pull requests, and the repo's rules, then answers: GO (yours to take), RISKY (possible, but know this first), TAKEN (someone is on it), GATED (a repo rule blocks you), or STALE (abandoned). It also spots partially-claimed work and issues where half the fix already shipped, so you scope to what remains.
|
|
20
|
+
2. **Claim the right way.** It drafts the claim comment in the form the repo's rules actually want: a plain "I'll work on this" where that is enough, an assignment request where the repo requires one, or a refusal where a vouch is needed (no tool can vouch for you). It never posts without your say-so.
|
|
21
|
+
3. **Prep your workspace with the repo's own rules.** It sets up your fork and branch, then writes a checklist that includes what it learned from the repo itself: the house-rules files, the verify command they insist on, whether the repo wants a changelog entry, and how its commits are styled.
|
|
22
|
+
4. **Open the PR only when the basics pass.** It checks the branch is really ahead of the repo, and on repos that require DCO sign-off it verifies every commit carries the Signed-off-by line before it opens the pull request.
|
|
23
|
+
|
|
24
|
+
## Use it when
|
|
25
|
+
|
|
26
|
+
* You found an issue you like and are about to spend real time on it.
|
|
27
|
+
* You want to know if an issue is really still yours to finish, or whether someone quietly claimed part of it in a comment.
|
|
28
|
+
* A repo's rules are unclear and you want to see them summarized before you start.
|
|
29
|
+
* You claimed something a while ago and want to know if that claim still counts.
|
|
30
|
+
* You are picking between several repos or issues and want the most winnable one first.
|
|
31
|
+
|
|
32
|
+
## What it does, technically
|
|
33
|
+
|
|
34
|
+
One engine, four surfaces:
|
|
35
|
+
|
|
36
|
+
1. **Availability verdicts** for an issue: `GO`, `RISKY`, `TAKEN`, `GATED`, `STALE`. Signals: assignees, linked open/closed/merged PRs (timeline + search + comment references), claim-comment heuristics including scoped claims (phrases like "please assign", "working on this", "taking the remaining fallback ask"), partially-addressed detection (merged PRs that reference the issue, maintainer comments like "half addressed ... leaving this open"), issue age and last activity.
|
|
37
|
+
2. **Repo friction scores** (0-100, 100 = easiest): contribution gates parsed from CONTRIBUTING variants plus house-rules files (`AGENTS.md`, `CLAUDE.md`), with each gate recording which file its evidence came from (assignment-first, vouch, CLA, DCO, discussion-first, comment-first, collaborators-only), plus outcome signals where computable.
|
|
38
|
+
3. **Scan mode**: rank a repo's open good-first-issue / help-wanted issues by verdict so a contributor (or agent) picks a winnable one first. Falls back to recent open unassigned issues when a repo has no labeled starter issues.
|
|
39
|
+
4. **Contribution automation**: `claim`, `prep`, and `pr` commands (plus matching MCP tools) that run the pipeline after the verdict. All writes are dry-run by default and need a token plus an explicit go flag.
|
|
40
|
+
|
|
41
|
+
A validation corpus of ten real cases from the campaign (`test/fixtures/cases/`, run by `test/cases.test.ts`) pins every verdict rule to something that actually happened: a taken issue, a weak PR mention, claim-first gates, assignment and vouch gates, a scoped claim, a half-shipped issue, a clean GO, and a stale claim.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx @reneturcios/greenlight check <issue-url>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or from source:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install
|
|
53
|
+
npm run build
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Set `GITHUB_TOKEN` (a classic personal access token, no scopes needed for public repos) to raise the GitHub API rate limit from 60 to 5000 requests per hour. Greenlight caches API responses under `~/.cache/greenlight`.
|
|
57
|
+
|
|
58
|
+
Run the MCP server with `npx @reneturcios/greenlight mcp` (stdio), or point your agent at the `greenlight` command with the single argument `mcp`.
|
|
59
|
+
|
|
60
|
+
## The toolkit
|
|
61
|
+
|
|
62
|
+
Greenlight is the front door of a four-tool lifecycle for open-source contribution work, all published under the same npm scope and cross-wired:
|
|
63
|
+
|
|
64
|
+
1. **gatefile** (`npx @reneturcios/gatefile extract owner/repo`) extracts a repo's contribution gates into a committed `contribution-gates.json`. Greenlight consumes that file directly: `greenlight check <issue-url> --gates-file contribution-gates.json`, or automatically when the file sits in the working directory, so gates are answered once and reused instead of re-derived from prose.
|
|
65
|
+
2. **greenlight** verdicts, scans, claims, prep, and PR opening (this tool).
|
|
66
|
+
3. **claimcheck** (`npx @reneturcios/claimcheck claims owner/repo`) watches claimed issues for stale claims and finished fixes parked on forks, the two ways claimed work silently dies.
|
|
67
|
+
4. **prwatch** (`npx @reneturcios/prwatch attention --user you`) triages your open PRs by what needs you right now: review threads, failing checks, conflicts, reviewer silence.
|
|
68
|
+
|
|
69
|
+
Each tool is a CLI and an MCP server (`<tool> mcp`).
|
|
70
|
+
|
|
71
|
+
## CLI
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Verdict for one issue
|
|
75
|
+
npx @reneturcios/greenlight check https://github.com/batrapulkit/squidbrake/issues/74
|
|
76
|
+
|
|
77
|
+
# [GO] batrapulkit/squidbrake#74
|
|
78
|
+
# Taint: tell the approver when an agent edits its own setup right after reading outside content
|
|
79
|
+
# - open, unassigned, no linked PRs, no claim signals, no blocking gates
|
|
80
|
+
|
|
81
|
+
# Rank a repo's starter issues, GO first (falls back to recent open
|
|
82
|
+
# unassigned issues when the repo does not use those labels; --no-fallback to opt out)
|
|
83
|
+
npx @reneturcios/greenlight scan PrefectHQ/fastmcp
|
|
84
|
+
|
|
85
|
+
# Friction score for a repo
|
|
86
|
+
npx @reneturcios/greenlight friction triggerdotdev/trigger.dev
|
|
87
|
+
|
|
88
|
+
# JSON output for scripting
|
|
89
|
+
npx @reneturcios/greenlight check <issue-url> --json
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Real examples from our vetting:
|
|
93
|
+
|
|
94
|
+
* `batrapulkit/squidbrake#74` scores **GO**: 0 comments, labeled help wanted, no claims, no gates.
|
|
95
|
+
* `shadcn-labs/pdfcn#58` scores **RISKY** (claimed flag): a volunteer asked for assignment the same day we vetted it.
|
|
96
|
+
* `langchain-ai/langchain#41185` scores **TAKEN** (claim race): 3 strong claimants while still "unassigned".
|
|
97
|
+
* `PrefectHQ/fastmcp#5718` scores **GATED**: FastMCP requires assignment or a "prs welcome" label before a PR.
|
|
98
|
+
* `triggerdotdev/trigger.dev#5016` scores **GATED**: unvouched-author PRs are auto-closed, a vouch request goes first.
|
|
99
|
+
|
|
100
|
+
## How scoring works
|
|
101
|
+
|
|
102
|
+
The verdict engine is deterministic (no LLM) and checks, in order:
|
|
103
|
+
|
|
104
|
+
1. Closed issue: **TAKEN** (never landable).
|
|
105
|
+
2. Any assignee: **TAKEN**.
|
|
106
|
+
3. An open linked PR that **closes** the issue: **TAKEN**. A PR that merely mentions the issue number (like pdfcn PR #91, which closes #70 but lists sibling issues in its body) only adds a `weak-pr-mention` flag and downgrades an otherwise-GO verdict to **RISKY**.
|
|
107
|
+
4. Two or more strong claimants: **TAKEN** (claim race).
|
|
108
|
+
5. One strong fresh whole-issue claim (under 45 days): **RISKY** with the `claimed` flag. A fresh claim scoped to part of the issue ("taking the remaining fallback ask"): **RISKY** with `claimed` + `partial-claim` flags and a reason naming the claimer and the scope, never TAKEN.
|
|
109
|
+
6. One strong claim older than 45 days with no closing PR: **RISKY** with the `stale_claim` flag. The claimant probably walked away, but nobody knows for sure. Stale scoped claims get the same treatment.
|
|
110
|
+
7. A hard gate (assignment, vouch, collaborators-only) with nobody assigned: **GATED**.
|
|
111
|
+
8. No activity for 180+ days: **STALE**.
|
|
112
|
+
9. A soft claim-first gate (the repo asks contributors to comment before starting, like pdfcn): never **GATED**; it caps an otherwise-GO verdict at **RISKY** with a note, the same downgrade shape as a weak PR mention.
|
|
113
|
+
10. Otherwise: **GO**.
|
|
114
|
+
11. An open PR referenced in a non-author comment whose title/body mentions the issue number: downgrades an otherwise-GO verdict to **RISKY** with the `comment-mentioned-pr` flag ("may already cover part of this issue"). Neither can produce **TAKEN**; only closing PRs do that.
|
|
115
|
+
12. **Partially-addressed**: merged PRs that reference the issue number (comment-mentioned or linked), or maintainer comments signaling part of the work already shipped ("Half addressed by #905, leaving this open for half B", "Shipped in v3.1.0" next to the issue reference). A plain **GO** hides the scoping work this needs, so the flag `partially-addressed` is added, an otherwise-GO verdict is capped at **RISKY** with a reason like "part of this issue already shipped (PR #905, merged); scope your work to what remains". Never **TAKEN**.
|
|
116
|
+
|
|
117
|
+
Claim detection scans comments for explicit claim phrases, in-progress signals ("fix ready", "PR incoming", "opened a PR"), and soft offers ("happy to fix"). Bot authors are ignored, as are issue reporters unless they announce a ready fix. Scoped claims ("taking the remaining fallback ask", "claiming this half") are recorded as partial: a fresh partial claim downgrades an otherwise-GO verdict to RISKY with a reason naming the claimer and the scope, never TAKEN. PR references (#NNN) in non-author comments are cross-checked against the PR API: an open referenced PR that mentions the issue downgrades GO to RISKY with the `comment-mentioned-pr` flag, and a merged one feeds rule 12 above.
|
|
118
|
+
|
|
119
|
+
Friction score starts at 100 and subtracts gate weights (assignment -25, vouch -35, collaborators-only -50, discussion-first -10, claim-first -5, CLA/DCO -5 each), 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.
|
|
120
|
+
|
|
121
|
+
## MCP server
|
|
122
|
+
|
|
123
|
+
The same engine is exposed over stdio for coding agents (Claude, Cursor, Cline). The wedge: agents waste the most tokens fixing already-taken issues. Have the agent pre-flight the issue before writing code.
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"mcpServers": {
|
|
128
|
+
"greenlight": {
|
|
129
|
+
"command": "npx",
|
|
130
|
+
"args": ["-y", "@reneturcios/greenlight", "mcp"],
|
|
131
|
+
"env": { "GITHUB_TOKEN": "your-token" }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Tools:
|
|
138
|
+
|
|
139
|
+
* `check_issue` - verdict for one issue URL
|
|
140
|
+
* `scan_repo` - rank a repo's open issues, GO first (label-tagged starter issues, falling back to recent open unassigned issues)
|
|
141
|
+
* `repo_friction` - friction score for a repo
|
|
142
|
+
* `claim_issue` - verdict-gated claim comment (dry run unless `execute: true`)
|
|
143
|
+
* `prep_issue` - fork and branch check plus a local PREP.md checklist with the repo's learned conventions (dry run unless `execute: true`)
|
|
144
|
+
* `open_pr` - DCO-aware PR opening from a fork branch (dry run unless `execute: true`)
|
|
145
|
+
|
|
146
|
+
Run it locally: `npm run dev` (MCP entry is `src/index.ts`; CLI is `src/cli.ts`).
|
|
147
|
+
|
|
148
|
+
## Automation
|
|
149
|
+
|
|
150
|
+
Greenlight 0.2.0 automates the contribution pipeline its author ran by hand
|
|
151
|
+
for four real PRs (shadcn-labs/pdfcn #92-#95): verdict, claim comment, fork
|
|
152
|
+
branch, and opening the PR, with DCO awareness throughout.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# 1. Claim the issue: verdict first, comment shaped by the repo's gates
|
|
156
|
+
greenlight claim https://github.com/shadcn-labs/pdfcn/issues/65
|
|
157
|
+
|
|
158
|
+
# 2. Prepare: fork/branch check (learning the repo's branch convention) plus a PREP.md checklist
|
|
159
|
+
greenlight prep https://github.com/shadcn-labs/pdfcn/issues/65 --dir /tmp/prep65
|
|
160
|
+
|
|
161
|
+
# 3. Open the PR from your fork branch (verifies DCO sign-off on DCO repos)
|
|
162
|
+
greenlight pr https://github.com/shadcn-labs/pdfcn/issues/65 --branch feat/quarterly-report-block
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Safety defaults, and this is a feature:
|
|
166
|
+
|
|
167
|
+
* **Dry run by default.** All three commands print exactly what they would
|
|
168
|
+
post or create and exit. Nothing is posted or created without `--yes`
|
|
169
|
+
(CLI) or `execute: true` (MCP).
|
|
170
|
+
* **Writes need a token.** Read ops work with no token at all. Write ops
|
|
171
|
+
require `GITHUB_TOKEN` (or `GH_TOKEN`); without one they print a clear
|
|
172
|
+
error naming the env var and exit non-zero.
|
|
173
|
+
* **Verdict-gated.** `claim` refuses TAKEN or STALE verdicts unless
|
|
174
|
+
`--force`, and refuses vouch-gated repos outright (a vouch cannot be
|
|
175
|
+
automated). Assignment-gated repos get an assignment request instead of
|
|
176
|
+
an intent comment; claim-first repos (comment before starting) get the
|
|
177
|
+
standard intent comment, which satisfies the ritual.
|
|
178
|
+
* **Repo-aware branch names.** `prep` reads the head branches of recent
|
|
179
|
+
closed PRs and follows a dominant convention (pdfcn's `feat/<slug>-block`)
|
|
180
|
+
while still showing the `feat/<slug>-<number>` default.
|
|
181
|
+
* **DCO-aware.** On DCO repos, `pr` verifies every commit on the branch
|
|
182
|
+
carries a `Signed-off-by:` line and refuses, listing the unsigned
|
|
183
|
+
commits, when one is missing.
|
|
184
|
+
* **Repo-aware prep.** `prep` also learns the repo's contribution rituals
|
|
185
|
+
for the PREP.md checklist: which house-rules files exist, the verify
|
|
186
|
+
command they insist on (like `pnpm verify`), whether the repo assembles
|
|
187
|
+
its changelog from a `.changes/` directory, which root package.json
|
|
188
|
+
scripts exist, and whether recent commits follow Conventional Commits.
|
|
189
|
+
Binding rules increasingly live in `AGENTS.md` rather than CONTRIBUTING,
|
|
190
|
+
and prep reads those too.
|
|
191
|
+
|
|
192
|
+
## The friction index
|
|
193
|
+
|
|
194
|
+
`data/friction-index.json` is a checked-in, growing dataset of scored repos. It starts with the MCP/AI ecosystem we hand-vetted on 2026-10-13 (FastMCP, trigger.dev, langchain, deepagents, openclaw, squidbrake, reticle, pdfcn, chatflow-agent, and the three MCP SDK repos). Regenerate it with `npm run index`.
|
|
195
|
+
|
|
196
|
+
Entries labeled `hand-verified 2026-10-13` come from reading the repos' actual policies and issue trackers by hand. Entries labeled `live` were parsed from live house-rules files (CONTRIBUTING variants, AGENTS.md, CLAUDE.md). Each gate records which file its evidence came from. Computed outcome fields (merge rates, review times) stay `null` until we can compute them honestly, never fabricated.
|
|
197
|
+
|
|
198
|
+
## Development
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
npm test # tsx --test, includes fixture tests that reproduce our real verdicts
|
|
202
|
+
npm run build
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Roadmap (Later)
|
|
206
|
+
|
|
207
|
+
* Browser extension that scores issues inline on github.com
|
|
208
|
+
* Hosted dashboard of the friction index, refreshed on a schedule
|
|
209
|
+
* Maintainer GitHub Action that auto-labels claim comments
|
|
210
|
+
* Parked-fix detection and auto-nudges: scan forks for branches referencing open issues and nudge when the gate is satisfied
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT. See LICENSE.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type { IssueSnapshot, VerdictResult, Gate, RepoConventions } from "./types.js";
|
|
2
|
+
/** Thrown when an automation command refuses to proceed. CLI exits 1 on this. */
|
|
3
|
+
export declare class AutomationRefusal extends Error {
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The write-capable GitHub surface automation needs. Implementations log
|
|
8
|
+
* nothing on their own; callers record what they did from the results.
|
|
9
|
+
*/
|
|
10
|
+
export interface GitHubClient {
|
|
11
|
+
getRepo(owner: string, repo: string): Promise<{
|
|
12
|
+
defaultBranch: string;
|
|
13
|
+
}>;
|
|
14
|
+
getViewer(): Promise<string>;
|
|
15
|
+
forkExists(viewer: string, repo: string): Promise<boolean>;
|
|
16
|
+
createFork(owner: string, repo: string): Promise<void>;
|
|
17
|
+
getBranchSha(viewer: string, repo: string, branch: string): Promise<string | undefined>;
|
|
18
|
+
createBranch(viewer: string, repo: string, branch: string, sha: string): Promise<void>;
|
|
19
|
+
compareCommits(owner: string, repo: string, base: string, headOwner: string, headBranch: string): Promise<{
|
|
20
|
+
aheadBy: number;
|
|
21
|
+
commits: Array<{
|
|
22
|
+
sha: string;
|
|
23
|
+
message: string;
|
|
24
|
+
}>;
|
|
25
|
+
}>;
|
|
26
|
+
/** Head branch names of recent closed PRs, used to learn the repo's branch convention. */
|
|
27
|
+
listClosedPullHeadRefs(owner: string, repo: string): Promise<string[]>;
|
|
28
|
+
/** Names of files and directories at the repo root (best-effort conventions detection). */
|
|
29
|
+
repoRootNames(owner: string, repo: string): Promise<string[]>;
|
|
30
|
+
/** Raw text of a repo-root file, or undefined when absent. */
|
|
31
|
+
fetchRootFile(owner: string, repo: string, path: string): Promise<string | undefined>;
|
|
32
|
+
/** First lines of the most recent commit messages on a branch. */
|
|
33
|
+
listRecentCommitMessages(owner: string, repo: string, branch: string, count: number): Promise<string[]>;
|
|
34
|
+
postIssueComment(owner: string, repo: string, number: number, body: string): Promise<string>;
|
|
35
|
+
createPullRequest(owner: string, repo: string, opts: {
|
|
36
|
+
title: string;
|
|
37
|
+
body: string;
|
|
38
|
+
head: string;
|
|
39
|
+
base: string;
|
|
40
|
+
}): Promise<string>;
|
|
41
|
+
}
|
|
42
|
+
/** Live REST implementation of GitHubClient. */
|
|
43
|
+
export declare function createRestClient(): GitHubClient;
|
|
44
|
+
/** Write commands need a token. Dry runs do not. */
|
|
45
|
+
export declare function requireWriteToken(): void;
|
|
46
|
+
/** Slugify an issue title: strip leading labels, lowercase, dashes, 40-char cap. */
|
|
47
|
+
export declare function titleSlug(title: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Branch name from an issue title: strip leading labels like "block:" or
|
|
50
|
+
* "feat:", slugify, cap at 40 chars, append the issue number.
|
|
51
|
+
* "block: Resume" -> "feat/resume-61"
|
|
52
|
+
*/
|
|
53
|
+
export declare function branchSlugFor(title: string, number: number): string;
|
|
54
|
+
/** A branch-name convention learned from a repo's recent closed PRs. */
|
|
55
|
+
export interface BranchPattern {
|
|
56
|
+
/** Dominant prefix before the "/", e.g. "feat". */
|
|
57
|
+
prefix: string;
|
|
58
|
+
/** Dominant trailing token of the branch rest, e.g. "block", or null. */
|
|
59
|
+
suffix: string | null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Learn a dominant branch naming pattern from recent closed PR head refs.
|
|
63
|
+
* Returns undefined when no prefix or suffix reaches the 3-branch
|
|
64
|
+
* threshold, so naming falls back to the default.
|
|
65
|
+
*/
|
|
66
|
+
export declare function detectBranchPattern(refs: string[]): BranchPattern | undefined;
|
|
67
|
+
export interface BranchSuggestion {
|
|
68
|
+
/** The branch name to use. */
|
|
69
|
+
branch: string;
|
|
70
|
+
/** The default name, for comparison when a pattern was found. */
|
|
71
|
+
defaultName: string;
|
|
72
|
+
/** Human-readable note about the learned pattern, empty when none. */
|
|
73
|
+
note: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Suggest a branch name, learning the repo's convention from recent closed
|
|
77
|
+
* PR head refs. A dominant suffix token (e.g. "-block" from
|
|
78
|
+
* feat/business-letter-block) replaces the issue number; a dominant
|
|
79
|
+
* prefix style replaces "feat/". Falls back to feat/<slug>-<number>.
|
|
80
|
+
*/
|
|
81
|
+
export declare function suggestBranchName(title: string, number: number, refs: string[]): BranchSuggestion;
|
|
82
|
+
/**
|
|
83
|
+
* Claim comment text shaped by the repo's gates. Assignment-gated repos get
|
|
84
|
+
* an assignment request and a promise not to start work early; every comment
|
|
85
|
+
* notes the comment-first convention; DCO repos get a sign-off commitment.
|
|
86
|
+
*/
|
|
87
|
+
export declare function buildClaimComment(snapshot: IssueSnapshot, gates: Gate[], viewer?: string): string;
|
|
88
|
+
/** Required actions checklist rendered from detected gates. */
|
|
89
|
+
export declare function gateActions(gates: Gate[]): string[];
|
|
90
|
+
export interface ClaimOptions {
|
|
91
|
+
yes: boolean;
|
|
92
|
+
force: boolean;
|
|
93
|
+
}
|
|
94
|
+
export interface ClaimResult {
|
|
95
|
+
verdict: VerdictResult;
|
|
96
|
+
commentBody: string;
|
|
97
|
+
commentUrl: string | null;
|
|
98
|
+
executed: boolean;
|
|
99
|
+
viewer: string | undefined;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* claim: verdict first, then post a claim comment shaped by the repo gates.
|
|
103
|
+
* Refuses on TAKEN or STALE verdicts unless forced, and refuses outright
|
|
104
|
+
* on vouch-gated repos (a vouch cannot be automated). Dry run by default.
|
|
105
|
+
*/
|
|
106
|
+
export declare function claimIssue(client: GitHubClient, snapshot: IssueSnapshot, opts: ClaimOptions): Promise<ClaimResult>;
|
|
107
|
+
/** Pure renderer for the PREP.md checklist file. */
|
|
108
|
+
export declare function renderPrepDoc(args: {
|
|
109
|
+
snapshot: IssueSnapshot;
|
|
110
|
+
verdict: VerdictResult;
|
|
111
|
+
gates: Gate[];
|
|
112
|
+
branch: string;
|
|
113
|
+
branchDefault?: string;
|
|
114
|
+
branchNote?: string;
|
|
115
|
+
viewer: string;
|
|
116
|
+
issueUrl: string;
|
|
117
|
+
conventions?: RepoConventions;
|
|
118
|
+
}): string;
|
|
119
|
+
export interface PrepOptions {
|
|
120
|
+
dir?: string;
|
|
121
|
+
yes: boolean;
|
|
122
|
+
}
|
|
123
|
+
export interface PrepResult {
|
|
124
|
+
verdict: VerdictResult;
|
|
125
|
+
branch: string;
|
|
126
|
+
branchDefault: string;
|
|
127
|
+
branchPatternNote: string;
|
|
128
|
+
forkReady: boolean;
|
|
129
|
+
forkCreated: boolean;
|
|
130
|
+
branchReady: boolean;
|
|
131
|
+
branchCreated: boolean;
|
|
132
|
+
prepFile: string;
|
|
133
|
+
nextCommands: string[];
|
|
134
|
+
/** Repo rituals learned during prep (best-effort; undefined when nothing was detectable). */
|
|
135
|
+
conventions?: RepoConventions;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Extract backticked run commands quoted in house-rules text, e.g. the
|
|
139
|
+
* `pnpm verify` reticle's AGENTS.md insists on. Returns them deduplicated,
|
|
140
|
+
* in order of appearance, capped at five.
|
|
141
|
+
*/
|
|
142
|
+
export declare function extractVerifyCommands(text: string): string[];
|
|
143
|
+
/**
|
|
144
|
+
* Learn the repo's contribution rituals for the PREP.md checklist:
|
|
145
|
+
* which house-rules files exist, the verify/test command they quote,
|
|
146
|
+
* whether the repo assembles its changelog from a .changes directory,
|
|
147
|
+
* which root package.json scripts exist, and whether recent commits
|
|
148
|
+
* follow Conventional Commits. Every probe is best-effort: a failing
|
|
149
|
+
* probe is skipped, never fatal.
|
|
150
|
+
*/
|
|
151
|
+
export declare function gatherRepoConventions(client: GitHubClient, snapshot: IssueSnapshot): Promise<RepoConventions | undefined>;
|
|
152
|
+
/**
|
|
153
|
+
* prep: verdict, fork check (create with --yes), branch naming and creation,
|
|
154
|
+
* and a local PREP.md checklist. Never clones; reports the clone command.
|
|
155
|
+
* Writes the PREP.md file in both dry-run and execute modes.
|
|
156
|
+
*/
|
|
157
|
+
export declare function prepIssue(client: GitHubClient, snapshot: IssueSnapshot, opts: PrepOptions): Promise<PrepResult>;
|
|
158
|
+
export interface PrOptions {
|
|
159
|
+
branch: string;
|
|
160
|
+
title?: string;
|
|
161
|
+
yes: boolean;
|
|
162
|
+
}
|
|
163
|
+
export interface PrResult {
|
|
164
|
+
verdict: VerdictResult;
|
|
165
|
+
branch: string;
|
|
166
|
+
head: string;
|
|
167
|
+
base: string;
|
|
168
|
+
title: string;
|
|
169
|
+
body: string;
|
|
170
|
+
checks: string[];
|
|
171
|
+
prUrl: string | null;
|
|
172
|
+
executed: boolean;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* pr: preconditions, DCO verification, then open the PR. Preconditions:
|
|
176
|
+
* the branch must exist on the fork and be at least one commit ahead of
|
|
177
|
+
* upstream's default branch. When the repo requires DCO, every ahead
|
|
178
|
+
* commit must carry a Signed-off-by line; the first unsigned commit is a
|
|
179
|
+
* hard refusal (this exact failure mode burned real review time). Dry run
|
|
180
|
+
* prints the composed PR without posting it.
|
|
181
|
+
*/
|
|
182
|
+
export declare function openPr(client: GitHubClient, snapshot: IssueSnapshot, opts: PrOptions): Promise<PrResult>;
|
|
183
|
+
/** PR body template: closes keyword, summary, and the checks at open time. */
|
|
184
|
+
export declare function composePrBody(snapshot: IssueSnapshot, result: VerdictResult, gates: Gate[]): string;
|