@within-7/minto 0.1.7 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (601) hide show
  1. package/cli.js +155 -37
  2. package/dist/Tool.js +38 -0
  3. package/dist/Tool.js.map +3 -3
  4. package/dist/commands/agents/AgentsCommand.js +73 -49
  5. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  6. package/dist/commands/agents/constants.js +1 -1
  7. package/dist/commands/agents/constants.js.map +1 -1
  8. package/dist/commands/agents/index.js +1 -1
  9. package/dist/commands/bug.js +74 -7
  10. package/dist/commands/bug.js.map +3 -3
  11. package/dist/commands/clear.js +3 -0
  12. package/dist/commands/clear.js.map +2 -2
  13. package/dist/commands/compact.js +37 -0
  14. package/dist/commands/compact.js.map +2 -2
  15. package/dist/commands/context.js +85 -0
  16. package/dist/commands/context.js.map +7 -0
  17. package/dist/commands/ctx_viz.js +18 -10
  18. package/dist/commands/ctx_viz.js.map +2 -2
  19. package/dist/commands/doctor.js +158 -12
  20. package/dist/commands/doctor.js.map +2 -2
  21. package/dist/commands/export.js +157 -0
  22. package/dist/commands/export.js.map +7 -0
  23. package/dist/commands/mcp-interactive.js +28 -18
  24. package/dist/commands/mcp-interactive.js.map +2 -2
  25. package/dist/commands/model.js +9 -7
  26. package/dist/commands/model.js.map +2 -2
  27. package/dist/commands/permissions.js +87 -0
  28. package/dist/commands/permissions.js.map +7 -0
  29. package/dist/commands/plugin/AddMarketplaceForm.js +3 -2
  30. package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
  31. package/dist/commands/plugin/ConfirmDialog.js +2 -1
  32. package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
  33. package/dist/commands/plugin/ErrorView.js +2 -1
  34. package/dist/commands/plugin/ErrorView.js.map +2 -2
  35. package/dist/commands/plugin/InstalledPluginsByMarketplace.js +5 -4
  36. package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
  37. package/dist/commands/plugin/InstalledPluginsManager.js +5 -4
  38. package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
  39. package/dist/commands/plugin/MainMenu.js +2 -1
  40. package/dist/commands/plugin/MainMenu.js.map +2 -2
  41. package/dist/commands/plugin/MarketplaceManager.js +5 -4
  42. package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
  43. package/dist/commands/plugin/MarketplaceSelector.js +4 -3
  44. package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
  45. package/dist/commands/plugin/PlaceholderScreen.js +3 -2
  46. package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
  47. package/dist/commands/plugin/PluginBrowser.js +6 -5
  48. package/dist/commands/plugin/PluginBrowser.js.map +2 -2
  49. package/dist/commands/plugin/PluginDetailsInstall.js +5 -4
  50. package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
  51. package/dist/commands/plugin/PluginDetailsManage.js +4 -3
  52. package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
  53. package/dist/commands/plugin.js +16 -15
  54. package/dist/commands/plugin.js.map +2 -2
  55. package/dist/commands/quit.js +3 -1
  56. package/dist/commands/quit.js.map +2 -2
  57. package/dist/commands/sandbox.js +105 -0
  58. package/dist/commands/sandbox.js.map +7 -0
  59. package/dist/commands/setup.js +2 -1
  60. package/dist/commands/setup.js.map +2 -2
  61. package/dist/commands/status.js +59 -0
  62. package/dist/commands/status.js.map +7 -0
  63. package/dist/commands/tasks.js +108 -0
  64. package/dist/commands/tasks.js.map +7 -0
  65. package/dist/commands/todos.js +123 -0
  66. package/dist/commands/todos.js.map +7 -0
  67. package/dist/commands/undo.js +245 -0
  68. package/dist/commands/undo.js.map +7 -0
  69. package/dist/commands.js +22 -2
  70. package/dist/commands.js.map +2 -2
  71. package/dist/components/AgentThinkingBlock.js +10 -18
  72. package/dist/components/AgentThinkingBlock.js.map +2 -2
  73. package/dist/components/AsciiLogo.js +7 -8
  74. package/dist/components/AsciiLogo.js.map +2 -2
  75. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
  76. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
  77. package/dist/components/AskUserQuestionDialog/QuestionView.js +2 -1
  78. package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
  79. package/dist/components/BackgroundTasksPanel.js +78 -29
  80. package/dist/components/BackgroundTasksPanel.js.map +2 -2
  81. package/dist/components/BashStreamingProgress.js +24 -0
  82. package/dist/components/BashStreamingProgress.js.map +7 -0
  83. package/dist/components/CollapsibleHint.js +15 -0
  84. package/dist/components/CollapsibleHint.js.map +7 -0
  85. package/dist/components/Config.js +3 -2
  86. package/dist/components/Config.js.map +2 -2
  87. package/dist/components/ConsoleOAuthFlow.js +2 -1
  88. package/dist/components/ConsoleOAuthFlow.js.map +2 -2
  89. package/dist/components/Cost.js +2 -1
  90. package/dist/components/Cost.js.map +2 -2
  91. package/dist/components/FileEditToolUpdatedMessage.js +1 -1
  92. package/dist/components/FileEditToolUpdatedMessage.js.map +2 -2
  93. package/dist/components/HeaderBar.js +13 -8
  94. package/dist/components/HeaderBar.js.map +2 -2
  95. package/dist/components/HistorySearchOverlay.js +4 -3
  96. package/dist/components/HistorySearchOverlay.js.map +2 -2
  97. package/dist/components/HotkeyHelpPanel.js +134 -0
  98. package/dist/components/HotkeyHelpPanel.js.map +7 -0
  99. package/dist/components/InvalidConfigDialog.js +2 -1
  100. package/dist/components/InvalidConfigDialog.js.map +2 -2
  101. package/dist/components/Logo.js +24 -68
  102. package/dist/components/Logo.js.map +2 -2
  103. package/dist/components/MCPServerApprovalDialog.js +2 -1
  104. package/dist/components/MCPServerApprovalDialog.js.map +2 -2
  105. package/dist/components/MCPServerDialogCopy.js +2 -1
  106. package/dist/components/MCPServerDialogCopy.js.map +2 -2
  107. package/dist/components/MCPServerMultiselectDialog.js +2 -1
  108. package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
  109. package/dist/components/Message.js +23 -7
  110. package/dist/components/Message.js.map +3 -3
  111. package/dist/components/MessageSelector.js +4 -3
  112. package/dist/components/MessageSelector.js.map +2 -2
  113. package/dist/components/ModeIndicator.js +2 -1
  114. package/dist/components/ModeIndicator.js.map +2 -2
  115. package/dist/components/ModelConfig.js +20 -6
  116. package/dist/components/ModelConfig.js.map +2 -2
  117. package/dist/components/ModelListManager.js +7 -6
  118. package/dist/components/ModelListManager.js.map +2 -2
  119. package/dist/components/ModelSelector/ModelSelector.js +27 -14
  120. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  121. package/dist/components/Onboarding.js +22 -16
  122. package/dist/components/Onboarding.js.map +2 -2
  123. package/dist/components/OperationSummary.js +130 -0
  124. package/dist/components/OperationSummary.js.map +7 -0
  125. package/dist/components/ProgressBar.js +74 -0
  126. package/dist/components/ProgressBar.js.map +7 -0
  127. package/dist/components/PromptInput.js +210 -87
  128. package/dist/components/PromptInput.js.map +2 -2
  129. package/dist/components/RequestStatusIndicator.js +194 -0
  130. package/dist/components/RequestStatusIndicator.js.map +7 -0
  131. package/dist/components/SensitiveFileWarning.js +31 -0
  132. package/dist/components/SensitiveFileWarning.js.map +7 -0
  133. package/dist/components/Spinner.js +141 -27
  134. package/dist/components/Spinner.js.map +2 -2
  135. package/dist/components/SpinnerSymbol.js +21 -27
  136. package/dist/components/SpinnerSymbol.js.map +2 -2
  137. package/dist/components/StreamingBashOutput.js +9 -8
  138. package/dist/components/StreamingBashOutput.js.map +2 -2
  139. package/dist/components/StructuredDiff.js +6 -8
  140. package/dist/components/StructuredDiff.js.map +2 -2
  141. package/dist/components/SubagentBlock.js +5 -3
  142. package/dist/components/SubagentBlock.js.map +2 -2
  143. package/dist/components/SubagentProgress.js +17 -15
  144. package/dist/components/SubagentProgress.js.map +2 -2
  145. package/dist/components/TaskCard.js +30 -24
  146. package/dist/components/TaskCard.js.map +2 -2
  147. package/dist/components/TextInput.js +9 -1
  148. package/dist/components/TextInput.js.map +2 -2
  149. package/dist/components/TodoChangeBlock.js +1 -1
  150. package/dist/components/TodoChangeBlock.js.map +2 -2
  151. package/dist/components/TodoPanel.js +140 -31
  152. package/dist/components/TodoPanel.js.map +3 -3
  153. package/dist/components/TokenCounter.js +74 -0
  154. package/dist/components/TokenCounter.js.map +7 -0
  155. package/dist/components/TokenWarning.js +2 -1
  156. package/dist/components/TokenWarning.js.map +2 -2
  157. package/dist/components/ToolUseLoader.js +2 -2
  158. package/dist/components/ToolUseLoader.js.map +2 -2
  159. package/dist/components/TreeConnector.js +26 -0
  160. package/dist/components/TreeConnector.js.map +7 -0
  161. package/dist/components/TrustDialog.js +2 -1
  162. package/dist/components/TrustDialog.js.map +2 -2
  163. package/dist/components/TurnCompletionIndicator.js +18 -0
  164. package/dist/components/TurnCompletionIndicator.js.map +7 -0
  165. package/dist/components/binary-feedback/BinaryFeedbackView.js +2 -1
  166. package/dist/components/binary-feedback/BinaryFeedbackView.js.map +2 -2
  167. package/dist/components/messages/AssistantTextMessage.js +20 -9
  168. package/dist/components/messages/AssistantTextMessage.js.map +2 -2
  169. package/dist/components/messages/AssistantThinkingMessage.js +18 -3
  170. package/dist/components/messages/AssistantThinkingMessage.js.map +2 -2
  171. package/dist/components/messages/AssistantToolUseMessage.js +17 -10
  172. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  173. package/dist/components/messages/GroupRenderer.js +54 -0
  174. package/dist/components/messages/GroupRenderer.js.map +7 -0
  175. package/dist/components/messages/NestedTasksPreview.js +24 -0
  176. package/dist/components/messages/NestedTasksPreview.js.map +7 -0
  177. package/dist/components/messages/ParallelTasksGroupView.js +93 -0
  178. package/dist/components/messages/ParallelTasksGroupView.js.map +7 -0
  179. package/dist/components/messages/TaskInModuleView.js +218 -0
  180. package/dist/components/messages/TaskInModuleView.js.map +7 -0
  181. package/dist/components/messages/TaskOutputContent.js +56 -0
  182. package/dist/components/messages/TaskOutputContent.js.map +7 -0
  183. package/dist/components/messages/UserPromptMessage.js +2 -2
  184. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  185. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +2 -3
  186. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
  187. package/dist/components/permissions/FallbackPermissionRequest.js +4 -4
  188. package/dist/components/permissions/FallbackPermissionRequest.js.map +2 -2
  189. package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js +4 -4
  190. package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js.map +2 -2
  191. package/dist/constants/colors.js +120 -54
  192. package/dist/constants/colors.js.map +2 -2
  193. package/dist/constants/formatRules.js +102 -0
  194. package/dist/constants/formatRules.js.map +7 -0
  195. package/dist/constants/prompts.js +12 -34
  196. package/dist/constants/prompts.js.map +2 -2
  197. package/dist/constants/symbols.js +64 -6
  198. package/dist/constants/symbols.js.map +2 -2
  199. package/dist/constants/timing.js +5 -0
  200. package/dist/constants/timing.js.map +2 -2
  201. package/dist/constants/toolInputExamples.js +84 -0
  202. package/dist/constants/toolInputExamples.js.map +7 -0
  203. package/dist/core/backupManager.js +321 -0
  204. package/dist/core/backupManager.js.map +7 -0
  205. package/dist/core/config/defaults.js +84 -0
  206. package/dist/core/config/defaults.js.map +7 -0
  207. package/dist/core/config/index.js +111 -0
  208. package/dist/core/config/index.js.map +7 -0
  209. package/dist/core/config/loader.js +221 -0
  210. package/dist/core/config/loader.js.map +7 -0
  211. package/dist/core/config/migrations.js +128 -0
  212. package/dist/core/config/migrations.js.map +7 -0
  213. package/dist/core/config/schema.js +178 -0
  214. package/dist/core/config/schema.js.map +7 -0
  215. package/dist/core/costTracker.js +129 -0
  216. package/dist/core/costTracker.js.map +7 -0
  217. package/dist/core/gitAutoCommit.js +287 -0
  218. package/dist/core/gitAutoCommit.js.map +7 -0
  219. package/dist/core/index.js +8 -0
  220. package/dist/core/index.js.map +7 -0
  221. package/dist/core/operationTracker.js +212 -0
  222. package/dist/core/operationTracker.js.map +7 -0
  223. package/dist/core/permissions/auditLog.js +204 -0
  224. package/dist/core/permissions/auditLog.js.map +7 -0
  225. package/dist/core/permissions/engine/index.js +3 -0
  226. package/dist/core/permissions/engine/index.js.map +7 -0
  227. package/dist/core/permissions/engine/permissionEngine.js +106 -0
  228. package/dist/core/permissions/engine/permissionEngine.js.map +7 -0
  229. package/dist/core/permissions/engine/types.js +1 -0
  230. package/dist/core/permissions/engine/types.js.map +7 -0
  231. package/dist/core/permissions/index.js +84 -0
  232. package/dist/core/permissions/index.js.map +7 -0
  233. package/dist/core/permissions/ruleEngine.js +259 -0
  234. package/dist/core/permissions/ruleEngine.js.map +7 -0
  235. package/dist/core/permissions/rules/allowedToolsRule.js +62 -0
  236. package/dist/core/permissions/rules/allowedToolsRule.js.map +7 -0
  237. package/dist/core/permissions/rules/autoEscalationRule.js +296 -0
  238. package/dist/core/permissions/rules/autoEscalationRule.js.map +7 -0
  239. package/dist/core/permissions/rules/index.js +46 -0
  240. package/dist/core/permissions/rules/index.js.map +7 -0
  241. package/dist/core/permissions/rules/planModeRule.js +55 -0
  242. package/dist/core/permissions/rules/planModeRule.js.map +7 -0
  243. package/dist/core/permissions/rules/projectBoundaryRule.js +173 -0
  244. package/dist/core/permissions/rules/projectBoundaryRule.js.map +7 -0
  245. package/dist/core/permissions/rules/safeModeRule.js +65 -0
  246. package/dist/core/permissions/rules/safeModeRule.js.map +7 -0
  247. package/dist/core/permissions/rules/sensitivePathsRule.js +345 -0
  248. package/dist/core/permissions/rules/sensitivePathsRule.js.map +7 -0
  249. package/dist/core/permissions/types.js +127 -0
  250. package/dist/core/permissions/types.js.map +7 -0
  251. package/dist/core/tokenStats.js +9 -0
  252. package/dist/core/tokenStats.js.map +7 -0
  253. package/dist/core/tokenStatsManager.js +331 -0
  254. package/dist/core/tokenStatsManager.js.map +7 -0
  255. package/dist/core/tools/executor.js +143 -0
  256. package/dist/core/tools/executor.js.map +7 -0
  257. package/dist/core/tools/index.js +15 -0
  258. package/dist/core/tools/index.js.map +7 -0
  259. package/dist/core/tools/registry.js +183 -0
  260. package/dist/core/tools/registry.js.map +7 -0
  261. package/dist/core/tools/types.js +1 -0
  262. package/dist/core/tools/types.js.map +7 -0
  263. package/dist/cost-tracker.js +23 -15
  264. package/dist/cost-tracker.js.map +2 -2
  265. package/dist/entrypoints/cli.js +158 -130
  266. package/dist/entrypoints/cli.js.map +2 -2
  267. package/dist/entrypoints/mcp.js +12 -4
  268. package/dist/entrypoints/mcp.js.map +2 -2
  269. package/dist/history.js +14 -3
  270. package/dist/history.js.map +2 -2
  271. package/dist/hooks/useAgentTokenStats.js +72 -0
  272. package/dist/hooks/useAgentTokenStats.js.map +7 -0
  273. package/dist/hooks/useAgentTranscripts.js +140 -0
  274. package/dist/hooks/useAgentTranscripts.js.map +7 -0
  275. package/dist/hooks/useAnimationSync.js +53 -0
  276. package/dist/hooks/useAnimationSync.js.map +7 -0
  277. package/dist/hooks/useArrowKeyHistory.js +4 -2
  278. package/dist/hooks/useArrowKeyHistory.js.map +2 -2
  279. package/dist/hooks/useCanUseTool.js +3 -1
  280. package/dist/hooks/useCanUseTool.js.map +2 -2
  281. package/dist/hooks/useExitOnCtrlCD.js +9 -5
  282. package/dist/hooks/useExitOnCtrlCD.js.map +2 -2
  283. package/dist/hooks/useHookStatus.js +40 -0
  284. package/dist/hooks/useHookStatus.js.map +7 -0
  285. package/dist/hooks/useLogMessages.js +29 -2
  286. package/dist/hooks/useLogMessages.js.map +2 -2
  287. package/dist/hooks/useMessageGroups.js +43 -0
  288. package/dist/hooks/useMessageGroups.js.map +7 -0
  289. package/dist/hooks/useTerminalSize.js +62 -6
  290. package/dist/hooks/useTerminalSize.js.map +2 -2
  291. package/dist/hooks/useUnifiedCompletion.js +69 -0
  292. package/dist/hooks/useUnifiedCompletion.js.map +2 -2
  293. package/dist/i18n/index.js +109 -0
  294. package/dist/i18n/index.js.map +7 -0
  295. package/dist/i18n/locales/en.js +348 -0
  296. package/dist/i18n/locales/en.js.map +7 -0
  297. package/dist/i18n/locales/index.js +7 -0
  298. package/dist/i18n/locales/index.js.map +7 -0
  299. package/dist/i18n/locales/zh-CN.js +348 -0
  300. package/dist/i18n/locales/zh-CN.js.map +7 -0
  301. package/dist/i18n/types.js +8 -0
  302. package/dist/i18n/types.js.map +7 -0
  303. package/dist/permissions.js +28 -1
  304. package/dist/permissions.js.map +2 -2
  305. package/dist/query.js +253 -21
  306. package/dist/query.js.map +3 -3
  307. package/dist/screens/REPL.js +523 -194
  308. package/dist/screens/REPL.js.map +3 -3
  309. package/dist/services/adapters/chatCompletions.js +3 -1
  310. package/dist/services/adapters/chatCompletions.js.map +2 -2
  311. package/dist/services/adapters/messageNormalizer.js +354 -0
  312. package/dist/services/adapters/messageNormalizer.js.map +7 -0
  313. package/dist/services/adapters/responsesAPI.js +6 -3
  314. package/dist/services/adapters/responsesAPI.js.map +2 -2
  315. package/dist/services/checkpointManager.js +386 -0
  316. package/dist/services/checkpointManager.js.map +7 -0
  317. package/dist/services/claude.js +192 -14
  318. package/dist/services/claude.js.map +3 -3
  319. package/dist/services/compressionService.js +50 -1
  320. package/dist/services/compressionService.js.map +2 -2
  321. package/dist/services/contextMonitor.js +162 -0
  322. package/dist/services/contextMonitor.js.map +7 -0
  323. package/dist/services/customCommands.js +60 -41
  324. package/dist/services/customCommands.js.map +2 -2
  325. package/dist/services/hookExecutor.js +173 -1
  326. package/dist/services/hookExecutor.js.map +2 -2
  327. package/dist/services/intelligentCompactor.js +281 -0
  328. package/dist/services/intelligentCompactor.js.map +7 -0
  329. package/dist/services/lspConfig.js +109 -0
  330. package/dist/services/lspConfig.js.map +7 -0
  331. package/dist/services/mcpClient.js +338 -43
  332. package/dist/services/mcpClient.js.map +2 -2
  333. package/dist/services/modelOrchestrator.js +310 -0
  334. package/dist/services/modelOrchestrator.js.map +7 -0
  335. package/dist/services/openai.js +8 -1
  336. package/dist/services/openai.js.map +2 -2
  337. package/dist/services/outputStyles.js +138 -0
  338. package/dist/services/outputStyles.js.map +7 -0
  339. package/dist/services/plugins/index.js +5 -0
  340. package/dist/services/plugins/index.js.map +7 -0
  341. package/dist/services/plugins/lspServers.js +188 -0
  342. package/dist/services/plugins/lspServers.js.map +7 -0
  343. package/dist/services/plugins/pluginRuntime.js +229 -0
  344. package/dist/services/plugins/pluginRuntime.js.map +7 -0
  345. package/dist/services/plugins/pluginValidation.js +219 -0
  346. package/dist/services/plugins/pluginValidation.js.map +7 -0
  347. package/dist/services/plugins/skillMarketplace.js +556 -0
  348. package/dist/services/plugins/skillMarketplace.js.map +7 -0
  349. package/dist/services/responseStateManager.js +37 -3
  350. package/dist/services/responseStateManager.js.map +2 -2
  351. package/dist/services/sandbox/filesystemBoundary.js +341 -0
  352. package/dist/services/sandbox/filesystemBoundary.js.map +7 -0
  353. package/dist/services/sandbox/index.js +14 -0
  354. package/dist/services/sandbox/index.js.map +7 -0
  355. package/dist/services/sandbox/networkProxy.js +293 -0
  356. package/dist/services/sandbox/networkProxy.js.map +7 -0
  357. package/dist/services/sandbox/sandboxController.js +574 -0
  358. package/dist/services/sandbox/sandboxController.js.map +7 -0
  359. package/dist/services/sandbox/types.js +50 -0
  360. package/dist/services/sandbox/types.js.map +7 -0
  361. package/dist/services/sessionMemory.js +266 -0
  362. package/dist/services/sessionMemory.js.map +7 -0
  363. package/dist/services/taskRouter.js +324 -0
  364. package/dist/services/taskRouter.js.map +7 -0
  365. package/dist/tools/ArchitectTool/ArchitectTool.js +7 -1
  366. package/dist/tools/ArchitectTool/ArchitectTool.js.map +2 -2
  367. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +6 -2
  368. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  369. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +2 -1
  370. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
  371. package/dist/tools/BaseTool.js +72 -0
  372. package/dist/tools/BaseTool.js.map +7 -0
  373. package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js +3 -0
  374. package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js.map +2 -2
  375. package/dist/tools/BashTool/BashTool.js +79 -3
  376. package/dist/tools/BashTool/BashTool.js.map +2 -2
  377. package/dist/tools/BashTool/BashToolResultMessage.js +3 -0
  378. package/dist/tools/BashTool/BashToolResultMessage.js.map +2 -2
  379. package/dist/tools/BashTool/OutputLine.js +54 -0
  380. package/dist/tools/BashTool/OutputLine.js.map +2 -2
  381. package/dist/tools/BashTool/prompt.js +336 -3
  382. package/dist/tools/BashTool/prompt.js.map +2 -2
  383. package/dist/tools/FileEditTool/FileEditTool.js +29 -4
  384. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  385. package/dist/tools/FileEditTool/prompt.js +6 -3
  386. package/dist/tools/FileEditTool/prompt.js.map +2 -2
  387. package/dist/tools/FileWriteTool/FileWriteTool.js +5 -5
  388. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  389. package/dist/tools/FileWriteTool/prompt.js +4 -2
  390. package/dist/tools/FileWriteTool/prompt.js.map +2 -2
  391. package/dist/tools/GlobTool/GlobTool.js +4 -2
  392. package/dist/tools/GlobTool/GlobTool.js.map +2 -2
  393. package/dist/tools/GrepTool/GrepTool.js +36 -7
  394. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  395. package/dist/tools/KillShellTool/KillShellToolResultMessage.js +3 -0
  396. package/dist/tools/KillShellTool/KillShellToolResultMessage.js.map +2 -2
  397. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js +109 -0
  398. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +7 -0
  399. package/dist/tools/ListMcpResourcesTool/prompt.js +19 -0
  400. package/dist/tools/ListMcpResourcesTool/prompt.js.map +7 -0
  401. package/dist/tools/LspTool/LspTool.js +664 -0
  402. package/dist/tools/LspTool/LspTool.js.map +7 -0
  403. package/dist/tools/LspTool/prompt.js +27 -0
  404. package/dist/tools/LspTool/prompt.js.map +7 -0
  405. package/dist/tools/MCPTool/MCPTool.js +9 -1
  406. package/dist/tools/MCPTool/MCPTool.js.map +2 -2
  407. package/dist/tools/MemoryReadTool/MemoryReadTool.js +19 -6
  408. package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +2 -2
  409. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +6 -6
  410. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +2 -2
  411. package/dist/tools/MultiEditTool/MultiEditTool.js +19 -2
  412. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  413. package/dist/tools/MultiEditTool/prompt.js +5 -3
  414. package/dist/tools/MultiEditTool/prompt.js.map +2 -2
  415. package/dist/tools/NotebookEditTool/NotebookEditTool.js +7 -2
  416. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  417. package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +2 -2
  418. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +75 -0
  419. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +7 -0
  420. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +109 -0
  421. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +7 -0
  422. package/dist/tools/PlanModeTool/prompt.js +94 -0
  423. package/dist/tools/PlanModeTool/prompt.js.map +7 -0
  424. package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js +130 -0
  425. package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js.map +7 -0
  426. package/dist/tools/ReadMcpResourceTool/prompt.js +17 -0
  427. package/dist/tools/ReadMcpResourceTool/prompt.js.map +7 -0
  428. package/dist/tools/SkillTool/SkillTool.js +10 -4
  429. package/dist/tools/SkillTool/SkillTool.js.map +2 -2
  430. package/dist/tools/SkillTool/prompt.js +1 -1
  431. package/dist/tools/SkillTool/prompt.js.map +1 -1
  432. package/dist/tools/SlashCommandTool/SlashCommandTool.js +260 -0
  433. package/dist/tools/SlashCommandTool/SlashCommandTool.js.map +7 -0
  434. package/dist/tools/SlashCommandTool/prompt.js +35 -0
  435. package/dist/tools/SlashCommandTool/prompt.js.map +7 -0
  436. package/dist/tools/TaskOutputTool/TaskOutputTool.js +190 -0
  437. package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +7 -0
  438. package/dist/tools/TaskOutputTool/prompt.js +15 -0
  439. package/dist/tools/TaskOutputTool/prompt.js.map +7 -0
  440. package/dist/tools/TaskTool/TaskTool.js +310 -104
  441. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  442. package/dist/tools/TaskTool/prompt.js.map +2 -2
  443. package/dist/tools/TodoWriteTool/TodoWriteTool.js +42 -77
  444. package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +2 -2
  445. package/dist/tools/URLFetcherTool/URLFetcherTool.js +4 -1
  446. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  447. package/dist/tools/URLFetcherTool/cache.js +55 -8
  448. package/dist/tools/URLFetcherTool/cache.js.map +2 -2
  449. package/dist/tools.js +31 -2
  450. package/dist/tools.js.map +2 -2
  451. package/dist/types/hooks.js +4 -0
  452. package/dist/types/hooks.js.map +2 -2
  453. package/dist/types/marketplace.js.map +2 -2
  454. package/dist/types/messageGroup.js +36 -0
  455. package/dist/types/messageGroup.js.map +7 -0
  456. package/dist/types/plugin.js.map +2 -2
  457. package/dist/types/thinking.js +1 -0
  458. package/dist/types/thinking.js.map +7 -0
  459. package/dist/utils/BackgroundShellManager.js +136 -39
  460. package/dist/utils/BackgroundShellManager.js.map +2 -2
  461. package/dist/utils/CircuitBreaker.js +242 -0
  462. package/dist/utils/CircuitBreaker.js.map +7 -0
  463. package/dist/utils/MessageBatchBuffer.js +102 -0
  464. package/dist/utils/MessageBatchBuffer.js.map +7 -0
  465. package/dist/utils/PersistentShell.js +151 -1
  466. package/dist/utils/PersistentShell.js.map +2 -2
  467. package/dist/utils/agentLoader.js +1 -23
  468. package/dist/utils/agentLoader.js.map +2 -2
  469. package/dist/utils/agentTranscripts.js +641 -0
  470. package/dist/utils/agentTranscripts.js.map +7 -0
  471. package/dist/utils/animationManager.js +213 -0
  472. package/dist/utils/animationManager.js.map +7 -0
  473. package/dist/utils/animationSync.js +110 -0
  474. package/dist/utils/animationSync.js.map +7 -0
  475. package/dist/utils/ask.js +2 -0
  476. package/dist/utils/ask.js.map +2 -2
  477. package/dist/utils/asyncFile.js +215 -0
  478. package/dist/utils/asyncFile.js.map +7 -0
  479. package/dist/utils/backgroundAgentManager.js +231 -0
  480. package/dist/utils/backgroundAgentManager.js.map +7 -0
  481. package/dist/utils/config.js +108 -10
  482. package/dist/utils/config.js.map +2 -2
  483. package/dist/utils/conversationRecovery.js +19 -0
  484. package/dist/utils/conversationRecovery.js.map +2 -2
  485. package/dist/utils/credentials/CredentialStore.js +1 -0
  486. package/dist/utils/credentials/CredentialStore.js.map +7 -0
  487. package/dist/utils/credentials/EncryptedFileStore.js +157 -0
  488. package/dist/utils/credentials/EncryptedFileStore.js.map +7 -0
  489. package/dist/utils/credentials/index.js +37 -0
  490. package/dist/utils/credentials/index.js.map +7 -0
  491. package/dist/utils/credentials/migration.js +82 -0
  492. package/dist/utils/credentials/migration.js.map +7 -0
  493. package/dist/utils/exit.js +73 -0
  494. package/dist/utils/exit.js.map +7 -0
  495. package/dist/utils/format.js +73 -5
  496. package/dist/utils/format.js.map +2 -2
  497. package/dist/utils/generators.js +76 -6
  498. package/dist/utils/generators.js.map +2 -2
  499. package/dist/utils/globalErrorHandler.js +149 -0
  500. package/dist/utils/globalErrorHandler.js.map +7 -0
  501. package/dist/utils/groupHandlers/index.js +8 -0
  502. package/dist/utils/groupHandlers/index.js.map +7 -0
  503. package/dist/utils/groupHandlers/parallelTasksHandler.js +140 -0
  504. package/dist/utils/groupHandlers/parallelTasksHandler.js.map +7 -0
  505. package/dist/utils/groupHandlers/taskHandler.js +104 -0
  506. package/dist/utils/groupHandlers/taskHandler.js.map +7 -0
  507. package/dist/utils/groupHandlers/types.js +1 -0
  508. package/dist/utils/groupHandlers/types.js.map +7 -0
  509. package/dist/utils/logRotation.js +224 -0
  510. package/dist/utils/logRotation.js.map +7 -0
  511. package/dist/utils/markdown.js +13 -1
  512. package/dist/utils/markdown.js.map +2 -2
  513. package/dist/utils/marketplaceManager.js +3 -5
  514. package/dist/utils/marketplaceManager.js.map +2 -2
  515. package/dist/utils/memSafety.js +264 -0
  516. package/dist/utils/memSafety.js.map +7 -0
  517. package/dist/utils/messageGroupManager.js +274 -0
  518. package/dist/utils/messageGroupManager.js.map +7 -0
  519. package/dist/utils/messages.js +13 -4
  520. package/dist/utils/messages.js.map +2 -2
  521. package/dist/utils/model.js +119 -15
  522. package/dist/utils/model.js.map +3 -3
  523. package/dist/utils/permissions/filesystem.js +162 -6
  524. package/dist/utils/permissions/filesystem.js.map +2 -2
  525. package/dist/utils/plan/planMode.js +143 -0
  526. package/dist/utils/plan/planMode.js.map +7 -0
  527. package/dist/utils/pluginLoader.js +17 -21
  528. package/dist/utils/pluginLoader.js.map +2 -2
  529. package/dist/utils/ripgrep.js +55 -2
  530. package/dist/utils/ripgrep.js.map +2 -2
  531. package/dist/utils/safePath.js +132 -0
  532. package/dist/utils/safePath.js.map +7 -0
  533. package/dist/utils/sanitizeInput.js +32 -0
  534. package/dist/utils/sanitizeInput.js.map +7 -0
  535. package/dist/utils/secureKeyStorage.js +312 -0
  536. package/dist/utils/secureKeyStorage.js.map +7 -0
  537. package/dist/utils/sensitiveFiles.js +125 -0
  538. package/dist/utils/sensitiveFiles.js.map +7 -0
  539. package/dist/utils/session/sessionPlugins.js +67 -0
  540. package/dist/utils/session/sessionPlugins.js.map +7 -0
  541. package/dist/utils/taskDisplayUtils.js +257 -0
  542. package/dist/utils/taskDisplayUtils.js.map +7 -0
  543. package/dist/utils/teamConfig.js +2 -1
  544. package/dist/utils/teamConfig.js.map +2 -2
  545. package/dist/utils/theme.js +6 -6
  546. package/dist/utils/theme.js.map +1 -1
  547. package/dist/utils/todoStorage.js +92 -2
  548. package/dist/utils/todoStorage.js.map +2 -2
  549. package/dist/utils/toolRiskClassification.js +207 -0
  550. package/dist/utils/toolRiskClassification.js.map +7 -0
  551. package/dist/utils/toolTimeout.js +136 -0
  552. package/dist/utils/toolTimeout.js.map +7 -0
  553. package/dist/utils/tooling/safeRender.js +116 -0
  554. package/dist/utils/tooling/safeRender.js.map +7 -0
  555. package/dist/utils/userFriendlyError.js +346 -0
  556. package/dist/utils/userFriendlyError.js.map +7 -0
  557. package/dist/utils/vendor/ripgrep/arm64-darwin/rg +0 -0
  558. package/dist/version.js +2 -2
  559. package/dist/version.js.map +1 -1
  560. package/package.json +17 -5
  561. package/scripts/postinstall.js +128 -38
  562. package/dist/commands/agents.js +0 -2086
  563. package/dist/commands/agents.js.map +0 -7
  564. package/dist/commands/build.js +0 -74
  565. package/dist/commands/build.js.map +0 -7
  566. package/dist/commands/compression.js +0 -57
  567. package/dist/commands/compression.js.map +0 -7
  568. package/dist/commands/listen.js +0 -37
  569. package/dist/commands/listen.js.map +0 -7
  570. package/dist/commands/login.js +0 -37
  571. package/dist/commands/login.js.map +0 -7
  572. package/dist/commands/logout.js +0 -33
  573. package/dist/commands/logout.js.map +0 -7
  574. package/dist/commands/mcp.js +0 -40
  575. package/dist/commands/mcp.js.map +0 -7
  576. package/dist/commands/mcp_refresh.js +0 -40
  577. package/dist/commands/mcp_refresh.js.map +0 -7
  578. package/dist/commands/modelstatus.js +0 -21
  579. package/dist/commands/modelstatus.js.map +0 -7
  580. package/dist/commands/onboarding.js +0 -36
  581. package/dist/commands/onboarding.js.map +0 -7
  582. package/dist/commands/plugin-interactive.js +0 -446
  583. package/dist/commands/plugin-interactive.js.map +0 -7
  584. package/dist/commands/pr_comments.js +0 -61
  585. package/dist/commands/pr_comments.js.map +0 -7
  586. package/dist/commands/release-notes.js +0 -30
  587. package/dist/commands/release-notes.js.map +0 -7
  588. package/dist/commands/review.js +0 -51
  589. package/dist/commands/review.js.map +0 -7
  590. package/dist/components/Bug.js +0 -147
  591. package/dist/components/Bug.js.map +0 -7
  592. package/dist/components/ModelSelector.js +0 -2062
  593. package/dist/components/ModelSelector.js.map +0 -7
  594. package/dist/components/ModelStatusDisplay.js +0 -87
  595. package/dist/components/ModelStatusDisplay.js.map +0 -7
  596. package/dist/entrypoints/cli-wrapper.js +0 -61
  597. package/dist/entrypoints/cli-wrapper.js.map +0 -7
  598. package/dist/hooks/useCancelRequest.js +0 -28
  599. package/dist/hooks/useCancelRequest.js.map +0 -7
  600. package/dist/screens/Doctor.js +0 -22
  601. package/dist/screens/Doctor.js.map +0 -7
