@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
@@ -18,432 +18,289 @@
18
18
  * @documentation https://mxf-dev.github.io/mxf/
19
19
  */
20
20
 
21
- import { Logger } from '../../../utils/Logger.js';
22
- import { executeShellCommand } from './InfrastructureTools.js';
23
- import { McpToolHandlerContext, McpToolHandlerResult, McpToolResultContent } from '../McpServerTypes.js';
21
+ /**
22
+ * GitTools.ts
23
+ *
24
+ * Git operations, run by shelling out to the `git` binary through
25
+ * executeShellCommand — which validates the command against the security guard
26
+ * and hands the child a stripped environment.
27
+ *
28
+ * Each tool is declared with defineTool: a git command that fails throws a
29
+ * ToolError and comes back as one envelope with `isError: true`, rather than a
30
+ * `{ success: false, error: '...' }` object that reads like a successful result.
31
+ */
24
32
 
25
- const logger = new Logger('info', 'GitTools', 'server');
33
+ import { TOOL_CATEGORIES } from '../../../constants/ToolNames.js';
34
+ import { defineTool, ToolRunContext } from '../defineTool.js';
35
+ import { ToolError } from '../ToolError.js';
36
+ import { executeShellCommand, ShellCommandResult } from './InfrastructureTools.js';
37
+
38
+ /** Working-directory property shared by every git tool's schema. */
39
+ const workingDirectoryProperty = {
40
+ type: 'string',
41
+ description: 'Working directory path (defaults to the server working directory)'
42
+ };
26
43
 
27
44
  /**
28
- * Git Tools for MXF
29
- *
30
- * Provides git version control operations using shell commands
31
- * These tools are placeholders that demonstrate the interface
32
- * Full implementation would integrate with shell_execute tool
45
+ * Run a git subcommand, throwing a ToolError when git reports failure.
46
+ *
47
+ * Non-zero exit is genuine failure for every subcommand used here — none of them
48
+ * use exit codes to signal a non-error condition the way `git diff --quiet` does.
33
49
  */
