@juspay/yama 1.5.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp-config.example.json +26 -0
- package/CHANGELOG.md +40 -0
- package/README.md +311 -685
- package/dist/cli/v2.cli.d.ts +13 -0
- package/dist/cli/v2.cli.js +290 -0
- package/dist/index.d.ts +12 -13
- package/dist/index.js +18 -19
- package/dist/v2/config/ConfigLoader.d.ts +50 -0
- package/dist/v2/config/ConfigLoader.js +205 -0
- package/dist/v2/config/DefaultConfig.d.ts +9 -0
- package/dist/v2/config/DefaultConfig.js +191 -0
- package/dist/v2/core/MCPServerManager.d.ts +22 -0
- package/dist/v2/core/MCPServerManager.js +92 -0
- package/dist/v2/core/SessionManager.d.ts +72 -0
- package/dist/v2/core/SessionManager.js +200 -0
- package/dist/v2/core/YamaV2Orchestrator.d.ts +112 -0
- package/dist/v2/core/YamaV2Orchestrator.js +549 -0
- package/dist/v2/prompts/EnhancementSystemPrompt.d.ts +8 -0
- package/dist/v2/prompts/EnhancementSystemPrompt.js +216 -0
- package/dist/v2/prompts/PromptBuilder.d.ts +38 -0
- package/dist/v2/prompts/PromptBuilder.js +228 -0
- package/dist/v2/prompts/ReviewSystemPrompt.d.ts +8 -0
- package/dist/v2/prompts/ReviewSystemPrompt.js +270 -0
- package/dist/v2/types/config.types.d.ts +120 -0
- package/dist/v2/types/config.types.js +5 -0
- package/dist/v2/types/mcp.types.d.ts +191 -0
- package/dist/v2/types/mcp.types.js +6 -0
- package/dist/v2/types/v2.types.d.ts +182 -0
- package/dist/v2/types/v2.types.js +42 -0
- package/dist/v2/utils/ObservabilityConfig.d.ts +22 -0
- package/dist/v2/utils/ObservabilityConfig.js +48 -0
- package/package.json +11 -9
- package/yama.config.example.yaml +214 -193
- package/dist/cli/index.d.ts +0 -12
- package/dist/cli/index.js +0 -538
- package/dist/core/ContextGatherer.d.ts +0 -110
- package/dist/core/ContextGatherer.js +0 -470
- package/dist/core/Guardian.d.ts +0 -81
- package/dist/core/Guardian.js +0 -474
- package/dist/core/providers/BitbucketProvider.d.ts +0 -105
- package/dist/core/providers/BitbucketProvider.js +0 -489
- package/dist/features/CodeReviewer.d.ts +0 -173
- package/dist/features/CodeReviewer.js +0 -1707
- package/dist/features/DescriptionEnhancer.d.ts +0 -64
- package/dist/features/DescriptionEnhancer.js +0 -445
- package/dist/features/MultiInstanceProcessor.d.ts +0 -74
- package/dist/features/MultiInstanceProcessor.js +0 -360
- package/dist/types/index.d.ts +0 -624
- package/dist/types/index.js +0 -104
- package/dist/utils/Cache.d.ts +0 -103
- package/dist/utils/Cache.js +0 -444
- package/dist/utils/ConfigManager.d.ts +0 -88
- package/dist/utils/ConfigManager.js +0 -603
- package/dist/utils/ContentSimilarityService.d.ts +0 -74
- package/dist/utils/ContentSimilarityService.js +0 -215
- package/dist/utils/ExactDuplicateRemover.d.ts +0 -77
- package/dist/utils/ExactDuplicateRemover.js +0 -361
- package/dist/utils/Logger.d.ts +0 -31
- package/dist/utils/Logger.js +0 -214
- package/dist/utils/MemoryBankManager.d.ts +0 -73
- package/dist/utils/MemoryBankManager.js +0 -310
- package/dist/utils/ParallelProcessing.d.ts +0 -140
- package/dist/utils/ParallelProcessing.js +0 -333
- package/dist/utils/ProviderLimits.d.ts +0 -58
- package/dist/utils/ProviderLimits.js +0 -143
- package/dist/utils/RetryManager.d.ts +0 -78
- package/dist/utils/RetryManager.js +0 -205
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Multi-Instance Processor for Parallel Code Review
|
|
3
|
-
* Orchestrates multiple Neurolink SDK instances for diverse code analysis
|
|
4
|
-
*/
|
|
5
|
-
import { createCodeReviewer } from "./CodeReviewer.js";
|
|
6
|
-
import { createExactDuplicateRemover, } from "../utils/ExactDuplicateRemover.js";
|
|
7
|
-
import { Semaphore, TokenBudgetManager, calculateOptimalConcurrency, } from "../utils/ParallelProcessing.js";
|
|
8
|
-
import { getProviderTokenLimit } from "../utils/ProviderLimits.js";
|
|
9
|
-
import { logger } from "../utils/Logger.js";
|
|
10
|
-
/**
|
|
11
|
-
* Multi-Instance Processor
|
|
12
|
-
* Manages parallel execution of multiple CodeReviewer instances
|
|
13
|
-
*/
|
|
14
|
-
export class MultiInstanceProcessor {
|
|
15
|
-
bitbucketProvider;
|
|
16
|
-
baseReviewConfig;
|
|
17
|
-
duplicateRemover;
|
|
18
|
-
constructor(bitbucketProvider, baseReviewConfig) {
|
|
19
|
-
this.bitbucketProvider = bitbucketProvider;
|
|
20
|
-
this.baseReviewConfig = baseReviewConfig;
|
|
21
|
-
this.duplicateRemover = createExactDuplicateRemover();
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Process code review using multiple instances
|
|
25
|
-
*/
|
|
26
|
-
async processWithMultipleInstances(context, options, multiInstanceConfig) {
|
|
27
|
-
const startTime = Date.now();
|
|
28
|
-
try {
|
|
29
|
-
logger.phase("🚀 Starting multi-instance code review processing");
|
|
30
|
-
logger.info(`🔄 Launching ${multiInstanceConfig.instanceCount} instances: ${multiInstanceConfig.instances.map((i) => i.name).join(", ")}`);
|
|
31
|
-
// Step 1: Validate configuration
|
|
32
|
-
this.validateMultiInstanceConfig(multiInstanceConfig);
|
|
33
|
-
// Step 2: Execute instances in parallel
|
|
34
|
-
const instanceResults = await this.executeInstancesInParallel(context, options, multiInstanceConfig);
|
|
35
|
-
// Step 3: Deduplicate results
|
|
36
|
-
const deduplicationResult = multiInstanceConfig.deduplication.enabled
|
|
37
|
-
? this.duplicateRemover.removeDuplicates(instanceResults)
|
|
38
|
-
: this.createNonDeduplicatedResult(instanceResults);
|
|
39
|
-
// Step 4: Apply final filtering if configured
|
|
40
|
-
const finalViolations = this.applyFinalFiltering(deduplicationResult.uniqueViolations, multiInstanceConfig.deduplication);
|
|
41
|
-
// Step 5: Create summary
|
|
42
|
-
const totalProcessingTime = Date.now() - startTime;
|
|
43
|
-
const summary = this.createSummary(instanceResults, deduplicationResult, finalViolations, totalProcessingTime);
|
|
44
|
-
logger.success(`✅ Multi-instance processing completed: ${summary.totalViolationsFound} → ${summary.uniqueViolationsAfterDedup} violations ` +
|
|
45
|
-
`(${summary.deduplicationRate.toFixed(1)}% reduction) in ${Math.round(totalProcessingTime / 1000)}s`);
|
|
46
|
-
// Step 6: Log detailed statistics
|
|
47
|
-
if (logger.getConfig().verbose) {
|
|
48
|
-
logger.info(this.duplicateRemover.getDeduplicationStats(deduplicationResult));
|
|
49
|
-
}
|
|
50
|
-
return {
|
|
51
|
-
instances: instanceResults,
|
|
52
|
-
deduplication: deduplicationResult,
|
|
53
|
-
finalViolations,
|
|
54
|
-
summary,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
logger.error(`Multi-instance processing failed: ${error.message}`);
|
|
59
|
-
throw error;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Execute all instances in parallel with concurrency control
|
|
64
|
-
*/
|
|
65
|
-
async executeInstancesInParallel(context, options, multiInstanceConfig) {
|
|
66
|
-
const instances = multiInstanceConfig.instances;
|
|
67
|
-
// Calculate optimal concurrency
|
|
68
|
-
const avgTokensPerInstance = this.estimateTokensPerInstance(context);
|
|
69
|
-
const totalTokenBudget = this.calculateTotalTokenBudget(instances);
|
|
70
|
-
const optimalConcurrency = calculateOptimalConcurrency(instances.length, Math.min(instances.length, 3), // Max 3 concurrent instances by default
|
|
71
|
-
avgTokensPerInstance, totalTokenBudget);
|
|
72
|
-
// Initialize concurrency control
|
|
73
|
-
const semaphore = new Semaphore(optimalConcurrency);
|
|
74
|
-
const tokenBudget = new TokenBudgetManager(totalTokenBudget);
|
|
75
|
-
logger.info(`🎯 Parallel execution: ${optimalConcurrency} concurrent instances, ${totalTokenBudget} total token budget`);
|
|
76
|
-
// Execute instances with controlled concurrency
|
|
77
|
-
const instancePromises = instances.map((instanceConfig, index) => this.executeInstanceWithConcurrency(instanceConfig, context, options, semaphore, tokenBudget, index, instances.length));
|
|
78
|
-
// Wait for all instances to complete
|
|
79
|
-
const results = await Promise.allSettled(instancePromises);
|
|
80
|
-
// Process results and handle failures
|
|
81
|
-
const instanceResults = [];
|
|
82
|
-
for (let i = 0; i < results.length; i++) {
|
|
83
|
-
const result = results[i];
|
|
84
|
-
const instanceConfig = instances[i];
|
|
85
|
-
if (result.status === "fulfilled") {
|
|
86
|
-
instanceResults.push(result.value);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
logger.error(`❌ Instance ${instanceConfig.name} failed: ${result.reason.message}`);
|
|
90
|
-
instanceResults.push({
|
|
91
|
-
instanceName: instanceConfig.name,
|
|
92
|
-
violations: [],
|
|
93
|
-
processingTime: 0,
|
|
94
|
-
error: result.reason.message,
|
|
95
|
-
success: false,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return instanceResults;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Execute a single instance with concurrency control
|
|
103
|
-
*/
|
|
104
|
-
async executeInstanceWithConcurrency(instanceConfig, context, options, semaphore, tokenBudget, instanceIndex, totalInstances) {
|
|
105
|
-
// Acquire semaphore permit
|
|
106
|
-
await semaphore.acquire();
|
|
107
|
-
try {
|
|
108
|
-
const estimatedTokens = this.estimateTokensPerInstance(context);
|
|
109
|
-
// Check token budget
|
|
110
|
-
if (!tokenBudget.allocateForBatch(instanceIndex, estimatedTokens)) {
|
|
111
|
-
throw new Error(`Insufficient token budget for instance ${instanceConfig.name}`);
|
|
112
|
-
}
|
|
113
|
-
logger.info(`🔄 Processing instance ${instanceIndex + 1}/${totalInstances}: ${instanceConfig.name} ` +
|
|
114
|
-
`(${instanceConfig.provider}, temp: ${instanceConfig.temperature || "default"})`);
|
|
115
|
-
// Execute the instance
|
|
116
|
-
const result = await this.executeInstance(instanceConfig, context, options);
|
|
117
|
-
logger.info(`✅ Instance ${instanceConfig.name} completed: ${result.violations.length} violations ` +
|
|
118
|
-
`in ${Math.round(result.processingTime / 1000)}s`);
|
|
119
|
-
return result;
|
|
120
|
-
}
|
|
121
|
-
finally {
|
|
122
|
-
// Always release resources
|
|
123
|
-
tokenBudget.releaseBatch(instanceIndex);
|
|
124
|
-
semaphore.release();
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Validate provider string against allowed provider types
|
|
129
|
-
*/
|
|
130
|
-
validateProvider(provider) {
|
|
131
|
-
const validProviders = [
|
|
132
|
-
"auto",
|
|
133
|
-
"google-ai",
|
|
134
|
-
"openai",
|
|
135
|
-
"anthropic",
|
|
136
|
-
"azure",
|
|
137
|
-
"bedrock",
|
|
138
|
-
"vertex",
|
|
139
|
-
];
|
|
140
|
-
if (!validProviders.includes(provider)) {
|
|
141
|
-
logger.warn(`Unknown provider '${provider}', falling back to 'auto'`);
|
|
142
|
-
return "auto";
|
|
143
|
-
}
|
|
144
|
-
return provider;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Execute a single instance
|
|
148
|
-
*/
|
|
149
|
-
async executeInstance(instanceConfig, context, options) {
|
|
150
|
-
const startTime = Date.now();
|
|
151
|
-
try {
|
|
152
|
-
// Create instance-specific AI config
|
|
153
|
-
const aiConfig = {
|
|
154
|
-
provider: this.validateProvider(instanceConfig.provider),
|
|
155
|
-
model: instanceConfig.model,
|
|
156
|
-
temperature: instanceConfig.temperature,
|
|
157
|
-
maxTokens: instanceConfig.maxTokens,
|
|
158
|
-
timeout: instanceConfig.timeout,
|
|
159
|
-
enableAnalytics: true,
|
|
160
|
-
enableEvaluation: false,
|
|
161
|
-
};
|
|
162
|
-
// Create CodeReviewer for this instance
|
|
163
|
-
const codeReviewer = createCodeReviewer(this.bitbucketProvider, aiConfig, this.baseReviewConfig);
|
|
164
|
-
// Execute review with dry run to get violations without posting
|
|
165
|
-
const instanceOptions = { ...options, dryRun: true };
|
|
166
|
-
const reviewResult = await codeReviewer.reviewCodeWithContext(context, instanceOptions);
|
|
167
|
-
const processingTime = Date.now() - startTime;
|
|
168
|
-
return {
|
|
169
|
-
instanceName: instanceConfig.name,
|
|
170
|
-
violations: reviewResult.violations,
|
|
171
|
-
processingTime,
|
|
172
|
-
tokenUsage: this.extractTokenUsage(reviewResult),
|
|
173
|
-
success: true,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
catch (error) {
|
|
177
|
-
const processingTime = Date.now() - startTime;
|
|
178
|
-
return {
|
|
179
|
-
instanceName: instanceConfig.name,
|
|
180
|
-
violations: [],
|
|
181
|
-
processingTime,
|
|
182
|
-
error: error.message,
|
|
183
|
-
success: false,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Validate multi-instance configuration
|
|
189
|
-
*/
|
|
190
|
-
validateMultiInstanceConfig(config) {
|
|
191
|
-
if (!config.enabled) {
|
|
192
|
-
throw new Error("Multi-instance processing is not enabled");
|
|
193
|
-
}
|
|
194
|
-
if (config.instances.length === 0) {
|
|
195
|
-
throw new Error("No instances configured for multi-instance processing");
|
|
196
|
-
}
|
|
197
|
-
if (config.instances.length !== config.instanceCount) {
|
|
198
|
-
logger.warn(`Instance count mismatch: configured ${config.instanceCount}, found ${config.instances.length} instances`);
|
|
199
|
-
}
|
|
200
|
-
// Validate each instance
|
|
201
|
-
for (const instance of config.instances) {
|
|
202
|
-
if (!instance.name || !instance.provider) {
|
|
203
|
-
throw new Error(`Invalid instance configuration: name and provider are required`);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
// Validate deduplication config
|
|
207
|
-
if (config.deduplication.enabled) {
|
|
208
|
-
if (config.deduplication.similarityThreshold < 0 ||
|
|
209
|
-
config.deduplication.similarityThreshold > 100) {
|
|
210
|
-
throw new Error("Similarity threshold must be between 0 and 100");
|
|
211
|
-
}
|
|
212
|
-
if (config.deduplication.maxCommentsToPost <= 0) {
|
|
213
|
-
throw new Error("Max comments to post must be greater than 0");
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Estimate tokens per instance based on context
|
|
219
|
-
*/
|
|
220
|
-
estimateTokensPerInstance(context) {
|
|
221
|
-
// Base estimation: context size + overhead
|
|
222
|
-
const contextSize = JSON.stringify(context).length;
|
|
223
|
-
const estimatedTokens = Math.ceil(contextSize / 4); // ~4 chars per token
|
|
224
|
-
// Add overhead for prompts and response
|
|
225
|
-
const overhead = 5000;
|
|
226
|
-
return estimatedTokens + overhead;
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Calculate total token budget for all instances
|
|
230
|
-
*/
|
|
231
|
-
calculateTotalTokenBudget(instances) {
|
|
232
|
-
// Use the most restrictive provider limit among all instances
|
|
233
|
-
let minLimit = Infinity;
|
|
234
|
-
for (const instance of instances) {
|
|
235
|
-
const providerLimit = getProviderTokenLimit(instance.provider, true);
|
|
236
|
-
const instanceLimit = instance.maxTokens || providerLimit;
|
|
237
|
-
minLimit = Math.min(minLimit, instanceLimit);
|
|
238
|
-
}
|
|
239
|
-
// Total budget is the sum of all instance limits, but with safety margin
|
|
240
|
-
// Use Math.floor to ensure integer result and avoid floating-point precision issues
|
|
241
|
-
const totalBudget = Math.floor(instances.length * minLimit * 0.8); // 80% safety margin
|
|
242
|
-
logger.debug(`Calculated total token budget: ${totalBudget} (${instances.length} instances × ${minLimit} × 0.8, floored)`);
|
|
243
|
-
return totalBudget;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Extract token usage from review result (if available)
|
|
247
|
-
*/
|
|
248
|
-
extractTokenUsage(reviewResult) {
|
|
249
|
-
// This would need to be implemented based on how NeuroLink returns usage data
|
|
250
|
-
// For now, return undefined as we don't have access to this data
|
|
251
|
-
return undefined;
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Create non-deduplicated result (when deduplication is disabled)
|
|
255
|
-
*/
|
|
256
|
-
createNonDeduplicatedResult(instanceResults) {
|
|
257
|
-
const allViolations = [];
|
|
258
|
-
const instanceContributions = new Map();
|
|
259
|
-
for (const result of instanceResults) {
|
|
260
|
-
if (result.success && result.violations) {
|
|
261
|
-
allViolations.push(...result.violations);
|
|
262
|
-
instanceContributions.set(result.instanceName, result.violations.length);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return {
|
|
266
|
-
uniqueViolations: allViolations,
|
|
267
|
-
duplicatesRemoved: {
|
|
268
|
-
exactDuplicates: 0,
|
|
269
|
-
normalizedDuplicates: 0,
|
|
270
|
-
sameLineDuplicates: 0,
|
|
271
|
-
},
|
|
272
|
-
instanceContributions,
|
|
273
|
-
processingMetrics: {
|
|
274
|
-
totalViolationsInput: allViolations.length,
|
|
275
|
-
exactDuplicatesRemoved: 0,
|
|
276
|
-
normalizedDuplicatesRemoved: 0,
|
|
277
|
-
sameLineDuplicatesRemoved: 0,
|
|
278
|
-
finalUniqueViolations: allViolations.length,
|
|
279
|
-
deduplicationRate: 0,
|
|
280
|
-
instanceContributions: Object.fromEntries(instanceContributions),
|
|
281
|
-
processingTimeMs: 0,
|
|
282
|
-
},
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Apply final filtering based on configuration
|
|
287
|
-
*/
|
|
288
|
-
applyFinalFiltering(violations, deduplicationConfig) {
|
|
289
|
-
if (!deduplicationConfig.maxCommentsToPost ||
|
|
290
|
-
violations.length <= deduplicationConfig.maxCommentsToPost) {
|
|
291
|
-
return violations;
|
|
292
|
-
}
|
|
293
|
-
logger.info(`📊 Applying final filtering: ${violations.length} → ${deduplicationConfig.maxCommentsToPost} violations`);
|
|
294
|
-
// Sort by priority based on configuration
|
|
295
|
-
const prioritized = this.prioritizeViolations(violations, deduplicationConfig.prioritizeBy);
|
|
296
|
-
// Take only the top N violations
|
|
297
|
-
const filtered = prioritized.slice(0, deduplicationConfig.maxCommentsToPost);
|
|
298
|
-
logger.info(`🎯 Final filtering applied: kept top ${filtered.length} violations prioritized by ${deduplicationConfig.prioritizeBy}`);
|
|
299
|
-
return filtered;
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Prioritize violations based on strategy
|
|
303
|
-
*/
|
|
304
|
-
prioritizeViolations(violations, strategy) {
|
|
305
|
-
const severityOrder = {
|
|
306
|
-
CRITICAL: 4,
|
|
307
|
-
MAJOR: 3,
|
|
308
|
-
MINOR: 2,
|
|
309
|
-
SUGGESTION: 1,
|
|
310
|
-
};
|
|
311
|
-
switch (strategy) {
|
|
312
|
-
case "severity":
|
|
313
|
-
return violations.sort((a, b) => {
|
|
314
|
-
const aScore = severityOrder[a.severity] || 0;
|
|
315
|
-
const bScore = severityOrder[b.severity] || 0;
|
|
316
|
-
return bScore - aScore; // Higher severity first
|
|
317
|
-
});
|
|
318
|
-
case "similarity":
|
|
319
|
-
case "confidence":
|
|
320
|
-
// For now, fall back to severity-based sorting
|
|
321
|
-
// These could be implemented with more sophisticated algorithms
|
|
322
|
-
logger.debug(`Prioritization strategy '${strategy}' not fully implemented, using severity`);
|
|
323
|
-
return this.prioritizeViolations(violations, "severity");
|
|
324
|
-
default:
|
|
325
|
-
logger.warn(`Unknown prioritization strategy: ${strategy}, using severity`);
|
|
326
|
-
return this.prioritizeViolations(violations, "severity");
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Create summary of multi-instance processing
|
|
331
|
-
*/
|
|
332
|
-
createSummary(instanceResults, deduplicationResult, finalViolations, totalProcessingTime) {
|
|
333
|
-
const successfulInstances = instanceResults.filter((r) => r.success).length;
|
|
334
|
-
const failedInstances = instanceResults.length - successfulInstances;
|
|
335
|
-
const totalViolationsFound = instanceResults
|
|
336
|
-
.filter((r) => r.success)
|
|
337
|
-
.reduce((sum, r) => sum + r.violations.length, 0);
|
|
338
|
-
const deduplicationRate = totalViolationsFound > 0
|
|
339
|
-
? ((totalViolationsFound - finalViolations.length) /
|
|
340
|
-
totalViolationsFound) *
|
|
341
|
-
100
|
|
342
|
-
: 0;
|
|
343
|
-
return {
|
|
344
|
-
totalInstances: instanceResults.length,
|
|
345
|
-
successfulInstances,
|
|
346
|
-
failedInstances,
|
|
347
|
-
totalViolationsFound,
|
|
348
|
-
uniqueViolationsAfterDedup: finalViolations.length,
|
|
349
|
-
deduplicationRate,
|
|
350
|
-
totalProcessingTime,
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Factory function to create MultiInstanceProcessor
|
|
356
|
-
*/
|
|
357
|
-
export function createMultiInstanceProcessor(bitbucketProvider, baseReviewConfig) {
|
|
358
|
-
return new MultiInstanceProcessor(bitbucketProvider, baseReviewConfig);
|
|
359
|
-
}
|
|
360
|
-
//# sourceMappingURL=MultiInstanceProcessor.js.map
|