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