secondpair 0.1.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 (62) hide show
  1. package/README.md +119 -0
  2. package/dist/bitbucket/comments.d.ts +49 -0
  3. package/dist/bitbucket/comments.js +198 -0
  4. package/dist/bitbucket/comments.js.map +1 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +208 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config.d.ts +33 -0
  9. package/dist/config.js +87 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/diff/github.d.ts +14 -0
  12. package/dist/diff/github.js +27 -0
  13. package/dist/diff/github.js.map +1 -0
  14. package/dist/diff/local.d.ts +10 -0
  15. package/dist/diff/local.js +39 -0
  16. package/dist/diff/local.js.map +1 -0
  17. package/dist/diff/parse.d.ts +9 -0
  18. package/dist/diff/parse.js +141 -0
  19. package/dist/diff/parse.js.map +1 -0
  20. package/dist/finding-id.d.ts +28 -0
  21. package/dist/finding-id.js +96 -0
  22. package/dist/finding-id.js.map +1 -0
  23. package/dist/github/comments.d.ts +25 -0
  24. package/dist/github/comments.js +193 -0
  25. package/dist/github/comments.js.map +1 -0
  26. package/dist/gitlab/comments.d.ts +46 -0
  27. package/dist/gitlab/comments.js +213 -0
  28. package/dist/gitlab/comments.js.map +1 -0
  29. package/dist/index.d.ts +10 -0
  30. package/dist/index.js +11 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/llm/prompt.d.ts +23 -0
  33. package/dist/llm/prompt.js +53 -0
  34. package/dist/llm/prompt.js.map +1 -0
  35. package/dist/llm/schema.d.ts +61 -0
  36. package/dist/llm/schema.js +73 -0
  37. package/dist/llm/schema.js.map +1 -0
  38. package/dist/reconcile.d.ts +20 -0
  39. package/dist/reconcile.js +70 -0
  40. package/dist/reconcile.js.map +1 -0
  41. package/dist/redact.d.ts +3 -0
  42. package/dist/redact.js +25 -0
  43. package/dist/redact.js.map +1 -0
  44. package/dist/report/cli.d.ts +5 -0
  45. package/dist/report/cli.js +63 -0
  46. package/dist/report/cli.js.map +1 -0
  47. package/dist/report/json.d.ts +27 -0
  48. package/dist/report/json.js +53 -0
  49. package/dist/report/json.js.map +1 -0
  50. package/dist/review.d.ts +41 -0
  51. package/dist/review.js +274 -0
  52. package/dist/review.js.map +1 -0
  53. package/dist/suppress-signals.d.ts +7 -0
  54. package/dist/suppress-signals.js +19 -0
  55. package/dist/suppress-signals.js.map +1 -0
  56. package/dist/suppressions.d.ts +6 -0
  57. package/dist/suppressions.js +48 -0
  58. package/dist/suppressions.js.map +1 -0
  59. package/dist/types.d.ts +92 -0
  60. package/dist/types.js +14 -0
  61. package/dist/types.js.map +1 -0
  62. package/package.json +49 -0
