code-simplifier 1.0.0 → 1.2.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/README.md +56 -1
- package/bin/code-simplifier.js +73 -1
- package/cypress.config.js +45 -0
- package/jest.config.js +46 -0
- package/lib/ai-auto-fix.js +829 -0
- package/lib/ai-code-review.js +705 -0
- package/lib/ai-knowledge-base.js +757 -0
- package/lib/ai-quality-analyzer.js +1095 -0
- package/lib/ai-refactor-advisor.js +853 -0
- package/lib/ai-trend-analyzer.js +674 -0
- package/lib/auto-fix.js +382 -0
- package/lib/eslint-integration.js +328 -0
- package/lib/git-hooks.js +353 -0
- package/lib/master.js +117 -0
- package/lib/multi-language-analyzer.js +397 -0
- package/lib/ralph-integration.js +541 -0
- package/package.json +87 -61
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AI-Powered Knowledge Base
|
|
5
|
+
* Automatically extracts and manages best practices from code analysis
|
|
6
|
+
* Provides intelligent Q&A and learning materials
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs-extra')
|
|
10
|
+
const path = require('path')
|
|
11
|
+
const chalk = require('chalk')
|
|
12
|
+
const { OpenAI } = require('openai')
|
|
13
|
+
const Anthropic = require('@anthropic-ai/sdk')
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* AI Knowledge Base - Manages best practices, patterns, and learning materials
|
|
17
|
+
*/
|
|
18
|
+
class AIKnowledgeBase {
|
|
19
|
+
constructor(config = {}) {
|
|
20
|
+
this.config = {
|
|
21
|
+
dataDir: config.dataDir || path.join(process.cwd(), 'knowledge-base'),
|
|
22
|
+
casesFile: config.casesFile || 'cases.json',
|
|
23
|
+
patternsFile: config.patternsFile || 'patterns.json',
|
|
24
|
+
minCasesPerWeek: config.minCasesPerWeek || 10,
|
|
25
|
+
maxIterations: config.maxIterations || 50,
|
|
26
|
+
openaiApiKey: config.openaiApiKey || process.env.OPENAI_API_KEY,
|
|
27
|
+
anthropicApiKey: config.anthropicApiKey || process.env.ANTHROPIC_API_KEY,
|
|
28
|
+
...config
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.cases = []
|
|
32
|
+
this.patterns = {}
|
|
33
|
+
this.statistics = {
|
|
34
|
+
totalCases: 0,
|
|
35
|
+
weeklyCases: 0,
|
|
36
|
+
tagAccuracy: 0,
|
|
37
|
+
lastUpdated: null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.openai = this.config.openaiApiKey ? new OpenAI({ apiKey: this.config.openaiApiKey }) : null
|
|
41
|
+
this.anthropic = this.config.anthropicApiKey ? new Anthropic({ apiKey: this.config.anthropicApiKey }) : null
|
|
42
|
+
|
|
43
|
+
this.knowledgeDir = path.join(this.config.dataDir, 'knowledge')
|
|
44
|
+
this.examplesDir = path.join(this.config.dataDir, 'examples')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initialize the knowledge base
|
|
49
|
+
*/
|
|
50
|
+
async initialize() {
|
|
51
|
+
await fs.ensureDir(this.knowledgeDir)
|
|
52
|
+
await fs.ensureDir(this.examplesDir)
|
|
53
|
+
await this.loadKnowledgeBase()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Load knowledge base from files
|
|
58
|
+
*/
|
|
59
|
+
async loadKnowledgeBase() {
|
|
60
|
+
try {
|
|
61
|
+
const casesPath = path.join(this.config.dataDir, this.config.casesFile)
|
|
62
|
+
const patternsPath = path.join(this.config.dataDir, this.config.patternsFile)
|
|
63
|
+
|
|
64
|
+
if (await fs.pathExists(casesPath)) {
|
|
65
|
+
this.cases = await fs.readJson(casesPath)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (await fs.pathExists(patternsPath)) {
|
|
69
|
+
this.patterns = await fs.readJson(patternsPath)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this.updateStatistics()
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error(chalk.red('Error loading knowledge base:'), error.message)
|
|
75
|
+
this.cases = []
|
|
76
|
+
this.patterns = {}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Save knowledge base to files
|
|
82
|
+
*/
|
|
83
|
+
async saveKnowledgeBase() {
|
|
84
|
+
try {
|
|
85
|
+
await fs.ensureDir(this.config.dataDir)
|
|
86
|
+
const casesPath = path.join(this.config.dataDir, this.config.casesFile)
|
|
87
|
+
const patternsPath = path.join(this.config.dataDir, this.config.patternsFile)
|
|
88
|
+
|
|
89
|
+
await fs.writeJson(casesPath, this.cases, { spaces: 2 })
|
|
90
|
+
await fs.writeJson(patternsPath, this.patterns, { spaces: 2 })
|
|
91
|
+
|
|
92
|
+
this.statistics.lastUpdated = new Date().toISOString()
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(chalk.red('Error saving knowledge base:'), error.message)
|
|
95
|
+
// Don't throw, just log the error
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Extract best practices from code analysis results
|
|
101
|
+
*/
|
|
102
|
+
async extractBestPractices(analysisResult, metadata = {}) {
|
|
103
|
+
console.log(chalk.blue('Extracting best practices from analysis...'))
|
|
104
|
+
|
|
105
|
+
const cases = []
|
|
106
|
+
|
|
107
|
+
for (const fileResult of analysisResult.files || []) {
|
|
108
|
+
const issues = fileResult.issues || []
|
|
109
|
+
|
|
110
|
+
for (const issue of issues) {
|
|
111
|
+
if (issue.severity === 'error' || issue.severity === 'warning') {
|
|
112
|
+
const bestPractice = await this.generateBestPractice(issue, fileResult, metadata)
|
|
113
|
+
if (bestPractice) {
|
|
114
|
+
cases.push(bestPractice)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Smart classification and tagging
|
|
121
|
+
for (const caseItem of cases) {
|
|
122
|
+
await this.classifyAndTagCase(caseItem)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Add to knowledge base
|
|
126
|
+
this.cases.push(...cases)
|
|
127
|
+
|
|
128
|
+
// Ensure we meet weekly quota
|
|
129
|
+
await this.ensureWeeklyQuota()
|
|
130
|
+
|
|
131
|
+
await this.saveKnowledgeBase()
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
extracted: cases.length,
|
|
135
|
+
totalCases: this.cases.length,
|
|
136
|
+
weeklyCases: this.statistics.weeklyCases
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Generate best practice from an issue
|
|
142
|
+
*/
|
|
143
|
+
async generateBestPractice(issue, fileResult, metadata) {
|
|
144
|
+
const prompt = `
|
|
145
|
+
Based on the following code issue, generate a comprehensive best practice case:
|
|
146
|
+
|
|
147
|
+
Issue: ${issue.type}
|
|
148
|
+
Description: ${issue.description}
|
|
149
|
+
File: ${fileResult.filePath}
|
|
150
|
+
Language: ${fileResult.language}
|
|
151
|
+
Severity: ${issue.severity}
|
|
152
|
+
Location: Line ${issue.line}
|
|
153
|
+
|
|
154
|
+
Code Context:
|
|
155
|
+
${issue.codeSnippet || 'No code snippet available'}
|
|
156
|
+
|
|
157
|
+
Generate a best practice case in JSON format with:
|
|
158
|
+
1. title: Clear, descriptive title
|
|
159
|
+
2. problem: Detailed explanation of the problem
|
|
160
|
+
3. whyItMatters: Why this issue is important
|
|
161
|
+
4. solution: Step-by-step solution
|
|
162
|
+
5. codeExample: Working code example
|
|
163
|
+
6. tags: Relevant tags (3-5 tags)
|
|
164
|
+
7. category: Main category
|
|
165
|
+
8. language: Programming language
|
|
166
|
+
9. difficulty: beginner/intermediate/advanced
|
|
167
|
+
10. relatedPatterns: Array of related patterns
|
|
168
|
+
11. preventionTips: Tips to prevent this issue
|
|
169
|
+
|
|
170
|
+
Return only valid JSON.
|
|
171
|
+
`
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
const response = await this.generateWithAI(prompt)
|
|
175
|
+
const parsed = JSON.parse(response)
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
id: this.generateCaseId(),
|
|
179
|
+
timestamp: new Date().toISOString(),
|
|
180
|
+
source: 'ai-analysis',
|
|
181
|
+
sourceFile: fileResult.filePath,
|
|
182
|
+
...parsed,
|
|
183
|
+
metadata: {
|
|
184
|
+
originalIssue: issue,
|
|
185
|
+
fileLanguage: fileResult.language,
|
|
186
|
+
analysisMetadata: metadata
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.warn(chalk.yellow('Could not generate AI case, using template:'), error.message)
|
|
191
|
+
return this.createTemplateCase(issue, fileResult)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Create a template case when AI is not available
|
|
197
|
+
*/
|
|
198
|
+
createTemplateCase(issue, fileResult) {
|
|
199
|
+
return {
|
|
200
|
+
id: this.generateCaseId(),
|
|
201
|
+
timestamp: new Date().toISOString(),
|
|
202
|
+
source: 'template',
|
|
203
|
+
sourceFile: fileResult.filePath,
|
|
204
|
+
title: `${issue.type}: ${issue.description}`,
|
|
205
|
+
problem: issue.description,
|
|
206
|
+
whyItMatters: `This ${issue.severity} issue affects code quality and maintainability.`,
|
|
207
|
+
solution: this.getDefaultSolution(issue.type),
|
|
208
|
+
codeExample: issue.codeSnippet || '// Example code needed',
|
|
209
|
+
tags: this.extractTagsFromIssue(issue),
|
|
210
|
+
category: this.getCategoryFromIssue(issue),
|
|
211
|
+
language: fileResult.language || 'unknown',
|
|
212
|
+
difficulty: 'intermediate',
|
|
213
|
+
relatedPatterns: [],
|
|
214
|
+
preventionTips: ['Follow coding standards', 'Regular code reviews', 'Use linters'],
|
|
215
|
+
metadata: {
|
|
216
|
+
originalIssue: issue,
|
|
217
|
+
fileLanguage: fileResult.language
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Classify and tag a case intelligently
|
|
224
|
+
*/
|
|
225
|
+
async classifyAndTagCase(caseItem) {
|
|
226
|
+
const prompt = `
|
|
227
|
+
Analyze this best practice case and provide smart classification:
|
|
228
|
+
|
|
229
|
+
Title: ${caseItem.title}
|
|
230
|
+
Problem: ${caseItem.problem}
|
|
231
|
+
Solution: ${caseItem.solution}
|
|
232
|
+
|
|
233
|
+
Provide enhanced tags (3-5 additional tags) and category refinements.
|
|
234
|
+
Focus on: design patterns, anti-patterns, best practices, language-specific idioms.
|
|
235
|
+
|
|
236
|
+
Return JSON with:
|
|
237
|
+
{
|
|
238
|
+
"enhancedTags": ["tag1", "tag2", "tag3"],
|
|
239
|
+
"confidence": 0.95,
|
|
240
|
+
"patternTypes": ["pattern1", "pattern2"]
|
|
241
|
+
}
|
|
242
|
+
`
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
const response = await this.generateWithAI(prompt)
|
|
246
|
+
const parsed = JSON.parse(response)
|
|
247
|
+
|
|
248
|
+
caseItem.tags = [...new Set([...caseItem.tags, ...parsed.enhancedTags])]
|
|
249
|
+
caseItem.patternTypes = parsed.patternTypes
|
|
250
|
+
caseItem.classificationConfidence = parsed.confidence
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.warn(chalk.yellow('Classification failed, using defaults'))
|
|
253
|
+
caseItem.classificationConfidence = 0.7
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Generate learning materials and examples
|
|
259
|
+
*/
|
|
260
|
+
async generateLearningMaterials(caseId) {
|
|
261
|
+
const caseItem = this.cases.find(c => c.id === caseId)
|
|
262
|
+
if (!caseItem) {
|
|
263
|
+
throw new Error(`Case ${caseId} not found`)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const materials = {
|
|
267
|
+
caseId,
|
|
268
|
+
generatedAt: new Date().toISOString(),
|
|
269
|
+
sections: []
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Generate different types of learning materials
|
|
273
|
+
materials.sections.push({
|
|
274
|
+
type: 'explanation',
|
|
275
|
+
title: 'Understanding the Problem',
|
|
276
|
+
content: await this.generateExplanation(caseItem)
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
materials.sections.push({
|
|
280
|
+
type: 'example',
|
|
281
|
+
title: 'Code Example',
|
|
282
|
+
content: await this.generateDetailedExample(caseItem)
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
materials.sections.push({
|
|
286
|
+
type: 'exercise',
|
|
287
|
+
title: 'Practice Exercise',
|
|
288
|
+
content: await this.generateExercise(caseItem)
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
materials.sections.push({
|
|
292
|
+
type: 'related',
|
|
293
|
+
title: 'Related Concepts',
|
|
294
|
+
content: await this.findRelatedConcepts(caseItem)
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
// Save materials
|
|
298
|
+
const materialsPath = path.join(this.knowledgeDir, `${caseId}-materials.md`)
|
|
299
|
+
await fs.writeFile(materialsPath, this.formatMaterialsAsMarkdown(materials))
|
|
300
|
+
|
|
301
|
+
return materials
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Answer questions using natural language
|
|
306
|
+
*/
|
|
307
|
+
async query(question, options = {}) {
|
|
308
|
+
console.log(chalk.blue(`Processing query: "${question}"`))
|
|
309
|
+
|
|
310
|
+
const prompt = `
|
|
311
|
+
Knowledge Base Query: ${question}
|
|
312
|
+
|
|
313
|
+
Available Cases: ${this.cases.length}
|
|
314
|
+
Categories: ${Object.keys(this.patterns).join(', ')}
|
|
315
|
+
|
|
316
|
+
Search through the knowledge base and provide a comprehensive answer.
|
|
317
|
+
Include:
|
|
318
|
+
1. Direct answer to the question
|
|
319
|
+
2. Relevant cases/examples
|
|
320
|
+
3. Best practices
|
|
321
|
+
4. Code snippets when applicable
|
|
322
|
+
5. Related recommendations
|
|
323
|
+
|
|
324
|
+
Format as a helpful, informative response.
|
|
325
|
+
`
|
|
326
|
+
|
|
327
|
+
try {
|
|
328
|
+
const response = await this.generateWithAI(prompt)
|
|
329
|
+
|
|
330
|
+
// Also perform keyword search
|
|
331
|
+
const keywordResults = this.performKeywordSearch(question)
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
question,
|
|
335
|
+
answer: response,
|
|
336
|
+
relevantCases: keywordResults.cases,
|
|
337
|
+
confidence: keywordResults.confidence,
|
|
338
|
+
timestamp: new Date().toISOString()
|
|
339
|
+
}
|
|
340
|
+
} catch (error) {
|
|
341
|
+
console.warn(chalk.yellow('AI query failed, using keyword search'))
|
|
342
|
+
return this.performKeywordSearch(question)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Perform keyword-based search
|
|
348
|
+
*/
|
|
349
|
+
performKeywordSearch(query) {
|
|
350
|
+
const keywords = query.toLowerCase().split(/\s+/)
|
|
351
|
+
const scoredCases = []
|
|
352
|
+
|
|
353
|
+
for (const caseItem of this.cases) {
|
|
354
|
+
let score = 0
|
|
355
|
+
const searchableText = [
|
|
356
|
+
caseItem.title,
|
|
357
|
+
caseItem.problem,
|
|
358
|
+
caseItem.solution,
|
|
359
|
+
...(caseItem.tags || [])
|
|
360
|
+
].join(' ').toLowerCase()
|
|
361
|
+
|
|
362
|
+
for (const keyword of keywords) {
|
|
363
|
+
if (searchableText.includes(keyword)) {
|
|
364
|
+
score += 1
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (score > 0) {
|
|
369
|
+
scoredCases.push({
|
|
370
|
+
...caseItem,
|
|
371
|
+
relevanceScore: score / keywords.length
|
|
372
|
+
})
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
scoredCases.sort((a, b) => b.relevanceScore - a.relevanceScore)
|
|
377
|
+
|
|
378
|
+
return {
|
|
379
|
+
cases: scoredCases.slice(0, 10),
|
|
380
|
+
confidence: scoredCases.length > 0 ? Math.min(scoredCases[0].relevanceScore, 1.0) : 0.0
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Provide related case recommendations
|
|
386
|
+
*/
|
|
387
|
+
async getRecommendations(caseId, limit = 5) {
|
|
388
|
+
const caseItem = this.cases.find(c => c.id === caseId)
|
|
389
|
+
if (!caseItem) {
|
|
390
|
+
return []
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const recommendations = []
|
|
394
|
+
|
|
395
|
+
for (const otherCase of this.cases) {
|
|
396
|
+
if (otherCase.id === caseId) continue
|
|
397
|
+
|
|
398
|
+
let similarity = 0
|
|
399
|
+
|
|
400
|
+
// Check tag overlap
|
|
401
|
+
const commonTags = (caseItem.tags || []).filter(tag =>
|
|
402
|
+
(otherCase.tags || []).includes(tag)
|
|
403
|
+
)
|
|
404
|
+
similarity += commonTags.length * 0.3
|
|
405
|
+
|
|
406
|
+
// Check category match
|
|
407
|
+
if (caseItem.category === otherCase.category) {
|
|
408
|
+
similarity += 0.4
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Check language match
|
|
412
|
+
if (caseItem.language === otherCase.language) {
|
|
413
|
+
similarity += 0.2
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Check pattern type match
|
|
417
|
+
const commonPatterns = (caseItem.patternTypes || []).filter(pattern =>
|
|
418
|
+
(otherCase.patternTypes || []).includes(pattern)
|
|
419
|
+
)
|
|
420
|
+
similarity += commonPatterns.length * 0.1
|
|
421
|
+
|
|
422
|
+
if (similarity > 0) {
|
|
423
|
+
recommendations.push({
|
|
424
|
+
...otherCase,
|
|
425
|
+
similarityScore: similarity,
|
|
426
|
+
commonTags,
|
|
427
|
+
commonPatterns
|
|
428
|
+
})
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
recommendations.sort((a, b) => b.similarityScore - a.similarityScore)
|
|
433
|
+
|
|
434
|
+
return recommendations.slice(0, limit)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Ensure minimum weekly case quota
|
|
439
|
+
*/
|
|
440
|
+
async ensureWeeklyQuota() {
|
|
441
|
+
const oneWeekAgo = new Date()
|
|
442
|
+
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7)
|
|
443
|
+
|
|
444
|
+
const recentCases = this.cases.filter(c =>
|
|
445
|
+
new Date(c.timestamp) > oneWeekAgo
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
this.statistics.weeklyCases = recentCases.length
|
|
449
|
+
|
|
450
|
+
if (recentCases.length < this.config.minCasesPerWeek) {
|
|
451
|
+
console.log(chalk.yellow(`Weekly quota not met. Extracting ${this.config.minCasesPerWeek - recentCases.length} more cases...`))
|
|
452
|
+
|
|
453
|
+
// This would typically trigger additional analysis or extraction
|
|
454
|
+
// For now, we'll mark it in statistics
|
|
455
|
+
this.statistics.quotaStatus = 'needs-attention'
|
|
456
|
+
} else {
|
|
457
|
+
this.statistics.quotaStatus = 'met'
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Update statistics
|
|
463
|
+
*/
|
|
464
|
+
updateStatistics() {
|
|
465
|
+
this.statistics.totalCases = this.cases.length
|
|
466
|
+
|
|
467
|
+
const oneWeekAgo = new Date()
|
|
468
|
+
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7)
|
|
469
|
+
|
|
470
|
+
const recentCases = this.cases.filter(c =>
|
|
471
|
+
new Date(c.timestamp) > oneWeekAgo
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
this.statistics.weeklyCases = recentCases.length
|
|
475
|
+
|
|
476
|
+
// Calculate tag accuracy (mock implementation)
|
|
477
|
+
const classifiedCases = this.cases.filter(c => c.classificationConfidence)
|
|
478
|
+
if (classifiedCases.length > 0) {
|
|
479
|
+
const avgConfidence = classifiedCases.reduce((sum, c) =>
|
|
480
|
+
sum + (c.classificationConfidence || 0), 0
|
|
481
|
+
) / classifiedCases.length
|
|
482
|
+
this.statistics.tagAccuracy = avgConfidence * 100
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Generate with AI (OpenAI or Anthropic)
|
|
488
|
+
*/
|
|
489
|
+
async generateWithAI(prompt) {
|
|
490
|
+
// Try OpenAI first
|
|
491
|
+
if (this.openai) {
|
|
492
|
+
try {
|
|
493
|
+
const response = await this.openai.chat.completions.create({
|
|
494
|
+
model: 'gpt-4',
|
|
495
|
+
messages: [{ role: 'user', content: prompt }],
|
|
496
|
+
temperature: 0.7,
|
|
497
|
+
max_tokens: 2000
|
|
498
|
+
})
|
|
499
|
+
return response.choices[0].message.content
|
|
500
|
+
} catch (error) {
|
|
501
|
+
console.warn(chalk.yellow('OpenAI failed, trying Anthropic...'))
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Try Anthropic
|
|
506
|
+
if (this.anthropic) {
|
|
507
|
+
try {
|
|
508
|
+
const response = await this.anthropic.messages.create({
|
|
509
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
510
|
+
max_tokens: 2000,
|
|
511
|
+
messages: [{ role: 'user', content: prompt }]
|
|
512
|
+
})
|
|
513
|
+
return response.content[0].text
|
|
514
|
+
} catch (error) {
|
|
515
|
+
console.warn(chalk.yellow('Anthropic failed, using mock mode'))
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Mock mode
|
|
520
|
+
return this.generateMockResponse(prompt)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Generate mock response for testing
|
|
525
|
+
*/
|
|
526
|
+
generateMockResponse(prompt) {
|
|
527
|
+
if (prompt.includes('best practice case')) {
|
|
528
|
+
return JSON.stringify({
|
|
529
|
+
title: 'Code Quality Best Practice',
|
|
530
|
+
problem: 'This is a mock problem description',
|
|
531
|
+
whyItMatters: 'Quality matters for maintainability',
|
|
532
|
+
solution: 'Follow best practices and coding standards',
|
|
533
|
+
codeExample: '// Example code here',
|
|
534
|
+
tags: ['best-practice', 'quality'],
|
|
535
|
+
category: 'best-practices',
|
|
536
|
+
language: 'javascript',
|
|
537
|
+
difficulty: 'intermediate',
|
|
538
|
+
relatedPatterns: ['clean-code'],
|
|
539
|
+
preventionTips: ['Use linters', 'Code reviews']
|
|
540
|
+
})
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (prompt.includes('enhanced tags')) {
|
|
544
|
+
return JSON.stringify({
|
|
545
|
+
enhancedTags: ['refactoring', 'clean-code'],
|
|
546
|
+
confidence: 0.85,
|
|
547
|
+
patternTypes: ['extract-method', 'rename-variable']
|
|
548
|
+
})
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return 'This is a mock AI response for testing purposes.'
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Generate explanation for learning materials
|
|
556
|
+
*/
|
|
557
|
+
async generateExplanation(caseItem) {
|
|
558
|
+
return `
|
|
559
|
+
## Understanding ${caseItem.title}
|
|
560
|
+
|
|
561
|
+
### The Problem
|
|
562
|
+
${caseItem.problem}
|
|
563
|
+
|
|
564
|
+
### Why It Matters
|
|
565
|
+
${caseItem.whyItMatters}
|
|
566
|
+
|
|
567
|
+
### Impact
|
|
568
|
+
- Affects code maintainability
|
|
569
|
+
- Increases technical debt
|
|
570
|
+
- Makes debugging harder
|
|
571
|
+
- Reduces team productivity
|
|
572
|
+
|
|
573
|
+
### Best Practices
|
|
574
|
+
${caseItem.preventionTips.map(tip => `- ${tip}`).join('\n')}
|
|
575
|
+
`.trim()
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Generate detailed example
|
|
580
|
+
*/
|
|
581
|
+
async generateDetailedExample(caseItem) {
|
|
582
|
+
return `
|
|
583
|
+
## Code Example (${caseItem.language})
|
|
584
|
+
|
|
585
|
+
### Bad Example
|
|
586
|
+
\`\`\`${caseItem.language}
|
|
587
|
+
${caseItem.codeExample}
|
|
588
|
+
\`\`\`
|
|
589
|
+
|
|
590
|
+
### Good Example
|
|
591
|
+
\`\`\`${caseItem.language}
|
|
592
|
+
// Refactored code following best practices
|
|
593
|
+
// This demonstrates the solution
|
|
594
|
+
`.trim()
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Generate practice exercise
|
|
599
|
+
*/
|
|
600
|
+
async generateExercise(caseItem) {
|
|
601
|
+
return `
|
|
602
|
+
## Practice Exercise
|
|
603
|
+
|
|
604
|
+
### Task
|
|
605
|
+
Refactor the following code to address the ${caseItem.title} issue.
|
|
606
|
+
|
|
607
|
+
### Hints
|
|
608
|
+
- Consider the single responsibility principle
|
|
609
|
+
- Follow naming conventions
|
|
610
|
+
- Keep functions small and focused
|
|
611
|
+
|
|
612
|
+
### Expected Outcome
|
|
613
|
+
- Improved code quality
|
|
614
|
+
- Better maintainability
|
|
615
|
+
- Clearer intent
|
|
616
|
+
`.trim()
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Find related concepts
|
|
621
|
+
*/
|
|
622
|
+
async findRelatedConcepts(caseItem) {
|
|
623
|
+
const related = await this.getRecommendations(caseItem.id, 3)
|
|
624
|
+
return related.map(r => `
|
|
625
|
+
- **${r.title}** (${(r.similarityScore * 100).toFixed(0)}% similar)
|
|
626
|
+
${r.problem.substring(0, 100)}...
|
|
627
|
+
`).join('\n')
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Format materials as Markdown
|
|
632
|
+
*/
|
|
633
|
+
formatMaterialsAsMarkdown(materials) {
|
|
634
|
+
return `# Learning Materials: ${materials.caseId}
|
|
635
|
+
|
|
636
|
+
Generated: ${materials.generatedAt}
|
|
637
|
+
|
|
638
|
+
${materials.sections.map(section => `
|
|
639
|
+
## ${section.title}
|
|
640
|
+
|
|
641
|
+
${section.content}
|
|
642
|
+
`).join('\n')}
|
|
643
|
+
`
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Generate case ID
|
|
648
|
+
*/
|
|
649
|
+
generateCaseId() {
|
|
650
|
+
return `KB-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Get default solution for issue type
|
|
655
|
+
*/
|
|
656
|
+
getDefaultSolution(issueType) {
|
|
657
|
+
const solutions = {
|
|
658
|
+
'longFunction': 'Extract smaller functions with single responsibilities',
|
|
659
|
+
'badVariableNames': 'Use descriptive names that explain purpose',
|
|
660
|
+
'highComplexity': 'Simplify logic and reduce decision points',
|
|
661
|
+
'duplicateCode': 'Extract to a shared function or constant',
|
|
662
|
+
'magicNumbers': 'Replace with named constants',
|
|
663
|
+
'nestedConditionals': 'Use early returns and polymorphism'
|
|
664
|
+
}
|
|
665
|
+
return solutions[issueType] || 'Review and improve code structure'
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Extract tags from issue
|
|
670
|
+
*/
|
|
671
|
+
extractTagsFromIssue(issue) {
|
|
672
|
+
const tags = [issue.type, issue.severity]
|
|
673
|
+
if (issue.category) tags.push(issue.category)
|
|
674
|
+
return tags
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Get category from issue
|
|
679
|
+
*/
|
|
680
|
+
getCategoryFromIssue(issue) {
|
|
681
|
+
return issue.category || 'general'
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Get statistics
|
|
686
|
+
*/
|
|
687
|
+
getStatistics() {
|
|
688
|
+
this.updateStatistics()
|
|
689
|
+
return this.statistics
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Export knowledge base
|
|
694
|
+
*/
|
|
695
|
+
async export(format = 'json') {
|
|
696
|
+
const exportData = {
|
|
697
|
+
cases: this.cases,
|
|
698
|
+
patterns: this.patterns,
|
|
699
|
+
statistics: this.getStatistics(),
|
|
700
|
+
exportedAt: new Date().toISOString()
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if (format === 'json') {
|
|
704
|
+
return JSON.stringify(exportData, null, 2)
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if (format === 'markdown') {
|
|
708
|
+
return this.exportAsMarkdown(exportData)
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
throw new Error(`Unsupported export format: ${format}`)
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Export as Markdown
|
|
716
|
+
*/
|
|
717
|
+
exportAsMarkdown(data) {
|
|
718
|
+
let markdown = `# Knowledge Base Export
|
|
719
|
+
|
|
720
|
+
Generated: ${data.exportedAt}
|
|
721
|
+
Total Cases: ${data.statistics.totalCases}
|
|
722
|
+
Weekly Cases: ${data.statistics.weeklyCases}
|
|
723
|
+
|
|
724
|
+
## Cases
|
|
725
|
+
|
|
726
|
+
`
|
|
727
|
+
|
|
728
|
+
for (const caseItem of data.cases) {
|
|
729
|
+
markdown += `
|
|
730
|
+
### ${caseItem.title}
|
|
731
|
+
|
|
732
|
+
**Category:** ${caseItem.category}
|
|
733
|
+
**Language:** ${caseItem.language}
|
|
734
|
+
**Difficulty:** ${caseItem.difficulty}
|
|
735
|
+
**Tags:** ${caseItem.tags.join(', ')}
|
|
736
|
+
|
|
737
|
+
#### Problem
|
|
738
|
+
${caseItem.problem}
|
|
739
|
+
|
|
740
|
+
#### Solution
|
|
741
|
+
${caseItem.solution}
|
|
742
|
+
|
|
743
|
+
#### Code Example
|
|
744
|
+
\`\`\`${caseItem.language}
|
|
745
|
+
${caseItem.codeExample}
|
|
746
|
+
\`\`\`
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
`
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
return markdown
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
module.exports = AIKnowledgeBase
|