@reneturcios/greenlight 0.3.11 → 0.5.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 (51) hide show
  1. package/README.md +42 -1
  2. package/dist/automate.d.ts +14 -1
  3. package/dist/automate.js +30 -12
  4. package/dist/automate.js.map +1 -1
  5. package/dist/cli.js +194 -7
  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/digest.js.map +1 -1
  10. package/dist/doctor.d.ts +34 -0
  11. package/dist/doctor.js +158 -0
  12. package/dist/doctor.js.map +1 -0
  13. package/dist/friction.d.ts +7 -0
  14. package/dist/friction.js +36 -0
  15. package/dist/friction.js.map +1 -1
  16. package/dist/github.js +2 -2
  17. package/dist/github.js.map +1 -1
  18. package/dist/guard.d.ts +5 -3
  19. package/dist/guard.js +60 -5
  20. package/dist/guard.js.map +1 -1
  21. package/dist/help.d.ts +25 -0
  22. package/dist/help.js +234 -0
  23. package/dist/help.js.map +1 -0
  24. package/dist/index.js +85 -33
  25. package/dist/index.js.map +1 -1
  26. package/dist/init.d.ts +61 -0
  27. package/dist/init.js +298 -0
  28. package/dist/init.js.map +1 -0
  29. package/dist/protocol-fetch.d.ts +142 -0
  30. package/dist/protocol-fetch.js +350 -0
  31. package/dist/protocol-fetch.js.map +1 -0
  32. package/dist/protocol.d.ts +232 -0
  33. package/dist/protocol.js +484 -0
  34. package/dist/protocol.js.map +1 -0
  35. package/dist/verify-comment.d.ts +75 -0
  36. package/dist/verify-comment.js +149 -0
  37. package/dist/verify-comment.js.map +1 -0
  38. package/dist/verify-parsers.d.ts +25 -0
  39. package/dist/verify-parsers.js +56 -0
  40. package/dist/verify-parsers.js.map +1 -0
  41. package/dist/verify.d.ts +52 -0
  42. package/dist/verify.js +276 -0
  43. package/dist/verify.js.map +1 -0
  44. package/integrations/README.md +4 -1
  45. package/integrations/claude-code/CLAUDE.snippet.md +6 -5
  46. package/integrations/cline/README.md +1 -1
  47. package/integrations/copilot/copilot-instructions.snippet.md +6 -3
  48. package/integrations/cursor/greenlight.mdc +2 -1
  49. package/integrations/windsurf/README.md +1 -1
  50. package/package.json +1 -1
  51. package/server.json +2 -2
