@danielsimonjr/memory-mcp 0.48.0 → 9.8.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 +22 -0
- package/README.md +2000 -194
- package/dist/__tests__/file-path.test.js +7 -11
- package/dist/__tests__/knowledge-graph.test.js +3 -8
- package/dist/core/EntityManager.d.ts +266 -0
- package/dist/core/EntityManager.d.ts.map +1 -0
- package/dist/core/EntityManager.js +85 -133
- package/dist/core/GraphEventEmitter.d.ts +202 -0
- package/dist/core/GraphEventEmitter.d.ts.map +1 -0
- package/dist/core/GraphEventEmitter.js +346 -0
- package/dist/core/GraphStorage.d.ts +395 -0
- package/dist/core/GraphStorage.d.ts.map +1 -0
- package/dist/core/GraphStorage.js +643 -31
- package/dist/core/GraphTraversal.d.ts +141 -0
- package/dist/core/GraphTraversal.d.ts.map +1 -0
- package/dist/core/GraphTraversal.js +573 -0
- package/dist/core/HierarchyManager.d.ts +111 -0
- package/dist/core/HierarchyManager.d.ts.map +1 -0
- package/dist/{features → core}/HierarchyManager.js +14 -9
- package/dist/core/ManagerContext.d.ts +72 -0
- package/dist/core/ManagerContext.d.ts.map +1 -0
- package/dist/core/ManagerContext.js +118 -0
- package/dist/core/ObservationManager.d.ts +85 -0
- package/dist/core/ObservationManager.d.ts.map +1 -0
- package/dist/core/ObservationManager.js +51 -57
- package/dist/core/RelationManager.d.ts +131 -0
- package/dist/core/RelationManager.d.ts.map +1 -0
- package/dist/core/RelationManager.js +31 -7
- package/dist/core/SQLiteStorage.d.ts +354 -0
- package/dist/core/SQLiteStorage.d.ts.map +1 -0
- package/dist/core/SQLiteStorage.js +917 -0
- package/dist/core/StorageFactory.d.ts +45 -0
- package/dist/core/StorageFactory.d.ts.map +1 -0
- package/dist/core/StorageFactory.js +64 -0
- package/dist/core/TransactionManager.d.ts +464 -0
- package/dist/core/TransactionManager.d.ts.map +1 -0
- package/dist/core/TransactionManager.js +490 -13
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +12 -2
- package/dist/features/AnalyticsManager.d.ts +44 -0
- package/dist/features/AnalyticsManager.d.ts.map +1 -0
- package/dist/features/AnalyticsManager.js +3 -2
- package/dist/features/ArchiveManager.d.ts +133 -0
- package/dist/features/ArchiveManager.d.ts.map +1 -0
- package/dist/features/ArchiveManager.js +221 -14
- package/dist/features/CompressionManager.d.ts +117 -0
- package/dist/features/CompressionManager.d.ts.map +1 -0
- package/dist/features/CompressionManager.js +189 -20
- package/dist/features/IOManager.d.ts +225 -0
- package/dist/features/IOManager.d.ts.map +1 -0
- package/dist/features/IOManager.js +1041 -0
- package/dist/features/StreamingExporter.d.ts +123 -0
- package/dist/features/StreamingExporter.d.ts.map +1 -0
- package/dist/features/StreamingExporter.js +203 -0
- package/dist/features/TagManager.d.ts +147 -0
- package/dist/features/TagManager.d.ts.map +1 -0
- package/dist/features/index.d.ts +12 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +5 -6
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -10
- package/dist/memory.jsonl +1 -26
- package/dist/search/BasicSearch.d.ts +51 -0
- package/dist/search/BasicSearch.d.ts.map +1 -0
- package/dist/search/BasicSearch.js +9 -3
- package/dist/search/BooleanSearch.d.ts +98 -0
- package/dist/search/BooleanSearch.d.ts.map +1 -0
- package/dist/search/BooleanSearch.js +156 -9
- package/dist/search/EmbeddingService.d.ts +178 -0
- package/dist/search/EmbeddingService.d.ts.map +1 -0
- package/dist/search/EmbeddingService.js +358 -0
- package/dist/search/FuzzySearch.d.ts +118 -0
- package/dist/search/FuzzySearch.d.ts.map +1 -0
- package/dist/search/FuzzySearch.js +241 -25
- package/dist/search/QueryCostEstimator.d.ts +111 -0
- package/dist/search/QueryCostEstimator.d.ts.map +1 -0
- package/dist/search/QueryCostEstimator.js +355 -0
- package/dist/search/RankedSearch.d.ts +71 -0
- package/dist/search/RankedSearch.d.ts.map +1 -0
- package/dist/search/RankedSearch.js +54 -6
- package/dist/search/SavedSearchManager.d.ts +79 -0
- package/dist/search/SavedSearchManager.d.ts.map +1 -0
- package/dist/search/SearchFilterChain.d.ts +120 -0
- package/dist/search/SearchFilterChain.d.ts.map +1 -0
- package/dist/search/SearchFilterChain.js +2 -4
- package/dist/search/SearchManager.d.ts +326 -0
- package/dist/search/SearchManager.d.ts.map +1 -0
- package/dist/search/SearchManager.js +148 -0
- package/dist/search/SearchSuggestions.d.ts +27 -0
- package/dist/search/SearchSuggestions.d.ts.map +1 -0
- package/dist/search/SearchSuggestions.js +1 -1
- package/dist/search/SemanticSearch.d.ts +149 -0
- package/dist/search/SemanticSearch.d.ts.map +1 -0
- package/dist/search/SemanticSearch.js +323 -0
- package/dist/search/TFIDFEventSync.d.ts +85 -0
- package/dist/search/TFIDFEventSync.d.ts.map +1 -0
- package/dist/search/TFIDFEventSync.js +133 -0
- package/dist/search/TFIDFIndexManager.d.ts +151 -0
- package/dist/search/TFIDFIndexManager.d.ts.map +1 -0
- package/dist/search/TFIDFIndexManager.js +232 -17
- package/dist/search/VectorStore.d.ts +235 -0
- package/dist/search/VectorStore.d.ts.map +1 -0
- package/dist/search/VectorStore.js +311 -0
- package/dist/search/index.d.ts +21 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +12 -0
- package/dist/server/MCPServer.d.ts +21 -0
- package/dist/server/MCPServer.d.ts.map +1 -0
- package/dist/server/MCPServer.js +4 -4
- package/dist/server/responseCompressor.d.ts +94 -0
- package/dist/server/responseCompressor.d.ts.map +1 -0
- package/dist/server/responseCompressor.js +127 -0
- package/dist/server/toolDefinitions.d.ts +27 -0
- package/dist/server/toolDefinitions.d.ts.map +1 -0
- package/dist/server/toolDefinitions.js +188 -17
- package/dist/server/toolHandlers.d.ts +41 -0
- package/dist/server/toolHandlers.d.ts.map +1 -0
- package/dist/server/toolHandlers.js +467 -75
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -1
- package/dist/types/types.d.ts +1654 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/types.js +9 -0
- package/dist/utils/compressedCache.d.ts +192 -0
- package/dist/utils/compressedCache.d.ts.map +1 -0
- package/dist/utils/compressedCache.js +309 -0
- package/dist/utils/compressionUtil.d.ts +214 -0
- package/dist/utils/compressionUtil.d.ts.map +1 -0
- package/dist/utils/compressionUtil.js +247 -0
- package/dist/utils/constants.d.ts +245 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +124 -0
- package/dist/utils/entityUtils.d.ts +321 -0
- package/dist/utils/entityUtils.d.ts.map +1 -0
- package/dist/utils/entityUtils.js +434 -4
- package/dist/utils/errors.d.ts +95 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +24 -0
- package/dist/utils/formatters.d.ts +145 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/{paginationUtils.js → formatters.js} +54 -3
- package/dist/utils/index.d.ts +23 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +69 -31
- package/dist/utils/indexes.d.ts +270 -0
- package/dist/utils/indexes.d.ts.map +1 -0
- package/dist/utils/indexes.js +526 -0
- package/dist/utils/logger.d.ts +24 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/operationUtils.d.ts +124 -0
- package/dist/utils/operationUtils.d.ts.map +1 -0
- package/dist/utils/operationUtils.js +175 -0
- package/dist/utils/parallelUtils.d.ts +72 -0
- package/dist/utils/parallelUtils.d.ts.map +1 -0
- package/dist/utils/parallelUtils.js +169 -0
- package/dist/utils/schemas.d.ts +374 -0
- package/dist/utils/schemas.d.ts.map +1 -0
- package/dist/utils/schemas.js +302 -2
- package/dist/utils/searchAlgorithms.d.ts +99 -0
- package/dist/utils/searchAlgorithms.d.ts.map +1 -0
- package/dist/utils/searchAlgorithms.js +167 -0
- package/dist/utils/searchCache.d.ts +108 -0
- package/dist/utils/searchCache.d.ts.map +1 -0
- package/dist/utils/taskScheduler.d.ts +290 -0
- package/dist/utils/taskScheduler.d.ts.map +1 -0
- package/dist/utils/taskScheduler.js +466 -0
- package/dist/workers/index.d.ts +12 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +9 -0
- package/dist/workers/levenshteinWorker.d.ts +60 -0
- package/dist/workers/levenshteinWorker.d.ts.map +1 -0
- package/dist/workers/levenshteinWorker.js +98 -0
- package/package.json +17 -4
- package/dist/__tests__/edge-cases/edge-cases.test.js +0 -406
- package/dist/__tests__/integration/workflows.test.js +0 -449
- package/dist/__tests__/performance/benchmarks.test.js +0 -413
- package/dist/__tests__/unit/core/EntityManager.test.js +0 -334
- package/dist/__tests__/unit/core/GraphStorage.test.js +0 -205
- package/dist/__tests__/unit/core/RelationManager.test.js +0 -274
- package/dist/__tests__/unit/features/CompressionManager.test.js +0 -350
- package/dist/__tests__/unit/search/BasicSearch.test.js +0 -311
- package/dist/__tests__/unit/search/BooleanSearch.test.js +0 -432
- package/dist/__tests__/unit/search/FuzzySearch.test.js +0 -448
- package/dist/__tests__/unit/search/RankedSearch.test.js +0 -379
- package/dist/__tests__/unit/utils/levenshtein.test.js +0 -77
- package/dist/core/KnowledgeGraphManager.js +0 -423
- package/dist/features/BackupManager.js +0 -311
- package/dist/features/ExportManager.js +0 -305
- package/dist/features/ImportExportManager.js +0 -50
- package/dist/features/ImportManager.js +0 -328
- package/dist/memory-saved-searches.jsonl +0 -0
- package/dist/memory-tag-aliases.jsonl +0 -0
- package/dist/types/analytics.types.js +0 -6
- package/dist/types/entity.types.js +0 -7
- package/dist/types/import-export.types.js +0 -7
- package/dist/types/search.types.js +0 -7
- package/dist/types/tag.types.js +0 -6
- package/dist/utils/dateUtils.js +0 -89
- package/dist/utils/filterUtils.js +0 -155
- package/dist/utils/levenshtein.js +0 -62
- package/dist/utils/pathUtils.js +0 -115
- package/dist/utils/responseFormatter.js +0 -55
- package/dist/utils/tagUtils.js +0 -107
- package/dist/utils/tfidf.js +0 -90
- package/dist/utils/validationHelper.js +0 -99
- package/dist/utils/validationUtils.js +0 -109
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Import Manager
|
|
3
|
-
*
|
|
4
|
-
* Imports knowledge graphs from various formats (JSON, CSV, GraphML) with merge strategies.
|
|
5
|
-
*
|
|
6
|
-
* @module features/ImportManager
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Manages knowledge graph imports from multiple formats.
|
|
10
|
-
*/
|
|
11
|
-
export class ImportManager {
|
|
12
|
-
storage;
|
|
13
|
-
constructor(storage) {
|
|
14
|
-
this.storage = storage;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Import graph from formatted data.
|
|
18
|
-
*
|
|
19
|
-
* @param format - Import format
|
|
20
|
-
* @param data - Import data string
|
|
21
|
-
* @param mergeStrategy - How to handle conflicts
|
|
22
|
-
* @param dryRun - If true, preview changes without applying
|
|
23
|
-
* @returns Import result with statistics
|
|
24
|
-
*/
|
|
25
|
-
async importGraph(format, data, mergeStrategy = 'skip', dryRun = false) {
|
|
26
|
-
let importedGraph;
|
|
27
|
-
try {
|
|
28
|
-
switch (format) {
|
|
29
|
-
case 'json':
|
|
30
|
-
importedGraph = this.parseJsonImport(data);
|
|
31
|
-
break;
|
|
32
|
-
case 'csv':
|
|
33
|
-
importedGraph = this.parseCsvImport(data);
|
|
34
|
-
break;
|
|
35
|
-
case 'graphml':
|
|
36
|
-
importedGraph = this.parseGraphMLImport(data);
|
|
37
|
-
break;
|
|
38
|
-
default:
|
|
39
|
-
throw new Error(`Unsupported import format: ${format}`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
return {
|
|
44
|
-
entitiesAdded: 0,
|
|
45
|
-
entitiesSkipped: 0,
|
|
46
|
-
entitiesUpdated: 0,
|
|
47
|
-
relationsAdded: 0,
|
|
48
|
-
relationsSkipped: 0,
|
|
49
|
-
errors: [`Failed to parse ${format} data: ${error instanceof Error ? error.message : String(error)}`],
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
return await this.mergeImportedGraph(importedGraph, mergeStrategy, dryRun);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Parse JSON format.
|
|
56
|
-
*/
|
|
57
|
-
parseJsonImport(data) {
|
|
58
|
-
const parsed = JSON.parse(data);
|
|
59
|
-
if (!parsed.entities || !Array.isArray(parsed.entities)) {
|
|
60
|
-
throw new Error('Invalid JSON: missing or invalid entities array');
|
|
61
|
-
}
|
|
62
|
-
if (!parsed.relations || !Array.isArray(parsed.relations)) {
|
|
63
|
-
throw new Error('Invalid JSON: missing or invalid relations array');
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
entities: parsed.entities,
|
|
67
|
-
relations: parsed.relations,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Parse CSV format.
|
|
72
|
-
*
|
|
73
|
-
* Expects: # ENTITIES section with header, then # RELATIONS section with header
|
|
74
|
-
*/
|
|
75
|
-
parseCsvImport(data) {
|
|
76
|
-
const lines = data
|
|
77
|
-
.split('\n')
|
|
78
|
-
.map(line => line.trim())
|
|
79
|
-
.filter(line => line);
|
|
80
|
-
const entities = [];
|
|
81
|
-
const relations = [];
|
|
82
|
-
let section = null;
|
|
83
|
-
let headerParsed = false;
|
|
84
|
-
const parseCsvLine = (line) => {
|
|
85
|
-
const fields = [];
|
|
86
|
-
let current = '';
|
|
87
|
-
let inQuotes = false;
|
|
88
|
-
for (let i = 0; i < line.length; i++) {
|
|
89
|
-
const char = line[i];
|
|
90
|
-
if (char === '"') {
|
|
91
|
-
if (inQuotes && line[i + 1] === '"') {
|
|
92
|
-
current += '"';
|
|
93
|
-
i++;
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
inQuotes = !inQuotes;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
else if (char === ',' && !inQuotes) {
|
|
100
|
-
fields.push(current);
|
|
101
|
-
current = '';
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
current += char;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
fields.push(current);
|
|
108
|
-
return fields;
|
|
109
|
-
};
|
|
110
|
-
for (const line of lines) {
|
|
111
|
-
if (line.startsWith('# ENTITIES')) {
|
|
112
|
-
section = 'entities';
|
|
113
|
-
headerParsed = false;
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
else if (line.startsWith('# RELATIONS')) {
|
|
117
|
-
section = 'relations';
|
|
118
|
-
headerParsed = false;
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
if (line.startsWith('#'))
|
|
122
|
-
continue;
|
|
123
|
-
if (section === 'entities') {
|
|
124
|
-
if (!headerParsed) {
|
|
125
|
-
headerParsed = true;
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
const fields = parseCsvLine(line);
|
|
129
|
-
if (fields.length >= 2) {
|
|
130
|
-
const entity = {
|
|
131
|
-
name: fields[0],
|
|
132
|
-
entityType: fields[1],
|
|
133
|
-
observations: fields[2]
|
|
134
|
-
? fields[2]
|
|
135
|
-
.split(';')
|
|
136
|
-
.map(s => s.trim())
|
|
137
|
-
.filter(s => s)
|
|
138
|
-
: [],
|
|
139
|
-
createdAt: fields[3] || undefined,
|
|
140
|
-
lastModified: fields[4] || undefined,
|
|
141
|
-
tags: fields[5]
|
|
142
|
-
? fields[5]
|
|
143
|
-
.split(';')
|
|
144
|
-
.map(s => s.trim().toLowerCase())
|
|
145
|
-
.filter(s => s)
|
|
146
|
-
: undefined,
|
|
147
|
-
importance: fields[6] ? parseFloat(fields[6]) : undefined,
|
|
148
|
-
};
|
|
149
|
-
entities.push(entity);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
else if (section === 'relations') {
|
|
153
|
-
if (!headerParsed) {
|
|
154
|
-
headerParsed = true;
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
const fields = parseCsvLine(line);
|
|
158
|
-
if (fields.length >= 3) {
|
|
159
|
-
const relation = {
|
|
160
|
-
from: fields[0],
|
|
161
|
-
to: fields[1],
|
|
162
|
-
relationType: fields[2],
|
|
163
|
-
createdAt: fields[3] || undefined,
|
|
164
|
-
lastModified: fields[4] || undefined,
|
|
165
|
-
};
|
|
166
|
-
relations.push(relation);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return { entities, relations };
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Parse GraphML format.
|
|
174
|
-
*
|
|
175
|
-
* Note: Simplified regex-based parser for basic GraphML structure.
|
|
176
|
-
*/
|
|
177
|
-
parseGraphMLImport(data) {
|
|
178
|
-
const entities = [];
|
|
179
|
-
const relations = [];
|
|
180
|
-
// Extract nodes
|
|
181
|
-
const nodeRegex = /<node\s+id="([^"]+)"[^>]*>([\s\S]*?)<\/node>/g;
|
|
182
|
-
let nodeMatch;
|
|
183
|
-
while ((nodeMatch = nodeRegex.exec(data)) !== null) {
|
|
184
|
-
const nodeId = nodeMatch[1];
|
|
185
|
-
const nodeContent = nodeMatch[2];
|
|
186
|
-
const getDataValue = (key) => {
|
|
187
|
-
const dataRegex = new RegExp(`<data\\s+key="${key}">([^<]*)<\/data>`);
|
|
188
|
-
const match = dataRegex.exec(nodeContent);
|
|
189
|
-
return match ? match[1] : undefined;
|
|
190
|
-
};
|
|
191
|
-
const entity = {
|
|
192
|
-
name: nodeId,
|
|
193
|
-
entityType: getDataValue('d0') || getDataValue('entityType') || 'unknown',
|
|
194
|
-
observations: (getDataValue('d1') || getDataValue('observations') || '')
|
|
195
|
-
.split(';')
|
|
196
|
-
.map(s => s.trim())
|
|
197
|
-
.filter(s => s),
|
|
198
|
-
createdAt: getDataValue('d2') || getDataValue('createdAt'),
|
|
199
|
-
lastModified: getDataValue('d3') || getDataValue('lastModified'),
|
|
200
|
-
tags: (getDataValue('d4') || getDataValue('tags') || '')
|
|
201
|
-
.split(';')
|
|
202
|
-
.map(s => s.trim().toLowerCase())
|
|
203
|
-
.filter(s => s),
|
|
204
|
-
importance: getDataValue('d5') || getDataValue('importance') ? parseFloat(getDataValue('d5') || getDataValue('importance') || '0') : undefined,
|
|
205
|
-
};
|
|
206
|
-
entities.push(entity);
|
|
207
|
-
}
|
|
208
|
-
// Extract edges
|
|
209
|
-
const edgeRegex = /<edge\s+[^>]*source="([^"]+)"\s+target="([^"]+)"[^>]*>([\s\S]*?)<\/edge>/g;
|
|
210
|
-
let edgeMatch;
|
|
211
|
-
while ((edgeMatch = edgeRegex.exec(data)) !== null) {
|
|
212
|
-
const source = edgeMatch[1];
|
|
213
|
-
const target = edgeMatch[2];
|
|
214
|
-
const edgeContent = edgeMatch[3];
|
|
215
|
-
const getDataValue = (key) => {
|
|
216
|
-
const dataRegex = new RegExp(`<data\\s+key="${key}">([^<]*)<\/data>`);
|
|
217
|
-
const match = dataRegex.exec(edgeContent);
|
|
218
|
-
return match ? match[1] : undefined;
|
|
219
|
-
};
|
|
220
|
-
const relation = {
|
|
221
|
-
from: source,
|
|
222
|
-
to: target,
|
|
223
|
-
relationType: getDataValue('e0') || getDataValue('relationType') || 'related_to',
|
|
224
|
-
createdAt: getDataValue('e1') || getDataValue('createdAt'),
|
|
225
|
-
lastModified: getDataValue('e2') || getDataValue('lastModified'),
|
|
226
|
-
};
|
|
227
|
-
relations.push(relation);
|
|
228
|
-
}
|
|
229
|
-
return { entities, relations };
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Merge imported graph with existing graph.
|
|
233
|
-
*/
|
|
234
|
-
async mergeImportedGraph(importedGraph, mergeStrategy, dryRun) {
|
|
235
|
-
const existingGraph = await this.storage.loadGraph();
|
|
236
|
-
const result = {
|
|
237
|
-
entitiesAdded: 0,
|
|
238
|
-
entitiesSkipped: 0,
|
|
239
|
-
entitiesUpdated: 0,
|
|
240
|
-
relationsAdded: 0,
|
|
241
|
-
relationsSkipped: 0,
|
|
242
|
-
errors: [],
|
|
243
|
-
};
|
|
244
|
-
const existingEntitiesMap = new Map();
|
|
245
|
-
for (const entity of existingGraph.entities) {
|
|
246
|
-
existingEntitiesMap.set(entity.name, entity);
|
|
247
|
-
}
|
|
248
|
-
const existingRelationsSet = new Set();
|
|
249
|
-
for (const relation of existingGraph.relations) {
|
|
250
|
-
existingRelationsSet.add(`${relation.from}|${relation.to}|${relation.relationType}`);
|
|
251
|
-
}
|
|
252
|
-
// Process entities
|
|
253
|
-
for (const importedEntity of importedGraph.entities) {
|
|
254
|
-
const existing = existingEntitiesMap.get(importedEntity.name);
|
|
255
|
-
if (!existing) {
|
|
256
|
-
result.entitiesAdded++;
|
|
257
|
-
if (!dryRun) {
|
|
258
|
-
existingGraph.entities.push(importedEntity);
|
|
259
|
-
existingEntitiesMap.set(importedEntity.name, importedEntity);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
switch (mergeStrategy) {
|
|
264
|
-
case 'replace':
|
|
265
|
-
result.entitiesUpdated++;
|
|
266
|
-
if (!dryRun) {
|
|
267
|
-
Object.assign(existing, importedEntity);
|
|
268
|
-
}
|
|
269
|
-
break;
|
|
270
|
-
case 'skip':
|
|
271
|
-
result.entitiesSkipped++;
|
|
272
|
-
break;
|
|
273
|
-
case 'merge':
|
|
274
|
-
result.entitiesUpdated++;
|
|
275
|
-
if (!dryRun) {
|
|
276
|
-
existing.observations = [
|
|
277
|
-
...new Set([...existing.observations, ...importedEntity.observations]),
|
|
278
|
-
];
|
|
279
|
-
if (importedEntity.tags) {
|
|
280
|
-
existing.tags = existing.tags || [];
|
|
281
|
-
existing.tags = [...new Set([...existing.tags, ...importedEntity.tags])];
|
|
282
|
-
}
|
|
283
|
-
if (importedEntity.importance !== undefined) {
|
|
284
|
-
existing.importance = importedEntity.importance;
|
|
285
|
-
}
|
|
286
|
-
existing.lastModified = new Date().toISOString();
|
|
287
|
-
}
|
|
288
|
-
break;
|
|
289
|
-
case 'fail':
|
|
290
|
-
result.errors.push(`Entity "${importedEntity.name}" already exists`);
|
|
291
|
-
break;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
// Process relations
|
|
296
|
-
for (const importedRelation of importedGraph.relations) {
|
|
297
|
-
const relationKey = `${importedRelation.from}|${importedRelation.to}|${importedRelation.relationType}`;
|
|
298
|
-
if (!existingEntitiesMap.has(importedRelation.from)) {
|
|
299
|
-
result.errors.push(`Relation source entity "${importedRelation.from}" does not exist`);
|
|
300
|
-
continue;
|
|
301
|
-
}
|
|
302
|
-
if (!existingEntitiesMap.has(importedRelation.to)) {
|
|
303
|
-
result.errors.push(`Relation target entity "${importedRelation.to}" does not exist`);
|
|
304
|
-
continue;
|
|
305
|
-
}
|
|
306
|
-
if (!existingRelationsSet.has(relationKey)) {
|
|
307
|
-
result.relationsAdded++;
|
|
308
|
-
if (!dryRun) {
|
|
309
|
-
existingGraph.relations.push(importedRelation);
|
|
310
|
-
existingRelationsSet.add(relationKey);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
if (mergeStrategy === 'fail') {
|
|
315
|
-
result.errors.push(`Relation "${relationKey}" already exists`);
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
result.relationsSkipped++;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
// Save if not dry run and no blocking errors
|
|
323
|
-
if (!dryRun && (mergeStrategy !== 'fail' || result.errors.length === 0)) {
|
|
324
|
-
await this.storage.saveGraph(existingGraph);
|
|
325
|
-
}
|
|
326
|
-
return result;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
File without changes
|
|
File without changes
|
package/dist/types/tag.types.js
DELETED
package/dist/utils/dateUtils.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Utilities
|
|
3
|
-
*
|
|
4
|
-
* Helper functions for date parsing, validation, and range filtering.
|
|
5
|
-
* All dates use ISO 8601 format (YYYY-MM-DDTHH:mm:ss.sssZ).
|
|
6
|
-
*
|
|
7
|
-
* @module utils/dateUtils
|
|
8
|
-
*/
|
|
9
|
-
/**
|
|
10
|
-
* Check if a date falls within a specified range.
|
|
11
|
-
*
|
|
12
|
-
* @param date - ISO 8601 date string to check
|
|
13
|
-
* @param start - Optional start date (inclusive)
|
|
14
|
-
* @param end - Optional end date (inclusive)
|
|
15
|
-
* @returns True if date is within range
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```typescript
|
|
19
|
-
* isWithinDateRange('2024-06-15T00:00:00Z', '2024-01-01T00:00:00Z', '2024-12-31T23:59:59Z'); // true
|
|
20
|
-
* isWithinDateRange('2024-06-15T00:00:00Z', '2024-07-01T00:00:00Z'); // false
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export function isWithinDateRange(date, start, end) {
|
|
24
|
-
const dateObj = new Date(date);
|
|
25
|
-
if (isNaN(dateObj.getTime())) {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
if (start) {
|
|
29
|
-
const startObj = new Date(start);
|
|
30
|
-
if (isNaN(startObj.getTime())) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
if (dateObj < startObj) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (end) {
|
|
38
|
-
const endObj = new Date(end);
|
|
39
|
-
if (isNaN(endObj.getTime())) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
if (dateObj > endObj) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Parse and validate date range strings.
|
|
50
|
-
*
|
|
51
|
-
* @param startDate - Optional ISO 8601 start date
|
|
52
|
-
* @param endDate - Optional ISO 8601 end date
|
|
53
|
-
* @returns Parsed Date objects or null
|
|
54
|
-
*/
|
|
55
|
-
export function parseDateRange(startDate, endDate) {
|
|
56
|
-
let start = null;
|
|
57
|
-
let end = null;
|
|
58
|
-
if (startDate) {
|
|
59
|
-
start = new Date(startDate);
|
|
60
|
-
if (isNaN(start.getTime())) {
|
|
61
|
-
start = null;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (endDate) {
|
|
65
|
-
end = new Date(endDate);
|
|
66
|
-
if (isNaN(end.getTime())) {
|
|
67
|
-
end = null;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return { start, end };
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Validate if a string is a valid ISO 8601 date.
|
|
74
|
-
*
|
|
75
|
-
* @param date - Date string to validate
|
|
76
|
-
* @returns True if valid ISO 8601 date
|
|
77
|
-
*/
|
|
78
|
-
export function isValidISODate(date) {
|
|
79
|
-
const dateObj = new Date(date);
|
|
80
|
-
return !isNaN(dateObj.getTime()) && dateObj.toISOString() === date;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Get current timestamp in ISO 8601 format.
|
|
84
|
-
*
|
|
85
|
-
* @returns Current timestamp string
|
|
86
|
-
*/
|
|
87
|
-
export function getCurrentTimestamp() {
|
|
88
|
-
return new Date().toISOString();
|
|
89
|
-
}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Entity Filtering Utilities
|
|
3
|
-
*
|
|
4
|
-
* Centralizes common filtering logic for importance, date ranges, and other
|
|
5
|
-
* entity properties to eliminate duplicate patterns across search implementations.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Checks if an entity's importance is within the specified range.
|
|
9
|
-
* Entities without importance are treated as not matching if any filter is set.
|
|
10
|
-
*
|
|
11
|
-
* @param importance - The entity's importance value (may be undefined)
|
|
12
|
-
* @param minImportance - Minimum importance filter (inclusive)
|
|
13
|
-
* @param maxImportance - Maximum importance filter (inclusive)
|
|
14
|
-
* @returns true if importance is within range or no filters are set
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```typescript
|
|
18
|
-
* // Check if entity passes importance filter
|
|
19
|
-
* if (isWithinImportanceRange(entity.importance, 5, 10)) {
|
|
20
|
-
* // Entity has importance between 5 and 10
|
|
21
|
-
* }
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export function isWithinImportanceRange(importance, minImportance, maxImportance) {
|
|
25
|
-
// If no filters set, always pass
|
|
26
|
-
if (minImportance === undefined && maxImportance === undefined) {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
// Check minimum importance
|
|
30
|
-
if (minImportance !== undefined) {
|
|
31
|
-
if (importance === undefined || importance < minImportance) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
// Check maximum importance
|
|
36
|
-
if (maxImportance !== undefined) {
|
|
37
|
-
if (importance === undefined || importance > maxImportance) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Filters entities by importance range.
|
|
45
|
-
* Returns all entities if no importance filters are specified.
|
|
46
|
-
*
|
|
47
|
-
* @param entities - Array of entities to filter
|
|
48
|
-
* @param minImportance - Minimum importance filter (inclusive)
|
|
49
|
-
* @param maxImportance - Maximum importance filter (inclusive)
|
|
50
|
-
* @returns Filtered entities within the importance range
|
|
51
|
-
*/
|
|
52
|
-
export function filterByImportance(entities, minImportance, maxImportance) {
|
|
53
|
-
if (minImportance === undefined && maxImportance === undefined) {
|
|
54
|
-
return entities;
|
|
55
|
-
}
|
|
56
|
-
return entities.filter(e => isWithinImportanceRange(e.importance, minImportance, maxImportance));
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Checks if a date value is within the specified range.
|
|
60
|
-
* Handles undefined values appropriately.
|
|
61
|
-
*
|
|
62
|
-
* @param dateValue - ISO 8601 date string to check (may be undefined)
|
|
63
|
-
* @param startDate - Start of date range (inclusive)
|
|
64
|
-
* @param endDate - End of date range (inclusive)
|
|
65
|
-
* @returns true if date is within range or no filters are set
|
|
66
|
-
*/
|
|
67
|
-
export function isWithinDateRange(dateValue, startDate, endDate) {
|
|
68
|
-
// If no filters set, always pass
|
|
69
|
-
if (!startDate && !endDate) {
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
// If date value is undefined but we have filters, fail
|
|
73
|
-
if (!dateValue) {
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
const date = new Date(dateValue);
|
|
77
|
-
if (startDate && date < new Date(startDate)) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
if (endDate && date > new Date(endDate)) {
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Filters entities by creation date range.
|
|
87
|
-
*
|
|
88
|
-
* @param entities - Array of entities to filter
|
|
89
|
-
* @param startDate - Start of date range (inclusive)
|
|
90
|
-
* @param endDate - End of date range (inclusive)
|
|
91
|
-
* @returns Filtered entities created within the date range
|
|
92
|
-
*/
|
|
93
|
-
export function filterByCreatedDate(entities, startDate, endDate) {
|
|
94
|
-
if (!startDate && !endDate) {
|
|
95
|
-
return entities;
|
|
96
|
-
}
|
|
97
|
-
return entities.filter(e => isWithinDateRange(e.createdAt, startDate, endDate));
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Filters entities by last modified date range.
|
|
101
|
-
*
|
|
102
|
-
* @param entities - Array of entities to filter
|
|
103
|
-
* @param startDate - Start of date range (inclusive)
|
|
104
|
-
* @param endDate - End of date range (inclusive)
|
|
105
|
-
* @returns Filtered entities modified within the date range
|
|
106
|
-
*/
|
|
107
|
-
export function filterByModifiedDate(entities, startDate, endDate) {
|
|
108
|
-
if (!startDate && !endDate) {
|
|
109
|
-
return entities;
|
|
110
|
-
}
|
|
111
|
-
return entities.filter(e => isWithinDateRange(e.lastModified, startDate, endDate));
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Filters entities by entity type.
|
|
115
|
-
*
|
|
116
|
-
* @param entities - Array of entities to filter
|
|
117
|
-
* @param entityType - Entity type to filter by (case-sensitive)
|
|
118
|
-
* @returns Filtered entities of the specified type
|
|
119
|
-
*/
|
|
120
|
-
export function filterByEntityType(entities, entityType) {
|
|
121
|
-
if (!entityType) {
|
|
122
|
-
return entities;
|
|
123
|
-
}
|
|
124
|
-
return entities.filter(e => e.entityType === entityType);
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Checks if an entity passes all the specified filters.
|
|
128
|
-
* Short-circuits on first failing filter for performance.
|
|
129
|
-
*
|
|
130
|
-
* Note: Tag filtering should be handled separately using tagUtils.hasMatchingTag
|
|
131
|
-
* as it requires special normalization logic.
|
|
132
|
-
*
|
|
133
|
-
* @param entity - Entity to check
|
|
134
|
-
* @param filters - Filters to apply
|
|
135
|
-
* @returns true if entity passes all filters
|
|
136
|
-
*/
|
|
137
|
-
export function entityPassesFilters(entity, filters) {
|
|
138
|
-
// Importance filter
|
|
139
|
-
if (!isWithinImportanceRange(entity.importance, filters.minImportance, filters.maxImportance)) {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
// Entity type filter
|
|
143
|
-
if (filters.entityType && entity.entityType !== filters.entityType) {
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
// Created date filter
|
|
147
|
-
if (!isWithinDateRange(entity.createdAt, filters.createdAfter, filters.createdBefore)) {
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
// Modified date filter
|
|
151
|
-
if (!isWithinDateRange(entity.lastModified, filters.modifiedAfter, filters.modifiedBefore)) {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
return true;
|
|
155
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Levenshtein Distance Algorithm
|
|
3
|
-
*
|
|
4
|
-
* Calculates the minimum number of single-character edits (insertions,
|
|
5
|
-
* deletions, or substitutions) needed to change one string into another.
|
|
6
|
-
*
|
|
7
|
-
* Used for fuzzy string matching to find similar entities despite typos.
|
|
8
|
-
*
|
|
9
|
-
* @module utils/levenshtein
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Calculate Levenshtein distance between two strings.
|
|
13
|
-
*
|
|
14
|
-
* Returns the minimum number of single-character edits needed to change
|
|
15
|
-
* one word into another.
|
|
16
|
-
*
|
|
17
|
-
* **Algorithm**: Dynamic programming with O(m*n) time and space complexity,
|
|
18
|
-
* where m and n are the lengths of the two strings.
|
|
19
|
-
*
|
|
20
|
-
* @param str1 - First string to compare
|
|
21
|
-
* @param str2 - Second string to compare
|
|
22
|
-
* @returns Minimum number of edits required (0 = identical strings)
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```typescript
|
|
26
|
-
* levenshteinDistance("kitten", "sitting"); // Returns 3
|
|
27
|
-
* levenshteinDistance("hello", "hello"); // Returns 0
|
|
28
|
-
* levenshteinDistance("abc", ""); // Returns 3
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export function levenshteinDistance(str1, str2) {
|
|
32
|
-
const m = str1.length;
|
|
33
|
-
const n = str2.length;
|
|
34
|
-
// Create 2D array for dynamic programming
|
|
35
|
-
const dp = Array(m + 1)
|
|
36
|
-
.fill(null)
|
|
37
|
-
.map(() => Array(n + 1).fill(0));
|
|
38
|
-
// Initialize base cases: distance from empty string
|
|
39
|
-
for (let i = 0; i <= m; i++) {
|
|
40
|
-
dp[i][0] = i;
|
|
41
|
-
}
|
|
42
|
-
for (let j = 0; j <= n; j++) {
|
|
43
|
-
dp[0][j] = j;
|
|
44
|
-
}
|
|
45
|
-
// Fill dp table
|
|
46
|
-
for (let i = 1; i <= m; i++) {
|
|
47
|
-
for (let j = 1; j <= n; j++) {
|
|
48
|
-
if (str1[i - 1] === str2[j - 1]) {
|
|
49
|
-
// Characters match, no edit needed
|
|
50
|
-
dp[i][j] = dp[i - 1][j - 1];
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
// Take minimum of three operations
|
|
54
|
-
dp[i][j] = Math.min(dp[i - 1][j] + 1, // deletion
|
|
55
|
-
dp[i][j - 1] + 1, // insertion
|
|
56
|
-
dp[i - 1][j - 1] + 1 // substitution
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return dp[m][n];
|
|
62
|
-
}
|