@@ -0,0 +1,193 @@
1
+ import { collectIdsFromBodies, embedFindingId, parseFindingId } from "../finding-id.js";
2
+ import { collectWontFixIds } from "../suppress-signals.js";
3
+ export const AGENT_MARKER = "<!-- secondpair -->";
4
+ export const SEVERITY_EMOJI = {
5
+ critical: "🟥",
6
+ high: "🔴",
7
+ medium: "🟡",
8
+ low: "🔵",
9
+ info: "⚪",
10
+ };
11
+ export function formatCommentBody(f) {
12
+ const parts = [
13
+ `${SEVERITY_EMOJI[f.severity]} **${f.severity.toUpperCase()}** · \`${f.category}\` · confidence ${Math.round(f.confidence * 100)}%`,
14
+ "",
15
+ `**${f.title}**`,
16
+ "",
17
+ f.body.trim(),
18
+ ];
19
+ if (f.suggestion) {
20
+ parts.push("", "```suggestion", f.suggestion.replace(/\n$/, ""), "```");
21
+ }
22
+ parts.push("", AGENT_MARKER);
23
+ let body = parts.join("\n");
24
+ if (f.id)
25
+ body = embedFindingId(body, f.id);
26
+ return body;
27
+ }
28
+ export function formatReviewBody(result, failed) {
29
+ const counts = countBySeverity(result.findings);
30
+ const countLine = result.findings.length === 0
31
+ ? "No findings."
32
+ : Object.entries(counts)
33
+ .map(([sev, n]) => `${SEVERITY_EMOJI[sev]} ${n} ${sev}`)
34
+ .join(" · ");
35
+ const recon = result.reconciliation;
36
+ const reconLine = recon
37
+ ? `\n_Lifecycle:_ ${recon.new.length} new · ${recon.persistent.length} persistent · ${recon.resolved.length} resolved · ${recon.suppressed.length} suppressed`
38
+ : "";
39
+ return [
40
+ `## PR Review Agent`,
41
+ "",
42
+ result.summary.trim(),
43
+ "",
44
+ countLine,
45
+ reconLine,
46
+ failed ? "\n❌ **Check failed**: findings at or above the configured severity threshold." : "",
47
+ AGENT_MARKER,
48
+ ].join("\n");
49
+ }
50
+ function countBySeverity(findings) {
51
+ const counts = {};
52
+ for (const f of findings)
53
+ counts[f.severity] = (counts[f.severity] ?? 0) + 1;
54
+ return counts;
55
+ }
56
+ /** Collect finding ids already posted on this PR by the agent. */
57
+ export async function listPostedFindingIds(octokit, pr) {
58
+ const existing = await octokit.paginate(octokit.pulls.listReviewComments, {
59
+ ...pr,
60
+ per_page: 100,
61
+ });
62
+ return collectIdsFromBodies(existing.filter((c) => c.body.includes(AGENT_MARKER)).map((c) => c.body));
63
+ }
64
+ export async function listWontFixFindingIds(octokit, pr) {
65
+ const comments = await octokit.paginate(octokit.pulls.listReviewComments, {
66
+ ...pr,
67
+ per_page: 100,
68
+ });
69
+ const byId = new Map(comments.map((comment) => [comment.id, comment]));
70
+ return collectWontFixIds(comments.map((comment) => {
71
+ const parent = comment.in_reply_to_id
72
+ ? byId.get(comment.in_reply_to_id)
73
+ : undefined;
74
+ return {
75
+ body: comment.body,
76
+ isAgent: comment.body.includes(AGENT_MARKER),
77
+ parentAgentId: parent?.body.includes(AGENT_MARKER) === true
78
+ ? parseFindingId(parent.body)
79
+ : null,
80
+ };
81
+ }));
82
+ }
83
+ /** Resolve unresolved review threads whose comments contain one of the finding ids. */
84
+ export async function resolveThreadsForIds(octokit, pr, ids, log = () => { }) {
85
+ const wanted = new Set(Array.from(ids, (id) => id.toLowerCase()));
86
+ if (wanted.size === 0)
87
+ return 0;
88
+ let threads;
89
+ try {
90
+ threads = [];
91
+ let cursor = null;
92
+ for (;;) {
93
+ const data = (await octokit.graphql(`query($owner:String!,$repo:String!,$number:Int!,$cursor:String){
94
+ repository(owner:$owner,name:$repo){
95
+ pullRequest(number:$number){
96
+ reviewThreads(first:100,after:$cursor){
97
+ nodes{id isResolved comments(first:100){nodes{body}}}
98
+ pageInfo{hasNextPage endCursor}
99
+ }
100
+ }
101
+ }
102
+ }`, { owner: pr.owner, repo: pr.repo, number: pr.pull_number, cursor }));
103
+ const page = data.repository?.pullRequest?.reviewThreads;
104
+ threads.push(...(page?.nodes ?? []));
105
+ if (!page?.pageInfo?.hasNextPage || !page.pageInfo.endCursor)
106
+ break;
107
+ cursor = page.pageInfo.endCursor;
108
+ }
109
+ }
110
+ catch (err) {
111
+ log(`warn: failed to list GitHub review threads: ${err.message}`);
112
+ return 0;
113
+ }
114
+ let resolved = 0;
115
+ for (const thread of threads) {
116
+ if (thread.isResolved ||
117
+ !thread.comments.nodes.some((comment) => {
118
+ const id = parseFindingId(comment.body);
119
+ return id != null && wanted.has(id.toLowerCase());
120
+ })) {
121
+ continue;
122
+ }
123
+ try {
124
+ await octokit.graphql(`mutation($id:ID!){
125
+ resolveReviewThread(input:{threadId:$id}){thread{isResolved}}
126
+ }`, { id: thread.id });
127
+ resolved++;
128
+ }
129
+ catch (err) {
130
+ log(`warn: failed to resolve GitHub review thread ${thread.id}: ${err.message}`);
131
+ }
132
+ }
133
+ return resolved;
134
+ }
135
+ /**
136
+ * Post new findings as one PR review with inline comments.
137
+ * Persistent findings (same id already on the PR) are skipped.
138
+ */
139
+ export async function postReview(opts) {
140
+ const { octokit, pr, result, log = () => { } } = opts;
141
+ const toPost = result.findingsToPost ?? result.findings;
142
+ const existingIds = await listPostedFindingIds(octokit, pr);
143
+ const comments = [];
144
+ let skipped = 0;
145
+ for (const f of toPost) {
146
+ if (f.id && existingIds.has(f.id)) {
147
+ skipped++;
148
+ continue;
149
+ }
150
+ comments.push({
151
+ path: f.file,
152
+ line: f.end_line,
153
+ ...(f.end_line > f.start_line ? { start_line: f.start_line, start_side: "RIGHT" } : {}),
154
+ side: "RIGHT",
155
+ body: formatCommentBody(f),
156
+ });
157
+ }
158
+ if (skipped)
159
+ log(`Skipping ${skipped} comment(s) already posted (same finding id).`);
160
+ const body = formatReviewBody(result, opts.failed);
161
+ try {
162
+ await octokit.pulls.createReview({
163
+ ...pr,
164
+ commit_id: opts.headSha,
165
+ event: "COMMENT",
166
+ body,
167
+ comments,
168
+ });
169
+ log(`Posted review with ${comments.length} inline comment(s).`);
170
+ }
171
+ catch (err) {
172
+ log(`Inline review failed (${err.message}); posting summary-only review.`);
173
+ const fallbackBody = [
174
+ body,
175
+ "",
176
+ "### Findings (inline placement failed)",
177
+ ...toPost.map((f) => `- **${f.severity}** \`${f.file}:${f.start_line}-${f.end_line}\` — ${f.title}${f.id ? ` (\`${f.id}\`)` : ""}\n\n ${f.body.split("\n").join("\n ")}`),
178
+ ].join("\n");
179
+ await octokit.pulls.createReview({
180
+ ...pr,
181
+ commit_id: opts.headSha,
182
+ event: "COMMENT",
183
+ body: fallbackBody,
184
+ });
185
+ }
186
+ const resolvedIds = result.reconciliation?.resolved ?? [];
187
+ if (resolvedIds.length > 0) {
188
+ const resolved = await resolveThreadsForIds(octokit, pr, resolvedIds, log);
189
+ if (resolved)
190
+ log(`Resolved ${resolved} thread(s) for fixed findings.`);
191
+ }
192
+ }
193
+ //# sourceMappingURL=comments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/github/comments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { ReviewResult } from "../types.js";
2
+ export interface GlRef {
3
+ /** GitLab server base URL, e.g. https://gitlab.com */
4
+ serverUrl: string;
5
+ /** URL-encoded project path ("group%2Fproject") or numeric project id. */
6
+ projectId: string;
7
+ mrIid: number;
8
+ }
9
+ export interface GlDiffRefs {
10
+ base_sha: string;
11
+ head_sha: string;
12
+ start_sha: string;
13
+ }
14
+ /** Resolve project/MR from flags or GitLab CI env vars. */
15
+ export declare function resolveGlRef(repoSlug: string | undefined, pr: number | undefined): GlRef;
16
+ /** Fetch MR changes and reconstruct a unified diff the parser understands. */
17
+ export declare function getGlMrDiff(ref: GlRef): Promise<{
18
+ diffText: string;
19
+ diffRefs: GlDiffRefs;
20
+ }>;
21
+ interface GlNote {
22
+ id?: number;
23
+ body?: string;
24
+ type?: string | null;
25
+ parent_id?: number;
26
+ reply_id?: number;
27
+ discussion_id?: string;
28
+ }
29
+ export declare function listGlNotes(ref: GlRef): Promise<GlNote[]>;
30
+ export declare function listGlFindingIds(ref: GlRef): Promise<Set<string>>;
31
+ export declare function listGlWontFixFindingIds(ref: GlRef): Promise<Set<string>>;
32
+ /** Resolve unresolved MR discussions whose notes contain one of the finding ids. */
33
+ export declare function resolveGlDiscussionsForIds(ref: GlRef, ids: Iterable<string>, log?: (msg: string) => void): Promise<number>;
34
+ export interface PostGlReviewOptions {
35
+ ref: GlRef;
36
+ diffRefs: GlDiffRefs;
37
+ result: ReviewResult;
38
+ failed: boolean;
39
+ log?: (msg: string) => void;
40
+ }
41
+ /**
42
+ * Post findings to a GitLab MR: one summary note plus one positioned discussion
43
+ * per *new* finding. Persistent findings (same pr-review-id) are skipped.
44
+ */
45
+ export declare function postGlReview(opts: PostGlReviewOptions): Promise<void>;
46
+ export {};
@@ -0,0 +1,213 @@
1
+ import { formatBbCommentBody, formatBbSummaryBody } from "../bitbucket/comments.js";
2
+ import { collectIdsFromBodies, parseFindingId } from "../finding-id.js";
3
+ import { AGENT_MARKER, SEVERITY_EMOJI } from "../github/comments.js";
4
+ import { collectWontFixIds } from "../suppress-signals.js";
5
+ function resolveGlToken() {
6
+ const token = process.env.GITLAB_TOKEN || process.env.GL_TOKEN;
7
+ if (!token) {
8
+ throw new Error("GitLab auth required: set GITLAB_TOKEN (personal or project access token with api scope). " +
9
+ "CI_JOB_TOKEN cannot post merge request notes.");
10
+ }
11
+ return token;
12
+ }
13
+ /** Resolve project/MR from flags or GitLab CI env vars. */
14
+ export function resolveGlRef(repoSlug, pr) {
15
+ const env = process.env;
16
+ const serverUrl = (env.CI_SERVER_URL || "https://gitlab.com").replace(/\/$/, "");
17
+ const projectId = repoSlug ? encodeURIComponent(repoSlug) : env.CI_PROJECT_ID;
18
+ const mrIid = pr ?? (env.CI_MERGE_REQUEST_IID ? parseInt(env.CI_MERGE_REQUEST_IID, 10) : undefined);
19
+ if (!projectId || mrIid == null || Number.isNaN(mrIid)) {
20
+ throw new Error("GitLab MR not identified. Pass --repo group/project and --pr <iid>, " +
21
+ "or run in a merge_request_event pipeline (CI_PROJECT_ID / CI_MERGE_REQUEST_IID).");
22
+ }
23
+ return { serverUrl, projectId, mrIid };
24
+ }
25
+ function glApi(ref) {
26
+ return `${ref.serverUrl}/api/v4/projects/${ref.projectId}/merge_requests/${ref.mrIid}`;
27
+ }
28
+ async function glFetch(url, init = {}) {
29
+ const res = await fetch(url, {
30
+ ...init,
31
+ headers: {
32
+ "private-token": resolveGlToken(),
33
+ accept: "application/json",
34
+ ...(init.body ? { "content-type": "application/json" } : {}),
35
+ ...(init.headers ?? {}),
36
+ },
37
+ });
38
+ if (!res.ok) {
39
+ const text = await res.text();
40
+ throw new Error(`GitLab API ${init.method ?? "GET"} ${url} failed (${res.status}): ${text.slice(0, 400)}`);
41
+ }
42
+ return res;
43
+ }
44
+ /** Fetch MR changes and reconstruct a unified diff the parser understands. */
45
+ export async function getGlMrDiff(ref) {
46
+ const res = await glFetch(`${glApi(ref)}/changes`);
47
+ const data = (await res.json());
48
+ if (!data.diff_refs)
49
+ throw new Error("GitLab MR has no diff_refs (empty or unmergeable MR?).");
50
+ const parts = (data.changes ?? []).map((c) => {
51
+ const oldFile = c.new_file ? "/dev/null" : `a/${c.old_path}`;
52
+ const newFile = c.deleted_file ? "/dev/null" : `b/${c.new_path}`;
53
+ return `diff --git a/${c.old_path} b/${c.new_path}\n--- ${oldFile}\n+++ ${newFile}\n${c.diff}`;
54
+ });
55
+ return { diffText: parts.join(""), diffRefs: data.diff_refs };
56
+ }
57
+ export async function listGlNotes(ref) {
58
+ const notes = [];
59
+ let page = 1;
60
+ for (;;) {
61
+ const res = await glFetch(`${glApi(ref)}/notes?per_page=100&page=${page}`);
62
+ const batch = (await res.json());
63
+ notes.push(...batch);
64
+ const next = res.headers.get("x-next-page");
65
+ if (!next)
66
+ break;
67
+ page = parseInt(next, 10);
68
+ }
69
+ return notes;
70
+ }
71
+ export async function listGlFindingIds(ref) {
72
+ const notes = await listGlNotes(ref);
73
+ return collectIdsFromBodies(notes.filter((n) => n.body?.includes(AGENT_MARKER)).map((n) => n.body ?? ""));
74
+ }
75
+ export async function listGlWontFixFindingIds(ref) {
76
+ const notes = await listGlNotes(ref);
77
+ const byId = new Map(notes.flatMap((note) => (note.id == null ? [] : [[note.id, note]])));
78
+ const discussionAgentIds = new Map();
79
+ for (const note of notes) {
80
+ const body = note.body ?? "";
81
+ const id = body.includes(AGENT_MARKER) ? parseFindingId(body) : null;
82
+ if (note.discussion_id && id)
83
+ discussionAgentIds.set(note.discussion_id, id);
84
+ }
85
+ return collectWontFixIds(notes.map((note) => {
86
+ let parent = byId.get(note.parent_id ?? note.reply_id ?? -1);
87
+ while (parent) {
88
+ const body = parent.body ?? "";
89
+ if (body.includes(AGENT_MARKER)) {
90
+ return { body: note.body ?? "", parentAgentId: parseFindingId(body) };
91
+ }
92
+ parent = byId.get(parent.parent_id ?? parent.reply_id ?? -1);
93
+ }
94
+ const body = note.body ?? "";
95
+ return {
96
+ body,
97
+ isAgent: body.includes(AGENT_MARKER),
98
+ parentAgentId: note.discussion_id
99
+ ? discussionAgentIds.get(note.discussion_id) ?? null
100
+ : null,
101
+ };
102
+ }));
103
+ }
104
+ /** Resolve unresolved MR discussions whose notes contain one of the finding ids. */
105
+ export async function resolveGlDiscussionsForIds(ref, ids, log = () => { }) {
106
+ const wanted = new Set(Array.from(ids, (id) => id.toLowerCase()));
107
+ if (wanted.size === 0)
108
+ return 0;
109
+ const discussions = [];
110
+ try {
111
+ let page = 1;
112
+ for (;;) {
113
+ const res = await glFetch(`${glApi(ref)}/discussions?per_page=100&page=${page}`);
114
+ discussions.push(...(await res.json()));
115
+ const next = res.headers.get("x-next-page");
116
+ if (!next)
117
+ break;
118
+ page = parseInt(next, 10);
119
+ }
120
+ }
121
+ catch (err) {
122
+ log(`warn: failed to list GitLab discussions: ${err.message}`);
123
+ return 0;
124
+ }
125
+ let resolved = 0;
126
+ for (const discussion of discussions) {
127
+ const matches = discussion.notes.some((note) => {
128
+ const id = parseFindingId(note.body ?? "");
129
+ return id != null && wanted.has(id.toLowerCase());
130
+ });
131
+ const unresolved = discussion.notes.some((note) => note.resolvable !== false && note.resolved !== true);
132
+ if (!matches || !unresolved)
133
+ continue;
134
+ try {
135
+ await glFetch(`${glApi(ref)}/discussions/${discussion.id}`, {
136
+ method: "PUT",
137
+ body: JSON.stringify({ resolved: true }),
138
+ });
139
+ resolved++;
140
+ }
141
+ catch (err) {
142
+ log(`warn: failed to resolve GitLab discussion ${discussion.id}: ${err.message}`);
143
+ }
144
+ }
145
+ return resolved;
146
+ }
147
+ /**
148
+ * Post findings to a GitLab MR: one summary note plus one positioned discussion
149
+ * per *new* finding. Persistent findings (same pr-review-id) are skipped.
150
+ */
151
+ export async function postGlReview(opts) {
152
+ const { ref, diffRefs, result, log = () => { } } = opts;
153
+ const notes = await listGlNotes(ref);
154
+ const mine = notes.filter((n) => n.body?.includes(AGENT_MARKER));
155
+ const existingIds = collectIdsFromBodies(mine.map((n) => n.body ?? ""));
156
+ const alreadySummarized = mine.some((n) => n.type == null);
157
+ if (!alreadySummarized || result.findings.length === 0) {
158
+ await glFetch(`${glApi(ref)}/notes`, {
159
+ method: "POST",
160
+ body: JSON.stringify({ body: formatBbSummaryBody(result, opts.failed) }),
161
+ });
162
+ }
163
+ const toPost = result.findingsToPost ?? result.findings;
164
+ let posted = 0;
165
+ let skipped = 0;
166
+ const failedInline = [];
167
+ for (const f of toPost) {
168
+ if (f.id && existingIds.has(f.id)) {
169
+ skipped++;
170
+ continue;
171
+ }
172
+ try {
173
+ await glFetch(`${glApi(ref)}/discussions`, {
174
+ method: "POST",
175
+ body: JSON.stringify({
176
+ body: formatBbCommentBody(f),
177
+ position: {
178
+ position_type: "text",
179
+ base_sha: diffRefs.base_sha,
180
+ start_sha: diffRefs.start_sha,
181
+ head_sha: diffRefs.head_sha,
182
+ new_path: f.file,
183
+ new_line: f.end_line,
184
+ },
185
+ }),
186
+ });
187
+ posted++;
188
+ }
189
+ catch {
190
+ failedInline.push(f);
191
+ }
192
+ }
193
+ if (failedInline.length > 0) {
194
+ const body = [
195
+ "### Findings that could not be placed inline",
196
+ ...failedInline.map((f) => `- ${SEVERITY_EMOJI[f.severity]} **${f.severity}** \`${f.file}:${f.start_line}-${f.end_line}\` — ${f.title}\n\n ${f.body.split("\n").join("\n ")}`),
197
+ "",
198
+ AGENT_MARKER,
199
+ ].join("\n");
200
+ await glFetch(`${glApi(ref)}/notes`, { method: "POST", body: JSON.stringify({ body }) });
201
+ }
202
+ log(`GitLab: posted ${posted} inline discussion(s)` +
203
+ (skipped ? `, skipped ${skipped} duplicate(s)` : "") +
204
+ (failedInline.length ? `, ${failedInline.length} moved to a summary note` : "") +
205
+ ".");
206
+ const resolvedIds = result.reconciliation?.resolved ?? [];
207
+ if (resolvedIds.length > 0) {
208
+ const resolved = await resolveGlDiscussionsForIds(ref, resolvedIds, log);
209
+ if (resolved)
210
+ log(`GitLab: resolved ${resolved} discussion(s) for fixed findings.`);
211
+ }
212
+ }
213
+ //# sourceMappingURL=comments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/gitlab/comments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export { runReview } from "./review.js";
2
+ export { runIndex, selectContext, loadIndex } from "codengram";
3
+ export { loadConfig, DEFAULT_CONFIG } from "./config.js";
4
+ export { parseDiff, renderDiffForPrompt } from "./diff/parse.js";
5
+ export { validateFindings, reviewOutputSchema, findingSchema } from "./llm/schema.js";
6
+ export { formatReport, shouldFail } from "./report/cli.js";
7
+ export { fingerprintFinding, normalizeTitle, parseFindingId, embedFindingId, findingsSoftMatch, titleSimilarity, } from "./finding-id.js";
8
+ export { reconcileFindings } from "./reconcile.js";
9
+ export { loadSuppressions, SUPPRESSIONS_FILENAME } from "./suppressions.js";
10
+ export * from "./types.js";
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { runReview } from "./review.js";
2
+ export { runIndex, selectContext, loadIndex } from "codengram";
3
+ export { loadConfig, DEFAULT_CONFIG } from "./config.js";
4
+ export { parseDiff, renderDiffForPrompt } from "./diff/parse.js";
5
+ export { validateFindings, reviewOutputSchema, findingSchema } from "./llm/schema.js";
6
+ export { formatReport, shouldFail } from "./report/cli.js";
7
+ export { fingerprintFinding, normalizeTitle, parseFindingId, embedFindingId, findingsSoftMatch, titleSimilarity, } from "./finding-id.js";
8
+ export { reconcileFindings } from "./reconcile.js";
9
+ export { loadSuppressions, SUPPRESSIONS_FILENAME } from "./suppressions.js";
10
+ export * from "./types.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,cAAc,YAAY,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { FileDiff, ReviewConfig } from "../types.js";
2
+ export declare const REVIEW_SYSTEM_PROMPT = "You are a senior software engineer reviewing a pull request. You are rigorous but pragmatic: you flag real problems, not style preferences the team hasn't asked for.\n\nReview the diff for these categories:\n- bug: logic errors, off-by-one mistakes, incorrect conditions, broken error handling, race conditions, wrong API usage\n- security: injection, unsafe deserialization, secrets in code, missing authorization or validation at trust boundaries, path traversal\n- missing-tests: changed or new behavior with no corresponding test change, especially branches and error paths\n- naming: identifiers inconsistent with the surrounding codebase's conventions, or misleading about what they do\n- complexity: functions that grew too long or deeply nested to reason about, duplicated logic that already exists elsewhere in the repo\n- custom: anything the repository's custom instructions ask you to flag\n\nRules:\n1. Comment ONLY on lines that appear as added (+) lines in the diff. Use the new-file line numbers printed at the start of each line.\n2. Use the REPOSITORY CONTEXT section (summaries and symbols of related files) to judge consistency, spot callers the change might break, and avoid flagging things the codebase already handles elsewhere. Do not report findings about context files themselves \u2014 only about the diff.\n3. Severity rubric:\n - critical: will corrupt data, break production, or is an exploitable vulnerability\n - high: incorrect behavior on realistic inputs, or a security weakness\n - medium: likely bug under edge cases, missing tests for risky logic, significant maintainability problem\n - low: minor issues worth fixing but not blocking\n - info: observations and suggestions, no action strictly required\n4. Report every real issue you find, including ones you are uncertain about \u2014 set confidence accordingly; a downstream filter handles thresholds. Do not pad the review with nitpicks to seem thorough.\n5. When you provide a suggestion, it must be a drop-in replacement for exactly the lines in start_line..end_line, complete and correctly indented.\n6. Keep each finding's body focused: what is wrong, why it matters, how to fix it.\n7. When the REPOSITORY CONTEXT contradicts a suspicion (the pattern is established elsewhere, a caller already handles the case, a convention explains the choice), do not report it as high or critical unless you can cite the specific added lines that break it \u2014 cite that evidence in the body, or lower the severity and confidence accordingly. Never report a critical/high finding that rests on guesses about code you cannot see.";
3
+ export declare const CRITIQUE_SYSTEM_PROMPT = "You are re-reading your own PR review before it is posted. Your ONLY job is to remove findings you would walk back if a developer pushed back \u2014 speculative issues, style opinions dressed as bugs, problems the surrounding code or repository context already handles, or duplicates.\n\nRules:\n1. You may ONLY drop findings. Never edit, merge, reword, or add findings.\n2. Keep every finding you would defend in a face-to-face review \u2014 when in doubt, keep it. Dropping a real bug is far worse than keeping a borderline nitpick.\n3. Return the ids of the findings to KEEP.";
4
+ export declare function buildCritiqueUserPrompt(input: {
5
+ findings: {
6
+ id?: string;
7
+ file: string;
8
+ start_line: number;
9
+ severity: string;
10
+ title: string;
11
+ body: string;
12
+ }[];
13
+ changeDescription: string;
14
+ }): string;
15
+ export interface ReviewPromptInput {
16
+ files: FileDiff[];
17
+ /** Rendered repository context from the codemap; empty when no index exists. */
18
+ context: string;
19
+ config: ReviewConfig;
20
+ /** e.g. "PR #42: Add session refresh" or "local diff vs origin/main" */
21
+ changeDescription: string;
22
+ }
23
+ export declare function buildReviewUserPrompt(input: ReviewPromptInput): string;
@@ -0,0 +1,53 @@
1
+ import { renderDiffForPrompt } from "../diff/parse.js";
2
+ export const REVIEW_SYSTEM_PROMPT = `You are a senior software engineer reviewing a pull request. You are rigorous but pragmatic: you flag real problems, not style preferences the team hasn't asked for.
3
+
4
+ Review the diff for these categories:
5
+ - bug: logic errors, off-by-one mistakes, incorrect conditions, broken error handling, race conditions, wrong API usage
6
+ - security: injection, unsafe deserialization, secrets in code, missing authorization or validation at trust boundaries, path traversal
7
+ - missing-tests: changed or new behavior with no corresponding test change, especially branches and error paths
8
+ - naming: identifiers inconsistent with the surrounding codebase's conventions, or misleading about what they do
9
+ - complexity: functions that grew too long or deeply nested to reason about, duplicated logic that already exists elsewhere in the repo
10
+ - custom: anything the repository's custom instructions ask you to flag
11
+
12
+ Rules:
13
+ 1. Comment ONLY on lines that appear as added (+) lines in the diff. Use the new-file line numbers printed at the start of each line.
14
+ 2. Use the REPOSITORY CONTEXT section (summaries and symbols of related files) to judge consistency, spot callers the change might break, and avoid flagging things the codebase already handles elsewhere. Do not report findings about context files themselves — only about the diff.
15
+ 3. Severity rubric:
16
+ - critical: will corrupt data, break production, or is an exploitable vulnerability
17
+ - high: incorrect behavior on realistic inputs, or a security weakness
18
+ - medium: likely bug under edge cases, missing tests for risky logic, significant maintainability problem
19
+ - low: minor issues worth fixing but not blocking
20
+ - info: observations and suggestions, no action strictly required
21
+ 4. Report every real issue you find, including ones you are uncertain about — set confidence accordingly; a downstream filter handles thresholds. Do not pad the review with nitpicks to seem thorough.
22
+ 5. When you provide a suggestion, it must be a drop-in replacement for exactly the lines in start_line..end_line, complete and correctly indented.
23
+ 6. Keep each finding's body focused: what is wrong, why it matters, how to fix it.
24
+ 7. When the REPOSITORY CONTEXT contradicts a suspicion (the pattern is established elsewhere, a caller already handles the case, a convention explains the choice), do not report it as high or critical unless you can cite the specific added lines that break it — cite that evidence in the body, or lower the severity and confidence accordingly. Never report a critical/high finding that rests on guesses about code you cannot see.`;
25
+ export const CRITIQUE_SYSTEM_PROMPT = `You are re-reading your own PR review before it is posted. Your ONLY job is to remove findings you would walk back if a developer pushed back — speculative issues, style opinions dressed as bugs, problems the surrounding code or repository context already handles, or duplicates.
26
+
27
+ Rules:
28
+ 1. You may ONLY drop findings. Never edit, merge, reword, or add findings.
29
+ 2. Keep every finding you would defend in a face-to-face review — when in doubt, keep it. Dropping a real bug is far worse than keeping a borderline nitpick.
30
+ 3. Return the ids of the findings to KEEP.`;
31
+ export function buildCritiqueUserPrompt(input) {
32
+ const list = input.findings
33
+ .map((f) => `- id: ${f.id}\n location: ${f.file}:${f.start_line} [${f.severity}]\n title: ${f.title}\n body: ${f.body}`)
34
+ .join("\n");
35
+ return `Change under review: ${input.changeDescription}\n\n# FINDINGS\n${list}\n\nReturn the ids to keep.`;
36
+ }
37
+ export function buildReviewUserPrompt(input) {
38
+ const parts = [];
39
+ parts.push(`Reviewing: ${input.changeDescription}`);
40
+ if (input.config.custom_instructions.trim()) {
41
+ parts.push(`# CUSTOM REVIEW INSTRUCTIONS (from this repository's .pr-review.yml)\n${input.config.custom_instructions.trim()}`);
42
+ }
43
+ if (input.context.trim()) {
44
+ parts.push(`# REPOSITORY CONTEXT\nSummaries and exported symbols of files related to this change (importers listed first — they depend on the changed code):\n\n${input.context}`);
45
+ }
46
+ else {
47
+ parts.push(`# REPOSITORY CONTEXT\n(none available — no codemap index; review the diff on its own)`);
48
+ }
49
+ const diffs = input.files.map((f) => renderDiffForPrompt(f)).join("\n\n");
50
+ parts.push(`# DIFF\nEach line is prefixed with its new-file line number. Only '+' lines are commentable.\n\n${diffs}`);
51
+ return parts.join("\n\n");
52
+ }
53
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/llm/prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;8aAsB0Y,CAAC;AAE/a,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;2CAKK,CAAC;AAE5C,MAAM,UAAU,uBAAuB,CAAC,KAGvC;IACC,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ;SACxB,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,SAAS,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,QAAQ,eAAe,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,IAAI,EAAE,CACjH;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,wBAAwB,KAAK,CAAC,iBAAiB,mBAAmB,IAAI,6BAA6B,CAAC;AAC7G,CAAC;AAWD,MAAM,UAAU,qBAAqB,CAAC,KAAwB;IAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,cAAc,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAEpD,IAAI,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,yEAAyE,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACjI,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,uJAAuJ,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACrL,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,uFAAuF,CAAC,CAAC;IACtG,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1E,KAAK,CAAC,IAAI,CAAC,mGAAmG,KAAK,EAAE,CAAC,CAAC;IAEvH,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC"}