aios-core 4.2.13 → 4.2.15

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 (95) hide show
  1. package/.aios-core/core/code-intel/helpers/dev-helper.js +206 -0
  2. package/.aios-core/core/registry/registry-schema.json +166 -166
  3. package/.aios-core/core/synapse/diagnostics/collectors/hook-collector.js +3 -3
  4. package/.aios-core/data/entity-registry.yaml +27 -0
  5. package/.aios-core/development/scripts/approval-workflow.js +642 -642
  6. package/.aios-core/development/scripts/backup-manager.js +606 -606
  7. package/.aios-core/development/scripts/branch-manager.js +389 -389
  8. package/.aios-core/development/scripts/code-quality-improver.js +1311 -1311
  9. package/.aios-core/development/scripts/commit-message-generator.js +849 -849
  10. package/.aios-core/development/scripts/conflict-resolver.js +674 -674
  11. package/.aios-core/development/scripts/dependency-analyzer.js +637 -637
  12. package/.aios-core/development/scripts/diff-generator.js +351 -351
  13. package/.aios-core/development/scripts/elicitation-engine.js +384 -384
  14. package/.aios-core/development/scripts/elicitation-session-manager.js +299 -299
  15. package/.aios-core/development/scripts/git-wrapper.js +461 -461
  16. package/.aios-core/development/scripts/manifest-preview.js +244 -244
  17. package/.aios-core/development/scripts/metrics-tracker.js +775 -775
  18. package/.aios-core/development/scripts/modification-validator.js +554 -554
  19. package/.aios-core/development/scripts/pattern-learner.js +1224 -1224
  20. package/.aios-core/development/scripts/performance-analyzer.js +757 -757
  21. package/.aios-core/development/scripts/refactoring-suggester.js +1138 -1138
  22. package/.aios-core/development/scripts/rollback-handler.js +530 -530
  23. package/.aios-core/development/scripts/security-checker.js +358 -358
  24. package/.aios-core/development/scripts/template-engine.js +239 -239
  25. package/.aios-core/development/scripts/template-validator.js +278 -278
  26. package/.aios-core/development/scripts/test-generator.js +843 -843
  27. package/.aios-core/development/scripts/transaction-manager.js +589 -589
  28. package/.aios-core/development/scripts/usage-tracker.js +673 -673
  29. package/.aios-core/development/scripts/validate-filenames.js +226 -226
  30. package/.aios-core/development/scripts/version-tracker.js +526 -526
  31. package/.aios-core/development/scripts/yaml-validator.js +396 -396
  32. package/.aios-core/development/tasks/build-autonomous.md +10 -4
  33. package/.aios-core/development/tasks/create-service.md +23 -0
  34. package/.aios-core/development/tasks/dev-develop-story.md +12 -6
  35. package/.aios-core/development/tasks/dev-suggest-refactoring.md +7 -1
  36. package/.aios-core/development/tasks/publish-npm.md +3 -3
  37. package/.aios-core/hooks/unified/README.md +1 -1
  38. package/.aios-core/install-manifest.yaml +65 -61
  39. package/.aios-core/manifests/schema/manifest-schema.json +190 -190
  40. package/.aios-core/product/templates/component-react-tmpl.tsx +98 -98
  41. package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -102
  42. package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -205
  43. package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -175
  44. package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -175
  45. package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -300
  46. package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -152
  47. package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -222
  48. package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -154
  49. package/.aios-core/product/templates/eslintrc-security.json +32 -32
  50. package/.aios-core/product/templates/github-actions-cd.yml +212 -212
  51. package/.aios-core/product/templates/github-actions-ci.yml +172 -172
  52. package/.aios-core/product/templates/shock-report-tmpl.html +502 -502
  53. package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -240
  54. package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -233
  55. package/.aios-core/scripts/migrate-framework-docs.sh +300 -300
  56. package/README.en.md +747 -0
  57. package/README.md +4 -2
  58. package/bin/aios.js +7 -4
  59. package/package.json +1 -1
  60. package/packages/aios-pro-cli/src/recover.js +1 -1
  61. package/packages/installer/src/wizard/ide-config-generator.js +6 -6
  62. package/packages/installer/src/wizard/pro-setup.js +3 -3
  63. package/pro/license/degradation.js +220 -220
  64. package/pro/license/errors.js +450 -450
  65. package/pro/license/feature-gate.js +354 -354
  66. package/pro/license/index.js +181 -181
  67. package/pro/license/license-cache.js +523 -523
  68. package/pro/license/license-crypto.js +303 -303
  69. package/scripts/package-synapse.js +5 -5
  70. package/scripts/validate-package-completeness.js +3 -3
  71. package/.aios-core/.session/current-session.json +0 -14
  72. package/.aios-core/data/registry-update-log.jsonl +0 -191
  73. package/.aios-core/docs/SHARD-TRANSLATION-GUIDE.md +0 -335
  74. package/.aios-core/docs/component-creation-guide.md +0 -458
  75. package/.aios-core/docs/session-update-pattern.md +0 -307
  76. package/.aios-core/docs/standards/AIOS-FRAMEWORK-MASTER.md +0 -1963
  77. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-SUMMARY.md +0 -1190
  78. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1.md +0 -439
  79. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO.md +0 -5398
  80. package/.aios-core/docs/standards/V3-ARCHITECTURAL-DECISIONS.md +0 -523
  81. package/.aios-core/docs/template-syntax.md +0 -267
  82. package/.aios-core/docs/troubleshooting-guide.md +0 -625
  83. package/.aios-core/infrastructure/tests/utilities-audit-results.json +0 -501
  84. package/.aios-core/manifests/agents.csv +0 -29
  85. package/.aios-core/manifests/tasks.csv +0 -198
  86. package/.aios-core/manifests/workers.csv +0 -204
  87. package/.claude/rules/agent-authority.md +0 -105
  88. package/.claude/rules/coderabbit-integration.md +0 -93
  89. package/.claude/rules/ids-principles.md +0 -112
  90. package/.claude/rules/story-lifecycle.md +0 -139
  91. package/.claude/rules/workflow-execution.md +0 -150
  92. package/scripts/glue/README.md +0 -355
  93. package/scripts/glue/compose-agent-prompt.cjs +0 -362
  94. /package/.claude/hooks/{precompact-session-digest.js → precompact-session-digest.cjs} +0 -0
  95. /package/.claude/hooks/{synapse-engine.js → synapse-engine.cjs} +0 -0
