aios-core 4.1.0 → 4.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.
Files changed (145) hide show
  1. package/.aios-core/.session/current-session.json +14 -0
  2. package/.aios-core/core/registry/registry-schema.json +166 -166
  3. package/.aios-core/core/registry/service-registry.json +6585 -6585
  4. package/.aios-core/data/entity-registry.yaml +208 -8
  5. package/.aios-core/data/registry-update-log.jsonl +165 -0
  6. package/.aios-core/development/scripts/approval-workflow.js +642 -642
  7. package/.aios-core/development/scripts/backup-manager.js +606 -606
  8. package/.aios-core/development/scripts/branch-manager.js +389 -389
  9. package/.aios-core/development/scripts/code-quality-improver.js +1311 -1311
  10. package/.aios-core/development/scripts/commit-message-generator.js +849 -849
  11. package/.aios-core/development/scripts/conflict-resolver.js +674 -674
  12. package/.aios-core/development/scripts/dependency-analyzer.js +637 -637
  13. package/.aios-core/development/scripts/diff-generator.js +351 -351
  14. package/.aios-core/development/scripts/elicitation-engine.js +384 -384
  15. package/.aios-core/development/scripts/elicitation-session-manager.js +299 -299
  16. package/.aios-core/development/scripts/git-wrapper.js +461 -461
  17. package/.aios-core/development/scripts/manifest-preview.js +244 -244
  18. package/.aios-core/development/scripts/metrics-tracker.js +775 -775
  19. package/.aios-core/development/scripts/modification-validator.js +554 -554
  20. package/.aios-core/development/scripts/pattern-learner.js +1224 -1224
  21. package/.aios-core/development/scripts/performance-analyzer.js +757 -757
  22. package/.aios-core/development/scripts/refactoring-suggester.js +1138 -1138
  23. package/.aios-core/development/scripts/rollback-handler.js +530 -530
  24. package/.aios-core/development/scripts/security-checker.js +358 -358
  25. package/.aios-core/development/scripts/template-engine.js +239 -239
  26. package/.aios-core/development/scripts/template-validator.js +278 -278
  27. package/.aios-core/development/scripts/test-generator.js +843 -843
  28. package/.aios-core/development/scripts/transaction-manager.js +589 -589
  29. package/.aios-core/development/scripts/usage-tracker.js +673 -673
  30. package/.aios-core/development/scripts/validate-filenames.js +226 -226
  31. package/.aios-core/development/scripts/version-tracker.js +526 -526
  32. package/.aios-core/development/scripts/yaml-validator.js +396 -396
  33. package/.aios-core/development/tasks/validate-next-story.md +99 -2
  34. package/.aios-core/development/templates/service-template/README.md.hbs +158 -158
  35. package/.aios-core/development/templates/service-template/__tests__/index.test.ts.hbs +237 -237
  36. package/.aios-core/development/templates/service-template/client.ts.hbs +403 -403
  37. package/.aios-core/development/templates/service-template/errors.ts.hbs +182 -182
  38. package/.aios-core/development/templates/service-template/index.ts.hbs +120 -120
  39. package/.aios-core/development/templates/service-template/package.json.hbs +87 -87
  40. package/.aios-core/development/templates/service-template/types.ts.hbs +145 -145
  41. package/.aios-core/development/templates/squad-template/LICENSE +21 -21
  42. package/.aios-core/docs/SHARD-TRANSLATION-GUIDE.md +335 -0
  43. package/.aios-core/docs/component-creation-guide.md +458 -0
  44. package/.aios-core/docs/session-update-pattern.md +307 -0
  45. package/.aios-core/docs/standards/AIOS-FRAMEWORK-MASTER.md +1963 -0
  46. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-SUMMARY.md +1190 -0
  47. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1.md +439 -0
  48. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO.md +5398 -0
  49. package/.aios-core/docs/standards/V3-ARCHITECTURAL-DECISIONS.md +523 -0
  50. package/.aios-core/docs/template-syntax.md +267 -0
  51. package/.aios-core/docs/troubleshooting-guide.md +625 -0
  52. package/.aios-core/infrastructure/templates/aios-sync.yaml.template +193 -193
  53. package/.aios-core/infrastructure/templates/coderabbit.yaml.template +279 -279
  54. package/.aios-core/infrastructure/templates/github-workflows/ci.yml.template +169 -169
  55. package/.aios-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -330
  56. package/.aios-core/infrastructure/templates/github-workflows/release.yml.template +196 -196
  57. package/.aios-core/infrastructure/templates/gitignore/gitignore-aios-base.tmpl +63 -63
  58. package/.aios-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -18
  59. package/.aios-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -85
  60. package/.aios-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -145
  61. package/.aios-core/infrastructure/tests/utilities-audit-results.json +501 -0
  62. package/.aios-core/install-manifest.yaml +101 -101
  63. package/.aios-core/local-config.yaml.template +70 -70
  64. package/.aios-core/manifests/agents.csv +29 -0
  65. package/.aios-core/manifests/schema/manifest-schema.json +190 -190
  66. package/.aios-core/manifests/tasks.csv +198 -0
  67. package/.aios-core/manifests/workers.csv +204 -0
  68. package/.aios-core/monitor/hooks/lib/__init__.py +1 -1
  69. package/.aios-core/monitor/hooks/lib/enrich.py +58 -58
  70. package/.aios-core/monitor/hooks/lib/send_event.py +47 -47
  71. package/.aios-core/monitor/hooks/notification.py +29 -29
  72. package/.aios-core/monitor/hooks/post_tool_use.py +45 -45
  73. package/.aios-core/monitor/hooks/pre_compact.py +29 -29
  74. package/.aios-core/monitor/hooks/pre_tool_use.py +40 -40
  75. package/.aios-core/monitor/hooks/stop.py +29 -29
  76. package/.aios-core/monitor/hooks/subagent_stop.py +29 -29
  77. package/.aios-core/monitor/hooks/user_prompt_submit.py +38 -38
  78. package/.aios-core/product/templates/adr.hbs +125 -125
  79. package/.aios-core/product/templates/component-react-tmpl.tsx +98 -98
  80. package/.aios-core/product/templates/dbdr.hbs +241 -241
  81. package/.aios-core/product/templates/engine/schemas/adr.schema.json +102 -102
  82. package/.aios-core/product/templates/engine/schemas/dbdr.schema.json +205 -205
  83. package/.aios-core/product/templates/engine/schemas/epic.schema.json +175 -175
  84. package/.aios-core/product/templates/engine/schemas/pmdr.schema.json +175 -175
  85. package/.aios-core/product/templates/engine/schemas/prd-v2.schema.json +300 -300
  86. package/.aios-core/product/templates/engine/schemas/prd.schema.json +152 -152
  87. package/.aios-core/product/templates/engine/schemas/story.schema.json +222 -222
  88. package/.aios-core/product/templates/engine/schemas/task.schema.json +154 -154
  89. package/.aios-core/product/templates/epic.hbs +212 -212
  90. package/.aios-core/product/templates/eslintrc-security.json +32 -32
  91. package/.aios-core/product/templates/github-actions-cd.yml +212 -212
  92. package/.aios-core/product/templates/github-actions-ci.yml +172 -172
  93. package/.aios-core/product/templates/pmdr.hbs +186 -186
  94. package/.aios-core/product/templates/prd-v2.0.hbs +216 -216
  95. package/.aios-core/product/templates/prd.hbs +201 -201
  96. package/.aios-core/product/templates/shock-report-tmpl.html +502 -502
  97. package/.aios-core/product/templates/story.hbs +263 -263
  98. package/.aios-core/product/templates/task.hbs +170 -170
  99. package/.aios-core/product/templates/tmpl-comment-on-examples.sql +158 -158
  100. package/.aios-core/product/templates/tmpl-migration-script.sql +91 -91
  101. package/.aios-core/product/templates/tmpl-rls-granular-policies.sql +104 -104
  102. package/.aios-core/product/templates/tmpl-rls-kiss-policy.sql +10 -10
  103. package/.aios-core/product/templates/tmpl-rls-roles.sql +135 -135
  104. package/.aios-core/product/templates/tmpl-rls-simple.sql +77 -77
  105. package/.aios-core/product/templates/tmpl-rls-tenant.sql +152 -152
  106. package/.aios-core/product/templates/tmpl-rollback-script.sql +77 -77
  107. package/.aios-core/product/templates/tmpl-seed-data.sql +140 -140
  108. package/.aios-core/product/templates/tmpl-smoke-test.sql +16 -16
  109. package/.aios-core/product/templates/tmpl-staging-copy-merge.sql +139 -139
  110. package/.aios-core/product/templates/tmpl-stored-proc.sql +140 -140
  111. package/.aios-core/product/templates/tmpl-trigger.sql +152 -152
  112. package/.aios-core/product/templates/tmpl-view-materialized.sql +133 -133
  113. package/.aios-core/product/templates/tmpl-view.sql +177 -177
  114. package/.aios-core/product/templates/token-exports-css-tmpl.css +240 -240
  115. package/.aios-core/quality/schemas/quality-metrics.schema.json +233 -233
  116. package/.aios-core/scripts/migrate-framework-docs.sh +300 -300
  117. package/.aios-core/scripts/pm.sh +0 -0
  118. package/.claude/hooks/enforce-architecture-first.py +196 -196
  119. package/.claude/hooks/mind-clone-governance.py +192 -192
  120. package/.claude/hooks/read-protection.py +151 -151
  121. package/.claude/hooks/slug-validation.py +176 -176
  122. package/.claude/hooks/sql-governance.py +182 -182
  123. package/.claude/hooks/write-path-validation.py +194 -194
  124. package/.claude/rules/agent-authority.md +105 -0
  125. package/.claude/rules/coderabbit-integration.md +93 -0
  126. package/.claude/rules/ids-principles.md +112 -0
  127. package/.claude/rules/story-lifecycle.md +139 -0
  128. package/.claude/rules/workflow-execution.md +150 -0
  129. package/LICENSE +48 -48
  130. package/bin/aios-minimal.js +0 -0
  131. package/bin/aios.js +0 -0
  132. package/package.json +1 -1
  133. package/packages/aios-install/bin/aios-install.js +0 -0
  134. package/packages/aios-install/bin/edmcp.js +0 -0
  135. package/packages/aios-pro-cli/bin/aios-pro.js +0 -0
  136. package/packages/installer/src/wizard/pro-setup.js +433 -49
  137. package/scripts/check-markdown-links.py +352 -352
  138. package/scripts/code-intel-health-check.js +343 -0
  139. package/scripts/dashboard-parallel-dev.sh +0 -0
  140. package/scripts/dashboard-parallel-phase3.sh +0 -0
  141. package/scripts/dashboard-parallel-phase4.sh +0 -0
  142. package/scripts/glue/README.md +355 -0
  143. package/scripts/glue/compose-agent-prompt.cjs +362 -0
  144. package/scripts/install-monitor-hooks.sh +0 -0
  145. package/.aios-core/lib/build.json +0 -1
@@ -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;