pmp-gywd 3.3.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 (126) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +567 -0
  3. package/bin/install.js +348 -0
  4. package/commands/gywd/add-phase.md +207 -0
  5. package/commands/gywd/anticipate.md +271 -0
  6. package/commands/gywd/bootstrap.md +336 -0
  7. package/commands/gywd/challenge.md +344 -0
  8. package/commands/gywd/check-drift.md +144 -0
  9. package/commands/gywd/complete-milestone.md +106 -0
  10. package/commands/gywd/consider-issues.md +202 -0
  11. package/commands/gywd/context.md +93 -0
  12. package/commands/gywd/create-roadmap.md +115 -0
  13. package/commands/gywd/deps.md +169 -0
  14. package/commands/gywd/digest.md +138 -0
  15. package/commands/gywd/discuss-milestone.md +47 -0
  16. package/commands/gywd/discuss-phase.md +60 -0
  17. package/commands/gywd/execute-plan.md +161 -0
  18. package/commands/gywd/extract-decisions.md +325 -0
  19. package/commands/gywd/health.md +150 -0
  20. package/commands/gywd/help.md +556 -0
  21. package/commands/gywd/history.md +278 -0
  22. package/commands/gywd/impact.md +317 -0
  23. package/commands/gywd/init.md +95 -0
  24. package/commands/gywd/insert-phase.md +227 -0
  25. package/commands/gywd/list-phase-assumptions.md +50 -0
  26. package/commands/gywd/map-codebase.md +84 -0
  27. package/commands/gywd/memory.md +159 -0
  28. package/commands/gywd/new-milestone.md +59 -0
  29. package/commands/gywd/new-project.md +315 -0
  30. package/commands/gywd/pause-work.md +123 -0
  31. package/commands/gywd/plan-fix.md +205 -0
  32. package/commands/gywd/plan-phase.md +93 -0
  33. package/commands/gywd/preview-plan.md +139 -0
  34. package/commands/gywd/profile.md +363 -0
  35. package/commands/gywd/progress.md +317 -0
  36. package/commands/gywd/remove-phase.md +338 -0
  37. package/commands/gywd/research-phase.md +91 -0
  38. package/commands/gywd/resume-work.md +40 -0
  39. package/commands/gywd/rollback.md +179 -0
  40. package/commands/gywd/status.md +42 -0
  41. package/commands/gywd/sync-github.md +234 -0
  42. package/commands/gywd/verify-work.md +71 -0
  43. package/commands/gywd/why.md +251 -0
  44. package/docs/COMMANDS.md +722 -0
  45. package/docs/CONTRIBUTING.md +342 -0
  46. package/docs/EXAMPLES.md +535 -0
  47. package/docs/GETTING-STARTED.md +262 -0
  48. package/docs/README.md +55 -0
  49. package/docs/RELEASING.md +159 -0
  50. package/get-your-work-done/core/agent-patterns.md +331 -0
  51. package/get-your-work-done/core/architecture.md +334 -0
  52. package/get-your-work-done/core/context-model-schema.json +154 -0
  53. package/get-your-work-done/core/decisions-schema.json +193 -0
  54. package/get-your-work-done/core/learning-state-schema.json +133 -0
  55. package/get-your-work-done/core/profile-schema.json +257 -0
  56. package/get-your-work-done/references/adaptive-decomposition.md +175 -0
  57. package/get-your-work-done/references/checkpoints.md +287 -0
  58. package/get-your-work-done/references/confidence-scoring.md +169 -0
  59. package/get-your-work-done/references/continuation-format.md +255 -0
  60. package/get-your-work-done/references/git-integration.md +254 -0
  61. package/get-your-work-done/references/plan-format.md +428 -0
  62. package/get-your-work-done/references/principles.md +157 -0
  63. package/get-your-work-done/references/questioning.md +162 -0
  64. package/get-your-work-done/references/research-pitfalls.md +215 -0
  65. package/get-your-work-done/references/scope-estimation.md +172 -0
  66. package/get-your-work-done/references/tdd.md +263 -0
  67. package/get-your-work-done/templates/codebase/architecture.md +255 -0
  68. package/get-your-work-done/templates/codebase/concerns.md +310 -0
  69. package/get-your-work-done/templates/codebase/conventions.md +307 -0
  70. package/get-your-work-done/templates/codebase/integrations.md +280 -0
  71. package/get-your-work-done/templates/codebase/stack.md +186 -0
  72. package/get-your-work-done/templates/codebase/structure.md +285 -0
  73. package/get-your-work-done/templates/codebase/testing.md +480 -0
  74. package/get-your-work-done/templates/config.json +18 -0
  75. package/get-your-work-done/templates/context.md +161 -0
  76. package/get-your-work-done/templates/continue-here.md +78 -0
  77. package/get-your-work-done/templates/discovery.md +146 -0
  78. package/get-your-work-done/templates/issues.md +32 -0
  79. package/get-your-work-done/templates/milestone-archive.md +123 -0
  80. package/get-your-work-done/templates/milestone-context.md +93 -0
  81. package/get-your-work-done/templates/milestone.md +115 -0
  82. package/get-your-work-done/templates/phase-prompt.md +303 -0
  83. package/get-your-work-done/templates/project.md +184 -0
  84. package/get-your-work-done/templates/research.md +529 -0
  85. package/get-your-work-done/templates/roadmap.md +196 -0
  86. package/get-your-work-done/templates/state.md +210 -0
  87. package/get-your-work-done/templates/summary.md +273 -0
  88. package/get-your-work-done/templates/uat-issues.md +143 -0
  89. package/get-your-work-done/workflows/complete-milestone.md +643 -0
  90. package/get-your-work-done/workflows/create-milestone.md +416 -0
  91. package/get-your-work-done/workflows/create-roadmap.md +481 -0
  92. package/get-your-work-done/workflows/discovery-phase.md +293 -0
  93. package/get-your-work-done/workflows/discuss-milestone.md +236 -0
  94. package/get-your-work-done/workflows/discuss-phase.md +247 -0
  95. package/get-your-work-done/workflows/execute-phase.md +1625 -0
  96. package/get-your-work-done/workflows/list-phase-assumptions.md +178 -0
  97. package/get-your-work-done/workflows/map-codebase.md +434 -0
  98. package/get-your-work-done/workflows/plan-phase.md +488 -0
  99. package/get-your-work-done/workflows/research-phase.md +436 -0
  100. package/get-your-work-done/workflows/resume-project.md +287 -0
  101. package/get-your-work-done/workflows/transition.md +580 -0
  102. package/get-your-work-done/workflows/verify-work.md +202 -0
  103. package/lib/automation/dependency-analyzer.js +635 -0
  104. package/lib/automation/doc-generator.js +643 -0
  105. package/lib/automation/index.js +42 -0
  106. package/lib/automation/test-generator.js +628 -0
  107. package/lib/context/context-analyzer.js +554 -0
  108. package/lib/context/context-cache.js +426 -0
  109. package/lib/context/context-predictor.js +622 -0
  110. package/lib/context/index.js +44 -0
  111. package/lib/memory/confidence-calibrator.js +484 -0
  112. package/lib/memory/feedback-collector.js +551 -0
  113. package/lib/memory/global-memory.js +465 -0
  114. package/lib/memory/index.js +75 -0
  115. package/lib/memory/pattern-aggregator.js +487 -0
  116. package/lib/memory/team-sync.js +501 -0
  117. package/lib/profile/index.js +24 -0
  118. package/lib/profile/pattern-learner.js +303 -0
  119. package/lib/profile/profile-manager.js +445 -0
  120. package/lib/questioning/index.js +49 -0
  121. package/lib/questioning/question-engine.js +311 -0
  122. package/lib/questioning/question-templates.js +315 -0
  123. package/lib/validators/command-validator.js +188 -0
  124. package/lib/validators/index.js +29 -0
  125. package/lib/validators/schema-validator.js +183 -0
  126. package/package.json +61 -0
