mcp-adr-analysis-server 2.0.21 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/README.md +94 -839
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/src/config/ai-config.d.ts.map +1 -1
  4. package/dist/src/config/ai-config.js +9 -9
  5. package/dist/src/config/ai-config.js.map +1 -1
  6. package/dist/src/index.d.ts +15 -0
  7. package/dist/src/index.d.ts.map +1 -1
  8. package/dist/src/index.js +1594 -837
  9. package/dist/src/index.js.map +1 -1
  10. package/dist/src/prompts/analysis-prompts.d.ts +4 -1
  11. package/dist/src/prompts/analysis-prompts.d.ts.map +1 -1
  12. package/dist/src/prompts/analysis-prompts.js +61 -30
  13. package/dist/src/prompts/analysis-prompts.js.map +1 -1
  14. package/dist/src/prompts/index.d.ts +17 -1
  15. package/dist/src/prompts/index.d.ts.map +1 -1
  16. package/dist/src/prompts/index.js +325 -1
  17. package/dist/src/prompts/index.js.map +1 -1
  18. package/dist/src/prompts/rule-generation-prompts.d.ts +5 -1
  19. package/dist/src/prompts/rule-generation-prompts.d.ts.map +1 -1
  20. package/dist/src/prompts/rule-generation-prompts.js +5 -1
  21. package/dist/src/prompts/rule-generation-prompts.js.map +1 -1
  22. package/dist/src/prompts/security-prompts.d.ts +6 -1
  23. package/dist/src/prompts/security-prompts.d.ts.map +1 -1
  24. package/dist/src/prompts/security-prompts.js +6 -1
  25. package/dist/src/prompts/security-prompts.js.map +1 -1
  26. package/dist/src/prompts/todo-prompts.d.ts +49 -0
  27. package/dist/src/prompts/todo-prompts.d.ts.map +1 -0
  28. package/dist/src/prompts/todo-prompts.js +824 -0
  29. package/dist/src/prompts/todo-prompts.js.map +1 -0
  30. package/dist/src/resources/index.d.ts.map +1 -1
  31. package/dist/src/resources/index.js +9 -7
  32. package/dist/src/resources/index.js.map +1 -1
  33. package/dist/src/tools/adr-bootstrap-validation-tool.d.ts +47 -0
  34. package/dist/src/tools/adr-bootstrap-validation-tool.d.ts.map +1 -0
  35. package/dist/src/tools/adr-bootstrap-validation-tool.js +979 -0
  36. package/dist/src/tools/adr-bootstrap-validation-tool.js.map +1 -0
  37. package/dist/src/tools/adr-suggestion-tool.d.ts +1 -0
  38. package/dist/src/tools/adr-suggestion-tool.d.ts.map +1 -1
  39. package/dist/src/tools/adr-suggestion-tool.js +330 -32
  40. package/dist/src/tools/adr-suggestion-tool.js.map +1 -1
  41. package/dist/src/tools/content-masking-tool.d.ts +5 -0
  42. package/dist/src/tools/content-masking-tool.d.ts.map +1 -1
  43. package/dist/src/tools/content-masking-tool.js +631 -28
  44. package/dist/src/tools/content-masking-tool.js.map +1 -1
  45. package/dist/src/tools/deployment-readiness-tool.d.ts +8 -5
  46. package/dist/src/tools/deployment-readiness-tool.d.ts.map +1 -1
  47. package/dist/src/tools/deployment-readiness-tool.js +1017 -93
  48. package/dist/src/tools/deployment-readiness-tool.js.map +1 -1
  49. package/dist/src/tools/environment-analysis-tool.d.ts +4 -0
  50. package/dist/src/tools/environment-analysis-tool.d.ts.map +1 -1
  51. package/dist/src/tools/environment-analysis-tool.js +568 -24
  52. package/dist/src/tools/environment-analysis-tool.js.map +1 -1
  53. package/dist/src/tools/interactive-adr-planning-tool.d.ts.map +1 -1
  54. package/dist/src/tools/interactive-adr-planning-tool.js +270 -108
  55. package/dist/src/tools/interactive-adr-planning-tool.js.map +1 -1
  56. package/dist/src/tools/mcp-planning-tool.d.ts.map +1 -1
  57. package/dist/src/tools/mcp-planning-tool.js +316 -183
  58. package/dist/src/tools/mcp-planning-tool.js.map +1 -1
  59. package/dist/src/tools/memory-loading-tool.d.ts +60 -0
  60. package/dist/src/tools/memory-loading-tool.d.ts.map +1 -0
  61. package/dist/src/tools/memory-loading-tool.js +457 -0
  62. package/dist/src/tools/memory-loading-tool.js.map +1 -0
  63. package/dist/src/tools/research-integration-tool.d.ts +4 -1
  64. package/dist/src/tools/research-integration-tool.d.ts.map +1 -1
  65. package/dist/src/tools/research-integration-tool.js +5 -1
  66. package/dist/src/tools/research-integration-tool.js.map +1 -1
  67. package/dist/src/tools/review-existing-adrs-tool.d.ts +19 -0
  68. package/dist/src/tools/review-existing-adrs-tool.d.ts.map +1 -0
  69. package/dist/src/tools/review-existing-adrs-tool.js +1204 -0
  70. package/dist/src/tools/review-existing-adrs-tool.js.map +1 -0
  71. package/dist/src/tools/rule-generation-tool.d.ts +2 -0
  72. package/dist/src/tools/rule-generation-tool.d.ts.map +1 -1
  73. package/dist/src/tools/rule-generation-tool.js +274 -33
  74. package/dist/src/tools/rule-generation-tool.js.map +1 -1
  75. package/dist/src/tools/smart-git-push-tool-v2.d.ts +4 -0
  76. package/dist/src/tools/smart-git-push-tool-v2.d.ts.map +1 -1
  77. package/dist/src/tools/smart-git-push-tool-v2.js +423 -229
  78. package/dist/src/tools/smart-git-push-tool-v2.js.map +1 -1
  79. package/dist/src/tools/smart-git-push-tool.d.ts +3 -0
  80. package/dist/src/tools/smart-git-push-tool.d.ts.map +1 -1
  81. package/dist/src/tools/smart-git-push-tool.js +241 -235
  82. package/dist/src/tools/smart-git-push-tool.js.map +1 -1
  83. package/dist/src/tools/tool-chain-orchestrator.d.ts +2 -2
  84. package/dist/src/tools/tool-chain-orchestrator.d.ts.map +1 -1
  85. package/dist/src/tools/tool-chain-orchestrator.js +152 -93
  86. package/dist/src/tools/tool-chain-orchestrator.js.map +1 -1
  87. package/dist/src/tools/troubleshoot-guided-workflow-tool.d.ts +22 -13
  88. package/dist/src/tools/troubleshoot-guided-workflow-tool.d.ts.map +1 -1
  89. package/dist/src/tools/troubleshoot-guided-workflow-tool.js +660 -28
  90. package/dist/src/tools/troubleshoot-guided-workflow-tool.js.map +1 -1
  91. package/dist/src/types/ape-framework.d.ts +93 -0
  92. package/dist/src/types/ape-framework.d.ts.map +1 -1
  93. package/dist/src/types/ape-framework.js +10 -10
  94. package/dist/src/types/ape-framework.js.map +1 -1
  95. package/dist/src/types/enhanced-errors.d.ts +173 -0
  96. package/dist/src/types/enhanced-errors.d.ts.map +1 -0
  97. package/dist/src/types/enhanced-errors.js +668 -0
  98. package/dist/src/types/enhanced-errors.js.map +1 -0
  99. package/dist/src/types/index.d.ts +129 -3
  100. package/dist/src/types/index.d.ts.map +1 -1
  101. package/dist/src/types/index.js +15 -0
  102. package/dist/src/types/index.js.map +1 -1
  103. package/dist/src/types/knowledge-generation.d.ts +78 -0
  104. package/dist/src/types/knowledge-generation.d.ts.map +1 -1
  105. package/dist/src/types/knowledge-generation.js +10 -6
  106. package/dist/src/types/knowledge-generation.js.map +1 -1
  107. package/dist/src/types/knowledge-graph-schemas.d.ts +92 -0
  108. package/dist/src/types/knowledge-graph-schemas.d.ts.map +1 -1
  109. package/dist/src/types/knowledge-graph-schemas.js +45 -17
  110. package/dist/src/types/knowledge-graph-schemas.js.map +1 -1
  111. package/dist/src/types/memory-entities.d.ts +7209 -0
  112. package/dist/src/types/memory-entities.d.ts.map +1 -0
  113. package/dist/src/types/memory-entities.js +395 -0
  114. package/dist/src/types/memory-entities.js.map +1 -0
  115. package/dist/src/types/reflexion-framework.d.ts +44 -0
  116. package/dist/src/types/reflexion-framework.d.ts.map +1 -1
  117. package/dist/src/types/reflexion-framework.js +7 -7
  118. package/dist/src/types/reflexion-framework.js.map +1 -1
  119. package/dist/src/types/todo-json-schemas.d.ts +7 -653
  120. package/dist/src/types/todo-json-schemas.d.ts.map +1 -1
  121. package/dist/src/types/todo-json-schemas.js +6 -110
  122. package/dist/src/types/todo-json-schemas.js.map +1 -1
  123. package/dist/src/types/tool-arguments.d.ts +224 -0
  124. package/dist/src/types/tool-arguments.d.ts.map +1 -0
  125. package/dist/src/types/tool-arguments.js +6 -0
  126. package/dist/src/types/tool-arguments.js.map +1 -0
  127. package/dist/src/utils/actual-file-operations.d.ts.map +1 -1
  128. package/dist/src/utils/actual-file-operations.js +25 -9
  129. package/dist/src/utils/actual-file-operations.js.map +1 -1
  130. package/dist/src/utils/adr-discovery.d.ts +33 -1
  131. package/dist/src/utils/adr-discovery.d.ts.map +1 -1
  132. package/dist/src/utils/adr-discovery.js +14 -9
  133. package/dist/src/utils/adr-discovery.js.map +1 -1
  134. package/dist/src/utils/adr-suggestions.d.ts +72 -0
  135. package/dist/src/utils/adr-suggestions.d.ts.map +1 -1
  136. package/dist/src/utils/adr-suggestions.js +6 -0
  137. package/dist/src/utils/adr-suggestions.js.map +1 -1
  138. package/dist/src/utils/cache.d.ts.map +1 -1
  139. package/dist/src/utils/cache.js +22 -19
  140. package/dist/src/utils/cache.js.map +1 -1
  141. package/dist/src/utils/chain-of-thought-template.d.ts +13 -1
  142. package/dist/src/utils/chain-of-thought-template.d.ts.map +1 -1
  143. package/dist/src/utils/chain-of-thought-template.js +31 -22
  144. package/dist/src/utils/chain-of-thought-template.js.map +1 -1
  145. package/dist/src/utils/config.d.ts.map +1 -1
  146. package/dist/src/utils/config.js +1 -0
  147. package/dist/src/utils/config.js.map +1 -1
  148. package/dist/src/utils/directory-compat.js +1 -1
  149. package/dist/src/utils/directory-compat.js.map +1 -1
  150. package/dist/src/utils/enhanced-logging.d.ts +195 -0
  151. package/dist/src/utils/enhanced-logging.d.ts.map +1 -0
  152. package/dist/src/utils/enhanced-logging.js +449 -0
  153. package/dist/src/utils/enhanced-logging.js.map +1 -0
  154. package/dist/src/utils/file-system.d.ts +182 -34
  155. package/dist/src/utils/file-system.d.ts.map +1 -1
  156. package/dist/src/utils/file-system.js +648 -774
  157. package/dist/src/utils/file-system.js.map +1 -1
  158. package/dist/src/utils/gitleaks-detector.d.ts +50 -0
  159. package/dist/src/utils/gitleaks-detector.d.ts.map +1 -0
  160. package/dist/src/utils/gitleaks-detector.js +334 -0
  161. package/dist/src/utils/gitleaks-detector.js.map +1 -0
  162. package/dist/src/utils/interactive-approval.d.ts +1 -1
  163. package/dist/src/utils/interactive-approval.d.ts.map +1 -1
  164. package/dist/src/utils/interactive-approval.js +22 -17
  165. package/dist/src/utils/interactive-approval.js.map +1 -1
  166. package/dist/src/utils/json-safe.d.ts.map +1 -1
  167. package/dist/src/utils/json-safe.js +9 -6
  168. package/dist/src/utils/json-safe.js.map +1 -1
  169. package/dist/src/utils/knowledge-graph-manager.d.ts +37 -1
  170. package/dist/src/utils/knowledge-graph-manager.d.ts.map +1 -1
  171. package/dist/src/utils/knowledge-graph-manager.js +315 -70
  172. package/dist/src/utils/knowledge-graph-manager.js.map +1 -1
  173. package/dist/src/utils/location-filter.d.ts +35 -10
  174. package/dist/src/utils/location-filter.d.ts.map +1 -1
  175. package/dist/src/utils/location-filter.js +360 -94
  176. package/dist/src/utils/location-filter.js.map +1 -1
  177. package/dist/src/utils/mcp-response-validator.d.ts.map +1 -1
  178. package/dist/src/utils/mcp-response-validator.js +34 -19
  179. package/dist/src/utils/mcp-response-validator.js.map +1 -1
  180. package/dist/src/utils/memory-entity-manager.d.ts +134 -0
  181. package/dist/src/utils/memory-entity-manager.d.ts.map +1 -0
  182. package/dist/src/utils/memory-entity-manager.js +851 -0
  183. package/dist/src/utils/memory-entity-manager.js.map +1 -0
  184. package/dist/src/utils/memory-health-scoring.d.ts +125 -0
  185. package/dist/src/utils/memory-health-scoring.d.ts.map +1 -0
  186. package/dist/src/utils/memory-health-scoring.js +277 -0
  187. package/dist/src/utils/memory-health-scoring.js.map +1 -0
  188. package/dist/src/utils/memory-migration-manager.d.ts +93 -0
  189. package/dist/src/utils/memory-migration-manager.d.ts.map +1 -0
  190. package/dist/src/utils/memory-migration-manager.js +842 -0
  191. package/dist/src/utils/memory-migration-manager.js.map +1 -0
  192. package/dist/src/utils/memory-relationship-mapper.d.ts +87 -0
  193. package/dist/src/utils/memory-relationship-mapper.d.ts.map +1 -0
  194. package/dist/src/utils/memory-relationship-mapper.js +482 -0
  195. package/dist/src/utils/memory-relationship-mapper.js.map +1 -0
  196. package/dist/src/utils/memory-rollback-manager.d.ts +105 -0
  197. package/dist/src/utils/memory-rollback-manager.d.ts.map +1 -0
  198. package/dist/src/utils/memory-rollback-manager.js +575 -0
  199. package/dist/src/utils/memory-rollback-manager.js.map +1 -0
  200. package/dist/src/utils/memory-transformation.d.ts +59 -0
  201. package/dist/src/utils/memory-transformation.d.ts.map +1 -0
  202. package/dist/src/utils/memory-transformation.js +742 -0
  203. package/dist/src/utils/memory-transformation.js.map +1 -0
  204. package/dist/src/utils/output-masking.d.ts +12 -0
  205. package/dist/src/utils/output-masking.d.ts.map +1 -1
  206. package/dist/src/utils/output-masking.js +5 -0
  207. package/dist/src/utils/output-masking.js.map +1 -1
  208. package/dist/src/utils/prompt-execution.d.ts.map +1 -1
  209. package/dist/src/utils/prompt-execution.js +72 -51
  210. package/dist/src/utils/prompt-execution.js.map +1 -1
  211. package/dist/src/utils/release-readiness-detector.d.ts.map +1 -1
  212. package/dist/src/utils/release-readiness-detector.js +43 -42
  213. package/dist/src/utils/release-readiness-detector.js.map +1 -1
  214. package/dist/src/utils/research-integration.d.ts.map +1 -1
  215. package/dist/src/utils/research-integration.js +73 -44
  216. package/dist/src/utils/research-integration.js.map +1 -1
  217. package/dist/src/utils/research-questions.d.ts.map +1 -1
  218. package/dist/src/utils/research-questions.js +40 -14
  219. package/dist/src/utils/research-questions.js.map +1 -1
  220. package/dist/src/utils/ripgrep-wrapper.d.ts +84 -0
  221. package/dist/src/utils/ripgrep-wrapper.d.ts.map +1 -0
  222. package/dist/src/utils/ripgrep-wrapper.js +255 -0
  223. package/dist/src/utils/ripgrep-wrapper.js.map +1 -0
  224. package/dist/src/utils/rule-generation.d.ts.map +1 -1
  225. package/dist/src/utils/rule-generation.js +26 -15
  226. package/dist/src/utils/rule-generation.js.map +1 -1
  227. package/dist/src/utils/todo-file-watcher.d.ts +11 -23
  228. package/dist/src/utils/todo-file-watcher.d.ts.map +1 -1
  229. package/dist/src/utils/todo-file-watcher.js +18 -156
  230. package/dist/src/utils/todo-file-watcher.js.map +1 -1
  231. package/dist/src/utils/tree-sitter-analyzer.d.ts +185 -0
  232. package/dist/src/utils/tree-sitter-analyzer.d.ts.map +1 -0
  233. package/dist/src/utils/tree-sitter-analyzer.js +885 -0
  234. package/dist/src/utils/tree-sitter-analyzer.js.map +1 -0
  235. package/package.json +51 -10
  236. package/dist/src/tools/smart-score-tool.d.ts +0 -173
  237. package/dist/src/tools/smart-score-tool.d.ts.map +0 -1
  238. package/dist/src/tools/smart-score-tool.js +0 -681
  239. package/dist/src/tools/smart-score-tool.js.map +0 -1
  240. package/dist/src/tools/todo-management-tool-v2.d.ts +0 -368
  241. package/dist/src/tools/todo-management-tool-v2.d.ts.map +0 -1
  242. package/dist/src/tools/todo-management-tool-v2.js +0 -922
  243. package/dist/src/tools/todo-management-tool-v2.js.map +0 -1
  244. package/dist/src/utils/enhanced-sensitive-detector.d.ts +0 -61
  245. package/dist/src/utils/enhanced-sensitive-detector.d.ts.map +0 -1
  246. package/dist/src/utils/enhanced-sensitive-detector.js +0 -437
  247. package/dist/src/utils/enhanced-sensitive-detector.js.map +0 -1
  248. package/dist/src/utils/project-health-scoring.d.ts +0 -177
  249. package/dist/src/utils/project-health-scoring.d.ts.map +0 -1
  250. package/dist/src/utils/project-health-scoring.js +0 -370
  251. package/dist/src/utils/project-health-scoring.js.map +0 -1
  252. package/dist/src/utils/todo-json-manager.d.ts +0 -71
  253. package/dist/src/utils/todo-json-manager.d.ts.map +0 -1
  254. package/dist/src/utils/todo-json-manager.js +0 -396
  255. package/dist/src/utils/todo-json-manager.js.map +0 -1
  256. package/dist/src/utils/todo-markdown-converter.d.ts +0 -16
  257. package/dist/src/utils/todo-markdown-converter.d.ts.map +0 -1
  258. package/dist/src/utils/todo-markdown-converter.js +0 -362
  259. package/dist/src/utils/todo-markdown-converter.js.map +0 -1
  260. package/dist/src/utils/todo-migration.d.ts +0 -47
  261. package/dist/src/utils/todo-migration.d.ts.map +0 -1
  262. package/dist/src/utils/todo-migration.js +0 -261
  263. package/dist/src/utils/todo-migration.js.map +0 -1
