@reneturcios/greenlight 0.4.0 → 0.6.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.
Files changed (47) hide show
  1. package/README.md +50 -1
  2. package/dist/babysit.d.ts +132 -0
  3. package/dist/babysit.js +439 -0
  4. package/dist/babysit.js.map +1 -0
  5. package/dist/cli.js +207 -3
  6. package/dist/cli.js.map +1 -1
  7. package/dist/digest.d.ts +1 -1
  8. package/dist/digest.js +1 -1
  9. package/dist/doctor.d.ts +34 -0
  10. package/dist/doctor.js +158 -0
  11. package/dist/doctor.js.map +1 -0
  12. package/dist/evidence.d.ts +48 -0
  13. package/dist/evidence.js +254 -0
  14. package/dist/evidence.js.map +1 -0
  15. package/dist/github.js +2 -2
  16. package/dist/github.js.map +1 -1
  17. package/dist/guard.d.ts +63 -3
  18. package/dist/guard.js +131 -4
  19. package/dist/guard.js.map +1 -1
  20. package/dist/help.d.ts +25 -0
  21. package/dist/help.js +234 -0
  22. package/dist/help.js.map +1 -0
  23. package/dist/index.js +79 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/init.d.ts +61 -0
  26. package/dist/init.js +298 -0
  27. package/dist/init.js.map +1 -0
  28. package/dist/passport.d.ts +52 -0
  29. package/dist/passport.js +218 -0
  30. package/dist/passport.js.map +1 -0
  31. package/dist/verify-comment.d.ts +75 -0
  32. package/dist/verify-comment.js +149 -0
  33. package/dist/verify-comment.js.map +1 -0
  34. package/dist/verify-parsers.d.ts +25 -0
  35. package/dist/verify-parsers.js +56 -0
  36. package/dist/verify-parsers.js.map +1 -0
  37. package/dist/verify.d.ts +52 -0
  38. package/dist/verify.js +276 -0
  39. package/dist/verify.js.map +1 -0
  40. package/integrations/README.md +4 -1
  41. package/integrations/claude-code/CLAUDE.snippet.md +6 -5
  42. package/integrations/cline/README.md +1 -1
  43. package/integrations/copilot/copilot-instructions.snippet.md +6 -3
  44. package/integrations/cursor/greenlight.mdc +2 -1
  45. package/integrations/windsurf/README.md +1 -1
  46. package/package.json +1 -1
  47. package/server.json +2 -2
