@unrdf/knowledge-engine 5.0.1 → 26.4.2

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 (71) hide show
  1. package/package.json +23 -17
  2. package/src/ai-enhanced-search.mjs +371 -0
  3. package/src/anomaly-detector.mjs +226 -0
  4. package/src/artifact-generator.mjs +252 -0
  5. package/src/browser.mjs +1 -1
  6. package/src/chatman/disruption-arithmetic.mjs +140 -0
  7. package/src/chatman/market-dynamics.mjs +140 -0
  8. package/src/chatman/organizational-dynamics.mjs +140 -0
  9. package/src/chatman/strategic-dynamics.mjs +140 -0
  10. package/src/chatman-config-loader.mjs +282 -0
  11. package/src/chatman-engine.mjs +435 -0
  12. package/src/chatman-operator.mjs +343 -0
  13. package/src/dark-field-detector.mjs +332 -0
  14. package/src/formation-theorems.mjs +345 -0
  15. package/src/index.mjs +20 -2
  16. package/src/knowledge-hook-manager.mjs +1 -1
  17. package/src/lockchain-writer-browser.mjs +2 -2
  18. package/src/observability.mjs +40 -4
  19. package/src/query-optimizer.mjs +1 -1
  20. package/src/resolution-layer.mjs +1 -1
  21. package/src/transaction.mjs +11 -9
  22. package/README.md +0 -84
  23. package/src/browser-shims.mjs +0 -343
  24. package/src/canonicalize.mjs +0 -414
  25. package/src/condition-cache.mjs +0 -109
  26. package/src/condition-evaluator.mjs +0 -722
  27. package/src/dark-matter-core.mjs +0 -742
  28. package/src/define-hook.mjs +0 -213
  29. package/src/effect-sandbox-browser.mjs +0 -283
  30. package/src/effect-sandbox-worker.mjs +0 -170
  31. package/src/effect-sandbox.mjs +0 -517
  32. package/src/engines/index.mjs +0 -11
  33. package/src/engines/rdf-engine.mjs +0 -299
  34. package/src/file-resolver.mjs +0 -387
  35. package/src/hook-executor-batching.mjs +0 -277
  36. package/src/hook-executor.mjs +0 -870
  37. package/src/hook-management.mjs +0 -150
  38. package/src/ken-parliment.mjs +0 -119
  39. package/src/ken.mjs +0 -149
  40. package/src/knowledge-engine/builtin-rules.mjs +0 -190
  41. package/src/knowledge-engine/inference-engine.mjs +0 -418
  42. package/src/knowledge-engine/knowledge-engine.mjs +0 -317
  43. package/src/knowledge-engine/pattern-dsl.mjs +0 -142
  44. package/src/knowledge-engine/pattern-matcher.mjs +0 -215
  45. package/src/knowledge-engine/rules.mjs +0 -184
  46. package/src/knowledge-engine.mjs +0 -319
  47. package/src/knowledge-hook-engine.mjs +0 -360
  48. package/src/knowledge-substrate-core.mjs +0 -927
  49. package/src/lite.mjs +0 -222
  50. package/src/lockchain-writer.mjs +0 -602
  51. package/src/monitoring/andon-signals.mjs +0 -775
  52. package/src/parse.mjs +0 -290
  53. package/src/performance-optimizer.mjs +0 -678
  54. package/src/policy-pack.mjs +0 -572
  55. package/src/query-cache.mjs +0 -116
  56. package/src/query.mjs +0 -306
  57. package/src/reason.mjs +0 -350
  58. package/src/schemas.mjs +0 -1063
  59. package/src/security/error-sanitizer.mjs +0 -257
  60. package/src/security/path-validator.mjs +0 -194
  61. package/src/security/sandbox-restrictions.mjs +0 -331
  62. package/src/security-validator.mjs +0 -389
  63. package/src/store-cache.mjs +0 -137
  64. package/src/telemetry.mjs +0 -167
  65. package/src/utils/adaptive-monitor.mjs +0 -746
  66. package/src/utils/circuit-breaker.mjs +0 -513
  67. package/src/utils/edge-case-handler.mjs +0 -503
  68. package/src/utils/memory-manager.mjs +0 -498
  69. package/src/utils/ring-buffer.mjs +0 -282
  70. package/src/validate.mjs +0 -319
  71. package/src/validators/index.mjs +0 -338
