@within-7/minto 0.1.7 → 0.2.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 (481) 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 +52 -26
  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 +84 -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 +156 -0
  22. package/dist/commands/export.js.map +7 -0
  23. package/dist/commands/mcp-interactive.js +21 -12
  24. package/dist/commands/mcp-interactive.js.map +2 -2
  25. package/dist/commands/model.js +6 -5
  26. package/dist/commands/model.js.map +2 -2
  27. package/dist/commands/permissions.js +86 -0
  28. package/dist/commands/permissions.js.map +7 -0
  29. package/dist/commands/quit.js +3 -1
  30. package/dist/commands/quit.js.map +2 -2
  31. package/dist/commands/sandbox.js +104 -0
  32. package/dist/commands/sandbox.js.map +7 -0
  33. package/dist/commands/status.js +58 -0
  34. package/dist/commands/status.js.map +7 -0
  35. package/dist/commands/tasks.js +108 -0
  36. package/dist/commands/tasks.js.map +7 -0
  37. package/dist/commands/todos.js +123 -0
  38. package/dist/commands/todos.js.map +7 -0
  39. package/dist/commands.js +20 -2
  40. package/dist/commands.js.map +2 -2
  41. package/dist/components/AgentThinkingBlock.js +10 -18
  42. package/dist/components/AgentThinkingBlock.js.map +2 -2
  43. package/dist/components/BackgroundTasksPanel.js +78 -29
  44. package/dist/components/BackgroundTasksPanel.js.map +2 -2
  45. package/dist/components/BashStreamingProgress.js +24 -0
  46. package/dist/components/BashStreamingProgress.js.map +7 -0
  47. package/dist/components/CollapsibleHint.js +14 -0
  48. package/dist/components/CollapsibleHint.js.map +7 -0
  49. package/dist/components/FileEditToolUpdatedMessage.js +1 -1
  50. package/dist/components/FileEditToolUpdatedMessage.js.map +2 -2
  51. package/dist/components/HotkeyHelpPanel.js +137 -0
  52. package/dist/components/HotkeyHelpPanel.js.map +7 -0
  53. package/dist/components/Logo.js +5 -5
  54. package/dist/components/Logo.js.map +2 -2
  55. package/dist/components/Message.js +23 -7
  56. package/dist/components/Message.js.map +3 -3
  57. package/dist/components/ModelConfig.js +16 -3
  58. package/dist/components/ModelConfig.js.map +2 -2
  59. package/dist/components/ModelListManager.js +3 -3
  60. package/dist/components/ModelListManager.js.map +2 -2
  61. package/dist/components/ModelSelector/ModelSelector.js +1 -1
  62. package/dist/components/Onboarding.js +19 -14
  63. package/dist/components/Onboarding.js.map +2 -2
  64. package/dist/components/ProgressBar.js +74 -0
  65. package/dist/components/ProgressBar.js.map +7 -0
  66. package/dist/components/PromptInput.js +156 -46
  67. package/dist/components/PromptInput.js.map +2 -2
  68. package/dist/components/RequestStatusIndicator.js +194 -0
  69. package/dist/components/RequestStatusIndicator.js.map +7 -0
  70. package/dist/components/Spinner.js +92 -27
  71. package/dist/components/Spinner.js.map +2 -2
  72. package/dist/components/SpinnerSymbol.js +21 -27
  73. package/dist/components/SpinnerSymbol.js.map +2 -2
  74. package/dist/components/StreamingBashOutput.js +9 -8
  75. package/dist/components/StreamingBashOutput.js.map +2 -2
  76. package/dist/components/SubagentBlock.js +1 -1
  77. package/dist/components/SubagentBlock.js.map +1 -1
  78. package/dist/components/SubagentProgress.js +10 -11
  79. package/dist/components/SubagentProgress.js.map +2 -2
  80. package/dist/components/TaskCard.js +16 -13
  81. package/dist/components/TaskCard.js.map +2 -2
  82. package/dist/components/TodoChangeBlock.js +1 -1
  83. package/dist/components/TodoChangeBlock.js.map +2 -2
  84. package/dist/components/TodoPanel.js +120 -29
  85. package/dist/components/TodoPanel.js.map +3 -3
  86. package/dist/components/TokenCounter.js +74 -0
  87. package/dist/components/TokenCounter.js.map +7 -0
  88. package/dist/components/TokenWarning.js +2 -1
  89. package/dist/components/TokenWarning.js.map +2 -2
  90. package/dist/components/TreeConnector.js +25 -0
  91. package/dist/components/TreeConnector.js.map +7 -0
  92. package/dist/components/TurnCompletionIndicator.js +18 -0
  93. package/dist/components/TurnCompletionIndicator.js.map +7 -0
  94. package/dist/components/messages/AssistantTextMessage.js +5 -2
  95. package/dist/components/messages/AssistantTextMessage.js.map +2 -2
  96. package/dist/components/messages/AssistantThinkingMessage.js +18 -3
  97. package/dist/components/messages/AssistantThinkingMessage.js.map +2 -2
  98. package/dist/components/messages/AssistantToolUseMessage.js +11 -8
  99. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  100. package/dist/components/messages/GroupRenderer.js +53 -0
  101. package/dist/components/messages/GroupRenderer.js.map +7 -0
  102. package/dist/components/messages/NestedTasksPreview.js +12 -0
  103. package/dist/components/messages/NestedTasksPreview.js.map +7 -0
  104. package/dist/components/messages/ParallelTasksGroupView.js +92 -0
  105. package/dist/components/messages/ParallelTasksGroupView.js.map +7 -0
  106. package/dist/components/messages/TaskInModuleView.js +198 -0
  107. package/dist/components/messages/TaskInModuleView.js.map +7 -0
  108. package/dist/components/messages/TaskOutputContent.js +53 -0
  109. package/dist/components/messages/TaskOutputContent.js.map +7 -0
  110. package/dist/components/messages/UserPromptMessage.js +1 -1
  111. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  112. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +2 -3
  113. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
  114. package/dist/components/permissions/FallbackPermissionRequest.js +4 -4
  115. package/dist/components/permissions/FallbackPermissionRequest.js.map +2 -2
  116. package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js +4 -4
  117. package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js.map +2 -2
  118. package/dist/constants/colors.js +48 -0
  119. package/dist/constants/colors.js.map +2 -2
  120. package/dist/constants/formatRules.js +102 -0
  121. package/dist/constants/formatRules.js.map +7 -0
  122. package/dist/constants/prompts.js +12 -34
  123. package/dist/constants/prompts.js.map +2 -2
  124. package/dist/constants/symbols.js +64 -6
  125. package/dist/constants/symbols.js.map +2 -2
  126. package/dist/constants/timing.js +5 -0
  127. package/dist/constants/timing.js.map +2 -2
  128. package/dist/core/config/defaults.js +84 -0
  129. package/dist/core/config/defaults.js.map +7 -0
  130. package/dist/core/config/index.js +111 -0
  131. package/dist/core/config/index.js.map +7 -0
  132. package/dist/core/config/loader.js +221 -0
  133. package/dist/core/config/loader.js.map +7 -0
  134. package/dist/core/config/migrations.js +128 -0
  135. package/dist/core/config/migrations.js.map +7 -0
  136. package/dist/core/config/schema.js +178 -0
  137. package/dist/core/config/schema.js.map +7 -0
  138. package/dist/core/costTracker.js +138 -0
  139. package/dist/core/costTracker.js.map +7 -0
  140. package/dist/core/index.js +5 -0
  141. package/dist/core/index.js.map +7 -0
  142. package/dist/core/permissions/auditLog.js +204 -0
  143. package/dist/core/permissions/auditLog.js.map +7 -0
  144. package/dist/core/permissions/engine/index.js +3 -0
  145. package/dist/core/permissions/engine/index.js.map +7 -0
  146. package/dist/core/permissions/engine/permissionEngine.js +106 -0
  147. package/dist/core/permissions/engine/permissionEngine.js.map +7 -0
  148. package/dist/core/permissions/engine/types.js +1 -0
  149. package/dist/core/permissions/engine/types.js.map +7 -0
  150. package/dist/core/permissions/index.js +84 -0
  151. package/dist/core/permissions/index.js.map +7 -0
  152. package/dist/core/permissions/ruleEngine.js +259 -0
  153. package/dist/core/permissions/ruleEngine.js.map +7 -0
  154. package/dist/core/permissions/rules/allowedToolsRule.js +62 -0
  155. package/dist/core/permissions/rules/allowedToolsRule.js.map +7 -0
  156. package/dist/core/permissions/rules/autoEscalationRule.js +291 -0
  157. package/dist/core/permissions/rules/autoEscalationRule.js.map +7 -0
  158. package/dist/core/permissions/rules/index.js +46 -0
  159. package/dist/core/permissions/rules/index.js.map +7 -0
  160. package/dist/core/permissions/rules/planModeRule.js +55 -0
  161. package/dist/core/permissions/rules/planModeRule.js.map +7 -0
  162. package/dist/core/permissions/rules/projectBoundaryRule.js +168 -0
  163. package/dist/core/permissions/rules/projectBoundaryRule.js.map +7 -0
  164. package/dist/core/permissions/rules/safeModeRule.js +65 -0
  165. package/dist/core/permissions/rules/safeModeRule.js.map +7 -0
  166. package/dist/core/permissions/rules/sensitivePathsRule.js +340 -0
  167. package/dist/core/permissions/rules/sensitivePathsRule.js.map +7 -0
  168. package/dist/core/permissions/types.js +127 -0
  169. package/dist/core/permissions/types.js.map +7 -0
  170. package/dist/core/tools/executor.js +143 -0
  171. package/dist/core/tools/executor.js.map +7 -0
  172. package/dist/core/tools/index.js +15 -0
  173. package/dist/core/tools/index.js.map +7 -0
  174. package/dist/core/tools/registry.js +183 -0
  175. package/dist/core/tools/registry.js.map +7 -0
  176. package/dist/core/tools/types.js +1 -0
  177. package/dist/core/tools/types.js.map +7 -0
  178. package/dist/cost-tracker.js +23 -15
  179. package/dist/cost-tracker.js.map +2 -2
  180. package/dist/entrypoints/cli.js +43 -43
  181. package/dist/entrypoints/cli.js.map +2 -2
  182. package/dist/entrypoints/mcp.js +12 -4
  183. package/dist/entrypoints/mcp.js.map +2 -2
  184. package/dist/history.js +14 -3
  185. package/dist/history.js.map +2 -2
  186. package/dist/hooks/useAgentTranscripts.js +116 -0
  187. package/dist/hooks/useAgentTranscripts.js.map +7 -0
  188. package/dist/hooks/useAnimationSync.js +53 -0
  189. package/dist/hooks/useAnimationSync.js.map +7 -0
  190. package/dist/hooks/useArrowKeyHistory.js +4 -2
  191. package/dist/hooks/useArrowKeyHistory.js.map +2 -2
  192. package/dist/hooks/useCanUseTool.js +3 -1
  193. package/dist/hooks/useCanUseTool.js.map +2 -2
  194. package/dist/hooks/useCancelRequest.js +4 -1
  195. package/dist/hooks/useCancelRequest.js.map +2 -2
  196. package/dist/hooks/useExitOnCtrlCD.js +9 -5
  197. package/dist/hooks/useExitOnCtrlCD.js.map +2 -2
  198. package/dist/hooks/useHookStatus.js +40 -0
  199. package/dist/hooks/useHookStatus.js.map +7 -0
  200. package/dist/hooks/useLogMessages.js +17 -1
  201. package/dist/hooks/useLogMessages.js.map +2 -2
  202. package/dist/hooks/useMessageGroups.js +43 -0
  203. package/dist/hooks/useMessageGroups.js.map +7 -0
  204. package/dist/hooks/useTerminalSize.js +62 -6
  205. package/dist/hooks/useTerminalSize.js.map +2 -2
  206. package/dist/hooks/useUnifiedCompletion.js +69 -0
  207. package/dist/hooks/useUnifiedCompletion.js.map +2 -2
  208. package/dist/i18n/index.js +109 -0
  209. package/dist/i18n/index.js.map +7 -0
  210. package/dist/i18n/locales/en.js +347 -0
  211. package/dist/i18n/locales/en.js.map +7 -0
  212. package/dist/i18n/locales/index.js +7 -0
  213. package/dist/i18n/locales/index.js.map +7 -0
  214. package/dist/i18n/locales/zh-CN.js +347 -0
  215. package/dist/i18n/locales/zh-CN.js.map +7 -0
  216. package/dist/i18n/types.js +8 -0
  217. package/dist/i18n/types.js.map +7 -0
  218. package/dist/query.js +175 -17
  219. package/dist/query.js.map +3 -3
  220. package/dist/screens/REPL.js +501 -192
  221. package/dist/screens/REPL.js.map +3 -3
  222. package/dist/services/adapters/chatCompletions.js +3 -1
  223. package/dist/services/adapters/chatCompletions.js.map +2 -2
  224. package/dist/services/adapters/messageNormalizer.js +354 -0
  225. package/dist/services/adapters/messageNormalizer.js.map +7 -0
  226. package/dist/services/adapters/responsesAPI.js +6 -3
  227. package/dist/services/adapters/responsesAPI.js.map +2 -2
  228. package/dist/services/checkpointManager.js +386 -0
  229. package/dist/services/checkpointManager.js.map +7 -0
  230. package/dist/services/claude.js +138 -11
  231. package/dist/services/claude.js.map +3 -3
  232. package/dist/services/compressionService.js +50 -1
  233. package/dist/services/compressionService.js.map +2 -2
  234. package/dist/services/contextMonitor.js +162 -0
  235. package/dist/services/contextMonitor.js.map +7 -0
  236. package/dist/services/customCommands.js +60 -41
  237. package/dist/services/customCommands.js.map +2 -2
  238. package/dist/services/hookExecutor.js +173 -1
  239. package/dist/services/hookExecutor.js.map +2 -2
  240. package/dist/services/intelligentCompactor.js +281 -0
  241. package/dist/services/intelligentCompactor.js.map +7 -0
  242. package/dist/services/lspConfig.js +109 -0
  243. package/dist/services/lspConfig.js.map +7 -0
  244. package/dist/services/mcpClient.js +273 -34
  245. package/dist/services/mcpClient.js.map +2 -2
  246. package/dist/services/modelOrchestrator.js +310 -0
  247. package/dist/services/modelOrchestrator.js.map +7 -0
  248. package/dist/services/openai.js +8 -1
  249. package/dist/services/openai.js.map +2 -2
  250. package/dist/services/outputStyles.js +138 -0
  251. package/dist/services/outputStyles.js.map +7 -0
  252. package/dist/services/plugins/index.js +5 -0
  253. package/dist/services/plugins/index.js.map +7 -0
  254. package/dist/services/plugins/lspServers.js +188 -0
  255. package/dist/services/plugins/lspServers.js.map +7 -0
  256. package/dist/services/plugins/pluginRuntime.js +229 -0
  257. package/dist/services/plugins/pluginRuntime.js.map +7 -0
  258. package/dist/services/plugins/pluginValidation.js +219 -0
  259. package/dist/services/plugins/pluginValidation.js.map +7 -0
  260. package/dist/services/plugins/skillMarketplace.js +556 -0
  261. package/dist/services/plugins/skillMarketplace.js.map +7 -0
  262. package/dist/services/responseStateManager.js +37 -3
  263. package/dist/services/responseStateManager.js.map +2 -2
  264. package/dist/services/sandbox/filesystemBoundary.js +300 -0
  265. package/dist/services/sandbox/filesystemBoundary.js.map +7 -0
  266. package/dist/services/sandbox/index.js +14 -0
  267. package/dist/services/sandbox/index.js.map +7 -0
  268. package/dist/services/sandbox/networkProxy.js +293 -0
  269. package/dist/services/sandbox/networkProxy.js.map +7 -0
  270. package/dist/services/sandbox/sandboxController.js +574 -0
  271. package/dist/services/sandbox/sandboxController.js.map +7 -0
  272. package/dist/services/sandbox/types.js +50 -0
  273. package/dist/services/sandbox/types.js.map +7 -0
  274. package/dist/services/sessionMemory.js +266 -0
  275. package/dist/services/sessionMemory.js.map +7 -0
  276. package/dist/services/taskRouter.js +324 -0
  277. package/dist/services/taskRouter.js.map +7 -0
  278. package/dist/tools/ArchitectTool/ArchitectTool.js +7 -1
  279. package/dist/tools/ArchitectTool/ArchitectTool.js.map +2 -2
  280. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +3 -0
  281. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  282. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
  283. package/dist/tools/BaseTool.js +72 -0
  284. package/dist/tools/BaseTool.js.map +7 -0
  285. package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js +3 -0
  286. package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js.map +2 -2
  287. package/dist/tools/BashTool/BashTool.js +60 -3
  288. package/dist/tools/BashTool/BashTool.js.map +2 -2
  289. package/dist/tools/BashTool/BashToolResultMessage.js +3 -0
  290. package/dist/tools/BashTool/BashToolResultMessage.js.map +2 -2
  291. package/dist/tools/BashTool/OutputLine.js +54 -0
  292. package/dist/tools/BashTool/OutputLine.js.map +2 -2
  293. package/dist/tools/BashTool/prompt.js +192 -3
  294. package/dist/tools/BashTool/prompt.js.map +2 -2
  295. package/dist/tools/FileEditTool/FileEditTool.js +29 -4
  296. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  297. package/dist/tools/FileWriteTool/FileWriteTool.js +5 -5
  298. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  299. package/dist/tools/GlobTool/GlobTool.js +4 -2
  300. package/dist/tools/GlobTool/GlobTool.js.map +2 -2
  301. package/dist/tools/GrepTool/GrepTool.js +36 -7
  302. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  303. package/dist/tools/KillShellTool/KillShellToolResultMessage.js +3 -0
  304. package/dist/tools/KillShellTool/KillShellToolResultMessage.js.map +2 -2
  305. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js +109 -0
  306. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +7 -0
  307. package/dist/tools/ListMcpResourcesTool/prompt.js +19 -0
  308. package/dist/tools/ListMcpResourcesTool/prompt.js.map +7 -0
  309. package/dist/tools/LspTool/LspTool.js +664 -0
  310. package/dist/tools/LspTool/LspTool.js.map +7 -0
  311. package/dist/tools/LspTool/prompt.js +27 -0
  312. package/dist/tools/LspTool/prompt.js.map +7 -0
  313. package/dist/tools/MCPTool/MCPTool.js +9 -1
  314. package/dist/tools/MCPTool/MCPTool.js.map +2 -2
  315. package/dist/tools/MemoryReadTool/MemoryReadTool.js +19 -6
  316. package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +2 -2
  317. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +6 -6
  318. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +2 -2
  319. package/dist/tools/MultiEditTool/MultiEditTool.js +19 -2
  320. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  321. package/dist/tools/NotebookEditTool/NotebookEditTool.js +5 -1
  322. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  323. package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +2 -2
  324. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +74 -0
  325. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +7 -0
  326. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +108 -0
  327. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +7 -0
  328. package/dist/tools/PlanModeTool/prompt.js +94 -0
  329. package/dist/tools/PlanModeTool/prompt.js.map +7 -0
  330. package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js +130 -0
  331. package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js.map +7 -0
  332. package/dist/tools/ReadMcpResourceTool/prompt.js +17 -0
  333. package/dist/tools/ReadMcpResourceTool/prompt.js.map +7 -0
  334. package/dist/tools/SkillTool/SkillTool.js +6 -1
  335. package/dist/tools/SkillTool/SkillTool.js.map +2 -2
  336. package/dist/tools/SlashCommandTool/SlashCommandTool.js +260 -0
  337. package/dist/tools/SlashCommandTool/SlashCommandTool.js.map +7 -0
  338. package/dist/tools/SlashCommandTool/prompt.js +35 -0
  339. package/dist/tools/SlashCommandTool/prompt.js.map +7 -0
  340. package/dist/tools/TaskOutputTool/TaskOutputTool.js +189 -0
  341. package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +7 -0
  342. package/dist/tools/TaskOutputTool/prompt.js +15 -0
  343. package/dist/tools/TaskOutputTool/prompt.js.map +7 -0
  344. package/dist/tools/TaskTool/TaskTool.js +302 -104
  345. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  346. package/dist/tools/TaskTool/prompt.js.map +2 -2
  347. package/dist/tools/TodoWriteTool/TodoWriteTool.js +42 -77
  348. package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +2 -2
  349. package/dist/tools/URLFetcherTool/URLFetcherTool.js +4 -1
  350. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  351. package/dist/tools/URLFetcherTool/cache.js +55 -8
  352. package/dist/tools/URLFetcherTool/cache.js.map +2 -2
  353. package/dist/tools.js +31 -2
  354. package/dist/tools.js.map +2 -2
  355. package/dist/types/hooks.js +4 -0
  356. package/dist/types/hooks.js.map +2 -2
  357. package/dist/types/marketplace.js.map +2 -2
  358. package/dist/types/messageGroup.js +36 -0
  359. package/dist/types/messageGroup.js.map +7 -0
  360. package/dist/types/plugin.js.map +2 -2
  361. package/dist/types/thinking.js +1 -0
  362. package/dist/types/thinking.js.map +7 -0
  363. package/dist/utils/BackgroundShellManager.js +136 -39
  364. package/dist/utils/BackgroundShellManager.js.map +2 -2
  365. package/dist/utils/MessageBatchBuffer.js +102 -0
  366. package/dist/utils/MessageBatchBuffer.js.map +7 -0
  367. package/dist/utils/PersistentShell.js +151 -1
  368. package/dist/utils/PersistentShell.js.map +2 -2
  369. package/dist/utils/agentLoader.js +1 -23
  370. package/dist/utils/agentLoader.js.map +2 -2
  371. package/dist/utils/agentTranscripts.js +641 -0
  372. package/dist/utils/agentTranscripts.js.map +7 -0
  373. package/dist/utils/animationManager.js +213 -0
  374. package/dist/utils/animationManager.js.map +7 -0
  375. package/dist/utils/animationSync.js +110 -0
  376. package/dist/utils/animationSync.js.map +7 -0
  377. package/dist/utils/asyncFile.js +215 -0
  378. package/dist/utils/asyncFile.js.map +7 -0
  379. package/dist/utils/backgroundAgentManager.js +231 -0
  380. package/dist/utils/backgroundAgentManager.js.map +7 -0
  381. package/dist/utils/config.js +63 -7
  382. package/dist/utils/config.js.map +2 -2
  383. package/dist/utils/conversationRecovery.js +19 -0
  384. package/dist/utils/conversationRecovery.js.map +2 -2
  385. package/dist/utils/exit.js +73 -0
  386. package/dist/utils/exit.js.map +7 -0
  387. package/dist/utils/format.js +73 -5
  388. package/dist/utils/format.js.map +2 -2
  389. package/dist/utils/generators.js +76 -6
  390. package/dist/utils/generators.js.map +2 -2
  391. package/dist/utils/globalErrorHandler.js +149 -0
  392. package/dist/utils/globalErrorHandler.js.map +7 -0
  393. package/dist/utils/groupHandlers/index.js +8 -0
  394. package/dist/utils/groupHandlers/index.js.map +7 -0
  395. package/dist/utils/groupHandlers/parallelTasksHandler.js +140 -0
  396. package/dist/utils/groupHandlers/parallelTasksHandler.js.map +7 -0
  397. package/dist/utils/groupHandlers/taskHandler.js +104 -0
  398. package/dist/utils/groupHandlers/taskHandler.js.map +7 -0
  399. package/dist/utils/groupHandlers/types.js +1 -0
  400. package/dist/utils/groupHandlers/types.js.map +7 -0
  401. package/dist/utils/logRotation.js +224 -0
  402. package/dist/utils/logRotation.js.map +7 -0
  403. package/dist/utils/marketplaceManager.js +3 -5
  404. package/dist/utils/marketplaceManager.js.map +2 -2
  405. package/dist/utils/memSafety.js +264 -0
  406. package/dist/utils/memSafety.js.map +7 -0
  407. package/dist/utils/messageGroupManager.js +274 -0
  408. package/dist/utils/messageGroupManager.js.map +7 -0
  409. package/dist/utils/messages.js +13 -4
  410. package/dist/utils/messages.js.map +2 -2
  411. package/dist/utils/model.js +119 -15
  412. package/dist/utils/model.js.map +3 -3
  413. package/dist/utils/permissions/filesystem.js +157 -5
  414. package/dist/utils/permissions/filesystem.js.map +2 -2
  415. package/dist/utils/plan/planMode.js +143 -0
  416. package/dist/utils/plan/planMode.js.map +7 -0
  417. package/dist/utils/pluginLoader.js +17 -21
  418. package/dist/utils/pluginLoader.js.map +2 -2
  419. package/dist/utils/ripgrep.js +55 -2
  420. package/dist/utils/ripgrep.js.map +2 -2
  421. package/dist/utils/sanitizeInput.js +32 -0
  422. package/dist/utils/sanitizeInput.js.map +7 -0
  423. package/dist/utils/secureKeyStorage.js +312 -0
  424. package/dist/utils/secureKeyStorage.js.map +7 -0
  425. package/dist/utils/session/sessionPlugins.js +67 -0
  426. package/dist/utils/session/sessionPlugins.js.map +7 -0
  427. package/dist/utils/taskDisplayUtils.js +257 -0
  428. package/dist/utils/taskDisplayUtils.js.map +7 -0
  429. package/dist/utils/teamConfig.js +2 -1
  430. package/dist/utils/teamConfig.js.map +2 -2
  431. package/dist/utils/todoStorage.js +92 -2
  432. package/dist/utils/todoStorage.js.map +2 -2
  433. package/dist/utils/toolTimeout.js +136 -0
  434. package/dist/utils/toolTimeout.js.map +7 -0
  435. package/dist/utils/tooling/safeRender.js +115 -0
  436. package/dist/utils/tooling/safeRender.js.map +7 -0
  437. package/dist/utils/userFriendlyError.js +346 -0
  438. package/dist/utils/userFriendlyError.js.map +7 -0
  439. package/dist/utils/vendor/ripgrep/arm64-darwin/rg +0 -0
  440. package/dist/version.js +2 -2
  441. package/dist/version.js.map +1 -1
  442. package/package.json +14 -4
  443. package/scripts/postinstall.js +128 -38
  444. package/dist/commands/agents.js +0 -2086
  445. package/dist/commands/agents.js.map +0 -7
  446. package/dist/commands/build.js +0 -74
  447. package/dist/commands/build.js.map +0 -7
  448. package/dist/commands/compression.js +0 -57
  449. package/dist/commands/compression.js.map +0 -7
  450. package/dist/commands/listen.js +0 -37
  451. package/dist/commands/listen.js.map +0 -7
  452. package/dist/commands/login.js +0 -37
  453. package/dist/commands/login.js.map +0 -7
  454. package/dist/commands/logout.js +0 -33
  455. package/dist/commands/logout.js.map +0 -7
  456. package/dist/commands/mcp.js +0 -40
  457. package/dist/commands/mcp.js.map +0 -7
  458. package/dist/commands/mcp_refresh.js +0 -40
  459. package/dist/commands/mcp_refresh.js.map +0 -7
  460. package/dist/commands/modelstatus.js +0 -21
  461. package/dist/commands/modelstatus.js.map +0 -7
  462. package/dist/commands/onboarding.js +0 -36
  463. package/dist/commands/onboarding.js.map +0 -7
  464. package/dist/commands/plugin-interactive.js +0 -446
  465. package/dist/commands/plugin-interactive.js.map +0 -7
  466. package/dist/commands/pr_comments.js +0 -61
  467. package/dist/commands/pr_comments.js.map +0 -7
  468. package/dist/commands/release-notes.js +0 -30
  469. package/dist/commands/release-notes.js.map +0 -7
  470. package/dist/commands/review.js +0 -51
  471. package/dist/commands/review.js.map +0 -7
  472. package/dist/components/Bug.js +0 -147
  473. package/dist/components/Bug.js.map +0 -7
  474. package/dist/components/ModelSelector.js +0 -2062
  475. package/dist/components/ModelSelector.js.map +0 -7
  476. package/dist/components/ModelStatusDisplay.js +0 -87
  477. package/dist/components/ModelStatusDisplay.js.map +0 -7
  478. package/dist/entrypoints/cli-wrapper.js +0 -61
  479. package/dist/entrypoints/cli-wrapper.js.map +0 -7
  480. package/dist/screens/Doctor.js +0 -22
  481. package/dist/screens/Doctor.js.map +0 -7
