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,501 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { GlobalMemory } = require('./global-memory');
|
|
5
|
+
const { PatternAggregator } = require('./pattern-aggregator');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Export format version
|
|
9
|
+
*/
|
|
10
|
+
const EXPORT_VERSION = '1.0.0';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Conflict resolution strategies
|
|
14
|
+
*/
|
|
15
|
+
const CONFLICT_STRATEGIES = {
|
|
16
|
+
MAJORITY: 'majority', // Use pattern with most support
|
|
17
|
+
HIGHEST_CONFIDENCE: 'highest_confidence', // Use highest confidence pattern
|
|
18
|
+
NEWEST: 'newest', // Use most recently updated
|
|
19
|
+
MERGE_ALL: 'merge_all', // Keep all patterns
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* TeamSync - Export/import for team pattern sharing
|
|
24
|
+
*
|
|
25
|
+
* Enables teams to share learned patterns, preferences, and
|
|
26
|
+
* expertise across multiple developers.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const sync = new TeamSync();
|
|
30
|
+
*
|
|
31
|
+
* // Export team data
|
|
32
|
+
* const teamData = sync.exportForTeam('engineering');
|
|
33
|
+
* fs.writeFileSync('team-patterns.json', JSON.stringify(teamData));
|
|
34
|
+
*
|
|
35
|
+
* // Import team data
|
|
36
|
+
* sync.importFromTeam(teamData, { strategy: 'majority' });
|
|
37
|
+
*/
|
|
38
|
+
class TeamSync {
|
|
39
|
+
/**
|
|
40
|
+
* @param {GlobalMemory} [globalMemory] - Optional global memory instance
|
|
41
|
+
*/
|
|
42
|
+
constructor(globalMemory = null) {
|
|
43
|
+
this.globalMemory = globalMemory || new GlobalMemory();
|
|
44
|
+
this.aggregator = null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get or create pattern aggregator
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
_getAggregator() {
|
|
52
|
+
if (!this.aggregator) {
|
|
53
|
+
this.aggregator = new PatternAggregator(this.globalMemory);
|
|
54
|
+
}
|
|
55
|
+
return this.aggregator;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ==================== EXPORT ====================
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Export global memory for team sharing
|
|
62
|
+
* @param {string} teamName - Name of the team
|
|
63
|
+
* @param {object} [options] - Export options
|
|
64
|
+
* @param {number} [options.minConfidence=0.5] - Minimum confidence to include
|
|
65
|
+
* @param {boolean} [options.includeExpertise=true] - Include expertise
|
|
66
|
+
* @param {boolean} [options.includePreferences=true] - Include preferences
|
|
67
|
+
* @param {boolean} [options.includeProjects=false] - Include project list
|
|
68
|
+
* @returns {object} Exportable team data
|
|
69
|
+
*/
|
|
70
|
+
exportForTeam(teamName, options = {}) {
|
|
71
|
+
const {
|
|
72
|
+
minConfidence = 0.5,
|
|
73
|
+
includeExpertise = true,
|
|
74
|
+
includePreferences = true,
|
|
75
|
+
includeProjects = false,
|
|
76
|
+
} = options;
|
|
77
|
+
|
|
78
|
+
this.globalMemory.init();
|
|
79
|
+
|
|
80
|
+
// Filter patterns by confidence
|
|
81
|
+
const patterns = this.globalMemory.patterns
|
|
82
|
+
.filter(p => (p.confidence || 0.5) >= minConfidence)
|
|
83
|
+
.map(p => ({
|
|
84
|
+
type: p.type,
|
|
85
|
+
pattern: p.pattern,
|
|
86
|
+
confidence: p.confidence,
|
|
87
|
+
occurrences: p.occurrences || 1,
|
|
88
|
+
sources: p.sources || [],
|
|
89
|
+
}));
|
|
90
|
+
|
|
91
|
+
const exportData = {
|
|
92
|
+
version: EXPORT_VERSION,
|
|
93
|
+
teamName,
|
|
94
|
+
exportedAt: new Date().toISOString(),
|
|
95
|
+
exportedBy: process.env.USER || process.env.USERNAME || 'unknown',
|
|
96
|
+
patterns,
|
|
97
|
+
patternCount: patterns.length,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
if (includeExpertise) {
|
|
101
|
+
exportData.expertise = { ...this.globalMemory.expertise };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (includePreferences) {
|
|
105
|
+
exportData.preferences = this.globalMemory.getAllPreferences();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (includeProjects) {
|
|
109
|
+
exportData.projects = this.globalMemory.projects.map(p => ({
|
|
110
|
+
name: p.name,
|
|
111
|
+
path: p.path,
|
|
112
|
+
languages: p.metadata?.languages || [],
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Calculate stats
|
|
117
|
+
exportData.stats = {
|
|
118
|
+
uniquePatternTypes: [...new Set(patterns.map(p => p.type))].length,
|
|
119
|
+
totalSources: [...new Set(patterns.flatMap(p => p.sources))].length,
|
|
120
|
+
expertiseAreas: includeExpertise ? Object.keys(exportData.expertise).length : 0,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
return exportData;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Export only high-confidence consensus patterns
|
|
128
|
+
* @param {string} teamName - Team name
|
|
129
|
+
* @returns {object} Consensus patterns export
|
|
130
|
+
*/
|
|
131
|
+
exportConsensusPatterns(teamName) {
|
|
132
|
+
this.globalMemory.init();
|
|
133
|
+
const aggregator = this._getAggregator();
|
|
134
|
+
aggregator.init();
|
|
135
|
+
|
|
136
|
+
const consensus = aggregator.getConsensusPatterns('moderate');
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
version: EXPORT_VERSION,
|
|
140
|
+
teamName,
|
|
141
|
+
exportedAt: new Date().toISOString(),
|
|
142
|
+
type: 'consensus',
|
|
143
|
+
patterns: consensus.map(p => ({
|
|
144
|
+
type: p.type,
|
|
145
|
+
pattern: p.pattern,
|
|
146
|
+
confidence: p.confidence,
|
|
147
|
+
consensusLevel: p.consensusLevel,
|
|
148
|
+
projectCount: p.projectCount,
|
|
149
|
+
})),
|
|
150
|
+
patternCount: consensus.length,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ==================== IMPORT ====================
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Import team data into global memory
|
|
158
|
+
* @param {object} teamData - Data exported from exportForTeam
|
|
159
|
+
* @param {object} [options] - Import options
|
|
160
|
+
* @param {string} [options.strategy='majority'] - Conflict resolution strategy
|
|
161
|
+
* @param {number} [options.confidenceBoost=0.1] - Boost for team patterns
|
|
162
|
+
* @param {boolean} [options.preserveLocal=true] - Keep local patterns
|
|
163
|
+
* @returns {object} Import summary
|
|
164
|
+
*/
|
|
165
|
+
importFromTeam(teamData, options = {}) {
|
|
166
|
+
const {
|
|
167
|
+
strategy = CONFLICT_STRATEGIES.MAJORITY,
|
|
168
|
+
confidenceBoost = 0.1,
|
|
169
|
+
preserveLocal = true,
|
|
170
|
+
} = options;
|
|
171
|
+
|
|
172
|
+
if (!teamData || !teamData.patterns) {
|
|
173
|
+
return { success: false, error: 'Invalid team data' };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this.globalMemory.init();
|
|
177
|
+
|
|
178
|
+
const summary = {
|
|
179
|
+
patternsImported: 0,
|
|
180
|
+
patternsSkipped: 0,
|
|
181
|
+
conflictsResolved: 0,
|
|
182
|
+
expertiseImported: 0,
|
|
183
|
+
preferencesImported: 0,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Import patterns
|
|
187
|
+
for (const pattern of teamData.patterns) {
|
|
188
|
+
const existing = this.globalMemory.patterns.find(
|
|
189
|
+
p => p.type === pattern.type && p.pattern === pattern.pattern,
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
if (existing) {
|
|
193
|
+
// Resolve conflict
|
|
194
|
+
const resolved = this._resolveConflict(existing, pattern, strategy);
|
|
195
|
+
if (resolved !== existing) {
|
|
196
|
+
Object.assign(existing, resolved);
|
|
197
|
+
summary.conflictsResolved++;
|
|
198
|
+
} else {
|
|
199
|
+
summary.patternsSkipped++;
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
// Add new pattern with team boost
|
|
203
|
+
this.globalMemory.recordPattern({
|
|
204
|
+
type: pattern.type,
|
|
205
|
+
pattern: pattern.pattern,
|
|
206
|
+
confidence: Math.min(0.99, (pattern.confidence || 0.5) + confidenceBoost),
|
|
207
|
+
source: teamData.teamName || 'team',
|
|
208
|
+
});
|
|
209
|
+
summary.patternsImported++;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Import expertise
|
|
214
|
+
if (teamData.expertise) {
|
|
215
|
+
for (const [domain, data] of Object.entries(teamData.expertise)) {
|
|
216
|
+
const level = typeof data === 'number' ? data : data.level;
|
|
217
|
+
if (level) {
|
|
218
|
+
this.globalMemory.addExpertise(domain, level);
|
|
219
|
+
summary.expertiseImported++;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Import preferences (only if not already set locally)
|
|
225
|
+
if (teamData.preferences && !preserveLocal) {
|
|
226
|
+
for (const [key, value] of Object.entries(teamData.preferences)) {
|
|
227
|
+
if (!this.globalMemory.getPreference(key)) {
|
|
228
|
+
this.globalMemory.setPreference(key, value);
|
|
229
|
+
summary.preferencesImported++;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return { success: true, summary };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Resolve a conflict between local and team patterns
|
|
239
|
+
* @private
|
|
240
|
+
*/
|
|
241
|
+
_resolveConflict(local, team, strategy) {
|
|
242
|
+
switch (strategy) {
|
|
243
|
+
case CONFLICT_STRATEGIES.HIGHEST_CONFIDENCE:
|
|
244
|
+
return (team.confidence || 0.5) > (local.confidence || 0.5) ? team : local;
|
|
245
|
+
|
|
246
|
+
case CONFLICT_STRATEGIES.NEWEST:
|
|
247
|
+
const localDate = local.lastSeen ? new Date(local.lastSeen) : new Date(0);
|
|
248
|
+
const teamDate = team.exportedAt ? new Date(team.exportedAt) : new Date(0);
|
|
249
|
+
return teamDate > localDate ? team : local;
|
|
250
|
+
|
|
251
|
+
case CONFLICT_STRATEGIES.MERGE_ALL:
|
|
252
|
+
// Merge sources and boost confidence
|
|
253
|
+
return {
|
|
254
|
+
...local,
|
|
255
|
+
confidence: Math.min(0.99, Math.max(local.confidence || 0.5, team.confidence || 0.5) + 0.05),
|
|
256
|
+
sources: [...new Set([...(local.sources || []), ...(team.sources || [])])],
|
|
257
|
+
occurrences: (local.occurrences || 1) + (team.occurrences || 1),
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
case CONFLICT_STRATEGIES.MAJORITY:
|
|
261
|
+
default:
|
|
262
|
+
// Prefer the one with more sources/occurrences
|
|
263
|
+
const localWeight = (local.sources?.length || 0) + (local.occurrences || 1);
|
|
264
|
+
const teamWeight = (team.sources?.length || 0) + (team.occurrences || 1);
|
|
265
|
+
return teamWeight > localWeight ? team : local;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ==================== TEAM AGGREGATION ====================
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Merge multiple team exports into one
|
|
273
|
+
* @param {Array<object>} teamExports - Array of team export data
|
|
274
|
+
* @returns {object} Merged team data
|
|
275
|
+
*/
|
|
276
|
+
mergeTeamExports(teamExports) {
|
|
277
|
+
if (!teamExports || teamExports.length === 0) {
|
|
278
|
+
return { success: false, error: 'No team data provided' };
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const merged = {
|
|
282
|
+
version: EXPORT_VERSION,
|
|
283
|
+
teamName: 'merged',
|
|
284
|
+
exportedAt: new Date().toISOString(),
|
|
285
|
+
patterns: [],
|
|
286
|
+
expertise: {},
|
|
287
|
+
preferences: {},
|
|
288
|
+
sourceTeams: [],
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// Aggregate patterns
|
|
292
|
+
const patternMap = new Map();
|
|
293
|
+
|
|
294
|
+
for (const teamData of teamExports) {
|
|
295
|
+
if (!teamData || !teamData.patterns) continue;
|
|
296
|
+
|
|
297
|
+
merged.sourceTeams.push(teamData.teamName || 'unknown');
|
|
298
|
+
|
|
299
|
+
for (const pattern of teamData.patterns) {
|
|
300
|
+
const key = `${pattern.type}::${pattern.pattern}`;
|
|
301
|
+
|
|
302
|
+
if (patternMap.has(key)) {
|
|
303
|
+
const existing = patternMap.get(key);
|
|
304
|
+
existing.confidence = Math.max(existing.confidence, pattern.confidence || 0.5);
|
|
305
|
+
existing.occurrences += pattern.occurrences || 1;
|
|
306
|
+
existing.teams.add(teamData.teamName || 'unknown');
|
|
307
|
+
} else {
|
|
308
|
+
patternMap.set(key, {
|
|
309
|
+
type: pattern.type,
|
|
310
|
+
pattern: pattern.pattern,
|
|
311
|
+
confidence: pattern.confidence || 0.5,
|
|
312
|
+
occurrences: pattern.occurrences || 1,
|
|
313
|
+
teams: new Set([teamData.teamName || 'unknown']),
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Merge expertise
|
|
319
|
+
if (teamData.expertise) {
|
|
320
|
+
for (const [domain, data] of Object.entries(teamData.expertise)) {
|
|
321
|
+
const level = typeof data === 'number' ? data : data.level;
|
|
322
|
+
if (level) {
|
|
323
|
+
if (!merged.expertise[domain]) {
|
|
324
|
+
merged.expertise[domain] = { level: 0, count: 0 };
|
|
325
|
+
}
|
|
326
|
+
merged.expertise[domain].level += level;
|
|
327
|
+
merged.expertise[domain].count += 1;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Merge preferences (first wins)
|
|
333
|
+
if (teamData.preferences) {
|
|
334
|
+
for (const [key, value] of Object.entries(teamData.preferences)) {
|
|
335
|
+
if (!merged.preferences[key]) {
|
|
336
|
+
merged.preferences[key] = value;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Finalize patterns
|
|
343
|
+
merged.patterns = Array.from(patternMap.values()).map(p => ({
|
|
344
|
+
type: p.type,
|
|
345
|
+
pattern: p.pattern,
|
|
346
|
+
confidence: p.confidence,
|
|
347
|
+
occurrences: p.occurrences,
|
|
348
|
+
teamCount: p.teams.size,
|
|
349
|
+
}));
|
|
350
|
+
|
|
351
|
+
// Average expertise levels
|
|
352
|
+
for (const domain of Object.keys(merged.expertise)) {
|
|
353
|
+
const data = merged.expertise[domain];
|
|
354
|
+
merged.expertise[domain] = {
|
|
355
|
+
level: data.level / data.count,
|
|
356
|
+
teamCount: data.count,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
merged.patternCount = merged.patterns.length;
|
|
361
|
+
merged.stats = {
|
|
362
|
+
teamsIncluded: merged.sourceTeams.length,
|
|
363
|
+
totalPatterns: merged.patterns.length,
|
|
364
|
+
crossTeamPatterns: merged.patterns.filter(p => p.teamCount > 1).length,
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
return merged;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get recommendations based on team patterns
|
|
372
|
+
* @param {object} teamData - Team export data
|
|
373
|
+
* @returns {object} Recommendations
|
|
374
|
+
*/
|
|
375
|
+
getTeamRecommendations(teamData) {
|
|
376
|
+
if (!teamData || !teamData.patterns) {
|
|
377
|
+
return { error: 'Invalid team data' };
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const recommendations = {};
|
|
381
|
+
const typeMap = new Map();
|
|
382
|
+
|
|
383
|
+
// Group by type
|
|
384
|
+
for (const pattern of teamData.patterns) {
|
|
385
|
+
if (!typeMap.has(pattern.type)) {
|
|
386
|
+
typeMap.set(pattern.type, []);
|
|
387
|
+
}
|
|
388
|
+
typeMap.get(pattern.type).push(pattern);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Get top pattern per type
|
|
392
|
+
for (const [type, patterns] of typeMap) {
|
|
393
|
+
patterns.sort((a, b) => (b.confidence || 0.5) - (a.confidence || 0.5));
|
|
394
|
+
const top = patterns[0];
|
|
395
|
+
|
|
396
|
+
recommendations[type] = {
|
|
397
|
+
recommended: top.pattern,
|
|
398
|
+
confidence: top.confidence,
|
|
399
|
+
alternatives: patterns.slice(1, 3).map(p => p.pattern),
|
|
400
|
+
teamSupport: top.teamCount || top.occurrences || 1,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return {
|
|
405
|
+
teamName: teamData.teamName,
|
|
406
|
+
generatedAt: new Date().toISOString(),
|
|
407
|
+
recommendations,
|
|
408
|
+
recommendationCount: Object.keys(recommendations).length,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// ==================== FILE OPERATIONS ====================
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Export team data to file
|
|
416
|
+
* @param {string} filePath - File path to write
|
|
417
|
+
* @param {string} teamName - Team name
|
|
418
|
+
* @param {object} [options] - Export options
|
|
419
|
+
*/
|
|
420
|
+
exportToFile(filePath, teamName, options = {}) {
|
|
421
|
+
const data = this.exportForTeam(teamName, options);
|
|
422
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
423
|
+
return { success: true, path: filePath, patternCount: data.patternCount };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Import team data from file
|
|
428
|
+
* @param {string} filePath - File path to read
|
|
429
|
+
* @param {object} [options] - Import options
|
|
430
|
+
* @returns {object} Import summary
|
|
431
|
+
*/
|
|
432
|
+
importFromFile(filePath, options = {}) {
|
|
433
|
+
if (!fs.existsSync(filePath)) {
|
|
434
|
+
return { success: false, error: 'File not found' };
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
try {
|
|
438
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
439
|
+
return this.importFromTeam(data, options);
|
|
440
|
+
} catch (err) {
|
|
441
|
+
return { success: false, error: `Failed to parse file: ${err.message}` };
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// ==================== UTILITIES ====================
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Validate team export data
|
|
449
|
+
* @param {object} data - Data to validate
|
|
450
|
+
* @returns {object} Validation result
|
|
451
|
+
*/
|
|
452
|
+
validateExport(data) {
|
|
453
|
+
const errors = [];
|
|
454
|
+
|
|
455
|
+
if (!data) {
|
|
456
|
+
errors.push('Data is null or undefined');
|
|
457
|
+
return { valid: false, errors };
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (!data.version) {
|
|
461
|
+
errors.push('Missing version field');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (!data.patterns || !Array.isArray(data.patterns)) {
|
|
465
|
+
errors.push('Missing or invalid patterns array');
|
|
466
|
+
} else {
|
|
467
|
+
for (let i = 0; i < data.patterns.length; i++) {
|
|
468
|
+
const p = data.patterns[i];
|
|
469
|
+
if (!p.type) errors.push(`Pattern ${i} missing type`);
|
|
470
|
+
if (!p.pattern) errors.push(`Pattern ${i} missing pattern value`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return {
|
|
475
|
+
valid: errors.length === 0,
|
|
476
|
+
errors,
|
|
477
|
+
version: data.version,
|
|
478
|
+
patternCount: data.patterns?.length || 0,
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Get sync statistics
|
|
484
|
+
* @returns {object} Statistics
|
|
485
|
+
*/
|
|
486
|
+
getStats() {
|
|
487
|
+
this.globalMemory.init();
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
localPatterns: this.globalMemory.patterns.length,
|
|
491
|
+
localExpertise: Object.keys(this.globalMemory.expertise).length,
|
|
492
|
+
localProjects: this.globalMemory.projects.length,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
module.exports = {
|
|
498
|
+
TeamSync,
|
|
499
|
+
CONFLICT_STRATEGIES,
|
|
500
|
+
EXPORT_VERSION,
|
|
501
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile Module
|
|
3
|
+
*
|
|
4
|
+
* Developer Digital Twin - models patterns, preferences, and expertise.
|
|
5
|
+
* Central export for all profile-related functionality.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { ProfileManager, DEFAULT_PROFILE } = require('./profile-manager');
|
|
9
|
+
const { PatternLearner, PATTERN_TYPES, PATTERN_SIGNALS } = require('./pattern-learner');
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
// Classes
|
|
13
|
+
ProfileManager,
|
|
14
|
+
PatternLearner,
|
|
15
|
+
|
|
16
|
+
// Constants
|
|
17
|
+
DEFAULT_PROFILE,
|
|
18
|
+
PATTERN_TYPES,
|
|
19
|
+
PATTERN_SIGNALS,
|
|
20
|
+
|
|
21
|
+
// Factory function
|
|
22
|
+
createProfileManager: (profileDir, options) => new ProfileManager(profileDir, options),
|
|
23
|
+
createPatternLearner: () => new PatternLearner(),
|
|
24
|
+
};
|