@@ -1,572 +0,0 @@
1
- /**
2
- * @file Policy Pack abstraction for versioned governance units
3
- * @module policy-pack
4
- *
5
- * @description
6
- * Policy packs bundle related knowledge hooks into versioned, portable
7
- * governance units that can be activated/deactivated as cohesive sets.
8
- */
9
-
10
- import { readFileSync, _writeFileSync, existsSync, _mkdirSync, readdirSync } from 'fs';
11
- import { join, dirname, _basename, _extname } from 'path';
12
- import { _createKnowledgeHook, validateKnowledgeHook } from './schemas.mjs';
13
- import { z } from 'zod';
14
- import { randomUUID } from 'crypto';
15
-
16
- /**
17
- * Schema for policy pack metadata
18
- */
19
- const PolicyPackMetaSchema = z.object({
20
- name: z
21
- .string()
22
- .min(1)
23
- .max(100)
24
- .regex(
25
- /^[a-zA-Z0-9:_-]+$/,
26
- 'Name must contain only alphanumeric characters, colons, hyphens, and underscores'
27
- ),
28
- version: z.string().regex(/^\d+\.\d+\.\d+$/, 'Version must be semantic version format'),
29
- description: z.string().min(1).max(1000).optional(),
30
- author: z.string().min(1).max(100).optional(),
31
- license: z.string().min(1).max(100).optional(),
32
- tags: z.array(z.string().min(1).max(50)).max(20).optional(),
33
- ontology: z.array(z.string().min(1).max(100)).max(10).optional(),
34
- dependencies: z
35
- .array(
36
- z.object({
37
- name: z.string().min(1),
38
- version: z.string().min(1),
39
- required: z.boolean().default(true),
40
- })
41
- )
42
- .max(20)
43
- .optional(),
44
- createdAt: z.coerce.date().optional(),
45
- updatedAt: z.coerce.date().optional(),
46
- });
47
-
48
- /**
49
- * Schema for policy pack configuration
50
- */
51
- const PolicyPackConfigSchema = z.object({
52
- enabled: z.boolean().default(true),
53
- priority: z.number().int().min(0).max(100).default(50),
54
- strictMode: z.boolean().default(false),
55
- timeout: z.number().int().positive().max(300000).default(30000),
56
- retries: z.number().int().nonnegative().max(5).default(1),
57
- conditions: z
58
- .object({
59
- environment: z.array(z.string()).optional(),
60
- version: z.string().optional(),
61
- features: z.array(z.string()).optional(),
62
- })
63
- .optional(),
64
- });
65
-
66
- /**
67
- * Schema for policy pack manifest
68
- */
69
- const PolicyPackManifestSchema = z.object({
70
- id: z.string().uuid(),
71
- meta: PolicyPackMetaSchema,
72
- config: PolicyPackConfigSchema,
73
- hooks: z.array(
74
- z.object({
75
- name: z.string().min(1),
76
- file: z.string().min(1),
77
- enabled: z.boolean().default(true),
78
- priority: z.number().int().min(0).max(100).default(50),
79
- })
80
- ),
81
- conditions: z
82
- .array(
83
- z.object({
84
- name: z.string().min(1),
85
- file: z.string().min(1),
86
- type: z.enum(['sparql-ask', 'sparql-select', 'shacl']),
87
- })
88
- )
89
- .optional(),
90
- resources: z
91
- .array(
92
- z.object({
93
- name: z.string().min(1),
94
- file: z.string().min(1),
95
- type: z.enum(['ontology', 'vocabulary', 'data', 'other']),
96
- })
97
- )
98
- .optional(),
99
- });
100
-
101
- /**
102
- * Policy Pack class for managing versioned governance units
103
- */
104
- export class PolicyPack {
105
- /**
106
- * Create a new policy pack
107
- * @param {Object} manifest - Policy pack manifest
108
- * @param {string} [basePath] - Base path for file resolution
109
- */
110
- constructor(manifest, basePath = process.cwd()) {
111
- this.basePath = basePath;
112
- this.manifest = PolicyPackManifestSchema.parse(manifest);
113
- this.hooks = new Map();
114
- this.conditions = new Map();
115
- this.resources = new Map();
116
- this.loaded = false;
117
- }
118
-
119
- /**
120
- * Load the policy pack from filesystem
121
- * @returns {Promise<void>}
122
- */
123
- async load() {
124
- if (this.loaded) return;
125
-
126
- const packPath = join(this.basePath, 'policy-packs', this.manifest.meta.name);
127
-
128
- // Load hooks
129
- for (const hookDef of this.manifest.hooks) {
130
- if (!hookDef.enabled) continue;
131
-
132
- const hookFile = join(packPath, hookDef.file);
133
- if (!existsSync(hookFile)) {
134
- throw new Error(`Hook file not found: ${hookFile}`);
135
- }
136
-
137
- const hookModule = await import(`file://${hookFile}`);
138
- const hook = hookModule.default || hookModule;
139
-
140
- // Validate hook
141
- const validation = validateKnowledgeHook(hook);
142
- if (!validation.success) {
143
- throw new Error(
144
- `Invalid hook ${hookDef.name}: ${validation.errors.map(e => e.message).join(', ')}`
145
- );
146
- }
147
-
148
- // Set priority from manifest
149
- hook.priority = hookDef.priority;
150
-
151
- this.hooks.set(hookDef.name, hook);
152
- }
153
-
154
- // Load conditions
155
- if (this.manifest.conditions) {
156
- for (const conditionDef of this.manifest.conditions) {
157
- const conditionFile = join(packPath, conditionDef.file);
158
- if (!existsSync(conditionFile)) {
159
- throw new Error(`Condition file not found: ${conditionFile}`);
160
- }
161
-
162
- const conditionContent = readFileSync(conditionFile, 'utf8');
163
- this.conditions.set(conditionDef.name, {
164
- content: conditionContent,
165
- type: conditionDef.type,
166
- file: conditionDef.file,
167
- });
168
- }
169
- }
170
-
171
- // Load resources
172
- if (this.manifest.resources) {
173
- for (const resourceDef of this.manifest.resources) {
174
- const resourceFile = join(packPath, resourceDef.file);
175
- if (!existsSync(resourceFile)) {
176
- throw new Error(`Resource file not found: ${resourceFile}`);
177
- }
178
-
179
- const resourceContent = readFileSync(resourceFile, 'utf8');
180
- this.resources.set(resourceDef.name, {
181
- content: resourceContent,
182
- type: resourceDef.type,
183
- file: resourceDef.file,
184
- });
185
- }
186
- }
187
-
188
- this.loaded = true;
189
- }
190
-
191
- /**
192
- * Get all hooks in this policy pack
193
- * @returns {Array} Array of hook definitions
194
- */
195
- getHooks() {
196
- if (!this.loaded) {
197
- throw new Error('Policy pack not loaded. Call load() first.');
198
- }
199
-
200
- return Array.from(this.hooks.values());
201
- }
202
-
203
- /**
204
- * Get a specific hook by name
205
- * @param {string} name - Hook name
206
- * @returns {Object} Hook definition or null
207
- */
208
- getHook(name) {
209
- if (!this.loaded) {
210
- throw new Error('Policy pack not loaded. Call load() first.');
211
- }
212
-
213
- return this.hooks.get(name) || null;
214
- }
215
-
216
- /**
217
- * Get all conditions in this policy pack
218
- * @returns {Array} Array of condition definitions
219
- */
220
- getConditions() {
221
- if (!this.loaded) {
222
- throw new Error('Policy pack not loaded. Call load() first.');
223
- }
224
-
225
- return Array.from(this.conditions.values());
226
- }
227
-
228
- /**
229
- * Get a specific condition by name
230
- * @param {string} name - Condition name
231
- * @returns {Object} Condition definition or null
232
- */
233
- getCondition(name) {
234
- if (!this.loaded) {
235
- throw new Error('Policy pack not loaded. Call load() first.');
236
- }
237
-
238
- return this.conditions.get(name) || null;
239
- }
240
-
241
- /**
242
- * Get all resources in this policy pack
243
- * @returns {Array} Array of resource definitions
244
- */
245
- getResources() {
246
- if (!this.loaded) {
247
- throw new Error('Policy pack not loaded. Call load() first.');
248
- }
249
-
250
- return Array.from(this.resources.values());
251
- }
252
-
253
- /**
254
- * Get a specific resource by name
255
- * @param {string} name - Resource name
256
- * @returns {Object} Resource definition or null
257
- */
258
- getResource(name) {
259
- if (!this.loaded) {
260
- throw new Error('Policy pack not loaded. Call load() first.');
261
- }
262
-
263
- return this.resources.get(name) || null;
264
- }
265
-
266
- /**
267
- * Check if this policy pack is compatible with the current environment
268
- * @param {Object} [environment] - Environment information
269
- * @returns {Object} Compatibility check result
270
- */
271
- checkCompatibility(environment = {}) {
272
- const result = {
273
- compatible: true,
274
- issues: [],
275
- warnings: [],
276
- };
277
-
278
- // Check version compatibility
279
- if (this.manifest.config.conditions?.version) {
280
- const requiredVersion = this.manifest.config.conditions.version;
281
- const currentVersion = environment.version || '1.0.0';
282
-
283
- if (!this._isVersionCompatible(currentVersion, requiredVersion)) {
284
- result.compatible = false;
285
- result.issues.push(
286
- `Version ${currentVersion} is not compatible with required ${requiredVersion}`
287
- );
288
- }
289
- }
290
-
291
- // Check environment compatibility
292
- if (this.manifest.config.conditions?.environment) {
293
- const requiredEnvs = this.manifest.config.conditions.environment;
294
- const currentEnv = environment.environment || 'development';
295
-
296
- if (!requiredEnvs.includes(currentEnv)) {
297
- result.warnings.push(
298
- `Environment ${currentEnv} not in required list: ${requiredEnvs.join(', ')}`
299
- );
300
- }
301
- }
302
-
303
- // Check feature compatibility
304
- if (this.manifest.config.conditions?.features) {
305
- const requiredFeatures = this.manifest.config.conditions.features;
306
- const availableFeatures = environment.features || [];
307
-
308
- for (const feature of requiredFeatures) {
309
- if (!availableFeatures.includes(feature)) {
310
- result.compatible = false;
311
- result.issues.push(`Required feature ${feature} is not available`);
312
- }
313
- }
314
- }
315
-
316
- return result;
317
- }
318
-
319
- /**
320
- * Get policy pack statistics
321
- * @returns {Object} Statistics
322
- */
323
- getStats() {
324
- return {
325
- id: this.manifest.id,
326
- name: this.manifest.meta.name,
327
- version: this.manifest.meta.version,
328
- loaded: this.loaded,
329
- hooks: {
330
- total: this.manifest.hooks.length,
331
- enabled: this.manifest.hooks.filter(h => h.enabled).length,
332
- loaded: this.hooks.size,
333
- },
334
- conditions: {
335
- total: this.manifest.conditions?.length || 0,
336
- loaded: this.conditions.size,
337
- },
338
- resources: {
339
- total: this.manifest.resources?.length || 0,
340
- loaded: this.resources.size,
341
- },
342
- config: this.manifest.config,
343
- };
344
- }
345
-
346
- /**
347
- * Check if version is compatible
348
- * @param {string} current - Current version
349
- * @param {string} required - Required version
350
- * @returns {boolean} Is compatible
351
- * @private
352
- */
353
- _isVersionCompatible(current, required) {
354
- // Simple version compatibility check
355
- // In production, this would use proper semver parsing
356
- const currentParts = current.split('.').map(Number);
357
- const requiredParts = required.split('.').map(Number);
358
-
359
- // Check major version compatibility
360
- return currentParts[0] >= requiredParts[0];
361
- }
362
- }
363
-
364
- /**
365
- * Policy Pack Manager for managing multiple policy packs
366
- */
367
- export class PolicyPackManager {
368
- /**
369
- * Create a new policy pack manager
370
- * @param {string} [basePath] - Base path for policy packs
371
- */
372
- constructor(basePath = process.cwd()) {
373
- this.basePath = basePath;
374
- this.packs = new Map();
375
- this.activePacks = new Set();
376
- }
377
-
378
- /**
379
- * Load a policy pack from manifest file
380
- * @param {string} manifestPath - Path to manifest file
381
- * @returns {Promise<PolicyPack>} Loaded policy pack
382
- */
383
- async loadPolicyPack(manifestPath) {
384
- if (!existsSync(manifestPath)) {
385
- throw new Error(`Manifest file not found: ${manifestPath}`);
386
- }
387
-
388
- const manifestContent = readFileSync(manifestPath, 'utf8');
389
- const manifest = JSON.parse(manifestContent);
390
-
391
- const pack = new PolicyPack(manifest, this.basePath);
392
- await pack.load();
393
-
394
- this.packs.set(pack.manifest.meta.name, pack);
395
- return pack;
396
- }
397
-
398
- /**
399
- * Load all policy packs from a directory
400
- * @param {string} [packsDir] - Directory containing policy packs
401
- * @returns {Promise<Array<PolicyPack>>} Array of loaded policy packs
402
- */
403
- async loadAllPolicyPacks(packsDir = join(this.basePath, 'policy-packs')) {
404
- if (!existsSync(packsDir)) {
405
- return [];
406
- }
407
-
408
- const packs = [];
409
- const entries = readdirSync(packsDir, { withFileTypes: true });
410
-
411
- for (const entry of entries) {
412
- if (entry.isDirectory()) {
413
- const manifestPath = join(packsDir, entry.name, 'manifest.json');
414
- if (existsSync(manifestPath)) {
415
- try {
416
- const pack = await this.loadPolicyPack(manifestPath);
417
- packs.push(pack);
418
- } catch (error) {
419
- console.warn(`Failed to load policy pack ${entry.name}:`, error.message);
420
- }
421
- }
422
- }
423
- }
424
-
425
- return packs;
426
- }
427
-
428
- /**
429
- * Activate a policy pack
430
- * @param {string} packName - Policy pack name
431
- * @returns {boolean} Success
432
- */
433
- activatePolicyPack(packName) {
434
- const pack = this.packs.get(packName);
435
- if (!pack) {
436
- throw new Error(`Policy pack ${packName} not found`);
437
- }
438
-
439
- if (!pack.manifest.config.enabled) {
440
- throw new Error(`Policy pack ${packName} is disabled`);
441
- }
442
-
443
- this.activePacks.add(packName);
444
- return true;
445
- }
446
-
447
- /**
448
- * Deactivate a policy pack
449
- * @param {string} packName - Policy pack name
450
- * @returns {boolean} Success
451
- */
452
- deactivatePolicyPack(packName) {
453
- return this.activePacks.delete(packName);
454
- }
455
-
456
- /**
457
- * Get all active policy packs
458
- * @returns {Array<PolicyPack>} Array of active policy packs
459
- */
460
- getActivePolicyPacks() {
461
- return Array.from(this.activePacks)
462
- .map(name => this.packs.get(name))
463
- .filter(pack => pack !== undefined);
464
- }
465
-
466
- /**
467
- * Get all hooks from active policy packs
468
- * @returns {Array} Array of hook definitions
469
- */
470
- getActiveHooks() {
471
- const hooks = [];
472
-
473
- for (const packName of this.activePacks) {
474
- const pack = this.packs.get(packName);
475
- if (pack) {
476
- hooks.push(...pack.getHooks());
477
- }
478
- }
479
-
480
- // Sort by priority
481
- return hooks.sort((a, b) => (b.priority || 50) - (a.priority || 50));
482
- }
483
-
484
- /**
485
- * Get policy pack by name
486
- * @param {string} name - Policy pack name
487
- * @returns {PolicyPack} Policy pack or null
488
- */
489
- getPolicyPack(name) {
490
- return this.packs.get(name) || null;
491
- }
492
-
493
- /**
494
- * Get all policy packs
495
- * @returns {Array<PolicyPack>} Array of all policy packs
496
- */
497
- getAllPolicyPacks() {
498
- return Array.from(this.packs.values());
499
- }
500
-
501
- /**
502
- * Get manager statistics
503
- * @returns {Object} Statistics
504
- */
505
- getStats() {
506
- const _activePacks = this.getActivePolicyPacks();
507
- const allHooks = this.getActiveHooks();
508
-
509
- return {
510
- totalPacks: this.packs.size,
511
- activePacks: this.activePacks.size,
512
- totalHooks: allHooks.length,
513
- packs: Array.from(this.packs.values()).map(pack => pack.getStats()),
514
- };
515
- }
516
- }
517
-
518
- /**
519
- * Create a policy pack from a directory structure
520
- * @param {string} packDir - Directory containing policy pack files
521
- * @returns {Promise<PolicyPack>} Created policy pack
522
- */
523
- export async function createPolicyPackFromDirectory(packDir) {
524
- const manifestPath = join(packDir, 'manifest.json');
525
-
526
- if (!existsSync(manifestPath)) {
527
- throw new Error(`Manifest file not found: ${manifestPath}`);
528
- }
529
-
530
- const manager = new PolicyPackManager(dirname(packDir));
531
- return manager.loadPolicyPack(manifestPath);
532
- }
533
-
534
- /**
535
- * Create a new policy pack manifest
536
- * @param {Object} options - Manifest options
537
- * @returns {Object} Policy pack manifest
538
- */
539
- export function createPolicyPackManifest(name, hooks, options = {}) {
540
- const manifest = {
541
- id: randomUUID(),
542
- meta: {
543
- name: name,
544
- version: options.version || '1.0.0',
545
- description: options.description,
546
- author: options.author,
547
- license: options.license || 'MIT',
548
- tags: options.tags || [],
549
- ontology: options.ontology || [],
550
- dependencies: options.dependencies || [],
551
- createdAt: new Date().toISOString(),
552
- },
553
- config: {
554
- enabled: options.enabled !== false,
555
- priority: options.priority || 50,
556
- strictMode: options.strictMode || false,
557
- timeout: options.timeout || 30000,
558
- retries: options.retries || 1,
559
- conditions: options.conditions || {},
560
- },
561
- hooks: hooks.map(hook => ({
562
- name: hook.meta.name,
563
- file: `${hook.meta.name}.mjs`,
564
- enabled: true,
565
- priority: hook.priority || 50,
566
- })),
567
- conditions: options.conditions || [],
568
- resources: options.resources || [],
569
- };
570
-
571
- return PolicyPackManifestSchema.parse(manifest);
572
- }
@@ -1,116 +0,0 @@
1
- /**
2
- * @file Query Cache (Legacy - Deprecated)
3
- * @module query-cache
4
- *
5
- * @description
6
- * This module has been deprecated with the migration from Comunica to Oxigraph.
7
- * Oxigraph uses synchronous execution with <1ms cold start, eliminating the need
8
- * for QueryEngine initialization caching.
9
- *
10
- * Maintained for backward compatibility only.
11
- */
12
-
13
- import { createHash } from 'node:crypto';
14
-
15
- /**
16
- * LRU cache for file content (keyed by SHA-256)
17
- * @type {Map<string, string>}
18
- */
19
- const fileContentCache = new Map();
20
-
21
- /**
22
- * Maximum cache entries
23
- */
24
- const MAX_FILE_CACHE = 50;
25
-
26
- /**
27
- * Cache statistics
28
- */
29
- const stats = {
30
- fileCacheHits: 0,
31
- fileCacheMisses: 0,
32
- };
33
-
34
- /**
35
- * Get query hash
36
- *
37
- * @param {string} sparql - SPARQL query string
38
- * @returns {string} Query hash for caching
39
- */
40
- export function getQueryHash(sparql) {
41
- return createHash('sha256').update(sparql.trim()).digest('hex');
42
- }
43
-
44
- /**
45
- * Cache file content by SHA-256 hash.
46
- *
47
- * @param {string} sha256 - Content hash
48
- * @param {string} content - File content
49
- */
50
- export function cacheFileContent(sha256, content) {
51
- // LRU eviction: Remove oldest entry if cache is full
52
- if (fileContentCache.size >= MAX_FILE_CACHE && !fileContentCache.has(sha256)) {
53
- const firstKey = fileContentCache.keys().next().value;
54
- fileContentCache.delete(firstKey);
55
- }
56
-
57
- fileContentCache.set(sha256, content);
58
- }
59
-
60
- /**
61
- * Get cached file content by SHA-256 hash.
62
- *
63
- * @param {string} sha256 - Content hash
64
- * @returns {string|null} Cached content or null
65
- */
66
- export function getCachedFileContent(sha256) {
67
- if (fileContentCache.has(sha256)) {
68
- stats.fileCacheHits++;
69
- return fileContentCache.get(sha256);
70
- }
71
- stats.fileCacheMisses++;
72
- return null;
73
- }
74
-
75
- /**
76
- * Get cache statistics.
77
- *
78
- * @returns {Object} Cache statistics
79
- */
80
- export function getCacheStats() {
81
- return {
82
- ...stats,
83
- fileCacheSize: fileContentCache.size,
84
- fileCacheHitRate: stats.fileCacheHits / (stats.fileCacheHits + stats.fileCacheMisses) || 0,
85
- };
86
- }
87
-
88
- /**
89
- * Clear all caches (for testing).
90
- */
91
- export function clearCaches() {
92
- fileContentCache.clear();
93
- stats.fileCacheHits = 0;
94
- stats.fileCacheMisses = 0;
95
- }
96
-
97
- /**
98
- * Shutdown hook for cleanup.
99
- * Should be called when process is exiting.
100
- */
101
- export function shutdown() {
102
- clearCaches();
103
- }
104
-
105
- // Register shutdown hook
106
- if (typeof process !== 'undefined') {
107
- process.on('exit', shutdown);
108
- process.on('SIGINT', () => {
109
- shutdown();
110
- process.exit(0);
111
- });
112
- process.on('SIGTERM', () => {
113
- shutdown();
114
- process.exit(0);
115
- });
116
- }