@@ -0,0 +1,851 @@
1
+ /**
2
+ * Memory Entity Manager
3
+ *
4
+ * Core manager for the memory-centric architecture that handles storage, retrieval,
5
+ * relationship management, and intelligence operations for memory entities.
6
+ */
7
+ import * as fs from 'fs/promises';
8
+ import * as path from 'path';
9
+ import * as os from 'os';
10
+ import crypto from 'crypto';
11
+ import { MemoryEntitySchema, } from '../types/memory-entities.js';
12
+ import { McpAdrError } from '../types/index.js';
13
+ import { loadConfig } from './config.js';
14
+ import { EnhancedLogger } from './enhanced-logging.js';
15
+ export class MemoryEntityManager {
16
+ fsOverride;
17
+ memoryDir;
18
+ entitiesFile;
19
+ relationshipsFile;
20
+ intelligenceFile;
21
+ evolutionLogFile;
22
+ config;
23
+ logger;
24
+ isTestMode;
25
+ // In-memory caches for performance
26
+ entitiesCache = new Map();
27
+ relationshipsCache = new Map();
28
+ intelligence = null;
29
+ lastSnapshotTime = 0;
30
+ constructor(config, testMode = false, fsOverride) {
31
+ this.fsOverride = fsOverride;
32
+ this.isTestMode = testMode;
33
+ const projectConfig = loadConfig();
34
+ this.logger = new EnhancedLogger();
35
+ // Use OS temp directory for memory storage
36
+ const projectName = path.basename(projectConfig.projectPath);
37
+ this.memoryDir = path.join(os.tmpdir(), projectName, 'memory');
38
+ this.entitiesFile = path.join(this.memoryDir, 'entities.json');
39
+ this.relationshipsFile = path.join(this.memoryDir, 'relationships.json');
40
+ this.intelligenceFile = path.join(this.memoryDir, 'intelligence.json');
41
+ this.evolutionLogFile = path.join(this.memoryDir, 'evolution-log.json');
42
+ this.config = {
43
+ storageType: 'file',
44
+ snapshotFrequency: testMode ? 0 : 30, // No automatic persistence in test mode
45
+ compressionEnabled: true,
46
+ backupRetention: 30, // 30 days
47
+ syncEnabled: !testMode, // Disable sync in test mode
48
+ conflictResolution: 'merge',
49
+ ...config,
50
+ };
51
+ }
52
+ /**
53
+ * Initialize the memory system
54
+ */
55
+ async initialize() {
56
+ try {
57
+ await this.ensureMemoryDirectory();
58
+ await this.loadFromPersistence();
59
+ await this.initializeIntelligence();
60
+ this.logger.info('Memory Entity Manager initialized successfully', 'MemoryEntityManager', {
61
+ entityCount: this.entitiesCache.size,
62
+ relationshipCount: this.relationshipsCache.size,
63
+ });
64
+ }
65
+ catch (error) {
66
+ throw new McpAdrError(`Failed to initialize memory system: ${error instanceof Error ? error.message : String(error)}`, 'MEMORY_INIT_ERROR');
67
+ }
68
+ }
69
+ /**
70
+ * Create or update a memory entity
71
+ */
72
+ async upsertEntity(entity) {
73
+ try {
74
+ const now = new Date().toISOString();
75
+ const id = entity.id || crypto.randomUUID();
76
+ // Get existing entity if updating
77
+ const existing = entity.id ? this.entitiesCache.get(entity.id) : null;
78
+ // Create full entity with defaults
79
+ const fullEntity = {
80
+ id,
81
+ created: existing?.created || now,
82
+ lastModified: now,
83
+ version: (existing?.version || 0) + 1,
84
+ confidence: entity.confidence || 0.85,
85
+ relevance: entity.relevance || 0.7,
86
+ tags: entity.tags || [],
87
+ relationships: entity.relationships || existing?.relationships || [],
88
+ context: {
89
+ projectPhase: entity.context?.projectPhase,
90
+ businessDomain: entity.context?.businessDomain,
91
+ technicalStack: entity.context?.technicalStack || [],
92
+ environmentalFactors: entity.context?.environmentalFactors || [],
93
+ stakeholders: entity.context?.stakeholders || [],
94
+ },
95
+ accessPattern: {
96
+ lastAccessed: now,
97
+ accessCount: (existing?.accessPattern?.accessCount || 0) + 1,
98
+ accessContext: entity.accessPattern?.accessContext || [],
99
+ },
100
+ evolution: {
101
+ origin: entity.evolution?.origin || (existing ? existing.evolution.origin : 'created'),
102
+ transformations: [
103
+ ...(existing?.evolution?.transformations || []),
104
+ {
105
+ timestamp: now,
106
+ type: existing ? 'updated' : 'created',
107
+ description: existing
108
+ ? `Updated ${entity.type} entity`
109
+ : `Created ${entity.type} entity`,
110
+ agent: 'MemoryEntityManager',
111
+ },
112
+ ],
113
+ },
114
+ validation: {
115
+ isVerified: entity.validation?.isVerified || false,
116
+ verificationMethod: entity.validation?.verificationMethod,
117
+ verificationTimestamp: entity.validation?.verificationTimestamp,
118
+ conflictResolution: entity.validation?.conflictResolution,
119
+ },
120
+ ...entity,
121
+ };
122
+ // Validate the entity
123
+ try {
124
+ MemoryEntitySchema.parse(fullEntity);
125
+ }
126
+ catch (validationError) {
127
+ throw new McpAdrError(`Entity validation failed: ${validationError instanceof Error ? validationError.message : String(validationError)}`, 'ENTITY_VALIDATION_ERROR');
128
+ }
129
+ // Store in cache
130
+ this.entitiesCache.set(id, fullEntity);
131
+ // Log evolution event
132
+ await this.logEvolutionEvent({
133
+ id: crypto.randomUUID(),
134
+ entityId: id,
135
+ timestamp: now,
136
+ eventType: existing ? 'modified' : 'created',
137
+ agent: 'MemoryEntityManager',
138
+ changes: existing ? this.calculateChanges(existing, fullEntity) : {},
139
+ });
140
+ // Update intelligence
141
+ await this.updateIntelligence('entity_updated', {
142
+ entityId: id,
143
+ entityType: fullEntity.type,
144
+ });
145
+ // Persist if needed
146
+ await this.maybePersist();
147
+ this.logger.debug(`${existing ? 'Updated' : 'Created'} entity`, 'MemoryEntityManager', {
148
+ entityId: id,
149
+ type: fullEntity.type,
150
+ title: fullEntity.title.substring(0, 50),
151
+ });
152
+ return fullEntity;
153
+ }
154
+ catch (error) {
155
+ throw new McpAdrError(`Failed to upsert entity: ${error instanceof Error ? error.message : String(error)}`, 'ENTITY_UPSERT_ERROR');
156
+ }
157
+ }
158
+ /**
159
+ * Get an entity by ID
160
+ */
161
+ async getEntity(id) {
162
+ const entity = this.entitiesCache.get(id);
163
+ if (entity) {
164
+ // Update access pattern
165
+ entity.accessPattern.lastAccessed = new Date().toISOString();
166
+ entity.accessPattern.accessCount += 1;
167
+ await this.logEvolutionEvent({
168
+ id: crypto.randomUUID(),
169
+ entityId: id,
170
+ timestamp: new Date().toISOString(),
171
+ eventType: 'accessed',
172
+ agent: 'MemoryEntityManager',
173
+ });
174
+ }
175
+ return entity || null;
176
+ }
177
+ /**
178
+ * Delete an entity
179
+ */
180
+ async deleteEntity(id) {
181
+ const entity = this.entitiesCache.get(id);
182
+ if (!entity)
183
+ return false;
184
+ // Remove entity
185
+ this.entitiesCache.delete(id);
186
+ // Remove all relationships involving this entity
187
+ const relationshipsToRemove = Array.from(this.relationshipsCache.values()).filter(rel => rel.sourceId === id || rel.targetId === id);
188
+ relationshipsToRemove.forEach(rel => this.relationshipsCache.delete(rel.id));
189
+ // Log evolution event
190
+ await this.logEvolutionEvent({
191
+ id: crypto.randomUUID(),
192
+ entityId: id,
193
+ timestamp: new Date().toISOString(),
194
+ eventType: 'deprecated',
195
+ agent: 'MemoryEntityManager',
196
+ context: 'Entity deleted by user request',
197
+ });
198
+ await this.maybePersist();
199
+ return true;
200
+ }
201
+ /**
202
+ * Create or update a relationship between entities
203
+ */
204
+ async upsertRelationship(relationship) {
205
+ try {
206
+ const now = new Date().toISOString();
207
+ const id = relationship.id || crypto.randomUUID();
208
+ // Validate that both entities exist
209
+ const sourceEntity = this.entitiesCache.get(relationship.sourceId);
210
+ const targetEntity = this.entitiesCache.get(relationship.targetId);
211
+ if (!sourceEntity || !targetEntity) {
212
+ throw new McpAdrError('Source or target entity not found', 'RELATIONSHIP_INVALID_ENTITIES');
213
+ }
214
+ const fullRelationship = {
215
+ id,
216
+ sourceId: relationship.sourceId,
217
+ targetId: relationship.targetId,
218
+ type: relationship.type,
219
+ strength: relationship.strength || 0.7,
220
+ context: relationship.context || '',
221
+ evidence: relationship.evidence || [],
222
+ created: relationship.created || now,
223
+ lastValidated: relationship.lastValidated || now,
224
+ confidence: relationship.confidence || 0.85,
225
+ };
226
+ // Store in cache
227
+ this.relationshipsCache.set(id, fullRelationship);
228
+ // Update entity relationships for both source and target
229
+ this.updateEntityRelationships(sourceEntity, fullRelationship);
230
+ this.updateEntityRelationships(targetEntity, fullRelationship);
231
+ // Log evolution events for both entities
232
+ await Promise.all([
233
+ this.logEvolutionEvent({
234
+ id: crypto.randomUUID(),
235
+ entityId: relationship.sourceId,
236
+ timestamp: now,
237
+ eventType: 'related',
238
+ agent: 'MemoryEntityManager',
239
+ context: `Relationship ${relationship.type} to ${targetEntity.title}`,
240
+ }),
241
+ this.logEvolutionEvent({
242
+ id: crypto.randomUUID(),
243
+ entityId: relationship.targetId,
244
+ timestamp: now,
245
+ eventType: 'related',
246
+ agent: 'MemoryEntityManager',
247
+ context: `Relationship ${relationship.type} from ${sourceEntity.title}`,
248
+ }),
249
+ ]);
250
+ await this.maybePersist();
251
+ return fullRelationship;
252
+ }
253
+ catch (error) {
254
+ throw new McpAdrError(`Failed to create relationship: ${error instanceof Error ? error.message : String(error)}`, 'RELATIONSHIP_CREATE_ERROR');
255
+ }
256
+ }
257
+ /**
258
+ * Query entities with advanced filtering
259
+ */
260
+ async queryEntities(query) {
261
+ const startTime = Date.now();
262
+ try {
263
+ let entities = Array.from(this.entitiesCache.values());
264
+ const relationships = Array.from(this.relationshipsCache.values());
265
+ // Apply filters
266
+ if (query.entityTypes?.length) {
267
+ entities = entities.filter(e => query.entityTypes.includes(e.type));
268
+ }
269
+ if (query.tags?.length) {
270
+ entities = entities.filter(e => query.tags.some(tag => e.tags.includes(tag)));
271
+ }
272
+ if (query.textQuery) {
273
+ const searchTerm = query.textQuery.toLowerCase();
274
+ entities = entities.filter(e => e.title.toLowerCase().includes(searchTerm) ||
275
+ e.description.toLowerCase().includes(searchTerm) ||
276
+ e.tags.some(tag => tag.toLowerCase().includes(searchTerm)));
277
+ }
278
+ if (query.confidenceThreshold !== undefined) {
279
+ entities = entities.filter(e => e.confidence >= query.confidenceThreshold);
280
+ }
281
+ if (query.relevanceThreshold !== undefined) {
282
+ entities = entities.filter(e => e.relevance >= query.relevanceThreshold);
283
+ }
284
+ if (query.timeRange) {
285
+ const fromTime = new Date(query.timeRange.from).getTime();
286
+ const toTime = new Date(query.timeRange.to).getTime();
287
+ entities = entities.filter(e => {
288
+ const entityTime = new Date(e.lastModified).getTime();
289
+ return entityTime >= fromTime && entityTime <= toTime;
290
+ });
291
+ }
292
+ // Apply context filters
293
+ if (query.contextFilters) {
294
+ if (query.contextFilters.projectPhase) {
295
+ entities = entities.filter(e => e.context.projectPhase === query.contextFilters.projectPhase);
296
+ }
297
+ if (query.contextFilters.businessDomain) {
298
+ entities = entities.filter(e => e.context.businessDomain === query.contextFilters.businessDomain);
299
+ }
300
+ if (query.contextFilters.technicalStack?.length) {
301
+ entities = entities.filter(e => query.contextFilters.technicalStack.some(tech => e.context.technicalStack.includes(tech)));
302
+ }
303
+ }
304
+ // Sort entities
305
+ const sortBy = query.sortBy || 'relevance';
306
+ entities.sort((a, b) => {
307
+ switch (sortBy) {
308
+ case 'confidence':
309
+ return b.confidence - a.confidence;
310
+ case 'lastModified':
311
+ return new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime();
312
+ case 'created':
313
+ return new Date(b.created).getTime() - new Date(a.created).getTime();
314
+ case 'accessCount':
315
+ return b.accessPattern.accessCount - a.accessPattern.accessCount;
316
+ case 'relevance':
317
+ default:
318
+ return b.relevance - a.relevance;
319
+ }
320
+ });
321
+ const totalCount = entities.length;
322
+ // Generate aggregations on ALL matching entities before applying limit
323
+ const aggregations = {
324
+ byType: {},
325
+ byTag: {},
326
+ byConfidence: {},
327
+ };
328
+ entities.forEach(entity => {
329
+ // By type
330
+ aggregations.byType[entity.type] = (aggregations.byType[entity.type] || 0) + 1;
331
+ // By tags
332
+ entity.tags.forEach(tag => {
333
+ aggregations.byTag[tag] = (aggregations.byTag[tag] || 0) + 1;
334
+ });
335
+ // By confidence range
336
+ const confidenceRange = Math.floor(entity.confidence * 10) / 10;
337
+ aggregations.byConfidence[`${confidenceRange}-${confidenceRange + 0.1}`] =
338
+ (aggregations.byConfidence[`${confidenceRange}-${confidenceRange + 0.1}`] || 0) + 1;
339
+ });
340
+ // Apply limit AFTER generating aggregations
341
+ if (query.limit && query.limit > 0) {
342
+ entities = entities.slice(0, query.limit);
343
+ }
344
+ // Include related entities if requested
345
+ let resultRelationships = relationships;
346
+ if (query.includeRelated) {
347
+ const entityIds = new Set(entities.map(e => e.id));
348
+ resultRelationships = relationships.filter(r => entityIds.has(r.sourceId) || entityIds.has(r.targetId));
349
+ }
350
+ const queryTime = Date.now() - startTime;
351
+ this.logger.debug('Entity query executed', 'MemoryEntityManager', {
352
+ queryTime,
353
+ totalCount,
354
+ returnedCount: entities.length,
355
+ filters: Object.keys(query).filter(key => query[key] !== undefined),
356
+ });
357
+ return {
358
+ entities,
359
+ relationships: resultRelationships,
360
+ totalCount,
361
+ queryTime,
362
+ aggregations,
363
+ };
364
+ }
365
+ catch (error) {
366
+ throw new McpAdrError(`Failed to query entities: ${error instanceof Error ? error.message : String(error)}`, 'QUERY_ERROR');
367
+ }
368
+ }
369
+ /**
370
+ * Find related entities through relationships
371
+ */
372
+ async findRelatedEntities(entityId, maxDepth = 2, relationshipTypes) {
373
+ const visited = new Set();
374
+ const paths = [];
375
+ const relatedEntities = new Map();
376
+ const traverse = (currentId, currentPath, currentRelationships, depth) => {
377
+ if (depth > maxDepth || visited.has(currentId))
378
+ return;
379
+ visited.add(currentId);
380
+ const currentEntity = this.entitiesCache.get(currentId);
381
+ if (!currentEntity)
382
+ return;
383
+ if (depth > 0) {
384
+ relatedEntities.set(currentId, currentEntity);
385
+ paths.push({
386
+ path: [...currentPath, currentId],
387
+ relationships: [...currentRelationships],
388
+ depth,
389
+ });
390
+ }
391
+ // Find both outgoing and incoming relationships
392
+ const allRels = Array.from(this.relationshipsCache.values()).filter(rel => {
393
+ const isOutgoing = rel.sourceId === currentId;
394
+ const isIncoming = rel.targetId === currentId;
395
+ if (!isOutgoing && !isIncoming)
396
+ return false;
397
+ if (relationshipTypes?.length && !relationshipTypes.includes(rel.type))
398
+ return false;
399
+ return true;
400
+ });
401
+ for (const rel of allRels) {
402
+ const targetId = rel.sourceId === currentId ? rel.targetId : rel.sourceId;
403
+ if (!visited.has(targetId)) {
404
+ traverse(targetId, [...currentPath, currentId], [...currentRelationships, rel], depth + 1);
405
+ }
406
+ }
407
+ };
408
+ traverse(entityId, [], [], 0);
409
+ return {
410
+ entities: Array.from(relatedEntities.values()),
411
+ relationshipPaths: paths,
412
+ };
413
+ }
414
+ /**
415
+ * Get memory intelligence data
416
+ */
417
+ async getIntelligence() {
418
+ if (!this.intelligence) {
419
+ await this.initializeIntelligence();
420
+ }
421
+ return this.intelligence;
422
+ }
423
+ /**
424
+ * Create a memory snapshot
425
+ */
426
+ async createSnapshot() {
427
+ const now = new Date().toISOString();
428
+ const intelligence = await this.getIntelligence();
429
+ const entities = Array.from(this.entitiesCache.values());
430
+ const relationships = Array.from(this.relationshipsCache.values());
431
+ const totalConfidence = entities.reduce((sum, e) => sum + e.confidence, 0);
432
+ const averageConfidence = entities.length > 0 ? totalConfidence / entities.length : 0;
433
+ return {
434
+ id: crypto.randomUUID(),
435
+ timestamp: now,
436
+ version: '1.0.0',
437
+ entities,
438
+ relationships,
439
+ intelligence,
440
+ metadata: {
441
+ totalEntities: entities.length,
442
+ totalRelationships: relationships.length,
443
+ averageConfidence,
444
+ lastOptimization: now,
445
+ },
446
+ };
447
+ }
448
+ // Private helper methods
449
+ async ensureMemoryDirectory() {
450
+ try {
451
+ const fsInstance = this.fsOverride || fs;
452
+ await fsInstance.access(this.memoryDir);
453
+ }
454
+ catch {
455
+ // Directory doesn't exist, create it
456
+ const fsInstance = this.fsOverride || fs;
457
+ await fsInstance.mkdir(this.memoryDir, { recursive: true });
458
+ }
459
+ }
460
+ async loadFromPersistence() {
461
+ // Skip loading from persistence in test mode to avoid conflicts
462
+ if (this.isTestMode) {
463
+ return;
464
+ }
465
+ try {
466
+ // Load entities
467
+ try {
468
+ const fsInstance = this.fsOverride || fs;
469
+ const entitiesData = await fsInstance.readFile(this.entitiesFile, 'utf-8');
470
+ const entities = JSON.parse(entitiesData);
471
+ entities.forEach(entity => {
472
+ this.entitiesCache.set(entity.id, entity);
473
+ });
474
+ }
475
+ catch {
476
+ // No entities file exists yet
477
+ }
478
+ // Load relationships
479
+ try {
480
+ const fsInstance = this.fsOverride || fs;
481
+ const relationshipsData = await fsInstance.readFile(this.relationshipsFile, 'utf-8');
482
+ const relationships = JSON.parse(relationshipsData);
483
+ relationships.forEach(relationship => {
484
+ this.relationshipsCache.set(relationship.id, relationship);
485
+ });
486
+ }
487
+ catch {
488
+ // No relationships file exists yet
489
+ }
490
+ // Load intelligence
491
+ try {
492
+ const fsInstance = this.fsOverride || fs;
493
+ const intelligenceData = await fsInstance.readFile(this.intelligenceFile, 'utf-8');
494
+ this.intelligence = JSON.parse(intelligenceData);
495
+ }
496
+ catch {
497
+ // Will initialize default intelligence
498
+ }
499
+ }
500
+ catch (error) {
501
+ this.logger.warn('Failed to load some memory data from persistence', 'MemoryEntityManager', {
502
+ error,
503
+ });
504
+ }
505
+ }
506
+ async maybePersist() {
507
+ // In test mode, persist when there are enough changes for testing purposes
508
+ if (this.isTestMode) {
509
+ // Check if we have enough entities to test persistence (2+ entities)
510
+ const now = Date.now();
511
+ const timeSinceLastSnapshot = now - this.lastSnapshotTime;
512
+ // In test mode, persist after 30 minutes of simulated time OR when we have 2+ entities
513
+ if (this.entitiesCache.size >= 2 && timeSinceLastSnapshot >= 30 * 60 * 1000) {
514
+ await this.persistToStorage();
515
+ this.lastSnapshotTime = now;
516
+ }
517
+ return;
518
+ }
519
+ // Skip auto-persistence if disabled
520
+ if (this.config.snapshotFrequency === 0) {
521
+ return;
522
+ }
523
+ const now = Date.now();
524
+ const timeSinceLastSnapshot = now - this.lastSnapshotTime;
525
+ const snapshotIntervalMs = this.config.snapshotFrequency * 60 * 1000;
526
+ if (timeSinceLastSnapshot >= snapshotIntervalMs) {
527
+ await this.persistToStorage();
528
+ this.lastSnapshotTime = now;
529
+ }
530
+ }
531
+ async persistToStorage() {
532
+ try {
533
+ const fsInstance = this.fsOverride || fs;
534
+ await this.ensureMemoryDirectory();
535
+ // Save entities
536
+ const entities = Array.from(this.entitiesCache.values());
537
+ await fsInstance.writeFile(this.entitiesFile, JSON.stringify(entities, null, 2));
538
+ // Save relationships
539
+ const relationships = Array.from(this.relationshipsCache.values());
540
+ await fsInstance.writeFile(this.relationshipsFile, JSON.stringify(relationships, null, 2));
541
+ // Save intelligence
542
+ if (this.intelligence) {
543
+ await fsInstance.writeFile(this.intelligenceFile, JSON.stringify(this.intelligence, null, 2));
544
+ }
545
+ this.logger.debug('Memory data persisted to storage', 'MemoryEntityManager', {
546
+ entityCount: entities.length,
547
+ relationshipCount: relationships.length,
548
+ });
549
+ }
550
+ catch (error) {
551
+ this.logger.error('Failed to persist memory data', 'MemoryEntityManager', error instanceof Error ? error : undefined, { error });
552
+ }
553
+ }
554
+ async initializeIntelligence() {
555
+ if (!this.intelligence) {
556
+ this.intelligence = {
557
+ contextAwareness: {
558
+ currentContext: {},
559
+ contextHistory: [],
560
+ },
561
+ patternRecognition: {
562
+ discoveredPatterns: [],
563
+ patternConfidence: {},
564
+ emergentBehaviors: [],
565
+ },
566
+ relationshipInference: {
567
+ suggestedRelationships: [],
568
+ weakConnections: [],
569
+ conflictDetection: [],
570
+ },
571
+ adaptiveRecommendations: {
572
+ nextActions: [],
573
+ knowledgeGaps: [],
574
+ optimizationOpportunities: [],
575
+ },
576
+ };
577
+ // Initialize with some default knowledge gaps and recommendations
578
+ await this.updateRecommendations();
579
+ }
580
+ }
581
+ async updateIntelligence(eventType, context) {
582
+ if (!this.intelligence)
583
+ await this.initializeIntelligence();
584
+ // Update context awareness
585
+ this.intelligence.contextAwareness.currentContext = {
586
+ ...this.intelligence.contextAwareness.currentContext,
587
+ lastEvent: eventType,
588
+ lastEventTime: new Date().toISOString(),
589
+ ...context,
590
+ };
591
+ // Basic pattern recognition - could be enhanced with ML
592
+ if (eventType === 'entity_updated') {
593
+ const pattern = `${context.entityType}_update`;
594
+ this.intelligence.patternRecognition.patternConfidence[pattern] =
595
+ (this.intelligence.patternRecognition.patternConfidence[pattern] || 0) + 1;
596
+ }
597
+ // Update recommendations based on current state
598
+ await this.updateRecommendations();
599
+ }
600
+ async updateRecommendations() {
601
+ if (!this.intelligence)
602
+ return;
603
+ const entities = Array.from(this.entitiesCache.values());
604
+ const relationships = Array.from(this.relationshipsCache.values());
605
+ // Identify knowledge gaps (entities with low confidence OR system lacking entities)
606
+ const knowledgeGaps = [];
607
+ if (entities.length === 0) {
608
+ knowledgeGaps.push('No architectural decisions documented in memory system');
609
+ }
610
+ else {
611
+ // Add gaps for low confidence entities
612
+ const lowConfidenceGaps = entities
613
+ .filter(e => e.confidence < 0.5)
614
+ .map(e => `Low confidence in ${e.type}: ${e.title}`)
615
+ .slice(0, 3);
616
+ knowledgeGaps.push(...lowConfidenceGaps);
617
+ // Add gaps for missing entity types
618
+ if (entities.length === 1) {
619
+ knowledgeGaps.push('Limited diversity in architectural entities - consider documenting more types');
620
+ }
621
+ // Add gaps for entities without tags
622
+ const untaggedEntities = entities.filter(e => !e.tags || e.tags.length === 0);
623
+ if (untaggedEntities.length > 0) {
624
+ knowledgeGaps.push(`${untaggedEntities.length} entities lack proper categorization tags`);
625
+ }
626
+ }
627
+ // Suggest relationships for entities without many connections
628
+ const suggestedRelationships = [];
629
+ for (const entity of entities) {
630
+ const entityRelationships = relationships.filter(r => r.sourceId === entity.id || r.targetId === entity.id);
631
+ if (entityRelationships.length < 2) {
632
+ // Find potential relationships based on tags or type similarity
633
+ const similar = entities.filter(other => other.id !== entity.id &&
634
+ (other.type === entity.type || other.tags.some(tag => entity.tags.includes(tag))));
635
+ for (const similarEntity of similar.slice(0, 2)) {
636
+ suggestedRelationships.push({
637
+ sourceId: entity.id,
638
+ targetId: similarEntity.id,
639
+ type: 'relates_to',
640
+ confidence: 0.6,
641
+ reasoning: `Similar ${entity.type} entities with overlapping tags`,
642
+ });
643
+ }
644
+ }
645
+ }
646
+ this.intelligence.adaptiveRecommendations = {
647
+ nextActions: [
648
+ {
649
+ action: 'Validate low-confidence entities',
650
+ priority: 1,
651
+ reasoning: 'Several entities have confidence below 50%',
652
+ requiredEntities: entities
653
+ .filter(e => e.confidence < 0.5)
654
+ .map(e => e.id)
655
+ .slice(0, 3),
656
+ },
657
+ ],
658
+ knowledgeGaps,
659
+ optimizationOpportunities: [
660
+ 'Consider consolidating similar entities',
661
+ 'Review and strengthen weak relationships',
662
+ 'Add more context to entities with generic descriptions',
663
+ ],
664
+ };
665
+ this.intelligence.relationshipInference.suggestedRelationships = suggestedRelationships.slice(0, 10);
666
+ }
667
+ updateEntityRelationships(entity, relationship) {
668
+ // Determine the target entity ID based on which entity this is
669
+ const isSourceEntity = entity.id === relationship.sourceId;
670
+ const targetEntityId = isSourceEntity ? relationship.targetId : relationship.sourceId;
671
+ // Add relationship to entity's relationship list if not already present
672
+ const existingRelIndex = entity.relationships.findIndex(r => r.targetId === targetEntityId && r.type === relationship.type);
673
+ const entityRel = {
674
+ targetId: targetEntityId,
675
+ type: relationship.type,
676
+ strength: relationship.strength,
677
+ context: relationship.context,
678
+ created: relationship.created,
679
+ };
680
+ if (existingRelIndex >= 0) {
681
+ entity.relationships[existingRelIndex] = entityRel;
682
+ }
683
+ else {
684
+ entity.relationships.push(entityRel);
685
+ }
686
+ }
687
+ calculateChanges(oldEntity, newEntity) {
688
+ const changes = {};
689
+ // Convert to any to avoid index signature access issues
690
+ const oldAny = oldEntity;
691
+ const newAny = newEntity;
692
+ if (oldAny['title'] !== newAny['title'])
693
+ changes['title'] = { old: oldAny['title'], new: newAny['title'] };
694
+ if (oldAny['description'] !== newAny['description'])
695
+ changes['description'] = { old: oldAny['description'], new: newAny['description'] };
696
+ if (oldEntity['confidence'] !== newEntity['confidence'])
697
+ changes['confidence'] = { old: oldEntity['confidence'], new: newEntity['confidence'] };
698
+ if (oldEntity['relevance'] !== newEntity['relevance'])
699
+ changes['relevance'] = { old: oldEntity['relevance'], new: newEntity['relevance'] };
700
+ return changes;
701
+ }
702
+ async logEvolutionEvent(event) {
703
+ try {
704
+ let existingLog = [];
705
+ try {
706
+ const fsInstance = this.fsOverride || fs;
707
+ const logData = await fsInstance.readFile(this.evolutionLogFile, 'utf-8');
708
+ existingLog = JSON.parse(logData);
709
+ }
710
+ catch {
711
+ // Log file doesn't exist yet
712
+ }
713
+ existingLog.push(event);
714
+ // Keep only the last 1000 events to manage file size
715
+ if (existingLog.length > 1000) {
716
+ existingLog = existingLog.slice(-1000);
717
+ }
718
+ const fsInstance = this.fsOverride || fs;
719
+ await fsInstance.writeFile(this.evolutionLogFile, JSON.stringify(existingLog, null, 2));
720
+ }
721
+ catch (error) {
722
+ this.logger.warn('Failed to log evolution event', 'MemoryEntityManager', { event, error });
723
+ }
724
+ }
725
+ /**
726
+ * Clear all cached data (useful for testing)
727
+ */
728
+ clearCache() {
729
+ this.entitiesCache.clear();
730
+ this.relationshipsCache.clear();
731
+ this.intelligence = null;
732
+ this.lastSnapshotTime = 0;
733
+ }
734
+ /**
735
+ * Force persistence (useful for testing)
736
+ */
737
+ async forcePersist() {
738
+ return this.persistToStorage();
739
+ }
740
+ /**
741
+ * Create cross-tool relationships using the MemoryRelationshipMapper
742
+ */
743
+ async createCrossToolRelationships() {
744
+ const { MemoryRelationshipMapper } = await import('./memory-relationship-mapper.js');
745
+ const mapper = new MemoryRelationshipMapper(this);
746
+ this.logger.info('Starting cross-tool relationship creation', 'MemoryEntityManager');
747
+ const result = await mapper.createCrossToolRelationships();
748
+ const autoCreatedCount = result.suggestedRelationships.filter(rel => rel.confidence >= 0.85).length;
749
+ this.logger.info('Cross-tool relationships created', 'MemoryEntityManager', {
750
+ totalSuggested: result.suggestedRelationships.length,
751
+ autoCreated: autoCreatedCount,
752
+ conflicts: result.conflicts.length,
753
+ });
754
+ return {
755
+ ...result,
756
+ autoCreatedCount,
757
+ };
758
+ }
759
+ /**
760
+ * Infer and suggest new relationships based on existing entity patterns
761
+ */
762
+ async inferRelationships(entityTypes, minConfidence = 0.7) {
763
+ const { MemoryRelationshipMapper } = await import('./memory-relationship-mapper.js');
764
+ const mapper = new MemoryRelationshipMapper(this, { confidenceThreshold: minConfidence });
765
+ const result = await mapper.createCrossToolRelationships();
766
+ // Filter by entity types if specified
767
+ let filteredSuggestions = result.suggestedRelationships;
768
+ if (entityTypes && entityTypes.length > 0) {
769
+ const entityCache = this.entitiesCache;
770
+ filteredSuggestions = result.suggestedRelationships.filter(rel => {
771
+ const sourceEntity = entityCache.get(rel.sourceId);
772
+ const targetEntity = entityCache.get(rel.targetId);
773
+ return (sourceEntity &&
774
+ targetEntity &&
775
+ (entityTypes.includes(sourceEntity.type) || entityTypes.includes(targetEntity.type)));
776
+ });
777
+ }
778
+ return {
779
+ suggestedRelationships: filteredSuggestions.filter(rel => rel.confidence >= minConfidence),
780
+ };
781
+ }
782
+ /**
783
+ * Validate existing relationships and detect conflicts
784
+ */
785
+ async validateRelationships() {
786
+ const validRelationships = [];
787
+ const invalidRelationships = [];
788
+ const suggestedActions = [];
789
+ for (const [relationshipId, relationship] of this.relationshipsCache) {
790
+ // Check if both entities still exist
791
+ const sourceExists = this.entitiesCache.has(relationship.sourceId);
792
+ const targetExists = this.entitiesCache.has(relationship.targetId);
793
+ if (!sourceExists || !targetExists) {
794
+ invalidRelationships.push({
795
+ relationshipId,
796
+ reason: `${!sourceExists ? 'Source' : 'Target'} entity no longer exists`,
797
+ severity: 'high',
798
+ });
799
+ suggestedActions.push({
800
+ action: 'remove',
801
+ relationshipId,
802
+ reason: 'Orphaned relationship - entity deleted',
803
+ });
804
+ continue;
805
+ }
806
+ // Check relationship age and confidence
807
+ const createdDate = new Date(relationship.created);
808
+ const now = new Date();
809
+ const ageInDays = (now.getTime() - createdDate.getTime()) / (1000 * 60 * 60 * 24);
810
+ if (ageInDays > 90 && relationship.confidence < 0.6) {
811
+ invalidRelationships.push({
812
+ relationshipId,
813
+ reason: 'Old relationship with low confidence',
814
+ severity: 'medium',
815
+ });
816
+ suggestedActions.push({
817
+ action: 'investigate',
818
+ relationshipId,
819
+ reason: 'Requires validation - old and low confidence',
820
+ });
821
+ }
822
+ else if (relationship.strength < 0.3) {
823
+ invalidRelationships.push({
824
+ relationshipId,
825
+ reason: 'Very low relationship strength',
826
+ severity: 'low',
827
+ });
828
+ suggestedActions.push({
829
+ action: 'update',
830
+ relationshipId,
831
+ reason: 'Consider strengthening or removing weak relationship',
832
+ });
833
+ }
834
+ else {
835
+ validRelationships.push(relationshipId);
836
+ }
837
+ }
838
+ this.logger.info('Relationship validation completed', 'MemoryEntityManager', {
839
+ total: this.relationshipsCache.size,
840
+ valid: validRelationships.length,
841
+ invalid: invalidRelationships.length,
842
+ suggestedActions: suggestedActions.length,
843
+ });
844
+ return {
845
+ validRelationships,
846
+ invalidRelationships,
847
+ suggestedActions,
848
+ };
849
+ }
850
+ }
851
+ //# sourceMappingURL=memory-entity-manager.js.map