@reneturcios/greenlight 0.0.0-stage → 0.3.3
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/LICENSE +21 -0
- package/README.md +213 -2
- package/dist/automate.d.ts +184 -0
- package/dist/automate.js +637 -0
- package/dist/automate.js.map +1 -0
- package/dist/claims.d.ts +20 -0
- package/dist/claims.js +117 -0
- package/dist/claims.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +337 -0
- package/dist/cli.js.map +1 -0
- package/dist/friction-index.d.ts +1 -0
- package/dist/friction-index.js +152 -0
- package/dist/friction-index.js.map +1 -0
- package/dist/friction.d.ts +30 -0
- package/dist/friction.js +56 -0
- package/dist/friction.js.map +1 -0
- package/dist/gates.d.ts +65 -0
- package/dist/gates.js +256 -0
- package/dist/gates.js.map +1 -0
- package/dist/github.d.ts +213 -0
- package/dist/github.js +787 -0
- package/dist/github.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +173 -0
- package/dist/index.js.map +1 -0
- package/dist/linkstrength.d.ts +27 -0
- package/dist/linkstrength.js +25 -0
- package/dist/linkstrength.js.map +1 -0
- package/dist/types.d.ts +169 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/verdict.d.ts +81 -0
- package/dist/verdict.js +272 -0
- package/dist/verdict.js.map +1 -0
- package/package.json +39 -3
- package/server.json +28 -0
package/dist/github.d.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import type { IssueSnapshot, LinkedPR, CommentSignal, GateKind, Gate, MentionedPR, DuplicateTarget } from "./types.js";
|
|
2
|
+
import { type WorkflowFile } from "./gates.js";
|
|
3
|
+
export declare class RateLimitError extends Error {
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
/** Thrown by apiGet/apiPost for HTTP 404, so callers can treat "missing" as data. */
|
|
7
|
+
export declare class ApiNotFoundError extends Error {
|
|
8
|
+
constructor(path: string);
|
|
9
|
+
}
|
|
10
|
+
export declare function githubToken(): string | undefined;
|
|
11
|
+
export declare function apiGet(path: string): Promise<unknown>;
|
|
12
|
+
/** POST helper for write operations (automation commands). Read paths use apiGet. */
|
|
13
|
+
export declare function apiPost(path: string, body: unknown): Promise<unknown>;
|
|
14
|
+
export interface IssueURL {
|
|
15
|
+
owner: string;
|
|
16
|
+
repo: string;
|
|
17
|
+
number: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function parseIssueUrl(url: string): IssueURL;
|
|
20
|
+
/** Fetch issue comments for claim detection. */
|
|
21
|
+
export declare function fetchComments(owner: string, repo: string, number: number): Promise<CommentSignal[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Find PRs that reference an issue. Timeline cross-references and a text
|
|
24
|
+
* search for the issue number are discovery only: every candidate PR is
|
|
25
|
+
* then fetched individually and scored with classifyLinkStrength, so a PR
|
|
26
|
+
* that merely lists a sibling issue (e.g. pdfcn #91 closing #70 while
|
|
27
|
+
* mentioning #61) is stored as a "mention", not a "closing" PR. See issue #1.
|
|
28
|
+
*/
|
|
29
|
+
export declare function fetchLinkedPRs(owner: string, repo: string, number: number): Promise<LinkedPR[]>;
|
|
30
|
+
/** Minimal PR detail needed for the comment-mention cross-check. */
|
|
31
|
+
export interface PullRefDetail {
|
|
32
|
+
number: number;
|
|
33
|
+
state: "open" | "closed";
|
|
34
|
+
merged: boolean;
|
|
35
|
+
title: string;
|
|
36
|
+
body: string;
|
|
37
|
+
url: string;
|
|
38
|
+
}
|
|
39
|
+
export interface MentionedPRDeps {
|
|
40
|
+
fetchPull?: (owner: string, repo: string, number: number) => Promise<PullRefDetail | null>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Policy files fetched for gate extraction. Binding contribution rules
|
|
44
|
+
* increasingly live in house-rules files that CONTRIBUTING only links to
|
|
45
|
+
* (reticle keeps its claim-first, DCO, .changes and `pnpm verify` rules in
|
|
46
|
+
* AGENTS.md), so CONTRIBUTING variants are fetched together with AGENTS.md
|
|
47
|
+
* and CLAUDE.md at the root and under .github/. fastmcp moved its rules
|
|
48
|
+
* again in 2026, into docs/development/contributing.mdx behind a pointer
|
|
49
|
+
* CONTRIBUTING.md, which is why the development-guide paths are here too.
|
|
50
|
+
*/
|
|
51
|
+
export declare const HOUSE_RULE_FILES: readonly ["CONTRIBUTING.md", "contributing.md", ".github/CONTRIBUTING.md", "docs/development/contributing.mdx", "docs/development/contributing.md", "AGENTS.md", "CLAUDE.md", ".github/AGENTS.md", ".github/CLAUDE.md"];
|
|
52
|
+
export interface HouseRuleDeps {
|
|
53
|
+
/** Test seam: fetch a repo-root file's raw text, or undefined when absent. */
|
|
54
|
+
fetchRaw?: (file: string) => Promise<string | undefined>;
|
|
55
|
+
}
|
|
56
|
+
/** Fetch all existing house-rules files for a repo (best-effort, cached). */
|
|
57
|
+
export declare function fetchHouseRules(owner: string, repo: string, deps?: HouseRuleDeps): Promise<{
|
|
58
|
+
file: string;
|
|
59
|
+
text: string;
|
|
60
|
+
}[]>;
|
|
61
|
+
/** Fetch CONTRIBUTING.md raw text; returns undefined when the repo has none. */
|
|
62
|
+
export declare function fetchContributing(owner: string, repo: string): Promise<string | undefined>;
|
|
63
|
+
/**
|
|
64
|
+
* Extract PR references from comment bodies: bare #NNN mentions and full
|
|
65
|
+
* github.com/<owner>/<repo>/pull/NNN URLs. Returns deduplicated numbers in
|
|
66
|
+
* order of first appearance.
|
|
67
|
+
*/
|
|
68
|
+
export declare function extractPRReferences(comments: CommentSignal[], owner: string, repo: string): number[];
|
|
69
|
+
/**
|
|
70
|
+
* PR references per citing comment author: number -> first comment author
|
|
71
|
+
* that cited it. Used to tag MentionedPRs with fromAuthor.
|
|
72
|
+
*/
|
|
73
|
+
export declare function extractPRReferenceAuthors(comments: CommentSignal[], owner: string, repo: string): Map<number, string>;
|
|
74
|
+
/**
|
|
75
|
+
* Cross-check PR references found in comments against the PR API.
|
|
76
|
+
*
|
|
77
|
+
* Motivation: reticlehq/reticle#691 got a clean GO verdict while its comments
|
|
78
|
+
* contained a partial claim ("Taking the remaining fallback ask") and a
|
|
79
|
+
* heads-up that PR #861 covers that work. Neither signal existed in the
|
|
80
|
+
* timeline or the issue-number search, so both were missed.
|
|
81
|
+
*
|
|
82
|
+
* All comments are scanned (PR references are cheap to extract), but each
|
|
83
|
+
* result records whether the citing comment came from the issue author.
|
|
84
|
+
* The open-PR downgrade (rule 11) only trusts non-author heads-ups; the
|
|
85
|
+
* partially-addressed rule (rule 12) also reads the author's, because the
|
|
86
|
+
* maintainer narrating what already shipped is usually the issue author.
|
|
87
|
+
* References already found via the timeline/search, and the issue's own
|
|
88
|
+
* number, are skipped. Bounded at 5 PR fetches per call; the walk is
|
|
89
|
+
* best-effort and cached like the rest of the issue data.
|
|
90
|
+
*/
|
|
91
|
+
export declare function fetchCommentMentionedPRs(owner: string, repo: string, issueNumber: number, comments: CommentSignal[], knownPRNumbers: number[], deps?: MentionedPRDeps & {
|
|
92
|
+
issueAuthor?: string;
|
|
93
|
+
}): Promise<MentionedPR[]>;
|
|
94
|
+
export interface WorkflowDeps {
|
|
95
|
+
/** Test seam: list .github/workflows file names, or undefined when the directory is absent. */
|
|
96
|
+
listFiles?: () => Promise<string[] | undefined>;
|
|
97
|
+
/** Test seam: fetch one workflow file's raw text, or undefined when absent. */
|
|
98
|
+
fetchRaw?: (name: string) => Promise<string | undefined>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* List the repo's .github/workflows files and fetch their contents
|
|
102
|
+
* (best-effort, cached). Contents fetch uses raw.githubusercontent, so it
|
|
103
|
+
* does not consume the api.github.com rate limit. Capped at 12 files: a
|
|
104
|
+
* repo with more workflows still shows the signal on the suspiciously
|
|
105
|
+
* named ones first (they are not reordered; name matching catches them).
|
|
106
|
+
*/
|
|
107
|
+
export declare function listWorkflows(owner: string, repo: string, deps?: WorkflowDeps): Promise<WorkflowFile[]>;
|
|
108
|
+
/** Scan a repo's workflows for auto-close automation; returns detected-only gates. */
|
|
109
|
+
export declare function scanWorkflowGates(owner: string, repo: string, deps?: WorkflowDeps): Promise<Gate[]>;
|
|
110
|
+
/**
|
|
111
|
+
* Extract duplicate target issue numbers from comment bodies ("duplicate
|
|
112
|
+
* of #N", GitHub's "This issue has been marked as a duplicate of #N").
|
|
113
|
+
* Pure; tests drive it directly. The last capture group always holds the
|
|
114
|
+
* number.
|
|
115
|
+
*/
|
|
116
|
+
export declare function extractDuplicateTargets(comments: CommentSignal[]): number[];
|
|
117
|
+
export interface DuplicateTargetDeps {
|
|
118
|
+
/** Test seam: issue timeline events, used instead of the live call. */
|
|
119
|
+
timelineEvents?: Array<Record<string, unknown>>;
|
|
120
|
+
/** Test seam: fetch a referenced issue's live state. */
|
|
121
|
+
fetchIssue?: (owner: string, repo: string, number: number) => Promise<{
|
|
122
|
+
state: string;
|
|
123
|
+
stateReason?: string;
|
|
124
|
+
} | null>;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Find other issues this one is marked a duplicate of. Signals: "duplicate
|
|
128
|
+
* of #N" comments (n8n's bot posts "marked as a duplicate of #N"), and
|
|
129
|
+
* marked_as_duplicate timeline events when the API surfaces them. Each
|
|
130
|
+
* unique target is fetched for its current state (bounded at 3), because
|
|
131
|
+
* only a target closed as completed means the work already shipped and a
|
|
132
|
+
* build here is wasted.
|
|
133
|
+
*/
|
|
134
|
+
export declare function fetchDuplicateTargets(owner: string, repo: string, number: number, comments: CommentSignal[], deps?: DuplicateTargetDeps): Promise<DuplicateTarget[]>;
|
|
135
|
+
/** A PR URL found in a fix-announcement comment, possibly in another repo of the same org. */
|
|
136
|
+
export interface AttemptPRLink {
|
|
137
|
+
author: string;
|
|
138
|
+
owner: string;
|
|
139
|
+
repo: string;
|
|
140
|
+
number: number;
|
|
141
|
+
url: string;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Extract PR links from fix-announcement comments. Comments from bots and
|
|
145
|
+
* from the issue author are skipped. The URLs routinely point at sibling
|
|
146
|
+
* repos in the same org (tscircuit/tscircuit#5563's fixes live in
|
|
147
|
+
* tscircuit/core and tscircuit/checks), so they are not limited to the
|
|
148
|
+
* issue's own repo. Pure; tests drive it directly. Bounded at 5 links.
|
|
149
|
+
*/
|
|
150
|
+
export declare function extractAttemptLinkedPRs(comments: CommentSignal[], issueAuthor: string): AttemptPRLink[];
|
|
151
|
+
/** Count open issues labelled good-first-issue or help-wanted. */
|
|
152
|
+
export declare function countStarterIssues(owner: string, repo: string): Promise<number | null>;
|
|
153
|
+
/** Detect a collaborators-only PR creation policy via the community metrics endpoint. */
|
|
154
|
+
export declare function detectRepoPolicy(owner: string, repo: string): Promise<{
|
|
155
|
+
collaboratorsOnly: boolean;
|
|
156
|
+
}>;
|
|
157
|
+
/** Build a full IssueSnapshot from the live API. */
|
|
158
|
+
export declare function buildIssueSnapshot(owner: string, repo: string, number: number): Promise<IssueSnapshot>;
|
|
159
|
+
export interface ScanCandidate {
|
|
160
|
+
number: number;
|
|
161
|
+
title: string;
|
|
162
|
+
url: string;
|
|
163
|
+
labels: string[];
|
|
164
|
+
updatedAt: string;
|
|
165
|
+
}
|
|
166
|
+
/** List open good-first-issue / help-wanted issues for scan mode. */
|
|
167
|
+
export declare function listStarterIssues(owner: string, repo: string, limit?: number): Promise<ScanCandidate[]>;
|
|
168
|
+
/** Raw issue-list item shape from GET /repos/:o/:r/issues. */
|
|
169
|
+
interface IssueListItem {
|
|
170
|
+
number: number;
|
|
171
|
+
title: string;
|
|
172
|
+
html_url: string;
|
|
173
|
+
labels: Array<{
|
|
174
|
+
name: string;
|
|
175
|
+
}>;
|
|
176
|
+
updated_at: string;
|
|
177
|
+
pull_request?: unknown;
|
|
178
|
+
assignees?: Array<{
|
|
179
|
+
login: string;
|
|
180
|
+
}>;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Filter raw issue-list items down to scan candidates: real issues (not
|
|
184
|
+
* pull requests) with no assignees, newest first. Pure so tests can drive
|
|
185
|
+
* it with fixtures.
|
|
186
|
+
*/
|
|
187
|
+
export declare function toScanCandidates(items: IssueListItem[]): ScanCandidate[];
|
|
188
|
+
/**
|
|
189
|
+
* Fallback candidate list for scan mode: the most recent open unassigned
|
|
190
|
+
* issues in the repo, for repos whose landable issues do not carry
|
|
191
|
+
* good-first-issue / help-wanted labels. Lists broadly (up to `cap`) so
|
|
192
|
+
* the caller can take the newest slice.
|
|
193
|
+
*/
|
|
194
|
+
export declare function listRecentUnassignedIssues(owner: string, repo: string, cap?: number): Promise<ScanCandidate[]>;
|
|
195
|
+
export interface ScanCandidateList {
|
|
196
|
+
issues: ScanCandidate[];
|
|
197
|
+
/** True when the label pass came back empty and the fallback list was used. */
|
|
198
|
+
fallbackUsed: boolean;
|
|
199
|
+
}
|
|
200
|
+
export interface ScanDeps {
|
|
201
|
+
starter?: (owner: string, repo: string, limit: number) => Promise<ScanCandidate[]>;
|
|
202
|
+
recent?: (owner: string, repo: string, cap: number) => Promise<ScanCandidate[]>;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Scan candidates for a repo: the label-tagged starter list first; when it
|
|
206
|
+
* is empty, fall back to recent open unassigned issues (opt out with
|
|
207
|
+
* fallback: false). Injectable deps keep tests offline.
|
|
208
|
+
*/
|
|
209
|
+
export declare function scanCandidates(owner: string, repo: string, opts?: {
|
|
210
|
+
fallback?: boolean;
|
|
211
|
+
limit?: number;
|
|
212
|
+
}, deps?: ScanDeps): Promise<ScanCandidateList>;
|
|
213
|
+
export type { GateKind };
|