neuronlayer 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.
Files changed (78) hide show
  1. package/CONTRIBUTING.md +127 -0
  2. package/LICENSE +21 -0
  3. package/README.md +305 -0
  4. package/dist/index.js +38016 -0
  5. package/esbuild.config.js +26 -0
  6. package/package.json +63 -0
  7. package/src/cli/commands.ts +382 -0
  8. package/src/core/adr-exporter.ts +253 -0
  9. package/src/core/architecture/architecture-enforcement.ts +228 -0
  10. package/src/core/architecture/duplicate-detector.ts +288 -0
  11. package/src/core/architecture/index.ts +6 -0
  12. package/src/core/architecture/pattern-learner.ts +306 -0
  13. package/src/core/architecture/pattern-library.ts +403 -0
  14. package/src/core/architecture/pattern-validator.ts +324 -0
  15. package/src/core/change-intelligence/bug-correlator.ts +444 -0
  16. package/src/core/change-intelligence/change-intelligence.ts +221 -0
  17. package/src/core/change-intelligence/change-tracker.ts +334 -0
  18. package/src/core/change-intelligence/fix-suggester.ts +340 -0
  19. package/src/core/change-intelligence/index.ts +5 -0
  20. package/src/core/code-verifier.ts +843 -0
  21. package/src/core/confidence/confidence-scorer.ts +251 -0
  22. package/src/core/confidence/conflict-checker.ts +289 -0
  23. package/src/core/confidence/index.ts +5 -0
  24. package/src/core/confidence/source-tracker.ts +263 -0
  25. package/src/core/confidence/warning-detector.ts +241 -0
  26. package/src/core/context-rot/compaction.ts +284 -0
  27. package/src/core/context-rot/context-health.ts +243 -0
  28. package/src/core/context-rot/context-rot-prevention.ts +213 -0
  29. package/src/core/context-rot/critical-context.ts +221 -0
  30. package/src/core/context-rot/drift-detector.ts +255 -0
  31. package/src/core/context-rot/index.ts +7 -0
  32. package/src/core/context.ts +263 -0
  33. package/src/core/decision-extractor.ts +339 -0
  34. package/src/core/decisions.ts +69 -0
  35. package/src/core/deja-vu.ts +421 -0
  36. package/src/core/engine.ts +1455 -0
  37. package/src/core/feature-context.ts +726 -0
  38. package/src/core/ghost-mode.ts +412 -0
  39. package/src/core/learning.ts +485 -0
  40. package/src/core/living-docs/activity-tracker.ts +296 -0
  41. package/src/core/living-docs/architecture-generator.ts +428 -0
  42. package/src/core/living-docs/changelog-generator.ts +348 -0
  43. package/src/core/living-docs/component-generator.ts +230 -0
  44. package/src/core/living-docs/doc-engine.ts +110 -0
  45. package/src/core/living-docs/doc-validator.ts +282 -0
  46. package/src/core/living-docs/index.ts +8 -0
  47. package/src/core/project-manager.ts +297 -0
  48. package/src/core/summarizer.ts +267 -0
  49. package/src/core/test-awareness/change-validator.ts +499 -0
  50. package/src/core/test-awareness/index.ts +5 -0
  51. package/src/index.ts +49 -0
  52. package/src/indexing/ast.ts +563 -0
  53. package/src/indexing/embeddings.ts +85 -0
  54. package/src/indexing/indexer.ts +245 -0
  55. package/src/indexing/watcher.ts +78 -0
  56. package/src/server/gateways/aggregator.ts +374 -0
  57. package/src/server/gateways/index.ts +473 -0
  58. package/src/server/gateways/memory-ghost.ts +343 -0
  59. package/src/server/gateways/memory-query.ts +452 -0
  60. package/src/server/gateways/memory-record.ts +346 -0
  61. package/src/server/gateways/memory-review.ts +410 -0
  62. package/src/server/gateways/memory-status.ts +517 -0
  63. package/src/server/gateways/memory-verify.ts +392 -0
  64. package/src/server/gateways/router.ts +434 -0
  65. package/src/server/gateways/types.ts +610 -0
  66. package/src/server/mcp.ts +154 -0
  67. package/src/server/resources.ts +85 -0
  68. package/src/server/tools.ts +2261 -0
  69. package/src/storage/database.ts +262 -0
  70. package/src/storage/tier1.ts +135 -0
  71. package/src/storage/tier2.ts +764 -0
  72. package/src/storage/tier3.ts +123 -0
  73. package/src/types/documentation.ts +619 -0
  74. package/src/types/index.ts +222 -0
  75. package/src/utils/config.ts +193 -0
  76. package/src/utils/files.ts +117 -0
  77. package/src/utils/time.ts +37 -0
  78. package/src/utils/tokens.ts +52 -0
