@krotovm/gitlab-ai-review 1.0.28 → 1.0.30

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 CHANGED
@@ -23,7 +23,7 @@ stages: [review]
23
23
 
24
24
  ai_review:
25
25
  stage: review
26
- image: node:20
26
+ image: node:24
27
27
  rules:
28
28
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
29
29
  script:
@@ -37,7 +37,7 @@ stages: [review]
37
37
 
38
38
  ai_review:
39
39
  stage: review
40
- image: node:20
40
+ image: node:24
41
41
  rules:
42
42
  - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
43
43
  script:
@@ -598,6 +598,7 @@ export async function reviewMergeRequestMultiPass(params) {
598
598
  }));
599
599
  const triageMessages = buildTriagePrompt(triageInputs);
600
600
  let triageResult = null;
601
+ let triageText = null;
601
602
  try {
602
603
  const triageCompletion = await createCompletionWithDebug({
603
604
  openaiInstance,
@@ -612,7 +613,7 @@ export async function reviewMergeRequestMultiPass(params) {
612
613
  response_format: { type: "json_object" },
613
614
  },
614
615
  });
615
- const triageText = extractCompletionText(triageCompletion);
616
+ triageText = extractCompletionText(triageCompletion);
616
617
  if (triageText != null)
617
618
  triageResult = parseTriageResponse(triageText);
618
619
  }
@@ -620,7 +621,15 @@ export async function reviewMergeRequestMultiPass(params) {
620
621
  logStep(`Triage pass failed: ${error?.message ?? error}. Falling back to single-pass.`);
621
622
  }
622
623
  if (triageResult == null) {
623
- logStep("Triage parse failed. Falling back to single-pass pipeline.");
624
+ if (triageText != null) {
625
+ const triagePreview = triageText.replace(/\s+/g, " ").trim().slice(0, 200);
626
+ const looksLikeHtml = /<html|<!doctype html/i.test(triageText);
627
+ logStep(`Triage parse failed: expected JSON but got ${looksLikeHtml ? "HTML/non-JSON" : "non-JSON"} response. Preview: ${triagePreview || "<empty>"}`);
628
+ }
629
+ else {
630
+ logStep("Triage parse failed: model returned empty response body.");
631
+ }
632
+ logStep("Falling back to single-pass pipeline.");
624
633
  return await reviewMergeRequestWithTools({
625
634
  openaiInstance,
626
635
  aiModel,
@@ -637,12 +646,14 @@ export async function reviewMergeRequestMultiPass(params) {
637
646
  });
638
647
  }
639
648
  const triageMap = new Map(triageResult.files.map((f) => [f.path, f.verdict]));
640
- const reviewFiles = changes.filter((c) => triageMap.get(c.new_path) !== "SKIP");
649
+ let reviewFiles = changes.filter((c) => triageMap.get(c.new_path) !== "SKIP");
641
650
  const skippedCount = changes.length - reviewFiles.length;
642
- logStep(`Triage: ${reviewFiles.length} file(s) to review, ${skippedCount} skipped. Summary: ${triageResult.summary.slice(0, 120)}...`);
643
651
  if (reviewFiles.length === 0) {
644
- const DISCLAIMER = "This comment was generated by AI review bot.";
645
- return `No confirmed bugs or high-value optimizations found.\n\n---\n_${DISCLAIMER}_`;
652
+ logStep(`Triage wanted to skip all ${changes.length} file(s) overriding to review all. Summary: ${triageResult.summary.slice(0, 120)}...`);
653
+ reviewFiles = changes;
654
+ }
655
+ else {
656
+ logStep(`Triage: ${reviewFiles.length} file(s) to review, ${skippedCount} skipped. Summary: ${triageResult.summary.slice(0, 120)}...`);
646
657
  }
647
658
  logStep(`Pass 2/4: reviewing ${reviewFiles.length} file(s) (concurrency=${reviewConcurrency})`);
648
659
  const allChangedPaths = changes.map((c) => c.new_path);
@@ -126,7 +126,7 @@ export function buildConsolidatePrompt(params) {
126
126
  ];
127
127
  }
128
128
  export function buildVerificationPrompt(params) {
129
- const { perFileFindings, summary, consolidatedFindings, maxFindings, refs, } = params;
129
+ const { perFileFindings, summary, consolidatedFindings, maxFindings, refs } = params;
130
130
  const findingsText = perFileFindings
131
131
  .map((f) => `### ${f.path}\n${f.findings}`)
132
132
  .join("\n\n");
@@ -10,8 +10,12 @@ export const TRIAGE_SYSTEM_LINES = [
10
10
  "",
11
11
  "Rules:",
12
12
  "- When in doubt, verdict is NEEDS_REVIEW.",
13
+ "- Look beyond comments and JSDoc: if the diff changes function signatures, return types, control flow, variable assignments, or adds/removes code lines (not just comments), it is a logic change → NEEDS_REVIEW.",
14
+ "- If a file mixes doc/comment edits with actual code changes, verdict is NEEDS_REVIEW.",
15
+ "- Refactoring (splitting/merging functions, changing data structures, renaming with signature changes) is NEEDS_REVIEW.",
13
16
  "- Deleted files are SKIP unless the deletion could break dependents.",
14
17
  "- New files containing logic are NEEDS_REVIEW.",
15
- "- Test-only files are SKIP unless they cover security-critical or complex logic.",
18
+ "- Test files that add, remove, or change assertions or expected values are NEEDS_REVIEW.",
19
+ "- Test-only files are SKIP only if changes are purely cosmetic (formatting, comments).",
16
20
  "- Config/CI/docs files are SKIP unless they modify build targets, env vars, or secrets.",
17
21
  ];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@krotovm/gitlab-ai-review",
4
- "version": "1.0.28",
4
+ "version": "1.0.30",
5
5
  "description": "CLI tool to generate AI code reviews for GitLab merge requests.",
6
6
  "main": "dist/cli.js",
7
7
  "bin": {