@@ -0,0 +1,487 @@
1
+ 'use strict';
2
+
3
+ const { GlobalMemory } = require('./global-memory');
4
+
5
+ /**
6
+ * Consensus thresholds for pattern classification
7
+ */
8
+ const CONSENSUS_THRESHOLDS = {
9
+ STRONG: 0.8, // 80%+ of projects agree
10
+ MODERATE: 0.5, // 50%+ of projects agree
11
+ WEAK: 0.25, // 25%+ of projects agree
12
+ };
13
+
14
+ /**
15
+ * Confidence boost factors
16
+ */
17
+ const CONFIDENCE_FACTORS = {
18
+ CROSS_PROJECT: 0.1, // Boost per additional project
19
+ CONSENSUS: 0.2, // Boost for strong consensus
20
+ RECENCY: 0.05, // Boost for recent patterns
21
+ MAX_CONFIDENCE: 0.99, // Cap confidence
22
+ };
23
+
24
+ /**
25
+ * PatternAggregator - Merges patterns from multiple projects
26
+ *
27
+ * Analyzes patterns across projects to identify:
28
+ * - Consensus patterns (used consistently across projects)
29
+ * - Outlier patterns (project-specific anomalies)
30
+ * - Emerging patterns (new but growing in adoption)
31
+ *
32
+ * @example
33
+ * const aggregator = new PatternAggregator();
34
+ * const consensus = aggregator.getConsensusPatterns();
35
+ * const unique = aggregator.getUniquePatterns('project-name');
36
+ */
37
+ class PatternAggregator {
38
+ /**
39
+ * @param {GlobalMemory} [globalMemory] - Optional global memory instance
40
+ */
41
+ constructor(globalMemory = null) {
42
+ this.globalMemory = globalMemory || new GlobalMemory();
43
+ this.aggregatedPatterns = new Map();
44
+ this.projectPatterns = new Map();
45
+ this.initialized = false;
46
+ }
47
+
48
+ /**
49
+ * Initialize the aggregator by loading and analyzing global patterns
50
+ * @returns {PatternAggregator} this for chaining
51
+ */
52
+ init() {
53
+ this.globalMemory.init();
54
+ this._analyzePatterns();
55
+ this.initialized = true;
56
+ return this;
57
+ }
58
+
59
+ /**
60
+ * Analyze all patterns from global memory
61
+ * @private
62
+ */
63
+ _analyzePatterns() {
64
+ const patterns = this.globalMemory.patterns;
65
+ const projects = this.globalMemory.projects;
66
+ const totalProjects = Math.max(projects.length, 1);
67
+
68
+ // Group patterns by type+pattern key
69
+ const patternGroups = new Map();
70
+
71
+ for (const pattern of patterns) {
72
+ const key = `${pattern.type}::${pattern.pattern}`;
73
+
74
+ if (!patternGroups.has(key)) {
75
+ patternGroups.set(key, {
76
+ type: pattern.type,
77
+ pattern: pattern.pattern,
78
+ instances: [],
79
+ sources: new Set(),
80
+ });
81
+ }
82
+
83
+ const group = patternGroups.get(key);
84
+ group.instances.push(pattern);
85
+ for (const source of (pattern.sources || [])) {
86
+ group.sources.add(source);
87
+ }
88
+ }
89
+
90
+ // Calculate aggregated statistics
91
+ for (const [key, group] of patternGroups) {
92
+ const projectCount = group.sources.size;
93
+ const projectRatio = projectCount / totalProjects;
94
+
95
+ // Calculate aggregate confidence
96
+ const baseConfidence = this._calculateAggregateConfidence(group.instances);
97
+ const crossProjectBoost = Math.min(
98
+ (projectCount - 1) * CONFIDENCE_FACTORS.CROSS_PROJECT,
99
+ 0.3,
100
+ );
101
+ const consensusBoost = projectRatio >= CONSENSUS_THRESHOLDS.STRONG
102
+ ? CONFIDENCE_FACTORS.CONSENSUS
103
+ : 0;
104
+
105
+ const aggregatedConfidence = Math.min(
106
+ baseConfidence + crossProjectBoost + consensusBoost,
107
+ CONFIDENCE_FACTORS.MAX_CONFIDENCE,
108
+ );
109
+
110
+ // Determine consensus level
111
+ let consensusLevel = 'none';
112
+ if (projectRatio >= CONSENSUS_THRESHOLDS.STRONG) {
113
+ consensusLevel = 'strong';
114
+ } else if (projectRatio >= CONSENSUS_THRESHOLDS.MODERATE) {
115
+ consensusLevel = 'moderate';
116
+ } else if (projectRatio >= CONSENSUS_THRESHOLDS.WEAK) {
117
+ consensusLevel = 'weak';
118
+ }
119
+
120
+ this.aggregatedPatterns.set(key, {
121
+ type: group.type,
122
+ pattern: group.pattern,
123
+ confidence: aggregatedConfidence,
124
+ projectCount,
125
+ projectRatio,
126
+ consensusLevel,
127
+ sources: Array.from(group.sources),
128
+ totalOccurrences: group.instances.reduce(
129
+ (sum, p) => sum + (p.occurrences || 1),
130
+ 0,
131
+ ),
132
+ isConsensus: projectRatio >= CONSENSUS_THRESHOLDS.MODERATE,
133
+ isOutlier: projectCount === 1 && totalProjects > 1,
134
+ });
135
+ }
136
+
137
+ // Build per-project pattern index
138
+ for (const project of projects) {
139
+ const projectName = project.name || project.path;
140
+ this.projectPatterns.set(projectName, new Set());
141
+ }
142
+
143
+ for (const [key, agg] of this.aggregatedPatterns) {
144
+ for (const source of agg.sources) {
145
+ if (this.projectPatterns.has(source)) {
146
+ this.projectPatterns.get(source).add(key);
147
+ }
148
+ }
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Calculate aggregate confidence from multiple pattern instances
154
+ * @private
155
+ * @param {Array} instances - Pattern instances
156
+ * @returns {number} Aggregate confidence 0-1
157
+ */
158
+ _calculateAggregateConfidence(instances) {
159
+ if (instances.length === 0) return 0;
160
+
161
+ // Weighted average, with higher weight for more recent patterns
162
+ let totalWeight = 0;
163
+ let weightedSum = 0;
164
+
165
+ for (const instance of instances) {
166
+ const recency = this._calculateRecencyWeight(instance.lastSeen);
167
+ const weight = (instance.occurrences || 1) * recency;
168
+ weightedSum += (instance.confidence || 0.5) * weight;
169
+ totalWeight += weight;
170
+ }
171
+
172
+ return totalWeight > 0 ? weightedSum / totalWeight : 0.5;
173
+ }
174
+
175
+ /**
176
+ * Calculate recency weight for a pattern
177
+ * @private
178
+ * @param {string} lastSeen - ISO date string
179
+ * @returns {number} Recency weight 0.5-1.0
180
+ */
181
+ _calculateRecencyWeight(lastSeen) {
182
+ if (!lastSeen) return 0.5;
183
+
184
+ const now = Date.now();
185
+ const seen = new Date(lastSeen).getTime();
186
+ const daysSince = (now - seen) / (1000 * 60 * 60 * 24);
187
+
188
+ // Decay over 30 days from 1.0 to 0.5
189
+ return Math.max(0.5, 1 - (daysSince / 60));
190
+ }
191
+
192
+ // ==================== QUERY METHODS ====================
193
+
194
+ /**
195
+ * Get consensus patterns (used across multiple projects)
196
+ * @param {string} [level='moderate'] - Minimum consensus level
197
+ * @returns {Array} Consensus patterns sorted by confidence
198
+ */
199
+ getConsensusPatterns(level = 'moderate') {
200
+ if (!this.initialized) this.init();
201
+
202
+ const threshold = CONSENSUS_THRESHOLDS[level.toUpperCase()] ||
203
+ CONSENSUS_THRESHOLDS.MODERATE;
204
+
205
+ return Array.from(this.aggregatedPatterns.values())
206
+ .filter(p => p.projectRatio >= threshold)
207
+ .sort((a, b) => b.confidence - a.confidence);
208
+ }
209
+
210
+ /**
211
+ * Get outlier patterns (unique to single project)
212
+ * @returns {Array} Outlier patterns
213
+ */
214
+ getOutlierPatterns() {
215
+ if (!this.initialized) this.init();
216
+
217
+ return Array.from(this.aggregatedPatterns.values())
218
+ .filter(p => p.isOutlier)
219
+ .sort((a, b) => b.confidence - a.confidence);
220
+ }
221
+
222
+ /**
223
+ * Get patterns unique to a specific project
224
+ * @param {string} projectName - Project name
225
+ * @returns {Array} Unique patterns for this project
226
+ */
227
+ getUniquePatterns(projectName) {
228
+ if (!this.initialized) this.init();
229
+
230
+ const projectKeys = this.projectPatterns.get(projectName);
231
+ if (!projectKeys) return [];
232
+
233
+ return Array.from(projectKeys)
234
+ .map(key => this.aggregatedPatterns.get(key))
235
+ .filter(p => p && p.isOutlier)
236
+ .sort((a, b) => b.confidence - a.confidence);
237
+ }
238
+
239
+ /**
240
+ * Get common patterns between two or more projects
241
+ * @param {Array<string>} projectNames - Project names to compare
242
+ * @returns {Array} Common patterns
243
+ */
244
+ getCommonPatterns(projectNames) {
245
+ if (!this.initialized) this.init();
246
+
247
+ const patternSets = projectNames
248
+ .map(name => this.projectPatterns.get(name))
249
+ .filter(set => set);
250
+
251
+ if (patternSets.length < 2) return [];
252
+
253
+ // Find intersection
254
+ const intersection = new Set(patternSets[0]);
255
+ for (let i = 1; i < patternSets.length; i++) {
256
+ for (const key of intersection) {
257
+ if (!patternSets[i].has(key)) {
258
+ intersection.delete(key);
259
+ }
260
+ }
261
+ }
262
+
263
+ return Array.from(intersection)
264
+ .map(key => this.aggregatedPatterns.get(key))
265
+ .filter(Boolean)
266
+ .sort((a, b) => b.confidence - a.confidence);
267
+ }
268
+
269
+ /**
270
+ * Get patterns by type
271
+ * @param {string} type - Pattern type
272
+ * @returns {Array} Patterns of this type
273
+ */
274
+ getPatternsByType(type) {
275
+ if (!this.initialized) this.init();
276
+
277
+ return Array.from(this.aggregatedPatterns.values())
278
+ .filter(p => p.type === type)
279
+ .sort((a, b) => b.confidence - a.confidence);
280
+ }
281
+
282
+ /**
283
+ * Get the dominant pattern for a type
284
+ * @param {string} type - Pattern type
285
+ * @returns {object|null} Most confident pattern or null
286
+ */
287
+ getDominantPattern(type) {
288
+ const patterns = this.getPatternsByType(type);
289
+ return patterns.length > 0 ? patterns[0] : null;
290
+ }
291
+
292
+ /**
293
+ * Get emerging patterns (new but appearing in multiple projects)
294
+ * @param {number} [minProjects=2] - Minimum projects
295
+ * @param {number} [maxDays=30] - Maximum age in days
296
+ * @returns {Array} Emerging patterns
297
+ */
298
+ getEmergingPatterns(minProjects = 2, maxDays = 30) {
299
+ if (!this.initialized) this.init();
300
+
301
+ const cutoff = new Date();
302
+ cutoff.setDate(cutoff.getDate() - maxDays);
303
+
304
+ return Array.from(this.aggregatedPatterns.values())
305
+ .filter(p => {
306
+ // Check project count
307
+ if (p.projectCount < minProjects) return false;
308
+
309
+ // Check recency - at least one instance must be recent
310
+ const recentInstances = this.globalMemory.patterns.filter(gp => {
311
+ const key = `${gp.type}::${gp.pattern}`;
312
+ if (key !== `${p.type}::${p.pattern}`) return false;
313
+ if (!gp.createdAt) return false;
314
+ return new Date(gp.createdAt) >= cutoff;
315
+ });
316
+
317
+ return recentInstances.length > 0;
318
+ })
319
+ .sort((a, b) => b.projectCount - a.projectCount);
320
+ }
321
+
322
+ // ==================== ANALYSIS METHODS ====================
323
+
324
+ /**
325
+ * Analyze pattern diversity across projects
326
+ * @returns {object} Diversity analysis
327
+ */
328
+ analyzePatternDiversity() {
329
+ if (!this.initialized) this.init();
330
+
331
+ const types = new Map();
332
+ for (const [, pattern] of this.aggregatedPatterns) {
333
+ if (!types.has(pattern.type)) {
334
+ types.set(pattern.type, { variations: [], consensus: null });
335
+ }
336
+ types.get(pattern.type).variations.push(pattern);
337
+ }
338
+
339
+ const analysis = {
340
+ totalPatternTypes: types.size,
341
+ typesWithConsensus: 0,
342
+ typesWithoutConsensus: 0,
343
+ typeAnalysis: {},
344
+ };
345
+
346
+ for (const [type, data] of types) {
347
+ const sorted = data.variations.sort((a, b) => b.confidence - a.confidence);
348
+ const dominant = sorted[0];
349
+ const hasConsensus = dominant && dominant.isConsensus;
350
+
351
+ if (hasConsensus) {
352
+ analysis.typesWithConsensus++;
353
+ } else {
354
+ analysis.typesWithoutConsensus++;
355
+ }
356
+
357
+ analysis.typeAnalysis[type] = {
358
+ variationCount: data.variations.length,
359
+ hasConsensus,
360
+ dominant: dominant ? dominant.pattern : null,
361
+ dominantConfidence: dominant ? dominant.confidence : 0,
362
+ alternatives: sorted.slice(1).map(p => ({
363
+ pattern: p.pattern,
364
+ confidence: p.confidence,
365
+ })),
366
+ };
367
+ }
368
+
369
+ return analysis;
370
+ }
371
+
372
+ /**
373
+ * Get recommendations for a new project based on consensus
374
+ * @returns {object} Recommended patterns by type
375
+ */
376
+ getRecommendations() {
377
+ if (!this.initialized) this.init();
378
+
379
+ const recommendations = {};
380
+ const types = new Set(
381
+ Array.from(this.aggregatedPatterns.values()).map(p => p.type),
382
+ );
383
+
384
+ for (const type of types) {
385
+ const dominant = this.getDominantPattern(type);
386
+ if (dominant && dominant.confidence >= 0.6) {
387
+ recommendations[type] = {
388
+ recommended: dominant.pattern,
389
+ confidence: dominant.confidence,
390
+ adoptedBy: dominant.projectCount,
391
+ consensusLevel: dominant.consensusLevel,
392
+ };
393
+ }
394
+ }
395
+
396
+ return recommendations;
397
+ }
398
+
399
+ /**
400
+ * Compare patterns between two projects
401
+ * @param {string} project1 - First project name
402
+ * @param {string} project2 - Second project name
403
+ * @returns {object} Comparison analysis
404
+ */
405
+ compareProjects(project1, project2) {
406
+ if (!this.initialized) this.init();
407
+
408
+ const patterns1 = this.projectPatterns.get(project1) || new Set();
409
+ const patterns2 = this.projectPatterns.get(project2) || new Set();
410
+
411
+ const common = new Set();
412
+ const onlyIn1 = new Set();
413
+ const onlyIn2 = new Set();
414
+
415
+ for (const key of patterns1) {
416
+ if (patterns2.has(key)) {
417
+ common.add(key);
418
+ } else {
419
+ onlyIn1.add(key);
420
+ }
421
+ }
422
+
423
+ for (const key of patterns2) {
424
+ if (!patterns1.has(key)) {
425
+ onlyIn2.add(key);
426
+ }
427
+ }
428
+
429
+ const getPatternDetails = (keys) => Array.from(keys)
430
+ .map(key => this.aggregatedPatterns.get(key))
431
+ .filter(Boolean)
432
+ .map(p => ({ type: p.type, pattern: p.pattern, confidence: p.confidence }));
433
+
434
+ return {
435
+ project1,
436
+ project2,
437
+ similarity: patterns1.size + patterns2.size > 0
438
+ ? (common.size * 2) / (patterns1.size + patterns2.size)
439
+ : 0,
440
+ common: getPatternDetails(common),
441
+ onlyInFirst: getPatternDetails(onlyIn1),
442
+ onlyInSecond: getPatternDetails(onlyIn2),
443
+ };
444
+ }
445
+
446
+ // ==================== UTILITIES ====================
447
+
448
+ /**
449
+ * Get aggregator statistics
450
+ * @returns {object} Statistics
451
+ */
452
+ getStats() {
453
+ if (!this.initialized) this.init();
454
+
455
+ const patterns = Array.from(this.aggregatedPatterns.values());
456
+
457
+ return {
458
+ totalAggregatedPatterns: patterns.length,
459
+ consensusPatterns: patterns.filter(p => p.isConsensus).length,
460
+ outlierPatterns: patterns.filter(p => p.isOutlier).length,
461
+ strongConsensus: patterns.filter(
462
+ p => p.consensusLevel === 'strong',
463
+ ).length,
464
+ moderateConsensus: patterns.filter(
465
+ p => p.consensusLevel === 'moderate',
466
+ ).length,
467
+ trackedProjects: this.projectPatterns.size,
468
+ patternTypes: [...new Set(patterns.map(p => p.type))],
469
+ };
470
+ }
471
+
472
+ /**
473
+ * Refresh aggregation from global memory
474
+ */
475
+ refresh() {
476
+ this.aggregatedPatterns.clear();
477
+ this.projectPatterns.clear();
478
+ this.globalMemory.init();
479
+ this._analyzePatterns();
480
+ }
481
+ }
482
+
483
+ module.exports = {
484
+ PatternAggregator,
485
+ CONSENSUS_THRESHOLDS,
486
+ CONFIDENCE_FACTORS,
487
+ };