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,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
+ };