@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 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 17 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).
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 {};