@@ -0,0 +1,251 @@
1
+ import type { Tier2Storage } from '../../storage/tier2.js';
2
+ import type { EmbeddingGenerator } from '../../indexing/embeddings.js';
3
+ import type {
4
+ ConfidenceResult,
5
+ ConfidenceLevel,
6
+ ConfidenceSources,
7
+ ConfidenceWarning,
8
+ CodebaseMatch,
9
+ DecisionMatch,
10
+ PatternMatch
11
+ } from '../../types/documentation.js';
12
+ import { SourceTracker } from './source-tracker.js';
13
+ import { WarningDetector } from './warning-detector.js';
14
+ import { ConflictChecker } from './conflict-checker.js';
15
+
16
+ // Weights for confidence calculation
17
+ const WEIGHTS = {
18
+ codebase: 0.5, // 50% weight from codebase matches
19
+ decision: 0.3, // 30% weight from decision alignment
20
+ pattern: 0.2 // 20% weight from pattern matching
21
+ };
22
+
23
+ // Thresholds for confidence levels
24
+ const THRESHOLDS = {
25
+ high: 80,
26
+ medium: 50,
27
+ low: 20
28
+ };
29
+
30
+ export class ConfidenceScorer {
31
+ private sourceTracker: SourceTracker;
32
+ private warningDetector: WarningDetector;
33
+ private conflictChecker: ConflictChecker;
34
+
35
+ constructor(
36
+ tier2: Tier2Storage,
37
+ embeddingGenerator: EmbeddingGenerator
38
+ ) {
39
+ this.sourceTracker = new SourceTracker(tier2, embeddingGenerator);
40
+ this.warningDetector = new WarningDetector(tier2);
41
+ this.conflictChecker = new ConflictChecker(tier2, embeddingGenerator);
42
+ }
43
+
44
+ async getConfidence(code: string, context?: string): Promise<ConfidenceResult> {
45
+ // 1. Track sources
46
+ const sources = await this.sourceTracker.trackSources(code, context);
47
+
48
+ // 2. Calculate scores for each component
49
+ const codeScore = this.calculateCodeScore(sources.codebase);
50
+ const decisionScore = this.calculateDecisionScore(sources.decisions);
51
+ const patternScore = this.calculatePatternScore(sources.patterns);
52
+
53
+ // 3. Calculate composite score
54
+ const compositeScore = this.calculateCompositeScore(codeScore, decisionScore, patternScore);
55
+
56
+ // 4. Determine confidence level
57
+ const confidence = this.determineLevel(compositeScore);
58
+
59
+ // 5. Detect warnings
60
+ const warnings = await this.warningDetector.detectWarnings(code, sources);
61
+
62
+ // 6. Check for decision conflicts
63
+ const conflicts = await this.conflictChecker.checkConflicts(code);
64
+ if (conflicts.hasConflicts) {
65
+ for (const conflict of conflicts.conflicts) {
66
+ warnings.push({
67
+ type: 'conflicts_with_decision',
68
+ message: `Conflicts with decision: "${conflict.decisionTitle}"`,
69
+ severity: conflict.severity === 'high' ? 'critical' : 'warning',
70
+ suggestion: conflict.conflictDescription,
71
+ relatedDecision: conflict.decisionId
72
+ });
73
+ }
74
+ }
75
+
76
+ // 7. Generate reasoning
77
+ const reasoning = this.generateReasoning(confidence, sources, warnings);
78
+
79
+ return {
80
+ confidence,
81
+ score: Math.round(compositeScore),
82
+ reasoning,
83
+ sources,
84
+ warnings
85
+ };
86
+ }
87
+
88
+ private calculateCodeScore(matches: CodebaseMatch[]): number {
89
+ if (matches.length === 0) return 0;
90
+
91
+ // Weight by similarity and usage count
92
+ let totalWeight = 0;
93
+ let weightedSum = 0;
94
+
95
+ for (const match of matches) {
96
+ const weight = 1 + Math.log10(1 + (match.usageCount || 1));
97
+ weightedSum += match.similarity * weight;
98
+ totalWeight += weight;
99
+ }
100
+
101
+ return totalWeight > 0 ? weightedSum / totalWeight : 0;
102
+ }
103
+
104
+ private calculateDecisionScore(matches: DecisionMatch[]): number {
105
+ if (matches.length === 0) return 50; // Neutral if no decisions
106
+
107
+ // Average relevance of matched decisions
108
+ const totalRelevance = matches.reduce((sum, m) => sum + m.relevance, 0);
109
+ return totalRelevance / matches.length;
110
+ }
111
+
112
+ private calculatePatternScore(matches: PatternMatch[]): number {
113
+ if (matches.length === 0) return 30; // Low baseline if no patterns
114
+
115
+ // Average confidence of matched patterns
116
+ const totalConfidence = matches.reduce((sum, m) => sum + m.confidence, 0);
117
+ return totalConfidence / matches.length;
118
+ }
119
+
120
+ private calculateCompositeScore(codeScore: number, decisionScore: number, patternScore: number): number {
121
+ return (
122
+ codeScore * WEIGHTS.codebase +
123
+ decisionScore * WEIGHTS.decision +
124
+ patternScore * WEIGHTS.pattern
125
+ );
126
+ }
127
+
128
+ private determineLevel(score: number): ConfidenceLevel {
129
+ if (score >= THRESHOLDS.high) return 'high';
130
+ if (score >= THRESHOLDS.medium) return 'medium';
131
+ if (score >= THRESHOLDS.low) return 'low';
132
+ return 'guessing';
133
+ }
134
+
135
+ private generateReasoning(
136
+ level: ConfidenceLevel,
137
+ sources: ConfidenceSources,
138
+ warnings: ConfidenceWarning[]
139
+ ): string {
140
+ const parts: string[] = [];
141
+
142
+ // Confidence level explanation
143
+ switch (level) {
144
+ case 'high':
145
+ parts.push('High confidence');
146
+ break;
147
+ case 'medium':
148
+ parts.push('Medium confidence');
149
+ break;
150
+ case 'low':
151
+ parts.push('Low confidence');
152
+ break;
153
+ case 'guessing':
154
+ parts.push('Best guess');
155
+ break;
156
+ }
157
+
158
+ // Source attribution
159
+ if (sources.codebase.length > 0) {
160
+ const topMatch = sources.codebase[0];
161
+ parts.push(`found similar code in ${topMatch.file}${topMatch.function ? `:${topMatch.function}` : ''} (${topMatch.similarity}% match)`);
162
+ }
163
+
164
+ if (sources.decisions.length > 0) {
165
+ parts.push(`aligns with ${sources.decisions.length} recorded decision(s)`);
166
+ }
167
+
168
+ if (sources.patterns.length > 0) {
169
+ parts.push(`matches ${sources.patterns.length} established pattern(s)`);
170
+ }
171
+
172
+ if (sources.usedGeneralKnowledge) {
173
+ parts.push('based partly on general knowledge');
174
+ }
175
+
176
+ // Warnings
177
+ const criticalWarnings = warnings.filter(w => w.severity === 'critical');
178
+ if (criticalWarnings.length > 0) {
179
+ parts.push(`${criticalWarnings.length} critical warning(s)`);
180
+ }
181
+
182
+ return parts.join(', ');
183
+ }
184
+
185
+ async listSources(code: string, context?: string, includeSnippets: boolean = false): Promise<ConfidenceSources> {
186
+ const sources = await this.sourceTracker.trackSources(code, context);
187
+
188
+ if (!includeSnippets) {
189
+ // Remove snippets for cleaner output
190
+ for (const match of sources.codebase) {
191
+ delete match.snippet;
192
+ }
193
+ }
194
+
195
+ return sources;
196
+ }
197
+
198
+ async checkConflicts(code: string) {
199
+ return this.conflictChecker.checkConflicts(code);
200
+ }
201
+
202
+ // Get confidence level indicator emoji
203
+ static getIndicator(level: ConfidenceLevel): string {
204
+ switch (level) {
205
+ case 'high': return '\u{1F7E2}'; // Green circle
206
+ case 'medium': return '\u{1F7E1}'; // Yellow circle
207
+ case 'low': return '\u{1F7E0}'; // Orange circle
208
+ case 'guessing': return '\u{1F534}'; // Red circle
209
+ }
210
+ }
211
+
212
+ // Format confidence result for display
213
+ static formatResult(result: ConfidenceResult): string {
214
+ const indicator = ConfidenceScorer.getIndicator(result.confidence);
215
+ const lines: string[] = [];
216
+
217
+ lines.push(`${indicator} ${result.confidence.toUpperCase()} Confidence (${result.score}%)`);
218
+ lines.push(result.reasoning);
219
+
220
+ if (result.sources.codebase.length > 0) {
221
+ lines.push('');
222
+ lines.push('Codebase Sources:');
223
+ for (const match of result.sources.codebase.slice(0, 3)) {
224
+ lines.push(` - ${match.file}${match.line ? `:${match.line}` : ''} (${match.similarity}% similar)`);
225
+ }
226
+ }
227
+
228
+ if (result.sources.decisions.length > 0) {
229
+ lines.push('');
230
+ lines.push('Related Decisions:');
231
+ for (const decision of result.sources.decisions.slice(0, 3)) {
232
+ lines.push(` - "${decision.title}" (${decision.relevance}% relevant)`);
233
+ }
234
+ }
235
+
236
+ if (result.warnings.length > 0) {
237
+ lines.push('');
238
+ lines.push('Warnings:');
239
+ for (const warning of result.warnings) {
240
+ const icon = warning.severity === 'critical' ? '\u{1F534}' :
241
+ warning.severity === 'warning' ? '\u{1F7E1}' : '\u{2139}\u{FE0F}';
242
+ lines.push(` ${icon} ${warning.message}`);
243
+ if (warning.suggestion) {
244
+ lines.push(` \u{2192} ${warning.suggestion}`);
245
+ }
246
+ }
247
+ }
248
+
249
+ return lines.join('\n');
250
+ }
251
+ }
@@ -0,0 +1,289 @@
1
+ import type { Tier2Storage } from '../../storage/tier2.js';
2
+ import type { EmbeddingGenerator } from '../../indexing/embeddings.js';
3
+ import type { ConflictResult } from '../../types/documentation.js';
4
+
5
+ // Common conflict patterns - decisions that might conflict with code patterns
6
+ const CONFLICT_PATTERNS = [
7
+ // Authentication patterns
8
+ {
9
+ decisionKeywords: ['jwt', 'json web token'],
10
+ conflictingCode: /session\s*=|cookie.*auth|express-session/i,
11
+ conflict: 'Code uses session-based auth, but decision specifies JWT'
12
+ },
13
+ {
14
+ decisionKeywords: ['session', 'cookie auth'],
15
+ conflictingCode: /jwt\.sign|jsonwebtoken/i,
16
+ conflict: 'Code uses JWT, but decision specifies session-based auth'
17
+ },
18
+
19
+ // Database patterns
20
+ {
21
+ decisionKeywords: ['parameterized queries', 'prepared statements', 'no string concatenation'],
22
+ conflictingCode: /\$\{.*\}.*(?:SELECT|INSERT|UPDATE|DELETE)|`.*\+.*\+.*(?:SELECT|INSERT)/i,
23
+ conflict: 'Code uses string concatenation for SQL, but decision requires parameterized queries'
24
+ },
25
+ {
26
+ decisionKeywords: ['orm', 'prisma', 'sequelize', 'typeorm'],
27
+ conflictingCode: /db\.query\s*\(|execute\s*\(\s*['"`]SELECT/i,
28
+ conflict: 'Code uses raw SQL, but decision specifies ORM usage'
29
+ },
30
+
31
+ // Error handling patterns
32
+ {
33
+ decisionKeywords: ['custom error classes', 'error types'],
34
+ conflictingCode: /throw\s+new\s+Error\s*\(/i,
35
+ conflict: 'Code throws generic Error, but decision specifies custom error classes'
36
+ },
37
+ {
38
+ decisionKeywords: ['always log errors', 'error logging'],
39
+ conflictingCode: /catch\s*\([^)]*\)\s*\{\s*\}/i,
40
+ conflict: 'Code has empty catch block, but decision requires error logging'
41
+ },
42
+
43
+ // API patterns
44
+ {
45
+ decisionKeywords: ['rest api', 'restful'],
46
+ conflictingCode: /graphql|gql`|ApolloServer/i,
47
+ conflict: 'Code uses GraphQL, but decision specifies REST API'
48
+ },
49
+ {
50
+ decisionKeywords: ['graphql'],
51
+ conflictingCode: /app\.(get|post|put|delete|patch)\s*\(/i,
52
+ conflict: 'Code uses REST endpoints, but decision specifies GraphQL'
53
+ },
54
+
55
+ // Testing patterns
56
+ {
57
+ decisionKeywords: ['jest', 'use jest'],
58
+ conflictingCode: /import.*mocha|describe.*chai|from\s+['"]vitest/i,
59
+ conflict: 'Code uses different testing framework, but decision specifies Jest'
60
+ },
61
+ {
62
+ decisionKeywords: ['vitest'],
63
+ conflictingCode: /import.*jest|from\s+['"]@jest/i,
64
+ conflict: 'Code uses Jest, but decision specifies Vitest'
65
+ },
66
+
67
+ // State management patterns
68
+ {
69
+ decisionKeywords: ['redux', 'use redux'],
70
+ conflictingCode: /useContext|createContext|zustand|mobx/i,
71
+ conflict: 'Code uses different state management, but decision specifies Redux'
72
+ },
73
+
74
+ // Styling patterns
75
+ {
76
+ decisionKeywords: ['tailwind', 'tailwindcss'],
77
+ conflictingCode: /styled-components|emotion|\.module\.css/i,
78
+ conflict: 'Code uses different styling approach, but decision specifies Tailwind'
79
+ },
80
+
81
+ // Async patterns
82
+ {
83
+ decisionKeywords: ['async/await', 'always use async'],
84
+ conflictingCode: /\.then\s*\([^)]*=>/i,
85
+ conflict: 'Code uses promise chains, but decision specifies async/await'
86
+ }
87
+ ];
88
+
89
+ export class ConflictChecker {
90
+ private tier2: Tier2Storage;
91
+ private embeddingGenerator: EmbeddingGenerator;
92
+
93
+ constructor(tier2: Tier2Storage, embeddingGenerator: EmbeddingGenerator) {
94
+ this.tier2 = tier2;
95
+ this.embeddingGenerator = embeddingGenerator;
96
+ }
97
+
98
+ async checkConflicts(code: string): Promise<ConflictResult> {
99
+ const conflicts: ConflictResult['conflicts'] = [];
100
+
101
+ // Get all decisions
102
+ const decisions = this.tier2.getAllDecisions();
103
+
104
+ if (decisions.length === 0) {
105
+ return { hasConflicts: false, conflicts: [] };
106
+ }
107
+
108
+ // Check each decision for conflicts
109
+ for (const decision of decisions) {
110
+ const conflict = this.checkDecisionConflict(code, decision);
111
+ if (conflict) {
112
+ conflicts.push(conflict);
113
+ }
114
+ }
115
+
116
+ // Also check using semantic similarity for decisions that might conflict
117
+ const semanticConflicts = await this.checkSemanticConflicts(code, decisions);
118
+ for (const conflict of semanticConflicts) {
119
+ // Avoid duplicates
120
+ if (!conflicts.some(c => c.decisionId === conflict.decisionId)) {
121
+ conflicts.push(conflict);
122
+ }
123
+ }
124
+
125
+ // Sort by severity
126
+ conflicts.sort((a, b) => {
127
+ const severityOrder = { high: 0, medium: 1, low: 2 };
128
+ return severityOrder[a.severity] - severityOrder[b.severity];
129
+ });
130
+
131
+ return {
132
+ hasConflicts: conflicts.length > 0,
133
+ conflicts
134
+ };
135
+ }
136
+
137
+ private checkDecisionConflict(
138
+ code: string,
139
+ decision: { id: string; title: string; description: string; createdAt: Date }
140
+ ): ConflictResult['conflicts'][0] | null {
141
+ const decisionText = `${decision.title} ${decision.description}`.toLowerCase();
142
+
143
+ for (const pattern of CONFLICT_PATTERNS) {
144
+ // Check if this decision matches the pattern keywords
145
+ const matchesKeywords = pattern.decisionKeywords.some(keyword =>
146
+ decisionText.includes(keyword.toLowerCase())
147
+ );
148
+
149
+ if (matchesKeywords && pattern.conflictingCode.test(code)) {
150
+ return {
151
+ decisionId: decision.id,
152
+ decisionTitle: decision.title,
153
+ decisionDate: decision.createdAt,
154
+ conflictDescription: pattern.conflict,
155
+ severity: this.determineSeverity(pattern.conflict)
156
+ };
157
+ }
158
+ }
159
+
160
+ return null;
161
+ }
162
+
163
+ private async checkSemanticConflicts(
164
+ code: string,
165
+ decisions: Array<{ id: string; title: string; description: string; createdAt: Date }>
166
+ ): Promise<ConflictResult['conflicts']> {
167
+ const conflicts: ConflictResult['conflicts'] = [];
168
+
169
+ try {
170
+ // Extract key concepts from the code
171
+ const codeApproach = this.extractApproach(code);
172
+ if (!codeApproach) return [];
173
+
174
+ // Generate embedding for the code approach
175
+ const codeEmbedding = await this.embeddingGenerator.embed(codeApproach);
176
+
177
+ // Search for related decisions
178
+ const relatedDecisions = this.tier2.searchDecisions(codeEmbedding, 5);
179
+
180
+ for (const related of relatedDecisions) {
181
+ // Check if the decision contradicts the approach
182
+ const contradiction = this.findContradiction(codeApproach, related.description);
183
+ if (contradiction) {
184
+ // Avoid duplicates
185
+ if (!conflicts.some(c => c.decisionId === related.id)) {
186
+ conflicts.push({
187
+ decisionId: related.id,
188
+ decisionTitle: related.title,
189
+ decisionDate: related.createdAt,
190
+ conflictDescription: contradiction,
191
+ severity: 'medium'
192
+ });
193
+ }
194
+ }
195
+ }
196
+ } catch (error) {
197
+ console.error('Error checking semantic conflicts:', error);
198
+ }
199
+
200
+ return conflicts;
201
+ }
202
+
203
+ private extractApproach(code: string): string | null {
204
+ // Extract what the code is doing
205
+ const patterns: Array<{ regex: RegExp; approach: string }> = [
206
+ { regex: /async\s+function\s+(\w+)/, approach: 'async function' },
207
+ { regex: /class\s+(\w+)\s+extends/, approach: 'class inheritance' },
208
+ { regex: /interface\s+(\w+)/, approach: 'interface definition' },
209
+ { regex: /import\s+.*from\s+['"](\w+)/, approach: 'using library' },
210
+ { regex: /\.then\s*\(/, approach: 'promise chains' },
211
+ { regex: /await\s+/, approach: 'async/await' },
212
+ { regex: /db\.(query|execute)/i, approach: 'direct database queries' },
213
+ { regex: /prisma\.\w+/, approach: 'Prisma ORM' },
214
+ { regex: /jwt\.(sign|verify)/i, approach: 'JWT authentication' },
215
+ { regex: /session\s*\[/i, approach: 'session-based authentication' }
216
+ ];
217
+
218
+ for (const { regex, approach } of patterns) {
219
+ if (regex.test(code)) {
220
+ return approach;
221
+ }
222
+ }
223
+
224
+ return null;
225
+ }
226
+
227
+ private findContradiction(codeApproach: string, decisionDescription: string): string | null {
228
+ const desc = decisionDescription.toLowerCase();
229
+ const approach = codeApproach.toLowerCase();
230
+
231
+ // Define contradictory pairs
232
+ const contradictions: Array<{ approaches: string[]; keywords: string[]; message: string }> = [
233
+ {
234
+ approaches: ['promise chains'],
235
+ keywords: ['async/await', 'always use async'],
236
+ message: 'Code uses promise chains, but decision prefers async/await'
237
+ },
238
+ {
239
+ approaches: ['direct database queries'],
240
+ keywords: ['orm', 'prisma', 'typeorm'],
241
+ message: 'Code uses direct queries, but decision specifies ORM'
242
+ },
243
+ {
244
+ approaches: ['class inheritance'],
245
+ keywords: ['composition', 'prefer composition'],
246
+ message: 'Code uses inheritance, but decision prefers composition'
247
+ }
248
+ ];
249
+
250
+ for (const { approaches, keywords, message } of contradictions) {
251
+ if (approaches.some(a => approach.includes(a)) &&
252
+ keywords.some(k => desc.includes(k))) {
253
+ return message;
254
+ }
255
+ }
256
+
257
+ return null;
258
+ }
259
+
260
+ private determineSeverity(conflictDescription: string): 'low' | 'medium' | 'high' {
261
+ const highSeverityKeywords = ['sql', 'security', 'authentication', 'injection', 'password'];
262
+ const mediumSeverityKeywords = ['orm', 'framework', 'testing', 'api'];
263
+
264
+ const lower = conflictDescription.toLowerCase();
265
+
266
+ if (highSeverityKeywords.some(k => lower.includes(k))) {
267
+ return 'high';
268
+ }
269
+
270
+ if (mediumSeverityKeywords.some(k => lower.includes(k))) {
271
+ return 'medium';
272
+ }
273
+
274
+ return 'low';
275
+ }
276
+
277
+ // Quick check without full analysis
278
+ quickConflictCheck(code: string): boolean {
279
+ const decisions = this.tier2.getAllDecisions();
280
+
281
+ for (const decision of decisions) {
282
+ if (this.checkDecisionConflict(code, decision)) {
283
+ return true;
284
+ }
285
+ }
286
+
287
+ return false;
288
+ }
289
+ }
@@ -0,0 +1,5 @@
1
+ // Confidence Scoring Module - Phase 8
2
+ export { ConfidenceScorer } from './confidence-scorer.js';
3
+ export { SourceTracker } from './source-tracker.js';
4
+ export { WarningDetector } from './warning-detector.js';
5
+ export { ConflictChecker } from './conflict-checker.js';