@@ -0,0 +1,116 @@
1
+ import { useState, useEffect, useMemo, useCallback } from "react";
2
+ import {
3
+ transcriptEmitter,
4
+ getAgentTranscript
5
+ } from "../utils/agentTranscripts.js";
6
+ function useAgentTranscripts(agentIds) {
7
+ const [transcripts, setTranscripts] = useState(
8
+ () => /* @__PURE__ */ new Map()
9
+ );
10
+ const trackedAgentIds = useMemo(
11
+ () => agentIds ? new Set(agentIds) : null,
12
+ [agentIds?.join(",")]
13
+ );
14
+ useEffect(() => {
15
+ const handleUpdate = (event) => {
16
+ if (trackedAgentIds && !trackedAgentIds.has(event.agentId)) {
17
+ return;
18
+ }
19
+ setTranscripts((prev) => {
20
+ const next = new Map(prev);
21
+ next.set(event.agentId, event.transcript);
22
+ return next;
23
+ });
24
+ };
25
+ transcriptEmitter.on("update", handleUpdate);
26
+ if (trackedAgentIds) {
27
+ for (const agentId of trackedAgentIds) {
28
+ const transcript = getAgentTranscript(agentId);
29
+ if (transcript) {
30
+ setTranscripts((prev) => {
31
+ const next = new Map(prev);
32
+ next.set(agentId, transcript);
33
+ return next;
34
+ });
35
+ }
36
+ }
37
+ }
38
+ return () => {
39
+ transcriptEmitter.off("update", handleUpdate);
40
+ };
41
+ }, [trackedAgentIds]);
42
+ const getTranscriptCallback = useCallback(
43
+ (agentId) => {
44
+ const cached = transcripts.get(agentId);
45
+ if (cached) {
46
+ return cached;
47
+ }
48
+ const loaded = getAgentTranscript(agentId);
49
+ if (loaded) {
50
+ setTranscripts((prev) => {
51
+ const next = new Map(prev);
52
+ next.set(agentId, loaded);
53
+ return next;
54
+ });
55
+ }
56
+ return loaded;
57
+ },
58
+ [transcripts]
59
+ );
60
+ const refreshTranscript = useCallback((agentId) => {
61
+ const fresh = getAgentTranscript(agentId);
62
+ if (fresh) {
63
+ setTranscripts((prev) => {
64
+ const next = new Map(prev);
65
+ next.set(agentId, fresh);
66
+ return next;
67
+ });
68
+ }
69
+ }, []);
70
+ const activeCount = useMemo(() => {
71
+ let count = 0;
72
+ for (const transcript of transcripts.values()) {
73
+ if (transcript.status === "running" || transcript.status === "pending") {
74
+ count++;
75
+ }
76
+ }
77
+ return count;
78
+ }, [transcripts]);
79
+ return {
80
+ transcripts,
81
+ getTranscript: getTranscriptCallback,
82
+ refreshTranscript,
83
+ activeCount
84
+ };
85
+ }
86
+ function useAgentTranscript(agentId) {
87
+ const [transcript, setTranscript] = useState(() => {
88
+ if (!agentId) return null;
89
+ return getAgentTranscript(agentId);
90
+ });
91
+ useEffect(() => {
92
+ if (!agentId) {
93
+ setTranscript(null);
94
+ return;
95
+ }
96
+ const initial = getAgentTranscript(agentId);
97
+ if (initial) {
98
+ setTranscript(initial);
99
+ }
100
+ const handleUpdate = (event) => {
101
+ if (event.agentId === agentId) {
102
+ setTranscript(event.transcript);
103
+ }
104
+ };
105
+ transcriptEmitter.on("update", handleUpdate);
106
+ return () => {
107
+ transcriptEmitter.off("update", handleUpdate);
108
+ };
109
+ }, [agentId]);
110
+ return transcript;
111
+ }
112
+ export {
113
+ useAgentTranscript,
114
+ useAgentTranscripts
115
+ };
116
+ //# sourceMappingURL=useAgentTranscripts.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hooks/useAgentTranscripts.ts"],
4
+ "sourcesContent": ["/**\n * useAgentTranscripts Hook\n *\n * Provides real-time access to agent transcripts with automatic updates.\n * Subscribes to transcript events and maintains a reactive map of transcripts.\n */\n\nimport { useState, useEffect, useMemo, useCallback } from 'react'\nimport {\n transcriptEmitter,\n getAgentTranscript,\n type AgentTranscript,\n type TranscriptEvent,\n} from '@utils/agentTranscripts'\n\ninterface UseAgentTranscriptsResult {\n /** Map of agentId to transcript */\n transcripts: Map<string, AgentTranscript>\n /** Get transcript by agentId */\n getTranscript: (agentId: string) => AgentTranscript | null\n /** Force refresh of a specific transcript */\n refreshTranscript: (agentId: string) => void\n /** Number of active transcripts */\n activeCount: number\n}\n\n/**\n * Hook for accessing agent transcripts with real-time updates\n *\n * @param agentIds - Optional list of specific agent IDs to track\n * @returns Transcript state and utilities\n */\nexport function useAgentTranscripts(\n agentIds?: string[],\n): UseAgentTranscriptsResult {\n // State to hold current transcripts\n const [transcripts, setTranscripts] = useState<Map<string, AgentTranscript>>(\n () => new Map(),\n )\n\n // Track which agents we're interested in\n const trackedAgentIds = useMemo(\n () => (agentIds ? new Set(agentIds) : null),\n [agentIds?.join(',')],\n )\n\n // Handle transcript updates\n useEffect(() => {\n const handleUpdate = (event: TranscriptEvent) => {\n // If we have a tracked list and this agent isn't in it, skip\n if (trackedAgentIds && !trackedAgentIds.has(event.agentId)) {\n return\n }\n\n setTranscripts(prev => {\n const next = new Map(prev)\n next.set(event.agentId, event.transcript)\n return next\n })\n }\n\n // Subscribe to all transcript updates\n transcriptEmitter.on('update', handleUpdate)\n\n // Initial load for tracked agents\n if (trackedAgentIds) {\n for (const agentId of trackedAgentIds) {\n const transcript = getAgentTranscript(agentId)\n if (transcript) {\n setTranscripts(prev => {\n const next = new Map(prev)\n next.set(agentId, transcript)\n return next\n })\n }\n }\n }\n\n return () => {\n transcriptEmitter.off('update', handleUpdate)\n }\n }, [trackedAgentIds])\n\n // Get transcript by ID (with fallback to disk)\n const getTranscriptCallback = useCallback(\n (agentId: string): AgentTranscript | null => {\n // Check memory first\n const cached = transcripts.get(agentId)\n if (cached) {\n return cached\n }\n\n // Try to load from disk\n const loaded = getAgentTranscript(agentId)\n if (loaded) {\n // Cache in state for future use\n setTranscripts(prev => {\n const next = new Map(prev)\n next.set(agentId, loaded)\n return next\n })\n }\n return loaded\n },\n [transcripts],\n )\n\n // Force refresh a specific transcript\n const refreshTranscript = useCallback((agentId: string) => {\n const fresh = getAgentTranscript(agentId)\n if (fresh) {\n setTranscripts(prev => {\n const next = new Map(prev)\n next.set(agentId, fresh)\n return next\n })\n }\n }, [])\n\n // Count active (non-completed) transcripts\n const activeCount = useMemo(() => {\n let count = 0\n for (const transcript of transcripts.values()) {\n if (transcript.status === 'running' || transcript.status === 'pending') {\n count++\n }\n }\n return count\n }, [transcripts])\n\n return {\n transcripts,\n getTranscript: getTranscriptCallback,\n refreshTranscript,\n activeCount,\n }\n}\n\n/**\n * Simplified hook for single transcript tracking\n */\nexport function useAgentTranscript(\n agentId: string | undefined,\n): AgentTranscript | null {\n const [transcript, setTranscript] = useState<AgentTranscript | null>(() => {\n if (!agentId) return null\n return getAgentTranscript(agentId)\n })\n\n useEffect(() => {\n if (!agentId) {\n setTranscript(null)\n return\n }\n\n // Load initial\n const initial = getAgentTranscript(agentId)\n if (initial) {\n setTranscript(initial)\n }\n\n // Subscribe to updates for this specific agent\n const handleUpdate = (event: TranscriptEvent) => {\n if (event.agentId === agentId) {\n setTranscript(event.transcript)\n }\n }\n\n transcriptEmitter.on('update', handleUpdate)\n return () => {\n transcriptEmitter.off('update', handleUpdate)\n }\n }, [agentId])\n\n return transcript\n}\n"],
5
+ "mappings": "AAOA,SAAS,UAAU,WAAW,SAAS,mBAAmB;AAC1D;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAmBA,SAAS,oBACd,UAC2B;AAE3B,QAAM,CAAC,aAAa,cAAc,IAAI;AAAA,IACpC,MAAM,oBAAI,IAAI;AAAA,EAChB;AAGA,QAAM,kBAAkB;AAAA,IACtB,MAAO,WAAW,IAAI,IAAI,QAAQ,IAAI;AAAA,IACtC,CAAC,UAAU,KAAK,GAAG,CAAC;AAAA,EACtB;AAGA,YAAU,MAAM;AACd,UAAM,eAAe,CAAC,UAA2B;AAE/C,UAAI,mBAAmB,CAAC,gBAAgB,IAAI,MAAM,OAAO,GAAG;AAC1D;AAAA,MACF;AAEA,qBAAe,UAAQ;AACrB,cAAM,OAAO,IAAI,IAAI,IAAI;AACzB,aAAK,IAAI,MAAM,SAAS,MAAM,UAAU;AACxC,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAGA,sBAAkB,GAAG,UAAU,YAAY;AAG3C,QAAI,iBAAiB;AACnB,iBAAW,WAAW,iBAAiB;AACrC,cAAM,aAAa,mBAAmB,OAAO;AAC7C,YAAI,YAAY;AACd,yBAAe,UAAQ;AACrB,kBAAM,OAAO,IAAI,IAAI,IAAI;AACzB,iBAAK,IAAI,SAAS,UAAU;AAC5B,mBAAO;AAAA,UACT,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,WAAO,MAAM;AACX,wBAAkB,IAAI,UAAU,YAAY;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAGpB,QAAM,wBAAwB;AAAA,IAC5B,CAAC,YAA4C;AAE3C,YAAM,SAAS,YAAY,IAAI,OAAO;AACtC,UAAI,QAAQ;AACV,eAAO;AAAA,MACT;AAGA,YAAM,SAAS,mBAAmB,OAAO;AACzC,UAAI,QAAQ;AAEV,uBAAe,UAAQ;AACrB,gBAAM,OAAO,IAAI,IAAI,IAAI;AACzB,eAAK,IAAI,SAAS,MAAM;AACxB,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAGA,QAAM,oBAAoB,YAAY,CAAC,YAAoB;AACzD,UAAM,QAAQ,mBAAmB,OAAO;AACxC,QAAI,OAAO;AACT,qBAAe,UAAQ;AACrB,cAAM,OAAO,IAAI,IAAI,IAAI;AACzB,aAAK,IAAI,SAAS,KAAK;AACvB,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,cAAc,QAAQ,MAAM;AAChC,QAAI,QAAQ;AACZ,eAAW,cAAc,YAAY,OAAO,GAAG;AAC7C,UAAI,WAAW,WAAW,aAAa,WAAW,WAAW,WAAW;AACtE;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT,GAAG,CAAC,WAAW,CAAC;AAEhB,SAAO;AAAA,IACL;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACF;AAKO,SAAS,mBACd,SACwB;AACxB,QAAM,CAAC,YAAY,aAAa,IAAI,SAAiC,MAAM;AACzE,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO,mBAAmB,OAAO;AAAA,EACnC,CAAC;AAED,YAAU,MAAM;AACd,QAAI,CAAC,SAAS;AACZ,oBAAc,IAAI;AAClB;AAAA,IACF;AAGA,UAAM,UAAU,mBAAmB,OAAO;AAC1C,QAAI,SAAS;AACX,oBAAc,OAAO;AAAA,IACvB;AAGA,UAAM,eAAe,CAAC,UAA2B;AAC/C,UAAI,MAAM,YAAY,SAAS;AAC7B,sBAAc,MAAM,UAAU;AAAA,MAChC;AAAA,IACF;AAEA,sBAAkB,GAAG,UAAU,YAAY;AAC3C,WAAO,MAAM;AACX,wBAAkB,IAAI,UAAU,YAAY;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,53 @@
1
+ import { useState, useEffect } from "react";
2
+ import { animationSync, ANIMATION_INTERVALS } from "../utils/animationSync.js";
3
+ function useAnimationSync() {
4
+ const [state, setState] = useState(
5
+ () => animationSync.getFrame()
6
+ );
7
+ useEffect(() => {
8
+ const unsubscribe = animationSync.subscribe((frame) => {
9
+ setState(frame);
10
+ });
11
+ return unsubscribe;
12
+ }, []);
13
+ return state;
14
+ }
15
+ function useSpinnerAnimation(frames) {
16
+ const [frameIndex, setFrameIndex] = useState(0);
17
+ useEffect(() => {
18
+ const timer = setInterval(() => {
19
+ setFrameIndex((f) => (f + 1) % frames.length);
20
+ }, ANIMATION_INTERVALS.SPINNER);
21
+ return () => clearInterval(timer);
22
+ }, [frames.length]);
23
+ return frames[frameIndex] || frames[0] || "";
24
+ }
25
+ function useBlinkAnimation() {
26
+ const [visible, setVisible] = useState(true);
27
+ useEffect(() => {
28
+ const timer = setInterval(() => {
29
+ setVisible((v) => !v);
30
+ }, ANIMATION_INTERVALS.BLINK);
31
+ return () => clearInterval(timer);
32
+ }, []);
33
+ return visible;
34
+ }
35
+ function useElapsedTime(startTime) {
36
+ const [elapsed, setElapsed] = useState(0);
37
+ const start = startTime ?? Date.now();
38
+ useEffect(() => {
39
+ const timer = setInterval(() => {
40
+ setElapsed(Math.floor((Date.now() - start) / 1e3));
41
+ }, ANIMATION_INTERVALS.ELAPSED_TIME);
42
+ return () => clearInterval(timer);
43
+ }, [start]);
44
+ return elapsed;
45
+ }
46
+ export {
47
+ ANIMATION_INTERVALS,
48
+ useAnimationSync,
49
+ useBlinkAnimation,
50
+ useElapsedTime,
51
+ useSpinnerAnimation
52
+ };
53
+ //# sourceMappingURL=useAnimationSync.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hooks/useAnimationSync.ts"],
4
+ "sourcesContent": ["/**\n * React hook for synchronized animations across components\n *\n * Provides synchronized animation state that updates at consistent intervals:\n * - Spinner: 120ms\n * - Blinking: 600ms\n * - Elapsed Time: 1000ms\n *\n * Usage:\n * ```tsx\n * function MySpinner() {\n * const { spinnerFrame, blinkVisible, elapsedSeconds } = useAnimationSync()\n * const spinnerChars = ['\u00B7', '\u2722', '\u2733', '\u2217', '\u273B', '\u273D']\n * return <Text>{spinnerChars[spinnerFrame % spinnerChars.length]}</Text>\n * }\n * ```\n */\n\nimport { useState, useEffect, useCallback } from 'react'\nimport { animationSync, ANIMATION_INTERVALS } from '@utils/animationSync'\n\nexport interface AnimationState {\n spinnerFrame: number\n blinkVisible: boolean\n elapsedSeconds: number\n}\n\n/**\n * Hook for synchronized animation state\n * Components using this hook will animate in sync with each other\n */\nexport function useAnimationSync(): AnimationState {\n const [state, setState] = useState<AnimationState>(() =>\n animationSync.getFrame(),\n )\n\n useEffect(() => {\n const unsubscribe = animationSync.subscribe(frame => {\n setState(frame)\n })\n\n return unsubscribe\n }, [])\n\n return state\n}\n\n/**\n * Hook for just the spinner animation (120ms interval)\n * Lighter weight than full animation sync if you only need spinner\n */\nexport function useSpinnerAnimation(frames: string[]): string {\n const [frameIndex, setFrameIndex] = useState(0)\n\n useEffect(() => {\n const timer = setInterval(() => {\n setFrameIndex(f => (f + 1) % frames.length)\n }, ANIMATION_INTERVALS.SPINNER)\n\n return () => clearInterval(timer)\n }, [frames.length])\n\n return frames[frameIndex] || frames[0] || ''\n}\n\n/**\n * Hook for blinking animation (600ms interval)\n */\nexport function useBlinkAnimation(): boolean {\n const [visible, setVisible] = useState(true)\n\n useEffect(() => {\n const timer = setInterval(() => {\n setVisible(v => !v)\n }, ANIMATION_INTERVALS.BLINK)\n\n return () => clearInterval(timer)\n }, [])\n\n return visible\n}\n\n/**\n * Hook for elapsed time counter (1000ms interval)\n */\nexport function useElapsedTime(startTime?: number): number {\n const [elapsed, setElapsed] = useState(0)\n const start = startTime ?? Date.now()\n\n useEffect(() => {\n const timer = setInterval(() => {\n setElapsed(Math.floor((Date.now() - start) / 1000))\n }, ANIMATION_INTERVALS.ELAPSED_TIME)\n\n return () => clearInterval(timer)\n }, [start])\n\n return elapsed\n}\n\n// Re-export intervals for convenience\nexport { ANIMATION_INTERVALS }\n"],
5
+ "mappings": "AAkBA,SAAS,UAAU,iBAA8B;AACjD,SAAS,eAAe,2BAA2B;AAY5C,SAAS,mBAAmC;AACjD,QAAM,CAAC,OAAO,QAAQ,IAAI;AAAA,IAAyB,MACjD,cAAc,SAAS;AAAA,EACzB;AAEA,YAAU,MAAM;AACd,UAAM,cAAc,cAAc,UAAU,WAAS;AACnD,eAAS,KAAK;AAAA,IAChB,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;AAMO,SAAS,oBAAoB,QAA0B;AAC5D,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,CAAC;AAE9C,YAAU,MAAM;AACd,UAAM,QAAQ,YAAY,MAAM;AAC9B,oBAAc,QAAM,IAAI,KAAK,OAAO,MAAM;AAAA,IAC5C,GAAG,oBAAoB,OAAO;AAE9B,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,OAAO,MAAM,CAAC;AAElB,SAAO,OAAO,UAAU,KAAK,OAAO,CAAC,KAAK;AAC5C;AAKO,SAAS,oBAA6B;AAC3C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAE3C,YAAU,MAAM;AACd,UAAM,QAAQ,YAAY,MAAM;AAC9B,iBAAW,OAAK,CAAC,CAAC;AAAA,IACpB,GAAG,oBAAoB,KAAK;AAE5B,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;AAKO,SAAS,eAAe,WAA4B;AACzD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,CAAC;AACxC,QAAM,QAAQ,aAAa,KAAK,IAAI;AAEpC,YAAU,MAAM;AACd,UAAM,QAAQ,YAAY,MAAM;AAC9B,iBAAW,KAAK,OAAO,KAAK,IAAI,IAAI,SAAS,GAAI,CAAC;AAAA,IACpD,GAAG,oBAAoB,YAAY;AAEnC,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -1,12 +1,14 @@
1
1
  import { useState } from "react";
