revu-ai 0.1.2 → 0.2.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/CHANGELOG.md +39 -0
- package/README.md +75 -12
- package/dist/cache/cross-reference.d.ts +37 -0
- package/dist/cache/cross-reference.js +94 -0
- package/dist/cache/cross-reference.js.map +1 -0
- package/dist/cli.js +106 -12
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.js +9 -10
- package/dist/config.js.map +1 -1
- package/dist/discovery.js +8 -1
- package/dist/discovery.js.map +1 -1
- package/dist/findings.d.ts +18 -0
- package/dist/findings.js +22 -0
- package/dist/findings.js.map +1 -0
- package/dist/forges/dedup.d.ts +17 -0
- package/dist/forges/dedup.js +42 -0
- package/dist/forges/dedup.js.map +1 -0
- package/dist/forges/diff-lines.d.ts +12 -0
- package/dist/forges/diff-lines.js +93 -0
- package/dist/forges/diff-lines.js.map +1 -0
- package/dist/forges/github/api.d.ts +70 -0
- package/dist/forges/github/api.js +102 -0
- package/dist/forges/github/api.js.map +1 -0
- package/dist/forges/github/index.d.ts +10 -0
- package/dist/forges/github/index.js +292 -0
- package/dist/forges/github/index.js.map +1 -0
- package/dist/forges/gitlab/index.d.ts +7 -0
- package/dist/forges/gitlab/index.js +13 -0
- package/dist/forges/gitlab/index.js.map +1 -0
- package/dist/forges/post-cmd.d.ts +20 -0
- package/dist/forges/post-cmd.js +54 -0
- package/dist/forges/post-cmd.js.map +1 -0
- package/dist/forges/registry.d.ts +5 -0
- package/dist/forges/registry.js +24 -0
- package/dist/forges/registry.js.map +1 -0
- package/dist/forges/render.d.ts +18 -0
- package/dist/forges/render.js +59 -0
- package/dist/forges/render.js.map +1 -0
- package/dist/forges/types.d.ts +65 -0
- package/dist/forges/types.js +2 -0
- package/dist/forges/types.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +3 -1
- package/dist/init.js +6 -3
- package/dist/init.js.map +1 -1
- package/dist/mcp/aggregator.d.ts +9 -1
- package/dist/mcp/aggregator.js +39 -3
- package/dist/mcp/aggregator.js.map +1 -1
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.js +60 -5
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +38 -2
- package/dist/mcp/tools.js +36 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/output/github.d.ts +1 -1
- package/dist/output/github.js +3 -7
- package/dist/output/github.js.map +1 -1
- package/dist/output/json.d.ts +3 -1
- package/dist/output/json.js +4 -7
- package/dist/output/json.js.map +1 -1
- package/dist/output/pretty.d.ts +1 -1
- package/dist/output/pretty.js +2 -8
- package/dist/output/pretty.js.map +1 -1
- package/dist/prompts/review-system.d.ts +3 -1
- package/dist/prompts/review-system.js +47 -2
- package/dist/prompts/review-system.js.map +1 -1
- package/dist/providers/claude-code.d.ts +7 -5
- package/dist/providers/claude-code.js +77 -15
- package/dist/providers/claude-code.js.map +1 -1
- package/dist/providers/opencode.d.ts +6 -0
- package/dist/providers/opencode.js +653 -0
- package/dist/providers/opencode.js.map +1 -0
- package/dist/providers/registry.d.ts +7 -7
- package/dist/providers/registry.js +29 -21
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/types.d.ts +8 -1
- package/dist/runner.d.ts +6 -1
- package/dist/runner.js +71 -26
- package/dist/runner.js.map +1 -1
- package/dist/scaffold-paths.d.ts +10 -0
- package/dist/scaffold-paths.js +25 -0
- package/dist/scaffold-paths.js.map +1 -0
- package/dist/types.d.ts +38 -3
- package/dist/types.js +4 -7
- package/dist/types.js.map +1 -1
- package/examples/github-workflow.yml +51 -10
- package/package.json +16 -10
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { SEVERITY_ORDER } from "../../types.js";
|
|
3
|
+
import { buildActionPlan } from "../../cache/cross-reference.js";
|
|
4
|
+
import { extractMarkers } from "../dedup.js";
|
|
5
|
+
import { isInlineable, parseUnifiedDiff } from "../diff-lines.js";
|
|
6
|
+
import { renderCommentBody, renderTopLevelBody } from "../render.js";
|
|
7
|
+
import { GitHubClient } from "./api.js";
|
|
8
|
+
export const githubForgeFactory = () => new GitHubForgeAdapter();
|
|
9
|
+
export class GitHubForgeAdapter {
|
|
10
|
+
fetchImpl;
|
|
11
|
+
name = "github";
|
|
12
|
+
/** Allow tests to inject a custom `fetch`. */
|
|
13
|
+
constructor(fetchImpl) {
|
|
14
|
+
this.fetchImpl = fetchImpl;
|
|
15
|
+
}
|
|
16
|
+
async resolveContext(env, flags) {
|
|
17
|
+
const tokenEnv = flags.tokenEnv ?? "GITHUB_TOKEN";
|
|
18
|
+
const token = env[tokenEnv];
|
|
19
|
+
if (!token) {
|
|
20
|
+
throw new Error(`GitHub: no token in $${tokenEnv}. Set it (\`permissions: pull-requests: write\` exposes \$GITHUB_TOKEN in Actions).`);
|
|
21
|
+
}
|
|
22
|
+
const repoStr = flags.repo ?? env["GITHUB_REPOSITORY"];
|
|
23
|
+
if (!repoStr || !repoStr.includes("/")) {
|
|
24
|
+
throw new Error("GitHub: repo not found. Set $GITHUB_REPOSITORY (owner/name) or pass --repo owner/name.");
|
|
25
|
+
}
|
|
26
|
+
const [owner, name] = repoStr.split("/", 2);
|
|
27
|
+
const pr = resolvePrNumber(flags.pr, env);
|
|
28
|
+
if (pr === undefined) {
|
|
29
|
+
throw new Error("GitHub: PR number not found. Set $GITHUB_REF (refs/pull/<n>/...) or pass --pr <n>.");
|
|
30
|
+
}
|
|
31
|
+
let headSha = flags.commitSha ?? env["GITHUB_SHA"];
|
|
32
|
+
let baseSha;
|
|
33
|
+
if (!headSha) {
|
|
34
|
+
// Fall back to the PR's head SHA from the API.
|
|
35
|
+
const client = new GitHubClient(token, this.fetchImpl);
|
|
36
|
+
const pull = await client.getPullRequest(owner, name, pr);
|
|
37
|
+
headSha = pull.head.sha;
|
|
38
|
+
baseSha = pull.base.sha;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
repo: { owner, name },
|
|
42
|
+
pr,
|
|
43
|
+
headSha,
|
|
44
|
+
...(baseSha ? { baseSha } : {}),
|
|
45
|
+
token,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async post(options) {
|
|
49
|
+
const { context, report, priorReport } = options;
|
|
50
|
+
const client = new GitHubClient(context.token, this.fetchImpl);
|
|
51
|
+
// Build the (priorReport, currentReport) → action plan.
|
|
52
|
+
const plan = buildActionPlan(priorReport, report);
|
|
53
|
+
// Compute event from the *new* posts (PR check stickiness story is documented in the README).
|
|
54
|
+
const ghEvent = computeEvent(plan.posts, options.requestChangesAtOrAbove);
|
|
55
|
+
const event = ghEventToAgnostic(ghEvent);
|
|
56
|
+
const totalFindings = plan.outputFindings.length;
|
|
57
|
+
// Short-circuit: nothing to do.
|
|
58
|
+
if (plan.posts.length === 0 && plan.patchesResolved.length === 0 && plan.patchesMoved.length === 0) {
|
|
59
|
+
const augmented = augmentReport(report, plan.outputFindings, plan.outputResolutions);
|
|
60
|
+
if (options.dryRun) {
|
|
61
|
+
process.stdout.write(`[dry-run] no PATCH or POST work to do (no plan changes)\n`);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
inline: { posted: 0, skipped: 0 },
|
|
65
|
+
body: { posted: 0, skipped: 1 },
|
|
66
|
+
patchesResolved: 0,
|
|
67
|
+
patchesMoved: 0,
|
|
68
|
+
totalFindings,
|
|
69
|
+
event,
|
|
70
|
+
augmentedReport: augmented,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Fetch the PR diff so we know which lines are inline-postable.
|
|
74
|
+
const diff = !options.dryRun
|
|
75
|
+
? await client.getPullRequestDiff(context.repo.owner, context.repo.name, context.pr)
|
|
76
|
+
: "";
|
|
77
|
+
const diffMap = parseUnifiedDiff(diff);
|
|
78
|
+
// Partition fresh posts into inline-eligible vs out-of-diff.
|
|
79
|
+
const inline = [];
|
|
80
|
+
const outOfDiff = [];
|
|
81
|
+
for (const f of plan.posts) {
|
|
82
|
+
if (f.line !== undefined && isInlineable(diffMap, f.path, f.line))
|
|
83
|
+
inline.push(f);
|
|
84
|
+
else
|
|
85
|
+
outOfDiff.push(f);
|
|
86
|
+
}
|
|
87
|
+
// Build the inline comments[] payload (single bundled review).
|
|
88
|
+
const comments = inline.map((f) => {
|
|
89
|
+
const line = f.line;
|
|
90
|
+
const lineEnd = f.lineEnd && f.lineEnd > line && isInlineable(diffMap, f.path, f.lineEnd) ? f.lineEnd : undefined;
|
|
91
|
+
return lineEnd
|
|
92
|
+
? {
|
|
93
|
+
path: f.path,
|
|
94
|
+
line: lineEnd,
|
|
95
|
+
side: "RIGHT",
|
|
96
|
+
body: renderCommentBody(f),
|
|
97
|
+
start_line: line,
|
|
98
|
+
start_side: "RIGHT",
|
|
99
|
+
}
|
|
100
|
+
: {
|
|
101
|
+
path: f.path,
|
|
102
|
+
line,
|
|
103
|
+
side: "RIGHT",
|
|
104
|
+
body: renderCommentBody(f),
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
const totalNew = plan.posts.length;
|
|
108
|
+
const bodyText = renderTopLevelBody({
|
|
109
|
+
total: totalNew + plan.patchesResolved.length + plan.patchesMoved.length,
|
|
110
|
+
newCount: totalNew,
|
|
111
|
+
alreadyPosted: plan.patchesMoved.length,
|
|
112
|
+
outOfDiff: outOfDiff.length,
|
|
113
|
+
}, outOfDiff);
|
|
114
|
+
const reviewBody = {
|
|
115
|
+
commit_id: context.headSha,
|
|
116
|
+
event: ghEvent,
|
|
117
|
+
body: bodyText,
|
|
118
|
+
comments,
|
|
119
|
+
};
|
|
120
|
+
if (options.dryRun) {
|
|
121
|
+
printDryRun({
|
|
122
|
+
url: `https://api.github.com/repos/${context.repo.owner}/${context.repo.name}/pulls/${context.pr}/reviews`,
|
|
123
|
+
reviewBody,
|
|
124
|
+
plan: {
|
|
125
|
+
patchesResolved: plan.patchesResolved.length,
|
|
126
|
+
patchesMoved: plan.patchesMoved.length,
|
|
127
|
+
posts: plan.posts.length,
|
|
128
|
+
outOfDiff: outOfDiff.length,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
const augmented = augmentReport(report, plan.outputFindings, plan.outputResolutions);
|
|
132
|
+
return {
|
|
133
|
+
inline: { posted: comments.length, skipped: 0 },
|
|
134
|
+
body: { posted: comments.length + outOfDiff.length > 0 ? 1 : 0, skipped: 0 },
|
|
135
|
+
patchesResolved: plan.patchesResolved.length,
|
|
136
|
+
patchesMoved: plan.patchesMoved.length,
|
|
137
|
+
totalFindings,
|
|
138
|
+
event,
|
|
139
|
+
augmentedReport: augmented,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// ---- Execute PATCHes (sequential; one failure does not abort the rest) ----
|
|
143
|
+
const shortSha = context.headSha.slice(0, 7);
|
|
144
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
145
|
+
const patchFailures = [];
|
|
146
|
+
for (const p of plan.patchesResolved) {
|
|
147
|
+
const original = renderCommentBody(p.finding);
|
|
148
|
+
const wrappedBody = wrapResolved(original, shortSha, today, p.reason);
|
|
149
|
+
try {
|
|
150
|
+
await client.patchReviewComment(context.repo.owner, context.repo.name, Number(p.commentId), { body: wrappedBody });
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
patchFailures.push({ commentId: p.commentId, kind: "resolved", error: e.message ?? String(e) });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const p of plan.patchesMoved) {
|
|
157
|
+
const newBody = renderCommentBody(p.finding);
|
|
158
|
+
try {
|
|
159
|
+
await client.patchReviewComment(context.repo.owner, context.repo.name, Number(p.commentId), { body: newBody });
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
patchFailures.push({ commentId: p.commentId, kind: "moved", error: e.message ?? String(e) });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// ---- POST a bundled review for new findings (if any) ----
|
|
166
|
+
let reviewUrl;
|
|
167
|
+
const bodyPosted = inline.length > 0 || outOfDiff.length > 0;
|
|
168
|
+
if (bodyPosted) {
|
|
169
|
+
const created = await client.createReview(context.repo.owner, context.repo.name, context.pr, reviewBody);
|
|
170
|
+
reviewUrl = created.html_url;
|
|
171
|
+
// Match new comments to their freshly-allocated GitHub ids by fingerprint marker.
|
|
172
|
+
// If listing fails (network blip etc.), continue with un-populated commentIds —
|
|
173
|
+
// the augmentedReport must still be returned so the next run's --prior-report
|
|
174
|
+
// can dedup; missing commentIds will resolve themselves on the next post.
|
|
175
|
+
if (inline.length > 0) {
|
|
176
|
+
try {
|
|
177
|
+
const created_comments = await client.listReviewCommentsForReview(context.repo.owner, context.repo.name, context.pr, created.id);
|
|
178
|
+
const fpToId = new Map();
|
|
179
|
+
for (const c of created_comments) {
|
|
180
|
+
for (const fp of extractMarkers(c.body))
|
|
181
|
+
fpToId.set(fp, c.id);
|
|
182
|
+
}
|
|
183
|
+
for (const f of plan.outputFindings) {
|
|
184
|
+
if (f.commentId !== undefined)
|
|
185
|
+
continue;
|
|
186
|
+
const id = fpToId.get(f.fingerprint);
|
|
187
|
+
if (id !== undefined)
|
|
188
|
+
f.commentId = id;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
process.stderr.write(`revu-ai github post: warning — failed to backfill commentIds (${e.message ?? String(e)}). ` +
|
|
193
|
+
`The augmented report will be written without ids; the next run will rediscover them.\n`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (patchFailures.length > 0) {
|
|
198
|
+
const summary = patchFailures
|
|
199
|
+
.slice(0, 5)
|
|
200
|
+
.map((f) => ` - ${f.kind} #${f.commentId}: ${f.error}`)
|
|
201
|
+
.join("\n");
|
|
202
|
+
const more = patchFailures.length > 5 ? `\n …and ${patchFailures.length - 5} more` : "";
|
|
203
|
+
process.stderr.write(`revu-ai github post: warning — ${patchFailures.length} of ` +
|
|
204
|
+
`${plan.patchesResolved.length + plan.patchesMoved.length} PATCH call(s) failed:\n${summary}${more}\n` +
|
|
205
|
+
`The next run will retry via the prior-report dedup logic.\n`);
|
|
206
|
+
}
|
|
207
|
+
const augmented = augmentReport(report, plan.outputFindings, plan.outputResolutions);
|
|
208
|
+
return {
|
|
209
|
+
...(reviewUrl ? { reviewUrl } : {}),
|
|
210
|
+
inline: { posted: inline.length, skipped: 0 },
|
|
211
|
+
body: { posted: bodyPosted ? 1 : 0, skipped: 0 },
|
|
212
|
+
patchesResolved: plan.patchesResolved.length - patchFailures.filter((f) => f.kind === "resolved").length,
|
|
213
|
+
patchesMoved: plan.patchesMoved.length - patchFailures.filter((f) => f.kind === "moved").length,
|
|
214
|
+
totalFindings,
|
|
215
|
+
event,
|
|
216
|
+
augmentedReport: augmented,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function augmentReport(report, outputFindings, outputResolutions) {
|
|
221
|
+
return {
|
|
222
|
+
...report,
|
|
223
|
+
findings: outputFindings,
|
|
224
|
+
resolutions: outputResolutions,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/** Wrap a comment body with strikethrough + a footer noting the resolution. */
|
|
228
|
+
function wrapResolved(originalBody, shortSha, isoDate, reason) {
|
|
229
|
+
const stripped = originalBody.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
230
|
+
const struck = stripped
|
|
231
|
+
.split("\n")
|
|
232
|
+
.map((line) => (line.length === 0 ? "" : `~~${line}~~`))
|
|
233
|
+
.join("\n");
|
|
234
|
+
const reasonText = reason === "stale" ? "no longer applicable" : "addressed by the new commits";
|
|
235
|
+
return `${struck}\n\n✅ **Marked resolved by revu-ai** at \`${shortSha}\` on ${isoDate} — ${reasonText}.`;
|
|
236
|
+
}
|
|
237
|
+
/** Compute the GitHub-native review event. */
|
|
238
|
+
function computeEvent(findings, threshold) {
|
|
239
|
+
if (!threshold)
|
|
240
|
+
return "COMMENT";
|
|
241
|
+
const t = SEVERITY_ORDER[threshold];
|
|
242
|
+
return findings.some((f) => SEVERITY_ORDER[f.severity] >= t) ? "REQUEST_CHANGES" : "COMMENT";
|
|
243
|
+
}
|
|
244
|
+
function ghEventToAgnostic(e) {
|
|
245
|
+
switch (e) {
|
|
246
|
+
case "COMMENT":
|
|
247
|
+
return "comment";
|
|
248
|
+
case "REQUEST_CHANGES":
|
|
249
|
+
return "request-changes";
|
|
250
|
+
case "APPROVE":
|
|
251
|
+
return "approve";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/** Resolve the PR number from --pr / $GITHUB_REF / $GITHUB_EVENT_PATH (in that order). */
|
|
255
|
+
function resolvePrNumber(prFlag, env) {
|
|
256
|
+
if (prFlag) {
|
|
257
|
+
const n = Number.parseInt(prFlag, 10);
|
|
258
|
+
if (Number.isFinite(n) && n > 0)
|
|
259
|
+
return n;
|
|
260
|
+
}
|
|
261
|
+
const ref = env["GITHUB_REF"];
|
|
262
|
+
if (ref) {
|
|
263
|
+
const m = ref.match(/^refs\/pull\/(\d+)\//);
|
|
264
|
+
if (m && m[1])
|
|
265
|
+
return Number.parseInt(m[1], 10);
|
|
266
|
+
}
|
|
267
|
+
const eventPath = env["GITHUB_EVENT_PATH"];
|
|
268
|
+
if (eventPath) {
|
|
269
|
+
try {
|
|
270
|
+
const event = JSON.parse(readFileSync(eventPath, "utf8"));
|
|
271
|
+
if (typeof event.pull_request?.number === "number")
|
|
272
|
+
return event.pull_request.number;
|
|
273
|
+
if (typeof event.number === "number")
|
|
274
|
+
return event.number;
|
|
275
|
+
}
|
|
276
|
+
catch (e) {
|
|
277
|
+
// Corrupted/missing event file shouldn't kill the post step — caller
|
|
278
|
+
// can still pass `--pr` explicitly. But surface the cause so a bad CI
|
|
279
|
+
// env isn't silent.
|
|
280
|
+
process.stderr.write(`revu-ai github post: warning — failed to parse $GITHUB_EVENT_PATH (${eventPath}): ${e.message ?? String(e)}\n`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
function printDryRun(info) {
|
|
286
|
+
process.stdout.write(`[dry-run] plan: PATCHes-resolved=${info.plan.patchesResolved}, PATCHes-moved=${info.plan.patchesMoved}, POSTs=${info.plan.posts}, out-of-diff=${info.plan.outOfDiff}\n`);
|
|
287
|
+
if (info.plan.posts > 0 || info.plan.outOfDiff > 0) {
|
|
288
|
+
process.stdout.write(`[dry-run] POST ${info.url}\n`);
|
|
289
|
+
process.stdout.write(JSON.stringify(info.reviewBody, null, 2) + "\n");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/forges/github/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ForgeAdapter, ForgeAdapterFactory, ForgeContext, PostOptions, PostResult, ResolveContextFlags } from "../types.js";
|
|
2
|
+
export declare const gitlabForgeFactory: ForgeAdapterFactory;
|
|
3
|
+
export declare class GitLabForgeAdapter implements ForgeAdapter {
|
|
4
|
+
readonly name = "gitlab";
|
|
5
|
+
resolveContext(_env: NodeJS.ProcessEnv, _flags: ResolveContextFlags): Promise<ForgeContext>;
|
|
6
|
+
post(_options: PostOptions): Promise<PostResult>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const gitlabForgeFactory = () => new GitLabForgeAdapter();
|
|
2
|
+
export class GitLabForgeAdapter {
|
|
3
|
+
name = "gitlab";
|
|
4
|
+
async resolveContext(_env, _flags) {
|
|
5
|
+
throw new Error("GitLab adapter is not yet implemented. The CLI grammar is reserved; the adapter is planned. " +
|
|
6
|
+
"Track progress in the project README under \"Forge integrations\".");
|
|
7
|
+
}
|
|
8
|
+
async post(_options) {
|
|
9
|
+
throw new Error("GitLab adapter is not yet implemented. The CLI grammar is reserved; the adapter is planned. " +
|
|
10
|
+
"Track progress in the project README under \"Forge integrations\".");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/forges/gitlab/index.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,kBAAkB,GAAwB,GAAG,EAAE,CAAC,IAAI,kBAAkB,EAAE,CAAC;AAEtF,MAAM,OAAO,kBAAkB;IACpB,IAAI,GAAG,QAAQ,CAAC;IAEzB,KAAK,CAAC,cAAc,CAClB,IAAuB,EACvB,MAA2B;QAE3B,MAAM,IAAI,KAAK,CACb,8FAA8F;YAC5F,oEAAoE,CACvE,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAqB;QAC9B,MAAM,IAAI,KAAK,CACb,8FAA8F;YAC5F,oEAAoE,CACvE,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PostResult, ResolveContextFlags } from "./types.js";
|
|
2
|
+
import type { Severity } from "../types.js";
|
|
3
|
+
export interface ForgePostOptions {
|
|
4
|
+
forge: string;
|
|
5
|
+
reportPath: string;
|
|
6
|
+
/** Optional path to a prior --output-file report. When present, the post step PATCHes
|
|
7
|
+
* existing comments instead of always creating fresh ones. */
|
|
8
|
+
priorReportPath?: string;
|
|
9
|
+
/** Optional path to write the augmented report to (with commentIds populated, etc.).
|
|
10
|
+
* This file is what next run feeds back as --prior-report. */
|
|
11
|
+
outputFile?: string;
|
|
12
|
+
flags: ResolveContextFlags;
|
|
13
|
+
requestChangesAtOrAbove?: Severity;
|
|
14
|
+
dryRun: boolean;
|
|
15
|
+
/** Optional injected env. Defaults to process.env. Useful in tests. */
|
|
16
|
+
env?: NodeJS.ProcessEnv;
|
|
17
|
+
/** Optional injected stdin reader for `--report -`. Useful in tests. */
|
|
18
|
+
readStdin?: () => Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
export declare function runForgePost(options: ForgePostOptions): Promise<PostResult>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { getForge } from "./registry.js";
|
|
3
|
+
export async function runForgePost(options) {
|
|
4
|
+
const reportText = options.reportPath === "-"
|
|
5
|
+
? await (options.readStdin ?? defaultReadStdin)()
|
|
6
|
+
: readFileSync(options.reportPath, "utf8");
|
|
7
|
+
const report = JSON.parse(reportText);
|
|
8
|
+
if (report.schemaVersion !== 2 && report.schemaVersion !== 1) {
|
|
9
|
+
throw new Error(`Unsupported report schemaVersion ${String(report.schemaVersion)}; expected 1 or 2.`);
|
|
10
|
+
}
|
|
11
|
+
let priorReport;
|
|
12
|
+
if (options.priorReportPath) {
|
|
13
|
+
try {
|
|
14
|
+
const priorText = readFileSync(options.priorReportPath, "utf8");
|
|
15
|
+
priorReport = JSON.parse(priorText);
|
|
16
|
+
if (priorReport.schemaVersion !== 2 && priorReport.schemaVersion !== 1) {
|
|
17
|
+
throw new Error(`Unsupported prior report schemaVersion ${String(priorReport.schemaVersion)}; expected 1 or 2.`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
const code = e.code;
|
|
22
|
+
if (code !== "ENOENT")
|
|
23
|
+
throw e;
|
|
24
|
+
// Missing prior file is normal on the first run; just proceed without one.
|
|
25
|
+
priorReport = undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const adapter = getForge(options.forge);
|
|
29
|
+
const env = options.env ?? process.env;
|
|
30
|
+
const context = await adapter.resolveContext(env, options.flags);
|
|
31
|
+
const result = await adapter.post({
|
|
32
|
+
report,
|
|
33
|
+
...(priorReport ? { priorReport } : {}),
|
|
34
|
+
context,
|
|
35
|
+
...(options.requestChangesAtOrAbove ? { requestChangesAtOrAbove: options.requestChangesAtOrAbove } : {}),
|
|
36
|
+
dryRun: options.dryRun,
|
|
37
|
+
});
|
|
38
|
+
if (options.outputFile) {
|
|
39
|
+
writeFileSync(options.outputFile, JSON.stringify(result.augmentedReport, null, 2) + "\n", "utf8");
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
function defaultReadStdin() {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
let data = "";
|
|
46
|
+
process.stdin.setEncoding("utf8");
|
|
47
|
+
process.stdin.on("data", (chunk) => {
|
|
48
|
+
data += chunk;
|
|
49
|
+
});
|
|
50
|
+
process.stdin.on("end", () => resolve(data));
|
|
51
|
+
process.stdin.on("error", reject);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=post-cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-cmd.js","sourceRoot":"","sources":["../../src/forges/post-cmd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ForgeAdapter, ForgeAdapterFactory } from "./types.js";
|
|
2
|
+
export declare function registerForge(name: string, factory: ForgeAdapterFactory): void;
|
|
3
|
+
export declare function unregisterForge(name: string): void;
|
|
4
|
+
export declare function getForge(name: string): ForgeAdapter;
|
|
5
|
+
export declare function listForges(): string[];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { githubForgeFactory } from "./github/index.js";
|
|
2
|
+
import { gitlabForgeFactory } from "./gitlab/index.js";
|
|
3
|
+
const REGISTRY = new Map([
|
|
4
|
+
["github", githubForgeFactory],
|
|
5
|
+
["gitlab", gitlabForgeFactory],
|
|
6
|
+
]);
|
|
7
|
+
export function registerForge(name, factory) {
|
|
8
|
+
REGISTRY.set(name, factory);
|
|
9
|
+
}
|
|
10
|
+
export function unregisterForge(name) {
|
|
11
|
+
REGISTRY.delete(name);
|
|
12
|
+
}
|
|
13
|
+
export function getForge(name) {
|
|
14
|
+
const factory = REGISTRY.get(name);
|
|
15
|
+
if (!factory) {
|
|
16
|
+
const known = [...REGISTRY.keys()].join(", ");
|
|
17
|
+
throw new Error(`Unknown forge "${name}". Known: ${known}`);
|
|
18
|
+
}
|
|
19
|
+
return factory();
|
|
20
|
+
}
|
|
21
|
+
export function listForges() {
|
|
22
|
+
return [...REGISTRY.keys()];
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/forges/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD,MAAM,QAAQ,GAAqC,IAAI,GAAG,CAAC;IACzD,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IAC9B,CAAC,QAAQ,EAAE,kBAAkB,CAAC;CAC/B,CAAC,CAAC;AAEH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAA4B;IACtE,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,kBAAkB,IAAI,aAAa,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Finding } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Render a single finding as a Markdown comment body, with a hidden HTML
|
|
4
|
+
* marker appended for dedup on subsequent runs.
|
|
5
|
+
*/
|
|
6
|
+
export declare function renderCommentBody(finding: Finding): string;
|
|
7
|
+
export interface SummaryStats {
|
|
8
|
+
total: number;
|
|
9
|
+
newCount: number;
|
|
10
|
+
alreadyPosted: number;
|
|
11
|
+
outOfDiff: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Render the top-level review body. Includes a one-line summary and, if any,
|
|
15
|
+
* a section listing findings that couldn't be posted inline because the line
|
|
16
|
+
* isn't in the PR diff.
|
|
17
|
+
*/
|
|
18
|
+
export declare function renderTopLevelBody(stats: SummaryStats, outOfDiff: Finding[]): string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { fingerprint, withMarker } from "./dedup.js";
|
|
2
|
+
// `Record<Severity, …>` makes `SEVERITIES` (in src/types.ts) the single source of
|
|
3
|
+
// truth — adding a new severity there fails typecheck here until this map is
|
|
4
|
+
// extended. Same pattern is reused for the cli's SEV_COLOR / SEV_LABEL maps.
|
|
5
|
+
const SEV_BADGE = {
|
|
6
|
+
aesthetic: "⚪ aesthetic",
|
|
7
|
+
low: "🔵 low",
|
|
8
|
+
medium: "🟡 medium",
|
|
9
|
+
high: "🔴 high",
|
|
10
|
+
critical: "⛔ critical",
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Render a single finding as a Markdown comment body, with a hidden HTML
|
|
14
|
+
* marker appended for dedup on subsequent runs.
|
|
15
|
+
*/
|
|
16
|
+
export function renderCommentBody(finding) {
|
|
17
|
+
const fp = fingerprint(finding);
|
|
18
|
+
const header = `**${SEV_BADGE[finding.severity]}** \`${finding.ruleId}\``;
|
|
19
|
+
const category = finding.category ? ` _${finding.category}_` : "";
|
|
20
|
+
const body = `${header}${category}\n\n${finding.message.trim()}`;
|
|
21
|
+
return withMarker(body, fp);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Render the top-level review body. Includes a one-line summary and, if any,
|
|
25
|
+
* a section listing findings that couldn't be posted inline because the line
|
|
26
|
+
* isn't in the PR diff.
|
|
27
|
+
*/
|
|
28
|
+
export function renderTopLevelBody(stats, outOfDiff) {
|
|
29
|
+
const sections = [];
|
|
30
|
+
sections.push(`**revu-ai** found ${stats.total} finding${stats.total === 1 ? "" : "s"} — ` +
|
|
31
|
+
`${stats.newCount} new, ${stats.alreadyPosted} already posted, ${stats.outOfDiff} outside the diff.`);
|
|
32
|
+
if (outOfDiff.length > 0) {
|
|
33
|
+
sections.push("### Findings outside the PR diff");
|
|
34
|
+
const byPath = groupByPath(outOfDiff);
|
|
35
|
+
for (const [path, findings] of byPath) {
|
|
36
|
+
sections.push(`- \`${path}\``);
|
|
37
|
+
for (const f of findings) {
|
|
38
|
+
const loc = f.line !== undefined ? `:${f.line}${f.lineEnd && f.lineEnd !== f.line ? `-${f.lineEnd}` : ""}` : "";
|
|
39
|
+
sections.push(` - ${SEV_BADGE[f.severity]} \`${f.ruleId}\`${loc} — ${oneLine(f.message)}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return sections.join("\n\n");
|
|
44
|
+
}
|
|
45
|
+
function groupByPath(findings) {
|
|
46
|
+
const out = new Map();
|
|
47
|
+
for (const f of findings) {
|
|
48
|
+
const list = out.get(f.path);
|
|
49
|
+
if (list)
|
|
50
|
+
list.push(f);
|
|
51
|
+
else
|
|
52
|
+
out.set(f.path, [f]);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
function oneLine(s) {
|
|
57
|
+
return s.replace(/\s+/g, " ").trim();
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/forges/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { RunReport, Severity } from "../types.js";
|
|
2
|
+
export interface ForgeContext {
|
|
3
|
+
repo: {
|
|
4
|
+
owner: string;
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
pr: number;
|
|
8
|
+
headSha: string;
|
|
9
|
+
baseSha?: string;
|
|
10
|
+
token: string;
|
|
11
|
+
}
|
|
12
|
+
export interface PostOptions {
|
|
13
|
+
report: RunReport;
|
|
14
|
+
/** Prior run's report (the one previously written to --output-file). When present,
|
|
15
|
+
* the post step PATCHes existing comments instead of always creating fresh ones. */
|
|
16
|
+
priorReport?: RunReport;
|
|
17
|
+
context: ForgeContext;
|
|
18
|
+
/** If any finding's severity is at or above this threshold, the review is submitted as the forge's "request changes" event. */
|
|
19
|
+
requestChangesAtOrAbove?: Severity;
|
|
20
|
+
dryRun: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface PostResult {
|
|
23
|
+
/** URL of the review/MR comment created, when applicable. */
|
|
24
|
+
reviewUrl?: string;
|
|
25
|
+
inline: {
|
|
26
|
+
posted: number;
|
|
27
|
+
skipped: number;
|
|
28
|
+
};
|
|
29
|
+
/** Top-level body / summary comment. */
|
|
30
|
+
body: {
|
|
31
|
+
posted: number;
|
|
32
|
+
skipped: number;
|
|
33
|
+
};
|
|
34
|
+
/** PATCH counts split out so the CLI can show "n resolved, m moved". */
|
|
35
|
+
patchesResolved: number;
|
|
36
|
+
patchesMoved: number;
|
|
37
|
+
totalFindings: number;
|
|
38
|
+
/** Forge-agnostic event label. The forge adapter maps this to its native enum. */
|
|
39
|
+
event: "comment" | "request-changes" | "approve";
|
|
40
|
+
/** The current report augmented with newly-populated commentIds and the next-run cache
|
|
41
|
+
* shape (outputFindings + outputResolutions baked into report.findings/resolutions).
|
|
42
|
+
* The CLI writes this to --output-file. */
|
|
43
|
+
augmentedReport: RunReport;
|
|
44
|
+
}
|
|
45
|
+
export interface ExistingComment {
|
|
46
|
+
/** The fingerprint extracted from the hidden HTML marker, if present. */
|
|
47
|
+
fingerprint?: string;
|
|
48
|
+
/** Forge-native comment id, opaque to callers. */
|
|
49
|
+
externalId: string | number;
|
|
50
|
+
}
|
|
51
|
+
export interface ResolveContextFlags {
|
|
52
|
+
pr?: string;
|
|
53
|
+
repo?: string;
|
|
54
|
+
commitSha?: string;
|
|
55
|
+
tokenEnv?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface ForgeAdapter {
|
|
58
|
+
readonly name: string;
|
|
59
|
+
/** Resolve `{ repo, pr, headSha, baseSha, token }` from environment + CLI flags. */
|
|
60
|
+
resolveContext(env: NodeJS.ProcessEnv, flags: ResolveContextFlags): Promise<ForgeContext>;
|
|
61
|
+
post(options: PostOptions): Promise<PostResult>;
|
|
62
|
+
}
|
|
63
|
+
export interface ForgeAdapterFactory {
|
|
64
|
+
(): ForgeAdapter;
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/forges/types.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { run, listRules, RevuExit } from "./runner.js";
|
|
2
|
-
export type { RunnerResult, RunHooks } from "./runner.js";
|
|
3
|
-
export {
|
|
2
|
+
export type { RunnerResult, RunHooks, RunInputs } from "./runner.js";
|
|
3
|
+
export { registerHarness, unregisterHarness, registerScaffoldHarness, unregisterScaffoldHarness, getHarnessFactory, getScaffoldHarness, listHarnesses, } from "./providers/registry.js";
|
|
4
4
|
export type { ReviewAgent, ReviewAgentFactory, ReviewInput, ReviewResult } from "./providers/types.js";
|
|
5
5
|
export { startSidecar } from "./mcp/server.js";
|
|
6
6
|
export type { SidecarHandle } from "./mcp/server.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { run, listRules, RevuExit } from "./runner.js";
|
|
2
|
-
export {
|
|
2
|
+
export { registerHarness, unregisterHarness, registerScaffoldHarness, unregisterScaffoldHarness, getHarnessFactory, getScaffoldHarness, listHarnesses, } from "./providers/registry.js";
|
|
3
3
|
export { startSidecar } from "./mcp/server.js";
|
|
4
4
|
export { FindingsAggregator } from "./mcp/aggregator.js";
|
|
5
5
|
export { loadConfig, DEFAULT_CONFIG } from "./config.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,GACd,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|