50
+ async function runGit(
51
+ args: string[],
52
+ workingDirectory: string | undefined,
53
+ context: ToolRunContext
54
+ ): Promise<ShellCommandResult> {
55
+ const result = await executeShellCommand('git', args, {
56
+ context: {
57
+ agentId: context.agentId,
58
+ channelId: context.channelId,
59
+ requestId: context.requestId
60
+ },
61
+ workingDirectory: workingDirectory || process.cwd(),
62
+ captureOutput: true
63
+ });
64
+
65
+ if (result.exitCode !== 0) {
66
+ throw ToolError.executionFailed(
67
+ `git ${args.join(' ')} failed (exit ${result.exitCode}): ` +
68
+ `${result.stderr?.trim() || 'no error output'}`,
69
+ { details: { exitCode: result.exitCode, args } }
70
+ );
71
+ }
34
72
 
35
- export const gitStatusTool = {
73
+ return result;
74
+ }
75
+
76
+ export const gitStatusTool = defineTool<
77
+ { workingDirectory?: string },
78
+ {
79
+ status: string;
80
+ branch: string;
81
+ files: { staged: string[]; modified: string[]; untracked: string[]; deleted: string[] };
82
+ }
83
+ >({
36
84
  name: 'git_status',
37
- description: 'Get git repository status including staged, modified, and untracked files',
85
+ category: TOOL_CATEGORIES.VERSION_CONTROL,
86
+ description: 'Report the current branch plus staged, modified, untracked and deleted files.',
38
87
  inputSchema: {
39
88
  type: 'object',
40
89
  properties: {
41
- workingDirectory: {
42
- type: 'string',
43
- description: 'Working directory path (defaults to current directory)'
44
- }
90
+ workingDirectory: workingDirectoryProperty
45
91
  }
46
92
  },
47
- handler: async (args: {
48
- workingDirectory?: string;
49
- }, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
50
-
51
- try {
52
- // Execute git status --porcelain to get parseable output
53
- const result = await executeShellCommand('git', ['status', '--porcelain', '--branch'], {
54
- workingDirectory: args.workingDirectory || process.cwd(),
55
- captureOutput: true
56
- });
57
-
58
- if (result.exitCode !== 0) {
59
- const content: McpToolResultContent = {
60
- type: 'application/json',
61
- data: {
62
- success: false,
63
- status: '',
64
- files: { staged: [], modified: [], untracked: [], deleted: [] },
65
- branch: 'unknown',
66
- error: result.stderr || 'Git command failed'
67
- }
68
- };
69
- return { content };
93
+ run: async (input, context) => {
94
+ const result = await runGit(['status', '--porcelain', '--branch'], input.workingDirectory, context);
95
+
96
+ const lines = result.stdout?.split('\n').filter(line => line.trim()) ?? [];
97
+ const files = {
98
+ staged: [] as string[],
99
+ modified: [] as string[],
100
+ untracked: [] as string[],
101
+ deleted: [] as string[]
102
+ };
103
+
104
+ let branch = 'unknown';
105
+
106
+ for (const line of lines) {
107
+ if (line.startsWith('## ')) {
108
+ const branchMatch = line.match(/^## (.+?)(?:\.\.\.|\s|$)/);
109
+ if (branchMatch) {
110
+ branch = branchMatch[1];
111
+ }
112
+ continue;
70
113
  }
71
114
 
72
- // Parse the output
73
- const lines = result.stdout?.split('\n').filter(line => line.trim()) || [];
74
- const files = {
75
- staged: [] as string[],
76
- modified: [] as string[],
77
- untracked: [] as string[],
78
- deleted: [] as string[]
79
- };
80
-
81
- let branch = 'unknown';
82
-
83
- for (const line of lines) {
84
- if (line.startsWith('## ')) {
85
- // Branch information
86
- const branchMatch = line.match(/^## (.+?)(?:\.\.\.|\s|$)/);
87
- if (branchMatch) {
88
- branch = branchMatch[1];
89
- }
90
- } else if (line.length >= 2) {
91
- // File status
92
- const statusCode = line.substring(0, 2);
93
- const fileName = line.substring(3);
94
-
95
- // Index status (first character)
96
- if (statusCode[0] === 'A' || statusCode[0] === 'M' || statusCode[0] === 'D') {
97
- files.staged.push(fileName);
98
- }
99
-
100
- // Working tree status (second character)
101
- if (statusCode[1] === 'M') {
102
- files.modified.push(fileName);
103
- } else if (statusCode[1] === 'D') {
104
- files.deleted.push(fileName);
105
- }
106
-
107
- // Untracked files
108
- if (statusCode === '??') {
109
- files.untracked.push(fileName);
110
- }
111
- }
115
+ if (line.length < 2) {
116
+ continue;
112
117
  }
113
118
 
114
- const content: McpToolResultContent = {
115
- type: 'application/json',
116
- data: {
117
- success: true,
118
- status: result.stdout || '',
119
- files,
120
- branch,
121
- error: null
122
- }
123
- };
124
- return { content };
125
- } catch (error) {
126
- logger.error('Git status failed', { error });
127
- const content: McpToolResultContent = {
128
- type: 'application/json',
129
- data: {
130
- success: false,
131
- status: '',
132
- files: { staged: [], modified: [], untracked: [], deleted: [] },
133
- branch: 'unknown',
134
- error: error instanceof Error ? error.message : String(error)
135
- }
136
- };
137
- return { content };
119
+ const statusCode = line.substring(0, 2);
120
+ const fileName = line.substring(3);
121
+
122
+ // Porcelain format: first char is the index state, second is the
123
+ // working-tree state. '??' in both positions means untracked.
124
+ if (statusCode === '??') {
125
+ files.untracked.push(fileName);
126
+ continue;
127
+ }
128
+ if (statusCode[0] === 'A' || statusCode[0] === 'M' || statusCode[0] === 'D') {
129
+ files.staged.push(fileName);
130
+ }
131
+ if (statusCode[1] === 'M') {
132
+ files.modified.push(fileName);
133
+ } else if (statusCode[1] === 'D') {
134
+ files.deleted.push(fileName);
135
+ }
138
136
  }
137
+
138
+ return {
139
+ status: result.stdout ?? '',
140
+ branch,
141
+ files
142
+ };
139
143
  }
140
- };
144
+ });
141
145
 
142
- export const gitAddTool = {
146
+ export const gitAddTool = defineTool<
147
+ { files: string[]; workingDirectory?: string },
148
+ { stagedCount: number; files: string[] }
149
+ >({
143
150
  name: 'git_add',
144
- description: 'Stage files for commit',
151
+ category: TOOL_CATEGORIES.VERSION_CONTROL,
152
+ description: 'Stage files for commit. Pass "." to stage everything.',
145
153
  inputSchema: {
146
154
  type: 'object',
147
155
  properties: {
148
156
  files: {
149
157
  type: 'array',
150
158
  items: { type: 'string' },
159
+ minItems: 1,
151
160
  description: 'Files to stage (use "." for all files)'
152
161
  },
153
- workingDirectory: {
154
- type: 'string',
155
- description: 'Working directory path (defaults to current directory)'
156
- }
162
+ workingDirectory: workingDirectoryProperty
157
163
  },
158
164
  required: ['files']
159
165
  },
160
- handler: async (args: {
161
- files: string[];
162
- workingDirectory?: string;
163
- }, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
164
-
165
- try {
166
- const result = await executeShellCommand('git', ['add', ...args.files], {
167
- workingDirectory: args.workingDirectory || process.cwd(),
168
- captureOutput: true
169
- });
166
+ run: async (input, context) => {
167
+ await runGit(['add', ...input.files], input.workingDirectory, context);
170
168
 
171
- if (result.exitCode !== 0) {
172
- const content: McpToolResultContent = {
173
- type: 'application/json',
174
- data: {
175
- success: false,
176
- message: result.stderr || 'Git add failed',
177
- error: result.stderr || 'Git add command failed'
178
- }
179
- };
180
- return { content };
181
- }
182
-
183
- const content: McpToolResultContent = {
184
- type: 'application/json',
185
- data: {
186
- success: true,
187
- message: `Successfully staged ${args.files.length} file(s)`,
188
- error: null
189
- }
190
- };
191
- return { content };
192
- } catch (error) {
193
- logger.error('Git add failed', { error });
194
- const content: McpToolResultContent = {
195
- type: 'application/json',
196
- data: {
197
- success: false,
198
- message: '',
199
- error: error instanceof Error ? error.message : String(error)
200
- }
201
- };
202
- return { content };
203
- }
169
+ return {
170
+ stagedCount: input.files.length,
171
+ files: input.files
172
+ };
204
173
  }
205
- };
174
+ });
206
175
 
207
- export const gitCommitTool = {
176
+ export const gitCommitTool = defineTool<
177
+ { message: string; workingDirectory?: string },
178
+ { message: string; commitHash: string }
179
+ >({
208
180
  name: 'git_commit',
209
- description: 'Create a git commit with a message',
181
+ category: TOOL_CATEGORIES.VERSION_CONTROL,
182
+ description: 'Create a commit from the staged changes.',
210
183
  inputSchema: {
211
184
  type: 'object',
212
185
  properties: {
213
186
  message: {
214
187
  type: 'string',
188
+ minLength: 1,
215
189
  description: 'Commit message'
216
190
  },
217
- workingDirectory: {
218
- type: 'string',
219
- description: 'Working directory path (defaults to current directory)'
220
- }
191
+ workingDirectory: workingDirectoryProperty
221
192
  },
222
193
  required: ['message']
223
194
  },
224
- handler: async (args: {
225
- message: string;
226
- workingDirectory?: string;
227
- }, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
228
-
229
- try {
230
- const result = await executeShellCommand('git', ['commit', '-m', args.message], {
231
- workingDirectory: args.workingDirectory || process.cwd(),
232
- captureOutput: true
233
- });
234
-
235
- if (result.exitCode !== 0) {
236
- const content: McpToolResultContent = {
237
- type: 'application/json',
238
- data: {
239
- success: false,
240
- message: args.message,
241
- error: result.stderr || 'Git commit failed'
242
- }
243
- };
244
- return { content };
245
- }
246
-
247
- const content: McpToolResultContent = {
248
- type: 'application/json',
249
- data: {
250
- success: true,
251
- message: args.message,
252
- commitHash: result.stdout?.match(/\[(.+?)\]/)?.[1] || 'unknown',
253
- error: null
254
- }
255
- };
256
- return { content };
257
- } catch (error) {
258
- logger.error('Git commit failed', { error });
259
- const content: McpToolResultContent = {
260
- type: 'application/json',
261
- data: {
262
- success: false,
263
- message: args.message,
264
- error: error instanceof Error ? error.message : String(error)
265
- }
266
- };
267
- return { content };
195
+ run: async (input, context) => {
196
+ const result = await runGit(['commit', '-m', input.message], input.workingDirectory, context);
197
+
198
+ // git prints `[branch abc1234] subject` on success.
199
+ const commitHash = result.stdout?.match(/\[[^\]]*\s([0-9a-f]{7,40})\]/)?.[1];
200
+ if (!commitHash) {
201
+ throw ToolError.executionFailed(
202
+ `git commit succeeded but its output did not contain a commit hash: ${result.stdout?.trim()}`
203
+ );
268
204
  }
205
+
206
+ return {
207
+ message: input.message,
208
+ commitHash
209
+ };
269
210
  }
270
- };
211
+ });
271
212
 
272
- export const gitDiffTool = {
213
+ export const gitDiffTool = defineTool<
214
+ { staged?: boolean; workingDirectory?: string },
215
+ { diff: string; filesChanged: number; insertions: number; deletions: number }
216
+ >({
273
217
  name: 'git_diff',
274
- description: 'Show differences between commits, commit and working tree, etc',
218
+ category: TOOL_CATEGORIES.VERSION_CONTROL,
219
+ description: 'Show the working-tree diff, or the staged diff when staged is true.',
275
220
  inputSchema: {
276
221
  type: 'object',
277
222
  properties: {
278
223
  staged: {
279
224
  type: 'boolean',
280
225
  default: false,
281
- description: 'Show staged changes (--cached)'
226
+ description: 'Show staged changes (--cached) instead of working-tree changes'
282
227
  },
283
- workingDirectory: {
284
- type: 'string',
285
- description: 'Working directory path (defaults to current directory)'
286
- }
228
+ workingDirectory: workingDirectoryProperty
287
229
  }
288
230
  },
289
- handler: async (args: {
290
- staged?: boolean;
291
- workingDirectory?: string;
292
- }, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
293
-
294
- try {
295
- const gitArgs = ['diff'];
296
- if (args.staged) {
297
- gitArgs.push('--cached');
298
- }
299
- gitArgs.push('--stat');
300
-
301
- const result = await executeShellCommand('git', gitArgs, {
302
- workingDirectory: args.workingDirectory || process.cwd(),
303
- captureOutput: true
304
- });
305
-
306
- if (result.exitCode !== 0) {
307
- const content: McpToolResultContent = {
308
- type: 'application/json',
309
- data: {
310
- success: false,
311
- diff: '',
312
- filesChanged: 0,
313
- insertions: 0,
314
- deletions: 0,
315
- error: result.stderr || 'Git diff failed'
316
- }
317
- };
318
- return { content };
319
- }
320
-
321
- // Get the actual diff content
322
- const diffResult = await executeShellCommand('git', args.staged ? ['diff', '--cached'] : ['diff'], {
323
- workingDirectory: args.workingDirectory || process.cwd(),
324
- captureOutput: true
325
- });
326
-
327
- // Parse stats from output
328
- const statsMatch = result.stdout?.match(/(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(\-\))?/);
329
-
330
- const content: McpToolResultContent = {
331
- type: 'application/json',
332
- data: {
333
- success: true,
334
- diff: diffResult.stdout || '',
335
- filesChanged: statsMatch ? parseInt(statsMatch[1]) : 0,
336
- insertions: statsMatch ? parseInt(statsMatch[2] || '0') : 0,
337
- deletions: statsMatch ? parseInt(statsMatch[3] || '0') : 0,
338
- error: null
339
- }
340
- };
341
- return { content };
342
- } catch (error) {
343
- logger.error('Git diff failed', { error });
344
- const content: McpToolResultContent = {
345
- type: 'application/json',
346
- data: {
347
- success: false,
348
- diff: '',
349
- filesChanged: 0,
350
- insertions: 0,
351
- deletions: 0,
352
- error: error instanceof Error ? error.message : String(error)
353
- }
354
- };
355
- return { content };
356
- }
231
+ run: async (input, context) => {
232
+ const baseArgs = input.staged ? ['diff', '--cached'] : ['diff'];
233
+
234
+ const statResult = await runGit([...baseArgs, '--stat'], input.workingDirectory, context);
235
+ const diffResult = await runGit(baseArgs, input.workingDirectory, context);
236
+
237
+ const statsMatch = statResult.stdout?.match(
238
+ /(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/
239
+ );
240
+
241
+ return {
242
+ diff: diffResult.stdout ?? '',
243
+ filesChanged: statsMatch ? parseInt(statsMatch[1], 10) : 0,
244
+ insertions: statsMatch ? parseInt(statsMatch[2] ?? '0', 10) : 0,
245
+ deletions: statsMatch ? parseInt(statsMatch[3] ?? '0', 10) : 0
246
+ };
357
247
  }
358
- };
248
+ });
359
249
 
360
- export const gitLogTool = {
250
+ export const gitLogTool = defineTool<
251
+ { maxCount?: number; workingDirectory?: string },
252
+ { commits: Array<{ hash: string; subject: string; author: string; date: string; refs: string }> }
253
+ >({
361
254
  name: 'git_log',
362
- description: 'Show commit logs',
255
+ category: TOOL_CATEGORIES.VERSION_CONTROL,
256
+ description: 'List recent commits with hash, subject, author and date.',
363
257
  inputSchema: {
364
258
  type: 'object',
365
259
  properties: {
366
260
  maxCount: {
367
261
  type: 'number',
368
262
  default: 10,
263
+ minimum: 1,
264
+ maximum: 500,
369
265
  description: 'Maximum number of commits to show'
370
266
  },
371
- workingDirectory: {
372
- type: 'string',
373
- description: 'Working directory path (defaults to current directory)'
374
- }
267
+ workingDirectory: workingDirectoryProperty
375
268
  }
376
269
  },
377
- handler: async (args: {
378
- maxCount?: number;
379
- workingDirectory?: string;
380
- }, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
381
-
382
- try {
383
- const result = await executeShellCommand('git', [
384
- 'log',
385
- '--oneline',
386
- '--format=%H|%s|%an|%ad|%d',
387
- '--date=iso',
388
- `-n${args.maxCount || 10}`
389
- ], {
390
- workingDirectory: args.workingDirectory || process.cwd(),
391
- captureOutput: true
392
- });
393
-
394
- if (result.exitCode !== 0) {
395
- const content: McpToolResultContent = {
396
- type: 'application/json',
397
- data: {
398
- success: false,
399
- commits: [],
400
- error: result.stderr || 'Git log failed'
401
- }
270
+ run: async (input, context) => {
271
+ const maxCount = input.maxCount ?? 10;
272
+
273
+ const result = await runGit(
274
+ ['log', '--format=%H|%s|%an|%ad|%d', '--date=iso', `-n${maxCount}`],
275
+ input.workingDirectory,
276
+ context
277
+ );
278
+
279
+ const commits = (result.stdout ?? '')
280
+ .split('\n')
281
+ .filter(line => line.trim())
282
+ .map(line => {
283
+ const [hash, subject, author, date, refs] = line.split('|');
284
+ return {
285
+ hash,
286
+ subject,
287
+ author,
288
+ date,
289
+ refs: refs ? refs.trim() : ''
402
290
  };
403
- return { content };
404
- }
291
+ });
405
292
 
406
- // Parse commits
407
- const commits = result.stdout?.split('\n')
408
- .filter(line => line.trim())
409
- .map(line => {
410
- const [hash, subject, author, date, refs] = line.split('|');
411
- return {
412
- hash,
413
- subject,
414
- author,
415
- date,
416
- refs: refs ? refs.trim() : ''
417
- };
418
- }) || [];
419
-
420
- const content: McpToolResultContent = {
421
- type: 'application/json',
422
- data: {
423
- success: true,
424
- commits,
425
- error: null
426
- }
427
- };
428
- return { content };
429
- } catch (error) {
430
- logger.error('Git log failed', { error });
431
- const content: McpToolResultContent = {
432
- type: 'application/json',
433
- data: {
434
- success: false,
435
- commits: [],
436
- error: error instanceof Error ? error.message : String(error)
437
- }
438
- };
439
- return { content };
440
- }
293
+ return { commits };
441
294
  }
442
- };
295
+ });
443
296
 
444
- export const gitBranchTool = {
297
+ export const gitBranchTool = defineTool<
298
+ { action?: 'list' | 'create' | 'delete' | 'switch'; branchName?: string; workingDirectory?: string },
299
+ { action: string; currentBranch: string; branches: string[] }
300
+ >({
445
301
  name: 'git_branch',
446
- description: 'List, create, or delete branches',
302
+ category: TOOL_CATEGORIES.VERSION_CONTROL,
303
+ description: 'List branches, or create, delete, or switch to a branch.',
447
304
  inputSchema: {
448
305
  type: 'object',
449
306
  properties: {
@@ -455,122 +312,67 @@ export const gitBranchTool = {
455
312
  },
456
313
  branchName: {
457
314
  type: 'string',
458
- description: 'Branch name (required for create, delete, switch actions)'
315
+ description: 'Branch name (required for create, delete and switch)'
459
316
  },
460
- workingDirectory: {
461
- type: 'string',
462
- description: 'Working directory path (defaults to current directory)'
463
- }
317
+ workingDirectory: workingDirectoryProperty
464
318
  }
465
319
  },
466
- handler: async (args: {
467
- action?: 'list' | 'create' | 'delete' | 'switch';
468
- branchName?: string;
469
- workingDirectory?: string;
470
- }, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
471
-
472
- try {
473
- let result;
474
-
475
- switch (args.action) {
476
- case 'create':
477
- if (!args.branchName) {
478
- throw new Error('Branch name required for create action');
479
- }
480
- result = await executeShellCommand('git', ['branch', args.branchName], {
481
- workingDirectory: args.workingDirectory || process.cwd(),
482
- captureOutput: true
483
- });
484
- break;
485
-
486
- case 'delete':
487
- if (!args.branchName) {
488
- throw new Error('Branch name required for delete action');
489
- }
490
- result = await executeShellCommand('git', ['branch', '-d', args.branchName], {
491
- workingDirectory: args.workingDirectory || process.cwd(),
492
- captureOutput: true
493
- });
494
- break;
495
-
496
- case 'switch':
497
- if (!args.branchName) {
498
- throw new Error('Branch name required for switch action');
499
- }
500
- result = await executeShellCommand('git', ['switch', args.branchName], {
501
- workingDirectory: args.workingDirectory || process.cwd(),
502
- captureOutput: true
503
- });
504
- break;
505
-
506
- case 'list':
507
- default:
508
- result = await executeShellCommand('git', ['branch', '-a'], {
509
- workingDirectory: args.workingDirectory || process.cwd(),
510
- captureOutput: true
511
- });
512
- break;
513
- }
320
+ run: async (input, context) => {
321
+ const action = input.action ?? 'list';
514
322
 
515
- if (result.exitCode !== 0) {
516
- const content: McpToolResultContent = {
517
- type: 'application/json',
518
- data: {
519
- success: false,
520
- currentBranch: '',
521
- branches: [],
522
- error: result.stderr || 'Git branch command failed'
523
- }
524
- };
525
- return { content };
526
- }
527
-
528
- // Get current branch
529
- const currentBranchResult = await executeShellCommand('git', ['branch', '--show-current'], {
530
- workingDirectory: args.workingDirectory || process.cwd(),
531
- captureOutput: true
532
- });
323
+ // create/delete/switch are meaningless without a name — reject before
324
+ // shelling out, so the model gets a precise correction.
325
+ if (action !== 'list' && !input.branchName) {
326
+ throw ToolError.invalidInput(`branchName is required for the "${action}" action.`);
327
+ }
533
328
 
534
- const currentBranch = currentBranchResult.stdout?.trim() || '';
535
-
536
- // Parse branches for list action
537
- let branches: string[] = [];
538
- if (args.action === 'list' || !args.action) {
539
- branches = result.stdout?.split('\n')
540
- .filter(line => line.trim())
541
- .map(line => line.replace(/^[\s\*]+/, '').trim())
542
- .filter(branch => branch) || [];
329
+ let listOutput = '';
330
+
331
+ switch (action) {
332
+ case 'create':
333
+ await runGit(['branch', input.branchName!], input.workingDirectory, context);
334
+ break;
335
+ case 'delete':
336
+ await runGit(['branch', '-d', input.branchName!], input.workingDirectory, context);
337
+ break;
338
+ case 'switch':
339
+ await runGit(['switch', input.branchName!], input.workingDirectory, context);
340
+ break;
341
+ case 'list':
342
+ default: {
343
+ const result = await runGit(['branch', '-a'], input.workingDirectory, context);
344
+ listOutput = result.stdout ?? '';
345
+ break;
543
346
  }
544
-
545
- const content: McpToolResultContent = {
546
- type: 'application/json',
547
- data: {
548
- success: true,
549
- currentBranch,
550
- branches,
551
- error: null
552
- }
553
- };
554
- return { content };
555
- } catch (error) {
556
- logger.error('Git branch failed', { error });
557
- const content: McpToolResultContent = {
558
- type: 'application/json',
559
- data: {
560
- success: false,
561
- currentBranch: '',
562
- branches: [],
563
- error: error instanceof Error ? error.message : String(error)
564
- }
565
- };
566
- return { content };
567
347
  }
348
+
349
+ const currentBranchResult = await runGit(
350
+ ['branch', '--show-current'],
351
+ input.workingDirectory,
352
+ context
353
+ );
354
+
355
+ const branches = listOutput
356
+ .split('\n')
357
+ .filter(line => line.trim())
358
+ .map(line => line.replace(/^[\s*]+/, '').trim())
359
+ .filter(branch => branch.length > 0);
360
+
361
+ return {
362
+ action,
363
+ currentBranch: currentBranchResult.stdout?.trim() ?? '',
364
+ branches
365
+ };
568
366
  }
569
- };
367
+ });
570
368
 
571
- export const gitPushTool = {
369
+ export const gitPushTool = defineTool<
370
+ { remote?: string; branch?: string; workingDirectory?: string },
371
+ { remote: string; branch?: string; output: string }
372
+ >({
572
373
  name: 'git_push',
573
- description: 'Push commits to remote repository',
374
+ category: TOOL_CATEGORIES.VERSION_CONTROL,
375
+ description: 'Push commits to a remote repository.',
574
376
  inputSchema: {
575
377
  type: 'object',
576
378
  properties: {
@@ -581,73 +383,36 @@ export const gitPushTool = {
581
383
  },
582
384
  branch: {
583
385
  type: 'string',
584
- description: 'Branch to push (defaults to current branch)'
386
+ description: 'Branch to push (defaults to the current branch)'
585
387
  },
586
- workingDirectory: {
587
- type: 'string',
588
- description: 'Working directory path (defaults to current directory)'
589
- }
388
+ workingDirectory: workingDirectoryProperty
590
389
  }
591
390
  },
592
- handler: async (args: {
593
- remote?: string;
594
- branch?: string;
595
- workingDirectory?: string;
596
- }, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
597
-
598
- try {
599
- const gitArgs = ['push'];
600
- if (args.remote) {
601
- gitArgs.push(args.remote);
602
- }
603
- if (args.branch) {
604
- gitArgs.push(args.branch);
605
- }
606
-
607
- const result = await executeShellCommand('git', gitArgs, {
608
- workingDirectory: args.workingDirectory || process.cwd(),
609
- captureOutput: true
610
- });
391
+ run: async (input, context) => {
392
+ const remote = input.remote ?? 'origin';
393
+ const args = ['push', remote];
394
+ if (input.branch) {
395
+ args.push(input.branch);
396
+ }
611
397
 
612
- if (result.exitCode !== 0) {
613
- const content: McpToolResultContent = {
614
- type: 'application/json',
615
- data: {
616
- success: false,
617
- message: result.stderr || 'Git push failed',
618
- error: result.stderr || 'Git push command failed'
619
- }
620
- };
621
- return { content };
622
- }
398
+ const result = await runGit(args, input.workingDirectory, context);
623
399
 
624
- const content: McpToolResultContent = {
625
- type: 'application/json',
626
- data: {
627
- success: true,
628
- message: result.stdout || 'Push completed successfully',
629
- error: null
630
- }
631
- };
632
- return { content };
633
- } catch (error) {
634
- logger.error('Git push failed', { error });
635
- const content: McpToolResultContent = {
636
- type: 'application/json',
637
- data: {
638
- success: false,
639
- message: '',
640
- error: error instanceof Error ? error.message : String(error)
641
- }
642
- };
643
- return { content };
644
- }
400
+ // git push reports progress on stderr even when it succeeds, so include both.
401
+ return {
402
+ remote,
403
+ branch: input.branch,
404
+ output: [result.stdout, result.stderr].filter(Boolean).join('\n').trim()
405
+ };
645
406
  }
646
- };
407
+ });
647
408
 
648
- export const gitPullTool = {
409
+ export const gitPullTool = defineTool<
410
+ { remote?: string; workingDirectory?: string },
411
+ { remote: string; output: string }
412
+ >({
649
413
  name: 'git_pull',
650
- description: 'Pull changes from remote repository',
414
+ category: TOOL_CATEGORIES.VERSION_CONTROL,
415
+ description: 'Pull changes from a remote repository.',
651
416
  inputSchema: {
652
417
  type: 'object',
653
418
  properties: {
@@ -656,65 +421,21 @@ export const gitPullTool = {
656
421
  default: 'origin',
657
422
  description: 'Remote name'
658
423
  },
659
- workingDirectory: {
660
- type: 'string',
661
- description: 'Working directory path (defaults to current directory)'
662
- }
424
+ workingDirectory: workingDirectoryProperty
663
425
  }
664
426
  },
665
- handler: async (args: {
666
- remote?: string;
667
- workingDirectory?: string;
668
- }, context: McpToolHandlerContext): Promise<McpToolHandlerResult> => {
669
-
670
- try {
671
- const gitArgs = ['pull'];
672
- if (args.remote) {
673
- gitArgs.push(args.remote);
674
- }
675
-
676
- const result = await executeShellCommand('git', gitArgs, {
677
- workingDirectory: args.workingDirectory || process.cwd(),
678
- captureOutput: true
679
- });
427
+ run: async (input, context) => {
428
+ const remote = input.remote ?? 'origin';
680
429
 
681
- if (result.exitCode !== 0) {
682
- const content: McpToolResultContent = {
683
- type: 'application/json',
684
- data: {
685
- success: false,
686
- message: result.stderr || 'Git pull failed',
687
- error: result.stderr || 'Git pull command failed'
688
- }
689
- };
690
- return { content };
691
- }
430
+ const result = await runGit(['pull', remote], input.workingDirectory, context);
692
431
 
693
- const content: McpToolResultContent = {
694
- type: 'application/json',
695
- data: {
696
- success: true,
697
- message: result.stdout || 'Pull completed successfully',
698
- error: null
699
- }
700
- };
701
- return { content };
702
- } catch (error) {
703
- logger.error('Git pull failed', { error });
704
- const content: McpToolResultContent = {
705
- type: 'application/json',
706
- data: {
707
- success: false,
708
- message: '',
709
- error: error instanceof Error ? error.message : String(error)
710
- }
711
- };
712
- return { content };
713
- }
432
+ return {
433
+ remote,
434
+ output: [result.stdout, result.stderr].filter(Boolean).join('\n').trim()
435
+ };
714
436
  }
715
- };
437
+ });
716
438
 
717
- // Export all git tools
718
439
  export const gitTools = [
719
440
  gitStatusTool,
720
441
  gitAddTool,