2
2
  import { getHistory } from "../history.js";
3
+ import { sanitizeInput } from "../utils/sanitizeInput.js";
3
4
  function useArrowKeyHistory(onSetInput, currentInput) {
4
5
  const [historyIndex, setHistoryIndex] = useState(0);
5
6
  const [lastTypedInput, setLastTypedInput] = useState("");
6
7
  const updateInput = (input) => {
7
8
  if (input !== void 0) {
8
- const mode = input.startsWith("!") ? "bash" : "prompt";
9
- const value = mode === "bash" ? input.slice(1) : input;
9
+ const sanitized = sanitizeInput(input);
10
+ const mode = sanitized.startsWith("!") ? "bash" : "prompt";
11
+ const value = mode === "bash" ? sanitized.slice(1) : sanitized;
10
12
  onSetInput(value, mode);
11
13
  }
12
14
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/hooks/useArrowKeyHistory.ts"],
4
- "sourcesContent": ["import { useState } from 'react'\nimport { getHistory } from '@history'\n\nexport function useArrowKeyHistory(\n onSetInput: (value: string, mode: 'bash' | 'prompt') => void,\n currentInput: string,\n) {\n const [historyIndex, setHistoryIndex] = useState(0)\n const [lastTypedInput, setLastTypedInput] = useState('')\n\n const updateInput = (input: string | undefined) => {\n if (input !== undefined) {\n const mode = input.startsWith('!') ? 'bash' : 'prompt'\n const value = mode === 'bash' ? input.slice(1) : input\n onSetInput(value, mode)\n }\n }\n\n function onHistoryUp() {\n const latestHistory = getHistory()\n if (historyIndex < latestHistory.length) {\n if (historyIndex === 0 && currentInput.trim() !== '') {\n setLastTypedInput(currentInput)\n }\n const newIndex = historyIndex + 1\n setHistoryIndex(newIndex)\n updateInput(latestHistory[historyIndex])\n }\n }\n\n function onHistoryDown() {\n const latestHistory = getHistory()\n if (historyIndex > 1) {\n const newIndex = historyIndex - 1\n setHistoryIndex(newIndex)\n updateInput(latestHistory[newIndex - 1])\n } else if (historyIndex === 1) {\n setHistoryIndex(0)\n updateInput(lastTypedInput)\n }\n }\n\n function resetHistory() {\n setLastTypedInput('')\n setHistoryIndex(0)\n }\n\n return {\n historyIndex,\n setHistoryIndex,\n onHistoryUp,\n onHistoryDown,\n resetHistory,\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAEpB,SAAS,mBACd,YACA,cACA;AACA,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,CAAC;AAClD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,EAAE;AAEvD,QAAM,cAAc,CAAC,UAA8B;AACjD,QAAI,UAAU,QAAW;AACvB,YAAM,OAAO,MAAM,WAAW,GAAG,IAAI,SAAS;AAC9C,YAAM,QAAQ,SAAS,SAAS,MAAM,MAAM,CAAC,IAAI;AACjD,iBAAW,OAAO,IAAI;AAAA,IACxB;AAAA,EACF;AAEA,WAAS,cAAc;AACrB,UAAM,gBAAgB,WAAW;AACjC,QAAI,eAAe,cAAc,QAAQ;AACvC,UAAI,iBAAiB,KAAK,aAAa,KAAK,MAAM,IAAI;AACpD,0BAAkB,YAAY;AAAA,MAChC;AACA,YAAM,WAAW,eAAe;AAChC,sBAAgB,QAAQ;AACxB,kBAAY,cAAc,YAAY,CAAC;AAAA,IACzC;AAAA,EACF;AAEA,WAAS,gBAAgB;AACvB,UAAM,gBAAgB,WAAW;AACjC,QAAI,eAAe,GAAG;AACpB,YAAM,WAAW,eAAe;AAChC,sBAAgB,QAAQ;AACxB,kBAAY,cAAc,WAAW,CAAC,CAAC;AAAA,IACzC,WAAW,iBAAiB,GAAG;AAC7B,sBAAgB,CAAC;AACjB,kBAAY,cAAc;AAAA,IAC5B;AAAA,EACF;AAEA,WAAS,eAAe;AACtB,sBAAkB,EAAE;AACpB,oBAAgB,CAAC;AAAA,EACnB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { useState } from 'react'\nimport { getHistory } from '@history'\nimport { sanitizeInput } from '@utils/sanitizeInput'\n\nexport function useArrowKeyHistory(\n onSetInput: (value: string, mode: 'bash' | 'prompt') => void,\n currentInput: string,\n) {\n const [historyIndex, setHistoryIndex] = useState(0)\n const [lastTypedInput, setLastTypedInput] = useState('')\n\n const updateInput = (input: string | undefined) => {\n if (input !== undefined) {\n // Sanitize input to remove dangerous escape sequences\n // This prevents corrupt history entries (like \"\\x1b\\x1bclear\") from\n // triggering terminal resets when loaded\n const sanitized = sanitizeInput(input)\n const mode = sanitized.startsWith('!') ? 'bash' : 'prompt'\n const value = mode === 'bash' ? sanitized.slice(1) : sanitized\n onSetInput(value, mode)\n }\n }\n\n function onHistoryUp() {\n const latestHistory = getHistory()\n if (historyIndex < latestHistory.length) {\n if (historyIndex === 0 && currentInput.trim() !== '') {\n setLastTypedInput(currentInput)\n }\n const newIndex = historyIndex + 1\n setHistoryIndex(newIndex)\n updateInput(latestHistory[historyIndex])\n }\n }\n\n function onHistoryDown() {\n const latestHistory = getHistory()\n if (historyIndex > 1) {\n const newIndex = historyIndex - 1\n setHistoryIndex(newIndex)\n updateInput(latestHistory[newIndex - 1])\n } else if (historyIndex === 1) {\n setHistoryIndex(0)\n updateInput(lastTypedInput)\n }\n }\n\n function resetHistory() {\n setLastTypedInput('')\n setHistoryIndex(0)\n }\n\n return {\n historyIndex,\n setHistoryIndex,\n onHistoryUp,\n onHistoryDown,\n resetHistory,\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAEvB,SAAS,mBACd,YACA,cACA;AACA,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,CAAC;AAClD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,EAAE;AAEvD,QAAM,cAAc,CAAC,UAA8B;AACjD,QAAI,UAAU,QAAW;AAIvB,YAAM,YAAY,cAAc,KAAK;AACrC,YAAM,OAAO,UAAU,WAAW,GAAG,IAAI,SAAS;AAClD,YAAM,QAAQ,SAAS,SAAS,UAAU,MAAM,CAAC,IAAI;AACrD,iBAAW,OAAO,IAAI;AAAA,IACxB;AAAA,EACF;AAEA,WAAS,cAAc;AACrB,UAAM,gBAAgB,WAAW;AACjC,QAAI,eAAe,cAAc,QAAQ;AACvC,UAAI,iBAAiB,KAAK,aAAa,KAAK,MAAM,IAAI;AACpD,0BAAkB,YAAY;AAAA,MAChC;AACA,YAAM,WAAW,eAAe;AAChC,sBAAgB,QAAQ;AACxB,kBAAY,cAAc,YAAY,CAAC;AAAA,IACzC;AAAA,EACF;AAEA,WAAS,gBAAgB;AACvB,UAAM,gBAAgB,WAAW;AACjC,QAAI,eAAe,GAAG;AACpB,YAAM,WAAW,eAAe;AAChC,sBAAgB,QAAQ;AACxB,kBAAY,cAAc,WAAW,CAAC,CAAC;AAAA,IACzC,WAAW,iBAAiB,GAAG;AAC7B,sBAAgB,CAAC;AACjB,kBAAY,cAAc;AAAA,IAC5B;AAAA,EACF;AAEA,WAAS,eAAe;AACtB,sBAAkB,EAAE;AACpB,oBAAgB,CAAC;AAAA,EACnB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,7 @@ import { hasPermissionsToUseTool } from "../permissions.js";
3
3
  import { BashTool, inputSchema } from "../tools/BashTool/BashTool.js";
4
4
  import { getCommandSubcommandPrefix } from "../utils/commands.js";
5
5
  import { REJECT_MESSAGE } from "../utils/messages.js";
6
+ import { getToolDescriptionAsync } from "../Tool.js";
6
7
  import { AbortError } from "../utils/errors.js";
7
8
  import { logError } from "../utils/log.js";
8
9
  function useCanUseTool(setToolUseConfirm) {
@@ -34,7 +35,8 @@ function useCanUseTool(setToolUseConfirm) {
34
35
  return;
35
36
  }
36
37
  const [description, commandPrefix] = await Promise.all([
37
- tool.description(input),
38
+ // Use getToolDescriptionAsync for safe async access
39
+ getToolDescriptionAsync(tool, input),
38
40
  tool === BashTool ? getCommandSubcommandPrefix(
39
41
  inputSchema.parse(input).command,
40
42
  // already validated upstream, so ok to parse (as opposed to safeParse)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/hooks/useCanUseTool.ts"],
4
- "sourcesContent": ["import React, { useCallback } from 'react'\nimport { hasPermissionsToUseTool } from '@permissions'\nimport { BashTool, inputSchema } from '@tools/BashTool/BashTool'\nimport { getCommandSubcommandPrefix } from '@utils/commands'\nimport { REJECT_MESSAGE } from '@utils/messages'\nimport type { Tool as ToolType, ToolUseContext } from '@tool'\nimport { AssistantMessage } from '@query'\nimport { ToolUseConfirm } from '@components/permissions/PermissionRequest'\nimport { AbortError } from '@utils/errors'\nimport { logError } from '@utils/log'\n\ntype SetState<T> = React.Dispatch<React.SetStateAction<T>>\n\nexport type CanUseToolFn = (\n tool: ToolType,\n input: { [key: string]: unknown },\n toolUseContext: ToolUseContext,\n assistantMessage: AssistantMessage,\n) => Promise<{ result: true } | { result: false; message: string }>\n\nfunction useCanUseTool(\n setToolUseConfirm: SetState<ToolUseConfirm | null>,\n): CanUseToolFn {\n return useCallback<CanUseToolFn>(\n async (tool, input, toolUseContext, assistantMessage) => {\n return new Promise(resolve => {\n function logCancelledEvent() {}\n\n function resolveWithCancelledAndAbortAllToolCalls() {\n resolve({\n result: false,\n message: REJECT_MESSAGE,\n })\n // Trigger a synthetic assistant message in query(), to cancel\n // any other pending tool uses and stop further requests to the\n // API and wait for user input.\n toolUseContext.abortController.abort()\n }\n\n if (toolUseContext.abortController.signal.aborted) {\n logCancelledEvent()\n resolveWithCancelledAndAbortAllToolCalls()\n return\n }\n\n return hasPermissionsToUseTool(\n tool,\n input,\n toolUseContext,\n assistantMessage,\n )\n .then(async result => {\n // Has permissions to use tool, granted in config\n if (result.result) {\n resolve({ result: true })\n return\n }\n\n const [description, commandPrefix] = await Promise.all([\n tool.description(input as never),\n tool === BashTool\n ? getCommandSubcommandPrefix(\n inputSchema.parse(input).command, // already validated upstream, so ok to parse (as opposed to safeParse)\n toolUseContext.abortController.signal,\n )\n : Promise.resolve(null),\n ])\n\n if (toolUseContext.abortController.signal.aborted) {\n logCancelledEvent()\n resolveWithCancelledAndAbortAllToolCalls()\n return\n }\n\n // Does not have permissions to use tool, ask the user\n setToolUseConfirm({\n assistantMessage,\n tool,\n description,\n input,\n commandPrefix,\n riskScore: null,\n onAbort() {\n logCancelledEvent()\n resolveWithCancelledAndAbortAllToolCalls()\n },\n onAllow(type) {\n if (type === 'permanent') {\n } else {\n }\n resolve({ result: true })\n },\n onReject() {\n resolveWithCancelledAndAbortAllToolCalls()\n },\n })\n })\n .catch(error => {\n if (error instanceof AbortError) {\n logCancelledEvent()\n resolveWithCancelledAndAbortAllToolCalls()\n } else {\n logError(error)\n }\n })\n })\n },\n [setToolUseConfirm],\n )\n}\n\nexport default useCanUseTool\n"],
5
- "mappings": "AAAA,SAAgB,mBAAmB;AACnC,SAAS,+BAA+B;AACxC,SAAS,UAAU,mBAAmB;AACtC,SAAS,kCAAkC;AAC3C,SAAS,sBAAsB;AAI/B,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AAWzB,SAAS,cACP,mBACc;AACd,SAAO;AAAA,IACL,OAAO,MAAM,OAAO,gBAAgB,qBAAqB;AACvD,aAAO,IAAI,QAAQ,aAAW;AAC5B,iBAAS,oBAAoB;AAAA,QAAC;AAE9B,iBAAS,2CAA2C;AAClD,kBAAQ;AAAA,YACN,QAAQ;AAAA,YACR,SAAS;AAAA,UACX,CAAC;AAID,yBAAe,gBAAgB,MAAM;AAAA,QACvC;AAEA,YAAI,eAAe,gBAAgB,OAAO,SAAS;AACjD,4BAAkB;AAClB,mDAAyC;AACzC;AAAA,QACF;AAEA,eAAO;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EACG,KAAK,OAAM,WAAU;AAEpB,cAAI,OAAO,QAAQ;AACjB,oBAAQ,EAAE,QAAQ,KAAK,CAAC;AACxB;AAAA,UACF;AAEA,gBAAM,CAAC,aAAa,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA,YACrD,KAAK,YAAY,KAAc;AAAA,YAC/B,SAAS,WACL;AAAA,cACE,YAAY,MAAM,KAAK,EAAE;AAAA;AAAA,cACzB,eAAe,gBAAgB;AAAA,YACjC,IACA,QAAQ,QAAQ,IAAI;AAAA,UAC1B,CAAC;AAED,cAAI,eAAe,gBAAgB,OAAO,SAAS;AACjD,8BAAkB;AAClB,qDAAyC;AACzC;AAAA,UACF;AAGA,4BAAkB;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,WAAW;AAAA,YACX,UAAU;AACR,gCAAkB;AAClB,uDAAyC;AAAA,YAC3C;AAAA,YACA,QAAQ,MAAM;AACZ,kBAAI,SAAS,aAAa;AAAA,cAC1B,OAAO;AAAA,cACP;AACA,sBAAQ,EAAE,QAAQ,KAAK,CAAC;AAAA,YAC1B;AAAA,YACA,WAAW;AACT,uDAAyC;AAAA,YAC3C;AAAA,UACF,CAAC;AAAA,QACH,CAAC,EACA,MAAM,WAAS;AACd,cAAI,iBAAiB,YAAY;AAC/B,8BAAkB;AAClB,qDAAyC;AAAA,UAC3C,OAAO;AACL,qBAAS,KAAK;AAAA,UAChB;AAAA,QACF,CAAC;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IACA,CAAC,iBAAiB;AAAA,EACpB;AACF;AAEA,IAAO,wBAAQ;",
4
+ "sourcesContent": ["import React, { useCallback } from 'react'\nimport { hasPermissionsToUseTool } from '@permissions'\nimport { BashTool, inputSchema } from '@tools/BashTool/BashTool'\nimport { getCommandSubcommandPrefix } from '@utils/commands'\nimport { REJECT_MESSAGE } from '@utils/messages'\nimport type { Tool as ToolType, ToolUseContext } from '@tool'\nimport { getToolDescriptionAsync } from '@tool'\nimport { AssistantMessage } from '@query'\nimport { ToolUseConfirm } from '@components/permissions/PermissionRequest'\nimport { AbortError } from '@utils/errors'\nimport { logError } from '@utils/log'\n\ntype SetState<T> = React.Dispatch<React.SetStateAction<T>>\n\nexport type CanUseToolFn = (\n tool: ToolType,\n input: { [key: string]: unknown },\n toolUseContext: ToolUseContext,\n assistantMessage: AssistantMessage,\n) => Promise<{ result: true } | { result: false; message: string }>\n\nfunction useCanUseTool(\n setToolUseConfirm: SetState<ToolUseConfirm | null>,\n): CanUseToolFn {\n return useCallback<CanUseToolFn>(\n async (tool, input, toolUseContext, assistantMessage) => {\n return new Promise(resolve => {\n function logCancelledEvent() {}\n\n function resolveWithCancelledAndAbortAllToolCalls() {\n resolve({\n result: false,\n message: REJECT_MESSAGE,\n })\n // Trigger a synthetic assistant message in query(), to cancel\n // any other pending tool uses and stop further requests to the\n // API and wait for user input.\n toolUseContext.abortController.abort()\n }\n\n if (toolUseContext.abortController.signal.aborted) {\n logCancelledEvent()\n resolveWithCancelledAndAbortAllToolCalls()\n return\n }\n\n return hasPermissionsToUseTool(\n tool,\n input,\n toolUseContext,\n assistantMessage,\n )\n .then(async result => {\n // Has permissions to use tool, granted in config\n if (result.result) {\n resolve({ result: true })\n return\n }\n\n const [description, commandPrefix] = await Promise.all([\n // Use getToolDescriptionAsync for safe async access\n getToolDescriptionAsync(tool, input),\n tool === BashTool\n ? getCommandSubcommandPrefix(\n inputSchema.parse(input).command, // already validated upstream, so ok to parse (as opposed to safeParse)\n toolUseContext.abortController.signal,\n )\n : Promise.resolve(null),\n ])\n\n if (toolUseContext.abortController.signal.aborted) {\n logCancelledEvent()\n resolveWithCancelledAndAbortAllToolCalls()\n return\n }\n\n // Does not have permissions to use tool, ask the user\n setToolUseConfirm({\n assistantMessage,\n tool,\n description,\n input,\n commandPrefix,\n riskScore: null,\n onAbort() {\n logCancelledEvent()\n resolveWithCancelledAndAbortAllToolCalls()\n },\n onAllow(type) {\n if (type === 'permanent') {\n } else {\n }\n resolve({ result: true })\n },\n onReject() {\n resolveWithCancelledAndAbortAllToolCalls()\n },\n })\n })\n .catch(error => {\n if (error instanceof AbortError) {\n logCancelledEvent()\n resolveWithCancelledAndAbortAllToolCalls()\n } else {\n logError(error)\n }\n })\n })\n },\n [setToolUseConfirm],\n )\n}\n\nexport default useCanUseTool\n"],
5
+ "mappings": "AAAA,SAAgB,mBAAmB;AACnC,SAAS,+BAA+B;AACxC,SAAS,UAAU,mBAAmB;AACtC,SAAS,kCAAkC;AAC3C,SAAS,sBAAsB;AAE/B,SAAS,+BAA+B;AAGxC,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AAWzB,SAAS,cACP,mBACc;AACd,SAAO;AAAA,IACL,OAAO,MAAM,OAAO,gBAAgB,qBAAqB;AACvD,aAAO,IAAI,QAAQ,aAAW;AAC5B,iBAAS,oBAAoB;AAAA,QAAC;AAE9B,iBAAS,2CAA2C;AAClD,kBAAQ;AAAA,YACN,QAAQ;AAAA,YACR,SAAS;AAAA,UACX,CAAC;AAID,yBAAe,gBAAgB,MAAM;AAAA,QACvC;AAEA,YAAI,eAAe,gBAAgB,OAAO,SAAS;AACjD,4BAAkB;AAClB,mDAAyC;AACzC;AAAA,QACF;AAEA,eAAO;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EACG,KAAK,OAAM,WAAU;AAEpB,cAAI,OAAO,QAAQ;AACjB,oBAAQ,EAAE,QAAQ,KAAK,CAAC;AACxB;AAAA,UACF;AAEA,gBAAM,CAAC,aAAa,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA;AAAA,YAErD,wBAAwB,MAAM,KAAK;AAAA,YACnC,SAAS,WACL;AAAA,cACE,YAAY,MAAM,KAAK,EAAE;AAAA;AAAA,cACzB,eAAe,gBAAgB;AAAA,YACjC,IACA,QAAQ,QAAQ,IAAI;AAAA,UAC1B,CAAC;AAED,cAAI,eAAe,gBAAgB,OAAO,SAAS;AACjD,8BAAkB;AAClB,qDAAyC;AACzC;AAAA,UACF;AAGA,4BAAkB;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,WAAW;AAAA,YACX,UAAU;AACR,gCAAkB;AAClB,uDAAyC;AAAA,YAC3C;AAAA,YACA,QAAQ,MAAM;AACZ,kBAAI,SAAS,aAAa;AAAA,cAC1B,OAAO;AAAA,cACP;AACA,sBAAQ,EAAE,QAAQ,KAAK,CAAC;AAAA,YAC1B;AAAA,YACA,WAAW;AACT,uDAAyC;AAAA,YAC3C;AAAA,UACF,CAAC;AAAA,QACH,CAAC,EACA,MAAM,WAAS;AACd,cAAI,iBAAiB,YAAY;AAC/B,8BAAkB;AAClB,qDAAyC;AAAA,UAC3C,OAAO;AACL,qBAAS,KAAK;AAAA,UAChB;AAAA,QACF,CAAC;AAAA,MACL,CAAC;AAAA,IACH;AAAA,IACA,CAAC,iBAAiB;AAAA,EACpB;AACF;AAEA,IAAO,wBAAQ;",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import { useInput } from "ink";
2
- function useCancelRequest(setToolJSX, setToolUseConfirm, setBinaryFeedbackContext, onCancel, isLoading, isMessageSelectorVisible, abortSignal) {
2
+ function useCancelRequest(setToolJSX, setToolUseConfirm, setBinaryFeedbackContext, onCancel, isLoading, isMessageSelectorVisible, abortSignal, hasInputContent) {
3
3
  useInput((_, key) => {
4
4
  if (!key.escape) {
5
5
  return;
@@ -16,6 +16,9 @@ function useCancelRequest(setToolJSX, setToolUseConfirm, setBinaryFeedbackContex
16
16
  if (isMessageSelectorVisible) {
17
17
  return;
18
18
  }
19
+ if (hasInputContent) {
20
+ return;
21
+ }
19
22
  setToolJSX(null);
20
23
  setToolUseConfirm(null);
21
24
  setBinaryFeedbackContext(null);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/hooks/useCancelRequest.ts"],
4
- "sourcesContent": ["import { useInput } from 'ink'\nimport { ToolUseConfirm } from '@components/permissions/PermissionRequest'\nimport { BinaryFeedbackContext } from '@screens/REPL'\nimport type { SetToolJSXFn } from '@tool'\n\nexport function useCancelRequest(\n setToolJSX: SetToolJSXFn,\n setToolUseConfirm: (toolUseConfirm: ToolUseConfirm | null) => void,\n setBinaryFeedbackContext: (bfContext: BinaryFeedbackContext | null) => void,\n onCancel: () => void,\n isLoading: boolean,\n isMessageSelectorVisible: boolean,\n abortSignal?: AbortSignal,\n) {\n useInput((_, key) => {\n if (!key.escape) {\n return\n }\n if (abortSignal?.aborted) {\n return\n }\n if (!abortSignal) {\n return\n }\n if (!isLoading) {\n return\n }\n if (isMessageSelectorVisible) {\n // Esc closes the message selector\n return\n }\n\n setToolJSX(null)\n setToolUseConfirm(null)\n setBinaryFeedbackContext(null)\n onCancel()\n })\n}\n"],
5
- "mappings": "AAAA,SAAS,gBAAgB;AAKlB,SAAS,iBACd,YACA,mBACA,0BACA,UACA,WACA,0BACA,aACA;AACA,WAAS,CAAC,GAAG,QAAQ;AACnB,QAAI,CAAC,IAAI,QAAQ;AACf;AAAA,IACF;AACA,QAAI,aAAa,SAAS;AACxB;AAAA,IACF;AACA,QAAI,CAAC,aAAa;AAChB;AAAA,IACF;AACA,QAAI,CAAC,WAAW;AACd;AAAA,IACF;AACA,QAAI,0BAA0B;AAE5B;AAAA,IACF;AAEA,eAAW,IAAI;AACf,sBAAkB,IAAI;AACtB,6BAAyB,IAAI;AAC7B,aAAS;AAAA,EACX,CAAC;AACH;",
4
+ "sourcesContent": ["import { useInput } from 'ink'\nimport { ToolUseConfirm } from '@components/permissions/PermissionRequest'\nimport { BinaryFeedbackContext } from '@screens/REPL'\nimport type { SetToolJSXFn } from '@tool'\n\nexport function useCancelRequest(\n setToolJSX: SetToolJSXFn,\n setToolUseConfirm: (toolUseConfirm: ToolUseConfirm | null) => void,\n setBinaryFeedbackContext: (bfContext: BinaryFeedbackContext | null) => void,\n onCancel: () => void,\n isLoading: boolean,\n isMessageSelectorVisible: boolean,\n abortSignal?: AbortSignal,\n /** If true, ESC will first clear input before canceling. Pass input.length > 0 */\n hasInputContent?: boolean,\n) {\n useInput((_, key) => {\n if (!key.escape) {\n return\n }\n if (abortSignal?.aborted) {\n return\n }\n if (!abortSignal) {\n return\n }\n if (!isLoading) {\n return\n }\n if (isMessageSelectorVisible) {\n // Esc closes the message selector\n return\n }\n // If input has content, let PromptInput handle ESC to clear input first\n if (hasInputContent) {\n return\n }\n\n setToolJSX(null)\n setToolUseConfirm(null)\n setBinaryFeedbackContext(null)\n onCancel()\n })\n}\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;AAKlB,SAAS,iBACd,YACA,mBACA,0BACA,UACA,WACA,0BACA,aAEA,iBACA;AACA,WAAS,CAAC,GAAG,QAAQ;AACnB,QAAI,CAAC,IAAI,QAAQ;AACf;AAAA,IACF;AACA,QAAI,aAAa,SAAS;AACxB;AAAA,IACF;AACA,QAAI,CAAC,aAAa;AAChB;AAAA,IACF;AACA,QAAI,CAAC,WAAW;AACd;AAAA,IACF;AACA,QAAI,0BAA0B;AAE5B;AAAA,IACF;AAEA,QAAI,iBAAiB;AACnB;AAAA,IACF;AAEA,eAAW,IAAI;AACf,sBAAkB,IAAI;AACtB,6BAAyB,IAAI;AAC7B,aAAS;AAAA,EACX,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,8 @@
1
1
  import { useInput } from "ink";
2
2
  import { useDoublePress } from "./useDoublePress.js";
3
3
  import { useState } from "react";
4
- function useExitOnCtrlCD(onExit) {
4
+ function useExitOnCtrlCD(onExit, options = {}) {
5
+ const { isActive = true } = options;
5
6
  const [exitState, setExitState] = useState({
6
7
  pending: false,
7
8
  keyName: null
@@ -14,10 +15,13 @@ function useExitOnCtrlCD(onExit) {
14
15
  (pending) => setExitState({ pending, keyName: "Ctrl-D" }),
15
16
  onExit
16
17
  );
17
- useInput((input, key) => {
18
- if (key.ctrl && input === "c") handleCtrlC();
19
- if (key.ctrl && input === "d") handleCtrlD();
20
- });
18
+ useInput(
19
+ (input, key) => {
20
+ if (key.ctrl && input === "c") handleCtrlC();
21
+ if (key.ctrl && input === "d") handleCtrlD();
22
+ },
23
+ { isActive }
24
+ );
21
25
  return exitState;
22
26
  }
23
27
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/hooks/useExitOnCtrlCD.ts"],
4
- "sourcesContent": ["import { useInput } from 'ink'\nimport { useDoublePress } from './useDoublePress'\nimport { useState } from 'react'\n\ntype ExitState = {\n pending: boolean\n keyName: 'Ctrl-C' | 'Ctrl-D' | null\n}\n\nexport function useExitOnCtrlCD(onExit: () => void): ExitState {\n const [exitState, setExitState] = useState<ExitState>({\n pending: false,\n keyName: null,\n })\n\n const handleCtrlC = useDoublePress(\n pending => setExitState({ pending, keyName: 'Ctrl-C' }),\n onExit,\n )\n const handleCtrlD = useDoublePress(\n pending => setExitState({ pending, keyName: 'Ctrl-D' }),\n onExit,\n )\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') handleCtrlC()\n if (key.ctrl && input === 'd') handleCtrlD()\n })\n\n return exitState\n}\n"],
5
- "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AAOlB,SAAS,gBAAgB,QAA+B;AAC7D,QAAM,CAAC,WAAW,YAAY,IAAI,SAAoB;AAAA,IACpD,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AAED,QAAM,cAAc;AAAA,IAClB,aAAW,aAAa,EAAE,SAAS,SAAS,SAAS,CAAC;AAAA,IACtD;AAAA,EACF;AACA,QAAM,cAAc;AAAA,IAClB,aAAW,aAAa,EAAE,SAAS,SAAS,SAAS,CAAC;AAAA,IACtD;AAAA,EACF;AAEA,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,QAAQ,UAAU,IAAK,aAAY;AAC3C,QAAI,IAAI,QAAQ,UAAU,IAAK,aAAY;AAAA,EAC7C,CAAC;AAED,SAAO;AACT;",
4
+ "sourcesContent": ["import { useInput } from 'ink'\nimport { useDoublePress } from './useDoublePress'\nimport { useState } from 'react'\n\ntype ExitState = {\n pending: boolean\n keyName: 'Ctrl-C' | 'Ctrl-D' | null\n}\n\ntype Options = {\n isActive?: boolean\n}\n\nexport function useExitOnCtrlCD(\n onExit: () => void,\n options: Options = {},\n): ExitState {\n const { isActive = true } = options\n const [exitState, setExitState] = useState<ExitState>({\n pending: false,\n keyName: null,\n })\n\n const handleCtrlC = useDoublePress(\n pending => setExitState({ pending, keyName: 'Ctrl-C' }),\n onExit,\n )\n const handleCtrlD = useDoublePress(\n pending => setExitState({ pending, keyName: 'Ctrl-D' }),\n onExit,\n )\n\n // Support isActive option to conditionally enable/disable input handling\n // This helps prevent EventEmitter listener accumulation in nested components\n useInput(\n (input, key) => {\n if (key.ctrl && input === 'c') handleCtrlC()\n if (key.ctrl && input === 'd') handleCtrlD()\n },\n { isActive },\n )\n\n return exitState\n}\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AAWlB,SAAS,gBACd,QACA,UAAmB,CAAC,GACT;AACX,QAAM,EAAE,WAAW,KAAK,IAAI;AAC5B,QAAM,CAAC,WAAW,YAAY,IAAI,SAAoB;AAAA,IACpD,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AAED,QAAM,cAAc;AAAA,IAClB,aAAW,aAAa,EAAE,SAAS,SAAS,SAAS,CAAC;AAAA,IACtD;AAAA,EACF;AACA,QAAM,cAAc;AAAA,IAClB,aAAW,aAAa,EAAE,SAAS,SAAS,SAAS,CAAC;AAAA,IACtD;AAAA,EACF;AAIA;AAAA,IACE,CAAC,OAAO,QAAQ;AACd,UAAI,IAAI,QAAQ,UAAU,IAAK,aAAY;AAC3C,UAAI,IAAI,QAAQ,UAAU,IAAK,aAAY;AAAA,IAC7C;AAAA,IACA,EAAE,SAAS;AAAA,EACb;AAEA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,40 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import { hookStatusEmitter } from "../services/hookExecutor.js";
3
+ function useHookStatus(enabled) {
4
+ const [state, setState] = useState({
5
+ recentEvents: [],
6
+ successCount: 0,
7
+ failureCount: 0
8
+ });
9
+ const handleStatus = useCallback((event) => {
10
+ setState((prev) => ({
11
+ recentEvents: [...prev.recentEvents.slice(-9), event],
12
+ // Keep last 10
13
+ successCount: prev.successCount + (event.success ? 1 : 0),
14
+ failureCount: prev.failureCount + (event.success ? 0 : 1)
15
+ }));
16
+ }, []);
17
+ useEffect(() => {
18
+ if (!enabled) return;
19
+ hookStatusEmitter.on("status", handleStatus);
20
+ return () => {
21
+ hookStatusEmitter.off("status", handleStatus);
22
+ };
23
+ }, [enabled, handleStatus]);
24
+ return state;
25
+ }
26
+ function formatHookStatus(event) {
27
+ const timestamp = new Date(event.timestamp).toLocaleTimeString("en-US", {
28
+ hour: "numeric",
29
+ minute: "2-digit",
30
+ second: "2-digit",
31
+ hour12: true
32
+ });
33
+ const status = event.success ? "\u2713" : "\u2717";
34
+ return `${timestamp} ${status} ${event.message}`;
35
+ }
36
+ export {
37
+ formatHookStatus,
38
+ useHookStatus
39
+ };
40
+ //# sourceMappingURL=useHookStatus.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hooks/useHookStatus.ts"],
4
+ "sourcesContent": ["/**\n * Hook Status Tracking for Verbose Mode\n *\n * Listens to hookStatusEmitter and provides status information\n * for display in verbose mode.\n */\n\nimport { useState, useEffect, useCallback } from 'react'\nimport { hookStatusEmitter, HookStatusEvent } from '@services/hookExecutor'\n\ninterface HookStatusState {\n /** Recent hook events (last 10) */\n recentEvents: HookStatusEvent[]\n /** Count of successful hooks */\n successCount: number\n /** Count of failed hooks */\n failureCount: number\n}\n\n/**\n * Hook to track hook status events for verbose mode display\n *\n * @param enabled - Whether to listen for events (should be verbose mode)\n * @returns Hook status state\n */\nexport function useHookStatus(enabled: boolean): HookStatusState {\n const [state, setState] = useState<HookStatusState>({\n recentEvents: [],\n successCount: 0,\n failureCount: 0,\n })\n\n const handleStatus = useCallback((event: HookStatusEvent) => {\n setState(prev => ({\n recentEvents: [...prev.recentEvents.slice(-9), event], // Keep last 10\n successCount: prev.successCount + (event.success ? 1 : 0),\n failureCount: prev.failureCount + (event.success ? 0 : 1),\n }))\n }, [])\n\n useEffect(() => {\n if (!enabled) return\n\n hookStatusEmitter.on('status', handleStatus)\n return () => {\n hookStatusEmitter.off('status', handleStatus)\n }\n }, [enabled, handleStatus])\n\n return state\n}\n\n/**\n * Format hook status for display\n */\nexport function formatHookStatus(event: HookStatusEvent): string {\n const timestamp = new Date(event.timestamp).toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: true,\n })\n const status = event.success ? '\u2713' : '\u2717'\n return `${timestamp} ${status} ${event.message}`\n}\n"],
5
+ "mappings": "AAOA,SAAS,UAAU,WAAW,mBAAmB;AACjD,SAAS,yBAA0C;AAiB5C,SAAS,cAAc,SAAmC;AAC/D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA0B;AAAA,IAClD,cAAc,CAAC;AAAA,IACf,cAAc;AAAA,IACd,cAAc;AAAA,EAChB,CAAC;AAED,QAAM,eAAe,YAAY,CAAC,UAA2B;AAC3D,aAAS,WAAS;AAAA,MAChB,cAAc,CAAC,GAAG,KAAK,aAAa,MAAM,EAAE,GAAG,KAAK;AAAA;AAAA,MACpD,cAAc,KAAK,gBAAgB,MAAM,UAAU,IAAI;AAAA,MACvD,cAAc,KAAK,gBAAgB,MAAM,UAAU,IAAI;AAAA,IACzD,EAAE;AAAA,EACJ,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,sBAAkB,GAAG,UAAU,YAAY;AAC3C,WAAO,MAAM;AACX,wBAAkB,IAAI,UAAU,YAAY;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,SAAS,YAAY,CAAC;AAE1B,SAAO;AACT;AAKO,SAAS,iBAAiB,OAAgC;AAC/D,QAAM,YAAY,IAAI,KAAK,MAAM,SAAS,EAAE,mBAAmB,SAAS;AAAA,IACtE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AACD,QAAM,SAAS,MAAM,UAAU,WAAM;AACrC,SAAO,GAAG,SAAS,IAAI,MAAM,IAAI,MAAM,OAAO;AAChD;",
6
+ "names": []
7
+ }
@@ -1,10 +1,26 @@
1
1
  import { useEffect } from "react";
2
2
  import { overwriteLog, getMessagesPath } from "../utils/log.js";
3
+ function serializeMessageForLog(message) {
4
+ if (message.type === "progress") {
5
+ const progressMsg = message;
6
+ return {
7
+ type: "progress",
8
+ uuid: progressMsg.uuid,
9
+ toolUseID: progressMsg.toolUseID,
10
+ // Convert Set to Array for JSON serialization
11
+ siblingToolUseIDs: Array.from(progressMsg.siblingToolUseIDs),
12
+ // Keep the content (AssistantMessage) for display
13
+ content: progressMsg.content
14
+ };
15
+ }
16
+ return message;
17
+ }
3
18
  function useLogMessages(messages, messageLogName, forkNumber) {
4
19
  useEffect(() => {
20
+ const serializedMessages = messages.map(serializeMessageForLog);
5
21
  overwriteLog(
6
22
  getMessagesPath(messageLogName, forkNumber, 0),
7
- messages.filter((_) => _.type !== "progress")
23
+ serializedMessages
8
24
  );
9
25
  }, [messages, messageLogName, forkNumber]);
10
26
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/hooks/useLogMessages.ts"],
4
- "sourcesContent": ["import { useEffect } from 'react'\nimport { type Message } from '@query'\nimport { overwriteLog, getMessagesPath } from '@utils/log'\n\nexport function useLogMessages(\n messages: Message[],\n messageLogName: string,\n forkNumber: number,\n): void {\n useEffect(() => {\n overwriteLog(\n getMessagesPath(messageLogName, forkNumber, 0),\n messages.filter(_ => _.type !== 'progress'),\n )\n }, [messages, messageLogName, forkNumber])\n}\n"],
5
- "mappings": "AAAA,SAAS,iBAAiB;AAE1B,SAAS,cAAc,uBAAuB;AAEvC,SAAS,eACd,UACA,gBACA,YACM;AACN,YAAU,MAAM;AACd;AAAA,MACE,gBAAgB,gBAAgB,YAAY,CAAC;AAAA,MAC7C,SAAS,OAAO,OAAK,EAAE,SAAS,UAAU;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,UAAU,gBAAgB,UAAU,CAAC;AAC3C;",
4
+ "sourcesContent": ["import { useEffect } from 'react'\nimport { type Message, type ProgressMessage } from '@query'\nimport { overwriteLog, getMessagesPath } from '@utils/log'\n\n/**\n * Serialize a message for persistence.\n * Progress messages need special handling because they contain Sets that\n * cannot be directly JSON serialized, and they include references to tools\n * that would create circular references.\n */\nfunction serializeMessageForLog(message: Message): object {\n if (message.type === 'progress') {\n // Convert Set to Array for JSON serialization\n // Only keep essential fields - omit tools and normalizedMessages to avoid circular refs\n const progressMsg = message as ProgressMessage\n return {\n type: 'progress',\n uuid: progressMsg.uuid,\n toolUseID: progressMsg.toolUseID,\n // Convert Set to Array for JSON serialization\n siblingToolUseIDs: Array.from(progressMsg.siblingToolUseIDs),\n // Keep the content (AssistantMessage) for display\n content: progressMsg.content,\n }\n }\n return message\n}\n\nexport function useLogMessages(\n messages: Message[],\n messageLogName: string,\n forkNumber: number,\n): void {\n useEffect(() => {\n // Serialize all messages including progress messages\n // Progress messages are essential for proper tool use grouping on resume\n const serializedMessages = messages.map(serializeMessageForLog)\n overwriteLog(\n getMessagesPath(messageLogName, forkNumber, 0),\n serializedMessages,\n )\n }, [messages, messageLogName, forkNumber])\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAE1B,SAAS,cAAc,uBAAuB;AAQ9C,SAAS,uBAAuB,SAA0B;AACxD,MAAI,QAAQ,SAAS,YAAY;AAG/B,UAAM,cAAc;AACpB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM,YAAY;AAAA,MAClB,WAAW,YAAY;AAAA;AAAA,MAEvB,mBAAmB,MAAM,KAAK,YAAY,iBAAiB;AAAA;AAAA,MAE3D,SAAS,YAAY;AAAA,IACvB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,eACd,UACA,gBACA,YACM;AACN,YAAU,MAAM;AAGd,UAAM,qBAAqB,SAAS,IAAI,sBAAsB;AAC9D;AAAA,MACE,gBAAgB,gBAAgB,YAAY,CAAC;AAAA,MAC7C;AAAA,IACF;AAAA,EACF,GAAG,CAAC,UAAU,gBAAgB,UAAU,CAAC;AAC3C;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,43 @@
1
+ import { useMemo } from "react";
2
+ import { MessageGroupManager } from "../utils/messageGroupManager.js";
3
+ import { DISPLAY_CONFIGS } from "../types/messageGroup.js";
4
+ function useMessageGroups(normalizedMessages, unresolvedToolUseIDs, inProgressToolUseIDs, verbose = false) {
5
+ const displayConfig = useMemo(
6
+ () => verbose ? DISPLAY_CONFIGS.verbose : DISPLAY_CONFIGS.normal,
7
+ [verbose]
8
+ );
9
+ const managerState = useMemo(() => {
10
+ const manager2 = new MessageGroupManager();
11
+ manager2.identifyGroups(normalizedMessages);
12
+ manager2.updateResolutionStates(unresolvedToolUseIDs, inProgressToolUseIDs);
13
+ const groups2 = manager2.getAllGroups();
14
+ const groupById2 = new Map(groups2.map((g) => [g.id, g]));
15
+ return { manager: manager2, groups: groups2, groupById: groupById2 };
16
+ }, [normalizedMessages, unresolvedToolUseIDs, inProgressToolUseIDs]);
17
+ const { manager, groups, groupById } = managerState;
18
+ const getGroupForMessage = useMemo(
19
+ () => (messageUuid) => manager.getGroupByMessageUuid(messageUuid),
20
+ [manager]
21
+ );
22
+ const getGroupForToolUse = useMemo(
23
+ () => (toolUseId) => manager.getGroupByToolUseId(toolUseId),
24
+ [manager]
25
+ );
26
+ const shouldGroupBeStatic = useMemo(
27
+ () => (group) => manager.shouldGroupBeStatic(group),
28
+ [manager]
29
+ );
30
+ return {
31
+ groups,
32
+ manager,
33
+ groupById,
34
+ getGroupForMessage,
35
+ getGroupForToolUse,
36
+ shouldGroupBeStatic,
37
+ displayConfig
38
+ };
39
+ }
40
+ export {
41
+ useMessageGroups
42
+ };
43
+ //# sourceMappingURL=useMessageGroups.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/hooks/useMessageGroups.ts"],
4
+ "sourcesContent": ["/**\n * useMessageGroups Hook\n *\n * Provides integration between MessageGroupManager and React components.\n * Handles group identification, resolution state updates, and memoization.\n */\n\nimport { useMemo } from 'react'\nimport type { NormalizedMessage } from '@utils/messages'\nimport type { AgentTranscript } from '@utils/agentTranscripts'\nimport { MessageGroupManager } from '@utils/messageGroupManager'\nimport type { MessageGroup, DisplayConfig } from '@minto-types/messageGroup'\nimport { DISPLAY_CONFIGS } from '@minto-types/messageGroup'\n\ninterface UseMessageGroupsResult {\n /** All identified message groups */\n groups: MessageGroup[]\n /** Group manager instance for direct access */\n manager: MessageGroupManager\n /** Map of group ID to group */\n groupById: Map<string, MessageGroup>\n /** Get group for a specific message UUID */\n getGroupForMessage: (messageUuid: string) => MessageGroup | undefined\n /** Get group for a specific toolUseId */\n getGroupForToolUse: (toolUseId: string) => MessageGroup | undefined\n /** Check if a group should be rendered as static */\n shouldGroupBeStatic: (group: MessageGroup) => boolean\n /** Current display configuration */\n displayConfig: DisplayConfig\n}\n\n/**\n * Hook for managing message groups in React components\n *\n * @param normalizedMessages - Normalized message array\n * @param unresolvedToolUseIDs - Set of unresolved tool use IDs\n * @param inProgressToolUseIDs - Set of in-progress tool use IDs\n * @param verbose - Whether verbose mode is enabled\n * @returns Message group utilities and state\n */\nexport function useMessageGroups(\n normalizedMessages: NormalizedMessage[],\n unresolvedToolUseIDs: Set<string>,\n inProgressToolUseIDs: Set<string>,\n verbose: boolean = false,\n): UseMessageGroupsResult {\n // Select display config based on verbose mode\n const displayConfig = useMemo(\n () => (verbose ? DISPLAY_CONFIGS.verbose : DISPLAY_CONFIGS.normal),\n [verbose],\n )\n\n // Create and update message group manager\n // Memoized to only recompute when dependencies change\n const managerState = useMemo(() => {\n const manager = new MessageGroupManager()\n\n // Identify groups from messages\n manager.identifyGroups(normalizedMessages)\n\n // Update resolution states\n manager.updateResolutionStates(unresolvedToolUseIDs, inProgressToolUseIDs)\n\n // Get all groups\n const groups = manager.getAllGroups()\n const groupById = new Map(groups.map(g => [g.id, g]))\n\n return { manager, groups, groupById }\n }, [normalizedMessages, unresolvedToolUseIDs, inProgressToolUseIDs])\n\n const { manager, groups, groupById } = managerState\n\n // Helper to get group for a message\n const getGroupForMessage = useMemo(\n () => (messageUuid: string) => manager.getGroupByMessageUuid(messageUuid),\n [manager],\n )\n\n // Helper to get group for a toolUseId\n const getGroupForToolUse = useMemo(\n () => (toolUseId: string) => manager.getGroupByToolUseId(toolUseId),\n [manager],\n )\n\n // Helper to check if group should be static\n const shouldGroupBeStatic = useMemo(\n () => (group: MessageGroup) => manager.shouldGroupBeStatic(group),\n [manager],\n )\n\n return {\n groups,\n manager,\n groupById,\n getGroupForMessage,\n getGroupForToolUse,\n shouldGroupBeStatic,\n displayConfig,\n }\n}\n"],
5
+ "mappings": "AAOA,SAAS,eAAe;AAGxB,SAAS,2BAA2B;AAEpC,SAAS,uBAAuB;AA4BzB,SAAS,iBACd,oBACA,sBACA,sBACA,UAAmB,OACK;AAExB,QAAM,gBAAgB;AAAA,IACpB,MAAO,UAAU,gBAAgB,UAAU,gBAAgB;AAAA,IAC3D,CAAC,OAAO;AAAA,EACV;AAIA,QAAM,eAAe,QAAQ,MAAM;AACjC,UAAMA,WAAU,IAAI,oBAAoB;AAGxC,IAAAA,SAAQ,eAAe,kBAAkB;AAGzC,IAAAA,SAAQ,uBAAuB,sBAAsB,oBAAoB;AAGzE,UAAMC,UAASD,SAAQ,aAAa;AACpC,UAAME,aAAY,IAAI,IAAID,QAAO,IAAI,OAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAEpD,WAAO,EAAE,SAAAD,UAAS,QAAAC,SAAQ,WAAAC,WAAU;AAAA,EACtC,GAAG,CAAC,oBAAoB,sBAAsB,oBAAoB,CAAC;AAEnE,QAAM,EAAE,SAAS,QAAQ,UAAU,IAAI;AAGvC,QAAM,qBAAqB;AAAA,IACzB,MAAM,CAAC,gBAAwB,QAAQ,sBAAsB,WAAW;AAAA,IACxE,CAAC,OAAO;AAAA,EACV;AAGA,QAAM,qBAAqB;AAAA,IACzB,MAAM,CAAC,cAAsB,QAAQ,oBAAoB,SAAS;AAAA,IAClE,CAAC,OAAO;AAAA,EACV;AAGA,QAAM,sBAAsB;AAAA,IAC1B,MAAM,CAAC,UAAwB,QAAQ,oBAAoB,KAAK;AAAA,IAChE,CAAC,OAAO;AAAA,EACV;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
+ "names": ["manager", "groups", "groupById"]
7
+ }
@@ -1,16 +1,47 @@
1
- import { useEffect, useState } from "react";
1
+ import { useEffect, useState, useRef } from "react";
2
2
  let globalSize = {
3
3
  columns: process.stdout.columns || 80,
4
4
  rows: process.stdout.rows || 24
5
5
  };
6
6
  const listeners = /* @__PURE__ */ new Set();
7
7
  let isListenerAttached = false;
8
+ let debounceTimer = null;
9
+ const resizeCallbacks = /* @__PURE__ */ new Set();
10
+ const RESIZE_DEBOUNCE_MS = 300;
11
+ const SIZE_CHANGE_THRESHOLD = 5;
12
+ let isInClearingCycle = false;
13
+ let lastSignificantResizeTime = 0;
14
+ const RESIZE_COOLDOWN_MS = 2e3;
8
15
  function updateAllListeners() {
9
- globalSize = {
10
- columns: process.stdout.columns || 80,
11
- rows: process.stdout.rows || 24
12
- };
13
- listeners.forEach((listener) => listener());
16
+ if (debounceTimer) {
17
+ clearTimeout(debounceTimer);
18
+ }
19
+ debounceTimer = setTimeout(() => {
20
+ const newColumns = process.stdout.columns || 80;
21
+ const newRows = process.stdout.rows || 24;
22
+ if (globalSize.columns !== newColumns || globalSize.rows !== newRows) {
23
+ const oldColumns = globalSize.columns;
24
+ const columnDiff = Math.abs(oldColumns - newColumns);
25
+ const isSignificantResize = columnDiff > SIZE_CHANGE_THRESHOLD;
26
+ globalSize = {
27
+ columns: newColumns,
28
+ rows: newRows
29
+ };
30
+ listeners.forEach((listener) => listener());
31
+ const now = Date.now();
32
+ const timeSinceLastResize = now - lastSignificantResizeTime;
33
+ const isCooldownExpired = timeSinceLastResize > RESIZE_COOLDOWN_MS;
34
+ if (isSignificantResize && !isInClearingCycle && isCooldownExpired) {
35
+ isInClearingCycle = true;
36
+ lastSignificantResizeTime = now;
37
+ resizeCallbacks.forEach((callback) => callback());
38
+ setTimeout(() => {
39
+ isInClearingCycle = false;
40
+ }, 500);
41
+ }
42
+ }
43
+ debounceTimer = null;
44
+ }, RESIZE_DEBOUNCE_MS);
14
45
  }
15
46
  function useTerminalSize() {
16
47
  const [size, setSize] = useState(globalSize);
@@ -27,12 +58,37 @@ function useTerminalSize() {
27
58
  if (listeners.size === 0 && isListenerAttached) {
28
59
  process.stdout.off("resize", updateAllListeners);
29
60
  isListenerAttached = false;
61
+ if (debounceTimer) {
62
+ clearTimeout(debounceTimer);
63
+ debounceTimer = null;
64
+ }
30
65
  }
31
66
  };
32
67
  }, []);
33
68
  return size;
34
69
  }
70
+ function useFullscreenExitCallback(callback) {
71
+ return useSignificantResizeCallback(callback);
72
+ }
73
+ function useSignificantResizeCallback(callback) {
74
+ const callbackRef = useRef(callback);
75
+ callbackRef.current = callback;
76
+ useEffect(() => {
77
+ if (!isListenerAttached) {
78
+ process.stdout.setMaxListeners(20);
79
+ process.stdout.on("resize", updateAllListeners);
80
+ isListenerAttached = true;
81
+ }
82
+ const wrappedCallback = () => callbackRef.current();
83
+ resizeCallbacks.add(wrappedCallback);
84
+ return () => {
85
+ resizeCallbacks.delete(wrappedCallback);
86
+ };
87
+ }, []);
88
+ }
35
89
  export {
90
+ useFullscreenExitCallback,
91
+ useSignificantResizeCallback,
36
92
  useTerminalSize
37
93
  };
38
94
  //# sourceMappingURL=useTerminalSize.js.map