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,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Git history analyzer for detecting AI-generated code patterns.
|
|
3
|
+
*
|
|
4
|
+
* This analyzer examines git commit history, patterns, and metadata to identify
|
|
5
|
+
* characteristics commonly associated with AI-generated code submissions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
CodeSubmission,
|
|
10
|
+
DetectedPattern,
|
|
11
|
+
GitAnalysisResult,
|
|
12
|
+
GitCommit,
|
|
13
|
+
PatternDetectionResult,
|
|
14
|
+
} from '../types/DetectionTypes';
|
|
15
|
+
import { BaseAnalyzer } from './BaseAnalyzer';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Analyzer for git history patterns that may indicate AI generation
|
|
19
|
+
*/
|
|
20
|
+
export class GitHistoryAnalyzer extends BaseAnalyzer {
|
|
21
|
+
/**
|
|
22
|
+
* Get analyzer name
|
|
23
|
+
*/
|
|
24
|
+
getAnalyzerName(): string {
|
|
25
|
+
return 'git';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Analyze git history for AI-generated patterns
|
|
30
|
+
* @param submission Code submission to analyze
|
|
31
|
+
* @returns Git analysis result
|
|
32
|
+
*/
|
|
33
|
+
async analyze(submission: CodeSubmission): Promise<GitAnalysisResult> {
|
|
34
|
+
this.startTimer();
|
|
35
|
+
const patterns: DetectedPattern[] = [];
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const commits = submission.repository.commits;
|
|
39
|
+
|
|
40
|
+
if (commits.length === 0) {
|
|
41
|
+
return this.createEmptyResult();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Pattern H1.1: Simultaneous File Creation
|
|
45
|
+
const bulkCreationResult = this.detectBulkFileCreation(commits);
|
|
46
|
+
if (bulkCreationResult.detected) {
|
|
47
|
+
patterns.push(
|
|
48
|
+
this.createDetectedPattern(
|
|
49
|
+
'H1.1',
|
|
50
|
+
'Simultaneous File Creation',
|
|
51
|
+
'high',
|
|
52
|
+
bulkCreationResult.score,
|
|
53
|
+
'Initial commit contains unusually large number of files, suggesting bulk generation',
|
|
54
|
+
bulkCreationResult.evidence || {},
|
|
55
|
+
),
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Pattern H1.2: AI-Generated Commit Messages
|
|
60
|
+
const aiCommitResult = this.detectAICommitMessages(commits);
|
|
61
|
+
if (aiCommitResult.detected) {
|
|
62
|
+
patterns.push(
|
|
63
|
+
this.createDetectedPattern(
|
|
64
|
+
'H1.2',
|
|
65
|
+
'AI-Generated Commit Messages',
|
|
66
|
+
'high',
|
|
67
|
+
aiCommitResult.score,
|
|
68
|
+
'Commit messages follow AI-generated patterns and templates',
|
|
69
|
+
aiCommitResult.evidence || {},
|
|
70
|
+
),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Pattern H1.3: Absence of Debugging Commits
|
|
75
|
+
const debuggingAbsenceResult = this.detectDebuggingAbsence(commits);
|
|
76
|
+
if (debuggingAbsenceResult.detected) {
|
|
77
|
+
patterns.push(
|
|
78
|
+
this.createDetectedPattern(
|
|
79
|
+
'H1.3',
|
|
80
|
+
'Missing Developer Workflow',
|
|
81
|
+
'high',
|
|
82
|
+
debuggingAbsenceResult.score,
|
|
83
|
+
'Lacks typical developer debugging and iteration patterns',
|
|
84
|
+
debuggingAbsenceResult.evidence || {},
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Pattern H1.4: Perfect Initial Commit
|
|
90
|
+
const perfectInitialResult = this.detectPerfectInitialCommit(commits);
|
|
91
|
+
if (perfectInitialResult.detected) {
|
|
92
|
+
patterns.push(
|
|
93
|
+
this.createDetectedPattern(
|
|
94
|
+
'H1.4',
|
|
95
|
+
'Perfect Initial Commit',
|
|
96
|
+
'high',
|
|
97
|
+
perfectInitialResult.score,
|
|
98
|
+
'Initial commit contains complete, working project without typical development artifacts',
|
|
99
|
+
perfectInitialResult.evidence || {},
|
|
100
|
+
),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
analyzer: 'git-history',
|
|
106
|
+
patterns,
|
|
107
|
+
metadata: {
|
|
108
|
+
totalCommits: commits.length,
|
|
109
|
+
analysisTime: this.getElapsedTime(),
|
|
110
|
+
sufficientHistory: commits.length >= 3,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error('Error in GitHistoryAnalyzer:', error);
|
|
115
|
+
return this.createEmptyResult();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Detect bulk file creation in initial commit
|
|
121
|
+
* @param commits Array of git commits
|
|
122
|
+
* @returns Pattern detection result
|
|
123
|
+
*/
|
|
124
|
+
private detectBulkFileCreation(commits: GitCommit[]): PatternDetectionResult {
|
|
125
|
+
if (commits.length === 0) {
|
|
126
|
+
return this.createPatternResult(false, 0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const initialCommit = commits[0];
|
|
130
|
+
const fileCount = initialCommit.changedFiles.length;
|
|
131
|
+
|
|
132
|
+
// Threshold: >15 files in initial commit is suspicious
|
|
133
|
+
// More files = higher suspicion
|
|
134
|
+
if (fileCount > 15) {
|
|
135
|
+
const score = Math.min(0.95, 0.6 + (fileCount - 15) * 0.02);
|
|
136
|
+
|
|
137
|
+
return this.createPatternResult(true, score, {
|
|
138
|
+
fileCount,
|
|
139
|
+
commitHash: initialCommit.hash,
|
|
140
|
+
message: initialCommit.message,
|
|
141
|
+
files: initialCommit.changedFiles.slice(0, 10), // First 10 files for evidence
|
|
142
|
+
timestamp: initialCommit.timestamp,
|
|
143
|
+
threshold: 15,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return this.createPatternResult(false, 0);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Detect AI-generated commit message patterns
|
|
152
|
+
* @param commits Array of git commits
|
|
153
|
+
* @returns Pattern detection result
|
|
154
|
+
*/
|
|
155
|
+
private detectAICommitMessages(commits: GitCommit[]): PatternDetectionResult {
|
|
156
|
+
const aiPatterns = [
|
|
157
|
+
// Conventional commit patterns (overly consistent usage)
|
|
158
|
+
/^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{20,}/,
|
|
159
|
+
// Template-like descriptive messages
|
|
160
|
+
/^(Add|Update|Fix|Implement|Create) .+ (feature|functionality|component|module)$/i,
|
|
161
|
+
// Overly formal initial commit messages
|
|
162
|
+
/^Initial (commit|implementation) with (complete|full) .+ structure$/i,
|
|
163
|
+
// Perfect grammar and structure
|
|
164
|
+
/^(Implement|Add|Create) comprehensive .+ with .+ support$/i,
|
|
165
|
+
// Emoji usage patterns common in AI
|
|
166
|
+
/^(✨|🚀|🎉|🔧|📝|🐛|💡) /,
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
let matches = 0;
|
|
170
|
+
const evidence: any[] = [];
|
|
171
|
+
const totalCommits = commits.length;
|
|
172
|
+
|
|
173
|
+
commits.forEach((commit, index) => {
|
|
174
|
+
const isAIPattern = aiPatterns.some((pattern) => pattern.test(commit.message));
|
|
175
|
+
if (isAIPattern) {
|
|
176
|
+
matches++;
|
|
177
|
+
evidence.push({
|
|
178
|
+
hash: commit.hash,
|
|
179
|
+
message: commit.message,
|
|
180
|
+
timestamp: commit.timestamp,
|
|
181
|
+
position: index === 0 ? 'initial' : index === totalCommits - 1 ? 'latest' : 'middle',
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const ratio = matches / totalCommits;
|
|
187
|
+
|
|
188
|
+
// >70% of commits match AI patterns is highly suspicious
|
|
189
|
+
if (ratio > 0.7 && totalCommits >= 3) {
|
|
190
|
+
const score = Math.min(0.95, 0.6 + ratio * 0.3);
|
|
191
|
+
|
|
192
|
+
return this.createPatternResult(true, score, {
|
|
193
|
+
matchingCommits: matches,
|
|
194
|
+
totalCommits,
|
|
195
|
+
ratio,
|
|
196
|
+
examples: evidence.slice(0, 5), // Top 5 examples
|
|
197
|
+
patterns: aiPatterns.map((p) => p.source),
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return this.createPatternResult(false, ratio * 0.4); // Partial score for moderate usage
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Detect absence of typical debugging/development commits
|
|
206
|
+
* @param commits Array of git commits
|
|
207
|
+
* @returns Pattern detection result
|
|
208
|
+
*/
|
|
209
|
+
private detectDebuggingAbsence(commits: GitCommit[]): PatternDetectionResult {
|
|
210
|
+
if (commits.length < 3) {
|
|
211
|
+
return this.createPatternResult(false, 0); // Need sufficient history
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const developmentPatterns = [
|
|
215
|
+
// Work in progress indicators
|
|
216
|
+
/\bwip\b/i,
|
|
217
|
+
/work.?in.?progress/i,
|
|
218
|
+
// Quick fixes and debugging
|
|
219
|
+
/\bfix\b(?!:)/i, // "fix" but not "fix:" (conventional commits)
|
|
220
|
+
/\bbug\b/i,
|
|
221
|
+
/\bdebug\b/i,
|
|
222
|
+
/oops/i,
|
|
223
|
+
/typo/i,
|
|
224
|
+
// Experimental work
|
|
225
|
+
/test/i,
|
|
226
|
+
/experiment/i,
|
|
227
|
+
/try/i,
|
|
228
|
+
/attempt/i,
|
|
229
|
+
// Informal language
|
|
230
|
+
/\btodo\b/i,
|
|
231
|
+
/\bfixme\b/i,
|
|
232
|
+
/wtf/i,
|
|
233
|
+
/hack/i,
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
let humanLikeCommits = 0;
|
|
237
|
+
const totalCommits = commits.length;
|
|
238
|
+
|
|
239
|
+
commits.forEach((commit) => {
|
|
240
|
+
const isHumanLike = developmentPatterns.some((pattern) => pattern.test(commit.message));
|
|
241
|
+
|
|
242
|
+
if (isHumanLike) {
|
|
243
|
+
humanLikeCommits++;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const humanRatio = humanLikeCommits / totalCommits;
|
|
248
|
+
|
|
249
|
+
// Very low ratio of human-like commits suggests AI generation
|
|
250
|
+
if (humanRatio < 0.1 && totalCommits >= 5) {
|
|
251
|
+
const score = Math.min(0.88, 0.5 + (0.1 - humanRatio) * 3);
|
|
252
|
+
|
|
253
|
+
return this.createPatternResult(true, score, {
|
|
254
|
+
humanLikeCommits,
|
|
255
|
+
totalCommits,
|
|
256
|
+
humanRatio,
|
|
257
|
+
missingPatterns: developmentPatterns.map((p) => p.source),
|
|
258
|
+
threshold: 0.1,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return this.createPatternResult(false, 0);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Detect perfect initial commit without development artifacts
|
|
267
|
+
* @param commits Array of git commits
|
|
268
|
+
* @returns Pattern detection result
|
|
269
|
+
*/
|
|
270
|
+
private detectPerfectInitialCommit(commits: GitCommit[]): PatternDetectionResult {
|
|
271
|
+
if (commits.length === 0) {
|
|
272
|
+
return this.createPatternResult(false, 0);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const initialCommit = commits[0];
|
|
276
|
+
const fileCount = initialCommit.changedFiles.length;
|
|
277
|
+
|
|
278
|
+
// Indicators of "perfect" initial commit
|
|
279
|
+
const indicators = {
|
|
280
|
+
largeFileCount: fileCount > 20,
|
|
281
|
+
hasCompleteStructure: this.hasCompleteProjectStructure(initialCommit.changedFiles),
|
|
282
|
+
hasConfigFiles: this.hasConfigurationFiles(initialCommit.changedFiles),
|
|
283
|
+
hasDocumentation: this.hasDocumentationFiles(initialCommit.changedFiles),
|
|
284
|
+
hasTests: this.hasTestFiles(initialCommit.changedFiles),
|
|
285
|
+
perfectMessage: this.isPerfectInitialMessage(initialCommit.message),
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const indicatorCount = Object.values(indicators).filter(Boolean).length;
|
|
289
|
+
const totalIndicators = Object.keys(indicators).length;
|
|
290
|
+
|
|
291
|
+
// If most indicators are present, it suggests AI generation
|
|
292
|
+
if (indicatorCount >= 4) {
|
|
293
|
+
const score = Math.min(0.92, 0.5 + (indicatorCount / totalIndicators) * 0.4);
|
|
294
|
+
|
|
295
|
+
return this.createPatternResult(true, score, {
|
|
296
|
+
indicators,
|
|
297
|
+
indicatorCount,
|
|
298
|
+
totalIndicators,
|
|
299
|
+
fileCount,
|
|
300
|
+
commitMessage: initialCommit.message,
|
|
301
|
+
fileTypes: this.categorizeFiles(initialCommit.changedFiles),
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return this.createPatternResult(false, (indicatorCount / totalIndicators) * 0.3);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Check if commit has complete project structure
|
|
310
|
+
* @param files Array of file paths
|
|
311
|
+
* @returns True if has complete structure
|
|
312
|
+
*/
|
|
313
|
+
private hasCompleteProjectStructure(files: string[]): boolean {
|
|
314
|
+
const structureFiles = [
|
|
315
|
+
'package.json',
|
|
316
|
+
'tsconfig.json',
|
|
317
|
+
'webpack.config.js',
|
|
318
|
+
'vite.config.js',
|
|
319
|
+
'babel.config.js',
|
|
320
|
+
'.eslintrc',
|
|
321
|
+
'.prettierrc',
|
|
322
|
+
'jest.config.js',
|
|
323
|
+
];
|
|
324
|
+
|
|
325
|
+
const foundStructureFiles = files.filter((file) =>
|
|
326
|
+
structureFiles.some((sf) => file.endsWith(sf)),
|
|
327
|
+
).length;
|
|
328
|
+
|
|
329
|
+
return foundStructureFiles >= 3;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Check if commit has configuration files
|
|
334
|
+
* @param files Array of file paths
|
|
335
|
+
* @returns True if has config files
|
|
336
|
+
*/
|
|
337
|
+
private hasConfigurationFiles(files: string[]): boolean {
|
|
338
|
+
const configPatterns = [/\.config\.(js|ts|json)$/, /^\.env/, /^\.git/, /^\.vscode/, /^\.idea/];
|
|
339
|
+
|
|
340
|
+
return files.some((file) => configPatterns.some((pattern) => pattern.test(file)));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Check if commit has documentation files
|
|
345
|
+
* @param files Array of file paths
|
|
346
|
+
* @returns True if has documentation
|
|
347
|
+
*/
|
|
348
|
+
private hasDocumentationFiles(files: string[]): boolean {
|
|
349
|
+
const docPatterns = [/README/i, /CHANGELOG/i, /LICENSE/i, /CONTRIBUTING/i, /\.md$/];
|
|
350
|
+
|
|
351
|
+
return files.some((file) => docPatterns.some((pattern) => pattern.test(file)));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Check if commit has test files
|
|
356
|
+
* @param files Array of file paths
|
|
357
|
+
* @returns True if has tests
|
|
358
|
+
*/
|
|
359
|
+
private hasTestFiles(files: string[]): boolean {
|
|
360
|
+
const testPatterns = [/\.(test|spec)\.(js|ts|jsx|tsx)$/, /^test\//, /^tests\//, /__tests__/];
|
|
361
|
+
|
|
362
|
+
return files.some((file) => testPatterns.some((pattern) => pattern.test(file)));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Check if initial commit message is "perfect" (suggests AI)
|
|
367
|
+
* @param message Commit message
|
|
368
|
+
* @returns True if message seems AI-generated
|
|
369
|
+
*/
|
|
370
|
+
private isPerfectInitialMessage(message: string): boolean {
|
|
371
|
+
const perfectPatterns = [
|
|
372
|
+
/^Initial commit with complete .+ implementation$/i,
|
|
373
|
+
/^feat: initial .+ setup with .+ integration$/i,
|
|
374
|
+
/^🎉 Initial release with comprehensive .+ support$/i,
|
|
375
|
+
/^Add complete .+ project structure$/i,
|
|
376
|
+
];
|
|
377
|
+
|
|
378
|
+
return perfectPatterns.some((pattern) => pattern.test(message));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Categorize files by type
|
|
383
|
+
* @param files Array of file paths
|
|
384
|
+
* @returns Object with file type counts
|
|
385
|
+
*/
|
|
386
|
+
private categorizeFiles(files: string[]): Record<string, number> {
|
|
387
|
+
const categories = {
|
|
388
|
+
source: 0,
|
|
389
|
+
config: 0,
|
|
390
|
+
test: 0,
|
|
391
|
+
documentation: 0,
|
|
392
|
+
assets: 0,
|
|
393
|
+
other: 0,
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
files.forEach((file) => {
|
|
397
|
+
if (/\.(js|ts|jsx|tsx|py|java|go|rb|php)$/.test(file)) {
|
|
398
|
+
categories.source++;
|
|
399
|
+
} else if (/\.(json|yaml|yml|toml|ini|env)$/.test(file) || file.includes('config')) {
|
|
400
|
+
categories.config++;
|
|
401
|
+
} else if (/\.(test|spec)\./.test(file) || file.includes('test')) {
|
|
402
|
+
categories.test++;
|
|
403
|
+
} else if (/\.(md|txt|rst)$/.test(file) || /README|LICENSE|CHANGELOG/i.test(file)) {
|
|
404
|
+
categories.documentation++;
|
|
405
|
+
} else if (/\.(png|jpg|jpeg|gif|svg|ico|woff|ttf)$/.test(file)) {
|
|
406
|
+
categories.assets++;
|
|
407
|
+
} else {
|
|
408
|
+
categories.other++;
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
return categories;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Create empty result for error cases
|
|
417
|
+
* @returns Empty git analysis result
|
|
418
|
+
*/
|
|
419
|
+
private createEmptyResult(): GitAnalysisResult {
|
|
420
|
+
return {
|
|
421
|
+
analyzer: 'git-history',
|
|
422
|
+
patterns: [],
|
|
423
|
+
metadata: {
|
|
424
|
+
totalCommits: 0,
|
|
425
|
+
analysisTime: this.getElapsedTime(),
|
|
426
|
+
sufficientHistory: false,
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
}
|