codereview-aia 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cr-aia.yml +23 -0
- package/.crignore +0 -0
- package/dist/index.js +27 -0
- package/package.json +85 -0
- package/src/analysis/FindingsExtractor.ts +431 -0
- package/src/analysis/ai-detection/analyzers/BaseAnalyzer.ts +267 -0
- package/src/analysis/ai-detection/analyzers/DocumentationAnalyzer.ts +622 -0
- package/src/analysis/ai-detection/analyzers/GitHistoryAnalyzer.ts +430 -0
- package/src/analysis/ai-detection/core/AIDetectionEngine.ts +467 -0
- package/src/analysis/ai-detection/types/DetectionTypes.ts +406 -0
- package/src/analysis/ai-detection/utils/SubmissionConverter.ts +390 -0
- package/src/analysis/context/ReviewContext.ts +378 -0
- package/src/analysis/context/index.ts +7 -0
- package/src/analysis/index.ts +8 -0
- package/src/analysis/tokens/TokenAnalysisFormatter.ts +154 -0
- package/src/analysis/tokens/TokenAnalyzer.ts +747 -0
- package/src/analysis/tokens/index.ts +8 -0
- package/src/clients/base/abstractClient.ts +190 -0
- package/src/clients/base/httpClient.ts +160 -0
- package/src/clients/base/index.ts +12 -0
- package/src/clients/base/modelDetection.ts +107 -0
- package/src/clients/base/responseProcessor.ts +586 -0
- package/src/clients/factory/clientFactory.ts +55 -0
- package/src/clients/factory/index.ts +8 -0
- package/src/clients/implementations/index.ts +8 -0
- package/src/clients/implementations/openRouterClient.ts +411 -0
- package/src/clients/openRouterClient.ts +863 -0
- package/src/clients/openRouterClientWrapper.ts +44 -0
- package/src/clients/utils/directoryStructure.ts +52 -0
- package/src/clients/utils/index.ts +11 -0
- package/src/clients/utils/languageDetection.ts +44 -0
- package/src/clients/utils/promptFormatter.ts +105 -0
- package/src/clients/utils/promptLoader.ts +53 -0
- package/src/clients/utils/tokenCounter.ts +297 -0
- package/src/core/ApiClientSelector.ts +37 -0
- package/src/core/ConfigurationService.ts +591 -0
- package/src/core/ConsolidationService.ts +423 -0
- package/src/core/InteractiveDisplayManager.ts +81 -0
- package/src/core/OutputManager.ts +275 -0
- package/src/core/ReviewGenerator.ts +140 -0
- package/src/core/fileDiscovery.ts +237 -0
- package/src/core/handlers/EstimationHandler.ts +104 -0
- package/src/core/handlers/FileProcessingHandler.ts +204 -0
- package/src/core/handlers/OutputHandler.ts +125 -0
- package/src/core/handlers/ReviewExecutor.ts +104 -0
- package/src/core/reviewOrchestrator.ts +333 -0
- package/src/core/utils/ModelInfoUtils.ts +56 -0
- package/src/formatters/outputFormatter.ts +62 -0
- package/src/formatters/utils/IssueFormatters.ts +83 -0
- package/src/formatters/utils/JsonFormatter.ts +77 -0
- package/src/formatters/utils/MarkdownFormatters.ts +609 -0
- package/src/formatters/utils/MetadataFormatter.ts +269 -0
- package/src/formatters/utils/ModelInfoExtractor.ts +115 -0
- package/src/index.ts +27 -0
- package/src/plugins/PluginInterface.ts +50 -0
- package/src/plugins/PluginManager.ts +126 -0
- package/src/prompts/PromptManager.ts +69 -0
- package/src/prompts/cache/PromptCache.ts +50 -0
- package/src/prompts/promptText/common/variables/css-frameworks.json +33 -0
- package/src/prompts/promptText/common/variables/framework-versions.json +45 -0
- package/src/prompts/promptText/frameworks/react/comprehensive.hbs +19 -0
- package/src/prompts/promptText/languages/css/comprehensive.hbs +18 -0
- package/src/prompts/promptText/languages/generic/comprehensive.hbs +20 -0
- package/src/prompts/promptText/languages/html/comprehensive.hbs +18 -0
- package/src/prompts/promptText/languages/javascript/comprehensive.hbs +18 -0
- package/src/prompts/promptText/languages/python/comprehensive.hbs +18 -0
- package/src/prompts/promptText/languages/typescript/comprehensive.hbs +18 -0
- package/src/runtime/auth/service.ts +58 -0
- package/src/runtime/auth/session.ts +103 -0
- package/src/runtime/auth/types.ts +11 -0
- package/src/runtime/cliEntry.ts +196 -0
- package/src/runtime/errors.ts +13 -0
- package/src/runtime/fileCollector.ts +188 -0
- package/src/runtime/manifest.ts +64 -0
- package/src/runtime/openrouterProxy.ts +45 -0
- package/src/runtime/proxyConfig.ts +94 -0
- package/src/runtime/proxyEnvironment.ts +71 -0
- package/src/runtime/reportMerge.ts +102 -0
- package/src/runtime/reporting/markdownReportBuilder.ts +138 -0
- package/src/runtime/reporting/reportDataCollector.ts +234 -0
- package/src/runtime/reporting/summaryGenerator.ts +86 -0
- package/src/runtime/reviewPipeline.ts +155 -0
- package/src/runtime/runAiCodeReview.ts +153 -0
- package/src/runtime/runtimeConfig.ts +5 -0
- package/src/runtime/ui/Layout.tsx +57 -0
- package/src/runtime/ui/RuntimeApp.tsx +150 -0
- package/src/runtime/ui/inkModules.ts +73 -0
- package/src/runtime/ui/screens/AuthScreen.tsx +128 -0
- package/src/runtime/ui/screens/ModeSelection.tsx +52 -0
- package/src/runtime/ui/screens/ProgressScreen.tsx +55 -0
- package/src/runtime/ui/screens/ResultsScreen.tsx +76 -0
- package/src/strategies/ArchitecturalReviewStrategy.ts +54 -0
- package/src/strategies/CodingTestReviewStrategy.ts +920 -0
- package/src/strategies/ConsolidatedReviewStrategy.ts +59 -0
- package/src/strategies/ExtractPatternsReviewStrategy.ts +64 -0
- package/src/strategies/MultiPassReviewStrategy.ts +785 -0
- package/src/strategies/ReviewStrategy.ts +64 -0
- package/src/strategies/StrategyFactory.ts +79 -0
- package/src/strategies/index.ts +14 -0
- package/src/tokenizers/baseTokenizer.ts +61 -0
- package/src/tokenizers/gptTokenizer.ts +27 -0
- package/src/tokenizers/index.ts +8 -0
- package/src/types/apiResponses.ts +40 -0
- package/src/types/cli.ts +24 -0
- package/src/types/common.ts +39 -0
- package/src/types/configuration.ts +201 -0
- package/src/types/handlebars.d.ts +5 -0
- package/src/types/patch.d.ts +25 -0
- package/src/types/review.ts +294 -0
- package/src/types/reviewContext.d.ts +65 -0
- package/src/types/reviewSchema.ts +181 -0
- package/src/types/structuredReview.ts +167 -0
- package/src/types/tokenAnalysis.ts +56 -0
- package/src/utils/FileReader.ts +93 -0
- package/src/utils/FileWriter.ts +76 -0
- package/src/utils/PathGenerator.ts +97 -0
- package/src/utils/api/apiUtils.ts +14 -0
- package/src/utils/api/index.ts +1 -0
- package/src/utils/apiErrorHandler.ts +287 -0
- package/src/utils/ciDataCollector.ts +252 -0
- package/src/utils/codingTestConfigLoader.ts +466 -0
- package/src/utils/dependencies/aiDependencyAnalyzer.ts +454 -0
- package/src/utils/detection/frameworkDetector.ts +879 -0
- package/src/utils/detection/index.ts +10 -0
- package/src/utils/detection/projectTypeDetector.ts +518 -0
- package/src/utils/diagramGenerator.ts +206 -0
- package/src/utils/errorLogger.ts +60 -0
- package/src/utils/estimationUtils.ts +407 -0
- package/src/utils/fileFilters.ts +373 -0
- package/src/utils/fileSystem.ts +57 -0
- package/src/utils/index.ts +36 -0
- package/src/utils/logger.ts +240 -0
- package/src/utils/pathValidator.ts +98 -0
- package/src/utils/priorityFilter.ts +59 -0
- package/src/utils/projectDocs.ts +189 -0
- package/src/utils/promptPaths.ts +29 -0
- package/src/utils/promptTemplateManager.ts +157 -0
- package/src/utils/review/consolidateReview.ts +553 -0
- package/src/utils/review/fixDisplay.ts +100 -0
- package/src/utils/review/fixImplementation.ts +61 -0
- package/src/utils/review/index.ts +36 -0
- package/src/utils/review/interactiveProcessing.ts +294 -0
- package/src/utils/review/progressTracker.ts +296 -0
- package/src/utils/review/reviewExtraction.ts +382 -0
- package/src/utils/review/types.ts +46 -0
- package/src/utils/reviewActionHandler.ts +18 -0
- package/src/utils/reviewParser.ts +253 -0
- package/src/utils/sanitizer.ts +238 -0
- package/src/utils/smartFileSelector.ts +255 -0
- package/src/utils/templateLoader.ts +514 -0
- package/src/utils/treeGenerator.ts +153 -0
- package/tsconfig.build.json +14 -0
- package/tsconfig.json +59 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Main AI detection engine that orchestrates analysis across multiple analyzers.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the central detection engine that coordinates various analyzers
|
|
5
|
+
* to determine if code was generated by AI, aggregating results and calculating confidence scores.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { BaseAnalyzer } from '../analyzers/BaseAnalyzer';
|
|
9
|
+
import { DocumentationAnalyzer } from '../analyzers/DocumentationAnalyzer';
|
|
10
|
+
import { GitHistoryAnalyzer } from '../analyzers/GitHistoryAnalyzer';
|
|
11
|
+
import type {
|
|
12
|
+
AnalysisBreakdown,
|
|
13
|
+
CodeSubmission,
|
|
14
|
+
DetectedPattern,
|
|
15
|
+
DetectionConfig,
|
|
16
|
+
DetectionMetadata,
|
|
17
|
+
DetectionResult,
|
|
18
|
+
} from '../types/DetectionTypes';
|
|
19
|
+
import { DEFAULT_DETECTION_CONFIG } from '../types/DetectionTypes';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Core AI detection engine interface
|
|
23
|
+
*/
|
|
24
|
+
export interface IAIDetectionEngine {
|
|
25
|
+
analyze(submission: CodeSubmission): Promise<DetectionResult>;
|
|
26
|
+
getConfig(): DetectionConfig;
|
|
27
|
+
setConfig(config: Partial<DetectionConfig>): void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Main AI detection engine that orchestrates analysis
|
|
32
|
+
*/
|
|
33
|
+
export class AIDetectionEngine implements IAIDetectionEngine {
|
|
34
|
+
private config: DetectionConfig;
|
|
35
|
+
private analyzers: Map<string, BaseAnalyzer>;
|
|
36
|
+
private cache: Map<string, DetectionResult>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a new AI detection engine
|
|
40
|
+
* @param config Detection configuration
|
|
41
|
+
*/
|
|
42
|
+
constructor(config: Partial<DetectionConfig> = {}) {
|
|
43
|
+
this.config = { ...DEFAULT_DETECTION_CONFIG, ...config };
|
|
44
|
+
this.analyzers = new Map();
|
|
45
|
+
this.cache = new Map();
|
|
46
|
+
this.initializeAnalyzers();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Analyze code submission for AI-generated patterns
|
|
51
|
+
* @param submission Code submission to analyze
|
|
52
|
+
* @returns Detection result with confidence score and patterns
|
|
53
|
+
*/
|
|
54
|
+
async analyze(submission: CodeSubmission): Promise<DetectionResult> {
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// Check cache if enabled
|
|
59
|
+
if (this.config.enableCaching) {
|
|
60
|
+
const cacheKey = this.generateCacheKey(submission);
|
|
61
|
+
const cached = this.cache.get(cacheKey);
|
|
62
|
+
if (cached) {
|
|
63
|
+
return {
|
|
64
|
+
...cached,
|
|
65
|
+
metadata: {
|
|
66
|
+
...cached.metadata,
|
|
67
|
+
cacheInfo: { hit: true, key: cacheKey },
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Run enabled analyzers in parallel
|
|
74
|
+
const analysisPromises = this.getEnabledAnalyzers().map((analyzer) =>
|
|
75
|
+
this.runAnalyzerWithTimeout(analyzer, submission),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const analysisResults = await Promise.allSettled(analysisPromises);
|
|
79
|
+
|
|
80
|
+
// Process successful results
|
|
81
|
+
const successfulResults = analysisResults
|
|
82
|
+
.filter((result): result is PromiseFulfilledResult<any> => result.status === 'fulfilled')
|
|
83
|
+
.map((result) => result.value);
|
|
84
|
+
|
|
85
|
+
// Collect warnings from failed analyses
|
|
86
|
+
const warnings = analysisResults
|
|
87
|
+
.filter((result): result is PromiseRejectedResult => result.status === 'rejected')
|
|
88
|
+
.map((result) => `Analyzer failed: ${result.reason.message}`);
|
|
89
|
+
|
|
90
|
+
// Extract all detected patterns
|
|
91
|
+
const allPatterns = successfulResults.flatMap((result) => result.patterns || []);
|
|
92
|
+
|
|
93
|
+
// Calculate overall confidence score
|
|
94
|
+
const confidenceScore = this.calculateConfidenceScore(allPatterns);
|
|
95
|
+
|
|
96
|
+
// Determine if AI-generated based on threshold
|
|
97
|
+
const isAIGenerated = confidenceScore >= this.config.detectionThreshold;
|
|
98
|
+
|
|
99
|
+
// Create analysis breakdown
|
|
100
|
+
const analysisBreakdown = this.createAnalysisBreakdown(successfulResults);
|
|
101
|
+
|
|
102
|
+
// Generate recommendations
|
|
103
|
+
const recommendations = this.generateRecommendations(allPatterns, isAIGenerated);
|
|
104
|
+
|
|
105
|
+
// Create metadata
|
|
106
|
+
const metadata = this.createMetadata(startTime, warnings);
|
|
107
|
+
|
|
108
|
+
const result: DetectionResult = {
|
|
109
|
+
isAIGenerated,
|
|
110
|
+
confidenceScore,
|
|
111
|
+
detectedPatterns: allPatterns,
|
|
112
|
+
analysisBreakdown,
|
|
113
|
+
recommendations,
|
|
114
|
+
metadata,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Cache result if enabled
|
|
118
|
+
if (this.config.enableCaching) {
|
|
119
|
+
const cacheKey = this.generateCacheKey(submission);
|
|
120
|
+
this.cache.set(cacheKey, result);
|
|
121
|
+
|
|
122
|
+
// Limit cache size (simple LRU-like behavior)
|
|
123
|
+
if (this.cache.size > 100) {
|
|
124
|
+
const firstKey = this.cache.keys().next().value;
|
|
125
|
+
if (firstKey) {
|
|
126
|
+
this.cache.delete(firstKey);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return result;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
134
|
+
console.error('â Error in AI detection analysis:', errorMessage);
|
|
135
|
+
|
|
136
|
+
// Log additional context for debugging
|
|
137
|
+
if (error instanceof Error && error.stack) {
|
|
138
|
+
console.debug('AI Detection Error Stack:', error.stack);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return this.createErrorResult(startTime, error as Error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get current configuration
|
|
147
|
+
* @returns Current detection configuration
|
|
148
|
+
*/
|
|
149
|
+
getConfig(): DetectionConfig {
|
|
150
|
+
return { ...this.config };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Update configuration
|
|
155
|
+
* @param config Partial configuration to merge
|
|
156
|
+
*/
|
|
157
|
+
setConfig(config: Partial<DetectionConfig>): void {
|
|
158
|
+
try {
|
|
159
|
+
// Validate configuration before applying
|
|
160
|
+
this.validateConfig(config);
|
|
161
|
+
this.config = { ...this.config, ...config };
|
|
162
|
+
this.initializeAnalyzers(); // Reinitialize with new config
|
|
163
|
+
} catch (error) {
|
|
164
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown configuration error';
|
|
165
|
+
console.error('â Failed to update AI detection configuration:', errorMessage);
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Validate detection configuration
|
|
172
|
+
* @param config Configuration to validate
|
|
173
|
+
*/
|
|
174
|
+
private validateConfig(config: Partial<DetectionConfig>): void {
|
|
175
|
+
if (config.detectionThreshold !== undefined) {
|
|
176
|
+
if (
|
|
177
|
+
typeof config.detectionThreshold !== 'number' ||
|
|
178
|
+
config.detectionThreshold < 0 ||
|
|
179
|
+
config.detectionThreshold > 1
|
|
180
|
+
) {
|
|
181
|
+
throw new Error('Detection threshold must be a number between 0.0 and 1.0');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (config.maxAnalysisTime !== undefined) {
|
|
186
|
+
if (typeof config.maxAnalysisTime !== 'number' || config.maxAnalysisTime <= 0) {
|
|
187
|
+
throw new Error('Max analysis time must be a positive number');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (config.enabledAnalyzers !== undefined) {
|
|
192
|
+
if (!Array.isArray(config.enabledAnalyzers)) {
|
|
193
|
+
throw new Error('Enabled analyzers must be an array');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const validAnalyzers = ['git', 'documentation', 'structural', 'statistical', 'linguistic'];
|
|
197
|
+
const invalidAnalyzers = config.enabledAnalyzers.filter(
|
|
198
|
+
(analyzer) => !validAnalyzers.includes(analyzer),
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
if (invalidAnalyzers.length > 0) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`Invalid analyzers: ${invalidAnalyzers.join(', ')}. Valid options: ${validAnalyzers.join(', ')}`,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Initialize all available analyzers
|
|
211
|
+
*/
|
|
212
|
+
private initializeAnalyzers(): void {
|
|
213
|
+
this.analyzers.clear();
|
|
214
|
+
this.analyzers.set('git', new GitHistoryAnalyzer(this.config));
|
|
215
|
+
this.analyzers.set('documentation', new DocumentationAnalyzer(this.config));
|
|
216
|
+
|
|
217
|
+
// Additional analyzers would be added here as implemented
|
|
218
|
+
// this.analyzers.set('structural', new StructuralAnalyzer(this.config));
|
|
219
|
+
// this.analyzers.set('statistical', new StatisticalAnalyzer(this.config));
|
|
220
|
+
// this.analyzers.set('linguistic', new LinguisticAnalyzer(this.config));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get enabled analyzers based on configuration
|
|
225
|
+
* @returns Array of enabled analyzers
|
|
226
|
+
*/
|
|
227
|
+
private getEnabledAnalyzers(): BaseAnalyzer[] {
|
|
228
|
+
return Array.from(this.analyzers.values()).filter((analyzer) => analyzer.isEnabled());
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Run analyzer with timeout protection
|
|
233
|
+
* @param analyzer Analyzer to run
|
|
234
|
+
* @param submission Code submission
|
|
235
|
+
* @returns Analysis result or timeout error
|
|
236
|
+
*/
|
|
237
|
+
private async runAnalyzerWithTimeout(
|
|
238
|
+
analyzer: BaseAnalyzer,
|
|
239
|
+
submission: CodeSubmission,
|
|
240
|
+
): Promise<any> {
|
|
241
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
242
|
+
setTimeout(
|
|
243
|
+
() => reject(new Error(`${analyzer.getAnalyzerName()} analyzer timed out`)),
|
|
244
|
+
this.config.maxAnalysisTime,
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
return Promise.race([analyzer.analyze(submission), timeoutPromise]);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Calculate overall confidence score from detected patterns
|
|
253
|
+
* @param patterns Array of detected patterns
|
|
254
|
+
* @returns Confidence score between 0.0 and 1.0
|
|
255
|
+
*/
|
|
256
|
+
private calculateConfidenceScore(patterns: DetectedPattern[]): number {
|
|
257
|
+
if (patterns.length === 0) {
|
|
258
|
+
return 0.0;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let weightedSum = 0;
|
|
262
|
+
let totalWeight = 0;
|
|
263
|
+
|
|
264
|
+
patterns.forEach((pattern) => {
|
|
265
|
+
let weight: number;
|
|
266
|
+
|
|
267
|
+
switch (pattern.confidence) {
|
|
268
|
+
case 'high':
|
|
269
|
+
weight = this.config.patternWeights.highConfidence;
|
|
270
|
+
break;
|
|
271
|
+
case 'medium':
|
|
272
|
+
weight = this.config.patternWeights.mediumConfidence;
|
|
273
|
+
break;
|
|
274
|
+
case 'low':
|
|
275
|
+
weight = this.config.patternWeights.lowConfidence;
|
|
276
|
+
break;
|
|
277
|
+
default:
|
|
278
|
+
weight = 0.5;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
weightedSum += pattern.score * weight;
|
|
282
|
+
totalWeight += weight;
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const baseScore = totalWeight > 0 ? weightedSum / totalWeight : 0;
|
|
286
|
+
|
|
287
|
+
// Apply pattern count bonus (more patterns = higher confidence)
|
|
288
|
+
const patternCountBonus = Math.min(0.1, patterns.length * 0.02);
|
|
289
|
+
|
|
290
|
+
// Apply high-confidence pattern bonus
|
|
291
|
+
const highConfidencePatterns = patterns.filter((p) => p.confidence === 'high').length;
|
|
292
|
+
const highConfidenceBonus = Math.min(0.15, highConfidencePatterns * 0.05);
|
|
293
|
+
|
|
294
|
+
const finalScore = Math.min(1.0, baseScore + patternCountBonus + highConfidenceBonus);
|
|
295
|
+
|
|
296
|
+
return Math.round(finalScore * 1000) / 1000; // Round to 3 decimal places
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Create analysis breakdown from results
|
|
301
|
+
* @param results Array of analysis results
|
|
302
|
+
* @returns Analysis breakdown object
|
|
303
|
+
*/
|
|
304
|
+
private createAnalysisBreakdown(results: any[]): AnalysisBreakdown {
|
|
305
|
+
const breakdown: any = {
|
|
306
|
+
gitHistoryAnalysis: null,
|
|
307
|
+
documentationAnalysis: null,
|
|
308
|
+
structuralAnalysis: null,
|
|
309
|
+
statisticalAnalysis: null,
|
|
310
|
+
linguisticAnalysis: null,
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
results.forEach((result) => {
|
|
314
|
+
if (result.analyzer === 'git-history') {
|
|
315
|
+
breakdown.gitHistoryAnalysis = result;
|
|
316
|
+
} else if (result.analyzer === 'documentation') {
|
|
317
|
+
breakdown.documentationAnalysis = result;
|
|
318
|
+
}
|
|
319
|
+
// Additional analyzer results would be mapped here
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return breakdown as AnalysisBreakdown;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Generate actionable recommendations based on detected patterns
|
|
327
|
+
* @param patterns Detected patterns
|
|
328
|
+
* @param isAIGenerated Whether code is determined to be AI-generated
|
|
329
|
+
* @returns Array of recommendation strings
|
|
330
|
+
*/
|
|
331
|
+
private generateRecommendations(patterns: DetectedPattern[], isAIGenerated: boolean): string[] {
|
|
332
|
+
if (!this.config.generateRecommendations) {
|
|
333
|
+
return [];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const recommendations: string[] = [];
|
|
337
|
+
|
|
338
|
+
if (isAIGenerated) {
|
|
339
|
+
recommendations.push('â ī¸ This submission shows strong indicators of AI-generated code');
|
|
340
|
+
|
|
341
|
+
const highConfidencePatterns = patterns.filter((p) => p.confidence === 'high');
|
|
342
|
+
if (highConfidencePatterns.length > 0) {
|
|
343
|
+
recommendations.push(
|
|
344
|
+
`đ ${highConfidencePatterns.length} high-confidence AI patterns detected`,
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Pattern-specific recommendations
|
|
349
|
+
patterns.forEach((pattern) => {
|
|
350
|
+
switch (pattern.id) {
|
|
351
|
+
case 'H1.1':
|
|
352
|
+
recommendations.push(
|
|
353
|
+
'đ Consider asking candidate about development process - large initial commit is unusual',
|
|
354
|
+
);
|
|
355
|
+
break;
|
|
356
|
+
case 'H1.2':
|
|
357
|
+
recommendations.push(
|
|
358
|
+
'đŦ Verify commit message authenticity - patterns suggest automated generation',
|
|
359
|
+
);
|
|
360
|
+
break;
|
|
361
|
+
case 'H2.1':
|
|
362
|
+
recommendations.push(
|
|
363
|
+
'đ README structure appears template-generated - verify candidate understanding',
|
|
364
|
+
);
|
|
365
|
+
break;
|
|
366
|
+
case 'H2.2':
|
|
367
|
+
recommendations.push(
|
|
368
|
+
'đ Comment density is suspiciously high and uniform across files',
|
|
369
|
+
);
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
recommendations.push(
|
|
375
|
+
'đ¯ Recommend conducting verbal technical interview to verify understanding',
|
|
376
|
+
);
|
|
377
|
+
recommendations.push(
|
|
378
|
+
'đŦ Consider asking candidate to explain specific code sections or make live modifications',
|
|
379
|
+
);
|
|
380
|
+
} else {
|
|
381
|
+
recommendations.push('â
Analysis suggests human-authored code');
|
|
382
|
+
|
|
383
|
+
if (patterns.length > 0) {
|
|
384
|
+
recommendations.push(
|
|
385
|
+
`âšī¸ ${patterns.length} minor indicators detected, but below confidence threshold`,
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return recommendations;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Create detection metadata
|
|
395
|
+
* @param startTime Analysis start time
|
|
396
|
+
* @param warnings Array of warning messages
|
|
397
|
+
* @returns Detection metadata object
|
|
398
|
+
*/
|
|
399
|
+
private createMetadata(startTime: number, warnings: string[]): DetectionMetadata {
|
|
400
|
+
return {
|
|
401
|
+
timestamp: new Date(),
|
|
402
|
+
engineVersion: '1.0.0',
|
|
403
|
+
enabledAnalyzers: this.config.enabledAnalyzers,
|
|
404
|
+
totalAnalysisTime: Date.now() - startTime,
|
|
405
|
+
warnings,
|
|
406
|
+
cacheInfo: { hit: false },
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Generate cache key for a submission
|
|
412
|
+
* @param submission Code submission
|
|
413
|
+
* @returns Cache key string
|
|
414
|
+
*/
|
|
415
|
+
private generateCacheKey(submission: CodeSubmission): string {
|
|
416
|
+
// Simple hash based on submission content
|
|
417
|
+
const hashInput = JSON.stringify({
|
|
418
|
+
commitHashes: submission.repository.commits.map((c) => c.hash),
|
|
419
|
+
fileCount: submission.codebase.files.length,
|
|
420
|
+
hasReadme: !!submission.documentation.readme,
|
|
421
|
+
configHash: JSON.stringify(this.config),
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Simple string hash (in production, use crypto.createHash)
|
|
425
|
+
let hash = 0;
|
|
426
|
+
for (let i = 0; i < hashInput.length; i++) {
|
|
427
|
+
const char = hashInput.charCodeAt(i);
|
|
428
|
+
hash = (hash << 5) - hash + char;
|
|
429
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return `ai-detection-${Math.abs(hash).toString(36)}`;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Create error result for failed analyses
|
|
437
|
+
* @param startTime Analysis start time
|
|
438
|
+
* @param error Error that occurred
|
|
439
|
+
* @returns Error detection result
|
|
440
|
+
*/
|
|
441
|
+
private createErrorResult(startTime: number, error: Error): DetectionResult {
|
|
442
|
+
return {
|
|
443
|
+
isAIGenerated: false,
|
|
444
|
+
confidenceScore: 0.0,
|
|
445
|
+
detectedPatterns: [],
|
|
446
|
+
analysisBreakdown: {
|
|
447
|
+
gitHistoryAnalysis: null as any,
|
|
448
|
+
documentationAnalysis: null as any,
|
|
449
|
+
structuralAnalysis: null as any,
|
|
450
|
+
statisticalAnalysis: null as any,
|
|
451
|
+
linguisticAnalysis: null as any,
|
|
452
|
+
},
|
|
453
|
+
recommendations: [
|
|
454
|
+
'â Analysis failed due to technical error',
|
|
455
|
+
'đ Please retry analysis or contact system administrator',
|
|
456
|
+
],
|
|
457
|
+
metadata: {
|
|
458
|
+
timestamp: new Date(),
|
|
459
|
+
engineVersion: '1.0.0',
|
|
460
|
+
enabledAnalyzers: this.config.enabledAnalyzers,
|
|
461
|
+
totalAnalysisTime: Date.now() - startTime,
|
|
462
|
+
warnings: [`Analysis failed: ${error.message}`],
|
|
463
|
+
cacheInfo: { hit: false },
|
|
464
|
+
},
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
}
|