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.
- package/LICENSE +27 -0
- package/README.md +567 -0
- package/bin/install.js +348 -0
- package/commands/gywd/add-phase.md +207 -0
- package/commands/gywd/anticipate.md +271 -0
- package/commands/gywd/bootstrap.md +336 -0
- package/commands/gywd/challenge.md +344 -0
- package/commands/gywd/check-drift.md +144 -0
- package/commands/gywd/complete-milestone.md +106 -0
- package/commands/gywd/consider-issues.md +202 -0
- package/commands/gywd/context.md +93 -0
- package/commands/gywd/create-roadmap.md +115 -0
- package/commands/gywd/deps.md +169 -0
- package/commands/gywd/digest.md +138 -0
- package/commands/gywd/discuss-milestone.md +47 -0
- package/commands/gywd/discuss-phase.md +60 -0
- package/commands/gywd/execute-plan.md +161 -0
- package/commands/gywd/extract-decisions.md +325 -0
- package/commands/gywd/health.md +150 -0
- package/commands/gywd/help.md +556 -0
- package/commands/gywd/history.md +278 -0
- package/commands/gywd/impact.md +317 -0
- package/commands/gywd/init.md +95 -0
- package/commands/gywd/insert-phase.md +227 -0
- package/commands/gywd/list-phase-assumptions.md +50 -0
- package/commands/gywd/map-codebase.md +84 -0
- package/commands/gywd/memory.md +159 -0
- package/commands/gywd/new-milestone.md +59 -0
- package/commands/gywd/new-project.md +315 -0
- package/commands/gywd/pause-work.md +123 -0
- package/commands/gywd/plan-fix.md +205 -0
- package/commands/gywd/plan-phase.md +93 -0
- package/commands/gywd/preview-plan.md +139 -0
- package/commands/gywd/profile.md +363 -0
- package/commands/gywd/progress.md +317 -0
- package/commands/gywd/remove-phase.md +338 -0
- package/commands/gywd/research-phase.md +91 -0
- package/commands/gywd/resume-work.md +40 -0
- package/commands/gywd/rollback.md +179 -0
- package/commands/gywd/status.md +42 -0
- package/commands/gywd/sync-github.md +234 -0
- package/commands/gywd/verify-work.md +71 -0
- package/commands/gywd/why.md +251 -0
- package/docs/COMMANDS.md +722 -0
- package/docs/CONTRIBUTING.md +342 -0
- package/docs/EXAMPLES.md +535 -0
- package/docs/GETTING-STARTED.md +262 -0
- package/docs/README.md +55 -0
- package/docs/RELEASING.md +159 -0
- package/get-your-work-done/core/agent-patterns.md +331 -0
- package/get-your-work-done/core/architecture.md +334 -0
- package/get-your-work-done/core/context-model-schema.json +154 -0
- package/get-your-work-done/core/decisions-schema.json +193 -0
- package/get-your-work-done/core/learning-state-schema.json +133 -0
- package/get-your-work-done/core/profile-schema.json +257 -0
- package/get-your-work-done/references/adaptive-decomposition.md +175 -0
- package/get-your-work-done/references/checkpoints.md +287 -0
- package/get-your-work-done/references/confidence-scoring.md +169 -0
- package/get-your-work-done/references/continuation-format.md +255 -0
- package/get-your-work-done/references/git-integration.md +254 -0
- package/get-your-work-done/references/plan-format.md +428 -0
- package/get-your-work-done/references/principles.md +157 -0
- package/get-your-work-done/references/questioning.md +162 -0
- package/get-your-work-done/references/research-pitfalls.md +215 -0
- package/get-your-work-done/references/scope-estimation.md +172 -0
- package/get-your-work-done/references/tdd.md +263 -0
- package/get-your-work-done/templates/codebase/architecture.md +255 -0
- package/get-your-work-done/templates/codebase/concerns.md +310 -0
- package/get-your-work-done/templates/codebase/conventions.md +307 -0
- package/get-your-work-done/templates/codebase/integrations.md +280 -0
- package/get-your-work-done/templates/codebase/stack.md +186 -0
- package/get-your-work-done/templates/codebase/structure.md +285 -0
- package/get-your-work-done/templates/codebase/testing.md +480 -0
- package/get-your-work-done/templates/config.json +18 -0
- package/get-your-work-done/templates/context.md +161 -0
- package/get-your-work-done/templates/continue-here.md +78 -0
- package/get-your-work-done/templates/discovery.md +146 -0
- package/get-your-work-done/templates/issues.md +32 -0
- package/get-your-work-done/templates/milestone-archive.md +123 -0
- package/get-your-work-done/templates/milestone-context.md +93 -0
- package/get-your-work-done/templates/milestone.md +115 -0
- package/get-your-work-done/templates/phase-prompt.md +303 -0
- package/get-your-work-done/templates/project.md +184 -0
- package/get-your-work-done/templates/research.md +529 -0
- package/get-your-work-done/templates/roadmap.md +196 -0
- package/get-your-work-done/templates/state.md +210 -0
- package/get-your-work-done/templates/summary.md +273 -0
- package/get-your-work-done/templates/uat-issues.md +143 -0
- package/get-your-work-done/workflows/complete-milestone.md +643 -0
- package/get-your-work-done/workflows/create-milestone.md +416 -0
- package/get-your-work-done/workflows/create-roadmap.md +481 -0
- package/get-your-work-done/workflows/discovery-phase.md +293 -0
- package/get-your-work-done/workflows/discuss-milestone.md +236 -0
- package/get-your-work-done/workflows/discuss-phase.md +247 -0
- package/get-your-work-done/workflows/execute-phase.md +1625 -0
- package/get-your-work-done/workflows/list-phase-assumptions.md +178 -0
- package/get-your-work-done/workflows/map-codebase.md +434 -0
- package/get-your-work-done/workflows/plan-phase.md +488 -0
- package/get-your-work-done/workflows/research-phase.md +436 -0
- package/get-your-work-done/workflows/resume-project.md +287 -0
- package/get-your-work-done/workflows/transition.md +580 -0
- package/get-your-work-done/workflows/verify-work.md +202 -0
- package/lib/automation/dependency-analyzer.js +635 -0
- package/lib/automation/doc-generator.js +643 -0
- package/lib/automation/index.js +42 -0
- package/lib/automation/test-generator.js +628 -0
- package/lib/context/context-analyzer.js +554 -0
- package/lib/context/context-cache.js +426 -0
- package/lib/context/context-predictor.js +622 -0
- package/lib/context/index.js +44 -0
- package/lib/memory/confidence-calibrator.js +484 -0
- package/lib/memory/feedback-collector.js +551 -0
- package/lib/memory/global-memory.js +465 -0
- package/lib/memory/index.js +75 -0
- package/lib/memory/pattern-aggregator.js +487 -0
- package/lib/memory/team-sync.js +501 -0
- package/lib/profile/index.js +24 -0
- package/lib/profile/pattern-learner.js +303 -0
- package/lib/profile/profile-manager.js +445 -0
- package/lib/questioning/index.js +49 -0
- package/lib/questioning/question-engine.js +311 -0
- package/lib/questioning/question-templates.js +315 -0
- package/lib/validators/command-validator.js +188 -0
- package/lib/validators/index.js +29 -0
- package/lib/validators/schema-validator.js +183 -0
- 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
|
+
};
|