@danielsimonjr/memory-mcp 11.0.1 → 11.1.1
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 +22 -22
- package/dist/core/EntityManager.d.ts +10 -15
- package/dist/core/EntityManager.d.ts.map +1 -1
- package/dist/core/EntityManager.js +21 -54
- package/dist/core/GraphStorage.d.ts +0 -51
- package/dist/core/GraphStorage.d.ts.map +1 -1
- package/dist/core/GraphStorage.js +2 -79
- package/dist/core/GraphTraversal.d.ts +2 -7
- package/dist/core/GraphTraversal.d.ts.map +1 -1
- package/dist/core/GraphTraversal.js +2 -19
- package/dist/core/ManagerContext.d.ts +0 -4
- package/dist/core/ManagerContext.d.ts.map +1 -1
- package/dist/core/ManagerContext.js +2 -12
- package/dist/core/RelationManager.d.ts.map +1 -1
- package/dist/core/RelationManager.js +4 -5
- package/dist/core/SQLiteStorage.d.ts.map +1 -1
- package/dist/core/SQLiteStorage.js +2 -3
- package/dist/core/TransactionManager.d.ts +2 -207
- package/dist/core/TransactionManager.d.ts.map +1 -1
- package/dist/core/TransactionManager.js +6 -482
- package/dist/core/index.d.ts +1 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -3
- package/dist/features/ArchiveManager.d.ts +2 -14
- package/dist/features/ArchiveManager.d.ts.map +1 -1
- package/dist/features/ArchiveManager.js +3 -44
- package/dist/features/CompressionManager.d.ts +4 -14
- package/dist/features/CompressionManager.d.ts.map +1 -1
- package/dist/features/CompressionManager.js +9 -74
- package/dist/features/IOManager.d.ts +2 -6
- package/dist/features/IOManager.d.ts.map +1 -1
- package/dist/features/IOManager.js +10 -105
- package/dist/features/StreamingExporter.d.ts +4 -27
- package/dist/features/StreamingExporter.d.ts.map +1 -1
- package/dist/features/StreamingExporter.js +4 -65
- package/dist/features/index.d.ts +0 -2
- package/dist/features/index.d.ts.map +1 -1
- package/dist/features/index.js +0 -3
- package/dist/search/EmbeddingService.d.ts +9 -108
- package/dist/search/EmbeddingService.d.ts.map +1 -1
- package/dist/search/EmbeddingService.js +15 -187
- package/dist/search/FuzzySearch.js +1 -1
- package/dist/search/SavedSearchManager.d.ts.map +1 -1
- package/dist/search/SavedSearchManager.js +2 -3
- package/dist/search/SearchManager.d.ts +1 -42
- package/dist/search/SearchManager.d.ts.map +1 -1
- package/dist/search/SearchManager.js +0 -115
- package/dist/search/SemanticSearch.d.ts +1 -4
- package/dist/search/SemanticSearch.d.ts.map +1 -1
- package/dist/search/SemanticSearch.js +2 -12
- package/dist/search/TFIDFIndexManager.d.ts +0 -88
- package/dist/search/TFIDFIndexManager.d.ts.map +1 -1
- package/dist/search/TFIDFIndexManager.js +0 -217
- package/dist/search/index.d.ts +1 -18
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +1 -32
- package/dist/server/MCPServer.d.ts.map +1 -1
- package/dist/server/MCPServer.js +4 -1
- package/dist/server/responseCompressor.js +5 -5
- package/dist/server/toolDefinitions.d.ts.map +1 -1
- package/dist/server/toolDefinitions.js +5 -1
- package/dist/server/toolHandlers.d.ts +9 -5
- package/dist/server/toolHandlers.d.ts.map +1 -1
- package/dist/server/toolHandlers.js +23 -8
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +2 -579
- package/dist/types/types.d.ts.map +1 -1
- package/dist/utils/compressedCache.d.ts +0 -29
- package/dist/utils/compressedCache.d.ts.map +1 -1
- package/dist/utils/compressedCache.js +0 -39
- package/dist/utils/entityUtils.d.ts +1 -59
- package/dist/utils/entityUtils.d.ts.map +1 -1
- package/dist/utils/entityUtils.js +3 -113
- package/dist/utils/errors.d.ts +0 -18
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +0 -24
- package/dist/utils/index.d.ts +2 -6
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -14
- package/dist/utils/logger.d.ts +0 -7
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +2 -9
- package/dist/utils/parallelUtils.d.ts +1 -5
- package/dist/utils/parallelUtils.d.ts.map +1 -1
- package/dist/utils/parallelUtils.js +1 -23
- package/dist/utils/schemas.d.ts +16 -16
- package/dist/utils/schemas.d.ts.map +1 -1
- package/dist/utils/schemas.js +12 -12
- package/dist/utils/taskScheduler.d.ts +0 -4
- package/dist/utils/taskScheduler.d.ts.map +1 -1
- package/dist/utils/taskScheduler.js +1 -21
- package/dist/workers/WorkerPool.d.ts +81 -0
- package/dist/workers/WorkerPool.d.ts.map +1 -0
- package/dist/workers/WorkerPool.js +121 -0
- package/dist/workers/index.d.ts +1 -1
- package/dist/workers/index.d.ts.map +1 -1
- package/dist/workers/levenshteinWorker.js +1 -1
- package/package.json +1 -4
- package/dist/__tests__/file-path.test.js +0 -119
- package/dist/__tests__/knowledge-graph.test.js +0 -318
- package/dist/core/GraphEventEmitter.d.ts +0 -202
- package/dist/core/GraphEventEmitter.d.ts.map +0 -1
- package/dist/core/GraphEventEmitter.js +0 -346
- package/dist/features/KeywordExtractor.d.ts +0 -61
- package/dist/features/KeywordExtractor.d.ts.map +0 -1
- package/dist/features/KeywordExtractor.js +0 -126
- package/dist/features/ObservationNormalizer.d.ts +0 -90
- package/dist/features/ObservationNormalizer.d.ts.map +0 -1
- package/dist/features/ObservationNormalizer.js +0 -193
- package/dist/memory.jsonl +0 -1
- package/dist/search/BM25Search.d.ts +0 -148
- package/dist/search/BM25Search.d.ts.map +0 -1
- package/dist/search/BM25Search.js +0 -339
- package/dist/search/EarlyTerminationManager.d.ts +0 -140
- package/dist/search/EarlyTerminationManager.d.ts.map +0 -1
- package/dist/search/EarlyTerminationManager.js +0 -279
- package/dist/search/EmbeddingCache.d.ts +0 -175
- package/dist/search/EmbeddingCache.d.ts.map +0 -1
- package/dist/search/EmbeddingCache.js +0 -246
- package/dist/search/HybridScorer.d.ts +0 -181
- package/dist/search/HybridScorer.d.ts.map +0 -1
- package/dist/search/HybridScorer.js +0 -257
- package/dist/search/HybridSearchManager.d.ts +0 -80
- package/dist/search/HybridSearchManager.d.ts.map +0 -1
- package/dist/search/HybridSearchManager.js +0 -187
- package/dist/search/IncrementalIndexer.d.ts +0 -201
- package/dist/search/IncrementalIndexer.d.ts.map +0 -1
- package/dist/search/IncrementalIndexer.js +0 -342
- package/dist/search/OptimizedInvertedIndex.d.ts +0 -163
- package/dist/search/OptimizedInvertedIndex.d.ts.map +0 -1
- package/dist/search/OptimizedInvertedIndex.js +0 -358
- package/dist/search/ParallelSearchExecutor.d.ts +0 -172
- package/dist/search/ParallelSearchExecutor.d.ts.map +0 -1
- package/dist/search/ParallelSearchExecutor.js +0 -309
- package/dist/search/QuantizedVectorStore.d.ts +0 -171
- package/dist/search/QuantizedVectorStore.d.ts.map +0 -1
- package/dist/search/QuantizedVectorStore.js +0 -307
- package/dist/search/QueryAnalyzer.d.ts +0 -76
- package/dist/search/QueryAnalyzer.d.ts.map +0 -1
- package/dist/search/QueryAnalyzer.js +0 -227
- package/dist/search/QueryCostEstimator.d.ts +0 -244
- package/dist/search/QueryCostEstimator.d.ts.map +0 -1
- package/dist/search/QueryCostEstimator.js +0 -652
- package/dist/search/QueryPlanCache.d.ts +0 -220
- package/dist/search/QueryPlanCache.d.ts.map +0 -1
- package/dist/search/QueryPlanCache.js +0 -379
- package/dist/search/QueryPlanner.d.ts +0 -58
- package/dist/search/QueryPlanner.d.ts.map +0 -1
- package/dist/search/QueryPlanner.js +0 -137
- package/dist/search/ReflectionManager.d.ts +0 -120
- package/dist/search/ReflectionManager.d.ts.map +0 -1
- package/dist/search/ReflectionManager.js +0 -231
- package/dist/search/SymbolicSearch.d.ts +0 -61
- package/dist/search/SymbolicSearch.d.ts.map +0 -1
- package/dist/search/SymbolicSearch.js +0 -163
- package/dist/search/TFIDFEventSync.d.ts +0 -85
- package/dist/search/TFIDFEventSync.d.ts.map +0 -1
- package/dist/search/TFIDFEventSync.js +0 -133
- package/dist/utils/BatchProcessor.d.ts +0 -271
- package/dist/utils/BatchProcessor.d.ts.map +0 -1
- package/dist/utils/BatchProcessor.js +0 -376
- package/dist/utils/MemoryMonitor.d.ts +0 -176
- package/dist/utils/MemoryMonitor.d.ts.map +0 -1
- package/dist/utils/MemoryMonitor.js +0 -305
- package/dist/utils/WorkerPoolManager.d.ts +0 -233
- package/dist/utils/WorkerPoolManager.d.ts.map +0 -1
- package/dist/utils/WorkerPoolManager.js +0 -420
- package/dist/utils/operationUtils.d.ts +0 -124
- package/dist/utils/operationUtils.d.ts.map +0 -1
- package/dist/utils/operationUtils.js +0 -175
- package/dist/vitest.config.js +0 -13
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { promises as fs } from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import { ensureMemoryFilePath, defaultMemoryPath } from '../index.js';
|
|
6
|
-
describe('ensureMemoryFilePath', () => {
|
|
7
|
-
const testDir = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const oldMemoryPath = path.join(testDir, '..', 'memory.json');
|
|
9
|
-
const newMemoryPath = path.join(testDir, '..', 'memory.jsonl');
|
|
10
|
-
let originalEnv;
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
// Save original environment variable
|
|
13
|
-
originalEnv = process.env.MEMORY_FILE_PATH;
|
|
14
|
-
// Delete environment variable
|
|
15
|
-
delete process.env.MEMORY_FILE_PATH;
|
|
16
|
-
});
|
|
17
|
-
afterEach(async () => {
|
|
18
|
-
// Restore original environment variable
|
|
19
|
-
if (originalEnv !== undefined) {
|
|
20
|
-
process.env.MEMORY_FILE_PATH = originalEnv;
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
delete process.env.MEMORY_FILE_PATH;
|
|
24
|
-
}
|
|
25
|
-
// Clean up test files
|
|
26
|
-
try {
|
|
27
|
-
await fs.unlink(oldMemoryPath);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
// Ignore if file doesn't exist
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
await fs.unlink(newMemoryPath);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
// Ignore if file doesn't exist
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
describe('with MEMORY_FILE_PATH environment variable', () => {
|
|
40
|
-
it('should return absolute path when MEMORY_FILE_PATH is absolute', async () => {
|
|
41
|
-
const absolutePath = '/tmp/custom-memory.jsonl';
|
|
42
|
-
process.env.MEMORY_FILE_PATH = absolutePath;
|
|
43
|
-
const result = await ensureMemoryFilePath();
|
|
44
|
-
expect(result).toBe(absolutePath);
|
|
45
|
-
});
|
|
46
|
-
it('should convert relative path to absolute when MEMORY_FILE_PATH is relative', async () => {
|
|
47
|
-
const relativePath = 'custom-memory.jsonl';
|
|
48
|
-
process.env.MEMORY_FILE_PATH = relativePath;
|
|
49
|
-
const result = await ensureMemoryFilePath();
|
|
50
|
-
expect(path.isAbsolute(result)).toBe(true);
|
|
51
|
-
expect(result).toContain('custom-memory.jsonl');
|
|
52
|
-
});
|
|
53
|
-
it('should handle Windows absolute paths', async () => {
|
|
54
|
-
const windowsPath = 'C:\\temp\\memory.jsonl';
|
|
55
|
-
process.env.MEMORY_FILE_PATH = windowsPath;
|
|
56
|
-
const result = await ensureMemoryFilePath();
|
|
57
|
-
// On Windows, should return as-is; on Unix, will be treated as relative
|
|
58
|
-
if (process.platform === 'win32') {
|
|
59
|
-
expect(result).toBe(windowsPath);
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
expect(path.isAbsolute(result)).toBe(true);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
describe('without MEMORY_FILE_PATH environment variable', () => {
|
|
67
|
-
it('should return default path when no files exist', async () => {
|
|
68
|
-
const result = await ensureMemoryFilePath();
|
|
69
|
-
expect(result).toBe(defaultMemoryPath);
|
|
70
|
-
});
|
|
71
|
-
it('should migrate from memory.json to memory.jsonl when only old file exists', async () => {
|
|
72
|
-
// Create old memory.json file
|
|
73
|
-
await fs.writeFile(oldMemoryPath, '{"test":"data"}');
|
|
74
|
-
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
75
|
-
const result = await ensureMemoryFilePath();
|
|
76
|
-
expect(result).toBe(defaultMemoryPath);
|
|
77
|
-
// Verify migration happened
|
|
78
|
-
const newFileExists = await fs.access(newMemoryPath).then(() => true).catch(() => false);
|
|
79
|
-
const oldFileExists = await fs.access(oldMemoryPath).then(() => true).catch(() => false);
|
|
80
|
-
expect(newFileExists).toBe(true);
|
|
81
|
-
expect(oldFileExists).toBe(false);
|
|
82
|
-
// Verify console messages
|
|
83
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('DETECTED: Found legacy memory.json file'));
|
|
84
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('COMPLETED: Successfully migrated'));
|
|
85
|
-
consoleErrorSpy.mockRestore();
|
|
86
|
-
});
|
|
87
|
-
it('should use new file when both old and new files exist', async () => {
|
|
88
|
-
// Create both files
|
|
89
|
-
await fs.writeFile(oldMemoryPath, '{"old":"data"}');
|
|
90
|
-
await fs.writeFile(newMemoryPath, '{"new":"data"}');
|
|
91
|
-
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
92
|
-
const result = await ensureMemoryFilePath();
|
|
93
|
-
expect(result).toBe(defaultMemoryPath);
|
|
94
|
-
// Verify no migration happened (both files should still exist)
|
|
95
|
-
const newFileExists = await fs.access(newMemoryPath).then(() => true).catch(() => false);
|
|
96
|
-
const oldFileExists = await fs.access(oldMemoryPath).then(() => true).catch(() => false);
|
|
97
|
-
expect(newFileExists).toBe(true);
|
|
98
|
-
expect(oldFileExists).toBe(true);
|
|
99
|
-
// Verify no console messages about migration
|
|
100
|
-
expect(consoleErrorSpy).not.toHaveBeenCalled();
|
|
101
|
-
consoleErrorSpy.mockRestore();
|
|
102
|
-
});
|
|
103
|
-
it('should preserve file content during migration', async () => {
|
|
104
|
-
const testContent = '{"entities": [{"name": "test", "type": "person"}]}';
|
|
105
|
-
await fs.writeFile(oldMemoryPath, testContent);
|
|
106
|
-
await ensureMemoryFilePath();
|
|
107
|
-
const migratedContent = await fs.readFile(newMemoryPath, 'utf-8');
|
|
108
|
-
expect(migratedContent).toBe(testContent);
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
describe('defaultMemoryPath', () => {
|
|
112
|
-
it('should end with memory.jsonl', () => {
|
|
113
|
-
expect(defaultMemoryPath).toMatch(/memory\.jsonl$/);
|
|
114
|
-
});
|
|
115
|
-
it('should be an absolute path', () => {
|
|
116
|
-
expect(path.isAbsolute(defaultMemoryPath)).toBe(true);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
});
|
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { promises as fs } from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import { KnowledgeGraphManager } from '../index.js';
|
|
6
|
-
describe('KnowledgeGraphManager', () => {
|
|
7
|
-
let manager;
|
|
8
|
-
let testFilePath;
|
|
9
|
-
beforeEach(async () => {
|
|
10
|
-
// Create a temporary test file path
|
|
11
|
-
testFilePath = path.join(path.dirname(fileURLToPath(import.meta.url)), `test-memory-${Date.now()}.jsonl`);
|
|
12
|
-
manager = new KnowledgeGraphManager(testFilePath);
|
|
13
|
-
});
|
|
14
|
-
afterEach(async () => {
|
|
15
|
-
// Clean up test file
|
|
16
|
-
try {
|
|
17
|
-
await fs.unlink(testFilePath);
|
|
18
|
-
}
|
|
19
|
-
catch (error) {
|
|
20
|
-
// Ignore errors if file doesn't exist
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
describe('createEntities', () => {
|
|
24
|
-
it('should create new entities', async () => {
|
|
25
|
-
const entities = [
|
|
26
|
-
{ name: 'Alice', entityType: 'person', observations: ['works at Acme Corp'] },
|
|
27
|
-
{ name: 'Bob', entityType: 'person', observations: ['likes programming'] },
|
|
28
|
-
];
|
|
29
|
-
const newEntities = await manager.createEntities(entities);
|
|
30
|
-
expect(newEntities).toHaveLength(2);
|
|
31
|
-
expect(newEntities).toEqual(entities);
|
|
32
|
-
const graph = await manager.readGraph();
|
|
33
|
-
expect(graph.entities).toHaveLength(2);
|
|
34
|
-
});
|
|
35
|
-
it('should not create duplicate entities', async () => {
|
|
36
|
-
const entities = [
|
|
37
|
-
{ name: 'Alice', entityType: 'person', observations: ['works at Acme Corp'] },
|
|
38
|
-
];
|
|
39
|
-
await manager.createEntities(entities);
|
|
40
|
-
const newEntities = await manager.createEntities(entities);
|
|
41
|
-
expect(newEntities).toHaveLength(0);
|
|
42
|
-
const graph = await manager.readGraph();
|
|
43
|
-
expect(graph.entities).toHaveLength(1);
|
|
44
|
-
});
|
|
45
|
-
it('should handle empty entity arrays', async () => {
|
|
46
|
-
const newEntities = await manager.createEntities([]);
|
|
47
|
-
expect(newEntities).toHaveLength(0);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
describe('createRelations', () => {
|
|
51
|
-
it('should create new relations', async () => {
|
|
52
|
-
await manager.createEntities([
|
|
53
|
-
{ name: 'Alice', entityType: 'person', observations: [] },
|
|
54
|
-
{ name: 'Bob', entityType: 'person', observations: [] },
|
|
55
|
-
]);
|
|
56
|
-
const relations = [
|
|
57
|
-
{ from: 'Alice', to: 'Bob', relationType: 'knows' },
|
|
58
|
-
];
|
|
59
|
-
const newRelations = await manager.createRelations(relations);
|
|
60
|
-
expect(newRelations).toHaveLength(1);
|
|
61
|
-
expect(newRelations).toEqual(relations);
|
|
62
|
-
const graph = await manager.readGraph();
|
|
63
|
-
expect(graph.relations).toHaveLength(1);
|
|
64
|
-
});
|
|
65
|
-
it('should not create duplicate relations', async () => {
|
|
66
|
-
await manager.createEntities([
|
|
67
|
-
{ name: 'Alice', entityType: 'person', observations: [] },
|
|
68
|
-
{ name: 'Bob', entityType: 'person', observations: [] },
|
|
69
|
-
]);
|
|
70
|
-
const relations = [
|
|
71
|
-
{ from: 'Alice', to: 'Bob', relationType: 'knows' },
|
|
72
|
-
];
|
|
73
|
-
await manager.createRelations(relations);
|
|
74
|
-
const newRelations = await manager.createRelations(relations);
|
|
75
|
-
expect(newRelations).toHaveLength(0);
|
|
76
|
-
const graph = await manager.readGraph();
|
|
77
|
-
expect(graph.relations).toHaveLength(1);
|
|
78
|
-
});
|
|
79
|
-
it('should handle empty relation arrays', async () => {
|
|
80
|
-
const newRelations = await manager.createRelations([]);
|
|
81
|
-
expect(newRelations).toHaveLength(0);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
describe('addObservations', () => {
|
|
85
|
-
it('should add observations to existing entities', async () => {
|
|
86
|
-
await manager.createEntities([
|
|
87
|
-
{ name: 'Alice', entityType: 'person', observations: ['works at Acme Corp'] },
|
|
88
|
-
]);
|
|
89
|
-
const results = await manager.addObservations([
|
|
90
|
-
{ entityName: 'Alice', contents: ['likes coffee', 'has a dog'] },
|
|
91
|
-
]);
|
|
92
|
-
expect(results).toHaveLength(1);
|
|
93
|
-
expect(results[0].entityName).toBe('Alice');
|
|
94
|
-
expect(results[0].addedObservations).toHaveLength(2);
|
|
95
|
-
const graph = await manager.readGraph();
|
|
96
|
-
const alice = graph.entities.find(e => e.name === 'Alice');
|
|
97
|
-
expect(alice?.observations).toHaveLength(3);
|
|
98
|
-
});
|
|
99
|
-
it('should not add duplicate observations', async () => {
|
|
100
|
-
await manager.createEntities([
|
|
101
|
-
{ name: 'Alice', entityType: 'person', observations: ['works at Acme Corp'] },
|
|
102
|
-
]);
|
|
103
|
-
await manager.addObservations([
|
|
104
|
-
{ entityName: 'Alice', contents: ['likes coffee'] },
|
|
105
|
-
]);
|
|
106
|
-
const results = await manager.addObservations([
|
|
107
|
-
{ entityName: 'Alice', contents: ['likes coffee', 'has a dog'] },
|
|
108
|
-
]);
|
|
109
|
-
expect(results[0].addedObservations).toHaveLength(1);
|
|
110
|
-
expect(results[0].addedObservations).toContain('has a dog');
|
|
111
|
-
const graph = await manager.readGraph();
|
|
112
|
-
const alice = graph.entities.find(e => e.name === 'Alice');
|
|
113
|
-
expect(alice?.observations).toHaveLength(3);
|
|
114
|
-
});
|
|
115
|
-
it('should throw error for non-existent entity', async () => {
|
|
116
|
-
await expect(manager.addObservations([
|
|
117
|
-
{ entityName: 'NonExistent', contents: ['some observation'] },
|
|
118
|
-
])).rejects.toThrow('Entity with name NonExistent not found');
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
describe('deleteEntities', () => {
|
|
122
|
-
it('should delete entities', async () => {
|
|
123
|
-
await manager.createEntities([
|
|
124
|
-
{ name: 'Alice', entityType: 'person', observations: [] },
|
|
125
|
-
{ name: 'Bob', entityType: 'person', observations: [] },
|
|
126
|
-
]);
|
|
127
|
-
await manager.deleteEntities(['Alice']);
|
|
128
|
-
const graph = await manager.readGraph();
|
|
129
|
-
expect(graph.entities).toHaveLength(1);
|
|
130
|
-
expect(graph.entities[0].name).toBe('Bob');
|
|
131
|
-
});
|
|
132
|
-
it('should cascade delete relations when deleting entities', async () => {
|
|
133
|
-
await manager.createEntities([
|
|
134
|
-
{ name: 'Alice', entityType: 'person', observations: [] },
|
|
135
|
-
{ name: 'Bob', entityType: 'person', observations: [] },
|
|
136
|
-
{ name: 'Charlie', entityType: 'person', observations: [] },
|
|
137
|
-
]);
|
|
138
|
-
await manager.createRelations([
|
|
139
|
-
{ from: 'Alice', to: 'Bob', relationType: 'knows' },
|
|
140
|
-
{ from: 'Bob', to: 'Charlie', relationType: 'knows' },
|
|
141
|
-
]);
|
|
142
|
-
await manager.deleteEntities(['Bob']);
|
|
143
|
-
const graph = await manager.readGraph();
|
|
144
|
-
expect(graph.entities).toHaveLength(2);
|
|
145
|
-
expect(graph.relations).toHaveLength(0);
|
|
146
|
-
});
|
|
147
|
-
it('should handle deleting non-existent entities', async () => {
|
|
148
|
-
await manager.deleteEntities(['NonExistent']);
|
|
149
|
-
const graph = await manager.readGraph();
|
|
150
|
-
expect(graph.entities).toHaveLength(0);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
describe('deleteObservations', () => {
|
|
154
|
-
it('should delete observations from entities', async () => {
|
|
155
|
-
await manager.createEntities([
|
|
156
|
-
{ name: 'Alice', entityType: 'person', observations: ['works at Acme Corp', 'likes coffee'] },
|
|
157
|
-
]);
|
|
158
|
-
await manager.deleteObservations([
|
|
159
|
-
{ entityName: 'Alice', observations: ['likes coffee'] },
|
|
160
|
-
]);
|
|
161
|
-
const graph = await manager.readGraph();
|
|
162
|
-
const alice = graph.entities.find(e => e.name === 'Alice');
|
|
163
|
-
expect(alice?.observations).toHaveLength(1);
|
|
164
|
-
expect(alice?.observations).toContain('works at Acme Corp');
|
|
165
|
-
});
|
|
166
|
-
it('should handle deleting from non-existent entities', async () => {
|
|
167
|
-
await manager.deleteObservations([
|
|
168
|
-
{ entityName: 'NonExistent', observations: ['some observation'] },
|
|
169
|
-
]);
|
|
170
|
-
// Should not throw error
|
|
171
|
-
const graph = await manager.readGraph();
|
|
172
|
-
expect(graph.entities).toHaveLength(0);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
describe('deleteRelations', () => {
|
|
176
|
-
it('should delete specific relations', async () => {
|
|
177
|
-
await manager.createEntities([
|
|
178
|
-
{ name: 'Alice', entityType: 'person', observations: [] },
|
|
179
|
-
{ name: 'Bob', entityType: 'person', observations: [] },
|
|
180
|
-
]);
|
|
181
|
-
await manager.createRelations([
|
|
182
|
-
{ from: 'Alice', to: 'Bob', relationType: 'knows' },
|
|
183
|
-
{ from: 'Alice', to: 'Bob', relationType: 'works_with' },
|
|
184
|
-
]);
|
|
185
|
-
await manager.deleteRelations([
|
|
186
|
-
{ from: 'Alice', to: 'Bob', relationType: 'knows' },
|
|
187
|
-
]);
|
|
188
|
-
const graph = await manager.readGraph();
|
|
189
|
-
expect(graph.relations).toHaveLength(1);
|
|
190
|
-
expect(graph.relations[0].relationType).toBe('works_with');
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
describe('readGraph', () => {
|
|
194
|
-
it('should return empty graph when file does not exist', async () => {
|
|
195
|
-
const graph = await manager.readGraph();
|
|
196
|
-
expect(graph.entities).toHaveLength(0);
|
|
197
|
-
expect(graph.relations).toHaveLength(0);
|
|
198
|
-
});
|
|
199
|
-
it('should return complete graph with entities and relations', async () => {
|
|
200
|
-
await manager.createEntities([
|
|
201
|
-
{ name: 'Alice', entityType: 'person', observations: ['works at Acme Corp'] },
|
|
202
|
-
]);
|
|
203
|
-
await manager.createRelations([
|
|
204
|
-
{ from: 'Alice', to: 'Alice', relationType: 'self' },
|
|
205
|
-
]);
|
|
206
|
-
const graph = await manager.readGraph();
|
|
207
|
-
expect(graph.entities).toHaveLength(1);
|
|
208
|
-
expect(graph.relations).toHaveLength(1);
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
describe('searchNodes', () => {
|
|
212
|
-
beforeEach(async () => {
|
|
213
|
-
await manager.createEntities([
|
|
214
|
-
{ name: 'Alice', entityType: 'person', observations: ['works at Acme Corp', 'likes programming'] },
|
|
215
|
-
{ name: 'Bob', entityType: 'person', observations: ['works at TechCo'] },
|
|
216
|
-
{ name: 'Acme Corp', entityType: 'company', observations: ['tech company'] },
|
|
217
|
-
]);
|
|
218
|
-
await manager.createRelations([
|
|
219
|
-
{ from: 'Alice', to: 'Acme Corp', relationType: 'works_at' },
|
|
220
|
-
{ from: 'Bob', to: 'Acme Corp', relationType: 'competitor' },
|
|
221
|
-
]);
|
|
222
|
-
});
|
|
223
|
-
it('should search by entity name', async () => {
|
|
224
|
-
const result = await manager.searchNodes('Alice');
|
|
225
|
-
expect(result.entities).toHaveLength(1);
|
|
226
|
-
expect(result.entities[0].name).toBe('Alice');
|
|
227
|
-
});
|
|
228
|
-
it('should search by entity type', async () => {
|
|
229
|
-
const result = await manager.searchNodes('company');
|
|
230
|
-
expect(result.entities).toHaveLength(1);
|
|
231
|
-
expect(result.entities[0].name).toBe('Acme Corp');
|
|
232
|
-
});
|
|
233
|
-
it('should search by observation content', async () => {
|
|
234
|
-
const result = await manager.searchNodes('programming');
|
|
235
|
-
expect(result.entities).toHaveLength(1);
|
|
236
|
-
expect(result.entities[0].name).toBe('Alice');
|
|
237
|
-
});
|
|
238
|
-
it('should be case insensitive', async () => {
|
|
239
|
-
const result = await manager.searchNodes('ALICE');
|
|
240
|
-
expect(result.entities).toHaveLength(1);
|
|
241
|
-
expect(result.entities[0].name).toBe('Alice');
|
|
242
|
-
});
|
|
243
|
-
it('should include relations between matched entities', async () => {
|
|
244
|
-
const result = await manager.searchNodes('Acme');
|
|
245
|
-
expect(result.entities).toHaveLength(2); // Alice and Acme Corp
|
|
246
|
-
expect(result.relations).toHaveLength(1); // Only Alice -> Acme Corp relation
|
|
247
|
-
});
|
|
248
|
-
it('should return empty graph for no matches', async () => {
|
|
249
|
-
const result = await manager.searchNodes('NonExistent');
|
|
250
|
-
expect(result.entities).toHaveLength(0);
|
|
251
|
-
expect(result.relations).toHaveLength(0);
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
describe('openNodes', () => {
|
|
255
|
-
beforeEach(async () => {
|
|
256
|
-
await manager.createEntities([
|
|
257
|
-
{ name: 'Alice', entityType: 'person', observations: [] },
|
|
258
|
-
{ name: 'Bob', entityType: 'person', observations: [] },
|
|
259
|
-
{ name: 'Charlie', entityType: 'person', observations: [] },
|
|
260
|
-
]);
|
|
261
|
-
await manager.createRelations([
|
|
262
|
-
{ from: 'Alice', to: 'Bob', relationType: 'knows' },
|
|
263
|
-
{ from: 'Bob', to: 'Charlie', relationType: 'knows' },
|
|
264
|
-
]);
|
|
265
|
-
});
|
|
266
|
-
it('should open specific nodes by name', async () => {
|
|
267
|
-
const result = await manager.openNodes(['Alice', 'Bob']);
|
|
268
|
-
expect(result.entities).toHaveLength(2);
|
|
269
|
-
expect(result.entities.map(e => e.name)).toContain('Alice');
|
|
270
|
-
expect(result.entities.map(e => e.name)).toContain('Bob');
|
|
271
|
-
});
|
|
272
|
-
it('should include relations between opened nodes', async () => {
|
|
273
|
-
const result = await manager.openNodes(['Alice', 'Bob']);
|
|
274
|
-
expect(result.relations).toHaveLength(1);
|
|
275
|
-
expect(result.relations[0].from).toBe('Alice');
|
|
276
|
-
expect(result.relations[0].to).toBe('Bob');
|
|
277
|
-
});
|
|
278
|
-
it('should exclude relations to unopened nodes', async () => {
|
|
279
|
-
const result = await manager.openNodes(['Bob']);
|
|
280
|
-
expect(result.relations).toHaveLength(0);
|
|
281
|
-
});
|
|
282
|
-
it('should handle opening non-existent nodes', async () => {
|
|
283
|
-
const result = await manager.openNodes(['NonExistent']);
|
|
284
|
-
expect(result.entities).toHaveLength(0);
|
|
285
|
-
});
|
|
286
|
-
it('should handle empty node list', async () => {
|
|
287
|
-
const result = await manager.openNodes([]);
|
|
288
|
-
expect(result.entities).toHaveLength(0);
|
|
289
|
-
expect(result.relations).toHaveLength(0);
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
describe('file persistence', () => {
|
|
293
|
-
it('should persist data across manager instances', async () => {
|
|
294
|
-
await manager.createEntities([
|
|
295
|
-
{ name: 'Alice', entityType: 'person', observations: ['persistent data'] },
|
|
296
|
-
]);
|
|
297
|
-
// Create new manager instance with same file path
|
|
298
|
-
const manager2 = new KnowledgeGraphManager(testFilePath);
|
|
299
|
-
const graph = await manager2.readGraph();
|
|
300
|
-
expect(graph.entities).toHaveLength(1);
|
|
301
|
-
expect(graph.entities[0].name).toBe('Alice');
|
|
302
|
-
});
|
|
303
|
-
it('should handle JSONL format correctly', async () => {
|
|
304
|
-
await manager.createEntities([
|
|
305
|
-
{ name: 'Alice', entityType: 'person', observations: [] },
|
|
306
|
-
]);
|
|
307
|
-
await manager.createRelations([
|
|
308
|
-
{ from: 'Alice', to: 'Alice', relationType: 'self' },
|
|
309
|
-
]);
|
|
310
|
-
// Read file directly
|
|
311
|
-
const fileContent = await fs.readFile(testFilePath, 'utf-8');
|
|
312
|
-
const lines = fileContent.split('\n').filter(line => line.trim());
|
|
313
|
-
expect(lines).toHaveLength(2);
|
|
314
|
-
expect(JSON.parse(lines[0])).toHaveProperty('type', 'entity');
|
|
315
|
-
expect(JSON.parse(lines[1])).toHaveProperty('type', 'relation');
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
|
-
});
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Graph Event Emitter
|
|
3
|
-
*
|
|
4
|
-
* Phase 10 Sprint 2: Provides event-based notifications for graph changes.
|
|
5
|
-
* Enables loose coupling between graph operations and dependent systems
|
|
6
|
-
* like search indexes, analytics, and external integrations.
|
|
7
|
-
*
|
|
8
|
-
* @module core/GraphEventEmitter
|
|
9
|
-
*/
|
|
10
|
-
import type { GraphEventType, GraphEvent, GraphEventListener, GraphEventMap, Entity, Relation } from '../types/index.js';
|
|
11
|
-
/**
|
|
12
|
-
* Phase 10 Sprint 2: Event emitter for graph change notifications.
|
|
13
|
-
*
|
|
14
|
-
* Provides a type-safe event system for subscribing to and emitting
|
|
15
|
-
* graph change events. Supports wildcard listeners for all events.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```typescript
|
|
19
|
-
* const emitter = new GraphEventEmitter();
|
|
20
|
-
*
|
|
21
|
-
* // Listen to specific event types
|
|
22
|
-
* emitter.on('entity:created', (event) => {
|
|
23
|
-
* console.log(`Entity ${event.entity.name} created`);
|
|
24
|
-
* });
|
|
25
|
-
*
|
|
26
|
-
* // Listen to all events
|
|
27
|
-
* emitter.onAny((event) => {
|
|
28
|
-
* console.log(`Event: ${event.type}`);
|
|
29
|
-
* });
|
|
30
|
-
*
|
|
31
|
-
* // Emit an event
|
|
32
|
-
* emitter.emitEntityCreated(entity);
|
|
33
|
-
*
|
|
34
|
-
* // Remove listener
|
|
35
|
-
* const unsubscribe = emitter.on('entity:deleted', handler);
|
|
36
|
-
* unsubscribe();
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export declare class GraphEventEmitter {
|
|
40
|
-
/**
|
|
41
|
-
* Map of event types to their registered listeners.
|
|
42
|
-
*/
|
|
43
|
-
private listeners;
|
|
44
|
-
/**
|
|
45
|
-
* Listeners that receive all events regardless of type.
|
|
46
|
-
*/
|
|
47
|
-
private wildcardListeners;
|
|
48
|
-
/**
|
|
49
|
-
* Whether to suppress errors from listeners (default: true).
|
|
50
|
-
* When true, listener errors are logged but don't stop event propagation.
|
|
51
|
-
*/
|
|
52
|
-
private suppressListenerErrors;
|
|
53
|
-
/**
|
|
54
|
-
* Create a new GraphEventEmitter instance.
|
|
55
|
-
*
|
|
56
|
-
* @param options - Optional configuration
|
|
57
|
-
*/
|
|
58
|
-
constructor(options?: {
|
|
59
|
-
suppressListenerErrors?: boolean;
|
|
60
|
-
});
|
|
61
|
-
/**
|
|
62
|
-
* Subscribe to a specific event type.
|
|
63
|
-
*
|
|
64
|
-
* @template K - The event type key
|
|
65
|
-
* @param eventType - The event type to listen for
|
|
66
|
-
* @param listener - Callback function to invoke when event occurs
|
|
67
|
-
* @returns Unsubscribe function to remove the listener
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* ```typescript
|
|
71
|
-
* const unsubscribe = emitter.on('entity:created', (event) => {
|
|
72
|
-
* console.log(`Created: ${event.entity.name}`);
|
|
73
|
-
* });
|
|
74
|
-
*
|
|
75
|
-
* // Later: unsubscribe();
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
on<K extends GraphEventType>(eventType: K, listener: GraphEventListener<GraphEventMap[K]>): () => void;
|
|
79
|
-
/**
|
|
80
|
-
* Unsubscribe from a specific event type.
|
|
81
|
-
*
|
|
82
|
-
* @template K - The event type key
|
|
83
|
-
* @param eventType - The event type to unsubscribe from
|
|
84
|
-
* @param listener - The listener function to remove
|
|
85
|
-
*/
|
|
86
|
-
off<K extends GraphEventType>(eventType: K, listener: GraphEventListener<GraphEventMap[K]>): void;
|
|
87
|
-
/**
|
|
88
|
-
* Subscribe to all event types.
|
|
89
|
-
*
|
|
90
|
-
* @param listener - Callback function to invoke for any event
|
|
91
|
-
* @returns Unsubscribe function to remove the listener
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```typescript
|
|
95
|
-
* emitter.onAny((event) => {
|
|
96
|
-
* console.log(`Event: ${event.type} at ${event.timestamp}`);
|
|
97
|
-
* });
|
|
98
|
-
* ```
|
|
99
|
-
*/
|
|
100
|
-
onAny(listener: GraphEventListener<GraphEvent>): () => void;
|
|
101
|
-
/**
|
|
102
|
-
* Unsubscribe from all events.
|
|
103
|
-
*
|
|
104
|
-
* @param listener - The listener function to remove
|
|
105
|
-
*/
|
|
106
|
-
offAny(listener: GraphEventListener<GraphEvent>): void;
|
|
107
|
-
/**
|
|
108
|
-
* Subscribe to an event type, but only receive the first occurrence.
|
|
109
|
-
*
|
|
110
|
-
* @template K - The event type key
|
|
111
|
-
* @param eventType - The event type to listen for once
|
|
112
|
-
* @param listener - Callback function to invoke once
|
|
113
|
-
* @returns Unsubscribe function to cancel before event occurs
|
|
114
|
-
*/
|
|
115
|
-
once<K extends GraphEventType>(eventType: K, listener: GraphEventListener<GraphEventMap[K]>): () => void;
|
|
116
|
-
/**
|
|
117
|
-
* Remove all listeners for all event types.
|
|
118
|
-
*/
|
|
119
|
-
removeAllListeners(): void;
|
|
120
|
-
/**
|
|
121
|
-
* Get the count of listeners for a specific event type.
|
|
122
|
-
*
|
|
123
|
-
* @param eventType - The event type to count listeners for
|
|
124
|
-
* @returns Number of listeners registered
|
|
125
|
-
*/
|
|
126
|
-
listenerCount(eventType?: GraphEventType): number;
|
|
127
|
-
/**
|
|
128
|
-
* Emit an event to all registered listeners.
|
|
129
|
-
*
|
|
130
|
-
* @param event - The event to emit
|
|
131
|
-
*/
|
|
132
|
-
emit(event: GraphEvent): void;
|
|
133
|
-
/**
|
|
134
|
-
* Emit an entity:created event.
|
|
135
|
-
*
|
|
136
|
-
* @param entity - The entity that was created
|
|
137
|
-
*/
|
|
138
|
-
emitEntityCreated(entity: Entity): void;
|
|
139
|
-
/**
|
|
140
|
-
* Emit an entity:updated event.
|
|
141
|
-
*
|
|
142
|
-
* @param entityName - Name of the updated entity
|
|
143
|
-
* @param changes - The changes that were applied
|
|
144
|
-
* @param previousValues - Optional previous values before update
|
|
145
|
-
*/
|
|
146
|
-
emitEntityUpdated(entityName: string, changes: Partial<Entity>, previousValues?: Partial<Entity>): void;
|
|
147
|
-
/**
|
|
148
|
-
* Emit an entity:deleted event.
|
|
149
|
-
*
|
|
150
|
-
* @param entityName - Name of the deleted entity
|
|
151
|
-
* @param entity - Optional entity data before deletion
|
|
152
|
-
*/
|
|
153
|
-
emitEntityDeleted(entityName: string, entity?: Entity): void;
|
|
154
|
-
/**
|
|
155
|
-
* Emit a relation:created event.
|
|
156
|
-
*
|
|
157
|
-
* @param relation - The relation that was created
|
|
158
|
-
*/
|
|
159
|
-
emitRelationCreated(relation: Relation): void;
|
|
160
|
-
/**
|
|
161
|
-
* Emit a relation:deleted event.
|
|
162
|
-
*
|
|
163
|
-
* @param from - Source entity name
|
|
164
|
-
* @param to - Target entity name
|
|
165
|
-
* @param relationType - Type of the deleted relation
|
|
166
|
-
*/
|
|
167
|
-
emitRelationDeleted(from: string, to: string, relationType: string): void;
|
|
168
|
-
/**
|
|
169
|
-
* Emit an observation:added event.
|
|
170
|
-
*
|
|
171
|
-
* @param entityName - Name of the entity
|
|
172
|
-
* @param observations - Observations that were added
|
|
173
|
-
*/
|
|
174
|
-
emitObservationAdded(entityName: string, observations: string[]): void;
|
|
175
|
-
/**
|
|
176
|
-
* Emit an observation:deleted event.
|
|
177
|
-
*
|
|
178
|
-
* @param entityName - Name of the entity
|
|
179
|
-
* @param observations - Observations that were deleted
|
|
180
|
-
*/
|
|
181
|
-
emitObservationDeleted(entityName: string, observations: string[]): void;
|
|
182
|
-
/**
|
|
183
|
-
* Emit a graph:saved event.
|
|
184
|
-
*
|
|
185
|
-
* @param entityCount - Number of entities in the saved graph
|
|
186
|
-
* @param relationCount - Number of relations in the saved graph
|
|
187
|
-
*/
|
|
188
|
-
emitGraphSaved(entityCount: number, relationCount: number): void;
|
|
189
|
-
/**
|
|
190
|
-
* Emit a graph:loaded event.
|
|
191
|
-
*
|
|
192
|
-
* @param entityCount - Number of entities in the loaded graph
|
|
193
|
-
* @param relationCount - Number of relations in the loaded graph
|
|
194
|
-
*/
|
|
195
|
-
emitGraphLoaded(entityCount: number, relationCount: number): void;
|
|
196
|
-
/**
|
|
197
|
-
* Safely invoke a listener, optionally catching errors.
|
|
198
|
-
* @private
|
|
199
|
-
*/
|
|
200
|
-
private invokeListener;
|
|
201
|
-
}
|
|
202
|
-
//# sourceMappingURL=GraphEventEmitter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GraphEventEmitter.d.ts","sourceRoot":"","sources":["../../src/core/GraphEventEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,MAAM,EACN,QAAQ,EAUT,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,iBAAiB;IAC5B;;OAEG;IACH,OAAO,CAAC,SAAS,CAAgE;IAEjF;;OAEG;IACH,OAAO,CAAC,iBAAiB,CAAkD;IAE3E;;;OAGG;IACH,OAAO,CAAC,sBAAsB,CAAiB;IAE/C;;;;OAIG;gBACS,OAAO,CAAC,EAAE;QAAE,sBAAsB,CAAC,EAAE,OAAO,CAAA;KAAE;IAQ1D;;;;;;;;;;;;;;;;OAgBG;IACH,EAAE,CAAC,CAAC,SAAS,cAAc,EACzB,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAC7C,MAAM,IAAI;IAYb;;;;;;OAMG;IACH,GAAG,CAAC,CAAC,SAAS,cAAc,EAC1B,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAC7C,IAAI;IAOP;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ,EAAE,kBAAkB,CAAC,UAAU,CAAC,GAAG,MAAM,IAAI;IAO3D;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,kBAAkB,CAAC,UAAU,CAAC,GAAG,IAAI;IAItD;;;;;;;OAOG;IACH,IAAI,CAAC,CAAC,SAAS,cAAc,EAC3B,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAC7C,MAAM,IAAI;IASb;;OAEG;IACH,kBAAkB,IAAI,IAAI;IAK1B;;;;;OAKG;IACH,aAAa,CAAC,SAAS,CAAC,EAAE,cAAc,GAAG,MAAM;IAcjD;;;;OAIG;IACH,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAe7B;;;;OAIG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IASvC;;;;;;OAMG;IACH,iBAAiB,CACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,EACxB,cAAc,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAC/B,IAAI;IAWP;;;;;OAKG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAU5D;;;;OAIG;IACH,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAS7C;;;;;;OAMG;IACH,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAWzE;;;;;OAKG;IACH,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI;IAYtE;;;;;OAKG;IACH,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI;IAYxE;;;;;OAKG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAUhE;;;;;OAKG;IACH,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAYjE;;;OAGG;IACH,OAAO,CAAC,cAAc;CAYvB"}
|