@krotovm/gitlab-ai-review 1.0.23 → 1.0.25
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/dist/cli/ci-review.js +3 -3
- package/dist/prompt/index.js +24 -86
- package/dist/prompt/messages.js +2 -62
- package/dist/prompt/templates/postprocess-system.js +36 -0
- package/dist/prompt/templates/review-system.js +47 -0
- package/dist/prompt/templates/triage-system.js +17 -0
- package/dist/prompt/templates/user-prompts.js +72 -0
- package/dist/prompt/utils.js +10 -2
- package/package.json +1 -1
package/dist/cli/ci-review.js
CHANGED
|
@@ -382,7 +382,7 @@ export async function reviewMergeRequestMultiPass(params) {
|
|
|
382
382
|
const skippedCount = changes.length - reviewFiles.length;
|
|
383
383
|
logStep(`Triage: ${reviewFiles.length} file(s) to review, ${skippedCount} skipped. Summary: ${triageResult.summary.slice(0, 120)}...`);
|
|
384
384
|
if (reviewFiles.length === 0) {
|
|
385
|
-
const DISCLAIMER = "This comment was generated by
|
|
385
|
+
const DISCLAIMER = "This comment was generated by AI review bot.";
|
|
386
386
|
return `No confirmed bugs or high-value optimizations found.\n\n---\n_${DISCLAIMER}_`;
|
|
387
387
|
}
|
|
388
388
|
logStep(`Pass 2/4: reviewing ${reviewFiles.length} file(s) (concurrency=${reviewConcurrency})`);
|
|
@@ -412,7 +412,7 @@ export async function reviewMergeRequestMultiPass(params) {
|
|
|
412
412
|
maxFindings,
|
|
413
413
|
});
|
|
414
414
|
if (consolidateMessages == null) {
|
|
415
|
-
const DISCLAIMER = "This comment was generated by
|
|
415
|
+
const DISCLAIMER = "This comment was generated by AI review bot.";
|
|
416
416
|
return `No confirmed bugs or high-value optimizations found.\n\n---\n_${DISCLAIMER}_`;
|
|
417
417
|
}
|
|
418
418
|
try {
|
|
@@ -449,7 +449,7 @@ export async function reviewMergeRequestMultiPass(params) {
|
|
|
449
449
|
}
|
|
450
450
|
catch (error) {
|
|
451
451
|
logStep(`Consolidation failed: ${error?.message ?? error}. Returning raw per-file findings.`);
|
|
452
|
-
const DISCLAIMER = "This comment was generated by
|
|
452
|
+
const DISCLAIMER = "This comment was generated by AI review bot.";
|
|
453
453
|
const raw = perFileFindings
|
|
454
454
|
.filter((f) => !f.findings.includes("No issues found.") &&
|
|
455
455
|
!f.findings.includes("No confirmed bugs"))
|
package/dist/prompt/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** @format */
|
|
2
2
|
import { buildMainSystemMessages, FILE_REVIEW_SYSTEM, TRIAGE_SYSTEM, } from "./messages.js";
|
|
3
3
|
import { normalizeReviewFindingsMarkdown, sanitizeGitLabMarkdown, truncateWithMarker, } from "./utils.js";
|
|
4
|
+
import { buildConsolidateSystemLines, buildVerificationSystemLines, } from "./templates/postprocess-system.js";
|
|
5
|
+
import { buildConsolidateUserContent, buildFileReviewUserContent, buildMainReviewUserContent, buildTriageUserContent, buildVerificationUserContent, } from "./templates/user-prompts.js";
|
|
4
6
|
export const DEFAULT_PROMPT_LIMITS = {
|
|
5
7
|
maxDiffs: 50,
|
|
6
8
|
maxDiffChars: 16000,
|
|
@@ -33,15 +35,11 @@ export const buildPrompt = ({ changes, limits, allowTools = false, }) => {
|
|
|
33
35
|
const toolNote = allowTools
|
|
34
36
|
? "Tools (get_file_at_ref, grep_repository) are available — use them to verify suspicions and inspect truncated or omitted files."
|
|
35
37
|
: "Tools are unavailable in this run; rely only on visible diff evidence.";
|
|
36
|
-
const userContent =
|
|
37
|
-
|
|
38
|
+
const userContent = buildMainReviewUserContent({
|
|
39
|
+
stats,
|
|
38
40
|
toolNote,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
changesText || "(no changes provided)",
|
|
42
|
-
"",
|
|
43
|
-
"Produce your review now. Follow the system instructions strictly.",
|
|
44
|
-
].join("\n");
|
|
41
|
+
changesText,
|
|
42
|
+
});
|
|
45
43
|
const boundedContent = truncateWithMarker(userContent, effectiveLimits.maxTotalPromptChars, "prompt payload");
|
|
46
44
|
return [...MESSAGES, { role: "user", content: boundedContent }];
|
|
47
45
|
};
|
|
@@ -50,26 +48,12 @@ export const buildPrompt = ({ changes, limits, allowTools = false, }) => {
|
|
|
50
48
|
// ---------------------------------------------------------------------------
|
|
51
49
|
export const DEFAULT_MAX_FINDINGS = 5;
|
|
52
50
|
export const DEFAULT_REVIEW_CONCURRENCY = 5;
|
|
53
|
-
export const DIFF_SNIPPET_CHARS = 300;
|
|
54
51
|
export function buildTriagePrompt(changes) {
|
|
55
|
-
const fileEntries = changes.map((c) => {
|
|
56
|
-
const flags = [];
|
|
57
|
-
if (c.new_file)
|
|
58
|
-
flags.push("new");
|
|
59
|
-
if (c.deleted_file)
|
|
60
|
-
flags.push("deleted");
|
|
61
|
-
if (c.renamed_file)
|
|
62
|
-
flags.push("renamed");
|
|
63
|
-
const flagStr = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
|
|
64
|
-
const snippet = c.diff.slice(0, DIFF_SNIPPET_CHARS);
|
|
65
|
-
const truncNote = c.diff.length > DIFF_SNIPPET_CHARS ? "..." : "";
|
|
66
|
-
return `### ${c.path}${flagStr}\n\`\`\`\n${snippet}${truncNote}\n\`\`\``;
|
|
67
|
-
});
|
|
68
52
|
return [
|
|
69
53
|
TRIAGE_SYSTEM,
|
|
70
54
|
{
|
|
71
55
|
role: "user",
|
|
72
|
-
content:
|
|
56
|
+
content: buildTriageUserContent(changes),
|
|
73
57
|
},
|
|
74
58
|
];
|
|
75
59
|
}
|
|
@@ -103,25 +87,17 @@ export function buildFileReviewPrompt(params) {
|
|
|
103
87
|
const toolNote = allowTools
|
|
104
88
|
? "Tools (get_file_at_ref, grep_repository) are available to verify suspicions or read the full file."
|
|
105
89
|
: "Tools are unavailable; rely only on visible diff evidence.";
|
|
106
|
-
const otherFilesNote = otherChangedFiles.length > 0
|
|
107
|
-
? `\nOther files changed in this MR: ${otherChangedFiles.join(", ")}`
|
|
108
|
-
: "";
|
|
109
90
|
return [
|
|
110
91
|
FILE_REVIEW_SYSTEM,
|
|
111
92
|
{
|
|
112
93
|
role: "user",
|
|
113
|
-
content:
|
|
114
|
-
|
|
115
|
-
otherFilesNote,
|
|
116
|
-
"",
|
|
117
|
-
toolNote,
|
|
118
|
-
"",
|
|
119
|
-
`File: ${filePath}`,
|
|
120
|
-
"Diff:",
|
|
94
|
+
content: buildFileReviewUserContent({
|
|
95
|
+
filePath,
|
|
121
96
|
fileDiff,
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
97
|
+
summary,
|
|
98
|
+
otherChangedFiles,
|
|
99
|
+
toolNote,
|
|
100
|
+
}),
|
|
125
101
|
},
|
|
126
102
|
];
|
|
127
103
|
}
|
|
@@ -137,32 +113,15 @@ export function buildConsolidatePrompt(params) {
|
|
|
137
113
|
return [
|
|
138
114
|
{
|
|
139
115
|
role: "system",
|
|
140
|
-
content:
|
|
141
|
-
"You consolidate per-file code review findings into a final ranked list.",
|
|
142
|
-
`Select the top ${maxFindings} most important findings. Deduplicate overlapping issues.`,
|
|
143
|
-
"Preserve this exact per-finding markdown block:",
|
|
144
|
-
"`- [high|medium] <title>`",
|
|
145
|
-
"` File: <path>`",
|
|
146
|
-
"` Line: ~<N>`",
|
|
147
|
-
"` Why: <one concise sentence with key evidence>`",
|
|
148
|
-
"Rank by: (1) [high] before [medium], (2) correctness > security > perf.",
|
|
149
|
-
"Do not add new findings. Do not add headings, summaries, or commentary.",
|
|
150
|
-
"Drop any finding that: claims a syntax error without quoting the invalid token, claims a function/variable is missing without concrete proof, or flags a refactoring rename as a bug.",
|
|
151
|
-
`If fewer than ${maxFindings} findings exist, return all of them.`,
|
|
152
|
-
'If all findings are low quality or dubious after dedup, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
153
|
-
"GitLab-flavoured markdown.",
|
|
154
|
-
].join("\n"),
|
|
116
|
+
content: buildConsolidateSystemLines(maxFindings).join("\n"),
|
|
155
117
|
},
|
|
156
118
|
{
|
|
157
119
|
role: "user",
|
|
158
|
-
content:
|
|
159
|
-
|
|
160
|
-
"",
|
|
161
|
-
"Per-file findings:",
|
|
120
|
+
content: buildConsolidateUserContent({
|
|
121
|
+
summary,
|
|
162
122
|
findingsText,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
].join("\n"),
|
|
123
|
+
maxFindings,
|
|
124
|
+
}),
|
|
166
125
|
},
|
|
167
126
|
];
|
|
168
127
|
}
|
|
@@ -174,36 +133,15 @@ export function buildVerificationPrompt(params) {
|
|
|
174
133
|
return [
|
|
175
134
|
{
|
|
176
135
|
role: "system",
|
|
177
|
-
content:
|
|
178
|
-
"You are a skeptical verifier of a merge request review.",
|
|
179
|
-
"Your job is to remove weak, speculative, or unsupported findings from the draft list.",
|
|
180
|
-
"Do not add new findings. Keep, rewrite for clarity, or remove existing findings only.",
|
|
181
|
-
"A finding can stay only if it is directly supported by evidence from the per-file findings.",
|
|
182
|
-
"If confidence is not high, drop the finding.",
|
|
183
|
-
"Preserve this exact per-finding markdown block:",
|
|
184
|
-
"`- [high|medium] <title>`",
|
|
185
|
-
"` File: <path>`",
|
|
186
|
-
"` Line: ~<N>`",
|
|
187
|
-
"` Why: <one concise sentence with key evidence>`",
|
|
188
|
-
"Do not add headings, summaries, or extra commentary.",
|
|
189
|
-
`Return at most ${maxFindings} findings.`,
|
|
190
|
-
'If no findings survive verification, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
191
|
-
"GitLab-flavoured markdown.",
|
|
192
|
-
].join("\n"),
|
|
136
|
+
content: buildVerificationSystemLines(maxFindings).join("\n"),
|
|
193
137
|
},
|
|
194
138
|
{
|
|
195
139
|
role: "user",
|
|
196
|
-
content:
|
|
197
|
-
|
|
198
|
-
"",
|
|
199
|
-
"Per-file findings (evidence pool):",
|
|
140
|
+
content: buildVerificationUserContent({
|
|
141
|
+
summary,
|
|
200
142
|
findingsText,
|
|
201
|
-
"",
|
|
202
|
-
"Draft consolidated findings to verify:",
|
|
203
143
|
consolidatedFindings,
|
|
204
|
-
|
|
205
|
-
"Return only the verified final findings.",
|
|
206
|
-
].join("\n"),
|
|
144
|
+
}),
|
|
207
145
|
},
|
|
208
146
|
];
|
|
209
147
|
}
|
|
@@ -232,8 +170,8 @@ export function extractCompletionText(completion) {
|
|
|
232
170
|
}
|
|
233
171
|
return null;
|
|
234
172
|
}
|
|
235
|
-
const ERROR_ANSWER = "
|
|
236
|
-
const DISCLAIMER = "This comment was generated by
|
|
173
|
+
const ERROR_ANSWER = "AI review could not be completed. Please ask a human to review this code change.";
|
|
174
|
+
const DISCLAIMER = "This comment was generated by AI review bot.";
|
|
237
175
|
export const buildAnswer = (completion) => {
|
|
238
176
|
if (completion instanceof Error) {
|
|
239
177
|
const maybeCause = completion.cause;
|
package/dist/prompt/messages.js
CHANGED
|
@@ -1,66 +1,6 @@
|
|
|
1
1
|
/** @format */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
"Find only real bugs introduced by the diff.",
|
|
5
|
-
"Return at most 3 findings. Prefer no finding over a weak one.",
|
|
6
|
-
"",
|
|
7
|
-
"Rules:",
|
|
8
|
-
"- Focus on changed lines.",
|
|
9
|
-
"- Ignore style, refactoring suggestions, and general best practices.",
|
|
10
|
-
"- If uncertain, use tools: get_file_at_ref and grep_repository.",
|
|
11
|
-
"- Report only issues clearly visible in diff or verified by tools.",
|
|
12
|
-
'- If uncertain after checking, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
13
|
-
"",
|
|
14
|
-
"Severity:",
|
|
15
|
-
"- [high]: deterministic runtime/security breakage with clear path.",
|
|
16
|
-
"- [medium]: likely bug with strong evidence.",
|
|
17
|
-
"",
|
|
18
|
-
"Output format (strict):",
|
|
19
|
-
"- `- [high|medium] <title>`",
|
|
20
|
-
"- ` File: <path>`",
|
|
21
|
-
"- ` Line: ~<N>`",
|
|
22
|
-
"- ` Why: <one concise sentence with evidence>`",
|
|
23
|
-
'- If no issues: exactly "No confirmed bugs or high-value optimizations found."',
|
|
24
|
-
];
|
|
25
|
-
export const TRIAGE_SYSTEM_LINES = [
|
|
26
|
-
"You are a senior developer triaging files in a merge request.",
|
|
27
|
-
"For each file, decide whether it NEEDS_REVIEW (modifies logic, functionality, security, or performance) or can be SKIPPED (cosmetic-only: formatting, comments, renaming for clarity, docs, auto-generated files).",
|
|
28
|
-
"",
|
|
29
|
-
"Also produce a concise summary (2-4 sentences) of the entire merge request: what it does and which areas it touches.",
|
|
30
|
-
"",
|
|
31
|
-
"Respond with a JSON object (no markdown fences) in this exact schema:",
|
|
32
|
-
'{ "summary": "<MR summary>", "files": [{ "path": "<file path>", "verdict": "NEEDS_REVIEW" | "SKIP" }] }',
|
|
33
|
-
"",
|
|
34
|
-
"Rules:",
|
|
35
|
-
"- When in doubt, verdict is NEEDS_REVIEW.",
|
|
36
|
-
"- Deleted files are SKIP unless the deletion could break dependents.",
|
|
37
|
-
"- New files containing logic are NEEDS_REVIEW.",
|
|
38
|
-
"- Test-only files are SKIP unless they cover security-critical or complex logic.",
|
|
39
|
-
"- Config/CI/docs files are SKIP unless they modify build targets, env vars, or secrets.",
|
|
40
|
-
];
|
|
41
|
-
export const FILE_REVIEW_SYSTEM_LINES = [
|
|
42
|
-
"You are an AI reviewer for a single-file diff.",
|
|
43
|
-
"Find only real bugs introduced by changed lines.",
|
|
44
|
-
"Return at most 2 findings. Prefer no finding over a weak one.",
|
|
45
|
-
"",
|
|
46
|
-
"Rules:",
|
|
47
|
-
"- Focus on changed lines only.",
|
|
48
|
-
"- Ignore style/refactor/general improvement comments.",
|
|
49
|
-
"- If uncertain, use tools: get_file_at_ref and grep_repository.",
|
|
50
|
-
"- Report only issues clearly visible in diff or verified by tools.",
|
|
51
|
-
'- If uncertain after checking, return exactly: "No issues found."',
|
|
52
|
-
"",
|
|
53
|
-
"Severity:",
|
|
54
|
-
"- [high]: deterministic runtime/security breakage with clear path.",
|
|
55
|
-
"- [medium]: likely bug with strong evidence.",
|
|
56
|
-
"",
|
|
57
|
-
"Output format (strict):",
|
|
58
|
-
"- `- [high|medium] <title>`",
|
|
59
|
-
"- ` File: <path>`",
|
|
60
|
-
"- ` Line: ~<N>`",
|
|
61
|
-
"- ` Why: <one concise sentence with evidence>`",
|
|
62
|
-
'- If no issues: exactly "No issues found."',
|
|
63
|
-
];
|
|
2
|
+
import { FILE_REVIEW_SYSTEM_LINES, MAIN_SYSTEM_LINES, } from "./templates/review-system.js";
|
|
3
|
+
import { TRIAGE_SYSTEM_LINES } from "./templates/triage-system.js";
|
|
64
4
|
export const buildMainSystemMessages = () => [
|
|
65
5
|
{
|
|
66
6
|
role: "system",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** @format */
|
|
2
|
+
export function buildConsolidateSystemLines(maxFindings) {
|
|
3
|
+
return [
|
|
4
|
+
"You consolidate per-file code review findings into a final ranked list.",
|
|
5
|
+
`Select the top ${maxFindings} most important findings. Deduplicate overlapping issues.`,
|
|
6
|
+
"Preserve this exact per-finding markdown block:",
|
|
7
|
+
"`- [high|medium] <title>`",
|
|
8
|
+
"` File: <path>`",
|
|
9
|
+
"` Line: ~<N>`",
|
|
10
|
+
"` Why: <one concise sentence with key evidence>`",
|
|
11
|
+
"Rank by: (1) [high] before [medium], (2) correctness > security > perf.",
|
|
12
|
+
"Do not add new findings. Do not add headings, summaries, or commentary.",
|
|
13
|
+
"Drop any finding that: claims a syntax error without quoting the invalid token, claims a function/variable is missing without concrete proof, or flags a refactoring rename as a bug.",
|
|
14
|
+
`If fewer than ${maxFindings} findings exist, return all of them.`,
|
|
15
|
+
'If all findings are low quality or dubious after dedup, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
16
|
+
"GitLab-flavoured markdown.",
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
export function buildVerificationSystemLines(maxFindings) {
|
|
20
|
+
return [
|
|
21
|
+
"You are a skeptical verifier of a merge request review.",
|
|
22
|
+
"Your job is to remove weak, speculative, or unsupported findings from the draft list.",
|
|
23
|
+
"Do not add new findings. Keep, rewrite for clarity, or remove existing findings only.",
|
|
24
|
+
"A finding can stay only if it is directly supported by evidence from the per-file findings.",
|
|
25
|
+
"If confidence is not high, drop the finding.",
|
|
26
|
+
"Preserve this exact per-finding markdown block:",
|
|
27
|
+
"`- [high|medium] <title>`",
|
|
28
|
+
"` File: <path>`",
|
|
29
|
+
"` Line: ~<N>`",
|
|
30
|
+
"` Why: <one concise sentence with key evidence>`",
|
|
31
|
+
"Do not add headings, summaries, or extra commentary.",
|
|
32
|
+
`Return at most ${maxFindings} findings.`,
|
|
33
|
+
'If no findings survive verification, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
34
|
+
"GitLab-flavoured markdown.",
|
|
35
|
+
];
|
|
36
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** @format */
|
|
2
|
+
export const MAIN_SYSTEM_LINES = [
|
|
3
|
+
"You are an AI code reviewer for pull requests.",
|
|
4
|
+
"Find only real bugs introduced by the diff.",
|
|
5
|
+
"Return at most 3 findings. Prefer no finding over a weak one.",
|
|
6
|
+
"",
|
|
7
|
+
"Rules:",
|
|
8
|
+
"- Focus on changed lines.",
|
|
9
|
+
"- Ignore style, refactoring suggestions, and general best practices.",
|
|
10
|
+
"- If uncertain, use tools: get_file_at_ref and grep_repository.",
|
|
11
|
+
"- Report only issues clearly visible in diff or verified by tools.",
|
|
12
|
+
'- If uncertain after checking, return exactly: "No confirmed bugs or high-value optimizations found."',
|
|
13
|
+
"",
|
|
14
|
+
"Severity:",
|
|
15
|
+
"- [high]: deterministic runtime/security breakage with clear path.",
|
|
16
|
+
"- [medium]: likely bug with strong evidence.",
|
|
17
|
+
"",
|
|
18
|
+
"Output format (strict):",
|
|
19
|
+
"- `- [high|medium] <title>`",
|
|
20
|
+
"- ` File: <path>`",
|
|
21
|
+
"- ` Line: ~<N>`",
|
|
22
|
+
"- ` Why: <one concise sentence with evidence>`",
|
|
23
|
+
'- If no issues: exactly "No confirmed bugs or high-value optimizations found."',
|
|
24
|
+
];
|
|
25
|
+
export const FILE_REVIEW_SYSTEM_LINES = [
|
|
26
|
+
"You are an AI reviewer for a single-file diff.",
|
|
27
|
+
"Find only real bugs introduced by changed lines.",
|
|
28
|
+
"Return at most 2 findings. Prefer no finding over a weak one.",
|
|
29
|
+
"",
|
|
30
|
+
"Rules:",
|
|
31
|
+
"- Focus on changed lines only.",
|
|
32
|
+
"- Ignore style/refactor/general improvement comments.",
|
|
33
|
+
"- If uncertain, use tools: get_file_at_ref and grep_repository.",
|
|
34
|
+
"- Report only issues clearly visible in diff or verified by tools.",
|
|
35
|
+
'- If uncertain after checking, return exactly: "No issues found."',
|
|
36
|
+
"",
|
|
37
|
+
"Severity:",
|
|
38
|
+
"- [high]: deterministic runtime/security breakage with clear path.",
|
|
39
|
+
"- [medium]: likely bug with strong evidence.",
|
|
40
|
+
"",
|
|
41
|
+
"Output format (strict):",
|
|
42
|
+
"- `- [high|medium] <title>`",
|
|
43
|
+
"- ` File: <path>`",
|
|
44
|
+
"- ` Line: ~<N>`",
|
|
45
|
+
"- ` Why: <one concise sentence with evidence>`",
|
|
46
|
+
'- If no issues: exactly "No issues found."',
|
|
47
|
+
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** @format */
|
|
2
|
+
export const TRIAGE_SYSTEM_LINES = [
|
|
3
|
+
"You are a senior developer triaging files in a merge request.",
|
|
4
|
+
"For each file, decide whether it NEEDS_REVIEW (modifies logic, functionality, security, or performance) or can be SKIPPED (cosmetic-only: formatting, comments, renaming for clarity, docs, auto-generated files).",
|
|
5
|
+
"",
|
|
6
|
+
"Also produce a concise summary (2-4 sentences) of the entire merge request: what it does and which areas it touches.",
|
|
7
|
+
"",
|
|
8
|
+
"Respond with a JSON object (no markdown fences) in this exact schema:",
|
|
9
|
+
'{ "summary": "<MR summary>", "files": [{ "path": "<file path>", "verdict": "NEEDS_REVIEW" | "SKIP" }] }',
|
|
10
|
+
"",
|
|
11
|
+
"Rules:",
|
|
12
|
+
"- When in doubt, verdict is NEEDS_REVIEW.",
|
|
13
|
+
"- Deleted files are SKIP unless the deletion could break dependents.",
|
|
14
|
+
"- New files containing logic are NEEDS_REVIEW.",
|
|
15
|
+
"- Test-only files are SKIP unless they cover security-critical or complex logic.",
|
|
16
|
+
"- Config/CI/docs files are SKIP unless they modify build targets, env vars, or secrets.",
|
|
17
|
+
];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** @format */
|
|
2
|
+
export function buildMainReviewUserContent(params) {
|
|
3
|
+
const { stats, toolNote, changesText } = params;
|
|
4
|
+
return [
|
|
5
|
+
`Review the following code changes (git diff format). ${stats}`,
|
|
6
|
+
toolNote,
|
|
7
|
+
"",
|
|
8
|
+
"Changes:",
|
|
9
|
+
changesText || "(no changes provided)",
|
|
10
|
+
"",
|
|
11
|
+
"Produce your review now. Follow the system instructions strictly.",
|
|
12
|
+
].join("\n");
|
|
13
|
+
}
|
|
14
|
+
export function buildTriageUserContent(changes) {
|
|
15
|
+
const fileEntries = changes.map((c) => {
|
|
16
|
+
const flags = [];
|
|
17
|
+
if (c.new_file)
|
|
18
|
+
flags.push("new");
|
|
19
|
+
if (c.deleted_file)
|
|
20
|
+
flags.push("deleted");
|
|
21
|
+
if (c.renamed_file)
|
|
22
|
+
flags.push("renamed");
|
|
23
|
+
const flagStr = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
|
|
24
|
+
const snippet = c.diff.slice(0, 300);
|
|
25
|
+
const truncNote = c.diff.length > 300 ? "..." : "";
|
|
26
|
+
return `### ${c.path}${flagStr}\n\`\`\`\n${snippet}${truncNote}\n\`\`\``;
|
|
27
|
+
});
|
|
28
|
+
return `Triage these ${changes.length} file(s):\n\n${fileEntries.join("\n\n")}`;
|
|
29
|
+
}
|
|
30
|
+
export function buildFileReviewUserContent(params) {
|
|
31
|
+
const { filePath, fileDiff, summary, otherChangedFiles, toolNote } = params;
|
|
32
|
+
const otherFilesNote = otherChangedFiles.length > 0
|
|
33
|
+
? `\nOther files changed in this MR: ${otherChangedFiles.join(", ")}`
|
|
34
|
+
: "";
|
|
35
|
+
return [
|
|
36
|
+
`MR Summary: ${summary}`,
|
|
37
|
+
otherFilesNote,
|
|
38
|
+
"",
|
|
39
|
+
toolNote,
|
|
40
|
+
"",
|
|
41
|
+
`File: ${filePath}`,
|
|
42
|
+
"Diff:",
|
|
43
|
+
fileDiff,
|
|
44
|
+
"",
|
|
45
|
+
"Review this file now.",
|
|
46
|
+
].join("\n");
|
|
47
|
+
}
|
|
48
|
+
export function buildConsolidateUserContent(params) {
|
|
49
|
+
const { summary, findingsText, maxFindings } = params;
|
|
50
|
+
return [
|
|
51
|
+
`MR Summary: ${summary}`,
|
|
52
|
+
"",
|
|
53
|
+
"Per-file findings:",
|
|
54
|
+
findingsText,
|
|
55
|
+
"",
|
|
56
|
+
`Return the top ${maxFindings} findings in the required bullet format.`,
|
|
57
|
+
].join("\n");
|
|
58
|
+
}
|
|
59
|
+
export function buildVerificationUserContent(params) {
|
|
60
|
+
const { summary, findingsText, consolidatedFindings } = params;
|
|
61
|
+
return [
|
|
62
|
+
`MR Summary: ${summary}`,
|
|
63
|
+
"",
|
|
64
|
+
"Per-file findings (evidence pool):",
|
|
65
|
+
findingsText,
|
|
66
|
+
"",
|
|
67
|
+
"Draft consolidated findings to verify:",
|
|
68
|
+
consolidatedFindings,
|
|
69
|
+
"",
|
|
70
|
+
"Return only the verified final findings.",
|
|
71
|
+
].join("\n");
|
|
72
|
+
}
|
package/dist/prompt/utils.js
CHANGED
|
@@ -17,9 +17,17 @@ export function normalizeReviewFindingsMarkdown(input) {
|
|
|
17
17
|
const normalized = input.replace(/\r\n/g, "\n").trim();
|
|
18
18
|
if (normalized === "" || normalized === NO_ISSUES_SENTENCE)
|
|
19
19
|
return normalized;
|
|
20
|
-
|
|
20
|
+
// Some providers collapse each finding into one long line.
|
|
21
|
+
// Expand inline markers so parser can recover structured blocks.
|
|
22
|
+
const expanded = normalized
|
|
23
|
+
.replace(/\s+(File:\s*)/gi, "\n$1")
|
|
24
|
+
.replace(/\s+(Line:\s*)/gi, "\n$1")
|
|
25
|
+
.replace(/\s+(Why:\s*)/gi, "\n$1")
|
|
26
|
+
.replace(/(Why:\s*[^\n]+?)\s+([-*•]\s*\[(?:high|medium)\])/gi, "$1\n$2")
|
|
27
|
+
.trim();
|
|
28
|
+
const lines = expanded.split("\n");
|
|
21
29
|
const findings = [];
|
|
22
|
-
const headerRe = /^\s
|
|
30
|
+
const headerRe = /^\s*(?:[-*•]\s*)?\[(high|medium)\]\s+(.+?)\s*$/i;
|
|
23
31
|
const fileRe = /^\s*[-*]?\s*File:\s*(.+?)\s*$/i;
|
|
24
32
|
const lineRe = /^\s*[-*]?\s*Line:\s*(.+?)\s*$/i;
|
|
25
33
|
const whyRe = /^\s*[-*]?\s*Why:\s*(.+?)\s*$/i;
|