@reneturcios/greenlight 0.12.0 → 0.14.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 +19 -2
- package/dist/ci-prep.d.ts +109 -0
- package/dist/ci-prep.js +768 -0
- package/dist/ci-prep.js.map +1 -0
- package/dist/cli.js +106 -3
- package/dist/cli.js.map +1 -1
- package/dist/github.js +5 -1
- package/dist/github.js.map +1 -1
- package/dist/help.js +32 -2
- package/dist/help.js.map +1 -1
- package/dist/index.js +65 -4
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/xray.d.ts +52 -0
- package/dist/xray.js +213 -0
- package/dist/xray.js.map +1 -0
- package/package.json +1 -1
- package/server.json +3 -6
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ One command sets it up:
|
|
|
18
18
|
npx @reneturcios/greenlight init --agent claude-code
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
(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
|
|
21
|
+
(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 24 tools (check_issue, scan_repo, repo_friction, claim_issue, prep_issue, open_pr, ci_triage, review_triage, guard_pr, repo_digest, claim_status, preflight, verify_comment, babysit_prs, evidence_pack, scout_campaign, my_claims, sync_campaign, campaign_portfolio, autopilot_report, api_status, claim_via_api, heartbeat_via_api, xray_issues).
|
|
22
22
|
|
|
23
23
|
## The problem
|
|
24
24
|
|
|
@@ -134,6 +134,10 @@ npx @reneturcios/greenlight check https://github.com/batrapulkit/squidbrake/issu
|
|
|
134
134
|
# unassigned issues when the repo does not use those labels; --no-fallback to opt out)
|
|
135
135
|
npx @reneturcios/greenlight scan PrefectHQ/fastmcp
|
|
136
136
|
|
|
137
|
+
# Deep-verify candidates against their timelines first (catches hidden in-flight PRs)
|
|
138
|
+
npx @reneturcios/greenlight xray usebruno/bruno --issues 8149,9319
|
|
139
|
+
npx @reneturcios/greenlight scan usebruno/bruno --deep
|
|
140
|
+
|
|
137
141
|
# Friction score for a repo
|
|
138
142
|
npx @reneturcios/greenlight friction triggerdotdev/trigger.dev
|
|
139
143
|
|
|
@@ -149,6 +153,14 @@ npx @reneturcios/greenlight ci https://github.com/reticlehq/reticle/pull/1620
|
|
|
149
153
|
# JSON output for scripting
|
|
150
154
|
npx @reneturcios/greenlight ci <pr-url> --json
|
|
151
155
|
|
|
156
|
+
# CI pre-flight: run a repo's own PR checks locally before pushing (exit 1 on NO-GO)
|
|
157
|
+
npx @reneturcios/greenlight ci-prep ~/work/bruno
|
|
158
|
+
|
|
159
|
+
# [PASS] tests (workflow ci, job build)
|
|
160
|
+
# [SKIPPED] publish (workflow release, job release) - publishes a package
|
|
161
|
+
# [PASS] convention: DCO sign-off
|
|
162
|
+
# Verdict: GO
|
|
163
|
+
|
|
152
164
|
# Review triage for a PR with review feedback: which comments need you?
|
|
153
165
|
npx @reneturcios/greenlight review https://github.com/n8n-io/n8n/pull/41235
|
|
154
166
|
|
|
@@ -276,6 +288,10 @@ The Agent Policy Index field work kept finding agent bans Greenlight itself miss
|
|
|
276
288
|
- **Scoped bans dual-class instead of collapsing.** A ban aimed at one kind of agent operation (TypeScript's "bulk, agent-driven contributions", ppt-master's "purely AI-generated PRs submitted without human review") now surfaces as both `agents_banned` for autonomous operation and `agents_disclosure` for the human-led path. An explicit prohibition (nuxt, ripgrep, zed) still stands on its own, and explicit welcome or waiver language (hyperframes welcomes AI help and waives disclosure) never reads as a ban.
|
|
277
289
|
- **Friction JSON states its units.** `friction --json` now carries `outsider_merge_share` (0 to 1 fraction) and `outsider_merge_share_pct` (0 to 100), plus `signals.externalPRMergeRate_pct` next to the existing fraction field. The human-readable output is unchanged.
|
|
278
290
|
|
|
291
|
+
### v0.13.0: Timeline X-Ray
|
|
292
|
+
|
|
293
|
+
`greenlight xray` deep-verifies candidate issues against their GitHub timelines: the linked-PR walk (timeline + search) with linkStrength scoring, reporter-owned-PR detection, and a lazy comment-claim scan, at ~4 API calls per issue. `scan --deep` demotes anything the x-ray finds taken before presenting results. New MCP tool `xray_issues`; `scan_repo` gains `deep`. Born from a Bruno focus session where 6 of 7 hand-vetted issues turned out to be secretly taken by timeline-only PRs.
|
|
294
|
+
|
|
279
295
|
### v0.12.0: the Claim Protocol GitHub App client
|
|
280
296
|
|
|
281
297
|
One command claims now: `greenlight claim <issue-url> --via-api` posts through the hosted claim API instead of handing you a comment to paste. `greenlight auth login` runs the GitHub device flow once and stores the token in your OS keychain (or `~/.greenlight/api-token` at 0600 when no keychain is available); `--token` / `GREENLIGHT_API_TOKEN` covers scripts. Before any `--via-api` write, the client checks whether the Greenlight Claims app is installed on the repo: installed means the claim goes through the app backend (durable state recorded via webhooks); not installed means the current direct-API comment path with a printed one-line note saying so. The downgrade is never silent. The flow is honest end to end: a hosted status read runs the TAKEN pre-flight (refuses on another holder unless `--queue-ok`), the posted comment is verified by re-reading the status, and a 401 re-runs the device flow once before printing the manual steps. `greenlight release --via-api` and `greenlight heartbeat --via-api` cover the rest of the lifecycle. The MCP server grows to 23 tools with `api_status`, `claim_via_api`, and `heartbeat_via_api` (all report-mode-safe).
|
|
@@ -325,7 +341,7 @@ The same engine is exposed over stdio for coding agents (Claude, Cursor, Cline).
|
|
|
325
341
|
Tools:
|
|
326
342
|
|
|
327
343
|
* `check_issue` - verdict for one issue URL
|
|
328
|
-
* `scan_repo` - rank a repo's open issues, GO first (label-tagged starter issues, falling back to recent open unassigned issues)
|
|
344
|
+
* `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)
|
|
329
345
|
* `repo_friction` - friction score for a repo
|
|
330
346
|
* `claim_issue` - verdict-gated claim comment (dry run unless `execute: true`)
|
|
331
347
|
* `prep_issue` - fork and branch check plus a local PREP.md checklist with the repo's learned conventions (dry run unless `execute: true`)
|
|
@@ -339,6 +355,7 @@ Tools:
|
|
|
339
355
|
* `verify_comment` - draft the verified-finding comment for maintainer-only repos (draft only, never posts)
|
|
340
356
|
* `babysit_prs` - watch open PRs and get the one prioritized action list (needs you now, waiting on them, quiet), diffed against stored watermarks; also watches the my-claims registry (linked, healthy-active, heartbeat-due, expiring, unlinked-stale, queue-lost)
|
|
341
357
|
* `evidence_pack` - the Verified PR evidence pack for one PR: guard verdict, CI triage, review triage, protocol status of linked issues, every claim citing its source
|
|
358
|
+
* `xray_issues` - Timeline X-Ray: deep-verify candidate issues against their timelines (hidden in-flight PRs, reporter-owned fix PRs, comment claims); GO / RISKY / TAKEN per issue with PR evidence
|
|
342
359
|
|
|
343
360
|
Run it locally: `npm run dev` (MCP entry is `src/index.ts`; CLI is `src/cli.ts`).
|
|
344
361
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI Pre-flight (`greenlight ci-prep` / MCP `ci_prep`).
|
|
3
|
+
*
|
|
4
|
+
* Answers one question with evidence, BEFORE a PR is pushed: would this
|
|
5
|
+
* repo's own pull_request workflows pass on the current tree?
|
|
6
|
+
*
|
|
7
|
+
* Pipeline:
|
|
8
|
+
* 1. DISCOVER: parse .github/workflows/*.yml for workflows triggered on
|
|
9
|
+
* pull_request / pull_request_target; extract jobs and steps.
|
|
10
|
+
* 2. MAP + RUN (native mode): translate each step into a local check.
|
|
11
|
+
* Steps that map to package scripts or common binaries (test, lint,
|
|
12
|
+
* typecheck, build) are EXECUTED with a per-step timeout. Steps that
|
|
13
|
+
* cannot run locally (deploys, secrets, external services, publishes)
|
|
14
|
+
* are SKIPPED with the reason named. A check is never reported PASS
|
|
15
|
+
* unless it actually ran.
|
|
16
|
+
* 3. CONVENTIONS: changeset requirement, conventional-commit subjects,
|
|
17
|
+
* and DCO sign-off are checked against git history when the repo
|
|
18
|
+
* signals that it requires them.
|
|
19
|
+
* 4. ACT MODE (--act): when `act` and a working docker daemon are both
|
|
20
|
+
* present, the discovered PR workflows run through `act` for real;
|
|
21
|
+
* otherwise the tool says so plainly and falls back to native mode.
|
|
22
|
+
*
|
|
23
|
+
* Honesty contract (same as verify.ts): this would rather say SKIPPED with
|
|
24
|
+
* a reason than report a verdict it cannot defend. Verdict is GO only
|
|
25
|
+
* when zero checks FAIL.
|
|
26
|
+
*/
|
|
27
|
+
export type CiPrepStatus = "PASS" | "FAIL" | "SKIPPED";
|
|
28
|
+
export interface CiPrepCheck {
|
|
29
|
+
/** e.g. "test (workflow ci, job build)" or "convention: changesets". */
|
|
30
|
+
name: string;
|
|
31
|
+
kind: "workflow-step" | "convention" | "act";
|
|
32
|
+
status: CiPrepStatus;
|
|
33
|
+
/** One-line evidence: exit code, timing, or the skip reason. */
|
|
34
|
+
detail: string;
|
|
35
|
+
/** Last ~30 lines of captured output when the step was executed. */
|
|
36
|
+
outputTail?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface CiPrepResult {
|
|
39
|
+
repoDir: string;
|
|
40
|
+
base: string | null;
|
|
41
|
+
verdict: "GO" | "NO-GO";
|
|
42
|
+
actMode: "used" | "unavailable" | "not-requested";
|
|
43
|
+
checks: CiPrepCheck[];
|
|
44
|
+
markdown: string;
|
|
45
|
+
}
|
|
46
|
+
export interface CiPrepOptions {
|
|
47
|
+
/** Base ref for convention checks (changesets/commits/DCO). */
|
|
48
|
+
base?: string;
|
|
49
|
+
/** Per-step execution timeout in seconds (default 300). */
|
|
50
|
+
timeoutSecs?: number;
|
|
51
|
+
/** Try act+docker; fall back to native mode when unavailable. */
|
|
52
|
+
useAct?: boolean;
|
|
53
|
+
/** Test seam: override the detected package manager. */
|
|
54
|
+
packageManager?: string;
|
|
55
|
+
/** Test seam: override act/docker detection. */
|
|
56
|
+
actAvailable?: boolean;
|
|
57
|
+
}
|
|
58
|
+
type YamlNode = string | number | boolean | null | YamlNode[] | {
|
|
59
|
+
[k: string]: YamlNode;
|
|
60
|
+
};
|
|
61
|
+
/** Parse a GitHub Actions workflow file into a plain object tree. Throws on structural problems. */
|
|
62
|
+
export declare function parseWorkflowYaml(text: string): Record<string, YamlNode>;
|
|
63
|
+
export interface WorkflowStep {
|
|
64
|
+
name: string;
|
|
65
|
+
uses?: string;
|
|
66
|
+
run?: string;
|
|
67
|
+
if?: string;
|
|
68
|
+
workingDirectory?: string;
|
|
69
|
+
}
|
|
70
|
+
export interface WorkflowJob {
|
|
71
|
+
id: string;
|
|
72
|
+
name: string;
|
|
73
|
+
steps: WorkflowStep[];
|
|
74
|
+
matrix?: string;
|
|
75
|
+
}
|
|
76
|
+
export interface DiscoveredWorkflow {
|
|
77
|
+
file: string;
|
|
78
|
+
jobs: WorkflowJob[];
|
|
79
|
+
/** Why this workflow was skipped entirely (unparseable, no PR trigger). */
|
|
80
|
+
skipReason?: string;
|
|
81
|
+
}
|
|
82
|
+
/** Does this workflow run on pull_request / pull_request_target? */
|
|
83
|
+
export declare function triggersOnPullRequest(doc: Record<string, YamlNode>): boolean;
|
|
84
|
+
export declare function discoverWorkflows(dir: string): DiscoveredWorkflow[];
|
|
85
|
+
export type StepMapping = {
|
|
86
|
+
kind: "execute";
|
|
87
|
+
script: string;
|
|
88
|
+
} | {
|
|
89
|
+
kind: "skip";
|
|
90
|
+
reason: string;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Decide what to do with a `run:` step. Conservative by design: anything
|
|
94
|
+
* that is not clearly a local test/lint/build invocation, or that touches
|
|
95
|
+
* secrets/publishes/deploys, becomes SKIPPED with a named reason.
|
|
96
|
+
*/
|
|
97
|
+
export declare function mapRunStep(script: string): StepMapping;
|
|
98
|
+
export declare function mapUsesStep(uses: string): StepMapping;
|
|
99
|
+
/** Push-only / main-only `if:` conditions make a step irrelevant to PRs. */
|
|
100
|
+
export declare function isPushOnlyCondition(ifExpr: string): boolean;
|
|
101
|
+
export declare function detectPackageManager(dir: string, override?: string): string | null;
|
|
102
|
+
export declare function actAvailable(): boolean;
|
|
103
|
+
export declare function runCiPrep(targetDir: string, opts?: CiPrepOptions): Promise<CiPrepResult>;
|
|
104
|
+
export declare function renderCiPrepMarkdown(r: CiPrepResult): string;
|
|
105
|
+
/** Human-readable console rendering (the --json flag prints the raw result). */
|
|
106
|
+
export declare function formatCiPrepHuman(r: CiPrepResult): string;
|
|
107
|
+
/** Ensure the tmp fixture helper can create scratch dirs outside the repo. */
|
|
108
|
+
export declare function scratchDir(prefix: string): string;
|
|
109
|
+
export {};
|