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,426 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Cache
|
|
3
|
+
*
|
|
4
|
+
* LRU cache for efficiently managing loaded context.
|
|
5
|
+
* Tracks usage patterns for intelligent preloading.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* LRU Cache implementation
|
|
10
|
+
*/
|
|
11
|
+
class LRUCache {
|
|
12
|
+
/**
|
|
13
|
+
* @param {number} maxSize - Maximum number of items
|
|
14
|
+
* @param {number} maxAge - Maximum age in ms (0 = no expiry)
|
|
15
|
+
*/
|
|
16
|
+
constructor(maxSize = 100, maxAge = 0) {
|
|
17
|
+
this.maxSize = maxSize;
|
|
18
|
+
this.maxAge = maxAge;
|
|
19
|
+
this.cache = new Map();
|
|
20
|
+
this.accessOrder = []; // Most recent at end
|
|
21
|
+
this.hits = 0;
|
|
22
|
+
this.misses = 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get an item from cache
|
|
27
|
+
* @param {string} key - Cache key
|
|
28
|
+
* @returns {any|undefined} Cached value or undefined
|
|
29
|
+
*/
|
|
30
|
+
get(key) {
|
|
31
|
+
const entry = this.cache.get(key);
|
|
32
|
+
|
|
33
|
+
if (!entry) {
|
|
34
|
+
this.misses++;
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check expiry
|
|
39
|
+
if (this.maxAge > 0 && Date.now() - entry.timestamp > this.maxAge) {
|
|
40
|
+
this.delete(key);
|
|
41
|
+
this.misses++;
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Update access order
|
|
46
|
+
this.touchKey(key);
|
|
47
|
+
this.hits++;
|
|
48
|
+
|
|
49
|
+
return entry.value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Set an item in cache
|
|
54
|
+
* @param {string} key - Cache key
|
|
55
|
+
* @param {any} value - Value to cache
|
|
56
|
+
* @param {object} metadata - Optional metadata
|
|
57
|
+
*/
|
|
58
|
+
set(key, value, metadata = {}) {
|
|
59
|
+
// If key exists, update it
|
|
60
|
+
if (this.cache.has(key)) {
|
|
61
|
+
const entry = this.cache.get(key);
|
|
62
|
+
entry.value = value;
|
|
63
|
+
entry.timestamp = Date.now();
|
|
64
|
+
entry.metadata = { ...entry.metadata, ...metadata };
|
|
65
|
+
this.touchKey(key);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Evict if at capacity
|
|
70
|
+
while (this.cache.size >= this.maxSize) {
|
|
71
|
+
this.evictOldest();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Add new entry
|
|
75
|
+
this.cache.set(key, {
|
|
76
|
+
value,
|
|
77
|
+
timestamp: Date.now(),
|
|
78
|
+
accessCount: 1,
|
|
79
|
+
metadata,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
this.accessOrder.push(key);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Check if key exists (without updating access)
|
|
87
|
+
* @param {string} key - Cache key
|
|
88
|
+
* @returns {boolean}
|
|
89
|
+
*/
|
|
90
|
+
has(key) {
|
|
91
|
+
if (!this.cache.has(key)) return false;
|
|
92
|
+
|
|
93
|
+
// Check expiry
|
|
94
|
+
const entry = this.cache.get(key);
|
|
95
|
+
if (this.maxAge > 0 && Date.now() - entry.timestamp > this.maxAge) {
|
|
96
|
+
this.delete(key);
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Delete an item from cache
|
|
105
|
+
* @param {string} key - Cache key
|
|
106
|
+
* @returns {boolean} True if deleted
|
|
107
|
+
*/
|
|
108
|
+
delete(key) {
|
|
109
|
+
if (!this.cache.has(key)) return false;
|
|
110
|
+
|
|
111
|
+
this.cache.delete(key);
|
|
112
|
+
const idx = this.accessOrder.indexOf(key);
|
|
113
|
+
if (idx !== -1) {
|
|
114
|
+
this.accessOrder.splice(idx, 1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Update access order for a key
|
|
122
|
+
* @param {string} key - Cache key
|
|
123
|
+
*/
|
|
124
|
+
touchKey(key) {
|
|
125
|
+
const idx = this.accessOrder.indexOf(key);
|
|
126
|
+
if (idx !== -1) {
|
|
127
|
+
this.accessOrder.splice(idx, 1);
|
|
128
|
+
}
|
|
129
|
+
this.accessOrder.push(key);
|
|
130
|
+
|
|
131
|
+
// Update access count
|
|
132
|
+
const entry = this.cache.get(key);
|
|
133
|
+
if (entry) {
|
|
134
|
+
entry.accessCount++;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Evict the oldest (least recently used) item
|
|
140
|
+
*/
|
|
141
|
+
evictOldest() {
|
|
142
|
+
if (this.accessOrder.length === 0) return;
|
|
143
|
+
|
|
144
|
+
const oldestKey = this.accessOrder.shift();
|
|
145
|
+
this.cache.delete(oldestKey);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Clear the cache
|
|
150
|
+
*/
|
|
151
|
+
clear() {
|
|
152
|
+
this.cache.clear();
|
|
153
|
+
this.accessOrder = [];
|
|
154
|
+
this.hits = 0;
|
|
155
|
+
this.misses = 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get cache size
|
|
160
|
+
* @returns {number}
|
|
161
|
+
*/
|
|
162
|
+
get size() {
|
|
163
|
+
return this.cache.size;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get all keys
|
|
168
|
+
* @returns {string[]}
|
|
169
|
+
*/
|
|
170
|
+
keys() {
|
|
171
|
+
return Array.from(this.cache.keys());
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get cache statistics
|
|
176
|
+
* @returns {object}
|
|
177
|
+
*/
|
|
178
|
+
getStats() {
|
|
179
|
+
const total = this.hits + this.misses;
|
|
180
|
+
return {
|
|
181
|
+
size: this.cache.size,
|
|
182
|
+
maxSize: this.maxSize,
|
|
183
|
+
hits: this.hits,
|
|
184
|
+
misses: this.misses,
|
|
185
|
+
hitRate: total > 0 ? this.hits / total : 0,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get most accessed items
|
|
191
|
+
* @param {number} limit - Maximum results
|
|
192
|
+
* @returns {Array<{key: string, accessCount: number}>}
|
|
193
|
+
*/
|
|
194
|
+
getMostAccessed(limit = 10) {
|
|
195
|
+
const items = [];
|
|
196
|
+
for (const [key, entry] of this.cache) {
|
|
197
|
+
items.push({ key, accessCount: entry.accessCount });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
items.sort((a, b) => b.accessCount - a.accessCount);
|
|
201
|
+
return items.slice(0, limit);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Context Cache Manager
|
|
207
|
+
* Manages multiple cache layers for different context types
|
|
208
|
+
*/
|
|
209
|
+
class ContextCache {
|
|
210
|
+
constructor(options = {}) {
|
|
211
|
+
const {
|
|
212
|
+
maxFileContent = 50,
|
|
213
|
+
maxMetadata = 200,
|
|
214
|
+
maxPredictions = 100,
|
|
215
|
+
contentMaxAge = 5 * 60 * 1000,
|
|
216
|
+
metadataMaxAge = 30 * 60 * 1000,
|
|
217
|
+
} = options;
|
|
218
|
+
|
|
219
|
+
this.fileContent = new LRUCache(maxFileContent, contentMaxAge);
|
|
220
|
+
this.metadata = new LRUCache(maxMetadata, metadataMaxAge);
|
|
221
|
+
this.predictions = new LRUCache(maxPredictions, 60 * 1000); // 1 min
|
|
222
|
+
this.preloadQueue = [];
|
|
223
|
+
this.preloadInProgress = new Set();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Cache file content
|
|
228
|
+
* @param {string} filePath - File path
|
|
229
|
+
* @param {string} content - File content
|
|
230
|
+
* @param {object} metadata - Optional metadata
|
|
231
|
+
*/
|
|
232
|
+
cacheFileContent(filePath, content, metadata = {}) {
|
|
233
|
+
this.fileContent.set(filePath, content, {
|
|
234
|
+
size: content.length,
|
|
235
|
+
lineCount: content.split('\n').length,
|
|
236
|
+
...metadata,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Get cached file content
|
|
242
|
+
* @param {string} filePath - File path
|
|
243
|
+
* @returns {string|undefined}
|
|
244
|
+
*/
|
|
245
|
+
getFileContent(filePath) {
|
|
246
|
+
return this.fileContent.get(filePath);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Cache metadata for a file
|
|
251
|
+
* @param {string} filePath - File path
|
|
252
|
+
* @param {object} meta - Metadata object
|
|
253
|
+
*/
|
|
254
|
+
cacheMetadata(filePath, meta) {
|
|
255
|
+
this.metadata.set(filePath, meta);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Get cached metadata
|
|
260
|
+
* @param {string} filePath - File path
|
|
261
|
+
* @returns {object|undefined}
|
|
262
|
+
*/
|
|
263
|
+
getMetadata(filePath) {
|
|
264
|
+
return this.metadata.get(filePath);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Cache a prediction result
|
|
269
|
+
* @param {string} key - Prediction key (e.g., "task:authentication")
|
|
270
|
+
* @param {object} prediction - Prediction result
|
|
271
|
+
*/
|
|
272
|
+
cachePrediction(key, prediction) {
|
|
273
|
+
this.predictions.set(key, prediction);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Get cached prediction
|
|
278
|
+
* @param {string} key - Prediction key
|
|
279
|
+
* @returns {object|undefined}
|
|
280
|
+
*/
|
|
281
|
+
getPrediction(key) {
|
|
282
|
+
return this.predictions.get(key);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Add files to preload queue
|
|
287
|
+
* @param {string[]} filePaths - Files to preload
|
|
288
|
+
* @param {string} priority - 'high' | 'normal' | 'low'
|
|
289
|
+
*/
|
|
290
|
+
queuePreload(filePaths, priority = 'normal') {
|
|
291
|
+
for (const filePath of filePaths) {
|
|
292
|
+
if (this.fileContent.has(filePath)) continue;
|
|
293
|
+
if (this.preloadInProgress.has(filePath)) continue;
|
|
294
|
+
|
|
295
|
+
const existing = this.preloadQueue.findIndex(p => p.path === filePath);
|
|
296
|
+
if (existing !== -1) {
|
|
297
|
+
// Update priority if higher
|
|
298
|
+
if (priority === 'high') {
|
|
299
|
+
this.preloadQueue[existing].priority = 'high';
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
this.preloadQueue.push({ path: filePath, priority });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Sort by priority
|
|
307
|
+
this.preloadQueue.sort((a, b) => {
|
|
308
|
+
const order = { high: 0, normal: 1, low: 2 };
|
|
309
|
+
return order[a.priority] - order[b.priority];
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Get next file to preload
|
|
315
|
+
* @returns {string|null}
|
|
316
|
+
*/
|
|
317
|
+
getNextPreload() {
|
|
318
|
+
while (this.preloadQueue.length > 0) {
|
|
319
|
+
const next = this.preloadQueue.shift();
|
|
320
|
+
if (!this.fileContent.has(next.path) && !this.preloadInProgress.has(next.path)) {
|
|
321
|
+
this.preloadInProgress.add(next.path);
|
|
322
|
+
return next.path;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Mark preload as complete
|
|
330
|
+
* @param {string} filePath - File path
|
|
331
|
+
*/
|
|
332
|
+
preloadComplete(filePath) {
|
|
333
|
+
this.preloadInProgress.delete(filePath);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Invalidate cached content for a file
|
|
338
|
+
* @param {string} filePath - File path
|
|
339
|
+
*/
|
|
340
|
+
invalidate(filePath) {
|
|
341
|
+
this.fileContent.delete(filePath);
|
|
342
|
+
this.metadata.delete(filePath);
|
|
343
|
+
|
|
344
|
+
// Invalidate any predictions that might include this file
|
|
345
|
+
for (const key of this.predictions.keys()) {
|
|
346
|
+
const prediction = this.predictions.get(key);
|
|
347
|
+
if (prediction?.files?.some(f => f.path === filePath)) {
|
|
348
|
+
this.predictions.delete(key);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Clear all caches
|
|
355
|
+
*/
|
|
356
|
+
clear() {
|
|
357
|
+
this.fileContent.clear();
|
|
358
|
+
this.metadata.clear();
|
|
359
|
+
this.predictions.clear();
|
|
360
|
+
this.preloadQueue = [];
|
|
361
|
+
this.preloadInProgress.clear();
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Get cache statistics
|
|
366
|
+
* @returns {object}
|
|
367
|
+
*/
|
|
368
|
+
getStats() {
|
|
369
|
+
return {
|
|
370
|
+
fileContent: this.fileContent.getStats(),
|
|
371
|
+
metadata: this.metadata.getStats(),
|
|
372
|
+
predictions: this.predictions.getStats(),
|
|
373
|
+
preloadQueue: this.preloadQueue.length,
|
|
374
|
+
preloadInProgress: this.preloadInProgress.size,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Get memory usage estimate
|
|
380
|
+
* @returns {object}
|
|
381
|
+
*/
|
|
382
|
+
getMemoryUsage() {
|
|
383
|
+
let contentSize = 0;
|
|
384
|
+
for (const key of this.fileContent.keys()) {
|
|
385
|
+
const content = this.fileContent.get(key);
|
|
386
|
+
if (content) {
|
|
387
|
+
contentSize += content.length * 2; // Rough estimate: 2 bytes per char
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
estimatedBytes: contentSize,
|
|
393
|
+
estimatedMB: (contentSize / (1024 * 1024)).toFixed(2),
|
|
394
|
+
cachedFiles: this.fileContent.size,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Warm cache with commonly accessed files
|
|
400
|
+
* @param {Array<{path: string, content: string}>} files - Files to warm
|
|
401
|
+
*/
|
|
402
|
+
warmCache(files) {
|
|
403
|
+
for (const { path: filePath, content } of files) {
|
|
404
|
+
this.cacheFileContent(filePath, content);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Export cache state (for persistence)
|
|
410
|
+
* @returns {object}
|
|
411
|
+
*/
|
|
412
|
+
export() {
|
|
413
|
+
return {
|
|
414
|
+
stats: this.getStats(),
|
|
415
|
+
mostAccessed: {
|
|
416
|
+
files: this.fileContent.getMostAccessed(20),
|
|
417
|
+
metadata: this.metadata.getMostAccessed(20),
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
module.exports = {
|
|
424
|
+
LRUCache,
|
|
425
|
+
ContextCache,
|
|
426
|
+
};
|