@@ -0,0 +1,484 @@
1
+ /**
2
+ * The Greenlight Claim Protocol core engine (Phase 1, Greenlight v0.4.0).
3
+ *
4
+ * Implements SPEC.md sections 3 (the claim), 4 (policy file) and 5.1 (status
5
+ * payload) as pure functions over injected data: no network, no dates other
6
+ * than the caller's `now`, no exceptions on bad input.
7
+ *
8
+ * Design commitments carried over from the spec:
9
+ * - GitHub is the source of truth: a claim is a comment carrying the marker
10
+ * `<!-- greenlight-claim v1 -->`, ordered by the comment's own created_at
11
+ * (ties broken by comment id). The engine never invents timestamps.
12
+ * - Claims are leases, not property: expiry is computed lazily by any reader.
13
+ * - The state machine replays events chronologically (claims, heartbeats,
14
+ * releases, PR links), so a later build phase (the Ledger indexer) and the
15
+ * client-side CLI share one truth.
16
+ *
17
+ * Spec ambiguities resolved here (each is flagged DECISION in a comment):
18
+ * 1. A second protocol claim by the same author while their earlier claim is
19
+ * still alive is treated as a heartbeat, not a new claim (anti-squatting).
20
+ * 2. A promoted claim restarts its lease at promotion time: its expiry is
21
+ * promotion + lease (capped by promotion + tenure cap). Without this, long
22
+ * queues would be born dead.
23
+ * 3. A rocket reaction carries no timestamp in our input shape, so it counts
24
+ * as a heartbeat "as of now" (extends expiry to now + lease).
25
+ * 4. A linked PR in state "closed" (not merged) keeps the claim "linked"
26
+ * (lease frozen); the claim does not quietly resume.
27
+ * 5. A mergedPrNumber that is not among linkedPrs is synthesized as a linked
28
+ * merged PR with createdAt = now. It freezes the current holder; it does
29
+ * not resurrect a claim that already expired before the merge was known
30
+ * (expiry is lazy but materialized, not speculative).
31
+ * 6. Heartbeats only count after a claim's activation; a queued claimant's
32
+ * earlier comments do not pre-extend the lease.
33
+ * 7. Comments with unparseable createdAt are skipped entirely (they cannot be
34
+ * ordered, and ordering is the whole game).
35
+ */
36
+ export const PROTOCOL_VERSION = 1;
37
+ export const CLAIM_MARKER = "<!-- greenlight-claim v1 -->";
38
+ export const RELEASE_MARKER = "<!-- greenlight-claim release -->";
39
+ /** Spec 3.4: squatting budget, indexed active claims per account. */
40
+ export const MAX_ACTIVE_CLAIMS_PER_ACCOUNT = 5;
41
+ const DAY_MS = 86_400_000;
42
+ export function defaultClaimsPolicy() {
43
+ return {
44
+ protocol: 1,
45
+ lease_days: 7,
46
+ tenure_cap_days: 28,
47
+ queue: true,
48
+ who_can_claim: "anyone",
49
+ maintainers: [],
50
+ };
51
+ }
52
+ function clampInt(value, fallback, min, max) {
53
+ const n = typeof value === "number" ? value : Number(value);
54
+ if (!Number.isFinite(n))
55
+ return fallback;
56
+ return Math.min(max, Math.max(min, Math.floor(n)));
57
+ }
58
+ /**
59
+ * Parse a `.greenlight/claims.json` body. Never throws: bad JSON (or a
60
+ * protocol version this engine cannot read) degrades to the defaults with
61
+ * `invalid: true`.
62
+ */
63
+ export function parseClaimsPolicy(jsonText) {
64
+ const base = defaultClaimsPolicy();
65
+ let raw;
66
+ try {
67
+ raw = JSON.parse(jsonText);
68
+ }
69
+ catch {
70
+ return { ...base, invalid: true };
71
+ }
72
+ if (typeof raw !== "object" || raw === null)
73
+ return { ...base, invalid: true };
74
+ const r = raw;
75
+ // DECISION: a policy naming a different protocol version is unreadable to
76
+ // this engine; fall back to defaults rather than half-applying it.
77
+ if (r.protocol !== PROTOCOL_VERSION)
78
+ return { ...base, invalid: true };
79
+ const lease_days = clampInt(r.lease_days, base.lease_days, 1, 30);
80
+ const tenureCapRaw = clampInt(r.tenure_cap_days, base.tenure_cap_days, 1, Number.MAX_SAFE_INTEGER);
81
+ // DECISION: a tenure cap below the lease would make leases meaningless;
82
+ // the cap can never be shorter than one lease.
83
+ const tenure_cap_days = Math.max(tenureCapRaw, lease_days);
84
+ const who = typeof r.who_can_claim === "string" && r.who_can_claim.trim() !== ""
85
+ ? r.who_can_claim.trim()
86
+ : base.who_can_claim;
87
+ const maintainers = Array.isArray(r.maintainers)
88
+ ? r.maintainers.filter((m) => typeof m === "string")
89
+ : [];
90
+ return {
91
+ protocol: 1,
92
+ lease_days,
93
+ tenure_cap_days,
94
+ queue: typeof r.queue === "boolean" ? r.queue : true,
95
+ who_can_claim: who,
96
+ maintainers,
97
+ };
98
+ }
99
+ const PLAN_RE = /^\s*plan\s*:\s*(.+?)\s*$/i;
100
+ const ETA_RE = /^\s*eta-days\s*:\s*(\d+)\s*$/i;
101
+ const QUEUE_OK_RE = /^\s*queue-ok\s*:\s*(yes|no|true|false)\s*$/i;
102
+ /**
103
+ * Detect a protocol claim (or release) comment and parse the optional
104
+ * structured lines after the marker. Unknown lines are ignored; the marker
105
+ * alone is a valid claim.
106
+ */
107
+ export function parseClaimComment(body) {
108
+ const out = {
109
+ isClaim: false,
110
+ isRelease: false,
111
+ plan: null,
112
+ etaDays: null,
113
+ queueOk: null,
114
+ };
115
+ if (typeof body !== "string")
116
+ return out;
117
+ const claimIdx = body.indexOf(CLAIM_MARKER);
118
+ out.isRelease = body.includes(RELEASE_MARKER);
119
+ if (claimIdx < 0)
120
+ return out;
121
+ out.isClaim = true;
122
+ const after = body.slice(claimIdx + CLAIM_MARKER.length);
123
+ for (const line of after.split("\n")) {
124
+ const plan = PLAN_RE.exec(line);
125
+ if (plan) {
126
+ out.plan = plan[1];
127
+ continue;
128
+ }
129
+ const eta = ETA_RE.exec(line);
130
+ if (eta) {
131
+ out.etaDays = parseInt(eta[1], 10);
132
+ continue;
133
+ }
134
+ const q = QUEUE_OK_RE.exec(line);
135
+ if (q) {
136
+ out.queueOk = q[1].toLowerCase() === "yes" || q[1].toLowerCase() === "true";
137
+ }
138
+ }
139
+ return out;
140
+ }
141
+ // ---------------------------------------------------------------------------
142
+ // State machine
143
+ // ---------------------------------------------------------------------------
144
+ function toMs(iso) {
145
+ const ms = Date.parse(iso);
146
+ return Number.isFinite(ms) ? ms : null;
147
+ }
148
+ function iso(ms) {
149
+ return new Date(ms).toISOString();
150
+ }
151
+ function compareIds(a, b) {
152
+ if (typeof a === "number" && typeof b === "number")
153
+ return a - b;
154
+ return String(a) < String(b) ? -1 : String(a) > String(b) ? 1 : 0;
155
+ }
156
+ /**
157
+ * Replay the claim chain for one issue and resolve every claim's state at
158
+ * `now`. Pure: no network, no exceptions on messy input.
159
+ */
160
+ export function computeClaimState(input) {
161
+ const policy = input.policy ?? defaultClaimsPolicy();
162
+ const nowMs = input.now ? toMs(input.now) ?? Date.now() : Date.now();
163
+ const leaseMs = policy.lease_days * DAY_MS;
164
+ const tenureMs = policy.tenure_cap_days * DAY_MS;
165
+ // 1. Parse claim comments into nodes, in chronological order.
166
+ const rawNodes = [];
167
+ for (const c of input.comments ?? []) {
168
+ const at = toMs(c.createdAt);
169
+ if (at === null)
170
+ continue; // DECISION 7: unordered comments are unusable
171
+ const parsed = parseClaimComment(c.body);
172
+ if (!parsed.isClaim)
173
+ continue;
174
+ rawNodes.push({
175
+ claimant: c.author,
176
+ claimedAtMs: at,
177
+ commentId: c.id,
178
+ commentUrl: c.url ?? null,
179
+ plan: parsed.plan,
180
+ etaDays: parsed.etaDays,
181
+ queueOk: parsed.queueOk,
182
+ releaseAtMs: null,
183
+ heartbeatMs: [],
184
+ });
185
+ }
186
+ rawNodes.sort((a, b) => a.claimedAtMs - b.claimedAtMs || compareIds(a.commentId, b.commentId));
187
+ // 2. Release markers: earliest release comment by the claimant, strictly
188
+ // after their claim comment.
189
+ for (const node of rawNodes) {
190
+ let earliest = null;
191
+ for (const c of input.comments ?? []) {
192
+ const at = toMs(c.createdAt);
193
+ if (at === null || at <= node.claimedAtMs)
194
+ continue;
195
+ if (c.author !== node.claimant)
196
+ continue;
197
+ if (!c.body.includes(RELEASE_MARKER))
198
+ continue;
199
+ if (earliest === null || at < earliest)
200
+ earliest = at;
201
+ }
202
+ node.releaseAtMs = earliest;
203
+ }
204
+ // 3. DECISION 1: a second protocol claim by the same author while their
205
+ // earlier claim is still alive is a heartbeat, not a new claim.
206
+ // Process per author: keep a claim only if the previous kept claim had
207
+ // already ended (by release or by its natural expiry) before this one.
208
+ const kept = [];
209
+ for (const node of rawNodes) {
210
+ const prev = [...kept].reverse().find((k) => k.claimant === node.claimant);
211
+ if (prev) {
212
+ const prevExpiry = Math.min(prev.claimedAtMs + leaseMs, prev.claimedAtMs + tenureMs);
213
+ const prevEnd = Math.min(prevExpiry, prev.releaseAtMs ?? Number.POSITIVE_INFINITY);
214
+ if (prevEnd > node.claimedAtMs) {
215
+ // Duplicate: the comment still counts as a heartbeat below.
216
+ continue;
217
+ }
218
+ }
219
+ kept.push(node);
220
+ }
221
+ kept.sort((a, b) => a.claimedAtMs - b.claimedAtMs || compareIds(a.commentId, b.commentId));
222
+ // 4. Heartbeats: any later comment by the claimant (excluding release
223
+ // comments), plus rocket reactions on their own claim comment (DECISION 3:
224
+ // reactions count as of `now`). Kept-node claim comments are excluded
225
+ // from each other's heartbeat lists so a re-claim after expiry is not
226
+ // also a heartbeat; dropped duplicate claims DO count.
227
+ const keptCommentIds = new Set(kept.map((k) => String(k.commentId)));
228
+ const duplicateClaimComments = new Set(rawNodes.filter((n) => !kept.includes(n)).map((n) => String(n.commentId)));
229
+ for (const node of kept) {
230
+ const beats = [];
231
+ for (const c of input.comments ?? []) {
232
+ const at = toMs(c.createdAt);
233
+ if (at === null || at <= node.claimedAtMs)
234
+ continue;
235
+ if (c.author !== node.claimant)
236
+ continue;
237
+ if (c.body.includes(RELEASE_MARKER))
238
+ continue;
239
+ // Heartbeats after the release ended the claim do not count.
240
+ if (node.releaseAtMs !== null && at >= node.releaseAtMs)
241
+ continue;
242
+ const cid = String(c.id);
243
+ if (keptCommentIds.has(cid) && !duplicateClaimComments.has(cid))
244
+ continue;
245
+ beats.push(at);
246
+ }
247
+ for (const r of input.reactions ?? []) {
248
+ if (String(r.commentId) !== String(node.commentId))
249
+ continue;
250
+ if (r.user !== node.claimant)
251
+ continue;
252
+ if (r.content !== "rocket")
253
+ continue;
254
+ beats.push(nowMs); // DECISION 3
255
+ }
256
+ node.heartbeatMs = beats.sort((a, b) => a - b);
257
+ }
258
+ const links = [];
259
+ for (const p of input.linkedPrs ?? []) {
260
+ const at = toMs(p.createdAt);
261
+ if (at === null)
262
+ continue;
263
+ links.push({ number: p.number, state: p.state, createdAtMs: at });
264
+ }
265
+ if (input.mergedPrNumber != null && !links.some((l) => l.number === input.mergedPrNumber)) {
266
+ links.push({ number: input.mergedPrNumber, state: "merged", createdAtMs: nowMs });
267
+ }
268
+ links.sort((a, b) => a.createdAtMs - b.createdAtMs);
269
+ const resolved = [];
270
+ let prevEnd = Number.NEGATIVE_INFINITY;
271
+ for (let i = 0; i < kept.length; i++) {
272
+ const node = kept[i];
273
+ const startMs = Math.max(node.claimedAtMs, prevEnd);
274
+ // DECISION 6: only heartbeats after activation extend the lease.
275
+ const beatsAfterStart = node.heartbeatMs.filter((h) => h > startMs);
276
+ const lastHb = beatsAfterStart.length > 0 ? beatsAfterStart[beatsAfterStart.length - 1] : startMs;
277
+ // DECISION 2: a promoted claim's tenure restarts at promotion time, and
278
+ // its lease restarts there too, so a queue can never be born dead.
279
+ const capBase = i === 0 ? node.claimedAtMs : startMs;
280
+ const expiryMs = Math.min(lastHb + leaseMs, capBase + tenureMs);
281
+ const releaseMs = node.releaseAtMs;
282
+ const hardEnd = Math.min(expiryMs, releaseMs ?? Number.POSITIVE_INFINITY);
283
+ const history = [
284
+ { event: "claimed", at: iso(node.claimedAtMs), by: node.claimant },
285
+ ];
286
+ if (i > 0)
287
+ history.push({ event: "promoted", at: iso(startMs), by: node.claimant });
288
+ for (const h of beatsAfterStart)
289
+ history.push({ event: "heartbeat", at: iso(h), by: node.claimant });
290
+ // A link that lands while the claim is alive (and not already released)
291
+ // freezes the lease. It is evaluated against the claim's natural end so
292
+ // a PR that arrives after expiry belongs to whoever holds the issue then.
293
+ const linkWindow = links.filter((l) => l.createdAtMs >= startMs && l.createdAtMs <= Math.min(hardEnd, nowMs));
294
+ const linkBeforeRelease = linkWindow.filter((l) => releaseMs === null || l.createdAtMs <= releaseMs);
295
+ const firstLink = linkBeforeRelease[0] ?? null;
296
+ let endMs = hardEnd;
297
+ let linkedPr = null;
298
+ if (firstLink) {
299
+ // DECISION 4: even a closed (unmerged) linked PR keeps the lease
300
+ // frozen; the claim does not quietly resume.
301
+ endMs = Number.POSITIVE_INFINITY;
302
+ linkedPr = firstLink.number;
303
+ history.push({ event: "linked", at: iso(firstLink.createdAtMs), by: node.claimant });
304
+ const mergedLink = linkBeforeRelease.find((l) => l.state === "merged" || l.number === input.mergedPrNumber);
305
+ if (mergedLink) {
306
+ history.push({ event: "completed", at: iso(mergedLink.createdAtMs), by: "protocol" });
307
+ }
308
+ }
309
+ resolved.push({
310
+ position: i + 1,
311
+ claimant: node.claimant,
312
+ claimedAt: iso(node.claimedAtMs),
313
+ commentId: node.commentId,
314
+ commentUrl: node.commentUrl,
315
+ plan: node.plan,
316
+ etaDays: node.etaDays,
317
+ queueOk: node.queueOk,
318
+ state: "queued",
319
+ activatedAt: iso(startMs),
320
+ expiresAt: iso(Math.min(expiryMs, capBase + tenureMs)),
321
+ lastHeartbeatAt: iso(lastHb),
322
+ linkedPr,
323
+ history,
324
+ startMs,
325
+ endMs,
326
+ expiryMs,
327
+ releaseMs,
328
+ });
329
+ prevEnd = endMs;
330
+ }
331
+ // 7. Resolve each claim's state at `now`.
332
+ const holderIdx = resolved.findIndex((r) => r.startMs <= nowMs && nowMs < r.endMs);
333
+ for (let i = 0; i < resolved.length; i++) {
334
+ const r = resolved[i];
335
+ if (holderIdx === -1 || i < holderIdx) {
336
+ // Terminal: the earlier of release or expiry decides. A release that
337
+ // lands exactly at expiry is credited to the explicit release.
338
+ const released = r.releaseMs !== null && r.releaseMs <= r.expiryMs;
339
+ if (released) {
340
+ r.state = "released";
341
+ r.history.push({ event: "released", at: iso(r.endMs), by: r.claimant });
342
+ }
343
+ else {
344
+ r.state = "expired";
345
+ r.history.push({ event: "expired", at: iso(r.endMs), by: "protocol" });
346
+ }
347
+ }
348
+ else if (i === holderIdx) {
349
+ // The walk already recorded the linked/completed history event.
350
+ r.state = r.linkedPr !== null ? (r.history.some((h) => h.event === "completed") ? "completed" : "linked") : "active";
351
+ }
352
+ else {
353
+ r.state = "queued";
354
+ }
355
+ }
356
+ function strip(r) {
357
+ const { startMs: _s, endMs: _e, expiryMs: _x, releaseMs: _r, ...rest } = r;
358
+ void _s;
359
+ void _e;
360
+ void _x;
361
+ void _r;
362
+ return rest;
363
+ }
364
+ const active = holderIdx === -1 ? null : resolved[holderIdx];
365
+ const queue = holderIdx === -1 ? [] : resolved.slice(holderIdx + 1);
366
+ // A claim whose chain ended is never "queued": nothing waits on it.
367
+ const visibleQueue = holderIdx === -1 ? [] : queue;
368
+ return {
369
+ claims: resolved.map(strip),
370
+ active: active ? strip(active) : null,
371
+ queue: visibleQueue.map(strip),
372
+ activeRecord: active ? toRecord(active) : null,
373
+ policy,
374
+ };
375
+ function toRecord(r) {
376
+ return {
377
+ v: 1,
378
+ repo: input.repo ?? null,
379
+ issue: input.issue ?? null,
380
+ claimant: r.claimant,
381
+ claimed_at: r.claimedAt,
382
+ comment_url: r.commentUrl,
383
+ state: r.state,
384
+ lease_days: policy.lease_days,
385
+ expires_at: r.expiresAt,
386
+ last_heartbeat_at: r.lastHeartbeatAt,
387
+ linked_pr: r.linkedPr,
388
+ queue_position: r.position,
389
+ history: r.history,
390
+ };
391
+ }
392
+ }
393
+ /**
394
+ * Spec 3.4: mark claims whose claimant holds more than the squatting budget
395
+ * of active claims. `activeCounts` maps login -> active claim count (the
396
+ * caller supplies it from the Ledger or another computation; nothing is
397
+ * fetched here). Returns new records; the input is untouched.
398
+ */
399
+ export function applyOverCap(records, activeCounts) {
400
+ return records.map((r) => (activeCounts[r.claimant] ?? 0) > MAX_ACTIVE_CLAIMS_PER_ACCOUNT
401
+ ? { ...r, over_cap: true }
402
+ : r);
403
+ }
404
+ function shortDate(isoTs) {
405
+ return isoTs.slice(0, 10);
406
+ }
407
+ /**
408
+ * Build the SPEC 5.1 issue-status payload from a protocol computation plus
409
+ * caller-supplied context (competing PRs, gates). Verdict mapping:
410
+ * active protocol claim -> TAKEN (expiry in the reason); a completed claim
411
+ * -> TAKEN naming the merged PR; expired-only history -> GO with a note;
412
+ * no protocol claims at all -> verdict null, claim null.
413
+ */
414
+ export function buildIssueStatus(args) {
415
+ const comp = args.computation;
416
+ const competing = args.competingPrs ?? [];
417
+ const openRaces = competing.filter((p) => p.state === "open");
418
+ const checkedAt = args.checkedAt ?? new Date().toISOString();
419
+ const staleAfterSeconds = args.staleAfterSeconds ?? 21600;
420
+ let verdict = null;
421
+ let reason = null;
422
+ let claim = null;
423
+ let protocolNote = null;
424
+ if (comp.activeRecord) {
425
+ const a = comp.activeRecord;
426
+ const queueDesc = comp.queue.length > 0
427
+ ? `; queue: ${comp.queue.map((q) => `@${q.claimant} (#${q.position})`).join(", ")}`
428
+ : "";
429
+ const raceDesc = openRaces.length > 0 ? `; open competing PRs: ${openRaces.map((p) => `#${p.number}`).join(", ")}` : "";
430
+ claim = {
431
+ state: a.state,
432
+ claimant: a.claimant,
433
+ claimed_at: a.claimed_at,
434
+ expires_at: a.expires_at,
435
+ queue: comp.queue.map((q) => ({
436
+ claimant: q.claimant,
437
+ position: q.position,
438
+ claimed_at: q.claimedAt,
439
+ })),
440
+ ...(a.over_cap ? { over_cap: true } : {}),
441
+ };
442
+ if (a.state === "completed") {
443
+ // DECISION: a completed claim means the issue is done, not free. TAKEN
444
+ // with the merged PR named is the honest pre-flight answer.
445
+ verdict = "TAKEN";
446
+ reason = `Protocol claim completed: @${a.claimant}'s linked PR (#${a.linked_pr}) merged; this issue is done${raceDesc}.`;
447
+ protocolNote = "The protocol claim on this issue completed with a merged PR.";
448
+ }
449
+ else {
450
+ verdict = "TAKEN";
451
+ reason =
452
+ `Protocol claim ${a.state}: @${a.claimant} holds this issue until ${shortDate(a.expires_at)}` +
453
+ queueDesc +
454
+ raceDesc +
455
+ ".";
456
+ protocolNote =
457
+ a.state === "linked"
458
+ ? "A protocol claim is linked to a pull request; review is in the maintainer's hands."
459
+ : "An active protocol claim governs this issue.";
460
+ }
461
+ }
462
+ else if (comp.claims.length > 0) {
463
+ const last = comp.claims[comp.claims.length - 1];
464
+ verdict = "GO";
465
+ reason = `Only expired or released protocol claims on this issue (last: @${last.claimant}, ${last.state} ${shortDate(last.expiresAt)}); it is free to claim.`;
466
+ protocolNote = "Past protocol claims have all ended; no active lease.";
467
+ }
468
+ else {
469
+ protocolNote = "No protocol claims found on this issue.";
470
+ }
471
+ return {
472
+ issue: args.issueUrl,
473
+ verdict,
474
+ reason,
475
+ claim,
476
+ protocol_note: protocolNote,
477
+ competing_prs: competing,
478
+ gates: args.gates ?? [],
479
+ repo_protocol: args.repoProtocol,
480
+ checked_at: checkedAt,
481
+ stale_after_seconds: staleAfterSeconds,
482
+ };
483
+ }
484
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Verified-comment mode.
3
+ *
4
+ * Some repos take no outside PRs at all. The proven examples are
5
+ * modelcontextprotocol/inspector ("Pull requests against this repo are
6
+ * opened by the repo maintainers only") and modelcontextprotocol/servers
7
+ * ("We accept issues, not pull requests"): outside PRs are closed on
8
+ * sight, and the contribution that lands is a detailed, verified issue
9
+ * comment instead — a reproduced problem, a located root cause, a
10
+ * fix sketch, and honest notes on what was actually run.
11
+ *
12
+ * This module assembles that comment from contributor-supplied inputs.
13
+ * It never posts anything (there is no post path), and it never invents
14
+ * facts: any section the contributor did not fill renders as an explicit
15
+ * gap marker ("not yet run", "not yet isolated", "not recorded") so a
16
+ * maintainer can see exactly what is verified and what is not. A
17
+ * plausible-looking filled-in section would be a lie; a labeled gap is
18
+ * the product.
19
+ */
20
+ import type { Gate } from "./types.js";
21
+ export interface VerifiedCommentFields {
22
+ /** One-line claim of the problem (usually the issue title restated). */
23
+ claim: string;
24
+ /** Environment: repo, ref/commit, date, platform. */
25
+ environment: string;
26
+ /** Reproduction steps, in order, exact commands. */
27
+ reproduction: string[];
28
+ /** What was observed when the repro ran. */
29
+ observed: string;
30
+ /** What should have happened instead. */
31
+ expected: string;
32
+ /** Root cause: file paths and line refs when known. */
33
+ rootCause: string;
34
+ /** Proposed fix sketch, not a code dump. */
35
+ fixSketch: string;
36
+ /** What was actually run (commands, counts). */
37
+ ran: string;
38
+ /** Who ran it. */
39
+ verifiedBy: string;
40
+ }
41
+ export type VerifiedCommentInput = Partial<VerifiedCommentFields>;
42
+ export interface BuiltComment {
43
+ markdown: string;
44
+ /** Names of sections that rendered as gap markers. */
45
+ gaps: string[];
46
+ }
47
+ /**
48
+ * Assemble the verified comment. Everything comes from the contributor's
49
+ * inputs (or the --from-file parse); nothing is fetched and nothing is
50
+ * invented. The greenlight version in the footer is a real fact about the
51
+ * tool that assembled the comment, not a fact about the bug.
52
+ */
53
+ export declare function buildVerifiedComment(issueUrl: string, fields: VerifiedCommentInput, greenlightVersion: string): BuiltComment;
54
+ /**
55
+ * True when the repo class is maintainer-only PRs: outside PRs are
56
+ * refused on sight, so the useful contribution is a verified comment.
57
+ * That is Greenlight's `collaborators_only` gate (inspector and servers
58
+ * both land there: their policy text is matched by the gate parser).
59
+ */
60
+ export declare function suggestsVerifiedComment(gates: Gate[]): boolean;
61
+ /** The suggestion line check_issue prints for maintainer-only repos. */
62
+ export declare function verifiedCommentSuggestion(issueUrl: string): string;
63
+ export interface ParsedNoteFile {
64
+ fields: VerifiedCommentInput;
65
+ /** Sections that did not map to a known field, kept verbatim. */
66
+ additionalNotes: string;
67
+ }
68
+ /**
69
+ * Parse a markdown notes file into comment fields. Lines under a heading
70
+ * map to that section; unmapped headings are preserved under
71
+ * "Additional notes" instead of being dropped, so contributor content is
72
+ * never silently lost. Unheaded text at the top of the file becomes the
73
+ * claim.
74
+ */
75
+ export declare function parseNoteFile(text: string): ParsedNoteFile;