package/dist/doctor.js ADDED
@@ -0,0 +1,158 @@
1
+ /**
2
+ * `greenlight doctor`: first-run setup check.
3
+ *
4
+ * Answers the three questions behind most "it doesn't work" reports: is my
5
+ * Node new enough, is my GitHub quota usable, and can Greenlight write its
6
+ * cache. Every check carries its fix, so the output is actionable without
7
+ * opening the docs. All inputs are injectable so the suite stays offline.
8
+ */
9
+ import { homedir } from "node:os";
10
+ import { join } from "node:path";
11
+ import { mkdirSync, writeFileSync, rmSync, readFileSync } from "node:fs";
12
+ import { fileURLToPath } from "node:url";
13
+ export const MIN_NODE_MAJOR = 20;
14
+ export function nodeMajor(version) {
15
+ const m = /^v?(\d+)/.exec(version.trim());
16
+ return m ? Number(m[1]) : 0;
17
+ }
18
+ export function defaultCacheDir() {
19
+ return join(homedir(), ".cache", "greenlight");
20
+ }
21
+ export function defaultPackageVersion() {
22
+ try {
23
+ // src/doctor.ts in dev, dist/doctor.js built: package.json is one up either way.
24
+ const pkg = JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8"));
25
+ return pkg.version ?? "unknown";
26
+ }
27
+ catch {
28
+ return "unknown";
29
+ }
30
+ }
31
+ /** One unauthenticated-capable call: GET /rate_limit shows quota either way. */
32
+ export async function defaultFetchRateLimit(token) {
33
+ try {
34
+ const headers = {
35
+ Accept: "application/vnd.github+json",
36
+ "User-Agent": "greenlight-cli",
37
+ };
38
+ if (token)
39
+ headers["Authorization"] = `Bearer ${token}`;
40
+ const res = await fetch("https://api.github.com/rate_limit", {
41
+ headers,
42
+ signal: AbortSignal.timeout(15000),
43
+ });
44
+ if (!res.ok) {
45
+ return { ok: false, error: `GitHub API ${res.status}` };
46
+ }
47
+ const body = (await res.json());
48
+ const core = body.resources?.core ?? {};
49
+ return {
50
+ ok: true,
51
+ remaining: core.remaining,
52
+ limit: core.limit,
53
+ resetAt: typeof core.reset === "number"
54
+ ? new Date(core.reset * 1000).toISOString()
55
+ : undefined,
56
+ };
57
+ }
58
+ catch (err) {
59
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
60
+ }
61
+ }
62
+ function checkCacheWritable(cacheDir) {
63
+ try {
64
+ mkdirSync(cacheDir, { recursive: true });
65
+ const probe = join(cacheDir, ".doctor-write-test");
66
+ writeFileSync(probe, "ok", "utf8");
67
+ rmSync(probe, { force: true });
68
+ return true;
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ }
74
+ export async function runDoctor(deps = {}) {
75
+ const nodeVersion = deps.nodeVersion ?? process.version;
76
+ const env = deps.env ?? process.env;
77
+ const cacheDir = deps.cacheDir ?? defaultCacheDir();
78
+ const version = deps.packageVersion ?? defaultPackageVersion();
79
+ const fetchRateLimit = deps.fetchRateLimit ?? defaultFetchRateLimit;
80
+ const checks = [];
81
+ const major = nodeMajor(nodeVersion);
82
+ checks.push(major >= MIN_NODE_MAJOR
83
+ ? { name: "node", status: "pass", detail: `${nodeVersion} (>= v${MIN_NODE_MAJOR} required)` }
84
+ : {
85
+ name: "node",
86
+ status: "fail",
87
+ detail: `${nodeVersion} is older than the required v${MIN_NODE_MAJOR}`,
88
+ fix: "Install Node 20+ from https://nodejs.org and re-run doctor.",
89
+ });
90
+ const tokenVar = env.GITHUB_TOKEN ? "GITHUB_TOKEN" : env.GH_TOKEN ? "GH_TOKEN" : undefined;
91
+ const token = tokenVar ? env[tokenVar] : undefined;
92
+ checks.push(tokenVar
93
+ ? { name: "github token", status: "pass", detail: `${tokenVar} is set` }
94
+ : {
95
+ name: "github token",
96
+ status: "warn",
97
+ detail: "no token set; sharing the 60 req/hr anonymous quota",
98
+ fix: "Create a classic personal access token (no scopes needed for public repos) and export GITHUB_TOKEN=<token>.",
99
+ });
100
+ const rate = await fetchRateLimit(token);
101
+ if (!rate.ok) {
102
+ checks.push({
103
+ name: "github api",
104
+ status: "fail",
105
+ detail: `unreachable: ${rate.error ?? "unknown error"}`,
106
+ fix: "Check your network connection or proxy, then re-run doctor.",
107
+ });
108
+ }
109
+ else if (rate.remaining === 0) {
110
+ checks.push({
111
+ name: "github api",
112
+ status: "warn",
113
+ detail: `quota exhausted${rate.resetAt ? `; resets at ${rate.resetAt}` : ""}`,
114
+ fix: tokenVar
115
+ ? "Wait for the reset time; the cache under ~/.cache/greenlight keeps repeat checks cheap."
116
+ : "Set GITHUB_TOKEN for the 5000 req/hr limit, or wait for the reset time.",
117
+ });
118
+ }
119
+ else {
120
+ checks.push({
121
+ name: "github api",
122
+ status: "pass",
123
+ detail: rate.remaining !== undefined && rate.limit !== undefined
124
+ ? `reachable, ${rate.remaining}/${rate.limit} requests remaining`
125
+ : "reachable",
126
+ });
127
+ }
128
+ checks.push(checkCacheWritable(cacheDir)
129
+ ? { name: "cache", status: "pass", detail: `${cacheDir} is writable` }
130
+ : {
131
+ name: "cache",
132
+ status: "fail",
133
+ detail: `${cacheDir} is not writable`,
134
+ fix: `Make ${cacheDir} writable (it caches GitHub responses so repeat checks stay cheap).`,
135
+ });
136
+ return { version, checks };
137
+ }
138
+ /** Human-readable report; one line per check plus the fix for anything off. */
139
+ export function formatDoctorHuman(report) {
140
+ const lines = [`greenlight ${report.version}: setup check`];
141
+ for (const c of report.checks) {
142
+ const tag = c.status === "pass" ? "[PASS]" : c.status === "warn" ? "[WARN]" : "[FAIL]";
143
+ lines.push(` ${tag} ${c.name}: ${c.detail}`);
144
+ if (c.fix)
145
+ lines.push(` fix: ${c.fix}`);
146
+ }
147
+ if (report.checks.some((c) => c.status === "fail")) {
148
+ lines.push("Result: NOT READY — fix the FAIL lines above, then re-run doctor.");
149
+ }
150
+ else if (report.checks.some((c) => c.status === "warn")) {
151
+ lines.push("Result: READY with warnings — greenlight works, but see the WARN lines.");
152
+ }
153
+ else {
154
+ lines.push("Result: READY — everything looks good.");
155
+ }
156
+ return lines.join("\n");
157
+ }
158
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { type GuardResult } from "./guard.js";
2
+ import { type CiTriageResult } from "./ci-triage.js";
3
+ import { type ReviewTriageResult } from "./review-triage.js";
4
+ import { type ProtocolFetchResult } from "./protocol-fetch.js";
5
+ import type { VerifyResult } from "./verify.js";
6
+ export interface EvidenceDeps {
7
+ guard?: (prUrl: string) => Promise<GuardResult>;
8
+ triageCi?: (prUrl: string) => Promise<CiTriageResult>;
9
+ triageReview?: (prUrl: string) => Promise<ReviewTriageResult>;
10
+ fetchPrMeta?: (owner: string, repo: string, number: number) => Promise<{
11
+ createdAt: string;
12
+ headSha: string;
13
+ }>;
14
+ protocolStatus?: (owner: string, repo: string, number: number) => Promise<ProtocolFetchResult | null>;
15
+ readVerifyJson?: (path: string) => Promise<VerifyResult | null>;
16
+ }
17
+ export interface EvidenceIssueProtocol {
18
+ issue: string;
19
+ url: string;
20
+ activeClaim: {
21
+ claimant: string;
22
+ state: string;
23
+ claimedAt: string;
24
+ expiresAt: string;
25
+ commentUrl: string | null;
26
+ } | null;
27
+ queue: string[];
28
+ }
29
+ export interface EvidencePack {
30
+ pr: string;
31
+ title: string;
32
+ author: string;
33
+ assembledAt: string;
34
+ version: string;
35
+ markdown: string;
36
+ json: Record<string, unknown>;
37
+ }
38
+ export interface EvidenceOptions {
39
+ verifyJsonPath?: string;
40
+ deps?: EvidenceDeps;
41
+ now?: Date;
42
+ }
43
+ /**
44
+ * Assemble the evidence pack. Best-effort throughout: a source that
45
+ * cannot be read becomes an explicit "could not be read" line, never a
46
+ * silent gap and never invented content.
47
+ */
48
+ export declare function buildEvidencePack(prUrl: string, opts?: EvidenceOptions): Promise<EvidencePack>;
@@ -0,0 +1,254 @@
1
+ /**
2
+ * The Verified PR evidence pack. One markdown document per PR that a
3
+ * reader can check without trusting Greenlight's word: every claim in
4
+ * it cites its source (the check run, the review anchor, the claim
5
+ * comment URL).
6
+ *
7
+ * Assembled from the existing engines: the guard, CI triage, review
8
+ * triage, and the Claim Protocol state of the PR's linked issues. The
9
+ * test-suite delta is included only when the caller passes a prior
10
+ * `greenlight verify --json` report via --verify-json: the pack never
11
+ * runs suites itself (they take minutes and belong where the code is).
12
+ */
13
+ import { apiGet, parsePullUrl, parseIssueUrl } from "./github.js";
14
+ import { guardPr } from "./guard.js";
15
+ import { triagePr } from "./ci-triage.js";
16
+ import { triageReview as defaultTriageReview } from "./review-triage.js";
17
+ import { fetchProtocolState } from "./protocol-fetch.js";
18
+ import { readFileSync } from "node:fs";
19
+ import { createRequire } from "node:module";
20
+ const GREENLIGHT_VERSION = (() => {
21
+ try {
22
+ return createRequire(import.meta.url)("../package.json").version;
23
+ }
24
+ catch {
25
+ return "unknown";
26
+ }
27
+ })();
28
+ async function defaultFetchPrMeta(owner, repo, number) {
29
+ const p = (await apiGet(`/repos/${owner}/${repo}/pulls/${number}`));
30
+ return {
31
+ createdAt: String(p.created_at ?? ""),
32
+ headSha: String(p.head?.sha ?? ""),
33
+ };
34
+ }
35
+ async function defaultReadVerifyJson(path) {
36
+ try {
37
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
38
+ if (parsed && typeof parsed === "object" && typeof parsed.outcome === "string")
39
+ return parsed;
40
+ return null;
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ function cite(url) {
47
+ return url && url.length > 0 ? url : "(no link recorded)";
48
+ }
49
+ /**
50
+ * Assemble the evidence pack. Best-effort throughout: a source that
51
+ * cannot be read becomes an explicit "could not be read" line, never a
52
+ * silent gap and never invented content.
53
+ */
54
+ export async function buildEvidencePack(prUrl, opts = {}) {
55
+ const deps = opts.deps ?? {};
56
+ const now = opts.now ?? new Date();
57
+ const { owner, repo, number } = parsePullUrl(prUrl);
58
+ const guard = deps.guard ?? guardPr;
59
+ const triageCi = deps.triageCi ?? triagePr;
60
+ const triageReview = deps.triageReview ?? defaultTriageReview;
61
+ const fetchPrMeta = deps.fetchPrMeta ?? defaultFetchPrMeta;
62
+ const protocolStatus = deps.protocolStatus ?? fetchProtocolState;
63
+ const readVerifyJson = deps.readVerifyJson ?? defaultReadVerifyJson;
64
+ const [guardRes, ciRes, reviewRes, meta] = await Promise.all([
65
+ guard(prUrl).catch((e) => ({ error: e instanceof Error ? e.message : String(e) })),
66
+ triageCi(prUrl).catch((e) => ({ error: e instanceof Error ? e.message : String(e) })),
67
+ triageReview(prUrl).catch((e) => ({ error: e instanceof Error ? e.message : String(e) })),
68
+ fetchPrMeta(owner, repo, number).catch(() => ({ createdAt: "", headSha: "" })),
69
+ ]);
70
+ const guardOk = (r) => typeof r === "object" && r !== null && !("error" in r);
71
+ const ciOk = (r) => typeof r === "object" && r !== null && !("error" in r);
72
+ const reviewOk = (r) => typeof r === "object" && r !== null && !("error" in r);
73
+ // Protocol status for each linked issue the guard found.
74
+ const issueProtocols = [];
75
+ if (guardOk(guardRes)) {
76
+ for (const li of guardRes.linkedIssues) {
77
+ try {
78
+ const { owner: iOwner, repo: iRepo, number: iNumber } = parseIssueUrl(li.url);
79
+ const proto = await protocolStatus(iOwner, iRepo, iNumber).catch(() => null);
80
+ const active = proto?.computation.active ?? null;
81
+ issueProtocols.push({
82
+ issue: `${iOwner}/${iRepo}#${iNumber}`,
83
+ url: li.url,
84
+ activeClaim: active
85
+ ? {
86
+ claimant: active.claimant,
87
+ state: active.state,
88
+ claimedAt: active.claimedAt,
89
+ expiresAt: active.expiresAt,
90
+ commentUrl: active.commentUrl,
91
+ }
92
+ : null,
93
+ queue: (proto?.computation.queue ?? []).map((q) => q.claimant),
94
+ });
95
+ }
96
+ catch {
97
+ issueProtocols.push({ issue: li.url, url: li.url, activeClaim: null, queue: [] });
98
+ }
99
+ }
100
+ }
101
+ let verifySection;
102
+ let verifyJson = null;
103
+ if (opts.verifyJsonPath) {
104
+ const vr = await readVerifyJson(opts.verifyJsonPath).catch(() => null);
105
+ if (vr && vr.delta) {
106
+ verifyJson = { outcome: vr.outcome, delta: vr.delta };
107
+ const d = vr.delta;
108
+ verifySection =
109
+ `Outcome: **${vr.outcome}** (from the provided verify report; the pack does not run suites itself).\n\n` +
110
+ `- newly failing (yours): ${d.newlyFailing.length > 0 ? d.newlyFailing.join(", ") : "none"}\n` +
111
+ `- newly passing (fixed by this PR): ${d.newlyPassing.length > 0 ? d.newlyPassing.join(", ") : "none"}\n` +
112
+ `- still failing (pre-existing): ${d.stillFailing.length > 0 ? d.stillFailing.join(", ") : "none"}\n` +
113
+ `- base ${d.baseTotal.passed}/${d.baseTotal.failed} passed/failed; head ${d.headTotal.passed}/${d.headTotal.failed} passed/failed`;
114
+ }
115
+ else {
116
+ verifySection = `No usable verify report at \`${opts.verifyJsonPath}\` (unreadable or not a verify result). Run \`greenlight verify --json\` where the code lives and pass it with --verify-json.`;
117
+ }
118
+ }
119
+ else {
120
+ verifySection = "Not included. Run `greenlight verify --json` where the code lives and pass the report with --verify-json to add the honest red-green delta.";
121
+ }
122
+ const lines = [];
123
+ const title = guardOk(guardRes) ? guardRes.title : "(title unavailable)";
124
+ const author = guardOk(guardRes) ? guardRes.author : "(unknown)";
125
+ lines.push(`# Evidence pack: ${owner}/${repo}#${number}`);
126
+ lines.push("");
127
+ lines.push(`"${title}" by @${author}. PR opened ${meta.createdAt ? meta.createdAt.slice(0, 10) : "(date unavailable)"}, head ${meta.headSha ? meta.headSha.slice(0, 7) : "(unknown)"}.`);
128
+ lines.push(`Assembled ${now.toISOString().slice(0, 10)} by Greenlight v${GREENLIGHT_VERSION}. Every claim below cites its source.`);
129
+ lines.push("");
130
+ // Guard section
131
+ lines.push("## Guard verdict");
132
+ if (guardOk(guardRes)) {
133
+ lines.push(guardRes.summary);
134
+ const flags = guardRes.findings.filter((f) => f.severity === "flag");
135
+ if (flags.length === 0) {
136
+ lines.push("No flags. Source: the guard's five checks (competing fix, prior claims, artifacts, first-time, protocol claims).");
137
+ }
138
+ else {
139
+ lines.push("");
140
+ lines.push("| Finding | Evidence |");
141
+ lines.push("|---|---|");
142
+ for (const f of flags) {
143
+ lines.push(`| ${f.title} | ${f.evidence.join(" ")} |`);
144
+ }
145
+ }
146
+ const notes = guardRes.findings.filter((f) => f.severity === "note");
147
+ if (notes.length > 0) {
148
+ lines.push("");
149
+ lines.push("Notes: " + notes.map((f) => f.evidence.join(" ")).join(" "));
150
+ }
151
+ }
152
+ else {
153
+ lines.push(`Could not be read this run: ${guardRes.error}`);
154
+ }
155
+ lines.push("");
156
+ // CI section
157
+ lines.push("## CI triage");
158
+ if (ciOk(ciRes)) {
159
+ lines.push(`Verdict: **${ciRes.verdict}**.`);
160
+ if (ciRes.checks.length === 0) {
161
+ lines.push("No failing checks on the PR head. Source: the check runs on the PR head.");
162
+ }
163
+ else {
164
+ lines.push("");
165
+ lines.push("| Check | Class | Evidence | Source |");
166
+ lines.push("|---|---|---|---|");
167
+ for (const c of ciRes.checks) {
168
+ lines.push(`| \`${c.name}\` | ${c.class}${c.lean ? ` (lean: ${c.lean})` : ""} | ${c.evidence} | ${cite(c.detailsUrl)} |`);
169
+ }
170
+ }
171
+ }
172
+ else {
173
+ lines.push(`Could not be read this run: ${ciRes.error}`);
174
+ }
175
+ lines.push("");
176
+ // Review section
177
+ lines.push("## Review triage");
178
+ if (reviewOk(reviewRes)) {
179
+ const c = reviewRes.counts;
180
+ lines.push(`Verdict: **${reviewRes.verdict}** (${c.likelyReal} likely-real, ${c.needsDecision} needs-decision, ${c.likelyNoise} likely-noise).`);
181
+ const actionable = reviewRes.findings.filter((f) => f.class === "likely-real" || f.class === "needs-decision");
182
+ if (actionable.length === 0) {
183
+ lines.push("No actionable findings. Source: review and issue comments on the PR.");
184
+ }
185
+ else {
186
+ lines.push("");
187
+ lines.push("| Finding | Class | Reviewer | Source |");
188
+ lines.push("|---|---|---|---|");
189
+ for (const f of actionable) {
190
+ const anchor = f.path ? `${f.path}${f.line ? `:${f.line}` : ""}` : "(review-level)";
191
+ lines.push(`| ${f.summary} | ${f.class} | @${f.author} (${f.authorKind}) | ${anchor} |`);
192
+ }
193
+ lines.push("");
194
+ lines.push("Reply drafts for each finding are in the review triage output; this pack records the findings, not the replies.");
195
+ }
196
+ }
197
+ else {
198
+ lines.push(`Could not be read this run: ${reviewRes.error}`);
199
+ }
200
+ lines.push("");
201
+ // Protocol section
202
+ lines.push("## Claim Protocol status of linked issues");
203
+ if (issueProtocols.length === 0) {
204
+ lines.push("No linked issues with readable protocol state.");
205
+ }
206
+ else {
207
+ for (const ip of issueProtocols) {
208
+ if (!ip.activeClaim) {
209
+ lines.push(`- ${ip.issue}: no protocol claims. Source: ${cite(ip.url)}`);
210
+ }
211
+ else {
212
+ const a = ip.activeClaim;
213
+ lines.push(`- ${ip.issue}: **${a.state}** claim held by @${a.claimant}, claimed ${a.claimedAt.slice(0, 10)}, expires ${a.expiresAt.slice(0, 10)}. Source: ${cite(a.commentUrl)}`);
214
+ if (ip.queue.length > 0)
215
+ lines.push(` Queue: ${ip.queue.map((q) => `@${q}`).join(", ")}`);
216
+ }
217
+ }
218
+ }
219
+ lines.push("");
220
+ // Verify section
221
+ lines.push("## Test-suite delta");
222
+ lines.push(verifySection);
223
+ lines.push("");
224
+ // Sources
225
+ lines.push("## Sources");
226
+ lines.push(`- PR: ${cite(prUrl)}`);
227
+ if (guardOk(guardRes)) {
228
+ for (const li of guardRes.linkedIssues)
229
+ lines.push(`- Linked issue: ${cite(li.url)}`);
230
+ }
231
+ lines.push(`- Pack generator: Greenlight v${GREENLIGHT_VERSION} (guard + ci_triage + review_triage + protocol engines).`);
232
+ lines.push("");
233
+ const markdown = lines.join("\n");
234
+ return {
235
+ pr: `${owner}/${repo}#${number}`,
236
+ title,
237
+ author,
238
+ assembledAt: now.toISOString(),
239
+ version: GREENLIGHT_VERSION,
240
+ markdown,
241
+ json: {
242
+ pr: `${owner}/${repo}#${number}`,
243
+ title,
244
+ author,
245
+ version: GREENLIGHT_VERSION,
246
+ guard: guardOk(guardRes) ? { summary: guardRes.summary, flags: guardRes.findings.filter((f) => f.severity === "flag").map((f) => ({ check: f.check, title: f.title, evidence: f.evidence })) } : { error: guardRes.error },
247
+ ci: ciOk(ciRes) ? { verdict: ciRes.verdict, checks: ciRes.checks } : { error: ciRes.error },
248
+ review: reviewOk(reviewRes) ? { verdict: reviewRes.verdict, counts: reviewRes.counts, findings: reviewRes.findings } : { error: reviewRes.error },
249
+ protocol: issueProtocols,
250
+ verify: verifyJson,
251
+ },
252
+ };
253
+ }
254
+ //# sourceMappingURL=evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../src/evidence.ts"],"names":[],"mappings":"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"}
package/dist/github.js CHANGED
@@ -133,14 +133,14 @@ async function paginate(path, perPage = 100, maxPages = 5) {
133
133
  export function parseIssueUrl(url) {
134
134
  const m = /github\.com\/([^/]+)\/([^/]+)\/(?:issues|pull)\/(\d+)/.exec(url);
135
135
  if (!m)
136
- throw new Error(`Not a GitHub issue URL: ${url}`);
136
+ throw new Error(`Not a GitHub issue URL: ${url} (expected https://github.com/<owner>/<repo>/issues/<number>)`);
137
137
  return { owner: m[1], repo: m[2], number: Number(m[3]) };
138
138
  }
139
139
  /** Strict parser for PR URLs (ci triage only accepts /pull/ URLs). */
140
140
  export function parsePullUrl(url) {
141
141
  const m = /github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/.exec(url);
142
142
  if (!m)
143
- throw new Error(`Not a GitHub pull request URL: ${url}`);
143
+ throw new Error(`Not a GitHub pull request URL: ${url} (expected https://github.com/<owner>/<repo>/pull/<number>)`);
144
144
  return { owner: m[1], repo: m[2], number: Number(m[3]) };
145
145
  }
146
146
  /** Fetch issue comments for claim detection. */