@@ -8,13 +8,19 @@ import { PRODUCT_NAME } from "../../constants/product.js";
8
8
  import { splitCommand } from "../../utils/commands.js";
9
9
  import { isInDirectory } from "../../utils/file.js";
10
10
  import { logError } from "../../utils/log.js";
11
- import { PersistentShell } from "../../utils/PersistentShell.js";
11
+ import {
12
+ PersistentShell
13
+ } from "../../utils/PersistentShell.js";
12
14
  import { getCwd, getOriginalCwd } from "../../utils/state.js";
13
15
  import { getGlobalConfig } from "../../utils/config.js";
14
16
  import { getModelManager } from "../../utils/model.js";
15
17
  import { BackgroundShellManager } from "../../utils/BackgroundShellManager.js";
16
18
  import BashToolResultMessage from "./BashToolResultMessage.js";
17
- import { BANNED_COMMANDS, PROMPT } from "./prompt.js";
19
+ import {
20
+ BANNED_COMMANDS,
21
+ PROMPT,
22
+ detectDangerousPatterns
23
+ } from "./prompt.js";
18
24
  import { formatOutput, getCommandFilePaths } from "./utils.js";
19
25
  const inputSchema = z.strictObject({
20
26
  command: z.string().describe("The command to execute"),
@@ -49,6 +55,27 @@ const BashTool = {
49
55
  return true;
50
56
  },
51
57
  async validateInput({ command }) {
58
+ const dangerousPatterns = detectDangerousPatterns(command);
59
+ const criticalPatterns = dangerousPatterns.filter(
60
+ (p) => p.severity === "critical"
61
+ );
62
+ if (criticalPatterns.length > 0) {
63
+ const patternNames = criticalPatterns.map((p) => p.name).join(", ");
64
+ logError(
65
+ `SECURITY: Critical dangerous patterns detected in command: ${patternNames}`
66
+ );
67
+ return {
68
+ result: false,
69
+ message: `Command contains critical security risks: ${patternNames}. This command has been blocked for security reasons.`
70
+ };
71
+ }
72
+ const highPatterns = dangerousPatterns.filter((p) => p.severity === "high");
73
+ if (highPatterns.length > 0) {
74
+ const patternNames = highPatterns.map((p) => p.name).join(", ");
75
+ logError(
76
+ `SECURITY WARNING: High-severity patterns detected in command: ${patternNames}. User confirmation required.`
77
+ );
78
+ }
52
79
  const commands = splitCommand(command);
53
80
  for (const cmd of commands) {
54
81
  const parts = cmd.split(" ");
@@ -59,6 +86,15 @@ const BashTool = {
59
86
  message: `Command '${baseCmd}' is not allowed for security reasons`
60
87
  };
61
88
  }
89
+ if (baseCmd && (baseCmd.startsWith("/") || baseCmd.startsWith("./"))) {
90
+ const cmdName = baseCmd.split("/").pop()?.toLowerCase();
91
+ if (cmdName && BANNED_COMMANDS.includes(cmdName)) {
92
+ return {
93
+ result: false,
94
+ message: `Command '${cmdName}' is not allowed for security reasons (full path: ${baseCmd})`
95
+ };
96
+ }
97
+ }
62
98
  if (baseCmd === "cd" && parts[1]) {
63
99
  const targetDir = parts[1].replace(/^['"]|['"]$/g, "");
64
100
  const fullTargetDir = isAbsolute(targetDir) ? targetDir : resolve(getCwd(), targetDir);
@@ -128,6 +164,7 @@ Command: ${command}`,
128
164
  }
129
165
  let stdout = "";
130
166
  let stderr = "";
167
+ let isCompleted = false;
131
168
  if (abortController.signal.aborted) {
132
169
  const data = {
133
170
  stdout: "",
@@ -144,11 +181,45 @@ Command: ${command}`,
144
181
  return;
145
182
  }
146
183
  try {
147
- const result = await PersistentShell.getInstance().exec(
184
+ let result = null;
185
+ let streamedStdout = "";
186
+ let streamedStderr = "";
187
+ const streamingGenerator = PersistentShell.getInstance().execStreaming(
148
188
  command,
149
189
  abortController.signal,
150
190
  timeout
151
191
  );
192
+ for await (const chunk of streamingGenerator) {
193
+ if (chunk.type === "chunk") {
194
+ if (chunk.stdout) {
195
+ streamedStdout += chunk.stdout;
196
+ }
197
+ if (chunk.stderr) {
198
+ streamedStderr += chunk.stderr;
199
+ }
200
+ yield {
201
+ type: "progress",
202
+ content: {
203
+ type: "streaming",
204
+ toolName: "Bash",
205
+ stdout: streamedStdout,
206
+ stderr: streamedStderr,
207
+ isStreaming: true
208
+ }
209
+ };
210
+ } else if (chunk.type === "result") {
211
+ result = chunk;
212
+ }
213
+ }
214
+ if (!result) {
215
+ result = {
216
+ type: "result",
217
+ stdout: streamedStdout,
218
+ stderr: streamedStderr,
219
+ code: 0,
220
+ interrupted: false
221
+ };
222
+ }
152
223
  stdout += (result.stdout || "").trim() + EOL;
153
224
  stderr += (result.stderr || "").trim() + EOL;
154
225
  if (result.code !== 0) {
@@ -160,6 +231,9 @@ Command: ${command}`,
160
231
  }
161
232
  if (process.env.NODE_ENV !== "test") {
162
233
  getCommandFilePaths(command, stdout).then((filePaths) => {
234
+ if (isCompleted) {
235
+ return;
236
+ }
163
237
  for (const filePath of filePaths) {
164
238
  const fullFilePath = isAbsolute(filePath) ? filePath : resolve(getCwd(), filePath);
165
239
  try {
@@ -199,6 +273,8 @@ Command: ${command}`,
199
273
  resultForAssistant: this.renderResultForAssistant(data),
200
274
  data
201
275
  };
276
+ } finally {
277
+ isCompleted = true;
202
278
  }
203
279
  }
204
280
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/tools/BashTool/BashTool.tsx"],
4
- "sourcesContent": ["import { statSync } from 'fs'\nimport { EOL } from 'os'\nimport { isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { PRODUCT_NAME } from '@constants/product'\nimport { queryQuick } from '@services/claude'\nimport { Tool, ValidationResult } from '@tool'\nimport { splitCommand } from '@utils/commands'\nimport { isInDirectory } from '@utils/file'\nimport { logError } from '@utils/log'\nimport { PersistentShell } from '@utils/PersistentShell'\nimport { getCwd, getOriginalCwd } from '@utils/state'\nimport { getGlobalConfig } from '@utils/config'\nimport { getModelManager } from '@utils/model'\nimport { BackgroundShellManager } from '@utils/BackgroundShellManager'\nimport BashToolResultMessage from './BashToolResultMessage'\nimport { BANNED_COMMANDS, PROMPT } from './prompt'\nimport { formatOutput, getCommandFilePaths } from './utils'\n\nexport const inputSchema = z.strictObject({\n command: z.string().describe('The command to execute'),\n timeout: z\n .number()\n .optional()\n .describe('Optional timeout in milliseconds (max 600000)'),\n run_in_background: z\n .boolean()\n .optional()\n .describe('Set to true to run this command in the background'),\n})\n\ntype In = typeof inputSchema\nexport type Out = {\n stdout: string\n stdoutLines: number // Total number of lines in original stdout, even if `stdout` is now truncated\n stderr: string\n stderrLines: number // Total number of lines in original stderr, even if `stderr` is now truncated\n interrupted: boolean\n shellId?: string // Present if run_in_background is true\n}\n\nexport const BashTool = {\n name: 'Bash',\n async description() {\n return 'Executes shell commands on your computer'\n },\n async prompt() {\n const config = getGlobalConfig()\n // \uD83D\uDD27 Fix: Use ModelManager to get actual current model\n const modelManager = getModelManager()\n const modelName =\n modelManager.getModelName('main') || '<No Model Configured>'\n // Substitute the placeholder in the static PROMPT string\n return PROMPT.replace(/{MODEL_NAME}/g, modelName)\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // BashTool modifies state/files, not safe for concurrent execution\n },\n inputSchema,\n userFacingName() {\n return 'Bash'\n },\n async isEnabled() {\n return true\n },\n needsPermissions(): boolean {\n // Always check per-project permissions for BashTool\n return true\n },\n async validateInput({ command }): Promise<ValidationResult> {\n const commands = splitCommand(command)\n for (const cmd of commands) {\n const parts = cmd.split(' ')\n const baseCmd = parts[0]\n\n // Check if command is banned\n if (baseCmd && BANNED_COMMANDS.includes(baseCmd.toLowerCase())) {\n return {\n result: false,\n message: `Command '${baseCmd}' is not allowed for security reasons`,\n }\n }\n\n // Special handling for cd command\n if (baseCmd === 'cd' && parts[1]) {\n const targetDir = parts[1]!.replace(/^['\"]|['\"]$/g, '') // Remove quotes if present\n const fullTargetDir = isAbsolute(targetDir)\n ? targetDir\n : resolve(getCwd(), targetDir)\n if (\n !isInDirectory(\n relative(getOriginalCwd(), fullTargetDir),\n relative(getCwd(), getOriginalCwd()),\n )\n ) {\n return {\n result: false,\n message: `ERROR: cd to '${fullTargetDir}' was blocked. For security, ${PRODUCT_NAME} may only change directories to child directories of the original working directory (${getOriginalCwd()}) for this session.`,\n }\n }\n }\n }\n\n return { result: true }\n },\n renderToolUseMessage({ command }) {\n // Clean up any command that uses the quoted HEREDOC pattern\n if (command.includes(\"\\\"$(cat <<'EOF'\")) {\n const match = command.match(\n /^(.*?)\"?\\$\\(cat <<'EOF'\\n([\\s\\S]*?)\\n\\s*EOF\\n\\s*\\)\"(.*)$/,\n )\n if (match && match[1] && match[2]) {\n const prefix = match[1]\n const content = match[2]\n const suffix = match[3] || ''\n return `${prefix.trim()} \"${content.trim()}\"${suffix.trim()}`\n }\n }\n return command\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n\n renderToolResultMessage(content) {\n return <BashToolResultMessage content={content} verbose={false} />\n },\n renderResultForAssistant({ interrupted, stdout, stderr }) {\n let errorMessage = stderr.trim()\n if (interrupted) {\n if (stderr) errorMessage += EOL\n errorMessage += '<error>Command was aborted before completion</error>'\n }\n const hasBoth = stdout.trim() && errorMessage\n return `${stdout.trim()}${hasBoth ? '\\n' : ''}${errorMessage.trim()}`\n },\n async *call(\n { command, timeout = 120000, run_in_background = false },\n { abortController, readFileTimestamps },\n ) {\n // Handle background execution\n if (run_in_background) {\n const shellId = BackgroundShellManager.getInstance().create(\n command,\n getCwd(),\n )\n\n const data: Out = {\n stdout: `Background shell started with ID: ${shellId}`,\n stdoutLines: 1,\n stderr: '',\n stderrLines: 0,\n interrupted: false,\n shellId,\n }\n\n yield {\n type: 'result',\n resultForAssistant: `Started background shell: ${shellId}\\nCommand: ${command}`,\n data,\n }\n return\n }\n\n let stdout = ''\n let stderr = ''\n\n // \uD83D\uDD27 Check if already cancelled before starting execution\n if (abortController.signal.aborted) {\n const data: Out = {\n stdout: '',\n stdoutLines: 0,\n stderr: 'Command cancelled before execution',\n stderrLines: 1,\n interrupted: true,\n }\n\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(data),\n data,\n }\n return\n }\n\n try {\n // Execute commands\n const result = await PersistentShell.getInstance().exec(\n command,\n abortController.signal,\n timeout,\n )\n stdout += (result.stdout || '').trim() + EOL\n stderr += (result.stderr || '').trim() + EOL\n if (result.code !== 0) {\n stderr += `Exit code ${result.code}`\n }\n\n if (!isInDirectory(getCwd(), getOriginalCwd())) {\n // Shell directory is outside original working directory, reset it\n await PersistentShell.getInstance().setCwd(getOriginalCwd())\n stderr = `${stderr.trim()}${EOL}Shell cwd was reset to ${getOriginalCwd()}`\n }\n\n // Update read timestamps for any files referenced by the command\n // Don't block the main thread!\n // Skip this in tests because it makes fixtures non-deterministic (they might not always get written),\n // so will be missing in CI.\n if (process.env.NODE_ENV !== 'test') {\n getCommandFilePaths(command, stdout).then(filePaths => {\n for (const filePath of filePaths) {\n const fullFilePath = isAbsolute(filePath)\n ? filePath\n : resolve(getCwd(), filePath)\n\n // Try/catch in case the file doesn't exist (because Haiku didn't properly extract it)\n try {\n readFileTimestamps[fullFilePath] = statSync(fullFilePath).mtimeMs\n } catch (e) {\n logError(e)\n }\n }\n })\n }\n\n const { totalLines: stdoutLines, truncatedContent: stdoutContent } =\n formatOutput(stdout.trim())\n const { totalLines: stderrLines, truncatedContent: stderrContent } =\n formatOutput(stderr.trim())\n\n const data: Out = {\n stdout: stdoutContent,\n stdoutLines,\n stderr: stderrContent,\n stderrLines,\n interrupted: result.interrupted,\n }\n\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(data),\n data,\n }\n } catch (error) {\n // \uD83D\uDD27 Handle cancellation or other errors properly\n const isAborted = abortController.signal.aborted\n const errorMessage = isAborted\n ? 'Command was cancelled by user'\n : `Command failed: ${error instanceof Error ? error.message : String(error)}`\n\n const data: Out = {\n stdout: stdout.trim(),\n stdoutLines: stdout.split('\\n').length,\n stderr: errorMessage,\n stderrLines: 1,\n interrupted: isAborted,\n }\n\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(data),\n data,\n }\n }\n },\n} satisfies Tool<In, Out>\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { statSync } from 'fs'\nimport { EOL } from 'os'\nimport { isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { PRODUCT_NAME } from '@constants/product'\nimport { queryQuick } from '@services/claude'\nimport { Tool, ValidationResult } from '@tool'\nimport { splitCommand } from '@utils/commands'\nimport { isInDirectory } from '@utils/file'\nimport { logError } from '@utils/log'\nimport {\n PersistentShell,\n type StreamingYield,\n type StreamingResult,\n} from '@utils/PersistentShell'\nimport { getCwd, getOriginalCwd } from '@utils/state'\nimport { getGlobalConfig } from '@utils/config'\nimport { getModelManager } from '@utils/model'\nimport { BackgroundShellManager } from '@utils/BackgroundShellManager'\nimport BashToolResultMessage from './BashToolResultMessage'\nimport {\n BANNED_COMMANDS,\n PROMPT,\n matchesDangerousPattern,\n detectDangerousPatterns,\n} from './prompt'\nimport { formatOutput, getCommandFilePaths } from './utils'\n\nexport const inputSchema = z.strictObject({\n command: z.string().describe('The command to execute'),\n timeout: z\n .number()\n .optional()\n .describe('Optional timeout in milliseconds (max 600000)'),\n run_in_background: z\n .boolean()\n .optional()\n .describe('Set to true to run this command in the background'),\n})\n\ntype In = typeof inputSchema\nexport type Out = {\n stdout: string\n stdoutLines: number // Total number of lines in original stdout, even if `stdout` is now truncated\n stderr: string\n stderrLines: number // Total number of lines in original stderr, even if `stderr` is now truncated\n interrupted: boolean\n shellId?: string // Present if run_in_background is true\n}\n\nexport const BashTool = {\n name: 'Bash',\n async description() {\n return 'Executes shell commands on your computer'\n },\n async prompt() {\n const config = getGlobalConfig()\n // \uD83D\uDD27 Fix: Use ModelManager to get actual current model\n const modelManager = getModelManager()\n const modelName =\n modelManager.getModelName('main') || '<No Model Configured>'\n // Substitute the placeholder in the static PROMPT string\n return PROMPT.replace(/{MODEL_NAME}/g, modelName)\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // BashTool modifies state/files, not safe for concurrent execution\n },\n inputSchema,\n userFacingName() {\n return 'Bash'\n },\n async isEnabled() {\n return true\n },\n needsPermissions(): boolean {\n // Always check per-project permissions for BashTool\n return true\n },\n async validateInput({ command }): Promise<ValidationResult> {\n // Detect dangerous patterns (critical only block, others warn)\n const dangerousPatterns = detectDangerousPatterns(command)\n const criticalPatterns = dangerousPatterns.filter(\n p => p.severity === 'critical',\n )\n\n if (criticalPatterns.length > 0) {\n const patternNames = criticalPatterns.map(p => p.name).join(', ')\n logError(\n `SECURITY: Critical dangerous patterns detected in command: ${patternNames}`,\n )\n return {\n result: false,\n message: `Command contains critical security risks: ${patternNames}. This command has been blocked for security reasons.`,\n }\n }\n\n // Log warnings for high-severity patterns (non-blocking)\n const highPatterns = dangerousPatterns.filter(p => p.severity === 'high')\n if (highPatterns.length > 0) {\n const patternNames = highPatterns.map(p => p.name).join(', ')\n logError(\n `SECURITY WARNING: High-severity patterns detected in command: ${patternNames}. User confirmation required.`,\n )\n }\n\n const commands = splitCommand(command)\n for (const cmd of commands) {\n const parts = cmd.split(' ')\n const baseCmd = parts[0]\n\n // Check if command is banned\n if (baseCmd && BANNED_COMMANDS.includes(baseCmd.toLowerCase())) {\n return {\n result: false,\n message: `Command '${baseCmd}' is not allowed for security reasons`,\n }\n }\n\n // Also check for commands that might be invoked with full path\n // e.g., /usr/bin/curl, /bin/rm\n if (baseCmd && (baseCmd.startsWith('/') || baseCmd.startsWith('./'))) {\n const cmdName = baseCmd.split('/').pop()?.toLowerCase()\n if (cmdName && BANNED_COMMANDS.includes(cmdName)) {\n return {\n result: false,\n message: `Command '${cmdName}' is not allowed for security reasons (full path: ${baseCmd})`,\n }\n }\n }\n\n // Special handling for cd command\n if (baseCmd === 'cd' && parts[1]) {\n const targetDir = parts[1]!.replace(/^['\"]|['\"]$/g, '') // Remove quotes if present\n const fullTargetDir = isAbsolute(targetDir)\n ? targetDir\n : resolve(getCwd(), targetDir)\n if (\n !isInDirectory(\n relative(getOriginalCwd(), fullTargetDir),\n relative(getCwd(), getOriginalCwd()),\n )\n ) {\n return {\n result: false,\n message: `ERROR: cd to '${fullTargetDir}' was blocked. For security, ${PRODUCT_NAME} may only change directories to child directories of the original working directory (${getOriginalCwd()}) for this session.`,\n }\n }\n }\n }\n\n return { result: true }\n },\n renderToolUseMessage({ command }) {\n // Clean up any command that uses the quoted HEREDOC pattern\n if (command.includes(\"\\\"$(cat <<'EOF'\")) {\n const match = command.match(\n /^(.*?)\"?\\$\\(cat <<'EOF'\\n([\\s\\S]*?)\\n\\s*EOF\\n\\s*\\)\"(.*)$/,\n )\n if (match && match[1] && match[2]) {\n const prefix = match[1]\n const content = match[2]\n const suffix = match[3] || ''\n return `${prefix.trim()} \"${content.trim()}\"${suffix.trim()}`\n }\n }\n return command\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n\n renderToolResultMessage(content) {\n return <BashToolResultMessage content={content} verbose={false} />\n },\n renderResultForAssistant({ interrupted, stdout, stderr }) {\n let errorMessage = stderr.trim()\n if (interrupted) {\n if (stderr) errorMessage += EOL\n errorMessage += '<error>Command was aborted before completion</error>'\n }\n const hasBoth = stdout.trim() && errorMessage\n return `${stdout.trim()}${hasBoth ? '\\n' : ''}${errorMessage.trim()}`\n },\n async *call(\n { command, timeout = 120000, run_in_background = false },\n { abortController, readFileTimestamps },\n ) {\n // Handle background execution\n if (run_in_background) {\n const shellId = BackgroundShellManager.getInstance().create(\n command,\n getCwd(),\n )\n\n const data: Out = {\n stdout: `Background shell started with ID: ${shellId}`,\n stdoutLines: 1,\n stderr: '',\n stderrLines: 0,\n interrupted: false,\n shellId,\n }\n\n yield {\n type: 'result',\n resultForAssistant: `Started background shell: ${shellId}\\nCommand: ${command}`,\n data,\n }\n return\n }\n\n let stdout = ''\n let stderr = ''\n\n // \uD83D\uDD27 CRITICAL FIX: Track whether this tool invocation has completed\n // to prevent async callbacks from accessing stale context\n let isCompleted = false\n\n // \uD83D\uDD27 Check if already cancelled before starting execution\n if (abortController.signal.aborted) {\n const data: Out = {\n stdout: '',\n stdoutLines: 0,\n stderr: 'Command cancelled before execution',\n stderrLines: 1,\n interrupted: true,\n }\n\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(data),\n data,\n }\n return\n }\n\n try {\n // Execute commands with streaming output\n let result: StreamingResult | null = null\n let streamedStdout = ''\n let streamedStderr = ''\n\n // Use streaming execution for real-time output\n const streamingGenerator = PersistentShell.getInstance().execStreaming(\n command,\n abortController.signal,\n timeout,\n )\n\n for await (const chunk of streamingGenerator) {\n if (chunk.type === 'chunk') {\n // Accumulate streamed output\n if (chunk.stdout) {\n streamedStdout += chunk.stdout\n }\n if (chunk.stderr) {\n streamedStderr += chunk.stderr\n }\n\n // Yield progress update for real-time UI feedback\n // Use StreamingProgressContent format for proper rendering\n yield {\n type: 'progress',\n content: {\n type: 'streaming',\n toolName: 'Bash',\n stdout: streamedStdout,\n stderr: streamedStderr,\n isStreaming: true,\n },\n }\n } else if (chunk.type === 'result') {\n // Final result\n result = chunk\n }\n }\n\n // Use the final result (or construct from streamed data)\n if (!result) {\n result = {\n type: 'result',\n stdout: streamedStdout,\n stderr: streamedStderr,\n code: 0,\n interrupted: false,\n }\n }\n\n stdout += (result.stdout || '').trim() + EOL\n stderr += (result.stderr || '').trim() + EOL\n if (result.code !== 0) {\n stderr += `Exit code ${result.code}`\n }\n\n if (!isInDirectory(getCwd(), getOriginalCwd())) {\n // Shell directory is outside original working directory, reset it\n await PersistentShell.getInstance().setCwd(getOriginalCwd())\n stderr = `${stderr.trim()}${EOL}Shell cwd was reset to ${getOriginalCwd()}`\n }\n\n // Update read timestamps for any files referenced by the command\n // Don't block the main thread!\n // Skip this in tests because it makes fixtures non-deterministic (they might not always get written),\n // so will be missing in CI.\n if (process.env.NODE_ENV !== 'test') {\n getCommandFilePaths(command, stdout).then(filePaths => {\n // \uD83D\uDD27 CRITICAL FIX: Check if tool invocation has already completed\n // to prevent accessing potentially stale context\n if (isCompleted) {\n return // Tool has finished, don't access readFileTimestamps\n }\n\n for (const filePath of filePaths) {\n const fullFilePath = isAbsolute(filePath)\n ? filePath\n : resolve(getCwd(), filePath)\n\n // Try/catch in case the file doesn't exist (because Haiku didn't properly extract it)\n try {\n readFileTimestamps[fullFilePath] = statSync(fullFilePath).mtimeMs\n } catch (e) {\n logError(e)\n }\n }\n })\n }\n\n const { totalLines: stdoutLines, truncatedContent: stdoutContent } =\n formatOutput(stdout.trim())\n const { totalLines: stderrLines, truncatedContent: stderrContent } =\n formatOutput(stderr.trim())\n\n const data: Out = {\n stdout: stdoutContent,\n stdoutLines,\n stderr: stderrContent,\n stderrLines,\n interrupted: result.interrupted,\n }\n\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(data),\n data,\n }\n } catch (error) {\n // \uD83D\uDD27 Handle cancellation or other errors properly\n const isAborted = abortController.signal.aborted\n const errorMessage = isAborted\n ? 'Command was cancelled by user'\n : `Command failed: ${error instanceof Error ? error.message : String(error)}`\n\n const data: Out = {\n stdout: stdout.trim(),\n stdoutLines: stdout.split('\\n').length,\n stderr: errorMessage,\n stderrLines: 1,\n interrupted: isAborted,\n }\n\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(data),\n data,\n }\n } finally {\n // \uD83D\uDD27 CRITICAL FIX: Mark tool invocation as completed\n // This prevents async callbacks (like getCommandFilePaths) from\n // accessing potentially stale context after this tool returns\n isCompleted = true\n }\n },\n} satisfies Tool<In, Out>\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,9 @@ import { OutputLine } from "./OutputLine.js";
3
3
  import React from "react";
4
4
  import { getTheme } from "../../utils/theme.js";
5
5
  function BashToolResultMessage({ content, verbose }) {
6
+ if (!content) {
7
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { color: getTheme().secondaryText }, "(No output)"));
8
+ }
6
9
  const { stdout, stdoutLines, stderr, stderrLines } = content;
7
10
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, stdout !== "" ? /* @__PURE__ */ React.createElement(OutputLine, { content: stdout, lines: stdoutLines, verbose }) : null, stderr !== "" ? /* @__PURE__ */ React.createElement(
8
11
  OutputLine,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/tools/BashTool/BashToolResultMessage.tsx"],
4
- "sourcesContent": ["import { Box, Text } from 'ink'\nimport { OutputLine } from './OutputLine'\nimport React from 'react'\nimport { getTheme } from '@utils/theme'\nimport { Out as BashOut } from './BashTool'\n\ntype Props = {\n content: Omit<BashOut, 'interrupted'>\n verbose: boolean\n}\n\nfunction BashToolResultMessage({ content, verbose }: Props): React.JSX.Element {\n const { stdout, stdoutLines, stderr, stderrLines } = content\n\n return (\n <Box flexDirection=\"column\">\n {stdout !== '' ? (\n <OutputLine content={stdout} lines={stdoutLines} verbose={verbose} />\n ) : null}\n {stderr !== '' ? (\n <OutputLine\n content={stderr}\n lines={stderrLines}\n verbose={verbose}\n isError\n />\n ) : null}\n {stdout === '' && stderr === '' ? (\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text color={getTheme().secondaryText}>(No content)</Text>\n </Box>\n ) : null}\n </Box>\n )\n}\n\nexport default BashToolResultMessage\n"],
5
- "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,SAAS,kBAAkB;AAC3B,OAAO,WAAW;AAClB,SAAS,gBAAgB;AAQzB,SAAS,sBAAsB,EAAE,SAAS,QAAQ,GAA6B;AAC7E,QAAM,EAAE,QAAQ,aAAa,QAAQ,YAAY,IAAI;AAErD,SACE,oCAAC,OAAI,eAAc,YAChB,WAAW,KACV,oCAAC,cAAW,SAAS,QAAQ,OAAO,aAAa,SAAkB,IACjE,MACH,WAAW,KACV;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,OAAO;AAAA,MACP;AAAA,MACA,SAAO;AAAA;AAAA,EACT,IACE,MACH,WAAW,MAAM,WAAW,KAC3B,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,QAAK,OAAO,SAAS,EAAE,iBAAe,cAAY,CACrD,IACE,IACN;AAEJ;AAEA,IAAO,gCAAQ;",
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport { OutputLine } from './OutputLine'\nimport React from 'react'\nimport { getTheme } from '@utils/theme'\nimport { Out as BashOut } from './BashTool'\n\ntype Props = {\n content: Omit<BashOut, 'interrupted'>\n verbose: boolean\n}\n\nfunction BashToolResultMessage({ content, verbose }: Props): React.JSX.Element {\n // Guard against undefined or null content\n if (!content) {\n return (\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text color={getTheme().secondaryText}>(No output)</Text>\n </Box>\n )\n }\n\n const { stdout, stdoutLines, stderr, stderrLines } = content\n\n return (\n <Box flexDirection=\"column\">\n {stdout !== '' ? (\n <OutputLine content={stdout} lines={stdoutLines} verbose={verbose} />\n ) : null}\n {stderr !== '' ? (\n <OutputLine\n content={stderr}\n lines={stderrLines}\n verbose={verbose}\n isError\n />\n ) : null}\n {stdout === '' && stderr === '' ? (\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Text color={getTheme().secondaryText}>(No content)</Text>\n </Box>\n ) : null}\n </Box>\n )\n}\n\nexport default BashToolResultMessage\n"],
5
+ "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,SAAS,kBAAkB;AAC3B,OAAO,WAAW;AAClB,SAAS,gBAAgB;AAQzB,SAAS,sBAAsB,EAAE,SAAS,QAAQ,GAA6B;AAE7E,MAAI,CAAC,SAAS;AACZ,WACE,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,QAAK,OAAO,SAAS,EAAE,iBAAe,aAAW,CACpD;AAAA,EAEJ;AAEA,QAAM,EAAE,QAAQ,aAAa,QAAQ,YAAY,IAAI;AAErD,SACE,oCAAC,OAAI,eAAc,YAChB,WAAW,KACV,oCAAC,cAAW,SAAS,QAAQ,OAAO,aAAa,SAAkB,IACjE,MACH,WAAW,KACV;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,OAAO;AAAA,MACP;AAAA,MACA,SAAO;AAAA;AAAA,EACT,IACE,MACH,WAAW,MAAM,WAAW,KAC3B,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,QAAK,OAAO,SAAS,EAAE,iBAAe,cAAY,CACrD,IACE,IACN;AAEJ;AAEA,IAAO,gCAAQ;",
6
6
  "names": []
7
7
  }
@@ -3,7 +3,61 @@ import * as React from "react";
3
3
  import { getTheme } from "../../utils/theme.js";
4
4
  import { MAX_RENDERED_LINES } from "./prompt.js";
5
5
  import chalk from "chalk";
6
+ function tryFormatGitCommit(content) {
7
+ const lines = content.trim().split("\n");
8
+ const commitMatch = lines[0]?.match(/^\[([^\]]+)\s+([a-f0-9]+)\]\s+(.+)$/);
9
+ if (!commitMatch) return null;
10
+ const [, branch, hash, message] = commitMatch;
11
+ const shortHash = hash.slice(0, 7);
12
+ const statsLine = lines.find((l) => l.match(/\d+\s+file.*changed/));
13
+ let stats = "";
14
+ if (statsLine) {
15
+ const filesMatch = statsLine.match(/(\d+)\s+file/);
16
+ const insertMatch = statsLine.match(/(\d+)\s+insertion/);
17
+ const deleteMatch = statsLine.match(/(\d+)\s+deletion/);
18
+ const parts = [];
19
+ if (filesMatch)
20
+ parts.push(`${filesMatch[1]} file${filesMatch[1] === "1" ? "" : "s"}`);
21
+ if (insertMatch) parts.push(`+${insertMatch[1]}`);
22
+ if (deleteMatch) parts.push(`-${deleteMatch[1]}`);
23
+ if (parts.length > 0) stats = ` (${parts.join(", ")})`;
24
+ }
25
+ const maxMsgLen = 50;
26
+ const truncatedMsg = message.length > maxMsgLen ? message.slice(0, maxMsgLen - 3) + "..." : message;
27
+ return `${shortHash} ${truncatedMsg}${stats}`;
28
+ }
29
+ function tryFormatGitStatus(content) {
30
+ const lines = content.trim().split("\n");
31
+ if (!lines.some(
32
+ (l) => l.includes("On branch") || l.includes("Changes") || l.includes("nothing to commit")
33
+ )) {
34
+ return null;
35
+ }
36
+ let staged = 0, modified = 0, untracked = 0;
37
+ let branch = "";
38
+ for (const line of lines) {
39
+ if (line.includes("On branch")) {
40
+ branch = line.replace("On branch", "").trim();
41
+ }
42
+ if (line.match(/^\s*(modified|new file|deleted):/)) staged++;
43
+ if (line.match(/^\s*modified:/)) modified++;
44
+ if (line.match(/^\?\?|Untracked files:/)) untracked++;
45
+ }
46
+ if (lines.some((l) => l.includes("nothing to commit"))) {
47
+ return branch ? `${branch}: clean` : "clean";
48
+ }
49
+ const parts = [];
50
+ if (branch) parts.push(branch);
51
+ if (staged > 0) parts.push(`${staged} staged`);
52
+ if (modified > 0) parts.push(`${modified} modified`);
53
+ if (untracked > 0) parts.push(`${untracked} untracked`);
54
+ return parts.length > 0 ? parts.join(", ") : null;
55
+ }
6
56
  function renderTruncatedContent(content, totalLines) {
57
+ const gitCommit = tryFormatGitCommit(content);
58
+ if (gitCommit) return gitCommit;
59
+ const gitStatus = tryFormatGitStatus(content);
60
+ if (gitStatus) return gitStatus;
7
61
  const allLines = content.split("\n");
8
62
  if (allLines.length <= MAX_RENDERED_LINES) {
9
63
  return allLines.join("\n");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/tools/BashTool/OutputLine.tsx"],
4
- "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { getTheme } from '@utils/theme'\nimport { MAX_RENDERED_LINES } from './prompt'\nimport chalk from 'chalk'\n\nfunction renderTruncatedContent(content: string, totalLines: number): string {\n const allLines = content.split('\\n')\n if (allLines.length <= MAX_RENDERED_LINES) {\n return allLines.join('\\n')\n }\n\n // Show last 5 lines of output by default (matching reference implementation)\n const lastLines = allLines.slice(-MAX_RENDERED_LINES)\n return [\n chalk.grey(\n `Showing last ${MAX_RENDERED_LINES} lines of ${totalLines} total lines`,\n ),\n ...lastLines,\n ].join('\\n')\n}\n\nexport function OutputLine({\n content,\n lines,\n verbose,\n isError,\n}: {\n content: string\n lines: number\n verbose: boolean\n isError?: boolean\n key?: React.Key\n}) {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Box flexDirection=\"column\">\n <Text color={isError ? getTheme().error : undefined}>\n {verbose\n ? content.trim()\n : renderTruncatedContent(content.trim(), lines)}\n </Text>\n </Box>\n </Box>\n </Box>\n )\n}\n"],
5
- "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,gBAAgB;AACzB,SAAS,0BAA0B;AACnC,OAAO,WAAW;AAElB,SAAS,uBAAuB,SAAiB,YAA4B;AAC3E,QAAM,WAAW,QAAQ,MAAM,IAAI;AACnC,MAAI,SAAS,UAAU,oBAAoB;AACzC,WAAO,SAAS,KAAK,IAAI;AAAA,EAC3B;AAGA,QAAM,YAAY,SAAS,MAAM,CAAC,kBAAkB;AACpD,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,gBAAgB,kBAAkB,aAAa,UAAU;AAAA,IAC3D;AAAA,IACA,GAAG;AAAA,EACL,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE,oCAAC,OAAI,gBAAe,iBAAgB,OAAM,UACxC,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,OAAI,eAAc,YACjB,oCAAC,QAAK,OAAO,UAAU,SAAS,EAAE,QAAQ,UACvC,UACG,QAAQ,KAAK,IACb,uBAAuB,QAAQ,KAAK,GAAG,KAAK,CAClD,CACF,CACF,CACF;AAEJ;",
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { getTheme } from '@utils/theme'\nimport { MAX_RENDERED_LINES } from './prompt'\nimport chalk from 'chalk'\n\n/**\n * Try to format git commit output as a concise single-line summary\n * Returns null if not a git commit output\n */\nfunction tryFormatGitCommit(content: string): string | null {\n const lines = content.trim().split('\\n')\n\n // Pattern: [branch hash] message\n const commitMatch = lines[0]?.match(/^\\[([^\\]]+)\\s+([a-f0-9]+)\\]\\s+(.+)$/)\n if (!commitMatch) return null\n\n const [, branch, hash, message] = commitMatch\n const shortHash = hash.slice(0, 7)\n\n // Look for file change stats\n const statsLine = lines.find(l => l.match(/\\d+\\s+file.*changed/))\n let stats = ''\n if (statsLine) {\n const filesMatch = statsLine.match(/(\\d+)\\s+file/)\n const insertMatch = statsLine.match(/(\\d+)\\s+insertion/)\n const deleteMatch = statsLine.match(/(\\d+)\\s+deletion/)\n const parts = []\n if (filesMatch)\n parts.push(`${filesMatch[1]} file${filesMatch[1] === '1' ? '' : 's'}`)\n if (insertMatch) parts.push(`+${insertMatch[1]}`)\n if (deleteMatch) parts.push(`-${deleteMatch[1]}`)\n if (parts.length > 0) stats = ` (${parts.join(', ')})`\n }\n\n // Truncate message if too long\n const maxMsgLen = 50\n const truncatedMsg =\n message.length > maxMsgLen\n ? message.slice(0, maxMsgLen - 3) + '...'\n : message\n\n return `${shortHash} ${truncatedMsg}${stats}`\n}\n\n/**\n * Try to format git status output concisely\n */\nfunction tryFormatGitStatus(content: string): string | null {\n const lines = content.trim().split('\\n')\n\n // Detect git status output\n if (\n !lines.some(\n l =>\n l.includes('On branch') ||\n l.includes('Changes') ||\n l.includes('nothing to commit'),\n )\n ) {\n return null\n }\n\n // Count different types of changes\n let staged = 0,\n modified = 0,\n untracked = 0\n let branch = ''\n\n for (const line of lines) {\n if (line.includes('On branch')) {\n branch = line.replace('On branch', '').trim()\n }\n if (line.match(/^\\s*(modified|new file|deleted):/)) staged++\n if (line.match(/^\\s*modified:/)) modified++\n if (line.match(/^\\?\\?|Untracked files:/)) untracked++\n }\n\n if (lines.some(l => l.includes('nothing to commit'))) {\n return branch ? `${branch}: clean` : 'clean'\n }\n\n const parts = []\n if (branch) parts.push(branch)\n if (staged > 0) parts.push(`${staged} staged`)\n if (modified > 0) parts.push(`${modified} modified`)\n if (untracked > 0) parts.push(`${untracked} untracked`)\n\n return parts.length > 0 ? parts.join(', ') : null\n}\n\nfunction renderTruncatedContent(content: string, totalLines: number): string {\n // Try git-specific formatting first\n const gitCommit = tryFormatGitCommit(content)\n if (gitCommit) return gitCommit\n\n const gitStatus = tryFormatGitStatus(content)\n if (gitStatus) return gitStatus\n\n const allLines = content.split('\\n')\n if (allLines.length <= MAX_RENDERED_LINES) {\n return allLines.join('\\n')\n }\n\n // Show last 5 lines of output by default (matching reference implementation)\n const lastLines = allLines.slice(-MAX_RENDERED_LINES)\n return [\n chalk.grey(\n `Showing last ${MAX_RENDERED_LINES} lines of ${totalLines} total lines`,\n ),\n ...lastLines,\n ].join('\\n')\n}\n\nexport function OutputLine({\n content,\n lines,\n verbose,\n isError,\n}: {\n content: string\n lines: number\n verbose: boolean\n isError?: boolean\n key?: React.Key\n}) {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text>&nbsp;&nbsp;\u23BF &nbsp;</Text>\n <Box flexDirection=\"column\">\n <Text color={isError ? getTheme().error : undefined}>\n {verbose\n ? content.trim()\n : renderTruncatedContent(content.trim(), lines)}\n </Text>\n </Box>\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }