@mxf-dev/core 1.0.1 → 2.0.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.
Files changed (303) hide show
  1. package/README.md +18 -0
  2. package/dist/adapters/FrameworkAdapter.js +1 -1
  3. package/dist/adapters/FrameworkAdapter.js.map +1 -1
  4. package/dist/config/ConfigManager.d.ts +9 -8
  5. package/dist/config/ConfigManager.d.ts.map +1 -1
  6. package/dist/config/ConfigManager.js +47 -17
  7. package/dist/config/ConfigManager.js.map +1 -1
  8. package/dist/config/memory-strata.config.d.ts +25 -0
  9. package/dist/config/memory-strata.config.d.ts.map +1 -0
  10. package/dist/config/memory-strata.config.js +107 -0
  11. package/dist/config/memory-strata.config.js.map +1 -0
  12. package/dist/constants/ToolNames.d.ts +1 -29
  13. package/dist/constants/ToolNames.d.ts.map +1 -1
  14. package/dist/constants/ToolNames.js +4 -17
  15. package/dist/constants/ToolNames.js.map +1 -1
  16. package/dist/database/DatabaseAdapterFactory.d.ts +14 -2
  17. package/dist/database/DatabaseAdapterFactory.d.ts.map +1 -1
  18. package/dist/database/DatabaseAdapterFactory.js +21 -6
  19. package/dist/database/DatabaseAdapterFactory.js.map +1 -1
  20. package/dist/database/adapters/mongodb/MongoBaseRepository.d.ts +7 -1
  21. package/dist/database/adapters/mongodb/MongoBaseRepository.d.ts.map +1 -1
  22. package/dist/database/adapters/mongodb/MongoBaseRepository.js +12 -2
  23. package/dist/database/adapters/mongodb/MongoBaseRepository.js.map +1 -1
  24. package/dist/events/ClientEventBus.d.ts +16 -77
  25. package/dist/events/ClientEventBus.d.ts.map +1 -1
  26. package/dist/events/ClientEventBus.js +38 -311
  27. package/dist/events/ClientEventBus.js.map +1 -1
  28. package/dist/events/EventBus.d.ts +1 -1
  29. package/dist/events/EventBus.d.ts.map +1 -1
  30. package/dist/events/EventBus.js +5 -4
  31. package/dist/events/EventBus.js.map +1 -1
  32. package/dist/events/EventBusBase.d.ts +139 -34
  33. package/dist/events/EventBusBase.d.ts.map +1 -1
  34. package/dist/events/EventBusBase.js +366 -88
  35. package/dist/events/EventBusBase.js.map +1 -1
  36. package/dist/events/EventNames.d.ts +10 -1
  37. package/dist/events/EventNames.d.ts.map +1 -1
  38. package/dist/events/EventNames.js +3 -0
  39. package/dist/events/EventNames.js.map +1 -1
  40. package/dist/events/PublicEvents.d.ts +6 -2
  41. package/dist/events/PublicEvents.d.ts.map +1 -1
  42. package/dist/events/PublicEvents.js +7 -4
  43. package/dist/events/PublicEvents.js.map +1 -1
  44. package/dist/events/ServerEventBus.d.ts +23 -112
  45. package/dist/events/ServerEventBus.d.ts.map +1 -1
  46. package/dist/events/ServerEventBus.js +58 -323
  47. package/dist/events/ServerEventBus.js.map +1 -1
  48. package/dist/events/event-definitions/LlmBudgetEvents.d.ts +68 -0
  49. package/dist/events/event-definitions/LlmBudgetEvents.d.ts.map +1 -0
  50. package/dist/events/event-definitions/LlmBudgetEvents.js +35 -0
  51. package/dist/events/event-definitions/LlmBudgetEvents.js.map +1 -0
  52. package/dist/interfaces/IMemoryPersistence.d.ts +41 -0
  53. package/dist/interfaces/IMemoryPersistence.d.ts.map +1 -0
  54. package/dist/interfaces/IMemoryPersistence.js +15 -0
  55. package/dist/interfaces/IMemoryPersistence.js.map +1 -0
  56. package/dist/middleware/MxpMiddleware.d.ts +8 -1
  57. package/dist/middleware/MxpMiddleware.d.ts.map +1 -1
  58. package/dist/middleware/MxpMiddleware.js +42 -20
  59. package/dist/middleware/MxpMiddleware.js.map +1 -1
  60. package/dist/models/channelKey.d.ts +1 -0
  61. package/dist/models/channelKey.d.ts.map +1 -1
  62. package/dist/models/channelKey.js +5 -0
  63. package/dist/models/channelKey.js.map +1 -1
  64. package/dist/models/memoryUtility.d.ts +39 -0
  65. package/dist/models/memoryUtility.d.ts.map +1 -0
  66. package/dist/models/memoryUtility.js +39 -0
  67. package/dist/models/memoryUtility.js.map +1 -0
  68. package/dist/models/user.d.ts.map +1 -1
  69. package/dist/models/user.js +23 -1
  70. package/dist/models/user.js.map +1 -1
  71. package/dist/mxp/BinaryProtocolLayer.d.ts +24 -8
  72. package/dist/mxp/BinaryProtocolLayer.d.ts.map +1 -1
  73. package/dist/mxp/BinaryProtocolLayer.js +90 -103
  74. package/dist/mxp/BinaryProtocolLayer.js.map +1 -1
  75. package/dist/mxp/ContextCompressionEngine.d.ts +57 -10
  76. package/dist/mxp/ContextCompressionEngine.d.ts.map +1 -1
  77. package/dist/mxp/ContextCompressionEngine.js +170 -128
  78. package/dist/mxp/ContextCompressionEngine.js.map +1 -1
  79. package/dist/mxp/MxpTokenOptimizer.d.ts +7 -3
  80. package/dist/mxp/MxpTokenOptimizer.d.ts.map +1 -1
  81. package/dist/mxp/MxpTokenOptimizer.js +8 -5
  82. package/dist/mxp/MxpTokenOptimizer.js.map +1 -1
  83. package/dist/prompts/MxfAgentSystemPrompt.d.ts +1 -1
  84. package/dist/prompts/MxfAgentSystemPrompt.d.ts.map +1 -1
  85. package/dist/prompts/MxfAgentSystemPrompt.js +47 -57
  86. package/dist/prompts/MxfAgentSystemPrompt.js.map +1 -1
  87. package/dist/protocols/mcp/ToolError.d.ts +123 -0
  88. package/dist/protocols/mcp/ToolError.d.ts.map +1 -0
  89. package/dist/protocols/mcp/ToolError.js +108 -0
  90. package/dist/protocols/mcp/ToolError.js.map +1 -0
  91. package/dist/protocols/mcp/defineTool.d.ts +133 -0
  92. package/dist/protocols/mcp/defineTool.d.ts.map +1 -0
  93. package/dist/protocols/mcp/defineTool.js +236 -0
  94. package/dist/protocols/mcp/defineTool.js.map +1 -0
  95. package/dist/protocols/mcp/security/HttpTargetGuard.d.ts +38 -0
  96. package/dist/protocols/mcp/security/HttpTargetGuard.d.ts.map +1 -0
  97. package/dist/protocols/mcp/security/HttpTargetGuard.js +227 -0
  98. package/dist/protocols/mcp/security/HttpTargetGuard.js.map +1 -0
  99. package/dist/protocols/mcp/security/McpSecurityGuard.d.ts +9 -1
  100. package/dist/protocols/mcp/security/McpSecurityGuard.d.ts.map +1 -1
  101. package/dist/protocols/mcp/security/McpSecurityGuard.js +10 -2
  102. package/dist/protocols/mcp/security/McpSecurityGuard.js.map +1 -1
  103. package/dist/protocols/mcp/security/McpToolPolicy.d.ts +81 -0
  104. package/dist/protocols/mcp/security/McpToolPolicy.d.ts.map +1 -0
  105. package/dist/protocols/mcp/security/McpToolPolicy.js +202 -0
  106. package/dist/protocols/mcp/security/McpToolPolicy.js.map +1 -0
  107. package/dist/protocols/mcp/services/ExternalMcpServerManager.d.ts +51 -18
  108. package/dist/protocols/mcp/services/ExternalMcpServerManager.d.ts.map +1 -1
  109. package/dist/protocols/mcp/services/ExternalMcpServerManager.js +256 -283
  110. package/dist/protocols/mcp/services/ExternalMcpServerManager.js.map +1 -1
  111. package/dist/protocols/mcp/services/ExternalServerConfigs.d.ts +39 -6
  112. package/dist/protocols/mcp/services/ExternalServerConfigs.d.ts.map +1 -1
  113. package/dist/protocols/mcp/services/ExternalServerConfigs.js +76 -18
  114. package/dist/protocols/mcp/services/ExternalServerConfigs.js.map +1 -1
  115. package/dist/protocols/mcp/tools/AnalyticsTools.js +1 -1
  116. package/dist/protocols/mcp/tools/AnalyticsTools.js.map +1 -1
  117. package/dist/protocols/mcp/tools/CodeAnalysisTools.d.ts.map +1 -1
  118. package/dist/protocols/mcp/tools/CodeAnalysisTools.js +15 -0
  119. package/dist/protocols/mcp/tools/CodeAnalysisTools.js.map +1 -1
  120. package/dist/protocols/mcp/tools/EffectivenessTools.js +3 -3
  121. package/dist/protocols/mcp/tools/EffectivenessTools.js.map +1 -1
  122. package/dist/protocols/mcp/tools/GitTools.d.ts +9 -369
  123. package/dist/protocols/mcp/tools/GitTools.d.ts.map +1 -1
  124. package/dist/protocols/mcp/tools/GitTools.js +222 -517
  125. package/dist/protocols/mcp/tools/GitTools.js.map +1 -1
  126. package/dist/protocols/mcp/tools/InfrastructureTools.d.ts +56 -24
  127. package/dist/protocols/mcp/tools/InfrastructureTools.d.ts.map +1 -1
  128. package/dist/protocols/mcp/tools/InfrastructureTools.js +117 -26
  129. package/dist/protocols/mcp/tools/InfrastructureTools.js.map +1 -1
  130. package/dist/protocols/mcp/tools/MemorySearchTools.d.ts +0 -3
  131. package/dist/protocols/mcp/tools/MemorySearchTools.d.ts.map +1 -1
  132. package/dist/protocols/mcp/tools/MemorySearchTools.js +58 -1
  133. package/dist/protocols/mcp/tools/MemorySearchTools.js.map +1 -1
  134. package/dist/protocols/mcp/tools/OrparTools.d.ts +8 -0
  135. package/dist/protocols/mcp/tools/OrparTools.d.ts.map +1 -1
  136. package/dist/protocols/mcp/tools/OrparTools.js +66 -0
  137. package/dist/protocols/mcp/tools/OrparTools.js.map +1 -1
  138. package/dist/protocols/mcp/tools/SafetyTools.d.ts +7 -525
  139. package/dist/protocols/mcp/tools/SafetyTools.d.ts.map +1 -1
  140. package/dist/protocols/mcp/tools/SafetyTools.js +349 -514
  141. package/dist/protocols/mcp/tools/SafetyTools.js.map +1 -1
  142. package/dist/protocols/mcp/tools/TaskPlanningTools.d.ts.map +1 -1
  143. package/dist/protocols/mcp/tools/TaskPlanningTools.js +56 -26
  144. package/dist/protocols/mcp/tools/TaskPlanningTools.js.map +1 -1
  145. package/dist/protocols/mcp/tools/TestTools.d.ts +15 -376
  146. package/dist/protocols/mcp/tools/TestTools.d.ts.map +1 -1
  147. package/dist/protocols/mcp/tools/TestTools.js +241 -363
  148. package/dist/protocols/mcp/tools/TestTools.js.map +1 -1
  149. package/dist/protocols/mcp/tools/TypeScriptTools.d.ts +6 -276
  150. package/dist/protocols/mcp/tools/TypeScriptTools.d.ts.map +1 -1
  151. package/dist/protocols/mcp/tools/TypeScriptTools.js +223 -337
  152. package/dist/protocols/mcp/tools/TypeScriptTools.js.map +1 -1
  153. package/dist/protocols/mcp/tools/WebTools.d.ts +15 -728
  154. package/dist/protocols/mcp/tools/WebTools.d.ts.map +1 -1
  155. package/dist/protocols/mcp/tools/WebTools.js +151 -257
  156. package/dist/protocols/mcp/tools/WebTools.js.map +1 -1
  157. package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.d.ts +5 -3
  158. package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.d.ts.map +1 -1
  159. package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.js +31 -6
  160. package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.js.map +1 -1
  161. package/dist/schemas/EventPayloadSchema.d.ts +21 -0
  162. package/dist/schemas/EventPayloadSchema.d.ts.map +1 -1
  163. package/dist/schemas/EventPayloadSchema.js +14 -0
  164. package/dist/schemas/EventPayloadSchema.js.map +1 -1
  165. package/dist/services/BackgroundTaskManager.d.ts.map +1 -1
  166. package/dist/services/BackgroundTaskManager.js +12 -4
  167. package/dist/services/BackgroundTaskManager.js.map +1 -1
  168. package/dist/services/BrowserManager.d.ts +1 -1
  169. package/dist/services/BrowserManager.d.ts.map +1 -1
  170. package/dist/services/BrowserManager.js +26 -3
  171. package/dist/services/BrowserManager.js.map +1 -1
  172. package/dist/services/MemoryCompressor.d.ts +11 -2
  173. package/dist/services/MemoryCompressor.d.ts.map +1 -1
  174. package/dist/services/MemoryCompressor.js +8 -26
  175. package/dist/services/MemoryCompressor.js.map +1 -1
  176. package/dist/services/MemoryService.d.ts +16 -3
  177. package/dist/services/MemoryService.d.ts.map +1 -1
  178. package/dist/services/MemoryService.js +79 -55
  179. package/dist/services/MemoryService.js.map +1 -1
  180. package/dist/services/MxfMLService.d.ts +5 -0
  181. package/dist/services/MxfMLService.d.ts.map +1 -1
  182. package/dist/services/MxfMLService.js +32 -6
  183. package/dist/services/MxfMLService.js.map +1 -1
  184. package/dist/services/PredictiveAnalyticsService.d.ts +45 -9
  185. package/dist/services/PredictiveAnalyticsService.d.ts.map +1 -1
  186. package/dist/services/PredictiveAnalyticsService.js +82 -44
  187. package/dist/services/PredictiveAnalyticsService.js.map +1 -1
  188. package/dist/services/QValueManager.d.ts +7 -0
  189. package/dist/services/QValueManager.d.ts.map +1 -1
  190. package/dist/services/QValueManager.js +9 -0
  191. package/dist/services/QValueManager.js.map +1 -1
  192. package/dist/services/RewardSignalProcessor.d.ts +38 -1
  193. package/dist/services/RewardSignalProcessor.d.ts.map +1 -1
  194. package/dist/services/RewardSignalProcessor.js +109 -7
  195. package/dist/services/RewardSignalProcessor.js.map +1 -1
  196. package/dist/services/SharedStateService.d.ts +16 -2
  197. package/dist/services/SharedStateService.d.ts.map +1 -1
  198. package/dist/services/SharedStateService.js +44 -3
  199. package/dist/services/SharedStateService.js.map +1 -1
  200. package/dist/services/TaskEffectivenessService.d.ts +34 -18
  201. package/dist/services/TaskEffectivenessService.d.ts.map +1 -1
  202. package/dist/services/TaskEffectivenessService.js +91 -155
  203. package/dist/services/TaskEffectivenessService.js.map +1 -1
  204. package/dist/services/WebSearchService.d.ts.map +1 -1
  205. package/dist/services/WebSearchService.js.map +1 -1
  206. package/dist/services/dag/TaskDagService.d.ts.map +1 -1
  207. package/dist/services/dag/TaskDagService.js +2 -0
  208. package/dist/services/dag/TaskDagService.js.map +1 -1
  209. package/dist/services/orpar-memory/OrparMemoryCoordinator.d.ts +7 -0
  210. package/dist/services/orpar-memory/OrparMemoryCoordinator.d.ts.map +1 -1
  211. package/dist/services/orpar-memory/OrparMemoryCoordinator.js +71 -10
  212. package/dist/services/orpar-memory/OrparMemoryCoordinator.js.map +1 -1
  213. package/dist/types/MemoryUtilityTypes.d.ts +2 -0
  214. package/dist/types/MemoryUtilityTypes.d.ts.map +1 -1
  215. package/dist/types/MemoryUtilityTypes.js.map +1 -1
  216. package/dist/utils/Logger.d.ts +43 -3
  217. package/dist/utils/Logger.d.ts.map +1 -1
  218. package/dist/utils/Logger.js +78 -36
  219. package/dist/utils/Logger.js.map +1 -1
  220. package/dist/utils/MxpEncryption.d.ts +19 -6
  221. package/dist/utils/MxpEncryption.d.ts.map +1 -1
  222. package/dist/utils/MxpEncryption.js +48 -16
  223. package/dist/utils/MxpEncryption.js.map +1 -1
  224. package/package.json +19 -4
  225. package/src/adapters/FrameworkAdapter.ts +1 -1
  226. package/src/config/ConfigManager.ts +52 -19
  227. package/src/config/memory-strata.config.ts +136 -0
  228. package/src/constants/ToolNames.ts +4 -18
  229. package/src/database/DatabaseAdapterFactory.ts +23 -6
  230. package/src/database/adapters/mongodb/MongoBaseRepository.ts +16 -2
  231. package/src/events/ClientEventBus.ts +68 -403
  232. package/src/events/EventBus.ts +7 -8
  233. package/src/events/EventBusBase.ts +479 -116
  234. package/src/events/EventNames.ts +6 -0
  235. package/src/events/PublicEvents.ts +7 -4
  236. package/src/events/ServerEventBus.ts +78 -473
  237. package/src/events/event-definitions/LlmBudgetEvents.ts +74 -0
  238. package/src/interfaces/IMemoryPersistence.ts +51 -0
  239. package/src/middleware/MxpMiddleware.ts +51 -24
  240. package/src/models/channelKey.ts +18 -4
  241. package/src/models/memoryUtility.ts +64 -0
  242. package/src/models/user.ts +36 -4
  243. package/src/mxp/BinaryProtocolLayer.ts +108 -124
  244. package/src/mxp/ContextCompressionEngine.ts +219 -161
  245. package/src/mxp/MxpTokenOptimizer.ts +10 -10
  246. package/src/prompts/MxfAgentSystemPrompt.ts +45 -55
  247. package/src/protocols/mcp/ToolError.ts +201 -0
  248. package/src/protocols/mcp/defineTool.ts +379 -0
  249. package/src/protocols/mcp/security/HttpTargetGuard.ts +267 -0
  250. package/src/protocols/mcp/security/McpSecurityGuard.ts +10 -3
  251. package/src/protocols/mcp/security/McpToolPolicy.ts +221 -0
  252. package/src/protocols/mcp/services/ExternalMcpServerManager.ts +340 -322
  253. package/src/protocols/mcp/services/ExternalServerConfigs.ts +82 -19
  254. package/src/protocols/mcp/tools/AnalyticsTools.ts +1 -1
  255. package/src/protocols/mcp/tools/CodeAnalysisTools.ts +15 -0
  256. package/src/protocols/mcp/tools/EffectivenessTools.ts +3 -3
  257. package/src/protocols/mcp/tools/GitTools.ts +290 -569
  258. package/src/protocols/mcp/tools/InfrastructureTools.ts +189 -43
  259. package/src/protocols/mcp/tools/MemorySearchTools.ts +77 -1
  260. package/src/protocols/mcp/tools/OrparTools.ts +87 -0
  261. package/src/protocols/mcp/tools/SafetyTools.ts +501 -579
  262. package/src/protocols/mcp/tools/TaskPlanningTools.ts +81 -39
  263. package/src/protocols/mcp/tools/TestTools.ts +339 -419
  264. package/src/protocols/mcp/tools/TypeScriptTools.ts +316 -376
  265. package/src/protocols/mcp/tools/WebTools.ts +209 -307
  266. package/src/protocols/mcp/tools/shell/ShellExecuteHandler.ts +53 -14
  267. package/src/schemas/EventPayloadSchema.ts +37 -0
  268. package/src/services/BackgroundTaskManager.ts +12 -4
  269. package/src/services/BrowserManager.ts +41 -1
  270. package/src/services/MemoryCompressor.ts +20 -32
  271. package/src/services/MemoryService.ts +96 -58
  272. package/src/services/MxfMLService.ts +41 -7
  273. package/src/services/PredictiveAnalyticsService.ts +101 -51
  274. package/src/services/QValueManager.ts +10 -0
  275. package/src/services/RewardSignalProcessor.ts +138 -9
  276. package/src/services/SharedStateService.ts +56 -8
  277. package/src/services/TaskEffectivenessService.ts +114 -187
  278. package/src/services/WebSearchService.ts +2 -1
  279. package/src/services/dag/TaskDagService.ts +2 -0
  280. package/src/services/orpar-memory/OrparMemoryCoordinator.ts +86 -10
  281. package/src/types/MemoryUtilityTypes.ts +2 -0
  282. package/src/utils/Logger.ts +116 -40
  283. package/src/utils/MxpEncryption.ts +69 -34
  284. package/dist/mxp/MxpEventForwardingEnhancer.d.ts +0 -134
  285. package/dist/mxp/MxpEventForwardingEnhancer.d.ts.map +0 -1
  286. package/dist/mxp/MxpEventForwardingEnhancer.js +0 -361
  287. package/dist/mxp/MxpEventForwardingEnhancer.js.map +0 -1
  288. package/dist/protocols/mcp/services/ToolSchemaEnhancements.d.ts +0 -56
  289. package/dist/protocols/mcp/services/ToolSchemaEnhancements.d.ts.map +0 -1
  290. package/dist/protocols/mcp/services/ToolSchemaEnhancements.js +0 -57
  291. package/dist/protocols/mcp/services/ToolSchemaEnhancements.js.map +0 -1
  292. package/dist/protocols/mcp/tools/ControlLoopLifecycle.d.ts +0 -270
  293. package/dist/protocols/mcp/tools/ControlLoopLifecycle.d.ts.map +0 -1
  294. package/dist/protocols/mcp/tools/ControlLoopLifecycle.js +0 -256
  295. package/dist/protocols/mcp/tools/ControlLoopLifecycle.js.map +0 -1
  296. package/dist/protocols/mcp/tools/LspTools.d.ts +0 -495
  297. package/dist/protocols/mcp/tools/LspTools.d.ts.map +0 -1
  298. package/dist/protocols/mcp/tools/LspTools.js +0 -469
  299. package/dist/protocols/mcp/tools/LspTools.js.map +0 -1
  300. package/src/mxp/MxpEventForwardingEnhancer.ts +0 -471
  301. package/src/protocols/mcp/services/ToolSchemaEnhancements.ts +0 -92
  302. package/src/protocols/mcp/tools/ControlLoopLifecycle.ts +0 -302
  303. package/src/protocols/mcp/tools/LspTools.ts +0 -476
@@ -37,6 +37,7 @@ import { promisify } from 'util';
37
37
  import crypto from 'crypto';
38
38
  import { getSecurityGuard, SecurityContext } from '../security/McpSecurityGuard.js';
39
39
  import { getConfirmationManager } from '../security/McpConfirmationManager.js';
40
+ import { buildShellChildEnv } from '../security/McpToolPolicy.js';
40
41
  import { execute as shellExecuteHandler } from './shell/ShellExecuteHandler.js';
41
42
  import { processOutput } from './shell/LargeOutputHandler.js';
42
43
  import { BackgroundTaskManager } from '../../../services/BackgroundTaskManager.js';
@@ -58,68 +59,173 @@ const logger = new Logger('info', 'InfrastructureTools', 'server');
58
59
  const validator = createStrictValidator('InfrastructureTools');
59
60
  const execAsync = promisify(exec);
60
61
 
61
- // Initialize security modules
62
- const securityGuard = getSecurityGuard(process.cwd());
63
- const confirmationManager = getConfirmationManager();
62
+ // Initialize the security guard singleton. Importing this module is what binds
63
+ // the guard to the project root; ShellExecuteHandler and executeShellCommand
64
+ // below then retrieve it with getSecurityGuard().
65
+ getSecurityGuard(process.cwd());
64
66
 
65
67
  /**
66
- * Helper function to execute shell commands - can be used by other tools
68
+ * Identity of the caller running a shell command.
69
+ *
70
+ * Required — the security guard makes its decision in the context of an agent
71
+ * and a channel, and every shell execution is attributable. There is no default:
72
+ * a missing identity is a wiring bug, not something to paper over with 'system'.
73
+ */
74
+ export interface ShellCommandContext {
75
+ agentId: AgentId;
76
+ channelId: ChannelId;
77
+ requestId: string;
78
+ }
79
+
80
+ /**
81
+ * Result of running a shell command through {@link executeShellCommand}.
82
+ */
83
+ export interface ShellCommandResult {
84
+ command: string;
85
+ exitCode: number;
86
+ stdout?: string;
87
+ stderr?: string;
88
+ executionTime: number;
89
+ executedAt: number;
90
+ /** Destructive-pattern warnings raised by the security guard, if any */
91
+ warnings?: string[];
92
+ }
93
+
94
+ /**
95
+ * Run a shell command on behalf of an agent.
96
+ *
97
+ * Every tool that shells out — git, tsc, eslint, prettier, jest, mocha, vitest,
98
+ * find, rg, and the rollback/backup tools — goes through here, so this is where
99
+ * the security controls have to live:
100
+ *
101
+ * 1. The command is validated by the McpSecurityGuard, which parses compound
102
+ * expressions and checks each effective command. A blocked command throws.
103
+ * 2. A command the guard flags for confirmation goes to the confirmation
104
+ * manager, and a refusal throws.
105
+ * 3. The child process receives a minimal environment built by the tool policy
106
+ * — not the server's, which holds JWT_SECRET, MONGODB_URI and
107
+ * OPENROUTER_API_KEY.
108
+ * 4. Arguments are shell-escaped before they reach the shell.
109
+ *
110
+ * @param command - The base command (for example 'git')
111
+ * @param args - Arguments, shell-escaped before use
112
+ * @param options - Execution options; `context` identifies the calling agent
113
+ * @throws Error when the guard blocks the command or confirmation is refused
67
114
  */
