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,622 @@
1
+ /**
2
+ * Context Predictor
3
+ *
4
+ * Predicts what context a developer needs based on patterns,
5
+ * relationships, and access history. The "anticipate" brain.
6
+ */
7
+
8
+ const { ContextAnalyzer, RELATIONSHIP_WEIGHTS: _RELATIONSHIP_WEIGHTS } = require('./context-analyzer');
9
+
10
+ /**
11
+ * Prediction confidence levels
12
+ */
13
+ const CONFIDENCE = {
14
+ HIGH: 'high',
15
+ MEDIUM: 'medium',
16
+ LOW: 'low',
17
+ };
18
+
19
+ /**
20
+ * Context types
21
+ */
22
+ const CONTEXT_TYPES = {
23
+ FILE: 'file',
24
+ DECISION: 'decision',
25
+ PATTERN: 'pattern',
26
+ DOCUMENTATION: 'documentation',
27
+ HISTORY: 'history',
28
+ };
29
+
30
+ /**
31
+ * Access pattern tracker
32
+ */
33
+ class AccessPattern {
34
+ constructor(maxSize = 1000) {
35
+ this.accesses = [];
36
+ this.sessions = [];
37
+ this.currentSession = [];
38
+ this.maxSize = maxSize;
39
+ this.coOccurrence = new Map();
40
+ }
41
+
42
+ /**
43
+ * Record a file access
44
+ * @param {string} file - File path
45
+ * @param {string} context - Access context (e.g., 'read', 'edit', 'search')
46
+ */
47
+ recordAccess(file, context = 'read') {
48
+ const entry = {
49
+ file,
50
+ timestamp: Date.now(),
51
+ context,
52
+ };
53
+
54
+ this.accesses.push(entry);
55
+ this.currentSession.push(file);
56
+
57
+ // Trim if exceeding max size
58
+ if (this.accesses.length > this.maxSize) {
59
+ this.accesses = this.accesses.slice(-this.maxSize);
60
+ }
61
+
62
+ // Update co-occurrence with recent accesses
63
+ const recentFiles = this.currentSession.slice(-5);
64
+ for (const recent of recentFiles) {
65
+ if (recent !== file) {
66
+ this.incrementCoOccurrence(file, recent);
67
+ }
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Increment co-occurrence count
73
+ * @param {string} file1 - First file
74
+ * @param {string} file2 - Second file
75
+ */
76
+ incrementCoOccurrence(file1, file2) {
77
+ if (!this.coOccurrence.has(file1)) {
78
+ this.coOccurrence.set(file1, new Map());
79
+ }
80
+ if (!this.coOccurrence.has(file2)) {
81
+ this.coOccurrence.set(file2, new Map());
82
+ }
83
+
84
+ const count1 = this.coOccurrence.get(file1).get(file2) || 0;
85
+ this.coOccurrence.get(file1).set(file2, count1 + 1);
86
+
87
+ const count2 = this.coOccurrence.get(file2).get(file1) || 0;
88
+ this.coOccurrence.get(file2).set(file1, count2 + 1);
89
+ }
90
+
91
+ /**
92
+ * End current session and start new one
93
+ */
94
+ endSession() {
95
+ if (this.currentSession.length > 0) {
96
+ this.sessions.push([...this.currentSession]);
97
+ this.currentSession = [];
98
+
99
+ // Keep only last 50 sessions
100
+ if (this.sessions.length > 50) {
101
+ this.sessions = this.sessions.slice(-50);
102
+ }
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Get files frequently accessed with given file
108
+ * @param {string} file - File path
109
+ * @param {number} limit - Maximum results
110
+ * @returns {Array<{file: string, count: number}>}
111
+ */
112
+ getFrequentlyAccessedWith(file, limit = 10) {
113
+ const coOccurMap = this.coOccurrence.get(file);
114
+ if (!coOccurMap) return [];
115
+
116
+ const results = [];
117
+ for (const [otherFile, count] of coOccurMap) {
118
+ results.push({ file: otherFile, count });
119
+ }
120
+
121
+ results.sort((a, b) => b.count - a.count);
122
+ return results.slice(0, limit);
123
+ }
124
+
125
+ /**
126
+ * Get recently accessed files
127
+ * @param {number} limit - Maximum results
128
+ * @returns {string[]}
129
+ */
130
+ getRecentFiles(limit = 10) {
131
+ const seen = new Set();
132
+ const result = [];
133
+
134
+ for (let i = this.accesses.length - 1; i >= 0 && result.length < limit; i--) {
135
+ const file = this.accesses[i].file;
136
+ if (!seen.has(file)) {
137
+ seen.add(file);
138
+ result.push(file);
139
+ }
140
+ }
141
+
142
+ return result;
143
+ }
144
+
145
+ /**
146
+ * Get session patterns (files commonly accessed together)
147
+ * @returns {Array<{files: string[], frequency: number}>}
148
+ */
149
+ getSessionPatterns() {
150
+ const patterns = new Map();
151
+
152
+ for (const session of this.sessions) {
153
+ // Look for pairs that appear together
154
+ for (let i = 0; i < session.length; i++) {
155
+ for (let j = i + 1; j < session.length; j++) {
156
+ const key = [session[i], session[j]].sort().join('|');
157
+ patterns.set(key, (patterns.get(key) || 0) + 1);
158
+ }
159
+ }
160
+ }
161
+
162
+ const result = [];
163
+ for (const [key, frequency] of patterns) {
164
+ if (frequency >= 2) { // Appeared in at least 2 sessions
165
+ result.push({
166
+ files: key.split('|'),
167
+ frequency,
168
+ });
169
+ }
170
+ }
171
+
172
+ result.sort((a, b) => b.frequency - a.frequency);
173
+ return result.slice(0, 20);
174
+ }
175
+
176
+ /**
177
+ * Export access data
178
+ * @returns {object}
179
+ */
180
+ export() {
181
+ const coOccur = {};
182
+ for (const [file, map] of this.coOccurrence) {
183
+ coOccur[file] = Object.fromEntries(map);
184
+ }
185
+
186
+ return {
187
+ accesses: this.accesses.slice(-500),
188
+ sessions: this.sessions.slice(-20),
189
+ coOccurrence: coOccur,
190
+ };
191
+ }
192
+
193
+ /**
194
+ * Import access data
195
+ * @param {object} data - Previously exported data
196
+ */
197
+ import(data) {
198
+ if (data.accesses) {
199
+ this.accesses = data.accesses;
200
+ }
201
+ if (data.sessions) {
202
+ this.sessions = data.sessions;
203
+ }
204
+ if (data.coOccurrence) {
205
+ for (const [file, map] of Object.entries(data.coOccurrence)) {
206
+ this.coOccurrence.set(file, new Map(Object.entries(map)));
207
+ }
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Clear all data
213
+ */
214
+ clear() {
215
+ this.accesses = [];
216
+ this.sessions = [];
217
+ this.currentSession = [];
218
+ this.coOccurrence.clear();
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Context Predictor class
224
+ */
225
+ class ContextPredictor {
226
+ constructor() {
227
+ this.analyzer = new ContextAnalyzer();
228
+ this.accessPattern = new AccessPattern();
229
+ this.featureFileMap = new Map(); // feature -> Set<files>
230
+ this.taskHistory = []; // [{task, files, timestamp}]
231
+ }
232
+
233
+ /**
234
+ * Get the context analyzer
235
+ * @returns {ContextAnalyzer}
236
+ */
237
+ getAnalyzer() {
238
+ return this.analyzer;
239
+ }
240
+
241
+ /**
242
+ * Record file access
243
+ * @param {string} file - File path
244
+ * @param {string} context - Access context
245
+ */
246
+ recordAccess(file, context = 'read') {
247
+ this.accessPattern.recordAccess(file, context);
248
+ }
249
+
250
+ /**
251
+ * Record a task with its associated files
252
+ * @param {string} task - Task description
253
+ * @param {string[]} files - Files used for task
254
+ */
255
+ recordTask(task, files) {
256
+ this.taskHistory.push({
257
+ task,
258
+ files,
259
+ timestamp: Date.now(),
260
+ });
261
+
262
+ // Keep last 100 tasks
263
+ if (this.taskHistory.length > 100) {
264
+ this.taskHistory = this.taskHistory.slice(-100);
265
+ }
266
+
267
+ // Extract keywords and map to files
268
+ const keywords = this.extractTaskKeywords(task);
269
+ for (const keyword of keywords) {
270
+ if (!this.featureFileMap.has(keyword)) {
271
+ this.featureFileMap.set(keyword, new Set());
272
+ }
273
+ for (const file of files) {
274
+ this.featureFileMap.get(keyword).add(file);
275
+ }
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Extract keywords from task description
281
+ * @param {string} task - Task description
282
+ * @returns {string[]} Keywords
283
+ */
284
+ extractTaskKeywords(task) {
285
+ const words = task
286
+ .toLowerCase()
287
+ .replace(/[^a-z0-9\s]/g, ' ')
288
+ .split(/\s+/)
289
+ .filter(w => w.length > 2);
290
+
291
+ // Filter common words
292
+ const stopWords = new Set([
293
+ 'the', 'and', 'for', 'add', 'fix', 'update', 'create', 'implement',
294
+ 'make', 'use', 'with', 'from', 'this', 'that', 'will', 'should',
295
+ ]);
296
+
297
+ return words.filter(w => !stopWords.has(w));
298
+ }
299
+
300
+ /**
301
+ * Predict context needed for a task
302
+ * @param {string} task - Task description
303
+ * @param {object} options - Prediction options
304
+ * @returns {object} Predicted context
305
+ */
306
+ predictForTask(task, options = {}) {
307
+ const {
308
+ maxFiles = 10,
309
+ includeDecisions: _includeDecisions = true,
310
+ includePatterns: _includePatterns = true,
311
+ } = options;
312
+
313
+ const predictions = {
314
+ files: [],
315
+ decisions: [],
316
+ patterns: [],
317
+ confidence: CONFIDENCE.MEDIUM,
318
+ reasoning: [],
319
+ };
320
+
321
+ const keywords = this.extractTaskKeywords(task);
322
+ const fileScores = new Map();
323
+
324
+ // Score files based on task keywords
325
+ for (const keyword of keywords) {
326
+ // Check feature-file map from task history
327
+ const featureFiles = this.featureFileMap.get(keyword);
328
+ if (featureFiles) {
329
+ for (const file of featureFiles) {
330
+ const current = fileScores.get(file) || 0;
331
+ fileScores.set(file, current + 0.8);
332
+ }
333
+ predictions.reasoning.push(`Keyword "${keyword}" matched from task history`);
334
+ }
335
+
336
+ // Check analyzer keywords
337
+ const analyzerFiles = this.analyzer.findByKeyword(keyword);
338
+ for (const file of analyzerFiles) {
339
+ const current = fileScores.get(file) || 0;
340
+ fileScores.set(file, current + 0.5);
341
+ }
342
+ if (analyzerFiles.length > 0) {
343
+ predictions.reasoning.push(`Keyword "${keyword}" found in ${analyzerFiles.length} files`);
344
+ }
345
+ }
346
+
347
+ // Add scores from recent access patterns
348
+ const recentFiles = this.accessPattern.getRecentFiles(5);
349
+ for (const file of recentFiles) {
350
+ // Get related files
351
+ const related = this.analyzer.getRelatedFiles(file, 5);
352
+ for (const { file: relatedFile, score } of related) {
353
+ const current = fileScores.get(relatedFile) || 0;
354
+ fileScores.set(relatedFile, current + score * 0.3);
355
+ }
356
+ }
357
+
358
+ // Check session patterns
359
+ const sessionPatterns = this.accessPattern.getSessionPatterns();
360
+ for (const { files: patternFiles } of sessionPatterns.slice(0, 5)) {
361
+ // If one file in pattern is scored, boost the others
362
+ for (const file of patternFiles) {
363
+ if (fileScores.has(file)) {
364
+ for (const otherFile of patternFiles) {
365
+ if (otherFile !== file) {
366
+ const current = fileScores.get(otherFile) || 0;
367
+ fileScores.set(otherFile, current + 0.4);
368
+ }
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+ // Sort and limit results
375
+ const sortedFiles = Array.from(fileScores.entries())
376
+ .map(([file, score]) => ({ file, score }))
377
+ .sort((a, b) => b.score - a.score)
378
+ .slice(0, maxFiles);
379
+
380
+ predictions.files = sortedFiles.map(({ file, score }) => ({
381
+ path: file,
382
+ score,
383
+ confidence: score > 1.5 ? CONFIDENCE.HIGH :
384
+ score > 0.8 ? CONFIDENCE.MEDIUM : CONFIDENCE.LOW,
385
+ type: CONTEXT_TYPES.FILE,
386
+ }));
387
+
388
+ // Determine overall confidence
389
+ if (predictions.files.length > 0) {
390
+ const avgScore = predictions.files.reduce((a, b) => a + b.score, 0) / predictions.files.length;
391
+ predictions.confidence = avgScore > 1.5 ? CONFIDENCE.HIGH :
392
+ avgScore > 0.8 ? CONFIDENCE.MEDIUM : CONFIDENCE.LOW;
393
+ }
394
+
395
+ return predictions;
396
+ }
397
+
398
+ /**
399
+ * Predict context for working with a specific file
400
+ * @param {string} filePath - File being worked on
401
+ * @param {object} options - Prediction options
402
+ * @returns {object} Predicted context
403
+ */
404
+ predictForFile(filePath, options = {}) {
405
+ const { maxFiles = 10 } = options;
406
+
407
+ const predictions = {
408
+ files: [],
409
+ confidence: CONFIDENCE.MEDIUM,
410
+ reasoning: [],
411
+ };
412
+
413
+ const fileScores = new Map();
414
+
415
+ // Get directly related files from analyzer
416
+ const related = this.analyzer.getRelatedFiles(filePath, maxFiles * 2);
417
+ for (const { file, score, relationships } of related) {
418
+ fileScores.set(file, score);
419
+ predictions.reasoning.push(`${file} related via: ${relationships.join(', ')}`);
420
+ }
421
+
422
+ // Get frequently accessed together
423
+ const frequentlyWith = this.accessPattern.getFrequentlyAccessedWith(filePath, 5);
424
+ for (const { file, count } of frequentlyWith) {
425
+ const current = fileScores.get(file) || 0;
426
+ const bonus = Math.min(count * 0.2, 1.0); // Cap bonus at 1.0
427
+ fileScores.set(file, current + bonus);
428
+ predictions.reasoning.push(`${file} accessed together ${count} times`);
429
+ }
430
+
431
+ // Sort and format results
432
+ const sortedFiles = Array.from(fileScores.entries())
433
+ .map(([file, score]) => ({ file, score }))
434
+ .sort((a, b) => b.score - a.score)
435
+ .slice(0, maxFiles);
436
+
437
+ predictions.files = sortedFiles.map(({ file, score }) => ({
438
+ path: file,
439
+ score,
440
+ confidence: score > 2.0 ? CONFIDENCE.HIGH :
441
+ score > 1.0 ? CONFIDENCE.MEDIUM : CONFIDENCE.LOW,
442
+ type: CONTEXT_TYPES.FILE,
443
+ }));
444
+
445
+ if (predictions.files.length > 0) {
446
+ const maxScore = predictions.files[0].score;
447
+ predictions.confidence = maxScore > 2.0 ? CONFIDENCE.HIGH :
448
+ maxScore > 1.0 ? CONFIDENCE.MEDIUM : CONFIDENCE.LOW;
449
+ }
450
+
451
+ return predictions;
452
+ }
453
+
454
+ /**
455
+ * Predict context for a feature/topic
456
+ * @param {string} feature - Feature or topic name
457
+ * @param {object} options - Prediction options
458
+ * @returns {object} Predicted context
459
+ */
460
+ predictForFeature(feature, options = {}) {
461
+ const { maxFiles = 15 } = options;
462
+
463
+ const predictions = {
464
+ files: [],
465
+ confidence: CONFIDENCE.LOW,
466
+ reasoning: [],
467
+ };
468
+
469
+ const keywords = feature
470
+ .toLowerCase()
471
+ .replace(/[^a-z0-9\s]/g, ' ')
472
+ .split(/\s+/)
473
+ .filter(w => w.length > 2);
474
+
475
+ const fileScores = new Map();
476
+
477
+ // Search by keywords
478
+ for (const keyword of keywords) {
479
+ const files = this.analyzer.findByKeyword(keyword);
480
+ for (const file of files) {
481
+ const current = fileScores.get(file) || 0;
482
+ fileScores.set(file, current + 1.0);
483
+ }
484
+
485
+ // Check feature-file map
486
+ const featureFiles = this.featureFileMap.get(keyword);
487
+ if (featureFiles) {
488
+ for (const file of featureFiles) {
489
+ const current = fileScores.get(file) || 0;
490
+ fileScores.set(file, current + 1.5);
491
+ }
492
+ }
493
+ }
494
+
495
+ // Search by multiple keywords (intersection gets bonus)
496
+ if (keywords.length > 1) {
497
+ const intersectionFiles = this.analyzer.findByKeywords(keywords);
498
+ for (const file of intersectionFiles) {
499
+ const current = fileScores.get(file) || 0;
500
+ fileScores.set(file, current + 2.0);
501
+ predictions.reasoning.push(`${file} matches multiple keywords`);
502
+ }
503
+ }
504
+
505
+ // Add related files for top scored files
506
+ const topFiles = Array.from(fileScores.entries())
507
+ .sort((a, b) => b[1] - a[1])
508
+ .slice(0, 3);
509
+
510
+ for (const [file] of topFiles) {
511
+ const related = this.analyzer.getRelatedFiles(file, 3);
512
+ for (const { file: relatedFile, score } of related) {
513
+ const current = fileScores.get(relatedFile) || 0;
514
+ fileScores.set(relatedFile, current + score * 0.5);
515
+ }
516
+ }
517
+
518
+ // Sort and format results
519
+ const sortedFiles = Array.from(fileScores.entries())
520
+ .map(([file, score]) => ({ file, score }))
521
+ .sort((a, b) => b.score - a.score)
522
+ .slice(0, maxFiles);
523
+
524
+ predictions.files = sortedFiles.map(({ file, score }) => ({
525
+ path: file,
526
+ score,
527
+ confidence: score > 3.0 ? CONFIDENCE.HIGH :
528
+ score > 1.5 ? CONFIDENCE.MEDIUM : CONFIDENCE.LOW,
529
+ type: CONTEXT_TYPES.FILE,
530
+ }));
531
+
532
+ if (predictions.files.length > 0) {
533
+ predictions.confidence = predictions.files[0].score > 3.0 ? CONFIDENCE.HIGH :
534
+ predictions.files[0].score > 1.5 ? CONFIDENCE.MEDIUM : CONFIDENCE.LOW;
535
+ }
536
+
537
+ predictions.reasoning.push(`Searched for feature: "${feature}"`);
538
+ predictions.reasoning.push(`Found ${predictions.files.length} relevant files`);
539
+
540
+ return predictions;
541
+ }
542
+
543
+ /**
544
+ * Get prediction summary
545
+ * @returns {object} Summary statistics
546
+ */
547
+ getSummary() {
548
+ return {
549
+ analyzer: this.analyzer.getSummary(),
550
+ accessPatterns: {
551
+ totalAccesses: this.accessPattern.accesses.length,
552
+ sessionsTracked: this.accessPattern.sessions.length,
553
+ currentSessionFiles: this.accessPattern.currentSession.length,
554
+ },
555
+ featuresTracked: this.featureFileMap.size,
556
+ tasksRecorded: this.taskHistory.length,
557
+ };
558
+ }
559
+
560
+ /**
561
+ * End current session
562
+ */
563
+ endSession() {
564
+ this.accessPattern.endSession();
565
+ }
566
+
567
+ /**
568
+ * Export all data for persistence
569
+ * @returns {object}
570
+ */
571
+ export() {
572
+ const featureMap = {};
573
+ for (const [feature, files] of this.featureFileMap) {
574
+ featureMap[feature] = Array.from(files);
575
+ }
576
+
577
+ return {
578
+ analyzer: this.analyzer.export(),
579
+ accessPattern: this.accessPattern.export(),
580
+ featureFileMap: featureMap,
581
+ taskHistory: this.taskHistory.slice(-50),
582
+ };
583
+ }
584
+
585
+ /**
586
+ * Import data from persistence
587
+ * @param {object} data - Previously exported data
588
+ */
589
+ import(data) {
590
+ if (data.analyzer) {
591
+ this.analyzer.import(data.analyzer);
592
+ }
593
+ if (data.accessPattern) {
594
+ this.accessPattern.import(data.accessPattern);
595
+ }
596
+ if (data.featureFileMap) {
597
+ for (const [feature, files] of Object.entries(data.featureFileMap)) {
598
+ this.featureFileMap.set(feature, new Set(files));
599
+ }
600
+ }
601
+ if (data.taskHistory) {
602
+ this.taskHistory = data.taskHistory;
603
+ }
604
+ }
605
+
606
+ /**
607
+ * Clear all data
608
+ */
609
+ clear() {
610
+ this.analyzer.clear();
611
+ this.accessPattern.clear();
612
+ this.featureFileMap.clear();
613
+ this.taskHistory = [];
614
+ }
615
+ }
616
+
617
+ module.exports = {
618
+ ContextPredictor,
619
+ AccessPattern,
620
+ CONFIDENCE,
621
+ CONTEXT_TYPES,
622
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Context Module
3
+ *
4
+ * Intelligent context prediction and management.
5
+ * The "anticipate" brain - pre-loads what you need before you ask.
6
+ */
7
+
8
+ const {
9
+ ContextAnalyzer,
10
+ RELATIONSHIP_TYPES,
11
+ RELATIONSHIP_WEIGHTS,
12
+ } = require('./context-analyzer');
13
+
14
+ const {
15
+ ContextPredictor,
16
+ AccessPattern,
17
+ CONFIDENCE,
18
+ CONTEXT_TYPES,
19
+ } = require('./context-predictor');
20
+
21
+ const {
22
+ LRUCache,
23
+ ContextCache,
24
+ } = require('./context-cache');
25
+
26
+ module.exports = {
27
+ // Classes
28
+ ContextAnalyzer,
29
+ ContextPredictor,
30
+ AccessPattern,
31
+ LRUCache,
32
+ ContextCache,
33
+
34
+ // Constants
35
+ RELATIONSHIP_TYPES,
36
+ RELATIONSHIP_WEIGHTS,
37
+ CONFIDENCE,
38
+ CONTEXT_TYPES,
39
+
40
+ // Factory functions
41
+ createContextPredictor: () => new ContextPredictor(),
42
+ createContextCache: (options) => new ContextCache(options),
43
+ createContextAnalyzer: () => new ContextAnalyzer(),
44
+ };