@reneturcios/greenlight 0.9.2 → 0.10.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 +35 -0
- package/dist/automate.js +11 -17
- package/dist/automate.js.map +1 -1
- package/dist/babysit.d.ts +10 -1
- package/dist/babysit.js +37 -6
- package/dist/babysit.js.map +1 -1
- package/dist/claims-registry.d.ts +21 -0
- package/dist/claims-registry.js +6 -1
- package/dist/claims-registry.js.map +1 -1
- package/dist/cli.js +70 -32
- package/dist/cli.js.map +1 -1
- package/dist/digest.d.ts +0 -1
- package/dist/digest.js +2 -2
- package/dist/digest.js.map +1 -1
- package/dist/friction.d.ts +12 -4
- package/dist/friction.js +45 -14
- package/dist/friction.js.map +1 -1
- package/dist/gates.d.ts +16 -0
- package/dist/gates.js +169 -4
- package/dist/gates.js.map +1 -1
- package/dist/github.d.ts +21 -1
- package/dist/github.js +93 -13
- package/dist/github.js.map +1 -1
- package/dist/guard.d.ts +0 -1
- package/dist/guard.js +2 -2
- package/dist/guard.js.map +1 -1
- package/dist/help.js +31 -1
- package/dist/help.js.map +1 -1
- package/dist/index.js +36 -2
- package/dist/index.js.map +1 -1
- package/dist/portfolio.d.ts +77 -0
- package/dist/portfolio.js +108 -0
- package/dist/portfolio.js.map +1 -0
- package/dist/posting-ledger.d.ts +51 -1
- package/dist/posting-ledger.js +145 -8
- package/dist/posting-ledger.js.map +1 -1
- package/dist/scout.d.ts +5 -0
- package/dist/scout.js +9 -1
- package/dist/scout.js.map +1 -1
- package/dist/sync.d.ts +88 -0
- package/dist/sync.js +320 -0
- package/dist/sync.js.map +1 -0
- package/dist/types.d.ts +15 -0
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/friction.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { gateLabel } from "./gates.js";
|
|
2
|
-
import {
|
|
3
|
-
import { parseGates } from "./gates.js";
|
|
1
|
+
import { gateLabel, parseGatesFromSources } from "./gates.js";
|
|
2
|
+
import { fetchPolicySources, detectRepoPolicy, countStarterIssues, } from "./github.js";
|
|
4
3
|
import { fetchMergeVelocity } from "./merge-velocity.js";
|
|
5
4
|
const GATE_WEIGHTS = {
|
|
6
5
|
assignment_required: -25,
|
|
@@ -47,38 +46,70 @@ export function scoreFriction(signals) {
|
|
|
47
46
|
if (bonus > 0)
|
|
48
47
|
reasons.push(`${signals.openGoodFirstIssueCount} open good-first-issues (+${bonus.toFixed(1)})`);
|
|
49
48
|
}
|
|
49
|
+
// v0.9.3: ratio fields in JSON always ship both units. The fraction
|
|
50
|
+
// keeps its meaning; the _pct sibling is unambiguous.
|
|
51
|
+
const signalsOut = {
|
|
52
|
+
...signals,
|
|
53
|
+
externalPRMergeRate_pct: signals.externalPRMergeRate === undefined || signals.externalPRMergeRate === null
|
|
54
|
+
? null
|
|
55
|
+
: Math.round(signals.externalPRMergeRate * 100),
|
|
56
|
+
};
|
|
50
57
|
return {
|
|
51
58
|
owner: signals.owner,
|
|
52
59
|
repo: signals.repo,
|
|
53
60
|
score: Math.round(clamp(score, 0, 100)),
|
|
54
61
|
gates: signals.gates,
|
|
55
62
|
reasons,
|
|
56
|
-
signals,
|
|
63
|
+
signals: signalsOut,
|
|
57
64
|
};
|
|
58
65
|
}
|
|
59
66
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
|
|
67
|
+
* Attach the outsider merge share to a friction report with an explicit
|
|
68
|
+
* unit contract (v0.9.3): the fraction and the 0..100 percent side by
|
|
69
|
+
* side, so no consumer can mistake one for the other again.
|
|
70
|
+
*/
|
|
71
|
+
export function attachOutsiderShare(report) {
|
|
72
|
+
const share = report.signals.externalPRMergeRate ??
|
|
73
|
+
report.mergeVelocity?.externalShare ??
|
|
74
|
+
null;
|
|
75
|
+
report.outsider_merge_share = share;
|
|
76
|
+
report.outsider_merge_share_pct = share === null ? null : Math.round(share * 100);
|
|
77
|
+
return report;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The repo_friction pipeline as one callable: gates from the full policy
|
|
81
|
+
* source set (CONTRIBUTING variants and house rules at root, .github/
|
|
82
|
+
* and docs/, plus the org-level AI_POLICY.md), starter-issue count, and
|
|
83
|
+
* merge velocity as a best-effort signal. Shared by the CLI, the MCP
|
|
84
|
+
* repo_friction tool, and the protocol preflight (which pairs it with
|
|
85
|
+
* the issue status).
|
|
64
86
|
*/
|
|
65
87
|
export async function fetchFrictionSummary(owner, repo) {
|
|
66
|
-
const [
|
|
67
|
-
|
|
88
|
+
const [sources, policy, starterCount] = await Promise.all([
|
|
89
|
+
fetchPolicySources(owner, repo),
|
|
68
90
|
detectRepoPolicy(owner, repo),
|
|
69
91
|
countStarterIssues(owner, repo),
|
|
70
92
|
]);
|
|
71
|
-
const gates =
|
|
72
|
-
|
|
93
|
+
const gates = parseGatesFromSources(sources);
|
|
94
|
+
if (policy.collaboratorsOnly && !gates.some((g) => g.kind === "collaborators_only" && g.detected)) {
|
|
95
|
+
gates.push({
|
|
96
|
+
kind: "collaborators_only",
|
|
97
|
+
detected: true,
|
|
98
|
+
evidence: "repo policy: PR creation restricted to collaborators",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const signals = {
|
|
73
102
|
owner,
|
|
74
103
|
repo,
|
|
75
104
|
gates,
|
|
76
105
|
externalPRMergeRate: null,
|
|
106
|
+
externalPRMergeRate_pct: null,
|
|
77
107
|
medianFirstReviewHours: null,
|
|
78
108
|
maintainerIssueResponseHours: null,
|
|
79
109
|
openGoodFirstIssueCount: starterCount,
|
|
80
110
|
note: "live",
|
|
81
|
-
}
|
|
111
|
+
};
|
|
112
|
+
const report = scoreFriction(signals);
|
|
82
113
|
// Merge velocity is a signal, never a score input. Best-effort: silent
|
|
83
114
|
// when it fails.
|
|
84
115
|
try {
|
|
@@ -87,6 +118,6 @@ export async function fetchFrictionSummary(owner, repo) {
|
|
|
87
118
|
catch {
|
|
88
119
|
report.mergeVelocity = null;
|
|
89
120
|
}
|
|
90
|
-
return report;
|
|
121
|
+
return attachOutsiderShare(report);
|
|
91
122
|
}
|
|
92
123
|
//# sourceMappingURL=friction.js.map
|
package/dist/friction.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"friction.js","sourceRoot":"","sources":["../src/friction.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"friction.js","sourceRoot":"","sources":["../src/friction.ts"],"names":[],"mappings":"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"}
|
package/dist/gates.d.ts
CHANGED
|
@@ -13,6 +13,22 @@
|
|
|
13
13
|
* first and get rejected, while soft gates like claim_first only add a note.
|
|
14
14
|
*/
|
|
15
15
|
import type { Gate, GateKind } from "./types.js";
|
|
16
|
+
/**
|
|
17
|
+
* v0.9.3 contradiction resolution (per policy file, never across files).
|
|
18
|
+
* Runs over one source's parsed gates plus its raw text:
|
|
19
|
+
* - An UNSCOPED ban (explicit prohibition: no autonomous agents, no AI
|
|
20
|
+
* PRs) stands on its own; welcome language elsewhere does not cancel an
|
|
21
|
+
* explicit prohibition (zed welcomes LLM coding and still bans
|
|
22
|
+
* autonomous-agent contributions, and both verdicts are correct).
|
|
23
|
+
* - A SCOPED ban (bulk/autonomous-only, unreviewed-only) plus welcome or
|
|
24
|
+
* disclosure language in the same file dual-classes: agents_banned
|
|
25
|
+
* (evidence: the scoped quote) AND agents_disclosure. If no disclosure
|
|
26
|
+
* pattern fired, the disclosure entry is synthesized from the welcome
|
|
27
|
+
* sentence so the human path is never silently lost (ppt-master,
|
|
28
|
+
* TypeScript). The ban is never downgraded away: for autonomous
|
|
29
|
+
* operation it is real.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveBanContradictions(gates: Gate[], text: string): Gate[];
|
|
16
32
|
export interface ParseOptions {
|
|
17
33
|
/** Repo-level policy passed in when detectable (e.g. from repo metadata). */
|
|
18
34
|
collaboratorsOnlyPolicy?: boolean;
|
package/dist/gates.js
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.9.3: ban patterns scoped to a KIND of agent operation rather than a
|
|
3
|
+
* blanket prohibition. TypeScript's CONTRIBUTING refuses "bulk,
|
|
4
|
+
* agent-driven contributions" outright while welcoming human-led AI work
|
|
5
|
+
* with disclosure; ppt-master closes "purely AI-generated PRs submitted
|
|
6
|
+
* without human review" while welcoming reviewed AI assistance. A scoped
|
|
7
|
+
* ban is still a ban for autonomous operation, but the file's welcome or
|
|
8
|
+
* disclosure path must survive next to it (dual-class), never be silently
|
|
9
|
+
* swallowed by the ban verdict. These patterns are spread into the
|
|
10
|
+
* agents_banned rule below and are ALSO listed here so the contradiction
|
|
11
|
+
* resolver can tell a scoped ban from an unscoped one. Every scoped
|
|
12
|
+
* pattern requires a consequence clause (refused, closed, not accepted)
|
|
13
|
+
* so bare quality guidance ("understand what you submit") never counts
|
|
14
|
+
* as a ban.
|
|
15
|
+
*/
|
|
16
|
+
const SCOPED_BAN_REGEXES = [
|
|
17
|
+
/do not accept.{0,80}(bulk|autonomous).{0,30}(agent|ai)[-\s]?driven (contributions?|pull requests?|prs?)/i,
|
|
18
|
+
/(bulk|mass)[-\s]?(agent|ai)[-\s]?driven (contributions?|pull requests?|prs?).{0,80}(not accepted|refused|will be closed|are not welcome|do not accept)/i,
|
|
19
|
+
/(purely|fully|entirely) ai[-\s]?(generated|authored|drafted).{0,50}(without human review|unreviewed|without (a )?human in the loop).{0,80}(closed|rejected|not a contribution|will not be merged)/i,
|
|
20
|
+
];
|
|
1
21
|
const RULES = [
|
|
2
22
|
{
|
|
3
23
|
kind: "assignment_required",
|
|
@@ -104,14 +124,40 @@ const RULES = [
|
|
|
104
124
|
// rules are anchored on explicit agent/bot-prohibition language, not
|
|
105
125
|
// on the mere word "AI", to avoid flagging repos that merely discuss
|
|
106
126
|
// AI features or ask for disclosure.
|
|
127
|
+
//
|
|
128
|
+
// v0.9.3: the Agent Policy Index field work found nine more bans the
|
|
129
|
+
// old patterns missed because they live in CONTRIBUTING.md or in an
|
|
130
|
+
// org-level AI_POLICY.md, in prose the old patterns never covered:
|
|
131
|
+
// immich ("We ask you not to open PRs generated with an LLM"),
|
|
132
|
+
// meilisearch ("We will not consider any content generated by
|
|
133
|
+
// generative AI tooling"), alacritty ("must not include content
|
|
134
|
+
// generated by large language models"), zed ("we don't accept
|
|
135
|
+
// contributions from autonomous agents"), astral-sh ("We do not allow
|
|
136
|
+
// autonomous agents to be used for contributing"), dspy ("Do not
|
|
137
|
+
// submit issues, PRs, or reviews from fully autonomous AI agents"),
|
|
138
|
+
// kedro ("We do not welcome AI contributions by bots with no human in
|
|
139
|
+
// the loop", "PRs must not be opened by bots"), home-assistant
|
|
140
|
+
// ("Contributions made by autonomous agents are not accepted", via
|
|
141
|
+
// its AI_POLICY.md). Each new pattern below is anchored on an
|
|
142
|
+
// explicit prohibition, never on the mere mention of AI tooling.
|
|
107
143
|
kind: "agents_banned",
|
|
108
144
|
regexes: [
|
|
109
145
|
/autonomous agents? (are|will be) not (allowed|accepted|welcome|permitted)/i,
|
|
110
146
|
/contributions? (by|from) autonomous agents? (are|is) not allowed/i,
|
|
111
147
|
/may only be submitted by a human/i,
|
|
112
148
|
/no ai[-\s]?(generated|authored|written) (pull requests?|prs?|contributions?)/i,
|
|
113
|
-
/do not (
|
|
149
|
+
/do not (draft|post).{0,80}(pr titles?|pr descriptions?|pull requests?|issues?, or discussion)/i,
|
|
114
150
|
/\b(bots?|agents?) (are|will be) (prohibited|banned|forbidden).{0,60}(from )?(contribut|opening|submitting)/i,
|
|
151
|
+
/(ask you )?not to open (prs?|pull requests?) generated (with|by) (an? )?(llm|ai)\b/i,
|
|
152
|
+
/(will not|do not|don't|does not) consider.{0,50}(content )?generated by (generative )?ai\b/i,
|
|
153
|
+
/(must not|shall not|may not|cannot).{0,50}content generated by (large language models|llms?|generative ai|ai)\b/i,
|
|
154
|
+
/(do not|don't|does not) accept.{0,60}(contributions?|prs?|pull requests?).{0,40}(from )?autonomous agents?/i,
|
|
155
|
+
/(do not|don't|does not) allow.{0,50}autonomous agents?/i,
|
|
156
|
+
/do not submit.{0,80}(from )?(fully )?autonomous (ai )?agents?/i,
|
|
157
|
+
/(do not|don't|does not) welcome.{0,40}ai contributions?/i,
|
|
158
|
+
/(pull requests?|prs?).{0,40}(must not|may not|cannot|will not) be opened by (bots|automated|agents?)/i,
|
|
159
|
+
/autonomous (ai )?agents? may not (submit|open|contribute)/i,
|
|
160
|
+
...SCOPED_BAN_REGEXES,
|
|
115
161
|
],
|
|
116
162
|
},
|
|
117
163
|
{
|
|
@@ -120,16 +166,120 @@ const RULES = [
|
|
|
120
166
|
// and an AI disclosure sentence in the PR description. Disclosure is
|
|
121
167
|
// a ritual to satisfy, not a block, so this is a flag, never a
|
|
122
168
|
// verdict change: prep turns it into concrete required actions.
|
|
169
|
+
//
|
|
170
|
+
// v0.9.3: the old patterns only caught "disclosure" next to "AI" in
|
|
171
|
+
// one word order, so meilisearch ("If you use AI tools during your
|
|
172
|
+
// work, remember to disclose it in your PR description"), astral-sh
|
|
173
|
+
// ("disclosed as such"), and coolify ("If AI tools were used at any
|
|
174
|
+
// stage, mention it in the pull request description") all slipped
|
|
175
|
+
// through. The new patterns cover both orders and the "mention"
|
|
176
|
+
// phrasing. They stay anchored on an explicit ask, so a repo that
|
|
177
|
+
// merely waives disclosure (hyperframes: "there is no need to
|
|
178
|
+
// disclose it") still reads as no disclosure gate.
|
|
123
179
|
kind: "agents_disclosure",
|
|
124
180
|
regexes: [
|
|
125
181
|
/\bai\b.{0,40}disclosure/i,
|
|
126
182
|
/disclos(e|ing).{0,40}\bai\b/i,
|
|
183
|
+
/\bai\b.{0,60}disclos(e|ing|ure)/i,
|
|
184
|
+
/\b(ai|artificial intelligence)\b.{0,40}(mention|state|note|indicate|declare|disclose)/i,
|
|
185
|
+
/require.{0,25}(you )?to disclose/i,
|
|
186
|
+
/disclosed as such/i,
|
|
127
187
|
/\[ai\].{0,60}(prefix|title|commit)/i,
|
|
128
188
|
/(prefix|title).{0,60}\[ai\]/i,
|
|
129
189
|
/ai[-\s]?generated.{0,60}(disclos|prefix|declare)/i,
|
|
130
190
|
],
|
|
131
191
|
},
|
|
132
192
|
];
|
|
193
|
+
/**
|
|
194
|
+
* v0.9.3: explicit welcome of AI-assisted contributions. Internal signal
|
|
195
|
+
* only, never a gate kind: it feeds the contradiction resolver so a ban
|
|
196
|
+
* verdict can never silently erase a file's welcome or disclosure path
|
|
197
|
+
* (the hyperframes false-ban shape: "Do not submit AI-generated code you
|
|
198
|
+
* don't understand" next to "We welcome contributions that use AI tools...
|
|
199
|
+
* there is no need to disclose it"). Generic "we welcome contributions"
|
|
200
|
+
* prose does not count; the welcome must name AI.
|
|
201
|
+
*/
|
|
202
|
+
const AI_WELCOME_RES = [
|
|
203
|
+
/we welcome.{0,80}\b(ai|artificial intelligence|llms?)\b/i,
|
|
204
|
+
/\bai[-\s]?(assistance|tools?) (is|are) welcome/i,
|
|
205
|
+
/we are pro ai assisted coding/i,
|
|
206
|
+
/(have|has) no objection to.{0,60}ai\b/i,
|
|
207
|
+
/there is no need to disclose/i,
|
|
208
|
+
];
|
|
209
|
+
/**
|
|
210
|
+
* v0.9.3 contradiction resolution (per policy file, never across files).
|
|
211
|
+
* Runs over one source's parsed gates plus its raw text:
|
|
212
|
+
* - An UNSCOPED ban (explicit prohibition: no autonomous agents, no AI
|
|
213
|
+
* PRs) stands on its own; welcome language elsewhere does not cancel an
|
|
214
|
+
* explicit prohibition (zed welcomes LLM coding and still bans
|
|
215
|
+
* autonomous-agent contributions, and both verdicts are correct).
|
|
216
|
+
* - A SCOPED ban (bulk/autonomous-only, unreviewed-only) plus welcome or
|
|
217
|
+
* disclosure language in the same file dual-classes: agents_banned
|
|
218
|
+
* (evidence: the scoped quote) AND agents_disclosure. If no disclosure
|
|
219
|
+
* pattern fired, the disclosure entry is synthesized from the welcome
|
|
220
|
+
* sentence so the human path is never silently lost (ppt-master,
|
|
221
|
+
* TypeScript). The ban is never downgraded away: for autonomous
|
|
222
|
+
* operation it is real.
|
|
223
|
+
*/
|
|
224
|
+
export function resolveBanContradictions(gates, text) {
|
|
225
|
+
const body = (text ?? "").replace(/\*+/g, "").replace(/\s+/g, " ");
|
|
226
|
+
const ban = gates.find((g) => g.kind === "agents_banned");
|
|
227
|
+
if (!ban || !ban.detected)
|
|
228
|
+
return gates;
|
|
229
|
+
const unscopedFired = UNSCOPED_BAN_RES.some((re) => re.test(body));
|
|
230
|
+
if (unscopedFired)
|
|
231
|
+
return gates;
|
|
232
|
+
const scopedFired = SCOPED_BAN_REGEXES.some((re) => re.test(body));
|
|
233
|
+
if (!scopedFired)
|
|
234
|
+
return gates;
|
|
235
|
+
const disclosure = gates.find((g) => g.kind === "agents_disclosure");
|
|
236
|
+
const welcomeFired = AI_WELCOME_RES.some((re) => re.test(body));
|
|
237
|
+
if (disclosure && disclosure.detected)
|
|
238
|
+
return gates;
|
|
239
|
+
if (!welcomeFired)
|
|
240
|
+
return gates;
|
|
241
|
+
// Scoped ban plus a welcome, but no disclosure pattern matched: the
|
|
242
|
+
// file describes a human-led path (review, understand, disclose), so
|
|
243
|
+
// surface it as agents_disclosure with the welcome as evidence rather
|
|
244
|
+
// than letting the ban verdict stand alone.
|
|
245
|
+
if (disclosure) {
|
|
246
|
+
disclosure.detected = true;
|
|
247
|
+
disclosure.evidence = snippet(body, AI_WELCOME_RES.find((re) => re.test(body)));
|
|
248
|
+
}
|
|
249
|
+
return gates;
|
|
250
|
+
}
|
|
251
|
+
/** The agents_banned patterns that are NOT scoped (explicit prohibitions). */
|
|
252
|
+
const UNSCOPED_BAN_RES = [
|
|
253
|
+
/autonomous agents? (are|will be) not (allowed|accepted|welcome|permitted)/i,
|
|
254
|
+
/contributions? (by|from) autonomous agents? (are|is) not allowed/i,
|
|
255
|
+
/may only be submitted by a human/i,
|
|
256
|
+
/no ai[-\s]?(generated|authored|written) (pull requests?|prs?|contributions?)/i,
|
|
257
|
+
/do not (draft|post).{0,80}(pr titles?|pr descriptions?|pull requests?|issues?, or discussion)/i,
|
|
258
|
+
/\b(bots?|agents?) (are|will be) (prohibited|banned|forbidden).{0,60}(from )?(contribut|opening|submitting)/i,
|
|
259
|
+
/(ask you )?not to open (prs?|pull requests?) generated (with|by) (an? )?(llm|ai)\b/i,
|
|
260
|
+
/(will not|do not|don't|does not) consider.{0,50}(content )?generated by (generative )?ai\b/i,
|
|
261
|
+
/(must not|shall not|may not|cannot).{0,50}content generated by (large language models|llms?|generative ai|ai)\b/i,
|
|
262
|
+
/(do not|don't|does not) accept.{0,60}(contributions?|prs?|pull requests?).{0,40}(from )?autonomous agents?/i,
|
|
263
|
+
/(do not|don't|does not) allow.{0,50}autonomous agents?/i,
|
|
264
|
+
/do not submit.{0,80}(from )?(fully )?autonomous (ai )?agents?/i,
|
|
265
|
+
/(do not|don't|does not) welcome.{0,40}ai contributions?/i,
|
|
266
|
+
/(pull requests?|prs?).{0,40}(must not|may not|cannot|will not) be opened by (bots|automated|agents?)/i,
|
|
267
|
+
/autonomous (ai )?agents? may not (submit|open|contribute)/i,
|
|
268
|
+
];
|
|
269
|
+
/**
|
|
270
|
+
* v0.9.3: explicit disclosure WAIVERS. hyperframes welcomes AI help and
|
|
271
|
+
* says "there is no need to disclose it" — a waiver is the opposite of a
|
|
272
|
+
* disclosure gate, so when waiver language is present the disclosure gate
|
|
273
|
+
* is suppressed. A file cannot both require and waive disclosure; the
|
|
274
|
+
* waiver wins because it is the more specific statement about the repo's
|
|
275
|
+
* actual ask.
|
|
276
|
+
*/
|
|
277
|
+
const DISCLOSURE_WAIVER_RES = [
|
|
278
|
+
/there is no need to disclose/i,
|
|
279
|
+
/no disclosure (is )?required/i,
|
|
280
|
+
/disclosure is not required/i,
|
|
281
|
+
/waives? disclosure/i,
|
|
282
|
+
];
|
|
133
283
|
/** Cut a short evidence snippet around the first regex match. */
|
|
134
284
|
function snippet(text, regex) {
|
|
135
285
|
const match = regex.exec(text);
|
|
@@ -157,7 +307,10 @@ export function parseGatesFromSources(sources) {
|
|
|
157
307
|
source: undefined,
|
|
158
308
|
}));
|
|
159
309
|
for (const src of ordered) {
|
|
160
|
-
|
|
310
|
+
// v0.9.3: contradiction resolution runs per file, before merging, so
|
|
311
|
+
// a scoped ban plus welcome/disclosure in the same file dual-classes
|
|
312
|
+
// instead of the ban verdict silently erasing the human path.
|
|
313
|
+
const gates = resolveBanContradictions(parseGates(src.text), src.text);
|
|
161
314
|
for (const g of gates) {
|
|
162
315
|
if (!g.detected)
|
|
163
316
|
continue;
|
|
@@ -176,8 +329,14 @@ export function parseGatesFromSources(sources) {
|
|
|
176
329
|
* with detected true/false, plus an evidence snippet when detected.
|
|
177
330
|
*/
|
|
178
331
|
export function parseGates(text, options = {}) {
|
|
179
|
-
|
|
180
|
-
|
|
332
|
+
// v0.9.3: collapse whitespace and strip markdown emphasis before
|
|
333
|
+
// matching. Policy files wrap lines mid-phrase ("autonomous\nagents
|
|
334
|
+
// are not accepted"), and bold markers split keywords ("to
|
|
335
|
+
// **disclose"), both of which a literal pattern would miss. Matching
|
|
336
|
+
// is on the normalized body; evidence snippets were already
|
|
337
|
+
// whitespace-collapsed for display.
|
|
338
|
+
const body = (text ?? "").replace(/\*+/g, "").replace(/\s+/g, " ");
|
|
339
|
+
const gates = RULES.map((rule) => {
|
|
181
340
|
const found = rule.regexes.find((re) => re.test(body));
|
|
182
341
|
if (rule.kind === "collaborators_only" && options.collaboratorsOnlyPolicy) {
|
|
183
342
|
return {
|
|
@@ -192,6 +351,12 @@ export function parseGates(text, options = {}) {
|
|
|
192
351
|
evidence: found ? snippet(body, found) : "",
|
|
193
352
|
};
|
|
194
353
|
});
|
|
354
|
+
const disclosure = gates.find((g) => g.kind === "agents_disclosure");
|
|
355
|
+
if (disclosure && disclosure.detected && DISCLOSURE_WAIVER_RES.some((re) => re.test(body))) {
|
|
356
|
+
disclosure.detected = false;
|
|
357
|
+
disclosure.evidence = "";
|
|
358
|
+
}
|
|
359
|
+
return gates;
|
|
195
360
|
}
|
|
196
361
|
/**
|
|
197
362
|
* gatefile's contribution-gates.json kinds mapped onto Greenlight kinds.
|
package/dist/gates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gates.js","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"AAqBA,MAAM,KAAK,GAAe;IACxB;QACE,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE;YACP,wCAAwC;YACxC,2BAA2B;YAC3B,2BAA2B;YAC3B,2CAA2C;YAC3C,yCAAyC;YACzC,sCAAsC;SACvC;KACF;IACD;QACE,qEAAqE;QACrE,sDAAsD;QACtD,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE;YACP,kDAAkD;YAClD,6BAA6B;YAC7B,+CAA+C;SAChD;KACF;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,CAAC,UAAU,EAAE,+BAA+B,CAAC;KACvD;IACD;QACE,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE;YACP,gCAAgC;YAChC,+BAA+B;YAC/B,qBAAqB;SACtB;KACF;IACD;QACE,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE;YACP,UAAU;YACV,kCAAkC;YAClC,oBAAoB;YACpB,gBAAgB;SACjB;KACF;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE;YACP,4CAA4C;YAC5C,uBAAuB;YACvB,2BAA2B;YAC3B,sBAAsB;YACtB,gCAAgC;SACjC;KACF;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE;YACP,qBAAqB;YACrB,qBAAqB;YACrB,6BAA6B;YAC7B,8DAA8D;YAC9D,uEAAuE;YACvE,sEAAsE;YACtE,qEAAqE;YACrE,iEAAiE;YACjE,iEAAiE;YACjE,iEAAiE;YACjE,qEAAqE;YACrE,gIAAgI;YAChI,oCAAoC;SACrC;KACF;IACD;QACE,qEAAqE;QACrE,qEAAqE;QACrE,iEAAiE;QACjE,oEAAoE;QACpE,mEAAmE;QACnE,2CAA2C;QAC3C,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EAAE;YACP,wEAAwE;YACxE,2DAA2D;YAC3D,6BAA6B;SAC9B;KACF;IACD;QACE,qEAAqE;QACrE,sEAAsE;QACtE,iEAAiE;QACjE,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE;YACP,qEAAqE;YACrE,qEAAqE;YACrE,mFAAmF;SACpF;KACF;IACD;QACE,qEAAqE;QACrE,oEAAoE;QACpE,gEAAgE;QAChE,oEAAoE;QACpE,mEAAmE;QACnE,iEAAiE;QACjE,qEAAqE;QACrE,qEAAqE;QACrE,qCAAqC;QACrC,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE;YACP,4EAA4E;YAC5E,mEAAmE;YACnE,mCAAmC;YACnC,+EAA+E;YAC/E,
|
|
1
|
+
{"version":3,"file":"gates.js","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"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"}
|
package/dist/github.d.ts
CHANGED
|
@@ -85,11 +85,31 @@ export interface MentionedPRDeps {
|
|
|
85
85
|
* again in 2026, into docs/development/contributing.mdx behind a pointer
|
|
86
86
|
* CONTRIBUTING.md, which is why the development-guide paths are here too.
|
|
87
87
|
*/
|
|
88
|
-
export declare const HOUSE_RULE_FILES: readonly ["CONTRIBUTING.md", "
|
|
88
|
+
export declare const HOUSE_RULE_FILES: readonly ["CONTRIBUTING.md", ".github/CONTRIBUTING.md", "docs/CONTRIBUTING.md", "contributing.md", "docs/development/contributing.mdx", "docs/development/contributing.md", "AGENTS.md", ".github/AGENTS.md", "docs/AGENTS.md", "CLAUDE.md", ".github/CLAUDE.md", "docs/CLAUDE.md", "AI_POLICY.md", ".github/AI_POLICY.md", "docs/AI_POLICY.md"];
|
|
89
89
|
export interface HouseRuleDeps {
|
|
90
90
|
/** Test seam: fetch a repo-root file's raw text, or undefined when absent. */
|
|
91
91
|
fetchRaw?: (file: string) => Promise<string | undefined>;
|
|
92
|
+
/** Test seam: fetch the org's AI_POLICY.md text, or undefined when absent. */
|
|
93
|
+
fetchOrgPolicy?: (owner: string) => Promise<string | undefined>;
|
|
92
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* v0.9.3: org-level AI policy. Binding agent rules sometimes live in the
|
|
97
|
+
* org's `.github` repo rather than the project repo (astral-sh's
|
|
98
|
+
* AI_POLICY.md bans autonomous agents for ruff and uv; mastodon's
|
|
99
|
+
* CONTRIBUTING only links to mastodon/.github's AI_POLICY.md). Probed
|
|
100
|
+
* once per org and cached under its own key so a sweep over N repos from
|
|
101
|
+
* one org costs one fetch, not N.
|
|
102
|
+
*/
|
|
103
|
+
export declare function fetchOrgAiPolicy(owner: string, deps?: HouseRuleDeps): Promise<string | undefined>;
|
|
104
|
+
/**
|
|
105
|
+
* v0.9.3: the full policy source set for gate detection: house-rules
|
|
106
|
+
* files (first hit per filename across root, .github/, docs/) plus the
|
|
107
|
+
* org-level AI_POLICY.md when the org publishes one.
|
|
108
|
+
*/
|
|
109
|
+
export declare function fetchPolicySources(owner: string, repo: string, deps?: HouseRuleDeps): Promise<{
|
|
110
|
+
file: string;
|
|
111
|
+
text: string;
|
|
112
|
+
}[]>;
|
|
93
113
|
/** Fetch all existing house-rules files for a repo (best-effort, cached). */
|
|
94
114
|
export declare function fetchHouseRules(owner: string, repo: string, deps?: HouseRuleDeps): Promise<{
|
|
95
115
|
file: string;
|
package/dist/github.js
CHANGED
|
@@ -39,6 +39,11 @@ const TTL_MS = {
|
|
|
39
39
|
issue: 6 * 60 * 60 * 1000,
|
|
40
40
|
search: 60 * 60 * 1000,
|
|
41
41
|
contributing: 24 * 60 * 60 * 1000,
|
|
42
|
+
// v0.9.3: house-rules and org-ai-policy had no TTL entry, which made
|
|
43
|
+
// `> undefined` false forever: a cached read never expired, so a repo
|
|
44
|
+
// whose policy files were once unreadable stayed "no policy" forever.
|
|
45
|
+
"house-rules": 60 * 60 * 1000,
|
|
46
|
+
"org-ai-policy": 24 * 60 * 60 * 1000,
|
|
42
47
|
// LLM claim classifications: comment bodies are immutable, so a long TTL
|
|
43
48
|
// means repeat checks cost nothing after the first classification.
|
|
44
49
|
llm: 30 * 24 * 60 * 60 * 1000,
|
|
@@ -352,15 +357,84 @@ export async function fetchLinkedPRs(owner, repo, number) {
|
|
|
352
357
|
*/
|
|
353
358
|
export const HOUSE_RULE_FILES = [
|
|
354
359
|
"CONTRIBUTING.md",
|
|
355
|
-
"contributing.md",
|
|
356
360
|
".github/CONTRIBUTING.md",
|
|
361
|
+
"docs/CONTRIBUTING.md",
|
|
362
|
+
"contributing.md",
|
|
357
363
|
"docs/development/contributing.mdx",
|
|
358
364
|
"docs/development/contributing.md",
|
|
359
365
|
"AGENTS.md",
|
|
360
|
-
"CLAUDE.md",
|
|
361
366
|
".github/AGENTS.md",
|
|
367
|
+
"docs/AGENTS.md",
|
|
368
|
+
"CLAUDE.md",
|
|
362
369
|
".github/CLAUDE.md",
|
|
370
|
+
"docs/CLAUDE.md",
|
|
371
|
+
"AI_POLICY.md",
|
|
372
|
+
".github/AI_POLICY.md",
|
|
373
|
+
"docs/AI_POLICY.md",
|
|
363
374
|
];
|
|
375
|
+
/**
|
|
376
|
+
* v0.9.3: org-level AI policy. Binding agent rules sometimes live in the
|
|
377
|
+
* org's `.github` repo rather than the project repo (astral-sh's
|
|
378
|
+
* AI_POLICY.md bans autonomous agents for ruff and uv; mastodon's
|
|
379
|
+
* CONTRIBUTING only links to mastodon/.github's AI_POLICY.md). Probed
|
|
380
|
+
* once per org and cached under its own key so a sweep over N repos from
|
|
381
|
+
* one org costs one fetch, not N.
|
|
382
|
+
*/
|
|
383
|
+
export async function fetchOrgAiPolicy(owner, deps = {}) {
|
|
384
|
+
if (!deps.fetchOrgPolicy) {
|
|
385
|
+
const cached = cacheGet("org-ai-policy", [owner.toLowerCase()]);
|
|
386
|
+
if (cached !== undefined)
|
|
387
|
+
return cached || undefined;
|
|
388
|
+
}
|
|
389
|
+
const headers = { "User-Agent": "greenlight-cli" };
|
|
390
|
+
const token = githubToken();
|
|
391
|
+
if (token)
|
|
392
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
393
|
+
const fetchOrgPolicy = deps.fetchOrgPolicy ??
|
|
394
|
+
((o) => fetchRawFile(o, ".github", "AI_POLICY.md", headers));
|
|
395
|
+
const text = await fetchOrgPolicy(owner);
|
|
396
|
+
if (!deps.fetchOrgPolicy)
|
|
397
|
+
cacheSet("org-ai-policy", [owner.toLowerCase()], text ?? "");
|
|
398
|
+
return text;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* v0.9.3: the full policy source set for gate detection: house-rules
|
|
402
|
+
* files (first hit per filename across root, .github/, docs/) plus the
|
|
403
|
+
* org-level AI_POLICY.md when the org publishes one.
|
|
404
|
+
*/
|
|
405
|
+
export async function fetchPolicySources(owner, repo, deps = {}) {
|
|
406
|
+
const rules = await fetchHouseRules(owner, repo, deps);
|
|
407
|
+
const orgPolicy = await fetchOrgAiPolicy(owner, deps);
|
|
408
|
+
if (orgPolicy)
|
|
409
|
+
rules.push({ file: `AI_POLICY.md (org ${owner})`, text: orgPolicy });
|
|
410
|
+
return rules;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* v0.9.3: fetch one policy file's raw text, honoring the API base
|
|
414
|
+
* override. In proxy mode (GREENLIGHT_GITHUB_BASE_URL set) the raw host
|
|
415
|
+
* is unreachable with the surrogate credential, so policy files are read
|
|
416
|
+
* through the contents API instead; otherwise the raw host is used as
|
|
417
|
+
* before. Returns undefined when the file does not exist.
|
|
418
|
+
*/
|
|
419
|
+
async function fetchRawFile(owner, repo, file, headers) {
|
|
420
|
+
if (githubApiBase() !== DEFAULT_API) {
|
|
421
|
+
try {
|
|
422
|
+
const data = (await apiGet(`/repos/${owner}/${repo}/contents/${file}`));
|
|
423
|
+
if (typeof data.content === "string" && data.encoding === "base64") {
|
|
424
|
+
return Buffer.from(data.content, "base64").toString("utf8");
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
catch { /* absent */ }
|
|
428
|
+
return undefined;
|
|
429
|
+
}
|
|
430
|
+
try {
|
|
431
|
+
const res = await fetch(`${RAW}/${owner}/${repo}/HEAD/${file}`, { headers });
|
|
432
|
+
if (res.ok)
|
|
433
|
+
return await res.text();
|
|
434
|
+
}
|
|
435
|
+
catch { /* try next */ }
|
|
436
|
+
return undefined;
|
|
437
|
+
}
|
|
364
438
|
/** Fetch all existing house-rules files for a repo (best-effort, cached). */
|
|
365
439
|
export async function fetchHouseRules(owner, repo, deps = {}) {
|
|
366
440
|
if (!deps.fetchRaw) {
|
|
@@ -373,20 +447,23 @@ export async function fetchHouseRules(owner, repo, deps = {}) {
|
|
|
373
447
|
if (token)
|
|
374
448
|
headers["Authorization"] = `Bearer ${token}`;
|
|
375
449
|
const fetchRaw = deps.fetchRaw ??
|
|
376
|
-
(
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
return undefined;
|
|
384
|
-
});
|
|
450
|
+
((file) => fetchRawFile(owner, repo, file, headers));
|
|
451
|
+
// v0.9.3: stop at the first hit per filename (root, then .github/, then
|
|
452
|
+
// docs/), so a repo with CONTRIBUTING.md at the root does not pay for
|
|
453
|
+
// two more 404s, and a repo with it only in docs/ is still found (the
|
|
454
|
+
// AFFiNE shape the 5k scan caught: root-only probing called it
|
|
455
|
+
// "no policy" while docs/CONTRIBUTING.md existed).
|
|
456
|
+
const seenBasenames = new Set();
|
|
385
457
|
const out = [];
|
|
386
458
|
for (const file of HOUSE_RULE_FILES) {
|
|
459
|
+
const base = file.split("/").pop().toLowerCase();
|
|
460
|
+
if (seenBasenames.has(base))
|
|
461
|
+
continue;
|
|
387
462
|
const text = await fetchRaw(file);
|
|
388
|
-
if (text)
|
|
463
|
+
if (text) {
|
|
389
464
|
out.push({ file, text });
|
|
465
|
+
seenBasenames.add(base);
|
|
466
|
+
}
|
|
390
467
|
}
|
|
391
468
|
if (!deps.fetchRaw)
|
|
392
469
|
cacheSet("house-rules", [owner, repo], out);
|
|
@@ -799,7 +876,10 @@ export async function buildIssueSnapshot(owner, repo, number) {
|
|
|
799
876
|
const [comments, linkedPRs, houseRules, workflowGates] = await Promise.all([
|
|
800
877
|
fetchComments(owner, repo, number),
|
|
801
878
|
fetchLinkedPRs(owner, repo, number),
|
|
802
|
-
|
|
879
|
+
// v0.9.3: the full policy source set, including the org-level
|
|
880
|
+
// AI_POLICY.md, so the verdict engine sees the same bans the
|
|
881
|
+
// Agent Policy Index field work found.
|
|
882
|
+
fetchPolicySources(owner, repo),
|
|
803
883
|
scanWorkflowGates(owner, repo),
|
|
804
884
|
]);
|
|
805
885
|
// Comment-mentioned PRs: references like "#861" in comments, cross-checked
|