@@ -1,1225 +1,1225 @@
1
- const fs = require('fs').promises;
2
- const path = require('path');
3
- const chalk = require('chalk');
4
- const EventEmitter = require('events');
5
-
6
- /**
7
- * Pattern learning system for successful modifications
8
- * Learns from successful modifications to suggest improvements and automate common patterns
9
- */
10
- class PatternLearner extends EventEmitter {
11
- constructor(options = {}) {
12
- super();
13
- this.rootPath = options.rootPath || process.cwd();
14
- this.patternsDir = path.join(this.rootPath, '.aios', 'patterns');
15
- this.historyFile = path.join(this.patternsDir, 'modification_history.json');
16
- this.patternsFile = path.join(this.patternsDir, 'learned_patterns.json');
17
- this.patterns = new Map();
18
- this.modificationHistory = [];
19
- this.learningThreshold = options.learningThreshold || 3; // Minimum occurrences to learn pattern
20
- this.similarityThreshold = options.similarityThreshold || 0.8; // 80% similarity
21
- }
22
-
23
- /**
24
- * Initialize pattern learner
25
- */
26
- async initialize() {
27
- await fs.mkdir(this.patternsDir, { recursive: true });
28
- await this.loadHistory();
29
- await this.loadPatterns();
30
- console.log(chalk.green('✅ Pattern learner initialized'));
31
- }
32
-
33
- /**
34
- * Record successful modification for learning
35
- */
36
- async recordSuccessfulModification(modification) {
37
- const record = {
38
- id: `mod-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`,
39
- timestamp: new Date().toISOString(),
40
- componentType: modification.componentType,
41
- modificationType: modification.modificationType,
42
- patterns: await this.extractPatterns(modification),
43
- outcomes: {
44
- success: true,
45
- metrics: modification.metrics || {},
46
- improvements: modification.improvements || []
47
- },
48
- metadata: {
49
- author: modification.author || process.env.USER || 'unknown',
50
- duration: modification.duration,
51
- complexity: modification.complexity
52
- }
53
- };
54
-
55
- // Add to history
56
- this.modificationHistory.push(record);
57
-
58
- // Learn from this modification
59
- await this.learnFromModification(record);
60
-
61
- // Save updated history
62
- await this.saveHistory();
63
-
64
- // Emit event for real-time learning
65
- this.emit('modification_recorded', record);
66
-
67
- console.log(chalk.green(`✅ Recorded successful modification: ${record.id}`));
68
-
69
- return {
70
- recordId: record.id,
71
- patternsExtracted: record.patterns.length,
72
- learningTriggered: await this.checkLearningThreshold(record.patterns)
73
- };
74
- }
75
-
76
- /**
77
- * Extract patterns from modification
78
- */
79
- async extractPatterns(modification) {
80
- const patterns = [];
81
-
82
- // Code change patterns
83
- if (modification.codeChanges) {
84
- patterns.push(...this.extractCodePatterns(modification.codeChanges));
85
- }
86
-
87
- // Structural patterns
88
- if (modification.structuralChanges) {
89
- patterns.push(...this.extractStructuralPatterns(modification.structuralChanges));
90
- }
91
-
92
- // Refactoring patterns
93
- if (modification.refactoringType) {
94
- patterns.push(...this.extractRefactoringPatterns(modification));
95
- }
96
-
97
- // Dependency patterns
98
- if (modification.dependencyChanges) {
99
- patterns.push(...this.extractDependencyPatterns(modification.dependencyChanges));
100
- }
101
-
102
- // Performance patterns
103
- if (modification.performanceImprovements) {
104
- patterns.push(...this.extractPerformancePatterns(modification.performanceImprovements));
105
- }
106
-
107
- return patterns;
108
- }
109
-
110
- /**
111
- * Extract code change patterns
112
- */
113
- extractCodePatterns(codeChanges) {
114
- const patterns = [];
115
-
116
- for (const change of codeChanges) {
117
- // Function transformation patterns
118
- if (change.type === 'function_transformation') {
119
- patterns.push({
120
- type: 'code_transformation',
121
- subtype: 'function',
122
- from: this.normalizeCode(change.before),
123
- to: this.normalizeCode(change.after),
124
- context: change.context,
125
- benefits: change.benefits || []
126
- });
127
- }
128
-
129
- // Error handling patterns
130
- if (change.type === 'error_handling') {
131
- patterns.push({
132
- type: 'error_handling',
133
- subtype: change.handlingType,
134
- pattern: change.pattern,
135
- improvement: change.improvement
136
- });
137
- }
138
-
139
- // Async/await patterns
140
- if (change.type === 'async_transformation') {
141
- patterns.push({
142
- type: 'async_pattern',
143
- from: change.callbackPattern,
144
- to: change.asyncPattern,
145
- complexity_reduction: change.complexityReduction
146
- });
147
- }
148
-
149
- // API usage patterns
150
- if (change.type === 'api_improvement') {
151
- patterns.push({
152
- type: 'api_usage',
153
- oldPattern: change.oldUsage,
154
- newPattern: change.newUsage,
155
- benefits: change.benefits
156
- });
157
- }
158
- }
159
-
160
- return patterns;
161
- }
162
-
163
- /**
164
- * Extract structural patterns
165
- */
166
- extractStructuralPatterns(structuralChanges) {
167
- const patterns = [];
168
-
169
- for (const change of structuralChanges) {
170
- patterns.push({
171
- type: 'structural',
172
- changeType: change.type,
173
- pattern: {
174
- before: change.beforeStructure,
175
- after: change.afterStructure
176
- },
177
- benefits: {
178
- modularity: change.modularityImprovement || 0,
179
- maintainability: change.maintainabilityImprovement || 0,
180
- testability: change.testabilityImprovement || 0
181
- }
182
- });
183
- }
184
-
185
- return patterns;
186
- }
187
-
188
- /**
189
- * Extract refactoring patterns
190
- */
191
- extractRefactoringPatterns(modification) {
192
- const patterns = [];
193
-
194
- patterns.push({
195
- type: 'refactoring',
196
- refactoringType: modification.refactoringType,
197
- triggers: modification.triggers || [],
198
- steps: modification.steps || [],
199
- validation: modification.validation || {},
200
- benefits: modification.measuredBenefits || {}
201
- });
202
-
203
- return patterns;
204
- }
205
-
206
- /**
207
- * Extract dependency patterns
208
- */
209
- extractDependencyPatterns(dependencyChanges) {
210
- const patterns = [];
211
-
212
- for (const change of dependencyChanges) {
213
- if (change.type === 'consolidation') {
214
- patterns.push({
215
- type: 'dependency_consolidation',
216
- from: change.originalDependencies,
217
- to: change.consolidatedDependency,
218
- reduction: change.dependencyReduction
219
- });
220
- }
221
-
222
- if (change.type === 'upgrade') {
223
- patterns.push({
224
- type: 'dependency_upgrade',
225
- dependency: change.dependency,
226
- fromVersion: change.fromVersion,
227
- toVersion: change.toVersion,
228
- migrationSteps: change.migrationSteps
229
- });
230
- }
231
- }
232
-
233
- return patterns;
234
- }
235
-
236
- /**
237
- * Extract performance patterns
238
- */
239
- extractPerformancePatterns(performanceImprovements) {
240
- const patterns = [];
241
-
242
- for (const improvement of performanceImprovements) {
243
- patterns.push({
244
- type: 'performance',
245
- optimizationType: improvement.type,
246
- technique: improvement.technique,
247
- metrics: {
248
- before: improvement.metricsBefore,
249
- after: improvement.metricsAfter,
250
- improvement: improvement.percentageImprovement
251
- },
252
- applicableContexts: improvement.contexts || []
253
- });
254
- }
255
-
256
- return patterns;
257
- }
258
-
259
- /**
260
- * Learn from modification
261
- */
262
- async learnFromModification(record) {
263
- for (const pattern of record.patterns) {
264
- const patternKey = this.generatePatternKey(pattern);
265
-
266
- // Check if similar pattern exists
267
- const similarPattern = await this.findSimilarPattern(pattern);
268
-
269
- if (similarPattern) {
270
- // Update existing pattern
271
- await this.updatePattern(similarPattern, pattern, record);
272
- } else {
273
- // Create new pattern entry
274
- await this.createPattern(patternKey, pattern, record);
275
- }
276
- }
277
-
278
- // Analyze cross-pattern relationships
279
- await this.analyzePatternRelationships(record.patterns);
280
-
281
- // Update pattern rankings
282
- await this.updatePatternRankings();
283
- }
284
-
285
- /**
286
- * Find similar pattern
287
- */
288
- async findSimilarPattern(pattern) {
289
- for (const [key, existingPattern] of this.patterns) {
290
- const similarity = await this.calculatePatternSimilarity(pattern, existingPattern);
291
-
292
- if (similarity >= this.similarityThreshold) {
293
- return { key, pattern: existingPattern, similarity };
294
- }
295
- }
296
-
297
- return null;
298
- }
299
-
300
- /**
301
- * Calculate pattern similarity
302
- */
303
- async calculatePatternSimilarity(pattern1, pattern2) {
304
- // Type must match
305
- if (pattern1.type !== pattern2.type) return 0;
306
-
307
- let similarity = 0;
308
- let factors = 0;
309
-
310
- // Type-specific similarity calculation
311
- switch (pattern1.type) {
312
- case 'code_transformation':
313
- similarity += this.calculateCodeSimilarity(pattern1, pattern2) * 0.7;
314
- similarity += this.calculateContextSimilarity(pattern1.context, pattern2.context) * 0.3;
315
- factors = 1;
316
- break;
317
-
318
- case 'structural':
319
- similarity += this.calculateStructuralSimilarity(pattern1.pattern, pattern2.pattern) * 0.6;
320
- similarity += this.calculateBenefitSimilarity(pattern1.benefits, pattern2.benefits) * 0.4;
321
- factors = 1;
322
- break;
323
-
324
- case 'refactoring':
325
- similarity += this.calculateRefactoringSimilarity(pattern1, pattern2);
326
- factors = 1;
327
- break;
328
-
329
- case 'performance':
330
- similarity += this.calculatePerformanceSimilarity(pattern1, pattern2);
331
- factors = 1;
332
- break;
333
-
334
- default:
335
- // Generic similarity based on pattern structure
336
- similarity = this.calculateGenericSimilarity(pattern1, pattern2);
337
- factors = 1;
338
- }
339
-
340
- return factors > 0 ? similarity / factors : 0;
341
- }
342
-
343
- /**
344
- * Calculate code similarity
345
- */
346
- calculateCodeSimilarity(pattern1, pattern2) {
347
- const from1 = this.tokenizeCode(pattern1.from);
348
- const from2 = this.tokenizeCode(pattern2.from);
349
- const to1 = this.tokenizeCode(pattern1.to);
350
- const to2 = this.tokenizeCode(pattern2.to);
351
-
352
- const fromSimilarity = this.calculateTokenSimilarity(from1, from2);
353
- const toSimilarity = this.calculateTokenSimilarity(to1, to2);
354
-
355
- return (fromSimilarity + toSimilarity) / 2;
356
- }
357
-
358
- /**
359
- * Tokenize code for comparison
360
- */
361
- tokenizeCode(code) {
362
- if (!code) return [];
363
-
364
- // Simple tokenization - can be enhanced with proper AST parsing
365
- return code
366
- .replace(/\s+/g, ' ')
367
- .replace(/[{}();,]/g, ' $& ')
368
- .split(/\s+/)
369
- .filter(token => token.length > 0);
370
- }
371
-
372
- /**
373
- * Calculate token similarity
374
- */
375
- calculateTokenSimilarity(tokens1, tokens2) {
376
- const set1 = new Set(tokens1);
377
- const set2 = new Set(tokens2);
378
-
379
- const intersection = new Set([...set1].filter(x => set2.has(x)));
380
- const union = new Set([...set1, ...set2]);
381
-
382
- return union.size > 0 ? intersection.size / union.size : 0;
383
- }
384
-
385
- /**
386
- * Update existing pattern
387
- */
388
- async updatePattern(similarPattern, newPattern, record) {
389
- const existingPattern = similarPattern.pattern;
390
-
391
- // Update occurrence count
392
- existingPattern.occurrences = (existingPattern.occurrences || 0) + 1;
393
-
394
- // Update success rate
395
- existingPattern.successCount = (existingPattern.successCount || 0) + 1;
396
- existingPattern.successRate = existingPattern.successCount / existingPattern.occurrences;
397
-
398
- // Merge benefits/improvements
399
- if (newPattern.benefits) {
400
- existingPattern.aggregatedBenefits = this.aggregateBenefits(
401
- existingPattern.aggregatedBenefits || {},
402
- newPattern.benefits
403
- );
404
- }
405
-
406
- // Add to usage history
407
- if (!existingPattern.usageHistory) {
408
- existingPattern.usageHistory = [];
409
- }
410
- existingPattern.usageHistory.push({
411
- recordId: record.id,
412
- timestamp: record.timestamp,
413
- author: record.metadata.author,
414
- outcomes: record.outcomes
415
- });
416
-
417
- // Update confidence score
418
- existingPattern.confidence = this.calculatePatternConfidence(existingPattern);
419
-
420
- // Check if pattern should be promoted
421
- if (existingPattern.occurrences >= this.learningThreshold && existingPattern.confidence > 0.8) {
422
- existingPattern.status = 'learned';
423
- existingPattern.learnedAt = new Date().toISOString();
424
-
425
- console.log(chalk.green(`✅ Pattern promoted to learned: ${similarPattern.key}`));
426
- this.emit('pattern_learned', existingPattern);
427
- }
428
- }
429
-
430
- /**
431
- * Create new pattern
432
- */
433
- async createPattern(key, pattern, record) {
434
- const newPattern = {
435
- ...pattern,
436
- key: key,
437
- occurrences: 1,
438
- successCount: 1,
439
- successRate: 1.0,
440
- firstSeen: record.timestamp,
441
- lastSeen: record.timestamp,
442
- status: 'candidate',
443
- confidence: 0.3, // Initial low confidence
444
- usageHistory: [{
445
- recordId: record.id,
446
- timestamp: record.timestamp,
447
- author: record.metadata.author,
448
- outcomes: record.outcomes
449
- }]
450
- };
451
-
452
- this.patterns.set(key, newPattern);
453
-
454
- console.log(chalk.gray(`New pattern candidate created: ${key}`));
455
- }
456
-
457
- /**
458
- * Calculate pattern confidence
459
- */
460
- calculatePatternConfidence(pattern) {
461
- let confidence = 0;
462
-
463
- // Occurrence factor (up to 0.3)
464
- const occurrenceFactor = Math.min(pattern.occurrences / 10, 0.3);
465
- confidence += occurrenceFactor;
466
-
467
- // Success rate factor (up to 0.4)
468
- confidence += pattern.successRate * 0.4;
469
-
470
- // Consistency factor (up to 0.2)
471
- const consistencyFactor = this.calculateConsistencyFactor(pattern.usageHistory);
472
- confidence += consistencyFactor * 0.2;
473
-
474
- // Recency factor (up to 0.1)
475
- const recencyFactor = this.calculateRecencyFactor(pattern.lastSeen);
476
- confidence += recencyFactor * 0.1;
477
-
478
- return Math.min(confidence, 1.0);
479
- }
480
-
481
- /**
482
- * Get pattern suggestions for modification
483
- */
484
- async getPatternSuggestions(_context) {
485
- const suggestions = [];
486
-
487
- // Filter applicable patterns
488
- const applicablePatterns = Array.from(this.patterns.values()).filter(pattern => {
489
- return pattern.status === 'learned' &&
490
- this.isPatternApplicable(pattern, context) &&
491
- pattern.confidence > 0.7;
492
- });
493
-
494
- // Sort by relevance and confidence
495
- applicablePatterns.sort((a, b) => {
496
- const relevanceA = this.calculateRelevance(a, context);
497
- const relevanceB = this.calculateRelevance(b, context);
498
- return (relevanceB * b.confidence) - (relevanceA * a.confidence);
499
- });
500
-
501
- // Create suggestions
502
- for (const pattern of applicablePatterns.slice(0, 5)) {
503
- suggestions.push({
504
- pattern: pattern,
505
- relevance: this.calculateRelevance(pattern, context),
506
- confidence: pattern.confidence,
507
- expectedBenefits: pattern.aggregatedBenefits || {},
508
- applicationGuide: await this.generateApplicationGuide(pattern, context),
509
- examples: this.getPatternExamples(pattern)
510
- });
511
- }
512
-
513
- return suggestions;
514
- }
515
-
516
- /**
517
- * Check if pattern is applicable
518
- */
519
- isPatternApplicable(pattern, context) {
520
- // Check component type compatibility
521
- if (pattern.componentType && context.componentType) {
522
- if (pattern.componentType !== context.componentType && pattern.componentType !== 'any') {
523
- return false;
524
- }
525
- }
526
-
527
- // Check context requirements
528
- if (pattern.requiredContext) {
529
- for (const requirement of pattern.requiredContext) {
530
- if (!this.meetsContextRequirement(_context, requirement)) {
531
- return false;
532
- }
533
- }
534
- }
535
-
536
- // Check applicability conditions
537
- if (pattern.applicableContexts) {
538
- return pattern.applicableContexts.some(ctx =>
539
- this.matchesContext(_context, ctx)
540
- );
541
- }
542
-
543
- return true;
544
- }
545
-
546
- /**
547
- * Generate application guide
548
- */
549
- async generateApplicationGuide(pattern, context) {
550
- const guide = {
551
- steps: [],
552
- preconditions: [],
553
- expectedOutcome: {},
554
- risks: [],
555
- alternatives: []
556
- };
557
-
558
- // Generate steps based on pattern type
559
- switch (pattern.type) {
560
- case 'code_transformation':
561
- guide.steps = this.generateCodeTransformationSteps(pattern, context);
562
- break;
563
- case 'refactoring':
564
- guide.steps = pattern.steps || [];
565
- guide.preconditions = pattern.triggers || [];
566
- break;
567
- case 'performance':
568
- guide.steps = this.generatePerformanceOptimizationSteps(pattern, context);
569
- guide.expectedOutcome = pattern.metrics;
570
- break;
571
- }
572
-
573
- // Add general guidance
574
- guide.confidence = `${Math.round(pattern.confidence * 100)}%`;
575
- guide.successRate = `${Math.round(pattern.successRate * 100)}%`;
576
- guide.usageCount = pattern.occurrences;
577
-
578
- return guide;
579
- }
580
-
581
- /**
582
- * Analyze pattern relationships
583
- */
584
- async analyzePatternRelationships(patterns) {
585
- // Find patterns that commonly occur together
586
- const coOccurrences = new Map();
587
-
588
- for (let i = 0; i < patterns.length; i++) {
589
- for (let j = i + 1; j < patterns.length; j++) {
590
- const key = this.generateRelationshipKey(patterns[i], patterns[j]);
591
- const existing = coOccurrences.get(key) || { count: 0, patterns: [] };
592
- existing.count++;
593
- existing.patterns = [patterns[i], patterns[j]];
594
- coOccurrences.set(key, existing);
595
- }
596
- }
597
-
598
- // Store significant relationships
599
- for (const [key, relationship] of coOccurrences) {
600
- if (relationship.count >= 2) {
601
- await this.storePatternRelationship(key, relationship);
602
- }
603
- }
604
- }
605
-
606
- /**
607
- * Get pattern analytics
608
- */
609
- async getPatternAnalytics() {
610
- const analytics = {
611
- totalPatterns: this.patterns.size,
612
- learnedPatterns: 0,
613
- candidatePatterns: 0,
614
- patternsByType: {},
615
- topPatterns: [],
616
- recentTrends: [],
617
- effectivenessMetrics: {}
618
- };
619
-
620
- // Count patterns by status and type
621
- for (const pattern of this.patterns.values()) {
622
- if (pattern.status === 'learned') {
623
- analytics.learnedPatterns++;
624
- } else {
625
- analytics.candidatePatterns++;
626
- }
627
-
628
- analytics.patternsByType[pattern.type] =
629
- (analytics.patternsByType[pattern.type] || 0) + 1;
630
- }
631
-
632
- // Get top patterns by usage
633
- const sortedPatterns = Array.from(this.patterns.values())
634
- .sort((a, b) => b.occurrences - a.occurrences);
635
-
636
- analytics.topPatterns = sortedPatterns.slice(0, 10).map(p => ({
637
- key: p.key,
638
- type: p.type,
639
- occurrences: p.occurrences,
640
- successRate: p.successRate,
641
- confidence: p.confidence
642
- }));
643
-
644
- // Calculate effectiveness metrics
645
- analytics.effectivenessMetrics = await this.calculateEffectivenessMetrics();
646
-
647
- // Get recent trends
648
- analytics.recentTrends = await this.analyzeRecentTrends();
649
-
650
- return analytics;
651
- }
652
-
653
- /**
654
- * Calculate effectiveness metrics
655
- */
656
- async calculateEffectivenessMetrics() {
657
- const metrics = {
658
- averageSuccessRate: 0,
659
- averageConfidence: 0,
660
- patternCoverage: 0,
661
- learningRate: 0
662
- };
663
-
664
- const learnedPatterns = Array.from(this.patterns.values())
665
- .filter(p => p.status === 'learned');
666
-
667
- if (learnedPatterns.length > 0) {
668
- metrics.averageSuccessRate = learnedPatterns.reduce((sum, p) =>
669
- sum + p.successRate, 0) / learnedPatterns.length;
670
-
671
- metrics.averageConfidence = learnedPatterns.reduce((sum, p) =>
672
- sum + p.confidence, 0) / learnedPatterns.length;
673
- }
674
-
675
- // Calculate pattern coverage
676
- const modificationTypes = new Set(this.modificationHistory.map(m => m.modificationType));
677
- const coveredTypes = new Set(learnedPatterns.map(p => p.type));
678
- metrics.patternCoverage = modificationTypes.size > 0 ?
679
- coveredTypes.size / modificationTypes.size : 0;
680
-
681
- // Calculate learning rate
682
- const recentHistory = this.modificationHistory.slice(-20);
683
- const recentLearned = recentHistory.filter(m =>
684
- m.patterns.some(p => this.patterns.get(this.generatePatternKey(p))?.status === 'learned')
685
- );
686
- metrics.learningRate = recentHistory.length > 0 ?
687
- recentLearned.length / recentHistory.length : 0;
688
-
689
- return metrics;
690
- }
691
-
692
- /**
693
- * Helper methods
694
- */
695
-
696
- normalizeCode(code) {
697
- if (!code) return '';
698
- return code.trim().replace(/\s+/g, ' ');
699
- }
700
-
701
- generatePatternKey(pattern) {
702
- return `${pattern.type}:${pattern.subtype || 'default'}:${
703
- crypto.createHash('md5').update(JSON.stringify(pattern)).digest('hex').substr(0, 8)
704
- }`;
705
- }
706
-
707
- aggregateBenefits(existing, newBenefits) {
708
- const aggregated = { ...existing };
709
-
710
- for (const [key, value] of Object.entries(newBenefits)) {
711
- if (typeof value === 'number') {
712
- aggregated[key] = (aggregated[key] || 0) + value;
713
- aggregated[`${key}_avg`] = aggregated[key] / ((aggregated[`${key}_count`] || 0) + 1);
714
- aggregated[`${key}_count`] = (aggregated[`${key}_count`] || 0) + 1;
715
- }
716
- }
717
-
718
- return aggregated;
719
- }
720
-
721
- calculateConsistencyFactor(usageHistory) {
722
- if (usageHistory.length < 2) return 1.0;
723
-
724
- // Check time intervals between uses
725
- const intervals = [];
726
- for (let i = 1; i < usageHistory.length; i++) {
727
- const interval = new Date(usageHistory[i].timestamp) - new Date(usageHistory[i-1].timestamp);
728
- intervals.push(interval);
729
- }
730
-
731
- // Calculate variance
732
- const avgInterval = intervals.reduce((sum, i) => sum + i, 0) / intervals.length;
733
- const variance = intervals.reduce((sum, i) => sum + Math.pow(i - avgInterval, 2), 0) / intervals.length;
734
- const stdDev = Math.sqrt(variance);
735
-
736
- // Lower variance = higher consistency
737
- return 1 / (1 + stdDev / avgInterval);
738
- }
739
-
740
- calculateRecencyFactor(lastSeen) {
741
- const daysSinceLastSeen = (Date.now() - new Date(lastSeen).getTime()) / (1000 * 60 * 60 * 24);
742
- return Math.max(0, 1 - daysSinceLastSeen / 30); // Decay over 30 days
743
- }
744
-
745
- calculateRelevance(pattern, context) {
746
- let relevance = 0;
747
-
748
- // Type match
749
- if (pattern.type === context.modificationType) {
750
- relevance += 0.3;
751
- }
752
-
753
- // Component type match
754
- if (pattern.componentType === context.componentType) {
755
- relevance += 0.2;
756
- }
757
-
758
- // Context similarity
759
- if (pattern.context && context.currentContext) {
760
- relevance += this.calculateContextSimilarity(pattern.context, context.currentContext) * 0.3;
761
- }
762
-
763
- // Goal alignment
764
- if (pattern.benefits && context.goals) {
765
- relevance += this.calculateGoalAlignment(pattern.benefits, context.goals) * 0.2;
766
- }
767
-
768
- return relevance;
769
- }
770
-
771
- getPatternExamples(pattern) {
772
- return pattern.usageHistory
773
- .slice(-3)
774
- .map(usage => ({
775
- recordId: usage.recordId,
776
- timestamp: usage.timestamp,
777
- author: usage.author,
778
- outcomes: usage.outcomes
779
- }));
780
- }
781
-
782
- /**
783
- * Save and load methods
784
- */
785
-
786
- async saveHistory() {
787
- await fs.writeFile(
788
- this.historyFile,
789
- JSON.stringify(this.modificationHistory, null, 2)
790
- );
791
- }
792
-
793
- async loadHistory() {
794
- try {
795
- const content = await fs.readFile(this.historyFile, 'utf-8');
796
- this.modificationHistory = JSON.parse(content);
797
- } catch (_error) {
798
- // No history file yet
799
- this.modificationHistory = [];
800
- }
801
- }
802
-
803
- async savePatterns() {
804
- const patternsArray = Array.from(this.patterns.entries()).map(([key, pattern]) => ({
805
- key,
806
- ...pattern
807
- }));
808
-
809
- await fs.writeFile(
810
- this.patternsFile,
811
- JSON.stringify(patternsArray, null, 2)
812
- );
813
- }
814
-
815
- async loadPatterns() {
816
- try {
817
- const content = await fs.readFile(this.patternsFile, 'utf-8');
818
- const patternsArray = JSON.parse(content);
819
-
820
- this.patterns.clear();
821
- for (const pattern of patternsArray) {
822
- this.patterns.set(pattern.key, pattern);
823
- }
824
- } catch (_error) {
825
- // No patterns file yet
826
- }
827
- }
828
-
829
- /**
830
- * Check learning threshold
831
- */
832
- async checkLearningThreshold(patterns) {
833
- let learnedCount = 0;
834
-
835
- for (const pattern of patterns) {
836
- const key = this.generatePatternKey(pattern);
837
- const existing = this.patterns.get(key);
838
-
839
- if (existing && existing.occurrences >= this.learningThreshold) {
840
- learnedCount++;
841
- }
842
- }
843
-
844
- return learnedCount > 0;
845
- }
846
-
847
- calculateContextSimilarity(context1, context2) {
848
- // Simple context similarity - can be enhanced
849
- if (!context1 || !context2) return 0;
850
-
851
- const keys1 = Object.keys(context1);
852
- const keys2 = Object.keys(context2);
853
- const commonKeys = keys1.filter(k => keys2.includes(k));
854
-
855
- if (commonKeys.length === 0) return 0;
856
-
857
- let similarity = commonKeys.length / Math.max(keys1.length, keys2.length);
858
-
859
- // Check value similarity for common keys
860
- for (const key of commonKeys) {
861
- if (context1[key] === context2[key]) {
862
- similarity += 0.1;
863
- }
864
- }
865
-
866
- return Math.min(similarity, 1.0);
867
- }
868
-
869
- calculateStructuralSimilarity(struct1, struct2) {
870
- // Compare structural patterns
871
- if (!struct1 || !struct2) return 0;
872
-
873
- const before1 = JSON.stringify(struct1.before);
874
- const before2 = JSON.stringify(struct2.before);
875
- const after1 = JSON.stringify(struct1.after);
876
- const after2 = JSON.stringify(struct2.after);
877
-
878
- const beforeSim = before1 === before2 ? 1 : 0.5;
879
- const afterSim = after1 === after2 ? 1 : 0.5;
880
-
881
- return (beforeSim + afterSim) / 2;
882
- }
883
-
884
- calculateBenefitSimilarity(benefits1, benefits2) {
885
- if (!benefits1 || !benefits2) return 0;
886
-
887
- const keys1 = Object.keys(benefits1);
888
- const keys2 = Object.keys(benefits2);
889
- const allKeys = new Set([...keys1, ...keys2]);
890
-
891
- let similarity = 0;
892
- for (const key of allKeys) {
893
- if (benefits1[key] && benefits2[key]) {
894
- // Both have the benefit
895
- similarity += 1;
896
- }
897
- }
898
-
899
- return allKeys.size > 0 ? similarity / allKeys.size : 0;
900
- }
901
-
902
- calculateRefactoringSimilarity(refactor1, refactor2) {
903
- if (refactor1.refactoringType !== refactor2.refactoringType) return 0;
904
-
905
- let similarity = 0.5; // Base similarity for same type
906
-
907
- // Compare triggers
908
- if (refactor1.triggers && refactor2.triggers) {
909
- const commonTriggers = refactor1.triggers.filter(t =>
910
- refactor2.triggers.includes(t)
911
- );
912
- similarity += commonTriggers.length / Math.max(refactor1.triggers.length, refactor2.triggers.length) * 0.3;
913
- }
914
-
915
- // Compare steps
916
- if (refactor1.steps && refactor2.steps) {
917
- const stepSimilarity = Math.min(refactor1.steps.length, refactor2.steps.length) /
918
- Math.max(refactor1.steps.length, refactor2.steps.length);
919
- similarity += stepSimilarity * 0.2;
920
- }
921
-
922
- return similarity;
923
- }
924
-
925
- calculatePerformanceSimilarity(perf1, perf2) {
926
- if (perf1.optimizationType !== perf2.optimizationType) return 0;
927
-
928
- let similarity = 0.4; // Base similarity for same type
929
-
930
- if (perf1.technique === perf2.technique) {
931
- similarity += 0.3;
932
- }
933
-
934
- // Compare applicable contexts
935
- if (perf1.applicableContexts && perf2.applicableContexts) {
936
- const commonContexts = perf1.applicableContexts.filter(c =>
937
- perf2.applicableContexts.includes(c)
938
- );
939
- similarity += commonContexts.length / Math.max(perf1.applicableContexts.length, perf2.applicableContexts.length) * 0.3;
940
- }
941
-
942
- return similarity;
943
- }
944
-
945
- calculateGenericSimilarity(pattern1, pattern2) {
946
- // Generic JSON similarity
947
- const json1 = JSON.stringify(pattern1);
948
- const json2 = JSON.stringify(pattern2);
949
-
950
- if (json1 === json2) return 1.0;
951
-
952
- // Calculate Levenshtein distance ratio
953
- const distance = this.levenshteinDistance(json1, json2);
954
- const maxLength = Math.max(json1.length, json2.length);
955
-
956
- return 1 - (distance / maxLength);
957
- }
958
-
959
- levenshteinDistance(str1, str2) {
960
- const matrix = [];
961
-
962
- for (let i = 0; i <= str2.length; i++) {
963
- matrix[i] = [i];
964
- }
965
-
966
- for (let j = 0; j <= str1.length; j++) {
967
- matrix[0][j] = j;
968
- }
969
-
970
- for (let i = 1; i <= str2.length; i++) {
971
- for (let j = 1; j <= str1.length; j++) {
972
- if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
973
- matrix[i][j] = matrix[i - 1][j - 1];
974
- } else {
975
- matrix[i][j] = Math.min(
976
- matrix[i - 1][j - 1] + 1,
977
- matrix[i][j - 1] + 1,
978
- matrix[i - 1][j] + 1
979
- );
980
- }
981
- }
982
- }
983
-
984
- return matrix[str2.length][str1.length];
985
- }
986
-
987
- meetsContextRequirement(_context, requirement) {
988
- // Check if context meets specific requirement
989
- if (requirement.type === 'has_property') {
990
- return context[requirement.property] !== undefined;
991
- }
992
-
993
- if (requirement.type === 'property_value') {
994
- return context[requirement.property] === requirement.value;
995
- }
996
-
997
- if (requirement.type === 'property_range') {
998
- const value = context[requirement.property];
999
- return value >= requirement.min && value <= requirement.max;
1000
- }
1001
-
1002
- return true;
1003
- }
1004
-
1005
- matchesContext(_context, patternContext) {
1006
- // Check if contexts match
1007
- for (const [key, value] of Object.entries(patternContext)) {
1008
- if (context[key] !== value) {
1009
- return false;
1010
- }
1011
- }
1012
- return true;
1013
- }
1014
-
1015
- generateCodeTransformationSteps(pattern, context) {
1016
- const steps = [];
1017
-
1018
- steps.push({
1019
- step: 1,
1020
- action: 'Identify target code pattern',
1021
- description: `Look for code matching: ${pattern.from}`,
1022
- validation: 'Ensure code structure matches the pattern'
1023
- });
1024
-
1025
- steps.push({
1026
- step: 2,
1027
- action: 'Apply transformation',
1028
- description: `Transform to: ${pattern.to}`,
1029
- validation: 'Verify transformation preserves functionality'
1030
- });
1031
-
1032
- if (pattern.context) {
1033
- steps.push({
1034
- step: 3,
1035
- action: 'Validate context',
1036
- description: 'Ensure transformation is appropriate for context',
1037
- validation: pattern.context
1038
- });
1039
- }
1040
-
1041
- steps.push({
1042
- step: 4,
1043
- action: 'Test changes',
1044
- description: 'Run tests to ensure no regression',
1045
- validation: 'All tests pass'
1046
- });
1047
-
1048
- return steps;
1049
- }
1050
-
1051
- generatePerformanceOptimizationSteps(pattern, context) {
1052
- const steps = [];
1053
-
1054
- steps.push({
1055
- step: 1,
1056
- action: 'Measure baseline performance',
1057
- description: 'Capture current performance metrics',
1058
- validation: 'Baseline metrics recorded'
1059
- });
1060
-
1061
- steps.push({
1062
- step: 2,
1063
- action: `Apply ${pattern.technique} optimization`,
1064
- description: pattern.description || 'Apply performance optimization technique',
1065
- validation: 'Optimization applied correctly'
1066
- });
1067
-
1068
- steps.push({
1069
- step: 3,
1070
- action: 'Measure improved performance',
1071
- description: 'Capture post-optimization metrics',
1072
- validation: `Expected improvement: ${pattern.metrics.improvement}%`
1073
- });
1074
-
1075
- steps.push({
1076
- step: 4,
1077
- action: 'Validate functionality',
1078
- description: 'Ensure optimization didn\'t break functionality',
1079
- validation: 'All tests pass'
1080
- });
1081
-
1082
- return steps;
1083
- }
1084
-
1085
- generateRelationshipKey(pattern1, pattern2) {
1086
- const types = [pattern1.type, pattern2.type].sort();
1087
- return `rel:${types.join(':')}`;
1088
- }
1089
-
1090
- async storePatternRelationship(key, relationship) {
1091
- // Store pattern relationships for future analysis
1092
- const relationshipsFile = path.join(this.patternsDir, 'relationships.json');
1093
-
1094
- let relationships = {};
1095
- try {
1096
- const content = await fs.readFile(relationshipsFile, 'utf-8');
1097
- relationships = JSON.parse(content);
1098
- } catch (_error) {
1099
- // No relationships file yet
1100
- }
1101
-
1102
- relationships[key] = relationship;
1103
-
1104
- await fs.writeFile(relationshipsFile, JSON.stringify(relationships, null, 2));
1105
- }
1106
-
1107
- async analyzeRecentTrends() {
1108
- const recentModifications = this.modificationHistory.slice(-30);
1109
- const trends = {
1110
- emergingPatterns: [],
1111
- decliningPatterns: [],
1112
- stablePatterns: []
1113
- };
1114
-
1115
- // Analyze pattern usage over time
1116
- const patternUsage = new Map();
1117
-
1118
- for (const mod of recentModifications) {
1119
- for (const pattern of mod.patterns) {
1120
- const key = this.generatePatternKey(pattern);
1121
- const usage = patternUsage.get(key) || { count: 0, recent: 0 };
1122
- usage.count++;
1123
-
1124
- // Check if in last 10 modifications
1125
- const modIndex = recentModifications.indexOf(mod);
1126
- if (modIndex >= recentModifications.length - 10) {
1127
- usage.recent++;
1128
- }
1129
-
1130
- patternUsage.set(key, usage);
1131
- }
1132
- }
1133
-
1134
- // Classify patterns
1135
- for (const [key, usage] of patternUsage) {
1136
- const pattern = this.patterns.get(key);
1137
- if (!pattern) continue;
1138
-
1139
- const recentRatio = usage.recent / usage.count;
1140
-
1141
- if (recentRatio > 0.6) {
1142
- trends.emergingPatterns.push({
1143
- key: key,
1144
- type: pattern.type,
1145
- trend: 'emerging',
1146
- usage: usage
1147
- });
1148
- } else if (recentRatio < 0.2) {
1149
- trends.decliningPatterns.push({
1150
- key: key,
1151
- type: pattern.type,
1152
- trend: 'declining',
1153
- usage: usage
1154
- });
1155
- } else {
1156
- trends.stablePatterns.push({
1157
- key: key,
1158
- type: pattern.type,
1159
- trend: 'stable',
1160
- usage: usage
1161
- });
1162
- }
1163
- }
1164
-
1165
- return trends;
1166
- }
1167
-
1168
- calculateGoalAlignment(benefits, goals) {
1169
- if (!benefits || !goals) return 0;
1170
-
1171
- let alignment = 0;
1172
- let _matchedGoals = 0;
1173
-
1174
- for (const goal of goals) {
1175
- if (goal.type === 'performance' && benefits.performanceImprovement) {
1176
- alignment += benefits.performanceImprovement > goal.target ? 1 : 0.5;
1177
- matchedGoals++;
1178
- }
1179
-
1180
- if (goal.type === 'maintainability' && benefits.maintainability) {
1181
- alignment += benefits.maintainability > goal.target ? 1 : 0.5;
1182
- matchedGoals++;
1183
- }
1184
-
1185
- if (goal.type === 'testability' && benefits.testability) {
1186
- alignment += benefits.testability > goal.target ? 1 : 0.5;
1187
- matchedGoals++;
1188
- }
1189
- }
1190
-
1191
- return goals.length > 0 ? alignment / goals.length : 0;
1192
- }
1193
-
1194
- async updatePatternRankings() {
1195
- // Update pattern rankings based on multiple factors
1196
- for (const pattern of this.patterns.values()) {
1197
- pattern.ranking = this.calculatePatternRanking(pattern);
1198
- }
1199
-
1200
- // Save updated patterns
1201
- await this.savePatterns();
1202
- }
1203
-
1204
- calculatePatternRanking(pattern) {
1205
- let ranking = 0;
1206
-
1207
- // Success rate (40%)
1208
- ranking += pattern.successRate * 40;
1209
-
1210
- // Usage frequency (30%)
1211
- const usageScore = Math.min(pattern.occurrences / 20, 1);
1212
- ranking += usageScore * 30;
1213
-
1214
- // Confidence (20%)
1215
- ranking += pattern.confidence * 20;
1216
-
1217
- // Recency (10%)
1218
- const recencyScore = this.calculateRecencyFactor(pattern.lastSeen);
1219
- ranking += recencyScore * 10;
1220
-
1221
- return ranking;
1222
- }
1223
- }
1224
-
1
+ const fs = require('fs').promises;
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const EventEmitter = require('events');
5
+
6
+ /**
7
+ * Pattern learning system for successful modifications
8
+ * Learns from successful modifications to suggest improvements and automate common patterns
9
+ */
10
+ class PatternLearner extends EventEmitter {
11
+ constructor(options = {}) {
12
+ super();
13
+ this.rootPath = options.rootPath || process.cwd();
14
+ this.patternsDir = path.join(this.rootPath, '.aios', 'patterns');
15
+ this.historyFile = path.join(this.patternsDir, 'modification_history.json');
16
+ this.patternsFile = path.join(this.patternsDir, 'learned_patterns.json');
17
+ this.patterns = new Map();
18
+ this.modificationHistory = [];
19
+ this.learningThreshold = options.learningThreshold || 3; // Minimum occurrences to learn pattern
20
+ this.similarityThreshold = options.similarityThreshold || 0.8; // 80% similarity
21
+ }
22
+
23
+ /**
24
+ * Initialize pattern learner
25
+ */
26
+ async initialize() {
27
+ await fs.mkdir(this.patternsDir, { recursive: true });
28
+ await this.loadHistory();
29
+ await this.loadPatterns();
30
+ console.log(chalk.green('✅ Pattern learner initialized'));
31
+ }
32
+
33
+ /**
34
+ * Record successful modification for learning
35
+ */
36
+ async recordSuccessfulModification(modification) {
37
+ const record = {
38
+ id: `mod-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`,
39
+ timestamp: new Date().toISOString(),
40
+ componentType: modification.componentType,
41
+ modificationType: modification.modificationType,
42
+ patterns: await this.extractPatterns(modification),
43
+ outcomes: {
44
+ success: true,
45
+ metrics: modification.metrics || {},
46
+ improvements: modification.improvements || []
47
+ },
48
+ metadata: {
49
+ author: modification.author || process.env.USER || 'unknown',
50
+ duration: modification.duration,
51
+ complexity: modification.complexity
52
+ }
53
+ };
54
+
55
+ // Add to history
56
+ this.modificationHistory.push(record);
57
+
58
+ // Learn from this modification
59
+ await this.learnFromModification(record);
60
+
61
+ // Save updated history
62
+ await this.saveHistory();
63
+
64
+ // Emit event for real-time learning
65
+ this.emit('modification_recorded', record);
66
+
67
+ console.log(chalk.green(`✅ Recorded successful modification: ${record.id}`));
68
+
69
+ return {
70
+ recordId: record.id,
71
+ patternsExtracted: record.patterns.length,
72
+ learningTriggered: await this.checkLearningThreshold(record.patterns)
73
+ };
74
+ }
75
+
76
+ /**
77
+ * Extract patterns from modification
78
+ */
79
+ async extractPatterns(modification) {
80
+ const patterns = [];
81
+
82
+ // Code change patterns
83
+ if (modification.codeChanges) {
84
+ patterns.push(...this.extractCodePatterns(modification.codeChanges));
85
+ }
86
+
87
+ // Structural patterns
88
+ if (modification.structuralChanges) {
89
+ patterns.push(...this.extractStructuralPatterns(modification.structuralChanges));
90
+ }
91
+
92
+ // Refactoring patterns
93
+ if (modification.refactoringType) {
94
+ patterns.push(...this.extractRefactoringPatterns(modification));
95
+ }
96
+
97
+ // Dependency patterns
98
+ if (modification.dependencyChanges) {
99
+ patterns.push(...this.extractDependencyPatterns(modification.dependencyChanges));
100
+ }
101
+
102
+ // Performance patterns
103
+ if (modification.performanceImprovements) {
104
+ patterns.push(...this.extractPerformancePatterns(modification.performanceImprovements));
105
+ }
106
+
107
+ return patterns;
108
+ }
109
+
110
+ /**
111
+ * Extract code change patterns
112
+ */
113
+ extractCodePatterns(codeChanges) {
114
+ const patterns = [];
115
+
116
+ for (const change of codeChanges) {
117
+ // Function transformation patterns
118
+ if (change.type === 'function_transformation') {
119
+ patterns.push({
120
+ type: 'code_transformation',
121
+ subtype: 'function',
122
+ from: this.normalizeCode(change.before),
123
+ to: this.normalizeCode(change.after),
124
+ context: change.context,
125
+ benefits: change.benefits || []
126
+ });
127
+ }
128
+
129
+ // Error handling patterns
130
+ if (change.type === 'error_handling') {
131
+ patterns.push({
132
+ type: 'error_handling',
133
+ subtype: change.handlingType,
134
+ pattern: change.pattern,
135
+ improvement: change.improvement
136
+ });
137
+ }
138
+
139
+ // Async/await patterns
140
+ if (change.type === 'async_transformation') {
141
+ patterns.push({
142
+ type: 'async_pattern',
143
+ from: change.callbackPattern,
144
+ to: change.asyncPattern,
145
+ complexity_reduction: change.complexityReduction
146
+ });
147
+ }
148
+
149
+ // API usage patterns
150
+ if (change.type === 'api_improvement') {
151
+ patterns.push({
152
+ type: 'api_usage',
153
+ oldPattern: change.oldUsage,
154
+ newPattern: change.newUsage,
155
+ benefits: change.benefits
156
+ });
157
+ }
158
+ }
159
+
160
+ return patterns;
161
+ }
162
+
163
+ /**
164
+ * Extract structural patterns
165
+ */
166
+ extractStructuralPatterns(structuralChanges) {
167
+ const patterns = [];
168
+
169
+ for (const change of structuralChanges) {
170
+ patterns.push({
171
+ type: 'structural',
172
+ changeType: change.type,
173
+ pattern: {
174
+ before: change.beforeStructure,
175
+ after: change.afterStructure
176
+ },
177
+ benefits: {
178
+ modularity: change.modularityImprovement || 0,
179
+ maintainability: change.maintainabilityImprovement || 0,
180
+ testability: change.testabilityImprovement || 0
181
+ }
182
+ });
183
+ }
184
+
185
+ return patterns;
186
+ }
187
+
188
+ /**
189
+ * Extract refactoring patterns
190
+ */
191
+ extractRefactoringPatterns(modification) {
192
+ const patterns = [];
193
+
194
+ patterns.push({
195
+ type: 'refactoring',
196
+ refactoringType: modification.refactoringType,
197
+ triggers: modification.triggers || [],
198
+ steps: modification.steps || [],
199
+ validation: modification.validation || {},
200
+ benefits: modification.measuredBenefits || {}
201
+ });
202
+
203
+ return patterns;
204
+ }
205
+
206
+ /**
207
+ * Extract dependency patterns
208
+ */
209
+ extractDependencyPatterns(dependencyChanges) {
210
+ const patterns = [];
211
+
212
+ for (const change of dependencyChanges) {
213
+ if (change.type === 'consolidation') {
214
+ patterns.push({
215
+ type: 'dependency_consolidation',
216
+ from: change.originalDependencies,
217
+ to: change.consolidatedDependency,
218
+ reduction: change.dependencyReduction
219
+ });
220
+ }
221
+
222
+ if (change.type === 'upgrade') {
223
+ patterns.push({
224
+ type: 'dependency_upgrade',
225
+ dependency: change.dependency,
226
+ fromVersion: change.fromVersion,
227
+ toVersion: change.toVersion,
228
+ migrationSteps: change.migrationSteps
229
+ });
230
+ }
231
+ }
232
+
233
+ return patterns;
234
+ }
235
+
236
+ /**
237
+ * Extract performance patterns
238
+ */
239
+ extractPerformancePatterns(performanceImprovements) {
240
+ const patterns = [];
241
+
242
+ for (const improvement of performanceImprovements) {
243
+ patterns.push({
244
+ type: 'performance',
245
+ optimizationType: improvement.type,
246
+ technique: improvement.technique,
247
+ metrics: {
248
+ before: improvement.metricsBefore,
249
+ after: improvement.metricsAfter,
250
+ improvement: improvement.percentageImprovement
251
+ },
252
+ applicableContexts: improvement.contexts || []
253
+ });
254
+ }
255
+
256
+ return patterns;
257
+ }
258
+
259
+ /**
260
+ * Learn from modification
261
+ */
262
+ async learnFromModification(record) {
263
+ for (const pattern of record.patterns) {
264
+ const patternKey = this.generatePatternKey(pattern);
265
+
266
+ // Check if similar pattern exists
267
+ const similarPattern = await this.findSimilarPattern(pattern);
268
+
269
+ if (similarPattern) {
270
+ // Update existing pattern
271
+ await this.updatePattern(similarPattern, pattern, record);
272
+ } else {
273
+ // Create new pattern entry
274
+ await this.createPattern(patternKey, pattern, record);
275
+ }
276
+ }
277
+
278
+ // Analyze cross-pattern relationships
279
+ await this.analyzePatternRelationships(record.patterns);
280
+
281
+ // Update pattern rankings
282
+ await this.updatePatternRankings();
283
+ }
284
+
285
+ /**
286
+ * Find similar pattern
287
+ */
288
+ async findSimilarPattern(pattern) {
289
+ for (const [key, existingPattern] of this.patterns) {
290
+ const similarity = await this.calculatePatternSimilarity(pattern, existingPattern);
291
+
292
+ if (similarity >= this.similarityThreshold) {
293
+ return { key, pattern: existingPattern, similarity };
294
+ }
295
+ }
296
+
297
+ return null;
298
+ }
299
+
300
+ /**
301
+ * Calculate pattern similarity
302
+ */
303
+ async calculatePatternSimilarity(pattern1, pattern2) {
304
+ // Type must match
305
+ if (pattern1.type !== pattern2.type) return 0;
306
+
307
+ let similarity = 0;
308
+ let factors = 0;
309
+
310
+ // Type-specific similarity calculation
311
+ switch (pattern1.type) {
312
+ case 'code_transformation':
313
+ similarity += this.calculateCodeSimilarity(pattern1, pattern2) * 0.7;
314
+ similarity += this.calculateContextSimilarity(pattern1.context, pattern2.context) * 0.3;
315
+ factors = 1;
316
+ break;
317
+
318
+ case 'structural':
319
+ similarity += this.calculateStructuralSimilarity(pattern1.pattern, pattern2.pattern) * 0.6;
320
+ similarity += this.calculateBenefitSimilarity(pattern1.benefits, pattern2.benefits) * 0.4;
321
+ factors = 1;
322
+ break;
323
+
324
+ case 'refactoring':
325
+ similarity += this.calculateRefactoringSimilarity(pattern1, pattern2);
326
+ factors = 1;
327
+ break;
328
+
329
+ case 'performance':
330
+ similarity += this.calculatePerformanceSimilarity(pattern1, pattern2);
331
+ factors = 1;
332
+ break;
333
+
334
+ default:
335
+ // Generic similarity based on pattern structure
336
+ similarity = this.calculateGenericSimilarity(pattern1, pattern2);
337
+ factors = 1;
338
+ }
339
+
340
+ return factors > 0 ? similarity / factors : 0;
341
+ }
342
+
343
+ /**
344
+ * Calculate code similarity
345
+ */
346
+ calculateCodeSimilarity(pattern1, pattern2) {
347
+ const from1 = this.tokenizeCode(pattern1.from);
348
+ const from2 = this.tokenizeCode(pattern2.from);
349
+ const to1 = this.tokenizeCode(pattern1.to);
350
+ const to2 = this.tokenizeCode(pattern2.to);
351
+
352
+ const fromSimilarity = this.calculateTokenSimilarity(from1, from2);
353
+ const toSimilarity = this.calculateTokenSimilarity(to1, to2);
354
+
355
+ return (fromSimilarity + toSimilarity) / 2;
356
+ }
357
+
358
+ /**
359
+ * Tokenize code for comparison
360
+ */
361
+ tokenizeCode(code) {
362
+ if (!code) return [];
363
+
364
+ // Simple tokenization - can be enhanced with proper AST parsing
365
+ return code
366
+ .replace(/\s+/g, ' ')
367
+ .replace(/[{}();,]/g, ' $& ')
368
+ .split(/\s+/)
369
+ .filter(token => token.length > 0);
370
+ }
371
+
372
+ /**
373
+ * Calculate token similarity
374
+ */
375
+ calculateTokenSimilarity(tokens1, tokens2) {
376
+ const set1 = new Set(tokens1);
377
+ const set2 = new Set(tokens2);
378
+
379
+ const intersection = new Set([...set1].filter(x => set2.has(x)));
380
+ const union = new Set([...set1, ...set2]);
381
+
382
+ return union.size > 0 ? intersection.size / union.size : 0;
383
+ }
384
+
385
+ /**
386
+ * Update existing pattern
387
+ */
388
+ async updatePattern(similarPattern, newPattern, record) {
389
+ const existingPattern = similarPattern.pattern;
390
+
391
+ // Update occurrence count
392
+ existingPattern.occurrences = (existingPattern.occurrences || 0) + 1;
393
+
394
+ // Update success rate
395
+ existingPattern.successCount = (existingPattern.successCount || 0) + 1;
396
+ existingPattern.successRate = existingPattern.successCount / existingPattern.occurrences;
397
+
398
+ // Merge benefits/improvements
399
+ if (newPattern.benefits) {
400
+ existingPattern.aggregatedBenefits = this.aggregateBenefits(
401
+ existingPattern.aggregatedBenefits || {},
402
+ newPattern.benefits
403
+ );
404
+ }
405
+
406
+ // Add to usage history
407
+ if (!existingPattern.usageHistory) {
408
+ existingPattern.usageHistory = [];
409
+ }
410
+ existingPattern.usageHistory.push({
411
+ recordId: record.id,
412
+ timestamp: record.timestamp,
413
+ author: record.metadata.author,
414
+ outcomes: record.outcomes
415
+ });
416
+
417
+ // Update confidence score
418
+ existingPattern.confidence = this.calculatePatternConfidence(existingPattern);
419
+
420
+ // Check if pattern should be promoted
421
+ if (existingPattern.occurrences >= this.learningThreshold && existingPattern.confidence > 0.8) {
422
+ existingPattern.status = 'learned';
423
+ existingPattern.learnedAt = new Date().toISOString();
424
+
425
+ console.log(chalk.green(`✅ Pattern promoted to learned: ${similarPattern.key}`));
426
+ this.emit('pattern_learned', existingPattern);
427
+ }
428
+ }
429
+
430
+ /**
431
+ * Create new pattern
432
+ */
433
+ async createPattern(key, pattern, record) {
434
+ const newPattern = {
435
+ ...pattern,
436
+ key: key,
437
+ occurrences: 1,
438
+ successCount: 1,
439
+ successRate: 1.0,
440
+ firstSeen: record.timestamp,
441
+ lastSeen: record.timestamp,
442
+ status: 'candidate',
443
+ confidence: 0.3, // Initial low confidence
444
+ usageHistory: [{
445
+ recordId: record.id,
446
+ timestamp: record.timestamp,
447
+ author: record.metadata.author,
448
+ outcomes: record.outcomes
449
+ }]
450
+ };
451
+
452
+ this.patterns.set(key, newPattern);
453
+
454
+ console.log(chalk.gray(`New pattern candidate created: ${key}`));
455
+ }
456
+
457
+ /**
458
+ * Calculate pattern confidence
459
+ */
460
+ calculatePatternConfidence(pattern) {
461
+ let confidence = 0;
462
+
463
+ // Occurrence factor (up to 0.3)
464
+ const occurrenceFactor = Math.min(pattern.occurrences / 10, 0.3);
465
+ confidence += occurrenceFactor;
466
+
467
+ // Success rate factor (up to 0.4)
468
+ confidence += pattern.successRate * 0.4;
469
+
470
+ // Consistency factor (up to 0.2)
471
+ const consistencyFactor = this.calculateConsistencyFactor(pattern.usageHistory);
472
+ confidence += consistencyFactor * 0.2;
473
+
474
+ // Recency factor (up to 0.1)
475
+ const recencyFactor = this.calculateRecencyFactor(pattern.lastSeen);
476
+ confidence += recencyFactor * 0.1;
477
+
478
+ return Math.min(confidence, 1.0);
479
+ }
480
+
481
+ /**
482
+ * Get pattern suggestions for modification
483
+ */
484
+ async getPatternSuggestions(_context) {
485
+ const suggestions = [];
486
+
487
+ // Filter applicable patterns
488
+ const applicablePatterns = Array.from(this.patterns.values()).filter(pattern => {
489
+ return pattern.status === 'learned' &&
490
+ this.isPatternApplicable(pattern, context) &&
491
+ pattern.confidence > 0.7;
492
+ });
493
+
494
+ // Sort by relevance and confidence
495
+ applicablePatterns.sort((a, b) => {
496
+ const relevanceA = this.calculateRelevance(a, context);
497
+ const relevanceB = this.calculateRelevance(b, context);
498
+ return (relevanceB * b.confidence) - (relevanceA * a.confidence);
499
+ });
500
+
501
+ // Create suggestions
502
+ for (const pattern of applicablePatterns.slice(0, 5)) {
503
+ suggestions.push({
504
+ pattern: pattern,
505
+ relevance: this.calculateRelevance(pattern, context),
506
+ confidence: pattern.confidence,
507
+ expectedBenefits: pattern.aggregatedBenefits || {},
508
+ applicationGuide: await this.generateApplicationGuide(pattern, context),
509
+ examples: this.getPatternExamples(pattern)
510
+ });
511
+ }
512
+
513
+ return suggestions;
514
+ }
515
+
516
+ /**
517
+ * Check if pattern is applicable
518
+ */
519
+ isPatternApplicable(pattern, context) {
520
+ // Check component type compatibility
521
+ if (pattern.componentType && context.componentType) {
522
+ if (pattern.componentType !== context.componentType && pattern.componentType !== 'any') {
523
+ return false;
524
+ }
525
+ }
526
+
527
+ // Check context requirements
528
+ if (pattern.requiredContext) {
529
+ for (const requirement of pattern.requiredContext) {
530
+ if (!this.meetsContextRequirement(_context, requirement)) {
531
+ return false;
532
+ }
533
+ }
534
+ }
535
+
536
+ // Check applicability conditions
537
+ if (pattern.applicableContexts) {
538
+ return pattern.applicableContexts.some(ctx =>
539
+ this.matchesContext(_context, ctx)
540
+ );
541
+ }
542
+
543
+ return true;
544
+ }
545
+
546
+ /**
547
+ * Generate application guide
548
+ */
549
+ async generateApplicationGuide(pattern, context) {
550
+ const guide = {
551
+ steps: [],
552
+ preconditions: [],
553
+ expectedOutcome: {},
554
+ risks: [],
555
+ alternatives: []
556
+ };
557
+
558
+ // Generate steps based on pattern type
559
+ switch (pattern.type) {
560
+ case 'code_transformation':
561
+ guide.steps = this.generateCodeTransformationSteps(pattern, context);
562
+ break;
563
+ case 'refactoring':
564
+ guide.steps = pattern.steps || [];
565
+ guide.preconditions = pattern.triggers || [];
566
+ break;
567
+ case 'performance':
568
+ guide.steps = this.generatePerformanceOptimizationSteps(pattern, context);
569
+ guide.expectedOutcome = pattern.metrics;
570
+ break;
571
+ }
572
+
573
+ // Add general guidance
574
+ guide.confidence = `${Math.round(pattern.confidence * 100)}%`;
575
+ guide.successRate = `${Math.round(pattern.successRate * 100)}%`;
576
+ guide.usageCount = pattern.occurrences;
577
+
578
+ return guide;
579
+ }
580
+
581
+ /**
582
+ * Analyze pattern relationships
583
+ */
584
+ async analyzePatternRelationships(patterns) {
585
+ // Find patterns that commonly occur together
586
+ const coOccurrences = new Map();
587
+
588
+ for (let i = 0; i < patterns.length; i++) {
589
+ for (let j = i + 1; j < patterns.length; j++) {
590
+ const key = this.generateRelationshipKey(patterns[i], patterns[j]);
591
+ const existing = coOccurrences.get(key) || { count: 0, patterns: [] };
592
+ existing.count++;
593
+ existing.patterns = [patterns[i], patterns[j]];
594
+ coOccurrences.set(key, existing);
595
+ }
596
+ }
597
+
598
+ // Store significant relationships
599
+ for (const [key, relationship] of coOccurrences) {
600
+ if (relationship.count >= 2) {
601
+ await this.storePatternRelationship(key, relationship);
602
+ }
603
+ }
604
+ }
605
+
606
+ /**
607
+ * Get pattern analytics
608
+ */
609
+ async getPatternAnalytics() {
610
+ const analytics = {
611
+ totalPatterns: this.patterns.size,
612
+ learnedPatterns: 0,
613
+ candidatePatterns: 0,
614
+ patternsByType: {},
615
+ topPatterns: [],
616
+ recentTrends: [],
617
+ effectivenessMetrics: {}
618
+ };
619
+
620
+ // Count patterns by status and type
621
+ for (const pattern of this.patterns.values()) {
622
+ if (pattern.status === 'learned') {
623
+ analytics.learnedPatterns++;
624
+ } else {
625
+ analytics.candidatePatterns++;
626
+ }
627
+
628
+ analytics.patternsByType[pattern.type] =
629
+ (analytics.patternsByType[pattern.type] || 0) + 1;
630
+ }
631
+
632
+ // Get top patterns by usage
633
+ const sortedPatterns = Array.from(this.patterns.values())
634
+ .sort((a, b) => b.occurrences - a.occurrences);
635
+
636
+ analytics.topPatterns = sortedPatterns.slice(0, 10).map(p => ({
637
+ key: p.key,
638
+ type: p.type,
639
+ occurrences: p.occurrences,
640
+ successRate: p.successRate,
641
+ confidence: p.confidence
642
+ }));
643
+
644
+ // Calculate effectiveness metrics
645
+ analytics.effectivenessMetrics = await this.calculateEffectivenessMetrics();
646
+
647
+ // Get recent trends
648
+ analytics.recentTrends = await this.analyzeRecentTrends();
649
+
650
+ return analytics;
651
+ }
652
+
653
+ /**
654
+ * Calculate effectiveness metrics
655
+ */
656
+ async calculateEffectivenessMetrics() {
657
+ const metrics = {
658
+ averageSuccessRate: 0,
659
+ averageConfidence: 0,
660
+ patternCoverage: 0,
661
+ learningRate: 0
662
+ };
663
+
664
+ const learnedPatterns = Array.from(this.patterns.values())
665
+ .filter(p => p.status === 'learned');
666
+
667
+ if (learnedPatterns.length > 0) {
668
+ metrics.averageSuccessRate = learnedPatterns.reduce((sum, p) =>
669
+ sum + p.successRate, 0) / learnedPatterns.length;
670
+
671
+ metrics.averageConfidence = learnedPatterns.reduce((sum, p) =>
672
+ sum + p.confidence, 0) / learnedPatterns.length;
673
+ }
674
+
675
+ // Calculate pattern coverage
676
+ const modificationTypes = new Set(this.modificationHistory.map(m => m.modificationType));
677
+ const coveredTypes = new Set(learnedPatterns.map(p => p.type));
678
+ metrics.patternCoverage = modificationTypes.size > 0 ?
679
+ coveredTypes.size / modificationTypes.size : 0;
680
+
681
+ // Calculate learning rate
682
+ const recentHistory = this.modificationHistory.slice(-20);
683
+ const recentLearned = recentHistory.filter(m =>
684
+ m.patterns.some(p => this.patterns.get(this.generatePatternKey(p))?.status === 'learned')
685
+ );
686
+ metrics.learningRate = recentHistory.length > 0 ?
687
+ recentLearned.length / recentHistory.length : 0;
688
+
689
+ return metrics;
690
+ }
691
+
692
+ /**
693
+ * Helper methods
694
+ */
695
+
696
+ normalizeCode(code) {
697
+ if (!code) return '';
698
+ return code.trim().replace(/\s+/g, ' ');
699
+ }
700
+
701
+ generatePatternKey(pattern) {
702
+ return `${pattern.type}:${pattern.subtype || 'default'}:${
703
+ crypto.createHash('md5').update(JSON.stringify(pattern)).digest('hex').substr(0, 8)
704
+ }`;
705
+ }
706
+
707
+ aggregateBenefits(existing, newBenefits) {
708
+ const aggregated = { ...existing };
709
+
710
+ for (const [key, value] of Object.entries(newBenefits)) {
711
+ if (typeof value === 'number') {
712
+ aggregated[key] = (aggregated[key] || 0) + value;
713
+ aggregated[`${key}_avg`] = aggregated[key] / ((aggregated[`${key}_count`] || 0) + 1);
714
+ aggregated[`${key}_count`] = (aggregated[`${key}_count`] || 0) + 1;
715
+ }
716
+ }
717
+
718
+ return aggregated;
719
+ }
720
+
721
+ calculateConsistencyFactor(usageHistory) {
722
+ if (usageHistory.length < 2) return 1.0;
723
+
724
+ // Check time intervals between uses
725
+ const intervals = [];
726
+ for (let i = 1; i < usageHistory.length; i++) {
727
+ const interval = new Date(usageHistory[i].timestamp) - new Date(usageHistory[i-1].timestamp);
728
+ intervals.push(interval);
729
+ }
730
+
731
+ // Calculate variance
732
+ const avgInterval = intervals.reduce((sum, i) => sum + i, 0) / intervals.length;
733
+ const variance = intervals.reduce((sum, i) => sum + Math.pow(i - avgInterval, 2), 0) / intervals.length;
734
+ const stdDev = Math.sqrt(variance);
735
+
736
+ // Lower variance = higher consistency
737
+ return 1 / (1 + stdDev / avgInterval);
738
+ }
739
+
740
+ calculateRecencyFactor(lastSeen) {
741
+ const daysSinceLastSeen = (Date.now() - new Date(lastSeen).getTime()) / (1000 * 60 * 60 * 24);
742
+ return Math.max(0, 1 - daysSinceLastSeen / 30); // Decay over 30 days
743
+ }
744
+
745
+ calculateRelevance(pattern, context) {
746
+ let relevance = 0;
747
+
748
+ // Type match
749
+ if (pattern.type === context.modificationType) {
750
+ relevance += 0.3;
751
+ }
752
+
753
+ // Component type match
754
+ if (pattern.componentType === context.componentType) {
755
+ relevance += 0.2;
756
+ }
757
+
758
+ // Context similarity
759
+ if (pattern.context && context.currentContext) {
760
+ relevance += this.calculateContextSimilarity(pattern.context, context.currentContext) * 0.3;
761
+ }
762
+
763
+ // Goal alignment
764
+ if (pattern.benefits && context.goals) {
765
+ relevance += this.calculateGoalAlignment(pattern.benefits, context.goals) * 0.2;
766
+ }
767
+
768
+ return relevance;
769
+ }
770
+
771
+ getPatternExamples(pattern) {
772
+ return pattern.usageHistory
773
+ .slice(-3)
774
+ .map(usage => ({
775
+ recordId: usage.recordId,
776
+ timestamp: usage.timestamp,
777
+ author: usage.author,
778
+ outcomes: usage.outcomes
779
+ }));
780
+ }
781
+
782
+ /**
783
+ * Save and load methods
784
+ */
785
+
786
+ async saveHistory() {
787
+ await fs.writeFile(
788
+ this.historyFile,
789
+ JSON.stringify(this.modificationHistory, null, 2)
790
+ );
791
+ }
792
+
793
+ async loadHistory() {
794
+ try {
795
+ const content = await fs.readFile(this.historyFile, 'utf-8');
796
+ this.modificationHistory = JSON.parse(content);
797
+ } catch (_error) {
798
+ // No history file yet
799
+ this.modificationHistory = [];
800
+ }
801
+ }
802
+
803
+ async savePatterns() {
804
+ const patternsArray = Array.from(this.patterns.entries()).map(([key, pattern]) => ({
805
+ key,
806
+ ...pattern
807
+ }));
808
+
809
+ await fs.writeFile(
810
+ this.patternsFile,
811
+ JSON.stringify(patternsArray, null, 2)
812
+ );
813
+ }
814
+
815
+ async loadPatterns() {
816
+ try {
817
+ const content = await fs.readFile(this.patternsFile, 'utf-8');
818
+ const patternsArray = JSON.parse(content);
819
+
820
+ this.patterns.clear();
821
+ for (const pattern of patternsArray) {
822
+ this.patterns.set(pattern.key, pattern);
823
+ }
824
+ } catch (_error) {
825
+ // No patterns file yet
826
+ }
827
+ }
828
+
829
+ /**
830
+ * Check learning threshold
831
+ */
832
+ async checkLearningThreshold(patterns) {
833
+ let learnedCount = 0;
834
+
835
+ for (const pattern of patterns) {
836
+ const key = this.generatePatternKey(pattern);
837
+ const existing = this.patterns.get(key);
838
+
839
+ if (existing && existing.occurrences >= this.learningThreshold) {
840
+ learnedCount++;
841
+ }
842
+ }
843
+
844
+ return learnedCount > 0;
845
+ }
846
+
847
+ calculateContextSimilarity(context1, context2) {
848
+ // Simple context similarity - can be enhanced
849
+ if (!context1 || !context2) return 0;
850
+
851
+ const keys1 = Object.keys(context1);
852
+ const keys2 = Object.keys(context2);
853
+ const commonKeys = keys1.filter(k => keys2.includes(k));
854
+
855
+ if (commonKeys.length === 0) return 0;
856
+
857
+ let similarity = commonKeys.length / Math.max(keys1.length, keys2.length);
858
+
859
+ // Check value similarity for common keys
860
+ for (const key of commonKeys) {
861
+ if (context1[key] === context2[key]) {
862
+ similarity += 0.1;
863
+ }
864
+ }
865
+
866
+ return Math.min(similarity, 1.0);
867
+ }
868
+
869
+ calculateStructuralSimilarity(struct1, struct2) {
870
+ // Compare structural patterns
871
+ if (!struct1 || !struct2) return 0;
872
+
873
+ const before1 = JSON.stringify(struct1.before);
874
+ const before2 = JSON.stringify(struct2.before);
875
+ const after1 = JSON.stringify(struct1.after);
876
+ const after2 = JSON.stringify(struct2.after);
877
+
878
+ const beforeSim = before1 === before2 ? 1 : 0.5;
879
+ const afterSim = after1 === after2 ? 1 : 0.5;
880
+
881
+ return (beforeSim + afterSim) / 2;
882
+ }
883
+
884
+ calculateBenefitSimilarity(benefits1, benefits2) {
885
+ if (!benefits1 || !benefits2) return 0;
886
+
887
+ const keys1 = Object.keys(benefits1);
888
+ const keys2 = Object.keys(benefits2);
889
+ const allKeys = new Set([...keys1, ...keys2]);
890
+
891
+ let similarity = 0;
892
+ for (const key of allKeys) {
893
+ if (benefits1[key] && benefits2[key]) {
894
+ // Both have the benefit
895
+ similarity += 1;
896
+ }
897
+ }
898
+
899
+ return allKeys.size > 0 ? similarity / allKeys.size : 0;
900
+ }
901
+
902
+ calculateRefactoringSimilarity(refactor1, refactor2) {
903
+ if (refactor1.refactoringType !== refactor2.refactoringType) return 0;
904
+
905
+ let similarity = 0.5; // Base similarity for same type
906
+
907
+ // Compare triggers
908
+ if (refactor1.triggers && refactor2.triggers) {
909
+ const commonTriggers = refactor1.triggers.filter(t =>
910
+ refactor2.triggers.includes(t)
911
+ );
912
+ similarity += commonTriggers.length / Math.max(refactor1.triggers.length, refactor2.triggers.length) * 0.3;
913
+ }
914
+
915
+ // Compare steps
916
+ if (refactor1.steps && refactor2.steps) {
917
+ const stepSimilarity = Math.min(refactor1.steps.length, refactor2.steps.length) /
918
+ Math.max(refactor1.steps.length, refactor2.steps.length);
919
+ similarity += stepSimilarity * 0.2;
920
+ }
921
+
922
+ return similarity;
923
+ }
924
+
925
+ calculatePerformanceSimilarity(perf1, perf2) {
926
+ if (perf1.optimizationType !== perf2.optimizationType) return 0;
927
+
928
+ let similarity = 0.4; // Base similarity for same type
929
+
930
+ if (perf1.technique === perf2.technique) {
931
+ similarity += 0.3;
932
+ }
933
+
934
+ // Compare applicable contexts
935
+ if (perf1.applicableContexts && perf2.applicableContexts) {
936
+ const commonContexts = perf1.applicableContexts.filter(c =>
937
+ perf2.applicableContexts.includes(c)
938
+ );
939
+ similarity += commonContexts.length / Math.max(perf1.applicableContexts.length, perf2.applicableContexts.length) * 0.3;
940
+ }
941
+
942
+ return similarity;
943
+ }
944
+
945
+ calculateGenericSimilarity(pattern1, pattern2) {
946
+ // Generic JSON similarity
947
+ const json1 = JSON.stringify(pattern1);
948
+ const json2 = JSON.stringify(pattern2);
949
+
950
+ if (json1 === json2) return 1.0;
951
+
952
+ // Calculate Levenshtein distance ratio
953
+ const distance = this.levenshteinDistance(json1, json2);
954
+ const maxLength = Math.max(json1.length, json2.length);
955
+
956
+ return 1 - (distance / maxLength);
957
+ }
958
+
959
+ levenshteinDistance(str1, str2) {
960
+ const matrix = [];
961
+
962
+ for (let i = 0; i <= str2.length; i++) {
963
+ matrix[i] = [i];
964
+ }
965
+
966
+ for (let j = 0; j <= str1.length; j++) {
967
+ matrix[0][j] = j;
968
+ }
969
+
970
+ for (let i = 1; i <= str2.length; i++) {
971
+ for (let j = 1; j <= str1.length; j++) {
972
+ if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
973
+ matrix[i][j] = matrix[i - 1][j - 1];
974
+ } else {
975
+ matrix[i][j] = Math.min(
976
+ matrix[i - 1][j - 1] + 1,
977
+ matrix[i][j - 1] + 1,
978
+ matrix[i - 1][j] + 1
979
+ );
980
+ }
981
+ }
982
+ }
983
+
984
+ return matrix[str2.length][str1.length];
985
+ }
986
+
987
+ meetsContextRequirement(_context, requirement) {
988
+ // Check if context meets specific requirement
989
+ if (requirement.type === 'has_property') {
990
+ return context[requirement.property] !== undefined;
991
+ }
992
+
993
+ if (requirement.type === 'property_value') {
994
+ return context[requirement.property] === requirement.value;
995
+ }
996
+
997
+ if (requirement.type === 'property_range') {
998
+ const value = context[requirement.property];
999
+ return value >= requirement.min && value <= requirement.max;
1000
+ }
1001
+
1002
+ return true;
1003
+ }
1004
+
1005
+ matchesContext(_context, patternContext) {
1006
+ // Check if contexts match
1007
+ for (const [key, value] of Object.entries(patternContext)) {
1008
+ if (context[key] !== value) {
1009
+ return false;
1010
+ }
1011
+ }
1012
+ return true;
1013
+ }
1014
+
1015
+ generateCodeTransformationSteps(pattern, context) {
1016
+ const steps = [];
1017
+
1018
+ steps.push({
1019
+ step: 1,
1020
+ action: 'Identify target code pattern',
1021
+ description: `Look for code matching: ${pattern.from}`,
1022
+ validation: 'Ensure code structure matches the pattern'
1023
+ });
1024
+
1025
+ steps.push({
1026
+ step: 2,
1027
+ action: 'Apply transformation',
1028
+ description: `Transform to: ${pattern.to}`,
1029
+ validation: 'Verify transformation preserves functionality'
1030
+ });
1031
+
1032
+ if (pattern.context) {
1033
+ steps.push({
1034
+ step: 3,
1035
+ action: 'Validate context',
1036
+ description: 'Ensure transformation is appropriate for context',
1037
+ validation: pattern.context
1038
+ });
1039
+ }
1040
+
1041
+ steps.push({
1042
+ step: 4,
1043
+ action: 'Test changes',
1044
+ description: 'Run tests to ensure no regression',
1045
+ validation: 'All tests pass'
1046
+ });
1047
+
1048
+ return steps;
1049
+ }
1050
+
1051
+ generatePerformanceOptimizationSteps(pattern, context) {
1052
+ const steps = [];
1053
+
1054
+ steps.push({
1055
+ step: 1,
1056
+ action: 'Measure baseline performance',
1057
+ description: 'Capture current performance metrics',
1058
+ validation: 'Baseline metrics recorded'
1059
+ });
1060
+
1061
+ steps.push({
1062
+ step: 2,
1063
+ action: `Apply ${pattern.technique} optimization`,
1064
+ description: pattern.description || 'Apply performance optimization technique',
1065
+ validation: 'Optimization applied correctly'
1066
+ });
1067
+
1068
+ steps.push({
1069
+ step: 3,
1070
+ action: 'Measure improved performance',
1071
+ description: 'Capture post-optimization metrics',
1072
+ validation: `Expected improvement: ${pattern.metrics.improvement}%`
1073
+ });
1074
+
1075
+ steps.push({
1076
+ step: 4,
1077
+ action: 'Validate functionality',
1078
+ description: 'Ensure optimization didn\'t break functionality',
1079
+ validation: 'All tests pass'
1080
+ });
1081
+
1082
+ return steps;
1083
+ }
1084
+
1085
+ generateRelationshipKey(pattern1, pattern2) {
1086
+ const types = [pattern1.type, pattern2.type].sort();
1087
+ return `rel:${types.join(':')}`;
1088
+ }
1089
+
1090
+ async storePatternRelationship(key, relationship) {
1091
+ // Store pattern relationships for future analysis
1092
+ const relationshipsFile = path.join(this.patternsDir, 'relationships.json');
1093
+
1094
+ let relationships = {};
1095
+ try {
1096
+ const content = await fs.readFile(relationshipsFile, 'utf-8');
1097
+ relationships = JSON.parse(content);
1098
+ } catch (_error) {
1099
+ // No relationships file yet
1100
+ }
1101
+
1102
+ relationships[key] = relationship;
1103
+
1104
+ await fs.writeFile(relationshipsFile, JSON.stringify(relationships, null, 2));
1105
+ }
1106
+
1107
+ async analyzeRecentTrends() {
1108
+ const recentModifications = this.modificationHistory.slice(-30);
1109
+ const trends = {
1110
+ emergingPatterns: [],
1111
+ decliningPatterns: [],
1112
+ stablePatterns: []
1113
+ };
1114
+
1115
+ // Analyze pattern usage over time
1116
+ const patternUsage = new Map();
1117
+
1118
+ for (const mod of recentModifications) {
1119
+ for (const pattern of mod.patterns) {
1120
+ const key = this.generatePatternKey(pattern);
1121
+ const usage = patternUsage.get(key) || { count: 0, recent: 0 };
1122
+ usage.count++;
1123
+
1124
+ // Check if in last 10 modifications
1125
+ const modIndex = recentModifications.indexOf(mod);
1126
+ if (modIndex >= recentModifications.length - 10) {
1127
+ usage.recent++;
1128
+ }
1129
+
1130
+ patternUsage.set(key, usage);
1131
+ }
1132
+ }
1133
+
1134
+ // Classify patterns
1135
+ for (const [key, usage] of patternUsage) {
1136
+ const pattern = this.patterns.get(key);
1137
+ if (!pattern) continue;
1138
+
1139
+ const recentRatio = usage.recent / usage.count;
1140
+
1141
+ if (recentRatio > 0.6) {
1142
+ trends.emergingPatterns.push({
1143
+ key: key,
1144
+ type: pattern.type,
1145
+ trend: 'emerging',
1146
+ usage: usage
1147
+ });
1148
+ } else if (recentRatio < 0.2) {
1149
+ trends.decliningPatterns.push({
1150
+ key: key,
1151
+ type: pattern.type,
1152
+ trend: 'declining',
1153
+ usage: usage
1154
+ });
1155
+ } else {
1156
+ trends.stablePatterns.push({
1157
+ key: key,
1158
+ type: pattern.type,
1159
+ trend: 'stable',
1160
+ usage: usage
1161
+ });
1162
+ }
1163
+ }
1164
+
1165
+ return trends;
1166
+ }
1167
+
1168
+ calculateGoalAlignment(benefits, goals) {
1169
+ if (!benefits || !goals) return 0;
1170
+
1171
+ let alignment = 0;
1172
+ let _matchedGoals = 0;
1173
+
1174
+ for (const goal of goals) {
1175
+ if (goal.type === 'performance' && benefits.performanceImprovement) {
1176
+ alignment += benefits.performanceImprovement > goal.target ? 1 : 0.5;
1177
+ matchedGoals++;
1178
+ }
1179
+
1180
+ if (goal.type === 'maintainability' && benefits.maintainability) {
1181
+ alignment += benefits.maintainability > goal.target ? 1 : 0.5;
1182
+ matchedGoals++;
1183
+ }
1184
+
1185
+ if (goal.type === 'testability' && benefits.testability) {
1186
+ alignment += benefits.testability > goal.target ? 1 : 0.5;
1187
+ matchedGoals++;
1188
+ }
1189
+ }
1190
+
1191
+ return goals.length > 0 ? alignment / goals.length : 0;
1192
+ }
1193
+
1194
+ async updatePatternRankings() {
1195
+ // Update pattern rankings based on multiple factors
1196
+ for (const pattern of this.patterns.values()) {
1197
+ pattern.ranking = this.calculatePatternRanking(pattern);
1198
+ }
1199
+
1200
+ // Save updated patterns
1201
+ await this.savePatterns();
1202
+ }
1203
+
1204
+ calculatePatternRanking(pattern) {
1205
+ let ranking = 0;
1206
+
1207
+ // Success rate (40%)
1208
+ ranking += pattern.successRate * 40;
1209
+
1210
+ // Usage frequency (30%)
1211
+ const usageScore = Math.min(pattern.occurrences / 20, 1);
1212
+ ranking += usageScore * 30;
1213
+
1214
+ // Confidence (20%)
1215
+ ranking += pattern.confidence * 20;
1216
+
1217
+ // Recency (10%)
1218
+ const recencyScore = this.calculateRecencyFactor(pattern.lastSeen);
1219
+ ranking += recencyScore * 10;
1220
+
1221
+ return ranking;
1222
+ }
1223
+ }
1224
+
1225
1225
  module.exports = PatternLearner;