@reneturcios/greenlight 0.5.0 → 0.7.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.
@@ -0,0 +1,218 @@
1
+ /**
2
+ * The contributor passport. Reads the Claim Ledger's public API for the
3
+ * account's protocol claims (held, completed, expired, queued, over-cap)
4
+ * and the GitHub search API for merged PRs, and renders one honest page.
5
+ *
6
+ * If the Ledger has no file for the account, it says so plainly: a
7
+ * passport starts with your first protocol claim.
8
+ */
9
+ import { createRequire } from "node:module";
10
+ const GREENLIGHT_VERSION = (() => {
11
+ try {
12
+ return createRequire(import.meta.url)("../package.json").version;
13
+ }
14
+ catch {
15
+ return "unknown";
16
+ }
17
+ })();
18
+ export function ledgerBaseUrl() {
19
+ const env = process.env["GREENLIGHT_LEDGER_URL"];
20
+ return (env && env.trim().length > 0 ? env : "https://cloudcorprecords.github.io/claim-ledger").replace(/\/+$/, "");
21
+ }
22
+ /**
23
+ * Normalize a Ledger account payload defensively: the Ledger is our own
24
+ * API and its fields can drift, so unknown shapes degrade to empties
25
+ * rather than crashing. Whatever is normalized is stated as coming from
26
+ * the Ledger; whatever is absent is stated as absent.
27
+ */
28
+ export function normalizeAccount(login, raw) {
29
+ const empty = { login, activeClaims: [], queuedClaims: [], completedCount: null, expiredCount: null, overCap: null };
30
+ if (!raw || typeof raw !== "object")
31
+ return empty;
32
+ const r = raw;
33
+ const normClaim = (c) => {
34
+ if (!c || typeof c !== "object")
35
+ return null;
36
+ const o = c;
37
+ const repo = typeof o["repo"] === "string"
38
+ ? o["repo"]
39
+ : typeof o["owner"] === "string" && typeof o["repo_name"] === "string"
40
+ ? `${o["owner"]}/${o["repo_name"]}`
41
+ : "unknown/unknown";
42
+ const issue = typeof o["issue"] === "number" ? o["issue"] : typeof o["number"] === "number" ? o["number"] : 0;
43
+ return {
44
+ repo,
45
+ issue,
46
+ url: typeof o["url"] === "string" && o["url"]
47
+ ? o["url"]
48
+ : issue > 0 && repo !== "unknown/unknown"
49
+ ? `https://github.com/${repo}/issues/${issue}`
50
+ : "",
51
+ claimedAt: typeof o["claimed_at"] === "string" ? o["claimed_at"] : typeof o["claimedAt"] === "string" ? o["claimedAt"] : "",
52
+ expiresAt: typeof o["expires_at"] === "string" ? o["expires_at"] : typeof o["expiresAt"] === "string" ? o["expiresAt"] : "",
53
+ state: typeof o["state"] === "string" ? o["state"] : "active",
54
+ commentUrl: typeof o["comment_url"] === "string" ? o["comment_url"] : typeof o["commentUrl"] === "string" ? o["commentUrl"] : null,
55
+ };
56
+ };
57
+ const arr = (v) => (Array.isArray(v) ? v.map(normClaim).filter((c) => c !== null) : []);
58
+ const num = (v) => (typeof v === "number" ? v : null);
59
+ const bool = (v) => (typeof v === "boolean" ? v : null);
60
+ return {
61
+ login,
62
+ activeClaims: arr(r["active_claims"] ?? r["activeClaims"] ?? r["claims"]),
63
+ queuedClaims: arr(r["queued_claims"] ?? r["queuedClaims"] ?? r["queue"]),
64
+ completedCount: num(r["completed_count"] ?? r["completedClaims"]),
65
+ expiredCount: num(r["expired_count"] ?? r["expiredClaims"]),
66
+ overCap: bool(r["over_cap"] ?? r["overCap"]),
67
+ };
68
+ }
69
+ async function defaultFetchAccount(login) {
70
+ const url = `${ledgerBaseUrl()}/v1/accounts/${encodeURIComponent(login)}.json`;
71
+ let res;
72
+ try {
73
+ res = await fetch(url);
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ if (res.status === 404)
79
+ return null;
80
+ if (!res.ok)
81
+ return null;
82
+ try {
83
+ return normalizeAccount(login, await res.json());
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ async function defaultFetchClaimDetail(repo, issue) {
90
+ const url = `${ledgerBaseUrl()}/v1/issues/${repo}/${issue}/status.json`;
91
+ try {
92
+ const res = await fetch(url);
93
+ if (!res.ok)
94
+ return null;
95
+ const data = (await res.json());
96
+ const claim = data.claim;
97
+ if (!claim || typeof claim !== "object")
98
+ return null;
99
+ return {
100
+ claimedAt: typeof claim.claimed_at === "string" ? claim.claimed_at : "",
101
+ expiresAt: typeof claim.expires_at === "string" ? claim.expires_at : "",
102
+ commentUrl: typeof claim.comment_url === "string" ? claim.comment_url : null,
103
+ };
104
+ }
105
+ catch {
106
+ return null;
107
+ }
108
+ }
109
+ async function defaultFetchMergedCount(login) {
110
+ const q = encodeURIComponent(`author:${login} type:pr is:merged`);
111
+ try {
112
+ const res = await fetch(`https://api.github.com/search/issues?q=${q}&per_page=1`, {
113
+ headers: { "User-Agent": "greenlight", Accept: "application/vnd.github+json" },
114
+ });
115
+ if (!res.ok)
116
+ return null;
117
+ const data = (await res.json());
118
+ return typeof data.total_count === "number" ? data.total_count : null;
119
+ }
120
+ catch {
121
+ return null;
122
+ }
123
+ }
124
+ function claimLine(c) {
125
+ const dates = [c.claimedAt.slice(0, 10), c.expiresAt.slice(0, 10)].filter((d) => d.length > 0).join(" -> ");
126
+ return `${c.repo}#${c.issue} (${c.state}${dates ? `, ${dates}` : ""}) ${c.commentUrl ? c.commentUrl : c.url}`;
127
+ }
128
+ export async function buildPassport(login, deps = {}, now = new Date()) {
129
+ const fetchAccount = deps.fetchAccount ?? defaultFetchAccount;
130
+ const fetchMergedCount = deps.fetchMergedCount ?? defaultFetchMergedCount;
131
+ const fetchClaimDetail = deps.fetchClaimDetail ?? defaultFetchClaimDetail;
132
+ const account = await fetchAccount(login).catch(() => null);
133
+ const mergedPrs = await fetchMergedCount(login).catch(() => null);
134
+ if (!account) {
135
+ const markdown = [
136
+ `# Contributor passport: @${login}`,
137
+ "",
138
+ "No passport file for this account in the Claim Ledger yet.",
139
+ "",
140
+ "Your passport starts with your first protocol claim: claim an issue with the Greenlight protocol marker " +
141
+ "(`greenlight claim` drafts it for you) and the Ledger indexes it within 15 minutes.",
142
+ "",
143
+ `Ledger: ${ledgerBaseUrl()}. Merged PRs on GitHub: ${mergedPrs === null ? "unknown (lookup failed)" : mergedPrs}.`,
144
+ "",
145
+ `_Passport generated by Greenlight v${GREENLIGHT_VERSION}._`,
146
+ ].join("\n");
147
+ return {
148
+ login,
149
+ found: false,
150
+ account: null,
151
+ mergedPrs,
152
+ honorRatio: "no ledger history",
153
+ markdown,
154
+ json: { login, found: false, mergedPrs, ledger: ledgerBaseUrl() },
155
+ };
156
+ }
157
+ // Enrich claims with dates from the per-issue status files. Each
158
+ // enrichment is independent and best-effort: a missing file leaves the
159
+ // claim exactly as the account file described it.
160
+ const enrich = async (claims) => Promise.all(claims.map(async (c) => {
161
+ if (c.issue <= 0)
162
+ return c;
163
+ const detail = await fetchClaimDetail(c.repo, c.issue).catch(() => null);
164
+ if (!detail)
165
+ return c;
166
+ return {
167
+ ...c,
168
+ claimedAt: c.claimedAt || detail.claimedAt,
169
+ expiresAt: c.expiresAt || detail.expiresAt,
170
+ commentUrl: c.commentUrl ?? detail.commentUrl,
171
+ };
172
+ }));
173
+ account.activeClaims = await enrich(account.activeClaims);
174
+ account.queuedClaims = await enrich(account.queuedClaims);
175
+ const completed = account.completedCount ?? account.activeClaims.filter((c) => c.state === "completed").length;
176
+ const expired = account.expiredCount ?? account.activeClaims.filter((c) => c.state === "expired").length;
177
+ const historyKnown = account.completedCount !== null || account.expiredCount !== null || account.activeClaims.some((c) => c.state === "completed" || c.state === "expired");
178
+ const honorRatio = !historyKnown || completed + expired === 0
179
+ ? "no completed/expired history in the ledger yet"
180
+ : `${completed} completed vs ${expired} expired (${Math.round((completed / (completed + expired)) * 100)}% completed)`;
181
+ const lines = [];
182
+ lines.push(`# Contributor passport: @${login}`);
183
+ lines.push("");
184
+ lines.push("## Claim Protocol record");
185
+ lines.push(`Active protocol claims: ${account.activeClaims.length}`);
186
+ for (const c of account.activeClaims)
187
+ lines.push(`- ${claimLine(c)}`);
188
+ lines.push(`Queued behind others: ${account.queuedClaims.length}`);
189
+ for (const c of account.queuedClaims)
190
+ lines.push(`- ${claimLine(c)}`);
191
+ lines.push(`Claim honor record: ${honorRatio}`);
192
+ lines.push(`Over the active-claim cap: ${account.overCap === null ? "not reported by the ledger" : account.overCap ? "yes (squatting flag)" : "no"}`);
193
+ lines.push("");
194
+ lines.push("## GitHub record");
195
+ lines.push(`Merged PRs: ${mergedPrs === null ? "unknown (lookup failed)" : mergedPrs}`);
196
+ lines.push("");
197
+ lines.push(`Ledger: ${ledgerBaseUrl()}. Checked ${now.toISOString().slice(0, 10)}.`);
198
+ lines.push(`_Passport generated by Greenlight v${GREENLIGHT_VERSION}._`);
199
+ return {
200
+ login,
201
+ found: true,
202
+ account,
203
+ mergedPrs,
204
+ honorRatio,
205
+ markdown: lines.join("\n"),
206
+ json: {
207
+ login,
208
+ found: true,
209
+ ledger: ledgerBaseUrl(),
210
+ activeClaims: account.activeClaims,
211
+ queuedClaims: account.queuedClaims,
212
+ honorRatio,
213
+ overCap: account.overCap,
214
+ mergedPrs,
215
+ },
216
+ };
217
+ }
218
+ //# sourceMappingURL=passport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passport.js","sourceRoot":"","sources":["../src/passport.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,18 @@ and never post anything to GitHub without the human's go-ahead.
8
8
 
9
9
  ## Install per tool
10
10
 
11
+ The fastest path is the one-command setup, run in your project:
12
+
13
+ ```bash
14
+ npx @reneturcios/greenlight init --agent claude-code
15
+ ```
16
+
17
+ (use `cursor`, `copilot`, `windsurf`, or `cline` for the other tools). Init
18
+ writes the MCP config and the instruction snippet for you, then tells you
19
+ what to restart. After that, run `greenlight doctor` to verify the setup.
20
+
21
+ The manual alternative, if you would rather copy files yourself:
22
+
11
23
  | Tool | Copy this file | To this destination |
12
24
  |---|---|---|
13
25
  | Claude Code | `claude-code/.mcp.json` | your project root as `.mcp.json` |
@@ -29,7 +41,7 @@ without it the tools still work but share the small anonymous budget.
29
41
  ## Verify it worked
30
42
 
31
43
  Ask the agent: "list your MCP tools." You should see the `greenlight`
32
- server with all 13 tools:
44
+ server with all 15 tools:
33
45
 
34
46
  - `check_issue` — verdict on whether an issue is landable (GO / RISKY / TAKEN / GATED / STALE)
35
47
  - `scan_repo` — find starter issues worth working in a repo
@@ -44,6 +56,8 @@ server with all 13 tools:
44
56
  - `claim_status` — Claim Protocol pre-flight for one issue: who holds it, until when, who is queued, competing PRs, gates, whether the repo honors the protocol
45
57
  - `preflight` — the one-call answer: claim_status plus the repo friction summary
46
58
  - `verify_comment` — draft the verified-finding comment for maintainer-only repos (draft only, never posts)
59
+ - `babysit_prs` — watch your open PRs: one prioritized action list (needs you now, waiting on them, quiet), diffed against stored watermarks
60
+ - `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
47
61
 
48
62
  ## Format notes
49
63
 
@@ -7,10 +7,11 @@ your project's CLAUDE.md (or keep the file and reference it from CLAUDE.md).
7
7
  ## Greenlight: check before you open a PR
8
8
 
9
9
  You have the Greenlight MCP server connected (server name: greenlight,
10
- 12 tools: check_issue, scan_repo, repo_friction, claim_issue, prep_issue,
10
+ 15 tools: check_issue, scan_repo, repo_friction, claim_issue, prep_issue,
11
11
  open_pr, ci_triage, review_triage, guard_pr, repo_digest, claim_status,
12
- preflight). It answers one question at every step:
13
- is this contribution worth doing, and is the problem mine?
12
+ preflight, verify_comment, babysit_prs, evidence_pack). It answers one
13
+ question at every step: is this contribution worth doing, and is the
14
+ problem mine?
14
15
 
15
16
  Rules:
16
17
 
@@ -22,18 +23,28 @@ Rules:
22
23
  start coding.
23
24
  - If the verdict is RISKY: explain the risk and ask before continuing.
24
25
  - If the verdict is GO: continue.
25
- 2. Before claiming an issue or setting up to work it, call `prep_issue`
26
- (dry run) to learn the repo's exact CLA path, house rules, changeset
27
- convention, and whether the fix even lives in this repo. Report the
28
- plan; do not create forks or branches without being asked.
29
- 3. If the PR's CI goes red: call `ci_triage` BEFORE changing any code, and
26
+ 2. Before claiming an issue, run the claim through `preflight` (or
27
+ `claim_status`): who holds the issue, until when, who is queued. Join
28
+ the queue rather than duplicating work that is already held. Then call
29
+ `prep_issue` (dry run) to learn the repo's exact CLA path, house rules,
30
+ changeset convention, and whether the fix even lives in this repo.
31
+ Report the plan; do not create forks or branches without being asked.
32
+ 3. If the repo takes no outside PRs (the check says the contribution is a
33
+ verified comment): draft with `verify_comment` from your notes, filling
34
+ every section you can. Do not open a PR there.
35
+ 4. If the PR's CI goes red: call `ci_triage` BEFORE changing any code, and
30
36
  tell the human whether each failure is pre-existing, likely yours,
31
37
  indeterminate, or an external blocker.
32
- 4. After review comments arrive: call `review_triage`. Fix likely-real
38
+ 5. After review comments arrive: call `review_triage`. Fix likely-real
33
39
  findings first, present needs-decision items to the human, and push
34
40
  back on likely-noise only with the evidence the tool gives you. The
35
41
  drafts are yours to adapt; the tool never posts them.
36
- 5. NEVER post claim comments, open PRs, or write anything to GitHub without
42
+ 6. When the human asks for proof a PR is sound: assemble `evidence_pack`
43
+ and present it. Every claim in the pack cites its source.
44
+ 7. To check on the human's open PRs without being asked about each one:
45
+ call `babysit_prs`. Report the needs-you-now items first; summarize
46
+ the waiting-on-them ones in one line each.
47
+ 8. NEVER post claim comments, open PRs, or write anything to GitHub without
37
48
  the human's explicit go-ahead. Drafts are output only.
38
49
 
39
50
  Tip: set GITHUB_TOKEN in your environment for the higher GitHub API rate
@@ -7,7 +7,7 @@ file form is:
7
7
 
8
8
  Copy the `cline_mcp_settings.json` file in this folder there (merging with
9
9
  any servers you already have), then check the Cline "MCP Servers" panel:
10
- the `greenlight` server should list 12 tools. The `disabled: false` field is
10
+ the `greenlight` server should list 15 tools. The `disabled: false` field is
11
11
  Cline's way of keeping the server enabled without deleting it.
12
12
 
13
13
  Workflow: see the integrations README — your agent checks Greenlight
@@ -9,7 +9,8 @@ it does not exist).
9
9
 
10
10
  You have the Greenlight MCP server connected (server `greenlight`, tools:
11
11
  check_issue, scan_repo, repo_friction, claim_issue, prep_issue, open_pr,
12
- ci_triage, review_triage, guard_pr, repo_digest, claim_status, preflight).
12
+ ci_triage, review_triage, guard_pr, repo_digest, claim_status, preflight,
13
+ verify_comment, babysit_prs, evidence_pack).
13
14
  Apply these instructions whenever working on a
14
15
  pull request to an open source project:
15
16
 
@@ -17,14 +18,23 @@ pull request to an open source project:
17
18
  issue URL. If the verdict is TAKEN or GATED, stop and tell the user why,
18
19
  quoting the reasons. Never start work on a TAKEN or GATED issue without
19
20
  being told to.
20
- 2. Before claiming or setting up work, call `prep_issue` (dry run) to learn
21
- the repo's exact CLA path, house rules, and changeset convention. Report
22
- the plan; do not create forks or branches unasked.
23
- 3. If the PR's CI goes red, call `ci_triage` before changing code, and tell
21
+ 2. Before claiming an issue, run it through `preflight` (or
22
+ `claim_status`): who holds the issue, until when, who is queued. Join
23
+ the queue instead of duplicating held work. Then call `prep_issue` (dry
24
+ run) to learn the repo's exact CLA path, house rules, and changeset
25
+ convention. Report the plan; do not create forks or branches unasked.
26
+ 3. If the repo takes no outside PRs (the check says the contribution is a
27
+ verified comment): draft with `verify_comment` from your notes. Do not
28
+ open a PR there.
29
+ 4. If the PR's CI goes red, call `ci_triage` before changing code, and tell
24
30
  the user whether each failure is pre-existing, likely theirs,
25
31
  indeterminate, or an external blocker.
26
- 4. After review comments arrive, call `review_triage`. Fix likely-real
32
+ 5. After review comments arrive, call `review_triage`. Fix likely-real
27
33
  findings first; bring needs-decision items to the user; push back on
28
34
  likely-noise only with the tool's evidence. Drafts are output only.
29
- 5. Never post claim comments, open PRs, or write anything to GitHub without
35
+ 6. When the user asks for proof a PR is sound, assemble `evidence_pack`
36
+ and present it.
37
+ 7. To check on the user's open PRs, call `babysit_prs` and lead with the
38
+ needs-you-now items.
39
+ 8. Never post claim comments, open PRs, or write anything to GitHub without
30
40
  the user's explicit go-ahead.
@@ -7,7 +7,8 @@ alwaysApply: false
7
7
 
8
8
  You have the Greenlight MCP server connected (server `greenlight`, tools:
9
9
  check_issue, scan_repo, repo_friction, claim_issue, prep_issue, open_pr,
10
- ci_triage, review_triage, guard_pr, repo_digest, claim_status, preflight).
10
+ ci_triage, review_triage, guard_pr, repo_digest, claim_status, preflight,
11
+ verify_comment, babysit_prs, evidence_pack).
11
12
  Apply these rules whenever the user is working on
12
13
  a pull request to an open source project:
13
14
 
@@ -15,14 +16,23 @@ a pull request to an open source project:
15
16
  issue URL. If the verdict is TAKEN or GATED, stop and tell the user why,
16
17
  quoting the reasons. Never start work on a TAKEN or GATED issue without
17
18
  being told to.
18
- 2. Before claiming or setting up work, call `prep_issue` (dry run) to learn
19
- the repo's exact CLA path, house rules, and changeset convention. Report
20
- the plan; do not create forks or branches unasked.
21
- 3. If the PR's CI goes red, call `ci_triage` before changing code, and tell
19
+ 2. Before claiming an issue, run it through `preflight` (or
20
+ `claim_status`): who holds the issue, until when, who is queued. Join
21
+ the queue instead of duplicating held work. Then call `prep_issue` (dry
22
+ run) to learn the repo's exact CLA path, house rules, and changeset
23
+ convention. Report the plan; do not create forks or branches unasked.
24
+ 3. If the repo takes no outside PRs (the check says the contribution is a
25
+ verified comment): draft with `verify_comment` from your notes. Do not
26
+ open a PR there.
27
+ 4. If the PR's CI goes red, call `ci_triage` before changing code, and tell
22
28
  the user whether each failure is pre-existing, likely theirs,
23
29
  indeterminate, or an external blocker.
24
- 4. After review comments arrive, call `review_triage`. Fix likely-real
30
+ 5. After review comments arrive, call `review_triage`. Fix likely-real
25
31
  findings first; bring needs-decision items to the user; push back on
26
32
  likely-noise only with the tool's evidence. Drafts are output only.
27
- 5. Never post claim comments, open PRs, or write anything to GitHub without
33
+ 6. When the user asks for proof a PR is sound, assemble `evidence_pack`
34
+ and present it.
35
+ 7. To check on the user's open PRs, call `babysit_prs` and lead with the
36
+ needs-you-now items.
37
+ 8. Never post claim comments, open PRs, or write anything to GitHub without
28
38
  the user's explicit go-ahead.
@@ -6,7 +6,7 @@ Windsurf's global MCP config lives at:
6
6
 
7
7
  Copy the `mcp_config.json` file in this folder there (merging with any
8
8
  servers you already have), then restart Windsurf and check its MCP panel:
9
- the `greenlight` server should list 12 tools. Newer Windsurf versions also
9
+ the `greenlight` server should list 15 tools. Newer Windsurf versions also
10
10
  accept a project-level `.windsurf/mcp.json` file using the same
11
11
  `mcpServers` format.
12
12
 
package/package.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "test": "tsx --test test/*.test.ts"
26
26
  },
27
27
  "type": "module",
28
- "version": "0.5.0",
28
+ "version": "0.7.0",
29
29
  "mcpName": "io.github.CloudCorpRecords/greenlight",
30
30
  "publishConfig": {
31
31
  "access": "public"
package/server.json CHANGED
@@ -6,13 +6,13 @@
6
6
  "url": "https://github.com/CloudCorpRecords/greenlight",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.5.0",
9
+ "version": "0.7.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "registryBaseUrl": "https://registry.npmjs.org",
14
14
  "identifier": "@reneturcios/greenlight",
15
- "version": "0.5.0",
15
+ "version": "0.7.0",
16
16
  "runtimeHint": "npx",
17
17
  "packageArguments": [
18
18
  {