68
115
  export async function executeShellCommand(
69
116
  command: string,
70
- args?: string[],
71
- options?: {
117
+ args: string[] | undefined,
118
+ options: {
119
+ /** Who is running this command. Required. */
120
+ context: ShellCommandContext;
72
121
  workingDirectory?: string;
73
122
  environment?: Record<string, string>;
74
123
  timeout?: number;
75
124
  captureOutput?: boolean;
76
125
  }
77
- ): Promise<{
78
- command: string;
79
- exitCode: number;
80
- stdout?: string;
81
- stderr?: string;
82
- executionTime: number;
83
- executedAt: number;
84
- }> {
126
+ ): Promise<ShellCommandResult> {
85
127
  const startTime = Date.now();
86
-
87
- try {
88
- // Build the full command string with properly escaped arguments
89
- // Shell-escape each argument by wrapping in single quotes and escaping any embedded single quotes
90
- const quotedArgs = args ? args.map(arg => `'${arg.replace(/'/g, "'\\''")}'`).join(' ') : '';
91
- const fullCommand = args ? `${command} ${quotedArgs}` : command;
92
128
 
93
- // Execute the command
129
+ validator.assertIsString(command, 'command');
130
+
131
+ const context = options?.context;
132
+ if (!context || typeof context.agentId !== 'string' || context.agentId.length === 0) {
133
+ throw new Error(
134
+ 'executeShellCommand requires context.agentId — shell execution must be attributable to an agent.'
135
+ );
136
+ }
137
+ if (typeof context.channelId !== 'string' || context.channelId.length === 0) {
138
+ throw new Error(
139
+ 'executeShellCommand requires context.channelId — shell execution must be attributable to a channel.'
140
+ );
141
+ }
142
+
143
+ // Build the full command string with properly escaped arguments. Each argument
144
+ // is wrapped in single quotes with embedded quotes escaped, so an argument can
145
+ // never break out into a new shell word.
146
+ const quotedArgs = args ? args.map(arg => `'${arg.replace(/'/g, "'\\''")}'`).join(' ') : '';
147
+ const fullCommand = args && args.length > 0 ? `${command} ${quotedArgs}` : command;
148
+
149
+ // ── Security validation ────────────────────────────────────────────────
150
+ // The guard parses compound expressions (`a && b`, `a; b`) and validates each
151
+ // effective command, so `git status; rm -rf /` cannot slip through on the
152
+ // strength of its first word.
153
+ const securityGuard = getSecurityGuard();
154
+ const securityContext: SecurityContext = {
155
+ agentId: context.agentId,
156
+ channelId: context.channelId,
157
+ requestId: context.requestId
158
+ };
159
+
160
+ const validation = securityGuard.validateCommand(fullCommand, securityContext);
161
+
162
+ if (!validation.allowed) {
163
+ throw new Error(
164
+ `Command blocked by security policy: ${validation.reason ?? 'command is not allowed'} ` +
165
+ `(command: ${command}, risk: ${validation.riskLevel ?? 'unknown'})`
166
+ );
167
+ }
168
+
169
+ if (validation.warnings && validation.warnings.length > 0) {
170
+ logger.warn(
171
+ `Destructive command warnings for "${fullCommand}": ${validation.warnings.join('; ')}`
172
+ );
173
+ }
174
+
175
+ if (validation.requiresConfirmation) {
176
+ const confirmationManager = getConfirmationManager();
177
+ const confirmed = await confirmationManager.requestConfirmation(
178
+ 'command',
179
+ 'Execute shell command',
180
+ {
181
+ command: fullCommand,
182
+ riskLevel: validation.riskLevel || 'medium',
183
+ reason: validation.reason || 'Command requires confirmation'
184
+ },
185
+ securityContext,
186
+ options?.timeout || 30000
187
+ );
188
+
189
+ if (!confirmed) {
190
+ throw new Error(`Command execution denied by confirmation policy: ${command}`);
191
+ }
192
+ }
193
+
194
+ // ── Execution ──────────────────────────────────────────────────────────
195
+ // Least privilege: the child gets PATH/HOME/locale plus whatever the caller
196
+ // declares, never the server's full environment.
197
+ const childEnv = buildShellChildEnv(options?.environment);
198
+
199
+ try {
94
200
  const result = await execAsync(fullCommand, {
95
201
  cwd: options?.workingDirectory || process.cwd(),
96
- env: { ...process.env, ...options?.environment },
202
+ env: childEnv,
97
203
  timeout: options?.timeout || 30000,
98
204
  maxBuffer: 1024 * 1024 * 10 // 10MB buffer
99
205
  });
100
-
101
- const executionTime = Date.now() - startTime;
102
-
206
+
103
207
  return {
104
208
  command: fullCommand,
105
209
  exitCode: 0,
106
210
  stdout: options?.captureOutput !== false ? result.stdout : undefined,
107
211
  stderr: options?.captureOutput !== false ? result.stderr : undefined,
108
- executionTime,
109
- executedAt: Date.now()
212
+ executionTime: Date.now() - startTime,
213
+ executedAt: Date.now(),
214
+ warnings: validation.warnings
110
215
  };
111
-
216
+
112
217
  } catch (execError: any) {
113
- const executionTime = Date.now() - startTime;
114
-
115
- // Handle execution errors (non-zero exit codes)
218
+ // A non-zero exit code is a result, not an exception — `git diff --quiet`
219
+ // and `grep` use exit codes to mean "no changes" / "no matches". The caller
220
+ // inspects exitCode. Genuine policy failures throw above, before we get here.
116
221
  return {
117
- command: command,
118
- exitCode: execError.code || 1,
222
+ command: fullCommand,
223
+ exitCode: execError.code ?? 1,
119
224
  stdout: options?.captureOutput !== false ? execError.stdout || '' : undefined,
120
225
  stderr: options?.captureOutput !== false ? execError.stderr || execError.message : undefined,
121
- executionTime,
122
- executedAt: Date.now()
226
+ executionTime: Date.now() - startTime,
227
+ executedAt: Date.now(),
228
+ warnings: validation.warnings
123
229
  };
124
230
  }
125
231
  }
@@ -351,11 +457,6 @@ export const shellExecTool = {
351
457
  default: true,
352
458
  description: 'Whether to capture command output'
353
459
  },
354
- allowedCommands: {
355
- type: 'array',
356
- items: { type: 'string' },
357
- description: 'List of allowed commands (for security)'
358
- },
359
460
  description: {
360
461
  type: 'string',
361
462
  description: 'Human-readable summary of what this command does (for logging, audit trails, and display)'
@@ -379,6 +480,7 @@ export const shellExecTool = {
379
480
  * to BackgroundTaskManager for background execution.
380
481
  *
381
482
  * Foreground mode provides:
483
+ * - Security guard validation and confirmation
382
484
  * - Command semantics (exit code interpretation)
383
485
  * - Destructive command warnings
384
486
  * - Command classification (read-only, silent, etc.)
@@ -391,6 +493,10 @@ export const shellExecTool = {
391
493
  * - Ring-buffer output accumulation
392
494
  * - Throttled progress events via EventBus
393
495
  * - Query via shell_task_status tool
496
+ *
497
+ * The command allowlist is NOT an input. It comes from MXF_SHELL_ALLOWED_COMMANDS
498
+ * (see McpToolPolicy) — an allowlist passed as a tool argument would be supplied
499
+ * by the same model it is meant to restrict.
394
500
  */
395
501
  async handler(input: {
396
502
  command: string;
@@ -399,7 +505,6 @@ export const shellExecTool = {
399
505
  environment?: Record<string, string>;
400
506
  timeout?: number;
401
507
  captureOutput?: boolean;
402
- allowedCommands?: string[];
403
508
  description?: string;
404
509
  runInBackground?: boolean;
405
510
  backgroundTimeout?: number;
@@ -408,14 +513,55 @@ export const shellExecTool = {
408
513
  channelId: ChannelId;
409
514
  requestId: string;
410
515
  }) {
411
- // Background execution: delegate to BackgroundTaskManager
516
+ // Background execution: delegate to BackgroundTaskManager.
517
+ //
518
+ // The guard runs here, at the tool boundary, because BackgroundTaskManager
519
+ // spawns directly. Without this the background path would be an unguarded
520
+ // way to run exactly the commands the foreground path blocks.
412
521
  if (input.runInBackground) {
522
+ const securityGuard = getSecurityGuard();
523
+ const securityContext: SecurityContext = {
524
+ agentId: context.agentId,
525
+ channelId: context.channelId,
526
+ requestId: context.requestId
527
+ };
528
+
529
+ const validation = securityGuard.validateCommand(input.command, securityContext);
530
+
531
+ if (!validation.allowed) {
532
+ throw new Error(
533
+ `Command blocked by security policy: ${validation.reason ?? 'command is not allowed'} ` +
534
+ `(command: ${input.command}, risk: ${validation.riskLevel ?? 'unknown'})`
535
+ );
536
+ }
537
+
538
+ if (validation.requiresConfirmation) {
539
+ const confirmed = await getConfirmationManager().requestConfirmation(
540
+ 'command',
541
+ 'Execute background shell command',
542
+ {
543
+ command: input.command,
544
+ riskLevel: validation.riskLevel || 'medium',
545
+ reason: validation.reason || 'Command requires confirmation'
546
+ },
547
+ securityContext,
548
+ input.timeout || 30000
549
+ );
550
+
551
+ if (!confirmed) {
552
+ throw new Error(`Background command execution denied by confirmation policy: ${input.command}`);
553
+ }
554
+ }
555
+
413
556
  const btm = BackgroundTaskManager.getInstance();
414
557
  const { taskId } = await btm.startBackground(
415
558
  input.command,
416
559
  {
417
560
  workingDirectory: input.workingDirectory,
418
- environment: input.environment,
561
+ // Hand the child a minimal environment. BackgroundTaskManager
562
+ // still merges this over process.env internally — see the
563
+ // reported fix for BackgroundTaskManager.ts:190.
564
+ environment: buildShellChildEnv(input.environment),
419
565
  timeout: input.backgroundTimeout,
420
566
  description: input.description
421
567
  },
@@ -25,6 +25,12 @@
25
25
  import { McpToolDefinition, McpToolHandlerContext, McpToolHandlerResult, McpToolResultContent } from '../McpServerTypes.js';
26
26
  import { Logger } from '../../../utils/Logger.js';
27
27
  import { MxfMeilisearchService, SearchParams } from '../../../services/MxfMeilisearchService.js';
28
+ import { MemoryService } from '../../../services/MemoryService.js';
29
+ import { QValueManager } from '../../../services/QValueManager.js';
30
+ import { UtilityScorerService } from '../../../services/UtilityScorerService.js';
31
+ import { RewardSignalProcessor } from '../../../services/RewardSignalProcessor.js';
32
+ import { MemoryCandidate } from '../../../types/MemoryUtilityTypes.js';
33
+ import { getCurrentMemoryPhase } from './OrparTools.js';
28
34
  import { paginationInputSchema, checkResultSize, PaginationMetadata } from '../../../utils/ToolPaginationUtils.js';
29
35
 
30
36
  const logger = new Logger('info', 'MemorySearchTools', 'server');
@@ -32,6 +38,73 @@ const logger = new Logger('info', 'MemorySearchTools', 'server');
32
38
  /**
33
39
  * Search conversation history semantically
34
40
  */
41
+ /**
42
+ * Re-rank search hits by learned utility, and record what was retrieved.
43
+ *
44
+ * This is the join between semantic search and the Memory Utility Learning System.
45
+ * Before this existed, Q-values were computed and stored but no reachable retrieval
46
+ * path consulted them, so learning could not change anything an agent saw — and no
47
+ * production code recorded which memories a task used, so no reward was ever
48
+ * attributed. Both halves of the loop close here.
49
+ *
50
+ * When MULS is disabled this returns the hits untouched, so search behaves exactly as
51
+ * it did before.
52
+ */
53
+ async function applyUtilityRanking<T extends { id: string; _rankingScore: number }>(
54
+ query: string,
55
+ hits: T[],
56
+ context: McpToolHandlerContext
57
+ ): Promise<T[]> {
58
+ const qValueManager = QValueManager.getInstance();
59
+ if (!qValueManager.isEnabled() || hits.length === 0) {
60
+ return hits;
61
+ }
62
+
63
+ const { agentId, channelId } = context;
64
+ const memoryIds = hits.map(hit => hit.id);
65
+
66
+ // Load Q-values learned in previous runs; without this every memory this process
67
+ // has not seen yet would score at the default and ranking would ignore all learning.
68
+ const memoryService = MemoryService.getInstance();
69
+ await memoryService.hydrateQValues(memoryIds);
70
+
71
+ const candidates: MemoryCandidate[] = hits.map(hit => ({
72
+ memoryId: hit.id,
73
+ similarity: hit._rankingScore,
74
+ qValue: qValueManager.getQValue(hit.id)
75
+ }));
76
+
77
+ // Phase-specific lambda when the agent is inside an ORPAR cycle; otherwise the
78
+ // configured default. We do not guess a phase.
79
+ const phase = agentId && channelId ? getCurrentMemoryPhase(agentId, channelId) : null;
80
+ const scorer = UtilityScorerService.getInstance();
81
+ const scoringResult = phase
82
+ ? scorer.scoreForPhase(query, candidates, phase)
83
+ : scorer.scoreMemories(query, candidates);
84
+
85
+ // Record the retrieval so RewardSignalProcessor can attribute the task's outcome to
86
+ // these memories when it completes.
87
+ if (agentId && channelId) {
88
+ RewardSignalProcessor.getInstance().trackAgentMemoriesUsage(
89
+ agentId,
90
+ channelId,
91
+ scoringResult.memories.map(m => m.memoryId),
92
+ phase ?? 'observation',
93
+ 'context'
94
+ );
95
+ }
96
+
97
+ const hitsById = new Map(hits.map(hit => [hit.id, hit]));
98
+ const ranked: T[] = [];
99
+ for (const scored of scoringResult.memories) {
100
+ const hit = hitsById.get(scored.memoryId);
101
+ if (hit) {
102
+ ranked.push(hit);
103
+ }
104
+ }
105
+ return ranked;
106
+ }
107
+
35
108
  export const memory_search_conversations = {
36
109
  name: 'memory_search_conversations',
37
110
  description: 'Search your entire conversation history using semantic search. Find relevant past discussions even if they happened hundreds of messages ago. Use this when you need to recall "that time we talked about X".',
@@ -159,7 +232,10 @@ export const memory_search_conversations = {
159
232
 
160
233
  const result = await meilisearch.searchConversations(searchParams);
161
234
 
162
- const formattedResults = result.hits.map(hit => ({
235
+ // Re-rank by learned utility and record the retrieval for reward attribution.
236
+ const rankedHits = await applyUtilityRanking(input.query, result.hits, context);
237
+
238
+ const formattedResults = rankedHits.map(hit => ({
163
239
  content: hit.content,
164
240
  role: hit.role,
165
241
  agentId: hit.agentId,
@@ -48,6 +48,9 @@ import { createStrictValidator } from '../../../utils/validation.js';
48
48
  import { AgentId } from '../../../types/Agent.js';
49
49
  import { ChannelId } from '../../../types/ChannelContext.js';
50
50
  import { Observation, Reflection } from '../../../types/ControlLoopTypes.js';
51
+ import { OrparPhase as MemoryOrparPhase } from '../../../types/MemoryUtilityTypes.js';
52
+ import { OrparGraphIntegration } from '../../../services/kg/OrparGraphIntegration.js';
53
+ import { EntityExtractionService } from '../../../services/kg/EntityExtractionService.js';
51
54
  import {
52
55
  normalizeOrparParameters,
53
56
  stripUnknownParameters,
@@ -68,6 +71,75 @@ let agentDisconnectListenerRegistered = false;
68
71
  */
69
72
  export type OrparPhase = 'observe' | 'reason' | 'plan' | 'act' | 'reflect';
70
73
 
74
+ /**
75
+ * The ORPAR tools name phases with verbs ('observe'), while the memory-utility system
76
+ * names them with nouns ('observation' — see MemoryUtilityTypes.OrparPhase). They are
77
+ * the same five phases in two vocabularies, which is part of why memory retrieval and
78
+ * phase-weighted learning were never connected. This map is the bridge.
79
+ */
80
+ const TOOL_PHASE_TO_MEMORY_PHASE: Record<OrparPhase, MemoryOrparPhase> = {
81
+ observe: 'observation',
82
+ reason: 'reasoning',
83
+ plan: 'planning',
84
+ act: 'action',
85
+ reflect: 'reflection'
86
+ };
87
+
88
+ /**
89
+ * The agent's current ORPAR phase, in the vocabulary the memory-utility system uses.
90
+ *
91
+ * Returns null when the agent has no active ORPAR cycle, in which case callers should
92
+ * fall back to phase-independent scoring rather than guessing a phase.
93
+ */
94
+ export function getCurrentMemoryPhase(agentId: string, channelId: string): MemoryOrparPhase | null {
95
+ const state = agentOrparStates.get(`${agentId}:${channelId}`);
96
+ if (!state?.currentPhase) {
97
+ return null;
98
+ }
99
+ return TOOL_PHASE_TO_MEMORY_PHASE[state.currentPhase];
100
+ }
101
+
102
+ /**
103
+ * Turn a reflection into knowledge-graph learning.
104
+ *
105
+ * Extracts the entities the agent named in its reflection, records them, and propagates
106
+ * the cycle's outcome as a reward across them — so entities that keep appearing in
107
+ * successful cycles gain utility and entities tied to failures lose it.
108
+ *
109
+ * Returns a summary of what changed. When the knowledge graph is disabled this reports
110
+ * zeroes rather than pretending work happened.
111
+ */
112
+ async function applyReflectionToGraph(
113
+ agentId: AgentId,
114
+ channelId: ChannelId,
115
+ reflection: string,
116
+ taskSuccess: boolean
117
+ ): Promise<{ entitiesCreated: number; relationshipsCreated: number; qValuesUpdated: number }> {
118
+ const graph = OrparGraphIntegration.getInstance();
119
+ if (!graph.isEnabled()) {
120
+ return { entitiesCreated: 0, relationshipsCreated: 0, qValuesUpdated: 0 };
121
+ }
122
+
123
+ const extraction = await EntityExtractionService.getInstance().extractFromText(
124
+ channelId,
125
+ reflection
126
+ );
127
+
128
+ const involvedEntityIds = extraction.entities
129
+ .map(entity => entity.id)
130
+ .filter((id): id is string => Boolean(id));
131
+
132
+ return graph.applyReflectionUpdate(channelId, agentId, {
133
+ // Extraction already persisted the entities and relationships it found, so this
134
+ // update only has to attribute the outcome to them.
135
+ newEntities: [],
136
+ newRelationships: [],
137
+ qValueUpdates: [],
138
+ involvedEntityIds,
139
+ taskSuccess
140
+ });
141
+ }
142
+
71
143
  /**
72
144
  * Valid phase transitions
73
145
  */
@@ -898,6 +970,20 @@ IMPORTANT - Parameter format:
898
970
  { learnings: input.learnings, phaseData: { reflection: input.reflection, learnings: input.learnings, expectationsMet: input.expectationsMet, adjustments: input.adjustments } }
899
971
  );
900
972
 
973
+ // Feed the reflection back into the knowledge graph.
974
+ //
975
+ // OrparGraphIntegration.applyReflectionUpdate — which creates entities from what the
976
+ // agent learned and propagates the task outcome as a reward across the entities
977
+ // involved — had no caller anywhere, so kg_get_high_utility_entities ranked entities
978
+ // on Q-values that were never once updated. Reflection is the only phase that knows
979
+ // whether expectations were met, so entity learning belongs here.
980
+ const knowledgeGraph = await applyReflectionToGraph(
981
+ agentId,
982
+ channelId,
983
+ input.reflection,
984
+ input.expectationsMet !== false
985
+ );
986
+
901
987
  return {
902
988
  success: true,
903
989
  phase: 'reflect',
@@ -909,6 +995,7 @@ IMPORTANT - Parameter format:
909
995
  expectationsMet: input.expectationsMet,
910
996
  adjustments: input.adjustments
911
997
  },
998
+ knowledgeGraph,
912
999
  cycleComplete: true,
913
1000
  nextPhase: 'observe',
914
1001
  guidance: getPhaseGuidance('reflect', context?.allowedTools || context?._allowedTools),