@juspay/yama 1.1.0 → 1.1.1

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.
@@ -1,15 +1,15 @@
1
- "use strict";
2
1
  /**
3
2
  * Enhanced Code Reviewer - Optimized to work with Unified Context
4
3
  * Preserves all original functionality from pr-police.js but optimized
5
4
  */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.CodeReviewer = void 0;
8
- exports.createCodeReviewer = createCodeReviewer;
9
5
  // NeuroLink will be dynamically imported
10
- const types_1 = require("../types");
11
- const Logger_1 = require("../utils/Logger");
12
- class CodeReviewer {
6
+ import { ProviderError, } from "../types/index.js";
7
+ import { logger } from "../utils/Logger.js";
8
+ export class CodeReviewer {
9
+ neurolink;
10
+ bitbucketProvider;
11
+ aiConfig;
12
+ reviewConfig;
13
13
  constructor(bitbucketProvider, aiConfig, reviewConfig) {
14
14
  this.bitbucketProvider = bitbucketProvider;
15
15
  this.aiConfig = aiConfig;
@@ -21,8 +21,8 @@ class CodeReviewer {
21
21
  async reviewCodeWithContext(context, options) {
22
22
  const startTime = Date.now();
23
23
  try {
24
- Logger_1.logger.phase('🧪 Conducting AI-powered code analysis...');
25
- Logger_1.logger.info(`Analyzing ${context.diffStrategy.fileCount} files using ${context.diffStrategy.strategy} strategy`);
24
+ logger.phase("🧪 Conducting AI-powered code analysis...");
25
+ logger.info(`Analyzing ${context.diffStrategy.fileCount} files using ${context.diffStrategy.strategy} strategy`);
26
26
  const analysisPrompt = this.buildAnalysisPrompt(context, options);
27
27
  const violations = await this.analyzeWithAI(analysisPrompt, context);
28
28
  const validatedViolations = this.validateViolations(violations, context);
@@ -31,12 +31,12 @@ class CodeReviewer {
31
31
  }
32
32
  const duration = Math.round((Date.now() - startTime) / 1000);
33
33
  const result = this.generateReviewResult(validatedViolations, duration, context);
34
- Logger_1.logger.success(`Code review completed in ${duration}s: ${validatedViolations.length} violations found`);
34
+ logger.success(`Code review completed in ${duration}s: ${validatedViolations.length} violations found`);
35
35
  return result;
36
36
  }
37
37
  catch (error) {
38
- Logger_1.logger.error(`Code review failed: ${error.message}`);
39
- throw new types_1.ProviderError(`Code review failed: ${error.message}`);
38
+ logger.error(`Code review failed: ${error.message}`);
39
+ throw new ProviderError(`Code review failed: ${error.message}`);
40
40
  }
41
41
  }
42
42
  /**
@@ -46,7 +46,9 @@ class CodeReviewer {
46
46
  const validatedViolations = [];
47
47
  const diffContent = this.extractDiffContent(context);
48
48
  for (const violation of violations) {
49
- if (violation.type === 'inline' && violation.code_snippet && violation.file) {
49
+ if (violation.type === "inline" &&
50
+ violation.code_snippet &&
51
+ violation.file) {
50
52
  // Check if the code snippet exists in the diff
51
53
  if (diffContent.includes(violation.code_snippet)) {
52
54
  validatedViolations.push(violation);
@@ -58,8 +60,8 @@ class CodeReviewer {
58
60
  validatedViolations.push(fixedViolation);
59
61
  }
60
62
  else {
61
- Logger_1.logger.debug(`⚠️ Skipping violation - snippet not found in diff: ${violation.file}`);
62
- Logger_1.logger.debug(` Original snippet: "${violation.code_snippet}"`);
63
+ logger.debug(`⚠️ Skipping violation - snippet not found in diff: ${violation.file}`);
64
+ logger.debug(` Original snippet: "${violation.code_snippet}"`);
63
65
  }
64
66
  }
65
67
  }
@@ -68,50 +70,56 @@ class CodeReviewer {
68
70
  validatedViolations.push(violation);
69
71
  }
70
72
  }
71
- Logger_1.logger.debug(`Validated ${validatedViolations.length} out of ${violations.length} violations`);
73
+ logger.debug(`Validated ${validatedViolations.length} out of ${violations.length} violations`);
72
74
  return validatedViolations;
73
75
  }
74
76
  /**
75
77
  * Try to fix code snippet by finding it in the actual diff
76
78
  */
77
79
  tryFixCodeSnippet(violation, context) {
78
- if (!violation.file || !violation.code_snippet)
80
+ if (!violation.file || !violation.code_snippet) {
79
81
  return null;
82
+ }
80
83
  try {
81
84
  // Get the diff for this specific file
82
85
  let fileDiff;
83
- if (context.diffStrategy.strategy === 'whole' && context.prDiff) {
86
+ if (context.diffStrategy.strategy === "whole" && context.prDiff) {
84
87
  // Extract file diff from whole diff - handle different path formats
85
- const diffLines = context.prDiff.diff.split('\n');
88
+ const diffLines = context.prDiff.diff.split("\n");
86
89
  let fileStartIndex = -1;
87
90
  // Generate all possible path variations
88
91
  const pathVariations = this.generatePathVariations(violation.file);
89
92
  // Try to find the file in the diff with various path formats
90
93
  for (let i = 0; i < diffLines.length; i++) {
91
94
  const line = diffLines[i];
92
- if (line.startsWith('diff --git') || line.startsWith('Index:')) {
95
+ if (line.startsWith("diff --git") || line.startsWith("Index:")) {
93
96
  for (const pathVariation of pathVariations) {
94
97
  if (line.includes(pathVariation)) {
95
98
  fileStartIndex = i;
96
99
  break;
97
100
  }
98
101
  }
99
- if (fileStartIndex >= 0)
102
+ if (fileStartIndex >= 0) {
100
103
  break;
104
+ }
101
105
  }
102
106
  }
103
107
  if (fileStartIndex >= 0) {
104
- const nextFileIndex = diffLines.findIndex((line, idx) => idx > fileStartIndex && (line.startsWith('diff --git') || line.startsWith('Index:')));
105
- fileDiff = diffLines.slice(fileStartIndex, nextFileIndex > 0 ? nextFileIndex : diffLines.length).join('\n');
108
+ const nextFileIndex = diffLines.findIndex((line, idx) => idx > fileStartIndex &&
109
+ (line.startsWith("diff --git") || line.startsWith("Index:")));
110
+ fileDiff = diffLines
111
+ .slice(fileStartIndex, nextFileIndex > 0 ? nextFileIndex : diffLines.length)
112
+ .join("\n");
106
113
  }
107
114
  }
108
- else if (context.diffStrategy.strategy === 'file-by-file' && context.fileDiffs) {
115
+ else if (context.diffStrategy.strategy === "file-by-file" &&
116
+ context.fileDiffs) {
109
117
  // Try all path variations
110
118
  const pathVariations = this.generatePathVariations(violation.file);
111
119
  for (const path of pathVariations) {
112
120
  fileDiff = context.fileDiffs.get(path);
113
121
  if (fileDiff) {
114
- Logger_1.logger.debug(`Found diff for ${violation.file} using variation: ${path}`);
122
+ logger.debug(`Found diff for ${violation.file} using variation: ${path}`);
115
123
  break;
116
124
  }
117
125
  }
@@ -120,14 +128,14 @@ class CodeReviewer {
120
128
  for (const [key, value] of context.fileDiffs.entries()) {
121
129
  if (key.endsWith(violation.file) || violation.file.endsWith(key)) {
122
130
  fileDiff = value;
123
- Logger_1.logger.debug(`Found diff for ${violation.file} using partial match: ${key}`);
131
+ logger.debug(`Found diff for ${violation.file} using partial match: ${key}`);
124
132
  break;
125
133
  }
126
134
  }
127
135
  }
128
136
  }
129
137
  if (!fileDiff) {
130
- Logger_1.logger.debug(`❌ Could not find diff for file: ${violation.file}`);
138
+ logger.debug(`❌ Could not find diff for file: ${violation.file}`);
131
139
  return null;
132
140
  }
133
141
  // First, try to find the exact line with line number extraction
@@ -136,27 +144,28 @@ class CodeReviewer {
136
144
  const fixedViolation = { ...violation };
137
145
  fixedViolation.line_type = lineInfo.lineType;
138
146
  // Extract search context from the diff
139
- const diffLines = fileDiff.split('\n');
140
- const snippetIndex = diffLines.findIndex(line => line === violation.code_snippet);
147
+ const diffLines = fileDiff.split("\n");
148
+ const snippetIndex = diffLines.findIndex((line) => line === violation.code_snippet);
141
149
  if (snippetIndex > 0 && snippetIndex < diffLines.length - 1) {
142
150
  fixedViolation.search_context = {
143
151
  before: [diffLines[snippetIndex - 1]],
144
- after: [diffLines[snippetIndex + 1]]
152
+ after: [diffLines[snippetIndex + 1]],
145
153
  };
146
154
  }
147
- Logger_1.logger.debug(`✅ Found exact match with line number for ${violation.file}`);
155
+ logger.debug(`✅ Found exact match with line number for ${violation.file}`);
148
156
  return fixedViolation;
149
157
  }
150
158
  // Fallback: Clean the snippet and try fuzzy matching
151
159
  const cleanSnippet = violation.code_snippet
152
160
  .trim()
153
- .replace(/^[+\-\s]/, ''); // Remove diff prefix for searching
161
+ .replace(/^[+\-\s]/, ""); // Remove diff prefix for searching
154
162
  // Look for the clean snippet in the diff
155
- const diffLines = fileDiff.split('\n');
163
+ const diffLines = fileDiff.split("\n");
156
164
  for (let i = 0; i < diffLines.length; i++) {
157
165
  const line = diffLines[i];
158
- const cleanLine = line.replace(/^[+\-\s]/, '').trim();
159
- if (cleanLine.includes(cleanSnippet) || cleanSnippet.includes(cleanLine)) {
166
+ const cleanLine = line.replace(/^[+\-\s]/, "").trim();
167
+ if (cleanLine.includes(cleanSnippet) ||
168
+ cleanSnippet.includes(cleanLine)) {
160
169
  // Found a match! Update the violation with the correct snippet
161
170
  const fixedViolation = { ...violation };
162
171
  fixedViolation.code_snippet = line; // Use the full line with diff prefix
@@ -164,18 +173,18 @@ class CodeReviewer {
164
173
  if (i > 0 && i < diffLines.length - 1) {
165
174
  fixedViolation.search_context = {
166
175
  before: [diffLines[i - 1]],
167
- after: [diffLines[i + 1]]
176
+ after: [diffLines[i + 1]],
168
177
  };
169
178
  }
170
- Logger_1.logger.debug(`✅ Fixed code snippet for ${violation.file} using fuzzy match`);
179
+ logger.debug(`✅ Fixed code snippet for ${violation.file} using fuzzy match`);
171
180
  return fixedViolation;
172
181
  }
173
182
  }
174
- Logger_1.logger.debug(`❌ Could not find snippet in diff for ${violation.file}`);
175
- Logger_1.logger.debug(` Looking for: "${violation.code_snippet}"`);
183
+ logger.debug(`❌ Could not find snippet in diff for ${violation.file}`);
184
+ logger.debug(` Looking for: "${violation.code_snippet}"`);
176
185
  }
177
186
  catch (error) {
178
- Logger_1.logger.debug(`Error fixing code snippet: ${error.message}`);
187
+ logger.debug(`Error fixing code snippet: ${error.message}`);
179
188
  }
180
189
  return null;
181
190
  }
@@ -183,7 +192,7 @@ class CodeReviewer {
183
192
  * Get system prompt for security-focused code review
184
193
  */
185
194
  getSecurityReviewSystemPrompt() {
186
- return this.reviewConfig.systemPrompt ||
195
+ return (this.reviewConfig.systemPrompt ||
187
196
  `You are an Expert Security Code Reviewer for enterprise applications. Your role is to:
188
197
 
189
198
  🔒 SECURITY FIRST: Prioritize security vulnerabilities and data protection
@@ -194,14 +203,17 @@ class CodeReviewer {
194
203
  You provide actionable, educational feedback with specific examples and solutions.
195
204
  Focus on critical issues that could impact production systems.
196
205
 
197
- CRITICAL INSTRUCTION: When identifying issues, you MUST copy the EXACT line from the diff, including the diff prefix (+, -, or space). Do not modify or clean the line in any way.`;
206
+ CRITICAL INSTRUCTION: When identifying issues, you MUST copy the EXACT line from the diff, including the diff prefix (+, -, or space). Do not modify or clean the line in any way.`);
198
207
  }
199
208
  /**
200
209
  * Get analysis requirements from config or defaults
201
210
  */
202
211
  getAnalysisRequirements() {
203
- if (this.reviewConfig.focusAreas && this.reviewConfig.focusAreas.length > 0) {
204
- return this.reviewConfig.focusAreas.map(area => `### ${area}`).join('\n\n');
212
+ if (this.reviewConfig.focusAreas &&
213
+ this.reviewConfig.focusAreas.length > 0) {
214
+ return this.reviewConfig.focusAreas
215
+ .map((area) => `### ${area}`)
216
+ .join("\n\n");
205
217
  }
206
218
  // Default analysis requirements
207
219
  return `### 🔒 Security Analysis (CRITICAL PRIORITY)
@@ -228,7 +240,7 @@ CRITICAL INSTRUCTION: When identifying issues, you MUST copy the EXACT line from
228
240
  */
229
241
  buildCoreAnalysisPrompt(context) {
230
242
  const diffContent = this.extractDiffContent(context);
231
- return `Conduct a comprehensive security and quality analysis of this ${context.diffStrategy.strategy === 'whole' ? 'pull request' : 'code changeset'}.
243
+ return `Conduct a comprehensive security and quality analysis of this ${context.diffStrategy.strategy === "whole" ? "pull request" : "code changeset"}.
232
244
 
233
245
  ## COMPLETE PR CONTEXT:
234
246
  **Title**: ${context.pr.title}
@@ -248,7 +260,7 @@ CRITICAL INSTRUCTION: When identifying issues, you MUST copy the EXACT line from
248
260
  ${context.projectContext.memoryBank.projectContext || context.projectContext.memoryBank.summary}
249
261
 
250
262
  ## PROJECT RULES & STANDARDS:
251
- ${context.projectContext.clinerules || 'No specific rules defined'}
263
+ ${context.projectContext.clinerules || "No specific rules defined"}
252
264
 
253
265
  ## COMPLETE CODE CHANGES (NO TRUNCATION):
254
266
  ${diffContent}
@@ -310,17 +322,18 @@ Return ONLY valid JSON:
310
322
  * Extract diff content based on strategy
311
323
  */
312
324
  extractDiffContent(context) {
313
- if (context.diffStrategy.strategy === 'whole' && context.prDiff) {
325
+ if (context.diffStrategy.strategy === "whole" && context.prDiff) {
314
326
  return context.prDiff.diff || JSON.stringify(context.prDiff, null, 2);
315
327
  }
316
- else if (context.diffStrategy.strategy === 'file-by-file' && context.fileDiffs) {
328
+ else if (context.diffStrategy.strategy === "file-by-file" &&
329
+ context.fileDiffs) {
317
330
  const fileDiffArray = Array.from(context.fileDiffs.entries()).map(([file, diff]) => ({
318
331
  file,
319
- diff
332
+ diff,
320
333
  }));
321
334
  return JSON.stringify(fileDiffArray, null, 2);
322
335
  }
323
- return 'No diff content available';
336
+ return "No diff content available";
324
337
  }
325
338
  /**
326
339
  * Detect project type for better context
@@ -329,42 +342,53 @@ Return ONLY valid JSON:
329
342
  const fileExtensions = new Set();
330
343
  // Extract file extensions from changes
331
344
  if (context.pr.fileChanges) {
332
- context.pr.fileChanges.forEach(file => {
333
- const ext = file.split('.').pop()?.toLowerCase();
334
- if (ext)
345
+ context.pr.fileChanges.forEach((file) => {
346
+ const ext = file.split(".").pop()?.toLowerCase();
347
+ if (ext) {
335
348
  fileExtensions.add(ext);
349
+ }
336
350
  });
337
351
  }
338
- if (fileExtensions.has('rs') || fileExtensions.has('res'))
339
- return 'rescript';
340
- if (fileExtensions.has('ts') || fileExtensions.has('tsx'))
341
- return 'typescript';
342
- if (fileExtensions.has('js') || fileExtensions.has('jsx'))
343
- return 'javascript';
344
- if (fileExtensions.has('py'))
345
- return 'python';
346
- if (fileExtensions.has('go'))
347
- return 'golang';
348
- if (fileExtensions.has('java'))
349
- return 'java';
350
- if (fileExtensions.has('cpp') || fileExtensions.has('c'))
351
- return 'cpp';
352
- return 'mixed';
352
+ if (fileExtensions.has("rs") || fileExtensions.has("res")) {
353
+ return "rescript";
354
+ }
355
+ if (fileExtensions.has("ts") || fileExtensions.has("tsx")) {
356
+ return "typescript";
357
+ }
358
+ if (fileExtensions.has("js") || fileExtensions.has("jsx")) {
359
+ return "javascript";
360
+ }
361
+ if (fileExtensions.has("py")) {
362
+ return "python";
363
+ }
364
+ if (fileExtensions.has("go")) {
365
+ return "golang";
366
+ }
367
+ if (fileExtensions.has("java")) {
368
+ return "java";
369
+ }
370
+ if (fileExtensions.has("cpp") || fileExtensions.has("c")) {
371
+ return "cpp";
372
+ }
373
+ return "mixed";
353
374
  }
354
375
  /**
355
376
  * Assess complexity level for better AI context
356
377
  */
357
378
  assessComplexity(context) {
358
379
  const fileCount = context.diffStrategy.fileCount;
359
- const hasLargeFiles = context.diffStrategy.estimatedSize.includes('Large');
380
+ const hasLargeFiles = context.diffStrategy.estimatedSize.includes("Large");
360
381
  const hasComments = (context.pr.comments?.length || 0) > 0;
361
- if (fileCount > 50)
362
- return 'very-high';
363
- if (fileCount > 20 || hasLargeFiles)
364
- return 'high';
365
- if (fileCount > 10 || hasComments)
366
- return 'medium';
367
- return 'low';
382
+ if (fileCount > 50) {
383
+ return "very-high";
384
+ }
385
+ if (fileCount > 20 || hasLargeFiles) {
386
+ return "high";
387
+ }
388
+ if (fileCount > 10 || hasComments) {
389
+ return "medium";
390
+ }
391
+ return "low";
368
392
  }
369
393
  /**
370
394
  * Legacy method - kept for compatibility but simplified
@@ -378,16 +402,15 @@ Return ONLY valid JSON:
378
402
  */
379
403
  async analyzeWithAI(prompt, context) {
380
404
  try {
381
- Logger_1.logger.debug('Starting AI analysis...');
405
+ logger.debug("Starting AI analysis...");
382
406
  // Initialize NeuroLink with eval-based dynamic import
383
407
  if (!this.neurolink) {
384
- const dynamicImport = eval('(specifier) => import(specifier)');
385
- const { NeuroLink } = await dynamicImport('@juspay/neurolink');
408
+ const { NeuroLink } = await import("@juspay/neurolink");
386
409
  this.neurolink = new NeuroLink();
387
410
  }
388
411
  // Extract context from unified context for better AI understanding
389
412
  const aiContext = {
390
- operation: 'code-review',
413
+ operation: "code-review",
391
414
  repository: `${context.identifier.workspace}/${context.identifier.repository}`,
392
415
  branch: context.identifier.branch,
393
416
  prId: context.identifier.pullRequestId,
@@ -395,52 +418,54 @@ Return ONLY valid JSON:
395
418
  prAuthor: context.pr.author,
396
419
  fileCount: context.diffStrategy.fileCount,
397
420
  diffStrategy: context.diffStrategy.strategy,
398
- analysisType: context.diffStrategy.strategy === 'whole' ? 'comprehensive' : 'file-by-file',
421
+ analysisType: context.diffStrategy.strategy === "whole"
422
+ ? "comprehensive"
423
+ : "file-by-file",
399
424
  projectType: this.detectProjectType(context),
400
425
  hasExistingComments: (context.pr.comments?.length || 0) > 0,
401
- complexity: this.assessComplexity(context)
426
+ complexity: this.assessComplexity(context),
402
427
  };
403
428
  // Simplified, focused prompt without context pollution
404
429
  const corePrompt = this.buildCoreAnalysisPrompt(context);
405
430
  const result = await this.neurolink.generate({
406
431
  input: { text: corePrompt },
407
432
  systemPrompt: this.getSecurityReviewSystemPrompt(),
408
- provider: this.aiConfig.provider || 'auto', // Auto-select best provider
409
- model: this.aiConfig.model || 'best', // Use most capable model
433
+ provider: this.aiConfig.provider || "auto", // Auto-select best provider
434
+ model: this.aiConfig.model || "best", // Use most capable model
410
435
  temperature: this.aiConfig.temperature || 0.3, // Lower for more focused analysis
411
436
  maxTokens: Math.max(this.aiConfig.maxTokens || 0, 2000000), // Quality first - always use higher limit
412
- timeout: '15m', // Allow plenty of time for thorough analysis
437
+ timeout: "15m", // Allow plenty of time for thorough analysis
413
438
  context: aiContext,
414
439
  enableAnalytics: this.aiConfig.enableAnalytics || true,
415
- enableEvaluation: false // Disabled to prevent evaluation warnings
440
+ enableEvaluation: false, // Disabled to prevent evaluation warnings
416
441
  });
417
442
  // Log analytics if available
418
443
  if (result.analytics) {
419
- Logger_1.logger.debug(`AI Analytics - Provider: ${result.provider}, Response Time: ${result.responseTime}ms, Quality Score: ${result.evaluation?.overallScore}`);
444
+ logger.debug(`AI Analytics - Provider: ${result.provider}, Response Time: ${result.responseTime}ms, Quality Score: ${result.evaluation?.overallScore}`);
420
445
  }
421
- Logger_1.logger.debug('AI analysis completed, parsing response...');
446
+ logger.debug("AI analysis completed, parsing response...");
422
447
  // Modern NeuroLink returns { content: string }
423
448
  const analysisData = this.parseAIResponse(result);
424
449
  // Display AI response for debugging
425
- if (Logger_1.logger.getConfig().verbose) {
426
- Logger_1.logger.debug('AI Analysis Response:');
427
- Logger_1.logger.debug(''.repeat(80));
428
- Logger_1.logger.debug(JSON.stringify(analysisData, null, 2));
429
- Logger_1.logger.debug(''.repeat(80));
450
+ if (logger.getConfig().verbose) {
451
+ logger.debug("AI Analysis Response:");
452
+ logger.debug("".repeat(80));
453
+ logger.debug(JSON.stringify(analysisData, null, 2));
454
+ logger.debug("".repeat(80));
430
455
  }
431
456
  if (!analysisData.violations || !Array.isArray(analysisData.violations)) {
432
- Logger_1.logger.debug('No violations array found in AI response');
457
+ logger.debug("No violations array found in AI response");
433
458
  return [];
434
459
  }
435
- Logger_1.logger.debug(`AI analysis found ${analysisData.violations.length} violations`);
460
+ logger.debug(`AI analysis found ${analysisData.violations.length} violations`);
436
461
  return analysisData.violations;
437
462
  }
438
463
  catch (error) {
439
- if (error.message?.includes('timeout')) {
440
- Logger_1.logger.error('⏰ AI analysis timed out after 15 minutes');
441
- throw new Error('Analysis timeout - try reducing diff size or adjusting timeout');
464
+ if (error.message?.includes("timeout")) {
465
+ logger.error("⏰ AI analysis timed out after 15 minutes");
466
+ throw new Error("Analysis timeout - try reducing diff size or adjusting timeout");
442
467
  }
443
- Logger_1.logger.error(`AI analysis failed: ${error.message}`);
468
+ logger.error(`AI analysis failed: ${error.message}`);
444
469
  throw error;
445
470
  }
446
471
  }
@@ -448,12 +473,12 @@ Return ONLY valid JSON:
448
473
  * Post comments to PR using unified context - matching pr-police.js exactly
449
474
  */
450
475
  async postComments(context, violations, _options) {
451
- Logger_1.logger.phase('📝 Posting review comments...');
476
+ logger.phase("📝 Posting review comments...");
452
477
  let commentsPosted = 0;
453
478
  let commentsFailed = 0;
454
479
  const failedComments = [];
455
480
  // Post inline comments
456
- const inlineViolations = violations.filter(v => v.type === 'inline' && v.file && v.code_snippet);
481
+ const inlineViolations = violations.filter((v) => v.type === "inline" && v.file && v.code_snippet);
457
482
  for (const violation of inlineViolations) {
458
483
  try {
459
484
  // Clean file path - remove protocol prefixes ONLY (keep a/ and b/ prefixes)
@@ -467,19 +492,19 @@ Return ONLY valid JSON:
467
492
  // Clean code snippet and fix search context - EXACTLY like pr-police.js
468
493
  const processedViolation = this.cleanCodeSnippet(violation);
469
494
  if (!processedViolation) {
470
- Logger_1.logger.debug(`⚠️ Skipping invalid violation for ${cleanFilePath}`);
495
+ logger.debug(`⚠️ Skipping invalid violation for ${cleanFilePath}`);
471
496
  continue;
472
497
  }
473
498
  const formattedComment = this.formatInlineComment(processedViolation);
474
499
  // Debug logging
475
- Logger_1.logger.debug(`🔍 Posting inline comment:`);
476
- Logger_1.logger.debug(` File: ${cleanFilePath}`);
477
- Logger_1.logger.debug(` Issue: ${processedViolation.issue}`);
478
- Logger_1.logger.debug(` Original snippet: ${violation.code_snippet}`);
479
- Logger_1.logger.debug(` Processed snippet: ${processedViolation.code_snippet}`);
500
+ logger.debug(`🔍 Posting inline comment:`);
501
+ logger.debug(` File: ${cleanFilePath}`);
502
+ logger.debug(` Issue: ${processedViolation.issue}`);
503
+ logger.debug(` Original snippet: ${violation.code_snippet}`);
504
+ logger.debug(` Processed snippet: ${processedViolation.code_snippet}`);
480
505
  if (processedViolation.search_context) {
481
- Logger_1.logger.debug(` Search context before: ${JSON.stringify(processedViolation.search_context.before)}`);
482
- Logger_1.logger.debug(` Search context after: ${JSON.stringify(processedViolation.search_context.after)}`);
506
+ logger.debug(` Search context before: ${JSON.stringify(processedViolation.search_context.before)}`);
507
+ logger.debug(` Search context after: ${JSON.stringify(processedViolation.search_context.after)}`);
483
508
  }
484
509
  // Use new code snippet approach - EXACTLY like pr-police.js
485
510
  await this.bitbucketProvider.addComment(context.identifier, formattedComment, {
@@ -489,21 +514,21 @@ Return ONLY valid JSON:
489
514
  codeSnippet: processedViolation.code_snippet,
490
515
  searchContext: processedViolation.search_context,
491
516
  matchStrategy: "best", // Use best match strategy instead of strict for flexibility
492
- suggestion: processedViolation.suggestion // Pass the suggestion for inline code suggestions
517
+ suggestion: processedViolation.suggestion, // Pass the suggestion for inline code suggestions
493
518
  });
494
519
  commentsPosted++;
495
- Logger_1.logger.debug(`✅ Posted inline comment: ${cleanFilePath} (${processedViolation.issue})`);
520
+ logger.debug(`✅ Posted inline comment: ${cleanFilePath} (${processedViolation.issue})`);
496
521
  }
497
522
  catch (error) {
498
523
  commentsFailed++;
499
524
  const errorMsg = error.message;
500
- Logger_1.logger.debug(`❌ Failed to post inline comment: ${errorMsg}`);
501
- Logger_1.logger.debug(` File: ${violation.file}, Issue: ${violation.issue}`);
502
- Logger_1.logger.debug(` Code snippet: ${violation.code_snippet}`);
525
+ logger.debug(`❌ Failed to post inline comment: ${errorMsg}`);
526
+ logger.debug(` File: ${violation.file}, Issue: ${violation.issue}`);
527
+ logger.debug(` Code snippet: ${violation.code_snippet}`);
503
528
  failedComments.push({
504
529
  file: violation.file,
505
530
  issue: violation.issue,
506
- error: errorMsg
531
+ error: errorMsg,
507
532
  });
508
533
  }
509
534
  }
@@ -513,15 +538,15 @@ Return ONLY valid JSON:
513
538
  const summaryComment = this.generateSummaryComment(violations, context, failedComments);
514
539
  await this.bitbucketProvider.addComment(context.identifier, summaryComment);
515
540
  commentsPosted++;
516
- Logger_1.logger.debug('✅ Posted summary comment');
541
+ logger.debug("✅ Posted summary comment");
517
542
  }
518
543
  catch (error) {
519
- Logger_1.logger.debug(`❌ Failed to post summary comment: ${error.message}`);
544
+ logger.debug(`❌ Failed to post summary comment: ${error.message}`);
520
545
  }
521
546
  }
522
- Logger_1.logger.success(`✅ Posted ${commentsPosted} comments successfully`);
547
+ logger.success(`✅ Posted ${commentsPosted} comments successfully`);
523
548
  if (commentsFailed > 0) {
524
- Logger_1.logger.warn(`⚠️ Failed to post ${commentsFailed} inline comments`);
549
+ logger.warn(`⚠️ Failed to post ${commentsFailed} inline comments`);
525
550
  }
526
551
  }
527
552
  /**
@@ -529,14 +554,23 @@ Return ONLY valid JSON:
529
554
  */
530
555
  formatInlineComment(violation) {
531
556
  const severityConfig = {
532
- CRITICAL: { emoji: '🚨', badge: '**🚨 CRITICAL SECURITY ISSUE**', color: 'red' },
533
- MAJOR: { emoji: '⚠️', badge: '**⚠️ MAJOR ISSUE**', color: 'orange' },
534
- MINOR: { emoji: '📝', badge: '**📝 MINOR IMPROVEMENT**', color: 'blue' },
535
- SUGGESTION: { emoji: '💡', badge: '**💡 SUGGESTION**', color: 'green' }
557
+ CRITICAL: {
558
+ emoji: "🚨",
559
+ badge: "**🚨 CRITICAL SECURITY ISSUE**",
560
+ color: "red",
561
+ },
562
+ MAJOR: { emoji: "⚠️", badge: "**⚠️ MAJOR ISSUE**", color: "orange" },
563
+ MINOR: { emoji: "📝", badge: "**📝 MINOR IMPROVEMENT**", color: "blue" },
564
+ SUGGESTION: { emoji: "💡", badge: "**💡 SUGGESTION**", color: "green" },
536
565
  };
537
566
  const categoryIcons = {
538
- security: '🔒', performance: '⚡', maintainability: '🏗️',
539
- functionality: '⚙️', error_handling: '🛡️', testing: '🧪', general: '📋'
567
+ security: "🔒",
568
+ performance: "⚡",
569
+ maintainability: "🏗️",
570
+ functionality: "⚙️",
571
+ error_handling: "🛡️",
572
+ testing: "🧪",
573
+ general: "📋",
540
574
  };
541
575
  const config = severityConfig[violation.severity] || severityConfig.MINOR;
542
576
  const categoryIcon = categoryIcons[violation.category] || categoryIcons.general;
@@ -544,20 +578,30 @@ Return ONLY valid JSON:
544
578
 
545
579
  **${categoryIcon} ${violation.issue}**
546
580
 
547
- **Category**: ${violation.category.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}
581
+ **Category**: ${violation.category.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase())}
548
582
 
549
583
  **Issue**: ${violation.message}`;
550
584
  if (violation.impact) {
551
585
  comment += `\n\n**Impact**: ${violation.impact}`;
552
586
  }
553
587
  if (violation.suggestion) {
554
- const fileExt = violation.file?.split('.').pop() || 'text';
588
+ const fileExt = violation.file?.split(".").pop() || "text";
555
589
  const langMap = {
556
- js: 'javascript', jsx: 'javascript', ts: 'typescript', tsx: 'typescript',
557
- res: 'rescript', resi: 'rescript', py: 'python', java: 'java',
558
- go: 'go', rb: 'ruby', php: 'php', sql: 'sql', json: 'json'
590
+ js: "javascript",
591
+ jsx: "javascript",
592
+ ts: "typescript",
593
+ tsx: "typescript",
594
+ res: "rescript",
595
+ resi: "rescript",
596
+ py: "python",
597
+ java: "java",
598
+ go: "go",
599
+ rb: "ruby",
600
+ php: "php",
601
+ sql: "sql",
602
+ json: "json",
559
603
  };
560
- const language = langMap[fileExt] || 'text';
604
+ const language = langMap[fileExt] || "text";
561
605
  // Use the escape method for code blocks
562
606
  const escapedCodeBlock = this.escapeMarkdownCodeBlock(violation.suggestion, language);
563
607
  comment += `\n\n**💡 Suggested Fix**:\n${escapedCodeBlock}`;
@@ -570,13 +614,20 @@ Return ONLY valid JSON:
570
614
  */
571
615
  generateSummaryComment(violations, context, failedComments = []) {
572
616
  const stats = this.calculateStats(violations);
573
- const statusEmoji = stats.criticalCount > 0 ? '🚨' :
574
- stats.majorCount > 0 ? '⚠️ ' :
575
- stats.minorCount > 0 ? '📝' : '✅';
576
- const statusText = stats.criticalCount > 0 ? 'CRITICAL ISSUES FOUND' :
577
- stats.majorCount > 0 ? 'ISSUES DETECTED' :
578
- stats.minorCount > 0 ? 'IMPROVEMENTS SUGGESTED' :
579
- 'CODE QUALITY APPROVED';
617
+ const statusEmoji = stats.criticalCount > 0
618
+ ? "🚨"
619
+ : stats.majorCount > 0
620
+ ? "⚠️ "
621
+ : stats.minorCount > 0
622
+ ? "📝"
623
+ : "✅";
624
+ const statusText = stats.criticalCount > 0
625
+ ? "CRITICAL ISSUES FOUND"
626
+ : stats.majorCount > 0
627
+ ? "ISSUES DETECTED"
628
+ : stats.minorCount > 0
629
+ ? "IMPROVEMENTS SUGGESTED"
630
+ : "CODE QUALITY APPROVED";
580
631
  let comment = `
581
632
  ╭─────────────────────────────────────────────────────────────╮
582
633
  │ ⚔️ **YAMA REVIEW REPORT** ⚔️ │
@@ -587,10 +638,10 @@ Return ONLY valid JSON:
587
638
  ### 📊 **Security & Quality Analysis**
588
639
  | **Severity** | **Count** | **Status** |
589
640
  |--------------|-----------|------------|
590
- | 🚨 Critical | ${stats.criticalCount} | ${stats.criticalCount > 0 ? '⛔ Must Fix' : '✅ Clear'} |
591
- | ⚠️ Major | ${stats.majorCount} | ${stats.majorCount > 0 ? '⚠️ Should Fix' : '✅ Clear'} |
592
- | 📝 Minor | ${stats.minorCount} | ${stats.minorCount > 0 ? '📝 Consider Fixing' : '✅ Clear'} |
593
- | 💡 Suggestions | ${stats.suggestionCount} | ${stats.suggestionCount > 0 ? '💡 Optional' : '✅ Clear'} |
641
+ | 🚨 Critical | ${stats.criticalCount} | ${stats.criticalCount > 0 ? "⛔ Must Fix" : "✅ Clear"} |
642
+ | ⚠️ Major | ${stats.majorCount} | ${stats.majorCount > 0 ? "⚠️ Should Fix" : "✅ Clear"} |
643
+ | 📝 Minor | ${stats.minorCount} | ${stats.minorCount > 0 ? "📝 Consider Fixing" : "✅ Clear"} |
644
+ | 💡 Suggestions | ${stats.suggestionCount} | ${stats.suggestionCount > 0 ? "💡 Optional" : "✅ Clear"} |
594
645
 
595
646
  ### 🔍 **Analysis Summary**
596
647
  - **📁 Files Analyzed**: ${context.diffStrategy.fileCount}
@@ -603,12 +654,19 @@ Return ONLY valid JSON:
603
654
  comment += `\n\n### 📍 **Issues by Category**\n`;
604
655
  for (const [category, categoryViolations] of Object.entries(violationsByCategory)) {
605
656
  const categoryIcons = {
606
- security: '🔒', performance: '⚡', maintainability: '🏗️',
607
- functionality: '⚙️', error_handling: '🛡️', testing: '🧪', general: '📋'
657
+ security: "🔒",
658
+ performance: "⚡",
659
+ maintainability: "🏗️",
660
+ functionality: "⚙️",
661
+ error_handling: "🛡️",
662
+ testing: "🧪",
663
+ general: "📋",
608
664
  };
609
- const icon = categoryIcons[category] || '📋';
610
- const name = category.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
611
- comment += `**${icon} ${name}**: ${categoryViolations.length} issue${categoryViolations.length !== 1 ? 's' : ''}\n`;
665
+ const icon = categoryIcons[category] || "📋";
666
+ const name = category
667
+ .replace(/_/g, " ")
668
+ .replace(/\b\w/g, (l) => l.toUpperCase());
669
+ comment += `**${icon} ${name}**: ${categoryViolations.length} issue${categoryViolations.length !== 1 ? "s" : ""}\n`;
612
670
  }
613
671
  }
614
672
  // Add failed comments section if any
@@ -617,17 +675,17 @@ Return ONLY valid JSON:
617
675
  comment += `Some inline comments could not be posted due to code matching issues. `;
618
676
  comment += `Please review the following issues manually:\n\n`;
619
677
  for (const failed of failedComments) {
620
- comment += `- **${failed.issue}** in \`${failed.file || 'unknown file'}\`\n`;
678
+ comment += `- **${failed.issue}** in \`${failed.file || "unknown file"}\`\n`;
621
679
  }
622
680
  }
623
681
  // Add recommendation
624
682
  const recommendation = stats.criticalCount > 0
625
- ? '🚨 **URGENT**: Critical security issues must be resolved before merge'
683
+ ? "🚨 **URGENT**: Critical security issues must be resolved before merge"
626
684
  : stats.majorCount > 0
627
- ? '⚠️ **RECOMMENDED**: Address major issues before merge'
685
+ ? "⚠️ **RECOMMENDED**: Address major issues before merge"
628
686
  : stats.minorCount > 0
629
- ? '📝 **OPTIONAL**: Consider addressing minor improvements'
630
- : '✅ **APPROVED**: Code meets security and quality standards';
687
+ ? "📝 **OPTIONAL**: Consider addressing minor improvements"
688
+ : "✅ **APPROVED**: Code meets security and quality standards";
631
689
  comment += `\n\n### 💡 **Recommendation**
632
690
  ${recommendation}
633
691
 
@@ -642,11 +700,10 @@ ${recommendation}
642
700
  cleanFilePath(filePath) {
643
701
  // Clean the file path but preserve the structure - EXACTLY like pr-police.js
644
702
  // Only clean src:// and dst:// prefixes, keep a/ and b/ prefixes
645
- const cleaned = filePath
646
- .replace(/^(src|dst):\/\//, '');
703
+ const cleaned = filePath.replace(/^(src|dst):\/\//, "");
647
704
  // Log the cleaning for debugging
648
705
  if (cleaned !== filePath) {
649
- Logger_1.logger.debug(`Cleaned file path: ${filePath} -> ${cleaned}`);
706
+ logger.debug(`Cleaned file path: ${filePath} -> ${cleaned}`);
650
707
  }
651
708
  return cleaned;
652
709
  }
@@ -654,12 +711,13 @@ ${recommendation}
654
711
  * Extract exact file path from diff
655
712
  */
656
713
  extractFilePathFromDiff(diff, fileName) {
657
- const lines = diff.split('\n');
714
+ const lines = diff.split("\n");
658
715
  for (const line of lines) {
659
- if (line.startsWith('diff --git')) {
716
+ if (line.startsWith("diff --git")) {
660
717
  // Extract both paths: a/path/to/file b/path/to/file
661
718
  const match = line.match(/diff --git a\/(.*?) b\/(.*?)$/);
662
- if (match && (match[1].includes(fileName) || match[2].includes(fileName))) {
719
+ if (match &&
720
+ (match[1].includes(fileName) || match[2].includes(fileName))) {
663
721
  return match[2]; // Return the 'b/' path (destination)
664
722
  }
665
723
  }
@@ -670,12 +728,12 @@ ${recommendation}
670
728
  * Extract line number from diff for a specific code snippet
671
729
  */
672
730
  extractLineNumberFromDiff(fileDiff, codeSnippet) {
673
- const lines = fileDiff.split('\n');
731
+ const lines = fileDiff.split("\n");
674
732
  let currentNewLine = 0;
675
733
  let currentOldLine = 0;
676
734
  let inHunk = false;
677
735
  // Debug logging
678
- Logger_1.logger.debug(`Looking for snippet: "${codeSnippet}"`);
736
+ logger.debug(`Looking for snippet: "${codeSnippet}"`);
679
737
  for (let i = 0; i < lines.length; i++) {
680
738
  const line = lines[i];
681
739
  // Parse hunk headers (e.g., @@ -10,6 +10,8 @@)
@@ -685,48 +743,51 @@ ${recommendation}
685
743
  currentOldLine = parseInt(hunkMatch[1]);
686
744
  currentNewLine = parseInt(hunkMatch[2]);
687
745
  inHunk = true;
688
- Logger_1.logger.debug(`Found hunk header: old=${currentOldLine}, new=${currentNewLine}`);
746
+ logger.debug(`Found hunk header: old=${currentOldLine}, new=${currentNewLine}`);
689
747
  continue;
690
748
  }
691
749
  // Skip lines that aren't part of the diff content
692
- if (!inHunk || (!line.startsWith('+') && !line.startsWith('-') && !line.startsWith(' '))) {
750
+ if (!inHunk ||
751
+ (!line.startsWith("+") &&
752
+ !line.startsWith("-") &&
753
+ !line.startsWith(" "))) {
693
754
  continue;
694
755
  }
695
756
  // Check if this line matches our snippet
696
757
  if (line === codeSnippet) {
697
758
  let resultLine;
698
759
  let lineType;
699
- if (line.startsWith('+')) {
760
+ if (line.startsWith("+")) {
700
761
  resultLine = currentNewLine;
701
- lineType = 'ADDED';
762
+ lineType = "ADDED";
702
763
  }
703
- else if (line.startsWith('-')) {
764
+ else if (line.startsWith("-")) {
704
765
  resultLine = currentOldLine;
705
- lineType = 'REMOVED';
766
+ lineType = "REMOVED";
706
767
  }
707
768
  else {
708
769
  resultLine = currentNewLine;
709
- lineType = 'CONTEXT';
770
+ lineType = "CONTEXT";
710
771
  }
711
- Logger_1.logger.debug(`Found match at line ${resultLine} (${lineType})`);
772
+ logger.debug(`Found match at line ${resultLine} (${lineType})`);
712
773
  return { lineNumber: resultLine, lineType };
713
774
  }
714
775
  // Update line counters AFTER checking for match
715
776
  // For added lines: only increment new line counter
716
777
  // For removed lines: only increment old line counter
717
778
  // For context lines: increment both counters
718
- if (line.startsWith('+')) {
779
+ if (line.startsWith("+")) {
719
780
  currentNewLine++;
720
781
  }
721
- else if (line.startsWith('-')) {
782
+ else if (line.startsWith("-")) {
722
783
  currentOldLine++;
723
784
  }
724
- else if (line.startsWith(' ')) {
785
+ else if (line.startsWith(" ")) {
725
786
  currentNewLine++;
726
787
  currentOldLine++;
727
788
  }
728
789
  }
729
- Logger_1.logger.debug(`Snippet not found in diff`);
790
+ logger.debug(`Snippet not found in diff`);
730
791
  return null;
731
792
  }
732
793
  /**
@@ -734,7 +795,7 @@ ${recommendation}
734
795
  */
735
796
  escapeMarkdownCodeBlock(code, language) {
736
797
  // If code contains triple backticks, use quadruple backticks
737
- if (code.includes('```')) {
798
+ if (code.includes("```")) {
738
799
  return `\`\`\`\`${language}\n${code}\n\`\`\`\``;
739
800
  }
740
801
  return `\`\`\`${language}\n${code}\n\`\`\``;
@@ -745,49 +806,51 @@ ${recommendation}
745
806
  const fixed = JSON.parse(JSON.stringify(violation));
746
807
  // Fix search_context arrays if they contain embedded newlines
747
808
  if (fixed.search_context) {
748
- if (fixed.search_context.before && Array.isArray(fixed.search_context.before)) {
809
+ if (fixed.search_context.before &&
810
+ Array.isArray(fixed.search_context.before)) {
749
811
  fixed.search_context.before = this.splitArrayLines(fixed.search_context.before);
750
812
  }
751
- if (fixed.search_context.after && Array.isArray(fixed.search_context.after)) {
813
+ if (fixed.search_context.after &&
814
+ Array.isArray(fixed.search_context.after)) {
752
815
  fixed.search_context.after = this.splitArrayLines(fixed.search_context.after);
753
816
  }
754
817
  }
755
818
  // Ensure line_type is set based on code snippet prefix BEFORE cleaning
756
819
  if (!fixed.line_type && fixed.code_snippet) {
757
- if (fixed.code_snippet.startsWith('+')) {
758
- fixed.line_type = 'ADDED';
820
+ if (fixed.code_snippet.startsWith("+")) {
821
+ fixed.line_type = "ADDED";
759
822
  }
760
- else if (fixed.code_snippet.startsWith('-')) {
761
- fixed.line_type = 'REMOVED';
823
+ else if (fixed.code_snippet.startsWith("-")) {
824
+ fixed.line_type = "REMOVED";
762
825
  }
763
826
  else {
764
- fixed.line_type = 'CONTEXT';
827
+ fixed.line_type = "CONTEXT";
765
828
  }
766
829
  }
767
830
  // Clean the code_snippet field to remove diff symbols - EXACTLY like pr-police.js
768
831
  if (fixed.code_snippet) {
769
- fixed.code_snippet = fixed.code_snippet.replace(/^[+\-\s]/, '').trim();
832
+ fixed.code_snippet = fixed.code_snippet.replace(/^[+\-\s]/, "").trim();
770
833
  }
771
834
  // Clean the suggestion field to remove any diff symbols
772
835
  if (fixed.suggestion) {
773
836
  fixed.suggestion = fixed.suggestion
774
- .split('\n')
775
- .map((line) => line.replace(/^[+\-\s]/, '')) // Remove diff symbols at start of each line
776
- .join('\n')
837
+ .split("\n")
838
+ .map((line) => line.replace(/^[+\-\s]/, "")) // Remove diff symbols at start of each line
839
+ .join("\n")
777
840
  .trim();
778
841
  }
779
842
  return fixed;
780
843
  }
781
844
  catch (error) {
782
- Logger_1.logger.debug(`❌ Error cleaning code snippet: ${error.message}`);
845
+ logger.debug(`❌ Error cleaning code snippet: ${error.message}`);
783
846
  return null;
784
847
  }
785
848
  }
786
849
  splitArrayLines(arr) {
787
850
  const result = [];
788
851
  for (const item of arr) {
789
- if (typeof item === 'string' && item.includes('\n')) {
790
- result.push(...item.split('\n').filter(line => line.length > 0));
852
+ if (typeof item === "string" && item.includes("\n")) {
853
+ result.push(...item.split("\n").filter((line) => line.length > 0));
791
854
  }
792
855
  else {
793
856
  result.push(item);
@@ -797,22 +860,24 @@ ${recommendation}
797
860
  }
798
861
  groupViolationsByCategory(violations) {
799
862
  const grouped = {};
800
- violations.forEach(v => {
801
- const category = v.category || 'general';
802
- if (!grouped[category])
863
+ violations.forEach((v) => {
864
+ const category = v.category || "general";
865
+ if (!grouped[category]) {
803
866
  grouped[category] = [];
867
+ }
804
868
  grouped[category].push(v);
805
869
  });
806
870
  return grouped;
807
871
  }
808
872
  calculateStats(violations) {
809
873
  return {
810
- criticalCount: violations.filter(v => v.severity === 'CRITICAL').length,
811
- majorCount: violations.filter(v => v.severity === 'MAJOR').length,
812
- minorCount: violations.filter(v => v.severity === 'MINOR').length,
813
- suggestionCount: violations.filter(v => v.severity === 'SUGGESTION').length,
874
+ criticalCount: violations.filter((v) => v.severity === "CRITICAL").length,
875
+ majorCount: violations.filter((v) => v.severity === "MAJOR").length,
876
+ minorCount: violations.filter((v) => v.severity === "MINOR").length,
877
+ suggestionCount: violations.filter((v) => v.severity === "SUGGESTION")
878
+ .length,
814
879
  totalIssues: violations.length,
815
- filesReviewed: new Set(violations.filter(v => v.file).map(v => v.file)).size || 1
880
+ filesReviewed: new Set(violations.filter((v) => v.file).map((v) => v.file)).size || 1,
816
881
  };
817
882
  }
818
883
  generateReviewResult(violations, _duration, _context) {
@@ -826,9 +891,9 @@ ${recommendation}
826
891
  criticalCount: stats.criticalCount,
827
892
  majorCount: stats.majorCount,
828
893
  minorCount: stats.minorCount,
829
- suggestionCount: stats.suggestionCount
894
+ suggestionCount: stats.suggestionCount,
830
895
  },
831
- positiveObservations: [] // Could be extracted from AI response
896
+ positiveObservations: [], // Could be extracted from AI response
832
897
  };
833
898
  }
834
899
  /**
@@ -836,7 +901,7 @@ ${recommendation}
836
901
  */
837
902
  parseAIResponse(result) {
838
903
  try {
839
- const responseText = result.content || result.text || result.response || '';
904
+ const responseText = result.content || result.text || result.response || "";
840
905
  if (!responseText) {
841
906
  return { violations: [] };
842
907
  }
@@ -848,7 +913,7 @@ ${recommendation}
848
913
  return { violations: [] };
849
914
  }
850
915
  catch (error) {
851
- Logger_1.logger.debug(`Failed to parse AI response: ${error.message}`);
916
+ logger.debug(`Failed to parse AI response: ${error.message}`);
852
917
  return { violations: [] };
853
918
  }
854
919
  }
@@ -856,20 +921,21 @@ ${recommendation}
856
921
  * Extract line information for comment from context
857
922
  */
858
923
  extractLineInfoForComment(violation, context) {
859
- if (!violation.file || !violation.code_snippet)
924
+ if (!violation.file || !violation.code_snippet) {
860
925
  return null;
926
+ }
861
927
  try {
862
928
  // Get the diff for this specific file
863
929
  let fileDiff;
864
- if (context.diffStrategy.strategy === 'whole' && context.prDiff) {
930
+ if (context.diffStrategy.strategy === "whole" && context.prDiff) {
865
931
  // Extract file diff from whole diff
866
- const diffLines = context.prDiff.diff.split('\n');
932
+ const diffLines = context.prDiff.diff.split("\n");
867
933
  let fileStartIndex = -1;
868
934
  // Create all possible path variations for matching
869
935
  const filePathVariations = this.generatePathVariations(violation.file);
870
936
  for (let i = 0; i < diffLines.length; i++) {
871
937
  const line = diffLines[i];
872
- if (line.startsWith('diff --git')) {
938
+ if (line.startsWith("diff --git")) {
873
939
  // Check if any variation matches
874
940
  for (const pathVariation of filePathVariations) {
875
941
  if (line.includes(pathVariation)) {
@@ -877,22 +943,26 @@ ${recommendation}
877
943
  break;
878
944
  }
879
945
  }
880
- if (fileStartIndex >= 0)
946
+ if (fileStartIndex >= 0) {
881
947
  break;
948
+ }
882
949
  }
883
950
  }
884
951
  if (fileStartIndex >= 0) {
885
- const nextFileIndex = diffLines.findIndex((line, idx) => idx > fileStartIndex && line.startsWith('diff --git'));
886
- fileDiff = diffLines.slice(fileStartIndex, nextFileIndex > 0 ? nextFileIndex : diffLines.length).join('\n');
952
+ const nextFileIndex = diffLines.findIndex((line, idx) => idx > fileStartIndex && line.startsWith("diff --git"));
953
+ fileDiff = diffLines
954
+ .slice(fileStartIndex, nextFileIndex > 0 ? nextFileIndex : diffLines.length)
955
+ .join("\n");
887
956
  }
888
957
  }
889
- else if (context.diffStrategy.strategy === 'file-by-file' && context.fileDiffs) {
958
+ else if (context.diffStrategy.strategy === "file-by-file" &&
959
+ context.fileDiffs) {
890
960
  // Try all possible path variations
891
961
  const pathVariations = this.generatePathVariations(violation.file);
892
962
  for (const path of pathVariations) {
893
963
  fileDiff = context.fileDiffs.get(path);
894
964
  if (fileDiff) {
895
- Logger_1.logger.debug(`Found diff for ${violation.file} using variation: ${path}`);
965
+ logger.debug(`Found diff for ${violation.file} using variation: ${path}`);
896
966
  break;
897
967
  }
898
968
  }
@@ -901,7 +971,7 @@ ${recommendation}
901
971
  for (const [key, value] of context.fileDiffs.entries()) {
902
972
  if (key.endsWith(violation.file) || violation.file.endsWith(key)) {
903
973
  fileDiff = value;
904
- Logger_1.logger.debug(`Found diff for ${violation.file} using partial match: ${key}`);
974
+ logger.debug(`Found diff for ${violation.file} using partial match: ${key}`);
905
975
  break;
906
976
  }
907
977
  }
@@ -910,16 +980,16 @@ ${recommendation}
910
980
  if (fileDiff) {
911
981
  const lineInfo = this.extractLineNumberFromDiff(fileDiff, violation.code_snippet);
912
982
  if (lineInfo) {
913
- Logger_1.logger.debug(`Extracted line info for ${violation.file}: line ${lineInfo.lineNumber}, type ${lineInfo.lineType}`);
983
+ logger.debug(`Extracted line info for ${violation.file}: line ${lineInfo.lineNumber}, type ${lineInfo.lineType}`);
914
984
  }
915
985
  return lineInfo;
916
986
  }
917
987
  else {
918
- Logger_1.logger.debug(`No diff found for file: ${violation.file}`);
988
+ logger.debug(`No diff found for file: ${violation.file}`);
919
989
  }
920
990
  }
921
991
  catch (error) {
922
- Logger_1.logger.debug(`Error extracting line info: ${error.message}`);
992
+ logger.debug(`Error extracting line info: ${error.message}`);
923
993
  }
924
994
  return null;
925
995
  }
@@ -933,29 +1003,29 @@ ${recommendation}
933
1003
  // Add with a/ and b/ prefixes
934
1004
  variations.add(`a/${filePath}`);
935
1005
  variations.add(`b/${filePath}`);
936
- // Handle nested paths
937
- if (filePath.includes('/')) {
938
- const parts = filePath.split('/');
1006
+ // Handle nested paths
1007
+ if (filePath.includes("/")) {
1008
+ const parts = filePath.split("/");
939
1009
  // Try removing first directory
940
1010
  if (parts.length > 1) {
941
- variations.add(parts.slice(1).join('/'));
1011
+ variations.add(parts.slice(1).join("/"));
942
1012
  }
943
1013
  // Try removing first two directories
944
1014
  if (parts.length > 2) {
945
- variations.add(parts.slice(2).join('/'));
1015
+ variations.add(parts.slice(2).join("/"));
946
1016
  }
947
1017
  // Try with just the filename
948
1018
  variations.add(parts[parts.length - 1]);
949
1019
  }
950
1020
  // Remove app/ prefix variations
951
- if (filePath.startsWith('app/')) {
1021
+ if (filePath.startsWith("app/")) {
952
1022
  const withoutApp = filePath.substring(4);
953
1023
  variations.add(withoutApp);
954
1024
  variations.add(`a/${withoutApp}`);
955
1025
  variations.add(`b/${withoutApp}`);
956
1026
  }
957
1027
  // Add app/ prefix variations
958
- if (!filePath.startsWith('app/')) {
1028
+ if (!filePath.startsWith("app/")) {
959
1029
  variations.add(`app/${filePath}`);
960
1030
  variations.add(`a/app/${filePath}`);
961
1031
  variations.add(`b/app/${filePath}`);
@@ -963,8 +1033,7 @@ ${recommendation}
963
1033
  return Array.from(variations);
964
1034
  }
965
1035
  }
966
- exports.CodeReviewer = CodeReviewer;
967
- function createCodeReviewer(bitbucketProvider, aiConfig, reviewConfig) {
1036
+ export function createCodeReviewer(bitbucketProvider, aiConfig, reviewConfig) {
968
1037
  return new CodeReviewer(bitbucketProvider, aiConfig, reviewConfig);
969
1038
  }
970
1039
  //# sourceMappingURL=CodeReviewer.js.map